diff options
author | Chris Mason <chris.mason@oracle.com> | 2010-05-25 09:48:28 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2010-05-25 10:34:58 -0400 |
commit | eaf25d933e64c2bf3c79b83e8820404f36fdfc52 (patch) | |
tree | 649dc862fcc9a243bdc925db34da618b25a275fc /fs/btrfs | |
parent | ed3b3d314cd2f16fac42676839854a68cab2e22b (diff) |
Btrfs: use async helpers for DIO write checksumming
The async helper threads offload crc work onto all the
CPUs, and make streaming writes much faster. This
changes the O_DIRECT write code to use them. The only
small complication was that we need to pass in the
logical offset in the file for each bio, because we can't
find it in the bio's pages.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/disk-io.c | 23 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 2 | ||||
-rw-r--r-- | fs/btrfs/extent_io.c | 2 | ||||
-rw-r--r-- | fs/btrfs/extent_io.h | 2 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 40 |
5 files changed, 52 insertions, 17 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index a8772b5a9cb5..f3b287c22caf 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -74,6 +74,11 @@ struct async_submit_bio { | |||
74 | int rw; | 74 | int rw; |
75 | int mirror_num; | 75 | int mirror_num; |
76 | unsigned long bio_flags; | 76 | unsigned long bio_flags; |
77 | /* | ||
78 | * bio_offset is optional, can be used if the pages in the bio | ||
79 | * can't tell us where in the file the bio should go | ||
80 | */ | ||
81 | u64 bio_offset; | ||
77 | struct btrfs_work work; | 82 | struct btrfs_work work; |
78 | }; | 83 | }; |
79 | 84 | ||
@@ -534,7 +539,8 @@ static void run_one_async_start(struct btrfs_work *work) | |||
534 | async = container_of(work, struct async_submit_bio, work); | 539 | async = container_of(work, struct async_submit_bio, work); |
535 | fs_info = BTRFS_I(async->inode)->root->fs_info; | 540 | fs_info = BTRFS_I(async->inode)->root->fs_info; |
536 | async->submit_bio_start(async->inode, async->rw, async->bio, | 541 | async->submit_bio_start(async->inode, async->rw, async->bio, |
537 | async->mirror_num, async->bio_flags); | 542 | async->mirror_num, async->bio_flags, |
543 | async->bio_offset); | ||
538 | } | 544 | } |
539 | 545 | ||
540 | static void run_one_async_done(struct btrfs_work *work) | 546 | static void run_one_async_done(struct btrfs_work *work) |
@@ -556,7 +562,8 @@ static void run_one_async_done(struct btrfs_work *work) | |||
556 | wake_up(&fs_info->async_submit_wait); | 562 | wake_up(&fs_info->async_submit_wait); |
557 | 563 | ||
558 | async->submit_bio_done(async->inode, async->rw, async->bio, | 564 | async->submit_bio_done(async->inode, async->rw, async->bio, |
559 | async->mirror_num, async->bio_flags); | 565 | async->mirror_num, async->bio_flags, |
566 | async->bio_offset); | ||
560 | } | 567 | } |
561 | 568 | ||
562 | static void run_one_async_free(struct btrfs_work *work) | 569 | static void run_one_async_free(struct btrfs_work *work) |
@@ -570,6 +577,7 @@ static void run_one_async_free(struct btrfs_work *work) | |||
570 | int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, | 577 | int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, |
571 | int rw, struct bio *bio, int mirror_num, | 578 | int rw, struct bio *bio, int mirror_num, |
572 | unsigned long bio_flags, | 579 | unsigned long bio_flags, |
580 | u64 bio_offset, | ||
573 | extent_submit_bio_hook_t *submit_bio_start, | 581 | extent_submit_bio_hook_t *submit_bio_start, |
574 | extent_submit_bio_hook_t *submit_bio_done) | 582 | extent_submit_bio_hook_t *submit_bio_done) |
575 | { | 583 | { |
@@ -592,6 +600,7 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, | |||
592 | 600 | ||
593 | async->work.flags = 0; | 601 | async->work.flags = 0; |
594 | async->bio_flags = bio_flags; | 602 | async->bio_flags = bio_flags; |
603 | async->bio_offset = bio_offset; | ||
595 | 604 | ||
596 | atomic_inc(&fs_info->nr_async_submits); | 605 | atomic_inc(&fs_info->nr_async_submits); |
597 | 606 | ||
@@ -627,7 +636,8 @@ static int btree_csum_one_bio(struct bio *bio) | |||
627 | 636 | ||
628 | static int __btree_submit_bio_start(struct inode *inode, int rw, | 637 | static int __btree_submit_bio_start(struct inode *inode, int rw, |
629 | struct bio *bio, int mirror_num, | 638 | struct bio *bio, int mirror_num, |
630 | unsigned long bio_flags) | 639 | unsigned long bio_flags, |
640 | u64 bio_offset) | ||
631 | { | 641 | { |
632 | /* | 642 | /* |
633 | * when we're called for a write, we're already in the async | 643 | * when we're called for a write, we're already in the async |
@@ -638,7 +648,8 @@ static int __btree_submit_bio_start(struct inode *inode, int rw, | |||
638 | } | 648 | } |
639 | 649 | ||
640 | static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio, | 650 | static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio, |
641 | int mirror_num, unsigned long bio_flags) | 651 | int mirror_num, unsigned long bio_flags, |
652 | u64 bio_offset) | ||
642 | { | 653 | { |
643 | /* | 654 | /* |
644 | * when we're called for a write, we're already in the async | 655 | * when we're called for a write, we're already in the async |
@@ -648,7 +659,8 @@ static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio, | |||
648 | } | 659 | } |
649 | 660 | ||
650 | static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, | 661 | static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, |
651 | int mirror_num, unsigned long bio_flags) | 662 | int mirror_num, unsigned long bio_flags, |
663 | u64 bio_offset) | ||
652 | { | 664 | { |
653 | int ret; | 665 | int ret; |
654 | 666 | ||
@@ -671,6 +683,7 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, | |||
671 | */ | 683 | */ |
672 | return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, | 684 | return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, |
673 | inode, rw, bio, mirror_num, 0, | 685 | inode, rw, bio, mirror_num, 0, |
686 | bio_offset, | ||
674 | __btree_submit_bio_start, | 687 | __btree_submit_bio_start, |
675 | __btree_submit_bio_done); | 688 | __btree_submit_bio_done); |
676 | } | 689 | } |
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 2c064eba6f09..88e825a0bf21 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -87,7 +87,7 @@ int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio, | |||
87 | int metadata); | 87 | int metadata); |
88 | int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, | 88 | int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, |
89 | int rw, struct bio *bio, int mirror_num, | 89 | int rw, struct bio *bio, int mirror_num, |
90 | unsigned long bio_flags, | 90 | unsigned long bio_flags, u64 bio_offset, |
91 | extent_submit_bio_hook_t *submit_bio_start, | 91 | extent_submit_bio_hook_t *submit_bio_start, |
92 | extent_submit_bio_hook_t *submit_bio_done); | 92 | extent_submit_bio_hook_t *submit_bio_done); |
93 | 93 | ||
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index a53aca338c7f..15392af21bfb 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -1913,7 +1913,7 @@ static int submit_one_bio(int rw, struct bio *bio, int mirror_num, | |||
1913 | 1913 | ||
1914 | if (tree->ops && tree->ops->submit_bio_hook) | 1914 | if (tree->ops && tree->ops->submit_bio_hook) |
1915 | tree->ops->submit_bio_hook(page->mapping->host, rw, bio, | 1915 | tree->ops->submit_bio_hook(page->mapping->host, rw, bio, |
1916 | mirror_num, bio_flags); | 1916 | mirror_num, bio_flags, start); |
1917 | else | 1917 | else |
1918 | submit_bio(rw, bio); | 1918 | submit_bio(rw, bio); |
1919 | if (bio_flagged(bio, BIO_EOPNOTSUPP)) | 1919 | if (bio_flagged(bio, BIO_EOPNOTSUPP)) |
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 86f10dc791d9..86c7b341d070 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h | |||
@@ -49,7 +49,7 @@ struct extent_state; | |||
49 | 49 | ||
50 | typedef int (extent_submit_bio_hook_t)(struct inode *inode, int rw, | 50 | typedef int (extent_submit_bio_hook_t)(struct inode *inode, int rw, |
51 | struct bio *bio, int mirror_num, | 51 | struct bio *bio, int mirror_num, |
52 | unsigned long bio_flags); | 52 | unsigned long bio_flags, u64 bio_offset); |
53 | struct extent_io_ops { | 53 | struct extent_io_ops { |
54 | int (*fill_delalloc)(struct inode *inode, struct page *locked_page, | 54 | int (*fill_delalloc)(struct inode *inode, struct page *locked_page, |
55 | u64 start, u64 end, int *page_started, | 55 | u64 start, u64 end, int *page_started, |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 1695440a59a4..13a4aa222861 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -1385,7 +1385,8 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset, | |||
1385 | */ | 1385 | */ |
1386 | static int __btrfs_submit_bio_start(struct inode *inode, int rw, | 1386 | static int __btrfs_submit_bio_start(struct inode *inode, int rw, |
1387 | struct bio *bio, int mirror_num, | 1387 | struct bio *bio, int mirror_num, |
1388 | unsigned long bio_flags) | 1388 | unsigned long bio_flags, |
1389 | u64 bio_offset) | ||
1389 | { | 1390 | { |
1390 | struct btrfs_root *root = BTRFS_I(inode)->root; | 1391 | struct btrfs_root *root = BTRFS_I(inode)->root; |
1391 | int ret = 0; | 1392 | int ret = 0; |
@@ -1404,7 +1405,8 @@ static int __btrfs_submit_bio_start(struct inode *inode, int rw, | |||
1404 | * are inserted into the btree | 1405 | * are inserted into the btree |
1405 | */ | 1406 | */ |
1406 | static int __btrfs_submit_bio_done(struct inode *inode, int rw, struct bio *bio, | 1407 | static int __btrfs_submit_bio_done(struct inode *inode, int rw, struct bio *bio, |
1407 | int mirror_num, unsigned long bio_flags) | 1408 | int mirror_num, unsigned long bio_flags, |
1409 | u64 bio_offset) | ||
1408 | { | 1410 | { |
1409 | struct btrfs_root *root = BTRFS_I(inode)->root; | 1411 | struct btrfs_root *root = BTRFS_I(inode)->root; |
1410 | return btrfs_map_bio(root, rw, bio, mirror_num, 1); | 1412 | return btrfs_map_bio(root, rw, bio, mirror_num, 1); |
@@ -1415,7 +1417,8 @@ static int __btrfs_submit_bio_done(struct inode *inode, int rw, struct bio *bio, | |||
1415 | * on write, or reading the csums from the tree before a read | 1417 | * on write, or reading the csums from the tree before a read |
1416 | */ | 1418 | */ |
1417 | static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, | 1419 | static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, |
1418 | int mirror_num, unsigned long bio_flags) | 1420 | int mirror_num, unsigned long bio_flags, |
1421 | u64 bio_offset) | ||
1419 | { | 1422 | { |
1420 | struct btrfs_root *root = BTRFS_I(inode)->root; | 1423 | struct btrfs_root *root = BTRFS_I(inode)->root; |
1421 | int ret = 0; | 1424 | int ret = 0; |
@@ -1440,7 +1443,8 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, | |||
1440 | /* we're doing a write, do the async checksumming */ | 1443 | /* we're doing a write, do the async checksumming */ |
1441 | return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, | 1444 | return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, |
1442 | inode, rw, bio, mirror_num, | 1445 | inode, rw, bio, mirror_num, |
1443 | bio_flags, __btrfs_submit_bio_start, | 1446 | bio_flags, bio_offset, |
1447 | __btrfs_submit_bio_start, | ||
1444 | __btrfs_submit_bio_done); | 1448 | __btrfs_submit_bio_done); |
1445 | } | 1449 | } |
1446 | 1450 | ||
@@ -1844,7 +1848,7 @@ static int btrfs_io_failed_hook(struct bio *failed_bio, | |||
1844 | 1848 | ||
1845 | BTRFS_I(inode)->io_tree.ops->submit_bio_hook(inode, rw, bio, | 1849 | BTRFS_I(inode)->io_tree.ops->submit_bio_hook(inode, rw, bio, |
1846 | failrec->last_mirror, | 1850 | failrec->last_mirror, |
1847 | failrec->bio_flags); | 1851 | failrec->bio_flags, 0); |
1848 | return 0; | 1852 | return 0; |
1849 | } | 1853 | } |
1850 | 1854 | ||
@@ -5484,6 +5488,17 @@ out_done: | |||
5484 | dio_end_io(bio, err); | 5488 | dio_end_io(bio, err); |
5485 | } | 5489 | } |
5486 | 5490 | ||
5491 | static int __btrfs_submit_bio_start_direct_io(struct inode *inode, int rw, | ||
5492 | struct bio *bio, int mirror_num, | ||
5493 | unsigned long bio_flags, u64 offset) | ||
5494 | { | ||
5495 | int ret; | ||
5496 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
5497 | ret = btrfs_csum_one_bio(root, inode, bio, offset, 1); | ||
5498 | BUG_ON(ret); | ||
5499 | return 0; | ||
5500 | } | ||
5501 | |||
5487 | static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode, | 5502 | static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode, |
5488 | loff_t file_offset) | 5503 | loff_t file_offset) |
5489 | { | 5504 | { |
@@ -5535,13 +5550,20 @@ static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode, | |||
5535 | if (ret) | 5550 | if (ret) |
5536 | goto out_err; | 5551 | goto out_err; |
5537 | 5552 | ||
5538 | if (write && !skip_sum) | 5553 | if (write && !skip_sum) { |
5539 | btrfs_csum_one_bio(root, inode, bio, dip->logical_offset, 1); | 5554 | ret = btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, |
5540 | else if (!skip_sum) | 5555 | inode, rw, bio, 0, 0, |
5556 | dip->logical_offset, | ||
5557 | __btrfs_submit_bio_start_direct_io, | ||
5558 | __btrfs_submit_bio_done); | ||
5559 | if (ret) | ||
5560 | goto out_err; | ||
5561 | return; | ||
5562 | } else if (!skip_sum) | ||
5541 | btrfs_lookup_bio_sums_dio(root, inode, bio, | 5563 | btrfs_lookup_bio_sums_dio(root, inode, bio, |
5542 | dip->logical_offset, dip->csums); | 5564 | dip->logical_offset, dip->csums); |
5543 | 5565 | ||
5544 | ret = btrfs_map_bio(root, rw, bio, 0, 0); | 5566 | ret = btrfs_map_bio(root, rw, bio, 0, 1); |
5545 | if (ret) | 5567 | if (ret) |
5546 | goto out_err; | 5568 | goto out_err; |
5547 | return; | 5569 | return; |