Skip to content

Commit 83a6307

Browse files
trondmyJ. Bruce Fields
authored andcommitted
nfsd: fix nfs read eof detection
Currently, the knfsd server assumes that a short read indicates an end of file. That assumption is incorrect. The short read means that either we've hit the end of file, or we've hit a read error. In the case of a read error, the client may want to retry (as per the implementation recommendations in RFC1813 and RFC7530), but currently it is being told that it hit an eof. Move the code to detect eof from version specific code into the generic nfsd read. Report eof only in the two following cases: 1) read() returns a zero length short read with no error. 2) the offset+length of the read is >= the file size. Signed-off-by: Trond Myklebust <[email protected]> Signed-off-by: J. Bruce Fields <[email protected]>
1 parent 65643f4 commit 83a6307

File tree

6 files changed

+41
-50
lines changed

6 files changed

+41
-50
lines changed

fs/nfsd/nfs3proc.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -172,13 +172,8 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
172172
nfserr = nfsd_read(rqstp, &resp->fh,
173173
argp->offset,
174174
rqstp->rq_vec, argp->vlen,
175-
&resp->count);
176-
if (nfserr == 0) {
177-
struct inode *inode = d_inode(resp->fh.fh_dentry);
178-
resp->eof = nfsd_eof_on_read(cnt, resp->count, argp->offset,
179-
inode->i_size);
180-
}
181-
175+
&resp->count,
176+
&resp->eof);
182177
RETURN_STATUS(nfserr);
183178
}
184179

