summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Meyering <meyering@redhat.com>2012-02-11 12:36:57 +0100
committerJim Meyering <meyering@redhat.com>2012-02-18 10:26:10 +0100
commit9f237a03c039eb9d71a16e93119dc1fc56152dd6 (patch)
tree6b7f2ebf983cbd35781290f222b95b07244eeafd
parentd55d3dd5886c146547482c9f45ac653c1ebe9237 (diff)
downloadcoreutils-9f237a03c039eb9d71a16e93119dc1fc56152dd6.tar.xz
ls: optimize for when getfilecon would often fail (~33% perf. gain)
On systems or file systems without SELinux support, all getfilecon and lgetfilecon calls would fail due to lack of support. We can non- invasively cache such failure (on most recently accessed device) and avoid the vast majority of the failing underlying getxattr syscalls. * src/ls.c (errno_unsupported): New function. (selinux_challenged_device): New file-scoped global. (getfilecon_cache, lgetfilecon_cache): New error-caching wrapper functions. (gobble_file): Use the caching wrappers, for when many *getfilecon calls would fail with ENOTSUP or EOPNOTSUPP. Suggested by Sven Breuner in http://thread.gmane.org/gmane.comp.gnu.coreutils.general/2187 Improved-by: Pádraig Brady.
-rw-r--r--src/ls.c36
1 files changed, 32 insertions, 4 deletions
diff --git a/src/ls.c b/src/ls.c
index f5cd37a2d..8a9cb4180 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -2777,10 +2777,40 @@ clear_files (void)
file_size_width = 0;
}
+/* Return true if ERR implies lack-of-support failure by a
+ getxattr-calling function like getfilecon. */
+static bool
+errno_unsupported (int err)
+{
+ return err == ENOTSUP || err == EOPNOTSUPP;
+}
+
+/* Cache *getfilecon failure, when it's trivial to do so.
+ Like getfilecon/lgetfilecon, but when F's st_dev says it's on a known-
+ SELinux-challenged file system, fail with ENOTSUP immediately. */
+static int
+getfilecon_cache (char const *file, struct fileinfo *f, bool deref)
+{
+ /* st_dev of the most recently processed device for which we've
+ found that [l]getfilecon fails indicating lack of support. */
+ static dev_t unsupported_device;
+
+ if (f->stat.st_dev == unsupported_device)
+ {
+ errno = ENOTSUP;
+ return -1;
+ }
+ int r = (deref
+ ? getfilecon (file, &f->scontext)
+ : lgetfilecon (file, &f->scontext));
+ if (r < 0 && errno_unsupported (errno))
+ unsupported_device = f->stat.st_dev;
+ return r;
+}
+
/* 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. */
-
static uintmax_t
gobble_file (char const *name, enum filetype type, ino_t inode,
bool command_line_arg, char const *dirname)
@@ -2918,9 +2948,7 @@ gobble_file (char const *name, enum filetype type, ino_t inode,
{
bool have_selinux = false;
bool have_acl = false;
- int attr_len = (do_deref
- ? getfilecon (absolute_name, &f->scontext)
- : lgetfilecon (absolute_name, &f->scontext));
+ int attr_len = getfilecon_cache (absolute_name, f, do_deref);
err = (attr_len < 0);
if (err == 0)