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-10 03:54:06 -0700
commit47c7a5e97d096d740b8c167ed4dded28b6877898 (patch)
tree6ce8ed5c12bf4b9d39224452d1c4bb265a00b080
parent8dee45b3a74b20f7cfbab68b9f8d71c125301772 (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 0cd6883c1b3..f6b99025557 100644
--- a/xlators/storage/posix/src/posix.c
+++ b/xlators/storage/posix/src/posix.c
@@ -404,6 +404,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)
@@ -425,7 +493,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;