diff options
Diffstat (limited to 'fs/nfsd/nfsxdr.c')
-rw-r--r-- | fs/nfsd/nfsxdr.c | 46 |
1 files changed, 39 insertions, 7 deletions
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 0c24b9e24fe8..6035e03655c6 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c | |||
@@ -284,8 +284,9 @@ int | |||
284 | nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | 284 | nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, |
285 | struct nfsd_writeargs *args) | 285 | struct nfsd_writeargs *args) |
286 | { | 286 | { |
287 | unsigned int len; | 287 | unsigned int len, hdr, dlen; |
288 | int v; | 288 | int v; |
289 | |||
289 | if (!(p = decode_fh(p, &args->fh))) | 290 | if (!(p = decode_fh(p, &args->fh))) |
290 | return 0; | 291 | return 0; |
291 | 292 | ||
@@ -293,11 +294,42 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | |||
293 | args->offset = ntohl(*p++); /* offset */ | 294 | args->offset = ntohl(*p++); /* offset */ |
294 | p++; /* totalcount */ | 295 | p++; /* totalcount */ |
295 | len = args->len = ntohl(*p++); | 296 | len = args->len = ntohl(*p++); |
296 | rqstp->rq_vec[0].iov_base = (void*)p; | 297 | /* |
297 | rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - | 298 | * The protocol specifies a maximum of 8192 bytes. |
298 | (((void*)p) - rqstp->rq_arg.head[0].iov_base); | 299 | */ |
299 | if (len > NFSSVC_MAXBLKSIZE_V2) | 300 | if (len > NFSSVC_MAXBLKSIZE_V2) |
300 | len = NFSSVC_MAXBLKSIZE_V2; | 301 | return 0; |
302 | |||
303 | /* | ||
304 | * Check to make sure that we got the right number of | ||
305 | * bytes. | ||
306 | * | ||
307 | * If more than one page was used, then compute the length | ||
308 | * of the data in the request as the total size of the | ||
309 | * request minus the transport protocol headers minus the | ||
310 | * RPC protocol headers minus the NFS protocol fields | ||
311 | * already consumed. If the request fits into a single | ||
312 | * page, then compete the length of the data as the size | ||
313 | * of the NFS portion of the request minus the NFS | ||
314 | * protocol fields already consumed. | ||
315 | */ | ||
316 | hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; | ||
317 | if (rqstp->rq_respages != rqstp->rq_pages + 1) { | ||
318 | dlen = rqstp->rq_arg.len - | ||
319 | (PAGE_SIZE - rqstp->rq_arg.head[0].iov_len) - hdr; | ||
320 | } else { | ||
321 | dlen = rqstp->rq_arg.head[0].iov_len - hdr; | ||
322 | } | ||
323 | /* | ||
324 | * Round the length of the data which was specified up to | ||
325 | * the next multiple of XDR units and then compare that | ||
326 | * against the length which was actually received. | ||
327 | */ | ||
328 | if (dlen != ((len + 3) & ~0x3)) | ||
329 | return 0; | ||
330 | |||
331 | rqstp->rq_vec[0].iov_base = (void*)p; | ||
332 | rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; | ||
301 | v = 0; | 333 | v = 0; |
302 | while (len > rqstp->rq_vec[v].iov_len) { | 334 | while (len > rqstp->rq_vec[v].iov_len) { |
303 | len -= rqstp->rq_vec[v].iov_len; | 335 | len -= rqstp->rq_vec[v].iov_len; |
@@ -306,8 +338,8 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | |||
306 | rqstp->rq_vec[v].iov_len = PAGE_SIZE; | 338 | rqstp->rq_vec[v].iov_len = PAGE_SIZE; |
307 | } | 339 | } |
308 | rqstp->rq_vec[v].iov_len = len; | 340 | rqstp->rq_vec[v].iov_len = len; |
309 | args->vlen = v+1; | 341 | args->vlen = v + 1; |
310 | return rqstp->rq_vec[0].iov_len > 0; | 342 | return 1; |
311 | } | 343 | } |
312 | 344 | ||
313 | int | 345 | int |