Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 15 Nov 2003 06:46:26 +1100 (EST)
From:      Bruce Evans <bde@zeta.org.au>
To:        Peter Edwards <peter.edwards@openet-telecom.com>
Cc:        current@freebsd.org
Subject:   Re: Who needs these silly statfs changes...
Message-ID:  <20031115054126.B9400@gamplex.bde.org>
In-Reply-To: <3FB4E8A1.6090402@openet-telecom.com>
References:  <20031113020400.GA44619@xor.obsecurity.org> <20031113085418.GA47995@xor.obsecurity.org> <3FB4E8A1.6090402@openet-telecom.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, 14 Nov 2003, Peter Edwards wrote:

> Bernd Walter wrote:
>
> >On Thu, Nov 13, 2003 at 12:54:18AM -0800, Kris Kennaway wrote:
> >
> >
> >>On Thu, Nov 13, 2003 at 06:44:25PM +1100, Peter Jeremy wrote:
> >>
> >>
> >>>On Wed, Nov 12, 2003 at 06:04:00PM -0800, Kris Kennaway wrote:
> >>>
> >>>
> >>>>...my sparc machine reports that my i386 nfs server has 15 exabytes of
> >>>>free space!
> >>>>
> >>>>enigma# df -k
> >>>>Filesystem  1K-blocks     Used             Avail Capacity  Mounted on
> >>>>rot13:/mnt2  56595176 54032286 18014398507517260     0%    /rot13/mnt2
> >>>>
> >>>>
> >>>18014398507517260 = 2^54 - 1964724.  and 2^54KB == 2^64 bytes.  Is it
> >>>possible that rot13:/mnt2 has negative free space?  (ie it's into the
> >>>8-10% reserved area).
> >>>
> >>>
> >>Yes, that's precisely what it is..the bug is either in df or the
> >>kernel (I suspect the latter, i.e. something in the nfs code).
> >>
> >>
> >
> >And it's nothing new - I'm seeing this since several years now.
> >
> >
>
> The NFS protocols have unsigned fields where statfs has signed
> equivalents: NFS can't represent negative available disk space ( Without
> the knowledge of the underlying filesystem on the server, negative free
> space is a little nonsensical anyway, I suppose)
>
> The attached patch stops the NFS server assigning negative values to
> unsigned fields in the statfs response, and works against my local
> solaris box.  Seem reasonable?

The client attampts to fix this by pretending that the unsigned fields
are signed.  -current tries to do more to support file system sizes larger
that 1TB, but the code for this is not even wrong except it may be wrong
enough to break the negative values.  See my reply to one of the PRs
for more details.

I just got around to testing the patch in that reply:

%%%
Index: nfs_vfsops.c
===================================================================
RCS file: /home/ncvs/src/sys/nfsclient/nfs_vfsops.c,v
retrieving revision 1.143
diff -u -2 -r1.143 nfs_vfsops.c
--- nfs_vfsops.c	12 Nov 2003 02:54:46 -0000	1.143
+++ nfs_vfsops.c	12 Nov 2003 14:37:46 -0000
@@ -223,5 +223,5 @@
 	struct mbuf *mreq, *mrep, *md, *mb;
 	struct nfsnode *np;
-	u_quad_t tquad;
+	quad_t tquad;
 	int bsize;

@@ -254,19 +254,19 @@
 		for (bsize = NFS_FABLKSIZE; ; bsize *= 2) {
 			sbp->f_bsize = bsize;
-			tquad = fxdr_hyper(&sfp->sf_tbytes);
-			if (((long)(tquad / bsize) > LONG_MAX) ||
-			    ((long)(tquad / bsize) < LONG_MIN))
+			tquad = (quad_t)fxdr_hyper(&sfp->sf_tbytes) / bsize;
+			if (bsize <= INT_MAX / 2 &&
+			    (tquad > LONG_MAX || tquad < LONG_MIN))
 				continue;
-			sbp->f_blocks = tquad / bsize;
-			tquad = fxdr_hyper(&sfp->sf_fbytes);
-			if (((long)(tquad / bsize) > LONG_MAX) ||
-			    ((long)(tquad / bsize) < LONG_MIN))
+			sbp->f_blocks = tquad;
+			tquad = (quad_t)fxdr_hyper(&sfp->sf_fbytes) / bsize;
+			if (bsize <= INT_MAX / 2 &&
+			    (tquad > LONG_MAX || tquad < LONG_MIN))
 				continue;
-			sbp->f_bfree = tquad / bsize;
-			tquad = fxdr_hyper(&sfp->sf_abytes);
-			if (((long)(tquad / bsize) > LONG_MAX) ||
-			    ((long)(tquad / bsize) < LONG_MIN))
+			sbp->f_bfree = tquad;
+			tquad = (quad_t)fxdr_hyper(&sfp->sf_abytes) / bsize;
+			if (bsize <= INT_MAX / 2 &&
+			    (tquad > LONG_MAX || tquad < LONG_MIN))
 				continue;
-			sbp->f_bavail = tquad / bsize;
+			sbp->f_bavail = tquad;
 			sbp->f_files = (fxdr_unsigned(int32_t,
 			    sfp->sf_tfiles.nfsuquad[1]) & 0x7fffffff);
%%%

This seems to work.  On a 2TB-epsilon ffs1 file system (*) on an md malloc
disk (**):

server:
Filesystem 1K-blocks  Used      Avail Capacity  Mounted on
/dev/md0   2147416896    0 1975624000     0%    /b
client:
Filesystem 1024-blocks Used      Avail Capacity  Mounted on
besplex:/b  2147416896    0 1975624000     0%    /b

These are 1K-blocks so their count fits in an int32_t, but the count in
512-blocks is too large for an int32_t so the scaling must be helping.

With newfs -m 100 (***) to get near negative free space:

server:
Filesystem 1K-blocks  Used Avail Capacity  Mounted on
/dev/md0   2147416896    0  5696     0%    /b
client:
Filesystem 1K-blocks  Used Avail Capacity  Mounted on
besplex:/b  2147416896    0  5696     0%    /b

After using up all the free space by creating a 6MB file:

server:
Filesystem 1K-blocks  Used Avail Capacity  Mounted on
/dev/md0   2147416896 6208  -512   109%    /b
client:
Filesystem 1024-blocks Used Avail Capacity  Mounted on
besplex:/b  2147416896 6208  -512   109%    /b

(*) Overflow at 1TB in fs.h:fsbtodb() must be fixed for 2TB ffs1 file
systems to be safe to use.

(**) mdconfig and md have overflow bugs at 2^32 sectors but we only
need 2^31+epsilon sectors to test file system overflow bugs at 1TB.

(***) The off-by-1 error in newfs -m must be fixed for newfs -m 100
to work.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20031115054126.B9400>