@@ -144,5 +144,6 @@
#define xfs_refc_block libxfs_refc_block
#define xfs_rtrmapbt_maxrecs libxfs_rtrmapbt_maxrecs
#define xfs_rtrmapbt_init_cursor libxfs_rtrmapbt_init_cursor
+#define xfs_rmap_map_extent libxfs_rmap_map_extent
#endif /* __LIBXFS_API_DEFS_H__ */
@@ -29,6 +29,8 @@
#include "dinode.h"
#include "progress.h"
#include "versions.h"
+#include "slab.h"
+#include "rmap.h"
static struct cred zerocr;
static struct fsxattr zerofsx;
@@ -831,6 +833,61 @@ mk_rsumino(xfs_mount_t *mp)
IRELE(ip);
}
+static void
+mk_rrmapino(
+ struct xfs_mount *mp)
+{
+ struct xfs_trans *tp;
+ struct xfs_inode *ip;
+ struct cred creds = {0};
+ struct fsxattr fsxattrs = {0};
+ struct xfs_btree_block *block;
+ int error;
+
+ if (!xfs_sb_version_hasrmapbt(&mp->m_sb) || mp->m_sb.sb_rblocks == 0)
+ return;
+
+ error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp);
+ if (error)
+ res_failed(error);
+
+ if (mp->m_sb.sb_rrmapino == 0 ||
+ mp->m_sb.sb_rrmapino == NULLFSINO ||
+ need_rrmapino) {
+ /* Allocate a new inode. */
+ error = -libxfs_inode_alloc(&tp, NULL, S_IFREG, 1, 0,
+ &creds, &fsxattrs, &ip);
+ if (error) {
+ do_error(_("Realtime rmap inode allocation failed -- error %d"),
+ error);
+ }
+ mp->m_sb.sb_rrmapino = ip->i_ino;
+ ip->i_df.if_broot_bytes = XFS_RTRMAP_BROOT_SPACE_CALC(0, 0);
+ ip->i_df.if_broot = kmem_alloc(ip->i_df.if_broot_bytes,
+ KM_SLEEP | KM_NOFS);
+ } else {
+ /* Grab the existing inode. */
+ error = -libxfs_trans_iget(mp, tp, mp->m_sb.sb_rrmapino,
+ 0, 0, &ip);
+ if (error)
+ do_error(_("Could not iget realtime rmapbt inode -- error %d"),
+ error);
+ }
+
+ /* Reset the btree root. */
+ ip->i_d.di_size = 0;
+ ip->i_d.di_nblocks = 0;
+ ip->i_d.di_format = XFS_DINODE_FMT_RMAP;
+ block = ip->i_df.if_broot;
+ block->bb_numrecs = cpu_to_be16(0);
+ block->bb_level = cpu_to_be16(0);
+
+ libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE | XFS_ILOG_DBROOT);
+ libxfs_log_sb(tp);
+ libxfs_trans_commit(tp);
+ IRELE(ip);
+}
+
/*
* makes a new root directory.
*/
@@ -3248,6 +3305,18 @@ phase6(xfs_mount_t *mp)
}
}
+ /*
+ * We always reinitialize the rrmapbt inode, but if it was bad we
+ * ought to say something.
+ */
+ if (no_modify) {
+ if (need_rrmapino)
+ do_warn(_("would reinitialize realtime rmap btree\n"));
+ } else {
+ need_rrmapino = 0;
+ mk_rrmapino(mp);
+ }
+
if (!no_modify) {
do_log(
_(" - resetting contents of realtime bitmap and summary inodes\n"));
@@ -3260,6 +3329,10 @@ _(" - resetting contents of realtime bitmap and summary inodes\n"));
do_warn(
_("Warning: realtime bitmap may be inconsistent\n"));
}
+
+ if (rmap_populate_realtime_rmapbt(mp))
+ do_warn(
+ _("Warning: realtime rmapbt may be inconsistent\n"));
}
mark_standalone_inodes(mp);
@@ -1525,3 +1525,71 @@ rmap_store_agflcount(
rmap_for_ag(agno)->ar_flcount = count;
}
+
+/* Store the realtime reverse-mappings in the rtrmapbt. */
+int
+rmap_populate_realtime_rmapbt(
+ struct xfs_mount *mp)
+{
+ struct xfs_trans *tp;
+ struct xfs_inode *ip;
+ struct xfs_inode fakei;
+ struct xfs_slab_cursor *rmap_cur;
+ struct xfs_defer_ops dfops;
+ xfs_fsblock_t firstfsb;
+ struct xfs_rmap_irec *rm_rec;
+ struct xfs_bmbt_irec imap;
+ int error;
+
+ if (!xfs_sb_version_hasrmapbt(&mp->m_sb) || mp->m_sb.sb_rblocks == 0)
+ return 0;
+
+ error = rmap_init_cursor(NULLAGNUMBER, &rmap_cur);
+ if (error) {
+ error = -ENOMEM;
+ goto out;
+ }
+
+ error = -libxfs_iget(mp, NULL, mp->m_sb.sb_rrmapino, 0, &ip, 0);
+ if (error)
+ goto out_inode;
+
+ mp->m_rrmapip = ip;
+ fakei.i_d.di_flags = XFS_DIFLAG_REALTIME;
+ fakei.i_d.di_flags2 = 0;
+
+ libxfs_defer_init(&dfops, &firstfsb);
+ while ((rm_rec = pop_slab_cursor(rmap_cur))) {
+ imap.br_startoff = rm_rec->rm_offset;
+ imap.br_startblock = rm_rec->rm_startblock;
+ imap.br_blockcount = rm_rec->rm_blockcount;
+ imap.br_state = (rm_rec->rm_flags & XFS_RMAP_UNWRITTEN ?
+ XFS_EXT_UNWRITTEN : XFS_EXT_NORM);
+ fakei.i_ino = rm_rec->rm_owner;
+ error = -libxfs_rmap_map_extent(mp, &dfops, &fakei,
+ XFS_DATA_FORK, &imap);
+ if (error)
+ goto out_defer;
+ }
+
+ error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
+ if (error)
+ goto out_defer;
+
+ error = -libxfs_defer_finish(&tp, &dfops, NULL);
+ if (error)
+ goto out_cancel;
+
+ error = -libxfs_trans_commit(tp);
+ goto out_inode;
+
+out_cancel:
+ libxfs_trans_cancel(tp);
+out_defer:
+ libxfs_defer_cancel(&dfops);
+out_inode:
+ mp->m_rrmapip = NULL;
+ IRELE(ip);
+out:
+ return error;
+}
@@ -70,4 +70,6 @@ extern void rmap_store_agflcount(struct xfs_mount *, xfs_agnumber_t, int);
for ((agno) = NULLAGNUMBER; (agno) == NULLAGNUMBER || \
(agno) < (mp)->m_sb.sb_agcount; (agno)++)
+extern int rmap_populate_realtime_rmapbt(struct xfs_mount *mp);
+
#endif /* RMAP_H_ */
@@ -936,11 +936,14 @@ main(int argc, char **argv)
/*
* Done with the block usage maps, toss them...
*/
- rmaps_free(mp);
+ if (mp->m_sb.sb_rblocks == 0)
+ rmaps_free(mp);
free_bmaps(mp);
if (!bad_ino_btree) {
phase6(mp);
+ if (mp->m_sb.sb_rblocks != 0)
+ rmaps_free(mp);
timestamp(PHASE_END, 6, NULL);
phase7(mp, phase2_threads);
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> --- libxfs/libxfs_api_defs.h | 1 + repair/phase6.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++ repair/rmap.c | 68 +++++++++++++++++++++++++++++++++++++++++++ repair/rmap.h | 2 + repair/xfs_repair.c | 5 +++ 5 files changed, 148 insertions(+), 1 deletion(-)