14f8ab
From 2f07d12f902e371d8cb8c76007d558e3a727b56a Mon Sep 17 00:00:00 2001
14f8ab
From: Kotresh HR <khiremat@redhat.com>
14f8ab
Date: Tue, 9 Apr 2019 18:23:05 +0530
14f8ab
Subject: [PATCH 122/124] posix/ctime: Fix stat(time attributes) inconsistency
14f8ab
 during readdirp
14f8ab
14f8ab
Problem:
14f8ab
   Creation of tar file on gluster volume throws warning
14f8ab
'file changed as we read it'
14f8ab
14f8ab
Cause:
14f8ab
   During readdirp, for few of the files whose inode is not
14f8ab
present, time attributes were served from backend. This caused
14f8ab
the ctime of few files to be different between before readdir
14f8ab
and after readdir by tar.
14f8ab
14f8ab
Solution:
14f8ab
  If ctime feature is enabled and inode is not present, don't
14f8ab
serve the time attributes from backend file, serve it from xattr.
14f8ab
14f8ab
Backport of:
14f8ab
 > Patch: https://review.gluster.org/22540
14f8ab
 > fixes: bz#1698078
14f8ab
 > Change-Id: I427ef865f97399475faf5aa6ca495f7e317603ae
14f8ab
 > Signed-off-by: Kotresh HR <khiremat@redhat.com>
14f8ab
14f8ab
BUG: 1699709
14f8ab
Change-Id: I427ef865f97399475faf5aa6ca495f7e317603ae
14f8ab
Signed-off-by: Kotresh HR <khiremat@redhat.com>
14f8ab
Reviewed-on: https://code.engineering.redhat.com/gerrit/168687
14f8ab
Tested-by: RHGS Build Bot <nigelb@redhat.com>
14f8ab
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
14f8ab
---
14f8ab
 tests/basic/ctime/ctime-readdir.c          | 29 +++++++++++++++++
14f8ab
 tests/basic/ctime/ctime-readdir.t          | 50 ++++++++++++++++++++++++++++++
14f8ab
 xlators/storage/posix/src/posix-helpers.c  | 29 +++++++++++------
14f8ab
 xlators/storage/posix/src/posix-metadata.c | 41 ++++++++++++++----------
14f8ab
 4 files changed, 123 insertions(+), 26 deletions(-)
14f8ab
 create mode 100644 tests/basic/ctime/ctime-readdir.c
14f8ab
 create mode 100644 tests/basic/ctime/ctime-readdir.t
