aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-04-09 16:28:12 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:01 -0400
commit22c599485b1fdd95e4476a4752596a6cf6c6629a (patch)
treef34285bfb545cf7abed9be6ad12a61e80dbb4bb5
parentce9adaa5a792c2099a83246265eb4055bc38b6b8 (diff)
Btrfs: Handle data block end_io through the async work queue
Before it was done by the bio end_io routine, the work queue code is able to scale much better with faster IO subsystems. Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/disk-io.c34
-rw-r--r--fs/btrfs/disk-io.h2
-rw-r--r--fs/btrfs/inode.c4
3 files changed, 28 insertions, 12 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 82109204788..94ff87d0eae 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -54,6 +54,7 @@ struct end_io_wq {
void *private;
struct btrfs_fs_info *info;
int error;
+ int metadata;
struct list_head list;
};
@@ -308,29 +309,40 @@ static int end_workqueue_bio(struct bio *bio,
#endif
}
-static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio)
+int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio,
+ int metadata)
{
- struct btrfs_root *root = BTRFS_I(inode)->root;
struct end_io_wq *end_io_wq;
- u64 offset;
- offset = bio->bi_sector << 9;
-
- if (rw & (1 << BIO_RW)) {
- return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio);
- }
-
end_io_wq = kmalloc(sizeof(*end_io_wq), GFP_NOFS);
if (!end_io_wq)
return -ENOMEM;
end_io_wq->private = bio->bi_private;
end_io_wq->end_io = bio->bi_end_io;
- end_io_wq->info = root->fs_info;
+ end_io_wq->info = info;
end_io_wq->error = 0;
end_io_wq->bio = bio;
+ end_io_wq->metadata = metadata;
bio->bi_private = end_io_wq;
bio->bi_end_io = end_workqueue_bio;
+ return 0;
+}
+
+static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio)
+{
+ struct btrfs_root *root = BTRFS_I(inode)->root;
+ u64 offset;
+ int ret;
+
+ offset = bio->bi_sector << 9;
+
+ if (rw & (1 << BIO_RW)) {
+ return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio);
+ }
+
+ ret = btrfs_bio_wq_end_io(root->fs_info, bio, 1);
+ BUG_ON(ret);
if (offset == BTRFS_SUPER_INFO_OFFSET) {
bio->bi_bdev = root->fs_info->sb->s_bdev;
@@ -880,7 +892,7 @@ void btrfs_end_io_csum(struct work_struct *work)
end_io_wq = list_entry(next, struct end_io_wq, list);
bio = end_io_wq->bio;
- if (!bio_ready_for_csum(bio)) {
+ if (end_io_wq->metadata && !bio_ready_for_csum(bio)) {
spin_lock_irqsave(&fs_info->end_io_work_lock, flags);
was_empty = list_empty(&fs_info->end_io_work_list);
list_add_tail(&end_io_wq->list,
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index 05b88d0e75e..4fac0ccbf8f 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -71,4 +71,6 @@ void btrfs_throttle(struct btrfs_root *root);
int btrfs_open_device(struct btrfs_device *dev);
int btrfs_verify_block_csum(struct btrfs_root *root,
struct extent_buffer *buf);
+int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio,
+ int metadata);
#endif
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 7ae677d8a6d..e1ef1acdb35 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -328,7 +328,9 @@ int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio)
struct btrfs_trans_handle *trans;
int ret = 0;
- if (rw != WRITE) {
+ if (!(rw & (1 << BIO_RW))) {
+ ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
+ BUG_ON(ret);
goto mapit;
}