aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4xdr.c
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2014-03-18 17:44:10 -0400
committerJ. Bruce Fields <bfields@redhat.com>2014-05-30 17:32:12 -0400
commitb042098063849794d69b5322fcc6cf9fb5f2586e (patch)
tree954338c0f2de77763df3e8728265b91842984466 /fs/nfsd/nfs4xdr.c
parentfec25fa4ad728dd9b063313f2a61ff65eae0d571 (diff)
nfsd4: allow exotic read compounds
I'm not sure why a client would want to stuff multiple reads in a single compound rpc, but it's legal for them to do it, and we should really support it. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfs4xdr.c')
-rw-r--r--fs/nfsd/nfs4xdr.c61
1 files changed, 25 insertions, 36 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 92f071b44f75..480f12c4e590 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3139,28 +3139,34 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
3139 struct xdr_stream *xdr = &resp->xdr; 3139 struct xdr_stream *xdr = &resp->xdr;
3140 u32 eof; 3140 u32 eof;
3141 int v; 3141 int v;
3142 struct page *page;
3143 int starting_len = xdr->buf->len - 8; 3142 int starting_len = xdr->buf->len - 8;
3144 int space_left;
3145 long len; 3143 long len;
3144 int thislen;
3146 __be32 nfserr; 3145 __be32 nfserr;
3147 __be32 tmp; 3146 __be32 tmp;
3148 __be32 *p; 3147 __be32 *p;
3148 u32 zzz = 0;
3149 int pad;
3149 3150
3150 len = maxcount; 3151 len = maxcount;
3151 v = 0; 3152 v = 0;
3152 while (len) {
3153 int thislen;
3154 3153
3155 page = *(resp->rqstp->rq_next_page); 3154 thislen = (void *)xdr->end - (void *)xdr->p;
3156 if (!page) { /* ran out of pages */ 3155 if (len < thislen)
3157 maxcount -= len; 3156 thislen = len;
3158 break; 3157 p = xdr_reserve_space(xdr, (thislen+3)&~3);
3159 } 3158 WARN_ON_ONCE(!p);
3159 resp->rqstp->rq_vec[v].iov_base = p;
3160 resp->rqstp->rq_vec[v].iov_len = thislen;
3161 v++;
3162 len -= thislen;
3163
3164 while (len) {
3160 thislen = min_t(long, len, PAGE_SIZE); 3165 thislen = min_t(long, len, PAGE_SIZE);
3161 resp->rqstp->rq_vec[v].iov_base = page_address(page); 3166 p = xdr_reserve_space(xdr, (thislen+3)&~3);
3167 WARN_ON_ONCE(!p);
3168 resp->rqstp->rq_vec[v].iov_base = p;
3162 resp->rqstp->rq_vec[v].iov_len = thislen; 3169 resp->rqstp->rq_vec[v].iov_len = thislen;
3163 resp->rqstp->rq_next_page++;
3164 v++; 3170 v++;
3165 len -= thislen; 3171 len -= thislen;
3166 } 3172 }
@@ -3170,6 +3176,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
3170 read->rd_vlen, &maxcount); 3176 read->rd_vlen, &maxcount);
3171 if (nfserr) 3177 if (nfserr)
3172 return nfserr; 3178 return nfserr;
3179 xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3));
3173 3180
3174 eof = (read->rd_offset + maxcount >= 3181 eof = (read->rd_offset + maxcount >=
3175 read->rd_fhp->fh_dentry->d_inode->i_size); 3182 read->rd_fhp->fh_dentry->d_inode->i_size);
@@ -3179,27 +3186,9 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
3179 tmp = htonl(maxcount); 3186 tmp = htonl(maxcount);
3180 write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4); 3187 write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
3181 3188
3182 resp->xdr.buf->page_len = maxcount; 3189 pad = (maxcount&3) ? 4 - (maxcount&3) : 0;
3183 xdr->buf->len += maxcount; 3190 write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + maxcount,
3184 xdr->page_ptr += v; 3191 &zzz, pad);
3185 xdr->iov = xdr->buf->tail;
3186
3187 /* Use rest of head for padding and remaining ops: */
3188 resp->xdr.buf->tail[0].iov_base = xdr->p;
3189 resp->xdr.buf->tail[0].iov_len = 0;
3190 if (maxcount&3) {
3191 p = xdr_reserve_space(xdr, 4);
3192 WRITE32(0);
3193 resp->xdr.buf->tail[0].iov_base += maxcount&3;
3194 resp->xdr.buf->tail[0].iov_len = 4 - (maxcount&3);
3195 xdr->buf->len -= (maxcount&3);
3196 }
3197
3198 space_left = min_t(int, (void *)xdr->end - (void *)xdr->p,
3199 xdr->buf->buflen - xdr->buf->len);
3200 xdr->buf->buflen = xdr->buf->len + space_left;
3201 xdr->end = (__be32 *)((void *)xdr->end + space_left);
3202
3203 return 0; 3192 return 0;
3204 3193
3205} 3194}
@@ -3224,15 +3213,15 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
3224 WARN_ON_ONCE(resp->rqstp->rq_splice_ok); 3213 WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
3225 return nfserr_resource; 3214 return nfserr_resource;
3226 } 3215 }
3227 3216 if (resp->xdr.buf->page_len && resp->rqstp->rq_splice_ok) {
3228 if (resp->xdr.buf->page_len) { 3217 WARN_ON_ONCE(1);
3229 WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
3230 return nfserr_resource; 3218 return nfserr_resource;
3231 } 3219 }
3232
3233 xdr_commit_encode(xdr); 3220 xdr_commit_encode(xdr);
3234 3221
3235 maxcount = svc_max_payload(resp->rqstp); 3222 maxcount = svc_max_payload(resp->rqstp);
3223 if (maxcount > xdr->buf->buflen - xdr->buf->len)
3224 maxcount = xdr->buf->buflen - xdr->buf->len;
3236 if (maxcount > read->rd_length) 3225 if (maxcount > read->rd_length)
3237 maxcount = read->rd_length; 3226 maxcount = read->rd_length;
3238 3227