14f8ab
14f8ab
diff --git a/tests/basic/ctime/ctime-readdir.c b/tests/basic/ctime/ctime-readdir.c
14f8ab
new file mode 100644
14f8ab
index 0000000..8760db2
14f8ab
--- /dev/null
14f8ab
+++ b/tests/basic/ctime/ctime-readdir.c
14f8ab
@@ -0,0 +1,29 @@
14f8ab
+#include <stdio.h>
14f8ab
+#include <dirent.h>
14f8ab
+#include <string.h>
14f8ab
+#include <assert.h>
14f8ab
+
14f8ab
+int
14f8ab
+main(int argc, char **argv)
14f8ab
+{
14f8ab
+    DIR *dir = NULL;
14f8ab
+    struct dirent *entry = NULL;
14f8ab
+    int ret = 0;
14f8ab
+    char *path = NULL;
14f8ab
+
14f8ab
+    assert(argc == 2);
14f8ab
+    path = argv[1];
14f8ab
+
14f8ab
+    dir = opendir(path);
14f8ab
+    if (!dir) {
14f8ab
+        printf("opendir(%s) failed.\n", path);
14f8ab
+        return -1;
14f8ab
+    }
14f8ab
+
14f8ab
+    while ((entry = readdir(dir)) != NULL) {
14f8ab
+    }
14f8ab
+    if (dir)
14f8ab
+        closedir(dir);
14f8ab
+
14f8ab
+    return ret;
14f8ab
+}
14f8ab
diff --git a/tests/basic/ctime/ctime-readdir.t b/tests/basic/ctime/ctime-readdir.t
14f8ab
new file mode 100644
14f8ab
index 0000000..4564fc1
14f8ab
--- /dev/null
14f8ab
+++ b/tests/basic/ctime/ctime-readdir.t
14f8ab
@@ -0,0 +1,50 @@
14f8ab
+#!/bin/bash
14f8ab
+
14f8ab
+. $(dirname $0)/../../include.rc
14f8ab
+. $(dirname $0)/../../volume.rc
14f8ab
+
14f8ab
+cleanup;
14f8ab
+
14f8ab
+TEST glusterd
14f8ab
+
14f8ab
+TEST $CLI volume create $V0 replica 3 ${H0}:$B0/brick{1,2,3};
14f8ab
+TEST $CLI volume set $V0 performance.stat-prefetch on
14f8ab
+TEST $CLI volume set $V0 performance.readdir-ahead off
14f8ab
+TEST $CLI volume start $V0;
14f8ab
+
14f8ab
+TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0;
14f8ab
+
14f8ab
+TEST mkdir $M0/dir0
14f8ab
+TEST "echo hello_world > $M0/dir0/FILE"
14f8ab
+
14f8ab
+ctime1=$(stat -c %Z $M0/dir0/FILE)
14f8ab
+echo "Mount change time: $ctime1"
14f8ab
+
14f8ab
+sleep 2
14f8ab
+
14f8ab
+#Write to back end directly to modify ctime of backend file
14f8ab
+TEST "echo write_from_backend >> $B0/brick1/dir0/FILE"
14f8ab
+TEST "echo write_from_backend >> $B0/brick2/dir0/FILE"
14f8ab
+TEST "echo write_from_backend >> $B0/brick3/dir0/FILE"
14f8ab
+echo "Backend change time"
14f8ab
+echo "brick1: $(stat -c %Z $B0/brick1/dir0/FILE)"
14f8ab
+echo "brick2: $(stat -c %Z $B0/brick2/dir0/FILE)"
14f8ab
+echo "brick3: $(stat -c %Z $B0/brick3/dir0/FILE)"
14f8ab
+
14f8ab
+#Stop and start to hit the case of no inode for readdir
14f8ab
+TEST umount $M0
14f8ab
+TEST $CLI volume stop $V0
14f8ab
+TEST $CLI volume start $V0
14f8ab
+TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0;
14f8ab
+
14f8ab
+TEST build_tester $(dirname $0)/ctime-readdir.c
14f8ab
+
14f8ab
+#Do readdir
14f8ab
+TEST ./$(dirname $0)/ctime-readdir $M0/dir0
14f8ab
+
14f8ab
+EXPECT "$ctime1" stat -c %Z $M0/dir0/FILE
14f8ab
+echo "Mount change time after readdir $(stat -c %Z $M0/dir0/FILE)"
14f8ab
+
14f8ab
+cleanup_tester $(dirname $0)/ctime-readdir
14f8ab
+
14f8ab
+cleanup;
14f8ab
diff --git a/xlators/storage/posix/src/posix-helpers.c b/xlators/storage/posix/src/posix-helpers.c
14f8ab
index 193afc5..37e33a9 100644
14f8ab
--- a/xlators/storage/posix/src/posix-helpers.c
14f8ab
+++ b/xlators/storage/posix/src/posix-helpers.c
14f8ab
@@ -832,17 +832,26 @@ posix_pstat(xlator_t *this, inode_t *inode, uuid_t gfid, const char *path,
14f8ab
 
14f8ab
     iatt_from_stat(&stbuf, &lstatbuf);
14f8ab
 
14f8ab
-    if (inode && priv->ctime) {
14f8ab
-        if (!inode_locked) {
14f8ab
-            ret = posix_get_mdata_xattr(this, path, -1, inode, &stbuf);
14f8ab
+    if (priv->ctime) {
14f8ab
+        if (inode) {
14f8ab
+            if (!inode_locked) {
14f8ab
+                ret = posix_get_mdata_xattr(this, path, -1, inode, &stbuf);
14f8ab
+            } else {
14f8ab
+                ret = __posix_get_mdata_xattr(this, path, -1, inode, &stbuf);
14f8ab
+            }
14f8ab
+            if (ret) {
14f8ab
+                gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_GETMDATA_FAILED,
14f8ab
+                       "posix get mdata failed on gfid: %s",
14f8ab
+                       uuid_utoa(inode->gfid));
14f8ab
+                goto out;
14f8ab
+            }
14f8ab
         } else {
14f8ab
-            ret = __posix_get_mdata_xattr(this, path, -1, inode, &stbuf);
14f8ab
-        }
14f8ab
-        if (ret) {
14f8ab
-            gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_GETMDATA_FAILED,
14f8ab
-                   "posix get mdata failed on gfid: %s",
14f8ab
-                   uuid_utoa(inode->gfid));
14f8ab
-            goto out;
14f8ab
+            ret = __posix_get_mdata_xattr(this, path, -1, NULL, &stbuf);
14f8ab
+            if (ret) {
14f8ab
+                gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_GETMDATA_FAILED,
14f8ab
+                       "posix get mdata failed on path: %s", path);
14f8ab
+                goto out;
14f8ab
+            }
14f8ab
         }
14f8ab
     }
14f8ab
 
14f8ab
diff --git a/xlators/storage/posix/src/posix-metadata.c b/xlators/storage/posix/src/posix-metadata.c
14f8ab
index 0ea9099..7ff5225 100644
14f8ab
--- a/xlators/storage/posix/src/posix-metadata.c
14f8ab
+++ b/xlators/storage/posix/src/posix-metadata.c
14f8ab
@@ -79,6 +79,7 @@ posix_fetch_mdata_xattr(xlator_t *this, const char *real_path_arg, int _fd,
14f8ab
         fd_based_fop = _gf_true;
14f8ab
     }
14f8ab
     if (!(fd_based_fop || real_path_arg)) {
14f8ab
+        GF_VALIDATE_OR_GOTO(this->name, inode, out);
14f8ab
         MAKE_HANDLE_PATH(real_path, this, inode->gfid, NULL);
14f8ab
         if (!real_path) {
14f8ab
             uuid_utoa_r(inode->gfid, gfid_str);
14f8ab
@@ -114,14 +115,14 @@ posix_fetch_mdata_xattr(xlator_t *this, const char *real_path_arg, int _fd,
14f8ab
                          key,
14f8ab
                          real_path ? real_path
14f8ab
                                    : (real_path_arg ? real_path_arg : "null"),
14f8ab
-                         uuid_utoa(inode->gfid));
14f8ab
+                         inode ? uuid_utoa(inode->gfid) : "null");
14f8ab
         } else {
14f8ab
             gf_msg(this->name, GF_LOG_DEBUG, *op_errno, P_MSG_XATTR_FAILED,
14f8ab
                    "getxattr failed"
14f8ab
                    " on %s gfid: %s key: %s ",
14f8ab
                    real_path ? real_path
14f8ab
                              : (real_path_arg ? real_path_arg : "null"),
14f8ab
-                   uuid_utoa(inode->gfid), key);
14f8ab
+                   inode ? uuid_utoa(inode->gfid) : "null", key);
14f8ab
         }
14f8ab
         op_ret = -1;
14f8ab
         goto out;
14f8ab
@@ -148,7 +149,7 @@ posix_fetch_mdata_xattr(xlator_t *this, const char *real_path_arg, int _fd,
14f8ab
                "getxattr failed on "
14f8ab
                " on %s gfid: %s key: %s ",
14f8ab
                real_path ? real_path : (real_path_arg ? real_path_arg : "null"),
14f8ab
-               uuid_utoa(inode->gfid), key);
14f8ab
+               inode ? uuid_utoa(inode->gfid) : "null", key);
14f8ab
         goto out;
14f8ab
     }
14f8ab
 
