xfs: iget for metadata inodes

Create a xfs_trans_metafile_iget function for metadata inodes to ensure
that when we try to iget a metadata file, the inode is allocated and its
file mode matches the metadata file type the caller expects.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
Darrick J. Wong 2024-11-03 20:18:50 -08:00
parent 4f3d4dd1b0
commit dcf6069143
5 changed files with 125 additions and 18 deletions

View File

@ -0,0 +1,16 @@
/* 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_trans_metafile_iget(struct xfs_trans *tp, xfs_ino_t ino,
enum xfs_metafile_type metafile_type, struct xfs_inode **ipp);
int xfs_metafile_iget(struct xfs_mount *mp, xfs_ino_t ino,
enum xfs_metafile_type metafile_type, struct xfs_inode **ipp);
#endif /* __XFS_METAFILE_H__ */

View 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>
@ -828,6 +831,68 @@ out_error_or_again:
return error;
}
/*
* Get a metadata inode.
*
* The metafile type must match the file mode exactly.
*/
int
xfs_trans_metafile_iget(
struct xfs_trans *tp,
xfs_ino_t ino,
enum xfs_metafile_type metafile_type,
struct xfs_inode **ipp)
{
struct xfs_mount *mp = tp->t_mountp;
struct xfs_inode *ip;
umode_t mode;
int error;
error = xfs_iget(mp, tp, ino, 0, 0, &ip);
if (error == -EFSCORRUPTED)
goto whine;
if (error)
return error;
if (VFS_I(ip)->i_nlink == 0)
goto bad_rele;
if (metafile_type == XFS_METAFILE_DIR)
mode = S_IFDIR;
else
mode = S_IFREG;
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 a metadata file if the caller doesn't already have a transaction. */
int
xfs_metafile_iget(
struct xfs_mount *mp,
xfs_ino_t ino,
enum xfs_metafile_type metafile_type,
struct xfs_inode **ipp)
{
struct xfs_trans *tp;
int error;
error = xfs_trans_alloc_empty(mp, &tp);
if (error)
return error;
error = xfs_trans_metafile_iget(tp, ino, metafile_type, ipp);
xfs_trans_cancel(tp);
return error;
}
/*
* Grab the inode for reclaim exclusively.
*

View 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;

View 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
@ -733,6 +735,17 @@ xfs_qm_destroy_quotainfo(
mp->m_quotainfo = NULL;
}
static inline enum xfs_metafile_type
xfs_qm_metafile_type(
unsigned int flags)
{
if (flags & XFS_QMOPT_UQUOTA)
return XFS_METAFILE_USRQUOTA;
else if (flags & XFS_QMOPT_GQUOTA)
return XFS_METAFILE_GRPQUOTA;
return XFS_METAFILE_PRJQUOTA;
}
/*
* Create an inode and return with a reference already taken, but unlocked
* This is how we create quota inodes
@ -744,6 +757,7 @@ xfs_qm_qino_alloc(
unsigned int flags)
{
struct xfs_trans *tp;
enum xfs_metafile_type metafile_type = xfs_qm_metafile_type(flags);
int error;
bool need_alloc = true;
@ -777,9 +791,10 @@ xfs_qm_qino_alloc(
}
}
if (ino != NULLFSINO) {
error = xfs_iget(mp, NULL, ino, 0, 0, ipp);
error = xfs_metafile_iget(mp, ino, metafile_type, ipp);
if (error)
return error;
mp->m_sb.sb_gquotino = NULLFSINO;
mp->m_sb.sb_pquotino = NULLFSINO;
need_alloc = false;
@ -1553,16 +1568,20 @@ xfs_qm_qino_load(
struct xfs_inode **ipp)
{
xfs_ino_t ino = NULLFSINO;
enum xfs_metafile_type metafile_type = XFS_METAFILE_UNKNOWN;
switch (type) {
case XFS_DQTYPE_USER:
ino = mp->m_sb.sb_uquotino;
metafile_type = XFS_METAFILE_USRQUOTA;
break;
case XFS_DQTYPE_GROUP:
ino = mp->m_sb.sb_gquotino;
metafile_type = XFS_METAFILE_GRPQUOTA;
break;
case XFS_DQTYPE_PROJ:
ino = mp->m_sb.sb_pquotino;
metafile_type = XFS_METAFILE_PRJQUOTA;
break;
default:
ASSERT(0);
@ -1572,7 +1591,7 @@ xfs_qm_qino_load(
if (ino == NULLFSINO)
return -ENOENT;
return xfs_iget(mp, NULL, ino, 0, 0, ipp);
return xfs_metafile_iget(mp, ino, metafile_type, ipp);
}
/*

View 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
@ -1101,16 +1103,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);
@ -1125,7 +1123,6 @@ xfs_rtmount_iread_extents(
out_unlock:
xfs_iunlock(ip, XFS_ILOCK_EXCL | lock_class);
xfs_trans_cancel(tp);
return error;
}
@ -1133,45 +1130,54 @@ 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_trans_metafile_iget(tp, mp->m_sb.sb_rbmino,
XFS_METAFILE_RTBITMAP, &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_trans_metafile_iget(tp, mp->m_sb.sb_rsumino,
XFS_METAFILE_RTSUMMARY, &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;
error = xfs_alloc_rsum_cache(mp, sbp->sb_rbmblocks);
if (error)
goto out_rele_summary;
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;
}