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

xfs: make inode unlinked bucket recovery work with quotacheck



Teach quotacheck to reload the unlinked inode lists when walking the
inode table.  This requires extra state handling, since it's possible
that a reloaded inode will get inactivated before quotacheck tries to
scan it; in this case, we need to ensure that the reloaded inode does
not have dquots attached when it is freed.

Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
parent 83771c50
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -333,7 +333,6 @@ xfs_attr_inactive(
	int			error = 0;

	mp = dp->i_mount;
	ASSERT(! XFS_NOT_DQATTACHED(mp, dp));

	xfs_ilock(dp, lock_mode);
	if (!xfs_inode_has_attr_fork(dp))
+9 −3
Original line number Diff line number Diff line
@@ -1742,9 +1742,13 @@ xfs_inactive(
	     ip->i_df.if_nextents > 0 || ip->i_delayed_blks > 0))
		truncate = 1;

	if (xfs_iflags_test(ip, XFS_IQUOTAUNCHECKED)) {
		xfs_qm_dqdetach(ip);
	} else {
		error = xfs_qm_dqattach(ip);
		if (error)
			goto out;
	}

	if (S_ISLNK(VFS_I(ip)->i_mode))
		error = xfs_inactive_symlink(ip);
@@ -1962,6 +1966,8 @@ xfs_iunlink_reload_next(
	trace_xfs_iunlink_reload_next(next_ip);
rele:
	ASSERT(!(VFS_I(next_ip)->i_state & I_DONTCACHE));
	if (xfs_is_quotacheck_running(mp) && next_ip)
		xfs_iflags_set(next_ip, XFS_IQUOTAUNCHECKED);
	xfs_irele(next_ip);
	return error;
}
+4 −1
Original line number Diff line number Diff line
@@ -344,6 +344,9 @@ static inline bool xfs_inode_has_large_extent_counts(struct xfs_inode *ip)
 */
#define XFS_INACTIVATING	(1 << 13)

/* Quotacheck is running but inode has not been added to quota counts. */
#define XFS_IQUOTAUNCHECKED	(1 << 14)

/* All inode state flags related to inode reclaim. */
#define XFS_ALL_IRECLAIM_FLAGS	(XFS_IRECLAIMABLE | \
				 XFS_IRECLAIM | \
@@ -358,7 +361,7 @@ static inline bool xfs_inode_has_large_extent_counts(struct xfs_inode *ip)
#define XFS_IRECLAIM_RESET_FLAGS	\
	(XFS_IRECLAIMABLE | XFS_IRECLAIM | \
	 XFS_IDIRTY_RELEASE | XFS_ITRUNCATED | XFS_NEED_INACTIVE | \
	 XFS_INACTIVATING)
	 XFS_INACTIVATING | XFS_IQUOTAUNCHECKED)

/*
 * Flags for inode locking.
+9 −1
Original line number Diff line number Diff line
@@ -405,6 +405,8 @@ __XFS_HAS_FEAT(nouuid, NOUUID)
#define XFS_OPSTATE_WARNED_SHRINK	8
/* Kernel has logged a warning about logged xattr updates being used. */
#define XFS_OPSTATE_WARNED_LARP		9
/* Mount time quotacheck is running */
#define XFS_OPSTATE_QUOTACHECK_RUNNING	10

#define __XFS_IS_OPSTATE(name, NAME) \
static inline bool xfs_is_ ## name (struct xfs_mount *mp) \
@@ -427,6 +429,11 @@ __XFS_IS_OPSTATE(inode32, INODE32)
__XFS_IS_OPSTATE(readonly, READONLY)
__XFS_IS_OPSTATE(inodegc_enabled, INODEGC_ENABLED)
__XFS_IS_OPSTATE(blockgc_enabled, BLOCKGC_ENABLED)
#ifdef CONFIG_XFS_QUOTA
__XFS_IS_OPSTATE(quotacheck_running, QUOTACHECK_RUNNING)
#else
# define xfs_is_quotacheck_running(mp)	(false)
#endif

static inline bool
xfs_should_warn(struct xfs_mount *mp, long nr)
@@ -444,7 +451,8 @@ xfs_should_warn(struct xfs_mount *mp, long nr)
	{ (1UL << XFS_OPSTATE_BLOCKGC_ENABLED),		"blockgc" }, \
	{ (1UL << XFS_OPSTATE_WARNED_SCRUB),		"wscrub" }, \
	{ (1UL << XFS_OPSTATE_WARNED_SHRINK),		"wshrink" }, \
	{ (1UL << XFS_OPSTATE_WARNED_LARP),		"wlarp" }
	{ (1UL << XFS_OPSTATE_WARNED_LARP),		"wlarp" }, \
	{ (1UL << XFS_OPSTATE_QUOTACHECK_RUNNING),	"quotacheck" }

/*
 * Max and min values for mount-option defined I/O
+7 −0
Original line number Diff line number Diff line
@@ -1160,6 +1160,10 @@ xfs_qm_dqusage_adjust(
	if (error)
		return error;

	error = xfs_inode_reload_unlinked(ip);
	if (error)
		goto error0;

	ASSERT(ip->i_delayed_blks == 0);

	if (XFS_IS_REALTIME_INODE(ip)) {
@@ -1173,6 +1177,7 @@ xfs_qm_dqusage_adjust(
	}

	nblks = (xfs_qcnt_t)ip->i_nblocks - rtblks;
	xfs_iflags_clear(ip, XFS_IQUOTAUNCHECKED);

	/*
	 * Add the (disk blocks and inode) resources occupied by this
@@ -1319,8 +1324,10 @@ xfs_qm_quotacheck(
		flags |= XFS_PQUOTA_CHKD;
	}

	xfs_set_quotacheck_running(mp);
	error = xfs_iwalk_threaded(mp, 0, 0, xfs_qm_dqusage_adjust, 0, true,
			NULL);
	xfs_clear_quotacheck_running(mp);

	/*
	 * On error, the inode walk may have partially populated the dquot