Resolves: #1558249 - fix crash caused by mistakenly enabled leaf optimization

This commit is contained in:
Kamil Dudka 2018-04-20 16:52:25 +02:00
parent 99e4b132c2
commit f41447a0f4
2 changed files with 239 additions and 7 deletions

View File

@ -1,7 +1,7 @@
From f3337786e55909538aacfd7c29b1cf58ff444fbf Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Mon, 12 Feb 2018 12:45:36 +0100
Subject: [PATCH 1/2] import gnulib's FTS module from upstream commit 281b825e
Subject: [PATCH 1/4] import gnulib's FTS module from upstream commit 281b825e
---
gl/lib/fts.c | 424 +++++++++++++++++++++++++++++-----------------------------
@ -474,10 +474,11 @@ index c91d7a1..bfa73e3 100644
size_t len, maxlen, new_len;
char *cp;
int dir_fd;
@@ -1370,24 +1394,6 @@ fts_build (register FTS *sp, int type)
@@ -1369,24 +1393,6 @@ fts_build (register FTS *sp, int type)
sorting, yet not so large that we risk exhausting memory. */
max_entries = sp->fts_compar ? SIZE_MAX : FTS_MAX_READDIR_ENTRIES;
/*
- /*
- * Nlinks is the number of possible entries of type directory in the
- * directory if we're cheating on stat calls, 0 if we're not doing
- * any stat calls at all, (nlink_t) -1 if we're statting everything.
@ -495,10 +496,9 @@ index c91d7a1..bfa73e3 100644
- nostat = false;
- }
-
- /*
/*
* If we're going to need to stat anything or we want to descend
* and stay in the directory, chdir. If this fails we keep going,
* but set a flag so we don't chdir after the post-order visit.
@@ -1408,15 +1414,22 @@ fts_build (register FTS *sp, int type)
the required dirp and dir_fd. */
descend = true;
@ -718,7 +718,7 @@ index b9a3f12..70cc9e3 100644
From ea88dd373c60feab541fe037369805f326dc3494 Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Mon, 12 Feb 2018 18:58:30 +0100
Subject: [PATCH 2/2] fts: remove dependency on gnulib's fleximember.h
Subject: [PATCH 2/4] fts: remove dependency on gnulib's fleximember.h
... by reverting upstream commit edb9d82948cb23f67a19e1b435047a0570225df3
---
@ -759,3 +759,232 @@ index bfa73e3..c37ebe2 100644
--
2.13.6
From 9c1720c99bbf8998dfdaa5976bca8bdc6d93f8e7 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Thu, 5 Apr 2018 08:48:01 -0700
Subject: [PATCH 3/4] fts: treat CIFS like NFS
Problem reported by Kamil Dudka in:
https://lists.gnu.org/r/bug-gnulib/2018-04/msg00015.html
* lib/fts.c (S_MAGIC_CIFS): New macro.
(dirent_inode_sort_may_be_useful, leaf_optimization):
Treat CIFS like NFS.
Upstream-commit: 2e53df541a30d438859087ed4b5a396e04697b9b
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
gl/lib/fts.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/gl/lib/fts.c b/gl/lib/fts.c
index c37ebe2..508ceac 100644
--- a/gl/lib/fts.c
+++ b/gl/lib/fts.c
@@ -684,6 +684,7 @@ enum leaf_optimization
/* Linux-specific constants from coreutils' src/fs.h */
# define S_MAGIC_AFS 0x5346414F
+# define S_MAGIC_CIFS 0xFF534D42
# define S_MAGIC_NFS 0x6969
# define S_MAGIC_PROC 0x9FA0
# define S_MAGIC_REISERFS 0x52654973
@@ -791,8 +792,9 @@ dirent_inode_sort_may_be_useful (FTSENT const *p)
switch (filesystem_type (p))
{
- case S_MAGIC_TMPFS:
+ case S_MAGIC_CIFS:
case S_MAGIC_NFS:
+ case S_MAGIC_TMPFS:
/* On a file system of any of these types, sorting
is unnecessary, and hence wasteful. */
return false;
@@ -826,6 +828,10 @@ leaf_optimization (FTSENT const *p)
/* Although AFS mount points are not counted in st_nlink, they
act like directories. See <https://bugs.debian.org/143111>. */
FALLTHROUGH;
+ case S_MAGIC_CIFS:
+ /* Leaf optimization causes 'find' to abort. See
+ <https://lists.gnu.org/r/bug-gnulib/2018-04/msg00015.html>. */
+ 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>
--
2.14.3
From ff64329a046e76ba553c15373ed61bbed814d286 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Wed, 11 Apr 2018 12:50:35 -0700
Subject: [PATCH 4/4] fts: fix bug in find across filesystems
This fixes a bug I introduced last summer.
Problem reported by Kamil Dudka in:
https://lists.gnu.org/r/bug-gnulib/2018-04/msg00033.html
* lib/fts.c (filesystem_type, dirent_inode_sort_may_be_useful)
(leaf_optimization):
New arg for file descriptor. All callers changed.
(fts_build): Check for whether inodes should be sorted
before closing the directory.
Upstream-commit: 81b8c0d3be98f5a77403599de3d06329b3e7673e
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
gl/lib/fts.c | 55 +++++++++++++++++++++++++++++++------------------------
1 file changed, 31 insertions(+), 24 deletions(-)
diff --git a/gl/lib/fts.c b/gl/lib/fts.c
index 508ceac..175f12a 100644
--- a/gl/lib/fts.c
+++ b/gl/lib/fts.c
@@ -725,11 +725,12 @@ dev_type_compare (void const *x, void const *y)
return ax->st_dev == ay->st_dev;
}
-/* Return the file system type of P, or 0 if not known.
+/* Return the file system type of P with file descriptor FD, or 0 if not known.
+ If FD is negative, P's file descriptor is unavailable.
Try to cache known values. */
static fsword
-filesystem_type (FTSENT const *p)
+filesystem_type (FTSENT const *p, int fd)
{
FTS *sp = p->fts_fts;
Hash_table *h = sp->fts_leaf_optimization_works_ht;
@@ -755,7 +756,7 @@ filesystem_type (FTSENT const *p)
}
/* Look-up failed. Query directly and cache the result. */
- if (fstatfs (p->fts_fts->fts_cwd_fd, &fs_buf) != 0)
+ if (fd < 0 || fstatfs (fd, &fs_buf) != 0)
return 0;
if (h)
@@ -777,12 +778,12 @@ filesystem_type (FTSENT const *p)
return fs_buf.f_type;
}
-/* Return false if it is easy to determine the file system type of the
- directory P, and sorting dirents on inode numbers is known not to
- improve traversal performance with that type of file system.
- Otherwise, return true. */
+/* Return true if sorting dirents on inode numbers is known to improve
+ traversal performance for the directory P with descriptor DIR_FD.
+ Return false otherwise. When in doubt, return true.
+ DIR_FD is negative if unavailable. */
static bool
-dirent_inode_sort_may_be_useful (FTSENT const *p)
+dirent_inode_sort_may_be_useful (FTSENT const *p, int dir_fd)
{
/* Skip the sort only if we can determine efficiently
that skipping it is the right thing to do.
@@ -790,7 +791,7 @@ dirent_inode_sort_may_be_useful (FTSENT const *p)
while the cost of *not* performing it can be O(N^2) with
a very large constant. */
- switch (filesystem_type (p))
+ switch (filesystem_type (p, dir_fd))
{
case S_MAGIC_CIFS:
case S_MAGIC_NFS:
@@ -804,16 +805,17 @@ dirent_inode_sort_may_be_useful (FTSENT const *p)
}
}
-/* Given an FTS entry P for a directory D,
+/* Given an FTS entry P for a directory with descriptor DIR_FD,
return true if it is both useful and valid to apply leaf optimization.
The optimization is useful only for file systems that lack usable
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. */
+ subdirectories of D, counting "." and ".." as subdirectories.
+ DIR_FD is negative if unavailable. */
static enum leaf_optimization
-leaf_optimization (FTSENT const *p)
+leaf_optimization (FTSENT const *p, int dir_fd)
{
- switch (filesystem_type (p))
+ switch (filesystem_type (p, dir_fd))
{
/* List here the file system types that may lack usable dirent.d_type
info, yet for which the optimization does apply. */
@@ -850,12 +852,13 @@ leaf_optimization (FTSENT const *p)
#else
static bool
-dirent_inode_sort_may_be_useful (FTSENT const *p _GL_UNUSED)
+dirent_inode_sort_may_be_useful (FTSENT const *p _GL_UNUSED,
+ int dir_fd _GL_UNUSED)
{
return true;
}
static enum leaf_optimization
-leaf_optimization (FTSENT const *p _GL_UNUSED)
+leaf_optimization (FTSENT const *p _GL_UNUSED, int dir_fd _GL_UNUSED)
{
return NO_LEAF_OPTIMIZATION;
}
@@ -1049,7 +1052,7 @@ check_for_dir:
if (parent->fts_n_dirs_remaining == 0
&& ISSET(FTS_NOSTAT)
&& ISSET(FTS_PHYSICAL)
- && (leaf_optimization (parent)
+ && (leaf_optimization (parent, sp->fts_cwd_fd)
== NOSTAT_LEAF_OPTIMIZATION))
{
/* nothing more needed */
@@ -1334,6 +1337,7 @@ fts_build (register FTS *sp, int type)
int dir_fd;
FTSENT *cur = sp->fts_cur;
bool continue_readdir = !!cur->fts_dirp;
+ bool sort_by_inode = false;
size_t max_entries;
/* When cur->fts_dirp is non-NULL, that means we should
@@ -1427,7 +1431,7 @@ fts_build (register FTS *sp, int type)
&& ! (ISSET (FTS_NOSTAT) && ISSET (FTS_PHYSICAL)
&& ! ISSET (FTS_SEEDOT)
&& cur->fts_statp->st_nlink == MIN_DIR_NLINK
- && (leaf_optimization (cur)
+ && (leaf_optimization (cur, dir_fd)
!= NO_LEAF_OPTIMIZATION)));
if (descend || type == BREAD)
{
@@ -1588,6 +1592,15 @@ mem1: saved_errno = errno;
tail->fts_link = p;
tail = p;
}
+
+ /* If there are many entries, no sorting function has been
+ specified, and this file system is of a type that may be
+ slow with a large number of entries, arrange to sort the
+ directory entries on increasing inode numbers. */
+ if (nitems == _FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD
+ && !sp->fts_compar)
+ sort_by_inode = dirent_inode_sort_may_be_useful (cur, dir_fd);
+
++nitems;
if (max_entries <= nitems) {
/* When there are too many dir entries, leave
@@ -1645,13 +1658,7 @@ mem1: saved_errno = errno;
return (NULL);
}
- /* If there are many entries, no sorting function has been specified,
- and this file system is of a type that may be slow with a large
- number of entries, then sort the directory entries on increasing
- inode numbers. */
- if (nitems > _FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD
- && !sp->fts_compar
- && dirent_inode_sort_may_be_useful (cur)) {
+ if (sort_by_inode) {
sp->fts_compar = fts_compare_ino;
head = fts_sort (sp, head, nitems);
sp->fts_compar = NULL;
--
2.14.3

View File

@ -1,7 +1,7 @@
Summary: The GNU versions of find utilities (find and xargs)
Name: findutils
Version: 4.6.0
Release: 18%{?dist}
Release: 19%{?dist}
Epoch: 1
License: GPLv3+
Group: Applications/File
@ -147,6 +147,9 @@ fi
%{_infodir}/find-maint.info.gz
%changelog
* Fri Apr 20 2018 Kamil Dudka <kdudka@redhat.com> - 1:4.6.0-19
- fix crash caused by mistakenly enabled leaf optimization (#1558249)
* Tue Mar 06 2018 Kamil Dudka <kdudka@redhat.com> - 1:4.6.0-18
- fix build failure with glibc-2.28