diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-05-18 13:28:27 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-05-18 13:28:27 -0400 |
commit | de428b63b16f9c74a24228a517713e8c65f79475 (patch) | |
tree | 0bb56423173f59e6237cf0cbc8052f72fb997347 | |
parent | 098f59c2512426926722a96f82af127bd91fb5e4 (diff) |
Btrfs: allocator optimizations, truncate readahead
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/ctree.h | 2 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 12 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 76 | ||||
-rw-r--r-- | fs/btrfs/super.c | 76 |
4 files changed, 129 insertions, 37 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index d8caeba5d758..5830b4333d83 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1081,7 +1081,7 @@ static inline void btrfs_mark_buffer_dirty(struct buffer_head *bh) | |||
1081 | struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | 1081 | struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, |
1082 | struct btrfs_block_group_cache | 1082 | struct btrfs_block_group_cache |
1083 | *hint, u64 search_start, | 1083 | *hint, u64 search_start, |
1084 | int data); | 1084 | int data, int owner); |
1085 | int btrfs_inc_root_ref(struct btrfs_trans_handle *trans, | 1085 | int btrfs_inc_root_ref(struct btrfs_trans_handle *trans, |
1086 | struct btrfs_root *root); | 1086 | struct btrfs_root *root); |
1087 | struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | 1087 | struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 678456d1e2f9..4c0262b57664 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -257,24 +257,30 @@ static struct address_space_operations btree_aops = { | |||
257 | int readahead_tree_block(struct btrfs_root *root, u64 blocknr) | 257 | int readahead_tree_block(struct btrfs_root *root, u64 blocknr) |
258 | { | 258 | { |
259 | struct buffer_head *bh = NULL; | 259 | struct buffer_head *bh = NULL; |
260 | int ret = 0; | ||
260 | 261 | ||
261 | bh = btrfs_find_create_tree_block(root, blocknr); | 262 | bh = btrfs_find_create_tree_block(root, blocknr); |
262 | if (!bh) | 263 | if (!bh) |
263 | return 0; | 264 | return 0; |
264 | if (buffer_uptodate(bh)) | 265 | if (buffer_uptodate(bh)) { |
266 | ret = 1; | ||
265 | goto done; | 267 | goto done; |
266 | if (test_set_buffer_locked(bh)) | 268 | } |
269 | if (test_set_buffer_locked(bh)) { | ||
270 | ret = 1; | ||
267 | goto done; | 271 | goto done; |
272 | } | ||
268 | if (!buffer_uptodate(bh)) { | 273 | if (!buffer_uptodate(bh)) { |
269 | get_bh(bh); | 274 | get_bh(bh); |
270 | bh->b_end_io = end_buffer_read_sync; | 275 | bh->b_end_io = end_buffer_read_sync; |
271 | submit_bh(READ, bh); | 276 | submit_bh(READ, bh); |
272 | } else { | 277 | } else { |
273 | unlock_buffer(bh); | 278 | unlock_buffer(bh); |
279 | ret = 1; | ||
274 | } | 280 | } |
275 | done: | 281 | done: |
276 | brelse(bh); | 282 | brelse(bh); |
277 | return 0; | 283 | return ret; |
278 | } | 284 | } |
279 | 285 | ||
280 | struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr) | 286 | struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr) |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 1497ff98f0d3..e3c6bfea3751 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -12,6 +12,33 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct | |||
12 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct | 12 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct |
13 | btrfs_root *extent_root); | 13 | btrfs_root *extent_root); |
14 | 14 | ||
15 | static void reada_extent_leaves(struct btrfs_root *root, | ||
16 | struct btrfs_path *path, u64 limit) | ||
17 | { | ||
18 | struct btrfs_node *node; | ||
19 | int i; | ||
20 | int nritems; | ||
21 | u64 item_objectid; | ||
22 | u64 blocknr; | ||
23 | int slot; | ||
24 | int ret; | ||
25 | |||
26 | if (!path->nodes[1]) | ||
27 | return; | ||
28 | node = btrfs_buffer_node(path->nodes[1]); | ||
29 | slot = path->slots[1] + 1; | ||
30 | nritems = btrfs_header_nritems(&node->header); | ||
31 | for (i = slot; i < nritems && i < slot + 8; i++) { | ||
32 | item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key); | ||
33 | if (item_objectid > limit) | ||
34 | break; | ||
35 | blocknr = btrfs_node_blockptr(node, i); | ||
36 | ret = readahead_tree_block(root, blocknr); | ||
37 | if (ret) | ||
38 | break; | ||
39 | } | ||
40 | } | ||
41 | |||
15 | static int cache_block_group(struct btrfs_root *root, | 42 | static int cache_block_group(struct btrfs_root *root, |
16 | struct btrfs_block_group_cache *block_group) | 43 | struct btrfs_block_group_cache *block_group) |
17 | { | 44 | { |
@@ -24,6 +51,7 @@ static int cache_block_group(struct btrfs_root *root, | |||
24 | u64 i; | 51 | u64 i; |
25 | u64 last = 0; | 52 | u64 last = 0; |
26 | u64 hole_size; | 53 | u64 hole_size; |
54 | u64 limit; | ||
27 | int found = 0; | 55 | int found = 0; |
28 | 56 | ||
29 | root = root->fs_info->extent_root; | 57 | root = root->fs_info->extent_root; |
@@ -46,14 +74,17 @@ printk("cache block group %Lu\n", block_group->key.objectid); | |||
46 | return ret; | 74 | return ret; |
47 | if (ret && path->slots[0] > 0) | 75 | if (ret && path->slots[0] > 0) |
48 | path->slots[0]--; | 76 | path->slots[0]--; |
77 | limit = block_group->key.objectid + block_group->key.offset; | ||
78 | reada_extent_leaves(root, path, limit); | ||
49 | while(1) { | 79 | while(1) { |
50 | leaf = btrfs_buffer_leaf(path->nodes[0]); | 80 | leaf = btrfs_buffer_leaf(path->nodes[0]); |
51 | slot = path->slots[0]; | 81 | slot = path->slots[0]; |
52 | if (slot >= btrfs_header_nritems(&leaf->header)) { | 82 | if (slot >= btrfs_header_nritems(&leaf->header)) { |
83 | reada_extent_leaves(root, path, limit); | ||
53 | ret = btrfs_next_leaf(root, path); | 84 | ret = btrfs_next_leaf(root, path); |
54 | if (ret == 0) | 85 | if (ret == 0) { |
55 | continue; | 86 | continue; |
56 | else { | 87 | } else { |
57 | if (found) { | 88 | if (found) { |
58 | hole_size = block_group->key.objectid + | 89 | hole_size = block_group->key.objectid + |
59 | block_group->key.offset - last; | 90 | block_group->key.offset - last; |
@@ -187,7 +218,7 @@ new_group: | |||
187 | return max((*cache_ret)->last_alloc, search_start); | 218 | return max((*cache_ret)->last_alloc, search_start); |
188 | } | 219 | } |
189 | cache = btrfs_find_block_group(root, cache, | 220 | cache = btrfs_find_block_group(root, cache, |
190 | last + cache->key.offset - 1, 0); | 221 | last + cache->key.offset - 1, 0, 0); |
191 | *cache_ret = cache; | 222 | *cache_ret = cache; |
192 | goto again; | 223 | goto again; |
193 | } | 224 | } |
@@ -195,7 +226,7 @@ new_group: | |||
195 | struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | 226 | struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, |
196 | struct btrfs_block_group_cache | 227 | struct btrfs_block_group_cache |
197 | *hint, u64 search_start, | 228 | *hint, u64 search_start, |
198 | int data) | 229 | int data, int owner) |
199 | { | 230 | { |
200 | struct btrfs_block_group_cache *cache[8]; | 231 | struct btrfs_block_group_cache *cache[8]; |
201 | struct btrfs_block_group_cache *found_group = NULL; | 232 | struct btrfs_block_group_cache *found_group = NULL; |
@@ -207,6 +238,10 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
207 | int i; | 238 | int i; |
208 | int ret; | 239 | int ret; |
209 | int full_search = 0; | 240 | int full_search = 0; |
241 | int factor = 8; | ||
242 | |||
243 | if (!owner) | ||
244 | factor = 5; | ||
210 | 245 | ||
211 | if (data) | 246 | if (data) |
212 | radix = &info->block_group_data_radix; | 247 | radix = &info->block_group_data_radix; |
@@ -219,14 +254,14 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
219 | if (shint->data == data) { | 254 | if (shint->data == data) { |
220 | used = btrfs_block_group_used(&shint->item); | 255 | used = btrfs_block_group_used(&shint->item); |
221 | if (used + shint->pinned < | 256 | if (used + shint->pinned < |
222 | (shint->key.offset * 8) / 10) { | 257 | (shint->key.offset * factor) / 10) { |
223 | return shint; | 258 | return shint; |
224 | } | 259 | } |
225 | } | 260 | } |
226 | } | 261 | } |
227 | if (hint && hint->data == data) { | 262 | if (hint && hint->data == data) { |
228 | used = btrfs_block_group_used(&hint->item); | 263 | used = btrfs_block_group_used(&hint->item); |
229 | if (used + hint->pinned < (hint->key.offset * 8) / 10) { | 264 | if (used + hint->pinned < (hint->key.offset * factor) / 10) { |
230 | return hint; | 265 | return hint; |
231 | } | 266 | } |
232 | if (used >= (hint->key.offset * 8) / 10) { | 267 | if (used >= (hint->key.offset * 8) / 10) { |
@@ -261,7 +296,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
261 | cache[i]->key.offset; | 296 | cache[i]->key.offset; |
262 | used = btrfs_block_group_used(&cache[i]->item); | 297 | used = btrfs_block_group_used(&cache[i]->item); |
263 | if (used + cache[i]->pinned < | 298 | if (used + cache[i]->pinned < |
264 | (cache[i]->key.offset * 8) / 10) { | 299 | (cache[i]->key.offset * factor) / 10) { |
265 | found_group = cache[i]; | 300 | found_group = cache[i]; |
266 | goto found; | 301 | goto found; |
267 | } | 302 | } |
@@ -272,6 +307,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
272 | BTRFS_BLOCK_GROUP_AVAIL); | 307 | BTRFS_BLOCK_GROUP_AVAIL); |
273 | } | 308 | } |
274 | } | 309 | } |
310 | cond_resched(); | ||
275 | } | 311 | } |
276 | last = hint_last; | 312 | last = hint_last; |
277 | again: | 313 | again: |
@@ -295,13 +331,16 @@ again: | |||
295 | BTRFS_BLOCK_GROUP_AVAIL); | 331 | BTRFS_BLOCK_GROUP_AVAIL); |
296 | } | 332 | } |
297 | } | 333 | } |
334 | cond_resched(); | ||
298 | } | 335 | } |
299 | if (!full_search) { | 336 | if (!full_search) { |
337 | printk("find block group doing full search data %d start %Lu\n", data, search_start); | ||
300 | last = search_start; | 338 | last = search_start; |
301 | full_search = 1; | 339 | full_search = 1; |
302 | goto again; | 340 | goto again; |
303 | } | 341 | } |
304 | if (!found_group) { | 342 | if (!found_group) { |
343 | printk("find block group bailing to zero data %d\n", data); | ||
305 | ret = radix_tree_gang_lookup(radix, | 344 | ret = radix_tree_gang_lookup(radix, |
306 | (void **)&found_group, 0, 1); | 345 | (void **)&found_group, 0, 1); |
307 | BUG_ON(ret != 1); | 346 | BUG_ON(ret != 1); |
@@ -554,8 +593,8 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
554 | blocknr + i); | 593 | blocknr + i); |
555 | } | 594 | } |
556 | } | 595 | } |
557 | if (old_val < (cache->key.offset * 6) / 10 && | 596 | if (old_val < (cache->key.offset * 5) / 10 && |
558 | old_val + num >= (cache->key.offset * 6) / 10) { | 597 | old_val + num >= (cache->key.offset * 5) / 10) { |
559 | printk("group %Lu now available\n", cache->key.objectid); | 598 | printk("group %Lu now available\n", cache->key.objectid); |
560 | radix_tree_tag_set(cache->radix, | 599 | radix_tree_tag_set(cache->radix, |
561 | cache->key.objectid + | 600 | cache->key.objectid + |
@@ -842,6 +881,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
842 | int level; | 881 | int level; |
843 | struct btrfs_block_group_cache *block_group; | 882 | struct btrfs_block_group_cache *block_group; |
844 | int full_scan = 0; | 883 | int full_scan = 0; |
884 | u64 limit; | ||
845 | 885 | ||
846 | path = btrfs_alloc_path(); | 886 | path = btrfs_alloc_path(); |
847 | ins->flags = 0; | 887 | ins->flags = 0; |
@@ -858,11 +898,11 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
858 | if (search_start) { | 898 | if (search_start) { |
859 | block_group = lookup_block_group(info, search_start); | 899 | block_group = lookup_block_group(info, search_start); |
860 | block_group = btrfs_find_block_group(root, block_group, | 900 | block_group = btrfs_find_block_group(root, block_group, |
861 | search_start, data); | 901 | search_start, data, 1); |
862 | } else { | 902 | } else { |
863 | block_group = btrfs_find_block_group(root, | 903 | block_group = btrfs_find_block_group(root, |
864 | trans->block_group, 0, | 904 | trans->block_group, 0, |
865 | data); | 905 | data, 1); |
866 | } | 906 | } |
867 | 907 | ||
868 | check_failed: | 908 | check_failed: |
@@ -916,6 +956,12 @@ check_failed: | |||
916 | info->extent_tree_prealloc_nr = 0; | 956 | info->extent_tree_prealloc_nr = 0; |
917 | total_found = 0; | 957 | total_found = 0; |
918 | } | 958 | } |
959 | if (start_found) | ||
960 | limit = last_block + | ||
961 | block_group->key.offset / 2; | ||
962 | else | ||
963 | limit = search_start + | ||
964 | block_group->key.offset / 2; | ||
919 | ret = btrfs_next_leaf(root, path); | 965 | ret = btrfs_next_leaf(root, path); |
920 | if (ret == 0) | 966 | if (ret == 0) |
921 | continue; | 967 | continue; |
@@ -960,6 +1006,7 @@ check_failed: | |||
960 | } | 1006 | } |
961 | next: | 1007 | next: |
962 | path->slots[0]++; | 1008 | path->slots[0]++; |
1009 | cond_resched(); | ||
963 | } | 1010 | } |
964 | // FIXME -ENOSPC | 1011 | // FIXME -ENOSPC |
965 | check_pending: | 1012 | check_pending: |
@@ -1049,7 +1096,8 @@ printk("doing full scan!\n"); | |||
1049 | block_group = lookup_block_group(info, search_start); | 1096 | block_group = lookup_block_group(info, search_start); |
1050 | if (!full_scan) | 1097 | if (!full_scan) |
1051 | block_group = btrfs_find_block_group(root, block_group, | 1098 | block_group = btrfs_find_block_group(root, block_group, |
1052 | search_start, data); | 1099 | search_start, data, 0); |
1100 | cond_resched(); | ||
1053 | goto check_failed; | 1101 | goto check_failed; |
1054 | 1102 | ||
1055 | error: | 1103 | error: |
@@ -1102,7 +1150,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1102 | * in the correct block group. | 1150 | * in the correct block group. |
1103 | */ | 1151 | */ |
1104 | if (data) { | 1152 | if (data) { |
1105 | ret = find_free_extent(trans, root, 0, search_start, | 1153 | ret = find_free_extent(trans, root, 0, 0, |
1106 | search_end, &prealloc_key, 0); | 1154 | search_end, &prealloc_key, 0); |
1107 | if (ret) { | 1155 | if (ret) { |
1108 | return ret; | 1156 | return ret; |
@@ -1173,7 +1221,7 @@ struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
1173 | struct buffer_head *buf; | 1221 | struct buffer_head *buf; |
1174 | 1222 | ||
1175 | ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, | 1223 | ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, |
1176 | 1, 0, (unsigned long)-1, &ins, 0); | 1224 | 1, hint, (unsigned long)-1, &ins, 0); |
1177 | if (ret) { | 1225 | if (ret) { |
1178 | BUG(); | 1226 | BUG(); |
1179 | return NULL; | 1227 | return NULL; |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index eaa48f09d1c4..0f79490123cf 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -351,6 +351,35 @@ static int btrfs_free_inode(struct btrfs_trans_handle *trans, | |||
351 | return ret; | 351 | return ret; |
352 | } | 352 | } |
353 | 353 | ||
354 | static void reada_truncate(struct btrfs_root *root, struct btrfs_path *path, | ||
355 | u64 objectid) | ||
356 | { | ||
357 | struct btrfs_node *node; | ||
358 | int i; | ||
359 | int nritems; | ||
360 | u64 item_objectid; | ||
361 | u64 blocknr; | ||
362 | int slot; | ||
363 | int ret; | ||
364 | |||
365 | if (!path->nodes[1]) | ||
366 | return; | ||
367 | node = btrfs_buffer_node(path->nodes[1]); | ||
368 | slot = path->slots[1]; | ||
369 | if (slot == 0) | ||
370 | return; | ||
371 | nritems = btrfs_header_nritems(&node->header); | ||
372 | for (i = slot - 1; i >= 0; i--) { | ||
373 | item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key); | ||
374 | if (item_objectid != objectid) | ||
375 | break; | ||
376 | blocknr = btrfs_node_blockptr(node, i); | ||
377 | ret = readahead_tree_block(root, blocknr); | ||
378 | if (ret) | ||
379 | break; | ||
380 | } | ||
381 | } | ||
382 | |||
354 | static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | 383 | static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, |
355 | struct btrfs_root *root, | 384 | struct btrfs_root *root, |
356 | struct inode *inode) | 385 | struct inode *inode) |
@@ -386,6 +415,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
386 | BUG_ON(path->slots[0] == 0); | 415 | BUG_ON(path->slots[0] == 0); |
387 | path->slots[0]--; | 416 | path->slots[0]--; |
388 | } | 417 | } |
418 | reada_truncate(root, path, inode->i_ino); | ||
389 | leaf = btrfs_buffer_leaf(path->nodes[0]); | 419 | leaf = btrfs_buffer_leaf(path->nodes[0]); |
390 | found_key = &leaf->items[path->slots[0]].key; | 420 | found_key = &leaf->items[path->slots[0]].key; |
391 | if (btrfs_disk_key_objectid(found_key) != inode->i_ino) | 421 | if (btrfs_disk_key_objectid(found_key) != inode->i_ino) |
@@ -587,28 +617,30 @@ printk("adding new root for inode %lu root %p (found %p)\n", inode->i_ino, sub_r | |||
587 | return d_splice_alias(inode, dentry); | 617 | return d_splice_alias(inode, dentry); |
588 | } | 618 | } |
589 | 619 | ||
590 | static void reada_leaves(struct btrfs_root *root, struct btrfs_path *path) | 620 | static void reada_leaves(struct btrfs_root *root, struct btrfs_path *path, |
621 | u64 objectid) | ||
591 | { | 622 | { |
592 | struct btrfs_node *node; | 623 | struct btrfs_node *node; |
593 | int i; | 624 | int i; |
594 | int nritems; | 625 | u32 nritems; |
595 | u64 objectid; | ||
596 | u64 item_objectid; | 626 | u64 item_objectid; |
597 | u64 blocknr; | 627 | u64 blocknr; |
598 | int slot; | 628 | int slot; |
629 | int ret; | ||
599 | 630 | ||
600 | if (!path->nodes[1]) | 631 | if (!path->nodes[1]) |
601 | return; | 632 | return; |
602 | node = btrfs_buffer_node(path->nodes[1]); | 633 | node = btrfs_buffer_node(path->nodes[1]); |
603 | slot = path->slots[1]; | 634 | slot = path->slots[1]; |
604 | objectid = btrfs_disk_key_objectid(&node->ptrs[slot].key); | ||
605 | nritems = btrfs_header_nritems(&node->header); | 635 | nritems = btrfs_header_nritems(&node->header); |
606 | for (i = slot; i < nritems; i++) { | 636 | for (i = slot + 1; i < nritems; i++) { |
607 | item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key); | 637 | item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key); |
608 | if (item_objectid != objectid) | 638 | if (item_objectid != objectid) |
609 | break; | 639 | break; |
610 | blocknr = btrfs_node_blockptr(node, i); | 640 | blocknr = btrfs_node_blockptr(node, i); |
611 | readahead_tree_block(root, blocknr); | 641 | ret = readahead_tree_block(root, blocknr); |
642 | if (ret) | ||
643 | break; | ||
612 | } | 644 | } |
613 | } | 645 | } |
614 | 646 | ||
@@ -646,21 +678,20 @@ static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
646 | if (ret < 0) | 678 | if (ret < 0) |
647 | goto err; | 679 | goto err; |
648 | advance = 0; | 680 | advance = 0; |
649 | reada_leaves(root, path); | 681 | reada_leaves(root, path, inode->i_ino); |
650 | while(1) { | 682 | while(1) { |
651 | leaf = btrfs_buffer_leaf(path->nodes[0]); | 683 | leaf = btrfs_buffer_leaf(path->nodes[0]); |
652 | nritems = btrfs_header_nritems(&leaf->header); | 684 | nritems = btrfs_header_nritems(&leaf->header); |
653 | slot = path->slots[0]; | 685 | slot = path->slots[0]; |
654 | if (advance || slot >= nritems) { | 686 | if (advance || slot >= nritems) { |
655 | if (slot >= nritems -1) { | 687 | if (slot >= nritems -1) { |
688 | reada_leaves(root, path, inode->i_ino); | ||
656 | ret = btrfs_next_leaf(root, path); | 689 | ret = btrfs_next_leaf(root, path); |
657 | if (ret) | 690 | if (ret) |
658 | break; | 691 | break; |
659 | leaf = btrfs_buffer_leaf(path->nodes[0]); | 692 | leaf = btrfs_buffer_leaf(path->nodes[0]); |
660 | nritems = btrfs_header_nritems(&leaf->header); | 693 | nritems = btrfs_header_nritems(&leaf->header); |
661 | slot = path->slots[0]; | 694 | slot = path->slots[0]; |
662 | if (path->slots[1] == 0) | ||
663 | reada_leaves(root, path); | ||
664 | } else { | 695 | } else { |
665 | slot++; | 696 | slot++; |
666 | path->slots[0]++; | 697 | path->slots[0]++; |
@@ -805,13 +836,18 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
805 | struct btrfs_inode_item inode_item; | 836 | struct btrfs_inode_item inode_item; |
806 | struct btrfs_key *location; | 837 | struct btrfs_key *location; |
807 | int ret; | 838 | int ret; |
839 | int owner; | ||
808 | 840 | ||
809 | inode = new_inode(root->fs_info->sb); | 841 | inode = new_inode(root->fs_info->sb); |
810 | if (!inode) | 842 | if (!inode) |
811 | return ERR_PTR(-ENOMEM); | 843 | return ERR_PTR(-ENOMEM); |
812 | 844 | ||
813 | BTRFS_I(inode)->root = root; | 845 | BTRFS_I(inode)->root = root; |
814 | group = btrfs_find_block_group(root, group, 0, 0); | 846 | if (mode & S_IFDIR) |
847 | owner = 0; | ||
848 | else | ||
849 | owner = 1; | ||
850 | group = btrfs_find_block_group(root, group, 0, 0, owner); | ||
815 | BTRFS_I(inode)->block_group = group; | 851 | BTRFS_I(inode)->block_group = group; |
816 | 852 | ||
817 | inode->i_uid = current->fsuid; | 853 | inode->i_uid = current->fsuid; |
@@ -1562,7 +1598,7 @@ failed: | |||
1562 | static int drop_extents(struct btrfs_trans_handle *trans, | 1598 | static int drop_extents(struct btrfs_trans_handle *trans, |
1563 | struct btrfs_root *root, | 1599 | struct btrfs_root *root, |
1564 | struct inode *inode, | 1600 | struct inode *inode, |
1565 | u64 start, u64 end) | 1601 | u64 start, u64 end, u64 *hint_block) |
1566 | { | 1602 | { |
1567 | int ret; | 1603 | int ret; |
1568 | struct btrfs_key key; | 1604 | struct btrfs_key key; |
@@ -1659,17 +1695,14 @@ static int drop_extents(struct btrfs_trans_handle *trans, | |||
1659 | new_num = (start - key.offset) >> | 1695 | new_num = (start - key.offset) >> |
1660 | inode->i_blkbits; | 1696 | inode->i_blkbits; |
1661 | old_num = btrfs_file_extent_num_blocks(extent); | 1697 | old_num = btrfs_file_extent_num_blocks(extent); |
1698 | *hint_block = | ||
1699 | btrfs_file_extent_disk_blocknr(extent); | ||
1662 | inode->i_blocks -= (old_num - new_num) << 3; | 1700 | inode->i_blocks -= (old_num - new_num) << 3; |
1663 | btrfs_set_file_extent_num_blocks(extent, | 1701 | btrfs_set_file_extent_num_blocks(extent, |
1664 | new_num); | 1702 | new_num); |
1665 | mark_buffer_dirty(path->nodes[0]); | 1703 | mark_buffer_dirty(path->nodes[0]); |
1666 | } else { | 1704 | } else { |
1667 | WARN_ON(1); | 1705 | WARN_ON(1); |
1668 | /* | ||
1669 | ret = btrfs_truncate_item(trans, root, path, | ||
1670 | start - key.offset); | ||
1671 | BUG_ON(ret); | ||
1672 | */ | ||
1673 | } | 1706 | } |
1674 | } | 1707 | } |
1675 | if (!keep) { | 1708 | if (!keep) { |
@@ -1683,6 +1716,8 @@ static int drop_extents(struct btrfs_trans_handle *trans, | |||
1683 | btrfs_file_extent_disk_num_blocks(extent); | 1716 | btrfs_file_extent_disk_num_blocks(extent); |
1684 | extent_num_blocks = | 1717 | extent_num_blocks = |
1685 | btrfs_file_extent_num_blocks(extent); | 1718 | btrfs_file_extent_num_blocks(extent); |
1719 | *hint_block = | ||
1720 | btrfs_file_extent_disk_blocknr(extent); | ||
1686 | } | 1721 | } |
1687 | ret = btrfs_del_item(trans, root, path); | 1722 | ret = btrfs_del_item(trans, root, path); |
1688 | BUG_ON(ret); | 1723 | BUG_ON(ret); |
@@ -1831,6 +1866,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1831 | u64 start_pos; | 1866 | u64 start_pos; |
1832 | u64 num_blocks; | 1867 | u64 num_blocks; |
1833 | u64 alloc_extent_start; | 1868 | u64 alloc_extent_start; |
1869 | u64 hint_block; | ||
1834 | struct btrfs_trans_handle *trans; | 1870 | struct btrfs_trans_handle *trans; |
1835 | struct btrfs_key ins; | 1871 | struct btrfs_key ins; |
1836 | pinned[0] = NULL; | 1872 | pinned[0] = NULL; |
@@ -1871,6 +1907,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1871 | } | 1907 | } |
1872 | if (first_index != last_index && | 1908 | if (first_index != last_index && |
1873 | (last_index << PAGE_CACHE_SHIFT) < inode->i_size && | 1909 | (last_index << PAGE_CACHE_SHIFT) < inode->i_size && |
1910 | pos + count < inode->i_size && | ||
1874 | (count & (PAGE_CACHE_SIZE - 1))) { | 1911 | (count & (PAGE_CACHE_SIZE - 1))) { |
1875 | pinned[1] = grab_cache_page(inode->i_mapping, last_index); | 1912 | pinned[1] = grab_cache_page(inode->i_mapping, last_index); |
1876 | if (!PageUptodate(pinned[1])) { | 1913 | if (!PageUptodate(pinned[1])) { |
@@ -1892,18 +1929,20 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1892 | btrfs_set_trans_block_group(trans, inode); | 1929 | btrfs_set_trans_block_group(trans, inode); |
1893 | /* FIXME blocksize != 4096 */ | 1930 | /* FIXME blocksize != 4096 */ |
1894 | inode->i_blocks += num_blocks << 3; | 1931 | inode->i_blocks += num_blocks << 3; |
1932 | hint_block = 0; | ||
1895 | if (start_pos < inode->i_size) { | 1933 | if (start_pos < inode->i_size) { |
1896 | /* FIXME blocksize != pagesize */ | 1934 | /* FIXME blocksize != pagesize */ |
1897 | ret = drop_extents(trans, root, inode, | 1935 | ret = drop_extents(trans, root, inode, |
1898 | start_pos, | 1936 | start_pos, |
1899 | (pos + count + root->blocksize -1) & | 1937 | (pos + count + root->blocksize -1) & |
1900 | ~((u64)root->blocksize - 1)); | 1938 | ~((u64)root->blocksize - 1), &hint_block); |
1901 | BUG_ON(ret); | 1939 | BUG_ON(ret); |
1902 | } | 1940 | } |
1903 | if (inode->i_size >= PAGE_CACHE_SIZE || pos + count < inode->i_size || | 1941 | if (inode->i_size >= PAGE_CACHE_SIZE || pos + count < inode->i_size || |
1904 | pos + count - start_pos > BTRFS_MAX_INLINE_DATA_SIZE(root)) { | 1942 | pos + count - start_pos > BTRFS_MAX_INLINE_DATA_SIZE(root)) { |
1905 | ret = btrfs_alloc_extent(trans, root, inode->i_ino, | 1943 | ret = btrfs_alloc_extent(trans, root, inode->i_ino, |
1906 | num_blocks, 1, (u64)-1, &ins, 1); | 1944 | num_blocks, hint_block, (u64)-1, |
1945 | &ins, 1); | ||
1907 | BUG_ON(ret); | 1946 | BUG_ON(ret); |
1908 | ret = btrfs_insert_file_extent(trans, root, inode->i_ino, | 1947 | ret = btrfs_insert_file_extent(trans, root, inode->i_ino, |
1909 | start_pos, ins.objectid, ins.offset); | 1948 | start_pos, ins.objectid, ins.offset); |
@@ -2455,7 +2494,6 @@ static int btrfs_get_sb(struct file_system_type *fs_type, | |||
2455 | btrfs_fill_super, mnt); | 2494 | btrfs_fill_super, mnt); |
2456 | } | 2495 | } |
2457 | 2496 | ||
2458 | |||
2459 | static int btrfs_getattr(struct vfsmount *mnt, | 2497 | static int btrfs_getattr(struct vfsmount *mnt, |
2460 | struct dentry *dentry, struct kstat *stat) | 2498 | struct dentry *dentry, struct kstat *stat) |
2461 | { | 2499 | { |