Blob Blame History Raw
From 44ef95f37891c6023dd625b495849673fe8ccece Mon Sep 17 00:00:00 2001
From: Soumya Koduri <skoduri@redhat.com>
Date: Sat, 30 Apr 2016 22:01:47 +0530
Subject: [PATCH 127/139] gfapi/upcall: Ignore handle create failures

In "glfs_h_poll_cache_invalidation", we need to send upcall only if there
is a corresponding inode entry in the gfapi inode table for that handle.

That's because the application will have reference to the inode as long as
it operates on any handle. That means the only case in which we cannot find
inode is when the application has closed the handle (either as part of unlink
or for any other purpose). But since it will have no more references and will
not be interested in any upcall event for that handle, we can safely ignore such
cases.

Note: This will affect only that particular applicaiton process/local libgfapi
client.

This is backport of the below upstream fixes -
 http://review.gluster.org/14132 (upstream)
 http://review.gluster.org/#/c/14181/ (release-3.7)

Change-Id: I9499cd9c284350d4a271e58f2a0966db65a7a61c
BUG: 1323424
Signed-off-by: Soumya Koduri <skoduri@redhat.com>
Reviewed-on: http://review.gluster.org/14132
Reviewed-by: jiffin tony Thottan <jthottan@redhat.com>
Reviewed-by: Kaleb KEITHLEY <kkeithle@redhat.com>
Reviewed-on: https://code.engineering.redhat.com/gerrit/73590
Reviewed-by: Jiffin Thottan <jthottan@redhat.com>
Reviewed-by: Kaleb Keithley <kkeithle@redhat.com>
Tested-by: Kaleb Keithley <kkeithle@redhat.com>
---
 api/src/glfs-handleops.c |  142 ++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 118 insertions(+), 24 deletions(-)

diff --git a/api/src/glfs-handleops.c b/api/src/glfs-handleops.c
index a230578..72aa7de 100644
--- a/api/src/glfs-handleops.c
+++ b/api/src/glfs-handleops.c
@@ -1805,6 +1805,69 @@ invalid_fs:
 
 GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_h_rename, 3.4.2);
 
