Blob Blame History Raw
From 032cbc5ebe94e7b9a6b79780431fa1ef56931656 Mon Sep 17 00:00:00 2001
From: Rajesh Joseph <rjoseph@redhat.com>
Date: Tue, 2 Feb 2016 04:22:04 +0530
Subject: [PATCH 09/26] libgfapi: glfd close is not correctly handled for async fop

There is chance that before the async fop is complete client can send
a close. libgfapi destroys glfd on close. Therefore it can lead to
crash or unexpected behaviour when the pening fop reaches libgfapi
layer. Currently we don't provide any api to cancel these outstanding
fops neither we check if the glfd is already closed or not.

Therefore as a fix provided refcount for glfd. Each fop (sync or async)
will take a ref and once the fop is complete it will unref the refcount.
We should not call the registered callback function if glfd is already
closed. To achieve this we maintain state of glfd so that we can safely
take a call if the fd is closed or not.

Change-Id: I1e01690ea72f34c12465eb084d7a1aa9de0d7b83
BUG: 1319646
Signed-off-by: Rajesh Joseph <rjoseph@redhat.com>
Reviewed-on: http://review.gluster.org/13340
Smoke: Gluster Build System <jenkins@build.gluster.com>
CentOS-regression: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Shyamsundar Ranganathan <srangana@redhat.com>
NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
Reviewed-on: https://code.engineering.redhat.com/gerrit/70350
Reviewed-by: Raghavendra Talur <rtalur@redhat.com>
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
Tested-by: Atin Mukherjee <amukherj@redhat.com>
---
 api/src/glfs-fops.c      |  181 +++++++++++++++++++++++++++++++++++++++++++---
 api/src/glfs-handleops.c |   15 +++--
 api/src/glfs-internal.h  |   18 ++++-
 api/src/glfs.c           |   50 +++++++------
 4 files changed, 224 insertions(+), 40 deletions(-)

diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c
index ce0cebc..fdffc7b 100644
--- a/api/src/glfs-fops.c
+++ b/api/src/glfs-fops.c
@@ -28,6 +28,35 @@
 #define READDIRBUF_SIZE (sizeof(struct dirent) + GF_NAME_MAX + 1)
 
 /*
+ * This function will mark glfd for deletion and decrement its refcount.
+ */
+int
+glfs_mark_glfd_for_deletion (struct glfs_fd *glfd)
+{
+        glfd->state = GLFD_CLOSE;
+
+        GF_REF_PUT (glfd);
+
+        return 0;
+}
+
+/* This function is usefull for all async fops. There is chance that glfd is
+ * closed before async fop is completed. When glfd is closed we change the
+ * state to GLFD_CLOSE.
+ *
+ * This function will return _gf_true if the glfd is still valid else return
+ * _gf_false.
+ */
+gf_boolean_t
+glfs_is_glfd_still_valid (struct glfs_fd *glfd)
+{
+        if (glfd->state != GLFD_CLOSE)
+                return _gf_true;
+
+        return _gf_false;
+}
+
+/*
  * This routine is called when an upcall event of type
  * 'GF_UPCALL_CACHE_INVALIDATION' is received.
  * It makes a copy of the contents of the upcall cache-invalidation
@@ -190,9 +219,10 @@ out:
 	loc_wipe (&loc);
 
 	if (ret && glfd) {
-		glfs_fd_destroy (glfd);
+                GF_REF_PUT (glfd);
 		glfd = NULL;
 	} else if (glfd) {
+                glfd->state = GLFD_OPEN;
 		fd_bind (glfd->fd);
 		glfs_fd_bind (glfd);
 	}
@@ -207,7 +237,6 @@ invalid_fs:
 
 GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_open, 3.4.0);
 
-
 int
 pub_glfs_close (struct glfs_fd *glfd)
 {
@@ -237,11 +266,11 @@ pub_glfs_close (struct glfs_fd *glfd)
         DECODE_SYNCOP_ERR (ret);
 out:
 	fs = glfd->fs;
-	glfs_fd_destroy (glfd);
 
-	if (fd)
-		fd_unref (fd);
+        if (fd)
+                fd_unref (fd);
 
+        glfs_mark_glfd_for_deletion (glfd);
 	glfs_subvol_done (fs, subvol);
 
         __GLFS_EXIT_FS;
@@ -342,6 +371,8 @@ pub_glfs_fstat (struct glfs_fd *glfd, struct stat *stat)
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
 	subvol = glfs_active_subvol (glfd->fs);
 	if (!subvol) {
 		ret = -1;
@@ -364,6 +395,8 @@ pub_glfs_fstat (struct glfs_fd *glfd, struct stat *stat)
 out:
 	if (fd)
 		fd_unref (fd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
 	glfs_subvol_done (glfd->fs, subvol);
 
@@ -502,9 +535,10 @@ out:
 		dict_unref (xattr_req);
 
 	if (ret && glfd) {
-		glfs_fd_destroy (glfd);
+                GF_REF_PUT (glfd);
 		glfd = NULL;
 	} else if (glfd) {
+                glfd->state = GLFD_OPEN;
 		fd_bind (glfd->fd);
 		glfs_fd_bind (glfd);
 	}
@@ -530,6 +564,8 @@ pub_glfs_lseek (struct glfs_fd *glfd, off_t offset, int whence)
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
 	switch (whence) {
 	case SEEK_SET:
 		glfd->offset = offset;
@@ -551,6 +587,9 @@ pub_glfs_lseek (struct glfs_fd *glfd, off_t offset, int whence)
                 errno = EINVAL;
 	}
 
+        if (glfd)
+                GF_REF_PUT (glfd);
+
         __GLFS_EXIT_FS;
 
         if (ret != -1)
@@ -580,6 +619,8 @@ pub_glfs_preadv (struct glfs_fd *glfd, const struct iovec *iovec, int iovcnt,
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
 	subvol = glfs_active_subvol (glfd->fs);
 	if (!subvol) {
 		ret = -1;
@@ -615,6 +656,8 @@ out:
 
 	if (fd)
 		fd_unref (fd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
 	glfs_subvol_done (glfd->fs, subvol);
 
@@ -693,7 +736,18 @@ glfs_io_async_cbk (int ret, call_frame_t *frame, void *data)
 {
 	struct glfs_io  *gio = data;
 
-	gio->fn (gio->glfd, ret, gio->data);
+        /* If the fd is already closed then
+         * no need to do the callback */
+        if (glfs_is_glfd_still_valid (gio->glfd)) {
+                gio->fn (gio->glfd, ret, gio->data);
+        }
+
+        /* Since the async operation is complete
+         * release the ref taken during the start
+         * of async operation
+         */
+        if (gio->glfd)
+                GF_REF_PUT (gio->glfd);
 
 	GF_FREE (gio->iov);
 	GF_FREE (gio);
