diff options
-rw-r--r-- | fs/btrfs/ctree.h | 11 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 8 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 18 | ||||
-rw-r--r-- | fs/btrfs/file.c | 2 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 8 | ||||
-rw-r--r-- | fs/btrfs/ref-cache.c | 71 | ||||
-rw-r--r-- | fs/btrfs/ref-cache.h | 18 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 34 |
8 files changed, 61 insertions, 109 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 34ed23d64eb5..4eca0aa1ce74 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -594,7 +594,6 @@ struct btrfs_fs_info { | |||
594 | 594 | ||
595 | spinlock_t ref_cache_lock; | 595 | spinlock_t ref_cache_lock; |
596 | u64 total_ref_cache_size; | 596 | u64 total_ref_cache_size; |
597 | u64 running_ref_cache_size; | ||
598 | 597 | ||
599 | u64 avail_data_alloc_bits; | 598 | u64 avail_data_alloc_bits; |
600 | u64 avail_metadata_alloc_bits; | 599 | u64 avail_metadata_alloc_bits; |
@@ -606,10 +605,18 @@ struct btrfs_fs_info { | |||
606 | void *bdev_holder; | 605 | void *bdev_holder; |
607 | }; | 606 | }; |
608 | 607 | ||
608 | struct btrfs_leaf_ref_tree { | ||
609 | struct rb_root root; | ||
610 | struct btrfs_leaf_ref *last; | ||
611 | struct list_head list; | ||
612 | spinlock_t lock; | ||
613 | }; | ||
614 | |||
609 | /* | 615 | /* |
610 | * in ram representation of the tree. extent_root is used for all allocations | 616 | * in ram representation of the tree. extent_root is used for all allocations |
611 | * and for the extent tree extent_root root. | 617 | * and for the extent tree extent_root root. |
612 | */ | 618 | */ |
619 | struct dirty_root; | ||
613 | struct btrfs_root { | 620 | struct btrfs_root { |
614 | struct extent_buffer *node; | 621 | struct extent_buffer *node; |
615 | 622 | ||
@@ -618,6 +625,8 @@ struct btrfs_root { | |||
618 | 625 | ||
619 | struct extent_buffer *commit_root; | 626 | struct extent_buffer *commit_root; |
620 | struct btrfs_leaf_ref_tree *ref_tree; | 627 | struct btrfs_leaf_ref_tree *ref_tree; |
628 | struct btrfs_leaf_ref_tree ref_tree_struct; | ||
629 | struct dirty_root *dirty_root; | ||
621 | 630 | ||
622 | struct btrfs_root_item root_item; | 631 | struct btrfs_root_item root_item; |
623 | struct btrfs_key root_key; | 632 | struct btrfs_key root_key; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 4f0e1d06c384..eccdf13a95ac 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "print-tree.h" | 40 | #include "print-tree.h" |
41 | #include "async-thread.h" | 41 | #include "async-thread.h" |
42 | #include "locking.h" | 42 | #include "locking.h" |
43 | #include "ref-cache.h" | ||
43 | 44 | ||
44 | #if 0 | 45 | #if 0 |
45 | static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf) | 46 | static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf) |
@@ -737,6 +738,10 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, | |||
737 | spin_lock_init(&root->node_lock); | 738 | spin_lock_init(&root->node_lock); |
738 | spin_lock_init(&root->orphan_lock); | 739 | spin_lock_init(&root->orphan_lock); |
739 | mutex_init(&root->objectid_mutex); | 740 | mutex_init(&root->objectid_mutex); |
741 | |||
742 | btrfs_leaf_ref_tree_init(&root->ref_tree_struct); | ||
743 | root->ref_tree = &root->ref_tree_struct; | ||
744 | |||
740 | memset(&root->root_key, 0, sizeof(root->root_key)); | 745 | memset(&root->root_key, 0, sizeof(root->root_key)); |
741 | memset(&root->root_item, 0, sizeof(root->root_item)); | 746 | memset(&root->root_item, 0, sizeof(root->root_item)); |
742 | memset(&root->defrag_progress, 0, sizeof(root->defrag_progress)); | 747 | memset(&root->defrag_progress, 0, sizeof(root->defrag_progress)); |
@@ -1176,9 +1181,6 @@ static int transaction_kthread(void *arg) | |||
1176 | goto sleep; | 1181 | goto sleep; |
1177 | } | 1182 | } |
1178 | 1183 | ||
1179 | printk("btrfs: running reference cache size %Lu\n", | ||
1180 | root->fs_info->running_ref_cache_size); | ||
1181 | |||
1182 | now = get_seconds(); | 1184 | now = get_seconds(); |
1183 | if (now < cur->start_time || now - cur->start_time < 30) { | 1185 | if (now < cur->start_time || now - cur->start_time < 30) { |
1184 | mutex_unlock(&root->fs_info->trans_mutex); | 1186 | mutex_unlock(&root->fs_info->trans_mutex); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 7b24f1511654..0e294cfaa60c 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -1004,8 +1004,6 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
1004 | goto out; | 1004 | goto out; |
1005 | } | 1005 | } |
1006 | 1006 | ||
1007 | btrfs_item_key_to_cpu(buf, &ref->key, 0); | ||
1008 | |||
1009 | ref->bytenr = buf->start; | 1007 | ref->bytenr = buf->start; |
1010 | ref->owner = btrfs_header_owner(buf); | 1008 | ref->owner = btrfs_header_owner(buf); |
1011 | ref->generation = btrfs_header_generation(buf); | 1009 | ref->generation = btrfs_header_generation(buf); |
@@ -2387,19 +2385,15 @@ static void noinline reada_walk_down(struct btrfs_root *root, | |||
2387 | } | 2385 | } |
2388 | } | 2386 | } |
2389 | 2387 | ||
2390 | /* | ||
2391 | * we want to avoid as much random IO as we can with the alloc mutex | ||
2392 | * held, so drop the lock and do the lookup, then do it again with the | ||
2393 | * lock held. | ||
2394 | */ | ||
2395 | int drop_snap_lookup_refcount(struct btrfs_root *root, u64 start, u64 len, | 2388 | int drop_snap_lookup_refcount(struct btrfs_root *root, u64 start, u64 len, |
2396 | u32 *refs) | 2389 | u32 *refs) |
2397 | { | 2390 | { |
2391 | int ret; | ||
2398 | mutex_unlock(&root->fs_info->alloc_mutex); | 2392 | mutex_unlock(&root->fs_info->alloc_mutex); |
2399 | lookup_extent_ref(NULL, root, start, len, refs); | 2393 | ret = lookup_extent_ref(NULL, root, start, len, refs); |
2400 | cond_resched(); | 2394 | cond_resched(); |
2401 | mutex_lock(&root->fs_info->alloc_mutex); | 2395 | mutex_lock(&root->fs_info->alloc_mutex); |
2402 | return lookup_extent_ref(NULL, root, start, len, refs); | 2396 | return ret; |
2403 | } | 2397 | } |
2404 | 2398 | ||
2405 | /* | 2399 | /* |
@@ -2468,11 +2462,11 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans, | |||
2468 | BUG_ON(ret); | 2462 | BUG_ON(ret); |
2469 | continue; | 2463 | continue; |
2470 | } | 2464 | } |
2471 | 2465 | ||
2472 | if (*level == 1) { | 2466 | if (*level == 1) { |
2473 | struct btrfs_key key; | 2467 | struct btrfs_key key; |
2474 | btrfs_node_key_to_cpu(cur, &key, path->slots[*level]); | 2468 | btrfs_node_key_to_cpu(cur, &key, path->slots[*level]); |
2475 | ref = btrfs_lookup_leaf_ref(root, &key); | 2469 | ref = btrfs_lookup_leaf_ref(root, bytenr); |
2476 | if (ref) { | 2470 | if (ref) { |
2477 | ret = drop_leaf_ref(trans, root, ref); | 2471 | ret = drop_leaf_ref(trans, root, ref); |
2478 | BUG_ON(ret); | 2472 | BUG_ON(ret); |
@@ -2482,7 +2476,6 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans, | |||
2482 | break; | 2476 | break; |
2483 | } | 2477 | } |
2484 | } | 2478 | } |
2485 | |||
2486 | next = btrfs_find_tree_block(root, bytenr, blocksize); | 2479 | next = btrfs_find_tree_block(root, bytenr, blocksize); |
2487 | if (!next || !btrfs_buffer_uptodate(next, ptr_gen)) { | 2480 | if (!next || !btrfs_buffer_uptodate(next, ptr_gen)) { |
2488 | free_extent_buffer(next); | 2481 | free_extent_buffer(next); |
@@ -2672,6 +2665,7 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
2672 | ret = -EAGAIN; | 2665 | ret = -EAGAIN; |
2673 | break; | 2666 | break; |
2674 | } | 2667 | } |
2668 | wake_up(&root->fs_info->transaction_throttle); | ||
2675 | } | 2669 | } |
2676 | for (i = 0; i <= orig_level; i++) { | 2670 | for (i = 0; i <= orig_level; i++) { |
2677 | if (path->nodes[i]) { | 2671 | if (path->nodes[i]) { |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index e5ffb66ad320..3efec25e34b0 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -347,7 +347,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
347 | btrfs_update_inode(trans, root, inode); | 347 | btrfs_update_inode(trans, root, inode); |
348 | } | 348 | } |
349 | failed: | 349 | failed: |
350 | err = btrfs_end_transaction_throttle(trans, root); | 350 | err = btrfs_end_transaction(trans, root); |
351 | out_unlock: | 351 | out_unlock: |
352 | unlock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS); | 352 | unlock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS); |
353 | return err; | 353 | return err; |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index cf9534b79aba..4f977ea5497e 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -2482,7 +2482,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, | |||
2482 | btrfs_update_inode_block_group(trans, dir); | 2482 | btrfs_update_inode_block_group(trans, dir); |
2483 | out_unlock: | 2483 | out_unlock: |
2484 | nr = trans->blocks_used; | 2484 | nr = trans->blocks_used; |
2485 | btrfs_end_transaction_throttle(trans, root); | 2485 | btrfs_end_transaction(trans, root); |
2486 | fail: | 2486 | fail: |
2487 | if (drop_inode) { | 2487 | if (drop_inode) { |
2488 | inode_dec_link_count(inode); | 2488 | inode_dec_link_count(inode); |
@@ -2535,7 +2535,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, | |||
2535 | drop_inode = 1; | 2535 | drop_inode = 1; |
2536 | 2536 | ||
2537 | nr = trans->blocks_used; | 2537 | nr = trans->blocks_used; |
2538 | btrfs_end_transaction_throttle(trans, root); | 2538 | btrfs_end_transaction(trans, root); |
2539 | fail: | 2539 | fail: |
2540 | if (drop_inode) { | 2540 | if (drop_inode) { |
2541 | inode_dec_link_count(inode); | 2541 | inode_dec_link_count(inode); |
@@ -2609,7 +2609,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
2609 | 2609 | ||
2610 | out_fail: | 2610 | out_fail: |
2611 | nr = trans->blocks_used; | 2611 | nr = trans->blocks_used; |
2612 | btrfs_end_transaction_throttle(trans, root); | 2612 | btrfs_end_transaction(trans, root); |
2613 | 2613 | ||
2614 | out_unlock: | 2614 | out_unlock: |
2615 | if (drop_on_err) | 2615 | if (drop_on_err) |
@@ -3548,7 +3548,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, | |||
3548 | 3548 | ||
3549 | out_unlock: | 3549 | out_unlock: |
3550 | nr = trans->blocks_used; | 3550 | nr = trans->blocks_used; |
3551 | btrfs_end_transaction_throttle(trans, root); | 3551 | btrfs_end_transaction(trans, root); |
3552 | out_fail: | 3552 | out_fail: |
3553 | if (drop_inode) { | 3553 | if (drop_inode) { |
3554 | inode_dec_link_count(inode); | 3554 | inode_dec_link_count(inode); |
diff --git a/fs/btrfs/ref-cache.c b/fs/btrfs/ref-cache.c index 95a9faeb9dc4..ec9587784a3d 100644 --- a/fs/btrfs/ref-cache.c +++ b/fs/btrfs/ref-cache.c | |||
@@ -29,6 +29,7 @@ struct btrfs_leaf_ref *btrfs_alloc_leaf_ref(int nr_extents) | |||
29 | if (ref) { | 29 | if (ref) { |
30 | memset(ref, 0, sizeof(*ref)); | 30 | memset(ref, 0, sizeof(*ref)); |
31 | atomic_set(&ref->usage, 1); | 31 | atomic_set(&ref->usage, 1); |
32 | INIT_LIST_HEAD(&ref->list); | ||
32 | } | 33 | } |
33 | return ref; | 34 | return ref; |
34 | } | 35 | } |
@@ -44,40 +45,21 @@ void btrfs_free_leaf_ref(struct btrfs_leaf_ref *ref) | |||
44 | } | 45 | } |
45 | } | 46 | } |
46 | 47 | ||
47 | static int comp_keys(struct btrfs_key *k1, struct btrfs_key *k2) | 48 | static struct rb_node *tree_insert(struct rb_root *root, u64 bytenr, |
48 | { | ||
49 | if (k1->objectid > k2->objectid) | ||
50 | return 1; | ||
51 | if (k1->objectid < k2->objectid) | ||
52 | return -1; | ||
53 | if (k1->type > k2->type) | ||
54 | return 1; | ||
55 | if (k1->type < k2->type) | ||
56 | return -1; | ||
57 | if (k1->offset > k2->offset) | ||
58 | return 1; | ||
59 | if (k1->offset < k2->offset) | ||
60 | return -1; | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static struct rb_node *tree_insert(struct rb_root *root, struct btrfs_key *key, | ||
65 | struct rb_node *node) | 49 | struct rb_node *node) |
66 | { | 50 | { |
67 | struct rb_node ** p = &root->rb_node; | 51 | struct rb_node ** p = &root->rb_node; |
68 | struct rb_node * parent = NULL; | 52 | struct rb_node * parent = NULL; |
69 | struct btrfs_leaf_ref *entry; | 53 | struct btrfs_leaf_ref *entry; |
70 | int ret; | ||
71 | 54 | ||
72 | while(*p) { | 55 | while(*p) { |
73 | parent = *p; | 56 | parent = *p; |
74 | entry = rb_entry(parent, struct btrfs_leaf_ref, rb_node); | 57 | entry = rb_entry(parent, struct btrfs_leaf_ref, rb_node); |
75 | WARN_ON(!entry->in_tree); | 58 | WARN_ON(!entry->in_tree); |
76 | 59 | ||
77 | ret = comp_keys(key, &entry->key); | 60 | if (bytenr < entry->bytenr) |
78 | if (ret < 0) | ||
79 | p = &(*p)->rb_left; | 61 | p = &(*p)->rb_left; |
80 | else if (ret > 0) | 62 | else if (bytenr > entry->bytenr) |
81 | p = &(*p)->rb_right; | 63 | p = &(*p)->rb_right; |
82 | else | 64 | else |
83 | return parent; | 65 | return parent; |
@@ -90,20 +72,18 @@ static struct rb_node *tree_insert(struct rb_root *root, struct btrfs_key *key, | |||
90 | return NULL; | 72 | return NULL; |
91 | } | 73 | } |
92 | 74 | ||
93 | static struct rb_node *tree_search(struct rb_root *root, struct btrfs_key *key) | 75 | static struct rb_node *tree_search(struct rb_root *root, u64 bytenr) |
94 | { | 76 | { |
95 | struct rb_node * n = root->rb_node; | 77 | struct rb_node * n = root->rb_node; |
96 | struct btrfs_leaf_ref *entry; | 78 | struct btrfs_leaf_ref *entry; |
97 | int ret; | ||
98 | 79 | ||
99 | while(n) { | 80 | while(n) { |
100 | entry = rb_entry(n, struct btrfs_leaf_ref, rb_node); | 81 | entry = rb_entry(n, struct btrfs_leaf_ref, rb_node); |
101 | WARN_ON(!entry->in_tree); | 82 | WARN_ON(!entry->in_tree); |
102 | 83 | ||
103 | ret = comp_keys(key, &entry->key); | 84 | if (bytenr < entry->bytenr) |
104 | if (ret < 0) | ||
105 | n = n->rb_left; | 85 | n = n->rb_left; |
106 | else if (ret > 0) | 86 | else if (bytenr > entry->bytenr) |
107 | n = n->rb_right; | 87 | n = n->rb_right; |
108 | else | 88 | else |
109 | return n; | 89 | return n; |
@@ -122,11 +102,11 @@ int btrfs_remove_leaf_refs(struct btrfs_root *root) | |||
122 | 102 | ||
123 | spin_lock(&tree->lock); | 103 | spin_lock(&tree->lock); |
124 | while(!btrfs_leaf_ref_tree_empty(tree)) { | 104 | while(!btrfs_leaf_ref_tree_empty(tree)) { |
125 | tree->last = NULL; | ||
126 | rb = rb_first(&tree->root); | 105 | rb = rb_first(&tree->root); |
127 | ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node); | 106 | ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node); |
128 | rb_erase(&ref->rb_node, &tree->root); | 107 | rb_erase(&ref->rb_node, &tree->root); |
129 | ref->in_tree = 0; | 108 | ref->in_tree = 0; |
109 | list_del_init(&ref->list); | ||
130 | 110 | ||
131 | spin_unlock(&tree->lock); | 111 | spin_unlock(&tree->lock); |
132 | 112 | ||
@@ -140,7 +120,7 @@ int btrfs_remove_leaf_refs(struct btrfs_root *root) | |||
140 | } | 120 | } |
141 | 121 | ||
142 | struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root, | 122 | struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root, |
143 | struct btrfs_key *key) | 123 | u64 bytenr) |
144 | { | 124 | { |
145 | struct rb_node *rb; | 125 | struct rb_node *rb; |
146 | struct btrfs_leaf_ref *ref = NULL; | 126 | struct btrfs_leaf_ref *ref = NULL; |
@@ -150,15 +130,9 @@ struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root, | |||
150 | return NULL; | 130 | return NULL; |
151 | 131 | ||
152 | spin_lock(&tree->lock); | 132 | spin_lock(&tree->lock); |
153 | if (tree->last && comp_keys(key, &tree->last->key) == 0) { | 133 | rb = tree_search(&tree->root, bytenr); |
154 | ref = tree->last; | 134 | if (rb) |
155 | } else { | 135 | ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node); |
156 | rb = tree_search(&tree->root, key); | ||
157 | if (rb) { | ||
158 | ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node); | ||
159 | tree->last = ref; | ||
160 | } | ||
161 | } | ||
162 | if (ref) | 136 | if (ref) |
163 | atomic_inc(&ref->usage); | 137 | atomic_inc(&ref->usage); |
164 | spin_unlock(&tree->lock); | 138 | spin_unlock(&tree->lock); |
@@ -171,21 +145,17 @@ int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref) | |||
171 | struct rb_node *rb; | 145 | struct rb_node *rb; |
172 | size_t size = btrfs_leaf_ref_size(ref->nritems); | 146 | size_t size = btrfs_leaf_ref_size(ref->nritems); |
173 | struct btrfs_leaf_ref_tree *tree = root->ref_tree; | 147 | struct btrfs_leaf_ref_tree *tree = root->ref_tree; |
174 | struct btrfs_transaction *trans = root->fs_info->running_transaction; | ||
175 | 148 | ||
176 | spin_lock(&tree->lock); | 149 | spin_lock(&tree->lock); |
177 | rb = tree_insert(&tree->root, &ref->key, &ref->rb_node); | 150 | rb = tree_insert(&tree->root, ref->bytenr, &ref->rb_node); |
178 | if (rb) { | 151 | if (rb) { |
179 | ret = -EEXIST; | 152 | ret = -EEXIST; |
180 | } else { | 153 | } else { |
181 | spin_lock(&root->fs_info->ref_cache_lock); | 154 | spin_lock(&root->fs_info->ref_cache_lock); |
182 | root->fs_info->total_ref_cache_size += size; | 155 | root->fs_info->total_ref_cache_size += size; |
183 | if (trans && tree->generation == trans->transid) | ||
184 | root->fs_info->running_ref_cache_size += size; | ||
185 | spin_unlock(&root->fs_info->ref_cache_lock); | 156 | spin_unlock(&root->fs_info->ref_cache_lock); |
186 | |||
187 | tree->last = ref; | ||
188 | atomic_inc(&ref->usage); | 157 | atomic_inc(&ref->usage); |
158 | list_add_tail(&ref->list, &tree->list); | ||
189 | } | 159 | } |
190 | spin_unlock(&tree->lock); | 160 | spin_unlock(&tree->lock); |
191 | return ret; | 161 | return ret; |
@@ -195,28 +165,17 @@ int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref) | |||
195 | { | 165 | { |
196 | size_t size = btrfs_leaf_ref_size(ref->nritems); | 166 | size_t size = btrfs_leaf_ref_size(ref->nritems); |
197 | struct btrfs_leaf_ref_tree *tree = root->ref_tree; | 167 | struct btrfs_leaf_ref_tree *tree = root->ref_tree; |
198 | struct btrfs_transaction *trans = root->fs_info->running_transaction; | ||
199 | 168 | ||
200 | BUG_ON(!ref->in_tree); | 169 | BUG_ON(!ref->in_tree); |
201 | spin_lock(&tree->lock); | 170 | spin_lock(&tree->lock); |
202 | 171 | ||
203 | spin_lock(&root->fs_info->ref_cache_lock); | 172 | spin_lock(&root->fs_info->ref_cache_lock); |
204 | root->fs_info->total_ref_cache_size -= size; | 173 | root->fs_info->total_ref_cache_size -= size; |
205 | if (trans && tree->generation == trans->transid) | ||
206 | root->fs_info->running_ref_cache_size -= size; | ||
207 | spin_unlock(&root->fs_info->ref_cache_lock); | 174 | spin_unlock(&root->fs_info->ref_cache_lock); |
208 | 175 | ||
209 | if (tree->last == ref) { | ||
210 | struct rb_node *next = rb_next(&ref->rb_node); | ||
211 | if (next) { | ||
212 | tree->last = rb_entry(next, struct btrfs_leaf_ref, | ||
213 | rb_node); | ||
214 | } else | ||
215 | tree->last = NULL; | ||
216 | } | ||
217 | |||
218 | rb_erase(&ref->rb_node, &tree->root); | 176 | rb_erase(&ref->rb_node, &tree->root); |
219 | ref->in_tree = 0; | 177 | ref->in_tree = 0; |
178 | list_del_init(&ref->list); | ||
220 | 179 | ||
221 | spin_unlock(&tree->lock); | 180 | spin_unlock(&tree->lock); |
222 | 181 | ||
diff --git a/fs/btrfs/ref-cache.h b/fs/btrfs/ref-cache.h index 79ecc47110f2..823c049f72f1 100644 --- a/fs/btrfs/ref-cache.h +++ b/fs/btrfs/ref-cache.h | |||
@@ -15,6 +15,8 @@ | |||
15 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 15 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
16 | * Boston, MA 021110-1307, USA. | 16 | * Boston, MA 021110-1307, USA. |
17 | */ | 17 | */ |
18 | #ifndef __REFCACHE__ | ||
19 | #define __REFCACHE__ | ||
18 | 20 | ||
19 | struct btrfs_extent_info { | 21 | struct btrfs_extent_info { |
20 | u64 bytenr; | 22 | u64 bytenr; |
@@ -25,7 +27,6 @@ struct btrfs_extent_info { | |||
25 | 27 | ||
26 | struct btrfs_leaf_ref { | 28 | struct btrfs_leaf_ref { |
27 | struct rb_node rb_node; | 29 | struct rb_node rb_node; |
28 | struct btrfs_key key; | ||
29 | int in_tree; | 30 | int in_tree; |
30 | atomic_t usage; | 31 | atomic_t usage; |
31 | 32 | ||
@@ -33,14 +34,9 @@ struct btrfs_leaf_ref { | |||
33 | u64 owner; | 34 | u64 owner; |
34 | u64 generation; | 35 | u64 generation; |
35 | int nritems; | 36 | int nritems; |
36 | struct btrfs_extent_info extents[]; | ||
37 | }; | ||
38 | 37 | ||
39 | struct btrfs_leaf_ref_tree { | 38 | struct list_head list; |
40 | struct rb_root root; | 39 | struct btrfs_extent_info extents[]; |
41 | struct btrfs_leaf_ref *last; | ||
42 | u64 generation; | ||
43 | spinlock_t lock; | ||
44 | }; | 40 | }; |
45 | 41 | ||
46 | static inline size_t btrfs_leaf_ref_size(int nr_extents) | 42 | static inline size_t btrfs_leaf_ref_size(int nr_extents) |
@@ -53,7 +49,7 @@ static inline void btrfs_leaf_ref_tree_init(struct btrfs_leaf_ref_tree *tree) | |||
53 | { | 49 | { |
54 | tree->root.rb_node = NULL; | 50 | tree->root.rb_node = NULL; |
55 | tree->last = NULL; | 51 | tree->last = NULL; |
56 | tree->generation = 0; | 52 | INIT_LIST_HEAD(&tree->list); |
57 | spin_lock_init(&tree->lock); | 53 | spin_lock_init(&tree->lock); |
58 | } | 54 | } |
59 | 55 | ||
@@ -66,7 +62,9 @@ void btrfs_leaf_ref_tree_init(struct btrfs_leaf_ref_tree *tree); | |||
66 | struct btrfs_leaf_ref *btrfs_alloc_leaf_ref(int nr_extents); | 62 | struct btrfs_leaf_ref *btrfs_alloc_leaf_ref(int nr_extents); |
67 | void btrfs_free_leaf_ref(struct btrfs_leaf_ref *ref); | 63 | void btrfs_free_leaf_ref(struct btrfs_leaf_ref *ref); |
68 | struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root, | 64 | struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root, |
69 | struct btrfs_key *key); | 65 | u64 bytenr); |
70 | int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); | 66 | int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); |
71 | int btrfs_remove_leaf_refs(struct btrfs_root *root); | 67 | int btrfs_remove_leaf_refs(struct btrfs_root *root); |
72 | int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); | 68 | int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); |
69 | |||
70 | #endif | ||
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 543e5ee4033a..fcef3cae0c92 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -36,7 +36,6 @@ struct dirty_root { | |||
36 | struct list_head list; | 36 | struct list_head list; |
37 | struct btrfs_root *root; | 37 | struct btrfs_root *root; |
38 | struct btrfs_root *latest_root; | 38 | struct btrfs_root *latest_root; |
39 | struct btrfs_leaf_ref_tree ref_tree; | ||
40 | }; | 39 | }; |
41 | 40 | ||
42 | static noinline void put_transaction(struct btrfs_transaction *transaction) | 41 | static noinline void put_transaction(struct btrfs_transaction *transaction) |
@@ -108,13 +107,13 @@ static noinline int record_root_in_trans(struct btrfs_root *root) | |||
108 | 107 | ||
109 | dirty->latest_root = root; | 108 | dirty->latest_root = root; |
110 | INIT_LIST_HEAD(&dirty->list); | 109 | INIT_LIST_HEAD(&dirty->list); |
111 | btrfs_leaf_ref_tree_init(&dirty->ref_tree); | ||
112 | dirty->ref_tree.generation = running_trans_id; | ||
113 | 110 | ||
114 | root->commit_root = btrfs_root_node(root); | 111 | root->commit_root = btrfs_root_node(root); |
115 | root->ref_tree = &dirty->ref_tree; | 112 | root->dirty_root = dirty; |
116 | 113 | ||
117 | memcpy(dirty->root, root, sizeof(*root)); | 114 | memcpy(dirty->root, root, sizeof(*root)); |
115 | dirty->root->ref_tree = &root->ref_tree_struct; | ||
116 | |||
118 | spin_lock_init(&dirty->root->node_lock); | 117 | spin_lock_init(&dirty->root->node_lock); |
119 | mutex_init(&dirty->root->objectid_mutex); | 118 | mutex_init(&dirty->root->objectid_mutex); |
120 | dirty->root->node = root->commit_root; | 119 | dirty->root->node = root->commit_root; |
@@ -217,12 +216,13 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
217 | if (waitqueue_active(&cur_trans->writer_wait)) | 216 | if (waitqueue_active(&cur_trans->writer_wait)) |
218 | wake_up(&cur_trans->writer_wait); | 217 | wake_up(&cur_trans->writer_wait); |
219 | 218 | ||
220 | if (0 && cur_trans->in_commit && throttle) { | 219 | if (throttle && atomic_read(&root->fs_info->throttles)) { |
221 | DEFINE_WAIT(wait); | 220 | DEFINE_WAIT(wait); |
222 | mutex_unlock(&root->fs_info->trans_mutex); | 221 | mutex_unlock(&root->fs_info->trans_mutex); |
223 | prepare_to_wait(&root->fs_info->transaction_throttle, &wait, | 222 | prepare_to_wait(&root->fs_info->transaction_throttle, &wait, |
224 | TASK_UNINTERRUPTIBLE); | 223 | TASK_UNINTERRUPTIBLE); |
225 | schedule(); | 224 | if (atomic_read(&root->fs_info->throttles)) |
225 | schedule(); | ||
226 | finish_wait(&root->fs_info->transaction_throttle, &wait); | 226 | finish_wait(&root->fs_info->transaction_throttle, &wait); |
227 | mutex_lock(&root->fs_info->trans_mutex); | 227 | mutex_lock(&root->fs_info->trans_mutex); |
228 | } | 228 | } |
@@ -333,6 +333,8 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans, | |||
333 | list_del_init(next); | 333 | list_del_init(next); |
334 | root = list_entry(next, struct btrfs_root, dirty_list); | 334 | root = list_entry(next, struct btrfs_root, dirty_list); |
335 | update_cowonly_root(trans, root); | 335 | update_cowonly_root(trans, root); |
336 | if (root->fs_info->closing) | ||
337 | btrfs_remove_leaf_refs(root); | ||
336 | } | 338 | } |
337 | return 0; | 339 | return 0; |
338 | } | 340 | } |
@@ -346,10 +348,8 @@ int btrfs_add_dead_root(struct btrfs_root *root, | |||
346 | dirty = kmalloc(sizeof(*dirty), GFP_NOFS); | 348 | dirty = kmalloc(sizeof(*dirty), GFP_NOFS); |
347 | if (!dirty) | 349 | if (!dirty) |
348 | return -ENOMEM; | 350 | return -ENOMEM; |
349 | btrfs_leaf_ref_tree_init(&dirty->ref_tree); | ||
350 | dirty->root = root; | 351 | dirty->root = root; |
351 | dirty->latest_root = latest; | 352 | dirty->latest_root = latest; |
352 | root->ref_tree = NULL; | ||
353 | list_add(&dirty->list, dead_list); | 353 | list_add(&dirty->list, dead_list); |
354 | return 0; | 354 | return 0; |
355 | } | 355 | } |
@@ -379,18 +379,14 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
379 | BTRFS_ROOT_TRANS_TAG); | 379 | BTRFS_ROOT_TRANS_TAG); |
380 | 380 | ||
381 | BUG_ON(!root->ref_tree); | 381 | BUG_ON(!root->ref_tree); |
382 | dirty = container_of(root->ref_tree, struct dirty_root, | 382 | dirty = root->dirty_root; |
383 | ref_tree); | ||
384 | 383 | ||
385 | if (root->commit_root == root->node) { | 384 | if (root->commit_root == root->node) { |
386 | WARN_ON(root->node->start != | 385 | WARN_ON(root->node->start != |
387 | btrfs_root_bytenr(&root->root_item)); | 386 | btrfs_root_bytenr(&root->root_item)); |
388 | 387 | ||
389 | BUG_ON(!btrfs_leaf_ref_tree_empty( | ||
390 | root->ref_tree)); | ||
391 | free_extent_buffer(root->commit_root); | 388 | free_extent_buffer(root->commit_root); |
392 | root->commit_root = NULL; | 389 | root->commit_root = NULL; |
393 | root->ref_tree = NULL; | ||
394 | 390 | ||
395 | kfree(dirty->root); | 391 | kfree(dirty->root); |
396 | kfree(dirty); | 392 | kfree(dirty); |
@@ -410,7 +406,6 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
410 | sizeof(struct btrfs_disk_key)); | 406 | sizeof(struct btrfs_disk_key)); |
411 | root->root_item.drop_level = 0; | 407 | root->root_item.drop_level = 0; |
412 | root->commit_root = NULL; | 408 | root->commit_root = NULL; |
413 | root->ref_tree = NULL; | ||
414 | root->root_key.offset = root->fs_info->generation; | 409 | root->root_key.offset = root->fs_info->generation; |
415 | btrfs_set_root_bytenr(&root->root_item, | 410 | btrfs_set_root_bytenr(&root->root_item, |
416 | root->node->start); | 411 | root->node->start); |
@@ -485,7 +480,7 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root, | |||
485 | while(!list_empty(list)) { | 480 | while(!list_empty(list)) { |
486 | struct btrfs_root *root; | 481 | struct btrfs_root *root; |
487 | 482 | ||
488 | dirty = list_entry(list->next, struct dirty_root, list); | 483 | dirty = list_entry(list->prev, struct dirty_root, list); |
489 | list_del_init(&dirty->list); | 484 | list_del_init(&dirty->list); |
490 | 485 | ||
491 | num_bytes = btrfs_root_used(&dirty->root->root_item); | 486 | num_bytes = btrfs_root_used(&dirty->root->root_item); |
@@ -507,7 +502,7 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root, | |||
507 | if (err) | 502 | if (err) |
508 | ret = err; | 503 | ret = err; |
509 | nr = trans->blocks_used; | 504 | nr = trans->blocks_used; |
510 | ret = btrfs_end_transaction_throttle(trans, tree_root); | 505 | ret = btrfs_end_transaction(trans, tree_root); |
511 | BUG_ON(ret); | 506 | BUG_ON(ret); |
512 | 507 | ||
513 | mutex_unlock(&root->fs_info->drop_mutex); | 508 | mutex_unlock(&root->fs_info->drop_mutex); |
@@ -517,6 +512,7 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root, | |||
517 | } | 512 | } |
518 | BUG_ON(ret); | 513 | BUG_ON(ret); |
519 | atomic_dec(&root->fs_info->throttles); | 514 | atomic_dec(&root->fs_info->throttles); |
515 | wake_up(&root->fs_info->transaction_throttle); | ||
520 | 516 | ||
521 | mutex_lock(&root->fs_info->alloc_mutex); | 517 | mutex_lock(&root->fs_info->alloc_mutex); |
522 | num_bytes -= btrfs_root_used(&dirty->root->root_item); | 518 | num_bytes -= btrfs_root_used(&dirty->root->root_item); |
@@ -539,8 +535,6 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root, | |||
539 | ret = btrfs_end_transaction(trans, tree_root); | 535 | ret = btrfs_end_transaction(trans, tree_root); |
540 | BUG_ON(ret); | 536 | BUG_ON(ret); |
541 | 537 | ||
542 | btrfs_remove_leaf_refs(dirty->root); | ||
543 | |||
544 | free_extent_buffer(dirty->root->node); | 538 | free_extent_buffer(dirty->root->node); |
545 | kfree(dirty->root); | 539 | kfree(dirty->root); |
546 | kfree(dirty); | 540 | kfree(dirty); |
@@ -725,10 +719,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
725 | &dirty_fs_roots); | 719 | &dirty_fs_roots); |
726 | BUG_ON(ret); | 720 | BUG_ON(ret); |
727 | 721 | ||
728 | spin_lock(&root->fs_info->ref_cache_lock); | ||
729 | root->fs_info->running_ref_cache_size = 0; | ||
730 | spin_unlock(&root->fs_info->ref_cache_lock); | ||
731 | |||
732 | ret = btrfs_commit_tree_roots(trans, root); | 722 | ret = btrfs_commit_tree_roots(trans, root); |
733 | BUG_ON(ret); | 723 | BUG_ON(ret); |
734 | 724 | ||