mirror of https://github.com/torvalds/linux.git
xfs: check AGI unlinked inode buckets
Look for corruptions in the AGI unlinked bucket chains. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
2651923d8d
commit
10d587ecb7
|
|
@ -15,6 +15,7 @@
|
||||||
#include "xfs_ialloc.h"
|
#include "xfs_ialloc.h"
|
||||||
#include "xfs_rmap.h"
|
#include "xfs_rmap.h"
|
||||||
#include "xfs_ag.h"
|
#include "xfs_ag.h"
|
||||||
|
#include "xfs_inode.h"
|
||||||
#include "scrub/scrub.h"
|
#include "scrub/scrub.h"
|
||||||
#include "scrub/common.h"
|
#include "scrub/common.h"
|
||||||
|
|
||||||
|
|
@ -865,6 +866,43 @@ xchk_agi_xref(
|
||||||
/* scrub teardown will take care of sc->sa for us */
|
/* scrub teardown will take care of sc->sa for us */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check the unlinked buckets for links to bad inodes. We hold the AGI, so
|
||||||
|
* there cannot be any threads updating unlinked list pointers in this AG.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
xchk_iunlink(
|
||||||
|
struct xfs_scrub *sc,
|
||||||
|
struct xfs_agi *agi)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
struct xfs_inode *ip;
|
||||||
|
|
||||||
|
for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) {
|
||||||
|
xfs_agino_t agino = be32_to_cpu(agi->agi_unlinked[i]);
|
||||||
|
|
||||||
|
while (agino != NULLAGINO) {
|
||||||
|
if (agino % XFS_AGI_UNLINKED_BUCKETS != i) {
|
||||||
|
xchk_block_set_corrupt(sc, sc->sa.agi_bp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip = xfs_iunlink_lookup(sc->sa.pag, agino);
|
||||||
|
if (!ip) {
|
||||||
|
xchk_block_set_corrupt(sc, sc->sa.agi_bp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!xfs_inode_on_unlinked_list(ip)) {
|
||||||
|
xchk_block_set_corrupt(sc, sc->sa.agi_bp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
agino = ip->i_next_unlinked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Scrub the AGI. */
|
/* Scrub the AGI. */
|
||||||
int
|
int
|
||||||
xchk_agi(
|
xchk_agi(
|
||||||
|
|
@ -949,6 +987,8 @@ xchk_agi(
|
||||||
if (pag->pagi_freecount != be32_to_cpu(agi->agi_freecount))
|
if (pag->pagi_freecount != be32_to_cpu(agi->agi_freecount))
|
||||||
xchk_block_set_corrupt(sc, sc->sa.agi_bp);
|
xchk_block_set_corrupt(sc, sc->sa.agi_bp);
|
||||||
|
|
||||||
|
xchk_iunlink(sc, agi);
|
||||||
|
|
||||||
xchk_agi_xref(sc);
|
xchk_agi_xref(sc);
|
||||||
out:
|
out:
|
||||||
return error;
|
return error;
|
||||||
|
|
|
||||||
|
|
@ -1985,7 +1985,7 @@ xfs_inactive(
|
||||||
* only unlinked, referenced inodes can be on the unlinked inode list. If we
|
* only unlinked, referenced inodes can be on the unlinked inode list. If we
|
||||||
* don't find the inode in cache, then let the caller handle the situation.
|
* don't find the inode in cache, then let the caller handle the situation.
|
||||||
*/
|
*/
|
||||||
static struct xfs_inode *
|
struct xfs_inode *
|
||||||
xfs_iunlink_lookup(
|
xfs_iunlink_lookup(
|
||||||
struct xfs_perag *pag,
|
struct xfs_perag *pag,
|
||||||
xfs_agino_t agino)
|
xfs_agino_t agino)
|
||||||
|
|
|
||||||
|
|
@ -619,6 +619,7 @@ bool xfs_inode_needs_inactive(struct xfs_inode *ip);
|
||||||
int xfs_iunlink(struct xfs_trans *tp, struct xfs_inode *ip);
|
int xfs_iunlink(struct xfs_trans *tp, struct xfs_inode *ip);
|
||||||
int xfs_iunlink_remove(struct xfs_trans *tp, struct xfs_perag *pag,
|
int xfs_iunlink_remove(struct xfs_trans *tp, struct xfs_perag *pag,
|
||||||
struct xfs_inode *ip);
|
struct xfs_inode *ip);
|
||||||
|
struct xfs_inode *xfs_iunlink_lookup(struct xfs_perag *pag, xfs_agino_t agino);
|
||||||
|
|
||||||
void xfs_end_io(struct work_struct *work);
|
void xfs_end_io(struct work_struct *work);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue