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

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