--- /dev/null
+/* 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__ */
#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>
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.
*
#include "xfs_parent.h"
#include "xfs_xattr.h"
#include "xfs_inode_util.h"
+#include "xfs_metafile.h"
struct kmem_cache *xfs_inode_cache;
#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
}
}
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;
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;
* 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;
}
return 0;
error_rele:
+ if (tp)
+ xfs_trans_cancel(tp);
if (uip)
xfs_irele(uip);
if (gip)
#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(
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;
#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
*/
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);
out_unlock:
xfs_iunlock(ip, XFS_ILOCK_EXCL | lock_class);
- xfs_trans_cancel(tp);
return error;
}
* 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;
}