diff --git a/coreutils-8.31-statx.patch b/coreutils-8.31-statx.patch deleted file mode 100644 index cc09c2e..0000000 --- a/coreutils-8.31-statx.patch +++ /dev/null @@ -1,1294 +0,0 @@ -From 061032235577e58980f76f6340e8b0e7f0350dd0 Mon Sep 17 00:00:00 2001 -From: Jeff Layton -Date: Tue, 28 May 2019 08:21:42 -0400 -Subject: [PATCH 1/4] stat: Use statx where available and support --cached - -* src/stat.c: Drop statbuf argument from out_epoch_sec(). -Use statx() rather than [lf]stat() where available, -so a separate call is not required to get birth time. -Set STATX_* mask bits only for things we want to print, -which can be more efficient on some file systems. -Add a new --cache= command-line option that sets the appropriate hint -flags in the statx call. These are primarily used with network -file systems to indicate what level of cache coherency is desired. -The new option is available unconditionally for better portability, -and ignored where not implemented. -* doc/coreutils.texi: Add documention for --cached. -* man/stat.x (SEE ALSO): Mention statx(). - -Upstream-commit: 6cc35de16fdc52d417602b66d5e90694d7e02994 -Signed-off-by: Kamil Dudka ---- - doc/coreutils.texi | 21 ++ - man/stat.x | 2 +- - src/stat.c | 623 ++++++++++++++++++++++++++++++--------------- - 3 files changed, 444 insertions(+), 202 deletions(-) - -diff --git a/doc/coreutils.texi b/doc/coreutils.texi -index c123860..957ee92 100644 ---- a/doc/coreutils.texi -+++ b/doc/coreutils.texi -@@ -12360,6 +12360,27 @@ Report information about the file systems where the given files are located - instead of information about the files themselves. - This option implies the @option{-L} option. - -+@item --cached=@var{mode} -+@opindex --cached=@var{mode} -+@cindex attribute caching -+Control how attributes are read from the file system; -+if supported by the system. This allows one to -+control the trade-off between freshness and efficiency -+of attribute access, especially useful with remote file systems. -+@var{mode} can be: -+ -+@table @samp -+@item always -+Always read the already cached attributes if available. -+ -+@item never -+Always sychronize with the latest file system attributes. -+ -+@item default -+Leave the caching behavior to the underlying file system. -+ -+@end table -+ - @item -c - @itemx --format=@var{format} - @opindex -c -diff --git a/man/stat.x b/man/stat.x -index dc3781e..b9f8c68 100644 ---- a/man/stat.x -+++ b/man/stat.x -@@ -3,4 +3,4 @@ stat \- display file or file system status - [DESCRIPTION] - .\" Add any additional description here - [SEE ALSO] --stat(2), statfs(2) -+stat(2), statfs(2), statx(2) -diff --git a/src/stat.c b/src/stat.c -index bb1ef1a..3bb84f3 100644 ---- a/src/stat.c -+++ b/src/stat.c -@@ -28,6 +28,12 @@ - # define USE_STATVFS 0 - #endif - -+#if HAVE_STATX && defined STATX_INO -+# define USE_STATX 1 -+#else -+# define USE_STATX 0 -+#endif -+ - #include - #include - #include -@@ -194,6 +200,23 @@ enum - PRINTF_OPTION = CHAR_MAX + 1 - }; - -+enum cached_mode -+{ -+ cached_default, -+ cached_never, -+ cached_always -+}; -+ -+static char const *const cached_args[] = -+{ -+ "default", "never", "always", NULL -+}; -+ -+static enum cached_mode const cached_modes[] = -+{ -+ cached_default, cached_never, cached_always -+}; -+ - static struct option const long_options[] = - { - {"dereference", no_argument, NULL, 'L'}, -@@ -201,6 +224,7 @@ static struct option const long_options[] = - {"format", required_argument, NULL, 'c'}, - {"printf", required_argument, NULL, PRINTF_OPTION}, - {"terse", no_argument, NULL, 't'}, -+ {"cached", required_argument, NULL, 0}, - {GETOPT_HELP_OPTION_DECL}, - {GETOPT_VERSION_OPTION_DECL}, - {NULL, 0, NULL, 0} -@@ -221,6 +245,10 @@ static char const *trailing_delim = ""; - static char const *decimal_point; - static size_t decimal_point_len; - -+static bool -+print_stat (char *pformat, size_t prefix_len, unsigned int m, -+ int fd, char const *filename, void const *data); -+ - /* Return the type of the specified file system. - Some systems have statfvs.f_basetype[FSTYPSZ] (AIX, HP-UX, and Solaris). - Others have statvfs.f_fstypename[_VFS_NAMELEN] (NetBSD 3.0). -@@ -676,7 +704,6 @@ out_minus_zero (char *pformat, size_t prefix_len) - acts like printf's %f format. */ - static void - out_epoch_sec (char *pformat, size_t prefix_len, -- struct stat const *statbuf _GL_UNUSED, - struct timespec arg) - { - char *dot = memchr (pformat, '.', prefix_len); -@@ -980,57 +1007,6 @@ print_mount_point: - return fail; - } - --static struct timespec --get_birthtime (int fd, char const *filename, struct stat const *st) --{ -- struct timespec ts = get_stat_birthtime (st); -- --#if HAVE_GETATTRAT -- if (ts.tv_nsec < 0) -- { -- nvlist_t *response; -- if ((fd < 0 -- ? getattrat (AT_FDCWD, XATTR_VIEW_READWRITE, filename, &response) -- : fgetattr (fd, XATTR_VIEW_READWRITE, &response)) -- == 0) -- { -- uint64_t *val; -- uint_t n; -- if (nvlist_lookup_uint64_array (response, A_CRTIME, &val, &n) == 0 -- && 2 <= n -- && val[0] <= TYPE_MAXIMUM (time_t) -- && val[1] < 1000000000 * 2 /* for leap seconds */) -- { -- ts.tv_sec = val[0]; -- ts.tv_nsec = val[1]; -- } -- nvlist_free (response); -- } -- } --#endif -- --#if HAVE_STATX && defined STATX_BTIME -- if (ts.tv_nsec < 0) -- { -- struct statx stx; -- if ((fd < 0 -- ? statx (AT_FDCWD, filename, -- follow_links ? 0 : AT_SYMLINK_NOFOLLOW, -- STATX_BTIME, &stx) -- : statx (fd, "", AT_EMPTY_PATH, STATX_BTIME, &stx)) == 0) -- { -- if ((stx.stx_mask & STATX_BTIME) && stx.stx_btime.tv_sec != 0) -- { -- ts.tv_sec = stx.stx_btime.tv_sec; -- ts.tv_nsec = stx.stx_btime.tv_nsec; -- } -- } -- } --#endif -- -- return ts; --} -- - /* Map a TS with negative TS.tv_nsec to {0,0}. */ - static inline struct timespec - neg_to_zero (struct timespec ts) -@@ -1067,139 +1043,6 @@ getenv_quoting_style (void) - /* Equivalent to quotearg(), but explicit to avoid syntax checks. */ - #define quoteN(x) quotearg_style (get_quoting_style (NULL), x) - --/* Print stat info. Return zero upon success, nonzero upon failure. */ --static bool --print_stat (char *pformat, size_t prefix_len, unsigned int m, -- int fd, char const *filename, void const *data) --{ -- struct stat *statbuf = (struct stat *) data; -- struct passwd *pw_ent; -- struct group *gw_ent; -- bool fail = false; -- -- switch (m) -- { -- case 'n': -- out_string (pformat, prefix_len, filename); -- break; -- case 'N': -- out_string (pformat, prefix_len, quoteN (filename)); -- if (S_ISLNK (statbuf->st_mode)) -- { -- char *linkname = areadlink_with_size (filename, statbuf->st_size); -- if (linkname == NULL) -- { -- error (0, errno, _("cannot read symbolic link %s"), -- quoteaf (filename)); -- return true; -- } -- printf (" -> "); -- out_string (pformat, prefix_len, quoteN (linkname)); -- free (linkname); -- } -- break; -- case 'd': -- out_uint (pformat, prefix_len, statbuf->st_dev); -- break; -- case 'D': -- out_uint_x (pformat, prefix_len, statbuf->st_dev); -- break; -- case 'i': -- out_uint (pformat, prefix_len, statbuf->st_ino); -- break; -- case 'a': -- out_uint_o (pformat, prefix_len, statbuf->st_mode & CHMOD_MODE_BITS); -- break; -- case 'A': -- out_string (pformat, prefix_len, human_access (statbuf)); -- break; -- case 'f': -- out_uint_x (pformat, prefix_len, statbuf->st_mode); -- break; -- case 'F': -- out_string (pformat, prefix_len, file_type (statbuf)); -- break; -- case 'h': -- out_uint (pformat, prefix_len, statbuf->st_nlink); -- break; -- case 'u': -- out_uint (pformat, prefix_len, statbuf->st_uid); -- break; -- case 'U': -- pw_ent = getpwuid (statbuf->st_uid); -- out_string (pformat, prefix_len, -- pw_ent ? pw_ent->pw_name : "UNKNOWN"); -- break; -- case 'g': -- out_uint (pformat, prefix_len, statbuf->st_gid); -- break; -- case 'G': -- gw_ent = getgrgid (statbuf->st_gid); -- out_string (pformat, prefix_len, -- gw_ent ? gw_ent->gr_name : "UNKNOWN"); -- break; -- case 't': -- out_uint_x (pformat, prefix_len, major (statbuf->st_rdev)); -- break; -- case 'm': -- fail |= out_mount_point (filename, pformat, prefix_len, statbuf); -- break; -- case 'T': -- out_uint_x (pformat, prefix_len, minor (statbuf->st_rdev)); -- break; -- case 's': -- out_int (pformat, prefix_len, statbuf->st_size); -- break; -- case 'B': -- out_uint (pformat, prefix_len, ST_NBLOCKSIZE); -- break; -- case 'b': -- out_uint (pformat, prefix_len, ST_NBLOCKS (*statbuf)); -- break; -- case 'o': -- out_uint (pformat, prefix_len, ST_BLKSIZE (*statbuf)); -- break; -- case 'w': -- { -- struct timespec t = get_birthtime (fd, filename, statbuf); -- if (t.tv_nsec < 0) -- out_string (pformat, prefix_len, "-"); -- else -- out_string (pformat, prefix_len, human_time (t)); -- } -- break; -- case 'W': -- out_epoch_sec (pformat, prefix_len, statbuf, -- neg_to_zero (get_birthtime (fd, filename, statbuf))); -- break; -- case 'x': -- out_string (pformat, prefix_len, human_time (get_stat_atime (statbuf))); -- break; -- case 'X': -- out_epoch_sec (pformat, prefix_len, statbuf, get_stat_atime (statbuf)); -- break; -- case 'y': -- out_string (pformat, prefix_len, human_time (get_stat_mtime (statbuf))); -- break; -- case 'Y': -- out_epoch_sec (pformat, prefix_len, statbuf, get_stat_mtime (statbuf)); -- break; -- case 'z': -- out_string (pformat, prefix_len, human_time (get_stat_ctime (statbuf))); -- break; -- case 'Z': -- out_epoch_sec (pformat, prefix_len, statbuf, get_stat_ctime (statbuf)); -- break; -- case 'C': -- fail |= out_file_context (pformat, prefix_len, filename); -- break; -- default: -- fputc ('?', stdout); -- break; -- } -- return fail; --} -- - /* Output a single-character \ escape. */ - - static void -@@ -1241,6 +1084,17 @@ print_esc_char (char c) - putchar (c); - } - -+static size_t _GL_ATTRIBUTE_PURE -+format_code_offset (char const* directive) -+{ -+ size_t len = strspn (directive + 1, printf_flags); -+ char const *fmt_char = directive + len + 1; -+ fmt_char += strspn (fmt_char, digits); -+ if (*fmt_char == '.') -+ fmt_char += 1 + strspn (fmt_char + 1, digits); -+ return fmt_char - directive; -+} -+ - /* Print the information specified by the format string, FORMAT, - calling PRINT_FUNC for each %-directive encountered. - Return zero upon success, nonzero upon failure. */ -@@ -1270,33 +1124,28 @@ print_it (char const *format, int fd, char const *filename, - { - case '%': - { -- size_t len = strspn (b + 1, printf_flags); -- char const *fmt_char = b + len + 1; -- fmt_char += strspn (fmt_char, digits); -- if (*fmt_char == '.') -- fmt_char += 1 + strspn (fmt_char + 1, digits); -- len = fmt_char - (b + 1); -- unsigned int fmt_code = *fmt_char; -- memcpy (dest, b, len + 1); -- -- b = fmt_char; -- switch (fmt_code) -+ size_t len = format_code_offset (b); -+ char const *fmt_char = b + len; -+ memcpy (dest, b, len); -+ b += len; -+ -+ switch (*fmt_char) - { - case '\0': - --b; - FALLTHROUGH; - case '%': -- if (0 < len) -+ if (1 < len) - { -- dest[len + 1] = *fmt_char; -- dest[len + 2] = '\0'; -+ dest[len] = *fmt_char; -+ dest[len + 1] = '\0'; - die (EXIT_FAILURE, 0, _("%s: invalid directive"), - quote (dest)); - } - putchar ('%'); - break; - default: -- fail |= print_func (dest, len + 1, fmt_code, -+ fail |= print_func (dest, len, to_uchar (*fmt_char), - fd, filename, data); - break; - } -@@ -1384,6 +1233,204 @@ do_statfs (char const *filename, char const *format) - return ! fail; - } - -+struct print_args { -+ struct stat *st; -+ struct timespec btime; -+}; -+ -+/* Ask statx to avoid syncing? */ -+static bool dont_sync; -+ -+/* Ask statx to force sync? */ -+static bool force_sync; -+ -+#if USE_STATX -+/* Much of the format printing requires a struct stat or timespec */ -+static struct timespec -+statx_timestamp_to_timespec (struct statx_timestamp tsx) -+{ -+ struct timespec ts; -+ -+ ts.tv_sec = tsx.tv_sec; -+ ts.tv_nsec = tsx.tv_nsec; -+ return ts; -+} -+ -+static void -+statx_to_stat (struct statx *stx, struct stat *stat) -+{ -+ stat->st_dev = makedev (stx->stx_dev_major, stx->stx_dev_minor); -+ stat->st_ino = stx->stx_ino; -+ stat->st_mode = stx->stx_mode; -+ stat->st_nlink = stx->stx_nlink; -+ stat->st_uid = stx->stx_uid; -+ stat->st_gid = stx->stx_gid; -+ stat->st_rdev = makedev (stx->stx_rdev_major, stx->stx_rdev_minor); -+ stat->st_size = stx->stx_size; -+ stat->st_blksize = stx->stx_blksize; -+/* define to avoid sc_prohibit_stat_st_blocks. */ -+# define SC_ST_BLOCKS st_blocks -+ stat->SC_ST_BLOCKS = stx->stx_blocks; -+ stat->st_atim = statx_timestamp_to_timespec (stx->stx_atime); -+ stat->st_mtim = statx_timestamp_to_timespec (stx->stx_mtime); -+ stat->st_ctim = statx_timestamp_to_timespec (stx->stx_ctime); -+} -+ -+static unsigned int -+fmt_to_mask (char fmt) -+{ -+ switch (fmt) -+ { -+ case 'N': -+ return STATX_MODE|STATX_SIZE; -+ case 'd': -+ case 'D': -+ return STATX_MODE; -+ case 'i': -+ return STATX_INO; -+ case 'a': -+ case 'A': -+ return STATX_MODE; -+ case 'f': -+ return STATX_MODE|STATX_TYPE; -+ case 'F': -+ return STATX_TYPE; -+ case 'h': -+ return STATX_NLINK; -+ case 'u': -+ case 'U': -+ return STATX_UID; -+ case 'g': -+ case 'G': -+ return STATX_GID; -+ case 'm': -+ return STATX_MODE|STATX_INO; -+ case 's': -+ return STATX_SIZE; -+ case 't': -+ case 'T': -+ return STATX_MODE; -+ case 'b': -+ return STATX_BLOCKS; -+ case 'w': -+ case 'W': -+ return STATX_BTIME; -+ case 'x': -+ case 'X': -+ return STATX_ATIME; -+ case 'y': -+ case 'Y': -+ return STATX_MTIME; -+ case 'z': -+ case 'Z': -+ return STATX_CTIME; -+ } -+ return 0; -+} -+ -+static unsigned int _GL_ATTRIBUTE_PURE -+format_to_mask (char const *format) -+{ -+ unsigned int mask = 0; -+ char const *b; -+ -+ for (b = format; *b; b++) -+ { -+ if (*b != '%') -+ continue; -+ -+ b += format_code_offset (b); -+ if (*b == '\0') -+ break; -+ mask |= fmt_to_mask (*b); -+ } -+ return mask; -+} -+ -+/* statx the file and print what we find */ -+static bool ATTRIBUTE_WARN_UNUSED_RESULT -+do_stat (char const *filename, char const *format, char const *format2) -+{ -+ int fd = STREQ (filename, "-") ? 0 : AT_FDCWD; -+ int flags = 0; -+ struct stat st; -+ struct statx stx; -+ const char *pathname = filename; -+ struct print_args pa; -+ pa.st = &st; -+ pa.btime = (struct timespec) {-1, -1}; -+ -+ if (AT_FDCWD != fd) -+ { -+ pathname = ""; -+ flags = AT_EMPTY_PATH; -+ } -+ else if (!follow_links) -+ { -+ flags = AT_SYMLINK_NOFOLLOW; -+ } -+ -+ if (dont_sync) -+ flags |= AT_STATX_DONT_SYNC; -+ else if (force_sync) -+ flags |= AT_STATX_FORCE_SYNC; -+ -+ fd = statx (fd, pathname, flags, format_to_mask (format), &stx); -+ if (fd < 0) -+ { -+ if (flags & AT_EMPTY_PATH) -+ error (0, errno, _("cannot stat standard input")); -+ else -+ error (0, errno, _("cannot statx %s"), quoteaf (filename)); -+ return false; -+ } -+ -+ if (S_ISBLK (stx.stx_mode) || S_ISCHR (stx.stx_mode)) -+ format = format2; -+ -+ statx_to_stat (&stx, &st); -+ if (stx.stx_mask & STATX_BTIME) -+ pa.btime = statx_timestamp_to_timespec (stx.stx_btime); -+ -+ bool fail = print_it (format, fd, filename, print_stat, &pa); -+ return ! fail; -+} -+ -+#else /* USE_STATX */ -+ -+static struct timespec -+get_birthtime (int fd, char const *filename, struct stat const *st) -+{ -+ struct timespec ts = get_stat_birthtime (st); -+ -+# if HAVE_GETATTRAT -+ if (ts.tv_nsec < 0) -+ { -+ nvlist_t *response; -+ if ((fd < 0 -+ ? getattrat (AT_FDCWD, XATTR_VIEW_READWRITE, filename, &response) -+ : fgetattr (fd, XATTR_VIEW_READWRITE, &response)) -+ == 0) -+ { -+ uint64_t *val; -+ uint_t n; -+ if (nvlist_lookup_uint64_array (response, A_CRTIME, &val, &n) == 0 -+ && 2 <= n -+ && val[0] <= TYPE_MAXIMUM (time_t) -+ && val[1] < 1000000000 * 2 /* for leap seconds */) -+ { -+ ts.tv_sec = val[0]; -+ ts.tv_nsec = val[1]; -+ } -+ nvlist_free (response); -+ } -+ } -+# endif -+ -+ return ts; -+} -+ -+ - /* stat the file and print what we find */ - static bool ATTRIBUTE_WARN_UNUSED_RESULT - do_stat (char const *filename, char const *format, -@@ -1391,6 +1438,9 @@ do_stat (char const *filename, char const *format, - { - int fd = STREQ (filename, "-") ? 0 : -1; - struct stat statbuf; -+ struct print_args pa; -+ pa.st = &statbuf; -+ pa.btime = (struct timespec) {-1, -1}; - - if (0 <= fd) - { -@@ -1414,9 +1464,152 @@ do_stat (char const *filename, char const *format, - if (S_ISBLK (statbuf.st_mode) || S_ISCHR (statbuf.st_mode)) - format = format2; - -- bool fail = print_it (format, fd, filename, print_stat, &statbuf); -+ bool fail = print_it (format, fd, filename, print_stat, &pa); - return ! fail; - } -+#endif /* USE_STATX */ -+ -+ -+/* Print stat info. Return zero upon success, nonzero upon failure. */ -+static bool -+print_stat (char *pformat, size_t prefix_len, unsigned int m, -+ int fd, char const *filename, void const *data) -+{ -+ struct print_args *parg = (struct print_args *) data; -+ struct stat *statbuf = parg->st; -+ struct timespec btime = parg->btime; -+ struct passwd *pw_ent; -+ struct group *gw_ent; -+ bool fail = false; -+ -+ switch (m) -+ { -+ case 'n': -+ out_string (pformat, prefix_len, filename); -+ break; -+ case 'N': -+ out_string (pformat, prefix_len, quoteN (filename)); -+ if (S_ISLNK (statbuf->st_mode)) -+ { -+ char *linkname = areadlink_with_size (filename, statbuf->st_size); -+ if (linkname == NULL) -+ { -+ error (0, errno, _("cannot read symbolic link %s"), -+ quoteaf (filename)); -+ return true; -+ } -+ printf (" -> "); -+ out_string (pformat, prefix_len, quoteN (linkname)); -+ free (linkname); -+ } -+ break; -+ case 'd': -+ out_uint (pformat, prefix_len, statbuf->st_dev); -+ break; -+ case 'D': -+ out_uint_x (pformat, prefix_len, statbuf->st_dev); -+ break; -+ case 'i': -+ out_uint (pformat, prefix_len, statbuf->st_ino); -+ break; -+ case 'a': -+ out_uint_o (pformat, prefix_len, statbuf->st_mode & CHMOD_MODE_BITS); -+ break; -+ case 'A': -+ out_string (pformat, prefix_len, human_access (statbuf)); -+ break; -+ case 'f': -+ out_uint_x (pformat, prefix_len, statbuf->st_mode); -+ break; -+ case 'F': -+ out_string (pformat, prefix_len, file_type (statbuf)); -+ break; -+ case 'h': -+ out_uint (pformat, prefix_len, statbuf->st_nlink); -+ break; -+ case 'u': -+ out_uint (pformat, prefix_len, statbuf->st_uid); -+ break; -+ case 'U': -+ pw_ent = getpwuid (statbuf->st_uid); -+ out_string (pformat, prefix_len, -+ pw_ent ? pw_ent->pw_name : "UNKNOWN"); -+ break; -+ case 'g': -+ out_uint (pformat, prefix_len, statbuf->st_gid); -+ break; -+ case 'G': -+ gw_ent = getgrgid (statbuf->st_gid); -+ out_string (pformat, prefix_len, -+ gw_ent ? gw_ent->gr_name : "UNKNOWN"); -+ break; -+ case 'm': -+ fail |= out_mount_point (filename, pformat, prefix_len, statbuf); -+ break; -+ case 's': -+ out_int (pformat, prefix_len, statbuf->st_size); -+ break; -+ case 't': -+ out_uint_x (pformat, prefix_len, major (statbuf->st_rdev)); -+ break; -+ case 'T': -+ out_uint_x (pformat, prefix_len, minor (statbuf->st_rdev)); -+ break; -+ case 'B': -+ out_uint (pformat, prefix_len, ST_NBLOCKSIZE); -+ break; -+ case 'b': -+ out_uint (pformat, prefix_len, ST_NBLOCKS (*statbuf)); -+ break; -+ case 'o': -+ out_uint (pformat, prefix_len, ST_BLKSIZE (*statbuf)); -+ break; -+ case 'w': -+ { -+#if ! USE_STATX -+ btime = get_birthtime (fd, filename, statbuf); -+#endif -+ if (btime.tv_nsec < 0) -+ out_string (pformat, prefix_len, "-"); -+ else -+ out_string (pformat, prefix_len, human_time (btime)); -+ } -+ break; -+ case 'W': -+ { -+#if ! USE_STATX -+ btime = get_birthtime (fd, filename, statbuf); -+#endif -+ out_epoch_sec (pformat, prefix_len, neg_to_zero (btime)); -+ } -+ break; -+ case 'x': -+ out_string (pformat, prefix_len, human_time (get_stat_atime (statbuf))); -+ break; -+ case 'X': -+ out_epoch_sec (pformat, prefix_len, get_stat_atime (statbuf)); -+ break; -+ case 'y': -+ out_string (pformat, prefix_len, human_time (get_stat_mtime (statbuf))); -+ break; -+ case 'Y': -+ out_epoch_sec (pformat, prefix_len, get_stat_mtime (statbuf)); -+ break; -+ case 'z': -+ out_string (pformat, prefix_len, human_time (get_stat_ctime (statbuf))); -+ break; -+ case 'Z': -+ out_epoch_sec (pformat, prefix_len, get_stat_ctime (statbuf)); -+ break; -+ case 'C': -+ fail |= out_file_context (pformat, prefix_len, filename); -+ break; -+ default: -+ fputc ('?', stdout); -+ break; -+ } -+ return fail; -+} - - /* Return an allocated format string in static storage that - corresponds to whether FS and TERSE options were declared. */ -@@ -1525,6 +1718,10 @@ Display file or file system status.\n\ - fputs (_("\ - -L, --dereference follow links\n\ - -f, --file-system display file system status instead of file status\n\ -+"), stdout); -+ fputs (_("\ -+ --cached=MODE specify how to use cached attributes;\n\ -+ useful on remote file systems. See MODE below\n\ - "), stdout); - fputs (_("\ - -c --format=FORMAT use the specified FORMAT instead of the default;\n\ -@@ -1537,6 +1734,13 @@ Display file or file system status.\n\ - fputs (HELP_OPTION_DESCRIPTION, stdout); - fputs (VERSION_OPTION_DESCRIPTION, stdout); - -+ fputs (_("\n\ -+The --cached MODE argument can be; always, never, or default.\n\ -+`always` will use cached attributes if available, while\n\ -+`never` will try to synchronize with the latest attributes, and\n\ -+`default` will leave it up to the underlying file system.\n\ -+"), stdout); -+ - fputs (_("\n\ - The valid format sequences for files (without --file-system):\n\ - \n\ -@@ -1670,6 +1874,23 @@ main (int argc, char *argv[]) - terse = true; - break; - -+ case 0: -+ switch (XARGMATCH ("--cached", optarg, cached_args, cached_modes)) -+ { -+ case cached_never: -+ force_sync = true; -+ dont_sync = false; -+ break; -+ case cached_always: -+ force_sync = false; -+ dont_sync = true; -+ break; -+ case cached_default: -+ force_sync = false; -+ dont_sync = false; -+ } -+ break; -+ - case_GETOPT_HELP_CHAR; - - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); --- -2.20.1 - - -From c19f77360d564e0c0d5ab0159299ebd8d6c34a2f Mon Sep 17 00:00:00 2001 -From: Jeff Layton -Date: Fri, 14 Jun 2019 14:37:43 -0400 -Subject: [PATCH 2/4] stat: fix enabling of statx logic - -* src/stat.c: STATX_INO isn't defined until stat.h is included. -Move the test down so it works properly. - -Upstream-commit: 0b9bac90d8283c1262e74f0dbda87583508de9a3 -Signed-off-by: Kamil Dudka ---- - src/stat.c | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/src/stat.c b/src/stat.c -index 3bb84f3..ec0bb7d 100644 ---- a/src/stat.c -+++ b/src/stat.c -@@ -28,12 +28,6 @@ - # define USE_STATVFS 0 - #endif - --#if HAVE_STATX && defined STATX_INO --# define USE_STATX 1 --#else --# define USE_STATX 0 --#endif -- - #include - #include - #include -@@ -80,6 +74,12 @@ - #include "find-mount-point.h" - #include "xvasprintf.h" - -+#if HAVE_STATX && defined STATX_INO -+# define USE_STATX 1 -+#else -+# define USE_STATX 0 -+#endif -+ - #if USE_STATVFS - # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATVFS_F_FSID_IS_INTEGER - # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS_F_TYPE --- -2.20.1 - - -From 0081747eb0fd1eb604e1f17c8c5bfaf5119310a9 Mon Sep 17 00:00:00 2001 -From: Andreas Dilger -Date: Thu, 27 Jun 2019 02:25:55 -0600 -Subject: [PATCH 3/4] stat: don't explicitly request file size for filenames - -When calling 'stat -c %N' to print the filename, don't explicitly -request the size of the file via statx(), as it may add overhead on -some filesystems. The size is only needed to optimize an allocation -for the relatively rare case of reading a symlink name, and the worst -effect is a somewhat-too-large temporary buffer may be allocated for -areadlink_with_size(), or internal retries if buffer is too small. - -The file size will be returned by statx() on most filesystems, even -if not requested, unless the filesystem considers this to be too -expensive for that file, in which case the tradeoff is worthwhile. - -* src/stat.c: Don't explicitly request STATX_SIZE for filenames. - -Upstream-commit: a1a5e9a32eb9525680edd02fd127240c27ba0999 -Signed-off-by: Kamil Dudka ---- - src/stat.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/stat.c b/src/stat.c -index ec0bb7d..ee68f16 100644 ---- a/src/stat.c -+++ b/src/stat.c -@@ -1282,7 +1282,7 @@ fmt_to_mask (char fmt) - switch (fmt) - { - case 'N': -- return STATX_MODE|STATX_SIZE; -+ return STATX_MODE; - case 'd': - case 'D': - return STATX_MODE; -@@ -1354,7 +1354,7 @@ do_stat (char const *filename, char const *format, char const *format2) - int fd = STREQ (filename, "-") ? 0 : AT_FDCWD; - int flags = 0; - struct stat st; -- struct statx stx; -+ struct statx stx = { 0, }; - const char *pathname = filename; - struct print_args pa; - pa.st = &st; --- -2.20.1 - - -From e18c739a523f760d8372f8dd33f047a88a1b48fd Mon Sep 17 00:00:00 2001 -From: Jeff Layton -Date: Thu, 19 Sep 2019 11:59:45 -0400 -Subject: [PATCH 4/4] ls: use statx instead of stat when available - -statx allows ls to indicate interest in only certain inode metadata. -This is potentially a win on networked/clustered/distributed -file systems. In cases where we'd have to do a full, heavyweight stat() -call we can now do a much lighter statx() call. - -As a real-world example, consider a file system like CephFS where one -client is actively writing to a file and another client does an -ls --color in the same directory. --color means that we need to fetch -the mode of the file. - -Doing that with a stat() call means that we have to fetch the size and -mtime in addition to the mode. The MDS in that situation will have to -revoke caps in order to ensure that it has up-to-date values to report, -which disrupts the writer. - -This has a measurable affect on performance. I ran a fio sequential -write test on one cephfs client and had a second client do "ls --color" -in a tight loop on the directory that held the file: - -Baseline -- no activity on the second client: - -WRITE: bw=76.7MiB/s (80.4MB/s), 76.7MiB/s-76.7MiB/s (80.4MB/s-80.4MB/s), - io=4600MiB (4824MB), run=60016-60016msec - -Without this patch series, we see a noticable performance hit: - -WRITE: bw=70.4MiB/s (73.9MB/s), 70.4MiB/s-70.4MiB/s (73.9MB/s-73.9MB/s), - io=4228MiB (4433MB), run=60012-60012msec - -With this patch series, we gain most of that ground back: - -WRITE: bw=75.9MiB/s (79.6MB/s), 75.9MiB/s-75.9MiB/s (79.6MB/s-79.6MB/s), - io=4555MiB (4776MB), run=60019-60019msec - -* src/stat.c: move statx to stat struct conversion to new header... -* src/statx.h: ...here. -* src/ls.c: Add wrapper functions for stat/lstat/fstat calls, -and add variants for when we are only interested in specific info. -Add statx-enabled functions and set the request mask based on the -output format and what values are needed. - -Upstream-commit: a99ab266110795ed94a9cb4d2765ddad9c4310da -Signed-off-by: Kamil Dudka ---- - src/local.mk | 1 + - src/ls.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++--- - src/stat.c | 32 +----------- - src/statx.h | 52 ++++++++++++++++++ - 4 files changed, 192 insertions(+), 38 deletions(-) - create mode 100644 src/statx.h - -diff --git a/src/local.mk b/src/local.mk -index a69d405..6075391 100644 ---- a/src/local.mk -+++ b/src/local.mk -@@ -58,6 +58,7 @@ noinst_HEADERS = \ - src/prog-fprintf.h \ - src/remove.h \ - src/set-fields.h \ -+ src/statx.h \ - src/system.h \ - src/uname.h - -diff --git a/src/ls.c b/src/ls.c -index 120ce15..034087f 100644 ---- a/src/ls.c -+++ b/src/ls.c -@@ -114,6 +114,7 @@ - #include "xgethostname.h" - #include "c-ctype.h" - #include "canonicalize.h" -+#include "statx.h" - - /* Include last to avoid a clash of - include guards with some premature versions of libcap. -@@ -1063,6 +1064,136 @@ dired_dump_obstack (const char *prefix, struct obstack *os) - } - } - -+#if HAVE_STATX && defined STATX_INO -+static unsigned int _GL_ATTRIBUTE_PURE -+time_type_to_statx (void) -+{ -+ switch (time_type) -+ { -+ case time_ctime: -+ return STATX_CTIME; -+ case time_mtime: -+ return STATX_MTIME; -+ case time_atime: -+ return STATX_ATIME; -+ default: -+ abort (); -+ } -+ return 0; -+} -+ -+static unsigned int _GL_ATTRIBUTE_PURE -+calc_req_mask (void) -+{ -+ unsigned int mask = STATX_MODE; -+ -+ if (print_inode) -+ mask |= STATX_INO; -+ -+ if (print_block_size) -+ mask |= STATX_BLOCKS; -+ -+ if (format == long_format) { -+ mask |= STATX_NLINK | STATX_SIZE | time_type_to_statx (); -+ if (print_owner || print_author) -+ mask |= STATX_UID; -+ if (print_group) -+ mask |= STATX_GID; -+ } -+ -+ switch (sort_type) -+ { -+ case sort_none: -+ case sort_name: -+ case sort_version: -+ case sort_extension: -+ break; -+ case sort_time: -+ mask |= time_type_to_statx (); -+ break; -+ case sort_size: -+ mask |= STATX_SIZE; -+ break; -+ default: -+ abort (); -+ } -+ -+ return mask; -+} -+ -+static int -+do_statx (int fd, const char *name, struct stat *st, int flags, -+ unsigned int mask) -+{ -+ struct statx stx; -+ int ret = statx (fd, name, flags, mask, &stx); -+ if (ret >= 0) -+ statx_to_stat (&stx, st); -+ return ret; -+} -+ -+static inline int -+do_stat (const char *name, struct stat *st) -+{ -+ return do_statx (AT_FDCWD, name, st, 0, calc_req_mask ()); -+} -+ -+static inline int -+do_lstat (const char *name, struct stat *st) -+{ -+ return do_statx (AT_FDCWD, name, st, AT_SYMLINK_NOFOLLOW, calc_req_mask ()); -+} -+ -+static inline int -+stat_for_mode (const char *name, struct stat *st) -+{ -+ return do_statx (AT_FDCWD, name, st, 0, STATX_MODE); -+} -+ -+/* dev+ino should be static, so no need to sync with backing store */ -+static inline int -+stat_for_ino (const char *name, struct stat *st) -+{ -+ return do_statx (AT_FDCWD, name, st, 0, STATX_INO); -+} -+ -+static inline int -+fstat_for_ino (int fd, struct stat *st) -+{ -+ return do_statx (fd, "", st, AT_EMPTY_PATH, STATX_INO); -+} -+#else -+static inline int -+do_stat (const char *name, struct stat *st) -+{ -+ return stat (name, st); -+} -+ -+static inline int -+do_lstat (const char *name, struct stat *st) -+{ -+ return lstat (name, st); -+} -+ -+static inline int -+stat_for_mode (const char *name, struct stat *st) -+{ -+ return stat (name, st); -+} -+ -+static inline int -+stat_for_ino (const char *name, struct stat *st) -+{ -+ return stat (name, st); -+} -+ -+static inline int -+fstat_for_ino (int fd, struct stat *st) -+{ -+ return fstat (fd, st); -+} -+#endif -+ - /* Return the address of the first plain %b spec in FMT, or NULL if - there is no such spec. %5b etc. do not match, so that user - widths/flags are honored. */ -@@ -2737,10 +2868,10 @@ print_dir (char const *name, char const *realname, bool command_line_arg) - struct stat dir_stat; - int fd = dirfd (dirp); - -- /* If dirfd failed, endure the overhead of using stat. */ -+ /* If dirfd failed, endure the overhead of stat'ing by path */ - if ((0 <= fd -- ? fstat (fd, &dir_stat) -- : stat (name, &dir_stat)) < 0) -+ ? fstat_for_ino (fd, &dir_stat) -+ : stat_for_ino (name, &dir_stat)) < 0) - { - file_failure (command_line_arg, - _("cannot determine device and inode of %s"), name); -@@ -3202,7 +3333,7 @@ gobble_file (char const *name, enum filetype type, ino_t inode, - switch (dereference) - { - case DEREF_ALWAYS: -- err = stat (full_name, &f->stat); -+ err = do_stat (full_name, &f->stat); - do_deref = true; - break; - -@@ -3211,7 +3342,7 @@ gobble_file (char const *name, enum filetype type, ino_t inode, - if (command_line_arg) - { - bool need_lstat; -- err = stat (full_name, &f->stat); -+ err = do_stat (full_name, &f->stat); - do_deref = true; - - if (dereference == DEREF_COMMAND_LINE_ARGUMENTS) -@@ -3231,7 +3362,7 @@ gobble_file (char const *name, enum filetype type, ino_t inode, - FALLTHROUGH; - - default: /* DEREF_NEVER */ -- err = lstat (full_name, &f->stat); -+ err = do_lstat (full_name, &f->stat); - do_deref = false; - break; - } -@@ -3320,7 +3451,7 @@ gobble_file (char const *name, enum filetype type, ino_t inode, - they won't be traced and when no indicator is needed. */ - if (linkname - && (file_type <= indicator_style || check_symlink_mode) -- && stat (linkname, &linkstats) == 0) -+ && stat_for_mode (linkname, &linkstats) == 0) - { - f->linkok = true; - f->linkmode = linkstats.st_mode; -diff --git a/src/stat.c b/src/stat.c -index ee68f16..f2bf0dc 100644 ---- a/src/stat.c -+++ b/src/stat.c -@@ -73,6 +73,7 @@ - #include "strftime.h" - #include "find-mount-point.h" - #include "xvasprintf.h" -+#include "statx.h" - - #if HAVE_STATX && defined STATX_INO - # define USE_STATX 1 -@@ -1245,37 +1246,6 @@ static bool dont_sync; - static bool force_sync; - - #if USE_STATX --/* Much of the format printing requires a struct stat or timespec */ --static struct timespec --statx_timestamp_to_timespec (struct statx_timestamp tsx) --{ -- struct timespec ts; -- -- ts.tv_sec = tsx.tv_sec; -- ts.tv_nsec = tsx.tv_nsec; -- return ts; --} -- --static void --statx_to_stat (struct statx *stx, struct stat *stat) --{ -- stat->st_dev = makedev (stx->stx_dev_major, stx->stx_dev_minor); -- stat->st_ino = stx->stx_ino; -- stat->st_mode = stx->stx_mode; -- stat->st_nlink = stx->stx_nlink; -- stat->st_uid = stx->stx_uid; -- stat->st_gid = stx->stx_gid; -- stat->st_rdev = makedev (stx->stx_rdev_major, stx->stx_rdev_minor); -- stat->st_size = stx->stx_size; -- stat->st_blksize = stx->stx_blksize; --/* define to avoid sc_prohibit_stat_st_blocks. */ --# define SC_ST_BLOCKS st_blocks -- stat->SC_ST_BLOCKS = stx->stx_blocks; -- stat->st_atim = statx_timestamp_to_timespec (stx->stx_atime); -- stat->st_mtim = statx_timestamp_to_timespec (stx->stx_mtime); -- stat->st_ctim = statx_timestamp_to_timespec (stx->stx_ctime); --} -- - static unsigned int - fmt_to_mask (char fmt) - { -diff --git a/src/statx.h b/src/statx.h -new file mode 100644 -index 0000000..19f3e18 ---- /dev/null -+++ b/src/statx.h -@@ -0,0 +1,52 @@ -+/* statx -> stat conversion functions for coreutils -+ Copyright (C) 2019 Free Software Foundation, Inc. -+ -+ This program is free software: you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation, either version 3 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program. If not, see . */ -+ -+#ifndef COREUTILS_STATX_H -+# define COREUTILS_STATX_H -+ -+# if HAVE_STATX && defined STATX_INO -+/* Much of the format printing requires a struct stat or timespec */ -+static inline struct timespec -+statx_timestamp_to_timespec (struct statx_timestamp tsx) -+{ -+ struct timespec ts; -+ -+ ts.tv_sec = tsx.tv_sec; -+ ts.tv_nsec = tsx.tv_nsec; -+ return ts; -+} -+ -+static inline void -+statx_to_stat (struct statx *stx, struct stat *stat) -+{ -+ stat->st_dev = makedev (stx->stx_dev_major, stx->stx_dev_minor); -+ stat->st_ino = stx->stx_ino; -+ stat->st_mode = stx->stx_mode; -+ stat->st_nlink = stx->stx_nlink; -+ stat->st_uid = stx->stx_uid; -+ stat->st_gid = stx->stx_gid; -+ stat->st_rdev = makedev (stx->stx_rdev_major, stx->stx_rdev_minor); -+ stat->st_size = stx->stx_size; -+ stat->st_blksize = stx->stx_blksize; -+/* define to avoid sc_prohibit_stat_st_blocks. */ -+# define SC_ST_BLOCKS st_blocks -+ stat->SC_ST_BLOCKS = stx->stx_blocks; -+ stat->st_atim = statx_timestamp_to_timespec (stx->stx_atime); -+ stat->st_mtim = statx_timestamp_to_timespec (stx->stx_mtime); -+ stat->st_ctim = statx_timestamp_to_timespec (stx->stx_ctime); -+} -+# endif /* HAVE_STATX && defined STATX_INO */ -+#endif /* COREUTILS_STATX_H */ --- -2.20.1 - diff --git a/coreutils.spec b/coreutils.spec index daff9d3..85d5eff 100644 --- a/coreutils.spec +++ b/coreutils.spec @@ -1,7 +1,7 @@ Summary: A set of basic GNU tools commonly used in shell scripts Name: coreutils Version: 8.31 -Release: 5%{?dist} +Release: 6%{?dist} License: GPLv3+ Url: https://www.gnu.org/software/coreutils/ Source0: https://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.xz @@ -16,9 +16,6 @@ Source106: coreutils-colorls.csh # md5sum,b2sum,sha*sum: --help: add note about binary/text mode Patch1: coreutils-8.31-sums-man-pages.patch -# use statx instead of stat when available (#1760300) -Patch2: coreutils-8.31-statx.patch - # disable the test-lock gnulib test prone to deadlock Patch100: coreutils-8.26-test-lock.patch @@ -238,6 +235,9 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir %license COPYING %changelog +* Thu Oct 17 2019 Kamil Dudka - 8.31-6 +- temporarily disable the use of statx (#1760300) + * Fri Oct 11 2019 Kamil Dudka - 8.31-5 - use statx instead of stat when available (#1760300)