50dc83
From 52dc121c412de9c1cc3058d782b949dc7b25dc3e Mon Sep 17 00:00:00 2001
50dc83
From: Soumya Koduri <skoduri@redhat.com>
50dc83
Date: Thu, 25 Jul 2019 12:56:12 +0530
50dc83
Subject: [PATCH 264/265] gfapi: Fix deadlock while processing upcall
50dc83
50dc83
As mentioned in bug1733166, there could be potential deadlock
50dc83
while processing upcalls depending on how each xlator choose
50dc83
to act on it. The right way of fixing such issues
50dc83
is to change rpc callback communication process.
50dc83
- https://github.com/gluster/glusterfs/issues/697
50dc83
50dc83
Till then, making changes in gfapi layer to avoid any I/O
50dc83
processing.
50dc83
50dc83
This is backport of below mainline patch
50dc83
> https://review.gluster.org/#/c/glusterfs/+/23108/
50dc83
> bz#1733166
50dc83
> https://review.gluster.org/#/c/glusterfs/+/23107/ (release-6)
50dc83
50dc83
Change-Id: I2079e95339e5d761d5060707f4555cfacab95c83
50dc83
fixes: bz#1733520
50dc83
Signed-off-by: Soumya Koduri <skoduri@redhat.com>
50dc83
Reviewed-on: https://code.engineering.redhat.com/gerrit/177675
50dc83
Tested-by: RHGS Build Bot <nigelb@redhat.com>
50dc83
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
50dc83
---
50dc83
 api/src/glfs-fops.c | 164 +++++++++++++++++++++++++++++++++++++++++-----------
50dc83
 1 file changed, 131 insertions(+), 33 deletions(-)
50dc83
50dc83
diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c
50dc83
index 396f18c..e6adea5 100644
50dc83
--- a/api/src/glfs-fops.c
50dc83
+++ b/api/src/glfs-fops.c
50dc83
@@ -34,7 +34,7 @@
50dc83
 
50dc83
 struct upcall_syncop_args {
50dc83
     struct glfs *fs;
50dc83
-    struct glfs_upcall *up_arg;
50dc83
+    struct gf_upcall upcall_data;
50dc83
 };
50dc83
 
50dc83
 #define READDIRBUF_SIZE (sizeof(struct dirent) + GF_NAME_MAX + 1)
50dc83
@@ -5716,8 +5716,28 @@ out:
50dc83
 static int
50dc83
 upcall_syncop_args_free(struct upcall_syncop_args *args)
50dc83
 {
50dc83
-    if (args && args->up_arg)
50dc83
-        GLFS_FREE(args->up_arg);
50dc83
+    dict_t *dict = NULL;
50dc83
+    struct gf_upcall *upcall_data = NULL;
50dc83
+
50dc83
+    if (args) {
50dc83
+        upcall_data = &args->upcall_data;
50dc83
+        switch (upcall_data->event_type) {
50dc83
+            case GF_UPCALL_CACHE_INVALIDATION:
50dc83
+                dict = ((struct gf_upcall_cache_invalidation *)(upcall_data
50dc83
+                                                                    ->data))
50dc83
+                           ->dict;
50dc83
+                break;
50dc83
+            case GF_UPCALL_RECALL_LEASE:
50dc83
+                dict = ((struct gf_upcall_recall_lease *)(upcall_data->data))
50dc83
+                           ->dict;
50dc83
+                break;
50dc83
+        }
50dc83
+        if (dict)
50dc83
+            dict_unref(dict);
50dc83
+
50dc83
+        GF_FREE(upcall_data->client_uid);
50dc83
+        GF_FREE(upcall_data->data);
50dc83
+    }
50dc83
     GF_FREE(args);
50dc83
     return 0;
50dc83
 }
50dc83
@@ -5727,14 +5747,7 @@ glfs_upcall_syncop_cbk(int ret, call_frame_t *frame, void *opaque)
50dc83
 {
50dc83
     struct upcall_syncop_args *args = opaque;
50dc83
 
50dc83
-    /* Here we not using upcall_syncop_args_free as application
50dc83
-     * will be cleaning up the args->up_arg using glfs_free
50dc83
-     * post processing upcall.
50dc83
-     */
50dc83
-    if (ret) {
50dc83
-        upcall_syncop_args_free(args);
50dc83
-    } else
50dc83
-        GF_FREE(args);
50dc83
+    (void)upcall_syncop_args_free(args);
50dc83
 
50dc83
     return 0;
50dc83
 }
