Subject: Re: NetBSD/sparc crashes when doing NFS to an NT box
To: Alan Perry <alanp@collabracare.com>
From: Frank van der Linden <frank@wins.uva.nl>
List: netbsd-help
Date: 08/16/1997 01:34:31
On Fri, Aug 15, 1997 at 10:13:17AM -0700, Alan Perry wrote:
> 
> I have a SPARCclassic running NetBSD 1.2.  I have a PC running NT 4 and
> Intergraph's Disk Share NFS server.
> 
> I am able to export (uh, er, sharing) directories from the NT box and
> mount the directories on the NetBSD box.  I am even able to 'ls' and
> 'touch filename' on the mounted stuff.  However, when I try put
> something with data in it on the mounted directory, NetBSD panics.

Right.. this is usual behavior; I changed the NFS code in such a way
that it refuses to interact with Microsoft products. You lose!

..ok, actually this is a problem that was reported and fixed by Olaf
Seibert. The NT NFS server sends 0 for some values in the FSINFO
RPC call, which causes the NetBSD client to get a division by zero
sometime later. The fix is appended below.

- Frank

===============================================================================

Earlier, I wrote in kern/3687:
> 	NFS client operation causes divide by zero trap in kernel
>
> 	The trace command of DDB showed (retyped from the screen)
>
> ___qdivrem(0,0,0,0,0) at ___qdivrem+0x2b
> ___divdi3(0,0,0,0) at ___divdi3+0x5f
> _nfs_bioread(f87cdf00,f9aacf20,0,f8795500,f9aaceec) at _nfs_bioread+0x43a
> _nfs_read(f9aaced8,4000,f9aacf88,f8761200,f9aaced8) at _nfs_read+0x1e
> _vn_read(f87ce000,f9aacf20,f8795500) at _vn_read+0xaf
> _sys_read(f876120,f9aacf88,f9aacf80,0,3) at _sys_read+0xa3
> _syscall() at _syscall+0x248
> --- syscall (number 3) ---
>
> >How-To-Repeat:
> 	I mounted a disk from an NT nfs server, cd'ed into a directory,
> 	and cat'ted an empty file.
>
> 	Other simple operation also caused crashes, maybe similar to
> 	this, maybe not. I'm not sure yet.
>
> 	I first saw this on a 586 with 32M ram, now I repeated it on
> 	a 486 with 16M ram. It also happened with an 1.2 kernel.
> >Fix:
> 	Dunno :-(
>

I have a fix now. I'm not 100% sure it is the best fix, but it probably
is (short of dumping NT, of course). It turns out that (several) NT NFS
servers set the preferred read/write block sizes to 0. The following
(approximate) patch (relative to 1.2.1 source) ignores these values if
they "don't make sense". I defined this as "are smaller than the natural
block size".

/*      $NetBSD: nfs_vfsops.c,v 1.46.4.2 1996/12/11 09:53:49 mycroft Exp $
*/

*** nfs_vfsops.c.dist	Mon Jun  2 16:44:24 1997
--- nfs_vfsops.c	Mon Jun  2 11:55:25 1997
***************
*** 215,221 ****
  	if (!error) {
  		nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
  		pref = fxdr_unsigned(u_int32_t, fsp->fs_wtpref);
! 		if (pref < nmp->nm_wsize)
  			nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
  				~(NFS_FABLKSIZE - 1);
  		max = fxdr_unsigned(u_int32_t, fsp->fs_wtmax);
--- 215,222 ----
  	if (!error) {
  		nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
  		pref = fxdr_unsigned(u_int32_t, fsp->fs_wtpref);
! 		/* && pref > NFS_ added by Rhialto */
! 		if (pref < nmp->nm_wsize && pref >= NFS_FABLKSIZE)
  			nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
  				~(NFS_FABLKSIZE - 1);
  		max = fxdr_unsigned(u_int32_t, fsp->fs_wtmax);
***************
*** 225,241 ****
  				nmp->nm_wsize = max;
  		}
  		pref = fxdr_unsigned(u_int32_t, fsp->fs_rtpref);
! 		if (pref < nmp->nm_rsize)
  			nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
  				~(NFS_FABLKSIZE - 1);
  		max = fxdr_unsigned(u_int32_t, fsp->fs_rtmax);
  		if (max < nmp->nm_rsize) {
  			nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
  			if (nmp->nm_rsize == 0)
  				nmp->nm_rsize = max;
  		}
  		pref = fxdr_unsigned(u_int32_t, fsp->fs_dtpref);
! 		if (pref < nmp->nm_readdirsize)
  			nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) &
  				~(NFS_DIRBLKSIZ - 1);
  		if (max < nmp->nm_readdirsize) {
--- 226,246 ----
  				nmp->nm_wsize = max;
  		}
  		pref = fxdr_unsigned(u_int32_t, fsp->fs_rtpref);
! 		/* && pref > NFS_ added by Rhialto */
! 		if (pref < nmp->nm_rsize && pref >= NFS_FABLKSIZE)
  			nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
  				~(NFS_FABLKSIZE - 1);
  		max = fxdr_unsigned(u_int32_t, fsp->fs_rtmax);
  		if (max < nmp->nm_rsize) {
  			nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
  			if (nmp->nm_rsize == 0)
  				nmp->nm_rsize = max;
  		}
  		pref = fxdr_unsigned(u_int32_t, fsp->fs_dtpref);
! 		/* && pref > NFS_ added by Rhialto */
! 		if (pref < nmp->nm_readdirsize && pref >= NFS_DIRBLKSIZ)
  			nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) &
  				~(NFS_DIRBLKSIZ - 1);
  		if (max < nmp->nm_readdirsize) {

-Olaf.
--
___ Olaf 'Rhialto' Seibert      D787B44DFC896063 4CBB95A5BD1DAA96 
\X/ It's not easy having a good time    rhialto@polder.ubc.kun.nl

==============================================================================