@@ -769,6 +823,9 @@ glfs_preadv_async_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
 	glfd = gio->glfd;
 	fs = glfd->fs;
 
+        if (!glfs_is_glfd_still_valid (glfd))
+                goto err;
+
 	if (op_ret <= 0)
 		goto out;
 
@@ -779,6 +836,13 @@ out:
 	errno = op_errno;
 	gio->fn (gio->glfd, op_ret, gio->data);
 
+err:
+        /* Since the async operation is complete
+         * release the ref taken during the start
+         * of async operation
+         */
+        GF_REF_PUT (glfd);
+
 	GF_FREE (gio->iov);
 	GF_FREE (gio);
 	STACK_DESTROY (frame->root);
@@ -803,6 +867,8 @@ pub_glfs_preadv_async (struct glfs_fd *glfd, const struct iovec *iovec,
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
 	subvol = glfs_active_subvol (glfd->fs);
 	if (!subvol) {
 		ret = -1;
@@ -856,6 +922,8 @@ pub_glfs_preadv_async (struct glfs_fd *glfd, const struct iovec *iovec,
 
 out:
         if (ret) {
+                if (glfd)
+                        GF_REF_PUT (glfd);
                 if (gio) {
                         GF_FREE (gio->iov);
                         GF_FREE (gio);
@@ -945,6 +1013,8 @@ pub_glfs_pwritev (struct glfs_fd *glfd, const struct iovec *iovec, int iovcnt,
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
 	subvol = glfs_active_subvol (glfd->fs);
 	if (!subvol) {
 		ret = -1;
@@ -1005,6 +1075,8 @@ pub_glfs_pwritev (struct glfs_fd *glfd, const struct iovec *iovec, int iovcnt,
 out:
 	if (fd)
 		fd_unref (fd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
 	glfs_subvol_done (glfd->fs, subvol);
 
@@ -1100,11 +1172,17 @@ pub_glfs_pwritev_async (struct glfs_fd *glfd, const struct iovec *iovec,
 	gio->fn     = fn;
 	gio->data   = data;
 
+        /* Need to take explicit ref so that the fd
+         * is not destroyed before the fop is complete
+         */
+        GF_REF_GET (glfd);
+
 	ret = synctask_new (pub_glfs_from_glfd (glfd)->ctx->env,
 			    glfs_io_async_task, glfs_io_async_cbk,
 			    NULL, gio);
 
 	if (ret) {
+                GF_REF_PUT (glfd);
 		GF_FREE (gio->iov);
 		GF_FREE (gio);
 	}
@@ -1179,6 +1257,8 @@ pub_glfs_fsync (struct glfs_fd *glfd)
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
 	subvol = glfs_active_subvol (glfd->fs);
 	if (!subvol) {
 		ret = -1;
@@ -1198,6 +1278,8 @@ pub_glfs_fsync (struct glfs_fd *glfd)
 out:
 	if (fd)
 		fd_unref (fd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
 	glfs_subvol_done (glfd->fs, subvol);
 
@@ -1223,6 +1305,11 @@ glfs_fsync_async_common (struct glfs_fd *glfd, glfs_io_cbk fn, void *data,
 		return -1;
 	}
 
+        /* Need to take explicit ref so that the fd
+         * is not destroyed before the fop is complete
+         */
+        GF_REF_GET (glfd);
+
 	gio->op     = GF_FOP_FSYNC;
 	gio->glfd   = glfd;
 	gio->flags  = dataonly;
@@ -1234,6 +1321,7 @@ glfs_fsync_async_common (struct glfs_fd *glfd, glfs_io_cbk fn, void *data,
 			    NULL, gio);
 
 	if (ret) {
+                GF_REF_PUT (glfd);
 		GF_FREE (gio->iov);
 		GF_FREE (gio);
 	}
@@ -1272,6 +1360,8 @@ pub_glfs_fdatasync (struct glfs_fd *glfd)
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
 	subvol = glfs_active_subvol (glfd->fs);
 	if (!subvol) {
 		ret = -1;
@@ -1291,6 +1381,8 @@ pub_glfs_fdatasync (struct glfs_fd *glfd)
 out:
 	if (fd)
 		fd_unref (fd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
 	glfs_subvol_done (glfd->fs, subvol);
 
@@ -1332,6 +1424,8 @@ pub_glfs_ftruncate (struct glfs_fd *glfd, off_t offset)
         DECLARE_OLD_THIS;
         __GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
 	subvol = glfs_active_subvol (glfd->fs);
 	if (!subvol) {
 		ret = -1;
@@ -1351,6 +1445,8 @@ pub_glfs_ftruncate (struct glfs_fd *glfd, off_t offset)
 out:
 	if (fd)
 		fd_unref (fd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
 	glfs_subvol_done (glfd->fs, subvol);
 
@@ -1385,11 +1481,17 @@ pub_glfs_ftruncate_async (struct glfs_fd *glfd, off_t offset, glfs_io_cbk fn,
 	gio->fn     = fn;
 	gio->data   = data;
 
+        /* Need to take explicit ref so that the fd
+         * is not destroyed before the fop is complete
+         */
+        GF_REF_GET (glfd);
+
 	ret = synctask_new (pub_glfs_from_glfd (glfd)->ctx->env,
 			    glfs_io_async_task, glfs_io_async_cbk,
 			    NULL, gio);
 
 	if (ret) {
+                GF_REF_PUT (glfd);
 		GF_FREE (gio->iov);
 		GF_FREE (gio);
 	}
@@ -2095,9 +2197,10 @@ out:
 	loc_wipe (&loc);
 
 	if (ret && glfd) {
-		glfs_fd_destroy (glfd);
+		GF_REF_PUT (glfd);
 		glfd = NULL;
 	} else if (glfd) {
+                glfd->state = GLFD_OPEN;
 		fd_bind (glfd->fd);
 		glfs_fd_bind (glfd);
 	}
@@ -2123,7 +2226,7 @@ pub_glfs_closedir (struct glfs_fd *glfd)
 
 	gf_dirent_free (list_entry (&glfd->entries, gf_dirent_t, list));
 
-	glfs_fd_destroy (glfd);
+        glfs_mark_glfd_for_deletion (glfd);
 
         __GLFS_EXIT_FS;
 
@@ -2185,6 +2288,11 @@ pub_glfs_discard_async (struct glfs_fd *glfd, off_t offset, size_t len,
         DECLARE_OLD_THIS;
         __GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        /* Need to take explicit ref so that the fd
+         * is not destroyed before the fop is complete
+         */
+        GF_REF_GET (glfd);
+
 	gio = GF_CALLOC (1, sizeof (*gio), glfs_mt_glfs_io_t);
 	if (!gio) {
 		errno = ENOMEM;
@@ -2203,6 +2311,7 @@ pub_glfs_discard_async (struct glfs_fd *glfd, off_t offset, size_t len,
 			    NULL, gio);
 
 	if (ret) {
+                GF_REF_PUT (glfd);
 		GF_FREE (gio->iov);
 		GF_FREE (gio);
 	}
@@ -2227,6 +2336,11 @@ pub_glfs_zerofill_async (struct glfs_fd *glfd, off_t offset, off_t len,
         DECLARE_OLD_THIS;
         __GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        /* Need to take explicit ref so that the fd
+         * is not destroyed before the fop is complete
+         */
+        GF_REF_GET (glfd);
+
         gio = GF_CALLOC (1, sizeof (*gio), glfs_mt_glfs_io_t);
         if (!gio) {
                 errno = ENOMEM;
@@ -2245,6 +2359,7 @@ pub_glfs_zerofill_async (struct glfs_fd *glfd, off_t offset, off_t len,
                             NULL, gio);
 
         if (ret) {
+                GF_REF_PUT (glfd);
                 GF_FREE (gio->iov);
                 GF_FREE (gio);
         }
@@ -2424,6 +2539,8 @@ pub_glfs_readdirplus_r (struct glfs_fd *glfd, struct stat *stat,
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
 	errno = 0;
 
 	if (ext)
@@ -2455,6 +2572,9 @@ pub_glfs_readdirplus_r (struct glfs_fd *glfd, struct stat *stat,
 	}
 
 out:
+        if (glfd)
+                GF_REF_PUT (glfd);
+
         __GLFS_EXIT_FS;
 
 	return ret;
@@ -2601,6 +2721,8 @@ glfs_fsetattr (struct glfs_fd *glfd, struct iatt *iatt, int valid)
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
 	subvol = glfs_active_subvol (glfd->fs);
 	if (!subvol) {
 		ret = -1;
@@ -2620,6 +2742,8 @@ glfs_fsetattr (struct glfs_fd *glfd, struct iatt *iatt, int valid)
 out:
 	if (fd)
 		fd_unref (fd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
 	glfs_subvol_done (glfd->fs, subvol);
 
@@ -2939,6 +3063,8 @@ pub_glfs_fgetxattr (struct glfs_fd *glfd, const char *name, void *value,
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
         if (!name || *name == '\0') {
                 ret = -1;
                 errno = EINVAL;
@@ -2974,6 +3100,8 @@ pub_glfs_fgetxattr (struct glfs_fd *glfd, const char *name, void *value,
 out:
 	if (fd)
 		fd_unref (fd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
 	glfs_subvol_done (glfd->fs, subvol);
 
@@ -3096,6 +3224,8 @@ pub_glfs_flistxattr (struct glfs_fd *glfd, void *value, size_t size)
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
 	subvol = glfs_active_subvol (glfd->fs);
 	if (!subvol) {
 		ret = -1;
@@ -3119,6 +3249,8 @@ pub_glfs_flistxattr (struct glfs_fd *glfd, void *value, size_t size)
 out:
 	if (fd)
 		fd_unref (fd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
 	glfs_subvol_done (glfd->fs, subvol);
 
@@ -3232,6 +3364,8 @@ pub_glfs_fsetxattr (struct glfs_fd *glfd, const char *name, const void *value,
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
         if (!name || *name == '\0') {
                 ret = -1;
                 errno = EINVAL;
@@ -3273,6 +3407,8 @@ out:
 
 	if (fd)
 		fd_unref (fd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
 	glfs_subvol_done (glfd->fs, subvol);
 
@@ -3360,6 +3496,8 @@ pub_glfs_fremovexattr (struct glfs_fd *glfd, const char *name)
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
 	subvol = glfs_active_subvol (glfd->fs);
 	if (!subvol) {
 		ret = -1;
@@ -3379,6 +3517,8 @@ pub_glfs_fremovexattr (struct glfs_fd *glfd, const char *name)
 out:
 	if (fd)
 		fd_unref (fd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
 	glfs_subvol_done (glfd->fs, subvol);
 
@@ -3401,6 +3541,8 @@ pub_glfs_fallocate (struct glfs_fd *glfd, int keep_size, off_t offset, size_t le
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
 	subvol = glfs_active_subvol (glfd->fs);
 	if (!subvol) {
 		ret = -1;
@@ -3420,6 +3562,8 @@ pub_glfs_fallocate (struct glfs_fd *glfd, int keep_size, off_t offset, size_t le
 out:
 	if (fd)
 		fd_unref(fd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
 	glfs_subvol_done (glfd->fs, subvol);
 
@@ -3442,6 +3586,8 @@ pub_glfs_discard (struct glfs_fd *glfd, off_t offset, size_t len)
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
 	subvol = glfs_active_subvol (glfd->fs);
 	if (!subvol) {
 		ret = -1;
@@ -3461,6 +3607,8 @@ pub_glfs_discard (struct glfs_fd *glfd, off_t offset, size_t len)
 out:
 	if (fd)
 		fd_unref(fd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
 	glfs_subvol_done (glfd->fs, subvol);
 
@@ -3483,6 +3631,8 @@ pub_glfs_zerofill (struct glfs_fd *glfd, off_t offset, off_t len)
         DECLARE_OLD_THIS;
         __GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
         subvol = glfs_active_subvol (glfd->fs);
         if (!subvol) {
                 errno = EIO;
@@ -3500,6 +3650,8 @@ pub_glfs_zerofill (struct glfs_fd *glfd, off_t offset, off_t len)
 out:
         if (fd)
                 fd_unref(fd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
         glfs_subvol_done (glfd->fs, subvol);
 
@@ -3571,6 +3723,8 @@ pub_glfs_fchdir (struct glfs_fd *glfd)
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
 	subvol = glfs_active_subvol (glfd->fs);
 	if (!subvol) {
 		ret = -1;
@@ -3598,6 +3752,8 @@ pub_glfs_fchdir (struct glfs_fd *glfd)
 out:
 	if (fd)
 		fd_unref (fd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
 	glfs_subvol_done (glfd->fs, subvol);
 
@@ -3759,6 +3915,7 @@ pub_glfs_posix_lock (struct glfs_fd *glfd, int cmd, struct flock *flock)
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
 	subvol = glfs_active_subvol (glfd->fs);
 	if (!subvol) {
 		ret = -1;
@@ -3784,6 +3941,8 @@ pub_glfs_posix_lock (struct glfs_fd *glfd, int cmd, struct flock *flock)
 out:
 	if (fd)
 		fd_unref (fd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
 	glfs_subvol_done (glfd->fs, subvol);
 
@@ -3807,6 +3966,8 @@ pub_glfs_dup (struct glfs_fd *glfd)
         DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
 
+        GF_REF_GET (glfd);
+
 	fs = glfd->fs;
 	subvol = glfs_active_subvol (fs);
 	if (!subvol) {
@@ -3832,6 +3993,8 @@ out:
 		fd_unref (fd);
 	if (dupfd)
 		glfs_fd_bind (dupfd);
+        if (glfd)
+                GF_REF_PUT (glfd);
 
 	glfs_subvol_done (fs, subvol);
 
diff --git a/api/src/glfs-handleops.c b/api/src/glfs-handleops.c
index cd0f6b3..a230578 100644
--- a/api/src/glfs-handleops.c
+++ b/api/src/glfs-handleops.c
@@ -686,8 +686,10 @@ out:
                 inode_unref (inode);
 
         if (ret && glfd) {
-                glfs_fd_destroy (glfd);
+                GF_REF_PUT (glfd);
                 glfd = NULL;
+        } else if (glfd) {
+                glfd->state = GLFD_OPEN;
         }
 
         glfs_subvol_done (fs, subvol);
@@ -808,9 +810,11 @@ out:
         if (xattr_req)
                 dict_unref (xattr_req);
 
-        if (glfd) {
-                glfs_fd_destroy (glfd);
+        if (ret && glfd) {
+                GF_REF_PUT (glfd);
                 glfd = NULL;
+        } else if (glfd) {
+                glfd->state = GLFD_OPEN;
         }
 
         glfs_subvol_done (fs, subvol);
@@ -1151,9 +1155,10 @@ out:
                 inode_unref (inode);
 
         if (ret && glfd) {
-                glfs_fd_destroy (glfd);
+                GF_REF_PUT (glfd);
                 glfd = NULL;
-        } else {
+        } else if (glfd) {
+                glfd->state = GLFD_OPEN;
                 fd_bind (glfd->fd);
                 glfs_fd_bind (glfd);
         }
diff --git a/api/src/glfs-internal.h b/api/src/glfs-internal.h
index dbf1791..e1b8c8a 100644
--- a/api/src/glfs-internal.h
+++ b/api/src/glfs-internal.h
@@ -16,6 +16,7 @@
 #include "glusterfs.h"
 #include "upcall-utils.h"
 #include "glfs-handles.h"
+#include "refcount.h"
 
 #define GLFS_SYMLINK_MAX_FOLLOW 2048
 
@@ -208,9 +209,20 @@ struct glfs {
         uint32_t            pthread_flags; /* GLFS_INIT_* # defines set this flag */
 };
 
+/* This enum is used to maintain the state of glfd. In case of async fops
+ * fd might be closed before the actual fop is complete. Therefore we need
+ * to track whether the fd is closed or not, instead actually closing it.*/
+enum glfs_fd_state {
+        GLFD_INIT,
+        GLFD_OPEN,
+        GLFD_CLOSE
+};
+
 struct glfs_fd {
 	struct list_head   openfds;
+        GF_REF_DECL;
 	struct glfs       *fs;
+        enum glfs_fd_state state;
 	off_t              offset;
 	fd_t              *fd; /* Currently guared by @fs->mutex. TODO: per-glfd lock */
 	struct list_head   entries;
@@ -269,7 +281,8 @@ do {                                                                \
 
 #define __GLFS_ENTRY_VALIDATE_FD(glfd, label)                       \
 do {                                                                \
-        if (!glfd || !glfd->fd || !glfd->fd->inode) {               \
+        if (!glfd || !glfd->fd || !glfd->fd->inode ||               \
+             glfd->state != GLFD_OPEN) {                           \
                 errno = EBADF;                                      \
                 goto label;                                         \
         }                                                           \
@@ -308,9 +321,6 @@ glfs_unlock (struct glfs *fs)
 	pthread_mutex_unlock (&fs->mutex);
 }
 
-
-void glfs_fd_destroy (struct glfs_fd *glfd);
-
 struct glfs_fd *glfs_fd_new (struct glfs *fs);
 void glfs_fd_bind (struct glfs_fd *glfd);
 
diff --git a/api/src/glfs.c b/api/src/glfs.c
index b3a3f97..8e2d2c3 100644
--- a/api/src/glfs.c
+++ b/api/src/glfs.c
@@ -516,6 +516,32 @@ pub_glfs_from_glfd (struct glfs_fd *glfd)
 
 GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_from_glfd, 3.4.0);
 
+void
+glfs_fd_destroy (void *data)
+{
+        struct glfs_fd  *glfd = NULL;
+
+        if (!data)
+                return;
+
+        glfd = (struct glfs_fd *)data;
+
+        glfs_lock (glfd->fs);
+        {
+                list_del_init (&glfd->openfds);
+        }
+        glfs_unlock (glfd->fs);
+
+        if (glfd->fd) {
+                fd_unref (glfd->fd);
+                glfd->fd = NULL;
+        }
+
+        GF_FREE (glfd->readdirbuf);
+
+        GF_FREE (glfd);
+}
+
 
 struct glfs_fd *
 glfs_fd_new (struct glfs *fs)
@@ -530,6 +556,8 @@ glfs_fd_new (struct glfs *fs)
 
 	INIT_LIST_HEAD (&glfd->openfds);
 
+        GF_REF_INIT (glfd, glfs_fd_destroy);
+
 	return glfd;
 }
 
@@ -548,28 +576,6 @@ glfs_fd_bind (struct glfs_fd *glfd)
 	glfs_unlock (fs);
 }
 
-void
-glfs_fd_destroy (struct glfs_fd *glfd)
-{
-	if (!glfd)
-		return;
-
-	glfs_lock (glfd->fs);
-	{
-		list_del_init (&glfd->openfds);
-	}
-	glfs_unlock (glfd->fs);
-
-        if (glfd->fd) {
-                fd_unref (glfd->fd);
-                glfd->fd = NULL;
-        }
-
-	GF_FREE (glfd->readdirbuf);
-
-	GF_FREE (glfd);
-}
-
 
 static void *
 glfs_poller (void *data)
-- 
1.7.1