Skip to content

Commit

Permalink
xfs: Add infrastructure needed for error propagation during buffer IO…
Browse files Browse the repository at this point in the history
… failure

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>
  • Loading branch information
Carlos Maiolino authored and Darrick J. Wong committed Aug 22, 2017
1 parent 6f4a1ee commit 0b80ae6
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 3 deletions.
32 changes: 31 additions & 1 deletion fs/xfs/xfs_buf_item.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
7 changes: 5 additions & 2 deletions fs/xfs/xfs_trans.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,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 *);
Expand All @@ -79,6 +81,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,
Expand Down

0 comments on commit 0b80ae6

Please sign in to comment.