Bug #12144
openBug in ``df -t`` filtering if two filesystems use the same mountpoint
0%
Description
When using RAM disks for /tmp
and /var
on a ZFS installation, the System Information widget on the Dashboard appears to show multiple copies of /var
instead of the expected ZFS datasets mounted under /var
.
This is simple to reproduce:
1. Install fresh with ZFS
2. Enable RAM disks for /tmp and /var under System > Advanced, Misc with the default values
3. Reboot
This appears to be due to a bug in df -t <type>
.
The full output of df
is OK:
: df -Th Filesystem Type Size Used Avail Capacity Mounted on pfSense/ROOT/default zfs 29G 670M 28G 2% / devfs devfs 1.0K 1.0K 0B 100% /dev pfSense/cf zfs 28G 96K 28G 0% /cf pfSense/var zfs 28G 3.2M 28G 0% /var pfSense/home zfs 28G 96K 28G 0% /home pfSense zfs 28G 96K 28G 0% /pfSense pfSense/cf/conf zfs 28G 616K 28G 0% /cf/conf pfSense/var/log zfs 28G 188K 28G 0% /var/log pfSense/var/empty zfs 28G 96K 28G 0% /var/empty pfSense/var/cache zfs 28G 96K 28G 0% /var/cache pfSense/var/db zfs 28G 1.1M 28G 0% /var/db pfSense/var/tmp zfs 28G 104K 28G 0% /var/tmp /dev/md0 ufs 38M 76K 35M 0% /tmp /dev/md1 ufs 58M 9.5M 44M 18% /var devfs devfs 1.0K 1.0K 0B 100% /var/dhcpd/dev
Filtering to only UFS shows the expected entries for /tmp and /var:
: df -Tht ufs Filesystem Type Size Used Avail Capacity Mounted on /dev/md0 ufs 38M 76K 35M 0% /tmp /dev/md1 ufs 58M 9.5M 44M 18% /var
Filtering for ZFS shows multiple copies of /var and not the datasets:
: df -Tht zfs Filesystem Type Size Used Avail Capacity Mounted on pfSense/ROOT/default zfs 29G 670M 28G 2% / pfSense/cf zfs 28G 96K 28G 0% /cf /dev/md1 ufs 58M 9.5M 44M 18% /var pfSense/home zfs 28G 96K 28G 0% /home pfSense zfs 28G 96K 28G 0% /pfSense pfSense/cf/conf zfs 28G 616K 28G 0% /cf/conf /dev/md1 ufs 58M 9.5M 44M 18% /var /dev/md1 ufs 58M 9.5M 44M 18% /var /dev/md1 ufs 58M 9.5M 44M 18% /var /dev/md1 ufs 58M 9.5M 44M 18% /var /dev/md1 ufs 58M 9.5M 44M 18% /var
N.B. The /var lines show their type as ufs
which doesn't match what we asked for
This appears to be an upstream bug in df
but it would be nice if we could work out a fix before the next release, either on our own or by coordinating with the maintainer of df
in FreeBSD.
Updated by Renato Botelho about 3 years ago
- Status changed from New to In Progress
- Assignee set to Mateusz Guzik
Mateusz reproduced the issue on stock FreeBSD and will work on a fix
Updated by Mateusz Guzik about 3 years ago
This comes from a deficiency in the API exposed to userspace.
Consider the following:
tmpfs on /tmp (tmpfs, local) /dev/md0 on /tmp (ufs, local) tmpfs on /tmp/test (tmpfs, local)
df sorts this out in 2 phases:
1. mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
This gets ALL filesystems, but the MNT_NOWAIT flag tells the kernel to not issue any I/O.
2. mntsize = regetmntinfo(&mntbuf, mntsize, vfslist);
This walks the list and issues an additional statfs(2) for filesystems of interest by passing the mount point as an identifier.
In the example above there are 2 filesystems with the same mount point and the kernel exports the second one. Should there be 3 filesystems stacked up, there would be no way to ask for the middle one.
Thus if you filter for tmpfs, you end up getting ufs as the first result.
In other words the interface needs to be fixed.
In the meantime as a hack the above can be reworked -- getmntinfo can be called with MNT_WAIT and then the result filtered out. The downside which makes it not committable upstream is the updates requested from all mount points, even ones of no interest.
Mount points carry "fs id" which in principle could be filtered on, but getting the value requires privileges and there is still no syscall to filter on it.
Another work around would be to zfs set mountpoint=none on the problematic dataset.
Updated by Mateusz Guzik about 3 years ago
The following is the hack which does the trick for me fwiw:
diff --git a/bin/df/df.c b/bin/df/df.c
index a0d43fca5789..1a11fae848f2 100644
--- a/bin/df/df.c
+++ b/bin/df/df.c
@@ -88,7 +88,7 @@ static void prthuman(const struct statfs *, int64_t);
static void prthumanval(const char *, int64_t);
static intmax_t fsbtoblk(int64_t, uint64_t, u_long);
static void prtstat(struct statfs *, struct maxwidths *);
-static size_t regetmntinfo(struct statfs **, long, const char **);
+static size_t filtermntinfo(struct statfs **, long, const char **);
static void update_maxwidths(struct maxwidths *, const struct statfs *);
static void usage(void);
@@ -213,8 +213,8 @@ main(int argc, char *argv[])
rv = 0;
if (!*argv) {
/* everything (modulo -t) */
- mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
- mntsize = regetmntinfo(&mntbuf, mntsize, vfslist);
+ mntsize = getmntinfo(&mntbuf, MNT_WAIT);
+ mntsize = filtermntinfo(&mntbuf, mntsize, vfslist);
} else {
/* just the filesystems specified on the command line */
mntbuf = malloc(argc * sizeof(*mntbuf));
@@ -316,35 +316,24 @@ getmntpt(const char *name)
* current (not cached) info. Returns the new count of valid statfs bufs.
*/
static size_t
-regetmntinfo(struct statfs **mntbufp, long mntsize, const char **vfslist)
+filtermntinfo(struct statfs **mntbufp, long mntsize, const char **vfslist)
{
- int error, i, j;
+ int i;
struct statfs *mntbuf;
if (vfslist == NULL)
return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT));
mntbuf = *mntbufp;
- for (j = 0, i = 0; i < mntsize; i++) {
- if (checkvfsname(mntbuf[i].f_fstypename, vfslist))
+
+ for (i = 0; i < mntsize; i++) {
+ if (checkvfsname(mntbuf[i].f_fstypename, vfslist)) {
+ mntbuf[i].f_flags |= MNT_IGNORE;
continue;
- /*
- * XXX statfs(2) can fail for various reasons. It may be
- * possible that the user does not have access to the
- * pathname, if this happens, we will fall back on
- * "stale" filesystem statistics.
- */
- error = statfs(mntbuf[i].f_mntonname, &mntbuf[j]);
- if (nflag || error < 0)
- if (i != j) {
- if (error < 0)
- xo_warnx("%s stats possibly stale",
- mntbuf[i].f_mntonname);
- mntbuf[j] = mntbuf[i];
- }
- j++;
+ }
}
- return (j);
+
+ return (mntsize);
}
static void
Updated by Jim Pingle about 3 years ago
- Subject changed from System Information Dashboard widget shows incorrect information with ZFS and RAM Disks enabled to Bug in ``df -t`` filtering if two filesystems use the same mountpoint
- Target version deleted (
2.6.0) - Plus Target Version deleted (
21.09)
The new Disks widget in #12349 uses df
in a different way and doesn't hit this problem, thus it is no longer a current need. Though it would still be nice to see it fixed in FreeBSD, we don't appear to have any more remaining uses of df
that use -t
, so nothing else on pfSense could trigger the bug.
I updated the subject to reflect that it's no longer a widget issue.