diff options
| -rw-r--r-- | fs/xfs/xfs_buf.c | 12 | ||||
| -rw-r--r-- | fs/xfs/xfs_buf.h | 20 | ||||
| -rw-r--r-- | fs/xfs/xfs_buf_item.c | 121 | ||||
| -rw-r--r-- | fs/xfs/xfs_mount.c | 22 | ||||
| -rw-r--r-- | fs/xfs/xfs_mount.h | 34 | ||||
| -rw-r--r-- | fs/xfs/xfs_sysfs.c | 291 | ||||
| -rw-r--r-- | fs/xfs/xfs_sysfs.h | 3 | ||||
| -rw-r--r-- | fs/xfs/xfs_trace.h | 1 |
8 files changed, 450 insertions, 54 deletions
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 9a2191b91137..e71cfbd5acb3 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c | |||
| @@ -1100,22 +1100,18 @@ xfs_bwrite( | |||
| 1100 | return error; | 1100 | return error; |
| 1101 | } | 1101 | } |
| 1102 | 1102 | ||
| 1103 | STATIC void | 1103 | static void |
| 1104 | xfs_buf_bio_end_io( | 1104 | xfs_buf_bio_end_io( |
| 1105 | struct bio *bio) | 1105 | struct bio *bio) |
| 1106 | { | 1106 | { |
| 1107 | xfs_buf_t *bp = (xfs_buf_t *)bio->bi_private; | 1107 | struct xfs_buf *bp = (struct xfs_buf *)bio->bi_private; |
| 1108 | 1108 | ||
| 1109 | /* | 1109 | /* |
| 1110 | * don't overwrite existing errors - otherwise we can lose errors on | 1110 | * don't overwrite existing errors - otherwise we can lose errors on |
| 1111 | * buffers that require multiple bios to complete. | 1111 | * buffers that require multiple bios to complete. |
| 1112 | */ | 1112 | */ |
| 1113 | if (bio->bi_error) { | 1113 | if (bio->bi_error) |
| 1114 | spin_lock(&bp->b_lock); | 1114 | cmpxchg(&bp->b_io_error, 0, bio->bi_error); |
| 1115 | if (!bp->b_io_error) | ||
| 1116 | bp->b_io_error = bio->bi_error; | ||
| 1117 | spin_unlock(&bp->b_lock); | ||
| 1118 | } | ||
| 1119 | 1115 | ||
| 1120 | if (!bp->b_error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ)) | 1116 | if (!bp->b_error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ)) |
| 1121 | invalidate_kernel_vmap_range(bp->b_addr, xfs_buf_vmap_len(bp)); | 1117 | invalidate_kernel_vmap_range(bp->b_addr, xfs_buf_vmap_len(bp)); |
diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h index 4eb89bd4ee73..8bfb974f0772 100644 --- a/fs/xfs/xfs_buf.h +++ b/fs/xfs/xfs_buf.h | |||
| @@ -183,6 +183,26 @@ 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 | |||
| 187 | /* | ||
| 188 | * async write failure retry count. Initialised to zero on the first | ||
| 189 | * failure, then when it exceeds the maximum configured without a | ||
| 190 | * success the write is considered to be failed permanently and the | ||
| 191 | * iodone handler will take appropriate action. | ||
| 192 | * | ||
| 193 | * For retry timeouts, we record the jiffie of the first failure. This | ||
| 194 | * means that we can change the retry timeout for buffers already under | ||
| 195 | * I/O and thus avoid getting stuck in a retry loop with a long timeout. | ||
| 196 | * | ||
| 197 | * last_error is used to ensure that we are getting repeated errors, not | ||
| 198 | * different errors. e.g. a block device might change ENOSPC to EIO when | ||
| 199 | * a failure timeout occurs, so we want to re-initialise the error | ||
| 200 | * retry behaviour appropriately when that happens. | ||
| 201 | */ | ||
| 202 | int b_retries; | ||
| 203 | unsigned long b_first_retry_time; /* in jiffies */ | ||
| 204 | int b_last_error; | ||
| 205 | |||
| 186 | const struct xfs_buf_ops *b_ops; | 206 | const struct xfs_buf_ops *b_ops; |
| 187 | 207 | ||
| 188 | #ifdef XFS_BUF_LOCK_TRACKING | 208 | #ifdef XFS_BUF_LOCK_TRACKING |
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 99e91a0e554e..34257992934c 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 | /* | 1045 | static bool |
| 1046 | * This is the iodone() function for buffers which have had callbacks | 1046 | xfs_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 | */ | ||
| 1052 | void | ||
| 1053 | xfs_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,93 @@ 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) { |
| 1085 | bp->b_flags |= (XBF_WRITE | XBF_ASYNC | | ||
| 1086 | XBF_DONE | XBF_WRITE_FAIL); | ||
| 1087 | bp->b_last_error = bp->b_error; | ||
| 1088 | bp->b_retries = 0; | ||
| 1089 | bp->b_first_retry_time = jiffies; | ||
| 1090 | |||
| 1091 | xfs_buf_ioerror(bp, 0); | ||
| 1092 | xfs_buf_submit(bp); | ||
| 1093 | return true; | ||
| 1094 | } | ||
| 1095 | 1095 | ||
| 1096 | trace_xfs_buf_item_iodone_async(bp, _RET_IP_); | 1096 | /* |
| 1097 | * Repeated failure on an async write. Take action according to the | ||
| 1098 | * error configuration we have been set up to use. | ||
| 1099 | */ | ||
| 1100 | cfg = xfs_error_get_cfg(mp, XFS_ERR_METADATA, bp->b_error); | ||
| 1097 | 1101 | ||
| 1098 | xfs_buf_ioerror(bp, 0); /* errno of 0 unsets the flag */ | 1102 | if (cfg->max_retries != XFS_ERR_RETRY_FOREVER && |
| 1103 | ++bp->b_retries > cfg->max_retries) | ||
| 1104 | goto permanent_error; | ||
| 1105 | if (cfg->retry_timeout && | ||
| 1106 | time_after(jiffies, cfg->retry_timeout + bp->b_first_retry_time)) | ||
| 1107 | goto permanent_error; | ||
| 1099 | 1108 | ||
| 1100 | if (!(bp->b_flags & (XBF_STALE|XBF_WRITE_FAIL))) { | 1109 | /* At unmount we may treat errors differently */ |
| 1101 | bp->b_flags |= XBF_WRITE | XBF_ASYNC | | 1110 | if ((mp->m_flags & XFS_MOUNT_UNMOUNTING) && mp->m_fail_unmount) |
| 1102 | XBF_DONE | XBF_WRITE_FAIL; | 1111 | goto permanent_error; |
| 1103 | xfs_buf_submit(bp); | ||
| 1104 | } else { | ||
| 1105 | xfs_buf_relse(bp); | ||
| 1106 | } | ||
| 1107 | 1112 | ||
| 1108 | return; | 1113 | /* still a transient error, higher layers will retry */ |
| 1109 | } | 1114 | xfs_buf_ioerror(bp, 0); |
| 1115 | xfs_buf_relse(bp); | ||
| 1116 | return true; | ||
| 1110 | 1117 | ||
| 1111 | /* | 1118 | /* |
| 1112 | * If the write of the buffer was synchronous, we want to make | 1119 | * 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(). | 1120 | * to indicate that inconsistency will result from this action. |
| 1114 | */ | 1121 | */ |
| 1122 | permanent_error: | ||
| 1123 | xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR); | ||
| 1124 | out_stale: | ||
| 1115 | xfs_buf_stale(bp); | 1125 | xfs_buf_stale(bp); |
| 1116 | bp->b_flags |= XBF_DONE; | 1126 | bp->b_flags |= XBF_DONE; |
| 1117 | |||
| 1118 | trace_xfs_buf_error_relse(bp, _RET_IP_); | 1127 | trace_xfs_buf_error_relse(bp, _RET_IP_); |
| 1128 | return false; | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | /* | ||
| 1132 | * This is the iodone() function for buffers which have had callbacks attached | ||
| 1133 | * to them by xfs_buf_attach_iodone(). We need to iterate the items on the | ||
| 1134 | * callback list, mark the buffer as having no more callbacks and then push the | ||
| 1135 | * buffer through IO completion processing. | ||
| 1136 | */ | ||
| 1137 | void | ||
| 1138 | xfs_buf_iodone_callbacks( | ||
| 1139 | struct xfs_buf *bp) | ||
| 1140 | { | ||
| 1141 | /* | ||
| 1142 | * If there is an error, process it. Some errors require us | ||
| 1143 | * to run callbacks after failure processing is done so we | ||
| 1144 | * detect that and take appropriate action. | ||
| 1145 | */ | ||
| 1146 | if (bp->b_error && xfs_buf_iodone_callback_error(bp)) | ||
| 1147 | return; | ||
| 1148 | |||
| 1149 | /* | ||
| 1150 | * Successful IO or permanent error. Either way, we can clear the | ||
| 1151 | * retry state here in preparation for the next error that may occur. | ||
| 1152 | */ | ||
| 1153 | bp->b_last_error = 0; | ||
| 1154 | bp->b_retries = 0; | ||
| 1119 | 1155 | ||
| 1120 | do_callbacks: | ||
| 1121 | xfs_buf_do_callbacks(bp); | 1156 | xfs_buf_do_callbacks(bp); |
| 1122 | bp->b_fspriv = NULL; | 1157 | bp->b_fspriv = NULL; |
| 1123 | bp->b_iodone = NULL; | 1158 | bp->b_iodone = NULL; |
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 654799f716fc..3b67b1470664 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
| @@ -680,6 +680,9 @@ xfs_mountfs( | |||
| 680 | 680 | ||
| 681 | xfs_set_maxicount(mp); | 681 | xfs_set_maxicount(mp); |
| 682 | 682 | ||
| 683 | /* enable fail_at_unmount as default */ | ||
| 684 | mp->m_fail_unmount = 1; | ||
| 685 | |||
| 683 | error = xfs_sysfs_init(&mp->m_kobj, &xfs_mp_ktype, NULL, mp->m_fsname); | 686 | error = xfs_sysfs_init(&mp->m_kobj, &xfs_mp_ktype, NULL, mp->m_fsname); |
| 684 | if (error) | 687 | if (error) |
| 685 | goto out; | 688 | goto out; |
| @@ -689,10 +692,15 @@ xfs_mountfs( | |||
| 689 | if (error) | 692 | if (error) |
| 690 | goto out_remove_sysfs; | 693 | goto out_remove_sysfs; |
| 691 | 694 | ||
| 692 | error = xfs_uuid_mount(mp); | 695 | error = xfs_error_sysfs_init(mp); |
| 693 | if (error) | 696 | if (error) |
| 694 | goto out_del_stats; | 697 | goto out_del_stats; |
| 695 | 698 | ||
| 699 | |||
| 700 | error = xfs_uuid_mount(mp); | ||
| 701 | if (error) | ||
| 702 | goto out_remove_error_sysfs; | ||
| 703 | |||
| 696 | /* | 704 | /* |
| 697 | * Set the minimum read and write sizes | 705 | * Set the minimum read and write sizes |
| 698 | */ | 706 | */ |
| @@ -956,6 +964,7 @@ xfs_mountfs( | |||
| 956 | cancel_delayed_work_sync(&mp->m_reclaim_work); | 964 | cancel_delayed_work_sync(&mp->m_reclaim_work); |
| 957 | xfs_reclaim_inodes(mp, SYNC_WAIT); | 965 | xfs_reclaim_inodes(mp, SYNC_WAIT); |
| 958 | out_log_dealloc: | 966 | out_log_dealloc: |
| 967 | mp->m_flags |= XFS_MOUNT_UNMOUNTING; | ||
| 959 | xfs_log_mount_cancel(mp); | 968 | xfs_log_mount_cancel(mp); |
| 960 | out_fail_wait: | 969 | out_fail_wait: |
| 961 | if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) | 970 | if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) |
| @@ -967,6 +976,8 @@ xfs_mountfs( | |||
| 967 | xfs_da_unmount(mp); | 976 | xfs_da_unmount(mp); |
| 968 | out_remove_uuid: | 977 | out_remove_uuid: |
| 969 | xfs_uuid_unmount(mp); | 978 | xfs_uuid_unmount(mp); |
| 979 | out_remove_error_sysfs: | ||
| 980 | xfs_error_sysfs_del(mp); | ||
| 970 | out_del_stats: | 981 | out_del_stats: |
| 971 | xfs_sysfs_del(&mp->m_stats.xs_kobj); | 982 | xfs_sysfs_del(&mp->m_stats.xs_kobj); |
| 972 | out_remove_sysfs: | 983 | out_remove_sysfs: |
| @@ -1005,6 +1016,14 @@ xfs_unmountfs( | |||
| 1005 | xfs_log_force(mp, XFS_LOG_SYNC); | 1016 | xfs_log_force(mp, XFS_LOG_SYNC); |
| 1006 | 1017 | ||
| 1007 | /* | 1018 | /* |
| 1019 | * We now need to tell the world we are unmounting. This will allow | ||
| 1020 | * us to detect that the filesystem is going away and we should error | ||
| 1021 | * out anything that we have been retrying in the background. This will | ||
| 1022 | * prevent neverending retries in AIL pushing from hanging the unmount. | ||
| 1023 | */ | ||
| 1024 | mp->m_flags |= XFS_MOUNT_UNMOUNTING; | ||
| 1025 | |||
| 1026 | /* | ||
| 1008 | * Flush all pending changes from the AIL. | 1027 | * Flush all pending changes from the AIL. |
| 1009 | */ | 1028 | */ |
| 1010 | xfs_ail_push_all_sync(mp->m_ail); | 1029 | xfs_ail_push_all_sync(mp->m_ail); |
| @@ -1055,6 +1074,7 @@ xfs_unmountfs( | |||
| 1055 | #endif | 1074 | #endif |
| 1056 | xfs_free_perag(mp); | 1075 | xfs_free_perag(mp); |
| 1057 | 1076 | ||
| 1077 | xfs_error_sysfs_del(mp); | ||
| 1058 | xfs_sysfs_del(&mp->m_stats.xs_kobj); | 1078 | xfs_sysfs_del(&mp->m_stats.xs_kobj); |
| 1059 | xfs_sysfs_del(&mp->m_kobj); | 1079 | xfs_sysfs_del(&mp->m_kobj); |
| 1060 | } | 1080 | } |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index bac6b3435591..9063a9c7b2fe 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
| @@ -37,6 +37,32 @@ enum { | |||
| 37 | XFS_LOWSP_MAX, | 37 | XFS_LOWSP_MAX, |
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | /* | ||
| 41 | * Error Configuration | ||
| 42 | * | ||
| 43 | * Error classes define the subsystem the configuration belongs to. | ||
| 44 | * Error numbers define the errors that are configurable. | ||
| 45 | */ | ||
| 46 | enum { | ||
| 47 | XFS_ERR_METADATA, | ||
| 48 | XFS_ERR_CLASS_MAX, | ||
| 49 | }; | ||
| 50 | enum { | ||
| 51 | XFS_ERR_DEFAULT, | ||
| 52 | XFS_ERR_EIO, | ||
| 53 | XFS_ERR_ENOSPC, | ||
| 54 | XFS_ERR_ENODEV, | ||
| 55 | XFS_ERR_ERRNO_MAX, | ||
| 56 | }; | ||
| 57 | |||
| 58 | #define XFS_ERR_RETRY_FOREVER -1 | ||
| 59 | |||
| 60 | struct xfs_error_cfg { | ||
| 61 | struct xfs_kobj kobj; | ||
| 62 | int max_retries; | ||
| 63 | unsigned long retry_timeout; /* in jiffies, 0 = no timeout */ | ||
| 64 | }; | ||
| 65 | |||
| 40 | typedef struct xfs_mount { | 66 | typedef struct xfs_mount { |
| 41 | struct super_block *m_super; | 67 | struct super_block *m_super; |
| 42 | xfs_tid_t m_tid; /* next unused tid for fs */ | 68 | xfs_tid_t m_tid; /* next unused tid for fs */ |
| @@ -127,6 +153,9 @@ typedef struct xfs_mount { | |||
| 127 | int64_t m_low_space[XFS_LOWSP_MAX]; | 153 | int64_t m_low_space[XFS_LOWSP_MAX]; |
| 128 | /* low free space thresholds */ | 154 | /* low free space thresholds */ |
| 129 | struct xfs_kobj m_kobj; | 155 | struct xfs_kobj m_kobj; |
| 156 | struct xfs_kobj m_error_kobj; | ||
| 157 | struct xfs_kobj m_error_meta_kobj; | ||
| 158 | struct xfs_error_cfg m_error_cfg[XFS_ERR_CLASS_MAX][XFS_ERR_ERRNO_MAX]; | ||
| 130 | struct xstats m_stats; /* per-fs stats */ | 159 | struct xstats m_stats; /* per-fs stats */ |
| 131 | 160 | ||
| 132 | struct workqueue_struct *m_buf_workqueue; | 161 | struct workqueue_struct *m_buf_workqueue; |
| @@ -148,6 +177,7 @@ typedef struct xfs_mount { | |||
| 148 | */ | 177 | */ |
| 149 | __uint32_t m_generation; | 178 | __uint32_t m_generation; |
| 150 | 179 | ||
| 180 | bool m_fail_unmount; | ||
| 151 | #ifdef DEBUG | 181 | #ifdef DEBUG |
| 152 | /* | 182 | /* |
| 153 | * DEBUG mode instrumentation to test and/or trigger delayed allocation | 183 | * DEBUG mode instrumentation to test and/or trigger delayed allocation |
| @@ -166,6 +196,7 @@ typedef struct xfs_mount { | |||
| 166 | #define XFS_MOUNT_WSYNC (1ULL << 0) /* for nfs - all metadata ops | 196 | #define XFS_MOUNT_WSYNC (1ULL << 0) /* for nfs - all metadata ops |
| 167 | must be synchronous except | 197 | must be synchronous except |
| 168 | for space allocations */ | 198 | for space allocations */ |
| 199 | #define XFS_MOUNT_UNMOUNTING (1ULL << 1) /* filesystem is unmounting */ | ||
| 169 | #define XFS_MOUNT_WAS_CLEAN (1ULL << 3) | 200 | #define XFS_MOUNT_WAS_CLEAN (1ULL << 3) |
| 170 | #define XFS_MOUNT_FS_SHUTDOWN (1ULL << 4) /* atomic stop of all filesystem | 201 | #define XFS_MOUNT_FS_SHUTDOWN (1ULL << 4) /* atomic stop of all filesystem |
| 171 | operations, typically for | 202 | operations, typically for |
| @@ -364,4 +395,7 @@ extern void xfs_set_low_space_thresholds(struct xfs_mount *); | |||
| 364 | int xfs_zero_extent(struct xfs_inode *ip, xfs_fsblock_t start_fsb, | 395 | int xfs_zero_extent(struct xfs_inode *ip, xfs_fsblock_t start_fsb, |
| 365 | xfs_off_t count_fsb); | 396 | xfs_off_t count_fsb); |
| 366 | 397 | ||
| 398 | struct xfs_error_cfg * xfs_error_get_cfg(struct xfs_mount *mp, | ||
| 399 | int error_class, int error); | ||
| 400 | |||
| 367 | #endif /* __XFS_MOUNT_H__ */ | 401 | #endif /* __XFS_MOUNT_H__ */ |
diff --git a/fs/xfs/xfs_sysfs.c b/fs/xfs/xfs_sysfs.c index 6ced4f143494..4c2c55086208 100644 --- a/fs/xfs/xfs_sysfs.c +++ b/fs/xfs/xfs_sysfs.c | |||
| @@ -17,10 +17,11 @@ | |||
| 17 | */ | 17 | */ |
| 18 | 18 | ||
| 19 | #include "xfs.h" | 19 | #include "xfs.h" |
| 20 | #include "xfs_sysfs.h" | 20 | #include "xfs_shared.h" |
| 21 | #include "xfs_format.h" | 21 | #include "xfs_format.h" |
| 22 | #include "xfs_log_format.h" | 22 | #include "xfs_log_format.h" |
| 23 | #include "xfs_trans_resv.h" | 23 | #include "xfs_trans_resv.h" |
| 24 | #include "xfs_sysfs.h" | ||
| 24 | #include "xfs_log.h" | 25 | #include "xfs_log.h" |
| 25 | #include "xfs_log_priv.h" | 26 | #include "xfs_log_priv.h" |
| 26 | #include "xfs_stats.h" | 27 | #include "xfs_stats.h" |
| @@ -362,3 +363,291 @@ struct kobj_type xfs_log_ktype = { | |||
| 362 | .sysfs_ops = &xfs_sysfs_ops, | 363 | .sysfs_ops = &xfs_sysfs_ops, |
| 363 | .default_attrs = xfs_log_attrs, | 364 | .default_attrs = xfs_log_attrs, |
| 364 | }; | 365 | }; |
| 366 | |||
| 367 | /* | ||
| 368 | * Metadata IO error configuration | ||
| 369 | * | ||
| 370 | * The sysfs structure here is: | ||
| 371 | * ...xfs/<dev>/error/<class>/<errno>/<error_attrs> | ||
| 372 | * | ||
| 373 | * where <class> allows us to discriminate between data IO and metadata IO, | ||
| 374 | * and any other future type of IO (e.g. special inode or directory error | ||
| 375 | * handling) we care to support. | ||
| 376 | */ | ||
| 377 | static inline struct xfs_error_cfg * | ||
| 378 | to_error_cfg(struct kobject *kobject) | ||
| 379 | { | ||
| 380 | struct xfs_kobj *kobj = to_kobj(kobject); | ||
| 381 | return container_of(kobj, struct xfs_error_cfg, kobj); | ||
| 382 | } | ||
| 383 | |||
| 384 | static inline struct xfs_mount * | ||
| 385 | err_to_mp(struct kobject *kobject) | ||
| 386 | { | ||
| 387 | struct xfs_kobj *kobj = to_kobj(kobject); | ||
| 388 | return container_of(kobj, struct xfs_mount, m_error_kobj); | ||
| 389 | } | ||
| 390 | |||
| 391 | static ssize_t | ||
| 392 | max_retries_show( | ||
| 393 | struct kobject *kobject, | ||
| 394 | char *buf) | ||
| 395 | { | ||
| 396 | struct xfs_error_cfg *cfg = to_error_cfg(kobject); | ||
| 397 | |||
| 398 | return snprintf(buf, PAGE_SIZE, "%d\n", cfg->max_retries); | ||
| 399 | } | ||
| 400 | |||
| 401 | static ssize_t | ||
| 402 | max_retries_store( | ||
| 403 | struct kobject *kobject, | ||
| 404 | const char *buf, | ||
| 405 | size_t count) | ||
| 406 | { | ||
| 407 | struct xfs_error_cfg *cfg = to_error_cfg(kobject); | ||
| 408 | int ret; | ||
| 409 | int val; | ||
| 410 | |||
| 411 | ret = kstrtoint(buf, 0, &val); | ||
| 412 | if (ret) | ||
| 413 | return ret; | ||
| 414 | |||
| 415 | if (val < -1) | ||
| 416 | return -EINVAL; | ||
| 417 | |||
| 418 | cfg->max_retries = val; | ||
| 419 | return count; | ||
| 420 | } | ||
| 421 | XFS_SYSFS_ATTR_RW(max_retries); | ||
| 422 | |||
| 423 | static ssize_t | ||
| 424 | retry_timeout_seconds_show( | ||
| 425 | struct kobject *kobject, | ||
| 426 | char *buf) | ||
| 427 | { | ||
| 428 | struct xfs_error_cfg *cfg = to_error_cfg(kobject); | ||
| 429 | |||
| 430 | return snprintf(buf, PAGE_SIZE, "%ld\n", | ||
| 431 | jiffies_to_msecs(cfg->retry_timeout) / MSEC_PER_SEC); | ||
| 432 | } | ||
| 433 | |||
| 434 | static ssize_t | ||
| 435 | retry_timeout_seconds_store( | ||
| 436 | struct kobject *kobject, | ||
| 437 | const char *buf, | ||
| 438 | size_t count) | ||
| 439 | { | ||
| 440 | struct xfs_error_cfg *cfg = to_error_cfg(kobject); | ||
| 441 | int ret; | ||
| 442 | int val; | ||
| 443 | |||
| 444 | ret = kstrtoint(buf, 0, &val); | ||
| 445 | if (ret) | ||
| 446 | return ret; | ||
| 447 | |||
| 448 | /* 1 day timeout maximum */ | ||
| 449 | if (val < 0 || val > 86400) | ||
| 450 | return -EINVAL; | ||
| 451 | |||
| 452 | cfg->retry_timeout = msecs_to_jiffies(val * MSEC_PER_SEC); | ||
| 453 | return count; | ||
| 454 | } | ||
| 455 | XFS_SYSFS_ATTR_RW(retry_timeout_seconds); | ||
| 456 | |||
| 457 | static ssize_t | ||
| 458 | fail_at_unmount_show( | ||
| 459 | struct kobject *kobject, | ||
| 460 | char *buf) | ||
| 461 | { | ||
| 462 | struct xfs_mount *mp = err_to_mp(kobject); | ||
| 463 | |||
| 464 | return snprintf(buf, PAGE_SIZE, "%d\n", mp->m_fail_unmount); | ||
| 465 | } | ||
| 466 | |||
| 467 | static ssize_t | ||
| 468 | fail_at_unmount_store( | ||
| 469 | struct kobject *kobject, | ||
| 470 | const char *buf, | ||
| 471 | size_t count) | ||
| 472 | { | ||
| 473 | struct xfs_mount *mp = err_to_mp(kobject); | ||
| 474 | int ret; | ||
| 475 | int val; | ||
| 476 | |||
| 477 | ret = kstrtoint(buf, 0, &val); | ||
| 478 | if (ret) | ||
| 479 | return ret; | ||
| 480 | |||
| 481 | if (val < 0 || val > 1) | ||
| 482 | return -EINVAL; | ||
| 483 | |||
| 484 | mp->m_fail_unmount = val; | ||
| 485 | return count; | ||
| 486 | } | ||
| 487 | XFS_SYSFS_ATTR_RW(fail_at_unmount); | ||
| 488 | |||
| 489 | static struct attribute *xfs_error_attrs[] = { | ||
| 490 | ATTR_LIST(max_retries), | ||
| 491 | ATTR_LIST(retry_timeout_seconds), | ||
| 492 | NULL, | ||
| 493 | }; | ||
| 494 | |||
| 495 | |||
| 496 | struct kobj_type xfs_error_cfg_ktype = { | ||
| 497 | .release = xfs_sysfs_release, | ||
| 498 | .sysfs_ops = &xfs_sysfs_ops, | ||
| 499 | .default_attrs = xfs_error_attrs, | ||
| 500 | }; | ||
| 501 | |||
| 502 | struct kobj_type xfs_error_ktype = { | ||
| 503 | .release = xfs_sysfs_release, | ||
| 504 | .sysfs_ops = &xfs_sysfs_ops, | ||
| 505 | }; | ||
| 506 | |||
| 507 | /* | ||
| 508 | * Error initialization tables. These need to be ordered in the same | ||
| 509 | * order as the enums used to index the array. All class init tables need to | ||
| 510 | * define a "default" behaviour as the first entry, all other entries can be | ||
| 511 | * empty. | ||
| 512 | */ | ||
| 513 | struct xfs_error_init { | ||
| 514 | char *name; | ||
| 515 | int max_retries; | ||
| 516 | int retry_timeout; /* in seconds */ | ||
| 517 | }; | ||
| 518 | |||
| 519 | static const struct xfs_error_init xfs_error_meta_init[XFS_ERR_ERRNO_MAX] = { | ||
| 520 | { .name = "default", | ||
| 521 | .max_retries = XFS_ERR_RETRY_FOREVER, | ||
| 522 | .retry_timeout = 0, | ||
| 523 | }, | ||
| 524 | { .name = "EIO", | ||
| 525 | .max_retries = XFS_ERR_RETRY_FOREVER, | ||
| 526 | .retry_timeout = 0, | ||
| 527 | }, | ||
| 528 | { .name = "ENOSPC", | ||
| 529 | .max_retries = XFS_ERR_RETRY_FOREVER, | ||
| 530 | .retry_timeout = 0, | ||
| 531 | }, | ||
| 532 | { .name = "ENODEV", | ||
| 533 | .max_retries = 0, | ||
| 534 | }, | ||
| 535 | }; | ||
| 536 | |||
| 537 | static int | ||
| 538 | xfs_error_sysfs_init_class( | ||
| 539 | struct xfs_mount *mp, | ||
| 540 | int class, | ||
| 541 | const char *parent_name, | ||
| 542 | struct xfs_kobj *parent_kobj, | ||
| 543 | const struct xfs_error_init init[]) | ||
| 544 | { | ||
| 545 | struct xfs_error_cfg *cfg; | ||
| 546 | int error; | ||
| 547 | int i; | ||
| 548 | |||
| 549 | ASSERT(class < XFS_ERR_CLASS_MAX); | ||
| 550 | |||
| 551 | error = xfs_sysfs_init(parent_kobj, &xfs_error_ktype, | ||
| 552 | &mp->m_error_kobj, parent_name); | ||
| 553 | if (error) | ||
| 554 | return error; | ||
| 555 | |||
| 556 | for (i = 0; i < XFS_ERR_ERRNO_MAX; i++) { | ||
| 557 | cfg = &mp->m_error_cfg[class][i]; | ||
| 558 | error = xfs_sysfs_init(&cfg->kobj, &xfs_error_cfg_ktype, | ||
| 559 | parent_kobj, init[i].name); | ||
| 560 | if (error) | ||
| 561 | goto out_error; | ||
| 562 | |||
| 563 | cfg->max_retries = init[i].max_retries; | ||
| 564 | cfg->retry_timeout = msecs_to_jiffies( | ||
| 565 | init[i].retry_timeout * MSEC_PER_SEC); | ||
| 566 | } | ||
| 567 | return 0; | ||
| 568 | |||
| 569 | out_error: | ||
| 570 | /* unwind the entries that succeeded */ | ||
| 571 | for (i--; i >= 0; i--) { | ||
| 572 | cfg = &mp->m_error_cfg[class][i]; | ||
| 573 | xfs_sysfs_del(&cfg->kobj); | ||
| 574 | } | ||
| 575 | xfs_sysfs_del(parent_kobj); | ||
| 576 | return error; | ||
| 577 | } | ||
| 578 | |||
| 579 | int | ||
| 580 | xfs_error_sysfs_init( | ||
| 581 | struct xfs_mount *mp) | ||
| 582 | { | ||
| 583 | int error; | ||
| 584 | |||
| 585 | /* .../xfs/<dev>/error/ */ | ||
| 586 | error = xfs_sysfs_init(&mp->m_error_kobj, &xfs_error_ktype, | ||
| 587 | &mp->m_kobj, "error"); | ||
| 588 | if (error) | ||
| 589 | return error; | ||
| 590 | |||
| 591 | error = sysfs_create_file(&mp->m_error_kobj.kobject, | ||
| 592 | ATTR_LIST(fail_at_unmount)); | ||
| 593 | |||
| 594 | if (error) | ||
| 595 | goto out_error; | ||
| 596 | |||
| 597 | /* .../xfs/<dev>/error/metadata/ */ | ||
| 598 | error = xfs_error_sysfs_init_class(mp, XFS_ERR_METADATA, | ||
| 599 | "metadata", &mp->m_error_meta_kobj, | ||
| 600 | xfs_error_meta_init); | ||
| 601 | if (error) | ||
| 602 | goto out_error; | ||
| 603 | |||
| 604 | return 0; | ||
| 605 | |||
| 606 | out_error: | ||
| 607 | xfs_sysfs_del(&mp->m_error_kobj); | ||
| 608 | return error; | ||
| 609 | } | ||
| 610 | |||
| 611 | void | ||
| 612 | xfs_error_sysfs_del( | ||
| 613 | struct xfs_mount *mp) | ||
| 614 | { | ||
| 615 | struct xfs_error_cfg *cfg; | ||
| 616 | int i, j; | ||
| 617 | |||
| 618 | for (i = 0; i < XFS_ERR_CLASS_MAX; i++) { | ||
| 619 | for (j = 0; j < XFS_ERR_ERRNO_MAX; j++) { | ||
| 620 | cfg = &mp->m_error_cfg[i][j]; | ||
| 621 | |||
| 622 | xfs_sysfs_del(&cfg->kobj); | ||
| 623 | } | ||
| 624 | } | ||
| 625 | xfs_sysfs_del(&mp->m_error_meta_kobj); | ||
| 626 | xfs_sysfs_del(&mp->m_error_kobj); | ||
| 627 | } | ||
| 628 | |||
| 629 | struct xfs_error_cfg * | ||
| 630 | xfs_error_get_cfg( | ||
| 631 | struct xfs_mount *mp, | ||
| 632 | int error_class, | ||
| 633 | int error) | ||
| 634 | { | ||
| 635 | struct xfs_error_cfg *cfg; | ||
| 636 | |||
| 637 | switch (error) { | ||
| 638 | case EIO: | ||
| 639 | cfg = &mp->m_error_cfg[error_class][XFS_ERR_EIO]; | ||
| 640 | break; | ||
| 641 | case ENOSPC: | ||
| 642 | cfg = &mp->m_error_cfg[error_class][XFS_ERR_ENOSPC]; | ||
| 643 | break; | ||
| 644 | case ENODEV: | ||
| 645 | cfg = &mp->m_error_cfg[error_class][XFS_ERR_ENODEV]; | ||
| 646 | break; | ||
| 647 | default: | ||
| 648 | cfg = &mp->m_error_cfg[error_class][XFS_ERR_DEFAULT]; | ||
| 649 | break; | ||
| 650 | } | ||
| 651 | |||
| 652 | return cfg; | ||
| 653 | } | ||
diff --git a/fs/xfs/xfs_sysfs.h b/fs/xfs/xfs_sysfs.h index be692e59938d..d04637181ef2 100644 --- a/fs/xfs/xfs_sysfs.h +++ b/fs/xfs/xfs_sysfs.h | |||
| @@ -58,4 +58,7 @@ xfs_sysfs_del( | |||
| 58 | wait_for_completion(&kobj->complete); | 58 | wait_for_completion(&kobj->complete); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | int xfs_error_sysfs_init(struct xfs_mount *mp); | ||
| 62 | void xfs_error_sysfs_del(struct xfs_mount *mp); | ||
| 63 | |||
| 61 | #endif /* __XFS_SYSFS_H__ */ | 64 | #endif /* __XFS_SYSFS_H__ */ |
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index 840d52e38f10..ea94ee0fe5ea 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h | |||
| @@ -364,7 +364,6 @@ DEFINE_BUF_EVENT(xfs_buf_delwri_split); | |||
| 364 | DEFINE_BUF_EVENT(xfs_buf_get_uncached); | 364 | DEFINE_BUF_EVENT(xfs_buf_get_uncached); |
| 365 | DEFINE_BUF_EVENT(xfs_bdstrat_shut); | 365 | DEFINE_BUF_EVENT(xfs_bdstrat_shut); |
| 366 | DEFINE_BUF_EVENT(xfs_buf_item_relse); | 366 | DEFINE_BUF_EVENT(xfs_buf_item_relse); |
| 367 | DEFINE_BUF_EVENT(xfs_buf_item_iodone); | ||
| 368 | DEFINE_BUF_EVENT(xfs_buf_item_iodone_async); | 367 | DEFINE_BUF_EVENT(xfs_buf_item_iodone_async); |
| 369 | DEFINE_BUF_EVENT(xfs_buf_error_relse); | 368 | DEFINE_BUF_EVENT(xfs_buf_error_relse); |
| 370 | DEFINE_BUF_EVENT(xfs_buf_wait_buftarg); | 369 | DEFINE_BUF_EVENT(xfs_buf_wait_buftarg); |
