Skip to content

Commit bbbf724

Browse files
lorddoskiaskdave
authored andcommitted
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>
1 parent c2d1b3a commit bbbf724

File tree

6 files changed

+51
-64
lines changed

6 files changed

+51
-64
lines changed

fs/btrfs/dev-replace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
662662
btrfs_device_set_disk_total_bytes(tgt_device,
663663
src_device->disk_total_bytes);
664664
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));
666666
tgt_device->commit_total_bytes = src_device->commit_total_bytes;
667667
tgt_device->commit_bytes_used = src_device->bytes_used;
668668

fs/btrfs/disk-io.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4479,10 +4479,17 @@ void btrfs_cleanup_dirty_bgs(struct btrfs_transaction *cur_trans,
44794479
void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
44804480
struct btrfs_fs_info *fs_info)
44814481
{
4482+
struct btrfs_device *dev, *tmp;
4483+
44824484
btrfs_cleanup_dirty_bgs(cur_trans, fs_info);
44834485
ASSERT(list_empty(&cur_trans->dirty_bgs));
44844486
ASSERT(list_empty(&cur_trans->io_bgs));
44854487

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+
44864493
btrfs_destroy_delayed_refs(cur_trans, fs_info);
44874494

44884495
cur_trans->state = TRANS_STATE_COMMIT_START;

fs/btrfs/transaction.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ void btrfs_put_transaction(struct btrfs_transaction *transaction)
7575
btrfs_put_block_group_trimming(cache);
7676
btrfs_put_block_group(cache);
7777
}
78+
WARN_ON(!list_empty(&transaction->dev_update_list));
7879
kfree(transaction);
7980
}
8081
}
@@ -264,6 +265,7 @@ static noinline int join_transaction(struct btrfs_fs_info *fs_info,
264265

265266
INIT_LIST_HEAD(&cur_trans->pending_snapshots);
266267
INIT_LIST_HEAD(&cur_trans->pending_chunks);
268+
INIT_LIST_HEAD(&cur_trans->dev_update_list);
267269
INIT_LIST_HEAD(&cur_trans->switch_commits);
268270
INIT_LIST_HEAD(&cur_trans->dirty_bgs);
269271
INIT_LIST_HEAD(&cur_trans->io_bgs);
@@ -2241,8 +2243,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
22412243
memcpy(fs_info->super_for_commit, fs_info->super_copy,
22422244
sizeof(*fs_info->super_copy));
22432245

2244-
btrfs_update_commit_device_size(fs_info);
2245-
btrfs_update_commit_device_bytes_used(cur_trans);
2246+
btrfs_commit_device_sizes(cur_trans);
22462247

22472248
clear_bit(BTRFS_FS_LOG1_ERR, &fs_info->flags);
22482249
clear_bit(BTRFS_FS_LOG2_ERR, &fs_info->flags);

fs/btrfs/transaction.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ struct btrfs_transaction {
5252
wait_queue_head_t commit_wait;
5353
struct list_head pending_snapshots;
5454
struct list_head pending_chunks;
55+
struct list_head dev_update_list;
5556
struct list_head switch_commits;
5657
struct list_head dirty_bgs;
5758

fs/btrfs/volumes.c

Lines changed: 36 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,6 @@ static struct btrfs_fs_devices *alloc_fs_devices(const u8 *fsid,
319319
mutex_init(&fs_devs->device_list_mutex);
320320

321321
INIT_LIST_HEAD(&fs_devs->devices);
322-
INIT_LIST_HEAD(&fs_devs->resized_devices);
323322
INIT_LIST_HEAD(&fs_devs->alloc_list);
324323
INIT_LIST_HEAD(&fs_devs->fs_list);
325324
if (fsid)
@@ -335,6 +334,7 @@ static struct btrfs_fs_devices *alloc_fs_devices(const u8 *fsid,
335334

336335
void btrfs_free_device(struct btrfs_device *device)
337336
{
337+
WARN_ON(!list_empty(&device->post_commit_list));
338338
rcu_string_free(device->name);
339339
bio_put(device->flush_bio);
340340
kfree(device);
@@ -403,7 +403,7 @@ static struct btrfs_device *__alloc_device(void)
403403

404404
INIT_LIST_HEAD(&dev->dev_list);
405405
INIT_LIST_HEAD(&dev->dev_alloc_list);
406-
INIT_LIST_HEAD(&dev->resized_list);
406+
INIT_LIST_HEAD(&dev->post_commit_list);
407407

408408
spin_lock_init(&dev->io_lock);
409409

@@ -2853,7 +2853,6 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
28532853
{
28542854
struct btrfs_fs_info *fs_info = device->fs_info;
28552855
struct btrfs_super_block *super_copy = fs_info->super_copy;
2856-
struct btrfs_fs_devices *fs_devices;
28572856
u64 old_total;
28582857
u64 diff;
28592858

@@ -2872,18 +2871,16 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
28722871
return -EINVAL;
28732872
}
28742873

2875-
fs_devices = fs_info->fs_devices;
2876-
28772874
btrfs_set_super_total_bytes(super_copy,
28782875
round_down(old_total + diff, fs_info->sectorsize));
28792876
device->fs_devices->total_rw_bytes += diff;
28802877

28812878
btrfs_device_set_total_bytes(device, new_size);
28822879
btrfs_device_set_disk_total_bytes(device, new_size);
28832880
btrfs_clear_space_info_full(device->fs_info);
2884-
if (list_empty(&device->resized_list))
2885-
list_add_tail(&device->resized_list,
2886-
&fs_devices->resized_devices);
2881+
if (list_empty(&device->post_commit_list))
2882+
list_add_tail(&device->post_commit_list,
2883+
&trans->transaction->dev_update_list);
28872884
mutex_unlock(&fs_info->chunk_mutex);
28882885

28892886
return btrfs_update_device(trans, device);
@@ -4872,9 +4869,9 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
48724869
}
48734870

48744871
btrfs_device_set_disk_total_bytes(device, new_size);
4875-
if (list_empty(&device->resized_list))
4876-
list_add_tail(&device->resized_list,
4877-
&fs_info->fs_devices->resized_devices);
4872+
if (list_empty(&device->post_commit_list))
4873+
list_add_tail(&device->post_commit_list,
4874+
&trans->transaction->dev_update_list);
48784875

48794876
WARN_ON(diff > old_total);
48804877
btrfs_set_super_total_bytes(super_copy,
@@ -5214,9 +5211,14 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
52145211
if (ret)
52155212
goto error_del_extent;
52165213

5217-
for (i = 0; i < map->num_stripes; i++)
5218-
btrfs_device_set_bytes_used(map->stripes[i].dev,
5219-
map->stripes[i].dev->bytes_used + stripe_size);
5214+
for (i = 0; i < map->num_stripes; i++) {
5215+
struct btrfs_device *dev = map->stripes[i].dev;
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+
}
52205222

52215223
atomic64_sub(stripe_size * map->num_stripes, &info->free_chunk_space);
52225224

@@ -7579,51 +7581,34 @@ void btrfs_scratch_superblocks(struct block_device *bdev, const char *device_pat
75797581
}
75807582

75817583
/*
7582-
* Update the size of all devices, which is used for writing out the
7583-
* super blocks.
7584+
* Update the size and bytes used for each device where it changed. This is
7585+
* delayed since we would otherwise get errors while writing out the
7586+
* superblocks.
7587+
*
7588+
* Must be invoked during transaction commit.
75847589
*/
7585-
void btrfs_update_commit_device_size(struct btrfs_fs_info *fs_info)
7590+
void btrfs_commit_device_sizes(struct btrfs_transaction *trans)
75867591
{
7587-
struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
75887592
struct btrfs_device *curr, *next;
75897593

7590-
if (list_empty(&fs_devices->resized_devices))
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 */
7605-
void 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;
7594+
ASSERT(trans->state == TRANS_STATE_COMMIT_DOING);
76127595

7613-
if (list_empty(&trans->pending_chunks))
7596+
if (list_empty(&trans->dev_update_list))
76147597
return;
76157598

7616-
/* In order to kick the device replace finish process */
7617-
mutex_lock(&fs_info->chunk_mutex);
7618-
list_for_each_entry(em, &trans->pending_chunks, list) {
7619-
map = em->map_lookup;
7620-
7621-
for (i = 0; i < map->num_stripes; i++) {
7622-
dev = map->stripes[i].dev;
7623-
dev->commit_bytes_used = dev->bytes_used;
7624-
}
7599+
/*
7600+
* We don't need the device_list_mutex here. This list is owned by the
7601+
* transaction and the transaction must complete before the device is
7602+
* released.
7603+
*/
7604+
mutex_lock(&trans->fs_info->chunk_mutex);
7605+
list_for_each_entry_safe(curr, next, &trans->dev_update_list,
7606+
post_commit_list) {
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;
76257610
}
7626-
mutex_unlock(&fs_info->chunk_mutex);
7611+
mutex_unlock(&trans->fs_info->chunk_mutex);
76277612
}
76287613

76297614
void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info)

fs/btrfs/volumes.h

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct btrfs_pending_bios {
4545
struct btrfs_device {
4646
struct list_head dev_list;
4747
struct list_head dev_alloc_list;
48+
struct list_head post_commit_list; /* chunk mutex */
4849
struct btrfs_fs_devices *fs_devices;
4950
struct btrfs_fs_info *fs_info;
5051

@@ -102,18 +103,12 @@ struct btrfs_device {
102103
* size of the device on the current transaction
103104
*
104105
* This variant is update when committing the transaction,
105-
* and protected by device_list_mutex
106+
* and protected by chunk mutex
106107
*/
107108
u64 commit_total_bytes;
108109

109110
/* bytes used on the current transaction */
110111
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;
117112

118113
/* for sending down flush barriers */
119114
struct bio *flush_bio;
@@ -235,7 +230,6 @@ struct btrfs_fs_devices {
235230
struct mutex device_list_mutex;
236231
struct list_head devices;
237232

238-
struct list_head resized_devices;
239233
/* devices not currently being allocated */
240234
struct list_head alloc_list;
241235

@@ -567,8 +561,7 @@ static inline enum btrfs_raid_types btrfs_bg_flags_to_raid_index(u64 flags)
567561

568562
const char *get_raid_name(enum btrfs_raid_types type);
569563

570-
void btrfs_update_commit_device_size(struct btrfs_fs_info *fs_info);
571-
void btrfs_update_commit_device_bytes_used(struct btrfs_transaction *trans);
564+
void btrfs_commit_device_sizes(struct btrfs_transaction *trans);
572565

573566
struct list_head *btrfs_get_fs_uuids(void);
574567
void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info);

0 commit comments

Comments
 (0)