summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnand Avati <avati@gluster.com>2011-06-10 03:51:39 +0000
committerAnand Avati <avati@gluster.com>2011-06-17 08:34:04 -0700
commit2b7e442245c90e4ef969591069434ac127427584 (patch)
tree57bb42df869beb4efa7a6cfdc454a680deb3c7fd
parent821854b5e832539e6bddb2db7d8b0c67e4df79cd (diff)
posix: fix GFID assignment race between mkdir and lookup
In lookup, treat inodes which have recent ctime and no GFID as though they are still getting created by another thread and return ENOENT Signed-off-by: Anand Avati <avati@gluster.com> BUG: 2994 ([glusterfs-3.2.1qa2]: untar and rm in parallel hangs untar) URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=2994
-rw-r--r--xlators/storage/posix/src/posix.c70
1 files changed, 69 insertions, 1 deletions
diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c
index f95c9f8ffbc..2472ff90c34 100644
--- a/xlators/storage/posix/src/posix.c
+++ b/xlators/storage/posix/src/posix.c
@@ -405,6 +405,74 @@ out:
}
+static int
+is_fresh_file (struct stat *stat)
+{
+ struct timeval tv;
+
+ gettimeofday (&tv, NULL);
+
+ if ((stat->st_ctime >= (tv.tv_sec - 1))
+ && (stat->st_ctime <= tv.tv_sec))
+ return 1;
+
+ return 0;
+}
+
+
+int
+posix_gfid_heal (xlator_t *this, const char *path, dict_t *xattr_req)
+{
+ /* The purpose of this function is to prevent a race
+ where an inode creation FOP (like mkdir/mknod/create etc)
+ races with lookup in the following way:
+
+ {create thread} | {lookup thread}
+ |
+ t0
+ mkdir ("name") |
+ t1
+ | posix_gfid_set ("name", 2);
+ t2
+ posix_gfid_set ("name", 1); |
+ t3
+ lstat ("name"); | lstat ("name");
+
+ In the above case mkdir FOP would have resulted with GFID 2 while
+ it should have been GFID 1. It matters in the case where GFID would
+ have gotten set to 1 on other subvolumes of replciate/distribute
+
+ The "solution" here is that, if we detect lookup is attempting to
+ set a GFID on a file which is created very recently, but does not
+ yet have a GFID (i.e, between t1 and t2), then "fake" it as though
+ posix_gfid_heal was called at t0 instead.
+ */
+
+ uuid_t uuid_curr;
+ int ret = 0;
+ struct stat stat = {0, };
+
+ if (!xattr_req)
+ goto out;
+
+ if (sys_lstat (path, &stat) != 0)
+ goto out;
+
+ ret = sys_lgetxattr (path, GFID_XATTR_KEY, uuid_curr, 16);
+ if (ret != 16) {
+ if (is_fresh_file (&stat)) {
+ ret = -1;
+ errno = ENOENT;
+ goto out;
+ }
+ }
+
+ ret = posix_gfid_set (this, path, xattr_req);
+out:
+ return ret;
+}
+
+
int32_t
posix_lookup (call_frame_t *frame, xlator_t *this,
loc_t *loc, dict_t *xattr_req)
@@ -426,7 +494,7 @@ posix_lookup (call_frame_t *frame, xlator_t *this,
MAKE_REAL_PATH (real_path, this, loc->path);
- posix_gfid_set (this, real_path, xattr_req);
+ posix_gfid_heal (this, real_path, xattr_req);
op_ret = posix_lstat_with_gfid (this, real_path, &buf);
op_errno = errno;