| From b1438f477934f5a4d5a44df26f3079a7575d5946 Mon Sep 17 00:00:00 2001 |
| From: Dave Chinner <dchinner@redhat.com> |
| Date: Wed, 18 May 2016 13:53:42 +1000 |
| Subject: xfs: xfs_iflush_cluster fails to abort on error |
| |
| From: Dave Chinner <dchinner@redhat.com> |
| |
| commit b1438f477934f5a4d5a44df26f3079a7575d5946 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> |
| |
| --- |
| fs/xfs/xfs_inode.c | 17 +++++++++++++---- |
| 1 file changed, 13 insertions(+), 4 deletions(-) |
| |
| --- a/fs/xfs/xfs_inode.c |
| +++ b/fs/xfs/xfs_inode.c |
| @@ -3327,7 +3327,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; |
| |
| @@ -3369,14 +3369,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. |
| @@ -3404,7 +3412,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 = -EFSCORRUPTED; |