Btrfs: Bring back mount -o ssd optimizations
authorChris Mason <chris.mason@oracle.com>
Mon, 24 Mar 2008 19:02:07 +0000 (15:02 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:04:01 +0000 (11:04 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/inode.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h

index 96a4932178600b68bce9cc4e8d45cf7b9431b2b2..acf22ad6115cc8e62322ca36afa28c1008c177e6 100644 (file)
@@ -1405,6 +1405,9 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root, struct btrfs_path *path,
                        u64 isize);
 /* inode.c */
+int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
+                        size_t size, struct bio *bio);
+
 static inline void dec_i_blocks(struct inode *inode, u64 dec)
 {
        dec = dec >> 9;
index 26185d46712c37691dbc465b937bb1df7219f145..4890151cd68d6143357857b2351ee6c1f831ad56 100644 (file)
@@ -1103,4 +1103,6 @@ int btrfs_read_buffer(struct extent_buffer *buf)
 static struct extent_io_ops btree_extent_io_ops = {
        .writepage_io_hook = btree_writepage_io_hook,
        .submit_bio_hook = btree_submit_bio_hook,
+       /* note we're sharing with inode.c for the merge bio hook */
+       .merge_bio_hook = btrfs_merge_bio_hook,
 };
index 14eb8fc87015d7d25099ec1622fa648cf6d74162..e9ef644ff56f841d3502d55405004b4d5c4614a8 100644 (file)
@@ -1473,13 +1473,31 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans,
        struct btrfs_root * root = orig_root->fs_info->extent_root;
        struct btrfs_fs_info *info = root->fs_info;
        u64 total_needed = num_bytes;
+       u64 *last_ptr = NULL;
        struct btrfs_block_group_cache *block_group;
        int full_scan = 0;
        int wrapped = 0;
+       int empty_cluster = 2 * 1024 * 1024;
 
        WARN_ON(num_bytes < root->sectorsize);
        btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
 
+       if (data & BTRFS_BLOCK_GROUP_METADATA) {
+               last_ptr = &root->fs_info->last_alloc;
+       }
+
+       if ((data & BTRFS_BLOCK_GROUP_DATA) && btrfs_test_opt(root, SSD)) {
+               last_ptr = &root->fs_info->last_data_alloc;
+       }
+
+       if (last_ptr) {
+               if (*last_ptr)
+                       hint_byte = *last_ptr;
+               else {
+                       empty_size += empty_cluster;
+               }
+       }
+
        if (search_end == (u64)-1)
                search_end = btrfs_super_total_bytes(&info->super_copy);
 
@@ -1489,11 +1507,14 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans,
                        hint_byte = search_start;
                block_group = btrfs_find_block_group(root, block_group,
                                                     hint_byte, data, 1);
+               if (last_ptr && *last_ptr == 0 && block_group)
+                       hint_byte = block_group->key.objectid;
        } else {
                block_group = btrfs_find_block_group(root,
                                                     trans->block_group,
                                                     search_start, data, 1);
        }
+       search_start = max(search_start, hint_byte);
 
        total_needed += empty_size;
 
@@ -1506,9 +1527,36 @@ check_failed:
        }
        ret = find_search_start(root, &block_group, &search_start,
                                total_needed, data);
+       if (ret == -ENOSPC && last_ptr && *last_ptr) {
+               *last_ptr = 0;
+               block_group = btrfs_lookup_block_group(info,
+                                                      orig_search_start);
+               search_start = orig_search_start;
+               ret = find_search_start(root, &block_group, &search_start,
+                                       total_needed, data);
+       }
+       if (ret == -ENOSPC)
+               goto enospc;
        if (ret)
                goto error;
 
+       if (last_ptr && *last_ptr && search_start != *last_ptr) {
+               *last_ptr = 0;
+               if (!empty_size) {
+                       empty_size += empty_cluster;
+                       total_needed += empty_size;
+               }
+               block_group = btrfs_lookup_block_group(info,
+                                                      orig_search_start);
+               search_start = orig_search_start;
+               ret = find_search_start(root, &block_group,
+                                       &search_start, total_needed, data);
+               if (ret == -ENOSPC)
+                       goto enospc;
+               if (ret)
+                       goto error;
+       }
+
        search_start = stripe_align(root, search_start);
        ins->objectid = search_start;
        ins->offset = num_bytes;
@@ -1547,6 +1595,13 @@ check_failed:
                        trans->block_group = block_group;
        }
        ins->offset = num_bytes;
+       if (last_ptr) {
+               *last_ptr = ins->objectid + ins->offset;
+               if (*last_ptr ==
+                   btrfs_super_total_bytes(&root->fs_info->super_copy)) {
+                       *last_ptr = 0;
+               }
+       }
        return 0;
 
 new_group:
@@ -1612,12 +1667,12 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
        if (root->ref_cows) {
                if (data != BTRFS_BLOCK_GROUP_METADATA) {
                        ret = do_chunk_alloc(trans, root->fs_info->extent_root,
-                                            num_bytes,
+                                            2 * 1024 * 1024,
                                             BTRFS_BLOCK_GROUP_METADATA);
                        BUG_ON(ret);
                }
                ret = do_chunk_alloc(trans, root->fs_info->extent_root,
-                                    num_bytes, data);
+                                    num_bytes + 2 * 1024 * 1024, data);
                BUG_ON(ret);
        }
 
index 7e3a1ebde9fc0f586b632c2e5213c351f11034dd..6dab664529c12bb964b45aec8e0f288f1197e82d 100644 (file)
@@ -1730,6 +1730,8 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
        if (bio_ret && *bio_ret) {
                bio = *bio_ret;
                if (bio->bi_sector + (bio->bi_size >> 9) != sector ||
+                   (tree->ops && tree->ops->merge_bio_hook &&
+                    tree->ops->merge_bio_hook(page, offset, size, bio)) ||
                    bio_add_page(bio, page, size, offset) < size) {
                        ret = submit_one_bio(rw, bio);
                        bio = NULL;
index 0dca89328f98752f8b60a1a29aba694e9cf34578..8b5319db2516d25a4bde448e4ae7c8a6aa4a3573 100644 (file)
@@ -29,6 +29,8 @@ struct extent_io_ops {
        int (*fill_delalloc)(struct inode *inode, u64 start, u64 end);
        int (*writepage_io_hook)(struct page *page, u64 start, u64 end);
        int (*submit_bio_hook)(struct inode *inode, int rw, struct bio *bio);
+       int (*merge_bio_hook)(struct page *page, unsigned long offset,
+                             size_t size, struct bio *bio);
        int (*readpage_io_hook)(struct page *page, u64 start, u64 end);
        int (*readpage_end_io_hook)(struct page *page, u64 start, u64 end,
                                    struct extent_state *state);
index 109576b57f69d0ee56fe0ba23d852005d3868aaa..5140d680184657fe9dfe55dcfaafd15ca8b0ea0b 100644 (file)
@@ -296,6 +296,34 @@ int btrfs_clear_bit_hook(struct inode *inode, u64 start, u64 end,
        return 0;
 }
 
+int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
+                        size_t size, struct bio *bio)
+{
+       struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
+       struct btrfs_mapping_tree *map_tree;
+       struct btrfs_device *dev;
+       u64 logical = bio->bi_sector << 9;
+       u64 physical;
+       u64 length = 0;
+       u64 map_length;
+       struct bio_vec *bvec;
+       int i;
+       int ret;
+
+       bio_for_each_segment(bvec, bio, i) {
+               length += bvec->bv_len;
+       }
+       map_tree = &root->fs_info->mapping_tree;
+       map_length = length;
+       ret = btrfs_map_block(map_tree, logical, &physical, &map_length, &dev);
+       if (map_length < length + size) {
+               printk("merge bio hook logical %Lu bio len %Lu physical %Lu "
+                      "len %Lu\n", logical, length, physical, map_length);
+               return 1;
+       }
+       return 0;
+}
+
 int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -3033,6 +3061,7 @@ static struct file_operations btrfs_dir_file_operations = {
 static struct extent_io_ops btrfs_extent_io_ops = {
        .fill_delalloc = run_delalloc_range,
        .submit_bio_hook = btrfs_submit_bio_hook,
+       .merge_bio_hook = btrfs_merge_bio_hook,
        .readpage_io_hook = btrfs_readpage_io_hook,
        .readpage_end_io_hook = btrfs_readpage_end_io_hook,
        .set_bit_hook = btrfs_set_bit_hook,
index ae22d01ecf54d787ded245517ff809632e282ece..16fb6bbe6e289206fa8364553ec686fbdb359360 100644 (file)
@@ -578,6 +578,11 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio)
        map_tree = &root->fs_info->mapping_tree;
        map_length = length;
        ret = btrfs_map_block(map_tree, logical, &physical, &map_length, &dev);
+       if (map_length < length) {
+               printk("mapping failed logical %Lu bio len %Lu physical %Lu "
+                      "len %Lu\n", logical, length, physical, map_length);
+               BUG();
+       }
        BUG_ON(map_length < length);
        bio->bi_sector = physical >> 9;
        bio->bi_bdev = dev->bdev;
index 77fa6efd79cfd3a8089b2eaa4dfe94fc0a81a487..20259128152ee54e0d14d128de4e827bcb157126 100644 (file)
@@ -64,4 +64,7 @@ void btrfs_mapping_init(struct btrfs_mapping_tree *tree);
 void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree);
 int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio);
 int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf);
+int btrfs_map_block(struct btrfs_mapping_tree *map_tree,
+                   u64 logical, u64 *phys, u64 *length,
+                   struct btrfs_device **dev);
 #endif