fs/nfsd/nfs4xdr.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3472,7 +3472,7 @@ static __be32 nfsd4_encode_splice_read(
34723472

34733473
len = maxcount;
34743474
nfserr = nfsd_splice_read(read->rd_rqstp, read->rd_fhp,
3475-
file, read->rd_offset, &maxcount);
3475+
file, read->rd_offset, &maxcount, &eof);
34763476
read->rd_length = maxcount;
34773477
if (nfserr) {
34783478
/*
@@ -3484,9 +3484,6 @@ static __be32 nfsd4_encode_splice_read(
34843484
return nfserr;
34853485
}
34863486

3487-
eof = nfsd_eof_on_read(len, maxcount, read->rd_offset,
3488-
d_inode(read->rd_fhp->fh_dentry)->i_size);
3489-
34903487
*(p++) = htonl(eof);
34913488
*(p++) = htonl(maxcount);
34923489

@@ -3557,15 +3554,13 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
35573554

35583555
len = maxcount;
35593556
nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset,
3560-
resp->rqstp->rq_vec, read->rd_vlen, &maxcount);
3557+
resp->rqstp->rq_vec, read->rd_vlen, &maxcount,
3558+
&eof);
35613559
read->rd_length = maxcount;
35623560
if (nfserr)
35633561
return nfserr;
35643562
xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3));
35653563

3566-
eof = nfsd_eof_on_read(len, maxcount, read->rd_offset,
3567-
d_inode(read->rd_fhp->fh_dentry)->i_size);
3568-
35693564
tmp = htonl(eof);
35703565
write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4);
35713566
tmp = htonl(maxcount);

fs/nfsd/nfsproc.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ nfsd_proc_read(struct svc_rqst *rqstp)
172172
struct nfsd_readargs *argp = rqstp->rq_argp;
173173
struct nfsd_readres *resp = rqstp->rq_resp;
174174
__be32 nfserr;
175+
u32 eof;
175176

176177
dprintk("nfsd: READ %s %d bytes at %d\n",
177178
SVCFH_fmt(&argp->fh),
@@ -195,7 +196,8 @@ nfsd_proc_read(struct svc_rqst *rqstp)
195196
nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
196197
argp->offset,
197198
rqstp->rq_vec, argp->vlen,
198-
&resp->count);
199+
&resp->count,
200+
&eof);
199201

200202
if (nfserr) return nfserr;
201203
return fh_getattr(&resp->fh, &resp->stat);

fs/nfsd/vfs.c

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -834,12 +834,23 @@ static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe,
834834
return __splice_from_pipe(pipe, sd, nfsd_splice_actor);
835835
}
836836

837+
static u32 nfsd_eof_on_read(struct file *file, loff_t offset, ssize_t len,
838+
size_t expected)
839+
{
840+
if (expected != 0 && len == 0)
841+
return 1;
842+
if (offset+len >= i_size_read(file_inode(file)))
843+
return 1;
844+
return 0;
845+
}
846+
837847
static __be32 nfsd_finish_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
838848
struct file *file, loff_t offset,
839-
unsigned long *count, int host_err)
849+
unsigned long *count, u32 *eof, ssize_t host_err)
840850
{
841851
if (host_err >= 0) {
842852
nfsdstats.io_read += host_err;
853+
*eof = nfsd_eof_on_read(file, offset, host_err, *count);
843854
*count = host_err;
844855
fsnotify_access(file);
845856
trace_nfsd_read_io_done(rqstp, fhp, offset, *count);
@@ -851,33 +862,36 @@ static __be32 nfsd_finish_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
851862
}
852863

853864
__be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
854-
struct file *file, loff_t offset, unsigned long *count)
865+
struct file *file, loff_t offset, unsigned long *count,
866+
u32 *eof)
855867
{
856868
struct splice_desc sd = {
857869
.len = 0,
858870
.total_len = *count,
859871
.pos = offset,
860872
.u.data = rqstp,
861873
};
862-
int host_err;
874+
ssize_t host_err;
863875

864876
trace_nfsd_read_splice(rqstp, fhp, offset, *count);
865877
rqstp->rq_next_page = rqstp->rq_respages + 1;
866878
host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);
867-
return nfsd_finish_read(rqstp, fhp, file, offset, count, host_err);
879+
return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err);
868880
}
869881

870882
__be32 nfsd_readv(struct svc_rqst *rqstp, struct svc_fh *fhp,
871883
struct file *file, loff_t offset,
872-
struct kvec *vec, int vlen, unsigned long *count)
884+
struct kvec *vec, int vlen, unsigned long *count,
885+
u32 *eof)
873886
{
874887
struct iov_iter iter;
875-
int host_err;
888+
loff_t ppos = offset;
889+
ssize_t host_err;
876890

877891
trace_nfsd_read_vector(rqstp, fhp, offset, *count);
878892
iov_iter_kvec(&iter, READ, vec, vlen, *count);
879-
host_err = vfs_iter_read(file, &iter, &offset, 0);
880-
return nfsd_finish_read(rqstp, fhp, file, offset, count, host_err);
893+
host_err = vfs_iter_read(file, &iter, &ppos, 0);
894+
return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err);
881895
}
882896

883897
/*
@@ -984,7 +998,8 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
984998
* N.B. After this call fhp needs an fh_put
985999
*/
9861000
__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
987-
loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
1001+
loff_t offset, struct kvec *vec, int vlen, unsigned long *count,
1002+
u32 *eof)
9881003
{
9891004
struct nfsd_file *nf;
9901005
struct file *file;
@@ -997,9 +1012,9 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
9971012

9981013
file = nf->nf_file;
9991014
if (file->f_op->splice_read && test_bit(RQ_SPLICE_OK, &rqstp->rq_flags))
1000-
err = nfsd_splice_read(rqstp, fhp, file, offset, count);
1015+
err = nfsd_splice_read(rqstp, fhp, file, offset, count, eof);
10011016
else
1002-
err = nfsd_readv(rqstp, fhp, file, offset, vec, vlen, count);
1017+
err = nfsd_readv(rqstp, fhp, file, offset, vec, vlen, count, eof);
10031018

10041019
nfsd_file_put(nf);
10051020

fs/nfsd/vfs.h

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,16 @@ __be32 nfsd_open_verified(struct svc_rqst *, struct svc_fh *, umode_t,
8080
int, struct file **);
8181
__be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
8282
struct file *file, loff_t offset,
83-
unsigned long *count);
83+
unsigned long *count,
84+
u32 *eof);
8485
__be32 nfsd_readv(struct svc_rqst *rqstp, struct svc_fh *fhp,
8586
struct file *file, loff_t offset,
8687
struct kvec *vec, int vlen,
87-
unsigned long *count);
88+
unsigned long *count,
89+
u32 *eof);
8890
__be32 nfsd_read(struct svc_rqst *, struct svc_fh *,
89-
loff_t, struct kvec *, int, unsigned long *);
91+
loff_t, struct kvec *, int, unsigned long *,
92+
u32 *eof);
9093
__be32 nfsd_write(struct svc_rqst *, struct svc_fh *, loff_t,
9194
struct kvec *, int, unsigned long *, int);
9295
__be32 nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp,
@@ -149,23 +152,4 @@ static inline int nfsd_create_is_exclusive(int createmode)
149152
|| createmode == NFS4_CREATE_EXCLUSIVE4_1;
150153
}
151154

152-
static inline bool nfsd_eof_on_read(long requested, long read,
153-
loff_t offset, loff_t size)
154-
{
155-
/* We assume a short read means eof: */
156-
if (requested > read)
157-
return true;
158-
/*
159-
* A non-short read might also reach end of file. The spec
160-
* still requires us to set eof in that case.
161-
*
162-
* Further operations may have modified the file size since
163-
* the read, so the following check is not atomic with the read.
164-
* We've only seen that cause a problem for a client in the case
165-
* where the read returned a count of 0 without setting eof.
166-
* That case was fixed by the addition of the above check.
167-
*/
168-
return (offset + read >= size);
169-
}
170-
171155
#endif /* LINUX_NFSD_VFS_H */

fs/nfsd/xdr3.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ struct nfsd3_readres {
151151
__be32 status;
152152
struct svc_fh fh;
153153
unsigned long count;
154-
int eof;
154+
__u32 eof;
155155
};
156156

157157
struct nfsd3_writeres {

0 commit comments

Comments
 (0)