diff options
author | Chris Mason <clm@fb.com> | 2016-06-01 20:03:50 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2016-06-01 20:03:50 -0400 |
commit | f881dd29bf31fb9e8072a3a47c834fa804f7d249 (patch) | |
tree | de3fd8d94140b60fb49bdcfc675c80ee069aec26 | |
parent | 56244ef151c3cd11f505020ab0b3f45454363bcc (diff) | |
parent | b5de8d0df80fa87f1f97fbcc4bbc8cad0a018802 (diff) |
Merge branch 'dev-replace-fixes-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/fdmanana/linux into for-linus-4.7
-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 | ||