| From foo@baz Mon Sep 18 10:16:36 CEST 2017 |
| From: Christoph Hellwig <hch@lst.de> |
| Date: Sun, 17 Sep 2017 14:06:49 -0700 |
| Subject: xfs: Add infrastructure needed for error propagation during buffer IO failure |
| To: stable@vger.kernel.org |
| Cc: linux-xfs@vger.kernel.org, Carlos Maiolino <cmaiolino@redhat.com>, "Darrick J . Wong" <darrick.wong@oracle.com> |
| Message-ID: <20170917210712.10804-25-hch@lst.de> |
| |
| From: Carlos Maiolino <cmaiolino@redhat.com> |
| |
| commit 0b80ae6ed13169bd3a244e71169f2cc020b0c57a upstream. |
| |
| With the current code, XFS never re-submit a failed buffer for IO, |
| because the failed item in the buffer is kept in the flush locked state |
| forever. |
| |
| To be able to resubmit an log item for IO, we need a way to mark an item |
| as failed, if, for any reason the buffer which the item belonged to |
| failed during writeback. |
| |
| Add a new log item callback to be used after an IO completion failure |
| and make the needed clean ups. |
| |
| Reviewed-by: Brian Foster <bfoster@redhat.com> |
| Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com> |
| Reviewed-by: Christoph Hellwig <hch@lst.de> |
| Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> |
| Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/xfs/xfs_buf_item.c | 32 +++++++++++++++++++++++++++++++- |
| fs/xfs/xfs_trans.h | 7 +++++-- |
| 2 files changed, 36 insertions(+), 3 deletions(-) |
| |
| --- a/fs/xfs/xfs_buf_item.c |
| +++ b/fs/xfs/xfs_buf_item.c |
| @@ -29,6 +29,7 @@ |
| #include "xfs_error.h" |
| #include "xfs_trace.h" |
| #include "xfs_log.h" |
| +#include "xfs_inode.h" |
| |
| |
| kmem_zone_t *xfs_buf_item_zone; |
| @@ -1054,6 +1055,31 @@ xfs_buf_do_callbacks( |
| } |
| } |
| |
| +/* |
| + * Invoke the error state callback for each log item affected by the failed I/O. |
| + * |
| + * If a metadata buffer write fails with a non-permanent error, the buffer is |
| + * eventually resubmitted and so the completion callbacks are not run. The error |
| + * state may need to be propagated to the log items attached to the buffer, |
| + * however, so the next AIL push of the item knows hot to handle it correctly. |
| + */ |
| +STATIC void |
| +xfs_buf_do_callbacks_fail( |
| + struct xfs_buf *bp) |
| +{ |
| + struct xfs_log_item *next; |
| + struct xfs_log_item *lip = bp->b_fspriv; |
| + struct xfs_ail *ailp = lip->li_ailp; |
| + |
| + spin_lock(&ailp->xa_lock); |
| + for (; lip; lip = next) { |
| + next = lip->li_bio_list; |
| + if (lip->li_ops->iop_error) |
| + lip->li_ops->iop_error(lip, bp); |
| + } |
| + spin_unlock(&ailp->xa_lock); |
| +} |
| + |
| static bool |
| xfs_buf_iodone_callback_error( |
| struct xfs_buf *bp) |
| @@ -1123,7 +1149,11 @@ xfs_buf_iodone_callback_error( |
| if ((mp->m_flags & XFS_MOUNT_UNMOUNTING) && mp->m_fail_unmount) |
| goto permanent_error; |
| |
| - /* still a transient error, higher layers will retry */ |
| + /* |
| + * Still a transient error, run IO completion failure callbacks and let |
| + * the higher layers retry the buffer. |
| + */ |
| + xfs_buf_do_callbacks_fail(bp); |
| xfs_buf_ioerror(bp, 0); |
| xfs_buf_relse(bp); |
| return true; |
| --- a/fs/xfs/xfs_trans.h |
| +++ b/fs/xfs/xfs_trans.h |
| @@ -65,11 +65,13 @@ typedef struct xfs_log_item { |
| } xfs_log_item_t; |
| |
| #define XFS_LI_IN_AIL 0x1 |
| -#define XFS_LI_ABORTED 0x2 |
| +#define XFS_LI_ABORTED 0x2 |
| +#define XFS_LI_FAILED 0x4 |
| |
| #define XFS_LI_FLAGS \ |
| { XFS_LI_IN_AIL, "IN_AIL" }, \ |
| - { XFS_LI_ABORTED, "ABORTED" } |
| + { XFS_LI_ABORTED, "ABORTED" }, \ |
| + { XFS_LI_FAILED, "FAILED" } |
| |
| struct xfs_item_ops { |
| void (*iop_size)(xfs_log_item_t *, int *, int *); |
| @@ -80,6 +82,7 @@ struct xfs_item_ops { |
| void (*iop_unlock)(xfs_log_item_t *); |
| xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t); |
| void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t); |
| + void (*iop_error)(xfs_log_item_t *, xfs_buf_t *); |
| }; |
| |
| void xfs_log_item_init(struct xfs_mount *mp, struct xfs_log_item *item, |