1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 * Copyright (c) 2013 Red Hat, Inc. 5 * All Rights Reserved. 6 */ 7 #include "xfs.h" 8 #include "xfs_fs.h" 9 #include "xfs_shared.h" 10 #include "xfs_format.h" 11 #include "xfs_log_format.h" 12 #include "xfs_trans_resv.h" 13 #include "xfs_bit.h" 14 #include "xfs_mount.h" 15 #include "xfs_defer.h" 16 #include "xfs_da_format.h" 17 #include "xfs_da_btree.h" 18 #include "xfs_inode.h" 19 #include "xfs_trans.h" 20 #include "xfs_bmap.h" 21 #include "xfs_attr.h" 22 #include "xfs_attr_remote.h" 23 #include "xfs_trace.h" 24 #include "xfs_error.h" 25 #include "xfs_health.h" 26 27 #define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */ 28 29 /* 30 * Remote Attribute Values 31 * ======================= 32 * 33 * Remote extended attribute values are conceptually simple -- they're written 34 * to data blocks mapped by an inode's attribute fork, and they have an upper 35 * size limit of 64k. Setting a value does not involve the XFS log. 36 * 37 * However, on a v5 filesystem, maximally sized remote attr values require one 38 * block more than 64k worth of space to hold both the remote attribute value 39 * header (64 bytes). On a 4k block filesystem this results in a 68k buffer; 40 * on a 64k block filesystem, this would be a 128k buffer. Note that the log 41 * format can only handle a dirty buffer of XFS_MAX_BLOCKSIZE length (64k). 42 * Therefore, we /must/ ensure that remote attribute value buffers never touch 43 * the logging system and therefore never have a log item. 44 */ 45 46 /* 47 * Each contiguous block has a header, so it is not just a simple attribute 48 * length to FSB conversion. 49 */ 50 int 51 xfs_attr3_rmt_blocks( 52 struct xfs_mount *mp, 53 int attrlen) 54 { 55 if (xfs_has_crc(mp)) { 56 int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize); 57 return (attrlen + buflen - 1) / buflen; 58 } 59 return XFS_B_TO_FSB(mp, attrlen); 60 } 61 62 /* 63 * Checking of the remote attribute header is split into two parts. The verifier 64 * does CRC, location and bounds checking, the unpacking function checks the 65 * attribute parameters and owner. 66 */ 67 static xfs_failaddr_t 68 xfs_attr3_rmt_hdr_ok( 69 void *ptr, 70 xfs_ino_t ino, 71 uint32_t offset, 72 uint32_t size, 73 xfs_daddr_t bno) 74 { 75 struct xfs_attr3_rmt_hdr *rmt = ptr; 76 77 if (bno != be64_to_cpu(rmt->rm_blkno)) 78 return __this_address; 79 if (offset != be32_to_cpu(rmt->rm_offset)) 80 return __this_address; 81 if (size != be32_to_cpu(rmt->rm_bytes)) 82 return __this_address; 83 if (ino != be64_to_cpu(rmt->rm_owner)) 84 return __this_address; 85 86 /* ok */ 87 return NULL; 88 } 89 90 static xfs_failaddr_t 91 xfs_attr3_rmt_verify( 92 struct xfs_mount *mp, 93 struct xfs_buf *bp, 94 void *ptr, 95 int fsbsize, 96 xfs_daddr_t bno) 97 { 98 struct xfs_attr3_rmt_hdr *rmt = ptr; 99 100 if (!xfs_verify_magic(bp, rmt->rm_magic)) 101 return __this_address; 102 if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid)) 103 return __this_address; 104 if (be64_to_cpu(rmt->rm_blkno) != bno) 105 return __this_address; 106 if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt)) 107 return __this_address; 108 if (be32_to_cpu(rmt->rm_offset) + 109 be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX) 110 return __this_address; 111 if (rmt->rm_owner == 0) 112 return __this_address; 113 114 return NULL; 115 } 116 117 static int 118 __xfs_attr3_rmt_read_verify( 119 struct xfs_buf *bp, 120 bool check_crc, 121 xfs_failaddr_t *failaddr) 122 { 123 struct xfs_mount *mp = bp->b_mount; 124 char *ptr; 125 int len; 126 xfs_daddr_t bno; 127 int blksize = mp->m_attr_geo->blksize; 128 129 /* no verification of non-crc buffers */ 130 if (!xfs_has_crc(mp)) 131 return 0; 132 133 ptr = bp->b_addr; 134 bno = xfs_buf_daddr(bp); 135 len = BBTOB(bp->b_length); 136 ASSERT(len >= blksize); 137 138 while (len > 0) { 139 if (check_crc && 140 !xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) { 141 *failaddr = __this_address; 142 return -EFSBADCRC; 143 } 144 *failaddr = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno); 145 if (*failaddr) 146 return -EFSCORRUPTED; 147 len -= blksize; 148 ptr += blksize; 149 bno += BTOBB(blksize); 150 } 151 152 if (len != 0) { 153 *failaddr = __this_address; 154 return -EFSCORRUPTED; 155 } 156 157 return 0; 158 } 159 160 static void 161 xfs_attr3_rmt_read_verify( 162 struct xfs_buf *bp) 163 { 164 xfs_failaddr_t fa; 165 int error; 166 167 error = __xfs_attr3_rmt_read_verify(bp, true, &fa); 168 if (error) 169 xfs_verifier_error(bp, error, fa); 170 } 171 172 static xfs_failaddr_t 173 xfs_attr3_rmt_verify_struct( 174 struct xfs_buf *bp) 175 { 176 xfs_failaddr_t fa; 177 int error; 178 179 error = __xfs_attr3_rmt_read_verify(bp, false, &fa); 180 return error ? fa : NULL; 181 } 182 183 static void 184 xfs_attr3_rmt_write_verify( 185 struct xfs_buf *bp) 186 { 187 struct xfs_mount *mp = bp->b_mount; 188 xfs_failaddr_t fa; 189 int blksize = mp->m_attr_geo->blksize; 190 char *ptr; 191 int len; 192 xfs_daddr_t bno; 193 194 /* no verification of non-crc buffers */ 195 if (!xfs_has_crc(mp)) 196 return; 197 198 ptr = bp->b_addr; 199 bno = xfs_buf_daddr(bp); 200 len = BBTOB(bp->b_length); 201 ASSERT(len >= blksize); 202 203 while (len > 0) { 204 struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr; 205 206 fa = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno); 207 if (fa) { 208 xfs_verifier_error(bp, -EFSCORRUPTED, fa); 209 return; 210 } 211 212 /* 213 * Ensure we aren't writing bogus LSNs to disk. See 214 * xfs_attr3_rmt_hdr_set() for the explanation. 215 */ 216 if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) { 217 xfs_verifier_error(bp, -EFSCORRUPTED, __this_address); 218 return; 219 } 220 xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF); 221 222 len -= blksize; 223 ptr += blksize; 224 bno += BTOBB(blksize); 225 } 226 227 if (len != 0) 228 xfs_verifier_error(bp, -EFSCORRUPTED, __this_address); 229 } 230 231 const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = { 232 .name = "xfs_attr3_rmt", 233 .magic = { 0, cpu_to_be32(XFS_ATTR3_RMT_MAGIC) }, 234 .verify_read = xfs_attr3_rmt_read_verify, 235 .verify_write = xfs_attr3_rmt_write_verify, 236 .verify_struct = xfs_attr3_rmt_verify_struct, 237 }; 238 239 STATIC int 240 xfs_attr3_rmt_hdr_set( 241 struct xfs_mount *mp, 242 void *ptr, 243 xfs_ino_t ino, 244 uint32_t offset, 245 uint32_t size, 246 xfs_daddr_t bno) 247 { 248 struct xfs_attr3_rmt_hdr *rmt = ptr; 249 250 if (!xfs_has_crc(mp)) 251 return 0; 252 253 rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC); 254 rmt->rm_offset = cpu_to_be32(offset); 255 rmt->rm_bytes = cpu_to_be32(size); 256 uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid); 257 rmt->rm_owner = cpu_to_be64(ino); 258 rmt->rm_blkno = cpu_to_be64(bno); 259 260 /* 261 * Remote attribute blocks are written synchronously, so we don't 262 * have an LSN that we can stamp in them that makes any sense to log 263 * recovery. To ensure that log recovery handles overwrites of these 264 * blocks sanely (i.e. once they've been freed and reallocated as some 265 * other type of metadata) we need to ensure that the LSN has a value 266 * that tells log recovery to ignore the LSN and overwrite the buffer 267 * with whatever is in it's log. To do this, we use the magic 268 * NULLCOMMITLSN to indicate that the LSN is invalid. 269 */ 270 rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN); 271 272 return sizeof(struct xfs_attr3_rmt_hdr); 273 } 274 275 /* 276 * Helper functions to copy attribute data in and out of the one disk extents 277 */ 278 STATIC int 279 xfs_attr_rmtval_copyout( 280 struct xfs_mount *mp, 281 struct xfs_buf *bp, 282 struct xfs_inode *dp, 283 int *offset, 284 int *valuelen, 285 uint8_t **dst) 286 { 287 char *src = bp->b_addr; 288 xfs_ino_t ino = dp->i_ino; 289 xfs_daddr_t bno = xfs_buf_daddr(bp); 290 int len = BBTOB(bp->b_length); 291 int blksize = mp->m_attr_geo->blksize; 292 293 ASSERT(len >= blksize); 294 295 while (len > 0 && *valuelen > 0) { 296 int hdr_size = 0; 297 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize); 298 299 byte_cnt = min(*valuelen, byte_cnt); 300 301 if (xfs_has_crc(mp)) { 302 if (xfs_attr3_rmt_hdr_ok(src, ino, *offset, 303 byte_cnt, bno)) { 304 xfs_alert(mp, 305 "remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)", 306 bno, *offset, byte_cnt, ino); 307 xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK); 308 return -EFSCORRUPTED; 309 } 310 hdr_size = sizeof(struct xfs_attr3_rmt_hdr); 311 } 312 313 memcpy(*dst, src + hdr_size, byte_cnt); 314 315 /* roll buffer forwards */ 316 len -= blksize; 317 src += blksize; 318 bno += BTOBB(blksize); 319 320 /* roll attribute data forwards */ 321 *valuelen -= byte_cnt; 322 *dst += byte_cnt; 323 *offset += byte_cnt; 324 } 325 return 0; 326 } 327 328 STATIC void 329 xfs_attr_rmtval_copyin( 330 struct xfs_mount *mp, 331 struct xfs_buf *bp, 332 xfs_ino_t ino, 333 int *offset, 334 int *valuelen, 335 uint8_t **src) 336 { 337 char *dst = bp->b_addr; 338 xfs_daddr_t bno = xfs_buf_daddr(bp); 339 int len = BBTOB(bp->b_length); 340 int blksize = mp->m_attr_geo->blksize; 341 342 ASSERT(len >= blksize); 343 344 while (len > 0 && *valuelen > 0) { 345 int hdr_size; 346 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize); 347 348 byte_cnt = min(*valuelen, byte_cnt); 349 hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset, 350 byte_cnt, bno); 351 352 memcpy(dst + hdr_size, *src, byte_cnt); 353 354 /* 355 * If this is the last block, zero the remainder of it. 356 * Check that we are actually the last block, too. 357 */ 358 if (byte_cnt + hdr_size < blksize) { 359 ASSERT(*valuelen - byte_cnt == 0); 360 ASSERT(len == blksize); 361 memset(dst + hdr_size + byte_cnt, 0, 362 blksize - hdr_size - byte_cnt); 363 } 364 365 /* roll buffer forwards */ 366 len -= blksize; 367 dst += blksize; 368 bno += BTOBB(blksize); 369 370 /* roll attribute data forwards */ 371 *valuelen -= byte_cnt; 372 *src += byte_cnt; 373 *offset += byte_cnt; 374 } 375 } 376 377 /* 378 * Read the value associated with an attribute from the out-of-line buffer 379 * that we stored it in. 380 * 381 * Returns 0 on successful retrieval, otherwise an error. 382 */ 383 int 384 xfs_attr_rmtval_get( 385 struct xfs_da_args *args) 386 { 387 struct xfs_bmbt_irec map[ATTR_RMTVALUE_MAPSIZE]; 388 struct xfs_mount *mp = args->dp->i_mount; 389 struct xfs_buf *bp; 390 xfs_dablk_t lblkno = args->rmtblkno; 391 uint8_t *dst = args->value; 392 int valuelen; 393 int nmap; 394 int error; 395 int blkcnt = args->rmtblkcnt; 396 int i; 397 int offset = 0; 398 399 trace_xfs_attr_rmtval_get(args); 400 401 ASSERT(args->valuelen != 0); 402 ASSERT(args->rmtvaluelen == args->valuelen); 403 404 valuelen = args->rmtvaluelen; 405 while (valuelen > 0) { 406 nmap = ATTR_RMTVALUE_MAPSIZE; 407 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, 408 blkcnt, map, &nmap, 409 XFS_BMAPI_ATTRFORK); 410 if (error) 411 return error; 412 ASSERT(nmap >= 1); 413 414 for (i = 0; (i < nmap) && (valuelen > 0); i++) { 415 xfs_daddr_t dblkno; 416 int dblkcnt; 417 418 ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) && 419 (map[i].br_startblock != HOLESTARTBLOCK)); 420 dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); 421 dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); 422 error = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt, 423 0, &bp, &xfs_attr3_rmt_buf_ops); 424 if (xfs_metadata_is_sick(error)) 425 xfs_dirattr_mark_sick(args->dp, XFS_ATTR_FORK); 426 if (error) 427 return error; 428 429 error = xfs_attr_rmtval_copyout(mp, bp, args->dp, 430 &offset, &valuelen, 431 &dst); 432 xfs_buf_relse(bp); 433 if (error) 434 return error; 435 436 /* roll attribute extent map forwards */ 437 lblkno += map[i].br_blockcount; 438 blkcnt -= map[i].br_blockcount; 439 } 440 } 441 ASSERT(valuelen == 0); 442 return 0; 443 } 444 445 /* 446 * Find a "hole" in the attribute address space large enough for us to drop the 447 * new attributes value into 448 */ 449 int 450 xfs_attr_rmt_find_hole( 451 struct xfs_da_args *args) 452 { 453 struct xfs_inode *dp = args->dp; 454 struct xfs_mount *mp = dp->i_mount; 455 int error; 456 int blkcnt; 457 xfs_fileoff_t lfileoff = 0; 458 459 /* 460 * Because CRC enable attributes have headers, we can't just do a 461 * straight byte to FSB conversion and have to take the header space 462 * into account. 463 */ 464 blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen); 465 error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, 466 XFS_ATTR_FORK); 467 if (error) 468 return error; 469 470 args->rmtblkno = (xfs_dablk_t)lfileoff; 471 args->rmtblkcnt = blkcnt; 472 473 return 0; 474 } 475 476 int 477 xfs_attr_rmtval_set_value( 478 struct xfs_da_args *args) 479 { 480 struct xfs_inode *dp = args->dp; 481 struct xfs_mount *mp = dp->i_mount; 482 struct xfs_bmbt_irec map; 483 xfs_dablk_t lblkno; 484 uint8_t *src = args->value; 485 int blkcnt; 486 int valuelen; 487 int nmap; 488 int error; 489 int offset = 0; 490 491 /* 492 * Roll through the "value", copying the attribute value to the 493 * already-allocated blocks. Blocks are written synchronously 494 * so that we can know they are all on disk before we turn off 495 * the INCOMPLETE flag. 496 */ 497 lblkno = args->rmtblkno; 498 blkcnt = args->rmtblkcnt; 499 valuelen = args->rmtvaluelen; 500 while (valuelen > 0) { 501 struct xfs_buf *bp; 502 xfs_daddr_t dblkno; 503 int dblkcnt; 504 505 ASSERT(blkcnt > 0); 506 507 nmap = 1; 508 error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno, 509 blkcnt, &map, &nmap, 510 XFS_BMAPI_ATTRFORK); 511 if (error) 512 return error; 513 ASSERT(nmap == 1); 514 ASSERT((map.br_startblock != DELAYSTARTBLOCK) && 515 (map.br_startblock != HOLESTARTBLOCK)); 516 517 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), 518 dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); 519 520 error = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, &bp); 521 if (error) 522 return error; 523 bp->b_ops = &xfs_attr3_rmt_buf_ops; 524 525 xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset, 526 &valuelen, &src); 527 528 error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */ 529 xfs_buf_relse(bp); 530 if (error) 531 return error; 532 533 534 /* roll attribute extent map forwards */ 535 lblkno += map.br_blockcount; 536 blkcnt -= map.br_blockcount; 537 } 538 ASSERT(valuelen == 0); 539 return 0; 540 } 541 542 /* Mark stale any incore buffers for the remote value. */ 543 int 544 xfs_attr_rmtval_stale( 545 struct xfs_inode *ip, 546 struct xfs_bmbt_irec *map, 547 xfs_buf_flags_t incore_flags) 548 { 549 struct xfs_mount *mp = ip->i_mount; 550 struct xfs_buf *bp; 551 int error; 552 553 xfs_assert_ilocked(ip, XFS_ILOCK_EXCL); 554 555 if (XFS_IS_CORRUPT(mp, map->br_startblock == DELAYSTARTBLOCK) || 556 XFS_IS_CORRUPT(mp, map->br_startblock == HOLESTARTBLOCK)) { 557 xfs_bmap_mark_sick(ip, XFS_ATTR_FORK); 558 return -EFSCORRUPTED; 559 } 560 561 error = xfs_buf_incore(mp->m_ddev_targp, 562 XFS_FSB_TO_DADDR(mp, map->br_startblock), 563 XFS_FSB_TO_BB(mp, map->br_blockcount), 564 incore_flags, &bp); 565 if (error) { 566 if (error == -ENOENT) 567 return 0; 568 return error; 569 } 570 571 xfs_buf_stale(bp); 572 xfs_buf_relse(bp); 573 return 0; 574 } 575 576 /* 577 * Find a hole for the attr and store it in the delayed attr context. This 578 * initializes the context to roll through allocating an attr extent for a 579 * delayed attr operation 580 */ 581 int 582 xfs_attr_rmtval_find_space( 583 struct xfs_attr_intent *attr) 584 { 585 struct xfs_da_args *args = attr->xattri_da_args; 586 struct xfs_bmbt_irec *map = &attr->xattri_map; 587 int error; 588 589 attr->xattri_lblkno = 0; 590 attr->xattri_blkcnt = 0; 591 args->rmtblkcnt = 0; 592 args->rmtblkno = 0; 593 memset(map, 0, sizeof(struct xfs_bmbt_irec)); 594 595 error = xfs_attr_rmt_find_hole(args); 596 if (error) 597 return error; 598 599 attr->xattri_blkcnt = args->rmtblkcnt; 600 attr->xattri_lblkno = args->rmtblkno; 601 602 return 0; 603 } 604 605 /* 606 * Write one block of the value associated with an attribute into the 607 * out-of-line buffer that we have defined for it. This is similar to a subset 608 * of xfs_attr_rmtval_set, but records the current block to the delayed attr 609 * context, and leaves transaction handling to the caller. 610 */ 611 int 612 xfs_attr_rmtval_set_blk( 613 struct xfs_attr_intent *attr) 614 { 615 struct xfs_da_args *args = attr->xattri_da_args; 616 struct xfs_inode *dp = args->dp; 617 struct xfs_bmbt_irec *map = &attr->xattri_map; 618 int nmap; 619 int error; 620 621 nmap = 1; 622 error = xfs_bmapi_write(args->trans, dp, 623 (xfs_fileoff_t)attr->xattri_lblkno, 624 attr->xattri_blkcnt, XFS_BMAPI_ATTRFORK, args->total, 625 map, &nmap); 626 if (error) 627 return error; 628 629 ASSERT(nmap == 1); 630 ASSERT((map->br_startblock != DELAYSTARTBLOCK) && 631 (map->br_startblock != HOLESTARTBLOCK)); 632 633 /* roll attribute extent map forwards */ 634 attr->xattri_lblkno += map->br_blockcount; 635 attr->xattri_blkcnt -= map->br_blockcount; 636 637 return 0; 638 } 639 640 /* 641 * Remove the value associated with an attribute by deleting the 642 * out-of-line buffer that it is stored on. 643 */ 644 int 645 xfs_attr_rmtval_invalidate( 646 struct xfs_da_args *args) 647 { 648 xfs_dablk_t lblkno; 649 int blkcnt; 650 int error; 651 652 /* 653 * Roll through the "value", invalidating the attribute value's blocks. 654 */ 655 lblkno = args->rmtblkno; 656 blkcnt = args->rmtblkcnt; 657 while (blkcnt > 0) { 658 struct xfs_bmbt_irec map; 659 int nmap; 660 661 /* 662 * Try to remember where we decided to put the value. 663 */ 664 nmap = 1; 665 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, 666 blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK); 667 if (error) 668 return error; 669 if (XFS_IS_CORRUPT(args->dp->i_mount, nmap != 1)) { 670 xfs_bmap_mark_sick(args->dp, XFS_ATTR_FORK); 671 return -EFSCORRUPTED; 672 } 673 error = xfs_attr_rmtval_stale(args->dp, &map, XBF_TRYLOCK); 674 if (error) 675 return error; 676 677 lblkno += map.br_blockcount; 678 blkcnt -= map.br_blockcount; 679 } 680 return 0; 681 } 682 683 /* 684 * Remove the value associated with an attribute by deleting the out-of-line 685 * buffer that it is stored on. Returns -EAGAIN for the caller to refresh the 686 * transaction and re-call the function. Callers should keep calling this 687 * routine until it returns something other than -EAGAIN. 688 */ 689 int 690 xfs_attr_rmtval_remove( 691 struct xfs_attr_intent *attr) 692 { 693 struct xfs_da_args *args = attr->xattri_da_args; 694 int error, done; 695 696 /* 697 * Unmap value blocks for this attr. 698 */ 699 error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno, 700 args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done); 701 if (error) 702 return error; 703 704 /* 705 * We don't need an explicit state here to pick up where we left off. We 706 * can figure it out using the !done return code. The actual value of 707 * attr->xattri_dela_state may be some value reminiscent of the calling 708 * function, but it's value is irrelevant with in the context of this 709 * function. Once we are done here, the next state is set as needed by 710 * the parent 711 */ 712 if (!done) { 713 trace_xfs_attr_rmtval_remove_return(attr->xattri_dela_state, 714 args->dp); 715 return -EAGAIN; 716 } 717 718 args->rmtblkno = 0; 719 args->rmtblkcnt = 0; 720 return 0; 721 } 722