summaryrefslogtreecommitdiff
path: root/0129-core-handle-memory-accounting-correctly.patch
diff options
context:
space:
mode:
Diffstat (limited to '0129-core-handle-memory-accounting-correctly.patch')
-rw-r--r--0129-core-handle-memory-accounting-correctly.patch401
1 files changed, 401 insertions, 0 deletions
diff --git a/0129-core-handle-memory-accounting-correctly.patch b/0129-core-handle-memory-accounting-correctly.patch
new file mode 100644
index 0000000..1281d04
--- /dev/null
+++ b/0129-core-handle-memory-accounting-correctly.patch
@@ -0,0 +1,401 @@
+From f305ee93ec9dbbd679e1eb58c7c0bf8d9b5659d5 Mon Sep 17 00:00:00 2001
+From: Xavi Hernandez <xhernandez@redhat.com>
+Date: Fri, 12 Apr 2019 13:40:59 +0200
+Subject: [PATCH 129/141] core: handle memory accounting correctly
+
+When a translator stops, memory accounting for that translator is not
+destroyed (because there could remain memory allocated that references
+it), but mutexes that coordinate updates of memory accounting were
+destroyed. This caused incorrect memory accounting and even crashes in
+debug mode.
+
+This patch also fixes some other things:
+
+* Reduce the number of atomic operations needed to manage memory
+ accounting.
+* Correctly account memory when realloc() is used.
+* Merge two critical sections into one.
+* Cleaned the code a bit.
+
+Upstream patch:
+> Change-Id: Id5eaee7338729b9bc52c931815ca3ff1e5a7dcc8
+> Upstream patch link : https://review.gluster.org/#/c/glusterfs/+/22554/
+> BUG: 1659334
+> Signed-off-by: Xavi Hernandez <xhernandez@redhat.com>
+
+Change-Id: Id5eaee7338729b9bc52c931815ca3ff1e5a7dcc8
+Fixes: bz#1702270
+Signed-off-by: Xavi Hernandez <xhernandez@redhat.com>
+Reviewed-on: https://code.engineering.redhat.com/gerrit/169325
+Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
+Tested-by: RHGS Build Bot <nigelb@redhat.com>
+---
+ libglusterfs/src/glusterfs/xlator.h | 2 +
+ libglusterfs/src/libglusterfs.sym | 1 +
+ libglusterfs/src/mem-pool.c | 193 ++++++++++++++++--------------------
+ 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 06152ec..8998976 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);
+ int
+diff --git a/libglusterfs/src/libglusterfs.sym b/libglusterfs/src/libglusterfs.sym
+index fa2025e..cf5757c 100644
+--- a/libglusterfs/src/libglusterfs.sym
++++ b/libglusterfs/src/libglusterfs.sym
+@@ -1093,6 +1093,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 34cb87a..3934a78 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);
+@@ -352,16 +331,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 5d6f8d2..022c3ed 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;
+--
+1.8.3.1
+