diff options
author | Niklas Hambüchen <mail@nh2.me> | 2017-02-18 00:49:02 +0100 |
---|---|---|
committer | Jeff Darcy <jdarcy@redhat.com> | 2017-03-07 12:10:02 -0500 |
commit | ce8d8195dc253a87cceaaeeb1a725090471ae4f8 (patch) | |
tree | 87c027440d7a6af44956861b34fec3844d699038 /xlators/storage | |
parent | 89c6bedc1c2e978f67ca29f212a357984cd8a2dd (diff) |
posix: use nanosecond accuracy when available
Programs that set mtime, such as `rsync -a`, don't work correctly on
GlusterFS, because it sets the nanoseconds to 000. This creates
problems for incremental backups, where files get accidentally copied
again and again.
For example, consider `myfile` on an ext4 system, being copied to a
GlusterFS volume, with `rsync -a` and then `cp -u` in turn. You'd
expect that after the first `rsync -a`, `cp -u` agrees that the file
need not be copied.
BUG: 1422074
Change-Id: I89c7b6a73e2e06c02851ff76b7e5cdfaa271e985
Signed-off-by: Niklas Hambüchen <mail@nh2.me>
Reviewed-on: https://review.gluster.org/16667
Smoke: Gluster Build System <jenkins@build.gluster.org>
Reviewed-by: Niels de Vos <ndevos@redhat.com>
Tested-by: Jeff Darcy <jdarcy@redhat.com>
NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
Reviewed-by: jiffin tony Thottan <jthottan@redhat.com>
CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
Reviewed-by: Jeff Darcy <jdarcy@redhat.com>
Diffstat (limited to 'xlators/storage')
-rw-r--r-- | xlators/storage/posix/src/posix.c | 37 |
1 files changed, 30 insertions, 7 deletions
diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c index f3fca45492b..04d141f41b2 100644 --- a/xlators/storage/posix/src/posix.c +++ b/xlators/storage/posix/src/posix.c @@ -84,6 +84,25 @@ extern char *marker_xattrs[]; #endif +/* Setting microseconds or nanoseconds depending on what's supported: + The passed in `tv` can be + struct timespec + if supported (better, because it supports nanosecond resolution) or + struct timeval + otherwise. */ +#if HAVE_UTIMENSAT +#define SET_TIMESPEC_NSEC_OR_TIMEVAL_USEC(tv, nanosecs) \ + tv.tv_nsec = nanosecs +#define PATH_SET_TIMESPEC_OR_TIMEVAL(path, tv) \ + (sys_utimensat (AT_FDCWD, path, tv, AT_SYMLINK_NOFOLLOW)) +#else +#define SET_TIMESPEC_NSEC_OR_TIMEVAL_USEC(tv, nanosecs) \ + tv.tv_usec = nanosecs / 1000 +#define PATH_SET_TIMESPEC_OR_TIMEVAL(path, tv) \ + (lutimes (path, tv)) +#endif + + dict_t* posix_dict_set_nlink (dict_t *req, dict_t *res, int32_t nlink) { @@ -384,7 +403,11 @@ posix_do_utimes (xlator_t *this, int valid) { int32_t ret = -1; - struct timeval tv[2] = {{0,},{0,}}; +#if defined(HAVE_UTIMENSAT) + struct timespec tv[2] = { {0,}, {0,} }; +#else + struct timeval tv[2] = { {0,}, {0,} }; +#endif struct stat stat; int is_symlink = 0; @@ -400,23 +423,23 @@ posix_do_utimes (xlator_t *this, if ((valid & GF_SET_ATTR_ATIME) == GF_SET_ATTR_ATIME) { tv[0].tv_sec = stbuf->ia_atime; - tv[0].tv_usec = stbuf->ia_atime_nsec / 1000; + SET_TIMESPEC_NSEC_OR_TIMEVAL_USEC(tv[0], stbuf->ia_atime_nsec); } else { /* atime is not given, use current values */ tv[0].tv_sec = ST_ATIM_SEC (&stat); - tv[0].tv_usec = ST_ATIM_NSEC (&stat) / 1000; + SET_TIMESPEC_NSEC_OR_TIMEVAL_USEC(tv[0], ST_ATIM_NSEC (&stat)); } if ((valid & GF_SET_ATTR_MTIME) == GF_SET_ATTR_MTIME) { tv[1].tv_sec = stbuf->ia_mtime; - tv[1].tv_usec = stbuf->ia_mtime_nsec / 1000; + SET_TIMESPEC_NSEC_OR_TIMEVAL_USEC(tv[1], stbuf->ia_mtime_nsec); } else { /* mtime is not given, use current values */ tv[1].tv_sec = ST_MTIM_SEC (&stat); - tv[1].tv_usec = ST_MTIM_NSEC (&stat) / 1000; + SET_TIMESPEC_NSEC_OR_TIMEVAL_USEC(tv[1], ST_MTIM_NSEC (&stat)); } - ret = lutimes (path, tv); + ret = PATH_SET_TIMESPEC_OR_TIMEVAL(path, tv); if ((ret == -1) && (errno == ENOSYS)) { gf_msg_debug (this->name, 0, "%s (%s)", path, strerror (errno)); @@ -425,7 +448,7 @@ posix_do_utimes (xlator_t *this, goto out; } - ret = sys_utimes (path, tv); + ret = PATH_SET_TIMESPEC_OR_TIMEVAL(path, tv); } out: |