]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: iget for metadata inodes
authorDarrick J. Wong <djwong@kernel.org>
Wed, 29 May 2024 04:10:54 +0000 (21:10 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Thu, 1 Aug 2024 00:10:01 +0000 (17:10 -0700)
Create a xfs_imeta_iget function for metadata inodes to ensure that when
we try to iget a metadata file, the inobt thinks a metadata inode is in
use and that the file type matches what we are expecting.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
fs/xfs/libxfs/xfs_metafile.h [new file with mode: 0644]
fs/xfs/xfs_icache.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_qm.c
fs/xfs/xfs_qm_syscalls.c
fs/xfs/xfs_rtalloc.c

diff --git a/fs/xfs/libxfs/xfs_metafile.h b/fs/xfs/libxfs/xfs_metafile.h
new file mode 100644 (file)
index 0000000..ea0ba76
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2018-2024 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+#ifndef __XFS_METAFILE_H__
+#define __XFS_METAFILE_H__
+
+/* Code specific to kernel/userspace; must be provided externally. */
+
+int xfs_metafile_iget(struct xfs_trans *tp, xfs_ino_t ino, umode_t mode,
+               struct xfs_inode **ipp);
+
+#endif /* __XFS_METAFILE_H__ */
index 42a1d2e8cd56fddbc49b29443b24befc93ffabab..7db98d4167fa38c0595ce1871c561d7fe3dab29f 100644 (file)
@@ -25,6 +25,9 @@
 #include "xfs_ag.h"
 #include "xfs_log_priv.h"
 #include "xfs_health.h"
+#include "xfs_da_format.h"
+#include "xfs_dir2.h"
+#include "xfs_metafile.h"
 
 #include <linux/iversion.h>
 
@@ -808,6 +811,42 @@ out_error_or_again:
        return error;
 }
 
