xfs: make xchk_iget safer in the presence of corrupt inode btrees
commit 3f113c2739b1b068854c7ffed635c2bd790d1492 upstream. When scrub is trying to iget an inode, ensure that it won't end up deadlocked on a cycle in the inode btree by using an empty transaction to store all the buffers. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Catherine Hoang <catherine.hoang@oracle.com> Acked-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
3f63080344
commit
fb6e584e74
|
@ -733,6 +733,8 @@ xchk_iget(
|
|||
xfs_ino_t inum,
|
||||
struct xfs_inode **ipp)
|
||||
{
|
||||
ASSERT(sc->tp != NULL);
|
||||
|
||||
return xfs_iget(sc->mp, sc->tp, inum, XFS_IGET_UNTRUSTED, 0, ipp);
|
||||
}
|
||||
|
||||
|
@ -882,8 +884,8 @@ xchk_iget_for_scrubbing(
|
|||
if (!xfs_verify_ino(sc->mp, sc->sm->sm_ino))
|
||||
return -ENOENT;
|
||||
|
||||
/* Try a regular untrusted iget. */
|
||||
error = xchk_iget(sc, sc->sm->sm_ino, &ip);
|
||||
/* Try a safe untrusted iget. */
|
||||
error = xchk_iget_safe(sc, sc->sm->sm_ino, &ip);
|
||||
if (!error)
|
||||
return xchk_install_handle_inode(sc, ip);
|
||||
if (error == -ENOENT)
|
||||
|
|
|
@ -151,12 +151,37 @@ void xchk_iunlock(struct xfs_scrub *sc, unsigned int ilock_flags);
|
|||
|
||||
void xchk_buffer_recheck(struct xfs_scrub *sc, struct xfs_buf *bp);
|
||||
|
||||
/*
|
||||
* Grab the inode at @inum. The caller must have created a scrub transaction
|
||||
* so that we can confirm the inumber by walking the inobt and not deadlock on
|
||||
* a loop in the inobt.
|
||||
*/
|
||||
int xchk_iget(struct xfs_scrub *sc, xfs_ino_t inum, struct xfs_inode **ipp);
|
||||
int xchk_iget_agi(struct xfs_scrub *sc, xfs_ino_t inum,
|
||||
struct xfs_buf **agi_bpp, struct xfs_inode **ipp);
|
||||
void xchk_irele(struct xfs_scrub *sc, struct xfs_inode *ip);
|
||||
int xchk_install_handle_inode(struct xfs_scrub *sc, struct xfs_inode *ip);
|
||||
|
||||
/*
|
||||
* Safe version of (untrusted) xchk_iget that uses an empty transaction to
|
||||
* avoid deadlocking on loops in the inobt. This should only be used in a
|
||||
* scrub or repair setup routine, and only prior to grabbing a transaction.
|
||||
*/
|
||||
static inline int
|
||||
xchk_iget_safe(struct xfs_scrub *sc, xfs_ino_t inum, struct xfs_inode **ipp)
|
||||
{
|
||||
int error;
|
||||
|
||||
ASSERT(sc->tp == NULL);
|
||||
|
||||
error = xchk_trans_alloc(sc, 0);
|
||||
if (error)
|
||||
return error;
|
||||
error = xchk_iget(sc, inum, ipp);
|
||||
xchk_trans_cancel(sc);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't bother cross-referencing if we already found corruption or cross
|
||||
* referencing discrepancies.
|
||||
|
|
|
@ -94,8 +94,8 @@ xchk_setup_inode(
|
|||
if (!xfs_verify_ino(sc->mp, sc->sm->sm_ino))
|
||||
return -ENOENT;
|
||||
|
||||
/* Try a regular untrusted iget. */
|
||||
error = xchk_iget(sc, sc->sm->sm_ino, &ip);
|
||||
/* Try a safe untrusted iget. */
|
||||
error = xchk_iget_safe(sc, sc->sm->sm_ino, &ip);
|
||||
if (!error)
|
||||
return xchk_install_handle_iscrub(sc, ip);
|
||||
if (error == -ENOENT)
|
||||
|
|
Loading…
Reference in New Issue