diff options
-rw-r--r-- | configure.ac | 8 | ||||
-rw-r--r-- | libglusterfs/src/common-utils.c | 28 | ||||
-rw-r--r-- | libglusterfs/src/libglusterfs-messages.h | 11 | ||||
-rw-r--r-- | libglusterfs/src/syscall.c | 10 | ||||
-rw-r--r-- | libglusterfs/src/syscall.h | 6 | ||||
-rw-r--r-- | xlators/storage/posix/src/posix.c | 37 |
6 files changed, 87 insertions, 13 deletions
diff --git a/configure.ac b/configure.ac index 6917322bd58..28ff3e5a3f4 100644 --- a/configure.ac +++ b/configure.ac @@ -981,6 +981,13 @@ if test "x${have_posix_fallocate}" = "xyes"; then AC_DEFINE(HAVE_POSIX_FALLOCATE, 1, [define if posix_fallocate exists]) fi +BUILD_NANOSECOND_TIMESTAMPS=no +AC_CHECK_FUNC([utimensat], [have_utimensat=yes]) +if test "x${have_utimensat}" = "xyes"; then + BUILD_NANOSECOND_TIMESTAMPS=yes + AC_DEFINE(HAVE_UTIMENSAT, 1, [define if utimensat exists]) +fi + OLD_CFLAGS=${CFLAGS} CFLAGS="-D_GNU_SOURCE" AC_CHECK_DECL([SEEK_HOLE], , , [#include <unistd.h>]) @@ -1544,4 +1551,5 @@ echo "Experimental xlators : $BUILD_EXPERIMENTAL" echo "Events : $BUILD_EVENTS" echo "EC dynamic support : $EC_DYNAMIC_SUPPORT" echo "Use memory pools : $USE_MEMPOOL" +echo "Nanosecond m/atimes : $BUILD_NANOSECOND_TIMESTAMPS" echo diff --git a/libglusterfs/src/common-utils.c b/libglusterfs/src/common-utils.c index 51f97442fec..e18c97f5aa1 100644 --- a/libglusterfs/src/common-utils.c +++ b/libglusterfs/src/common-utils.c @@ -3806,7 +3806,11 @@ int gf_set_timestamp (const char *src, const char* dest) { struct stat sb = {0, }; - struct timeval new_time[2] = {{0, },{0,}}; +#if defined(HAVE_UTIMENSAT) + struct timespec new_time[2] = { {0, }, {0, } }; +#else + struct timeval new_time[2] = { {0, }, {0, } }; +#endif int ret = 0; xlator_t *this = NULL; @@ -3821,21 +3825,35 @@ gf_set_timestamp (const char *src, const char* dest) LG_MSG_FILE_STAT_FAILED, "stat on %s", src); goto out; } + /* The granularity is nano seconds if `utimensat()` is available, + * and micro seconds otherwise. + */ +#if defined(HAVE_UTIMENSAT) + new_time[0].tv_sec = sb.st_atime; + new_time[0].tv_nsec = ST_ATIM_NSEC (&sb); + + new_time[1].tv_sec = sb.st_mtime; + new_time[1].tv_nsec = ST_MTIM_NSEC (&sb); + + /* dirfd = 0 is ignored because `dest` is an absolute path. */ + ret = sys_utimensat (AT_FDCWD, dest, new_time, AT_SYMLINK_NOFOLLOW); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, errno, + LG_MSG_UTIMENSAT_FAILED, "utimensat on %s", dest); + } +#else new_time[0].tv_sec = sb.st_atime; new_time[0].tv_usec = ST_ATIM_NSEC (&sb)/1000; new_time[1].tv_sec = sb.st_mtime; new_time[1].tv_usec = ST_MTIM_NSEC (&sb)/1000; - /* The granularity is micro seconds as per the current - * requiremnt. Hence using 'utimes'. This can be updated - * to 'utimensat' if we need timestamp in nanoseconds. - */ ret = sys_utimes (dest, new_time); if (ret) { gf_msg (this->name, GF_LOG_ERROR, errno, LG_MSG_UTIMES_FAILED, "utimes on %s", dest); } +#endif out: return ret; } diff --git a/libglusterfs/src/libglusterfs-messages.h b/libglusterfs/src/libglusterfs-messages.h index 29196929eb3..23ed7b727d3 100644 --- a/libglusterfs/src/libglusterfs-messages.h +++ b/libglusterfs/src/libglusterfs-messages.h @@ -37,7 +37,7 @@ #define GLFS_LG_BASE GLFS_MSGID_COMP_LIBGLUSTERFS -#define GLFS_LG_NUM_MESSAGES 209 +#define GLFS_LG_NUM_MESSAGES 210 #define GLFS_LG_MSGID_END (GLFS_LG_BASE + GLFS_LG_NUM_MESSAGES + 1) /* Messaged with message IDs */ @@ -1791,6 +1791,15 @@ * @recommendedaction * */ + +#define LG_MSG_UTIMENSAT_FAILED (GLFS_LG_BASE + 210) + +/*! + * @messageid + * @diagnosis + * @recommendedaction + * + */ /*------------*/ #define glfs_msg_end_lg GLFS_LG_MSGID_END, "Invalid: End of messages" diff --git a/libglusterfs/src/syscall.c b/libglusterfs/src/syscall.c index 4e4c6a728da..a7d4402808d 100644 --- a/libglusterfs/src/syscall.c +++ b/libglusterfs/src/syscall.c @@ -272,6 +272,16 @@ sys_utimes (const char *filename, const struct timeval times[2]) } +#if defined(HAVE_UTIMENSAT) +int +sys_utimensat (int dirfd, const char *filename, const struct timespec times[2], + int flags) +{ + return utimensat (dirfd, filename, times, flags); +} +#endif + + int sys_creat (const char *pathname, mode_t mode) { diff --git a/libglusterfs/src/syscall.h b/libglusterfs/src/syscall.h index b1bcad138c5..6bb374822ee 100644 --- a/libglusterfs/src/syscall.h +++ b/libglusterfs/src/syscall.h @@ -129,6 +129,12 @@ sys_ftruncate (int fd, off_t length); int sys_utimes (const char *filename, const struct timeval times[2]); +#if defined(HAVE_UTIMENSAT) +int +sys_utimensat (int dirfd, const char *filename, const struct timespec times[2], + int flags); +#endif + int sys_creat (const char *pathname, mode_t mode); 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: |