Blame SOURCES/coreutils-8.22-du-bindmountcycles.patch

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