e7a346
From 919597d141dd79b34a9c0ef9e52a63cc43320d6c Mon Sep 17 00:00:00 2001
e7a346
From: Mohit Agrawal <moagrawa@redhat.com>
e7a346
Date: Mon, 3 Dec 2018 17:05:19 +0530
e7a346
Subject: [PATCH 453/453] server: Resolve memory leak path in server_init
e7a346
e7a346
Problem: 1) server_init does not cleanup allocate resources
e7a346
            while it is failed before return error
e7a346
         2) dict leak at the time of graph destroying
e7a346
e7a346
Solution: 1) free resources in case of server_init is failed
e7a346
          2) Take dict_ref of graph xlator before destroying
e7a346
             the graph to avoid leak
e7a346
e7a346
> Change-Id: I9e31e156b9ed6bebe622745a8be0e470774e3d15
e7a346
> fixes: bz#1654917
e7a346
> Cherry pick from commit 46c15ea8fa98bb3d92580b192f03863c2e2a2d9c
e7a346
> Reviewed on upstream link https://review.gluster.org/#/c/glusterfs/+/21750/
e7a346
e7a346
Change-Id: I5ba1b37840bcaa4a7fa4c05822c84016a2d89ea2
e7a346
BUG: 1650138
e7a346
Signed-off-by: Mohit Agrawal <moagrawa@redhat.com>
e7a346
Reviewed-on: https://code.engineering.redhat.com/gerrit/157445
e7a346
Tested-by: RHGS Build Bot <nigelb@redhat.com>
e7a346
Reviewed-by: Pranith Kumar Karampuri <pkarampu@redhat.com>
e7a346
Reviewed-by: Raghavendra Gowdappa <rgowdapp@redhat.com>
e7a346
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
e7a346
---
e7a346
 glusterfsd/src/glusterfsd.c                |  4 +++
e7a346
 libglusterfs/src/xlator.c                  | 31 ++++++++++++++++++
e7a346
 libglusterfs/src/xlator.h                  |  3 ++
e7a346
 rpc/rpc-lib/src/rpc-transport.c            | 26 ++++++++++++----
e7a346
 rpc/rpc-lib/src/rpc-transport.h            |  3 ++
e7a346
 rpc/rpc-lib/src/rpcsvc.c                   | 40 ++++++++++++++++++++++++
e7a346
 rpc/rpc-lib/src/rpcsvc.h                   |  3 ++
e7a346
 xlators/mgmt/glusterd/src/glusterd-utils.c | 33 ++------------------
e7a346
 xlators/protocol/server/src/server.c       | 50 +++++++++++++++++++++++++++---
e7a346
 9 files changed, 151 insertions(+), 42 deletions(-)
e7a346
e7a346
diff --git a/glusterfsd/src/glusterfsd.c b/glusterfsd/src/glusterfsd.c
e7a346
index 2e43cdb..78f3719 100644
e7a346
--- a/glusterfsd/src/glusterfsd.c
e7a346
+++ b/glusterfsd/src/glusterfsd.c
e7a346
@@ -2411,6 +2411,10 @@ out:
e7a346
                         xl = graph->first;
e7a346
                         if ((ctx && (ctx->active != graph)) &&
e7a346
                             (xl && !strcmp(xl->type, "protocol/server"))) {
e7a346
+                                /* Take dict ref for every graph xlator to avoid dict leak
e7a346
+                                   at the time of graph destroying
e7a346
+                                */
e7a346
+                                gluster_graph_take_reference(graph->first);
e7a346
                                 glusterfs_graph_fini(graph);
e7a346
                                 glusterfs_graph_destroy(graph);
e7a346
                         }
e7a346
diff --git a/libglusterfs/src/xlator.c b/libglusterfs/src/xlator.c
e7a346
index 8aa8aa1..340d83d 100644
e7a346
--- a/libglusterfs/src/xlator.c
e7a346
+++ b/libglusterfs/src/xlator.c
e7a346
@@ -1225,3 +1225,34 @@ glusterfs_delete_volfile_checksum (glusterfs_ctx_t *ctx,
e7a346
 
e7a346
         return 0;
e7a346
 }
