Commit 6a2f7744 authored by Chuck Lever's avatar Chuck Lever

NFSD: Fix zero-length NFSv3 WRITEs

The Linux NFS server currently responds to a zero-length NFSv3 WRITE
request with NFS3ERR_IO. It responds to a zero-length NFSv4 WRITE
with NFS4_OK and count of zero.

RFC 1813 says of the WRITE procedure's @count argument:

count
         The number of bytes of data to be written. If count is
         0, the WRITE will succeed and return a count of 0,
         barring errors due to permissions checking.

RFC 8881 has similar language for NFSv4, though NFSv4 removed the
explicit @count argument because that value is already contained in
the opaque payload array.

The synthetic client pynfs's WRT4 and WRT15 tests do emit zero-
length WRITEs to exercise this spec requirement. Commit fdec6114
("nfsd4: zero-length WRITE should succeed") addressed the same
problem there with the same fix.

But interestingly the Linux NFS client does not appear to emit zero-
length WRITEs, instead squelching them. I'm not aware of a test that
can generate such WRITEs for NFSv3, so I wrote a naive C program to
generate a zero-length WRITE and test this fix.

Fixes: 8154ef27 ("NFSD: Clean up legacy NFS WRITE argument XDR decoders")
Reported-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 47446d74
...@@ -202,15 +202,11 @@ nfsd3_proc_write(struct svc_rqst *rqstp) ...@@ -202,15 +202,11 @@ nfsd3_proc_write(struct svc_rqst *rqstp)
fh_copy(&resp->fh, &argp->fh); fh_copy(&resp->fh, &argp->fh);
resp->committed = argp->stable; resp->committed = argp->stable;
nvecs = svc_fill_write_vector(rqstp, &argp->payload); nvecs = svc_fill_write_vector(rqstp, &argp->payload);
if (!nvecs) {
resp->status = nfserr_io;
goto out;
}
resp->status = nfsd_write(rqstp, &resp->fh, argp->offset, resp->status = nfsd_write(rqstp, &resp->fh, argp->offset,
rqstp->rq_vec, nvecs, &cnt, rqstp->rq_vec, nvecs, &cnt,
resp->committed, resp->verf); resp->committed, resp->verf);
resp->count = cnt; resp->count = cnt;
out:
return rpc_success; return rpc_success;
} }
......
...@@ -235,10 +235,6 @@ nfsd_proc_write(struct svc_rqst *rqstp) ...@@ -235,10 +235,6 @@ nfsd_proc_write(struct svc_rqst *rqstp)
argp->len, argp->offset); argp->len, argp->offset);
nvecs = svc_fill_write_vector(rqstp, &argp->payload); nvecs = svc_fill_write_vector(rqstp, &argp->payload);
if (!nvecs) {
resp->status = nfserr_io;
goto out;
}
resp->status = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), resp->status = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
argp->offset, rqstp->rq_vec, nvecs, argp->offset, rqstp->rq_vec, nvecs,
...@@ -247,7 +243,6 @@ nfsd_proc_write(struct svc_rqst *rqstp) ...@@ -247,7 +243,6 @@ nfsd_proc_write(struct svc_rqst *rqstp)
resp->status = fh_getattr(&resp->fh, &resp->stat); resp->status = fh_getattr(&resp->fh, &resp->stat);
else if (resp->status == nfserr_jukebox) else if (resp->status == nfserr_jukebox)
return rpc_drop_reply; return rpc_drop_reply;
out:
return rpc_success; return rpc_success;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment