diff options
-rw-r--r-- | fs/btrfs/ctree.h | 14 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 7 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 78 | ||||
-rw-r--r-- | fs/btrfs/relocation.c | 6 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 6 |
5 files changed, 103 insertions, 8 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 8fd9fe4282f5..cad16566da37 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1333,6 +1333,7 @@ struct btrfs_fs_info { | |||
1333 | struct btrfs_workers generic_worker; | 1333 | struct btrfs_workers generic_worker; |
1334 | struct btrfs_workers workers; | 1334 | struct btrfs_workers workers; |
1335 | struct btrfs_workers delalloc_workers; | 1335 | struct btrfs_workers delalloc_workers; |
1336 | struct btrfs_workers flush_workers; | ||
1336 | struct btrfs_workers endio_workers; | 1337 | struct btrfs_workers endio_workers; |
1337 | struct btrfs_workers endio_meta_workers; | 1338 | struct btrfs_workers endio_meta_workers; |
1338 | struct btrfs_workers endio_meta_write_workers; | 1339 | struct btrfs_workers endio_meta_write_workers; |
@@ -3277,6 +3278,19 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans, | |||
3277 | int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, | 3278 | int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, |
3278 | struct list_head *list, int search_commit); | 3279 | struct list_head *list, int search_commit); |
3279 | /* inode.c */ | 3280 | /* inode.c */ |
3281 | struct btrfs_delalloc_work { | ||
3282 | struct inode *inode; | ||
3283 | int wait; | ||
3284 | int delay_iput; | ||
3285 | struct completion completion; | ||
3286 | struct list_head list; | ||
3287 | struct btrfs_work work; | ||
3288 | }; | ||
3289 | |||
3290 | struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode, | ||
3291 | int wait, int delay_iput); | ||
3292 | void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work); | ||
3293 | |||
3280 | struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page, | 3294 | struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page, |
3281 | size_t pg_offset, u64 start, u64 len, | 3295 | size_t pg_offset, u64 start, u64 len, |
3282 | int create); | 3296 | int create); |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 7cda51995c1e..bd70c2852ba0 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -2279,6 +2279,10 @@ int open_ctree(struct super_block *sb, | |||
2279 | fs_info->thread_pool_size, | 2279 | fs_info->thread_pool_size, |
2280 | &fs_info->generic_worker); | 2280 | &fs_info->generic_worker); |
2281 | 2281 | ||
2282 | btrfs_init_workers(&fs_info->flush_workers, "flush_delalloc", | ||
2283 | fs_info->thread_pool_size, | ||
2284 | &fs_info->generic_worker); | ||
2285 | |||
2282 | btrfs_init_workers(&fs_info->submit_workers, "submit", | 2286 | btrfs_init_workers(&fs_info->submit_workers, "submit", |
2283 | min_t(u64, fs_devices->num_devices, | 2287 | min_t(u64, fs_devices->num_devices, |
2284 | fs_info->thread_pool_size), | 2288 | fs_info->thread_pool_size), |
@@ -2350,6 +2354,7 @@ int open_ctree(struct super_block *sb, | |||
2350 | ret |= btrfs_start_workers(&fs_info->delayed_workers); | 2354 | ret |= btrfs_start_workers(&fs_info->delayed_workers); |
2351 | ret |= btrfs_start_workers(&fs_info->caching_workers); | 2355 | ret |= btrfs_start_workers(&fs_info->caching_workers); |
2352 | ret |= btrfs_start_workers(&fs_info->readahead_workers); | 2356 | ret |= btrfs_start_workers(&fs_info->readahead_workers); |
2357 | ret |= btrfs_start_workers(&fs_info->flush_workers); | ||
2353 | if (ret) { | 2358 | if (ret) { |
2354 | err = -ENOMEM; | 2359 | err = -ENOMEM; |
2355 | goto fail_sb_buffer; | 2360 | goto fail_sb_buffer; |
@@ -2667,6 +2672,7 @@ fail_sb_buffer: | |||
2667 | btrfs_stop_workers(&fs_info->submit_workers); | 2672 | btrfs_stop_workers(&fs_info->submit_workers); |
2668 | btrfs_stop_workers(&fs_info->delayed_workers); | 2673 | btrfs_stop_workers(&fs_info->delayed_workers); |
2669 | btrfs_stop_workers(&fs_info->caching_workers); | 2674 | btrfs_stop_workers(&fs_info->caching_workers); |
2675 | btrfs_stop_workers(&fs_info->flush_workers); | ||
2670 | fail_alloc: | 2676 | fail_alloc: |
2671 | fail_iput: | 2677 | fail_iput: |
2672 | btrfs_mapping_tree_free(&fs_info->mapping_tree); | 2678 | btrfs_mapping_tree_free(&fs_info->mapping_tree); |
@@ -3339,6 +3345,7 @@ int close_ctree(struct btrfs_root *root) | |||
3339 | btrfs_stop_workers(&fs_info->delayed_workers); | 3345 | btrfs_stop_workers(&fs_info->delayed_workers); |
3340 | btrfs_stop_workers(&fs_info->caching_workers); | 3346 | btrfs_stop_workers(&fs_info->caching_workers); |
3341 | btrfs_stop_workers(&fs_info->readahead_workers); | 3347 | btrfs_stop_workers(&fs_info->readahead_workers); |
3348 | btrfs_stop_workers(&fs_info->flush_workers); | ||
3342 | 3349 | ||
3343 | #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY | 3350 | #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY |
3344 | if (btrfs_test_opt(root, CHECK_INTEGRITY)) | 3351 | if (btrfs_test_opt(root, CHECK_INTEGRITY)) |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index db3dd4ed057f..dce9e218b845 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -71,6 +71,7 @@ static const struct file_operations btrfs_dir_file_operations; | |||
71 | static struct extent_io_ops btrfs_extent_io_ops; | 71 | static struct extent_io_ops btrfs_extent_io_ops; |
72 | 72 | ||
73 | static struct kmem_cache *btrfs_inode_cachep; | 73 | static struct kmem_cache *btrfs_inode_cachep; |
74 | static struct kmem_cache *btrfs_delalloc_work_cachep; | ||
74 | struct kmem_cache *btrfs_trans_handle_cachep; | 75 | struct kmem_cache *btrfs_trans_handle_cachep; |
75 | struct kmem_cache *btrfs_transaction_cachep; | 76 | struct kmem_cache *btrfs_transaction_cachep; |
76 | struct kmem_cache *btrfs_path_cachep; | 77 | struct kmem_cache *btrfs_path_cachep; |
@@ -7204,6 +7205,8 @@ void btrfs_destroy_cachep(void) | |||
7204 | kmem_cache_destroy(btrfs_path_cachep); | 7205 | kmem_cache_destroy(btrfs_path_cachep); |
7205 | if (btrfs_free_space_cachep) | 7206 | if (btrfs_free_space_cachep) |
7206 | kmem_cache_destroy(btrfs_free_space_cachep); | 7207 | kmem_cache_destroy(btrfs_free_space_cachep); |
7208 | if (btrfs_delalloc_work_cachep) | ||
7209 | kmem_cache_destroy(btrfs_delalloc_work_cachep); | ||
7207 | } | 7210 | } |
7208 | 7211 | ||
7209 | int btrfs_init_cachep(void) | 7212 | int btrfs_init_cachep(void) |
@@ -7238,6 +7241,13 @@ int btrfs_init_cachep(void) | |||
7238 | if (!btrfs_free_space_cachep) | 7241 | if (!btrfs_free_space_cachep) |
7239 | goto fail; | 7242 | goto fail; |
7240 | 7243 | ||
7244 | btrfs_delalloc_work_cachep = kmem_cache_create("btrfs_delalloc_work", | ||
7245 | sizeof(struct btrfs_delalloc_work), 0, | ||
7246 | SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, | ||
7247 | NULL); | ||
7248 | if (!btrfs_delalloc_work_cachep) | ||
7249 | goto fail; | ||
7250 | |||
7241 | return 0; | 7251 | return 0; |
7242 | fail: | 7252 | fail: |
7243 | btrfs_destroy_cachep(); | 7253 | btrfs_destroy_cachep(); |
@@ -7448,6 +7458,49 @@ out_notrans: | |||
7448 | return ret; | 7458 | return ret; |
7449 | } | 7459 | } |
7450 | 7460 | ||
7461 | static void btrfs_run_delalloc_work(struct btrfs_work *work) | ||
7462 | { | ||
7463 | struct btrfs_delalloc_work *delalloc_work; | ||
7464 | |||
7465 | delalloc_work = container_of(work, struct btrfs_delalloc_work, | ||
7466 | work); | ||
7467 | if (delalloc_work->wait) | ||
7468 | btrfs_wait_ordered_range(delalloc_work->inode, 0, (u64)-1); | ||
7469 | else | ||
7470 | filemap_flush(delalloc_work->inode->i_mapping); | ||
7471 | |||
7472 | if (delalloc_work->delay_iput) | ||
7473 | btrfs_add_delayed_iput(delalloc_work->inode); | ||
7474 | else | ||
7475 | iput(delalloc_work->inode); | ||
7476 | complete(&delalloc_work->completion); | ||
7477 | } | ||
7478 | |||
7479 | struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode, | ||
7480 | int wait, int delay_iput) | ||
7481 | { | ||
7482 | struct btrfs_delalloc_work *work; | ||
7483 | |||
7484 | work = kmem_cache_zalloc(btrfs_delalloc_work_cachep, GFP_NOFS); | ||
7485 | if (!work) | ||
7486 | return NULL; | ||
7487 | |||
7488 | init_completion(&work->completion); | ||
7489 | INIT_LIST_HEAD(&work->list); | ||
7490 | work->inode = inode; | ||
7491 | work->wait = wait; | ||
7492 | work->delay_iput = delay_iput; | ||
7493 | work->work.func = btrfs_run_delalloc_work; | ||
7494 | |||
7495 | return work; | ||
7496 | } | ||
7497 | |||
7498 | void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work) | ||
7499 | { | ||
7500 | wait_for_completion(&work->completion); | ||
7501 | kmem_cache_free(btrfs_delalloc_work_cachep, work); | ||
7502 | } | ||
7503 | |||
7451 | /* | 7504 | /* |
7452 | * some fairly slow code that needs optimization. This walks the list | 7505 | * some fairly slow code that needs optimization. This walks the list |
7453 | * of all the inodes with pending delalloc and forces them to disk. | 7506 | * of all the inodes with pending delalloc and forces them to disk. |
@@ -7457,10 +7510,15 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput) | |||
7457 | struct list_head *head = &root->fs_info->delalloc_inodes; | 7510 | struct list_head *head = &root->fs_info->delalloc_inodes; |
7458 | struct btrfs_inode *binode; | 7511 | struct btrfs_inode *binode; |
7459 | struct inode *inode; | 7512 | struct inode *inode; |
7513 | struct btrfs_delalloc_work *work, *next; | ||
7514 | struct list_head works; | ||
7515 | int ret = 0; | ||
7460 | 7516 | ||
7461 | if (root->fs_info->sb->s_flags & MS_RDONLY) | 7517 | if (root->fs_info->sb->s_flags & MS_RDONLY) |
7462 | return -EROFS; | 7518 | return -EROFS; |
7463 | 7519 | ||
7520 | INIT_LIST_HEAD(&works); | ||
7521 | |||
7464 | spin_lock(&root->fs_info->delalloc_lock); | 7522 | spin_lock(&root->fs_info->delalloc_lock); |
7465 | while (!list_empty(head)) { | 7523 | while (!list_empty(head)) { |
7466 | binode = list_entry(head->next, struct btrfs_inode, | 7524 | binode = list_entry(head->next, struct btrfs_inode, |
@@ -7470,11 +7528,14 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput) | |||
7470 | list_del_init(&binode->delalloc_inodes); | 7528 | list_del_init(&binode->delalloc_inodes); |
7471 | spin_unlock(&root->fs_info->delalloc_lock); | 7529 | spin_unlock(&root->fs_info->delalloc_lock); |
7472 | if (inode) { | 7530 | if (inode) { |
7473 | filemap_flush(inode->i_mapping); | 7531 | work = btrfs_alloc_delalloc_work(inode, 0, delay_iput); |
7474 | if (delay_iput) | 7532 | if (!work) { |
7475 | btrfs_add_delayed_iput(inode); | 7533 | ret = -ENOMEM; |
7476 | else | 7534 | goto out; |
7477 | iput(inode); | 7535 | } |
7536 | list_add_tail(&work->list, &works); | ||
7537 | btrfs_queue_worker(&root->fs_info->flush_workers, | ||
7538 | &work->work); | ||
7478 | } | 7539 | } |
7479 | cond_resched(); | 7540 | cond_resched(); |
7480 | spin_lock(&root->fs_info->delalloc_lock); | 7541 | spin_lock(&root->fs_info->delalloc_lock); |
@@ -7493,7 +7554,12 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput) | |||
7493 | atomic_read(&root->fs_info->async_delalloc_pages) == 0)); | 7554 | atomic_read(&root->fs_info->async_delalloc_pages) == 0)); |
7494 | } | 7555 | } |
7495 | atomic_dec(&root->fs_info->async_submit_draining); | 7556 | atomic_dec(&root->fs_info->async_submit_draining); |
7496 | return 0; | 7557 | out: |
7558 | list_for_each_entry_safe(work, next, &works, list) { | ||
7559 | list_del_init(&work->list); | ||
7560 | btrfs_wait_and_free_delalloc_work(work); | ||
7561 | } | ||
7562 | return ret; | ||
7497 | } | 7563 | } |
7498 | 7564 | ||
7499 | static int btrfs_symlink(struct inode *dir, struct dentry *dentry, | 7565 | static int btrfs_symlink(struct inode *dir, struct dentry *dentry, |
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 242d6de4d8eb..270f24ffe1be 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c | |||
@@ -4061,7 +4061,11 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start) | |||
4061 | (unsigned long long)rc->block_group->key.objectid, | 4061 | (unsigned long long)rc->block_group->key.objectid, |
4062 | (unsigned long long)rc->block_group->flags); | 4062 | (unsigned long long)rc->block_group->flags); |
4063 | 4063 | ||
4064 | btrfs_start_delalloc_inodes(fs_info->tree_root, 0); | 4064 | ret = btrfs_start_delalloc_inodes(fs_info->tree_root, 0); |
4065 | if (ret < 0) { | ||
4066 | err = ret; | ||
4067 | goto out; | ||
4068 | } | ||
4065 | btrfs_wait_ordered_extents(fs_info->tree_root, 0); | 4069 | btrfs_wait_ordered_extents(fs_info->tree_root, 0); |
4066 | 4070 | ||
4067 | while (1) { | 4071 | while (1) { |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 4e1def4c06b1..9c466f9f8175 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -1497,7 +1497,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1497 | WARN_ON(cur_trans != trans->transaction); | 1497 | WARN_ON(cur_trans != trans->transaction); |
1498 | 1498 | ||
1499 | if (flush_on_commit || snap_pending) { | 1499 | if (flush_on_commit || snap_pending) { |
1500 | btrfs_start_delalloc_inodes(root, 1); | 1500 | ret = btrfs_start_delalloc_inodes(root, 1); |
1501 | if (ret) { | ||
1502 | btrfs_abort_transaction(trans, root, ret); | ||
1503 | goto cleanup_transaction; | ||
1504 | } | ||
1501 | btrfs_wait_ordered_extents(root, 1); | 1505 | btrfs_wait_ordered_extents(root, 1); |
1502 | } | 1506 | } |
1503 | 1507 | ||