Commit 10c0b6ba authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'xfs-6.6-fixes-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull xfs fix from Chandan Babu:

 - fix for commit 68b957f6 ("xfs: load uncached unlinked inodes into
   memory on demand") which address review comments provided by Dave
   Chinner

* tag 'xfs-6.6-fixes-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  xfs: fix reloading entire unlinked bucket lists
parents 95289e49 59c71548
...@@ -146,10 +146,18 @@ xfs_nfs_get_inode( ...@@ -146,10 +146,18 @@ xfs_nfs_get_inode(
return ERR_PTR(error); return ERR_PTR(error);
} }
error = xfs_inode_reload_unlinked(ip); /*
if (error) { * Reload the incore unlinked list to avoid failure in inodegc.
xfs_irele(ip); * Use an unlocked check here because unrecovered unlinked inodes
return ERR_PTR(error); * should be somewhat rare.
*/
if (xfs_inode_unlinked_incomplete(ip)) {
error = xfs_inode_reload_unlinked(ip);
if (error) {
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
xfs_irele(ip);
return ERR_PTR(error);
}
} }
if (VFS_I(ip)->i_generation != generation) { if (VFS_I(ip)->i_generation != generation) {
......
...@@ -1743,6 +1743,14 @@ xfs_inactive( ...@@ -1743,6 +1743,14 @@ xfs_inactive(
truncate = 1; truncate = 1;
if (xfs_iflags_test(ip, XFS_IQUOTAUNCHECKED)) { if (xfs_iflags_test(ip, XFS_IQUOTAUNCHECKED)) {
/*
* If this inode is being inactivated during a quotacheck and
* has not yet been scanned by quotacheck, we /must/ remove
* the dquots from the inode before inactivation changes the
* block and inode counts. Most probably this is a result of
* reloading the incore iunlinked list to purge unrecovered
* unlinked inodes.
*/
xfs_qm_dqdetach(ip); xfs_qm_dqdetach(ip);
} else { } else {
error = xfs_qm_dqattach(ip); error = xfs_qm_dqattach(ip);
...@@ -3641,6 +3649,16 @@ xfs_inode_reload_unlinked_bucket( ...@@ -3641,6 +3649,16 @@ xfs_inode_reload_unlinked_bucket(
if (error) if (error)
return error; return error;
/*
* We've taken ILOCK_SHARED and the AGI buffer lock to stabilize the
* incore unlinked list pointers for this inode. Check once more to
* see if we raced with anyone else to reload the unlinked list.
*/
if (!xfs_inode_unlinked_incomplete(ip)) {
foundit = true;
goto out_agibp;
}
bucket = agino % XFS_AGI_UNLINKED_BUCKETS; bucket = agino % XFS_AGI_UNLINKED_BUCKETS;
agi = agibp->b_addr; agi = agibp->b_addr;
...@@ -3655,25 +3673,27 @@ xfs_inode_reload_unlinked_bucket( ...@@ -3655,25 +3673,27 @@ xfs_inode_reload_unlinked_bucket(
while (next_agino != NULLAGINO) { while (next_agino != NULLAGINO) {
struct xfs_inode *next_ip = NULL; struct xfs_inode *next_ip = NULL;
/* Found this caller's inode, set its backlink. */
if (next_agino == agino) { if (next_agino == agino) {
/* Found this inode, set its backlink. */
next_ip = ip; next_ip = ip;
next_ip->i_prev_unlinked = prev_agino; next_ip->i_prev_unlinked = prev_agino;
foundit = true; foundit = true;
goto next_inode;
} }
if (!next_ip) {
/* Inode already in memory. */
next_ip = xfs_iunlink_lookup(pag, next_agino);
}
if (!next_ip) {
/* Inode not in memory, reload. */
error = xfs_iunlink_reload_next(tp, agibp, prev_agino,
next_agino);
if (error)
break;
next_ip = xfs_iunlink_lookup(pag, next_agino); /* Try in-memory lookup first. */
} next_ip = xfs_iunlink_lookup(pag, next_agino);
if (next_ip)
goto next_inode;
/* Inode not in memory, try reloading it. */
error = xfs_iunlink_reload_next(tp, agibp, prev_agino,
next_agino);
if (error)
break;
/* Grab the reloaded inode. */
next_ip = xfs_iunlink_lookup(pag, next_agino);
if (!next_ip) { if (!next_ip) {
/* No incore inode at all? We reloaded it... */ /* No incore inode at all? We reloaded it... */
ASSERT(next_ip != NULL); ASSERT(next_ip != NULL);
...@@ -3681,10 +3701,12 @@ xfs_inode_reload_unlinked_bucket( ...@@ -3681,10 +3701,12 @@ xfs_inode_reload_unlinked_bucket(
break; break;
} }
next_inode:
prev_agino = next_agino; prev_agino = next_agino;
next_agino = next_ip->i_next_unlinked; next_agino = next_ip->i_next_unlinked;
} }
out_agibp:
xfs_trans_brelse(tp, agibp); xfs_trans_brelse(tp, agibp);
/* Should have found this inode somewhere in the iunlinked bucket. */ /* Should have found this inode somewhere in the iunlinked bucket. */
if (!error && !foundit) if (!error && !foundit)
......
...@@ -80,10 +80,12 @@ xfs_bulkstat_one_int( ...@@ -80,10 +80,12 @@ xfs_bulkstat_one_int(
if (error) if (error)
goto out; goto out;
/* Reload the incore unlinked list to avoid failure in inodegc. */
if (xfs_inode_unlinked_incomplete(ip)) { if (xfs_inode_unlinked_incomplete(ip)) {
error = xfs_inode_reload_unlinked_bucket(tp, ip); error = xfs_inode_reload_unlinked_bucket(tp, ip);
if (error) { if (error) {
xfs_iunlock(ip, XFS_ILOCK_SHARED); xfs_iunlock(ip, XFS_ILOCK_SHARED);
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
xfs_irele(ip); xfs_irele(ip);
return error; return error;
} }
......
...@@ -1160,9 +1160,18 @@ xfs_qm_dqusage_adjust( ...@@ -1160,9 +1160,18 @@ xfs_qm_dqusage_adjust(
if (error) if (error)
return error; return error;
error = xfs_inode_reload_unlinked(ip); /*
if (error) * Reload the incore unlinked list to avoid failure in inodegc.
goto error0; * Use an unlocked check here because unrecovered unlinked inodes
* should be somewhat rare.
*/
if (xfs_inode_unlinked_incomplete(ip)) {
error = xfs_inode_reload_unlinked(ip);
if (error) {
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
goto error0;
}
}
ASSERT(ip->i_delayed_blks == 0); ASSERT(ip->i_delayed_blks == 0);
......
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