+/*
+ * Given a handle/gfid, find if the corresponding inode is present in
+ * the inode table. If yes create and return the corresponding glfs_object.
+ */
+struct glfs_object *
+glfs_h_find_handle (struct glfs *fs, unsigned char *handle, int len)
+{
+        int                 ret = -1;
+        inode_t            *newinode = NULL;
+        xlator_t           *subvol = NULL;
+        struct glfs_object *object = NULL;
+        uuid_t gfid;
+
+        /* validate in args */
+        if ((fs == NULL) || (handle == NULL) || (len != GFAPI_HANDLE_LENGTH)) {
+                errno = EINVAL;
+                return NULL;
+        }
+
+        DECLARE_OLD_THIS;
+        __GLFS_ENTRY_VALIDATE_FS (fs, invalid_fs);
+
+        /* get the active volume */
+        subvol = glfs_active_subvol (fs);
+        if (!subvol) {
+                errno = EIO;
+                goto out;
+        }
+
+        memcpy (gfid, handle, GFAPI_HANDLE_LENGTH);
+
+        /* make sure the gfid received is valid */
+        GF_VALIDATE_OR_GOTO ("glfs_h_find_handle",
+                             !(gf_uuid_is_null (gfid)), out);
+
+        newinode = inode_find (subvol->itable, gfid);
+        if (!newinode) {
+                goto out;
+        }
+
+        object = GF_CALLOC (1, sizeof(struct glfs_object),
+                            glfs_mt_glfs_object_t);
+        if (object == NULL) {
+                errno = ENOMEM;
+                ret = -1;
+                goto out;
+        }
+
+        /* populate the return object. The ref taken here
+         * is un'refed when the application does glfs_h_close() */
+        object->inode = inode_ref(newinode);
+        gf_uuid_copy (object->gfid, object->inode->gfid);
+
+out:
+        glfs_subvol_done (fs, subvol);
+
+        __GLFS_EXIT_FS;
+
+invalid_fs:
+        return object;
+
+}
+
 int
 glfs_h_poll_cache_invalidation (struct glfs *fs,
                                 struct callback_arg *up_arg,
@@ -1821,11 +1884,24 @@ glfs_h_poll_cache_invalidation (struct glfs *fs,
         GF_VALIDATE_OR_GOTO ("glfs_h_poll_cache_invalidation",
                              ca_data, out);
 
-        object = glfs_h_create_from_handle (fs, upcall_data->gfid,
-                                            GFAPI_HANDLE_LENGTH,
-                                            NULL);
-        GF_VALIDATE_OR_GOTO ("glfs_h_poll_cache_invalidation",
-                             object, out);
+        object = glfs_h_find_handle (fs, upcall_data->gfid,
+                                     GFAPI_HANDLE_LENGTH);
+        if (!object) {
+                /* The reason handle creation will fail is because we
+                 * couldn't find the inode in the gfapi inode table.
+                 *
+                 * But since application would have taken inode_ref, the
+                 * only case when this can happen is when it has closed
+                 * the handle and hence will no more be interested in
+                 * the upcall for this particular gfid.
+                 */
+                gf_msg (THIS->name, GF_LOG_DEBUG, errno,
+                        API_MSG_CREATE_HANDLE_FAILED,
+                        "handle creation of %s failed",
+                         uuid_utoa (upcall_data->gfid));
+                errno = ESTALE;
+                goto out;
+        }
 
         up_inode_arg = calloc (1, sizeof (struct callback_inode_arg));
         GF_VALIDATE_OR_GOTO ("glfs_h_poll_cache_invalidation",
@@ -1844,12 +1920,17 @@ glfs_h_poll_cache_invalidation (struct glfs *fs,
         }
 
         if (ca_data->flags & GFAPI_UP_PARENT_TIMES) {
-                p_object = glfs_h_create_from_handle (fs,
-                                                      ca_data->p_stat.ia_gfid,
-                                                      GFAPI_HANDLE_LENGTH,
-                                                      NULL);
-                GF_VALIDATE_OR_GOTO ("glfs_h_poll_cache_invalidation",
-                                       p_object, out);
+                p_object = glfs_h_find_handle (fs,
+                                               ca_data->p_stat.ia_gfid,
+                                               GFAPI_HANDLE_LENGTH);
+                if (!p_object) {
+                        gf_msg (THIS->name, GF_LOG_DEBUG, errno,
+                                API_MSG_CREATE_HANDLE_FAILED,
+                                "handle creation of %s failed",
+                                 uuid_utoa (ca_data->p_stat.ia_gfid));
+                        errno = ESTALE;
+                        goto out;
+                }
 
                 glfs_iatt_to_stat (fs, &ca_data->p_stat, &up_inode_arg->p_buf);
         }
@@ -1857,12 +1938,21 @@ glfs_h_poll_cache_invalidation (struct glfs *fs,
 
         /* In case of RENAME, update old parent as well */
         if (ca_data->flags & GFAPI_UP_RENAME) {
-                oldp_object = glfs_h_create_from_handle (fs,
-                                                     ca_data->oldp_stat.ia_gfid,
-                                                     GFAPI_HANDLE_LENGTH,
-                                                     NULL);
-                GF_VALIDATE_OR_GOTO ("glfs_h_poll_cache_invalidation",
-                                       oldp_object, out);
+                oldp_object = glfs_h_find_handle (fs,
+                                                  ca_data->oldp_stat.ia_gfid,
+                                                  GFAPI_HANDLE_LENGTH);
+                if (!oldp_object) {
+                        gf_msg (THIS->name, GF_LOG_DEBUG, errno,
+                                API_MSG_CREATE_HANDLE_FAILED,
+                                "handle creation of %s failed",
+                                 uuid_utoa (ca_data->oldp_stat.ia_gfid));
+                        errno = ESTALE;
+                        /* By the time we receive upcall old parent_dir may
+                         * have got removed. We still need to send upcall
+                         * for the file/dir and current parent handles. */
+                        up_inode_arg->oldp_object = NULL;
+                        ret = 0;
+                }
 
                 glfs_iatt_to_stat (fs, &ca_data->oldp_stat,
                                    &up_inode_arg->oldp_buf);
@@ -1872,6 +1962,15 @@ glfs_h_poll_cache_invalidation (struct glfs *fs,
         ret = 0;
 
 out:
+        if (ret) {
+                /* Close p_object and oldp_object as well if being referenced.*/
+                if (object)
+                        glfs_h_close (object);
+
+                /* Reset event_arg as well*/
+                up_arg->event_arg = NULL;
+                GF_FREE (up_inode_arg);
+        }
         return ret;
 }
 
@@ -1972,16 +2071,11 @@ pub_glfs_h_poll_upcall (struct glfs *fs, struct callback_arg *up_arg)
                         }
                         /* It could so happen that the file which got
                          * upcall notification may have got deleted
-                         * by other thread. Irrespective of the error,
-                         * log it and return with CBK_NULL reason.
+                         * by the same client. Irrespective of the error,
+                         * return with CBK_NULL reason.
                          *
                          * Applications will ignore this notification
                          * as up_arg->object will be NULL */
-                        gf_msg (subvol->name, GF_LOG_WARNING, errno,
-                                API_MSG_CREATE_HANDLE_FAILED,
-                                "handle creation of %s failed",
-                                uuid_utoa (upcall_data->gfid));
-
                         reason = GFAPI_CBK_EVENT_NULL;
                         break;
                 default:
-- 
1.7.1