cb8e9e
From bc759c626e16af3be07f82bb8203a3c455973757 Mon Sep 17 00:00:00 2001
cb8e9e
From: vmallika <vmallika@redhat.com>
cb8e9e
Date: Mon, 24 Aug 2015 08:07:14 +0530
cb8e9e
Subject: [PATCH 310/320] cli: on error invoke cli_cmd_broadcast_response function in separate thread
cb8e9e
cb8e9e
This is a backport of http://review.gluster.org/#/c/11990/
cb8e9e
cb8e9e
There is a problem in current CLI framework
cb8e9e
CLI holds the lock when processing command.
cb8e9e
When processing quota list command, below sequence of steps executed in the
cb8e9e
same thread and causing deadlock
cb8e9e
cb8e9e
1) CLI holds the lock
cb8e9e
2) Send rpc_clnt_submit request to quotad for quota usage
cb8e9e
3) If quotad is down, rpc_clnt_submit invokes cbk function with error
cb8e9e
4) cbk function cli_quotad_getlimit_cbk tries to hold lock to broadcast
cb8e9e
   the results and hangs, because same thread has already holding the lock
cb8e9e
cb8e9e
This patch fixes the problem by creating seperate thread for
cb8e9e
broadcasting the result
cb8e9e
cb8e9e
> Change-Id: I53be006eadf6aaf348083d9168535530d70a8ab3
cb8e9e
> BUG: 1242819
cb8e9e
> Signed-off-by: vmallika <vmallika@redhat.com>
cb8e9e
cb8e9e
Change-Id: Id010b95be689a947dd7ef75500d6c00d0f78cd3c
cb8e9e
BUG: 1242803
cb8e9e
Signed-off-by: vmallika <vmallika@redhat.com>
cb8e9e
Reviewed-on: https://code.engineering.redhat.com/gerrit/56573
cb8e9e
Reviewed-by: Krishnan Parthasarathi <kparthas@redhat.com>
cb8e9e
Tested-by: Krishnan Parthasarathi <kparthas@redhat.com>
cb8e9e
---
cb8e9e
 cli/src/cli-cmd-volume.c |   12 ------
cb8e9e
 cli/src/cli-rpc-ops.c    |   94 ++++++++++++++++++++++++++++++++++++++++++---
cb8e9e
 cli/src/cli.c            |    1 +
cb8e9e
 cli/src/cli.h            |    1 +
cb8e9e
 4 files changed, 89 insertions(+), 19 deletions(-)
cb8e9e
cb8e9e
diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c
cb8e9e
index 6dd3058..ca18108 100644
cb8e9e
--- a/cli/src/cli-cmd-volume.c
cb8e9e
+++ b/cli/src/cli-cmd-volume.c
cb8e9e
@@ -1381,18 +1381,6 @@ cli_cmd_quota_handle_list_all (const char **words, dict_t *options)
cb8e9e
         CLI_LOCAL_INIT (local, words, frame, xdata);
cb8e9e
         proc = &cli_quotad_clnt.proctable[GF_AGGREGATOR_GETLIMIT];
cb8e9e
 
cb8e9e
-        if (!(global_state->mode & GLUSTER_MODE_XML)) {
cb8e9e
-                print_quota_list_header (type);
cb8e9e
-        } else {
cb8e9e
-                ret = cli_xml_output_vol_quota_limit_list_begin
cb8e9e
-                        (local, 0, 0, NULL);
cb8e9e
-                if (ret) {
cb8e9e
-                        gf_log ("cli", GF_LOG_ERROR, "Error in printing "
cb8e9e
-                                "xml output");
cb8e9e
-                        goto out;
cb8e9e
-                }
cb8e9e
-        }
cb8e9e
-
cb8e9e
         gfid_str = GF_CALLOC (1, gf_common_mt_char, 64);
cb8e9e
         if (!gfid_str) {
cb8e9e
                 ret = -1;
cb8e9e
diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c
cb8e9e
index dfc5c6b..fd76df7 100644
cb8e9e
--- a/cli/src/cli-rpc-ops.c
cb8e9e
+++ b/cli/src/cli-rpc-ops.c
cb8e9e
@@ -3232,7 +3232,8 @@ out:
cb8e9e
 }
cb8e9e
 
cb8e9e
 int
cb8e9e
-print_quota_list_from_quotad (call_frame_t *frame, dict_t *rsp_dict)
cb8e9e
+print_quota_list_from_quotad (call_frame_t *frame, dict_t *rsp_dict,
cb8e9e
+                              int32_t list_count)
cb8e9e
 {
cb8e9e
         char             *path          = NULL;
cb8e9e
         char             *default_sl    = NULL;
cb8e9e
@@ -3244,11 +3245,11 @@ print_quota_list_from_quotad (call_frame_t *frame, dict_t *rsp_dict)
cb8e9e
         quota_limits_t  *size_limits    = NULL;
cb8e9e
         int32_t          type           = 0;
cb8e9e
 
cb8e9e
+        GF_ASSERT (frame);
cb8e9e
+
cb8e9e
         local = frame->local;
cb8e9e
         gd_rsp_dict = local->dict;
cb8e9e
 
cb8e9e
-        GF_ASSERT (frame);
cb8e9e
-
cb8e9e
         ret = dict_get_int32 (rsp_dict, "type", &type);
cb8e9e
         if (ret) {
cb8e9e
                 gf_log ("cli", GF_LOG_ERROR, "Failed to get type");
cb8e9e
@@ -3306,12 +3307,37 @@ print_quota_list_from_quotad (call_frame_t *frame, dict_t *rsp_dict)
cb8e9e
                 goto out;
cb8e9e
         }
cb8e9e
 
cb8e9e
+        if (list_count == 0) {
cb8e9e
+                if (!(global_state->mode & GLUSTER_MODE_XML)) {
cb8e9e
+                        print_quota_list_header (type);
cb8e9e
+                } else {
cb8e9e
+                        ret = cli_xml_output_vol_quota_limit_list_begin
cb8e9e
+                                (local, 0, 0, NULL);
cb8e9e
+                        if (ret) {
cb8e9e
+                                gf_log ("cli", GF_LOG_ERROR, "Error in "
cb8e9e
+                                        "printing xml output");
cb8e9e
+                                goto out;
cb8e9e
+                        }
cb8e9e
+                }
cb8e9e
+        }
cb8e9e
+
cb8e9e
         ret = print_quota_list_output (local, path, default_sl, &limits,
cb8e9e
                                        &used_space, type);
cb8e9e
 out:
cb8e9e
         return ret;
cb8e9e
 }
cb8e9e
 
cb8e9e
+void*
cb8e9e
+cli_cmd_broadcast_response_detached (void *opaque)
cb8e9e
+{
cb8e9e
+        int32_t ret = 0;
cb8e9e
+
cb8e9e
+        ret = (intptr_t) opaque;
cb8e9e
+        cli_cmd_broadcast_response (ret);
cb8e9e
+
cb8e9e
+        return NULL;
cb8e9e
+}
cb8e9e
+
cb8e9e
 int
cb8e9e
 cli_quotad_getlimit_cbk (struct rpc_req *req, struct iovec *iov,
cb8e9e
                           int count, void *myframe)
cb8e9e
@@ -3321,12 +3347,41 @@ cli_quotad_getlimit_cbk (struct rpc_req *req, struct iovec *iov,
cb8e9e
         int                ret         = -1;
cb8e9e
         dict_t            *dict        = NULL;
cb8e9e
         call_frame_t      *frame       = NULL;
cb8e9e
+        cli_local_t       *local       = NULL;
cb8e9e
+        dict_t            *gd_rsp_dict = NULL;
cb8e9e
+        int32_t            list_count  = 0;
cb8e9e
+        pthread_t          th_id       = {0, };
cb8e9e
 
cb8e9e
-        if (-1 == req->rpc_status) {
cb8e9e
+        frame = myframe;
cb8e9e
+        GF_ASSERT (frame);
cb8e9e
+
cb8e9e
+        local = frame->local;
cb8e9e
+        gd_rsp_dict = local->dict;
cb8e9e
+
cb8e9e
+        LOCK (&local->lock);
cb8e9e
+        {
cb8e9e
+                ret = dict_get_int32 (gd_rsp_dict, "quota-list-count",
cb8e9e
+                                      &list_count);
cb8e9e
+                if (ret)
cb8e9e
+                        list_count = 0;
cb8e9e
+                ret = dict_set_int32 (gd_rsp_dict, "quota-list-count",
cb8e9e
+                                      list_count + 1);
cb8e9e
+        }
cb8e9e
+        UNLOCK (&local->lock);
cb8e9e
+
cb8e9e
+        if (ret) {
cb8e9e
+                gf_log ("cli", GF_LOG_ERROR, "Failed to set "
cb8e9e
+                        "quota-list-count in dict");
cb8e9e
                 goto out;
cb8e9e
         }
cb8e9e
 
cb8e9e
-        frame = myframe;
cb8e9e
+        if (-1 == req->rpc_status) {
cb8e9e
+                if (list_count == 0)
cb8e9e
+                        cli_err ("Connection failed. Please check if quota "
cb8e9e
+                                 "daemon is operational.");
cb8e9e
+                ret = -1;
cb8e9e
+                goto out;
cb8e9e
+        }
cb8e9e
 
cb8e9e
         ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp);
cb8e9e
         if (ret < 0) {
cb8e9e
@@ -3357,11 +3412,36 @@ cli_quotad_getlimit_cbk (struct rpc_req *req, struct iovec *iov,
cb8e9e
                                 "unserialize req-buffer to dictionary");
cb8e9e
                         goto out;
cb8e9e
                 }
cb8e9e
-                print_quota_list_from_quotad (frame, dict);
cb8e9e
+                print_quota_list_from_quotad (frame, dict, list_count);
cb8e9e
         }
cb8e9e
 
cb8e9e
 out:
cb8e9e
-        cli_cmd_broadcast_response (ret);
cb8e9e
+        /* Bad Fix: CLI holds the lock to process a command.
cb8e9e
+         * When processing quota list command, below sequence of steps executed
cb8e9e
+         * in the same thread and causing deadlock
cb8e9e
+         *
cb8e9e
+         * 1) CLI holds the lock
cb8e9e
+         * 2) Send rpc_clnt_submit request to quotad for quota usage
cb8e9e
+         * 3) If quotad is down, rpc_clnt_submit invokes cbk function with error
cb8e9e
+         * 4) cbk function cli_quotad_getlimit_cbk invokes
cb8e9e
+         *    cli_cmd_broadcast_response which tries to hold lock to broadcast
cb8e9e
+         *    the results and hangs, because same thread has already holding
cb8e9e
+         *    the lock
cb8e9e
+         *
cb8e9e
+         * Broadcasting response in a seperate thread which is not a
cb8e9e
+         * good fix. This needs to be re-visted with better solution
cb8e9e
+         */
cb8e9e
+        if (ret == -1) {
cb8e9e
+                ret = pthread_create (&th_id, NULL,
cb8e9e
+                                cli_cmd_broadcast_response_detached,
cb8e9e
+                                (void *)-1);
cb8e9e
+                if (ret)
cb8e9e
+                        gf_log ("cli", GF_LOG_ERROR, "pthread_create failed: "
cb8e9e
+                                "%s", strerror (errno));
cb8e9e
+        } else {
cb8e9e
+                cli_cmd_broadcast_response (ret);
cb8e9e
+        }
cb8e9e
+
cb8e9e
         if (dict)
cb8e9e
                 dict_unref (dict);
cb8e9e
 
cb8e9e
diff --git a/cli/src/cli.c b/cli/src/cli.c
cb8e9e
index 851178b..fa5b682 100644
cb8e9e
--- a/cli/src/cli.c
cb8e9e
+++ b/cli/src/cli.c
cb8e9e
@@ -653,6 +653,7 @@ cli_local_get ()
cb8e9e
         cli_local_t     *local = NULL;
cb8e9e
 
cb8e9e
         local = GF_CALLOC (1, sizeof (*local), cli_mt_cli_local_t);
cb8e9e
+        LOCK_INIT (&local->lock);
cb8e9e
 
cb8e9e
         return local;
cb8e9e
 }
cb8e9e
diff --git a/cli/src/cli.h b/cli/src/cli.h
cb8e9e
index 6c0fbce..d831af0 100644
cb8e9e
--- a/cli/src/cli.h
cb8e9e
+++ b/cli/src/cli.h
cb8e9e
@@ -151,6 +151,7 @@ struct cli_local {
cb8e9e
         xmlDocPtr               doc;
cb8e9e
         int                     vol_count;
cb8e9e
 #endif
cb8e9e
+        gf_lock_t               lock;
cb8e9e
 };
cb8e9e
 
cb8e9e
 struct cli_volume_status {
cb8e9e
-- 
cb8e9e
1.7.1
cb8e9e