diff options
| -rw-r--r-- | fs/btrfs/ctree.h | 5 | ||||
| -rw-r--r-- | fs/btrfs/disk-io.c | 109 | ||||
| -rw-r--r-- | fs/btrfs/disk-io.h | 2 | ||||
| -rw-r--r-- | fs/btrfs/ioctl.c | 8 | ||||
| -rw-r--r-- | fs/btrfs/tree-log.c | 7 | ||||
| -rw-r--r-- | fs/btrfs/volumes.c | 30 |
6 files changed, 142 insertions, 19 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 50dcd0fbae11..1630be831210 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -1468,6 +1468,8 @@ struct btrfs_fs_info { | |||
| 1468 | 1468 | ||
| 1469 | /* next backup root to be overwritten */ | 1469 | /* next backup root to be overwritten */ |
| 1470 | int backup_root_index; | 1470 | int backup_root_index; |
| 1471 | |||
| 1472 | int num_tolerated_disk_barrier_failures; | ||
| 1471 | }; | 1473 | }; |
| 1472 | 1474 | ||
| 1473 | /* | 1475 | /* |
| @@ -3361,6 +3363,9 @@ void btrfs_inherit_iflags(struct inode *inode, struct inode *dir); | |||
| 3361 | int btrfs_defrag_file(struct inode *inode, struct file *file, | 3363 | int btrfs_defrag_file(struct inode *inode, struct file *file, |
| 3362 | struct btrfs_ioctl_defrag_range_args *range, | 3364 | struct btrfs_ioctl_defrag_range_args *range, |
| 3363 | u64 newer_than, unsigned long max_pages); | 3365 | u64 newer_than, unsigned long max_pages); |
| 3366 | void btrfs_get_block_group_info(struct list_head *groups_list, | ||
| 3367 | struct btrfs_ioctl_space_info *space); | ||
| 3368 | |||
| 3364 | /* file.c */ | 3369 | /* file.c */ |
| 3365 | int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, | 3370 | int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, |
| 3366 | struct inode *inode); | 3371 | struct inode *inode); |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index c69995556f61..835523687707 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -2505,6 +2505,8 @@ retry_root_backup: | |||
| 2505 | printk(KERN_ERR "Failed to read block groups: %d\n", ret); | 2505 | printk(KERN_ERR "Failed to read block groups: %d\n", ret); |
| 2506 | goto fail_block_groups; | 2506 | goto fail_block_groups; |
| 2507 | } | 2507 | } |
| 2508 | fs_info->num_tolerated_disk_barrier_failures = | ||
| 2509 | btrfs_calc_num_tolerated_disk_barrier_failures(fs_info); | ||
| 2508 | 2510 | ||
| 2509 | fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root, | 2511 | fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root, |
| 2510 | "btrfs-cleaner"); | 2512 | "btrfs-cleaner"); |
| @@ -2888,12 +2890,10 @@ static int write_dev_flush(struct btrfs_device *device, int wait) | |||
| 2888 | printk_in_rcu("btrfs: disabling barriers on dev %s\n", | 2890 | printk_in_rcu("btrfs: disabling barriers on dev %s\n", |
| 2889 | rcu_str_deref(device->name)); | 2891 | rcu_str_deref(device->name)); |
| 2890 | device->nobarriers = 1; | 2892 | device->nobarriers = 1; |
| 2891 | } | 2893 | } else if (!bio_flagged(bio, BIO_UPTODATE)) { |
| 2892 | if (!bio_flagged(bio, BIO_UPTODATE)) { | ||
| 2893 | ret = -EIO; | 2894 | ret = -EIO; |
| 2894 | if (!bio_flagged(bio, BIO_EOPNOTSUPP)) | 2895 | btrfs_dev_stat_inc_and_print(device, |
| 2895 | btrfs_dev_stat_inc_and_print(device, | 2896 | BTRFS_DEV_STAT_FLUSH_ERRS); |
| 2896 | BTRFS_DEV_STAT_FLUSH_ERRS); | ||
| 2897 | } | 2897 | } |
| 2898 | 2898 | ||
| 2899 | /* drop the reference from the wait == 0 run */ | 2899 | /* drop the reference from the wait == 0 run */ |
| @@ -2932,14 +2932,15 @@ static int barrier_all_devices(struct btrfs_fs_info *info) | |||
| 2932 | { | 2932 | { |
| 2933 | struct list_head *head; | 2933 | struct list_head *head; |
| 2934 | struct btrfs_device *dev; | 2934 | struct btrfs_device *dev; |
| 2935 | int errors = 0; | 2935 | int errors_send = 0; |
| 2936 | int errors_wait = 0; | ||
| 2936 | int ret; | 2937 | int ret; |
| 2937 | 2938 | ||
| 2938 | /* send down all the barriers */ | 2939 | /* send down all the barriers */ |
| 2939 | head = &info->fs_devices->devices; | 2940 | head = &info->fs_devices->devices; |
| 2940 | list_for_each_entry_rcu(dev, head, dev_list) { | 2941 | list_for_each_entry_rcu(dev, head, dev_list) { |
| 2941 | if (!dev->bdev) { | 2942 | if (!dev->bdev) { |
| 2942 | errors++; | 2943 | errors_send++; |
| 2943 | continue; | 2944 | continue; |
| 2944 | } | 2945 | } |
| 2945 | if (!dev->in_fs_metadata || !dev->writeable) | 2946 | if (!dev->in_fs_metadata || !dev->writeable) |
| @@ -2947,13 +2948,13 @@ static int barrier_all_devices(struct btrfs_fs_info *info) | |||
| 2947 | 2948 | ||
| 2948 | ret = write_dev_flush(dev, 0); | 2949 | ret = write_dev_flush(dev, 0); |
| 2949 | if (ret) | 2950 | if (ret) |
| 2950 | errors++; | 2951 | errors_send++; |
| 2951 | } | 2952 | } |
| 2952 | 2953 | ||
| 2953 | /* wait for all the barriers */ | 2954 | /* wait for all the barriers */ |
| 2954 | list_for_each_entry_rcu(dev, head, dev_list) { | 2955 | list_for_each_entry_rcu(dev, head, dev_list) { |
| 2955 | if (!dev->bdev) { | 2956 | if (!dev->bdev) { |
| 2956 | errors++; | 2957 | errors_wait++; |
| 2957 | continue; | 2958 | continue; |
| 2958 | } | 2959 | } |
| 2959 | if (!dev->in_fs_metadata || !dev->writeable) | 2960 | if (!dev->in_fs_metadata || !dev->writeable) |
| @@ -2961,13 +2962,87 @@ static int barrier_all_devices(struct btrfs_fs_info *info) | |||
| 2961 | 2962 | ||
| 2962 | ret = write_dev_flush(dev, 1); | 2963 | ret = write_dev_flush(dev, 1); |
| 2963 | if (ret) | 2964 | if (ret) |
| 2964 | errors++; | 2965 | errors_wait++; |
| 2965 | } | 2966 | } |
| 2966 | if (errors) | 2967 | if (errors_send > info->num_tolerated_disk_barrier_failures || |
| 2968 | errors_wait > info->num_tolerated_disk_barrier_failures) | ||
| 2967 | return -EIO; | 2969 | return -EIO; |
| 2968 | return 0; | 2970 | return 0; |
| 2969 | } | 2971 | } |
| 2970 | 2972 | ||
| 2973 | int btrfs_calc_num_tolerated_disk_barrier_failures( | ||
| 2974 | struct btrfs_fs_info *fs_info) | ||
| 2975 | { | ||
| 2976 | struct btrfs_ioctl_space_info space; | ||
| 2977 | struct btrfs_space_info *sinfo; | ||
| 2978 | u64 types[] = {BTRFS_BLOCK_GROUP_DATA, | ||
| 2979 | BTRFS_BLOCK_GROUP_SYSTEM, | ||
| 2980 | BTRFS_BLOCK_GROUP_METADATA, | ||
| 2981 | BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA}; | ||
| 2982 | int num_types = 4; | ||
| 2983 | int i; | ||
| 2984 | int c; | ||
| 2985 | int num_tolerated_disk_barrier_failures = | ||
| 2986 | (int)fs_info->fs_devices->num_devices; | ||
| 2987 | |||
| 2988 | for (i = 0; i < num_types; i++) { | ||
| 2989 | struct btrfs_space_info *tmp; | ||
| 2990 | |||
| 2991 | sinfo = NULL; | ||
| 2992 | rcu_read_lock(); | ||
| 2993 | list_for_each_entry_rcu(tmp, &fs_info->space_info, list) { | ||
| 2994 | if (tmp->flags == types[i]) { | ||
| 2995 | sinfo = tmp; | ||
| 2996 | break; | ||
| 2997 | } | ||
| 2998 | } | ||
| 2999 | rcu_read_unlock(); | ||
| 3000 | |||
| 3001 | if (!sinfo) | ||
| 3002 | continue; | ||
| 3003 | |||
| 3004 | down_read(&sinfo->groups_sem); | ||
| 3005 | for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) { | ||
| 3006 | if (!list_empty(&sinfo->block_groups[c])) { | ||
| 3007 | u64 flags; | ||
| 3008 | |||
| 3009 | btrfs_get_block_group_info( | ||
| 3010 | &sinfo->block_groups[c], &space); | ||
| 3011 | if (space.total_bytes == 0 || | ||
| 3012 | space.used_bytes == 0) | ||
| 3013 | continue; | ||
| 3014 | flags = space.flags; | ||
| 3015 | /* | ||
| 3016 | * return | ||
| 3017 | * 0: if dup, single or RAID0 is configured for | ||
| 3018 | * any of metadata, system or data, else | ||
| 3019 | * 1: if RAID5 is configured, or if RAID1 or | ||
| 3020 | * RAID10 is configured and only two mirrors | ||
| 3021 | * are used, else | ||
| 3022 | * 2: if RAID6 is configured, else | ||
| 3023 | * num_mirrors - 1: if RAID1 or RAID10 is | ||
| 3024 | * configured and more than | ||
| 3025 | * 2 mirrors are used. | ||
| 3026 | */ | ||
| 3027 | if (num_tolerated_disk_barrier_failures > 0 && | ||
| 3028 | ((flags & (BTRFS_BLOCK_GROUP_DUP | | ||
| 3029 | BTRFS_BLOCK_GROUP_RAID0)) || | ||
| 3030 | ((flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) | ||
| 3031 | == 0))) | ||
| 3032 | num_tolerated_disk_barrier_failures = 0; | ||
| 3033 | else if (num_tolerated_disk_barrier_failures > 1 | ||
| 3034 | && | ||
| 3035 | (flags & (BTRFS_BLOCK_GROUP_RAID1 | | ||
| 3036 | BTRFS_BLOCK_GROUP_RAID10))) | ||
| 3037 | num_tolerated_disk_barrier_failures = 1; | ||
| 3038 | } | ||
| 3039 | } | ||
| 3040 | up_read(&sinfo->groups_sem); | ||
| 3041 | } | ||
| 3042 | |||
| 3043 | return num_tolerated_disk_barrier_failures; | ||
| 3044 | } | ||
| 3045 | |||
| 2971 | int write_all_supers(struct btrfs_root *root, int max_mirrors) | 3046 | int write_all_supers(struct btrfs_root *root, int max_mirrors) |
| 2972 | { | 3047 | { |
| 2973 | struct list_head *head; | 3048 | struct list_head *head; |
| @@ -2990,8 +3065,16 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors) | |||
| 2990 | mutex_lock(&root->fs_info->fs_devices->device_list_mutex); | 3065 | mutex_lock(&root->fs_info->fs_devices->device_list_mutex); |
| 2991 | head = &root->fs_info->fs_devices->devices; | 3066 | head = &root->fs_info->fs_devices->devices; |
| 2992 | 3067 | ||
| 2993 | if (do_barriers) | 3068 | if (do_barriers) { |
| 2994 | barrier_all_devices(root->fs_info); | 3069 | ret = barrier_all_devices(root->fs_info); |
| 3070 | if (ret) { | ||
| 3071 | mutex_unlock( | ||
| 3072 | &root->fs_info->fs_devices->device_list_mutex); | ||
| 3073 | btrfs_error(root->fs_info, ret, | ||
| 3074 | "errors while submitting device barriers."); | ||
| 3075 | return ret; | ||
| 3076 | } | ||
| 3077 | } | ||
| 2995 | 3078 | ||
| 2996 | list_for_each_entry_rcu(dev, head, dev_list) { | 3079 | list_for_each_entry_rcu(dev, head, dev_list) { |
| 2997 | if (!dev->bdev) { | 3080 | if (!dev->bdev) { |
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index c5b00a735fef..2025a9132c16 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
| @@ -95,6 +95,8 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, | |||
| 95 | u64 objectid); | 95 | u64 objectid); |
| 96 | int btree_lock_page_hook(struct page *page, void *data, | 96 | int btree_lock_page_hook(struct page *page, void *data, |
| 97 | void (*flush_fn)(void *)); | 97 | void (*flush_fn)(void *)); |
| 98 | int btrfs_calc_num_tolerated_disk_barrier_failures( | ||
| 99 | struct btrfs_fs_info *fs_info); | ||
| 98 | 100 | ||
| 99 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | 101 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
| 100 | void btrfs_init_lockdep(void); | 102 | void btrfs_init_lockdep(void); |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index d6836af6d60f..f5a2e6c4320a 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
| @@ -2875,8 +2875,8 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) | |||
| 2875 | return 0; | 2875 | return 0; |
| 2876 | } | 2876 | } |
| 2877 | 2877 | ||
| 2878 | static void get_block_group_info(struct list_head *groups_list, | 2878 | void btrfs_get_block_group_info(struct list_head *groups_list, |
| 2879 | struct btrfs_ioctl_space_info *space) | 2879 | struct btrfs_ioctl_space_info *space) |
| 2880 | { | 2880 | { |
| 2881 | struct btrfs_block_group_cache *block_group; | 2881 | struct btrfs_block_group_cache *block_group; |
| 2882 | 2882 | ||
| @@ -2984,8 +2984,8 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) | |||
| 2984 | down_read(&info->groups_sem); | 2984 | down_read(&info->groups_sem); |
| 2985 | for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) { | 2985 | for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) { |
| 2986 | if (!list_empty(&info->block_groups[c])) { | 2986 | if (!list_empty(&info->block_groups[c])) { |
| 2987 | get_block_group_info(&info->block_groups[c], | 2987 | btrfs_get_block_group_info( |
| 2988 | &space); | 2988 | &info->block_groups[c], &space); |
| 2989 | memcpy(dest, &space, sizeof(space)); | 2989 | memcpy(dest, &space, sizeof(space)); |
| 2990 | dest++; | 2990 | dest++; |
| 2991 | space_args.total_spaces++; | 2991 | space_args.total_spaces++; |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 47911fd18310..67eab2d4d8a9 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
| @@ -2425,9 +2425,12 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
| 2425 | * in and cause problems either. | 2425 | * in and cause problems either. |
| 2426 | */ | 2426 | */ |
| 2427 | btrfs_scrub_pause_super(root); | 2427 | btrfs_scrub_pause_super(root); |
| 2428 | write_ctree_super(trans, root->fs_info->tree_root, 1); | 2428 | ret = write_ctree_super(trans, root->fs_info->tree_root, 1); |
| 2429 | btrfs_scrub_continue_super(root); | 2429 | btrfs_scrub_continue_super(root); |
| 2430 | ret = 0; | 2430 | if (ret) { |
| 2431 | btrfs_abort_transaction(trans, root, ret); | ||
| 2432 | goto out_wake_log_root; | ||
| 2433 | } | ||
| 2431 | 2434 | ||
| 2432 | mutex_lock(&root->log_mutex); | 2435 | mutex_lock(&root->log_mutex); |
| 2433 | if (root->last_log_commit < log_transid) | 2436 | if (root->last_log_commit < log_transid) |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index dfe5e3a22f55..029b903a4ae3 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
| @@ -1475,6 +1475,9 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
| 1475 | free_fs_devices(cur_devices); | 1475 | free_fs_devices(cur_devices); |
| 1476 | } | 1476 | } |
| 1477 | 1477 | ||
| 1478 | root->fs_info->num_tolerated_disk_barrier_failures = | ||
| 1479 | btrfs_calc_num_tolerated_disk_barrier_failures(root->fs_info); | ||
| 1480 | |||
| 1478 | /* | 1481 | /* |
| 1479 | * at this point, the device is zero sized. We want to | 1482 | * at this point, the device is zero sized. We want to |
| 1480 | * remove it from the devices list and zero out the old super | 1483 | * remove it from the devices list and zero out the old super |
| @@ -1799,6 +1802,8 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) | |||
| 1799 | btrfs_clear_space_info_full(root->fs_info); | 1802 | btrfs_clear_space_info_full(root->fs_info); |
| 1800 | 1803 | ||
| 1801 | unlock_chunks(root); | 1804 | unlock_chunks(root); |
| 1805 | root->fs_info->num_tolerated_disk_barrier_failures = | ||
| 1806 | btrfs_calc_num_tolerated_disk_barrier_failures(root->fs_info); | ||
| 1802 | ret = btrfs_commit_transaction(trans, root); | 1807 | ret = btrfs_commit_transaction(trans, root); |
| 1803 | 1808 | ||
| 1804 | if (seeding_dev) { | 1809 | if (seeding_dev) { |
| @@ -2809,6 +2814,26 @@ int btrfs_balance(struct btrfs_balance_control *bctl, | |||
| 2809 | } | 2814 | } |
| 2810 | } | 2815 | } |
| 2811 | 2816 | ||
| 2817 | if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) { | ||
| 2818 | int num_tolerated_disk_barrier_failures; | ||
| 2819 | u64 target = bctl->sys.target; | ||
| 2820 | |||
| 2821 | num_tolerated_disk_barrier_failures = | ||
| 2822 | btrfs_calc_num_tolerated_disk_barrier_failures(fs_info); | ||
| 2823 | if (num_tolerated_disk_barrier_failures > 0 && | ||
| 2824 | (target & | ||
| 2825 | (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID0 | | ||
| 2826 | BTRFS_AVAIL_ALLOC_BIT_SINGLE))) | ||
| 2827 | num_tolerated_disk_barrier_failures = 0; | ||
| 2828 | else if (num_tolerated_disk_barrier_failures > 1 && | ||
| 2829 | (target & | ||
| 2830 | (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10))) | ||
| 2831 | num_tolerated_disk_barrier_failures = 1; | ||
| 2832 | |||
| 2833 | fs_info->num_tolerated_disk_barrier_failures = | ||
| 2834 | num_tolerated_disk_barrier_failures; | ||
| 2835 | } | ||
| 2836 | |||
| 2812 | ret = insert_balance_item(fs_info->tree_root, bctl); | 2837 | ret = insert_balance_item(fs_info->tree_root, bctl); |
| 2813 | if (ret && ret != -EEXIST) | 2838 | if (ret && ret != -EEXIST) |
| 2814 | goto out; | 2839 | goto out; |
| @@ -2841,6 +2866,11 @@ int btrfs_balance(struct btrfs_balance_control *bctl, | |||
| 2841 | __cancel_balance(fs_info); | 2866 | __cancel_balance(fs_info); |
| 2842 | } | 2867 | } |
| 2843 | 2868 | ||
| 2869 | if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) { | ||
| 2870 | fs_info->num_tolerated_disk_barrier_failures = | ||
| 2871 | btrfs_calc_num_tolerated_disk_barrier_failures(fs_info); | ||
| 2872 | } | ||
| 2873 | |||
| 2844 | wake_up(&fs_info->balance_wait_q); | 2874 | wake_up(&fs_info->balance_wait_q); |
| 2845 | 2875 | ||
| 2846 | return ret; | 2876 | return ret; |
