diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_rmap.c')
-rw-r--r-- | fs/xfs/libxfs/xfs_rmap.c | 99 |
1 files changed, 76 insertions, 23 deletions
diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c index dd019cee1b3b..50db920ceeeb 100644 --- a/fs/xfs/libxfs/xfs_rmap.c +++ b/fs/xfs/libxfs/xfs_rmap.c | |||
@@ -368,6 +368,51 @@ xfs_rmap_lookup_le_range( | |||
368 | } | 368 | } |
369 | 369 | ||
370 | /* | 370 | /* |
371 | * Perform all the relevant owner checks for a removal op. If we're doing an | ||
372 | * unknown-owner removal then we have no owner information to check. | ||
373 | */ | ||
374 | static int | ||
375 | xfs_rmap_free_check_owner( | ||
376 | struct xfs_mount *mp, | ||
377 | uint64_t ltoff, | ||
378 | struct xfs_rmap_irec *rec, | ||
379 | xfs_fsblock_t bno, | ||
380 | xfs_filblks_t len, | ||
381 | uint64_t owner, | ||
382 | uint64_t offset, | ||
383 | unsigned int flags) | ||
384 | { | ||
385 | int error = 0; | ||
386 | |||
387 | if (owner == XFS_RMAP_OWN_UNKNOWN) | ||
388 | return 0; | ||
389 | |||
390 | /* Make sure the unwritten flag matches. */ | ||
391 | XFS_WANT_CORRUPTED_GOTO(mp, (flags & XFS_RMAP_UNWRITTEN) == | ||
392 | (rec->rm_flags & XFS_RMAP_UNWRITTEN), out); | ||
393 | |||
394 | /* Make sure the owner matches what we expect to find in the tree. */ | ||
395 | XFS_WANT_CORRUPTED_GOTO(mp, owner == rec->rm_owner, out); | ||
396 | |||
397 | /* Check the offset, if necessary. */ | ||
398 | if (XFS_RMAP_NON_INODE_OWNER(owner)) | ||
399 | goto out; | ||
400 | |||
401 | if (flags & XFS_RMAP_BMBT_BLOCK) { | ||
402 | XFS_WANT_CORRUPTED_GOTO(mp, rec->rm_flags & XFS_RMAP_BMBT_BLOCK, | ||
403 | out); | ||
404 | } else { | ||
405 | XFS_WANT_CORRUPTED_GOTO(mp, rec->rm_offset <= offset, out); | ||
406 | XFS_WANT_CORRUPTED_GOTO(mp, | ||
407 | ltoff + rec->rm_blockcount >= offset + len, | ||
408 | out); | ||
409 | } | ||
410 | |||
411 | out: | ||
412 | return error; | ||
413 | } | ||
414 | |||
415 | /* | ||
371 | * Find the extent in the rmap btree and remove it. | 416 | * Find the extent in the rmap btree and remove it. |
372 | * | 417 | * |
373 | * The record we find should always be an exact match for the extent that we're | 418 | * The record we find should always be an exact match for the extent that we're |
@@ -444,33 +489,40 @@ xfs_rmap_unmap( | |||
444 | goto out_done; | 489 | goto out_done; |
445 | } | 490 | } |
446 | 491 | ||
447 | /* Make sure the unwritten flag matches. */ | 492 | /* |
448 | XFS_WANT_CORRUPTED_GOTO(mp, (flags & XFS_RMAP_UNWRITTEN) == | 493 | * If we're doing an unknown-owner removal for EFI recovery, we expect |
449 | (ltrec.rm_flags & XFS_RMAP_UNWRITTEN), out_error); | 494 | * to find the full range in the rmapbt or nothing at all. If we |
495 | * don't find any rmaps overlapping either end of the range, we're | ||
496 | * done. Hopefully this means that the EFI creator already queued | ||
497 | * (and finished) a RUI to remove the rmap. | ||
498 | */ | ||
499 | if (owner == XFS_RMAP_OWN_UNKNOWN && | ||
500 | ltrec.rm_startblock + ltrec.rm_blockcount <= bno) { | ||
501 | struct xfs_rmap_irec rtrec; | ||
502 | |||
503 | error = xfs_btree_increment(cur, 0, &i); | ||
504 | if (error) | ||
505 | goto out_error; | ||
506 | if (i == 0) | ||
507 | goto out_done; | ||
508 | error = xfs_rmap_get_rec(cur, &rtrec, &i); | ||
509 | if (error) | ||
510 | goto out_error; | ||
511 | XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); | ||
512 | if (rtrec.rm_startblock >= bno + len) | ||
513 | goto out_done; | ||
514 | } | ||
450 | 515 | ||
451 | /* Make sure the extent we found covers the entire freeing range. */ | 516 | /* Make sure the extent we found covers the entire freeing range. */ |
452 | XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno && | 517 | XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno && |
453 | ltrec.rm_startblock + ltrec.rm_blockcount >= | 518 | ltrec.rm_startblock + ltrec.rm_blockcount >= |
454 | bno + len, out_error); | 519 | bno + len, out_error); |
455 | 520 | ||
456 | /* Make sure the owner matches what we expect to find in the tree. */ | 521 | /* Check owner information. */ |
457 | XFS_WANT_CORRUPTED_GOTO(mp, owner == ltrec.rm_owner || | 522 | error = xfs_rmap_free_check_owner(mp, ltoff, <rec, bno, len, owner, |
458 | XFS_RMAP_NON_INODE_OWNER(owner), out_error); | 523 | offset, flags); |
459 | 524 | if (error) | |
460 | /* Check the offset, if necessary. */ | 525 | goto out_error; |
461 | if (!XFS_RMAP_NON_INODE_OWNER(owner)) { | ||
462 | if (flags & XFS_RMAP_BMBT_BLOCK) { | ||
463 | XFS_WANT_CORRUPTED_GOTO(mp, | ||
464 | ltrec.rm_flags & XFS_RMAP_BMBT_BLOCK, | ||
465 | out_error); | ||
466 | } else { | ||
467 | XFS_WANT_CORRUPTED_GOTO(mp, | ||
468 | ltrec.rm_offset <= offset, out_error); | ||
469 | XFS_WANT_CORRUPTED_GOTO(mp, | ||
470 | ltoff + ltrec.rm_blockcount >= offset + len, | ||
471 | out_error); | ||
472 | } | ||
473 | } | ||
474 | 526 | ||
475 | if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) { | 527 | if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) { |
476 | /* exact match, simply remove the record from rmap tree */ | 528 | /* exact match, simply remove the record from rmap tree */ |
@@ -664,6 +716,7 @@ xfs_rmap_map( | |||
664 | flags |= XFS_RMAP_UNWRITTEN; | 716 | flags |= XFS_RMAP_UNWRITTEN; |
665 | trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len, | 717 | trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len, |
666 | unwritten, oinfo); | 718 | unwritten, oinfo); |
719 | ASSERT(!xfs_rmap_should_skip_owner_update(oinfo)); | ||
667 | 720 | ||
668 | /* | 721 | /* |
669 | * For the initial lookup, look for an exact match or the left-adjacent | 722 | * For the initial lookup, look for an exact match or the left-adjacent |