Skip to content

Commit 59c7154

Browse files
author
Chandan Babu R
committed
Merge tag 'fix-fix-iunlink-6.6_2023-09-25' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-6.6-fixesB
xfs: fix reloading the last iunlink item It's not a good idea to be trying to send bug fixes to the mailing list while also trying to take a vacation. Dave sent some review comments about the iunlink reloading patches, I changed them in djwong-dev, and forgot to backport those changes to my -fixes tree. As a result, the patch is missing some important pieces. Perhaps manually copying code diffs between email and two separate git trees is archaic and stupid^W^W^W^Wisn't really a good idea? Signed-off-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Chandan Babu R <chandanbabu@kernel.org> * tag 'fix-fix-iunlink-6.6_2023-09-25' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux: xfs: fix reloading entire unlinked bucket lists
2 parents 6465e26 + 537c013 commit 59c7154

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)