aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2014-01-20 17:08:27 -0500
committerJ. Bruce Fields <bfields@redhat.com>2014-05-30 17:32:05 -0400
commit476a7b1f4b2c9c38255653fa55157565be8b14be (patch)
treed44f678620c4789cb9679ddd6cbf8e52d8e8d314
parent3b299709091befc0e02aa33d55ddd5baef006853 (diff)
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: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfsd/nfs4xdr.c42
1 files changed, 12 insertions, 30 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 3f2a52ccb9d1..cda6226bda91 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3160,8 +3160,9 @@ static __be32
3160nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink) 3160nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink)
3161{ 3161{
3162 int maxcount; 3162 int maxcount;
3163 __be32 wire_count;
3164 int zero = 0;
3163 struct xdr_stream *xdr = &resp->xdr; 3165 struct xdr_stream *xdr = &resp->xdr;
3164 char *page;
3165 int length_offset = xdr->buf->len; 3166 int length_offset = xdr->buf->len;
3166 __be32 *p; 3167 __be32 *p;
3167 3168
@@ -3171,26 +3172,19 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
3171 p = xdr_reserve_space(xdr, 4); 3172 p = xdr_reserve_space(xdr, 4);
3172 if (!p) 3173 if (!p)
3173 return nfserr_resource; 3174 return nfserr_resource;
3174
3175 if (resp->xdr.buf->page_len)
3176 return nfserr_resource;
3177 if (!*resp->rqstp->rq_next_page)
3178 return nfserr_resource;
3179
3180 page = page_address(*(resp->rqstp->rq_next_page++));
3181
3182 maxcount = PAGE_SIZE; 3175 maxcount = PAGE_SIZE;
3183 3176
3184 if (xdr->end - xdr->p < 1) 3177 p = xdr_reserve_space(xdr, maxcount);
3178 if (!p)
3185 return nfserr_resource; 3179 return nfserr_resource;
3186
3187 /* 3180 /*
3188 * XXX: By default, the ->readlink() VFS op will truncate symlinks 3181 * XXX: By default, the ->readlink() VFS op will truncate symlinks
3189 * if they would overflow the buffer. Is this kosher in NFSv4? If 3182 * if they would overflow the buffer. Is this kosher in NFSv4? If
3190 * not, one easy fix is: if ->readlink() precisely fills the buffer, 3183 * not, one easy fix is: if ->readlink() precisely fills the buffer,
3191 * assume that truncation occurred, and return NFS4ERR_RESOURCE. 3184 * assume that truncation occurred, and return NFS4ERR_RESOURCE.
3192 */ 3185 */
3193 nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp, page, &maxcount); 3186 nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp,
3187 (char *)p, &maxcount);
3194 if (nfserr == nfserr_isdir) 3188 if (nfserr == nfserr_isdir)
3195 nfserr = nfserr_inval; 3189 nfserr = nfserr_inval;
3196 if (nfserr) { 3190 if (nfserr) {
@@ -3198,24 +3192,12 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
3198 return nfserr; 3192 return nfserr;
3199 } 3193 }
3200 3194
3201 WRITE32(maxcount); 3195 wire_count = htonl(maxcount);
3202 resp->xdr.buf->head[0].iov_len = (char *)p 3196 write_bytes_to_xdr_buf(xdr->buf, length_offset, &wire_count, 4);
3203 - (char *)resp->xdr.buf->head[0].iov_base; 3197 xdr_truncate_encode(xdr, length_offset + 4 + maxcount);
3204 resp->xdr.buf->page_len = maxcount; 3198 if (maxcount & 3)
3205 xdr->buf->len += maxcount; 3199 write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount,
3206 xdr->page_ptr += 1; 3200 &zero, 4 - (maxcount&3));
3207 xdr->buf->buflen -= PAGE_SIZE;
3208 xdr->iov = xdr->buf->tail;
3209
3210 /* Use rest of head for padding and remaining ops: */
3211 resp->xdr.buf->tail[0].iov_base = p;
3212 resp->xdr.buf->tail[0].iov_len = 0;
3213 if (maxcount&3) {
3214 p = xdr_reserve_space(xdr, 4);
3215 WRITE32(0);
3216 resp->xdr.buf->tail[0].iov_base += maxcount&3;
3217 resp->xdr.buf->tail[0].iov_len = 4 - (maxcount&3);
3218 }
3219 return 0; 3201 return 0;
3220} 3202}
3221 3203