diff options
author | Anand Avati <avati@gluster.com> | 2011-06-10 03:51:39 +0000 |
---|---|---|
committer | Anand Avati <avati@gluster.com> | 2011-06-10 03:54:06 -0700 |
commit | 47c7a5e97d096d740b8c167ed4dded28b6877898 (patch) | |
tree | 6ce8ed5c12bf4b9d39224452d1c4bb265a00b080 | |
parent | 8dee45b3a74b20f7cfbab68b9f8d71c125301772 (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.c | 70 |
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; |