|
|
dd59ef |
From dc1c0523a61932fb0c26a795b7e7391eadf2171a Mon Sep 17 00:00:00 2001
|
|
|
dd59ef |
From: Boris Ranto <branto@redhat.com>
|
|
|
dd59ef |
Date: Mon, 1 Dec 2014 09:24:14 +0100
|
|
|
dd59ef |
Subject: [PATCH 1/1] du: handle sub-bind-mount cycles gracefully
|
|
|
dd59ef |
|
|
|
dd59ef |
This patch fixes the handling of sub-bind-mount cycles which are
|
|
|
dd59ef |
incorrectly detected as the file system errors. If you bind mount the
|
|
|
dd59ef |
directory 'a' to its subdirectory 'a/b/c' and then run 'du a/b' you
|
|
|
dd59ef |
will get the circular dependency warning even though nothing is wrong
|
|
|
dd59ef |
with the file system. This happens because the first directory that is
|
|
|
dd59ef |
traversed twice in this case is not a bind mount but a child of bind
|
|
|
dd59ef |
mount. The solution is to traverse all the directories in the cycle
|
|
|
dd59ef |
that fts detected and check whether they are not a (bind) mount.
|
|
|
dd59ef |
|
|
|
dd59ef |
* src/du.c (mount_point_in_fts_cycle): New function that checks whether
|
|
|
dd59ef |
any of the directories in the cycle that fts detected is a mount point.
|
|
|
dd59ef |
* src/du.c (process_file): Update the function to use the new function
|
|
|
dd59ef |
that looks up all the directories in the fts cycle instead of only the
|
|
|
dd59ef |
last one.
|
|
|
dd59ef |
* tests/du/bind-mount-dir-cycle-v2.sh: New test case that exhibits the
|
|
|
dd59ef |
described behavior.
|
|
|
dd59ef |
* tests/local.mk: Reference the new root test.
|
|
|
dd59ef |
---
|
|
|
dd59ef |
src/du.c | 23 ++++++++++++++++++++-
|
|
|
dd59ef |
tests/du/bind-mount-dir-cycle-v2.sh | 38 +++++++++++++++++++++++++++++++++++
|
|
|
dd59ef |
tests/local.mk | 1 +
|
|
|
dd59ef |
3 files changed, 61 insertions(+), 1 deletions(-)
|
|
|
dd59ef |
create mode 100755 tests/du/bind-mount-dir-cycle-v2.sh
|
|
|
dd59ef |
|
|
|
dd59ef |
diff --git a/src/du.c b/src/du.c
|
|
|
dd59ef |
index ba20120..f5726c7 100644
|
|
|
dd59ef |
--- a/src/du.c
|
|
|
dd59ef |
+++ b/src/du.c
|
|
|
dd59ef |
@@ -419,6 +419,27 @@ print_size (const struct duinfo *pdui, const char *string)
|
|
|
dd59ef |
fflush (stdout);
|
|
|
dd59ef |
}
|
|
|
dd59ef |
|
|
|
dd59ef |
+/* This function checks whether any of the directories in the cycle that
|
|
|
dd59ef |
+ fts detected is a mount point. */
|
|
|
dd59ef |
+
|
|
|
dd59ef |
+static bool
|
|
|
dd59ef |
+mount_point_in_fts_cycle (FTSENT const *ent)
|
|
|
dd59ef |
+{
|
|
|
dd59ef |
+ FTSENT const *cycle_ent = ent->fts_cycle;
|
|
|
dd59ef |
+
|
|
|
dd59ef |
+ while (ent && ent != cycle_ent)
|
|
|
dd59ef |
+ {
|
|
|
dd59ef |
+ if (di_set_lookup (di_mnt, ent->fts_statp->st_dev,
|
|
|
dd59ef |
+ ent->fts_statp->st_ino) > 0)
|
|
|
dd59ef |
+ {
|
|
|
dd59ef |
+ return true;
|
|
|
dd59ef |
+ }
|
|
|
dd59ef |
+ ent = ent->fts_parent;
|
|
|
dd59ef |
+ }
|
|
|
dd59ef |
+
|
|
|
dd59ef |
+ return false;
|
|
|
dd59ef |
+}
|
|
|
dd59ef |
+
|
|
|
dd59ef |
/* This function is called once for every file system object that fts
|
|
|
dd59ef |
encounters. fts does a depth-first traversal. This function knows
|
|
|
dd59ef |
that and accumulates per-directory totals based on changes in
|
|
|
dd59ef |
@@ -514,15 +514,11 @@ process_file (FTS *fts, FTSENT *ent)
|
|
|
dd59ef |
break;
|
|
|
dd59ef |
|
|
|
dd59ef |
case FTS_DC:
|
|
|
dd59ef |
- if (cycle_warning_required (fts, ent))
|
|
|
dd59ef |
+ /* If not following symlinks and not a (bind) mount point. */
|
|
|
dd59ef |
+ if (cycle_warning_required (fts, ent)
|
|
|
dd59ef |
+ && ! mount_point_in_fts_cycle (ent))
|
|
|
dd59ef |
{
|
|
|
dd59ef |
- /* If this is a mount point, then diagnose it and avoid
|
|
|
dd59ef |
- the cycle. */
|
|
|
dd59ef |
- if (di_set_lookup (di_mnt, sb->st_dev, sb->st_ino))
|
|
|
dd59ef |
- error (0, 0, _("mount point %s already traversed"),
|
|
|
dd59ef |
- quote (file));
|
|
|
dd59ef |
- else
|
|
|
dd59ef |
- emit_cycle_warning (file);
|
|
|
dd59ef |
+ emit_cycle_warning (file);
|
|
|
dd59ef |
return false;
|
|
|
dd59ef |
}
|
|
|
dd59ef |
return true;
|
|
|
dd59ef |
diff --git a/tests/du/bind-mount-dir-cycle-v2.sh b/tests/du/bind-mount-dir-cycle-v2.sh
|
|
|
dd59ef |
new file mode 100755
|
|
|
dd59ef |
index 0000000..08bfae2
|
|
|
dd59ef |
--- /dev/null
|
|
|
dd59ef |
+++ b/tests/du/bind-mount-dir-cycle-v2.sh
|
|
|
dd59ef |
@@ -0,0 +1,38 @@
|
|
|
dd59ef |
+#!/bin/sh
|
|
|
dd59ef |
+# Check that du can handle sub-bind-mounts cycles as well.
|
|
|
dd59ef |
+
|
|
|
dd59ef |
+# Copyright (C) 2014 Free Software foundation, Inc.
|
|
|
dd59ef |
+
|
|
|
dd59ef |
+# This program is free software: you can redistribute it and/or modify
|
|
|
dd59ef |
+# it under the terms of the GNU General Public License as published by
|
|
|
dd59ef |
+# the Free Software Foundation, either version 3 of the License, or
|
|
|
dd59ef |
+# (at your option) any later version.
|
|
|
dd59ef |
+
|
|
|
dd59ef |
+# This program is distributed in the hope that it will be useful,
|
|
|
dd59ef |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
dd59ef |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
dd59ef |
+# GNU General Public License for more details.
|
|
|
dd59ef |
+
|
|
|
dd59ef |
+# You should have received a copy of the GNU General Public License
|
|
|
dd59ef |
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
dd59ef |
+
|
|
|
dd59ef |
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
|
|
|
dd59ef |
+print_ver_ du
|
|
|
dd59ef |
+require_root_
|
|
|
dd59ef |
+
|
|
|
dd59ef |
+cleanup_() { umount a/b/c; }
|
|
|
dd59ef |
+
|
|
|
dd59ef |
+mkdir -p a/b/c || framework_failure_
|
|
|
dd59ef |
+mount --bind a a/b/c \
|
|
|
dd59ef |
+ || skip_ 'This test requires mount with a working --bind option.'
|
|
|
dd59ef |
+
|
|
|
dd59ef |
+echo a/b/c > exp || framework_failure_
|
|
|
dd59ef |
+echo a/b >> exp || framework_failure_
|
|
|
dd59ef |
+
|
|
|
dd59ef |
+du a/b > out 2> err || fail=1
|
|
|
dd59ef |
+sed 's/^[0-9][0-9]* //' out > k && mv k out
|
|
|
dd59ef |
+
|
|
|
dd59ef |
+compare /dev/null err || fail=1
|
|
|
dd59ef |
+compare exp out || fail=1
|
|
|
dd59ef |
+
|
|
|
dd59ef |
+Exit $fail
|
|
|
dd59ef |
diff --git a/tests/local.mk b/tests/local.mk
|
|
|
dd59ef |
index 653c984..349e322 100644
|
|
|
dd59ef |
--- a/tests/local.mk
|
|
|
dd59ef |
+++ b/tests/local.mk
|
|
|
dd59ef |
@@ -117,6 +117,7 @@ all_root_tests = \
|
|
|
dd59ef |
tests/dd/skip-seek-past-dev.sh \
|
|
|
dd59ef |
tests/df/problematic-chars.sh \
|
|
|
dd59ef |
tests/du/bind-mount-dir-cycle.sh \
|
|
|
dd59ef |
+ tests/du/bind-mount-dir-cycle-v2.sh \
|
|
|
dd59ef |
tests/id/setgid.sh \
|
|
|
dd59ef |
tests/install/install-C-root.sh \
|
|
|
dd59ef |
tests/ls/capability.sh \
|
|
|
dd59ef |
--
|
|
|
dd59ef |
1.7.2.5
|
|
|
dd59ef |
diff -urNp coreutils-8.22-orig/tests/du/bind-mount-dir-cycle.sh coreutils-8.22/tests/du/bind-mount-dir-cycle.sh
|
|
|
dd59ef |
--- coreutils-8.22-orig/tests/du/bind-mount-dir-cycle.sh 2013-12-04 15:48:30.000000000 +0100
|
|
|
dd59ef |
+++ coreutils-8.22/tests/du/bind-mount-dir-cycle.sh 2015-07-02 15:58:49.230632316 +0200
|
|
|
dd59ef |
@@ -27,12 +27,11 @@ mount --bind a a/b \
|
|
|
dd59ef |
|| skip_ "This test requires mount with a working --bind option."
|
|
|
dd59ef |
|
|
|
dd59ef |
echo a > exp || framework_failure_
|
|
|
dd59ef |
-echo "du: mount point 'a/b' already traversed" > exp-err || framework_failure_
|
|
|
dd59ef |
|
|
|
dd59ef |
-du a > out 2> err && fail=1
|
|
|
dd59ef |
+du a > out 2> err || fail=1
|
|
|
dd59ef |
sed 's/^[0-9][0-9]* //' out > k && mv k out
|
|
|
dd59ef |
|
|
|
dd59ef |
-compare exp-err err || fail=1
|
|
|
dd59ef |
+compare /dev/null err || fail=1
|
|
|
dd59ef |
compare exp out || fail=1
|
|
|
dd59ef |
|
|
|
dd59ef |
Exit $fail
|