e7a346
+
e7a346
+/*
e7a346
+   The function is required to take dict ref for every xlator at graph.
e7a346
+   At the time of compare graph topology create a graph and populate
e7a346
+   key values in the dictionary, after finished graph comparison we do destroy
e7a346
+   the new graph.At the time of construct graph we don't take any reference
e7a346
+   so to avoid dict leak at the of destroying graph due to ref counter underflow
e7a346
+   we need to call dict_ref here.
e7a346
+
e7a346
+*/
e7a346
+
e7a346
+void
e7a346
+gluster_graph_take_reference(xlator_t *tree)
e7a346
+{
e7a346
+    xlator_t *trav = tree;
e7a346
+    xlator_t *prev = tree;
e7a346
+
e7a346
+    if (!tree) {
e7a346
+        gf_msg("parser", GF_LOG_ERROR, 0, LG_MSG_TREE_NOT_FOUND,
e7a346
+               "Translator tree not found");
e7a346
+        return;
e7a346
+    }
e7a346
+
e7a346
+    while (prev) {
e7a346
+        trav = prev->next;
e7a346
+        if (prev->options)
e7a346
+            dict_ref(prev->options);
e7a346
+        prev = trav;
e7a346
+    }
e7a346
+    return;
e7a346
+}
e7a346
diff --git a/libglusterfs/src/xlator.h b/libglusterfs/src/xlator.h
e7a346
index 1879641..f8f2630 100644
e7a346
--- a/libglusterfs/src/xlator.h
e7a346
+++ b/libglusterfs/src/xlator.h
e7a346
@@ -1087,4 +1087,7 @@ glusterfs_delete_volfile_checksum (glusterfs_ctx_t *ctx,
e7a346
                                    const char *volfile_id);
e7a346
 int
e7a346
 xlator_memrec_free (xlator_t *xl);
e7a346
+
e7a346
+void
e7a346
+gluster_graph_take_reference(xlator_t *tree);
e7a346
 #endif /* _XLATOR_H */
e7a346
diff --git a/rpc/rpc-lib/src/rpc-transport.c b/rpc/rpc-lib/src/rpc-transport.c
e7a346
index 94880f4..77abf96 100644
e7a346
--- a/rpc/rpc-lib/src/rpc-transport.c
e7a346
+++ b/rpc/rpc-lib/src/rpc-transport.c
e7a346
@@ -160,6 +160,25 @@ out:
e7a346
         return msg;
e7a346
 }
e7a346
 
e7a346
+void
e7a346
+rpc_transport_cleanup(rpc_transport_t *trans)
e7a346
+{
e7a346
+    if (!trans)
e7a346
+        return;
e7a346
+
e7a346
+    if (trans->fini)
e7a346
+        trans->fini(trans);
e7a346
+
e7a346
+    GF_FREE(trans->name);
e7a346
+
e7a346
+    if (trans->xl)
e7a346
+        pthread_mutex_destroy(&trans->lock);
e7a346
+
e7a346
+    if (trans->dl_handle)
e7a346
+        dlclose(trans->dl_handle);
e7a346
+
e7a346
+    GF_FREE(trans);
e7a346
+}
e7a346
 
e7a346
 
e7a346
 rpc_transport_t *
e7a346
@@ -361,12 +380,7 @@ rpc_transport_load (glusterfs_ctx_t *ctx, dict_t *options, char *trans_name)
e7a346
 
e7a346
 fail:
e7a346
         if (trans) {
e7a346
-                GF_FREE (trans->name);
e7a346
-
e7a346
-                if (trans->dl_handle)
e7a346
-                        dlclose (trans->dl_handle);
e7a346
-
e7a346
-                GF_FREE (trans);
e7a346
+               rpc_transport_cleanup(trans);
e7a346
         }
e7a346
 
e7a346
         GF_FREE (name);
e7a346
diff --git a/rpc/rpc-lib/src/rpc-transport.h b/rpc/rpc-lib/src/rpc-transport.h
e7a346
index 33f474e..23246c5 100644
e7a346
--- a/rpc/rpc-lib/src/rpc-transport.h
e7a346
+++ b/rpc/rpc-lib/src/rpc-transport.h
e7a346
@@ -316,4 +316,7 @@ rpc_transport_unix_options_build (dict_t **options, char *filepath,
e7a346
 
e7a346
 int
e7a346
 rpc_transport_inet_options_build (dict_t **options, const char *hostname, int port);
e7a346
+
e7a346
+void
e7a346
+rpc_transport_cleanup(rpc_transport_t *);
e7a346
 #endif /* __RPC_TRANSPORT_H__ */
e7a346
diff --git a/rpc/rpc-lib/src/rpcsvc.c b/rpc/rpc-lib/src/rpcsvc.c
e7a346
index 8d0c409..695e9fb 100644
e7a346
--- a/rpc/rpc-lib/src/rpcsvc.c
e7a346
+++ b/rpc/rpc-lib/src/rpcsvc.c
e7a346
@@ -36,6 +36,7 @@
e7a346
 #include <fnmatch.h>
e7a346
 #include <stdarg.h>
e7a346
 #include <stdio.h>
e7a346
+#include <dlfcn.h>
e7a346
 
e7a346
 #include "xdr-rpcclnt.h"
e7a346
 #include "glusterfs-acl.h"
e7a346
@@ -1677,6 +1678,7 @@ rpcsvc_create_listener (rpcsvc_t *svc, dict_t *options, char *name)
e7a346
 
e7a346
         listener = rpcsvc_listener_alloc (svc, trans);
e7a346
         if (listener == NULL) {
e7a346
+                ret = -1;
e7a346
                 goto out;
e7a346
         }
e7a346
 
e7a346
@@ -1684,6 +1686,7 @@ rpcsvc_create_listener (rpcsvc_t *svc, dict_t *options, char *name)
e7a346
 out:
e7a346
         if (!listener && trans) {
e7a346
                 rpc_transport_disconnect (trans, _gf_true);
e7a346
+                rpc_transport_cleanup(trans);
e7a346
         }
e7a346
 
e7a346
         return ret;
e7a346
@@ -2285,6 +2288,43 @@ rpcsvc_get_throttle (rpcsvc_t *svc)
e7a346
         return svc->throttle;
e7a346
 }