50dc83
@@ -5743,29 +5756,17 @@ static int
50dc83
 glfs_cbk_upcall_syncop(void *opaque)
50dc83
 {
50dc83
     struct upcall_syncop_args *args = opaque;
50dc83
+    struct gf_upcall *upcall_data = NULL;
50dc83
     struct glfs_upcall *up_arg = NULL;
50dc83
     struct glfs *fs;
50dc83
+    int ret = -1;
50dc83
 
50dc83
     fs = args->fs;
50dc83
-    up_arg = args->up_arg;
50dc83
-
50dc83
-    if (fs->up_cbk && up_arg) {
50dc83
-        (fs->up_cbk)(up_arg, fs->up_data);
50dc83
-        return 0;
50dc83
-    }
50dc83
-
50dc83
-    return -1;
50dc83
-}
50dc83
+    upcall_data = &args->upcall_data;
50dc83
 
50dc83
-static struct upcall_syncop_args *
50dc83
-upcall_syncop_args_init(struct glfs *fs, struct gf_upcall *upcall_data)
50dc83
-{
50dc83
-    struct upcall_syncop_args *args = NULL;
50dc83
-    int ret = -1;
50dc83
-    struct glfs_upcall *up_arg = NULL;
50dc83
-
50dc83
-    if (!fs || !upcall_data)
50dc83
+    if (!upcall_data) {
50dc83
         goto out;
50dc83
+    }
50dc83
 
50dc83
     up_arg = GLFS_CALLOC(1, sizeof(struct gf_upcall), glfs_release_upcall,
50dc83
                          glfs_mt_upcall_entry_t);
50dc83
@@ -5795,6 +5796,8 @@ upcall_syncop_args_init(struct glfs *fs, struct gf_upcall *upcall_data)
50dc83
     if (up_arg->reason == GLFS_UPCALL_EVENT_NULL) {
50dc83
         gf_msg(THIS->name, GF_LOG_DEBUG, errno, API_MSG_INVALID_ENTRY,
50dc83
                "Upcall_EVENT_NULL received. Skipping it.");
50dc83
+        ret = 0;
50dc83
+        GLFS_FREE(up_arg);
50dc83
         goto out;
50dc83
     } else if (ret) {
50dc83
         gf_msg(THIS->name, GF_LOG_ERROR, errno, API_MSG_INVALID_ENTRY,
50dc83
@@ -5802,6 +5805,85 @@ upcall_syncop_args_init(struct glfs *fs, struct gf_upcall *upcall_data)
50dc83
         goto out;
50dc83
     }
50dc83
 
50dc83
+    if (fs->up_cbk && up_arg)
50dc83
+        (fs->up_cbk)(up_arg, fs->up_data);
50dc83
+
50dc83
+    /* application takes care of calling glfs_free on up_arg post
50dc83
+     * their processing */
50dc83
+
50dc83
+out:
50dc83
+    return ret;
50dc83
+}
50dc83
+
50dc83
+static struct gf_upcall_cache_invalidation *
50dc83
+gf_copy_cache_invalidation(struct gf_upcall_cache_invalidation *src)
50dc83
+{
50dc83
+    struct gf_upcall_cache_invalidation *dst = NULL;
50dc83
+
50dc83
+    if (!src)
50dc83
+        goto out;
50dc83
+
50dc83
+    dst = GF_CALLOC(1, sizeof(struct gf_upcall_cache_invalidation),
50dc83
+                    glfs_mt_upcall_entry_t);
50dc83
+
50dc83
+    if (!dst) {
50dc83
+        gf_msg(THIS->name, GF_LOG_ERROR, ENOMEM, API_MSG_ALLOC_FAILED,
50dc83
+               "Upcall entry allocation failed.");
50dc83
+        goto out;
50dc83
+    }
50dc83
+
50dc83
+    dst->flags = src->flags;
50dc83
+    dst->expire_time_attr = src->expire_time_attr;
50dc83
+    dst->stat = src->stat;
50dc83
+    dst->p_stat = src->p_stat;
50dc83
+    dst->oldp_stat = src->oldp_stat;
50dc83
+
50dc83
+    if (src->dict)
50dc83
+        dst->dict = dict_copy_with_ref(src->dict, NULL);
50dc83
+
50dc83
+    return dst;
50dc83
+out:
50dc83
+    return NULL;
50dc83
+}
50dc83
+
50dc83
+static struct gf_upcall_recall_lease *
50dc83
+gf_copy_recall_lease(struct gf_upcall_recall_lease *src)
50dc83
+{
50dc83
+    struct gf_upcall_recall_lease *dst = NULL;
50dc83
+
50dc83
+    if (!src)
50dc83
+        goto out;
50dc83
+
50dc83
+    dst = GF_CALLOC(1, sizeof(struct gf_upcall_recall_lease),
50dc83
+                    glfs_mt_upcall_entry_t);
50dc83
+
50dc83
+    if (!dst) {
50dc83
+        gf_msg(THIS->name, GF_LOG_ERROR, ENOMEM, API_MSG_ALLOC_FAILED,
50dc83
+               "Upcall entry allocation failed.");
50dc83
+        goto out;
50dc83
+    }
50dc83
+
50dc83
+    dst->lease_type = src->lease_type;
50dc83
+    memcpy(dst->tid, src->tid, 16);
50dc83
+
50dc83
+    if (src->dict)
50dc83
+        dst->dict = dict_copy_with_ref(src->dict, NULL);
50dc83
+
50dc83
+    return dst;
50dc83
+out:
50dc83
+    return NULL;
50dc83
+}
50dc83
+
50dc83
+static struct upcall_syncop_args *
50dc83
+upcall_syncop_args_init(struct glfs *fs, struct gf_upcall *upcall_data)
50dc83
+{
50dc83
+    struct upcall_syncop_args *args = NULL;
50dc83
+    int ret = -1;
50dc83
+    struct gf_upcall *t_data = NULL;
50dc83
+
50dc83
+    if (!fs || !upcall_data)
50dc83
+        goto out;
50dc83
+
50dc83
     args = GF_CALLOC(1, sizeof(struct upcall_syncop_args),
50dc83
                      glfs_mt_upcall_entry_t);
50dc83
     if (!args) {
50dc83
@@ -5819,15 +5901,31 @@ upcall_syncop_args_init(struct glfs *fs, struct gf_upcall *upcall_data)
50dc83
      * notification without taking any lock/ref.
50dc83
      */
50dc83
     args->fs = fs;
50dc83
-    args->up_arg = up_arg;
50dc83
+    t_data = &(args->upcall_data);
50dc83
+    t_data->client_uid = gf_strdup(upcall_data->client_uid);
50dc83
 
50dc83
-    /* application takes care of calling glfs_free on up_arg post
50dc83
-     * their processing */
50dc83
+    gf_uuid_copy(t_data->gfid, upcall_data->gfid);
50dc83
+    t_data->event_type = upcall_data->event_type;
50dc83
+
50dc83
+    switch (t_data->event_type) {
50dc83
+        case GF_UPCALL_CACHE_INVALIDATION:
50dc83
+            t_data->data = gf_copy_cache_invalidation(
50dc83
+                (struct gf_upcall_cache_invalidation *)upcall_data->data);
50dc83
+            break;
50dc83
+        case GF_UPCALL_RECALL_LEASE:
50dc83
+            t_data->data = gf_copy_recall_lease(
50dc83
+                (struct gf_upcall_recall_lease *)upcall_data->data);
50dc83
+            break;
50dc83
+    }
50dc83
+
50dc83
+    if (!t_data->data)
50dc83
+        goto out;
50dc83
 
50dc83
     return args;
50dc83
 out:
50dc83
-    if (up_arg) {
50dc83
-        GLFS_FREE(up_arg);
50dc83
+    if (ret) {
50dc83
+        GF_FREE(args->upcall_data.client_uid);
50dc83
+        GF_FREE(args);
50dc83
     }
50dc83
 
50dc83
     return NULL;
50dc83
-- 
50dc83
1.8.3.1
50dc83