Date: Mon, 2 Feb 2004 10:39:55 -0800 (PST) From: Xiaolin Zang <czang@panasas.FreeBSD.ORG> To: freebsd-gnats-submit@FreeBSD.org Subject: kern/62278: NFS server may not set eof flag when reading last chunk of file Message-ID: <200402021839.i12Idtgp060646@www.freebsd.org> Resent-Message-ID: <200402021850.i12IoICT018150@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 62278 >Category: kern >Synopsis: NFS server may not set eof flag when reading last chunk of file >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Mon Feb 02 10:50:18 PST 2004 >Closed-Date: >Last-Modified: >Originator: Xiaolin Zang >Release: 4.6.2 >Organization: Panasas, Inc >Environment: FreeBSD rack-bsd14 4.6.2-RELEASE FreeBSD 4.6.2-RELEASE #0: Wed Aug 14 21:23:26 GMT 2002 murray@builder.freebsdmall.com:/usr/src/sys/compile/GENERIC i386 >Description: According to RCF 1813 (NFS v3 spec), when the read has reached the end of the file and it should set the eof flag to true in the reply. However in freebsd 4.6.2 (may be the newer versions, too) the eof flag is not set when it should be in the following cases. Suppose the number of bytes requested by the client is N and (N mod 4) == 0. And the read is getting the last chunk of the file and the size of this chunk is M. (N - M) is 1, 2 or 3. The cause is the following lines near the end of the nfsrv_read function. if (v3) { *tl++ = txdr_unsigned(cnt); if (len < reqlen) /* *tl++ = nfs_true; /* else *tl++ = nfs_false; Note variable len is the round-up (to a 4-byte word) of the actually number of bytes read (in variable cnt). >How-To-Repeat: This was found when using RH-8.0 2.4.20-19.8 as the NFS client against a FreeBsd NFS server since that RH Linux uses the eof flag to check the correctness of a read when fewer bytes are read than requested. The RH NFS client always asks for chunks of 4096 bytes. Thus reading (cat, cp, etc) any file of size (N * 4096 - n) where N > 0 and n is 1, 2 or 3 yields input/output error. But the same operation will succeed if repeated immediately, probably because the chunks are in the cache already. >Fix: The following change should fix the problem. ==== freebsd/src/sys/nfs/nfs_serv.c#3 - freebsd/src/sys/nfs/nfs_serv.c ==== @@ -785,7 +785,7 @@ struct uio io, *uiop = &io; struct vattr va, *vap = &va; struct nfsheur *nh; - off_t off; + off_t off, initial_off; int ioflag = 0; u_quad_t frev; @@ -794,10 +794,10 @@ nfsm_srvmtofh(fhp); if (v3) { nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - off = fxdr_hyper(tl); + initial_off = off = fxdr_hyper(tl); } else { nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - off = (off_t)fxdr_unsigned(u_int32_t, *tl); + initial_off = off = (off_t)fxdr_unsigned(u_int32_t, *tl); } nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd)); @@ -991,7 +991,7 @@ nfsm_adj(mb, len - tlen, tlen - cnt); if (v3) { *tl++ = txdr_unsigned(cnt); - if (len < reqlen) + if (initial_off + cnt >= vap->va_size) *tl++ = nfs_true; else *tl++ = nfs_false; By the way I have made a robot that can read the image and enter it in the little yellow space -- just kidding. >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200402021839.i12Idtgp060646>