e7a346
 
e7a346
+/* Function call to cleanup resources for svc
e7a346
+ */
e7a346
+int
e7a346
+rpcsvc_destroy(rpcsvc_t *svc)
e7a346
+{
e7a346
+    struct rpcsvc_auth_list *auth = NULL;
e7a346
+    struct rpcsvc_auth_list *tmp = NULL;
e7a346
+    rpcsvc_listener_t *listener = NULL;
e7a346
+    rpcsvc_listener_t *next = NULL;
e7a346
+    int ret = 0;
e7a346
+
e7a346
+    if (!svc)
e7a346
+        return ret;
e7a346
+
e7a346
+    list_for_each_entry_safe(listener, next, &svc->listeners, list)
e7a346
+    {
e7a346
+        rpcsvc_listener_destroy(listener);
e7a346
+    }
e7a346
+
e7a346
+    list_for_each_entry_safe(auth, tmp, &svc->authschemes, authlist)
e7a346
+    {
e7a346
+        list_del_init(&auth->authlist);
e7a346
+        GF_FREE(auth);
e7a346
+    }
e7a346
+
e7a346
+    rpcsvc_program_unregister(svc, &gluster_dump_prog);
e7a346
+    if (svc->rxpool) {
e7a346
+        mem_pool_destroy(svc->rxpool);
e7a346
+        svc->rxpool = NULL;
e7a346
+    }
e7a346
+
e7a346
+    pthread_mutex_destroy(&svc->rpclock);
e7a346
+    GF_FREE(svc);
e7a346
+
e7a346
+    return ret;
e7a346
+}
e7a346
+
e7a346
 /* The global RPC service initializer.
e7a346
  */
e7a346
 rpcsvc_t *
e7a346
diff --git a/rpc/rpc-lib/src/rpcsvc.h b/rpc/rpc-lib/src/rpcsvc.h
e7a346
index 34429b4..d3aafac 100644
e7a346
--- a/rpc/rpc-lib/src/rpcsvc.h
e7a346
+++ b/rpc/rpc-lib/src/rpcsvc.h
e7a346
@@ -610,4 +610,7 @@ rpcsvc_auth_array (rpcsvc_t *svc, char *volname, int *autharr, int arrlen);
e7a346
 rpcsvc_vector_sizer
e7a346
 rpcsvc_get_program_vector_sizer (rpcsvc_t *svc, uint32_t prognum,
e7a346
                                  uint32_t progver, int procnum);
e7a346
+
e7a346
+extern int
e7a346
+rpcsvc_destroy(rpcsvc_t *svc);
e7a346
 #endif
e7a346
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c
e7a346
index ec7e27a..b63c95a 100644
e7a346
--- a/xlators/mgmt/glusterd/src/glusterd-utils.c
e7a346
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.c
e7a346
@@ -9384,35 +9384,6 @@ glusterd_defrag_volume_status_update (glusterd_volinfo_t *volinfo,
e7a346
 
e7a346
         return ret;
e7a346
 }
e7a346
-/*
e7a346
-   The function is required to take dict ref for every xlator at graph.
e7a346
-   At the time of compare graph topology create a graph and populate
e7a346
-   key values in the dictionary, after finished graph comparison we do destroy
e7a346
-   the new graph.At the time of construct graph we don't take any reference
e7a346
-   so to avoid leak due to ref counter underflow we need to call dict_ref here.
e7a346
-
e7a346
-*/
e7a346
-
e7a346
-void
e7a346
-glusterd_graph_take_reference (xlator_t *tree)
e7a346
-{        xlator_t *trav = tree;
e7a346
-         xlator_t *prev = tree;
e7a346
-
e7a346
-        if (!tree) {
e7a346
-                gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_TREE_NOT_FOUND,
e7a346
-                        "Translator tree not found");
e7a346
-                return;
e7a346
-        }
e7a346
-
e7a346
-        while (prev) {
e7a346
-                trav = prev->next;
e7a346
-                if (prev->options)
e7a346
-                        dict_ref (prev->options);
e7a346
-                prev = trav;
e7a346
-        }
e7a346
-        return;
e7a346
-}
e7a346
-
e7a346
 
e7a346
 
e7a346
 int
e7a346
@@ -9461,14 +9432,14 @@ glusterd_check_topology_identical (const char   *filename1,
e7a346
         if (grph1 == NULL)
e7a346
                 goto out;
e7a346
 
e7a346
-        glusterd_graph_take_reference (grph1->first);
e7a346
+        gluster_graph_take_reference (grph1->first);
e7a346
 
e7a346
         /* create the graph for filename2 */
e7a346
         grph2 = glusterfs_graph_construct(fp2);
e7a346
         if (grph2 == NULL)
e7a346
                 goto out;
e7a346
 
e7a346
-        glusterd_graph_take_reference (grph2->first);
e7a346
+        gluster_graph_take_reference (grph2->first);
e7a346
 
e7a346
         /* compare the graph topology */
e7a346
         *identical = is_graph_topology_equal(grph1, grph2);
e7a346
diff --git a/xlators/protocol/server/src/server.c b/xlators/protocol/server/src/server.c
e7a346
index 65d712f..6f510ea 100644
e7a346
--- a/xlators/protocol/server/src/server.c
e7a346
+++ b/xlators/protocol/server/src/server.c
e7a346
@@ -1144,12 +1144,54 @@ client_destroy_cbk (xlator_t *this, client_t *client)
e7a346
         return 0;
e7a346
 }
e7a346
 
e7a346
+void
e7a346
+server_cleanup(xlator_t *this, server_conf_t *conf)
e7a346
+{
e7a346
+    if (!this || !conf)
e7a346
+        return;
e7a346
+
e7a346
+    LOCK_DESTROY(&conf->itable_lock);
e7a346
+    pthread_mutex_destroy(&conf->mutex);
e7a346
+
e7a346
+    if (this->ctx->event_pool) {
e7a346
+        /* Free the event pool */
e7a346
+        (void)event_pool_destroy(this->ctx->event_pool);
e7a346
+    }
e7a346
+
e7a346
+    if (dict_get(this->options, "config-directory")) {
e7a346
+        GF_FREE(conf->conf_dir);
e7a346
+        conf->conf_dir = NULL;
e7a346
+    }
e7a346
+
e7a346
+    if (conf->child_status) {
e7a346
+        GF_FREE(conf->child_status);
e7a346
+        conf->child_status = NULL;
e7a346
+    }
e7a346
+
e7a346
+    if (this->ctx->statedump_path) {
e7a346
+        GF_FREE(this->ctx->statedump_path);
e7a346
+        this->ctx->statedump_path = NULL;
e7a346
+    }
e7a346
+
e7a346
+    if (conf->auth_modules) {
e7a346
+        gf_auth_fini(conf->auth_modules);
e7a346
+        dict_unref(conf->auth_modules);
e7a346
+    }
e7a346
+
e7a346
+    if (conf->rpc) {
e7a346
+        (void)rpcsvc_destroy(conf->rpc);
e7a346
+        conf->rpc = NULL;
e7a346
+    }
e7a346
+
e7a346
+    GF_FREE(conf);
e7a346
+    this->private = NULL;
e7a346
+}
e7a346
+
e7a346
 int
e7a346
 init (xlator_t *this)
e7a346
 {
e7a346
         int32_t            ret      = -1;
e7a346
         server_conf_t     *conf     = NULL;
e7a346
-        rpcsvc_listener_t *listener = NULL;
e7a346
         char              *transport_type = NULL;
e7a346
         char              *statedump_path = NULL;
e7a346
         int               total_transport = 0;
e7a346
@@ -1226,6 +1268,7 @@ init (xlator_t *this)
e7a346
         ret = gf_auth_init (this, conf->auth_modules);
e7a346
         if (ret) {
e7a346
                 dict_unref (conf->auth_modules);
e7a346
+                conf->auth_modules = NULL;
e7a346
                 goto out;
e7a346
         }
e7a346
 
e7a346
@@ -1378,10 +1421,7 @@ out:
e7a346
                 if (this != NULL) {
e7a346
                         this->fini (this);
e7a346
                 }
e7a346
-
e7a346
-                if (listener != NULL) {
e7a346
-                        rpcsvc_listener_destroy (listener);
e7a346
-                }
e7a346
+                server_cleanup(this, conf);
e7a346
         }
e7a346
 
e7a346
         return ret;
e7a346
-- 
e7a346
1.8.3.1
e7a346