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

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
...@@ -333,7 +333,6 @@ xfs_attr_inactive( ...@@ -333,7 +333,6 @@ xfs_attr_inactive(
int error = 0; int error = 0;
mp = dp->i_mount; mp = dp->i_mount;
ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
xfs_ilock(dp, lock_mode); xfs_ilock(dp, lock_mode);
if (!xfs_inode_has_attr_fork(dp)) if (!xfs_inode_has_attr_fork(dp))
......
...@@ -1742,9 +1742,13 @@ xfs_inactive( ...@@ -1742,9 +1742,13 @@ xfs_inactive(
ip->i_df.if_nextents > 0 || ip->i_delayed_blks > 0)) ip->i_df.if_nextents > 0 || ip->i_delayed_blks > 0))
truncate = 1; truncate = 1;
if (xfs_iflags_test(ip, XFS_IQUOTAUNCHECKED)) {
xfs_qm_dqdetach(ip);
} else {
error = xfs_qm_dqattach(ip); error = xfs_qm_dqattach(ip);
if (error) if (error)
goto out; goto out;
}
if (S_ISLNK(VFS_I(ip)->i_mode)) if (S_ISLNK(VFS_I(ip)->i_mode))
error = xfs_inactive_symlink(ip); error = xfs_inactive_symlink(ip);
...@@ -1962,6 +1966,8 @@ xfs_iunlink_reload_next( ...@@ -1962,6 +1966,8 @@ xfs_iunlink_reload_next(
trace_xfs_iunlink_reload_next(next_ip); trace_xfs_iunlink_reload_next(next_ip);
rele: rele:
ASSERT(!(VFS_I(next_ip)->i_state & I_DONTCACHE)); 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); xfs_irele(next_ip);
return error; return error;
} }
......
...@@ -344,6 +344,9 @@ static inline bool xfs_inode_has_large_extent_counts(struct xfs_inode *ip) ...@@ -344,6 +344,9 @@ static inline bool xfs_inode_has_large_extent_counts(struct xfs_inode *ip)
*/ */
#define XFS_INACTIVATING (1 << 13) #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. */ /* All inode state flags related to inode reclaim. */
#define XFS_ALL_IRECLAIM_FLAGS (XFS_IRECLAIMABLE | \ #define XFS_ALL_IRECLAIM_FLAGS (XFS_IRECLAIMABLE | \
XFS_IRECLAIM | \ XFS_IRECLAIM | \
...@@ -358,7 +361,7 @@ static inline bool xfs_inode_has_large_extent_counts(struct xfs_inode *ip) ...@@ -358,7 +361,7 @@ static inline bool xfs_inode_has_large_extent_counts(struct xfs_inode *ip)
#define XFS_IRECLAIM_RESET_FLAGS \ #define XFS_IRECLAIM_RESET_FLAGS \
(XFS_IRECLAIMABLE | XFS_IRECLAIM | \ (XFS_IRECLAIMABLE | XFS_IRECLAIM | \
XFS_IDIRTY_RELEASE | XFS_ITRUNCATED | XFS_NEED_INACTIVE | \ XFS_IDIRTY_RELEASE | XFS_ITRUNCATED | XFS_NEED_INACTIVE | \
XFS_INACTIVATING) XFS_INACTIVATING | XFS_IQUOTAUNCHECKED)
/* /*
* Flags for inode locking. * Flags for inode locking.
......
...@@ -405,6 +405,8 @@ __XFS_HAS_FEAT(nouuid, NOUUID) ...@@ -405,6 +405,8 @@ __XFS_HAS_FEAT(nouuid, NOUUID)
#define XFS_OPSTATE_WARNED_SHRINK 8 #define XFS_OPSTATE_WARNED_SHRINK 8
/* Kernel has logged a warning about logged xattr updates being used. */ /* Kernel has logged a warning about logged xattr updates being used. */
#define XFS_OPSTATE_WARNED_LARP 9 #define XFS_OPSTATE_WARNED_LARP 9
/* Mount time quotacheck is running */
#define XFS_OPSTATE_QUOTACHECK_RUNNING 10
#define __XFS_IS_OPSTATE(name, NAME) \ #define __XFS_IS_OPSTATE(name, NAME) \
static inline bool xfs_is_ ## name (struct xfs_mount *mp) \ static inline bool xfs_is_ ## name (struct xfs_mount *mp) \
...@@ -427,6 +429,11 @@ __XFS_IS_OPSTATE(inode32, INODE32) ...@@ -427,6 +429,11 @@ __XFS_IS_OPSTATE(inode32, INODE32)
__XFS_IS_OPSTATE(readonly, READONLY) __XFS_IS_OPSTATE(readonly, READONLY)
__XFS_IS_OPSTATE(inodegc_enabled, INODEGC_ENABLED) __XFS_IS_OPSTATE(inodegc_enabled, INODEGC_ENABLED)
__XFS_IS_OPSTATE(blockgc_enabled, BLOCKGC_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 static inline bool
xfs_should_warn(struct xfs_mount *mp, long nr) xfs_should_warn(struct xfs_mount *mp, long nr)
...@@ -444,7 +451,8 @@ 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_BLOCKGC_ENABLED), "blockgc" }, \
{ (1UL << XFS_OPSTATE_WARNED_SCRUB), "wscrub" }, \ { (1UL << XFS_OPSTATE_WARNED_SCRUB), "wscrub" }, \
{ (1UL << XFS_OPSTATE_WARNED_SHRINK), "wshrink" }, \ { (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 * Max and min values for mount-option defined I/O
......
...@@ -1160,6 +1160,10 @@ xfs_qm_dqusage_adjust( ...@@ -1160,6 +1160,10 @@ xfs_qm_dqusage_adjust(
if (error) if (error)
return error; return error;
error = xfs_inode_reload_unlinked(ip);
if (error)
goto error0;
ASSERT(ip->i_delayed_blks == 0); ASSERT(ip->i_delayed_blks == 0);
if (XFS_IS_REALTIME_INODE(ip)) { if (XFS_IS_REALTIME_INODE(ip)) {
...@@ -1173,6 +1177,7 @@ xfs_qm_dqusage_adjust( ...@@ -1173,6 +1177,7 @@ xfs_qm_dqusage_adjust(
} }
nblks = (xfs_qcnt_t)ip->i_nblocks - rtblks; nblks = (xfs_qcnt_t)ip->i_nblocks - rtblks;
xfs_iflags_clear(ip, XFS_IQUOTAUNCHECKED);
/* /*
* Add the (disk blocks and inode) resources occupied by this * Add the (disk blocks and inode) resources occupied by this
...@@ -1319,8 +1324,10 @@ xfs_qm_quotacheck( ...@@ -1319,8 +1324,10 @@ xfs_qm_quotacheck(
flags |= XFS_PQUOTA_CHKD; flags |= XFS_PQUOTA_CHKD;
} }
xfs_set_quotacheck_running(mp);
error = xfs_iwalk_threaded(mp, 0, 0, xfs_qm_dqusage_adjust, 0, true, error = xfs_iwalk_threaded(mp, 0, 0, xfs_qm_dqusage_adjust, 0, true,
NULL); NULL);
xfs_clear_quotacheck_running(mp);
/* /*
* On error, the inode walk may have partially populated the dquot * On error, the inode walk may have partially populated the dquot
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment