3604df
From 06c59167d972b7034f3ee3d93dc2629bf53043df Mon Sep 17 00:00:00 2001
3604df
From: Raghavendra Talur <rtalur@redhat.com>
3604df
Date: Wed, 2 Nov 2016 19:51:26 +0530
3604df
Subject: [PATCH 150/157] gfapi: async fops should unref in callbacks
3604df
3604df
    Backport of http://review.gluster.org/#/c/15768
3604df
3604df
If fd is unref'd at the end of async call then the unref in cbks would
3604df
lead to double unref and possible crash. Removing duplicate unrefs.
3604df
3604df
Added unref only in failure cases.
3604df
3604df
A simple test case has been added to test async write case. Need to
3604df
extend the same for other async APIs too.
3604df
3604df
Details:
3604df
All glfd based calls in libgfapi, except for glfs_open and glfs_close,
3604df
behave in the same way. At the start of the operation, they take a ref
3604df
on glfd and fd. At the end of the operation, they unref it. Async calls
3604df
are a little different as they unref in the cbk function. A successfull
3604df
open call does not unref either the glfd or fd, thereby functioning as a
3604df
reference for a OPEN file object. glfs_close makes a syncop_flush call
3604df
sandwiched between a fd ref and unref(this can be removed, more on this
3604df
below), followed by a call to glfs_mark_glfd_for_deletion which unrefs
3604df
glfd and also calls glfs_fd_destroy as a release function thereby doing
3604df
a unref on fd too.
3604df
3604df
Functionally, there is no problem with how everything works when as
3604df
described above. However, it is a little non-intuitive that we need to
3604df
perform a fd_unref as a consequence of a implicit fd_ref that happens
3604df
within glfs_resolve_fd. As we perform a GF_REF_GET(glfd) at the start of
3604df
every operation, it would be worthwhile to remove the fd_ref that
3604df
glfs_resovle_fd takes and do away with explicit fd_unref()s at the end
3604df
of every operation. This is the same reason why we don't need the fd_ref
3604df
in glfs_close. This is however not in the scope of this patch.
3604df
3604df
Change-Id: I86b1d3b2ad846b16ea527d541dc82b5e90b0ba85
3604df
BUG: 1391093
3604df
Reviewed-on: http://review.gluster.org/15768
3604df
Smoke: Gluster Build System <jenkins@build.gluster.org>
3604df
NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
3604df
Reviewed-by: Rajesh Joseph <rjoseph@redhat.com>
3604df
Reviewed-by: Xavier Hernandez <xhernandez@datalab.es>
3604df
Reviewed-by: soumya k <skoduri@redhat.com>
3604df
Reviewed-by: Prasanna Kumar Kalever <pkalever@redhat.com>
3604df
CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
3604df
Reviewed-by: Shyamsundar Ranganathan <srangana@redhat.com>
3604df
Signed-off-by: Raghavendra Talur <rtalur@redhat.com>
3604df
Reviewed-on: https://code.engineering.redhat.com/gerrit/89229
3604df
---
3604df
 api/src/glfs-fops.c                        |   30 ++---
3604df
 tests/basic/gfapi/gfapi-async-calls-test.c |  177 ++++++++++++++++++++++++++++
3604df
 tests/basic/gfapi/gfapi-async-calls-test.t |   26 ++++
3604df
 3 files changed, 215 insertions(+), 18 deletions(-)
3604df
 create mode 100644 tests/basic/gfapi/gfapi-async-calls-test.c
3604df
 create mode 100644 tests/basic/gfapi/gfapi-async-calls-test.t
3604df
3604df
diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c
3604df
index bbbf61d..41d4795 100644
3604df
--- a/api/src/glfs-fops.c
3604df
+++ b/api/src/glfs-fops.c
3604df
@@ -934,10 +934,9 @@ pub_glfs_preadv_async (struct glfs_fd *glfd, const struct iovec *iovec,
3604df
 			   offset, flags, NULL);
