Skip to content

Commit 537c013

Browse files
author
Darrick J. Wong
committed
xfs: fix reloading entire unlinked bucket lists
During review of the patcheset that provided reloading of the incore iunlink list, Dave made a few suggestions, and I updated the copy in my dev tree. Unfortunately, I then got distracted by ... who even knows what ... and forgot to backport those changes from my dev tree to my release candidate branch. I then sent multiple pull requests with stale patches, and that's what was merged into -rc3. So. This patch re-adds the use of an unlocked iunlink list check to determine if we want to allocate the resources to recreate the incore list. Since lost iunlinked inodes are supposed to be rare, this change helps us avoid paying the transaction and AGF locking costs every time we open any inode. This also re-adds the shutdowns on failure, and re-applies the restructuring of the inner loop in xfs_inode_reload_unlinked_bucket, and re-adds a requested comment about the quotachecking code. Retain the original RVB tag from Dave since there's no code change from the last submission. Fixes: 68b957f ("xfs: load uncached unlinked inodes into memory on demand") Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com>
1 parent 6465e26 commit 537c013

File tree

4 files changed

+61
-20
lines changed

4 files changed

+61
-20
lines changed

fs/xfs/xfs_export.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,18 @@ xfs_nfs_get_inode(
146146
return ERR_PTR(error);
147147
}
148148

149-
error = xfs_inode_reload_unlinked(ip);
150-
if (error) {
151-
xfs_irele(ip);
152-
return ERR_PTR(error);
149+
/*
150+
* Reload the incore unlinked list to avoid failure in inodegc.
151+
* Use an unlocked check here because unrecovered unlinked inodes
152+
* should be somewhat rare.
153+
*/
154+
if (xfs_inode_unlinked_incomplete(ip)) {
155+
error = xfs_inode_reload_unlinked(ip);
156+
if (error) {
157+
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
158+
xfs_irele(ip);
159+
return ERR_PTR(error);
160+
}
153161
}
154162

155163
if (VFS_I(ip)->i_generation != generation) {

fs/xfs/xfs_inode.c

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,6 +1743,14 @@ xfs_inactive(
17431743
truncate = 1;
17441744

17451745
if (xfs_iflags_test(ip, XFS_IQUOTAUNCHECKED)) {
1746+
/*
1747+
* If this inode is being inactivated during a quotacheck and
1748+
* has not yet been scanned by quotacheck, we /must/ remove
1749+
* the dquots from the inode before inactivation changes the
1750+
* block and inode counts. Most probably this is a result of
1751+
* reloading the incore iunlinked list to purge unrecovered
1752+
* unlinked inodes.
1753+
*/
17461754
xfs_qm_dqdetach(ip);
17471755
} else {
17481756
error = xfs_qm_dqattach(ip);
@@ -3641,6 +3649,16 @@ xfs_inode_reload_unlinked_bucket(
36413649
if (error)
36423650
return error;
36433651

3652+
/*
3653+
* We've taken ILOCK_SHARED and the AGI buffer lock to stabilize the
3654+
* incore unlinked list pointers for this inode. Check once more to
3655+
* see if we raced with anyone else to reload the unlinked list.
3656+
*/
3657+
if (!xfs_inode_unlinked_incomplete(ip)) {
3658+
foundit = true;
3659+
goto out_agibp;
3660+
}
3661+
36443662
bucket = agino % XFS_AGI_UNLINKED_BUCKETS;
36453663
agi = agibp->b_addr;
36463664

@@ -3655,36 +3673,40 @@ xfs_inode_reload_unlinked_bucket(
36553673
while (next_agino != NULLAGINO) {
36563674
struct xfs_inode *next_ip = NULL;
36573675

3676+
/* Found this caller's inode, set its backlink. */
36583677
if (next_agino == agino) {
3659-
/* Found this inode, set its backlink. */
36603678
next_ip = ip;
36613679
next_ip->i_prev_unlinked = prev_agino;
36623680
foundit = true;
3681+
goto next_inode;
36633682
}
3664-
if (!next_ip) {
3665-
/* Inode already in memory. */
3666-
next_ip = xfs_iunlink_lookup(pag, next_agino);
3667-
}
3668-
if (!next_ip) {
3669-
/* Inode not in memory, reload. */
3670-
error = xfs_iunlink_reload_next(tp, agibp, prev_agino,
3671-
next_agino);
3672-
if (error)
3673-
break;
36743683

3675-
next_ip = xfs_iunlink_lookup(pag, next_agino);
3676-
}
3684+
/* Try in-memory lookup first. */
3685+
next_ip = xfs_iunlink_lookup(pag, next_agino);
3686+
if (next_ip)
3687+
goto next_inode;
3688+
3689+
/* Inode not in memory, try reloading it. */
3690+
error = xfs_iunlink_reload_next(tp, agibp, prev_agino,
3691+
next_agino);
3692+
if (error)
3693+
break;
3694+
3695+
/* Grab the reloaded inode. */
3696+
next_ip = xfs_iunlink_lookup(pag, next_agino);
36773697
if (!next_ip) {
36783698
/* No incore inode at all? We reloaded it... */
36793699
ASSERT(next_ip != NULL);
36803700
error = -EFSCORRUPTED;
36813701
break;
36823702
}
36833703

3704+
next_inode:
36843705
prev_agino = next_agino;
36853706
next_agino = next_ip->i_next_unlinked;
36863707
}
36873708

3709+
out_agibp:
36883710
xfs_trans_brelse(tp, agibp);
36893711
/* Should have found this inode somewhere in the iunlinked bucket. */
36903712
if (!error && !foundit)

fs/xfs/xfs_itable.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,12 @@ xfs_bulkstat_one_int(
8080
if (error)
8181
goto out;
8282

83+
/* Reload the incore unlinked list to avoid failure in inodegc. */
8384
if (xfs_inode_unlinked_incomplete(ip)) {
8485
error = xfs_inode_reload_unlinked_bucket(tp, ip);
8586
if (error) {
8687
xfs_iunlock(ip, XFS_ILOCK_SHARED);
88+
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
8789
xfs_irele(ip);
8890
return error;
8991
}

fs/xfs/xfs_qm.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,9 +1160,18 @@ xfs_qm_dqusage_adjust(
11601160
if (error)
11611161
return error;
11621162

1163-
error = xfs_inode_reload_unlinked(ip);
1164-
if (error)
1165-
goto error0;
1163+
/*
1164+
* Reload the incore unlinked list to avoid failure in inodegc.
1165+
* Use an unlocked check here because unrecovered unlinked inodes
1166+
* should be somewhat rare.
1167+
*/
1168+
if (xfs_inode_unlinked_incomplete(ip)) {
1169+
error = xfs_inode_reload_unlinked(ip);
1170+
if (error) {
1171+
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
1172+
goto error0;
1173+
}
1174+
}
11661175

11671176
ASSERT(ip->i_delayed_blks == 0);
11681177

0 commit comments

Comments
 (0)