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