e3c68b
From bd553499909d2d57fd05696dc7604901cef3a36a Mon Sep 17 00:00:00 2001
e3c68b
From: Soumya Koduri <skoduri@redhat.com>
e3c68b
Date: Fri, 7 Jun 2019 17:20:15 +0530
e3c68b
Subject: [PATCH 200/221] gfapi: fix incorrect initialization of upcall syncop
e3c68b
 arguments
e3c68b
e3c68b
While sending upcall notifications via synctasks, the argument used to
e3c68b
carry relevant data for these tasks is not initialized properly. This patch
e3c68b
is to fix the same.
e3c68b
e3c68b
This is backport of below upstream fix -
e3c68b
mainline: https://review.gluster.org/22839
e3c68b
release-6: https://review.gluster.org/22871
e3c68b
e3c68b
Change-Id: I9fa8f841e71d3c37d3819fbd430382928c07176c
e3c68b
fixes: bz#1717784
e3c68b
Signed-off-by: Soumya Koduri <skoduri@redhat.com>
e3c68b
Reviewed-on: https://code.engineering.redhat.com/gerrit/173508
e3c68b
Tested-by: RHGS Build Bot <nigelb@redhat.com>
e3c68b
Reviewed-by: Kaleb Keithley <kkeithle@redhat.com>
e3c68b
---
e3c68b
 api/src/glfs-fops.c | 109 ++++++++++++++++++++++++++++++++++------------------
e3c68b
 1 file changed, 72 insertions(+), 37 deletions(-)
e3c68b
e3c68b
diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c
e3c68b
index 01ba60b..396f18c 100644
e3c68b
--- a/api/src/glfs-fops.c
e3c68b
+++ b/api/src/glfs-fops.c
e3c68b
@@ -34,7 +34,7 @@
e3c68b
 
e3c68b
 struct upcall_syncop_args {
e3c68b
     struct glfs *fs;
e3c68b
-    struct gf_upcall *upcall_data;
e3c68b
+    struct glfs_upcall *up_arg;
e3c68b
 };
e3c68b
 
e3c68b
 #define READDIRBUF_SIZE (sizeof(struct dirent) + GF_NAME_MAX + 1)
e3c68b
@@ -5714,12 +5714,28 @@ out:
e3c68b
 }
e3c68b
 
e3c68b
 static int
e3c68b
+upcall_syncop_args_free(struct upcall_syncop_args *args)
e3c68b
+{
e3c68b
+    if (args && args->up_arg)
e3c68b
+        GLFS_FREE(args->up_arg);
e3c68b
+    GF_FREE(args);
e3c68b
+    return 0;
e3c68b
+}
e3c68b
+
e3c68b
+static int
e3c68b
 glfs_upcall_syncop_cbk(int ret, call_frame_t *frame, void *opaque)
e3c68b
 {
e3c68b
     struct upcall_syncop_args *args = opaque;
e3c68b
 
e3c68b
-    GF_FREE(args->upcall_data);
e3c68b
-    GF_FREE(args);
e3c68b
+    /* Here we not using upcall_syncop_args_free as application
e3c68b
+     * will be cleaning up the args->up_arg using glfs_free
e3c68b
+     * post processing upcall.
e3c68b
+     */
e3c68b
+    if (ret) {
e3c68b
+        upcall_syncop_args_free(args);
e3c68b
+    } else
e3c68b
+        GF_FREE(args);
e3c68b
+
e3c68b
     return 0;
e3c68b
 }
e3c68b
 
e3c68b
@@ -5727,13 +5743,29 @@ static int
e3c68b
 glfs_cbk_upcall_syncop(void *opaque)
e3c68b
 {
e3c68b
     struct upcall_syncop_args *args = opaque;
e3c68b
-    int ret = -1;
e3c68b
     struct glfs_upcall *up_arg = NULL;
e3c68b
     struct glfs *fs;
e3c68b
-    struct gf_upcall *upcall_data;
e3c68b
 
e3c68b
     fs = args->fs;
e3c68b
-    upcall_data = args->upcall_data;
e3c68b
+    up_arg = args->up_arg;
e3c68b
+
e3c68b
+    if (fs->up_cbk && up_arg) {
e3c68b
+        (fs->up_cbk)(up_arg, fs->up_data);
e3c68b
+        return 0;
e3c68b
+    }
e3c68b
+
e3c68b
+    return -1;
e3c68b
+}
e3c68b
+
e3c68b
+static struct upcall_syncop_args *
e3c68b
+upcall_syncop_args_init(struct glfs *fs, struct gf_upcall *upcall_data)
e3c68b
+{
e3c68b
+    struct upcall_syncop_args *args = NULL;
e3c68b
+    int ret = -1;
e3c68b
+    struct glfs_upcall *up_arg = NULL;
e3c68b
+
e3c68b
+    if (!fs || !upcall_data)
e3c68b
+        goto out;
e3c68b
 
e3c68b
     up_arg = GLFS_CALLOC(1, sizeof(struct gf_upcall), glfs_release_upcall,
e3c68b
                          glfs_mt_upcall_entry_t);
e3c68b
@@ -5754,33 +5786,51 @@ glfs_cbk_upcall_syncop(void *opaque)
e3c68b
             errno = EINVAL;
e3c68b
     }
e3c68b
 
