Btrfs: Handle data block end_io through the async work queue
authorChris Mason <chris.mason@oracle.com>
Wed, 9 Apr 2008 20:28:12 +0000 (16:28 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:04:01 +0000 (11:04 -0400)
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>
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/inode.c

index 82109204788c67ac5809e9be916198755a58ff39..94ff87d0eae4a77c6ec1d656d3921becd28d85d2 100644 (file)
@@ -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,
index 05b88d0e75eb7c3defc5c3ced95e8cd084023acf..4fac0ccbf8f8d8bf046bb62e5e54307058dd26ba 100644 (file)
@@ -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
index 7ae677d8a6dea67774abd294373e4d9674504825..e1ef1acdb3503fda709239b482f70e54d9b19eca 100644 (file)
@@ -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;
        }