| .. | .. |
|---|
| 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 | +} |
|---|