|
@@ -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;
|