From hscholz@goanna.lan.raisdorf.net  Mon Sep  8 12:30:05 2003
Return-Path: <hscholz@goanna.lan.raisdorf.net>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 8F2CB16A4BF
	for <freebsd-gnats-submit@freebsd.org>; Mon,  8 Sep 2003 12:30:05 -0700 (PDT)
Received: from mail.drunkencomputing.de (ratz.drunkencomputing.de [195.244.235.248])
	by mx1.FreeBSD.org (Postfix) with ESMTP id A401C43FE5
	for <freebsd-gnats-submit@freebsd.org>; Mon,  8 Sep 2003 12:30:03 -0700 (PDT)
	(envelope-from hscholz@goanna.lan.raisdorf.net)
Received: from localhost (localhost [127.0.0.1])
	by mail.drunkencomputing.de (Postfix) with ESMTP
	id 9F3718AF81; Mon,  8 Sep 2003 21:30:01 +0200 (CEST)
Received: from mail.drunkencomputing.de ([127.0.0.1])
 by localhost (winter.drunkencomputing.de [127.0.0.1]) (amavisd-new, port 10024)
 with ESMTP id 72767-04; Mon,  8 Sep 2003 21:30:00 +0200 (CEST)
Received: by mail.drunkencomputing.de (Postfix, from userid 66)
	id 312888AF90; Mon,  8 Sep 2003 21:30:00 +0200 (CEST)
Received: by pandemonium.lan.raisdorf.net (Postfix, from userid 1009)
	id 96DEB76EEA; Mon,  8 Sep 2003 21:17:52 +0200 (CEST)
Received: from goanna.lan.raisdorf.net (goanna.lan.raisdorf.net [10.10.1.2])
	by pandemonium.lan.raisdorf.net (Postfix) with ESMTP
	id 63DE076250; Mon,  8 Sep 2003 21:17:46 +0200 (CEST)
Received: from goanna.lan.raisdorf.net (localhost.lan.raisdorf.net [127.0.0.1])
	by goanna.lan.raisdorf.net (8.12.9/8.12.9) with ESMTP id h88JHcGO057922;
	Mon, 8 Sep 2003 21:17:38 +0200 (CEST)
	(envelope-from hscholz@goanna.lan.raisdorf.net)
Received: (from hscholz@localhost)
	by goanna.lan.raisdorf.net (8.12.9/8.12.9/Submit) id h88JHb0D057921;
	Mon, 8 Sep 2003 21:17:37 +0200 (CEST)
Message-Id: <200309081917.h88JHb0D057921@goanna.lan.raisdorf.net>
Date: Mon, 8 Sep 2003 21:17:37 +0200 (CEST)
From: Hendrik Scholz <hendrik@scholz.net>
Reply-To: Hendrik Scholz <hendrik@scholz.net>
To: FreeBSD-gnats-submit@freebsd.org
Cc: Hendrik Scholz <hendrik@scholz.net>
Subject: df cannot handle 2TB NFS volumes
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         56606
>Category:       bin
>Synopsis:       [2TB] df cannot handle 2TB NFS volumes
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Sep 08 12:30:18 PDT 2003
>Closed-Date:    Sun Mar 11 10:16:50 GMT 2007
>Last-Modified:  Sun Mar 11 10:16:50 GMT 2007
>Originator:     Hendrik Scholz
>Release:        FreeBSD 5.1-CURRENT i386
>Organization:
>Environment:
System: FreeBSD goanna.lan.raisdorf.net 5.1-CURRENT FreeBSD 5.1-CURRENT #0: Tue Jul 29 19:34:39 CEST 2003 hscholz@goanna.lan.raisdorf.net:/usr/src/sys/i386/compile/GOANNA i386

>Description:
Mounting a 1.8TB NFS volume shows negative values:
$ \df /mnt/foo
Filesystem          1K-blocks        Used     Avail Capacity  Mounted on
x.x.x.x:/spool1 -222502944 -463076980 240574036   208%    /mnt/foo
$ mount | grep foo
x.x.x.x:/spool1 on /mnt/foo (nfs)

It should read (copied from Linux box):
x.x.x.x:/spool1  1924980704 1684406656 240574048  88% /news/spool1

Same problem with inodes ...

>How-To-Repeat:
	
>Fix:
I did not have the time to have a look at the df code :-|

>Release-Note:
>Audit-Trail:

From: Bruce Evans <bde@zeta.org.au>
To: Hendrik Scholz <hendrik@scholz.net>
Cc: FreeBSD-gnats-submit@freebsd.org, freebsd-bugs@freebsd.org,
	peter@freebsd.org
