aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarlos Maiolino <cmaiolino@redhat.com>2016-05-17 21:05:33 -0400
committerDave Chinner <david@fromorbit.com>2016-05-17 21:05:33 -0400
commitdf3093907ccc718459c54c99da29dd774af41186 (patch)
tree339b0e68135d4523dd1ebac6886158cf93ae1d6d
parentffd40ef697dfd3e06f44b1bb5fea93079de8c77d (diff)
xfs: add configurable error support to metadata buffers
With the error configuration handle for async metadata write errors in place, we can now add initial support to the IO error processing in xfs_buf_iodone_error(). Add an infrastructure function to look up the configuration handle, and rearrange the error handling to prepare the way for different error handling conigurations to be used. Signed-off-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r--fs/xfs/xfs_buf.h1
-rw-r--r--fs/xfs/xfs_buf_item.c112
-rw-r--r--fs/xfs/xfs_mount.h3
-rw-r--r--fs/xfs/xfs_sysfs.c17
-rw-r--r--fs/xfs/xfs_trace.h1
5 files changed, 88 insertions, 46 deletions
diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
index 4eb89bd4ee73..adef116db0c3 100644
--- a/fs/xfs/xfs_buf.h
+++ b/fs/xfs/xfs_buf.h
@@ -183,6 +183,7 @@ typedef struct xfs_buf {
183 unsigned int b_page_count; /* size of page array */ 183 unsigned int b_page_count; /* size of page array */
184 unsigned int b_offset; /* page offset in first page */ 184 unsigned int b_offset; /* page offset in first page */
185 int b_error; /* error code on I/O */ 185 int b_error; /* error code on I/O */
186 int b_last_error; /* previous async I/O error */
186 const struct xfs_buf_ops *b_ops; 187 const struct xfs_buf_ops *b_ops;
187 188
188#ifdef XFS_BUF_LOCK_TRACKING 189#ifdef XFS_BUF_LOCK_TRACKING
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index 99e91a0e554e..b8d0cd4adb81 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -1042,35 +1042,22 @@ xfs_buf_do_callbacks(
1042 } 1042 }
1043} 1043}
1044 1044
1045/* 1045static bool
1046 * This is the iodone() function for buffers which have had callbacks 1046xfs_buf_iodone_callback_error(
1047 * attached to them by xfs_buf_attach_iodone(). It should remove each
1048 * log item from the buffer's list and call the callback of each in turn.
1049 * When done, the buffer's fsprivate field is set to NULL and the buffer
1050 * is unlocked with a call to iodone().
1051 */
1052void
1053xfs_buf_iodone_callbacks(
1054 struct xfs_buf *bp) 1047 struct xfs_buf *bp)
1055{ 1048{
1056 struct xfs_log_item *lip = bp->b_fspriv; 1049 struct xfs_log_item *lip = bp->b_fspriv;
1057 struct xfs_mount *mp = lip->li_mountp; 1050 struct xfs_mount *mp = lip->li_mountp;
1058 static ulong lasttime; 1051 static ulong lasttime;
1059 static xfs_buftarg_t *lasttarg; 1052 static xfs_buftarg_t *lasttarg;
1060 1053 struct xfs_error_cfg *cfg;
1061 if (likely(!bp->b_error))
1062 goto do_callbacks;
1063 1054
1064 /* 1055 /*
1065 * If we've already decided to shutdown the filesystem because of 1056 * If we've already decided to shutdown the filesystem because of
1066 * I/O errors, there's no point in giving this a retry. 1057 * I/O errors, there's no point in giving this a retry.
1067 */ 1058 */
1068 if (XFS_FORCED_SHUTDOWN(mp)) { 1059 if (XFS_FORCED_SHUTDOWN(mp))
1069 xfs_buf_stale(bp); 1060 goto out_stale;
1070 bp->b_flags |= XBF_DONE;
1071 trace_xfs_buf_item_iodone(bp, _RET_IP_);
1072 goto do_callbacks;
1073 }
1074 1061
1075 if (bp->b_target != lasttarg || 1062 if (bp->b_target != lasttarg ||
1076 time_after(jiffies, (lasttime + 5*HZ))) { 1063 time_after(jiffies, (lasttime + 5*HZ))) {
@@ -1079,45 +1066,80 @@ xfs_buf_iodone_callbacks(
1079 } 1066 }
1080 lasttarg = bp->b_target; 1067 lasttarg = bp->b_target;
1081 1068
1069 /* synchronous writes will have callers process the error */
1070 if (!(bp->b_flags & XBF_ASYNC))
1071 goto out_stale;
1072
1073 trace_xfs_buf_item_iodone_async(bp, _RET_IP_);
1074 ASSERT(bp->b_iodone != NULL);
1075
1082 /* 1076 /*
1083 * If the write was asynchronous then no one will be looking for the 1077 * If the write was asynchronous then no one will be looking for the
1084 * error. Clear the error state and write the buffer out again. 1078 * error. If this is the first failure of this type, clear the error
1085 * 1079 * state and write the buffer out again. This means we always retry an
1086 * XXX: This helps against transient write errors, but we need to find 1080 * async write failure at least once, but we also need to set the buffer
1087 * a way to shut the filesystem down if the writes keep failing. 1081 * up to behave correctly now for repeated failures.
1088 *
1089 * In practice we'll shut the filesystem down soon as non-transient
1090 * errors tend to affect the whole device and a failing log write
1091 * will make us give up. But we really ought to do better here.
1092 */ 1082 */
1093 if (bp->b_flags & XBF_ASYNC) { 1083 if (!(bp->b_flags & (XBF_STALE|XBF_WRITE_FAIL)) ||
1094 ASSERT(bp->b_iodone != NULL); 1084 bp->b_last_error != bp->b_error) {
1095 1085 bp->b_flags |= (XBF_WRITE | XBF_ASYNC |
1096 trace_xfs_buf_item_iodone_async(bp, _RET_IP_); 1086 XBF_DONE | XBF_WRITE_FAIL);
1087 bp->b_last_error = bp->b_error;
1088 xfs_buf_ioerror(bp, 0);
1089 xfs_buf_submit(bp);
1090 return true;
1091 }
1097 1092
1098 xfs_buf_ioerror(bp, 0); /* errno of 0 unsets the flag */ 1093 /*
1094 * Repeated failure on an async write. Take action according to the
1095 * error configuration we have been set up to use.
1096 */
1097 cfg = xfs_error_get_cfg(mp, XFS_ERR_METADATA, bp->b_error);
1098 if (!cfg->max_retries)
1099 goto permanent_error;
1099 1100
1100 if (!(bp->b_flags & (XBF_STALE|XBF_WRITE_FAIL))) { 1101 /* still a transient error, higher layers will retry */
1101 bp->b_flags |= XBF_WRITE | XBF_ASYNC | 1102 xfs_buf_ioerror(bp, 0);
1102 XBF_DONE | XBF_WRITE_FAIL; 1103 xfs_buf_relse(bp);
1103 xfs_buf_submit(bp); 1104 return true;
1104 } else {
1105 xfs_buf_relse(bp);
1106 }
1107
1108 return;
1109 }
1110 1105
1111 /* 1106 /*
1112 * If the write of the buffer was synchronous, we want to make 1107 * Permanent error - we need to trigger a shutdown if we haven't already
1113 * sure to return the error to the caller of xfs_bwrite(). 1108 * to indicate that inconsistency will result from this action.
1114 */ 1109 */
1110permanent_error:
1111 xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
1112out_stale:
1115 xfs_buf_stale(bp); 1113 xfs_buf_stale(bp);
1116 bp->b_flags |= XBF_DONE; 1114 bp->b_flags |= XBF_DONE;
1117
1118 trace_xfs_buf_error_relse(bp, _RET_IP_); 1115 trace_xfs_buf_error_relse(bp, _RET_IP_);
1116 return false;
1117}
1118
1119/*
1120 * This is the iodone() function for buffers which have had callbacks attached
1121 * to them by xfs_buf_attach_iodone(). We need to iterate the items on the
1122 * callback list, mark the buffer as having no more callbacks and then push the
1123 * buffer through IO completion processing.
1124 */
1125void
1126xfs_buf_iodone_callbacks(
1127 struct xfs_buf *bp)
1128{
1129 /*
1130 * If there is an error, process it. Some errors require us
1131 * to run callbacks after failure processing is done so we
1132 * detect that and take appropriate action.
1133 */
1134 if (bp->b_error && xfs_buf_iodone_callback_error(bp))
1135 return;
1136
1137 /*
1138 * Successful IO or permanent error. Either way, we can clear the
1139 * retry state here in preparation for the next error that may occur.
1140 */
1141 bp->b_last_error = 0;
1119 1142
1120do_callbacks:
1121 xfs_buf_do_callbacks(bp); 1143 xfs_buf_do_callbacks(bp);
1122 bp->b_fspriv = NULL; 1144 bp->b_fspriv = NULL;
1123 bp->b_iodone = NULL; 1145 bp->b_iodone = NULL;
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 352a5c88d7e9..0c5a97644d78 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -387,4 +387,7 @@ extern void xfs_set_low_space_thresholds(struct xfs_mount *);
387int xfs_zero_extent(struct xfs_inode *ip, xfs_fsblock_t start_fsb, 387int xfs_zero_extent(struct xfs_inode *ip, xfs_fsblock_t start_fsb,
388 xfs_off_t count_fsb); 388 xfs_off_t count_fsb);
389 389
390struct xfs_error_cfg * xfs_error_get_cfg(struct xfs_mount *mp,
391 int error_class, int error);
392
390#endif /* __XFS_MOUNT_H__ */ 393#endif /* __XFS_MOUNT_H__ */
diff --git a/fs/xfs/xfs_sysfs.c b/fs/xfs/xfs_sysfs.c
index 07c95999541e..1cb5a85409af 100644
--- a/fs/xfs/xfs_sysfs.c
+++ b/fs/xfs/xfs_sysfs.c
@@ -447,3 +447,20 @@ xfs_error_sysfs_del(
447 xfs_sysfs_del(&mp->m_error_meta_kobj); 447 xfs_sysfs_del(&mp->m_error_meta_kobj);
448 xfs_sysfs_del(&mp->m_error_kobj); 448 xfs_sysfs_del(&mp->m_error_kobj);
449} 449}
450
451struct xfs_error_cfg *
452xfs_error_get_cfg(
453 struct xfs_mount *mp,
454 int error_class,
455 int error)
456{
457 struct xfs_error_cfg *cfg;
458
459 switch (error) {
460 default:
461 cfg = &mp->m_error_cfg[error_class][XFS_ERR_DEFAULT];
462 break;
463 }
464
465 return cfg;
466}
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index c8d58426008e..a133dd4c43bc 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -364,7 +364,6 @@ DEFINE_BUF_EVENT(xfs_buf_delwri_split);
364DEFINE_BUF_EVENT(xfs_buf_get_uncached); 364DEFINE_BUF_EVENT(xfs_buf_get_uncached);
365DEFINE_BUF_EVENT(xfs_bdstrat_shut); 365DEFINE_BUF_EVENT(xfs_bdstrat_shut);
366DEFINE_BUF_EVENT(xfs_buf_item_relse); 366DEFINE_BUF_EVENT(xfs_buf_item_relse);
367DEFINE_BUF_EVENT(xfs_buf_item_iodone);
368DEFINE_BUF_EVENT(xfs_buf_item_iodone_async); 367DEFINE_BUF_EVENT(xfs_buf_item_iodone_async);
369DEFINE_BUF_EVENT(xfs_buf_error_relse); 368DEFINE_BUF_EVENT(xfs_buf_error_relse);
370DEFINE_BUF_EVENT(xfs_buf_wait_buftarg); 369DEFINE_BUF_EVENT(xfs_buf_wait_buftarg);