xfs: refactor xlog_recover_process_iunlinks()
For upcoming changes to the way inode unlinked list processing is done, the structure of recovery needs to change slightly. We also really need to untangle the messy error handling in list recovery so that actions like emptying the bucket on inode lookup failure are associated with the bucket list walk failing, not failing to look up the inode. Refactor the recovery code now to keep the re-organisation seperate to the algorithm changes. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Darrick J. Wong <djwong@kernel.org>
This commit is contained in:
committed by
Dave Chinner
parent
4fcc94d653
commit
04755d2e58
@@ -2667,41 +2667,35 @@ out_error:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC xfs_agino_t
|
static int
|
||||||
xlog_recover_process_one_iunlink(
|
xlog_recover_iunlink_bucket(
|
||||||
struct xfs_perag *pag,
|
struct xfs_perag *pag,
|
||||||
xfs_agino_t agino,
|
struct xfs_agi *agi,
|
||||||
int bucket)
|
int bucket)
|
||||||
{
|
{
|
||||||
|
struct xfs_mount *mp = pag->pag_mount;
|
||||||
struct xfs_inode *ip;
|
struct xfs_inode *ip;
|
||||||
xfs_ino_t ino;
|
xfs_agino_t agino;
|
||||||
|
|
||||||
|
agino = be32_to_cpu(agi->agi_unlinked[bucket]);
|
||||||
|
while (agino != NULLAGINO) {
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
ino = XFS_AGINO_TO_INO(pag->pag_mount, pag->pag_agno, agino);
|
error = xfs_iget(mp, NULL,
|
||||||
error = xfs_iget(pag->pag_mount, NULL, ino, 0, 0, &ip);
|
XFS_AGINO_TO_INO(mp, pag->pag_agno, agino),
|
||||||
|
0, 0, &ip);
|
||||||
if (error)
|
if (error)
|
||||||
goto fail;
|
return error;;
|
||||||
|
|
||||||
xfs_iflags_clear(ip, XFS_IRECOVERY);
|
|
||||||
ASSERT(VFS_I(ip)->i_nlink == 0);
|
ASSERT(VFS_I(ip)->i_nlink == 0);
|
||||||
ASSERT(VFS_I(ip)->i_mode != 0);
|
ASSERT(VFS_I(ip)->i_mode != 0);
|
||||||
|
xfs_iflags_clear(ip, XFS_IRECOVERY);
|
||||||
agino = ip->i_next_unlinked;
|
agino = ip->i_next_unlinked;
|
||||||
xfs_irele(ip);
|
|
||||||
return agino;
|
|
||||||
|
|
||||||
fail:
|
xfs_irele(ip);
|
||||||
/*
|
cond_resched();
|
||||||
* We can't read in the inode this bucket points to, or this inode
|
}
|
||||||
* is messed up. Just ditch this bucket of inodes. We will lose
|
return 0;
|
||||||
* some inodes and space, but at least we won't hang.
|
|
||||||
*
|
|
||||||
* Call xlog_recover_clear_agi_bucket() to perform a transaction to
|
|
||||||
* clear the inode pointer in the bucket.
|
|
||||||
*/
|
|
||||||
xfs_inodegc_flush(pag->pag_mount);
|
|
||||||
xlog_recover_clear_agi_bucket(pag, bucket);
|
|
||||||
return NULLAGINO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2727,59 +2721,70 @@ xlog_recover_process_one_iunlink(
|
|||||||
* scheduled on this CPU to ensure other scheduled work can run without undue
|
* scheduled on this CPU to ensure other scheduled work can run without undue
|
||||||
* latency.
|
* latency.
|
||||||
*/
|
*/
|
||||||
STATIC void
|
static void
|
||||||
xlog_recover_process_iunlinks(
|
xlog_recover_iunlink_ag(
|
||||||
struct xlog *log)
|
struct xfs_perag *pag)
|
||||||
{
|
{
|
||||||
struct xfs_mount *mp = log->l_mp;
|
|
||||||
struct xfs_perag *pag;
|
|
||||||
xfs_agnumber_t agno;
|
|
||||||
struct xfs_agi *agi;
|
struct xfs_agi *agi;
|
||||||
struct xfs_buf *agibp;
|
struct xfs_buf *agibp;
|
||||||
xfs_agino_t agino;
|
|
||||||
int bucket;
|
int bucket;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
for_each_perag(mp, agno, pag) {
|
|
||||||
error = xfs_read_agi(pag, NULL, &agibp);
|
error = xfs_read_agi(pag, NULL, &agibp);
|
||||||
if (error) {
|
if (error) {
|
||||||
/*
|
/*
|
||||||
* AGI is b0rked. Don't process it.
|
* AGI is b0rked. Don't process it.
|
||||||
*
|
*
|
||||||
* We should probably mark the filesystem as corrupt
|
* We should probably mark the filesystem as corrupt after we've
|
||||||
* after we've recovered all the ag's we can....
|
* recovered all the ag's we can....
|
||||||
*/
|
*/
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unlock the buffer so that it can be acquired in the normal
|
* Unlock the buffer so that it can be acquired in the normal course of
|
||||||
* course of the transaction to truncate and free each inode.
|
* the transaction to truncate and free each inode. Because we are not
|
||||||
* Because we are not racing with anyone else here for the AGI
|
* racing with anyone else here for the AGI buffer, we don't even need
|
||||||
* buffer, we don't even need to hold it locked to read the
|
* to hold it locked to read the initial unlinked bucket entries out of
|
||||||
* initial unlinked bucket entries out of the buffer. We keep
|
* the buffer. We keep buffer reference though, so that it stays pinned
|
||||||
* buffer reference though, so that it stays pinned in memory
|
* in memory while we need the buffer.
|
||||||
* while we need the buffer.
|
|
||||||
*/
|
*/
|
||||||
agi = agibp->b_addr;
|
agi = agibp->b_addr;
|
||||||
xfs_buf_unlock(agibp);
|
xfs_buf_unlock(agibp);
|
||||||
|
|
||||||
for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) {
|
for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) {
|
||||||
agino = be32_to_cpu(agi->agi_unlinked[bucket]);
|
error = xlog_recover_iunlink_bucket(pag, agi, bucket);
|
||||||
while (agino != NULLAGINO) {
|
if (error) {
|
||||||
agino = xlog_recover_process_one_iunlink(pag,
|
/*
|
||||||
agino, bucket);
|
* Bucket is unrecoverable, so only a repair scan can
|
||||||
cond_resched();
|
* free the remaining unlinked inodes. Just empty the
|
||||||
|
* bucket and remaining inodes on it unreferenced and
|
||||||
|
* unfreeable.
|
||||||
|
*/
|
||||||
|
xfs_inodegc_flush(pag->pag_mount);
|
||||||
|
xlog_recover_clear_agi_bucket(pag, bucket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xfs_buf_rele(agibp);
|
xfs_buf_rele(agibp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
xlog_recover_process_iunlinks(
|
||||||
|
struct xlog *log)
|
||||||
|
{
|
||||||
|
struct xfs_perag *pag;
|
||||||
|
xfs_agnumber_t agno;
|
||||||
|
|
||||||
|
for_each_perag(log->l_mp, agno, pag)
|
||||||
|
xlog_recover_iunlink_ag(pag);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flush the pending unlinked inodes to ensure that the inactivations
|
* Flush the pending unlinked inodes to ensure that the inactivations
|
||||||
* are fully completed on disk and the incore inodes can be reclaimed
|
* are fully completed on disk and the incore inodes can be reclaimed
|
||||||
* before we signal that recovery is complete.
|
* before we signal that recovery is complete.
|
||||||
*/
|
*/
|
||||||
xfs_inodegc_flush(mp);
|
xfs_inodegc_flush(log->l_mp);
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC void
|
STATIC void
|
||||||
|
Reference in New Issue
Block a user