Commit 476a7b1f authored by J. Bruce Fields's avatar J. Bruce Fields

nfsd4: don't treat readlink like a zero-copy operation

There's no advantage to this zero-copy-style readlink encoding, and it
unnecessarily limits the kinds of compounds we can handle.  (In practice
I can't see why a client would want e.g. multiple readlink calls in a
comound, but it's probably a spec violation for us not to handle it.)
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 3b299709
...@@ -3160,8 +3160,9 @@ static __be32 ...@@ -3160,8 +3160,9 @@ static __be32
nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink) nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink)
{ {
int maxcount; int maxcount;
__be32 wire_count;
int zero = 0;
struct xdr_stream *xdr = &resp->xdr; struct xdr_stream *xdr = &resp->xdr;
char *page;
int length_offset = xdr->buf->len; int length_offset = xdr->buf->len;
__be32 *p; __be32 *p;
...@@ -3171,26 +3172,19 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd ...@@ -3171,26 +3172,19 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
p = xdr_reserve_space(xdr, 4); p = xdr_reserve_space(xdr, 4);
if (!p) if (!p)
return nfserr_resource; return nfserr_resource;
if (resp->xdr.buf->page_len)
return nfserr_resource;
if (!*resp->rqstp->rq_next_page)
return nfserr_resource;
page = page_address(*(resp->rqstp->rq_next_page++));
maxcount = PAGE_SIZE; maxcount = PAGE_SIZE;
if (xdr->end - xdr->p < 1) p = xdr_reserve_space(xdr, maxcount);
if (!p)
return nfserr_resource; return nfserr_resource;
/* /*
* XXX: By default, the ->readlink() VFS op will truncate symlinks * XXX: By default, the ->readlink() VFS op will truncate symlinks
* if they would overflow the buffer. Is this kosher in NFSv4? If * if they would overflow the buffer. Is this kosher in NFSv4? If
* not, one easy fix is: if ->readlink() precisely fills the buffer, * not, one easy fix is: if ->readlink() precisely fills the buffer,
* assume that truncation occurred, and return NFS4ERR_RESOURCE. * assume that truncation occurred, and return NFS4ERR_RESOURCE.
*/ */
nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp, page, &maxcount); nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp,
(char *)p, &maxcount);
if (nfserr == nfserr_isdir) if (nfserr == nfserr_isdir)
nfserr = nfserr_inval; nfserr = nfserr_inval;
if (nfserr) { if (nfserr) {
...@@ -3198,24 +3192,12 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd ...@@ -3198,24 +3192,12 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
return nfserr; return nfserr;
} }
WRITE32(maxcount); wire_count = htonl(maxcount);
resp->xdr.buf->head[0].iov_len = (char *)p write_bytes_to_xdr_buf(xdr->buf, length_offset, &wire_count, 4);
- (char *)resp->xdr.buf->head[0].iov_base; xdr_truncate_encode(xdr, length_offset + 4 + maxcount);
resp->xdr.buf->page_len = maxcount; if (maxcount & 3)
xdr->buf->len += maxcount; write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount,
xdr->page_ptr += 1; &zero, 4 - (maxcount&3));
xdr->buf->buflen -= PAGE_SIZE;
xdr->iov = xdr->buf->tail;
/* Use rest of head for padding and remaining ops: */
resp->xdr.buf->tail[0].iov_base = p;
resp->xdr.buf->tail[0].iov_len = 0;
if (maxcount&3) {
p = xdr_reserve_space(xdr, 4);
WRITE32(0);
resp->xdr.buf->tail[0].iov_base += maxcount&3;
resp->xdr.buf->tail[0].iov_len = 4 - (maxcount&3);
}
return 0; return 0;
} }
......
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