14f8ab
@@ -233,9 +234,14 @@ __posix_get_mdata_xattr(xlator_t *this, const char *real_path, int _fd,
14f8ab
     int ret = -1;
14f8ab
     int op_errno = 0;
14f8ab
 
14f8ab
-    GF_VALIDATE_OR_GOTO(this->name, inode, out);
14f8ab
+    /* Handle readdirp: inode might be null, time attributes should be served
14f8ab
+     * from xattr not from backend's file attributes */
14f8ab
+    if (inode) {
14f8ab
+        ret = __inode_ctx_get1(inode, this, (uint64_t *)&mdata);
14f8ab
+    } else {
14f8ab
+        ret = -1;
14f8ab
+    }
14f8ab
 
14f8ab
-    ret = __inode_ctx_get1(inode, this, (uint64_t *)&mdata);
14f8ab
     if (ret == -1 || !mdata) {
14f8ab
         mdata = GF_CALLOC(1, sizeof(posix_mdata_t), gf_posix_mt_mdata_attr);
14f8ab
         if (!mdata) {
14f8ab
@@ -251,7 +257,9 @@ __posix_get_mdata_xattr(xlator_t *this, const char *real_path, int _fd,
14f8ab
              * is hit when in-memory status is lost due to brick
14f8ab
              * down scenario
14f8ab
              */
14f8ab
-            __inode_ctx_set1(inode, this, (uint64_t *)&mdata);
14f8ab
+            if (inode) {
14f8ab
+                __inode_ctx_set1(inode, this, (uint64_t *)&mdata);
14f8ab
+            }
14f8ab
         } else {
14f8ab
             /* Failed to get mdata from disk, xattr missing.
14f8ab
              * This happens on two cases.
14f8ab
@@ -278,7 +286,8 @@ __posix_get_mdata_xattr(xlator_t *this, const char *real_path, int _fd,
14f8ab
                  */
14f8ab
                 gf_msg(this->name, GF_LOG_WARNING, op_errno,
14f8ab
                        P_MSG_FETCHMDATA_FAILED, "file: %s: gfid: %s key:%s ",
14f8ab
-                       real_path ? real_path : "null", uuid_utoa(inode->gfid),
14f8ab
+                       real_path ? real_path : "null",
14f8ab
+                       inode ? uuid_utoa(inode->gfid) : "null",
14f8ab
                        GF_XATTR_MDATA_KEY);
14f8ab
                 GF_FREE(mdata);
14f8ab
                 ret = 0;
14f8ab
@@ -297,6 +306,10 @@ __posix_get_mdata_xattr(xlator_t *this, const char *real_path, int _fd,
14f8ab
         stbuf->ia_atime = mdata->atime.tv_sec;
14f8ab
         stbuf->ia_atime_nsec = mdata->atime.tv_nsec;
14f8ab
     }
14f8ab
+    /* Not set in inode context, hence free mdata */
14f8ab
+    if (!inode) {
14f8ab
+        GF_FREE(mdata);
14f8ab
+    }
14f8ab
 
14f8ab
 out:
14f8ab
     return ret;
14f8ab
@@ -416,6 +429,11 @@ posix_set_mdata_xattr(xlator_t *this, const char *real_path, int fd,
14f8ab
             }
14f8ab
         }
14f8ab
 
14f8ab
+        if ((flag->ctime == 0) && (flag->mtime == 0) && (flag->atime == 0)) {
14f8ab
+            ret = 0;
14f8ab
+            goto unlock;
14f8ab
+        }
14f8ab
+
14f8ab
         /* Earlier, mdata was updated only if the existing time is less
14f8ab
          * than the time to be updated. This would fail the scenarios
14f8ab
          * where mtime can be set to any time using the syscall. Hence
14f8ab
@@ -486,7 +504,6 @@ out:
14f8ab
         stbuf->ia_atime_nsec = mdata->atime.tv_nsec;
14f8ab
     }
14f8ab
 
14f8ab
-
14f8ab
     return ret;
14f8ab
 }
14f8ab
 
14f8ab
@@ -604,10 +621,6 @@ posix_set_ctime(call_frame_t *frame, xlator_t *this, const char *real_path,
14f8ab
 
14f8ab
     if (priv->ctime) {
14f8ab
         (void)posix_get_mdata_flag(frame->root->flags, &flag;;
14f8ab
-        if ((flag.ctime == 0) && (flag.mtime == 0) && (flag.atime == 0)) {
14f8ab
-            goto out;
14f8ab
-        }
14f8ab
-
14f8ab
         if (frame->root->ctime.tv_sec == 0) {
14f8ab
             gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_SETMDATA_FAILED,
14f8ab
                    "posix set mdata failed, No ctime : %s gfid:%s", real_path,
14f8ab
@@ -643,9 +656,6 @@ posix_set_parent_ctime(call_frame_t *frame, xlator_t *this,
14f8ab
 
14f8ab
     if (inode && priv->ctime) {
14f8ab
         (void)posix_get_parent_mdata_flag(frame->root->flags, &flag;;
14f8ab
-        if ((flag.ctime == 0) && (flag.mtime == 0) && (flag.atime == 0)) {
14f8ab
-            goto out;
14f8ab
-        }
14f8ab
         ret = posix_set_mdata_xattr(this, real_path, fd, inode,
14f8ab
                                     &frame->root->ctime, stbuf, &flag,
14f8ab
                                     _gf_false);
14f8ab
@@ -655,7 +665,6 @@ posix_set_parent_ctime(call_frame_t *frame, xlator_t *this,
14f8ab
                    uuid_utoa(inode->gfid));
14f8ab
         }
14f8ab
     }
14f8ab
-out:
14f8ab
     return;
14f8ab
 }
14f8ab
 
14f8ab
-- 
14f8ab
1.8.3.1
14f8ab