diff options
author | Darrick J. Wong <djwong@kernel.org> | 2021-11-04 13:28:36 -0700 |
---|---|---|
committer | Darrick J. Wong <djwong@kernel.org> | 2021-12-15 17:28:48 -0800 |
commit | 8eaf95eb503571a717ee930018df843c07d433cb (patch) | |
tree | c78510dd1c252b2fca902286b923453da7b059c5 /fs/xfs/libxfs | |
parent | 807adbc190326add1b13b7aae8f79729231ac1c1 (diff) |
xfs: amend xfs_rmap_has_other_keys to check file offsets properly
This function was created to help online repair deal with freeing blocks
from an old metadata structure after a repair completes. When
considering a block to free, we want to know if the rmap btree contains
records of any other owners. If yes, the block is crosslinked and we
merely want to drop the forward reference to the block and any rmap
record from the deleted structure. If no, then we should additionally
free the block.
The current version doesn't actually check file offsets properly, since
I hadn't built gotten that far with online repair. Now that I have, I
know that it should be performing a range comparison of the offsets and
not the simple offset check that it currently performs.
So, fix this deficiency ahead of the rest of online repair.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Diffstat (limited to 'fs/xfs/libxfs')
-rw-r--r-- | fs/xfs/libxfs/xfs_rmap.c | 19 |
1 files changed, 15 insertions, 4 deletions
diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c index 4ed07e1d333c..424b358c08fb 100644 --- a/fs/xfs/libxfs/xfs_rmap.c +++ b/fs/xfs/libxfs/xfs_rmap.c @@ -2751,6 +2751,7 @@ xfs_rmap_record_exists( struct xfs_rmap_key_state { uint64_t owner; uint64_t offset; + uint64_t len; unsigned int flags; }; @@ -2763,10 +2764,20 @@ xfs_rmap_has_other_keys_helper( { struct xfs_rmap_key_state *rks = priv; - if (rks->owner == rec->rm_owner && rks->offset == rec->rm_offset && - ((rks->flags & rec->rm_flags) & XFS_RMAP_KEY_FLAGS) == rks->flags) + if (rks->owner != rec->rm_owner) + return -ECANCELED; + if (((rks->flags & rec->rm_flags) & XFS_RMAP_KEY_FLAGS) != rks->flags) + return -ECANCELED; + + if (XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) || + (rec->rm_flags & XFS_RMAP_BMBT_BLOCK)) return 0; - return -ECANCELED; + + if (rec->rm_offset + rec->rm_blockcount <= rks->offset) + return -ECANCELED; + if (rks->offset + rks->len <= rec->rm_offset) + return -ECANCELED; + return 0; } /* @@ -2783,7 +2794,7 @@ xfs_rmap_has_other_keys( { struct xfs_rmap_irec low = {0}; struct xfs_rmap_irec high; - struct xfs_rmap_key_state rks; + struct xfs_rmap_key_state rks = { .len = len }; int error; xfs_owner_info_unpack(oinfo, &rks.owner, &rks.offset, &rks.flags); |