diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-08-15 15:34:17 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:06 -0400 |
commit | 4854ddd0ed0a687fc2d7c45a529c406232e31e7b (patch) | |
tree | 6de9774969875cc30c21c96e145294727c56e73b | |
parent | 5443be45f5cb57d02fd895a0bcaf7e7d9890b1df (diff) |
Btrfs: Wait for kernel threads to make progress during async submission
Before this change, btrfs would use a bdi congestion function to make
sure there weren't too many pending async checksum work items.
This change makes the process creating async work items wait instead,
leading to fewer congestion returns from the bdi. This improves
pdflush background_writeout scanning.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/async-thread.c | 7 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 45 |
3 files changed, 33 insertions, 20 deletions
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 5f2f5a8c2289..958cd8b5f0d7 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c | |||
@@ -48,6 +48,7 @@ struct btrfs_worker_thread { | |||
48 | 48 | ||
49 | /* number of things on the pending list */ | 49 | /* number of things on the pending list */ |
50 | atomic_t num_pending; | 50 | atomic_t num_pending; |
51 | unsigned long sequence; | ||
51 | 52 | ||
52 | /* protects the pending list. */ | 53 | /* protects the pending list. */ |
53 | spinlock_t lock; | 54 | spinlock_t lock; |
@@ -197,6 +198,7 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers) | |||
197 | 198 | ||
198 | spin_lock_irq(&workers->lock); | 199 | spin_lock_irq(&workers->lock); |
199 | list_add_tail(&worker->worker_list, &workers->idle_list); | 200 | list_add_tail(&worker->worker_list, &workers->idle_list); |
201 | worker->idle = 1; | ||
200 | workers->num_workers++; | 202 | workers->num_workers++; |
201 | spin_unlock_irq(&workers->lock); | 203 | spin_unlock_irq(&workers->lock); |
202 | } | 204 | } |
@@ -238,7 +240,10 @@ static struct btrfs_worker_thread *next_worker(struct btrfs_workers *workers) | |||
238 | */ | 240 | */ |
239 | next = workers->worker_list.next; | 241 | next = workers->worker_list.next; |
240 | worker = list_entry(next, struct btrfs_worker_thread, worker_list); | 242 | worker = list_entry(next, struct btrfs_worker_thread, worker_list); |
241 | list_move_tail(next, &workers->worker_list); | 243 | atomic_inc(&worker->num_pending); |
244 | worker->sequence++; | ||
245 | if (worker->sequence % 4 == 0) | ||
246 | list_move_tail(next, &workers->worker_list); | ||
242 | return worker; | 247 | return worker; |
243 | } | 248 | } |
244 | 249 | ||
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index bb4a8d2200d0..040213359393 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -526,6 +526,7 @@ struct btrfs_fs_info { | |||
526 | struct btrfs_transaction *running_transaction; | 526 | struct btrfs_transaction *running_transaction; |
527 | wait_queue_head_t transaction_throttle; | 527 | wait_queue_head_t transaction_throttle; |
528 | wait_queue_head_t transaction_wait; | 528 | wait_queue_head_t transaction_wait; |
529 | wait_queue_head_t async_submit_wait; | ||
529 | struct btrfs_super_block super_copy; | 530 | struct btrfs_super_block super_copy; |
530 | struct btrfs_super_block super_for_commit; | 531 | struct btrfs_super_block super_for_commit; |
531 | struct block_device *__bdev; | 532 | struct block_device *__bdev; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 1bf210dadef6..1aed1f4616b6 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -429,31 +429,36 @@ int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio, | |||
429 | return 0; | 429 | return 0; |
430 | } | 430 | } |
431 | 431 | ||
432 | int btrfs_congested_async(struct btrfs_fs_info *info, int iodone) | 432 | static unsigned long async_submit_limit(struct btrfs_fs_info *info) |
433 | { | 433 | { |
434 | int limit = 256 * info->fs_devices->open_devices; | 434 | unsigned long limit = min_t(unsigned long, |
435 | 435 | info->workers.max_workers, | |
436 | if (iodone) | 436 | info->fs_devices->open_devices); |
437 | limit = (limit * 3) / 2; | 437 | return 256 * limit; |
438 | if (atomic_read(&info->nr_async_submits) > limit) | 438 | } |
439 | return 1; | ||
440 | 439 | ||
441 | return atomic_read(&info->nr_async_bios) > limit; | 440 | int btrfs_congested_async(struct btrfs_fs_info *info, int iodone) |
441 | { | ||
442 | return atomic_read(&info->nr_async_bios) > async_submit_limit(info); | ||
442 | } | 443 | } |
443 | 444 | ||
444 | static void run_one_async_submit(struct btrfs_work *work) | 445 | static void run_one_async_submit(struct btrfs_work *work) |
445 | { | 446 | { |
446 | struct btrfs_fs_info *fs_info; | 447 | struct btrfs_fs_info *fs_info; |
447 | struct async_submit_bio *async; | 448 | struct async_submit_bio *async; |
449 | int limit; | ||
448 | 450 | ||
449 | async = container_of(work, struct async_submit_bio, work); | 451 | async = container_of(work, struct async_submit_bio, work); |
450 | fs_info = BTRFS_I(async->inode)->root->fs_info; | 452 | fs_info = BTRFS_I(async->inode)->root->fs_info; |
453 | |||
454 | limit = async_submit_limit(fs_info); | ||
455 | limit = limit * 2 / 3; | ||
456 | |||
451 | atomic_dec(&fs_info->nr_async_submits); | 457 | atomic_dec(&fs_info->nr_async_submits); |
452 | 458 | ||
453 | if ((async->bio->bi_rw & (1 << BIO_RW)) && | 459 | if (atomic_read(&fs_info->nr_async_submits) < limit) |
454 | !btrfs_congested_async(fs_info, 1)) { | 460 | wake_up(&fs_info->async_submit_wait); |
455 | clear_bdi_congested(&fs_info->bdi, WRITE); | 461 | |
456 | } | ||
457 | async->submit_bio_hook(async->inode, async->rw, async->bio, | 462 | async->submit_bio_hook(async->inode, async->rw, async->bio, |
458 | async->mirror_num); | 463 | async->mirror_num); |
459 | kfree(async); | 464 | kfree(async); |
@@ -464,6 +469,7 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, | |||
464 | extent_submit_bio_hook_t *submit_bio_hook) | 469 | extent_submit_bio_hook_t *submit_bio_hook) |
465 | { | 470 | { |
466 | struct async_submit_bio *async; | 471 | struct async_submit_bio *async; |
472 | int limit = async_submit_limit(fs_info); | ||
467 | 473 | ||
468 | async = kmalloc(sizeof(*async), GFP_NOFS); | 474 | async = kmalloc(sizeof(*async), GFP_NOFS); |
469 | if (!async) | 475 | if (!async) |
@@ -478,6 +484,10 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, | |||
478 | async->work.flags = 0; | 484 | async->work.flags = 0; |
479 | atomic_inc(&fs_info->nr_async_submits); | 485 | atomic_inc(&fs_info->nr_async_submits); |
480 | btrfs_queue_worker(&fs_info->workers, &async->work); | 486 | btrfs_queue_worker(&fs_info->workers, &async->work); |
487 | |||
488 | wait_event_timeout(fs_info->async_submit_wait, | ||
489 | (atomic_read(&fs_info->nr_async_submits) < limit), | ||
490 | HZ/10); | ||
481 | return 0; | 491 | return 0; |
482 | } | 492 | } |
483 | 493 | ||
@@ -545,16 +555,11 @@ static int btree_writepages(struct address_space *mapping, | |||
545 | if (wbc->sync_mode == WB_SYNC_NONE) { | 555 | if (wbc->sync_mode == WB_SYNC_NONE) { |
546 | u64 num_dirty; | 556 | u64 num_dirty; |
547 | u64 start = 0; | 557 | u64 start = 0; |
548 | unsigned long thresh = 96 * 1024 * 1024; | 558 | unsigned long thresh = 8 * 1024 * 1024; |
549 | 559 | ||
550 | if (wbc->for_kupdate) | 560 | if (wbc->for_kupdate) |
551 | return 0; | 561 | return 0; |
552 | 562 | ||
553 | if (current_is_pdflush()) { | ||
554 | thresh = 96 * 1024 * 1024; | ||
555 | } else { | ||
556 | thresh = 8 * 1024 * 1024; | ||
557 | } | ||
558 | num_dirty = count_range_bits(tree, &start, (u64)-1, | 563 | num_dirty = count_range_bits(tree, &start, (u64)-1, |
559 | thresh, EXTENT_DIRTY); | 564 | thresh, EXTENT_DIRTY); |
560 | if (num_dirty < thresh) { | 565 | if (num_dirty < thresh) { |
@@ -1333,6 +1338,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1333 | mutex_init(&fs_info->volume_mutex); | 1338 | mutex_init(&fs_info->volume_mutex); |
1334 | init_waitqueue_head(&fs_info->transaction_throttle); | 1339 | init_waitqueue_head(&fs_info->transaction_throttle); |
1335 | init_waitqueue_head(&fs_info->transaction_wait); | 1340 | init_waitqueue_head(&fs_info->transaction_wait); |
1341 | init_waitqueue_head(&fs_info->async_submit_wait); | ||
1336 | 1342 | ||
1337 | #if 0 | 1343 | #if 0 |
1338 | ret = add_hasher(fs_info, "crc32c"); | 1344 | ret = add_hasher(fs_info, "crc32c"); |
@@ -1380,6 +1386,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1380 | * devices | 1386 | * devices |
1381 | */ | 1387 | */ |
1382 | fs_info->submit_workers.idle_thresh = 64; | 1388 | fs_info->submit_workers.idle_thresh = 64; |
1389 | fs_info->workers.idle_thresh = 32; | ||
1383 | 1390 | ||
1384 | btrfs_init_workers(&fs_info->fixup_workers, "fixup", 1); | 1391 | btrfs_init_workers(&fs_info->fixup_workers, "fixup", 1); |
1385 | btrfs_init_workers(&fs_info->endio_workers, "endio", | 1392 | btrfs_init_workers(&fs_info->endio_workers, "endio", |
@@ -1849,7 +1856,7 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) | |||
1849 | struct extent_io_tree *tree; | 1856 | struct extent_io_tree *tree; |
1850 | u64 num_dirty; | 1857 | u64 num_dirty; |
1851 | u64 start = 0; | 1858 | u64 start = 0; |
1852 | unsigned long thresh = 2 * 1024 * 1024; | 1859 | unsigned long thresh = 12 * 1024 * 1024; |
1853 | tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree; | 1860 | tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree; |
1854 | 1861 | ||
1855 | if (current_is_pdflush()) | 1862 | if (current_is_pdflush()) |