xfs_repair: allow sysadmins to add metadata directories
authorDarrick J. Wong <djwong@kernel.org>
Wed, 3 Jul 2024 21:21:56 +0000 (14:21 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 30 Jul 2024 00:13:19 +0000 (17:13 -0700)
Allow the sysadmin to use xfs_repair to upgrade an existing filesystem
to support metadata directories.  This will be needed to upgrade
filesystems to support realtime rmap and reflink.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
man/man8/xfs_admin.8
repair/dino_chunks.c
repair/dinode.c
repair/globals.c
repair/globals.h
repair/phase2.c
repair/phase4.c
repair/protos.h
repair/xfs_repair.c

index a25e599e5f8e2ce9f2aa143f12dc9b4de3178953..e55dee6070e460d33e7bb75417710f3589bb60ca 100644 (file)
@@ -191,6 +191,14 @@ This enables much stronger cross-referencing and online repairs of the
 directory tree.
 The filesystem cannot be downgraded after this feature is enabled.
 This upgrade can fail if the filesystem has less than 25% free space remaining.
+.TP 0.4i
+.B metadir
+Create a directory tree of metadata inodes instead of storing them all in the
+superblock.
+This is required for reverse mapping btrees and reflink support on the realtime
+device.
+The filesystem cannot be downgraded after this feature is enabled.
+This upgrade can fail if any AG has less than 5% free space remaining.
 This feature is not upstream yet.
 .RE
 .TP
index 7e18991a3d527c1c8c7e1aabbc1dcd8f2d9c9270..c09dac20ac1af7c200ec5776f6a148b4e5915b70 100644 (file)
@@ -951,7 +951,11 @@ next_readbuf:
                }
 
                if (status)  {
-                       if (mp->m_sb.sb_rootino == ino) {
+                       if (wipe_pre_metadir_file(ino)) {
+                               if (!ino_discovery)
+                                       do_warn(
+       _("wiping pre-metadir metadata inode %"PRIu64".\n"), ino);
+                       } else if (mp->m_sb.sb_rootino == ino) {
                                need_root_inode = 1;
 
                                if (!no_modify)  {
index 6d1549aa66a569b93c824bd69d48b946dadc026f..b9337c1adfc573b88df546858ac367ca7f6b6542 100644 (file)
@@ -2450,6 +2450,9 @@ process_dinode_int(
        ASSERT(uncertain == 0 || verify_mode != 0);
        ASSERT(ino_bpp != NULL || verify_mode != 0);
 
+       if (wipe_pre_metadir_file(lino))
+               goto clear_bad_out;
+
        /*
         * This is the only valid point to check the CRC; after this we may have
         * made changes which invalidate it, and the CRC is only updated again
@@ -2659,7 +2662,7 @@ _("bad (negative) size %" PRId64 " on inode %" PRIu64 "\n"),
                if (flags & XFS_DIFLAG_NEWRTBM) {
                        /* must be a rt bitmap inode */
                        if (lino != mp->m_sb.sb_rbmino) {
-                               if (!uncertain) {
+                               if (!uncertain && !add_metadir) {
                                        do_warn(
        _("inode %" PRIu64 " not rt bitmap\n"),
                                                lino);
index 624c092636796d8af0194de60b1387da1d30f72a..ad01fcc23e39ad11c06bf157fe259fc3e8daa4e8 100644 (file)
@@ -57,6 +57,7 @@ bool  add_finobt;             /* add free inode btrees */
 bool   add_reflink;            /* add reference count btrees */
 bool   add_rmapbt;             /* add reverse mapping btrees */
 bool   add_parent;             /* add parent pointers */
+bool   add_metadir;            /* add metadata directory tree */
 
 /* misc status variables */
 
index 31c87b37b409abe29d41360ab037a5713dfdd6c7..9a5d444a8e7564fccf63bd4a949f3fc8d98dc120 100644 (file)
@@ -98,6 +98,7 @@ extern bool   add_finobt;             /* add free inode btrees */
 extern bool    add_reflink;            /* add reference count btrees */
 extern bool    add_rmapbt;             /* add reverse mapping btrees */
 extern bool    add_parent;             /* add parent pointers */
+extern bool    add_metadir;            /* add metadata directory tree */
 
 /* misc status variables */
 
index f26cc6d25f7860ef0f64dba19c90d16c19ec08c8..c3e462ae1ee2a4fd3b01706d4273dc803616017b 100644 (file)
@@ -14,6 +14,7 @@
 #include "incore.h"
 #include "progress.h"
 #include "scan.h"
+#include "quotacheck.h"
 
 /* workaround craziness in the xlog routines */
 int xlog_recover_do_trans(struct xlog *log, struct xlog_recover *t, int p)
@@ -315,6 +316,70 @@ set_parent(
        return true;
 }
 
+static xfs_ino_t doomed_rbmino = NULLFSINO;
+static xfs_ino_t doomed_rsumino = NULLFSINO;
+static xfs_ino_t doomed_uquotino = NULLFSINO;
+static xfs_ino_t doomed_gquotino = NULLFSINO;
+static xfs_ino_t doomed_pquotino = NULLFSINO;
+
+bool
+wipe_pre_metadir_file(
+       xfs_ino_t       ino)
+{
+       if (ino == doomed_rbmino ||
+           ino == doomed_rsumino ||
+           ino == doomed_uquotino ||
+           ino == doomed_gquotino ||
+           ino == doomed_pquotino)
+               return true;
+       return false;
+}
+
+static bool
+set_metadir(
+       struct xfs_mount        *mp,
+       struct xfs_sb           *new_sb)
+{
+       if (xfs_has_metadir(mp)) {
+               printf(_("Filesystem already supports metadata directory trees.\n"));
+               exit(0);
+       }
+
+       if (!xfs_has_crc(mp)) {
+               printf(
+       _("Metadata directory trees only supported on V5 filesystems.\n"));
+               exit(0);
+       }
+
+       printf(_("Adding metadata directory trees to filesystem.\n"));
+       new_sb->sb_features_incompat |= (XFS_SB_FEAT_INCOMPAT_METADIR |
+                                        XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR);
+
+       /* Blow out all the old metadata inodes; we'll rebuild in phase6. */
+       new_sb->sb_metadirino = new_sb->sb_rootino + 1;
+       doomed_rbmino = mp->m_sb.sb_rbmino;
+       doomed_rsumino = mp->m_sb.sb_rsumino;
+       doomed_uquotino = mp->m_sb.sb_uquotino;
+       doomed_gquotino = mp->m_sb.sb_gquotino;
+       doomed_pquotino = mp->m_sb.sb_pquotino;
+
+       new_sb->sb_rbmino = NULLFSINO;
+       new_sb->sb_rsumino = NULLFSINO;
+       new_sb->sb_uquotino = NULLFSINO;
+       new_sb->sb_gquotino = NULLFSINO;
+       new_sb->sb_pquotino = NULLFSINO;
+
+       /* Indicate that we need a rebuild. */
+       need_metadir_inode = 1;
+       need_rbmino = 1;
+       need_rsumino = 1;
+       have_uquotino = 0;
+       have_gquotino = 0;
+       have_pquotino = 0;
+       quotacheck_skip();
+       return true;
+}
+
 struct check_state {
        struct xfs_sb           sb;
        uint64_t                features;
@@ -503,6 +568,8 @@ need_check_fs_free_space(
                return true;
        if (xfs_has_parent(mp) && !(old->features & XFS_FEAT_PARENT))
                return true;
+       if (xfs_has_metadir(mp) && !(old->features & XFS_FEAT_METADIR))
+               return true;
        return false;
 }
 
@@ -588,6 +655,8 @@ upgrade_filesystem(
                dirty |= set_rmapbt(mp, &new_sb);
        if (add_parent)
                dirty |= set_parent(mp, &new_sb);
+       if (add_metadir)
+               dirty |= set_metadir(mp, &new_sb);
        if (!dirty)
                return;
 
index e8bd5982147764d7d7717f8009af444449159e0b..cfdea1460e54e67c85526eb754691687e3611de2 100644 (file)
@@ -272,7 +272,10 @@ phase4(xfs_mount_t *mp)
        if (xfs_has_metadir(mp) &&
            (is_inode_free(irec, 1) || !inode_isadir(irec, 1))) {
                need_metadir_inode = true;
-               if (no_modify)
+               if (add_metadir)
+                       do_warn(
+       _("metadata directory root inode needs to be initialized\n"));
+               else if (no_modify)
                        do_warn(
        _("metadata directory root inode would be lost\n"));
                else
index e2f39f1d6e8aa307a414d1dcd0e60db1c1719ae4..ce171f3dd87cb6c398fe455f91ff7343126e058b 100644 (file)
@@ -3,6 +3,8 @@
  * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
  * All Rights Reserved.
  */
+#ifndef __XFS_REPAIR_PROTOS_H__
+#define __XFS_REPAIR_PROTOS_H__
 
 void   xfs_init(struct libxfs_init *args);
 
@@ -45,3 +47,7 @@ void  phase7(struct xfs_mount *, int);
 int    verify_set_agheader(struct xfs_mount *, struct xfs_buf *,
                struct xfs_sb *, struct xfs_agf *, struct xfs_agi *,
                xfs_agnumber_t);
+
+bool wipe_pre_metadir_file(xfs_ino_t ino);
+
+#endif  /* __XFS_REPAIR_PROTOS_H__ */
index 26bdfac865975a5838353c2cae5930c29917bdc4..8a3442d4e0e9c9571c9fe2b7367e7f767405eba7 100644 (file)
@@ -74,6 +74,7 @@ enum c_opt_nums {
        CONVERT_REFLINK,
        CONVERT_RMAPBT,
        CONVERT_PARENT,
+       CONVERT_METADIR,
        C_MAX_OPTS,
 };
 
@@ -87,6 +88,7 @@ static char *c_opts[] = {
        [CONVERT_REFLINK]       = "reflink",
        [CONVERT_RMAPBT]        = "rmapbt",
        [CONVERT_PARENT]        = "parent",
+       [CONVERT_METADIR]       = "metadir",
        [C_MAX_OPTS]            = NULL,
 };
 
@@ -415,6 +417,15 @@ process_args(int argc, char **argv)
                _("-c parent only supports upgrades\n"));
                                        add_parent = true;
                                        break;
+                               case CONVERT_METADIR:
+                                       if (!val)
+                                               do_abort(
+               _("-c metadir requires a parameter\n"));
+                                       if (strtol(val, NULL, 0) != 1)
+                                               do_abort(
+               _("-c metadir only supports upgrades\n"));
+                                       add_metadir = true;
+                                       break;
                                default:
                                        unknown('c', val);
                                        break;