.. | .. |
---|
16 | 16 | #include "xfs_da_format.h" |
---|
17 | 17 | #include "xfs_da_btree.h" |
---|
18 | 18 | #include "xfs_inode.h" |
---|
19 | | -#include "xfs_alloc.h" |
---|
20 | 19 | #include "xfs_trans.h" |
---|
21 | | -#include "xfs_inode_item.h" |
---|
22 | 20 | #include "xfs_bmap.h" |
---|
23 | | -#include "xfs_bmap_util.h" |
---|
24 | 21 | #include "xfs_attr.h" |
---|
25 | | -#include "xfs_attr_leaf.h" |
---|
26 | 22 | #include "xfs_attr_remote.h" |
---|
27 | | -#include "xfs_trans_space.h" |
---|
28 | 23 | #include "xfs_trace.h" |
---|
29 | | -#include "xfs_cksum.h" |
---|
30 | | -#include "xfs_buf_item.h" |
---|
31 | 24 | #include "xfs_error.h" |
---|
32 | 25 | |
---|
33 | 26 | #define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */ |
---|
| 27 | + |
---|
| 28 | +/* |
---|
| 29 | + * Remote Attribute Values |
---|
| 30 | + * ======================= |
---|
| 31 | + * |
---|
| 32 | + * Remote extended attribute values are conceptually simple -- they're written |
---|
| 33 | + * to data blocks mapped by an inode's attribute fork, and they have an upper |
---|
| 34 | + * size limit of 64k. Setting a value does not involve the XFS log. |
---|
| 35 | + * |
---|
| 36 | + * However, on a v5 filesystem, maximally sized remote attr values require one |
---|
| 37 | + * block more than 64k worth of space to hold both the remote attribute value |
---|
| 38 | + * header (64 bytes). On a 4k block filesystem this results in a 68k buffer; |
---|
| 39 | + * on a 64k block filesystem, this would be a 128k buffer. Note that the log |
---|
| 40 | + * format can only handle a dirty buffer of XFS_MAX_BLOCKSIZE length (64k). |
---|
| 41 | + * Therefore, we /must/ ensure that remote attribute value buffers never touch |
---|
| 42 | + * the logging system and therefore never have a log item. |
---|
| 43 | + */ |
---|
34 | 44 | |
---|
35 | 45 | /* |
---|
36 | 46 | * Each contiguous block has a header, so it is not just a simple attribute |
---|
.. | .. |
---|
79 | 89 | static xfs_failaddr_t |
---|
80 | 90 | xfs_attr3_rmt_verify( |
---|
81 | 91 | struct xfs_mount *mp, |
---|
| 92 | + struct xfs_buf *bp, |
---|
82 | 93 | void *ptr, |
---|
83 | 94 | int fsbsize, |
---|
84 | 95 | xfs_daddr_t bno) |
---|
85 | 96 | { |
---|
86 | 97 | struct xfs_attr3_rmt_hdr *rmt = ptr; |
---|
87 | 98 | |
---|
88 | | - if (!xfs_sb_version_hascrc(&mp->m_sb)) |
---|
89 | | - return __this_address; |
---|
90 | | - if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC)) |
---|
| 99 | + if (!xfs_verify_magic(bp, rmt->rm_magic)) |
---|
91 | 100 | return __this_address; |
---|
92 | 101 | if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid)) |
---|
93 | 102 | return __this_address; |
---|
.. | .. |
---|
110 | 119 | bool check_crc, |
---|
111 | 120 | xfs_failaddr_t *failaddr) |
---|
112 | 121 | { |
---|
113 | | - struct xfs_mount *mp = bp->b_target->bt_mount; |
---|
| 122 | + struct xfs_mount *mp = bp->b_mount; |
---|
114 | 123 | char *ptr; |
---|
115 | 124 | int len; |
---|
116 | 125 | xfs_daddr_t bno; |
---|
.. | .. |
---|
131 | 140 | *failaddr = __this_address; |
---|
132 | 141 | return -EFSBADCRC; |
---|
133 | 142 | } |
---|
134 | | - *failaddr = xfs_attr3_rmt_verify(mp, ptr, blksize, bno); |
---|
| 143 | + *failaddr = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno); |
---|
135 | 144 | if (*failaddr) |
---|
136 | 145 | return -EFSCORRUPTED; |
---|
137 | 146 | len -= blksize; |
---|
.. | .. |
---|
174 | 183 | xfs_attr3_rmt_write_verify( |
---|
175 | 184 | struct xfs_buf *bp) |
---|
176 | 185 | { |
---|
177 | | - struct xfs_mount *mp = bp->b_target->bt_mount; |
---|
| 186 | + struct xfs_mount *mp = bp->b_mount; |
---|
178 | 187 | xfs_failaddr_t fa; |
---|
179 | 188 | int blksize = mp->m_attr_geo->blksize; |
---|
180 | 189 | char *ptr; |
---|
.. | .. |
---|
193 | 202 | while (len > 0) { |
---|
194 | 203 | struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr; |
---|
195 | 204 | |
---|
196 | | - fa = xfs_attr3_rmt_verify(mp, ptr, blksize, bno); |
---|
| 205 | + fa = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno); |
---|
197 | 206 | if (fa) { |
---|
198 | 207 | xfs_verifier_error(bp, -EFSCORRUPTED, fa); |
---|
199 | 208 | return; |
---|
.. | .. |
---|
220 | 229 | |
---|
221 | 230 | const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = { |
---|
222 | 231 | .name = "xfs_attr3_rmt", |
---|
| 232 | + .magic = { 0, cpu_to_be32(XFS_ATTR3_RMT_MAGIC) }, |
---|
223 | 233 | .verify_read = xfs_attr3_rmt_read_verify, |
---|
224 | 234 | .verify_write = xfs_attr3_rmt_write_verify, |
---|
225 | 235 | .verify_struct = xfs_attr3_rmt_verify_struct, |
---|
.. | .. |
---|
364 | 374 | /* |
---|
365 | 375 | * Read the value associated with an attribute from the out-of-line buffer |
---|
366 | 376 | * that we stored it in. |
---|
| 377 | + * |
---|
| 378 | + * Returns 0 on successful retrieval, otherwise an error. |
---|
367 | 379 | */ |
---|
368 | 380 | int |
---|
369 | 381 | xfs_attr_rmtval_get( |
---|
.. | .. |
---|
383 | 395 | |
---|
384 | 396 | trace_xfs_attr_rmtval_get(args); |
---|
385 | 397 | |
---|
386 | | - ASSERT(!(args->flags & ATTR_KERNOVAL)); |
---|
| 398 | + ASSERT(args->valuelen != 0); |
---|
387 | 399 | ASSERT(args->rmtvaluelen == args->valuelen); |
---|
388 | 400 | |
---|
389 | 401 | valuelen = args->rmtvaluelen; |
---|
.. | .. |
---|
404 | 416 | (map[i].br_startblock != HOLESTARTBLOCK)); |
---|
405 | 417 | dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); |
---|
406 | 418 | dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); |
---|
407 | | - error = xfs_trans_read_buf(mp, args->trans, |
---|
408 | | - mp->m_ddev_targp, |
---|
409 | | - dblkno, dblkcnt, 0, &bp, |
---|
410 | | - &xfs_attr3_rmt_buf_ops); |
---|
| 419 | + error = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt, |
---|
| 420 | + 0, &bp, &xfs_attr3_rmt_buf_ops); |
---|
411 | 421 | if (error) |
---|
412 | 422 | return error; |
---|
413 | 423 | |
---|
414 | 424 | error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino, |
---|
415 | 425 | &offset, &valuelen, |
---|
416 | 426 | &dst); |
---|
417 | | - xfs_trans_brelse(args->trans, bp); |
---|
| 427 | + xfs_buf_relse(bp); |
---|
418 | 428 | if (error) |
---|
419 | 429 | return error; |
---|
420 | 430 | |
---|
.. | .. |
---|
428 | 438 | } |
---|
429 | 439 | |
---|
430 | 440 | /* |
---|
| 441 | + * Find a "hole" in the attribute address space large enough for us to drop the |
---|
| 442 | + * new attribute's value into |
---|
| 443 | + */ |
---|
| 444 | +STATIC int |
---|
| 445 | +xfs_attr_rmt_find_hole( |
---|
| 446 | + struct xfs_da_args *args) |
---|
| 447 | +{ |
---|
| 448 | + struct xfs_inode *dp = args->dp; |
---|
| 449 | + struct xfs_mount *mp = dp->i_mount; |
---|
| 450 | + int error; |
---|
| 451 | + int blkcnt; |
---|
| 452 | + xfs_fileoff_t lfileoff = 0; |
---|
| 453 | + |
---|
| 454 | + /* |
---|
| 455 | + * Because CRC enable attributes have headers, we can't just do a |
---|
| 456 | + * straight byte to FSB conversion and have to take the header space |
---|
| 457 | + * into account. |
---|
| 458 | + */ |
---|
| 459 | + blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen); |
---|
| 460 | + error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, |
---|
| 461 | + XFS_ATTR_FORK); |
---|
| 462 | + if (error) |
---|
| 463 | + return error; |
---|
| 464 | + |
---|
| 465 | + args->rmtblkno = (xfs_dablk_t)lfileoff; |
---|
| 466 | + args->rmtblkcnt = blkcnt; |
---|
| 467 | + |
---|
| 468 | + return 0; |
---|
| 469 | +} |
---|
| 470 | + |
---|
| 471 | +STATIC int |
---|
| 472 | +xfs_attr_rmtval_set_value( |
---|
| 473 | + struct xfs_da_args *args) |
---|
| 474 | +{ |
---|
| 475 | + struct xfs_inode *dp = args->dp; |
---|
| 476 | + struct xfs_mount *mp = dp->i_mount; |
---|
| 477 | + struct xfs_bmbt_irec map; |
---|
| 478 | + xfs_dablk_t lblkno; |
---|
| 479 | + uint8_t *src = args->value; |
---|
| 480 | + int blkcnt; |
---|
| 481 | + int valuelen; |
---|
| 482 | + int nmap; |
---|
| 483 | + int error; |
---|
| 484 | + int offset = 0; |
---|
| 485 | + |
---|
| 486 | + /* |
---|
| 487 | + * Roll through the "value", copying the attribute value to the |
---|
| 488 | + * already-allocated blocks. Blocks are written synchronously |
---|
| 489 | + * so that we can know they are all on disk before we turn off |
---|
| 490 | + * the INCOMPLETE flag. |
---|
| 491 | + */ |
---|
| 492 | + lblkno = args->rmtblkno; |
---|
| 493 | + blkcnt = args->rmtblkcnt; |
---|
| 494 | + valuelen = args->rmtvaluelen; |
---|
| 495 | + while (valuelen > 0) { |
---|
| 496 | + struct xfs_buf *bp; |
---|
| 497 | + xfs_daddr_t dblkno; |
---|
| 498 | + int dblkcnt; |
---|
| 499 | + |
---|
| 500 | + ASSERT(blkcnt > 0); |
---|
| 501 | + |
---|
| 502 | + nmap = 1; |
---|
| 503 | + error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno, |
---|
| 504 | + blkcnt, &map, &nmap, |
---|
| 505 | + XFS_BMAPI_ATTRFORK); |
---|
| 506 | + if (error) |
---|
| 507 | + return error; |
---|
| 508 | + ASSERT(nmap == 1); |
---|
| 509 | + ASSERT((map.br_startblock != DELAYSTARTBLOCK) && |
---|
| 510 | + (map.br_startblock != HOLESTARTBLOCK)); |
---|
| 511 | + |
---|
| 512 | + dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), |
---|
| 513 | + dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); |
---|
| 514 | + |
---|
| 515 | + error = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, &bp); |
---|
| 516 | + if (error) |
---|
| 517 | + return error; |
---|
| 518 | + bp->b_ops = &xfs_attr3_rmt_buf_ops; |
---|
| 519 | + |
---|
| 520 | + xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset, |
---|
| 521 | + &valuelen, &src); |
---|
| 522 | + |
---|
| 523 | + error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */ |
---|
| 524 | + xfs_buf_relse(bp); |
---|
| 525 | + if (error) |
---|
| 526 | + return error; |
---|
| 527 | + |
---|
| 528 | + |
---|
| 529 | + /* roll attribute extent map forwards */ |
---|
| 530 | + lblkno += map.br_blockcount; |
---|
| 531 | + blkcnt -= map.br_blockcount; |
---|
| 532 | + } |
---|
| 533 | + ASSERT(valuelen == 0); |
---|
| 534 | + return 0; |
---|
| 535 | +} |
---|
| 536 | + |
---|
| 537 | +/* Mark stale any incore buffers for the remote value. */ |
---|
| 538 | +int |
---|
| 539 | +xfs_attr_rmtval_stale( |
---|
| 540 | + struct xfs_inode *ip, |
---|
| 541 | + struct xfs_bmbt_irec *map, |
---|
| 542 | + xfs_buf_flags_t incore_flags) |
---|
| 543 | +{ |
---|
| 544 | + struct xfs_mount *mp = ip->i_mount; |
---|
| 545 | + struct xfs_buf *bp; |
---|
| 546 | + |
---|
| 547 | + ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); |
---|
| 548 | + |
---|
| 549 | + if (XFS_IS_CORRUPT(mp, map->br_startblock == DELAYSTARTBLOCK) || |
---|
| 550 | + XFS_IS_CORRUPT(mp, map->br_startblock == HOLESTARTBLOCK)) |
---|
| 551 | + return -EFSCORRUPTED; |
---|
| 552 | + |
---|
| 553 | + bp = xfs_buf_incore(mp->m_ddev_targp, |
---|
| 554 | + XFS_FSB_TO_DADDR(mp, map->br_startblock), |
---|
| 555 | + XFS_FSB_TO_BB(mp, map->br_blockcount), incore_flags); |
---|
| 556 | + if (bp) { |
---|
| 557 | + xfs_buf_stale(bp); |
---|
| 558 | + xfs_buf_relse(bp); |
---|
| 559 | + } |
---|
| 560 | + |
---|
| 561 | + return 0; |
---|
| 562 | +} |
---|
| 563 | + |
---|
| 564 | +/* |
---|
431 | 565 | * Write the value associated with an attribute into the out-of-line buffer |
---|
432 | 566 | * that we have defined for it. |
---|
433 | 567 | */ |
---|
.. | .. |
---|
436 | 570 | struct xfs_da_args *args) |
---|
437 | 571 | { |
---|
438 | 572 | struct xfs_inode *dp = args->dp; |
---|
439 | | - struct xfs_mount *mp = dp->i_mount; |
---|
440 | 573 | struct xfs_bmbt_irec map; |
---|
441 | 574 | xfs_dablk_t lblkno; |
---|
442 | | - xfs_fileoff_t lfileoff = 0; |
---|
443 | | - uint8_t *src = args->value; |
---|
444 | 575 | int blkcnt; |
---|
445 | | - int valuelen; |
---|
446 | 576 | int nmap; |
---|
447 | 577 | int error; |
---|
448 | | - int offset = 0; |
---|
449 | 578 | |
---|
450 | 579 | trace_xfs_attr_rmtval_set(args); |
---|
451 | 580 | |
---|
452 | | - /* |
---|
453 | | - * Find a "hole" in the attribute address space large enough for |
---|
454 | | - * us to drop the new attribute's value into. Because CRC enable |
---|
455 | | - * attributes have headers, we can't just do a straight byte to FSB |
---|
456 | | - * conversion and have to take the header space into account. |
---|
457 | | - */ |
---|
458 | | - blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen); |
---|
459 | | - error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, |
---|
460 | | - XFS_ATTR_FORK); |
---|
| 581 | + error = xfs_attr_rmt_find_hole(args); |
---|
461 | 582 | if (error) |
---|
462 | 583 | return error; |
---|
463 | 584 | |
---|
464 | | - args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff; |
---|
465 | | - args->rmtblkcnt = blkcnt; |
---|
466 | | - |
---|
| 585 | + blkcnt = args->rmtblkcnt; |
---|
| 586 | + lblkno = (xfs_dablk_t)args->rmtblkno; |
---|
467 | 587 | /* |
---|
468 | 588 | * Roll through the "value", allocating blocks on disk as required. |
---|
469 | 589 | */ |
---|
.. | .. |
---|
504 | 624 | return error; |
---|
505 | 625 | } |
---|
506 | 626 | |
---|
507 | | - /* |
---|
508 | | - * Roll through the "value", copying the attribute value to the |
---|
509 | | - * already-allocated blocks. Blocks are written synchronously |
---|
510 | | - * so that we can know they are all on disk before we turn off |
---|
511 | | - * the INCOMPLETE flag. |
---|
512 | | - */ |
---|
513 | | - lblkno = args->rmtblkno; |
---|
514 | | - blkcnt = args->rmtblkcnt; |
---|
515 | | - valuelen = args->rmtvaluelen; |
---|
516 | | - while (valuelen > 0) { |
---|
517 | | - struct xfs_buf *bp; |
---|
518 | | - xfs_daddr_t dblkno; |
---|
519 | | - int dblkcnt; |
---|
520 | | - |
---|
521 | | - ASSERT(blkcnt > 0); |
---|
522 | | - |
---|
523 | | - nmap = 1; |
---|
524 | | - error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno, |
---|
525 | | - blkcnt, &map, &nmap, |
---|
526 | | - XFS_BMAPI_ATTRFORK); |
---|
527 | | - if (error) |
---|
528 | | - return error; |
---|
529 | | - ASSERT(nmap == 1); |
---|
530 | | - ASSERT((map.br_startblock != DELAYSTARTBLOCK) && |
---|
531 | | - (map.br_startblock != HOLESTARTBLOCK)); |
---|
532 | | - |
---|
533 | | - dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), |
---|
534 | | - dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); |
---|
535 | | - |
---|
536 | | - bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, 0); |
---|
537 | | - if (!bp) |
---|
538 | | - return -ENOMEM; |
---|
539 | | - bp->b_ops = &xfs_attr3_rmt_buf_ops; |
---|
540 | | - |
---|
541 | | - xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset, |
---|
542 | | - &valuelen, &src); |
---|
543 | | - |
---|
544 | | - error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */ |
---|
545 | | - xfs_buf_relse(bp); |
---|
546 | | - if (error) |
---|
547 | | - return error; |
---|
548 | | - |
---|
549 | | - |
---|
550 | | - /* roll attribute extent map forwards */ |
---|
551 | | - lblkno += map.br_blockcount; |
---|
552 | | - blkcnt -= map.br_blockcount; |
---|
553 | | - } |
---|
554 | | - ASSERT(valuelen == 0); |
---|
555 | | - return 0; |
---|
| 627 | + return xfs_attr_rmtval_set_value(args); |
---|
556 | 628 | } |
---|
557 | 629 | |
---|
558 | 630 | /* |
---|
.. | .. |
---|
560 | 632 | * out-of-line buffer that it is stored on. |
---|
561 | 633 | */ |
---|
562 | 634 | int |
---|
563 | | -xfs_attr_rmtval_remove( |
---|
| 635 | +xfs_attr_rmtval_invalidate( |
---|
564 | 636 | struct xfs_da_args *args) |
---|
565 | 637 | { |
---|
566 | | - struct xfs_mount *mp = args->dp->i_mount; |
---|
567 | 638 | xfs_dablk_t lblkno; |
---|
568 | 639 | int blkcnt; |
---|
569 | 640 | int error; |
---|
570 | | - int done; |
---|
571 | | - |
---|
572 | | - trace_xfs_attr_rmtval_remove(args); |
---|
573 | 641 | |
---|
574 | 642 | /* |
---|
575 | 643 | * Roll through the "value", invalidating the attribute value's blocks. |
---|
.. | .. |
---|
578 | 646 | blkcnt = args->rmtblkcnt; |
---|
579 | 647 | while (blkcnt > 0) { |
---|
580 | 648 | struct xfs_bmbt_irec map; |
---|
581 | | - struct xfs_buf *bp; |
---|
582 | | - xfs_daddr_t dblkno; |
---|
583 | | - int dblkcnt; |
---|
584 | 649 | int nmap; |
---|
585 | 650 | |
---|
586 | 651 | /* |
---|
.. | .. |
---|
591 | 656 | blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK); |
---|
592 | 657 | if (error) |
---|
593 | 658 | return error; |
---|
594 | | - ASSERT(nmap == 1); |
---|
595 | | - ASSERT((map.br_startblock != DELAYSTARTBLOCK) && |
---|
596 | | - (map.br_startblock != HOLESTARTBLOCK)); |
---|
597 | | - |
---|
598 | | - dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), |
---|
599 | | - dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); |
---|
600 | | - |
---|
601 | | - /* |
---|
602 | | - * If the "remote" value is in the cache, remove it. |
---|
603 | | - */ |
---|
604 | | - bp = xfs_buf_incore(mp->m_ddev_targp, dblkno, dblkcnt, XBF_TRYLOCK); |
---|
605 | | - if (bp) { |
---|
606 | | - xfs_buf_stale(bp); |
---|
607 | | - xfs_buf_relse(bp); |
---|
608 | | - bp = NULL; |
---|
609 | | - } |
---|
| 659 | + if (XFS_IS_CORRUPT(args->dp->i_mount, nmap != 1)) |
---|
| 660 | + return -EFSCORRUPTED; |
---|
| 661 | + error = xfs_attr_rmtval_stale(args->dp, &map, XBF_TRYLOCK); |
---|
| 662 | + if (error) |
---|
| 663 | + return error; |
---|
610 | 664 | |
---|
611 | 665 | lblkno += map.br_blockcount; |
---|
612 | 666 | blkcnt -= map.br_blockcount; |
---|
613 | 667 | } |
---|
| 668 | + return 0; |
---|
| 669 | +} |
---|
| 670 | + |
---|
| 671 | +/* |
---|
| 672 | + * Remove the value associated with an attribute by deleting the |
---|
| 673 | + * out-of-line buffer that it is stored on. |
---|
| 674 | + */ |
---|
| 675 | +int |
---|
| 676 | +xfs_attr_rmtval_remove( |
---|
| 677 | + struct xfs_da_args *args) |
---|
| 678 | +{ |
---|
| 679 | + int error; |
---|
| 680 | + int retval; |
---|
| 681 | + |
---|
| 682 | + trace_xfs_attr_rmtval_remove(args); |
---|
614 | 683 | |
---|
615 | 684 | /* |
---|
616 | 685 | * Keep de-allocating extents until the remote-value region is gone. |
---|
617 | 686 | */ |
---|
618 | | - lblkno = args->rmtblkno; |
---|
619 | | - blkcnt = args->rmtblkcnt; |
---|
620 | | - done = 0; |
---|
621 | | - while (!done) { |
---|
622 | | - error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt, |
---|
623 | | - XFS_BMAPI_ATTRFORK, 1, &done); |
---|
624 | | - if (error) |
---|
625 | | - return error; |
---|
626 | | - error = xfs_defer_finish(&args->trans); |
---|
627 | | - if (error) |
---|
628 | | - return error; |
---|
| 687 | + do { |
---|
| 688 | + retval = __xfs_attr_rmtval_remove(args); |
---|
| 689 | + if (retval && retval != -EAGAIN) |
---|
| 690 | + return retval; |
---|
629 | 691 | |
---|
630 | 692 | /* |
---|
631 | 693 | * Close out trans and start the next one in the chain. |
---|
.. | .. |
---|
633 | 695 | error = xfs_trans_roll_inode(&args->trans, args->dp); |
---|
634 | 696 | if (error) |
---|
635 | 697 | return error; |
---|
636 | | - } |
---|
| 698 | + } while (retval == -EAGAIN); |
---|
| 699 | + |
---|
637 | 700 | return 0; |
---|
638 | 701 | } |
---|
| 702 | + |
---|
| 703 | +/* |
---|
| 704 | + * Remove the value associated with an attribute by deleting the out-of-line |
---|
| 705 | + * buffer that it is stored on. Returns EAGAIN for the caller to refresh the |
---|
| 706 | + * transaction and re-call the function |
---|
| 707 | + */ |
---|
| 708 | +int |
---|
| 709 | +__xfs_attr_rmtval_remove( |
---|
| 710 | + struct xfs_da_args *args) |
---|
| 711 | +{ |
---|
| 712 | + int error, done; |
---|
| 713 | + |
---|
| 714 | + /* |
---|
| 715 | + * Unmap value blocks for this attr. |
---|
| 716 | + */ |
---|
| 717 | + error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno, |
---|
| 718 | + args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done); |
---|
| 719 | + if (error) |
---|
| 720 | + return error; |
---|
| 721 | + |
---|
| 722 | + error = xfs_defer_finish(&args->trans); |
---|
| 723 | + if (error) |
---|
| 724 | + return error; |
---|
| 725 | + |
---|
| 726 | + if (!done) |
---|
| 727 | + return -EAGAIN; |
---|
| 728 | + |
---|
| 729 | + return error; |
---|
| 730 | +} |
---|