Btrfs: Optimize allocations as we need to mix data and metadata into one group
authorChris Mason <chris.mason@oracle.com>
Tue, 6 Nov 2007 15:26:29 +0000 (10:26 -0500)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:03:57 +0000 (11:03 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.h
fs/btrfs/extent-tree.c
fs/btrfs/tree-defrag.c

index d82afb618bf11fc3119a8f0c626a4a0cc7ac0aaf..f7907b02fa778b0b059c24571cf9da96b2b7e9f3 100644 (file)
@@ -279,6 +279,8 @@ struct btrfs_csum_item {
 
 
 #define BTRFS_BLOCK_GROUP_DATA 1
+#define BTRFS_BLOCK_GROUP_MIXED 2
+
 struct btrfs_block_group_item {
        __le64 used;
        u8 flags;
index 9eb2ee02f6433c82f8b4f2b68d4dae76d94fe9be..d54ab8ef06d593ee1831429d44fd542581b9508b 100644 (file)
@@ -168,11 +168,13 @@ static u64 find_search_start(struct btrfs_root *root,
        u64 last;
        u64 start = 0;
        u64 end = 0;
+       int wrapped = 0;
 
 again:
        ret = cache_block_group(root, cache);
        if (ret)
                goto out;
+
        last = max(search_start, cache->key.objectid);
 
        while(1) {
@@ -195,8 +197,15 @@ out:
 
 new_group:
        last = cache->key.objectid + cache->key.offset;
+wrapped:
        cache = btrfs_lookup_block_group(root->fs_info, last);
        if (!cache) {
+               if (!wrapped) {
+                       wrapped = 1;
+                       last = search_start;
+                       data = BTRFS_BLOCK_GROUP_MIXED;
+                       goto wrapped;
+               }
                return search_start;
        }
        cache = btrfs_find_block_group(root, cache, last, data, 0);
@@ -236,9 +245,11 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
        block_group_cache = &info->block_group_cache;
 
        if (!owner)
-               factor = 5;
+               factor = 8;
 
-       if (data)
+       if (data == BTRFS_BLOCK_GROUP_MIXED)
+               bit = BLOCK_GROUP_DATA | BLOCK_GROUP_METADATA;
+       else if (data)
                bit = BLOCK_GROUP_DATA;
        else
                bit = BLOCK_GROUP_METADATA;
@@ -246,14 +257,16 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
        if (search_start) {
                struct btrfs_block_group_cache *shint;
                shint = btrfs_lookup_block_group(info, search_start);
-               if (shint && shint->data == data) {
+               if (shint && (shint->data == data ||
+                             shint->data == BTRFS_BLOCK_GROUP_MIXED)) {
                        used = btrfs_block_group_used(&shint->item);
                        if (used < div_factor(shint->key.offset, factor)) {
                                return shint;
                        }
                }
        }
-       if (hint && hint->data == data) {
+       if (hint && (hint->data == data ||
+                    hint->data == BTRFS_BLOCK_GROUP_MIXED)) {
                used = btrfs_block_group_used(&hint->item);
                if (used < div_factor(hint->key.offset, factor)) {
                        return hint;
@@ -592,11 +605,15 @@ static int update_block_group(struct btrfs_trans_handle *trans,
                                if (data) {
                                        bit_to_clear = BLOCK_GROUP_METADATA;
                                        bit_to_set = BLOCK_GROUP_DATA;
+                                       cache->item.flags &=
+                                               ~BTRFS_BLOCK_GROUP_MIXED;
                                        cache->item.flags |=
                                                BTRFS_BLOCK_GROUP_DATA;
                                } else {
                                        bit_to_clear = BLOCK_GROUP_DATA;
                                        bit_to_set = BLOCK_GROUP_METADATA;
+                                       cache->item.flags &=
+                                               ~BTRFS_BLOCK_GROUP_MIXED;
                                        cache->item.flags &=
                                                ~BTRFS_BLOCK_GROUP_DATA;
                                }
@@ -606,6 +623,14 @@ static int update_block_group(struct btrfs_trans_handle *trans,
                                set_extent_bits(&info->block_group_cache,
                                                start, end, bit_to_set,
                                                GFP_NOFS);
+                       } else if (cache->data != data &&
+                                  cache->data != BTRFS_BLOCK_GROUP_MIXED) {
+                               cache->data = BTRFS_BLOCK_GROUP_MIXED;
+                               set_extent_bits(&info->block_group_cache,
+                                               start, end,
+                                               BLOCK_GROUP_DATA |
+                                               BLOCK_GROUP_METADATA,
+                                               GFP_NOFS);
                        }
                        old_val += num_bytes;
                } else {
@@ -886,6 +911,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
        struct btrfs_block_group_cache *block_group;
        int full_scan = 0;
        int wrapped = 0;
+       u64 cached_start;
 
        WARN_ON(num_bytes < root->sectorsize);
        btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
@@ -910,6 +936,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
 check_failed:
        search_start = find_search_start(root, &block_group,
                                         search_start, total_needed, data);
+       cached_start = search_start;
        btrfs_init_path(path);
        ins->objectid = search_start;
        ins->offset = 0;
@@ -1532,9 +1559,12 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                key.objectid = found_key.objectid + found_key.offset;
                btrfs_release_path(root, path);
 
-               if (cache->item.flags & BTRFS_BLOCK_GROUP_DATA) {
+               if (cache->item.flags & BTRFS_BLOCK_GROUP_MIXED) {
+                       bit = BLOCK_GROUP_DATA | BLOCK_GROUP_METADATA;
+                       cache->data = BTRFS_BLOCK_GROUP_MIXED;
+               } else if (cache->item.flags & BTRFS_BLOCK_GROUP_DATA) {
                        bit = BLOCK_GROUP_DATA;
-                       cache->data = 1;
+                       cache->data = BTRFS_BLOCK_GROUP_DATA;
                } else {
                        bit = BLOCK_GROUP_METADATA;
                        cache->data = 0;
index 6ef1ba5f9c2fd1fadde34dba562780592d8978c9..3994795edfebf3ed02c4b78f410a551d20b5dabb 100644 (file)
@@ -58,6 +58,10 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans,
        if (root->fs_info->extent_root == root)
                is_extent = 1;
 
+       if (*level == 1 && cache_only && path->nodes[1] &&
+           !btrfs_buffer_defrag(path->nodes[1])) {
+               goto out;
+       }
        while(*level > 0) {
                WARN_ON(*level < 0);
                WARN_ON(*level >= BTRFS_MAX_LEVEL);
@@ -116,7 +120,7 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans,
        WARN_ON(*level >= BTRFS_MAX_LEVEL);
 
        btrfs_clear_buffer_defrag(path->nodes[*level]);
-
+out:
        free_extent_buffer(path->nodes[*level]);
        path->nodes[*level] = NULL;
        *level += 1;