e3c68b
-    if (!ret && (up_arg->reason != GLFS_UPCALL_EVENT_NULL)) {
e3c68b
-        /* It could so happen that the file which got
e3c68b
-         * upcall notification may have got deleted by
e3c68b
-         * the same client. In such cases up_arg->reason
e3c68b
-         * is set to GLFS_UPCALL_EVENT_NULL. No need to
e3c68b
-         * send upcall then */
e3c68b
-        (fs->up_cbk)(up_arg, fs->up_data);
e3c68b
-    } else if (up_arg->reason == GLFS_UPCALL_EVENT_NULL) {
e3c68b
+    /* It could so happen that the file which got
e3c68b
+     * upcall notification may have got deleted by
e3c68b
+     * the same client. In such cases up_arg->reason
e3c68b
+     * is set to GLFS_UPCALL_EVENT_NULL. No need to
e3c68b
+     * send upcall then
e3c68b
+     */
e3c68b
+    if (up_arg->reason == GLFS_UPCALL_EVENT_NULL) {
e3c68b
         gf_msg(THIS->name, GF_LOG_DEBUG, errno, API_MSG_INVALID_ENTRY,
e3c68b
                "Upcall_EVENT_NULL received. Skipping it.");
e3c68b
         goto out;
e3c68b
-    } else {
e3c68b
+    } else if (ret) {
e3c68b
         gf_msg(THIS->name, GF_LOG_ERROR, errno, API_MSG_INVALID_ENTRY,
e3c68b
                "Upcall entry validation failed.");
e3c68b
         goto out;
e3c68b
     }
e3c68b
 
e3c68b
+    args = GF_CALLOC(1, sizeof(struct upcall_syncop_args),
e3c68b
+                     glfs_mt_upcall_entry_t);
e3c68b
+    if (!args) {
e3c68b
+        gf_msg(THIS->name, GF_LOG_ERROR, ENOMEM, API_MSG_ALLOC_FAILED,
e3c68b
+               "Upcall syncop args allocation failed.");
e3c68b
+        goto out;
e3c68b
+    }
e3c68b
+
e3c68b
+    /* Note: we are not taking any ref on fs here.
e3c68b
+     * Ideally applications have to unregister for upcall events
e3c68b
+     * or stop polling for upcall events before performing
e3c68b
+     * glfs_fini. And as for outstanding synctasks created, we wait
e3c68b
+     * for all syncenv threads to finish tasks before cleaning up the
e3c68b
+     * fs->ctx. Hence it seems safe to process these callback
e3c68b
+     * notification without taking any lock/ref.
e3c68b
+     */
e3c68b
+    args->fs = fs;
e3c68b
+    args->up_arg = up_arg;
e3c68b
+
e3c68b
     /* application takes care of calling glfs_free on up_arg post
e3c68b
      * their processing */
e3c68b
-    ret = 0;
e3c68b
 
e3c68b
+    return args;
e3c68b
 out:
e3c68b
-    if (ret && up_arg) {
e3c68b
+    if (up_arg) {
e3c68b
         GLFS_FREE(up_arg);
e3c68b
     }
e3c68b
 
e3c68b
-    return 0;
e3c68b
+    return NULL;
e3c68b
 }
e3c68b
 
e3c68b
 static void
e3c68b
@@ -5797,24 +5847,10 @@ glfs_cbk_upcall_data(struct glfs *fs, struct gf_upcall *upcall_data)
e3c68b
         goto out;
e3c68b
     }
e3c68b
 
e3c68b
-    args = GF_CALLOC(1, sizeof(struct upcall_syncop_args),
e3c68b
-                     glfs_mt_upcall_entry_t);
e3c68b
-    if (!args) {
e3c68b
-        gf_msg(THIS->name, GF_LOG_ERROR, ENOMEM, API_MSG_ALLOC_FAILED,
e3c68b
-               "Upcall syncop args allocation failed.");
e3c68b
-        goto out;
e3c68b
-    }
e3c68b
+    args = upcall_syncop_args_init(fs, upcall_data);
e3c68b
 
e3c68b
-    /* Note: we are not taking any ref on fs here.
e3c68b
-     * Ideally applications have to unregister for upcall events
e3c68b
-     * or stop polling for upcall events before performing
e3c68b
-     * glfs_fini. And as for outstanding synctasks created, we wait
e3c68b
-     * for all syncenv threads to finish tasks before cleaning up the
e3c68b
-     * fs->ctx. Hence it seems safe to process these callback
e3c68b
-     * notification without taking any lock/ref.
e3c68b
-     */
e3c68b
-    args->fs = fs;
e3c68b
-    args->upcall_data = gf_memdup(upcall_data, sizeof(*upcall_data));
e3c68b
+    if (!args)
e3c68b
+        goto out;
e3c68b
 
e3c68b
     ret = synctask_new(THIS->ctx->env, glfs_cbk_upcall_syncop,
e3c68b
                        glfs_upcall_syncop_cbk, NULL, args);
e3c68b
@@ -5823,8 +5859,7 @@ glfs_cbk_upcall_data(struct glfs *fs, struct gf_upcall *upcall_data)
e3c68b
         gf_msg(THIS->name, GF_LOG_ERROR, errno, API_MSG_UPCALL_SYNCOP_FAILED,
e3c68b
                "Synctak for Upcall event_type(%d) and gfid(%s) failed",
e3c68b
                upcall_data->event_type, (char *)(upcall_data->gfid));
e3c68b
-        GF_FREE(args->upcall_data);
e3c68b
-        GF_FREE(args);
e3c68b
+        upcall_syncop_args_free(args);
e3c68b
     }
e3c68b
 
e3c68b
 out:
e3c68b
-- 
e3c68b
1.8.3.1
e3c68b