]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
df: improve detection of duplicate entries
authorLukáš Zaoral <lzaoral@redhat.com>
Tue, 14 Apr 2026 12:09:02 +0000 (14:09 +0200)
committerPádraig Brady <P@draigBrady.com>
Wed, 15 Apr 2026 11:56:16 +0000 (12:56 +0100)
Do not compare only with the latest entry for given device id but also
all previously saved entries with the same id.

* src/df.c (struct devlist): Add next_same_dev struct member.
(filter_mount_list): Iterate over next_same_dev to find duplicates.
* tests/df/skip-duplicates.sh: Add test cases.
* NEWS: Mention the improvement.
https://redhat.atlassian.net/browse/RHEL-5649

NEWS
src/df.c
tests/df/skip-duplicates.sh

diff --git a/NEWS b/NEWS
index ce9645f5c19fa89f0f3d02e427050466f18fe42a..b2edbbc26b8b90a6312d95a709a5e6a7f143f14e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -62,6 +62,9 @@ GNU coreutils NEWS                                    -*- outline -*-
   'df --local' recognises more file system types as remote.
   Specifically: autofs, ncpfs, smb, smb2, gfs, gfs2, userlandfs.
 
+  'df' improves duplicate mount suppression, by checking each mount against
+  all previously kept entries for the same device, not just the latest one.
+
   'expand' and 'unexpand' now support multi-byte characters.
 
   'groups' and 'id' will now exit sooner after a write error,
index 377b59dceee475d1cb60dc0f3309d75d751f5e70..f41ba3a870ff0dad1e999d5efe7de1309972f2c8 100644 (file)
--- a/src/df.c
+++ b/src/df.c
@@ -50,6 +50,7 @@ struct devlist
   dev_t dev_num;
   struct mount_entry *me;
   struct devlist *next;
+  struct devlist *next_same_dev;
   struct devlist *seen_last; /* valid for hashed devlist entries only */
 };
 
@@ -720,6 +721,7 @@ filter_mount_list (bool devices_only)
     {
       struct stat buf;
       struct mount_entry *discard_me = NULL;
+      struct devlist *last_seen_dev = NULL, *seen_dev = NULL;
 
       /* Avoid stating remote file systems as that may hang.
          On Linux we probably have me_dev populated from /proc/self/mountinfo,
@@ -737,9 +739,9 @@ filter_mount_list (bool devices_only)
       else
         {
           /* If we've already seen this device...  */
-          struct devlist *seen_dev = devlist_for_dev (buf.st_dev);
+          last_seen_dev = seen_dev = devlist_for_dev (buf.st_dev);
 
-          if (seen_dev)
+          for (; seen_dev && ! discard_me; seen_dev = seen_dev->next_same_dev)
             {
               bool target_nearer_root = strlen (seen_dev->me->me_mountdir)
                                         > strlen (me->me_mountdir);
@@ -796,6 +798,7 @@ filter_mount_list (bool devices_only)
           struct devlist *devlist = xmalloc (sizeof *devlist);
           devlist->me = me;
           devlist->dev_num = buf.st_dev;
+          devlist->next_same_dev = last_seen_dev;
           devlist->next = device_list;
           device_list = devlist;
 
index ed7657bf621d7fe894f0c0a7edf4cd350ccac552..aa1a9ac30366df438cd6aef29f9c3bba728181f8 100755 (executable)
@@ -138,6 +138,8 @@ struct mntent *getmntent (FILE *fp)
     {.mnt_fsname="rem:ote1",.mnt_dir="/REMOTE",                  .mnt_opts=""},
     {.mnt_fsname="rem:ote1",.mnt_dir="/REMOTE",                  .mnt_opts=""},
     {.mnt_fsname="rem:ote2",.mnt_dir="/REMOTE",                  .mnt_opts=""},
+    {.mnt_fsname="rem:ote1",.mnt_dir="/REMOTE",                  .mnt_opts=""},
+    {.mnt_fsname="rem:ote2",.mnt_dir="/REMOTE",                  .mnt_opts=""},
   };
 
   if (done == 1)
@@ -152,7 +154,7 @@ struct mntent *getmntent (FILE *fp)
   if (done == 1 && !getenv ("CU_TEST_DUPE_INVALID"))
     done++;  /* skip the first entry.  */
 
-  while (done++ <= 10)
+  while (done++ <= 12)
     {
       if (!mntents[done-2].mnt_type)
         mntents[done-2].mnt_type = "-";
@@ -210,7 +212,7 @@ test $(grep -c 'virtfs2.*t2' <out) -eq 1 || { fail=1; cat out; }
 
 # Ensure that filtering duplicates does not affect -a processing.
 LD_PRELOAD=$LD_PRELOAD:./k.so df -a >out || fail=1
-total_fs=6; test "$CU_REMOTE_FS" && total_fs=$(expr $total_fs + 3)
+total_fs=6; test "$CU_REMOTE_FS" && total_fs=$(expr $total_fs + 5)
 test $(wc -l <out) -eq $total_fs || { fail=1; cat out; }
 # Ensure placeholder "-" values used for the eclipsed "virtfs"
 test $(grep -c 'virtfs *-' <out) -eq 1 || { fail=1; cat out; }