diff options
| -rw-r--r-- | fs/btrfs/extent-tree.c | 6 | ||||
| -rw-r--r-- | fs/btrfs/extent_io.c | 10 | ||||
| -rw-r--r-- | fs/btrfs/ordered-data.c | 6 | ||||
| -rw-r--r-- | fs/btrfs/ordered-data.h | 2 | ||||
| -rw-r--r-- | fs/btrfs/reada.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/scrub.c | 50 | ||||
| -rw-r--r-- | fs/btrfs/volumes.c | 32 |
7 files changed, 91 insertions, 17 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index a400951e8678..689d25ac6a68 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
| @@ -2042,6 +2042,11 @@ int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr, | |||
| 2042 | struct btrfs_bio *bbio = NULL; | 2042 | struct btrfs_bio *bbio = NULL; |
| 2043 | 2043 | ||
| 2044 | 2044 | ||
| 2045 | /* | ||
| 2046 | * Avoid races with device replace and make sure our bbio has devices | ||
| 2047 | * associated to its stripes that don't go away while we are discarding. | ||
| 2048 | */ | ||
| 2049 | btrfs_bio_counter_inc_blocked(root->fs_info); | ||
| 2045 | /* Tell the block device(s) that the sectors can be discarded */ | 2050 | /* Tell the block device(s) that the sectors can be discarded */ |
| 2046 | ret = btrfs_map_block(root->fs_info, REQ_DISCARD, | 2051 | ret = btrfs_map_block(root->fs_info, REQ_DISCARD, |
| 2047 | bytenr, &num_bytes, &bbio, 0); | 2052 | bytenr, &num_bytes, &bbio, 0); |
| @@ -2074,6 +2079,7 @@ int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr, | |||
| 2074 | } | 2079 | } |
| 2075 | btrfs_put_bbio(bbio); | 2080 | btrfs_put_bbio(bbio); |
| 2076 | } | 2081 | } |
| 2082 | btrfs_bio_counter_dec(root->fs_info); | ||
| 2077 | 2083 | ||
| 2078 | if (actual_bytes) | 2084 | if (actual_bytes) |
| 2079 | *actual_bytes = discarded_bytes; | 2085 | *actual_bytes = discarded_bytes; |
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 3cd57825c75f..6e953de83f08 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
| @@ -2025,9 +2025,16 @@ int repair_io_failure(struct inode *inode, u64 start, u64 length, u64 logical, | |||
| 2025 | bio->bi_iter.bi_size = 0; | 2025 | bio->bi_iter.bi_size = 0; |
| 2026 | map_length = length; | 2026 | map_length = length; |
| 2027 | 2027 | ||
| 2028 | /* | ||
| 2029 | * Avoid races with device replace and make sure our bbio has devices | ||
| 2030 | * associated to its stripes that don't go away while we are doing the | ||
| 2031 | * read repair operation. | ||
| 2032 | */ | ||
| 2033 | btrfs_bio_counter_inc_blocked(fs_info); | ||
| 2028 | ret = btrfs_map_block(fs_info, WRITE, logical, | 2034 | ret = btrfs_map_block(fs_info, WRITE, logical, |
| 2029 | &map_length, &bbio, mirror_num); | 2035 | &map_length, &bbio, mirror_num); |
| 2030 | if (ret) { | 2036 | if (ret) { |
| 2037 | btrfs_bio_counter_dec(fs_info); | ||
| 2031 | bio_put(bio); | 2038 | bio_put(bio); |
| 2032 | return -EIO; | 2039 | return -EIO; |
| 2033 | } | 2040 | } |
| @@ -2037,6 +2044,7 @@ int repair_io_failure(struct inode *inode, u64 start, u64 length, u64 logical, | |||
| 2037 | dev = bbio->stripes[mirror_num-1].dev; | 2044 | dev = bbio->stripes[mirror_num-1].dev; |
| 2038 | btrfs_put_bbio(bbio); | 2045 | btrfs_put_bbio(bbio); |
| 2039 | if (!dev || !dev->bdev || !dev->writeable) { | 2046 | if (!dev || !dev->bdev || !dev->writeable) { |
| 2047 | btrfs_bio_counter_dec(fs_info); | ||
| 2040 | bio_put(bio); | 2048 | bio_put(bio); |
| 2041 | return -EIO; | 2049 | return -EIO; |
| 2042 | } | 2050 | } |
| @@ -2045,6 +2053,7 @@ int repair_io_failure(struct inode *inode, u64 start, u64 length, u64 logical, | |||
| 2045 | 2053 | ||
| 2046 | if (btrfsic_submit_bio_wait(WRITE_SYNC, bio)) { | 2054 | if (btrfsic_submit_bio_wait(WRITE_SYNC, bio)) { |
| 2047 | /* try to remap that extent elsewhere? */ | 2055 | /* try to remap that extent elsewhere? */ |
| 2056 | btrfs_bio_counter_dec(fs_info); | ||
| 2048 | bio_put(bio); | 2057 | bio_put(bio); |
| 2049 | btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS); | 2058 | btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS); |
| 2050 | return -EIO; | 2059 | return -EIO; |
| @@ -2054,6 +2063,7 @@ int repair_io_failure(struct inode *inode, u64 start, u64 length, u64 logical, | |||
| 2054 | "read error corrected: ino %llu off %llu (dev %s sector %llu)", | 2063 | "read error corrected: ino %llu off %llu (dev %s sector %llu)", |
| 2055 | btrfs_ino(inode), start, | 2064 | btrfs_ino(inode), start, |
| 2056 | rcu_str_deref(dev->name), sector); | 2065 | rcu_str_deref(dev->name), sector); |
| 2066 | btrfs_bio_counter_dec(fs_info); | ||
| 2057 | bio_put(bio); | 2067 | bio_put(bio); |
| 2058 | return 0; | 2068 | return 0; |
| 2059 | } | 2069 | } |
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 559170464d7c..e96634a725c3 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c | |||
| @@ -718,12 +718,13 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr, | |||
| 718 | return count; | 718 | return count; |
| 719 | } | 719 | } |
| 720 | 720 | ||
| 721 | void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr, | 721 | int btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr, |
| 722 | const u64 range_start, const u64 range_len) | 722 | const u64 range_start, const u64 range_len) |
| 723 | { | 723 | { |
| 724 | struct btrfs_root *root; | 724 | struct btrfs_root *root; |
| 725 | struct list_head splice; | 725 | struct list_head splice; |
| 726 | int done; | 726 | int done; |
| 727 | int total_done = 0; | ||
| 727 | 728 | ||
| 728 | INIT_LIST_HEAD(&splice); | 729 | INIT_LIST_HEAD(&splice); |
| 729 | 730 | ||
| @@ -742,6 +743,7 @@ void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr, | |||
| 742 | done = btrfs_wait_ordered_extents(root, nr, | 743 | done = btrfs_wait_ordered_extents(root, nr, |
| 743 | range_start, range_len); | 744 | range_start, range_len); |
| 744 | btrfs_put_fs_root(root); | 745 | btrfs_put_fs_root(root); |
| 746 | total_done += done; | ||
| 745 | 747 | ||
| 746 | spin_lock(&fs_info->ordered_root_lock); | 748 | spin_lock(&fs_info->ordered_root_lock); |
| 747 | if (nr != -1) { | 749 | if (nr != -1) { |
| @@ -752,6 +754,8 @@ void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr, | |||
| 752 | list_splice_tail(&splice, &fs_info->ordered_roots); | 754 | list_splice_tail(&splice, &fs_info->ordered_roots); |
| 753 | spin_unlock(&fs_info->ordered_root_lock); | 755 | spin_unlock(&fs_info->ordered_root_lock); |
| 754 | mutex_unlock(&fs_info->ordered_operations_mutex); | 756 | mutex_unlock(&fs_info->ordered_operations_mutex); |
| 757 | |||
| 758 | return total_done; | ||
| 755 | } | 759 | } |
| 756 | 760 | ||
| 757 | /* | 761 | /* |
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index 2049c9be85ee..451507776ff5 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h | |||
| @@ -199,7 +199,7 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, | |||
| 199 | u32 *sum, int len); | 199 | u32 *sum, int len); |
| 200 | int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr, | 200 | int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr, |
| 201 | const u64 range_start, const u64 range_len); | 201 | const u64 range_start, const u64 range_len); |
| 202 | void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr, | 202 | int btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr, |
| 203 | const u64 range_start, const u64 range_len); | 203 | const u64 range_start, const u64 range_len); |
| 204 | void btrfs_get_logged_extents(struct inode *inode, | 204 | void btrfs_get_logged_extents(struct inode *inode, |
| 205 | struct list_head *logged_list, | 205 | struct list_head *logged_list, |
diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c index 298631eaee78..8428db7cd88f 100644 --- a/fs/btrfs/reada.c +++ b/fs/btrfs/reada.c | |||
| @@ -761,12 +761,14 @@ static void __reada_start_machine(struct btrfs_fs_info *fs_info) | |||
| 761 | 761 | ||
| 762 | do { | 762 | do { |
| 763 | enqueued = 0; | 763 | enqueued = 0; |
| 764 | mutex_lock(&fs_devices->device_list_mutex); | ||
| 764 | list_for_each_entry(device, &fs_devices->devices, dev_list) { | 765 | list_for_each_entry(device, &fs_devices->devices, dev_list) { |
| 765 | if (atomic_read(&device->reada_in_flight) < | 766 | if (atomic_read(&device->reada_in_flight) < |
| 766 | MAX_IN_FLIGHT) | 767 | MAX_IN_FLIGHT) |
| 767 | enqueued += reada_start_machine_dev(fs_info, | 768 | enqueued += reada_start_machine_dev(fs_info, |
| 768 | device); | 769 | device); |
| 769 | } | 770 | } |
| 771 | mutex_unlock(&fs_devices->device_list_mutex); | ||
| 770 | total += enqueued; | 772 | total += enqueued; |
| 771 | } while (enqueued && total < 10000); | 773 | } while (enqueued && total < 10000); |
| 772 | 774 | ||
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 46d847f66e4b..70427ef66b04 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c | |||
| @@ -3582,6 +3582,46 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, | |||
| 3582 | */ | 3582 | */ |
| 3583 | scrub_pause_on(fs_info); | 3583 | scrub_pause_on(fs_info); |
| 3584 | ret = btrfs_inc_block_group_ro(root, cache); | 3584 | ret = btrfs_inc_block_group_ro(root, cache); |
| 3585 | if (!ret && is_dev_replace) { | ||
| 3586 | /* | ||
| 3587 | * If we are doing a device replace wait for any tasks | ||
| 3588 | * that started dellaloc right before we set the block | ||
| 3589 | * group to RO mode, as they might have just allocated | ||
| 3590 | * an extent from it or decided they could do a nocow | ||
| 3591 | * write. And if any such tasks did that, wait for their | ||
| 3592 | * ordered extents to complete and then commit the | ||
| 3593 | * current transaction, so that we can later see the new | ||
| 3594 | * extent items in the extent tree - the ordered extents | ||
| 3595 | * create delayed data references (for cow writes) when | ||
| 3596 | * they complete, which will be run and insert the | ||
| 3597 | * corresponding extent items into the extent tree when | ||
| 3598 | * we commit the transaction they used when running | ||
| 3599 | * inode.c:btrfs_finish_ordered_io(). We later use | ||
| 3600 | * the commit root of the extent tree to find extents | ||
| 3601 | * to copy from the srcdev into the tgtdev, and we don't | ||
| 3602 | * want to miss any new extents. | ||
| 3603 | */ | ||
| 3604 | btrfs_wait_block_group_reservations(cache); | ||
| 3605 | btrfs_wait_nocow_writers(cache); | ||
| 3606 | ret = btrfs_wait_ordered_roots(fs_info, -1, | ||
| 3607 | cache->key.objectid, | ||
| 3608 | cache->key.offset); | ||
| 3609 | if (ret > 0) { | ||
| 3610 | struct btrfs_trans_handle *trans; | ||
| 3611 | |||
| 3612 | trans = btrfs_join_transaction(root); | ||
| 3613 | if (IS_ERR(trans)) | ||
| 3614 | ret = PTR_ERR(trans); | ||
| 3615 | else | ||
| 3616 | ret = btrfs_commit_transaction(trans, | ||
| 3617 | root); | ||
| 3618 | if (ret) { | ||
| 3619 | scrub_pause_off(fs_info); | ||
| 3620 | btrfs_put_block_group(cache); | ||
| 3621 | break; | ||
| 3622 | } | ||
| 3623 | } | ||
| 3624 | } | ||
| 3585 | scrub_pause_off(fs_info); | 3625 | scrub_pause_off(fs_info); |
| 3586 | 3626 | ||
| 3587 | if (ret == 0) { | 3627 | if (ret == 0) { |
| @@ -3602,9 +3642,11 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, | |||
| 3602 | break; | 3642 | break; |
| 3603 | } | 3643 | } |
| 3604 | 3644 | ||
| 3645 | btrfs_dev_replace_lock(&fs_info->dev_replace, 1); | ||
| 3605 | dev_replace->cursor_right = found_key.offset + length; | 3646 | dev_replace->cursor_right = found_key.offset + length; |
| 3606 | dev_replace->cursor_left = found_key.offset; | 3647 | dev_replace->cursor_left = found_key.offset; |
| 3607 | dev_replace->item_needs_writeback = 1; | 3648 | dev_replace->item_needs_writeback = 1; |
| 3649 | btrfs_dev_replace_unlock(&fs_info->dev_replace, 1); | ||
| 3608 | ret = scrub_chunk(sctx, scrub_dev, chunk_offset, length, | 3650 | ret = scrub_chunk(sctx, scrub_dev, chunk_offset, length, |
| 3609 | found_key.offset, cache, is_dev_replace); | 3651 | found_key.offset, cache, is_dev_replace); |
| 3610 | 3652 | ||
| @@ -3640,6 +3682,11 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, | |||
| 3640 | 3682 | ||
| 3641 | scrub_pause_off(fs_info); | 3683 | scrub_pause_off(fs_info); |
| 3642 | 3684 | ||
| 3685 | btrfs_dev_replace_lock(&fs_info->dev_replace, 1); | ||
| 3686 | dev_replace->cursor_left = dev_replace->cursor_right; | ||
| 3687 | dev_replace->item_needs_writeback = 1; | ||
| 3688 | btrfs_dev_replace_unlock(&fs_info->dev_replace, 1); | ||
| 3689 | |||
| 3643 | if (ro_set) | 3690 | if (ro_set) |
| 3644 | btrfs_dec_block_group_ro(root, cache); | 3691 | btrfs_dec_block_group_ro(root, cache); |
| 3645 | 3692 | ||
| @@ -3677,9 +3724,6 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, | |||
| 3677 | ret = -ENOMEM; | 3724 | ret = -ENOMEM; |
| 3678 | break; | 3725 | break; |
| 3679 | } | 3726 | } |
| 3680 | |||
| 3681 | dev_replace->cursor_left = dev_replace->cursor_right; | ||
| 3682 | dev_replace->item_needs_writeback = 1; | ||
| 3683 | skip: | 3727 | skip: |
| 3684 | key.offset = found_key.offset + length; | 3728 | key.offset = found_key.offset + length; |
| 3685 | btrfs_release_path(path); | 3729 | btrfs_release_path(path); |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 9c01824eef08..765aabd9145f 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
| @@ -2761,6 +2761,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans, | |||
| 2761 | u64 dev_extent_len = 0; | 2761 | u64 dev_extent_len = 0; |
| 2762 | u64 chunk_objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; | 2762 | u64 chunk_objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; |
| 2763 | int i, ret = 0; | 2763 | int i, ret = 0; |
| 2764 | struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; | ||
| 2764 | 2765 | ||
| 2765 | /* Just in case */ | 2766 | /* Just in case */ |
| 2766 | root = root->fs_info->chunk_root; | 2767 | root = root->fs_info->chunk_root; |
| @@ -2787,12 +2788,19 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans, | |||
| 2787 | check_system_chunk(trans, extent_root, map->type); | 2788 | check_system_chunk(trans, extent_root, map->type); |
| 2788 | unlock_chunks(root->fs_info->chunk_root); | 2789 | unlock_chunks(root->fs_info->chunk_root); |
| 2789 | 2790 | ||
| 2791 | /* | ||
| 2792 | * Take the device list mutex to prevent races with the final phase of | ||
| 2793 | * a device replace operation that replaces the device object associated | ||
| 2794 | * with map stripes (dev-replace.c:btrfs_dev_replace_finishing()). | ||
| 2795 | */ | ||
| 2796 | mutex_lock(&fs_devices->device_list_mutex); | ||
| 2790 | for (i = 0; i < map->num_stripes; i++) { | 2797 | for (i = 0; i < map->num_stripes; i++) { |
| 2791 | struct btrfs_device *device = map->stripes[i].dev; | 2798 | struct btrfs_device *device = map->stripes[i].dev; |
| 2792 | ret = btrfs_free_dev_extent(trans, device, | 2799 | ret = btrfs_free_dev_extent(trans, device, |
| 2793 | map->stripes[i].physical, | 2800 | map->stripes[i].physical, |
| 2794 | &dev_extent_len); | 2801 | &dev_extent_len); |
| 2795 | if (ret) { | 2802 | if (ret) { |
| 2803 | mutex_unlock(&fs_devices->device_list_mutex); | ||
| 2796 | btrfs_abort_transaction(trans, root, ret); | 2804 | btrfs_abort_transaction(trans, root, ret); |
| 2797 | goto out; | 2805 | goto out; |
| 2798 | } | 2806 | } |
| @@ -2811,11 +2819,14 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans, | |||
| 2811 | if (map->stripes[i].dev) { | 2819 | if (map->stripes[i].dev) { |
| 2812 | ret = btrfs_update_device(trans, map->stripes[i].dev); | 2820 | ret = btrfs_update_device(trans, map->stripes[i].dev); |
| 2813 | if (ret) { | 2821 | if (ret) { |
| 2822 | mutex_unlock(&fs_devices->device_list_mutex); | ||
| 2814 | btrfs_abort_transaction(trans, root, ret); | 2823 | btrfs_abort_transaction(trans, root, ret); |
| 2815 | goto out; | 2824 | goto out; |
| 2816 | } | 2825 | } |
| 2817 | } | 2826 | } |
| 2818 | } | 2827 | } |
| 2828 | mutex_unlock(&fs_devices->device_list_mutex); | ||
| 2829 | |||
| 2819 | ret = btrfs_free_chunk(trans, root, chunk_objectid, chunk_offset); | 2830 | ret = btrfs_free_chunk(trans, root, chunk_objectid, chunk_offset); |
| 2820 | if (ret) { | 2831 | if (ret) { |
| 2821 | btrfs_abort_transaction(trans, root, ret); | 2832 | btrfs_abort_transaction(trans, root, ret); |
| @@ -5762,20 +5773,17 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, | |||
| 5762 | } | 5773 | } |
| 5763 | } | 5774 | } |
| 5764 | if (found) { | 5775 | if (found) { |
| 5765 | if (physical_of_found + map->stripe_len <= | 5776 | struct btrfs_bio_stripe *tgtdev_stripe = |
| 5766 | dev_replace->cursor_left) { | 5777 | bbio->stripes + num_stripes; |
| 5767 | struct btrfs_bio_stripe *tgtdev_stripe = | ||
| 5768 | bbio->stripes + num_stripes; | ||
| 5769 | 5778 | ||
| 5770 | tgtdev_stripe->physical = physical_of_found; | 5779 | tgtdev_stripe->physical = physical_of_found; |
| 5771 | tgtdev_stripe->length = | 5780 | tgtdev_stripe->length = |
| 5772 | bbio->stripes[index_srcdev].length; | 5781 | bbio->stripes[index_srcdev].length; |
| 5773 | tgtdev_stripe->dev = dev_replace->tgtdev; | 5782 | tgtdev_stripe->dev = dev_replace->tgtdev; |
| 5774 | bbio->tgtdev_map[index_srcdev] = num_stripes; | 5783 | bbio->tgtdev_map[index_srcdev] = num_stripes; |
| 5775 | 5784 | ||
| 5776 | tgtdev_indexes++; | 5785 | tgtdev_indexes++; |
| 5777 | num_stripes++; | 5786 | num_stripes++; |
| 5778 | } | ||
| 5779 | } | 5787 | } |
| 5780 | } | 5788 | } |
| 5781 | 5789 | ||
