Hello,

This patch adds shared reference cache support. The new space
balancing code plays with multiple subvols at the same time, So
the old per-subvol reference cache isn't fit for it.

Regards
Yan Zheng

---
diff -r 47aa0c51998a ctree.h
--- a/ctree.h   Thu Sep 25 16:00:36 2008 +0800
+++ b/ctree.h   Thu Sep 25 16:02:11 2008 +0800
@@ -80,6 +80,10 @@
 /* does write ahead logging to speed up fsyncs */
 #define BTRFS_TREE_LOG_OBJECTID -6ULL
 #define BTRFS_TREE_LOG_FIXUP_OBJECTID -7ULL
+
+/* for space balancing */
+#define BTRFS_TREE_RELOC_OBJECTID -8ULL
+#define BTRFS_DATA_RELOC_TREE_OBJECTID -9ULL
 
 /* dummy objectid represents multiple objectids */
 #define BTRFS_MULTIPLE_OBJECTIDS -255ULL
@@ -539,6 +543,12 @@
        struct list_head list;
 };
 
+struct btrfs_leaf_ref_tree {
+       struct rb_root root;
+       struct list_head list;
+       spinlock_t lock;
+};
+
 struct btrfs_device;
 struct btrfs_fs_devices;
 struct btrfs_fs_info {
@@ -637,6 +647,8 @@
        struct task_struct *cleaner_kthread;
        int thread_pool_size;
 
+       struct btrfs_leaf_ref_tree shared_ref_tree;
+
        struct kobject super_kobj;
        struct completion kobj_unregister;
        int do_barriers;
@@ -668,13 +680,6 @@
        u64 system_alloc_profile;
 
        void *bdev_holder;
-};
-
-struct btrfs_leaf_ref_tree {
-       struct rb_root root;
-       struct btrfs_leaf_ref *last;
-       struct list_head list;
-       spinlock_t lock;
 };
 
 /*
diff -r 47aa0c51998a disk-io.c
--- a/disk-io.c Thu Sep 25 16:00:36 2008 +0800
+++ b/disk-io.c Thu Sep 25 16:02:11 2008 +0800
@@ -1430,6 +1430,8 @@
                             fs_info->btree_inode->i_mapping, GFP_NOFS);
        fs_info->do_barriers = 1;
 
+       btrfs_leaf_ref_tree_init(&fs_info->shared_ref_tree);
+
        BTRFS_I(fs_info->btree_inode)->root = tree_root;
        memset(&BTRFS_I(fs_info->btree_inode)->location, 0,
               sizeof(struct btrfs_key));
diff -r 47aa0c51998a extent-tree.c
--- a/extent-tree.c     Thu Sep 25 16:00:36 2008 +0800
+++ b/extent-tree.c     Thu Sep 25 16:02:11 2008 +0800
@@ -1091,15 +1091,25 @@
 int btrfs_cache_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                    struct extent_buffer *buf, u32 nr_extents)
 {
-       u32 nritems;
        struct btrfs_key key;
        struct btrfs_file_extent_item *fi;
-       int i;
-       int level;
-       int ret = 0;
+       u64 root_gen;
+       u32 nritems;
+       int i;
+       int level;
+       int ret = 0;
+       int shared = 0;
 
        if (!root->ref_cows)
                return 0;
+
+       if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) {
+               shared = 0;
+               root_gen = root->root_key.offset;
+       } else {
+               shared = 1;
+               root_gen = trans->transid - 1;
+       }
 
        level = btrfs_header_level(buf);
        nritems = btrfs_header_nritems(buf);
@@ -1114,7 +1124,7 @@
                        goto out;
                }
 
-               ref->root_gen = root->root_key.offset;
+               ref->root_gen = root_gen;
                ref->bytenr = buf->start;
                ref->owner = btrfs_header_owner(buf);
                ref->generation = btrfs_header_generation(buf);
@@ -1143,8 +1153,7 @@
                        info++;
                }
 
-               BUG_ON(!root->ref_tree);
-               ret = btrfs_add_leaf_ref(root, ref);
+               ret = btrfs_add_leaf_ref(root, ref, shared);
                WARN_ON(ret);
                btrfs_free_leaf_ref(root, ref);
        }
diff -r 47aa0c51998a ref-cache.c
--- a/ref-cache.c       Thu Sep 25 16:00:36 2008 +0800
+++ b/ref-cache.c       Thu Sep 25 16:02:11 2008 +0800
@@ -78,7 +78,6 @@
        }
 
        entry = rb_entry(node, struct btrfs_leaf_ref, rb_node);
-       entry->in_tree = 1;
        rb_link_node(node, parent, p);
        rb_insert_color(node, root);
        return NULL;
@@ -103,23 +102,29 @@
        return NULL;
 }
 
-int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen)
+int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen,
+                          int shared)
 {
        struct btrfs_leaf_ref *ref = NULL;
        struct btrfs_leaf_ref_tree *tree = root->ref_tree;
 
+       if (shared)
+               tree = &root->fs_info->shared_ref_tree;
        if (!tree)
                return 0;
 
        spin_lock(&tree->lock);
        while(!list_empty(&tree->list)) {
                ref = list_entry(tree->list.next, struct btrfs_leaf_ref, list);
-               BUG_ON(!ref->in_tree);
+               BUG_ON(ref->tree != tree);
                if (ref->root_gen > max_root_gen)
                        break;
+               if (!xchg(&ref->in_tree, 0)) {
+                       cond_resched_lock(&tree->lock);
+                       continue;
+               }
 
                rb_erase(&ref->rb_node, &tree->root);
-               ref->in_tree = 0;
                list_del_init(&ref->list);
 
                spin_unlock(&tree->lock);
@@ -137,25 +142,34 @@
        struct rb_node *rb;
        struct btrfs_leaf_ref *ref = NULL;
        struct btrfs_leaf_ref_tree *tree = root->ref_tree;
-
-       if (!tree)
-               return NULL;
-
-       spin_lock(&tree->lock);
-       rb = tree_search(&tree->root, bytenr);
-       if (rb)
-               ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node);
-       if (ref)
-               atomic_inc(&ref->usage);
-       spin_unlock(&tree->lock);
-       return ref;
+again:
+       if (tree) {
+               spin_lock(&tree->lock);
+               rb = tree_search(&tree->root, bytenr);
+               if (rb)
+                       ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node);
+               if (ref)
+                       atomic_inc(&ref->usage);
+               spin_unlock(&tree->lock);
+               if (ref)
+                       return ref;
+       }
+       if (tree != &root->fs_info->shared_ref_tree) {
+               tree = &root->fs_info->shared_ref_tree;
+               goto again;
+       }
+       return NULL;
 }
 
-int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
+int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref,
+                      int shared)
 {
        int ret = 0;
        struct rb_node *rb;
        struct btrfs_leaf_ref_tree *tree = root->ref_tree;
+
+       if (shared)
+               tree = &root->fs_info->shared_ref_tree;
 
        spin_lock(&tree->lock);
        rb = tree_insert(&tree->root, ref->bytenr, &ref->rb_node);
@@ -163,6 +177,8 @@
                ret = -EEXIST;
        } else {
                atomic_inc(&ref->usage);
+               ref->tree = tree;
+               ref->in_tree = 1;
                list_add_tail(&ref->list, &tree->list);
        }
        spin_unlock(&tree->lock);
@@ -171,13 +187,15 @@
 
 int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
 {
-       struct btrfs_leaf_ref_tree *tree = root->ref_tree;
+       struct btrfs_leaf_ref_tree *tree;
 
-       BUG_ON(!ref->in_tree);
+       if (!xchg(&ref->in_tree, 0))
+               return 0;
+
+       tree = ref->tree;
        spin_lock(&tree->lock);
 
        rb_erase(&ref->rb_node, &tree->root);
-       ref->in_tree = 0;
        list_del_init(&ref->list);
 
        spin_unlock(&tree->lock);
diff -r 47aa0c51998a ref-cache.h
--- a/ref-cache.h       Thu Sep 25 16:00:36 2008 +0800
+++ b/ref-cache.h       Thu Sep 25 16:02:11 2008 +0800
@@ -27,6 +27,7 @@
 
 struct btrfs_leaf_ref {
        struct rb_node rb_node;
+       struct btrfs_leaf_ref_tree *tree;
        int in_tree;
        atomic_t usage;
 
@@ -64,8 +65,10 @@
 void btrfs_free_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref);
 struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root,
                                             u64 bytenr);
-int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref);
-int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen);
+int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref,
+                      int shared);
+int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen,
+                          int shared);
 int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref);
 
 #endif
diff -r 47aa0c51998a transaction.c
--- a/transaction.c     Thu Sep 25 16:00:36 2008 +0800
+++ b/transaction.c     Thu Sep 25 16:02:11 2008 +0800
@@ -650,7 +650,7 @@
                ret = btrfs_end_transaction(trans, tree_root);
                BUG_ON(ret);
 
-               ret = btrfs_remove_leaf_refs(root, max_useless);
+               ret = btrfs_remove_leaf_refs(root, max_useless, 0);
                BUG_ON(ret);
 
                free_extent_buffer(dirty->root->node);
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to