3604df
 
3604df
 out:
3604df
-        if (fd)
3604df
-                fd_unref (fd);
3604df
-
3604df
         if (ret) {
3604df
+                if (fd)
3604df
+                        fd_unref (fd);
3604df
                 if (glfd)
3604df
                         GF_REF_PUT (glfd);
3604df
                 if (gio) {
3604df
@@ -1252,10 +1251,9 @@ pub_glfs_pwritev_async (struct glfs_fd *glfd, const struct iovec *iovec,
3604df
 
3604df
         ret = 0;
3604df
 out:
3604df
-        if (fd)
3604df
-                fd_unref (fd);
3604df
-
3604df
         if (ret) {
3604df
+                if (fd)
3604df
+                        fd_unref (fd);
3604df
                 if (glfd)
3604df
                         GF_REF_PUT (glfd);
3604df
                 GF_FREE (gio);
3604df
@@ -1439,10 +1437,9 @@ glfs_fsync_async_common (struct glfs_fd *glfd, glfs_io_cbk fn, void *data,
3604df
                            subvol->fops->fsync, fd, dataonly, NULL);
3604df
 
3604df
 out:
3604df
-        if (fd)
3604df
-                fd_unref (fd);
3604df
-
3604df
         if (ret) {
3604df
+                if (fd)
3604df
+                        fd_unref (fd);
3604df
                 if (glfd)
3604df
                         GF_REF_PUT (glfd);
3604df
                 GF_FREE (gio);
3604df
@@ -1693,10 +1690,9 @@ pub_glfs_ftruncate_async (struct glfs_fd *glfd, off_t offset, glfs_io_cbk fn,
3604df
         ret = 0;
3604df
 
3604df
 out:
3604df
-        if (fd)
3604df
-                fd_unref (fd);
3604df
-
3604df
         if (ret) {
3604df
+                if (fd)
3604df
+                        fd_unref (fd);
3604df
                 if (glfd)
3604df
                         GF_REF_PUT (glfd);
3604df
                 GF_FREE (gio);
3604df
@@ -2552,10 +2548,9 @@ pub_glfs_discard_async (struct glfs_fd *glfd, off_t offset, size_t len,
3604df
 
3604df
         ret = 0;
3604df
 out:
3604df
-        if (fd)
3604df
-                fd_unref (fd);
3604df
-
3604df
         if (ret) {
3604df
+                if (fd)
3604df
+                        fd_unref (fd);
3604df
                 if (glfd)
3604df
                         GF_REF_PUT (glfd);
3604df
                 GF_FREE (gio);
3604df
@@ -2640,10 +2635,9 @@ pub_glfs_zerofill_async (struct glfs_fd *glfd, off_t offset, off_t len,
3604df
                            subvol->fops->zerofill, fd, offset, len, NULL);
3604df
         ret = 0;
3604df
 out:
3604df
-        if (fd)
3604df
-                fd_unref (fd);
3604df
-
3604df
         if (ret) {
3604df
+                if (fd)
3604df
+                        fd_unref (fd);
3604df
                 if (glfd)
3604df
                         GF_REF_PUT (glfd);
3604df
                 GF_FREE (gio);
3604df
diff --git a/tests/basic/gfapi/gfapi-async-calls-test.c b/tests/basic/gfapi/gfapi-async-calls-test.c
3604df
new file mode 100644
3604df
index 0000000..277067b
3604df
--- /dev/null
3604df
+++ b/tests/basic/gfapi/gfapi-async-calls-test.c
3604df
@@ -0,0 +1,177 @@
3604df
+#include <fcntl.h>
3604df
+#include <unistd.h>
3604df
+#include <time.h>
3604df
+#include <limits.h>
3604df
+#include <string.h>
3604df
+#include <stdio.h>
3604df
+#include <stdlib.h>
3604df
+#include <errno.h>
3604df
+#include <glusterfs/api/glfs.h>
3604df
+#include <glusterfs/api/glfs-handles.h>
3604df
+
3604df
+#define LOG_ERR(msg) do { \
3604df
+        fprintf (stderr, "%s : Error (%s)\n", msg, strerror (errno)); \
3604df
+        } while (0)
3604df
+
3604df
+int cbk_complete = 0;
3604df
+int cbk_ret_val = -1;
3604df
+
3604df
+int
3604df
+fill_iov (struct iovec *iov, char fillchar, int count)
3604df
+{
3604df
+        int ret = -1;
3604df
+
3604df
+        iov->iov_base = calloc (count + 1, sizeof(fillchar));
3604df
+        if (iov->iov_base == NULL) {
3604df
+                return ret;
3604df
+        } else {
3604df
+                iov->iov_len = count;
3604df
+                ret = 0;
3604df
+        }
3604df
+        memset (iov->iov_base, fillchar, count);
3604df
+        memset (iov->iov_base + count, '\0', 1);
3604df
+
3604df
+        return ret;
3604df
+}
3604df
+
3604df
+glfs_t *
3604df
+init_glfs (const char *hostname, const char *volname,
3604df
+           const char *logfile)
3604df
+{
3604df
+        int     ret     = -1;
3604df
+        glfs_t *fs      = NULL;
3604df
+
3604df
+        fs = glfs_new (volname);
3604df
+        if (!fs) {
3604df
+                LOG_ERR ("glfs_new failed");
3604df
+                return NULL;
3604df
+        }
3604df
+
3604df
+        ret = glfs_set_volfile_server (fs, "tcp", hostname, 24007);
3604df
+        if (ret < 0) {
3604df
+                LOG_ERR ("glfs_set_volfile_server failed");
3604df
+                goto out;
3604df
+        }
3604df
+
3604df
+        ret = glfs_set_logging (fs, logfile, 7);
3604df
+        if (ret < 0) {
3604df
+                LOG_ERR ("glfs_set_logging failed");
3604df
+                goto out;
3604df
+        }
3604df
+
3604df
+        ret = glfs_init (fs);
3604df
+        if (ret < 0) {
3604df
+                LOG_ERR ("glfs_init failed");
3604df
+                goto out;
3604df
+        }
3604df
+
3604df
+        ret = 0;
3604df
+out:
3604df
+        if (ret) {
3604df
+                glfs_fini (fs);
3604df
+                fs = NULL;
3604df
+        }
3604df
+
3604df
+        return fs;
3604df
+}
3604df
+
3604df
+void
3604df
+write_async_cbk (glfs_fd_t *fd, ssize_t ret, void *cookie)
3604df
+{
3604df
+
3604df
+        if (ret < 0) {
3604df
+                LOG_ERR ("glfs_write failed");
3604df
+        }
3604df
+        cbk_ret_val = ret;
3604df
+        cbk_complete = 1;
3604df
+}
3604df
+
3604df
+int
3604df
+write_async (glfs_t *fs, glfs_fd_t *glfd, int char_count)
3604df
+{
3604df
+        ssize_t         ret          = -1;
3604df
+        int             flags        = O_RDWR;
3604df
+        const char     *buff         = "This is from my prog\n";
3604df
+        struct iovec    iov          = {0};
3604df
+        void           *write_cookie = NULL;
3604df
+        void           *read_cookie  = NULL;
3604df
+
3604df
+
3604df
+
3604df
+        ret = fill_iov (&iov, 'a', char_count);
3604df
+        if (ret) {
3604df
+                LOG_ERR ("failed to create iov");
3604df
+                goto out;
3604df
+        }
3604df
+
3604df
+        write_cookie = strdup ("write_cookie");
3604df
+        ret = glfs_pwritev_async (glfd, &iov, 1, 0, flags, write_async_cbk,
3604df
+                                  &write_cookie);
3604df
+out:
3604df
+        if (ret < 0) {
3604df
+                LOG_ERR ("glfs_pwritev async failed");
3604df
+        }
3604df
+        return ret;
3604df
+
3604df
+}
3604df
+
3604df
+int
3604df
+main (int argc, char *argv[])
3604df
+{
3604df
+        int         ret      = 0;
3604df
+        char       *hostname = NULL;
3604df
+        char       *volname  = NULL;
3604df
+        char       *logfile  = NULL;
3604df
+        glfs_t     *fs       = NULL;
3604df
+        const char *filename = "glfs_test.txt";
3604df
+        int         flags    = (O_RDWR|O_CREAT);
3604df
+        glfs_fd_t  *glfd     = NULL;
3604df
+        int         count    = 200;
3604df
+
3604df
+        if (argc != 4) {
3604df
+                fprintf (stderr, "Invalid argument\n");
3604df
+                exit(1);
3604df
+        }
3604df
+
3604df
+        hostname = argv[1];
3604df
+        volname = argv[2];
3604df
+        logfile = argv[3];
3604df
+
3604df
+        fs = init_glfs (hostname, volname, logfile);
3604df
+        if (fs == NULL) {
3604df
+                LOG_ERR ("init_glfs failed");
3604df
+                return -1;
3604df
+        }
3604df
+
3604df
+        glfd = glfs_creat (fs, filename, flags, 0644);
3604df
+        if (glfd == NULL) {
3604df
+                LOG_ERR ("glfs_creat failed");
3604df
+                exit(1);
3604df
+        }
3604df
+
3604df
+        ret = write_async (fs, glfd, count);
3604df
+        if (ret) {
3604df
+                LOG_ERR ("glfs_test_function failed");
3604df
+                exit(1);
3604df
+        }
3604df
+
3604df
+        while (cbk_complete != 1) {
3604df
+                sleep(1);
3604df
+        }
3604df
+
3604df
+        ret = glfs_close (glfd);
3604df
+        if (ret < 0) {
3604df
+                LOG_ERR ("glfs close  failed");
3604df
+        }
3604df
+
3604df
+        /*
3604df
+         * skipping fini
3604df
+         */
3604df
+
3604df
+        if (cbk_ret_val == count)
3604df
+                return 0;
3604df
+        else
3604df
+                return -1;
3604df
+}
3604df
+
3604df
+
3604df
diff --git a/tests/basic/gfapi/gfapi-async-calls-test.t b/tests/basic/gfapi/gfapi-async-calls-test.t
3604df
new file mode 100644
3604df
index 0000000..9e5cd7c
3604df
--- /dev/null
3604df
+++ b/tests/basic/gfapi/gfapi-async-calls-test.t
3604df
@@ -0,0 +1,26 @@
3604df
+#!/bin/bash
3604df
+
3604df
+. $(dirname $0)/../../include.rc
3604df
+. $(dirname $0)/../../volume.rc
3604df
+
3604df
+cleanup;
3604df
+EXIT_EARLY=1;
3604df
+
3604df
+TEST glusterd
3604df
+
3604df
+TEST $CLI volume create $V0 ${H0}:$B0/brick1;
3604df
+EXPECT 'Created' volinfo_field $V0 'Status';
3604df
+
3604df
+TEST $CLI volume start $V0;
3604df
+EXPECT 'Started' volinfo_field $V0 'Status';
3604df
+
3604df
+logdir=`gluster --print-logdir`
3604df
+
3604df
+TEST build_tester $(dirname $0)/gfapi-async-calls-test.c -lgfapi
3604df
+
3604df
+
3604df
+TEST ./$(dirname $0)/gfapi-async-calls-test ${H0} $V0 $logdir/gfapi-async-calls-test.log
3604df
+
3604df
+cleanup_tester $(dirname $0)/gfapi-async-calls-test
3604df
+
3604df
+cleanup;
3604df
-- 
3604df
1.7.1
3604df