+/*
+ * Get a metadata inode.  The file type part of @mode must match the inode
+ * exactly.  Caller must supply a transaction (even if empty) to avoid
+ * livelocking if the inobt has a cycle.
+ */
+int
+xfs_metafile_iget(
+       struct xfs_trans        *tp,
+       xfs_ino_t               ino,
+       umode_t                 mode,
+       struct xfs_inode        **ipp)
+{
+       struct xfs_mount        *mp = tp->t_mountp;
+       struct xfs_inode        *ip;
+       int                     error;
+
+       error = xfs_iget(mp, tp, ino, XFS_IGET_UNTRUSTED, 0, &ip);
+       if (error == -EFSCORRUPTED)
+               goto whine;
+       if (error)
+               return error;
+
+       if (VFS_I(ip)->i_nlink == 0)
+               goto bad_rele;
+       if (inode_wrong_type(VFS_I(ip), mode))
+               goto bad_rele;
+
+       *ipp = ip;
+       return 0;
+bad_rele:
+       xfs_irele(ip);
+whine:
+       xfs_err(mp, "metadata inode 0x%llx is corrupt", ino);
+       return -EFSCORRUPTED;
+}
+
 /*
  * Grab the inode for reclaim exclusively.
  *
index 9ea7a18f5da1421d7fcfd9a2dea6b0d460adee12..e1c65507479cd238229d4659f21e573b0dd131b6 100644 (file)
@@ -43,6 +43,7 @@
 #include "xfs_parent.h"
 #include "xfs_xattr.h"
 #include "xfs_inode_util.h"
+#include "xfs_metafile.h"
 
 struct kmem_cache *xfs_inode_cache;
 
index 63f6ca2db25151cbdc573488fadbdcb9d336d740..9c232e758af7bfa69335014bf66f945fb4074331 100644 (file)
@@ -27,6 +27,8 @@
 #include "xfs_ialloc.h"
 #include "xfs_log_priv.h"
 #include "xfs_health.h"
+#include "xfs_da_format.h"
+#include "xfs_metafile.h"
 
 /*
  * The global quota manager. There is only one of these for the entire
@@ -777,9 +779,17 @@ xfs_qm_qino_alloc(
                        }
                }
                if (ino != NULLFSINO) {
-                       error = xfs_iget(mp, NULL, ino, 0, 0, ipp);
+                       struct xfs_trans        *tp;
+
+                       error = xfs_trans_alloc_empty(mp, &tp);
+                       if (error)
+                               return error;
+
+                       error = xfs_metafile_iget(tp, ino, S_IFREG, ipp);
+                       xfs_trans_cancel(tp);
                        if (error)
                                return error;
+
                        mp->m_sb.sb_gquotino = NULLFSINO;
                        mp->m_sb.sb_pquotino = NULLFSINO;
                        need_alloc = false;
@@ -1549,6 +1559,7 @@ xfs_qm_init_quotainos(
        struct xfs_inode        *uip = NULL;
        struct xfs_inode        *gip = NULL;
        struct xfs_inode        *pip = NULL;
+       struct xfs_trans        *tp = NULL;
        int                     error;
        uint                    flags = 0;
 
@@ -1558,30 +1569,37 @@ xfs_qm_init_quotainos(
         * Get the uquota and gquota inodes
         */
        if (xfs_has_quota(mp)) {
+               error = xfs_trans_alloc_empty(mp, &tp);
+               if (error)
+                       return error;
+
                if (XFS_IS_UQUOTA_ON(mp) &&
                    mp->m_sb.sb_uquotino != NULLFSINO) {
                        ASSERT(mp->m_sb.sb_uquotino > 0);
-                       error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
-                                            0, 0, &uip);
+                       error = xfs_metafile_iget(tp, mp->m_sb.sb_uquotino,
+                                       S_IFREG, &uip);
                        if (error)
-                               return error;
+                               goto error_rele;
                }
                if (XFS_IS_GQUOTA_ON(mp) &&
                    mp->m_sb.sb_gquotino != NULLFSINO) {
                        ASSERT(mp->m_sb.sb_gquotino > 0);
-                       error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
-                                            0, 0, &gip);
+                       error = xfs_metafile_iget(tp, mp->m_sb.sb_gquotino,
+                                       S_IFREG, &gip);
                        if (error)
                                goto error_rele;
                }
                if (XFS_IS_PQUOTA_ON(mp) &&
                    mp->m_sb.sb_pquotino != NULLFSINO) {
                        ASSERT(mp->m_sb.sb_pquotino > 0);
-                       error = xfs_iget(mp, NULL, mp->m_sb.sb_pquotino,
-                                            0, 0, &pip);
+                       error = xfs_metafile_iget(tp, mp->m_sb.sb_pquotino,
+                                       S_IFREG, &pip);
                        if (error)
                                goto error_rele;
                }
+
+               xfs_trans_cancel(tp);
+               tp = NULL;
        } else {
                flags |= XFS_QMOPT_SBVERSION;
        }
