Skip to content

Commit

Permalink
xfs: xfs_iflush_cluster fails to abort on error
Browse files Browse the repository at this point in the history
commit b1438f4 upstream.

When a failure due to an inode buffer occurs, the error handling
fails to abort the inode writeback correctly. This can result in the
inode being reclaimed whilst still in the AIL, leading to
use-after-free situations as well as filesystems that cannot be
unmounted as the inode log items left in the AIL never get removed.

Fix this by ensuring fatal errors from xfs_imap_to_bp() result in
the inode flush being aborted correctly.

Reported-by: Shyam Kaushik <shyam@zadarastorage.com>
Diagnosed-by: Shyam Kaushik <shyam@zadarastorage.com>
Tested-by: Shyam Kaushik <shyam@zadarastorage.com>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Chinner <david@fromorbit.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Dave Chinner authored and Greg Kroah-Hartman committed Jun 8, 2016
1 parent 07a9b7b commit c66edea
Showing 1 changed file with 13 additions and 4 deletions.
17 changes: 13 additions & 4 deletions fs/xfs/xfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -3045,7 +3045,7 @@ xfs_iflush(
struct xfs_buf **bpp)
{
struct xfs_mount *mp = ip->i_mount;
struct xfs_buf *bp;
struct xfs_buf *bp = NULL;
struct xfs_dinode *dip;
int error;

Expand Down Expand Up @@ -3087,14 +3087,22 @@ xfs_iflush(
}

/*
* Get the buffer containing the on-disk inode.
* Get the buffer containing the on-disk inode. We are doing a try-lock
* operation here, so we may get an EAGAIN error. In that case, we
* simply want to return with the inode still dirty.
*
* If we get any other error, we effectively have a corruption situation
* and we cannot flush the inode, so we treat it the same as failing
* xfs_iflush_int().
*/
error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &bp, XBF_TRYLOCK,
0);
if (error || !bp) {
if (error == -EAGAIN) {
xfs_ifunlock(ip);
return error;
}
if (error)
goto corrupt_out;

/*
* First flush out the inode that xfs_iflush was called with.
Expand Down Expand Up @@ -3122,7 +3130,8 @@ xfs_iflush(
return 0;

corrupt_out:
xfs_buf_relse(bp);
if (bp)
xfs_buf_relse(bp);
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
cluster_corrupt_out:
error = XFS_ERROR(EFSCORRUPTED);
Expand Down

0 comments on commit c66edea

Please sign in to comment.