summaryrefslogtreecommitdiff
path: root/src/du.c
diff options
context:
space:
mode:
authorBoris Ranto <branto@redhat.com>2014-12-01 09:24:14 +0100
committerPádraig Brady <P@draigBrady.com>2014-12-02 01:01:35 +0000
commitdc1c0523a61932fb0c26a795b7e7391eadf2171a (patch)
tree0df0a12d1053bfb16c41f2336fbbd3b500d5227c /src/du.c
parent6f16c63963b0624cbcbf285fb936b79276c047de (diff)
downloadcoreutils-dc1c0523a61932fb0c26a795b7e7391eadf2171a.tar.gz
du: handle sub-bind-mount cycles gracefully
This patch fixes the handling of sub-bind-mount cycles which are incorrectly detected as the file system errors. If you bind mount the directory 'a' to its subdirectory 'a/b/c' and then run 'du a/b' you will get the circular dependency warning even though nothing is wrong with the file system. This happens because the first directory that is traversed twice in this case is not a bind mount but a child of bind mount. The solution is to traverse all the directories in the cycle that fts detected and check whether they are not a (bind) mount. * src/du.c (mount_point_in_fts_cycle): New function that checks whether any of the directories in the cycle that fts detected is a mount point. * src/du.c (process_file): Update the function to use the new function that looks up all the directories in the fts cycle instead of only the last one. * tests/du/bind-mount-dir-cycle-v2.sh: New test case that exhibits the described behavior. * tests/local.mk: Reference the new root test. * NEWS: Mention the bug fix.
Diffstat (limited to 'src/du.c')
-rw-r--r--src/du.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/src/du.c b/src/du.c
index ba2012059..f5726c7c4 100644
--- a/src/du.c
+++ b/src/du.c
@@ -419,6 +419,27 @@ print_size (const struct duinfo *pdui, const char *string)
fflush (stdout);
}
+/* This function checks whether any of the directories in the cycle that
+ fts detected is a mount point. */
+
+static bool
+mount_point_in_fts_cycle (FTSENT const *ent)
+{
+ FTSENT const *cycle_ent = ent->fts_cycle;
+
+ while (ent && ent != cycle_ent)
+ {
+ if (di_set_lookup (di_mnt, ent->fts_statp->st_dev,
+ ent->fts_statp->st_ino) > 0)
+ {
+ return true;
+ }
+ ent = ent->fts_parent;
+ }
+
+ return false;
+}
+
/* This function is called once for every file system object that fts
encounters. fts does a depth-first traversal. This function knows
that and accumulates per-directory totals based on changes in
@@ -516,7 +537,7 @@ process_file (FTS *fts, FTSENT *ent)
case FTS_DC:
/* If not following symlinks and not a (bind) mount point. */
if (cycle_warning_required (fts, ent)
- && ! di_set_lookup (di_mnt, sb->st_dev, sb->st_ino))
+ && ! mount_point_in_fts_cycle (ent))
{
emit_cycle_warning (file);
return false;