From fc4c8ed8036b2e7fceebd745d4a9d108f150d6b5 Mon Sep 17 00:00:00 2001 From: Charlie Jacobsen Date: Mon, 11 Jan 2016 12:33:35 -0700 Subject: [PATCH] static-cptr-cache: Updates cptr and cspace code for new cache, and tests. I'm seeing what appears to be race conditions in the tests, so we're not out of the woods yet. I think I just need to introduce a lock for the cptr cache. It wasn't originally designed to be thread safe since only one thread at a time was using it. But we need it now. There are a few other miscellaneous changes: - Moves cptr manipulation into public header. Doc cleanup. - cptr_init returns an integer now (non-zero signals failure). - Adds CAP_BUG macro. Library code invokes this to abort or signal a serious internal library error (e.g., unexpected switch case). kernel: CAP_BUG ==> BUG user: CAP_BUG ==> abort - Aside from the cptr cache code updates for the modified struct, separates cptr cache initialization into two parts: alloc and init. Motivation: Some users of libcap will have already allocated the cptr cache (e.g., declared it as a static global), and only need it initialized. So, to fully initialize a cptr cache, you now need to do, e.g., int ret; cptr_cache *cache; ret = cptr_cache_alloc(&cache); if (ret) ... handle error ... ret = cptr_cache_init(cache); if (ret) { cptr_cache_free(cache); ... handle error ... } - Updates test apps to use new cptr cache API (alloc then init). Adds some extra error handling/clean up code. --- include/libcap.h | 218 +++++++++++++++++++++++++++---- include/libcap_internal.h | 4 +- include/libcap_internal_kernel.h | 2 +- include/libcap_kernel.h | 3 + include/libcap_types.h | 103 ++------------- include/libcap_user.h | 5 + src/common/cap.c | 13 +- src/common/cptr_cache.c | 130 +++++++++--------- src/user/cap_user.c | 2 +- src/user/cptr_cache_user.c | 6 +- test/user/cap-stuff.c | 158 ++++++++++++++-------- test/user/multi_thrd_cap.c | 60 ++++++--- 12 files changed, 446 insertions(+), 258 deletions(-) diff --git a/include/libcap.h b/include/libcap.h index 9653e37..2f5d0b9 100644 --- a/include/libcap.h +++ b/include/libcap.h @@ -57,28 +57,193 @@ struct cap_type_ops { #define CAP_TYPE_MAX 256 #endif +#define CAP_BUG() __cap_bug() + /** - * Initalize the cptr cache subsystem + * For now, put debug macros in the user-accessible part; convenient. */ -void cptr_init(void); +extern int cap_debug_level; + +#define CAP_ERR __cap_err +#define CAP_WARN __cap_warn +#define CAP_MSG __cap_msg + +#define CAP_DEBUG_ERR 1 +#define CAP_DEBUG_WARN 2 +#define CAP_DEBUG_MSG 3 + +#define CAP_DEBUG(lvl, msg, ...) { \ + if (lvl <= cap_debug_level) \ + __cap_debug(msg,## __VA_ARGS__); \ + } + +/* CPTRs -------------------------------------------------- */ + /** - * Allocate and initialize a new cptr_cache. + * __cptr -- Construct a cptr from an unsigned long + * @cptr: the unsigned long to use + * + * This is a low-level function. You need to know how to pack + * the bits into the unsigned long. */ -int cptr_cache_init(struct cptr_cache **c_out); +static inline cptr_t __cptr(unsigned long cptr) +{ + return (cptr_t) {cptr}; +} /** - * Free and delete a cptr_cache + * cptr_val -- Extract the unsigned long (bits) in the cptr + * @c: the ctpr to extract + * + * This can be useful if you want to pass a cptr in a register, + * as a scalar. */ -void cptr_cache_destroy(struct cptr_cache *c); +static inline unsigned long cptr_val(cptr_t c) +{ + return c.cptr; +} /** - * Allocate a new cptr in the given cptr_cache. The cptr is stored in the memory - * pointed to by 'free_cptr'. + * cap_cptr_slot -- Returns the slot index into the final cnode table + * @c: the cptr + * + * Once you have arrived at the correct cnode table in the cspace + * radix tree, this is the index into that table to get the + * capability that @c refers to. + */ +static inline unsigned long cap_cptr_slot(cptr_t c) +{ + /* + * Mask off low bits + */ + return cptr_val(c) & ((1 << (CAP_CSPACE_CNODE_TABLE_BITS - 1)) - 1); +} +/** + * cap_cptr_fanout -- Gives fanout index for going *from* @lvl to @lvl + 1 + * @c: the cptr + * @lvl: the level in the cspace radix tree, where 0 <= lvl < CAP_CSPACE_DEPTH + * + * Each node in the cspace radix tree is a cnode table. Each cnode + * table is split in half: the first half are capability slots, and + * the other half are pointers to further nodes in the tree. If a + * cptr refers to a slot in a deeper level in the tree, you need to + * follow these pointers. The fanout index tells you which pointers + * to follow at each level. + */ +static inline unsigned long cap_cptr_fanout(cptr_t c, int lvl) +{ + unsigned long i; + + if (lvl >= CAP_CSPACE_DEPTH - 1) + CAP_BUG(); + + i = cptr_val(c); + /* + * Shift and mask off bits at correct section + */ + i >>= ((lvl + 1) * (CAP_CSPACE_CNODE_TABLE_BITS - 1)); + i &= ((1 << (CAP_CSPACE_CNODE_TABLE_BITS - 1)) - 1); + + return i; +} +/** + * cap_cptr_level -- The zero-indexed level in the cspace radix tree + * @c: the cptr + * + * Returns the level of the slot which @c refers to. 0 means the root + * cnode table. + */ +static inline unsigned long cap_cptr_level(cptr_t c) +{ + unsigned long i; + + i = cptr_val(c); + /* + * Shift and mask + */ + i >>= (CAP_CSPACE_DEPTH * (CAP_CSPACE_CNODE_TABLE_BITS - 1)); + i &= ((1 << CAP_CSPACE_DEPTH_BITS) - 1); + + return i; +} +/** + * cap_cptr_set_level -- Sets the level for @c + * @c: the cptr + * @lvl: the level in the cspace radix tree, 0 <= lvl < CAP_CSPACE_DEPTH + */ +static inline void cap_cptr_set_level(cptr_t *c, int lvl) +{ + /* Shift and OR to store lvl */ + c->cptr |= (lvl << + (CAP_CSPACE_DEPTH * (CAP_CSPACE_CNODE_TABLE_BITS - 1))); +} +/** + * cptr_is_null -- Returns non-zero if cptr is the special null cptr + * @c: cptr to test + */ +static inline int cptr_is_null(cptr_t c) +{ + return cptr_val(c) == cptr_val(CAP_CPTR_NULL); +} + +/* CPTR CACHEs -------------------------------------------------- */ + +/** + * cptr_init -- Initalize the cptr cache subsystem + */ +int cptr_init(void); +/** + * cptr_fini -- Tear down the cptr cache subsystem. + */ +void cptr_fini(void); +/** + * cptr_cache_alloc -- Allocate a cptr cache data structure (not initialized) + * @out: out param, pointer to newly alloc'd cache + * + * You should call cptr_cache_free when done with the cache. Returns + * non-zero on error. + */ +int cptr_cache_alloc(struct cptr_cache **out); +/** + * cptr_cache_free -- Free a cptr cache alloc'd via cptr_cache_alloc + * @cache: the cptr cache to free + */ +void cptr_cache_free(struct cptr_cache *cache); +/** + * cptr_cache_init -- Initialize the data in a cptr cache + * @cache: the cptr cache to initialize + * + * Zeros out things, and sets some initial values. You *must* call this + * function before using the cptr cache. + */ +int cptr_cache_init(struct cptr_cache *cache); +/** + * cptr_cache_destroy -- Destroys internals of cptr cache + * @cache: cache to destroy + * + * For now, this is a no-op. You *must* call this before freeing the + * cache. (Yes, for now it is a no-op, but perhaps it won't be in the + * future.) + */ +void cptr_cache_destroy(struct cptr_cache *cache); +/** + * cptr_alloc -- Allocate a new cptr from the cache + * @cache: the cptr cache to allocate from + * @free_cptr: out param, points to the allocated cptr + * + * Returns non-zero if there are no more slots left. */ int cptr_alloc(struct cptr_cache *cptr_cache, cptr_t *free_cptr); /** - * Remove the value pointed to by the + * cptr_free -- Return a cptr to the cache + * @cache: the cptr cache to return the cptr to + * @c: the cptr to return + * + * Fails silently if the cptr is free already. */ void cptr_free(struct cptr_cache *cptr_cache, cptr_t c); + +/* CSPACES -------------------------------------------------- */ + /** * Initializes caches, etc. in capability subsystem. Called when microkernel * intializes. @@ -89,6 +254,24 @@ int cap_init(void); * is exiting. */ void cap_fini(void); + +/** + * cap_cspace_slots_in_level -- Return total number of slots in cspace at lvl + * @lvl: the level to query + * + * Returns the total number of *capability* slots in all of the + * cnode tables at a given @lvl of the cspace radix tree. + */ +static inline int cap_cspace_slots_in_level(int lvl) +{ + int out = CAP_CSPACE_CNODE_TABLE_SIZE/2; + if (lvl < 0 || lvl >= CAP_CSPACE_DEPTH) + CAP_BUG(); + for ( ; lvl > 0; lvl-- ) + out *= CAP_CSPACE_CNODE_TABLE_SIZE/2; + return out; +} + /** * Register a new capability object type. If you pass type == 0, the * system will select the next available identifier and return it. You @@ -215,22 +398,5 @@ cap_type_t cap_cnode_type(struct cnode *cnode); */ struct cspace * cap_cnode_cspace(struct cnode *cnode); -/** - * For now, put debug macros in the user-accessible part; convenient. - */ -extern int cap_debug_level; - -#define CAP_ERR __cap_err -#define CAP_WARN __cap_warn -#define CAP_MSG __cap_msg - -#define CAP_DEBUG_ERR 1 -#define CAP_DEBUG_WARN 2 -#define CAP_DEBUG_MSG 3 - -#define CAP_DEBUG(lvl, msg, ...) { \ - if (lvl <= cap_debug_level) \ - __cap_debug(msg,## __VA_ARGS__); \ - } #endif /* __LIBCAP_H__ */ diff --git a/include/libcap_internal.h b/include/libcap_internal.h index 4c107dd..5e729fe 100644 --- a/include/libcap_internal.h +++ b/include/libcap_internal.h @@ -39,7 +39,7 @@ struct cnode { }; struct cnode_table { - struct cnode cnode[CAP_CNODE_TABLE_NUM_SLOTS]; + struct cnode cnode[CAP_CSPACE_CNODE_TABLE_SIZE]; uint8_t table_level; struct list_head table_list; }; @@ -61,7 +61,7 @@ struct cdt_root_node { /* The init and finish routines are defined in their own compoents. The * implementations differ between the kernel and userspace. */ -void __cptr_init(void); +int __cptr_init(void); void __cptr_fini(void); /** diff --git a/include/libcap_internal_kernel.h b/include/libcap_internal_kernel.h index 603f9c7..f40de1e 100644 --- a/include/libcap_internal_kernel.h +++ b/include/libcap_internal_kernel.h @@ -85,7 +85,7 @@ static inline void __cap_cache_free(cap_cache_t *cache, void *obj) #define __cap_zalloc(nmemb,size) kzalloc((nmemb)*(size),GFP_KERNEL) #define __cap_free(addr) kfree(addr) -static inline void __cptr_init(void) { } +static inline int __cptr_init(void) { return 0; } static inline void __cptr_fini(void) { } #endif /* __LIBCAP_INTERNAL_KERNEL_H__ */ diff --git a/include/libcap_kernel.h b/include/libcap_kernel.h index 68c978b..c8fd597 100644 --- a/include/libcap_kernel.h +++ b/include/libcap_kernel.h @@ -3,6 +3,7 @@ #include #include +#include CAP_BUILD_CORE_TYPES_NOBUILTIN(); @@ -15,4 +16,6 @@ CAP_BUILD_CORE_TYPES_NOBUILTIN(); #define __cap_debug(format,...) \ printk(KERN_DEBUG,"cap: %s:%d: "format,__FUNCTION__,__LINE__,##__VA_ARGS__) +#define __cap_bug() BUG() + #endif /* __LIBCAP_KERNEL_H__ */ diff --git a/include/libcap_types.h b/include/libcap_types.h index b801057..32b2e70 100644 --- a/include/libcap_types.h +++ b/include/libcap_types.h @@ -41,7 +41,7 @@ * cptr allocation algorithm works, and (2) because a cnode table needs at * least one capability slot and one pointer slot. */ -#define CAP_CSPACE_CNODE_TABLE_BITS 8 +#define CAP_CSPACE_CNODE_TABLE_BITS 6 #define CAP_CSPACE_CNODE_TABLE_SIZE (1 << CAP_CSPACE_CNODE_TABLE_BITS) #if (CAP_CSPACE_CNODE_TABLE_SIZE < 2) @@ -52,10 +52,12 @@ * All of the data - the level, fanout sections, and slot - must fit * inside an unsigned long. The current configuration was chosen so * that this works on 32- and 64-bit. The cspace size is fairly - * significant - over 200 million slot capacity. + * significant - over 1 million slot capacity. You don't want it to + * be too big or else the (inefficient) cptr cache with bitmaps will + * be enormous. */ #if ((CAP_CSPACE_DEPTH * (CAP_CSPACE_CNODE_TABLE_BITS - 1) + \ - CAP_CSPACE_DEPTH_BITS) > SIZEOF_UNSIGNED_LONG) + CAP_CSPACE_DEPTH_BITS) > (SIZEOF_UNSIGNED_LONG * 8)) #error "Adjust cspace sizing, otherwise cptrs won't work." #endif @@ -81,92 +83,30 @@ #else #error "cspace depth not 4, you need to update this" #endif -static inline int cap_cspace_slots_in_level(int lvl) -{ - int out = CAP_CSPACE_CNODE_TABLE_SIZE/2; - if (lvl < 0 || lvl >= CAP_CSPACE_DEPTH) - BUG(); - for ( ; lvl > 0; lvl-- ) - out *= CAP_CSPACE_CNODE_TABLE_SIZE/2; - return out; -} /* CPTRs -------------------------------------------------- */ +/** + * cptr_t -- Index into cspace radix tree (like a file descriptor) + * + * We wrap it inside a struct def so that the compiler will do strong + * type checking. + */ typedef struct { unsigned long cptr; } cptr_t; -static inline cptr_t __cptr(unsigned long cptr) -{ - return (cptr_t) {cptr}; -} - -static inline unsigned long cptr_val(cptr_t c) -{ - return c.cptr; -} - -static inline unsigned long cap_cptr_slot(cptr_t c) -{ - /* - * Mask off low bits - */ - return cptr_val(c) & ((1 << (CAP_CSPACE_CNODE_TABLE_BITS - 1)) - 1); -} - -/* - * Gives fanout index for going *from* lvl to lvl + 1, where - * 0 <= lvl < CAP_CSPACE_DEPTH. - */ -static inline unsigned long cap_cptr_fanout(cptr_t c, int lvl) -{ - unsigned long i; - - if (unlikely(lvl >= 3)) - BUG(); - - i = cptr_val(c); - /* - * Shift and mask off bits at correct section - */ - i >>= ((lvl + 1) * (CAP_CSPACE_CNODE_TABLE_BITS - 1)); - i &= ((1 << (CAP_CSPACE_CNODE_TABLE_BITS - 1)) - 1); - - return i; -} - -/* - * Gives depth/level of cptr, zero indexed (0 means the root cnode table) - */ -static inline unsigned long cap_cptr_level(cptr_t c) -{ - unsigned long i; - - i = cptr_val(c); - /* - * Shift and mask - */ - i >>= (CAP_CSPACE_DEPTH * (CAP_CSPACE_CNODE_TABLE_BITS - 1)); - i &= ((1 << CAP_CSPACE_DEPTH_BITS) - 1); - - return i; -} - /* * Reserved cnodes: * * cptr = 0 is always null */ -#define CAP_CPTR_NULL __cptr(0) +#define CAP_CPTR_NULL ((cptr_t){0}) -static inline int cptr_is_null(cptr_t c) -{ - return cptr_val(c) == cptr_val(CAP_CPTR_NULL); -} /* CPTR CACHE -------------------------------------------------- */ + #if (CAP_CSPACE_DEPTH == 4) struct cptr_cache { @@ -180,23 +120,6 @@ struct cptr_cache { unsigned long bmap3[CAP_BITS_TO_LONGS(CAP_CSPACE_SLOTS_IN_LEVEL(3))]; }; -static inline unsigned long* -cap_cptr_cache_bmap_for_level(struct cptr_cache *c, int lvl) -{ - switch (lvl) { - case 0: - return c->bmap0; - case 1: - return c->bmap1; - case 2: - return c->bmap2; - case 3: - return c->bmap3; - default: - BUG(); - } -} - #else #error "You need to adjust the cptr cache def." #endif diff --git a/include/libcap_user.h b/include/libcap_user.h index de44a10..6545fca 100644 --- a/include/libcap_user.h +++ b/include/libcap_user.h @@ -2,6 +2,7 @@ #define __LIBCAP_USER_H__ #include +#include #include CAP_BUILD_CORE_TYPES_NOBUILTIN(); @@ -15,4 +16,8 @@ CAP_BUILD_CORE_TYPES_NOBUILTIN(); #define __cap_debug(format,...) \ fprintf(stderr,"CDEBUG: %s:%d: "format,__FUNCTION__,__LINE__,## __VA_ARGS__) +#define __cap_bug() \ + abort() + + #endif /* __LIBCAP_USER_H__ */ diff --git a/src/common/cap.c b/src/common/cap.c index 04765d5..6a9383a 100644 --- a/src/common/cap.c +++ b/src/common/cap.c @@ -159,7 +159,7 @@ static int make_empty_cnode_table(struct cspace *cspace, uint8_t level, * We delay some of the other set up until the cnode is * actually used. */ - for (i = 0; i < CAP_CNODE_TABLE_NUM_SLOTS; i++) { + for (i = 0; i < CAP_CSPACE_CNODE_TABLE_SIZE; i++) { new->cnode[i].type = CAP_TYPE_FREE; INIT_LIST_HEAD(&new->cnode[i].children); INIT_LIST_HEAD(&new->cnode[i].siblings); @@ -262,7 +262,7 @@ static int update_cnode_table(struct cspace *cspace, * pointers. Skip over cap slots by adding half the number of slots * to level_id. */ - index = level_id + (CAP_CNODE_TABLE_NUM_SLOTS >> 1); + index = level_id + (CAP_CSPACE_CNODE_TABLE_SIZE >> 1); if (old->cnode[index].type == CAP_TYPE_CNODE) { /* @@ -324,6 +324,11 @@ static int find_cnode(struct cspace *cspace, struct cnode_table *old, /* * invalid indexing, etc. */ + CAP_DEBUG(1, + "Error in lookup: cnode is %s, and we are%s trying to alloc\n", + old->cnode[level_id].type == CAP_TYPE_FREE ? + "free" : "occupied", + alloc ? "" : " not"); return -EINVAL; /* signal an error in look up */ } } @@ -381,7 +386,7 @@ static int __cap_cnode_lookup(struct cspace *cspace, cptr_t c, bool alloc, /* * If cptr is null, fail */ - if (cptr_val(c) == cptr_val(CAP_CPTR_NULL)) + if (cptr_is_null(c)) return -EINVAL; /* @@ -1079,7 +1084,7 @@ static void cnode_table_tear_down(struct cnode_table *t, struct cspace *cspace) /* * Loop over cap slots (first half), and tear down each cnode */ - for (i = 0; i < (CAP_CNODE_TABLE_NUM_SLOTS >> 1); i++) { + for (i = 0; i < (CAP_CSPACE_CNODE_TABLE_SIZE >> 1); i++) { cnode = &t->cnode[i]; cnode_tear_down(cnode, cspace); } diff --git a/src/common/cptr_cache.c b/src/common/cptr_cache.c index c715027..dbad931 100644 --- a/src/common/cptr_cache.c +++ b/src/common/cptr_cache.c @@ -10,9 +10,31 @@ #include "libcap_types.h" #include "libcap_internal.h" -void cptr_init(void) +#if (CAP_CSPACE_DEPTH == 4) +static inline unsigned long* +cap_cptr_cache_bmap_for_level(struct cptr_cache *c, int lvl) { - __cptr_init(); + switch (lvl) { + case 0: + return c->bmap0; + case 1: + return c->bmap1; + case 2: + return c->bmap2; + case 3: + return c->bmap3; + default: + CAP_BUG(); + } +} + +#else +#error "You need to adjust this function def." +#endif + +int cptr_init(void) +{ + return __cptr_init(); } void cptr_fini(void) @@ -20,70 +42,52 @@ void cptr_fini(void) __cptr_fini(); } -int cptr_cache_init(struct cptr_cache **out) +int cptr_cache_alloc(struct cptr_cache **out) { struct cptr_cache *cache; - int ret; - int i, j; - int nbits; /* * Allocate the container */ cache = cap_zalloc(1, sizeof(*cache)); - if (!cache) { - ret = -ENOMEM; - goto fail1; - } - /* - * Allocate the bitmaps - */ - for (i = 0; i < (1 << CAP_CPTR_DEPTH_BITS); i++) { - /* - * For level i, we use the slot bits plus i * fanout bits - * - * So e.g. for level 0, we use only slot bits, so there - * are only 2^(num slot bits) cap slots at level 0. - */ - nbits = 1 << (CAP_CPTR_SLOT_BITS + i * CAP_CPTR_FANOUT_BITS); - /* - * Alloc bitmap - */ - cache->bmaps[i] = cap_zalloc(BITS_TO_LONGS(nbits), - sizeof(unsigned long)); - if (!cache->bmaps[i]) { - ret = -ENOMEM; - goto fail2; /* i = level we failed at */ - } - } - /* - * Mark reserved cptr's as allocated - */ - cap_set_bit(0, cache->bmaps[0]); - + if (!cache) + return -ENOMEM; *out = cache; - return 0; +} - fail2: - for (j = 0; j < i; j++) - cap_free(cache->bmaps[j]); +void cptr_cache_free(struct cptr_cache *cache) +{ + /* + * Free container + */ cap_free(cache); - fail1: - return ret; } -void cptr_cache_destroy(struct cptr_cache *cache) +int cptr_cache_init(struct cptr_cache *cache) { int i; + unsigned long *bmap; /* - * Free bitmaps + * Zero out the bitmaps. (The caller may not have + * necessarily used zalloc.) */ - for (i = 0; i < (1 << CAP_CPTR_DEPTH_BITS); i++) - cap_free(cache->bmaps[i]); + for (i = 0; i < CAP_CSPACE_DEPTH; i++) { + bmap = cap_cptr_cache_bmap_for_level(cache, i); + memset(bmap, + 0, + CAP_BITS_TO_LONGS(cap_cspace_slots_in_level(i))); + } /* - * Free container + * Mark reserved cptr's as allocated */ - cap_free(cache); + cap_set_bit(0, cap_cptr_cache_bmap_for_level(cache, 0)); + + return 0; +} + +void cptr_cache_destroy(struct cptr_cache *cache) +{ + /* No-op for now */ } int __cap_alloc_cptr_from_bmap(unsigned long *bmap, int size, @@ -114,14 +118,15 @@ int cptr_alloc(struct cptr_cache *cptr_cache, cptr_t *free_cptr) unsigned long *bmap; unsigned long idx; int size; + cptr_t result; depth = 0; do { - bmap = cptr_cache->bmaps[depth]; - size = 1 << (CAP_CPTR_SLOT_BITS + depth * CAP_CPTR_FANOUT_BITS); + bmap = cap_cptr_cache_bmap_for_level(cptr_cache, depth); + size = cap_cspace_slots_in_level(depth); done = __cap_alloc_cptr_from_bmap(bmap, size, &idx); depth++; - } while (!done && depth < (1 << CAP_CPTR_DEPTH_BITS)); + } while (!done && depth < CAP_CSPACE_DEPTH); if (!done) { /* @@ -129,19 +134,20 @@ int cptr_alloc(struct cptr_cache *cptr_cache, cptr_t *free_cptr) */ CAP_ERR("out of cptrs"); ret = -ENOMEM; - goto fail2; + goto fail1; } /* * Found one; dec depth back to what it was, and encode * depth in cptr */ depth--; - idx |= (depth << CAP_CPTR_LEVEL_SHIFT); - *free_cptr = __cptr(idx); + result = __cptr(idx); + cap_cptr_set_level(&result, depth); + *free_cptr = result; return 0; - fail2: + fail1: return ret; } @@ -150,17 +156,21 @@ void cptr_free(struct cptr_cache *cptr_cache, cptr_t c) unsigned long *bmap; unsigned long bmap_idx; unsigned long level; - + unsigned long mask; /* * Get the correct level bitmap */ level = cap_cptr_level(c); - bmap = cptr_cache->bmaps[level]; + bmap = cap_cptr_cache_bmap_for_level(cptr_cache, level); /* - * The bitmap index includes all fanout bits and the slot bits + * The bitmap index includes all fanout bits and the slot bits (this + * is what makes allocation fast and easy). + * + * It's also a good idea to mask off in case some stray erroneous bits + * ended up in the cptr. */ - bmap_idx = ((1 << (CAP_CPTR_FANOUT_BITS * level + CAP_CPTR_SLOT_BITS)) - - 1) & cptr_val(c); + mask = (1 << ((level + 1) * (CAP_CSPACE_CNODE_TABLE_BITS - 1))) - 1; + bmap_idx = cptr_val(c) & mask; /* * Clear the bit in the bitmap */ diff --git a/src/user/cap_user.c b/src/user/cap_user.c index 973ca83..a1349d8 100644 --- a/src/user/cap_user.c +++ b/src/user/cap_user.c @@ -1,4 +1,4 @@ #include "libcap.h" -int cap_debug_level = 0; +int cap_debug_level = 1; diff --git a/src/user/cptr_cache_user.c b/src/user/cptr_cache_user.c index 5b7553c..48617fd 100644 --- a/src/user/cptr_cache_user.c +++ b/src/user/cptr_cache_user.c @@ -41,7 +41,7 @@ static int __get_l1_cache_size(int *size, int *line) return 0; } -void __cptr_init() +int __cptr_init(void) { int i; @@ -53,10 +53,10 @@ void __cptr_init() pthread_spin_init(&__spinlocks[i], PTHREAD_PROCESS_PRIVATE); } - return; + return 0; } -void __cptr_fini() +void __cptr_fini(void) { if (__spinlocks) free((void *)__spinlocks); diff --git a/test/user/cap-stuff.c b/test/user/cap-stuff.c index 9c85faf..0c88cc4 100644 --- a/test/user/cap-stuff.c +++ b/test/user/cap-stuff.c @@ -47,23 +47,36 @@ int testcase1() /* Initialize a cspace */ csp = cap_alloc_cspace(); + if (!csp) { + printf("bad alloc\n"); + goto out; + } printf("\nTestCase : Cspace Initialization.\n"); ret = cap_init_cspace(csp); if (ret < 0) { printf("Cspace Initialization Failed!!\n"); - goto fail1; + goto free_cspace; } else printf("Cspace Initialization Passed Address:%p \n", csp); /* cptr cache intialization. This is totally users stuff */ - ret = cptr_cache_init(&cache); + ret = cptr_cache_alloc(&cache); + if (ret < 0) { + printf("cptr cache alloc failed\n"); + goto destroy_cspace; + } + ret = cptr_cache_init(cache); + if (ret < 0) { + printf("cptr cache init failed\n"); + goto free_cache; + } ret = cptr_alloc(cache, &slot_out); p = strdup("testcase1"); if (!p) { CAP_ERR("alloc failed"); ret = -ENOMEM; - goto fail; + goto destroy_cache; } /* Insert capability in cspace */ @@ -72,14 +85,14 @@ int testcase1() if (ret < 0) { CAP_ERR("cap insertion failed\n"); - goto fail; + goto destroy_cache; } /* Verification if capability is properly inserted in the cspace. */ ret = cap_cnode_verify(csp, slot_out); if (ret < 0) { CAP_ERR("Lookup failed"); - goto fail; + goto destroy_cache; } else printf("Capability Addition & Lookup Passed\n"); @@ -111,15 +124,18 @@ int testcase1() */ ret = cap_insert(csp, slot_out, p, stringobj_type); - if (ret) { + if (ret) printf("Cspace Deletion Passed\n"); - goto fail1; - } -fail: + +destroy_cache: + cptr_cache_destroy(cache); +free_cache: + cptr_cache_free(cache); +destroy_cspace: cap_destroy_cspace(csp); -fail1: - if (csp) - cap_free_cspace(csp); +free_cspace: + cap_free_cspace(csp); +out: return ret; } @@ -141,80 +157,97 @@ int testcase_grant() ret = cap_init_cspace(scsp); if (ret < 0) { printf("Cspace Setup Failed\n"); - goto fail; + goto free_scspace; } printf("Source Cspace Initilaized: Address=%p\n", scsp); /* cptr cache intialization. This is totally users stuff */ - ret = cptr_cache_init(&scache); + ret = cptr_cache_alloc(&scache); + if (ret < 0) { + printf("cache alloc failed\n"); + goto destroy_scspace; + } + ret = cptr_cache_init(scache); if (ret < 0) { printf("Cache Initilization failed\n"); - goto fail1; + goto free_scache; } ret = cptr_alloc(scache, &sslot); if (ret < 0) { printf("cptr allocation Failed!!\n"); - goto fail1; + goto destroy_scache; } p = strdup("testcase_grant"); /* Insert capability in cspace */ ret = cap_insert(scsp, sslot, p, stringobj_type); if (ret) { CAP_ERR("cap insertion failed\n"); - goto fail1; + goto destroy_scache; } printf("Added capability [%p] to Source cspace\n", p); /* Setup destination cspace */ dcsp = cap_alloc_cspace(); if (!dcsp) - goto fail1; + goto destroy_scache; ret = cap_init_cspace(dcsp); if (ret < 0) { printf("Cspace Setup Failed\n"); - goto fail1; + goto free_dcspace; } printf("Destination Cspace Initilaized: Address=%p\n", dcsp); - ret = cptr_cache_init(&dcache); + ret = cptr_cache_alloc(&dcache); + if (ret < 0) { + printf("cache alloc failed\n"); + goto destroy_dcspace; + } + ret = cptr_cache_init(dcache); if (ret < 0) { printf("Cache Initilization failed\n"); - goto fail2; + goto free_dcache; } ret = cptr_alloc(dcache, &dslot); if (ret < 0) { printf("cptr allocation Failed!!\n"); - goto fail2; + goto destroy_dcache; } ret = cap_grant(scsp, sslot, dcsp, dslot); if (ret < 0) { printf("Granting capability failed\n"); - goto fail2; + goto destroy_dcache; } ret = cap_cnode_verify(dcsp, dslot); if (ret < 0) { CAP_ERR("Lookup failed\n"); - goto fail2; + goto destroy_dcache; } else { printf("Capability granted successfully from Cspace[%p] at slot 0x%lx \ to Cspace[%p] at slot 0x%lx\n", scsp, cptr_val(sslot), dcsp, cptr_val(dslot)); } -fail2: + +destroy_dcache: + cptr_cache_destroy(dcache); +free_dcache: + cptr_cache_free(dcache); +destroy_dcspace: cap_destroy_cspace(dcsp); -fail1: +free_dcspace: + cap_free_cspace(dcsp); +destroy_scache: + cptr_cache_destroy(scache); +free_scache: + cptr_cache_free(scache); +destroy_scspace: cap_destroy_cspace(scsp); -fail: - if (dcsp) - cap_free_cspace(dcsp); - if (scsp) - cap_free_cspace(scsp); - +free_scspace: + cap_free_cspace(scsp); return ret; } @@ -301,72 +334,91 @@ int testcase_revoke() { scsp = cap_alloc_cspace(); if (!scsp) { perror("Source Cspace allocation failed\n"); - goto fail; + goto out; } ret = cap_init_cspace(scsp); if (ret < 0) { printf("Cspace Initialization failed\n"); - goto fail; + goto free_scspace; } - ret = cptr_cache_init(&scache); + + ret = cptr_cache_alloc(&scache); + if (ret < 0) { + printf("cache alloc failed\n"); + goto destroy_scspace; + } + ret = cptr_cache_init(scache); if (ret < 0) { printf("cptr cache Initialization failed\n"); - goto fail1; + goto free_scache; } /* 2nd CSPACE */ dcsp = cap_alloc_cspace(); if (!dcsp) { perror("malloc cspace\n"); - goto fail1; + goto destroy_scache; } ret = cap_init_cspace(dcsp); if (ret < 0) { printf("Cspace Initialization failed\n"); - goto fail1; + goto free_dcspace; } - ret = cptr_cache_init(&dcache); + ret = cptr_cache_alloc(&dcache); + if (ret < 0) { + printf("cache alloc failed\n"); + goto destroy_dcspace; + } + ret = cptr_cache_init(dcache); if (ret < 0) { printf("cptr cache Initialization failed\n"); - goto fail2; + goto free_dcache; } ret = cptr_alloc(scache, &sslot); if (ret < 0) { printf("cptr aloocation failed\n"); - goto fail2; + goto destroy_dcache; } ret = cptr_alloc(dcache, &dslot); if (ret < 0) { printf("cptr aloocation failed\n"); - goto fail2; + goto destroy_dcache; } ret = insert(scsp, sslot); if (ret < 0) - goto fail2; + goto destroy_dcache; ret = grant(scsp, dcsp, sslot, dslot); if (ret < 0) - goto fail2; + goto destroy_dcache; ret = do_revoke(scsp, sslot, scache); if (ret < 0) - goto fail2; + goto destroy_dcache; ret = cap_cnode_verify(dcsp, dslot); if (ret < 0) { printf("\nTestcase Capability Revocation Passed\n"); - goto fail2; + goto destroy_dcache; } printf("\nTestcase capability Revocation Failed\n"); -fail2: +destroy_dcache: + cptr_cache_destroy(dcache); +free_dcache: + cptr_cache_free(dcache); +destroy_dcspace: cap_destroy_cspace(dcsp); -fail1: +free_dcspace: + cap_free_cspace(dcsp); +destroy_scache: + cptr_cache_destroy(scache); +free_scache: + cptr_cache_free(scache); +destroy_scspace: cap_destroy_cspace(scsp); -fail: - if (dcsp) - cap_free_cspace(dcsp); - if (scsp) - cap_free_cspace(scsp); +free_scspace: + cap_free_cspace(scsp); +out: return ret; } diff --git a/test/user/multi_thrd_cap.c b/test/user/multi_thrd_cap.c index 2c8551d..844a98f 100644 --- a/test/user/multi_thrd_cap.c +++ b/test/user/multi_thrd_cap.c @@ -249,9 +249,13 @@ int main() ret = cap_init(); if (ret < 0) { CAP_ERR("libcap init failed"); - return ret; + goto out; + } + ret = cptr_init(); + if (ret < 0) { + CAP_ERR("cptr init failed"); + goto cap_exit; } - cptr_init(); stringobj_type = cap_register_type(stringobj_type, &stringobj_ops); @@ -260,38 +264,48 @@ int main() scsp = cap_alloc_cspace(); if (!scsp) { printf("Source Cspace allocation failed!\n"); - goto fail2; + goto cptr_exit; } ret = cap_init_cspace(scsp); if (ret < 0) { printf("Cspace Initialization failed\n"); - goto fail2; + goto free_scspace; } /* 2nd CSPACE */ dcsp = cap_alloc_cspace(); if (!dcsp) { printf("Destination Cspace allocation failed!\n"); - goto fail1; + goto destroy_scspace; } ret = cap_init_cspace(dcsp); if (ret < 0) { printf("Cspace Initialization failed\n"); - goto fail1; + goto free_dcspace; } - ret = cptr_cache_init(&scache); + ret = cptr_cache_alloc(&scache); + if (ret < 0) { + printf("cptr cache alloc failed\n"); + goto destroy_dcspace; + } + ret = cptr_cache_init(scache); if (ret < 0) { printf("cptr cache Initialization failed\n"); - goto fail; + goto free_scache; } - ret = cptr_cache_init(&dcache); + ret = cptr_cache_alloc(&dcache); + if (ret < 0) { + printf("cptr cache alloc failed\n"); + goto destroy_scache; + } + ret = cptr_cache_init(dcache); if (ret < 0) { printf("cptr cache Initialization failed\n"); - goto fail; + goto free_dcache; } for (i = 0; i < SLOTS; i++) { @@ -328,17 +342,27 @@ int main() printf("Problem join %d\n", i); } } - fail: + +destroy_dcache: + cptr_cache_destroy(dcache); +free_dcache: + cptr_cache_free(dcache); +destroy_scache: + cptr_cache_destroy(scache); +free_scache: + cptr_cache_free(scache); +destroy_dcspace: cap_destroy_cspace(dcsp); - fail1: +free_dcspace: + cap_free_cspace(dcsp); +destroy_scspace: cap_destroy_cspace(scsp); - fail2: - if (dcsp) - cap_free_cspace(dcsp); - if (scsp) - cap_free_cspace(scsp); +free_scspace: + cap_free_cspace(scsp); +cptr_exit: cptr_fini(); +cap_exit: cap_fini(); - +out: return ret; } -- GitLab