aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorStefan Behrens <sbehrens@giantdisaster.de>2012-08-01 07:45:52 -0400
committerChris Mason <chris.mason@oracle.com>2012-08-28 16:53:38 -0400
commit68ce9682a4bb95d6be5529cb57214bf2a1b7d20e (patch)
tree65e5b635d5a0071afad76668b9dbefc07459db27 /fs
parentae1e206b806ccc490dadff59af8a7a2477b32884 (diff)
Btrfs: remove superblock writing after fatal error
With commit acce952b0, btrfs was changed to flag the filesystem with BTRFS_SUPER_FLAG_ERROR and switch to read-only mode after a fatal error happened like a write I/O errors of all mirrors. In such situations, on unmount, the superblock is written in btrfs_error_commit_super(). This is done with the intention to be able to evaluate the error flag on the next mount. A warning is printed in this case during the next mount and the log tree is ignored. The issue is that it is possible that the superblock points to a root that was not written (due to write I/O errors). The result is that the filesystem cannot be mounted. btrfsck also does not start and all the other btrfs-progs tools fail to start as well. However, mount -o recovery is working well and does the right things to recover the filesystem (i.e., don't use the log root, clear the free space cache and use the next mountable root that is stored in the root backup array). This patch removes the writing of the superblock when BTRFS_SUPER_FLAG_ERROR is set, and removes the handling of the error flag in the mount function. These lines can be used to reproduce the issue (using /dev/sdm): SCRATCH_DEV=/dev/sdm SCRATCH_MNT=/mnt echo 0 25165824 linear $SCRATCH_DEV 0 | dmsetup create foo ls -alLF /dev/mapper/foo mkfs.btrfs /dev/mapper/foo mount /dev/mapper/foo $SCRATCH_MNT echo bar > $SCRATCH_MNT/foo sync echo 0 25165824 error | dmsetup reload foo dmsetup resume foo ls -alF $SCRATCH_MNT touch $SCRATCH_MNT/1 ls -alF $SCRATCH_MNT sleep 35 echo 0 25165824 linear $SCRATCH_DEV 0 | dmsetup reload foo dmsetup resume foo sleep 1 umount $SCRATCH_MNT btrfsck /dev/mapper/foo dmsetup remove foo Signed-off-by: Stefan Behrens <sbehrens@giantdisaster.de> Signed-off-by: Jan Schmidt <list.btrfs@jan-o-sch.net>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/disk-io.c36
-rw-r--r--fs/btrfs/disk-io.h2
2 files changed, 5 insertions, 33 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index dd86a5d88428..3c4c4397f470 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2527,8 +2527,7 @@ retry_root_backup:
2527 goto fail_trans_kthread; 2527 goto fail_trans_kthread;
2528 2528
2529 /* do not make disk changes in broken FS */ 2529 /* do not make disk changes in broken FS */
2530 if (btrfs_super_log_root(disk_super) != 0 && 2530 if (btrfs_super_log_root(disk_super) != 0) {
2531 !(fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)) {
2532 u64 bytenr = btrfs_super_log_root(disk_super); 2531 u64 bytenr = btrfs_super_log_root(disk_super);
2533 2532
2534 if (fs_devices->rw_devices == 0) { 2533 if (fs_devices->rw_devices == 0) {
@@ -3188,30 +3187,14 @@ int close_ctree(struct btrfs_root *root)
3188 /* clear out the rbtree of defraggable inodes */ 3187 /* clear out the rbtree of defraggable inodes */
3189 btrfs_run_defrag_inodes(fs_info); 3188 btrfs_run_defrag_inodes(fs_info);
3190 3189
3191 /*
3192 * Here come 2 situations when btrfs is broken to flip readonly:
3193 *
3194 * 1. when btrfs flips readonly somewhere else before
3195 * btrfs_commit_super, sb->s_flags has MS_RDONLY flag,
3196 * and btrfs will skip to write sb directly to keep
3197 * ERROR state on disk.
3198 *
3199 * 2. when btrfs flips readonly just in btrfs_commit_super,
3200 * and in such case, btrfs cannot write sb via btrfs_commit_super,
3201 * and since fs_state has been set BTRFS_SUPER_FLAG_ERROR flag,
3202 * btrfs will cleanup all FS resources first and write sb then.
3203 */
3204 if (!(fs_info->sb->s_flags & MS_RDONLY)) { 3190 if (!(fs_info->sb->s_flags & MS_RDONLY)) {
3205 ret = btrfs_commit_super(root); 3191 ret = btrfs_commit_super(root);
3206 if (ret) 3192 if (ret)
3207 printk(KERN_ERR "btrfs: commit super ret %d\n", ret); 3193 printk(KERN_ERR "btrfs: commit super ret %d\n", ret);
3208 } 3194 }
3209 3195
3210 if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { 3196 if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
3211 ret = btrfs_error_commit_super(root); 3197 btrfs_error_commit_super(root);
3212 if (ret)
3213 printk(KERN_ERR "btrfs: commit super ret %d\n", ret);
3214 }
3215 3198
3216 btrfs_put_block_group_cache(fs_info); 3199 btrfs_put_block_group_cache(fs_info);
3217 3200
@@ -3433,18 +3416,11 @@ static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
3433 if (read_only) 3416 if (read_only)
3434 return 0; 3417 return 0;
3435 3418
3436 if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
3437 printk(KERN_WARNING "warning: mount fs with errors, "
3438 "running btrfsck is recommended\n");
3439 }
3440
3441 return 0; 3419 return 0;
3442} 3420}
3443 3421
3444int btrfs_error_commit_super(struct btrfs_root *root) 3422void btrfs_error_commit_super(struct btrfs_root *root)
3445{ 3423{
3446 int ret;
3447
3448 mutex_lock(&root->fs_info->cleaner_mutex); 3424 mutex_lock(&root->fs_info->cleaner_mutex);
3449 btrfs_run_delayed_iputs(root); 3425 btrfs_run_delayed_iputs(root);
3450 mutex_unlock(&root->fs_info->cleaner_mutex); 3426 mutex_unlock(&root->fs_info->cleaner_mutex);
@@ -3454,10 +3430,6 @@ int btrfs_error_commit_super(struct btrfs_root *root)
3454 3430
3455 /* cleanup FS via transaction */ 3431 /* cleanup FS via transaction */
3456 btrfs_cleanup_transaction(root); 3432 btrfs_cleanup_transaction(root);
3457
3458 ret = write_ctree_super(NULL, root, 0);
3459
3460 return ret;
3461} 3433}
3462 3434
3463static void btrfs_destroy_ordered_operations(struct btrfs_root *root) 3435static void btrfs_destroy_ordered_operations(struct btrfs_root *root)
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index 95e147eea239..c5b00a735fef 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -54,7 +54,7 @@ int write_ctree_super(struct btrfs_trans_handle *trans,
54 struct btrfs_root *root, int max_mirrors); 54 struct btrfs_root *root, int max_mirrors);
55struct buffer_head *btrfs_read_dev_super(struct block_device *bdev); 55struct buffer_head *btrfs_read_dev_super(struct block_device *bdev);
56int btrfs_commit_super(struct btrfs_root *root); 56int btrfs_commit_super(struct btrfs_root *root);
57int btrfs_error_commit_super(struct btrfs_root *root); 57void btrfs_error_commit_super(struct btrfs_root *root);
58struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, 58struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
59 u64 bytenr, u32 blocksize); 59 u64 bytenr, u32 blocksize);
60struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, 60struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,