Subject: Re: bin/56606: df cannot handle 2TB NFS volumes
Date: Wed, 10 Sep 2003 03:15:07 +1000 (EST)

 On Mon, 8 Sep 2003, Hendrik Scholz wrote:
 
 > >Description:
 > Mounting a 1.8TB NFS volume shows negative values:
 > $ \df /mnt/foo
 > Filesystem          1K-blocks        Used     Avail Capacity  Mounted on
 > x.x.x.x:/spool1 -222502944 -463076980 240574036   208%    /mnt/foo
 > $ mount | grep foo
 > x.x.x.x:/spool1 on /mnt/foo (nfs)
 >
 > It should read (copied from Linux box):
 > x.x.x.x:/spool1  1924980704 1684406656 240574048  88% /news/spool1
 
 I think this was supposed to have been fixed in nfs_vfsops.c nfs_vfsops.c,
 but the fix was buggy and was turned into verbose nonsense that happens to
 have no effect in rev.1.135.
 
 I sent the following to the author of the fix 3 weeks ago but received
 no reply.  It contains a hopefully correct fix.  This has not been
 tested with multi-TB filesystems but hasn't caused any problems with
 ones in the 4-13 GB range.
 
 [Old mail]
 % Index: nfs_vfsops.c
 % ===================================================================
 % RCS file: /home/ncvs/src/sys/nfsclient/nfs_vfsops.c,v
 % retrieving revision 1.134
 % retrieving revision 1.135
 % diff -u -2 -r1.134 -r1.135
 % --- nfs_vfsops.c	29 Apr 2003 13:36:04 -0000	1.134
 % +++ nfs_vfsops.c	19 May 2003 22:35:00 -0000	1.135
 % @@ -38,5 +38,5 @@
 %
 %  #include <sys/cdefs.h>
 % -__FBSDID("$FreeBSD: src/sys/nfsclient/nfs_vfsops.c,v 1.134 2003/04/29 13:36:04 kan Exp $");
 % +__FBSDID("$FreeBSD: src/sys/nfsclient/nfs_vfsops.c,v 1.135 2003/05/19 22:35:00 peter Exp $");
 %
 %  #include "opt_bootp.h"
 % @@ -278,13 +278,16 @@
 %  			sbp->f_bsize = bsize;
 %  			tquad = fxdr_hyper(&sfp->sf_tbytes);
 % -			if ((tquad / bsize) > LONG_MAX)
 % +			if (((long)(tquad / bsize) > LONG_MAX) ||
 % +			    ((long)(tquad / bsize) < LONG_MIN))
 %  				continue;
 %  			sbp->f_blocks = tquad / bsize;
 %  			tquad = fxdr_hyper(&sfp->sf_fbytes);
 % -			if ((tquad / bsize) > LONG_MAX)
 % +			if (((long)(tquad / bsize) > LONG_MAX) ||
 % +			    ((long)(tquad / bsize) < LONG_MIN))
 %  				continue;
 %  			sbp->f_bfree = tquad / bsize;
 %  			tquad = fxdr_hyper(&sfp->sf_abytes);
 % -			if ((tquad / bsize) > LONG_MAX)
 % +			if (((long)(tquad / bsize) > LONG_MAX) ||
 % +			    ((long)(tquad / bsize) < LONG_MIN))
 %  				continue;
 %  			sbp->f_bavail = tquad / bsize;
 
 Values of type long have the remarkable property of always being between
 LONG_MIN and LONG_MAX, so this change is just a verbose way of backing
 out rev.1.33.  Attempted fix:
 
 %%%
 Index: nfs_vfsops.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/nfsclient/nfs_vfsops.c,v
 retrieving revision 1.136
 diff -u -2 -r1.136 nfs_vfsops.c
 --- nfs_vfsops.c	12 Jun 2003 20:48:38 -0000	1.136
 +++ nfs_vfsops.c	16 Aug 2003 04:01:37 -0000
 @@ -239,5 +239,5 @@
  	struct mbuf *mreq, *mrep, *md, *mb;
  	struct nfsnode *np;
 -	u_quad_t tquad;
 +	quad_t tquad;
  	int bsize;
 
 @@ -270,19 +270,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 has not been tested at runtime.
 
 Rev.1.33 apparently didn't work essentially because of overflow (-1
 became UQUAD_MAX, and dividing that by bsize made a mess).  The patch
 assumes that values larger than QUAD_MAX really mean negative values.
 
 The patch also ensures that doubling bsize never overflows.  bsize
 could be limited to a less preposterous size than INT_MAX.
 
 The patch also fixes some style bugs (excessive parentheses).
 
 It's interesting that gcc doesn't warn about this.  It now seems to
 warn only about null comparisons of chars with their limits.  I think
 it recently expanded this warning from one involving only one-sided
 limits of chars.  ISTR looking at the code for this more than 10 years
 ago.  It could have warned about all sorts of null comparisons but
 intentially only gave warnings for a couple of cases to limit the
 warnings.
 
 Hmm, there are more sloppy conversions here:
 
 % 			sbp->f_files = (fxdr_unsigned(int32_t,
 % 			    sfp->sf_tfiles.nfsuquad[1]) & 0x7fffffff);
 % 			sbp->f_ffree = (fxdr_unsigned(int32_t,
 % 			    sfp->sf_ffiles.nfsuquad[1]) & 0x7fffffff);
 
 Looks like it blindly truncates to a 31-bit (positive) int.  f_ffree
 could easily be >= 2^31.  Truncating to 2^31-1 or a documented weird
 (negative) value meaning "overflow" would be better.
 [End of old mail]
 
 Bruce

From: Hendrik Scholz <hscholz@raisdorf.net>
To: freebsd-gnats-submit@freebsd.org
Cc:  
Subject: Re: bin/56606: df cannot handle 2TB NFS volumes
Date: Tue, 30 Sep 2003 22:54:21 +0200

 Hi!
 
 I've just upgraded an Alpha to -current ($FreeBSD: src/sys/nfsclient/nfs_vfsops.c,v 1.137 2003/08/15 12:04:02 phk Exp $) and df now shows
 the correct values.
 5.1-RELEASE-p8 (on i386) on the other hand still shows the broken values.
 
 Hendrik
 
 -- 
 Hendrik Scholz - <hscholz@raisdorf.net> - http://raisdorf.net/
 
 drag me, drop me - treat me like an object 
State-Changed-From-To: open->patched 
State-Changed-By: tjr 
State-Changed-When: Wed Sep 1 02:23:02 GMT 2004 
State-Changed-Why:  
Fixed in -current a long time ago. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=56606 
State-Changed-From-To: patched->closed 
State-Changed-By: remko 
State-Changed-When: Sun Mar 11 10:16:49 UTC 2007 
State-Changed-Why:  
Things that were in -CURRENT in 2004, are in 6.x now (and beyond); so 
assume this is fixed in supported versions now. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=56606 
>Unformatted:
