summaryrefslogtreecommitdiff
path: root/fs/xfs/libxfs
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-11-04 13:28:36 -0700
committerDarrick J. Wong <djwong@kernel.org>2021-12-15 17:28:48 -0800
commit8eaf95eb503571a717ee930018df843c07d433cb (patch)
treec78510dd1c252b2fca902286b923453da7b059c5 /fs/xfs/libxfs
parent807adbc190326add1b13b7aae8f79729231ac1c1 (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.c19
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);