2017-07-24 Paul Eggert <eggert@cs.ucla.edu>
+ fts: three levels of leaf optimization
+ * lib/fts.c (enum leaf_optimization): New type with three values.
+ (S_MAGIC_AFS): New macro. Sort them.
+ (leaf_optimization): Rename from leaf_optimization_applies, and
+ return enum leaf_optimization instead of bool. All uses changed.
+ Add cases for unknown type and for AFS.
+ (fts_build): Don’t rely on link counts if NO_LEAF_OPTIMIZATION.
+
fts: cache dirent_inode_sort_may_be_useful too
* lib/fts.c (struct dev_type): New struct.
(DEV_TYPE_HT_INITIAL_SIZE): New constant.
".."). */
enum { MIN_DIR_NLINK = 2 };
+/* Whether leaf optimization is OK for a directory. */
+enum leaf_optimization
+ {
+ /* st_nlink is not reliable for this directory's subdirectories. */
+ NO_LEAF_OPTIMIZATION,
+
+ /* Leaf optimization is OK, but is not useful for avoiding stat calls. */
+ OK_LEAF_OPTIMIZATION,
+
+ /* Leaf optimization is not only OK: it is useful for avoiding
+ stat calls, because dirent.d_type does not work. */
+ NOSTAT_LEAF_OPTIMIZATION
+ };
+
#if defined __linux__ \
&& HAVE_SYS_VFS_H && HAVE_FSTATFS && HAVE_STRUCT_STATFS_F_TYPE
# include <sys/vfs.h>
/* Linux-specific constants from coreutils' src/fs.h */
-# define S_MAGIC_TMPFS 0x1021994
+# define S_MAGIC_AFS 0x5346414F
# define S_MAGIC_NFS 0x6969
+# define S_MAGIC_PROC 0x9FA0
# define S_MAGIC_REISERFS 0x52654973
+# define S_MAGIC_TMPFS 0x1021994
# define S_MAGIC_XFS 0x58465342
-# define S_MAGIC_PROC 0x9FA0
/* Map a stat.st_dev number to a file system type number f_ftype. */
struct dev_type
dirent.d_type info. The optimization is valid if an st_nlink value
of at least MIN_DIR_NLINK is an upper bound on the number of
subdirectories of D, counting "." and ".." as subdirectories. */
-static bool
-leaf_optimization_applies (FTSENT const *p)
+static enum leaf_optimization
+leaf_optimization (FTSENT const *p)
{
- /* FIXME: do we need to detect AFS mount points? I doubt it,
- unless fstatfs can report S_MAGIC_REISERFS for such a directory. */
-
switch (filesystem_type (p))
{
/* List here the file system types that lack usable dirent.d_type
info, yet for which the optimization does apply. */
case S_MAGIC_REISERFS:
case S_MAGIC_XFS:
- return true;
+ return NOSTAT_LEAF_OPTIMIZATION;
- /* Explicitly list here any other file system type for which the
- optimization is not applicable, but need documentation. */
+ case 0:
+ /* Leaf optimization is unsafe if the file system type is unknown. */
+ FALLTHROUGH;
+ case S_MAGIC_AFS:
+ /* Although AFS mount points are not counted in st_nlink, they
+ act like directories. See <https://bugs.debian.org/143111>. */
+ FALLTHROUGH;
case S_MAGIC_NFS:
/* NFS provides usable dirent.d_type but not necessarily for all entries
of large directories, so as per <https://bugzilla.redhat.com/1252549>
case S_MAGIC_PROC:
/* Per <http://bugs.debian.org/143111> /proc may have
bogus stat.st_nlink values. */
- FALLTHROUGH;
+ return NO_LEAF_OPTIMIZATION;
+
default:
- return false;
+ return OK_LEAF_OPTIMIZATION;
}
}
{
return true;
}
-static bool
-leaf_optimization_applies (FTSENT const *p _GL_UNUSED)
+static enum leaf_optimization
+leaf_optimization (FTSENT const *p _GL_UNUSED)
{
- return false;
+ return NO_LEAF_OPTIMIZATION;
}
#endif
if (parent->fts_n_dirs_remaining == 0
&& ISSET(FTS_NOSTAT)
&& ISSET(FTS_PHYSICAL)
- && leaf_optimization_applies (parent))
+ && (leaf_optimization (parent)
+ == NOSTAT_LEAF_OPTIMIZATION))
{
/* nothing more needed */
}
nlinks = 0;
/* Be quiet about nostat, GCC. */
nostat = false;
- } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
+ } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)
+ && leaf_optimization (cur) != NO_LEAF_OPTIMIZATION) {
nlinks = (cur->fts_statp->st_nlink
- (ISSET (FTS_SEEDOT) ? 0 : MIN_DIR_NLINK));
nostat = true;