diff options
Diffstat (limited to 'libglusterfs')
-rw-r--r-- | libglusterfs/src/glusterfs/xlator.h | 2 | ||||
-rw-r--r-- | libglusterfs/src/libglusterfs.sym | 1 | ||||
-rw-r--r-- | libglusterfs/src/mem-pool.c | 193 | ||||
-rw-r--r-- | libglusterfs/src/xlator.c | 23 |
4 files changed, 105 insertions, 114 deletions
diff --git a/libglusterfs/src/glusterfs/xlator.h b/libglusterfs/src/glusterfs/xlator.h index 90396f93431..b7d0249c9c8 100644 --- a/libglusterfs/src/glusterfs/xlator.h +++ b/libglusterfs/src/glusterfs/xlator.h @@ -1035,6 +1035,8 @@ gf_boolean_t loc_is_nameless(loc_t *loc); int xlator_mem_acct_init(xlator_t *xl, int num_types); +void +xlator_mem_acct_unref(struct mem_acct *mem_acct); int is_gf_log_command(xlator_t *trans, const char *name, char *value, size_t size); int diff --git a/libglusterfs/src/libglusterfs.sym b/libglusterfs/src/libglusterfs.sym index 0fdb62c810f..d5413f41c89 100644 --- a/libglusterfs/src/libglusterfs.sym +++ b/libglusterfs/src/libglusterfs.sym @@ -1097,6 +1097,7 @@ xlator_foreach xlator_foreach_depth_first xlator_init xlator_mem_acct_init +xlator_mem_acct_unref xlator_notify xlator_option_info_list xlator_option_init_bool diff --git a/libglusterfs/src/mem-pool.c b/libglusterfs/src/mem-pool.c index 92f78ee952b..d717e9ffab9 100644 --- a/libglusterfs/src/mem-pool.c +++ b/libglusterfs/src/mem-pool.c @@ -35,61 +35,92 @@ gf_mem_acct_enable_set(void *data) return; } -int -gf_mem_set_acct_info(xlator_t *xl, char **alloc_ptr, size_t size, uint32_t type, - const char *typestr) +static void * +gf_mem_header_prepare(struct mem_header *header, size_t size) { - void *ptr = NULL; - struct mem_header *header = NULL; + void *ptr; - if (!alloc_ptr) - return -1; + header->size = size; - ptr = *alloc_ptr; + ptr = header + 1; - GF_ASSERT(xl != NULL); + /* data follows in this gap of 'size' bytes */ + *(uint32_t *)(ptr + size) = GF_MEM_TRAILER_MAGIC; - GF_ASSERT(xl->mem_acct != NULL); + return ptr; +} - GF_ASSERT(type <= xl->mem_acct->num_types); +static void * +gf_mem_set_acct_info(struct mem_acct *mem_acct, struct mem_header *header, + size_t size, uint32_t type, const char *typestr) +{ + struct mem_acct_rec *rec = NULL; + bool new_ref = false; - LOCK(&xl->mem_acct->rec[type].lock); - { - if (!xl->mem_acct->rec[type].typestr) - xl->mem_acct->rec[type].typestr = typestr; - xl->mem_acct->rec[type].size += size; - xl->mem_acct->rec[type].num_allocs++; - xl->mem_acct->rec[type].total_allocs++; - xl->mem_acct->rec[type].max_size = max(xl->mem_acct->rec[type].max_size, - xl->mem_acct->rec[type].size); - xl->mem_acct->rec[type].max_num_allocs = max( - xl->mem_acct->rec[type].max_num_allocs, - xl->mem_acct->rec[type].num_allocs); - } - UNLOCK(&xl->mem_acct->rec[type].lock); + if (mem_acct != NULL) { + GF_ASSERT(type <= mem_acct->num_types); - GF_ATOMIC_INC(xl->mem_acct->refcnt); + rec = &mem_acct->rec[type]; + LOCK(&rec->lock); + { + if (!rec->typestr) { + rec->typestr = typestr; + } + rec->size += size; + new_ref = (rec->num_allocs == 0); + rec->num_allocs++; + rec->total_allocs++; + rec->max_size = max(rec->max_size, rec->size); + rec->max_num_allocs = max(rec->max_num_allocs, rec->num_allocs); + +#ifdef DEBUG + list_add(&header->acct_list, &rec->obj_list); +#endif + } + UNLOCK(&rec->lock); + + /* We only take a reference for each memory type used, not for each + * allocation. This minimizes the use of atomic operations. */ + if (new_ref) { + GF_ATOMIC_INC(mem_acct->refcnt); + } + } - header = (struct mem_header *)ptr; header->type = type; - header->size = size; - header->mem_acct = xl->mem_acct; + header->mem_acct = mem_acct; header->magic = GF_MEM_HEADER_MAGIC; + return gf_mem_header_prepare(header, size); +} + +static void * +gf_mem_update_acct_info(struct mem_acct *mem_acct, struct mem_header *header, + size_t size) +{ + struct mem_acct_rec *rec = NULL; + + if (mem_acct != NULL) { + rec = &mem_acct->rec[header->type]; + LOCK(&rec->lock); + { + rec->size += size - header->size; + rec->total_allocs++; + rec->max_size = max(rec->max_size, rec->size); + #ifdef DEBUG - INIT_LIST_HEAD(&header->acct_list); - LOCK(&xl->mem_acct->rec[type].lock); - { - list_add(&header->acct_list, &(xl->mem_acct->rec[type].obj_list)); - } - UNLOCK(&xl->mem_acct->rec[type].lock); + /* The old 'header' already was present in 'obj_list', but + * realloc() could have changed its address. We need to remove + * the old item from the list and add the new one. This can be + * done this way because list_move() doesn't use the pointers + * to the old location (which are not valid anymore) already + * present in the list, it simply overwrites them. */ + list_move(&header->acct_list, &rec->obj_list); #endif - ptr += sizeof(struct mem_header); - /* data follows in this gap of 'size' bytes */ - *(uint32_t *)(ptr + size) = GF_MEM_TRAILER_MAGIC; + } + UNLOCK(&rec->lock); + } - *alloc_ptr = ptr; - return 0; + return gf_mem_header_prepare(header, size); } void * @@ -97,7 +128,7 @@ __gf_calloc(size_t nmemb, size_t size, uint32_t type, const char *typestr) { size_t tot_size = 0; size_t req_size = 0; - char *ptr = NULL; + void *ptr = NULL; xlator_t *xl = NULL; if (!THIS->ctx->mem_acct_enable) @@ -114,16 +145,15 @@ __gf_calloc(size_t nmemb, size_t size, uint32_t type, const char *typestr) gf_msg_nomem("", GF_LOG_ALERT, tot_size); return NULL; } - gf_mem_set_acct_info(xl, &ptr, req_size, type, typestr); - return (void *)ptr; + return gf_mem_set_acct_info(xl->mem_acct, ptr, req_size, type, typestr); } void * __gf_malloc(size_t size, uint32_t type, const char *typestr) { size_t tot_size = 0; - char *ptr = NULL; + void *ptr = NULL; xlator_t *xl = NULL; if (!THIS->ctx->mem_acct_enable) @@ -138,84 +168,32 @@ __gf_malloc(size_t size, uint32_t type, const char *typestr) gf_msg_nomem("", GF_LOG_ALERT, tot_size); return NULL; } - gf_mem_set_acct_info(xl, &ptr, size, type, typestr); - return (void *)ptr; + return gf_mem_set_acct_info(xl->mem_acct, ptr, size, type, typestr); } void * __gf_realloc(void *ptr, size_t size) { size_t tot_size = 0; - char *new_ptr; - struct mem_header *old_header = NULL; - struct mem_header *new_header = NULL; - struct mem_header tmp_header; + struct mem_header *header = NULL; if (!THIS->ctx->mem_acct_enable) return REALLOC(ptr, size); REQUIRE(NULL != ptr); - old_header = (struct mem_header *)(ptr - GF_MEM_HEADER_SIZE); - GF_ASSERT(old_header->magic == GF_MEM_HEADER_MAGIC); - tmp_header = *old_header; - -#ifdef DEBUG - int type = 0; - size_t copy_size = 0; - - /* Making these changes for realloc is not straightforward. So - * I am simulating realloc using calloc and free - */ - - type = tmp_header.type; - new_ptr = __gf_calloc(1, size, type, - tmp_header.mem_acct->rec[type].typestr); - if (new_ptr) { - copy_size = (size > tmp_header.size) ? tmp_header.size : size; - memcpy(new_ptr, ptr, copy_size); - __gf_free(ptr); - } - - /* This is not quite what the man page says should happen */ - return new_ptr; -#endif + header = (struct mem_header *)(ptr - GF_MEM_HEADER_SIZE); + GF_ASSERT(header->magic == GF_MEM_HEADER_MAGIC); tot_size = size + GF_MEM_HEADER_SIZE + GF_MEM_TRAILER_SIZE; - new_ptr = realloc(old_header, tot_size); - if (!new_ptr) { + header = realloc(header, tot_size); + if (!header) { gf_msg_nomem("", GF_LOG_ALERT, tot_size); return NULL; } - /* - * We used to pass (char **)&ptr as the second - * argument after the value of realloc was saved - * in ptr, but the compiler warnings complained - * about the casting to and forth from void ** to - * char **. - * TBD: it would be nice to adjust the memory accounting info here, - * but calling gf_mem_set_acct_info here is wrong because it bumps - * up counts as though this is a new allocation - which it's not. - * The consequence of doing nothing here is only that the sizes will be - * wrong, but at least the counts won't be. - uint32_t type = 0; - xlator_t *xl = NULL; - type = header->type; - xl = (xlator_t *) header->xlator; - gf_mem_set_acct_info (xl, &new_ptr, size, type, NULL); - */ - - new_header = (struct mem_header *)new_ptr; - *new_header = tmp_header; - new_header->size = size; - - new_ptr += sizeof(struct mem_header); - /* data follows in this gap of 'size' bytes */ - *(uint32_t *)(new_ptr + size) = GF_MEM_TRAILER_MAGIC; - - return (void *)new_ptr; + return gf_mem_update_acct_info(header->mem_acct, header, size); } int @@ -321,6 +299,7 @@ __gf_free(void *free_ptr) void *ptr = NULL; struct mem_acct *mem_acct; struct mem_header *header = NULL; + bool last_ref = false; if (!THIS->ctx->mem_acct_enable) { FREE(free_ptr); @@ -353,16 +332,18 @@ __gf_free(void *free_ptr) mem_acct->rec[header->type].num_allocs--; /* If all the instances are freed up then ensure typestr is set * to NULL */ - if (!mem_acct->rec[header->type].num_allocs) + if (!mem_acct->rec[header->type].num_allocs) { + last_ref = true; mem_acct->rec[header->type].typestr = NULL; + } #ifdef DEBUG list_del(&header->acct_list); #endif } UNLOCK(&mem_acct->rec[header->type].lock); - if (GF_ATOMIC_DEC(mem_acct->refcnt) == 0) { - FREE(mem_acct); + if (last_ref) { + xlator_mem_acct_unref(mem_acct); } free: diff --git a/libglusterfs/src/xlator.c b/libglusterfs/src/xlator.c index 6bba99a74ef..292416ae449 100644 --- a/libglusterfs/src/xlator.c +++ b/libglusterfs/src/xlator.c @@ -736,6 +736,19 @@ xlator_mem_acct_init(xlator_t *xl, int num_types) } void +xlator_mem_acct_unref(struct mem_acct *mem_acct) +{ + uint32_t i; + + if (GF_ATOMIC_DEC(mem_acct->refcnt) == 0) { + for (i = 0; i < mem_acct->num_types; i++) { + LOCK_DESTROY(&(mem_acct->rec[i].lock)); + } + FREE(mem_acct); + } +} + +void xlator_tree_fini(xlator_t *xl) { xlator_t *top = NULL; @@ -766,7 +779,6 @@ xlator_list_destroy(xlator_list_t *list) int xlator_memrec_free(xlator_t *xl) { - uint32_t i = 0; struct mem_acct *mem_acct = NULL; if (!xl) { @@ -775,13 +787,8 @@ xlator_memrec_free(xlator_t *xl) mem_acct = xl->mem_acct; if (mem_acct) { - for (i = 0; i < mem_acct->num_types; i++) { - LOCK_DESTROY(&(mem_acct->rec[i].lock)); - } - if (GF_ATOMIC_DEC(mem_acct->refcnt) == 0) { - FREE(mem_acct); - xl->mem_acct = NULL; - } + xlator_mem_acct_unref(mem_acct); + xl->mem_acct = NULL; } return 0; |