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