>From 838318741e094db41210f37ab2f2a8d216749e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1draig=20Brady?= Date: Wed, 29 Oct 2014 02:49:17 +0000 Subject: [PATCH] df: only suppress remote mounts of separate exports with --total * src/df.c (filter_mount_list): Separate remote locations are generally explicitly mounted so list each even if they share the same remote device and thus storage. However with --total keep the suppression to give a more accurate value for the total storage available. (usage): Expand on the new implications of --total and move it in the options list according to alphabetic order. doc/coreutils.texi (df invocation): Mention that --total impacts on deduplication of remote file systems and also move location according to alphabetic order. * tests/df/skip-duplicates.sh: Add remote test cases. * NEWS: Mention the change in behavior. Reported in http://bugs.debian.org/737399 Reported in http://bugzilla.redhat.com/920806 --- NEWS | 5 +++++ doc/coreutils.texi | 31 ++++++++++++++++--------------- src/df.c | 41 ++++++++++++++++++++++++++++------------- tests/df/skip-duplicates.sh | 31 ++++++++++++++++++++++++++++--- 4 files changed, 77 insertions(+), 31 deletions(-) diff --git a/NEWS b/NEWS index 5d3bc58..3491a9d 100644 --- a/NEWS +++ b/NEWS @@ -32,6 +32,11 @@ GNU coreutils NEWS -*- outline -*- ** Changes in behavior + df no longer suppresses separate exports of the same remote device, + these are probably explicitly mounted. The --total option does still + suppress duplicate remote file systems. + [suppression was introduced in coreutils-8.21] + mv no longer supports moving a file to a hardlink, instead issuing an error. The implementation was susceptible to races in the presence of multiple mv instances, which could result in both hardlinks being deleted. Also on case diff --git a/doc/coreutils.texi b/doc/coreutils.texi index db24a75..e9008c0 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -11205,8 +11205,7 @@ Non-integer quantities are rounded up to the next higher unit. For bind mounts and without arguments, @command{df} only outputs the statistics for that device with the shortest mount point name in the list of file systems (@var{mtab}), i.e., it hides duplicate entries, unless the @option{-a} option is -specified. Remote file systems, such as NFS, are treated the same way as local -ones; only one mount entry per remote file system is shown by default. +specified. With the same logic, @command{df} elides a mount entry of a dummy pseudo device if there is another mount entry of a real block device for that mount point with @@ -11248,19 +11247,6 @@ due to permissions of the mount point etc. Scale sizes by @var{size} before printing them (@pxref{Block size}). For example, @option{-BG} prints sizes in units of 1,073,741,824 bytes. -@item --total -@opindex --total -@cindex grand total of disk size, usage and available space -Print a grand total of all arguments after all arguments have -been processed. This can be used to find out the total disk size, usage -and available space of all listed devices. - -For the grand total line, @command{df} prints @samp{"total"} into the -@var{source} column, and @samp{"-"} into the @var{target} column. -If there is no @var{source} column (see @option{--output}), then -@command{df} prints @samp{"total"} into the @var{target} column, -if present. - @optHumanReadable @item -H @@ -11401,6 +11387,21 @@ some systems (notably SunOS), doing this yields more up to date results, but in general this option makes @command{df} much slower, especially when there are many or very busy file systems. +@item --total +@opindex --total +@cindex grand total of disk size, usage and available space +Print a grand total of all arguments after all arguments have +been processed. This can be used to find out the total disk size, usage +and available space of all listed devices. If no arguments are specified +df will try harder to elide file systems insignificant to the total +available space, by suppressing duplicate remote file systems. + +For the grand total line, @command{df} prints @samp{"total"} into the +@var{source} column, and @samp{"-"} into the @var{target} column. +If there is no @var{source} column (see @option{--output}), then +@command{df} prints @samp{"total"} into the @var{target} column, +if present. + @item -t @var{fstype} @itemx --type=@var{fstype} @opindex -t diff --git a/src/df.c b/src/df.c index a52afc4..7bac184 100644 --- a/src/df.c +++ b/src/df.c @@ -640,18 +640,28 @@ filter_mount_list (bool devices_only) if (devlist) { - /* let "real" devices with '/' in the name win. */ - if ((strchr (me->me_devname, '/') - && ! strchr (devlist->me->me_devname, '/')) - /* let a shorter mountdir win. */ - || (strlen (devlist->me->me_mountdir) - > strlen (me->me_mountdir)) - /* let an entry overmounted on a different device win... */ - || (! STREQ (devlist->me->me_devname, me->me_devname) - /* ... but only when matching an existing mount point, to - avoid problematic replacement when given inaccurate mount - lists, seen with some chroot environments for example. */ - && STREQ (me->me_mountdir, devlist->me->me_mountdir))) + if (! print_grand_total && me->me_remote && devlist->me->me_remote + && ! STREQ (devlist->me->me_devname, me->me_devname)) + { + /* Don't discard remote entries with different locations, + as these are more likely to be explicitly mounted. + However avoid this when producing a total to give + a more accurate value in that case. */ + } + else if ((strchr (me->me_devname, '/') + /* let "real" devices with '/' in the name win. */ + && ! strchr (devlist->me->me_devname, '/')) + /* let a shorter mountdir win. */ + || (strlen (devlist->me->me_mountdir) + > strlen (me->me_mountdir)) + /* let an entry overmounted on a new device win... */ + || (! STREQ (devlist->me->me_devname, me->me_devname) + /* ... but only when matching an existing mnt point, + to avoid problematic replacement when given + inaccurate mount lists, seen with some chroot + environments for example. */ + && STREQ (me->me_mountdir, + devlist->me->me_mountdir))) { /* Discard mount entry for existing device. */ discard_me = devlist->me; @@ -1403,7 +1413,6 @@ or all file systems by default.\n\ -B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\ '-BM' prints sizes in units of 1,048,576 bytes;\n\ see SIZE format below\n\ - --total produce a grand total\n\ -h, --human-readable print sizes in powers of 1024 (e.g., 1023M)\n\ -H, --si print sizes in powers of 1000 (e.g., 1.1G)\n\ "), stdout); @@ -1419,6 +1428,12 @@ or all file systems by default.\n\ or print all fields if FIELD_LIST is omitted.\n\ -P, --portability use the POSIX output format\n\ --sync invoke sync before getting usage info\n\ +"), stdout); + fputs (_("\ + --total elide all entries insignificant to available space,\n\ + and produce a grand total\n\ +"), stdout); + fputs (_("\ -t, --type=TYPE limit listing to file systems of type TYPE\n\ -T, --print-type print file system type\n\ -x, --exclude-type=TYPE limit listing to file systems not of type TYPE\n\ diff --git a/tests/df/skip-duplicates.sh b/tests/df/skip-duplicates.sh index 52b9014..6b984ad 100755 --- a/tests/df/skip-duplicates.sh +++ b/tests/df/skip-duplicates.sh @@ -26,7 +26,12 @@ require_gcc_shared_ df --local || skip_ "df fails" export CU_NONROOT_FS=$(df --local --output=target 2>&1 | grep /. | head -n1) -test -z "$CU_NONROOT_FS" && unique_entries=1 || unique_entries=2 +export CU_REMOTE_FS=$(df --local --output=target 2>&1 | grep /. | + tail -n+2 | head -n1) + +unique_entries=1 +test -z "$CU_NONROOT_FS" || unique_entries=$(expr $unique_entries + 1) +test -z "$CU_REMOTE_FS" || unique_entries=$(expr $unique_entries + 2) grep '^#define HAVE_MNTENT_H 1' $CONFIG_HEADER > /dev/null \ || skip_ "no mntent.h available to confirm the interface" @@ -46,6 +51,7 @@ cat > k.c <<'EOF' || framework_failure_ struct mntent *getmntent (FILE *fp) { static char *nonroot_fs; + static char *remote_fs; static int done; /* Prove that LD_PRELOAD works. */ @@ -63,6 +69,9 @@ struct mntent *getmntent (FILE *fp) {.mnt_fsname="virtfs", .mnt_dir="/NONROOT", .mnt_type="fstype1"}, {.mnt_fsname="virtfs2", .mnt_dir="/NONROOT", .mnt_type="fstype2"}, {.mnt_fsname="netns", .mnt_dir="net:[1234567]"}, + {.mnt_fsname="rem:ote1",.mnt_dir="/REMOTE"}, + {.mnt_fsname="rem:ote1",.mnt_dir="/REMOTE"}, + {.mnt_fsname="rem:ote2",.mnt_dir="/REMOTE"}, }; if (done == 1) @@ -70,17 +79,26 @@ struct mntent *getmntent (FILE *fp) nonroot_fs = getenv ("CU_NONROOT_FS"); if (!nonroot_fs || !*nonroot_fs) nonroot_fs = "/"; /* merge into / entries. */ + + remote_fs = getenv ("CU_REMOTE_FS"); } if (done == 1 && !getenv ("CU_TEST_DUPE_INVALID")) done++; /* skip the first entry. */ - while (done++ <= 7) + while (done++ <= 10) { if (!mntents[done-2].mnt_type) mntents[done-2].mnt_type = "-"; if (STREQ (mntents[done-2].mnt_dir, "/NONROOT")) mntents[done-2].mnt_dir = nonroot_fs; + if (STREQ (mntents[done-2].mnt_dir, "/REMOTE")) + { + if (!remote_fs || !*remote_fs) + continue; + else + mntents[done-2].mnt_dir = remote_fs; + } return &mntents[done-2]; } @@ -102,6 +120,12 @@ test -f x || skip_ "internal test failure: maybe LD_PRELOAD doesn't work?" LD_PRELOAD=./k.so df -T >out || fail=1 test $(wc -l out || fail=1 +test "$CU_REMOTE_FS" && elide_remote=1 || elide_remote=0 +test $(wc -l out || fail=1 test $(wc -l out || fail=1 -test $(wc -l