aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarlos Maiolino <cmaiolino@redhat.com>2016-05-17 21:11:27 -0400
committerDave Chinner <david@fromorbit.com>2016-05-17 21:11:27 -0400
commite6b3bb78962e65c4ad125598755cfbf2a8779e86 (patch)
tree0089723eb2f5ea74989458c53558a38181ddc55f
parente0a431b3a3cc3d0a4c38ccfca8c7320fde40efb6 (diff)
xfs: add "fail at unmount" error handling configuration
If we take "retry forever" literally on metadata IO errors, we can hang at unmount, once it retries those writes forever. This is the default behavior, unfortunately. Add an error configuration option for this behavior and default it to "fail" so that an unmount will trigger actuall errors, a shutdown and allow the unmount to succeed. It will be noisy, though, as it will log the errors and shutdown that occurs. To fix this, we need to mark the filesystem as being in the process of unmounting. Do this with a mount flag that is added at the appropriate time (i.e. before the blocking AIL sync). We also need to add this flag if mount fails after the initial phase of log recovery has been run. 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_item.c4
-rw-r--r--fs/xfs/xfs_mount.c12
-rw-r--r--fs/xfs/xfs_mount.h2
-rw-r--r--fs/xfs/xfs_sysfs.c46
4 files changed, 64 insertions, 0 deletions
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index 0d95c59f7c68..34257992934c 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -1106,6 +1106,10 @@ xfs_buf_iodone_callback_error(
1106 time_after(jiffies, cfg->retry_timeout + bp->b_first_retry_time)) 1106 time_after(jiffies, cfg->retry_timeout + bp->b_first_retry_time))
1107 goto permanent_error; 1107 goto permanent_error;
1108 1108
1109 /* At unmount we may treat errors differently */
1110 if ((mp->m_flags & XFS_MOUNT_UNMOUNTING) && mp->m_fail_unmount)
1111 goto permanent_error;
1112
1109 /* still a transient error, higher layers will retry */ 1113 /* still a transient error, higher layers will retry */
1110 xfs_buf_ioerror(bp, 0); 1114 xfs_buf_ioerror(bp, 0);
1111 xfs_buf_relse(bp); 1115 xfs_buf_relse(bp);
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 677c3e0da472..7c05a22c1a73 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -681,6 +681,9 @@ xfs_mountfs(
681 681
682 xfs_set_maxicount(mp); 682 xfs_set_maxicount(mp);
683 683
684 /* enable fail_at_unmount as default */
685 mp->m_fail_unmount = 1;
686
684 error = xfs_sysfs_init(&mp->m_kobj, &xfs_mp_ktype, NULL, mp->m_fsname); 687 error = xfs_sysfs_init(&mp->m_kobj, &xfs_mp_ktype, NULL, mp->m_fsname);
685 if (error) 688 if (error)
686 goto out; 689 goto out;
@@ -962,6 +965,7 @@ xfs_mountfs(
962 cancel_delayed_work_sync(&mp->m_reclaim_work); 965 cancel_delayed_work_sync(&mp->m_reclaim_work);
963 xfs_reclaim_inodes(mp, SYNC_WAIT); 966 xfs_reclaim_inodes(mp, SYNC_WAIT);
964 out_log_dealloc: 967 out_log_dealloc:
968 mp->m_flags |= XFS_MOUNT_UNMOUNTING;
965 xfs_log_mount_cancel(mp); 969 xfs_log_mount_cancel(mp);
966 out_fail_wait: 970 out_fail_wait:
967 if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) 971 if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp)
@@ -1013,6 +1017,14 @@ xfs_unmountfs(
1013 xfs_log_force(mp, XFS_LOG_SYNC); 1017 xfs_log_force(mp, XFS_LOG_SYNC);
1014 1018
1015 /* 1019 /*
1020 * We now need to tell the world we are unmounting. This will allow
1021 * us to detect that the filesystem is going away and we should error
1022 * out anything that we have been retrying in the background. This will
1023 * prevent neverending retries in AIL pushing from hanging the unmount.
1024 */
1025 mp->m_flags |= XFS_MOUNT_UNMOUNTING;
1026
1027 /*
1016 * Flush all pending changes from the AIL. 1028 * Flush all pending changes from the AIL.
1017 */ 1029 */
1018 xfs_ail_push_all_sync(mp->m_ail); 1030 xfs_ail_push_all_sync(mp->m_ail);
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 72ec3e3c988e..9063a9c7b2fe 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -177,6 +177,7 @@ typedef struct xfs_mount {
177 */ 177 */
178 __uint32_t m_generation; 178 __uint32_t m_generation;
179 179
180 bool m_fail_unmount;
180#ifdef DEBUG 181#ifdef DEBUG
181 /* 182 /*
182 * DEBUG mode instrumentation to test and/or trigger delayed allocation 183 * DEBUG mode instrumentation to test and/or trigger delayed allocation
@@ -195,6 +196,7 @@ typedef struct xfs_mount {
195#define XFS_MOUNT_WSYNC (1ULL << 0) /* for nfs - all metadata ops 196#define XFS_MOUNT_WSYNC (1ULL << 0) /* for nfs - all metadata ops
196 must be synchronous except 197 must be synchronous except
197 for space allocations */ 198 for space allocations */
199#define XFS_MOUNT_UNMOUNTING (1ULL << 1) /* filesystem is unmounting */
198#define XFS_MOUNT_WAS_CLEAN (1ULL << 3) 200#define XFS_MOUNT_WAS_CLEAN (1ULL << 3)
199#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
200 operations, typically for 202 operations, typically for
diff --git a/fs/xfs/xfs_sysfs.c b/fs/xfs/xfs_sysfs.c
index 084a606840a1..4c2c55086208 100644
--- a/fs/xfs/xfs_sysfs.c
+++ b/fs/xfs/xfs_sysfs.c
@@ -381,6 +381,13 @@ to_error_cfg(struct kobject *kobject)
381 return container_of(kobj, struct xfs_error_cfg, kobj); 381 return container_of(kobj, struct xfs_error_cfg, kobj);
382} 382}
383 383
384static inline struct xfs_mount *
385err_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
384static ssize_t 391static ssize_t
385max_retries_show( 392max_retries_show(
386 struct kobject *kobject, 393 struct kobject *kobject,
@@ -447,6 +454,38 @@ retry_timeout_seconds_store(
447} 454}
448XFS_SYSFS_ATTR_RW(retry_timeout_seconds); 455XFS_SYSFS_ATTR_RW(retry_timeout_seconds);
449 456
457static ssize_t
458fail_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
467static ssize_t
468fail_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}
487XFS_SYSFS_ATTR_RW(fail_at_unmount);
488
450static struct attribute *xfs_error_attrs[] = { 489static struct attribute *xfs_error_attrs[] = {
451 ATTR_LIST(max_retries), 490 ATTR_LIST(max_retries),
452 ATTR_LIST(retry_timeout_seconds), 491 ATTR_LIST(retry_timeout_seconds),
@@ -462,6 +501,7 @@ struct kobj_type xfs_error_cfg_ktype = {
462 501
463struct kobj_type xfs_error_ktype = { 502struct kobj_type xfs_error_ktype = {
464 .release = xfs_sysfs_release, 503 .release = xfs_sysfs_release,
504 .sysfs_ops = &xfs_sysfs_ops,
465}; 505};
466 506
467/* 507/*
@@ -548,6 +588,12 @@ xfs_error_sysfs_init(
548 if (error) 588 if (error)
549 return error; 589 return error;
550 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
551 /* .../xfs/<dev>/error/metadata/ */ 597 /* .../xfs/<dev>/error/metadata/ */
552 error = xfs_error_sysfs_init_class(mp, XFS_ERR_METADATA, 598 error = xfs_error_sysfs_init_class(mp, XFS_ERR_METADATA,
553 "metadata", &mp->m_error_meta_kobj, 599 "metadata", &mp->m_error_meta_kobj,