diff options
author | Kotresh HR <khiremat@redhat.com> | 2018-06-01 01:48:31 -0400 |
---|---|---|
committer | Amar Tumballi <amarts@redhat.com> | 2018-06-03 09:09:47 +0000 |
commit | a6f0e7a4f1ca203762cae2ed5e426b52124c74dc (patch) | |
tree | e95cc91ba349b73dca9bb6bf27fb385c8e55ebf7 /xlators/storage | |
parent | 2c1131e5868e46cfc806fb3a1cb63a5e554b4d6c (diff) |
posix/ctime: Fix fops racing in updating mtime/atime
In distributed systems, there could be races with fops
updating mtime/atime which could result in different
mtime/atime for same file. So updating them only if
time is greater than the existing makes sure, only
the highest time is retained. If the mtime/atime
update comes from the explicit utime syscall, it is
allowed to set to previous time.
Thanks Xavi for helping in rooting the issue.
fixes: bz#1584981
Change-Id: If1230a75b96d7f9a828795189fcc699049e7826e
Signed-off-by: Kotresh HR <khiremat@redhat.com>
Diffstat (limited to 'xlators/storage')
-rw-r--r-- | xlators/storage/posix/src/posix-metadata.c | 42 |
1 files changed, 31 insertions, 11 deletions
diff --git a/xlators/storage/posix/src/posix-metadata.c b/xlators/storage/posix/src/posix-metadata.c index 5da46d6bd99..eb2f24dbd69 100644 --- a/xlators/storage/posix/src/posix-metadata.c +++ b/xlators/storage/posix/src/posix-metadata.c @@ -353,7 +353,8 @@ posix_compare_timespec (struct timespec *first, struct timespec *second) static int posix_set_mdata_xattr (xlator_t *this, const char *real_path, int fd, inode_t *inode, struct timespec *time, - struct iatt *stbuf, posix_mdata_flag_t *flag) + struct iatt *stbuf, posix_mdata_flag_t *flag, + gf_boolean_t update_utime) { posix_mdata_t *mdata = NULL; int ret = -1; @@ -428,14 +429,31 @@ posix_set_mdata_xattr (xlator_t *this, const char *real_path, int fd, * allowed to changed to older date. */ if (flag->ctime && - posix_compare_timespec (time, &mdata->ctime) > 0) { + posix_compare_timespec (time, &mdata->ctime) > 0) { mdata->ctime = *time; } - if (flag->mtime) { - mdata->mtime = *time; - } - if (flag->atime) { - mdata->atime = *time; + /* In distributed systems, there could races with fops updating + * mtime/atime which could result in different mtime/atime + * for same file. So this makes sure, only the highest time is + * retained. If the mtime/atime update comes from the explicit + * utime syscall, it is allowed to set to previous time + */ + if (update_utime) { + if (flag->mtime) { + mdata->mtime = *time; + } + if (flag->atime) { + mdata->atime = *time; + } + } else { + if (flag->mtime && + posix_compare_timespec (time, &mdata->mtime) > 0) { + mdata->mtime = *time; + } + if (flag->atime && + posix_compare_timespec (time, &mdata->atime) > 0) { + mdata->atime = *time; + } } if (inode->ia_type == IA_INVAL) { @@ -507,7 +525,7 @@ posix_update_utime_in_mdata (xlator_t *this, const char *real_path, int fd, flag.mtime = 0; flag.atime = 1; ret = posix_set_mdata_xattr (this, real_path, -1, inode, &tv, NULL, - &flag); + &flag, _gf_true); if (ret) { gf_msg (this->name, GF_LOG_WARNING, errno, P_MSG_SETMDATA_FAILED, @@ -526,7 +544,7 @@ posix_update_utime_in_mdata (xlator_t *this, const char *real_path, int fd, flag.atime = 0; ret = posix_set_mdata_xattr (this, real_path, -1, inode, &tv, NULL, - &flag); + &flag, _gf_true); if (ret) { gf_msg (this->name, GF_LOG_WARNING, errno, P_MSG_SETMDATA_FAILED, @@ -602,7 +620,8 @@ posix_set_ctime (call_frame_t *frame, xlator_t *this, const char* real_path, } ret = posix_set_mdata_xattr (this, real_path, fd, inode, - &frame->root->ctime, stbuf, &flag); + &frame->root->ctime, stbuf, &flag, + _gf_false); if (ret) { gf_msg (this->name, GF_LOG_WARNING, errno, P_MSG_SETMDATA_FAILED, @@ -629,7 +648,8 @@ posix_set_parent_ctime (call_frame_t *frame, xlator_t *this, if (inode && priv->ctime) { (void) posix_get_parent_mdata_flag (frame->root->flags, &flag); ret = posix_set_mdata_xattr (this, real_path, fd, inode, - &frame->root->ctime, stbuf, &flag); + &frame->root->ctime, stbuf, &flag, + _gf_false); if (ret) { gf_msg (this->name, GF_LOG_WARNING, errno, P_MSG_SETMDATA_FAILED, |