|
@@ -3160,8 +3160,9 @@ static __be32
|
|
|
nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink)
|
|
|
{
|
|
|
int maxcount;
|
|
|
+ __be32 wire_count;
|
|
|
+ int zero = 0;
|
|
|
struct xdr_stream *xdr = &resp->xdr;
|
|
|
- char *page;
|
|
|
int length_offset = xdr->buf->len;
|
|
|
__be32 *p;
|
|
|
|
|
@@ -3171,26 +3172,19 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
|
|
|
p = xdr_reserve_space(xdr, 4);
|
|
|
if (!p)
|
|
|
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;
|
|
|
|
|
|
- if (xdr->end - xdr->p < 1)
|
|
|
+ p = xdr_reserve_space(xdr, maxcount);
|
|
|
+ if (!p)
|
|
|
return nfserr_resource;
|
|
|
-
|
|
|
/*
|
|
|
* XXX: By default, the ->readlink() VFS op will truncate symlinks
|
|
|
* if they would overflow the buffer. Is this kosher in NFSv4? If
|
|
|
* not, one easy fix is: if ->readlink() precisely fills the buffer,
|
|
|
* 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)
|
|
|
nfserr = nfserr_inval;
|
|
|
if (nfserr) {
|
|
@@ -3198,24 +3192,12 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
|
|
|
return nfserr;
|
|
|
}
|
|
|
|
|
|
- WRITE32(maxcount);
|
|
|
- resp->xdr.buf->head[0].iov_len = (char *)p
|
|
|
- - (char *)resp->xdr.buf->head[0].iov_base;
|
|
|
- resp->xdr.buf->page_len = maxcount;
|
|
|
- xdr->buf->len += maxcount;
|
|
|
- xdr->page_ptr += 1;
|
|
|
- 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);
|
|
|
- }
|
|
|
+ wire_count = htonl(maxcount);
|
|
|
+ write_bytes_to_xdr_buf(xdr->buf, length_offset, &wire_count, 4);
|
|
|
+ xdr_truncate_encode(xdr, length_offset + 4 + maxcount);
|
|
|
+ if (maxcount & 3)
|
|
|
+ write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount,
|
|
|
+ &zero, 4 - (maxcount&3));
|
|
|
return 0;
|
|
|
}
|
|
|
|