Merge data and attribute fork reverse mappings.
Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
---
repair/phase4.c | 10 ++++++++++
repair/rmap.c | 32 +++++++++++++++++++++++++++++---
repair/rmap.h | 2 ++
3 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/repair/phase4.c b/repair/phase4.c
index e234d92..3be3786 100644
--- a/repair/phase4.c
+++ b/repair/phase4.c
@@ -154,7 +154,17 @@ static void
process_ags(
xfs_mount_t *mp)
{
+ xfs_agnumber_t i;
+ int error;
+
do_inode_prefetch(mp, ag_stride, process_ag_func, true, false);
+ for (i = 0; i < mp->m_sb.sb_agcount; i++) {
+ error = finish_collecting_fork_rmaps(mp, i);
+ if (error)
+ do_error(
+_("unable to finish adding attr/data fork reverse-mapping data for AG %u.\n"),
+ i);
+ }
}
static void
diff --git a/repair/rmap.c b/repair/rmap.c
index 9c17ee8..e39df5a 100644
--- a/repair/rmap.c
+++ b/repair/rmap.c
@@ -41,6 +41,7 @@ struct xfs_ag_rmap {
struct xfs_slab *ar_raw_rmaps; /* unmerged rmaps */
int ar_flcount; /* agfl entries from leftover */
/* agbt allocations */
+ struct xfs_rmap_irec ar_last_rmap; /* last rmap seen */
};
static struct xfs_ag_rmap *ag_rmaps;
@@ -118,6 +119,7 @@ _("Insufficient memory while allocating reverse mapping
slabs."));
if (error)
do_error(
_("Insufficient memory while allocating raw metadata reverse mapping slabs."));
+ ag_rmaps[i].ar_last_rmap.rm_owner = XFS_RMAP_OWN_UNKNOWN;
}
}
@@ -177,10 +179,11 @@ add_rmap(
int whichfork,
struct xfs_bmbt_irec *irec)
{
- struct xfs_slab *rmaps;
struct xfs_rmap_irec rmap;
xfs_agnumber_t agno;
xfs_agblock_t agbno;
+ struct xfs_rmap_irec *last_rmap;
+ int error = 0;
if (!needs_rmap_work(mp))
return 0;
@@ -193,7 +196,6 @@ add_rmap(
ASSERT(ino != NULLFSINO);
ASSERT(whichfork == XFS_DATA_FORK || whichfork == XFS_ATTR_FORK);
- rmaps = ag_rmaps[agno].ar_rmaps;
rmap.rm_owner = ino;
rmap.rm_offset = irec->br_startoff;
rmap.rm_flags = 0;
@@ -203,7 +205,31 @@ add_rmap(
rmap.rm_blockcount = irec->br_blockcount;
if (irec->br_state == XFS_EXT_UNWRITTEN)
rmap.rm_flags |= XFS_RMAP_UNWRITTEN;
- return slab_add(rmaps, &rmap);
+ last_rmap = &ag_rmaps[agno].ar_last_rmap;
+ if (last_rmap->rm_owner == XFS_RMAP_OWN_UNKNOWN)
+ *last_rmap = rmap;
+ else if (mergeable_rmaps(last_rmap, &rmap))
+ last_rmap->rm_blockcount += rmap.rm_blockcount;
+ else {
+ error = slab_add(ag_rmaps[agno].ar_rmaps, last_rmap);
+ if (error)
+ return error;
+ *last_rmap = rmap;
+ }
+
+ return error;
+}
+
+/* Finish collecting inode data/attr fork rmaps. */
+int
+finish_collecting_fork_rmaps(
+ struct xfs_mount *mp,
+ xfs_agnumber_t agno)
+{
+ if (!needs_rmap_work(mp) ||
+ ag_rmaps[agno].ar_last_rmap.rm_owner == XFS_RMAP_OWN_UNKNOWN)
+ return 0;
+ return slab_add(ag_rmaps[agno].ar_rmaps, &ag_rmaps[agno].ar_last_rmap);
}
/* add a raw rmap; these will be merged later */
diff --git a/repair/rmap.h b/repair/rmap.h
index 4722266..69215e8 100644
--- a/repair/rmap.h
+++ b/repair/rmap.h
@@ -28,6 +28,8 @@ extern void init_rmaps(struct xfs_mount *);
extern void free_rmaps(struct xfs_mount *);
extern int add_rmap(struct xfs_mount *, xfs_ino_t, int, struct xfs_bmbt_irec
*);
+extern int finish_collecting_fork_rmaps(struct xfs_mount *mp,
+ xfs_agnumber_t agno);
extern int add_ag_rmap(struct xfs_mount *, xfs_agnumber_t agno,
xfs_agblock_t agbno, xfs_extlen_t len, uint64_t owner);
extern int add_bmbt_rmap(struct xfs_mount *, xfs_ino_t, int, xfs_fsblock_t);
|