@@ -1622,6 +1640,8 @@ xfs_qm_init_quotainos(
        return 0;
 
 error_rele:
+       if (tp)
+               xfs_trans_cancel(tp);
        if (uip)
                xfs_irele(uip);
        if (gip)
index 392cb39cc10c8395acbef5097b79057930d4dbc7..87253427800b8d81d4f02f9ff7e3afc81426364a 100644 (file)
@@ -18,6 +18,8 @@
 #include "xfs_quota.h"
 #include "xfs_qm.h"
 #include "xfs_icache.h"
+#include "xfs_da_format.h"
+#include "xfs_metafile.h"
 
 int
 xfs_qm_scall_quotaoff(
@@ -62,7 +64,12 @@ xfs_qm_scall_trunc_qfile(
        if (ino == NULLFSINO)
                return 0;
 
-       error = xfs_iget(mp, NULL, ino, 0, 0, &ip);
+       error = xfs_trans_alloc_empty(mp, &tp);
+       if (error)
+               return error;
+
+       error = xfs_metafile_iget(tp, ino, S_IFREG, &ip);
+       xfs_trans_cancel(tp);
        if (error)
                return error;
 
index 0c3e96c621a672d43fb9394d703f7a5dfbb8e0e4..3eb402cce2f58fc4c73c23f3a57c37edfdbbf79a 100644 (file)
@@ -25,6 +25,8 @@
 #include "xfs_quota.h"
 #include "xfs_log_priv.h"
 #include "xfs_health.h"
+#include "xfs_da_format.h"
+#include "xfs_metafile.h"
 
 /*
  * Return whether there are any free extents in the size range given
@@ -1154,16 +1156,12 @@ xfs_rtalloc_reinit_frextents(
  */
 static inline int
 xfs_rtmount_iread_extents(
+       struct xfs_trans        *tp,
        struct xfs_inode        *ip,
        unsigned int            lock_class)
 {
-       struct xfs_trans        *tp;
        int                     error;
 
-       error = xfs_trans_alloc_empty(ip->i_mount, &tp);
-       if (error)
-               return error;
-
        xfs_ilock(ip, XFS_ILOCK_EXCL | lock_class);
 
        error = xfs_iread_extents(tp, ip, XFS_DATA_FORK);
@@ -1178,7 +1176,6 @@ xfs_rtmount_iread_extents(
 
 out_unlock:
        xfs_iunlock(ip, XFS_ILOCK_EXCL | lock_class);
-       xfs_trans_cancel(tp);
        return error;
 }
 
@@ -1186,43 +1183,50 @@ out_unlock:
  * Get the bitmap and summary inodes and the summary cache into the mount
  * structure at mount time.
  */
-int                                    /* error */
+int
 xfs_rtmount_inodes(
-       xfs_mount_t     *mp)            /* file system mount structure */
+       struct xfs_mount        *mp)
 {
-       int             error;          /* error return value */
-       xfs_sb_t        *sbp;
+       struct xfs_trans        *tp;
+       struct xfs_sb           *sbp = &mp->m_sb;
+       int                     error;
 
-       sbp = &mp->m_sb;
-       error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, 0, &mp->m_rbmip);
+       error = xfs_trans_alloc_empty(mp, &tp);
+       if (error)
+               return error;
+
+       error = xfs_metafile_iget(tp, mp->m_sb.sb_rbmino, S_IFREG, &mp->m_rbmip);
        if (xfs_metadata_is_sick(error))
                xfs_rt_mark_sick(mp, XFS_SICK_RT_BITMAP);
        if (error)
-               return error;
+               goto out_trans;
        ASSERT(mp->m_rbmip != NULL);
 
-       error = xfs_rtmount_iread_extents(mp->m_rbmip, XFS_ILOCK_RTBITMAP);
+       error = xfs_rtmount_iread_extents(tp, mp->m_rbmip, XFS_ILOCK_RTBITMAP);
        if (error)
                goto out_rele_bitmap;
 
-       error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, 0, &mp->m_rsumip);
+       error = xfs_metafile_iget(tp, mp->m_sb.sb_rsumino, S_IFREG, &mp->m_rsumip);
        if (xfs_metadata_is_sick(error))
                xfs_rt_mark_sick(mp, XFS_SICK_RT_SUMMARY);
        if (error)
                goto out_rele_bitmap;
        ASSERT(mp->m_rsumip != NULL);
 
-       error = xfs_rtmount_iread_extents(mp->m_rsumip, XFS_ILOCK_RTSUM);
+       error = xfs_rtmount_iread_extents(tp, mp->m_rsumip, XFS_ILOCK_RTSUM);
        if (error)
                goto out_rele_summary;
 
        xfs_alloc_rsum_cache(mp, sbp->sb_rbmblocks);
+       xfs_trans_cancel(tp);
        return 0;
 
 out_rele_summary:
        xfs_irele(mp->m_rsumip);
 out_rele_bitmap:
        xfs_irele(mp->m_rbmip);
+out_trans:
+       xfs_trans_cancel(tp);
        return error;
 }