Commit dcf60691 authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

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: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 4f3d4dd1
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
/* 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__ */
+65 −0
Original line number Diff line number Diff line
@@ -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 @@ xfs_iget(
	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.
 *
+1 −0
Original line number Diff line number Diff line
@@ -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;

+21 −2
Original line number Diff line number Diff line
@@ -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);
}

/*
+22 −16
Original line number Diff line number Diff line
@@ -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 @@ xfs_rtmount_iread_extents(
 * 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;
}