Skip to content

Commit 0cb59c9

Browse files
Josef Bacikchrismason-xx
authored andcommitted
Btrfs: write out free space cache
This is a simple bit, just dump the free space cache out to our preallocated inode when we're writing out dirty block groups. There are a bunch of changes in inode.c in order to account for special cases. Mostly when we're doing the writeout we're holding trans_mutex, so we need to use the nolock transacation functions. Also we can't do asynchronous completions since the async thread could be blocked on already completed IO waiting for the transaction lock. This has been tested with xfstests and btrfs filesystem balance, as well as my ENOSPC tests. Thanks, Signed-off-by: Josef Bacik <josef@redhat.com>
1 parent 0af3d00 commit 0cb59c9

File tree

6 files changed

+420
-13
lines changed

6 files changed

+420
-13
lines changed

fs/btrfs/ctree.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,7 @@ struct btrfs_fs_info {
982982
struct btrfs_workers endio_meta_workers;
983983
struct btrfs_workers endio_meta_write_workers;
984984
struct btrfs_workers endio_write_workers;
985+
struct btrfs_workers endio_freespace_worker;
985986
struct btrfs_workers submit_workers;
986987
/*
987988
* fixup workers take dirty pages that didn't properly go through

fs/btrfs/disk-io.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,9 +481,12 @@ static void end_workqueue_bio(struct bio *bio, int err)
481481
end_io_wq->work.flags = 0;
482482

483483
if (bio->bi_rw & REQ_WRITE) {
484-
if (end_io_wq->metadata)
484+
if (end_io_wq->metadata == 1)
485485
btrfs_queue_worker(&fs_info->endio_meta_write_workers,
486486
&end_io_wq->work);
487+
else if (end_io_wq->metadata == 2)
488+
btrfs_queue_worker(&fs_info->endio_freespace_worker,
489+
&end_io_wq->work);
487490
else
488491
btrfs_queue_worker(&fs_info->endio_write_workers,
489492
&end_io_wq->work);
@@ -497,6 +500,13 @@ static void end_workqueue_bio(struct bio *bio, int err)
497500
}
498501
}
499502

503+
/*
504+
* For the metadata arg you want
505+
*
506+
* 0 - if data
507+
* 1 - if normal metadta
508+
* 2 - if writing to the free space cache area
509+
*/
500510
int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio,
501511
int metadata)
502512
{
@@ -1774,6 +1784,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
17741784
btrfs_init_workers(&fs_info->endio_write_workers, "endio-write",
17751785
fs_info->thread_pool_size,
17761786
&fs_info->generic_worker);
1787+
btrfs_init_workers(&fs_info->endio_freespace_worker, "freespace-write",
1788+
1, &fs_info->generic_worker);
17771789

17781790
/*
17791791
* endios are largely parallel and should have a very
@@ -1794,6 +1806,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
17941806
btrfs_start_workers(&fs_info->endio_meta_workers, 1);
17951807
btrfs_start_workers(&fs_info->endio_meta_write_workers, 1);
17961808
btrfs_start_workers(&fs_info->endio_write_workers, 1);
1809+
btrfs_start_workers(&fs_info->endio_freespace_worker, 1);
17971810

17981811
fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super);
17991812
fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages,
@@ -2035,6 +2048,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
20352048
btrfs_stop_workers(&fs_info->endio_meta_workers);
20362049
btrfs_stop_workers(&fs_info->endio_meta_write_workers);
20372050
btrfs_stop_workers(&fs_info->endio_write_workers);
2051+
btrfs_stop_workers(&fs_info->endio_freespace_worker);
20382052
btrfs_stop_workers(&fs_info->submit_workers);
20392053
fail_iput:
20402054
invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
@@ -2468,6 +2482,7 @@ int close_ctree(struct btrfs_root *root)
24682482
btrfs_stop_workers(&fs_info->endio_meta_workers);
24692483
btrfs_stop_workers(&fs_info->endio_meta_write_workers);
24702484
btrfs_stop_workers(&fs_info->endio_write_workers);
2485+
btrfs_stop_workers(&fs_info->endio_freespace_worker);
24712486
btrfs_stop_workers(&fs_info->submit_workers);
24722487

24732488
btrfs_close_devices(fs_info->fs_devices);

fs/btrfs/extent-tree.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2847,6 +2847,8 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
28472847
continue;
28482848
}
28492849

2850+
if (cache->disk_cache_state == BTRFS_DC_SETUP)
2851+
cache->disk_cache_state = BTRFS_DC_NEED_WRITE;
28502852
cache->dirty = 0;
28512853
last = cache->key.objectid + cache->key.offset;
28522854

@@ -2855,6 +2857,52 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
28552857
btrfs_put_block_group(cache);
28562858
}
28572859

2860+
while (1) {
2861+
/*
2862+
* I don't think this is needed since we're just marking our
2863+
* preallocated extent as written, but just in case it can't
2864+
* hurt.
2865+
*/
2866+
if (last == 0) {
2867+
err = btrfs_run_delayed_refs(trans, root,
2868+
(unsigned long)-1);
2869+
BUG_ON(err);
2870+
}
2871+
2872+
cache = btrfs_lookup_first_block_group(root->fs_info, last);
2873+
while (cache) {
2874+
/*
2875+
* Really this shouldn't happen, but it could if we
2876+
* couldn't write the entire preallocated extent and
2877+
* splitting the extent resulted in a new block.
2878+
*/
2879+
if (cache->dirty) {
2880+
btrfs_put_block_group(cache);
2881+
goto again;
2882+
}
2883+
if (cache->disk_cache_state == BTRFS_DC_NEED_WRITE)
2884+
break;
2885+
cache = next_block_group(root, cache);
2886+
}
2887+
if (!cache) {
2888+
if (last == 0)
2889+
break;
2890+
last = 0;
2891+
continue;
2892+
}
2893+
2894+
btrfs_write_out_cache(root, trans, cache, path);
2895+
2896+
/*
2897+
* If we didn't have an error then the cache state is still
2898+
* NEED_WRITE, so we can set it to WRITTEN.
2899+
*/
2900+
if (cache->disk_cache_state == BTRFS_DC_NEED_WRITE)
2901+
cache->disk_cache_state = BTRFS_DC_WRITTEN;
2902+
last = cache->key.objectid + cache->key.offset;
2903+
btrfs_put_block_group(cache);
2904+
}
2905+
28582906
btrfs_free_path(path);
28592907
return 0;
28602908
}

0 commit comments

Comments
 (0)