summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJim Meyering <meyering@redhat.com>2012-02-13 12:05:40 +0100
committerJim Meyering <meyering@redhat.com>2012-02-18 10:26:10 +0100
commit8ca2b9659d4fae1d968b8bd4e00fcee7d9d75356 (patch)
tree82ce84f87ffee64ccc196b91da4f5080b375d7a5 /src
parent9f237a03c039eb9d71a16e93119dc1fc56152dd6 (diff)
downloadcoreutils-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.c61
1 files changed, 57 insertions, 4 deletions
diff --git a/src/ls.c b/src/ls.c
index 8a9cb4180..92b17a4b4 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -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);
}