{
        __be32  nfserr;
        u32     max_blocksize = svc_max_payload(rqstp);
+       unsigned long cnt = min(argp->count, max_blocksize);
 
        dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
                                SVCFH_fmt(&argp->fh),
         * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
         * + 1 (xdr opaque byte count) = 26
         */
-       resp->count = min(argp->count, max_blocksize);
+       resp->count = cnt;
        svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
 
        fh_copy(&resp->fh, &argp->fh);
                                  &resp->count);
        if (nfserr == 0) {
                struct inode    *inode = d_inode(resp->fh.fh_dentry);
-
-               resp->eof = (argp->offset + resp->count) >= inode->i_size;
+               resp->eof = nfsd_eof_on_read(cnt, resp->count, argp->offset,
+                                                       inode->i_size);
        }
 
        RETURN_STATUS(nfserr);
 
        struct xdr_stream *xdr = &resp->xdr;
        struct xdr_buf *buf = xdr->buf;
        u32 eof;
+       long len;
        int space_left;
        __be32 nfserr;
        __be32 *p = xdr->p - 2;
        if (xdr->end - xdr->p < 1)
                return nfserr_resource;
 
+       len = maxcount;
        nfserr = nfsd_splice_read(read->rd_rqstp, file,
                                  read->rd_offset, &maxcount);
        if (nfserr) {
                return nfserr;
        }
 
-       eof = (read->rd_offset + maxcount >=
-              d_inode(read->rd_fhp->fh_dentry)->i_size);
+       eof = nfsd_eof_on_read(len, maxcount, read->rd_offset,
+                               d_inode(read->rd_fhp->fh_dentry)->i_size);
 
        *(p++) = htonl(eof);
        *(p++) = htonl(maxcount);
        }
        read->rd_vlen = v;
 
+       len = maxcount;
        nfserr = nfsd_readv(file, read->rd_offset, resp->rqstp->rq_vec,
                        read->rd_vlen, &maxcount);
        if (nfserr)
                return nfserr;
        xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3));
 
-       eof = (read->rd_offset + maxcount >=
-              d_inode(read->rd_fhp->fh_dentry)->i_size);
+       eof = nfsd_eof_on_read(len, maxcount, read->rd_offset,
+                               d_inode(read->rd_fhp->fh_dentry)->i_size);
 
        tmp = htonl(eof);
        write_bytes_to_xdr_buf(xdr->buf, starting_len    , &tmp, 4);
 
               || createmode == NFS4_CREATE_EXCLUSIVE4_1;
 }
 
+static inline bool nfsd_eof_on_read(long requested, long read,
+                               loff_t offset, loff_t size)
+{
+       /* We assume a short read means eof: */
+       if (requested > read)
+               return true;
+       /*
+        * A non-short read might also reach end of file.  The spec
+        * still requires us to set eof in that case.
+        *
+        * Further operations may have modified the file size since
+        * the read, so the following check is not atomic with the read.
+        * We've only seen that cause a problem for a client in the case
+        * where the read returned a count of 0 without setting eof.
+        * That case was fixed by the addition of the above check.
+        */
+       return (offset + read >= size);
+}
+
 #endif /* LINUX_NFSD_VFS_H */