diff options
author | Jim Meyering <meyering@redhat.com> | 2012-02-13 12:05:40 +0100 |
---|---|---|
committer | Jim Meyering <meyering@redhat.com> | 2012-02-18 10:26:10 +0100 |
commit | 8ca2b9659d4fae1d968b8bd4e00fcee7d9d75356 (patch) | |
tree | 82ce84f87ffee64ccc196b91da4f5080b375d7a5 /src | |
parent | 9f237a03c039eb9d71a16e93119dc1fc56152dd6 (diff) | |
download | coreutils-8ca2b9659d4fae1d968b8bd4e00fcee7d9d75356.tar.xz |
ls: cache ACL- and CAP-querying syscall failures
Like the optimization to avoid always-failing getfilecon calls,
this change avoids always-failing queries for whether a file has
a nontrivial ACL and for whether a file has certain "capabilities".
When such a query fails for one file (indicating no support), we know it
will always fail that way for the affected device. With this change, we
have thus eliminated nearly all failing-unsupported getxattr syscalls.
* src/ls.c (has_capability) [!HAVE_CAP]: Set errno to ENOTSUP.
(errno_unsupported): Expand the list of E* errno values to match
that of lib/acl-internal.h's ACL_NOT_WELL_SUPPORTED macro.
(file_has_acl_cache, has_capability_cache): New functions.
(gobble_file): Use them in place of non-caching ones.
* NEWS (Improvements): Mention it.
Suggested by Sven Breuner in
http://thread.gmane.org/gmane.comp.gnu.coreutils.general/2187
While eliminating most getfilecon calls saved about 33%,
eliminating these other calls can save almost all of the
remaining ~67% cost, on some remote file systems.
Diffstat (limited to 'src')
-rw-r--r-- | src/ls.c | 61 |
1 files changed, 57 insertions, 4 deletions
@@ -2736,6 +2736,7 @@ has_capability (char const *name) static bool has_capability (char const *name ATTRIBUTE_UNUSED) { + errno = ENOTSUP; return false; } #endif @@ -2778,11 +2779,16 @@ clear_files (void) } /* Return true if ERR implies lack-of-support failure by a - getxattr-calling function like getfilecon. */ + getxattr-calling function like getfilecon or file_has_acl. */ static bool errno_unsupported (int err) { - return err == ENOTSUP || err == EOPNOTSUPP; + return (err == EBUSY + || err == EINVAL + || err == ENOENT + || err == ENOSYS + || err == ENOTSUP + || err == EOPNOTSUPP); } /* Cache *getfilecon failure, when it's trivial to do so. @@ -2808,6 +2814,53 @@ getfilecon_cache (char const *file, struct fileinfo *f, bool deref) return r; } +/* Cache file_has_acl failure, when it's trivial to do. + Like file_has_acl, but when F's st_dev says it's on a file + system lacking ACL support, return 0 with ENOTSUP immediately. */ +static int +file_has_acl_cache (char const *file, struct fileinfo *f) +{ + /* st_dev of the most recently processed device for which we've + found that file_has_acl fails indicating lack of support. */ + static dev_t unsupported_device; + + if (f->stat.st_dev == unsupported_device) + { + errno = ENOTSUP; + return 0; + } + + /* Zero errno so that we can distinguish between two 0-returning cases: + "has-ACL-support, but only a default ACL" and "no ACL support". */ + errno = 0; + int n = file_has_acl (file, &f->stat); + if (n <= 0 && errno_unsupported (errno)) + unsupported_device = f->stat.st_dev; + return n; +} + +/* Cache has_capability failure, when it's trivial to do. + Like has_capability, but when F's st_dev says it's on a file + system lacking capability support, return 0 with ENOTSUP immediately. */ +static bool +has_capability_cache (char const *file, struct fileinfo *f) +{ + /* st_dev of the most recently processed device for which we've + found that has_capability fails indicating lack of support. */ + static dev_t unsupported_device; + + if (f->stat.st_dev == unsupported_device) + { + errno = ENOTSUP; + return 0; + } + + bool b = has_capability (file); + if ( !b && errno_unsupported (errno)) + unsupported_device = f->stat.st_dev; + return b; +} + /* Add a file to the current table of files. Verify that the file exists, and print an error message if it does not. Return the number of blocks that the file occupies. */ @@ -2942,7 +2995,7 @@ gobble_file (char const *name, enum filetype type, ino_t inode, /* Note has_capability() adds around 30% runtime to 'ls --color' */ if ((type == normal || S_ISREG (f->stat.st_mode)) && print_with_color && is_colored (C_CAP)) - f->has_capability = has_capability (absolute_name); + f->has_capability = has_capability_cache (absolute_name, f); if (format == long_format || print_scontext) { @@ -2967,7 +3020,7 @@ gobble_file (char const *name, enum filetype type, ino_t inode, if (err == 0 && format == long_format) { - int n = file_has_acl (absolute_name, &f->stat); + int n = file_has_acl_cache (absolute_name, f); err = (n < 0); have_acl = (0 < n); } |