aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikolay Borisov <nborisov@suse.com>2019-03-25 08:31:22 -0400
committerDavid Sterba <dsterba@suse.com>2019-04-29 13:02:36 -0400
commitbbbf7243d62d8be73b7ef60721c127b36b2d523e (patch)
treefeffc8d55f1080c8f1e6e73c988aa6ca0137e7ff
parentc2d1b3aae33605a61cbab445d8ae1c708ccd2698 (diff)
btrfs: combine device update operations during transaction commit
We currently overload the pending_chunks list to handle updating btrfs_device->commit_bytes used. We don't actually care about the extent mapping or even the device mapping for the chunk - we just need the device, and we can end up processing it multiple times. The fs_devices->resized_list does more or less the same thing, but with the disk size. They are called consecutively during commit and have more or less the same purpose. We can combine the two lists into a single list that attaches to the transaction and contains a list of devices that need updating. Since we always add the device to a list when we change bytes_used or disk_total_size, there's no harm in copying both values at once. Signed-off-by: Nikolay Borisov <nborisov@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/dev-replace.c2
-rw-r--r--fs/btrfs/disk-io.c7
-rw-r--r--fs/btrfs/transaction.c5
-rw-r--r--fs/btrfs/transaction.h1
-rw-r--r--fs/btrfs/volumes.c87
-rw-r--r--fs/btrfs/volumes.h13
6 files changed, 51 insertions, 64 deletions
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index ee193c5222b2..dba43ada41d1 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -662,7 +662,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
662 btrfs_device_set_disk_total_bytes(tgt_device, 662 btrfs_device_set_disk_total_bytes(tgt_device,
663 src_device->disk_total_bytes); 663 src_device->disk_total_bytes);
664 btrfs_device_set_bytes_used(tgt_device, src_device->bytes_used); 664 btrfs_device_set_bytes_used(tgt_device, src_device->bytes_used);
665 ASSERT(list_empty(&src_device->resized_list)); 665 ASSERT(list_empty(&src_device->post_commit_list));
666 tgt_device->commit_total_bytes = src_device->commit_total_bytes; 666 tgt_device->commit_total_bytes = src_device->commit_total_bytes;
667 tgt_device->commit_bytes_used = src_device->bytes_used; 667 tgt_device->commit_bytes_used = src_device->bytes_used;
668 668
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 0fa65aca56a3..de1dcccc7c9d 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -4479,10 +4479,17 @@ void btrfs_cleanup_dirty_bgs(struct btrfs_transaction *cur_trans,
4479void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans, 4479void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
4480 struct btrfs_fs_info *fs_info) 4480 struct btrfs_fs_info *fs_info)
4481{ 4481{
4482 struct btrfs_device *dev, *tmp;
4483
4482 btrfs_cleanup_dirty_bgs(cur_trans, fs_info); 4484 btrfs_cleanup_dirty_bgs(cur_trans, fs_info);
4483 ASSERT(list_empty(&cur_trans->dirty_bgs)); 4485 ASSERT(list_empty(&cur_trans->dirty_bgs));
4484 ASSERT(list_empty(&cur_trans->io_bgs)); 4486 ASSERT(list_empty(&cur_trans->io_bgs));
4485 4487
4488 list_for_each_entry_safe(dev, tmp, &cur_trans->dev_update_list,
4489 post_commit_list) {
4490 list_del_init(&dev->post_commit_list);
4491 }
4492
4486 btrfs_destroy_delayed_refs(cur_trans, fs_info); 4493 btrfs_destroy_delayed_refs(cur_trans, fs_info);
4487 4494
4488 cur_trans->state = TRANS_STATE_COMMIT_START; 4495 cur_trans->state = TRANS_STATE_COMMIT_START;
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index f1732b77a379..4aa827a2e951 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -75,6 +75,7 @@ void btrfs_put_transaction(struct btrfs_transaction *transaction)
75 btrfs_put_block_group_trimming(cache); 75 btrfs_put_block_group_trimming(cache);
76 btrfs_put_block_group(cache); 76 btrfs_put_block_group(cache);
77 } 77 }
78 WARN_ON(!list_empty(&transaction->dev_update_list));
78 kfree(transaction); 79 kfree(transaction);
79 } 80 }
80} 81}
@@ -264,6 +265,7 @@ loop:
264 265
265 INIT_LIST_HEAD(&cur_trans->pending_snapshots); 266 INIT_LIST_HEAD(&cur_trans->pending_snapshots);
266 INIT_LIST_HEAD(&cur_trans->pending_chunks); 267 INIT_LIST_HEAD(&cur_trans->pending_chunks);
268 INIT_LIST_HEAD(&cur_trans->dev_update_list);
267 INIT_LIST_HEAD(&cur_trans->switch_commits); 269 INIT_LIST_HEAD(&cur_trans->switch_commits);
268 INIT_LIST_HEAD(&cur_trans->dirty_bgs); 270 INIT_LIST_HEAD(&cur_trans->dirty_bgs);
269 INIT_LIST_HEAD(&cur_trans->io_bgs); 271 INIT_LIST_HEAD(&cur_trans->io_bgs);
@@ -2241,8 +2243,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
2241 memcpy(fs_info->super_for_commit, fs_info->super_copy, 2243 memcpy(fs_info->super_for_commit, fs_info->super_copy,
2242 sizeof(*fs_info->super_copy)); 2244 sizeof(*fs_info->super_copy));
2243 2245
2244 btrfs_update_commit_device_size(fs_info); 2246 btrfs_commit_device_sizes(cur_trans);
2245 btrfs_update_commit_device_bytes_used(cur_trans);
2246 2247
2247 clear_bit(BTRFS_FS_LOG1_ERR, &fs_info->flags); 2248 clear_bit(BTRFS_FS_LOG1_ERR, &fs_info->flags);
2248 clear_bit(BTRFS_FS_LOG2_ERR, &fs_info->flags); 2249 clear_bit(BTRFS_FS_LOG2_ERR, &fs_info->flags);
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index b34678e7968e..2bd76f681520 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -52,6 +52,7 @@ struct btrfs_transaction {
52 wait_queue_head_t commit_wait; 52 wait_queue_head_t commit_wait;
53 struct list_head pending_snapshots; 53 struct list_head pending_snapshots;
54 struct list_head pending_chunks; 54 struct list_head pending_chunks;
55 struct list_head dev_update_list;
55 struct list_head switch_commits; 56 struct list_head switch_commits;
56 struct list_head dirty_bgs; 57 struct list_head dirty_bgs;
57 58
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 77bca3a61e26..72e069c227ab 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -319,7 +319,6 @@ static struct btrfs_fs_devices *alloc_fs_devices(const u8 *fsid,
319 mutex_init(&fs_devs->device_list_mutex); 319 mutex_init(&fs_devs->device_list_mutex);
320 320
321 INIT_LIST_HEAD(&fs_devs->devices); 321 INIT_LIST_HEAD(&fs_devs->devices);
322 INIT_LIST_HEAD(&fs_devs->resized_devices);
323 INIT_LIST_HEAD(&fs_devs->alloc_list); 322 INIT_LIST_HEAD(&fs_devs->alloc_list);
324 INIT_LIST_HEAD(&fs_devs->fs_list); 323 INIT_LIST_HEAD(&fs_devs->fs_list);
325 if (fsid) 324 if (fsid)
@@ -335,6 +334,7 @@ static struct btrfs_fs_devices *alloc_fs_devices(const u8 *fsid,
335 334
336void btrfs_free_device(struct btrfs_device *device) 335void btrfs_free_device(struct btrfs_device *device)
337{ 336{
337 WARN_ON(!list_empty(&device->post_commit_list));
338 rcu_string_free(device->name); 338 rcu_string_free(device->name);
339 bio_put(device->flush_bio); 339 bio_put(device->flush_bio);
340 kfree(device); 340 kfree(device);
@@ -403,7 +403,7 @@ static struct btrfs_device *__alloc_device(void)
403 403
404 INIT_LIST_HEAD(&dev->dev_list); 404 INIT_LIST_HEAD(&dev->dev_list);
405 INIT_LIST_HEAD(&dev->dev_alloc_list); 405 INIT_LIST_HEAD(&dev->dev_alloc_list);
406 INIT_LIST_HEAD(&dev->resized_list); 406 INIT_LIST_HEAD(&dev->post_commit_list);
407 407
408 spin_lock_init(&dev->io_lock); 408 spin_lock_init(&dev->io_lock);
409 409
@@ -2853,7 +2853,6 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
2853{ 2853{
2854 struct btrfs_fs_info *fs_info = device->fs_info; 2854 struct btrfs_fs_info *fs_info = device->fs_info;
2855 struct btrfs_super_block *super_copy = fs_info->super_copy; 2855 struct btrfs_super_block *super_copy = fs_info->super_copy;
2856 struct btrfs_fs_devices *fs_devices;
2857 u64 old_total; 2856 u64 old_total;
2858 u64 diff; 2857 u64 diff;
2859 2858
@@ -2872,8 +2871,6 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
2872 return -EINVAL; 2871 return -EINVAL;
2873 } 2872 }
2874 2873
2875 fs_devices = fs_info->fs_devices;
2876
2877 btrfs_set_super_total_bytes(super_copy, 2874 btrfs_set_super_total_bytes(super_copy,
2878 round_down(old_total + diff, fs_info->sectorsize)); 2875 round_down(old_total + diff, fs_info->sectorsize));
2879 device->fs_devices->total_rw_bytes += diff; 2876 device->fs_devices->total_rw_bytes += diff;
@@ -2881,9 +2878,9 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
2881 btrfs_device_set_total_bytes(device, new_size); 2878 btrfs_device_set_total_bytes(device, new_size);
2882 btrfs_device_set_disk_total_bytes(device, new_size); 2879 btrfs_device_set_disk_total_bytes(device, new_size);
2883 btrfs_clear_space_info_full(device->fs_info); 2880 btrfs_clear_space_info_full(device->fs_info);
2884 if (list_empty(&device->resized_list)) 2881 if (list_empty(&device->post_commit_list))
2885 list_add_tail(&device->resized_list, 2882 list_add_tail(&device->post_commit_list,
2886 &fs_devices->resized_devices); 2883 &trans->transaction->dev_update_list);
2887 mutex_unlock(&fs_info->chunk_mutex); 2884 mutex_unlock(&fs_info->chunk_mutex);
2888 2885
2889 return btrfs_update_device(trans, device); 2886 return btrfs_update_device(trans, device);
@@ -4872,9 +4869,9 @@ again:
4872 } 4869 }
4873 4870
4874 btrfs_device_set_disk_total_bytes(device, new_size); 4871 btrfs_device_set_disk_total_bytes(device, new_size);
4875 if (list_empty(&device->resized_list)) 4872 if (list_empty(&device->post_commit_list))
4876 list_add_tail(&device->resized_list, 4873 list_add_tail(&device->post_commit_list,
4877 &fs_info->fs_devices->resized_devices); 4874 &trans->transaction->dev_update_list);
4878 4875
4879 WARN_ON(diff > old_total); 4876 WARN_ON(diff > old_total);
4880 btrfs_set_super_total_bytes(super_copy, 4877 btrfs_set_super_total_bytes(super_copy,
@@ -5214,9 +5211,14 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
5214 if (ret) 5211 if (ret)
5215 goto error_del_extent; 5212 goto error_del_extent;
5216 5213
5217 for (i = 0; i < map->num_stripes; i++) 5214 for (i = 0; i < map->num_stripes; i++) {
5218 btrfs_device_set_bytes_used(map->stripes[i].dev, 5215 struct btrfs_device *dev = map->stripes[i].dev;
5219 map->stripes[i].dev->bytes_used + stripe_size); 5216
5217 btrfs_device_set_bytes_used(dev, dev->bytes_used + stripe_size);
5218 if (list_empty(&dev->post_commit_list))
5219 list_add_tail(&dev->post_commit_list,
5220 &trans->transaction->dev_update_list);
5221 }
5220 5222
5221 atomic64_sub(stripe_size * map->num_stripes, &info->free_chunk_space); 5223 atomic64_sub(stripe_size * map->num_stripes, &info->free_chunk_space);
5222 5224
@@ -7579,51 +7581,34 @@ void btrfs_scratch_superblocks(struct block_device *bdev, const char *device_pat
7579} 7581}
7580 7582
7581/* 7583/*
7582 * Update the size of all devices, which is used for writing out the 7584 * Update the size and bytes used for each device where it changed. This is
7583 * super blocks. 7585 * delayed since we would otherwise get errors while writing out the
7586 * superblocks.
7587 *
7588 * Must be invoked during transaction commit.
7584 */ 7589 */
7585void btrfs_update_commit_device_size(struct btrfs_fs_info *fs_info) 7590void btrfs_commit_device_sizes(struct btrfs_transaction *trans)
7586{ 7591{
7587 struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
7588 struct btrfs_device *curr, *next; 7592 struct btrfs_device *curr, *next;
7589 7593
7590 if (list_empty(&fs_devices->resized_devices)) 7594 ASSERT(trans->state == TRANS_STATE_COMMIT_DOING);
7591 return;
7592
7593 mutex_lock(&fs_devices->device_list_mutex);
7594 mutex_lock(&fs_info->chunk_mutex);
7595 list_for_each_entry_safe(curr, next, &fs_devices->resized_devices,
7596 resized_list) {
7597 list_del_init(&curr->resized_list);
7598 curr->commit_total_bytes = curr->disk_total_bytes;
7599 }
7600 mutex_unlock(&fs_info->chunk_mutex);
7601 mutex_unlock(&fs_devices->device_list_mutex);
7602}
7603
7604/* Must be invoked during the transaction commit */
7605void btrfs_update_commit_device_bytes_used(struct btrfs_transaction *trans)
7606{
7607 struct btrfs_fs_info *fs_info = trans->fs_info;
7608 struct extent_map *em;
7609 struct map_lookup *map;
7610 struct btrfs_device *dev;
7611 int i;
7612 7595
7613 if (list_empty(&trans->pending_chunks)) 7596 if (list_empty(&trans->dev_update_list))
7614 return; 7597 return;
7615 7598
7616 /* In order to kick the device replace finish process */ 7599 /*
7617 mutex_lock(&fs_info->chunk_mutex); 7600 * We don't need the device_list_mutex here. This list is owned by the
7618 list_for_each_entry(em, &trans->pending_chunks, list) { 7601 * transaction and the transaction must complete before the device is
7619 map = em->map_lookup; 7602 * released.
7620 7603 */
7621 for (i = 0; i < map->num_stripes; i++) { 7604 mutex_lock(&trans->fs_info->chunk_mutex);
7622 dev = map->stripes[i].dev; 7605 list_for_each_entry_safe(curr, next, &trans->dev_update_list,
7623 dev->commit_bytes_used = dev->bytes_used; 7606 post_commit_list) {
7624 } 7607 list_del_init(&curr->post_commit_list);
7608 curr->commit_total_bytes = curr->disk_total_bytes;
7609 curr->commit_bytes_used = curr->bytes_used;
7625 } 7610 }
7626 mutex_unlock(&fs_info->chunk_mutex); 7611 mutex_unlock(&trans->fs_info->chunk_mutex);
7627} 7612}
7628 7613
7629void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info) 7614void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info)
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 38ed94b77202..b9912b910d6d 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -45,6 +45,7 @@ struct btrfs_pending_bios {
45struct btrfs_device { 45struct btrfs_device {
46 struct list_head dev_list; 46 struct list_head dev_list;
47 struct list_head dev_alloc_list; 47 struct list_head dev_alloc_list;
48 struct list_head post_commit_list; /* chunk mutex */
48 struct btrfs_fs_devices *fs_devices; 49 struct btrfs_fs_devices *fs_devices;
49 struct btrfs_fs_info *fs_info; 50 struct btrfs_fs_info *fs_info;
50 51
@@ -102,18 +103,12 @@ struct btrfs_device {
102 * size of the device on the current transaction 103 * size of the device on the current transaction
103 * 104 *
104 * This variant is update when committing the transaction, 105 * This variant is update when committing the transaction,
105 * and protected by device_list_mutex 106 * and protected by chunk mutex
106 */ 107 */
107 u64 commit_total_bytes; 108 u64 commit_total_bytes;
108 109
109 /* bytes used on the current transaction */ 110 /* bytes used on the current transaction */
110 u64 commit_bytes_used; 111 u64 commit_bytes_used;
111 /*
112 * used to manage the device which is resized
113 *
114 * It is protected by chunk_lock.
115 */
116 struct list_head resized_list;
117 112
118 /* for sending down flush barriers */ 113 /* for sending down flush barriers */
119 struct bio *flush_bio; 114 struct bio *flush_bio;
@@ -235,7 +230,6 @@ struct btrfs_fs_devices {
235 struct mutex device_list_mutex; 230 struct mutex device_list_mutex;
236 struct list_head devices; 231 struct list_head devices;
237 232
238 struct list_head resized_devices;
239 /* devices not currently being allocated */ 233 /* devices not currently being allocated */
240 struct list_head alloc_list; 234 struct list_head alloc_list;
241 235
@@ -567,8 +561,7 @@ static inline enum btrfs_raid_types btrfs_bg_flags_to_raid_index(u64 flags)
567 561
568const char *get_raid_name(enum btrfs_raid_types type); 562const char *get_raid_name(enum btrfs_raid_types type);
569 563
570void btrfs_update_commit_device_size(struct btrfs_fs_info *fs_info); 564void btrfs_commit_device_sizes(struct btrfs_transaction *trans);
571void btrfs_update_commit_device_bytes_used(struct btrfs_transaction *trans);
572 565
573struct list_head *btrfs_get_fs_uuids(void); 566struct list_head *btrfs_get_fs_uuids(void);
574void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info); 567void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info);