Andrew Geissler | 0903674 | 2021-06-25 14:25:14 -0500 | [diff] [blame] | 1 | From 3a48610860a9a75692d2cbedde69ac15269d540a Mon Sep 17 00:00:00 2001 |
| 2 | Message-Id: <3a48610860a9a75692d2cbedde69ac15269d540a.1624302273.git.wallinux@gmail.com> |
| 3 | From: Paul Eggert <eggert@cs.ucla.edu> |
| 4 | Date: Wed, 15 Apr 2020 20:50:32 -0700 |
| 5 | Subject: [PATCH] fts: remove NOSTAT_LEAF_OPTIMIZATION |
| 6 | MIME-Version: 1.0 |
| 7 | Content-Type: text/plain; charset=UTF-8 |
| 8 | Content-Transfer-Encoding: 8bit |
| 9 | |
| 10 | It caused ‘find’ and ‘du’ to dump core, and it was useful |
| 11 | only for obsolescent Linux filesystems anyway. Problem reported in: |
| 12 | https://lists.gnu.org/r/bug-gnulib/2020-04/msg00068.html |
| 13 | Quite possibly there is still a serious underlying fts bug with |
| 14 | tight-loop-check and mutating file systems, but if so this patch |
| 15 | should cause the bug to be triggered less often. |
| 16 | * lib/fts.c (enum leaf_optimization): Remove |
| 17 | NOSTAT_LEAF_OPTIMIZATION, as it’s problematic. |
| 18 | (S_MAGIC_REISERFS, S_MAGIC_XFS): Remove; no longer needed. |
| 19 | (leaf_optimization): Remove special cases for ReiserFS and XFS. |
| 20 | (fts_read): Remove NOSTAT_LEAF_OPTIMIZATION code. |
| 21 | * lib/fts_.h (struct _ftsent.fts_n_dirs_remaining): |
| 22 | Remove. All uses removed. |
| 23 | |
| 24 | Upstream-Status: Backport [upstream gnulib commit: |
| 25 | 47bf2cf3184027c1eb9c1dfeea5c5b8b2d69710d] |
| 26 | |
| 27 | Signed-off-by: Anders Wallin <wallinux@gmail.com> |
| 28 | --- |
| 29 | lib/fts.c | 56 ++++++++---------------------------------------------- |
| 30 | lib/fts_.h | 5 ----- |
| 31 | 2 files changed, 8 insertions(+), 53 deletions(-) |
| 32 | |
| 33 | diff --git a/lib/fts.c b/lib/fts.c |
| 34 | index d3a0472..ade8c33 100644 |
| 35 | --- a/lib/fts.c |
| 36 | +++ b/lib/fts.c |
| 37 | @@ -445,7 +445,6 @@ fts_open (char * const *argv, |
| 38 | if ((parent = fts_alloc(sp, "", 0)) == NULL) |
| 39 | goto mem2; |
| 40 | parent->fts_level = FTS_ROOTPARENTLEVEL; |
| 41 | - parent->fts_n_dirs_remaining = -1; |
| 42 | } |
| 43 | |
| 44 | /* The classic fts implementation would call fts_stat with |
| 45 | @@ -634,9 +633,8 @@ fts_close (FTS *sp) |
| 46 | } |
| 47 | |
| 48 | /* Minimum link count of a traditional Unix directory. When leaf |
| 49 | - optimization is OK and MIN_DIR_NLINK <= st_nlink, then st_nlink is |
| 50 | - an upper bound on the number of subdirectories (counting "." and |
| 51 | - ".."). */ |
| 52 | + optimization is OK and a directory's st_nlink == MIN_DIR_NLINK, |
| 53 | + then the directory has no subdirectories. */ |
| 54 | enum { MIN_DIR_NLINK = 2 }; |
| 55 | |
| 56 | /* Whether leaf optimization is OK for a directory. */ |
| 57 | @@ -645,12 +643,8 @@ enum leaf_optimization |
| 58 | /* st_nlink is not reliable for this directory's subdirectories. */ |
| 59 | NO_LEAF_OPTIMIZATION, |
| 60 | |
| 61 | - /* Leaf optimization is OK, but is not useful for avoiding stat calls. */ |
| 62 | - OK_LEAF_OPTIMIZATION, |
| 63 | - |
| 64 | - /* Leaf optimization is not only OK: it is useful for avoiding |
| 65 | - stat calls, because dirent.d_type does not work. */ |
| 66 | - NOSTAT_LEAF_OPTIMIZATION |
| 67 | + /* st_nlink == 2 means the directory lacks subdirectories. */ |
| 68 | + OK_LEAF_OPTIMIZATION |
| 69 | }; |
| 70 | |
| 71 | #if (defined __linux__ || defined __ANDROID__) \ |
| 72 | @@ -663,9 +657,7 @@ enum leaf_optimization |
| 73 | # define S_MAGIC_CIFS 0xFF534D42 |
| 74 | # define S_MAGIC_NFS 0x6969 |
| 75 | # define S_MAGIC_PROC 0x9FA0 |
| 76 | -# define S_MAGIC_REISERFS 0x52654973 |
| 77 | # define S_MAGIC_TMPFS 0x1021994 |
| 78 | -# define S_MAGIC_XFS 0x58465342 |
| 79 | |
| 80 | # ifdef HAVE___FSWORD_T |
| 81 | typedef __fsword_t fsword; |
| 82 | @@ -782,23 +774,15 @@ dirent_inode_sort_may_be_useful (FTSENT const *p, int dir_fd) |
| 83 | } |
| 84 | |
| 85 | /* Given an FTS entry P for a directory with descriptor DIR_FD, |
| 86 | - return true if it is both useful and valid to apply leaf optimization. |
| 87 | - The optimization is useful only for file systems that lack usable |
| 88 | - dirent.d_type info. The optimization is valid if an st_nlink value |
| 89 | - of at least MIN_DIR_NLINK is an upper bound on the number of |
| 90 | - subdirectories of D, counting "." and ".." as subdirectories. |
| 91 | + return whether it is valid to apply leaf optimization. |
| 92 | + The optimization is valid if a directory's st_nlink value equal |
| 93 | + to MIN_DIR_NLINK means the directory has no subdirectories. |
| 94 | DIR_FD is negative if unavailable. */ |
| 95 | static enum leaf_optimization |
| 96 | leaf_optimization (FTSENT const *p, int dir_fd) |
| 97 | { |
| 98 | switch (filesystem_type (p, dir_fd)) |
| 99 | { |
| 100 | - /* List here the file system types that may lack usable dirent.d_type |
| 101 | - info, yet for which the optimization does apply. */ |
| 102 | - case S_MAGIC_REISERFS: |
| 103 | - case S_MAGIC_XFS: /* XFS lacked it until 2013-08-22 commit. */ |
| 104 | - return NOSTAT_LEAF_OPTIMIZATION; |
| 105 | - |
| 106 | case 0: |
| 107 | /* Leaf optimization is unsafe if the file system type is unknown. */ |
| 108 | FALLTHROUGH; |
| 109 | @@ -1023,26 +1007,7 @@ check_for_dir: |
| 110 | if (p->fts_info == FTS_NSOK) |
| 111 | { |
| 112 | if (p->fts_statp->st_size == FTS_STAT_REQUIRED) |
| 113 | - { |
| 114 | - FTSENT *parent = p->fts_parent; |
| 115 | - if (parent->fts_n_dirs_remaining == 0 |
| 116 | - && ISSET(FTS_NOSTAT) |
| 117 | - && ISSET(FTS_PHYSICAL) |
| 118 | - && (leaf_optimization (parent, sp->fts_cwd_fd) |
| 119 | - == NOSTAT_LEAF_OPTIMIZATION)) |
| 120 | - { |
| 121 | - /* nothing more needed */ |
| 122 | - } |
| 123 | - else |
| 124 | - { |
| 125 | - p->fts_info = fts_stat(sp, p, false); |
| 126 | - if (S_ISDIR(p->fts_statp->st_mode) |
| 127 | - && p->fts_level != FTS_ROOTLEVEL |
| 128 | - && 0 < parent->fts_n_dirs_remaining |
| 129 | - && parent->fts_n_dirs_remaining != (nlink_t) -1) |
| 130 | - parent->fts_n_dirs_remaining--; |
| 131 | - } |
| 132 | - } |
| 133 | + p->fts_info = fts_stat(sp, p, false); |
| 134 | else |
| 135 | fts_assert (p->fts_statp->st_size == FTS_NO_STAT_REQUIRED); |
| 136 | } |
| 137 | @@ -1826,11 +1791,6 @@ err: memset(sbp, 0, sizeof(struct stat)); |
| 138 | } |
| 139 | |
| 140 | if (S_ISDIR(sbp->st_mode)) { |
| 141 | - p->fts_n_dirs_remaining |
| 142 | - = ((sbp->st_nlink < MIN_DIR_NLINK |
| 143 | - || p->fts_level <= FTS_ROOTLEVEL) |
| 144 | - ? -1 |
| 145 | - : sbp->st_nlink - (ISSET (FTS_SEEDOT) ? 0 : MIN_DIR_NLINK)); |
| 146 | if (ISDOT(p->fts_name)) { |
| 147 | /* Command-line "." and ".." are real directories. */ |
| 148 | return (p->fts_level == FTS_ROOTLEVEL ? FTS_D : FTS_DOT); |
| 149 | diff --git a/lib/fts_.h b/lib/fts_.h |
| 150 | index 6c7d0ce..15c248c 100644 |
| 151 | --- a/lib/fts_.h |
| 152 | +++ b/lib/fts_.h |
| 153 | @@ -219,11 +219,6 @@ typedef struct _ftsent { |
| 154 | |
| 155 | size_t fts_namelen; /* strlen(fts_name) */ |
| 156 | |
| 157 | - /* If not (nlink_t) -1, an upper bound on the number of |
| 158 | - remaining subdirectories of interest. If this becomes |
| 159 | - zero, some work can be avoided. */ |
| 160 | - nlink_t fts_n_dirs_remaining; |
| 161 | - |
| 162 | # define FTS_D 1 /* preorder directory */ |
| 163 | # define FTS_DC 2 /* directory that causes cycles */ |
| 164 | # define FTS_DEFAULT 3 /* none of the above */ |
| 165 | -- |
| 166 | 2.32.0 |
| 167 | |