Commit 01ee4801 authored by Dave Chinner's avatar Dave Chinner Committed by Willy Tarreau

xfs: xfs_iflush_cluster fails to abort on error

commit b1438f47 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: default avatarShyam Kaushik <shyam@zadarastorage.com>
Diagnosed-by: default avatarShyam Kaushik <shyam@zadarastorage.com>
Tested-by: default avatarShyam Kaushik <shyam@zadarastorage.com>
Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
[wt: in kernels < 3.17, the error sign is positive, not negative]
Signed-off-by: default avatarWilly Tarreau <w@1wt.eu>
parent 0ed4547f
...@@ -2726,7 +2726,7 @@ xfs_iflush( ...@@ -2726,7 +2726,7 @@ xfs_iflush(
struct xfs_buf **bpp) struct xfs_buf **bpp)
{ {
struct xfs_mount *mp = ip->i_mount; struct xfs_mount *mp = ip->i_mount;
struct xfs_buf *bp; struct xfs_buf *bp = NULL;
struct xfs_dinode *dip; struct xfs_dinode *dip;
int error; int error;
...@@ -2768,14 +2768,22 @@ xfs_iflush( ...@@ -2768,14 +2768,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, error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &bp, XBF_TRYLOCK,
0); 0);
if (error || !bp) { if (error == EAGAIN) {
xfs_ifunlock(ip); xfs_ifunlock(ip);
return error; return error;
} }
if (error)
goto corrupt_out;
/* /*
* First flush out the inode that xfs_iflush was called with. * First flush out the inode that xfs_iflush was called with.
...@@ -2803,7 +2811,8 @@ xfs_iflush( ...@@ -2803,7 +2811,8 @@ xfs_iflush(
return 0; return 0;
corrupt_out: corrupt_out:
xfs_buf_relse(bp); if (bp)
xfs_buf_relse(bp);
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
cluster_corrupt_out: cluster_corrupt_out:
error = XFS_ERROR(EFSCORRUPTED); error = XFS_ERROR(EFSCORRUPTED);
......
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