]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs_repair: support quota inodes in the metadata directory
authorDarrick J. Wong <djwong@kernel.org>
Thu, 22 Aug 2024 16:43:34 +0000 (09:43 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 9 Oct 2024 23:29:16 +0000 (16:29 -0700)
Handle quota inodes on metadir filesystems.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
include/xfs_mount.h
libxfs/init.c
repair/agheader.c
repair/phase2.c
repair/phase6.c
repair/quotacheck.c
repair/quotacheck.h
repair/xfs_repair.c

index 0c09dbf3d97ef50784f2fab06bcbb639488e7941..19d08cf047f2028136728ef68b5299658935a01b 100644 (file)
@@ -85,7 +85,6 @@ typedef struct xfs_mount {
        xfs_filblks_t           m_rsumblocks;   /* size of rt summary, FSBs */
        struct xfs_inode        *m_metadirip;   /* ptr to metadata directory */
        struct xfs_inode        *m_rtdirip;     /* ptr to realtime metadir */
-       struct xfs_inode        *m_qdirip;      /* ptr to quota metadir */
        struct xfs_buftarg      *m_ddev_targp;
        struct xfs_buftarg      *m_logdev_targp;
        struct xfs_buftarg      *m_rtdev_targp;
index a7a669887b08ef0332ee7c518b66b4cb01707fe2..dd2be84c090ba42176bf916e9d167d39ad08aada 100644 (file)
@@ -1000,8 +1000,6 @@ libxfs_umount(
        int                     error;
 
        libxfs_rtmount_destroy(mp);
-       if (mp->m_qdirip)
-               libxfs_irele(mp->m_qdirip);
        if (mp->m_metadirip)
                libxfs_irele(mp->m_metadirip);
 
index bc6c4579661bdda19ac32e841818ff749e4eeb4d..5735bb720d94ec773816e8ef1824ae7e3892b2f7 100644 (file)
@@ -509,7 +509,8 @@ secondary_sb_whack(
                        rval |= XR_AG_SB_SEC;
        }
 
-       rval |= secondary_sb_quota(mp, sbuf, sb, i, do_bzero);
+       if (!xfs_has_metadir(mp))
+               rval |= secondary_sb_quota(mp, sbuf, sb, i, do_bzero);
 
        /*
         * if the secondaries agree on a stripe unit/width or inode
index 27c873fca76747ce67d3d0625a41923f5f270ef0..71576f5806e473b44279cea92513995dc9d7d861 100644 (file)
@@ -15,6 +15,7 @@
 #include "progress.h"
 #include "scan.h"
 #include "rt.h"
+#include "quotacheck.h"
 
 /* workaround craziness in the xlog routines */
 int xlog_recover_do_trans(struct xlog *log, struct xlog_recover *t, int p)
@@ -625,6 +626,8 @@ phase2(
        }
 
        discover_rtgroup_inodes(mp);
+       if (xfs_has_metadir(mp) && xfs_has_quota(mp))
+               discover_quota_inodes(mp);
 
        /*
         * Upgrade the filesystem now that we've done a preliminary check of
index acd3051751a6e3818c14a74c1c0a1e6dae3c2902..28e6bf3b754bdcc7017d77577c081bdeb08d91b3 100644 (file)
@@ -20,6 +20,7 @@
 #include "versions.h"
 #include "repair/pptr.h"
 #include "repair/rt.h"
+#include "repair/quotacheck.h"
 
 static xfs_ino_t               orphanage_ino;
 
@@ -3189,7 +3190,7 @@ mark_standalone_inodes(xfs_mount_t *mp)
                mark_inode(mp, mp->m_sb.sb_rsumino);
        }
 
-       if (!fs_quotas)
+       if (!fs_quotas || xfs_has_metadir(mp))
                return;
 
        if (has_quota_inode(XFS_DQTYPE_USER))
@@ -3411,6 +3412,116 @@ _("        - resetting contents of realtime bitmap and summary inodes\n"));
        }
 }
 
+static bool
+ensure_quota_file(
+       struct xfs_inode        *dp,
+       xfs_dqtype_t            type)
+{
+       struct xfs_mount        *mp = dp->i_mount;
+       struct xfs_inode        *ip;
+       const char              *name = libxfs_dqinode_path(type);
+       int                     error;
+
+       if (!has_quota_inode(type))
+               return false;
+
+       if (no_modify) {
+               if (lost_quota_inode(type))
+                       do_warn(_("would reset %s quota inode\n"), name);
+               return false;
+       }
+
+       if (!lost_quota_inode(type)) {
+               /*
+                * The /quotas directory has been discarded, but we should
+                * be able to iget the quota files directly.
+                */
+               error = -libxfs_metafile_iget(mp, get_quota_inode(type),
+                               xfs_dqinode_metafile_type(type), &ip);
+               if (error) {
+                       do_warn(
+_("Could not open %s quota inode, error %d\n"),
+                                       name, error);
+                       lose_quota_inode(type);
+               }
+       }
+
+       if (lost_quota_inode(type)) {
+               /*
+                * The inode was bad or missing, state that we'll make a new
+                * one even though we always create a new one.
+                */
+               do_warn(_("resetting %s quota inode\n"), name);
+               error =  -libxfs_dqinode_metadir_create(dp, type, &ip);
+               if (error) {
+                       do_warn(
+_("Couldn't create %s quota inode, error %d\n"),
+                                       name, error);
+                       goto bad;
+               }
+       } else {
+               struct xfs_trans        *tp;
+
+               /* Erase parent pointers before we create the new link */
+               try_erase_parent_ptrs(ip);
+
+               error = -libxfs_dqinode_metadir_link(dp, type, ip);
+               if (error) {
+                       do_warn(
+_("Couldn't link %s quota inode, error %d\n"),
+                                       name, error);
+                       goto bad;
+               }
+
+               /*
+                * Reset the link count to 1 because quota files are never
+                * hardlinked, but the link above probably bumped it.
+                */
+               error = -libxfs_trans_alloc_inode(ip, &M_RES(mp)->tr_ichange,
+                               0, 0, false, &tp);
+               if (!error) {
+                       set_nlink(VFS_I(ip), 1);
+                       libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+                       error = -libxfs_trans_commit(tp);
+               }
+               if (error)
+                       do_error(
+_("Couldn't reset link count on %s quota inode, error %d\n"),
+                                       name, error);
+       }
+
+       /* Mark the inode in use. */
+       mark_ino_inuse(mp, ip->i_ino, S_IFREG, dp->i_ino);
+       mark_ino_metadata(mp, ip->i_ino);
+       libxfs_irele(ip);
+       return true;
+bad:
+       /* Zeroes qflags */
+       quotacheck_skip();
+       return false;
+}
+
+static void
+reset_quota_metadir_inodes(
+       struct xfs_mount        *mp)
+{
+       struct xfs_inode        *dp = NULL;
+       int                     error;
+
+       error = -libxfs_dqinode_mkdir_parent(mp, &dp);
+       if (error)
+               do_error(_("failed to create quota metadir (%d)\n"),
+                               error);
+
+       mark_ino_inuse(mp, dp->i_ino, S_IFDIR, mp->m_metadirip->i_ino);
+       mark_ino_metadata(mp, dp->i_ino);
+
+       ensure_quota_file(dp, XFS_DQTYPE_USER);
+       ensure_quota_file(dp, XFS_DQTYPE_GROUP);
+       ensure_quota_file(dp, XFS_DQTYPE_PROJ);
+       libxfs_irele(dp);
+}
+
 void
 phase6(xfs_mount_t *mp)
 {
@@ -3464,6 +3575,9 @@ phase6(xfs_mount_t *mp)
        else
                reset_rt_sb_inodes(mp);
 
+       if (xfs_has_metadir(mp) && xfs_has_quota(mp) && !no_modify)
+               reset_quota_metadir_inodes(mp);
+
        mark_standalone_inodes(mp);
 
        do_log(_("        - traversing filesystem ...\n"));
index c4baf70e41d6b1ef3a9fce3c26253c32faf65ba1..8c7339b267d8e602a9b9257f5fa5c50cff9bc22f 100644 (file)
@@ -645,3 +645,74 @@ update_sb_quotinos(
        if (dirty)
                libxfs_sb_to_disk(sbp->b_addr, &mp->m_sb);
 }
+
+static inline int
+mark_quota_inode(
+       struct xfs_trans        *tp,
+       struct xfs_inode        *dp,
+       xfs_dqtype_t            type)
+{
+       struct xfs_inode        *ip;
+       int                     error;
+
+       error = -libxfs_dqinode_load(tp, dp, type, &ip);
+       if (error == ENOENT)
+               return 0;
+       if (error)
+               goto out_corrupt;
+
+       set_quota_inode(type, ip->i_ino);
+       libxfs_irele(ip);
+       return 0;
+
+out_corrupt:
+       lose_quota_inode(type);
+       return error;
+}
+
+/* Mark the reachable quota metadata inodes prior to the inode scan. */
+void
+discover_quota_inodes(
+       struct xfs_mount        *mp)
+{
+       struct xfs_trans        *tp;
+       struct xfs_inode        *dp = NULL;
+       int                     error, err2;
+
+       error = -libxfs_trans_alloc_empty(mp, &tp);
+       if (error)
+               goto out;
+
+       error = -libxfs_dqinode_load_parent(tp, &dp);
+       if (error)
+               goto out_cancel;
+
+       error = mark_quota_inode(tp, dp, XFS_DQTYPE_USER);
+       err2 = mark_quota_inode(tp, dp, XFS_DQTYPE_GROUP);
+       if (err2 && !error)
+               error = err2;
+       error = mark_quota_inode(tp, dp, XFS_DQTYPE_PROJ);
+       if (err2 && !error)
+               error = err2;
+
+       libxfs_irele(dp);
+out_cancel:
+       libxfs_trans_cancel(tp);
+out:
+       if (error) {
+               switch (error) {
+               case EFSCORRUPTED:
+                       do_warn(
+ _("corruption in metadata directory tree while discovering quota inodes\n"));
+                       break;
+               case ENOENT:
+                       /* Do nothing, we'll just clear qflags later. */
+                       break;
+               default:
+                       do_warn(
+ _("couldn't discover quota inodes, err %d\n"),
+                                               error);
+                       break;
+               }
+       }
+}
index 36f9f5a12f7f3e8de18aa2e99366f369c6901f23..24c9ffa418a3bf01458e4fd8892ab6c337e944b7 100644 (file)
@@ -14,5 +14,6 @@ int quotacheck_setup(struct xfs_mount *mp);
 void quotacheck_teardown(void);
 
 void update_sb_quotinos(struct xfs_mount *mp, struct xfs_buf *sbp);
+void discover_quota_inodes(struct xfs_mount *mp);
 
 #endif /* __XFS_REPAIR_QUOTACHECK_H__ */
index 363f8260bd575a53ba5c87bb2b94021b95b7f85d..9509f04685c870d0ee3662c8a2fe217f9fe6dfe8 100644 (file)
@@ -1487,7 +1487,8 @@ _("Warning:  project quota information would be cleared.\n"
        if (!sbp)
                do_error(_("couldn't get superblock\n"));
 
-       update_sb_quotinos(mp, sbp);
+       if (!xfs_has_metadir(mp))
+               update_sb_quotinos(mp, sbp);
 
        if ((mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD) != quotacheck_results()) {
                do_warn(_("Note - quota info will be regenerated on next "