diff options
author | Weston Andros Adamson <dros@netapp.com> | 2011-03-24 16:48:21 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-03-24 17:01:41 -0400 |
commit | 35124a0994fc02545b14b9fa3aad000b3331f1c0 (patch) | |
tree | 5149267f387199fd9ca2718c74d86b6779013501 /fs/nfs/nfs4filelayoutdev.c | |
parent | ef31153786bc1e4304e6b9422cc8b9efef455611 (diff) |
Cleanup XDR parsing for LAYOUTGET, GETDEVICEINFO
changes LAYOUTGET and GETDEVICEINFO XDR parsing to:
- not use vmap, which doesn't work on incoherent archs
- use xdr_stream parsing for all xdr
Signed-off-by: Weston Andros Adamson <dros@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4filelayoutdev.c')
-rw-r--r-- | fs/nfs/nfs4filelayoutdev.c | 178 |
1 files changed, 122 insertions, 56 deletions
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index 68143c162e3b..de5350f2b249 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c | |||
@@ -261,7 +261,7 @@ out: | |||
261 | * Currently only support ipv4, and one multi-path address. | 261 | * Currently only support ipv4, and one multi-path address. |
262 | */ | 262 | */ |
263 | static struct nfs4_pnfs_ds * | 263 | static struct nfs4_pnfs_ds * |
264 | decode_and_add_ds(__be32 **pp, struct inode *inode) | 264 | decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode) |
265 | { | 265 | { |
266 | struct nfs4_pnfs_ds *ds = NULL; | 266 | struct nfs4_pnfs_ds *ds = NULL; |
267 | char *buf; | 267 | char *buf; |
@@ -269,25 +269,34 @@ decode_and_add_ds(__be32 **pp, struct inode *inode) | |||
269 | u32 ip_addr, port; | 269 | u32 ip_addr, port; |
270 | int nlen, rlen, i; | 270 | int nlen, rlen, i; |
271 | int tmp[2]; | 271 | int tmp[2]; |
272 | __be32 *r_netid, *r_addr, *p = *pp; | 272 | __be32 *p; |
273 | 273 | ||
274 | /* r_netid */ | 274 | /* r_netid */ |
275 | p = xdr_inline_decode(streamp, 4); | ||
276 | if (unlikely(!p)) | ||
277 | goto out_err; | ||
275 | nlen = be32_to_cpup(p++); | 278 | nlen = be32_to_cpup(p++); |
276 | r_netid = p; | ||
277 | p += XDR_QUADLEN(nlen); | ||
278 | 279 | ||
279 | /* r_addr */ | 280 | p = xdr_inline_decode(streamp, nlen); |
280 | rlen = be32_to_cpup(p++); | 281 | if (unlikely(!p)) |
281 | r_addr = p; | 282 | goto out_err; |
282 | p += XDR_QUADLEN(rlen); | ||
283 | *pp = p; | ||
284 | 283 | ||
285 | /* Check that netid is "tcp" */ | 284 | /* Check that netid is "tcp" */ |
286 | if (nlen != 3 || memcmp((char *)r_netid, "tcp", 3)) { | 285 | if (nlen != 3 || memcmp((char *)p, "tcp", 3)) { |
287 | dprintk("%s: ERROR: non ipv4 TCP r_netid\n", __func__); | 286 | dprintk("%s: ERROR: non ipv4 TCP r_netid\n", __func__); |
288 | goto out_err; | 287 | goto out_err; |
289 | } | 288 | } |
290 | 289 | ||
290 | /* r_addr */ | ||
291 | p = xdr_inline_decode(streamp, 4); | ||
292 | if (unlikely(!p)) | ||
293 | goto out_err; | ||
294 | rlen = be32_to_cpup(p); | ||
295 | |||
296 | p = xdr_inline_decode(streamp, rlen); | ||
297 | if (unlikely(!p)) | ||
298 | goto out_err; | ||
299 | |||
291 | /* ipv6 length plus port is legal */ | 300 | /* ipv6 length plus port is legal */ |
292 | if (rlen > INET6_ADDRSTRLEN + 8) { | 301 | if (rlen > INET6_ADDRSTRLEN + 8) { |
293 | dprintk("%s: Invalid address, length %d\n", __func__, | 302 | dprintk("%s: Invalid address, length %d\n", __func__, |
@@ -300,7 +309,7 @@ decode_and_add_ds(__be32 **pp, struct inode *inode) | |||
300 | goto out_err; | 309 | goto out_err; |
301 | } | 310 | } |
302 | buf[rlen] = '\0'; | 311 | buf[rlen] = '\0'; |
303 | memcpy(buf, r_addr, rlen); | 312 | memcpy(buf, p, rlen); |
304 | 313 | ||
305 | /* replace the port dots with dashes for the in4_pton() delimiter*/ | 314 | /* replace the port dots with dashes for the in4_pton() delimiter*/ |
306 | for (i = 0; i < 2; i++) { | 315 | for (i = 0; i < 2; i++) { |
@@ -336,90 +345,154 @@ out_err: | |||
336 | static struct nfs4_file_layout_dsaddr* | 345 | static struct nfs4_file_layout_dsaddr* |
337 | decode_device(struct inode *ino, struct pnfs_device *pdev) | 346 | decode_device(struct inode *ino, struct pnfs_device *pdev) |
338 | { | 347 | { |
339 | int i, dummy; | 348 | int i; |
340 | u32 cnt, num; | 349 | u32 cnt, num; |
341 | u8 *indexp; | 350 | u8 *indexp; |
342 | __be32 *p = (__be32 *)pdev->area, *indicesp; | 351 | __be32 *p; |
343 | struct nfs4_file_layout_dsaddr *dsaddr; | 352 | u8 *stripe_indices; |
353 | u8 max_stripe_index; | ||
354 | struct nfs4_file_layout_dsaddr *dsaddr = NULL; | ||
355 | struct xdr_stream stream; | ||
356 | struct xdr_buf buf = { | ||
357 | .pages = pdev->pages, | ||
358 | .page_len = pdev->pglen, | ||
359 | .buflen = pdev->pglen, | ||
360 | .len = pdev->pglen, | ||
361 | }; | ||
362 | struct page *scratch; | ||
363 | |||
364 | /* set up xdr stream */ | ||
365 | scratch = alloc_page(GFP_KERNEL); | ||
366 | if (!scratch) | ||
367 | goto out_err; | ||
368 | |||
369 | xdr_init_decode(&stream, &buf, NULL); | ||
370 | xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE); | ||
344 | 371 | ||
345 | /* Get the stripe count (number of stripe index) */ | 372 | /* Get the stripe count (number of stripe index) */ |
346 | cnt = be32_to_cpup(p++); | 373 | p = xdr_inline_decode(&stream, 4); |
374 | if (unlikely(!p)) | ||
375 | goto out_err_free_scratch; | ||
376 | |||
377 | cnt = be32_to_cpup(p); | ||
347 | dprintk("%s stripe count %d\n", __func__, cnt); | 378 | dprintk("%s stripe count %d\n", __func__, cnt); |
348 | if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) { | 379 | if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) { |
349 | printk(KERN_WARNING "%s: stripe count %d greater than " | 380 | printk(KERN_WARNING "%s: stripe count %d greater than " |
350 | "supported maximum %d\n", __func__, | 381 | "supported maximum %d\n", __func__, |
351 | cnt, NFS4_PNFS_MAX_STRIPE_CNT); | 382 | cnt, NFS4_PNFS_MAX_STRIPE_CNT); |
352 | goto out_err; | 383 | goto out_err_free_scratch; |
384 | } | ||
385 | |||
386 | /* read stripe indices */ | ||
387 | stripe_indices = kcalloc(cnt, sizeof(u8), GFP_KERNEL); | ||
388 | if (!stripe_indices) | ||
389 | goto out_err_free_scratch; | ||
390 | |||
391 | p = xdr_inline_decode(&stream, cnt << 2); | ||
392 | if (unlikely(!p)) | ||
393 | goto out_err_free_stripe_indices; | ||
394 | |||
395 | indexp = &stripe_indices[0]; | ||
396 | max_stripe_index = 0; | ||
397 | for (i = 0; i < cnt; i++) { | ||
398 | *indexp = be32_to_cpup(p++); | ||
399 | max_stripe_index = max(max_stripe_index, *indexp); | ||
400 | indexp++; | ||
353 | } | 401 | } |
354 | 402 | ||
355 | /* Check the multipath list count */ | 403 | /* Check the multipath list count */ |
356 | indicesp = p; | 404 | p = xdr_inline_decode(&stream, 4); |
357 | p += XDR_QUADLEN(cnt << 2); | 405 | if (unlikely(!p)) |
358 | num = be32_to_cpup(p++); | 406 | goto out_err_free_stripe_indices; |
407 | |||
408 | num = be32_to_cpup(p); | ||
359 | dprintk("%s ds_num %u\n", __func__, num); | 409 | dprintk("%s ds_num %u\n", __func__, num); |
360 | if (num > NFS4_PNFS_MAX_MULTI_CNT) { | 410 | if (num > NFS4_PNFS_MAX_MULTI_CNT) { |
361 | printk(KERN_WARNING "%s: multipath count %d greater than " | 411 | printk(KERN_WARNING "%s: multipath count %d greater than " |
362 | "supported maximum %d\n", __func__, | 412 | "supported maximum %d\n", __func__, |
363 | num, NFS4_PNFS_MAX_MULTI_CNT); | 413 | num, NFS4_PNFS_MAX_MULTI_CNT); |
364 | goto out_err; | 414 | goto out_err_free_stripe_indices; |
365 | } | 415 | } |
416 | |||
417 | /* validate stripe indices are all < num */ | ||
418 | if (max_stripe_index >= num) { | ||
419 | printk(KERN_WARNING "%s: stripe index %u >= num ds %u\n", | ||
420 | __func__, max_stripe_index, num); | ||
421 | goto out_err_free_stripe_indices; | ||
422 | } | ||
423 | |||
366 | dsaddr = kzalloc(sizeof(*dsaddr) + | 424 | dsaddr = kzalloc(sizeof(*dsaddr) + |
367 | (sizeof(struct nfs4_pnfs_ds *) * (num - 1)), | 425 | (sizeof(struct nfs4_pnfs_ds *) * (num - 1)), |
368 | GFP_KERNEL); | 426 | GFP_KERNEL); |
369 | if (!dsaddr) | 427 | if (!dsaddr) |
370 | goto out_err; | 428 | goto out_err_free_stripe_indices; |
371 | |||
372 | dsaddr->stripe_indices = kzalloc(sizeof(u8) * cnt, GFP_KERNEL); | ||
373 | if (!dsaddr->stripe_indices) | ||
374 | goto out_err_free; | ||
375 | 429 | ||
376 | dsaddr->stripe_count = cnt; | 430 | dsaddr->stripe_count = cnt; |
431 | dsaddr->stripe_indices = stripe_indices; | ||
432 | stripe_indices = NULL; | ||
377 | dsaddr->ds_num = num; | 433 | dsaddr->ds_num = num; |
378 | 434 | ||
379 | memcpy(&dsaddr->deviceid, &pdev->dev_id, sizeof(pdev->dev_id)); | 435 | memcpy(&dsaddr->deviceid, &pdev->dev_id, sizeof(pdev->dev_id)); |
380 | 436 | ||
381 | /* Go back an read stripe indices */ | ||
382 | p = indicesp; | ||
383 | indexp = &dsaddr->stripe_indices[0]; | ||
384 | for (i = 0; i < dsaddr->stripe_count; i++) { | ||
385 | *indexp = be32_to_cpup(p++); | ||
386 | if (*indexp >= num) | ||
387 | goto out_err_free; | ||
388 | indexp++; | ||
389 | } | ||
390 | /* Skip already read multipath list count */ | ||
391 | p++; | ||
392 | |||
393 | for (i = 0; i < dsaddr->ds_num; i++) { | 437 | for (i = 0; i < dsaddr->ds_num; i++) { |
394 | int j; | 438 | int j; |
439 | u32 mp_count; | ||
440 | |||
441 | p = xdr_inline_decode(&stream, 4); | ||
442 | if (unlikely(!p)) | ||
443 | goto out_err_free_deviceid; | ||
395 | 444 | ||
396 | dummy = be32_to_cpup(p++); /* multipath count */ | 445 | mp_count = be32_to_cpup(p); /* multipath count */ |
397 | if (dummy > 1) { | 446 | if (mp_count > 1) { |
398 | printk(KERN_WARNING | 447 | printk(KERN_WARNING |
399 | "%s: Multipath count %d not supported, " | 448 | "%s: Multipath count %d not supported, " |
400 | "skipping all greater than 1\n", __func__, | 449 | "skipping all greater than 1\n", __func__, |
401 | dummy); | 450 | mp_count); |
402 | } | 451 | } |
403 | for (j = 0; j < dummy; j++) { | 452 | for (j = 0; j < mp_count; j++) { |
404 | if (j == 0) { | 453 | if (j == 0) { |
405 | dsaddr->ds_list[i] = decode_and_add_ds(&p, ino); | 454 | dsaddr->ds_list[i] = decode_and_add_ds(&stream, |
455 | ino); | ||
406 | if (dsaddr->ds_list[i] == NULL) | 456 | if (dsaddr->ds_list[i] == NULL) |
407 | goto out_err_free; | 457 | goto out_err_free_deviceid; |
408 | } else { | 458 | } else { |
409 | u32 len; | 459 | u32 len; |
410 | /* skip extra multipath */ | 460 | /* skip extra multipath */ |
411 | len = be32_to_cpup(p++); | 461 | |
412 | p += XDR_QUADLEN(len); | 462 | /* read len, skip */ |
413 | len = be32_to_cpup(p++); | 463 | p = xdr_inline_decode(&stream, 4); |
414 | p += XDR_QUADLEN(len); | 464 | if (unlikely(!p)) |
415 | continue; | 465 | goto out_err_free_deviceid; |
466 | len = be32_to_cpup(p); | ||
467 | |||
468 | p = xdr_inline_decode(&stream, len); | ||
469 | if (unlikely(!p)) | ||
470 | goto out_err_free_deviceid; | ||
471 | |||
472 | /* read len, skip */ | ||
473 | p = xdr_inline_decode(&stream, 4); | ||
474 | if (unlikely(!p)) | ||
475 | goto out_err_free_deviceid; | ||
476 | len = be32_to_cpup(p); | ||
477 | |||
478 | p = xdr_inline_decode(&stream, len); | ||
479 | if (unlikely(!p)) | ||
480 | goto out_err_free_deviceid; | ||
416 | } | 481 | } |
417 | } | 482 | } |
418 | } | 483 | } |
484 | |||
485 | __free_page(scratch); | ||
419 | return dsaddr; | 486 | return dsaddr; |
420 | 487 | ||
421 | out_err_free: | 488 | out_err_free_deviceid: |
422 | nfs4_fl_free_deviceid(dsaddr); | 489 | nfs4_fl_free_deviceid(dsaddr); |
490 | /* stripe_indicies was part of dsaddr */ | ||
491 | goto out_err_free_scratch; | ||
492 | out_err_free_stripe_indices: | ||
493 | kfree(stripe_indices); | ||
494 | out_err_free_scratch: | ||
495 | __free_page(scratch); | ||
423 | out_err: | 496 | out_err: |
424 | dprintk("%s ERROR: returning NULL\n", __func__); | 497 | dprintk("%s ERROR: returning NULL\n", __func__); |
425 | return NULL; | 498 | return NULL; |
@@ -498,11 +571,6 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id) | |||
498 | goto out_free; | 571 | goto out_free; |
499 | } | 572 | } |
500 | 573 | ||
501 | /* set pdev->area */ | ||
502 | pdev->area = vmap(pages, max_pages, VM_MAP, PAGE_KERNEL); | ||
503 | if (!pdev->area) | ||
504 | goto out_free; | ||
505 | |||
506 | memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id)); | 574 | memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id)); |
507 | pdev->layout_type = LAYOUT_NFSV4_1_FILES; | 575 | pdev->layout_type = LAYOUT_NFSV4_1_FILES; |
508 | pdev->pages = pages; | 576 | pdev->pages = pages; |
@@ -521,8 +589,6 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id) | |||
521 | */ | 589 | */ |
522 | dsaddr = decode_and_add_device(inode, pdev); | 590 | dsaddr = decode_and_add_device(inode, pdev); |
523 | out_free: | 591 | out_free: |
524 | if (pdev->area != NULL) | ||
525 | vunmap(pdev->area); | ||
526 | for (i = 0; i < max_pages; i++) | 592 | for (i = 0; i < max_pages; i++) |
527 | __free_page(pages[i]); | 593 | __free_page(pages[i]); |
528 | kfree(pages); | 594 | kfree(pages); |