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). 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. 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.
State Changed From-To: open->analyzed This has already been fixed in FreeBSD 5.2 and FreeBSD 4.9, but I think your patch possibly results in more correct behaviour than the current code (your patch returns eof=true when the request ends exactly at the end of the file, whereas the current code returns false but the next read returns 0 bytes with eof=true).
Responsible Changed From-To: freebsd-bugs->iedowse I'll take this as a reminder to look at it.
Responsible Changed From-To: iedowse->freebsd-bugs With permission, reassign from committer who is away from FreeBSD work for now. From the audit trail, it sounds as though the problem may have been fixed another way by now.
For bugs matching the following conditions: - Status == In Progress - Assignee == "bugs@FreeBSD.org" - Last Modified Year <= 2017 Do - Set Status to "Open"
Keyword: patch or patch-ready – in lieu of summary line prefix: [patch] * bulk change for the keyword * summary lines may be edited manually (not in bulk). Keyword descriptions and search interface: <https://bugs.freebsd.org/bugzilla/describekeywords.cgi>