Blame view
fs/btrfs/ctree.c
111 KB
6cbd55707 Btrfs: add GPLv2 |
1 |
/* |
d352ac681 Btrfs: add and im... |
2 |
* Copyright (C) 2007,2008 Oracle. All rights reserved. |
6cbd55707 Btrfs: add GPLv2 |
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ |
a6b6e75e0 Btrfs: Defrag onl... |
18 |
#include <linux/sched.h> |
5a0e3ad6a include cleanup: ... |
19 |
#include <linux/slab.h> |
eb60ceac0 Btrfs: Add backin... |
20 21 |
#include "ctree.h" #include "disk-io.h" |
7f5c15160 Add generation nu... |
22 |
#include "transaction.h" |
5f39d397d Btrfs: Create ext... |
23 |
#include "print-tree.h" |
925baeddc Btrfs: Start btre... |
24 |
#include "locking.h" |
9a8dd1502 Btrfs: Block size... |
25 |
|
e089f05c1 Btrfs: transactio... |
26 27 28 |
static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int level); static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root |
d4dbff953 Btrfs: support fo... |
29 |
*root, struct btrfs_key *ins_key, |
cc0c55384 Btrfs: Fix split_... |
30 |
struct btrfs_path *path, int data_size, int extend); |
5f39d397d Btrfs: Create ext... |
31 32 |
static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *dst, |
971a1f664 Btrfs: Don't empt... |
33 |
struct extent_buffer *src, int empty); |
5f39d397d Btrfs: Create ext... |
34 35 36 37 |
static int balance_node_right(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *dst_buf, struct extent_buffer *src_buf); |
e089f05c1 Btrfs: transactio... |
38 39 |
static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int level, int slot); |
d97e63b69 Btrfs: early exte... |
40 |
|
df24a2b9c Btrfs: early inli... |
41 |
struct btrfs_path *btrfs_alloc_path(void) |
2c90e5d65 Btrfs: still corr... |
42 |
{ |
df24a2b9c Btrfs: early inli... |
43 |
struct btrfs_path *path; |
e00f73086 Btrfs: remove btr... |
44 |
path = kmem_cache_zalloc(btrfs_path_cachep, GFP_NOFS); |
df24a2b9c Btrfs: early inli... |
45 |
return path; |
2c90e5d65 Btrfs: still corr... |
46 |
} |
b4ce94de9 Btrfs: Change btr... |
47 48 49 50 51 52 53 54 |
/* * set all locked nodes in the path to blocking locks. This should * be done before scheduling */ noinline void btrfs_set_path_blocking(struct btrfs_path *p) { int i; for (i = 0; i < BTRFS_MAX_LEVEL; i++) { |
bd681513f Btrfs: switch the... |
55 56 57 58 59 60 61 |
if (!p->nodes[i] || !p->locks[i]) continue; btrfs_set_lock_blocking_rw(p->nodes[i], p->locks[i]); if (p->locks[i] == BTRFS_READ_LOCK) p->locks[i] = BTRFS_READ_LOCK_BLOCKING; else if (p->locks[i] == BTRFS_WRITE_LOCK) p->locks[i] = BTRFS_WRITE_LOCK_BLOCKING; |
b4ce94de9 Btrfs: Change btr... |
62 63 64 65 66 |
} } /* * reset all the locked nodes in the patch to spinning locks. |
4008c04a0 Btrfs: make a loc... |
67 68 69 70 71 |
* * held is used to keep lockdep happy, when lockdep is enabled * we set held to a blocking lock before we go around and * retake all the spinlocks in the path. You can safely use NULL * for held |
b4ce94de9 Btrfs: Change btr... |
72 |
*/ |
4008c04a0 Btrfs: make a loc... |
73 |
noinline void btrfs_clear_path_blocking(struct btrfs_path *p, |
bd681513f Btrfs: switch the... |
74 |
struct extent_buffer *held, int held_rw) |
b4ce94de9 Btrfs: Change btr... |
75 76 |
{ int i; |
4008c04a0 Btrfs: make a loc... |
77 78 79 80 81 82 83 84 |
#ifdef CONFIG_DEBUG_LOCK_ALLOC /* lockdep really cares that we take all of these spinlocks * in the right order. If any of the locks in the path are not * currently blocking, it is going to complain. So, make really * really sure by forcing the path to blocking before we clear * the path blocking. */ |
bd681513f Btrfs: switch the... |
85 86 87 88 89 90 91 |
if (held) { btrfs_set_lock_blocking_rw(held, held_rw); if (held_rw == BTRFS_WRITE_LOCK) held_rw = BTRFS_WRITE_LOCK_BLOCKING; else if (held_rw == BTRFS_READ_LOCK) held_rw = BTRFS_READ_LOCK_BLOCKING; } |
4008c04a0 Btrfs: make a loc... |
92 93 94 95 |
btrfs_set_path_blocking(p); #endif for (i = BTRFS_MAX_LEVEL - 1; i >= 0; i--) { |
bd681513f Btrfs: switch the... |
96 97 98 99 100 101 102 |
if (p->nodes[i] && p->locks[i]) { btrfs_clear_lock_blocking_rw(p->nodes[i], p->locks[i]); if (p->locks[i] == BTRFS_WRITE_LOCK_BLOCKING) p->locks[i] = BTRFS_WRITE_LOCK; else if (p->locks[i] == BTRFS_READ_LOCK_BLOCKING) p->locks[i] = BTRFS_READ_LOCK; } |
b4ce94de9 Btrfs: Change btr... |
103 |
} |
4008c04a0 Btrfs: make a loc... |
104 105 106 |
#ifdef CONFIG_DEBUG_LOCK_ALLOC if (held) |
bd681513f Btrfs: switch the... |
107 |
btrfs_clear_lock_blocking_rw(held, held_rw); |
4008c04a0 Btrfs: make a loc... |
108 |
#endif |
b4ce94de9 Btrfs: Change btr... |
109 |
} |
d352ac681 Btrfs: add and im... |
110 |
/* this also releases the path */ |
df24a2b9c Btrfs: early inli... |
111 |
void btrfs_free_path(struct btrfs_path *p) |
be0e5c097 Btrfs: Initial ch... |
112 |
{ |
ff175d57f btrfs: Don't pass... |
113 114 |
if (!p) return; |
b3b4aa74b btrfs: drop unuse... |
115 |
btrfs_release_path(p); |
df24a2b9c Btrfs: early inli... |
116 |
kmem_cache_free(btrfs_path_cachep, p); |
be0e5c097 Btrfs: Initial ch... |
117 |
} |
d352ac681 Btrfs: add and im... |
118 119 120 121 122 123 |
/* * path release drops references on the extent buffers in the path * and it drops any locks held by this path * * It is safe to call this on paths that no locks or extent buffers held. */ |
b3b4aa74b btrfs: drop unuse... |
124 |
noinline void btrfs_release_path(struct btrfs_path *p) |
eb60ceac0 Btrfs: Add backin... |
125 126 |
{ int i; |
a21350115 Btrfs: Replace th... |
127 |
|
234b63a09 rename funcs and ... |
128 |
for (i = 0; i < BTRFS_MAX_LEVEL; i++) { |
3f157a2fd Btrfs: Online btr... |
129 |
p->slots[i] = 0; |
eb60ceac0 Btrfs: Add backin... |
130 |
if (!p->nodes[i]) |
925baeddc Btrfs: Start btre... |
131 132 |
continue; if (p->locks[i]) { |
bd681513f Btrfs: switch the... |
133 |
btrfs_tree_unlock_rw(p->nodes[i], p->locks[i]); |
925baeddc Btrfs: Start btre... |
134 135 |
p->locks[i] = 0; } |
5f39d397d Btrfs: Create ext... |
136 |
free_extent_buffer(p->nodes[i]); |
3f157a2fd Btrfs: Online btr... |
137 |
p->nodes[i] = NULL; |
eb60ceac0 Btrfs: Add backin... |
138 139 |
} } |
d352ac681 Btrfs: add and im... |
140 141 142 143 144 145 146 147 148 149 |
/* * safely gets a reference on the root node of a tree. A lock * is not taken, so a concurrent writer may put a different node * at the root of the tree. See btrfs_lock_root_node for the * looping required. * * The extent buffer returned by this has a reference taken, so * it won't disappear. It may stop being the root of the tree * at any time because there are no locks held. */ |
925baeddc Btrfs: Start btre... |
150 151 152 |
struct extent_buffer *btrfs_root_node(struct btrfs_root *root) { struct extent_buffer *eb; |
240f62c87 Btrfs: use RCU in... |
153 154 155 |
rcu_read_lock(); eb = rcu_dereference(root->node); |
925baeddc Btrfs: Start btre... |
156 |
extent_buffer_get(eb); |
240f62c87 Btrfs: use RCU in... |
157 |
rcu_read_unlock(); |
925baeddc Btrfs: Start btre... |
158 159 |
return eb; } |
d352ac681 Btrfs: add and im... |
160 161 162 163 |
/* loop around taking references on and locking the root node of the * tree until you end up with a lock on the root. A locked buffer * is returned, with a reference held. */ |
925baeddc Btrfs: Start btre... |
164 165 166 |
struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root) { struct extent_buffer *eb; |
d397712bc Btrfs: Fix checkp... |
167 |
while (1) { |
925baeddc Btrfs: Start btre... |
168 169 |
eb = btrfs_root_node(root); btrfs_tree_lock(eb); |
240f62c87 Btrfs: use RCU in... |
170 |
if (eb == root->node) |
925baeddc Btrfs: Start btre... |
171 |
break; |
925baeddc Btrfs: Start btre... |
172 173 174 175 176 |
btrfs_tree_unlock(eb); free_extent_buffer(eb); } return eb; } |
bd681513f Btrfs: switch the... |
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
/* loop around taking references on and locking the root node of the * tree until you end up with a lock on the root. A locked buffer * is returned, with a reference held. */ struct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root) { struct extent_buffer *eb; while (1) { eb = btrfs_root_node(root); btrfs_tree_read_lock(eb); if (eb == root->node) break; btrfs_tree_read_unlock(eb); free_extent_buffer(eb); } return eb; } |
d352ac681 Btrfs: add and im... |
195 196 197 198 |
/* cowonly root (everything not a reference counted cow subvolume), just get * put onto a simple dirty list. transaction.c walks this to make sure they * get properly updated on disk. */ |
0b86a832a Btrfs: Add suppor... |
199 200 201 202 203 204 205 |
static void add_root_to_dirty_list(struct btrfs_root *root) { if (root->track_dirty && list_empty(&root->dirty_list)) { list_add(&root->dirty_list, &root->fs_info->dirty_cowonly_roots); } } |
d352ac681 Btrfs: add and im... |
206 207 208 209 210 |
/* * used by snapshot creation to make a copy of a root for a tree with * a given objectid. The buffer with the new root node is returned in * cow_ret, and this func returns zero on success or a negative error code. */ |
be20aa9db Btrfs: Add mount ... |
211 212 213 214 215 216 |
int btrfs_copy_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, struct extent_buffer **cow_ret, u64 new_root_objectid) { struct extent_buffer *cow; |
be20aa9db Btrfs: Add mount ... |
217 218 |
int ret = 0; int level; |
5d4f98a28 Btrfs: Mixed back... |
219 |
struct btrfs_disk_key disk_key; |
be20aa9db Btrfs: Add mount ... |
220 221 222 223 224 225 |
WARN_ON(root->ref_cows && trans->transid != root->fs_info->running_transaction->transid); WARN_ON(root->ref_cows && trans->transid != root->last_trans); level = btrfs_header_level(buf); |
5d4f98a28 Btrfs: Mixed back... |
226 227 228 229 |
if (level == 0) btrfs_item_key(buf, &disk_key, 0); else btrfs_node_key(buf, &disk_key, 0); |
31840ae1a Btrfs: Full back ... |
230 |
|
5d4f98a28 Btrfs: Mixed back... |
231 232 233 234 |
cow = btrfs_alloc_free_block(trans, root, buf->len, 0, new_root_objectid, &disk_key, level, buf->start, 0); if (IS_ERR(cow)) |
be20aa9db Btrfs: Add mount ... |
235 236 237 238 239 |
return PTR_ERR(cow); copy_extent_buffer(cow, buf, 0, 0, cow->len); btrfs_set_header_bytenr(cow, cow->start); btrfs_set_header_generation(cow, trans->transid); |
5d4f98a28 Btrfs: Mixed back... |
240 241 242 243 244 245 246 |
btrfs_set_header_backref_rev(cow, BTRFS_MIXED_BACKREF_REV); btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN | BTRFS_HEADER_FLAG_RELOC); if (new_root_objectid == BTRFS_TREE_RELOC_OBJECTID) btrfs_set_header_flag(cow, BTRFS_HEADER_FLAG_RELOC); else btrfs_set_header_owner(cow, new_root_objectid); |
be20aa9db Btrfs: Add mount ... |
247 |
|
2b82032c3 Btrfs: Seed devic... |
248 249 250 |
write_extent_buffer(cow, root->fs_info->fsid, (unsigned long)btrfs_header_fsid(cow), BTRFS_FSID_SIZE); |
be20aa9db Btrfs: Add mount ... |
251 |
WARN_ON(btrfs_header_generation(buf) > trans->transid); |
5d4f98a28 Btrfs: Mixed back... |
252 253 254 255 |
if (new_root_objectid == BTRFS_TREE_RELOC_OBJECTID) ret = btrfs_inc_ref(trans, root, cow, 1); else ret = btrfs_inc_ref(trans, root, cow, 0); |
4aec2b523 kmalloc a few lar... |
256 |
|
be20aa9db Btrfs: Add mount ... |
257 258 259 260 261 262 263 |
if (ret) return ret; btrfs_mark_buffer_dirty(cow); *cow_ret = cow; return 0; } |
d352ac681 Btrfs: add and im... |
264 |
/* |
5d4f98a28 Btrfs: Mixed back... |
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
* check if the tree block can be shared by multiple trees */ int btrfs_block_can_be_shared(struct btrfs_root *root, struct extent_buffer *buf) { /* * Tree blocks not in refernece counted trees and tree roots * are never shared. If a block was allocated after the last * snapshot and the block was not allocated by tree relocation, * we know the block is not shared. */ if (root->ref_cows && buf != root->node && buf != root->commit_root && (btrfs_header_generation(buf) <= btrfs_root_last_snapshot(&root->root_item) || btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC))) return 1; #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 if (root->ref_cows && btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV) return 1; #endif return 0; } static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, |
f0486c68e Btrfs: Introduce ... |
293 294 |
struct extent_buffer *cow, int *last_ref) |
5d4f98a28 Btrfs: Mixed back... |
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
{ u64 refs; u64 owner; u64 flags; u64 new_flags = 0; int ret; /* * Backrefs update rules: * * Always use full backrefs for extent pointers in tree block * allocated by tree relocation. * * If a shared tree block is no longer referenced by its owner * tree (btrfs_header_owner(buf) == root->root_key.objectid), * use full backrefs for extent pointers in tree block. * * If a tree block is been relocating * (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID), * use full backrefs for extent pointers in tree block. * The reason for this is some operations (such as drop tree) * are only allowed for blocks use full backrefs. */ if (btrfs_block_can_be_shared(root, buf)) { ret = btrfs_lookup_extent_info(trans, root, buf->start, buf->len, &refs, &flags); BUG_ON(ret); BUG_ON(refs == 0); } else { refs = 1; if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID || btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV) flags = BTRFS_BLOCK_FLAG_FULL_BACKREF; else flags = 0; } owner = btrfs_header_owner(buf); BUG_ON(owner == BTRFS_TREE_RELOC_OBJECTID && !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)); if (refs > 1) { if ((owner == root->root_key.objectid || root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) && !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) { ret = btrfs_inc_ref(trans, root, buf, 1); BUG_ON(ret); if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) { ret = btrfs_dec_ref(trans, root, buf, 0); BUG_ON(ret); ret = btrfs_inc_ref(trans, root, cow, 1); BUG_ON(ret); } new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF; } else { if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) ret = btrfs_inc_ref(trans, root, cow, 1); else ret = btrfs_inc_ref(trans, root, cow, 0); BUG_ON(ret); } if (new_flags != 0) { ret = btrfs_set_disk_extent_flags(trans, root, buf->start, buf->len, new_flags, 0); BUG_ON(ret); } } else { if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) { if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) ret = btrfs_inc_ref(trans, root, cow, 1); else ret = btrfs_inc_ref(trans, root, cow, 0); BUG_ON(ret); ret = btrfs_dec_ref(trans, root, buf, 1); BUG_ON(ret); } clean_tree_block(trans, root, buf); |
f0486c68e Btrfs: Introduce ... |
380 |
*last_ref = 1; |
5d4f98a28 Btrfs: Mixed back... |
381 382 383 384 385 |
} return 0; } /* |
d397712bc Btrfs: Fix checkp... |
386 387 388 389 |
* does the dirty work in cow of a single block. The parent block (if * supplied) is updated to point to the new cow copy. The new buffer is marked * dirty and returned locked. If you modify the block it needs to be marked * dirty again. |
d352ac681 Btrfs: add and im... |
390 391 392 |
* * search_start -- an allocation hint for the new block * |
d397712bc Btrfs: Fix checkp... |
393 394 395 |
* empty_size -- a hint that you plan on doing more cow. This is the size in * bytes the allocator should try to find free next to the block it returns. * This is just a hint and may be ignored by the allocator. |
d352ac681 Btrfs: add and im... |
396 |
*/ |
d397712bc Btrfs: Fix checkp... |
397 |
static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, |
5f39d397d Btrfs: Create ext... |
398 399 400 401 |
struct btrfs_root *root, struct extent_buffer *buf, struct extent_buffer *parent, int parent_slot, struct extent_buffer **cow_ret, |
9fa8cfe70 Btrfs: don't prea... |
402 |
u64 search_start, u64 empty_size) |
02217ed29 Btrfs: early refe... |
403 |
{ |
5d4f98a28 Btrfs: Mixed back... |
404 |
struct btrfs_disk_key disk_key; |
5f39d397d Btrfs: Create ext... |
405 |
struct extent_buffer *cow; |
7bb86316c Btrfs: Add back p... |
406 |
int level; |
f0486c68e Btrfs: Introduce ... |
407 |
int last_ref = 0; |
925baeddc Btrfs: Start btre... |
408 |
int unlock_orig = 0; |
5d4f98a28 Btrfs: Mixed back... |
409 |
u64 parent_start; |
7bb86316c Btrfs: Add back p... |
410 |
|
925baeddc Btrfs: Start btre... |
411 412 |
if (*cow_ret == buf) unlock_orig = 1; |
b9447ef80 Btrfs: fix spinlo... |
413 |
btrfs_assert_tree_locked(buf); |
925baeddc Btrfs: Start btre... |
414 |
|
7bb86316c Btrfs: Add back p... |
415 416 |
WARN_ON(root->ref_cows && trans->transid != root->fs_info->running_transaction->transid); |
6702ed490 Btrfs: Add run ti... |
417 |
WARN_ON(root->ref_cows && trans->transid != root->last_trans); |
5f39d397d Btrfs: Create ext... |
418 |
|
7bb86316c Btrfs: Add back p... |
419 |
level = btrfs_header_level(buf); |
31840ae1a Btrfs: Full back ... |
420 |
|
5d4f98a28 Btrfs: Mixed back... |
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 |
if (level == 0) btrfs_item_key(buf, &disk_key, 0); else btrfs_node_key(buf, &disk_key, 0); if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) { if (parent) parent_start = parent->start; else parent_start = 0; } else parent_start = 0; cow = btrfs_alloc_free_block(trans, root, buf->len, parent_start, root->root_key.objectid, &disk_key, level, search_start, empty_size); |
54aa1f4df Btrfs: Audit call... |
437 438 |
if (IS_ERR(cow)) return PTR_ERR(cow); |
6702ed490 Btrfs: Add run ti... |
439 |
|
b4ce94de9 Btrfs: Change btr... |
440 |
/* cow is set to blocking by btrfs_init_new_buffer */ |
5f39d397d Btrfs: Create ext... |
441 |
copy_extent_buffer(cow, buf, 0, 0, cow->len); |
db94535db Btrfs: Allow tree... |
442 |
btrfs_set_header_bytenr(cow, cow->start); |
5f39d397d Btrfs: Create ext... |
443 |
btrfs_set_header_generation(cow, trans->transid); |
5d4f98a28 Btrfs: Mixed back... |
444 445 446 447 448 449 450 |
btrfs_set_header_backref_rev(cow, BTRFS_MIXED_BACKREF_REV); btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN | BTRFS_HEADER_FLAG_RELOC); if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) btrfs_set_header_flag(cow, BTRFS_HEADER_FLAG_RELOC); else btrfs_set_header_owner(cow, root->root_key.objectid); |
6702ed490 Btrfs: Add run ti... |
451 |
|
2b82032c3 Btrfs: Seed devic... |
452 453 454 |
write_extent_buffer(cow, root->fs_info->fsid, (unsigned long)btrfs_header_fsid(cow), BTRFS_FSID_SIZE); |
f0486c68e Btrfs: Introduce ... |
455 |
update_ref_for_cow(trans, root, buf, cow, &last_ref); |
1a40e23b9 Btrfs: update spa... |
456 |
|
3fd0a5585 Btrfs: Metadata E... |
457 458 |
if (root->ref_cows) btrfs_reloc_cow_block(trans, root, buf, cow); |
02217ed29 Btrfs: early refe... |
459 |
if (buf == root->node) { |
925baeddc Btrfs: Start btre... |
460 |
WARN_ON(parent && parent != buf); |
5d4f98a28 Btrfs: Mixed back... |
461 462 463 464 465 |
if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID || btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV) parent_start = buf->start; else parent_start = 0; |
925baeddc Btrfs: Start btre... |
466 |
|
5f39d397d Btrfs: Create ext... |
467 |
extent_buffer_get(cow); |
240f62c87 Btrfs: use RCU in... |
468 |
rcu_assign_pointer(root->node, cow); |
925baeddc Btrfs: Start btre... |
469 |
|
f0486c68e Btrfs: Introduce ... |
470 471 |
btrfs_free_tree_block(trans, root, buf, parent_start, last_ref); |
5f39d397d Btrfs: Create ext... |
472 |
free_extent_buffer(buf); |
0b86a832a Btrfs: Add suppor... |
473 |
add_root_to_dirty_list(root); |
02217ed29 Btrfs: early refe... |
474 |
} else { |
5d4f98a28 Btrfs: Mixed back... |
475 476 477 478 479 480 |
if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) parent_start = parent->start; else parent_start = 0; WARN_ON(trans->transid != btrfs_header_generation(parent)); |
5f39d397d Btrfs: Create ext... |
481 |
btrfs_set_node_blockptr(parent, parent_slot, |
db94535db Btrfs: Allow tree... |
482 |
cow->start); |
74493f7a5 Btrfs: Implement ... |
483 484 |
btrfs_set_node_ptr_generation(parent, parent_slot, trans->transid); |
d60255795 Btrfs: corruption... |
485 |
btrfs_mark_buffer_dirty(parent); |
f0486c68e Btrfs: Introduce ... |
486 487 |
btrfs_free_tree_block(trans, root, buf, parent_start, last_ref); |
02217ed29 Btrfs: early refe... |
488 |
} |
925baeddc Btrfs: Start btre... |
489 490 |
if (unlock_orig) btrfs_tree_unlock(buf); |
5f39d397d Btrfs: Create ext... |
491 |
free_extent_buffer(buf); |
ccd467d60 Btrfs: crash reco... |
492 |
btrfs_mark_buffer_dirty(cow); |
2c90e5d65 Btrfs: still corr... |
493 |
*cow_ret = cow; |
02217ed29 Btrfs: early refe... |
494 495 |
return 0; } |
5d4f98a28 Btrfs: Mixed back... |
496 497 498 499 |
static inline int should_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf) { |
f1ebcc74d Btrfs: fix tree c... |
500 501 502 503 504 505 506 507 508 509 510 511 512 513 |
/* ensure we can see the force_cow */ smp_rmb(); /* * We do not need to cow a block if * 1) this block is not created or changed in this transaction; * 2) this block does not belong to TREE_RELOC tree; * 3) the root is not forced COW. * * What is forced COW: * when we create snapshot during commiting the transaction, * after we've finished coping src root, we must COW the shared * block to ensure the metadata consistency. */ |
5d4f98a28 Btrfs: Mixed back... |
514 515 516 |
if (btrfs_header_generation(buf) == trans->transid && !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) && !(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID && |
f1ebcc74d Btrfs: fix tree c... |
517 518 |
btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)) && !root->force_cow) |
5d4f98a28 Btrfs: Mixed back... |
519 520 521 |
return 0; return 1; } |
d352ac681 Btrfs: add and im... |
522 523 524 525 526 |
/* * cows a single block, see __btrfs_cow_block for the real work. * This version of it has extra checks so that a block isn't cow'd more than * once per transaction, as long as it hasn't been written yet */ |
d397712bc Btrfs: Fix checkp... |
527 |
noinline int btrfs_cow_block(struct btrfs_trans_handle *trans, |
5f39d397d Btrfs: Create ext... |
528 529 |
struct btrfs_root *root, struct extent_buffer *buf, struct extent_buffer *parent, int parent_slot, |
9fa8cfe70 Btrfs: don't prea... |
530 |
struct extent_buffer **cow_ret) |
6702ed490 Btrfs: Add run ti... |
531 532 |
{ u64 search_start; |
f510cfecf Btrfs: Fix extent... |
533 |
int ret; |
dc17ff8f1 Btrfs: Add data=o... |
534 |
|
6702ed490 Btrfs: Add run ti... |
535 |
if (trans->transaction != root->fs_info->running_transaction) { |
d397712bc Btrfs: Fix checkp... |
536 537 538 539 |
printk(KERN_CRIT "trans %llu running %llu ", (unsigned long long)trans->transid, (unsigned long long) |
6702ed490 Btrfs: Add run ti... |
540 541 542 543 |
root->fs_info->running_transaction->transid); WARN_ON(1); } if (trans->transid != root->fs_info->generation) { |
d397712bc Btrfs: Fix checkp... |
544 545 546 547 |
printk(KERN_CRIT "trans %llu running %llu ", (unsigned long long)trans->transid, (unsigned long long)root->fs_info->generation); |
6702ed490 Btrfs: Add run ti... |
548 549 |
WARN_ON(1); } |
dc17ff8f1 Btrfs: Add data=o... |
550 |
|
5d4f98a28 Btrfs: Mixed back... |
551 |
if (!should_cow_block(trans, root, buf)) { |
6702ed490 Btrfs: Add run ti... |
552 553 554 |
*cow_ret = buf; return 0; } |
c487685d7 Btrfs: hash_lock ... |
555 |
|
0b86a832a Btrfs: Add suppor... |
556 |
search_start = buf->start & ~((u64)(1024 * 1024 * 1024) - 1); |
b4ce94de9 Btrfs: Change btr... |
557 558 559 560 |
if (parent) btrfs_set_lock_blocking(parent); btrfs_set_lock_blocking(buf); |
f510cfecf Btrfs: Fix extent... |
561 |
ret = __btrfs_cow_block(trans, root, buf, parent, |
9fa8cfe70 Btrfs: don't prea... |
562 |
parent_slot, cow_ret, search_start, 0); |
1abe9b8a1 Btrfs: add initia... |
563 564 |
trace_btrfs_cow_block(root, buf, *cow_ret); |
f510cfecf Btrfs: Fix extent... |
565 |
return ret; |
6702ed490 Btrfs: Add run ti... |
566 |
} |
d352ac681 Btrfs: add and im... |
567 568 569 570 |
/* * helper function for defrag to decide if two blocks pointed to by a * node are actually close by */ |
6b80053d0 Btrfs: Add back t... |
571 |
static int close_blocks(u64 blocknr, u64 other, u32 blocksize) |
6702ed490 Btrfs: Add run ti... |
572 |
{ |
6b80053d0 Btrfs: Add back t... |
573 |
if (blocknr < other && other - (blocknr + blocksize) < 32768) |
6702ed490 Btrfs: Add run ti... |
574 |
return 1; |
6b80053d0 Btrfs: Add back t... |
575 |
if (blocknr > other && blocknr - (other + blocksize) < 32768) |
6702ed490 Btrfs: Add run ti... |
576 577 578 |
return 1; return 0; } |
081e95736 Btrfs: Make defra... |
579 580 581 582 583 584 585 586 |
/* * compare two keys in a memcmp fashion */ static int comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2) { struct btrfs_key k1; btrfs_disk_key_to_cpu(&k1, disk); |
20736abaa Btrfs: Remove cod... |
587 |
return btrfs_comp_cpu_keys(&k1, k2); |
081e95736 Btrfs: Make defra... |
588 |
} |
f3465ca44 Btrfs: batch exte... |
589 590 591 |
/* * same as comp_keys only with two btrfs_key's */ |
5d4f98a28 Btrfs: Mixed back... |
592 |
int btrfs_comp_cpu_keys(struct btrfs_key *k1, struct btrfs_key *k2) |
f3465ca44 Btrfs: batch exte... |
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 |
{ if (k1->objectid > k2->objectid) return 1; if (k1->objectid < k2->objectid) return -1; if (k1->type > k2->type) return 1; if (k1->type < k2->type) return -1; if (k1->offset > k2->offset) return 1; if (k1->offset < k2->offset) return -1; return 0; } |
081e95736 Btrfs: Make defra... |
608 |
|
d352ac681 Btrfs: add and im... |
609 610 611 612 613 |
/* * this is used by the defrag code to go through all the * leaves pointed to by a node and reallocate them so that * disk order is close to key order */ |
6702ed490 Btrfs: Add run ti... |
614 |
int btrfs_realloc_node(struct btrfs_trans_handle *trans, |
5f39d397d Btrfs: Create ext... |
615 |
struct btrfs_root *root, struct extent_buffer *parent, |
a6b6e75e0 Btrfs: Defrag onl... |
616 617 |
int start_slot, int cache_only, u64 *last_ret, struct btrfs_key *progress) |
6702ed490 Btrfs: Add run ti... |
618 |
{ |
6b80053d0 Btrfs: Add back t... |
619 |
struct extent_buffer *cur; |
6702ed490 Btrfs: Add run ti... |
620 |
u64 blocknr; |
ca7a79ad8 Btrfs: Pass down ... |
621 |
u64 gen; |
e9d0b13b5 Btrfs: Btree defr... |
622 623 |
u64 search_start = *last_ret; u64 last_block = 0; |
6702ed490 Btrfs: Add run ti... |
624 625 |
u64 other; u32 parent_nritems; |
6702ed490 Btrfs: Add run ti... |
626 627 628 |
int end_slot; int i; int err = 0; |
f2183bde1 Btrfs: Add BH_Def... |
629 |
int parent_level; |
6b80053d0 Btrfs: Add back t... |
630 631 |
int uptodate; u32 blocksize; |
081e95736 Btrfs: Make defra... |
632 633 |
int progress_passed = 0; struct btrfs_disk_key disk_key; |
6702ed490 Btrfs: Add run ti... |
634 |
|
5708b9591 Btrfs: Tune the a... |
635 636 637 |
parent_level = btrfs_header_level(parent); if (cache_only && parent_level != 1) return 0; |
d397712bc Btrfs: Fix checkp... |
638 |
if (trans->transaction != root->fs_info->running_transaction) |
6702ed490 Btrfs: Add run ti... |
639 |
WARN_ON(1); |
d397712bc Btrfs: Fix checkp... |
640 |
if (trans->transid != root->fs_info->generation) |
6702ed490 Btrfs: Add run ti... |
641 |
WARN_ON(1); |
86479a04e Add support for d... |
642 |
|
6b80053d0 Btrfs: Add back t... |
643 |
parent_nritems = btrfs_header_nritems(parent); |
6b80053d0 Btrfs: Add back t... |
644 |
blocksize = btrfs_level_size(root, parent_level - 1); |
6702ed490 Btrfs: Add run ti... |
645 646 647 648 |
end_slot = parent_nritems; if (parent_nritems == 1) return 0; |
b4ce94de9 Btrfs: Change btr... |
649 |
btrfs_set_lock_blocking(parent); |
6702ed490 Btrfs: Add run ti... |
650 651 |
for (i = start_slot; i < end_slot; i++) { int close = 1; |
a6b6e75e0 Btrfs: Defrag onl... |
652 |
|
081e95736 Btrfs: Make defra... |
653 654 655 656 657 |
btrfs_node_key(parent, &disk_key, i); if (!progress_passed && comp_keys(&disk_key, progress) < 0) continue; progress_passed = 1; |
6b80053d0 Btrfs: Add back t... |
658 |
blocknr = btrfs_node_blockptr(parent, i); |
ca7a79ad8 Btrfs: Pass down ... |
659 |
gen = btrfs_node_ptr_generation(parent, i); |
e9d0b13b5 Btrfs: Btree defr... |
660 661 |
if (last_block == 0) last_block = blocknr; |
5708b9591 Btrfs: Tune the a... |
662 |
|
6702ed490 Btrfs: Add run ti... |
663 |
if (i > 0) { |
6b80053d0 Btrfs: Add back t... |
664 665 |
other = btrfs_node_blockptr(parent, i - 1); close = close_blocks(blocknr, other, blocksize); |
6702ed490 Btrfs: Add run ti... |
666 |
} |
0ef3e66b6 Btrfs: Allocator ... |
667 |
if (!close && i < end_slot - 2) { |
6b80053d0 Btrfs: Add back t... |
668 669 |
other = btrfs_node_blockptr(parent, i + 1); close = close_blocks(blocknr, other, blocksize); |
6702ed490 Btrfs: Add run ti... |
670 |
} |
e9d0b13b5 Btrfs: Btree defr... |
671 672 |
if (close) { last_block = blocknr; |
6702ed490 Btrfs: Add run ti... |
673 |
continue; |
e9d0b13b5 Btrfs: Btree defr... |
674 |
} |
6702ed490 Btrfs: Add run ti... |
675 |
|
6b80053d0 Btrfs: Add back t... |
676 677 |
cur = btrfs_find_tree_block(root, blocknr, blocksize); if (cur) |
1259ab75c Btrfs: Handle wri... |
678 |
uptodate = btrfs_buffer_uptodate(cur, gen); |
6b80053d0 Btrfs: Add back t... |
679 680 |
else uptodate = 0; |
5708b9591 Btrfs: Tune the a... |
681 |
if (!cur || !uptodate) { |
6702ed490 Btrfs: Add run ti... |
682 |
if (cache_only) { |
6b80053d0 Btrfs: Add back t... |
683 |
free_extent_buffer(cur); |
6702ed490 Btrfs: Add run ti... |
684 685 |
continue; } |
6b80053d0 Btrfs: Add back t... |
686 687 |
if (!cur) { cur = read_tree_block(root, blocknr, |
ca7a79ad8 Btrfs: Pass down ... |
688 |
blocksize, gen); |
97d9a8a42 Btrfs: check retu... |
689 690 |
if (!cur) return -EIO; |
6b80053d0 Btrfs: Add back t... |
691 |
} else if (!uptodate) { |
ca7a79ad8 Btrfs: Pass down ... |
692 |
btrfs_read_buffer(cur, gen); |
f2183bde1 Btrfs: Add BH_Def... |
693 |
} |
6702ed490 Btrfs: Add run ti... |
694 |
} |
e9d0b13b5 Btrfs: Btree defr... |
695 |
if (search_start == 0) |
6b80053d0 Btrfs: Add back t... |
696 |
search_start = last_block; |
e9d0b13b5 Btrfs: Btree defr... |
697 |
|
e7a84565b Btrfs: Add btree ... |
698 |
btrfs_tree_lock(cur); |
b4ce94de9 Btrfs: Change btr... |
699 |
btrfs_set_lock_blocking(cur); |
6b80053d0 Btrfs: Add back t... |
700 |
err = __btrfs_cow_block(trans, root, cur, parent, i, |
e7a84565b Btrfs: Add btree ... |
701 |
&cur, search_start, |
6b80053d0 Btrfs: Add back t... |
702 |
min(16 * blocksize, |
9fa8cfe70 Btrfs: don't prea... |
703 |
(end_slot - i) * blocksize)); |
252c38f06 Btrfs: ctree.c cl... |
704 |
if (err) { |
e7a84565b Btrfs: Add btree ... |
705 |
btrfs_tree_unlock(cur); |
6b80053d0 Btrfs: Add back t... |
706 |
free_extent_buffer(cur); |
6702ed490 Btrfs: Add run ti... |
707 |
break; |
252c38f06 Btrfs: ctree.c cl... |
708 |
} |
e7a84565b Btrfs: Add btree ... |
709 710 |
search_start = cur->start; last_block = cur->start; |
f2183bde1 Btrfs: Add BH_Def... |
711 |
*last_ret = search_start; |
e7a84565b Btrfs: Add btree ... |
712 713 |
btrfs_tree_unlock(cur); free_extent_buffer(cur); |
6702ed490 Btrfs: Add run ti... |
714 715 716 |
} return err; } |
74123bd72 Btrfs: Commenting... |
717 718 719 720 721 |
/* * The leaf data grows from end-to-front in the node. * this returns the address of the start of the last item, * which is the stop of the leaf data stack */ |
123abc88c Btrfs: variable b... |
722 |
static inline unsigned int leaf_data_end(struct btrfs_root *root, |
5f39d397d Btrfs: Create ext... |
723 |
struct extent_buffer *leaf) |
be0e5c097 Btrfs: Initial ch... |
724 |
{ |
5f39d397d Btrfs: Create ext... |
725 |
u32 nr = btrfs_header_nritems(leaf); |
be0e5c097 Btrfs: Initial ch... |
726 |
if (nr == 0) |
123abc88c Btrfs: variable b... |
727 |
return BTRFS_LEAF_DATA_SIZE(root); |
5f39d397d Btrfs: Create ext... |
728 |
return btrfs_item_offset_nr(leaf, nr - 1); |
be0e5c097 Btrfs: Initial ch... |
729 |
} |
aa5d6bed2 Btrfs: return cod... |
730 |
|
74123bd72 Btrfs: Commenting... |
731 |
/* |
5f39d397d Btrfs: Create ext... |
732 733 734 |
* search for key in the extent_buffer. The items start at offset p, * and they are item_size apart. There are 'max' items in p. * |
74123bd72 Btrfs: Commenting... |
735 736 737 738 739 740 |
* the slot in the array is returned via slot, and it points to * the place where you would insert key if it is not found in * the array. * * slot may point to max if the key is bigger than all of the keys */ |
e02119d5a Btrfs: Add a writ... |
741 742 743 744 |
static noinline int generic_bin_search(struct extent_buffer *eb, unsigned long p, int item_size, struct btrfs_key *key, int max, int *slot) |
be0e5c097 Btrfs: Initial ch... |
745 746 747 748 749 |
{ int low = 0; int high = max; int mid; int ret; |
479965d66 Btrfs: Optimizati... |
750 |
struct btrfs_disk_key *tmp = NULL; |
5f39d397d Btrfs: Create ext... |
751 752 |
struct btrfs_disk_key unaligned; unsigned long offset; |
5f39d397d Btrfs: Create ext... |
753 754 755 |
char *kaddr = NULL; unsigned long map_start = 0; unsigned long map_len = 0; |
479965d66 Btrfs: Optimizati... |
756 |
int err; |
be0e5c097 Btrfs: Initial ch... |
757 |
|
d397712bc Btrfs: Fix checkp... |
758 |
while (low < high) { |
be0e5c097 Btrfs: Initial ch... |
759 |
mid = (low + high) / 2; |
5f39d397d Btrfs: Create ext... |
760 |
offset = p + mid * item_size; |
a65917156 Btrfs: stop using... |
761 |
if (!kaddr || offset < map_start || |
5f39d397d Btrfs: Create ext... |
762 763 |
(offset + sizeof(struct btrfs_disk_key)) > map_start + map_len) { |
934d375ba Btrfs: Use map_pr... |
764 765 |
err = map_private_extent_buffer(eb, offset, |
479965d66 Btrfs: Optimizati... |
766 |
sizeof(struct btrfs_disk_key), |
a65917156 Btrfs: stop using... |
767 |
&kaddr, &map_start, &map_len); |
479965d66 Btrfs: Optimizati... |
768 769 770 771 772 773 774 775 776 |
if (!err) { tmp = (struct btrfs_disk_key *)(kaddr + offset - map_start); } else { read_extent_buffer(eb, &unaligned, offset, sizeof(unaligned)); tmp = &unaligned; } |
5f39d397d Btrfs: Create ext... |
777 |
|
5f39d397d Btrfs: Create ext... |
778 779 780 781 |
} else { tmp = (struct btrfs_disk_key *)(kaddr + offset - map_start); } |
be0e5c097 Btrfs: Initial ch... |
782 783 784 785 786 787 788 789 790 791 792 793 794 795 |
ret = comp_keys(tmp, key); if (ret < 0) low = mid + 1; else if (ret > 0) high = mid; else { *slot = mid; return 0; } } *slot = low; return 1; } |
97571fd0c Btrfs: cleanup & ... |
796 797 798 799 |
/* * simple bin_search frontend that does the right thing for * leaves vs nodes */ |
5f39d397d Btrfs: Create ext... |
800 801 |
static int bin_search(struct extent_buffer *eb, struct btrfs_key *key, int level, int *slot) |
be0e5c097 Btrfs: Initial ch... |
802 |
{ |
5f39d397d Btrfs: Create ext... |
803 804 805 |
if (level == 0) { return generic_bin_search(eb, offsetof(struct btrfs_leaf, items), |
0783fcfc4 Btrfs: struct ite... |
806 |
sizeof(struct btrfs_item), |
5f39d397d Btrfs: Create ext... |
807 |
key, btrfs_header_nritems(eb), |
7518a238e Btrfs: get/set fo... |
808 |
slot); |
be0e5c097 Btrfs: Initial ch... |
809 |
} else { |
5f39d397d Btrfs: Create ext... |
810 811 |
return generic_bin_search(eb, offsetof(struct btrfs_node, ptrs), |
123abc88c Btrfs: variable b... |
812 |
sizeof(struct btrfs_key_ptr), |
5f39d397d Btrfs: Create ext... |
813 |
key, btrfs_header_nritems(eb), |
7518a238e Btrfs: get/set fo... |
814 |
slot); |
be0e5c097 Btrfs: Initial ch... |
815 816 817 |
} return -1; } |
5d4f98a28 Btrfs: Mixed back... |
818 819 820 821 822 |
int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, int level, int *slot) { return bin_search(eb, key, level, slot); } |
f0486c68e Btrfs: Introduce ... |
823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 |
static void root_add_used(struct btrfs_root *root, u32 size) { spin_lock(&root->accounting_lock); btrfs_set_root_used(&root->root_item, btrfs_root_used(&root->root_item) + size); spin_unlock(&root->accounting_lock); } static void root_sub_used(struct btrfs_root *root, u32 size) { spin_lock(&root->accounting_lock); btrfs_set_root_used(&root->root_item, btrfs_root_used(&root->root_item) - size); spin_unlock(&root->accounting_lock); } |
d352ac681 Btrfs: add and im... |
838 839 840 841 |
/* given a node and slot number, this reads the blocks it points to. The * extent buffer is returned with a reference taken (but unlocked). * NULL is returned on error. */ |
e02119d5a Btrfs: Add a writ... |
842 |
static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root, |
5f39d397d Btrfs: Create ext... |
843 |
struct extent_buffer *parent, int slot) |
bb8039515 Btrfs: merge on t... |
844 |
{ |
ca7a79ad8 Btrfs: Pass down ... |
845 |
int level = btrfs_header_level(parent); |
bb8039515 Btrfs: merge on t... |
846 847 |
if (slot < 0) return NULL; |
5f39d397d Btrfs: Create ext... |
848 |
if (slot >= btrfs_header_nritems(parent)) |
bb8039515 Btrfs: merge on t... |
849 |
return NULL; |
ca7a79ad8 Btrfs: Pass down ... |
850 851 |
BUG_ON(level == 0); |
db94535db Btrfs: Allow tree... |
852 |
return read_tree_block(root, btrfs_node_blockptr(parent, slot), |
ca7a79ad8 Btrfs: Pass down ... |
853 854 |
btrfs_level_size(root, level - 1), btrfs_node_ptr_generation(parent, slot)); |
bb8039515 Btrfs: merge on t... |
855 |
} |
d352ac681 Btrfs: add and im... |
856 857 858 859 860 |
/* * node level balancing, used to make sure nodes are in proper order for * item deletion. We balance from the top down, so we have to make sure * that a deletion won't leave an node completely empty later on. */ |
e02119d5a Btrfs: Add a writ... |
861 |
static noinline int balance_level(struct btrfs_trans_handle *trans, |
98ed51747 Btrfs: Force inli... |
862 863 |
struct btrfs_root *root, struct btrfs_path *path, int level) |
bb8039515 Btrfs: merge on t... |
864 |
{ |
5f39d397d Btrfs: Create ext... |
865 866 867 868 |
struct extent_buffer *right = NULL; struct extent_buffer *mid; struct extent_buffer *left = NULL; struct extent_buffer *parent = NULL; |
bb8039515 Btrfs: merge on t... |
869 870 871 |
int ret = 0; int wret; int pslot; |
bb8039515 Btrfs: merge on t... |
872 |
int orig_slot = path->slots[level]; |
79f95c82d Btrfs: Fixup the ... |
873 |
u64 orig_ptr; |
bb8039515 Btrfs: merge on t... |
874 875 876 |
if (level == 0) return 0; |
5f39d397d Btrfs: Create ext... |
877 |
mid = path->nodes[level]; |
b4ce94de9 Btrfs: Change btr... |
878 |
|
bd681513f Btrfs: switch the... |
879 880 |
WARN_ON(path->locks[level] != BTRFS_WRITE_LOCK && path->locks[level] != BTRFS_WRITE_LOCK_BLOCKING); |
7bb86316c Btrfs: Add back p... |
881 |
WARN_ON(btrfs_header_generation(mid) != trans->transid); |
1d4f8a0c1 Btrfs: node->bloc... |
882 |
orig_ptr = btrfs_node_blockptr(mid, orig_slot); |
79f95c82d Btrfs: Fixup the ... |
883 |
|
a05a9bb18 Btrfs: fix array ... |
884 |
if (level < BTRFS_MAX_LEVEL - 1) { |
5f39d397d Btrfs: Create ext... |
885 |
parent = path->nodes[level + 1]; |
a05a9bb18 Btrfs: fix array ... |
886 887 |
pslot = path->slots[level + 1]; } |
bb8039515 Btrfs: merge on t... |
888 |
|
406894788 Btrfs: minor comm... |
889 890 891 892 |
/* * deal with the case where there is only one pointer in the root * by promoting the node below to a root */ |
5f39d397d Btrfs: Create ext... |
893 894 |
if (!parent) { struct extent_buffer *child; |
bb8039515 Btrfs: merge on t... |
895 |
|
5f39d397d Btrfs: Create ext... |
896 |
if (btrfs_header_nritems(mid) != 1) |
bb8039515 Btrfs: merge on t... |
897 898 899 |
return 0; /* promote the child to a root */ |
5f39d397d Btrfs: Create ext... |
900 |
child = read_node_slot(root, mid, 0); |
7951f3cef Btrfs: balance_le... |
901 |
BUG_ON(!child); |
925baeddc Btrfs: Start btre... |
902 |
btrfs_tree_lock(child); |
b4ce94de9 Btrfs: Change btr... |
903 |
btrfs_set_lock_blocking(child); |
9fa8cfe70 Btrfs: don't prea... |
904 |
ret = btrfs_cow_block(trans, root, child, mid, 0, &child); |
f0486c68e Btrfs: Introduce ... |
905 906 907 908 909 |
if (ret) { btrfs_tree_unlock(child); free_extent_buffer(child); goto enospc; } |
2f375ab9c Call btrfs_cow_bl... |
910 |
|
240f62c87 Btrfs: use RCU in... |
911 |
rcu_assign_pointer(root->node, child); |
925baeddc Btrfs: Start btre... |
912 |
|
0b86a832a Btrfs: Add suppor... |
913 |
add_root_to_dirty_list(root); |
925baeddc Btrfs: Start btre... |
914 |
btrfs_tree_unlock(child); |
b4ce94de9 Btrfs: Change btr... |
915 |
|
925baeddc Btrfs: Start btre... |
916 |
path->locks[level] = 0; |
bb8039515 Btrfs: merge on t... |
917 |
path->nodes[level] = NULL; |
5f39d397d Btrfs: Create ext... |
918 |
clean_tree_block(trans, root, mid); |
925baeddc Btrfs: Start btre... |
919 |
btrfs_tree_unlock(mid); |
bb8039515 Btrfs: merge on t... |
920 |
/* once for the path */ |
5f39d397d Btrfs: Create ext... |
921 |
free_extent_buffer(mid); |
f0486c68e Btrfs: Introduce ... |
922 923 924 |
root_sub_used(root, mid->len); btrfs_free_tree_block(trans, root, mid, 0, 1); |
bb8039515 Btrfs: merge on t... |
925 |
/* once for the root ptr */ |
5f39d397d Btrfs: Create ext... |
926 |
free_extent_buffer(mid); |
f0486c68e Btrfs: Introduce ... |
927 |
return 0; |
bb8039515 Btrfs: merge on t... |
928 |
} |
5f39d397d Btrfs: Create ext... |
929 |
if (btrfs_header_nritems(mid) > |
123abc88c Btrfs: variable b... |
930 |
BTRFS_NODEPTRS_PER_BLOCK(root) / 4) |
bb8039515 Btrfs: merge on t... |
931 |
return 0; |
559af8211 Btrfs: cleanup wa... |
932 |
btrfs_header_nritems(mid); |
54aa1f4df Btrfs: Audit call... |
933 |
|
5f39d397d Btrfs: Create ext... |
934 935 |
left = read_node_slot(root, parent, pslot - 1); if (left) { |
925baeddc Btrfs: Start btre... |
936 |
btrfs_tree_lock(left); |
b4ce94de9 Btrfs: Change btr... |
937 |
btrfs_set_lock_blocking(left); |
5f39d397d Btrfs: Create ext... |
938 |
wret = btrfs_cow_block(trans, root, left, |
9fa8cfe70 Btrfs: don't prea... |
939 |
parent, pslot - 1, &left); |
54aa1f4df Btrfs: Audit call... |
940 941 942 943 |
if (wret) { ret = wret; goto enospc; } |
2cc58cf24 Btrfs: Do more ex... |
944 |
} |
5f39d397d Btrfs: Create ext... |
945 946 |
right = read_node_slot(root, parent, pslot + 1); if (right) { |
925baeddc Btrfs: Start btre... |
947 |
btrfs_tree_lock(right); |
b4ce94de9 Btrfs: Change btr... |
948 |
btrfs_set_lock_blocking(right); |
5f39d397d Btrfs: Create ext... |
949 |
wret = btrfs_cow_block(trans, root, right, |
9fa8cfe70 Btrfs: don't prea... |
950 |
parent, pslot + 1, &right); |
2cc58cf24 Btrfs: Do more ex... |
951 952 953 954 955 956 957 |
if (wret) { ret = wret; goto enospc; } } /* first, try to make some room in the middle buffer */ |
5f39d397d Btrfs: Create ext... |
958 959 |
if (left) { orig_slot += btrfs_header_nritems(left); |
bce4eae98 Btrfs: Fix balanc... |
960 |
wret = push_node_left(trans, root, left, mid, 1); |
79f95c82d Btrfs: Fixup the ... |
961 962 |
if (wret < 0) ret = wret; |
559af8211 Btrfs: cleanup wa... |
963 |
btrfs_header_nritems(mid); |
bb8039515 Btrfs: merge on t... |
964 |
} |
79f95c82d Btrfs: Fixup the ... |
965 966 967 968 |
/* * then try to empty the right most buffer into the middle */ |
5f39d397d Btrfs: Create ext... |
969 |
if (right) { |
971a1f664 Btrfs: Don't empt... |
970 |
wret = push_node_left(trans, root, mid, right, 1); |
54aa1f4df Btrfs: Audit call... |
971 |
if (wret < 0 && wret != -ENOSPC) |
79f95c82d Btrfs: Fixup the ... |
972 |
ret = wret; |
5f39d397d Btrfs: Create ext... |
973 |
if (btrfs_header_nritems(right) == 0) { |
5f39d397d Btrfs: Create ext... |
974 |
clean_tree_block(trans, root, right); |
925baeddc Btrfs: Start btre... |
975 |
btrfs_tree_unlock(right); |
e089f05c1 Btrfs: transactio... |
976 977 |
wret = del_ptr(trans, root, path, level + 1, pslot + 1); |
bb8039515 Btrfs: merge on t... |
978 979 |
if (wret) ret = wret; |
f0486c68e Btrfs: Introduce ... |
980 981 982 983 |
root_sub_used(root, right->len); btrfs_free_tree_block(trans, root, right, 0, 1); free_extent_buffer(right); right = NULL; |
bb8039515 Btrfs: merge on t... |
984 |
} else { |
5f39d397d Btrfs: Create ext... |
985 986 987 988 |
struct btrfs_disk_key right_key; btrfs_node_key(right, &right_key, 0); btrfs_set_node_key(parent, &right_key, pslot + 1); btrfs_mark_buffer_dirty(parent); |
bb8039515 Btrfs: merge on t... |
989 990 |
} } |
5f39d397d Btrfs: Create ext... |
991 |
if (btrfs_header_nritems(mid) == 1) { |
79f95c82d Btrfs: Fixup the ... |
992 993 994 995 996 997 998 999 1000 |
/* * we're not allowed to leave a node with one item in the * tree during a delete. A deletion from lower in the tree * could try to delete the only pointer in this node. * So, pull some keys from the left. * There has to be a left pointer at this point because * otherwise we would have pulled some pointers from the * right */ |
5f39d397d Btrfs: Create ext... |
1001 1002 |
BUG_ON(!left); wret = balance_node_right(trans, root, mid, left); |
54aa1f4df Btrfs: Audit call... |
1003 |
if (wret < 0) { |
79f95c82d Btrfs: Fixup the ... |
1004 |
ret = wret; |
54aa1f4df Btrfs: Audit call... |
1005 1006 |
goto enospc; } |
bce4eae98 Btrfs: Fix balanc... |
1007 1008 1009 1010 1011 |
if (wret == 1) { wret = push_node_left(trans, root, left, mid, 1); if (wret < 0) ret = wret; } |
79f95c82d Btrfs: Fixup the ... |
1012 1013 |
BUG_ON(wret == 1); } |
5f39d397d Btrfs: Create ext... |
1014 |
if (btrfs_header_nritems(mid) == 0) { |
5f39d397d Btrfs: Create ext... |
1015 |
clean_tree_block(trans, root, mid); |
925baeddc Btrfs: Start btre... |
1016 |
btrfs_tree_unlock(mid); |
e089f05c1 Btrfs: transactio... |
1017 |
wret = del_ptr(trans, root, path, level + 1, pslot); |
bb8039515 Btrfs: merge on t... |
1018 1019 |
if (wret) ret = wret; |
f0486c68e Btrfs: Introduce ... |
1020 1021 1022 1023 |
root_sub_used(root, mid->len); btrfs_free_tree_block(trans, root, mid, 0, 1); free_extent_buffer(mid); mid = NULL; |
79f95c82d Btrfs: Fixup the ... |
1024 1025 |
} else { /* update the parent key to reflect our changes */ |
5f39d397d Btrfs: Create ext... |
1026 1027 1028 1029 |
struct btrfs_disk_key mid_key; btrfs_node_key(mid, &mid_key, 0); btrfs_set_node_key(parent, &mid_key, pslot); btrfs_mark_buffer_dirty(parent); |
79f95c82d Btrfs: Fixup the ... |
1030 |
} |
bb8039515 Btrfs: merge on t... |
1031 |
|
79f95c82d Btrfs: Fixup the ... |
1032 |
/* update the path */ |
5f39d397d Btrfs: Create ext... |
1033 1034 1035 |
if (left) { if (btrfs_header_nritems(left) > orig_slot) { extent_buffer_get(left); |
925baeddc Btrfs: Start btre... |
1036 |
/* left was locked after cow */ |
5f39d397d Btrfs: Create ext... |
1037 |
path->nodes[level] = left; |
bb8039515 Btrfs: merge on t... |
1038 1039 |
path->slots[level + 1] -= 1; path->slots[level] = orig_slot; |
925baeddc Btrfs: Start btre... |
1040 1041 |
if (mid) { btrfs_tree_unlock(mid); |
5f39d397d Btrfs: Create ext... |
1042 |
free_extent_buffer(mid); |
925baeddc Btrfs: Start btre... |
1043 |
} |
bb8039515 Btrfs: merge on t... |
1044 |
} else { |
5f39d397d Btrfs: Create ext... |
1045 |
orig_slot -= btrfs_header_nritems(left); |
bb8039515 Btrfs: merge on t... |
1046 1047 1048 |
path->slots[level] = orig_slot; } } |
79f95c82d Btrfs: Fixup the ... |
1049 |
/* double check we haven't messed things up */ |
e20d96d64 Mountable btrfs, ... |
1050 |
if (orig_ptr != |
5f39d397d Btrfs: Create ext... |
1051 |
btrfs_node_blockptr(path->nodes[level], path->slots[level])) |
79f95c82d Btrfs: Fixup the ... |
1052 |
BUG(); |
54aa1f4df Btrfs: Audit call... |
1053 |
enospc: |
925baeddc Btrfs: Start btre... |
1054 1055 |
if (right) { btrfs_tree_unlock(right); |
5f39d397d Btrfs: Create ext... |
1056 |
free_extent_buffer(right); |
925baeddc Btrfs: Start btre... |
1057 1058 1059 1060 |
} if (left) { if (path->nodes[level] != left) btrfs_tree_unlock(left); |
5f39d397d Btrfs: Create ext... |
1061 |
free_extent_buffer(left); |
925baeddc Btrfs: Start btre... |
1062 |
} |
bb8039515 Btrfs: merge on t... |
1063 1064 |
return ret; } |
d352ac681 Btrfs: add and im... |
1065 1066 1067 1068 |
/* Node balancing for insertion. Here we only split or push nodes around * when they are completely full. This is also done top down, so we * have to be pessimistic. */ |
d397712bc Btrfs: Fix checkp... |
1069 |
static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans, |
98ed51747 Btrfs: Force inli... |
1070 1071 |
struct btrfs_root *root, struct btrfs_path *path, int level) |
e66f709b1 Btrfs: write barr... |
1072 |
{ |
5f39d397d Btrfs: Create ext... |
1073 1074 1075 1076 |
struct extent_buffer *right = NULL; struct extent_buffer *mid; struct extent_buffer *left = NULL; struct extent_buffer *parent = NULL; |
e66f709b1 Btrfs: write barr... |
1077 1078 1079 1080 |
int ret = 0; int wret; int pslot; int orig_slot = path->slots[level]; |
e66f709b1 Btrfs: write barr... |
1081 1082 1083 |
if (level == 0) return 1; |
5f39d397d Btrfs: Create ext... |
1084 |
mid = path->nodes[level]; |
7bb86316c Btrfs: Add back p... |
1085 |
WARN_ON(btrfs_header_generation(mid) != trans->transid); |
e66f709b1 Btrfs: write barr... |
1086 |
|
a05a9bb18 Btrfs: fix array ... |
1087 |
if (level < BTRFS_MAX_LEVEL - 1) { |
5f39d397d Btrfs: Create ext... |
1088 |
parent = path->nodes[level + 1]; |
a05a9bb18 Btrfs: fix array ... |
1089 1090 |
pslot = path->slots[level + 1]; } |
e66f709b1 Btrfs: write barr... |
1091 |
|
5f39d397d Btrfs: Create ext... |
1092 |
if (!parent) |
e66f709b1 Btrfs: write barr... |
1093 |
return 1; |
e66f709b1 Btrfs: write barr... |
1094 |
|
5f39d397d Btrfs: Create ext... |
1095 |
left = read_node_slot(root, parent, pslot - 1); |
e66f709b1 Btrfs: write barr... |
1096 1097 |
/* first, try to make some room in the middle buffer */ |
5f39d397d Btrfs: Create ext... |
1098 |
if (left) { |
e66f709b1 Btrfs: write barr... |
1099 |
u32 left_nr; |
925baeddc Btrfs: Start btre... |
1100 1101 |
btrfs_tree_lock(left); |
b4ce94de9 Btrfs: Change btr... |
1102 |
btrfs_set_lock_blocking(left); |
5f39d397d Btrfs: Create ext... |
1103 |
left_nr = btrfs_header_nritems(left); |
33ade1f82 Btrfs: node balan... |
1104 1105 1106 |
if (left_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { wret = 1; } else { |
5f39d397d Btrfs: Create ext... |
1107 |
ret = btrfs_cow_block(trans, root, left, parent, |
9fa8cfe70 Btrfs: don't prea... |
1108 |
pslot - 1, &left); |
54aa1f4df Btrfs: Audit call... |
1109 1110 1111 |
if (ret) wret = 1; else { |
54aa1f4df Btrfs: Audit call... |
1112 |
wret = push_node_left(trans, root, |
971a1f664 Btrfs: Don't empt... |
1113 |
left, mid, 0); |
54aa1f4df Btrfs: Audit call... |
1114 |
} |
33ade1f82 Btrfs: node balan... |
1115 |
} |
e66f709b1 Btrfs: write barr... |
1116 1117 1118 |
if (wret < 0) ret = wret; if (wret == 0) { |
5f39d397d Btrfs: Create ext... |
1119 |
struct btrfs_disk_key disk_key; |
e66f709b1 Btrfs: write barr... |
1120 |
orig_slot += left_nr; |
5f39d397d Btrfs: Create ext... |
1121 1122 1123 1124 1125 |
btrfs_node_key(mid, &disk_key, 0); btrfs_set_node_key(parent, &disk_key, pslot); btrfs_mark_buffer_dirty(parent); if (btrfs_header_nritems(left) > orig_slot) { path->nodes[level] = left; |
e66f709b1 Btrfs: write barr... |
1126 1127 |
path->slots[level + 1] -= 1; path->slots[level] = orig_slot; |
925baeddc Btrfs: Start btre... |
1128 |
btrfs_tree_unlock(mid); |
5f39d397d Btrfs: Create ext... |
1129 |
free_extent_buffer(mid); |
e66f709b1 Btrfs: write barr... |
1130 1131 |
} else { orig_slot -= |
5f39d397d Btrfs: Create ext... |
1132 |
btrfs_header_nritems(left); |
e66f709b1 Btrfs: write barr... |
1133 |
path->slots[level] = orig_slot; |
925baeddc Btrfs: Start btre... |
1134 |
btrfs_tree_unlock(left); |
5f39d397d Btrfs: Create ext... |
1135 |
free_extent_buffer(left); |
e66f709b1 Btrfs: write barr... |
1136 |
} |
e66f709b1 Btrfs: write barr... |
1137 1138 |
return 0; } |
925baeddc Btrfs: Start btre... |
1139 |
btrfs_tree_unlock(left); |
5f39d397d Btrfs: Create ext... |
1140 |
free_extent_buffer(left); |
e66f709b1 Btrfs: write barr... |
1141 |
} |
925baeddc Btrfs: Start btre... |
1142 |
right = read_node_slot(root, parent, pslot + 1); |
e66f709b1 Btrfs: write barr... |
1143 1144 1145 1146 |
/* * then try to empty the right most buffer into the middle */ |
5f39d397d Btrfs: Create ext... |
1147 |
if (right) { |
33ade1f82 Btrfs: node balan... |
1148 |
u32 right_nr; |
b4ce94de9 Btrfs: Change btr... |
1149 |
|
925baeddc Btrfs: Start btre... |
1150 |
btrfs_tree_lock(right); |
b4ce94de9 Btrfs: Change btr... |
1151 |
btrfs_set_lock_blocking(right); |
5f39d397d Btrfs: Create ext... |
1152 |
right_nr = btrfs_header_nritems(right); |
33ade1f82 Btrfs: node balan... |
1153 1154 1155 |
if (right_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { wret = 1; } else { |
5f39d397d Btrfs: Create ext... |
1156 1157 |
ret = btrfs_cow_block(trans, root, right, parent, pslot + 1, |
9fa8cfe70 Btrfs: don't prea... |
1158 |
&right); |
54aa1f4df Btrfs: Audit call... |
1159 1160 1161 |
if (ret) wret = 1; else { |
54aa1f4df Btrfs: Audit call... |
1162 |
wret = balance_node_right(trans, root, |
5f39d397d Btrfs: Create ext... |
1163 |
right, mid); |
54aa1f4df Btrfs: Audit call... |
1164 |
} |
33ade1f82 Btrfs: node balan... |
1165 |
} |
e66f709b1 Btrfs: write barr... |
1166 1167 1168 |
if (wret < 0) ret = wret; if (wret == 0) { |
5f39d397d Btrfs: Create ext... |
1169 1170 1171 1172 1173 1174 1175 1176 |
struct btrfs_disk_key disk_key; btrfs_node_key(right, &disk_key, 0); btrfs_set_node_key(parent, &disk_key, pslot + 1); btrfs_mark_buffer_dirty(parent); if (btrfs_header_nritems(mid) <= orig_slot) { path->nodes[level] = right; |
e66f709b1 Btrfs: write barr... |
1177 1178 |
path->slots[level + 1] += 1; path->slots[level] = orig_slot - |
5f39d397d Btrfs: Create ext... |
1179 |
btrfs_header_nritems(mid); |
925baeddc Btrfs: Start btre... |
1180 |
btrfs_tree_unlock(mid); |
5f39d397d Btrfs: Create ext... |
1181 |
free_extent_buffer(mid); |
e66f709b1 Btrfs: write barr... |
1182 |
} else { |
925baeddc Btrfs: Start btre... |
1183 |
btrfs_tree_unlock(right); |
5f39d397d Btrfs: Create ext... |
1184 |
free_extent_buffer(right); |
e66f709b1 Btrfs: write barr... |
1185 |
} |
e66f709b1 Btrfs: write barr... |
1186 1187 |
return 0; } |
925baeddc Btrfs: Start btre... |
1188 |
btrfs_tree_unlock(right); |
5f39d397d Btrfs: Create ext... |
1189 |
free_extent_buffer(right); |
e66f709b1 Btrfs: write barr... |
1190 |
} |
e66f709b1 Btrfs: write barr... |
1191 1192 |
return 1; } |
74123bd72 Btrfs: Commenting... |
1193 |
/* |
d352ac681 Btrfs: add and im... |
1194 1195 |
* readahead one full node of leaves, finding things that are close * to the block in 'slot', and triggering ra on them. |
3c69faecb Btrfs: Fold some ... |
1196 |
*/ |
c8c42864f Btrfs: break up b... |
1197 1198 1199 |
static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path, int level, int slot, u64 objectid) |
3c69faecb Btrfs: Fold some ... |
1200 |
{ |
5f39d397d Btrfs: Create ext... |
1201 |
struct extent_buffer *node; |
01f466580 Btrfs: Less aggre... |
1202 |
struct btrfs_disk_key disk_key; |
3c69faecb Btrfs: Fold some ... |
1203 |
u32 nritems; |
3c69faecb Btrfs: Fold some ... |
1204 |
u64 search; |
a71753194 Btrfs: do less ag... |
1205 |
u64 target; |
6b80053d0 Btrfs: Add back t... |
1206 |
u64 nread = 0; |
cb25c2ea6 Btrfs: map the no... |
1207 |
u64 gen; |
3c69faecb Btrfs: Fold some ... |
1208 |
int direction = path->reada; |
5f39d397d Btrfs: Create ext... |
1209 |
struct extent_buffer *eb; |
6b80053d0 Btrfs: Add back t... |
1210 1211 1212 |
u32 nr; u32 blocksize; u32 nscan = 0; |
db94535db Btrfs: Allow tree... |
1213 |
|
a6b6e75e0 Btrfs: Defrag onl... |
1214 |
if (level != 1) |
6702ed490 Btrfs: Add run ti... |
1215 1216 1217 |
return; if (!path->nodes[level]) |
3c69faecb Btrfs: Fold some ... |
1218 |
return; |
5f39d397d Btrfs: Create ext... |
1219 |
node = path->nodes[level]; |
925baeddc Btrfs: Start btre... |
1220 |
|
3c69faecb Btrfs: Fold some ... |
1221 |
search = btrfs_node_blockptr(node, slot); |
6b80053d0 Btrfs: Add back t... |
1222 1223 |
blocksize = btrfs_level_size(root, level - 1); eb = btrfs_find_tree_block(root, search, blocksize); |
5f39d397d Btrfs: Create ext... |
1224 1225 |
if (eb) { free_extent_buffer(eb); |
3c69faecb Btrfs: Fold some ... |
1226 1227 |
return; } |
a71753194 Btrfs: do less ag... |
1228 |
target = search; |
6b80053d0 Btrfs: Add back t... |
1229 |
|
5f39d397d Btrfs: Create ext... |
1230 |
nritems = btrfs_header_nritems(node); |
6b80053d0 Btrfs: Add back t... |
1231 |
nr = slot; |
25b8b936e Btrfs: don't map ... |
1232 |
|
d397712bc Btrfs: Fix checkp... |
1233 |
while (1) { |
6b80053d0 Btrfs: Add back t... |
1234 1235 1236 1237 1238 1239 1240 1241 |
if (direction < 0) { if (nr == 0) break; nr--; } else if (direction > 0) { nr++; if (nr >= nritems) break; |
3c69faecb Btrfs: Fold some ... |
1242 |
} |
01f466580 Btrfs: Less aggre... |
1243 1244 1245 1246 1247 |
if (path->reada < 0 && objectid) { btrfs_node_key(node, &disk_key, nr); if (btrfs_disk_key_objectid(&disk_key) != objectid) break; } |
6b80053d0 Btrfs: Add back t... |
1248 |
search = btrfs_node_blockptr(node, nr); |
a71753194 Btrfs: do less ag... |
1249 1250 |
if ((search <= target && target - search <= 65536) || (search > target && search - target <= 65536)) { |
cb25c2ea6 Btrfs: map the no... |
1251 |
gen = btrfs_node_ptr_generation(node, nr); |
cb25c2ea6 Btrfs: map the no... |
1252 |
readahead_tree_block(root, search, blocksize, gen); |
6b80053d0 Btrfs: Add back t... |
1253 1254 1255 |
nread += blocksize; } nscan++; |
a71753194 Btrfs: do less ag... |
1256 |
if ((nread > 65536 || nscan > 32)) |
6b80053d0 Btrfs: Add back t... |
1257 |
break; |
3c69faecb Btrfs: Fold some ... |
1258 1259 |
} } |
925baeddc Btrfs: Start btre... |
1260 |
|
d352ac681 Btrfs: add and im... |
1261 |
/* |
b4ce94de9 Btrfs: Change btr... |
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 |
* returns -EAGAIN if it had to drop the path, or zero if everything was in * cache */ static noinline int reada_for_balance(struct btrfs_root *root, struct btrfs_path *path, int level) { int slot; int nritems; struct extent_buffer *parent; struct extent_buffer *eb; u64 gen; u64 block1 = 0; u64 block2 = 0; int ret = 0; int blocksize; |
8c594ea81 Btrfs: use the ri... |
1277 |
parent = path->nodes[level + 1]; |
b4ce94de9 Btrfs: Change btr... |
1278 1279 1280 1281 |
if (!parent) return 0; nritems = btrfs_header_nritems(parent); |
8c594ea81 Btrfs: use the ri... |
1282 |
slot = path->slots[level + 1]; |
b4ce94de9 Btrfs: Change btr... |
1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 |
blocksize = btrfs_level_size(root, level); if (slot > 0) { block1 = btrfs_node_blockptr(parent, slot - 1); gen = btrfs_node_ptr_generation(parent, slot - 1); eb = btrfs_find_tree_block(root, block1, blocksize); if (eb && btrfs_buffer_uptodate(eb, gen)) block1 = 0; free_extent_buffer(eb); } |
8c594ea81 Btrfs: use the ri... |
1293 |
if (slot + 1 < nritems) { |
b4ce94de9 Btrfs: Change btr... |
1294 1295 1296 1297 1298 1299 1300 1301 1302 |
block2 = btrfs_node_blockptr(parent, slot + 1); gen = btrfs_node_ptr_generation(parent, slot + 1); eb = btrfs_find_tree_block(root, block2, blocksize); if (eb && btrfs_buffer_uptodate(eb, gen)) block2 = 0; free_extent_buffer(eb); } if (block1 || block2) { ret = -EAGAIN; |
8c594ea81 Btrfs: use the ri... |
1303 1304 |
/* release the whole path */ |
b3b4aa74b btrfs: drop unuse... |
1305 |
btrfs_release_path(path); |
8c594ea81 Btrfs: use the ri... |
1306 1307 |
/* read the blocks */ |
b4ce94de9 Btrfs: Change btr... |
1308 1309 1310 1311 1312 1313 1314 1315 1316 |
if (block1) readahead_tree_block(root, block1, blocksize, 0); if (block2) readahead_tree_block(root, block2, blocksize, 0); if (block1) { eb = read_tree_block(root, block1, blocksize, 0); free_extent_buffer(eb); } |
8c594ea81 Btrfs: use the ri... |
1317 |
if (block2) { |
b4ce94de9 Btrfs: Change btr... |
1318 1319 1320 1321 1322 1323 1324 1325 1326 |
eb = read_tree_block(root, block2, blocksize, 0); free_extent_buffer(eb); } } return ret; } /* |
d397712bc Btrfs: Fix checkp... |
1327 1328 1329 1330 |
* when we walk down the tree, it is usually safe to unlock the higher layers * in the tree. The exceptions are when our path goes through slot 0, because * operations on the tree might require changing key pointers higher up in the * tree. |
d352ac681 Btrfs: add and im... |
1331 |
* |
d397712bc Btrfs: Fix checkp... |
1332 1333 1334 |
* callers might also have set path->keep_locks, which tells this code to keep * the lock if the path points to the last slot in the block. This is part of * walking through the tree, and selecting the next slot in the higher block. |
d352ac681 Btrfs: add and im... |
1335 |
* |
d397712bc Btrfs: Fix checkp... |
1336 1337 |
* lowest_unlock sets the lowest level in the tree we're allowed to unlock. so * if lowest_unlock is 1, level 0 won't be unlocked |
d352ac681 Btrfs: add and im... |
1338 |
*/ |
e02119d5a Btrfs: Add a writ... |
1339 1340 |
static noinline void unlock_up(struct btrfs_path *path, int level, int lowest_unlock) |
925baeddc Btrfs: Start btre... |
1341 1342 1343 |
{ int i; int skip_level = level; |
051e1b9f7 Drop locks in btr... |
1344 |
int no_skips = 0; |
925baeddc Btrfs: Start btre... |
1345 1346 1347 1348 1349 1350 1351 |
struct extent_buffer *t; for (i = level; i < BTRFS_MAX_LEVEL; i++) { if (!path->nodes[i]) break; if (!path->locks[i]) break; |
051e1b9f7 Drop locks in btr... |
1352 |
if (!no_skips && path->slots[i] == 0) { |
925baeddc Btrfs: Start btre... |
1353 1354 1355 |
skip_level = i + 1; continue; } |
051e1b9f7 Drop locks in btr... |
1356 |
if (!no_skips && path->keep_locks) { |
925baeddc Btrfs: Start btre... |
1357 1358 1359 |
u32 nritems; t = path->nodes[i]; nritems = btrfs_header_nritems(t); |
051e1b9f7 Drop locks in btr... |
1360 |
if (nritems < 1 || path->slots[i] >= nritems - 1) { |
925baeddc Btrfs: Start btre... |
1361 1362 1363 1364 |
skip_level = i + 1; continue; } } |
051e1b9f7 Drop locks in btr... |
1365 1366 |
if (skip_level < i && i >= lowest_unlock) no_skips = 1; |
925baeddc Btrfs: Start btre... |
1367 1368 |
t = path->nodes[i]; if (i >= lowest_unlock && i > skip_level && path->locks[i]) { |
bd681513f Btrfs: switch the... |
1369 |
btrfs_tree_unlock_rw(t, path->locks[i]); |
925baeddc Btrfs: Start btre... |
1370 1371 1372 1373 |
path->locks[i] = 0; } } } |
3c69faecb Btrfs: Fold some ... |
1374 |
/* |
b4ce94de9 Btrfs: Change btr... |
1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 |
* This releases any locks held in the path starting at level and * going all the way up to the root. * * btrfs_search_slot will keep the lock held on higher nodes in a few * corner cases, such as COW of the block at slot zero in the node. This * ignores those rules, and it should only be called when there are no * more updates to be done higher up in the tree. */ noinline void btrfs_unlock_up_safe(struct btrfs_path *path, int level) { int i; |
5d4f98a28 Btrfs: Mixed back... |
1386 |
if (path->keep_locks) |
b4ce94de9 Btrfs: Change btr... |
1387 1388 1389 1390 |
return; for (i = level; i < BTRFS_MAX_LEVEL; i++) { if (!path->nodes[i]) |
12f4daccf Btrfs: fix btrfs_... |
1391 |
continue; |
b4ce94de9 Btrfs: Change btr... |
1392 |
if (!path->locks[i]) |
12f4daccf Btrfs: fix btrfs_... |
1393 |
continue; |
bd681513f Btrfs: switch the... |
1394 |
btrfs_tree_unlock_rw(path->nodes[i], path->locks[i]); |
b4ce94de9 Btrfs: Change btr... |
1395 1396 1397 1398 1399 |
path->locks[i] = 0; } } /* |
c8c42864f Btrfs: break up b... |
1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 |
* helper function for btrfs_search_slot. The goal is to find a block * in cache without setting the path to blocking. If we find the block * we return zero and the path is unchanged. * * If we can't find the block, we set the path blocking and do some * reada. -EAGAIN is returned and the search must be repeated. */ static int read_block_for_search(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *p, struct extent_buffer **eb_ret, int level, int slot, struct btrfs_key *key) { u64 blocknr; u64 gen; u32 blocksize; struct extent_buffer *b = *eb_ret; struct extent_buffer *tmp; |
76a05b35a Btrfs: Don't loop... |
1418 |
int ret; |
c8c42864f Btrfs: break up b... |
1419 1420 1421 1422 1423 1424 |
blocknr = btrfs_node_blockptr(b, slot); gen = btrfs_node_ptr_generation(b, slot); blocksize = btrfs_level_size(root, level - 1); tmp = btrfs_find_tree_block(root, blocknr, blocksize); |
cb44921a0 Btrfs: don't loop... |
1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 |
if (tmp) { if (btrfs_buffer_uptodate(tmp, 0)) { if (btrfs_buffer_uptodate(tmp, gen)) { /* * we found an up to date block without * sleeping, return * right away */ *eb_ret = tmp; return 0; } /* the pages were up to date, but we failed * the generation number check. Do a full * read for the generation number that is correct. * We must do this without dropping locks so * we can trust our generation number */ free_extent_buffer(tmp); |
bd681513f Btrfs: switch the... |
1443 |
btrfs_set_path_blocking(p); |
cb44921a0 Btrfs: don't loop... |
1444 1445 1446 1447 1448 1449 |
tmp = read_tree_block(root, blocknr, blocksize, gen); if (tmp && btrfs_buffer_uptodate(tmp, gen)) { *eb_ret = tmp; return 0; } free_extent_buffer(tmp); |
b3b4aa74b btrfs: drop unuse... |
1450 |
btrfs_release_path(p); |
cb44921a0 Btrfs: don't loop... |
1451 1452 |
return -EIO; } |
c8c42864f Btrfs: break up b... |
1453 1454 1455 1456 1457 |
} /* * reduce lock contention at high levels * of the btree by dropping locks before |
76a05b35a Btrfs: Don't loop... |
1458 1459 1460 |
* we read. Don't release the lock on the current * level because we need to walk this node to figure * out which blocks to read. |
c8c42864f Btrfs: break up b... |
1461 |
*/ |
8c594ea81 Btrfs: use the ri... |
1462 1463 |
btrfs_unlock_up_safe(p, level + 1); btrfs_set_path_blocking(p); |
cb44921a0 Btrfs: don't loop... |
1464 |
free_extent_buffer(tmp); |
c8c42864f Btrfs: break up b... |
1465 1466 |
if (p->reada) reada_for_search(root, p, level, slot, key->objectid); |
b3b4aa74b btrfs: drop unuse... |
1467 |
btrfs_release_path(p); |
76a05b35a Btrfs: Don't loop... |
1468 1469 |
ret = -EAGAIN; |
5bdd3536c Btrfs: Fix block ... |
1470 |
tmp = read_tree_block(root, blocknr, blocksize, 0); |
76a05b35a Btrfs: Don't loop... |
1471 1472 1473 1474 1475 1476 1477 1478 1479 |
if (tmp) { /* * If the read above didn't mark this buffer up to date, * it will never end up being up to date. Set ret to EIO now * and give up so that our caller doesn't loop forever * on our EAGAINs. */ if (!btrfs_buffer_uptodate(tmp, 0)) ret = -EIO; |
c8c42864f Btrfs: break up b... |
1480 |
free_extent_buffer(tmp); |
76a05b35a Btrfs: Don't loop... |
1481 1482 |
} return ret; |
c8c42864f Btrfs: break up b... |
1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 |
} /* * helper function for btrfs_search_slot. This does all of the checks * for node-level blocks and does any balancing required based on * the ins_len. * * If no extra work was required, zero is returned. If we had to * drop the path, -EAGAIN is returned and btrfs_search_slot must * start over */ static int setup_nodes_for_search(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *p, |
bd681513f Btrfs: switch the... |
1497 1498 |
struct extent_buffer *b, int level, int ins_len, int *write_lock_level) |
c8c42864f Btrfs: break up b... |
1499 1500 1501 1502 1503 |
{ int ret; if ((p->search_for_split || ins_len > 0) && btrfs_header_nritems(b) >= BTRFS_NODEPTRS_PER_BLOCK(root) - 3) { int sret; |
bd681513f Btrfs: switch the... |
1504 1505 1506 1507 1508 |
if (*write_lock_level < level + 1) { *write_lock_level = level + 1; btrfs_release_path(p); goto again; } |
c8c42864f Btrfs: break up b... |
1509 1510 1511 1512 1513 1514 |
sret = reada_for_balance(root, p, level); if (sret) goto again; btrfs_set_path_blocking(p); sret = split_node(trans, root, p, level); |
bd681513f Btrfs: switch the... |
1515 |
btrfs_clear_path_blocking(p, NULL, 0); |
c8c42864f Btrfs: break up b... |
1516 1517 1518 1519 1520 1521 1522 1523 |
BUG_ON(sret > 0); if (sret) { ret = sret; goto done; } b = p->nodes[level]; } else if (ins_len < 0 && btrfs_header_nritems(b) < |
cfbb93084 Btrfs: balance bt... |
1524 |
BTRFS_NODEPTRS_PER_BLOCK(root) / 2) { |
c8c42864f Btrfs: break up b... |
1525 |
int sret; |
bd681513f Btrfs: switch the... |
1526 1527 1528 1529 1530 |
if (*write_lock_level < level + 1) { *write_lock_level = level + 1; btrfs_release_path(p); goto again; } |
c8c42864f Btrfs: break up b... |
1531 1532 1533 1534 1535 1536 |
sret = reada_for_balance(root, p, level); if (sret) goto again; btrfs_set_path_blocking(p); sret = balance_level(trans, root, p, level); |
bd681513f Btrfs: switch the... |
1537 |
btrfs_clear_path_blocking(p, NULL, 0); |
c8c42864f Btrfs: break up b... |
1538 1539 1540 1541 1542 1543 1544 |
if (sret) { ret = sret; goto done; } b = p->nodes[level]; if (!b) { |
b3b4aa74b btrfs: drop unuse... |
1545 |
btrfs_release_path(p); |
c8c42864f Btrfs: break up b... |
1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 |
goto again; } BUG_ON(btrfs_header_nritems(b) == 1); } return 0; again: ret = -EAGAIN; done: return ret; } /* |
74123bd72 Btrfs: Commenting... |
1559 1560 1561 1562 1563 |
* look for key in the tree. path is filled in with nodes along the way * if key is found, we return zero and you can find the item in the leaf * level of the path (level 0) * * If the key isn't found, the path points to the slot where it should |
aa5d6bed2 Btrfs: return cod... |
1564 1565 |
* be inserted, and 1 is returned. If there are other errors during the * search a negative error number is returned. |
97571fd0c Btrfs: cleanup & ... |
1566 1567 1568 1569 |
* * if ins_len > 0, nodes and leaves will be split as we walk down the * tree. if ins_len < 0, nodes will be merged as we walk down the tree (if * possible) |
74123bd72 Btrfs: Commenting... |
1570 |
*/ |
e089f05c1 Btrfs: transactio... |
1571 1572 1573 |
int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key, struct btrfs_path *p, int ins_len, int cow) |
be0e5c097 Btrfs: Initial ch... |
1574 |
{ |
5f39d397d Btrfs: Create ext... |
1575 |
struct extent_buffer *b; |
be0e5c097 Btrfs: Initial ch... |
1576 1577 |
int slot; int ret; |
33c66f430 Btrfs: fix lockin... |
1578 |
int err; |
be0e5c097 Btrfs: Initial ch... |
1579 |
int level; |
925baeddc Btrfs: Start btre... |
1580 |
int lowest_unlock = 1; |
bd681513f Btrfs: switch the... |
1581 1582 1583 |
int root_lock; /* everything at write_lock_level or lower must be write locked */ int write_lock_level = 0; |
9f3a74273 Btrfs: Do snapsho... |
1584 |
u8 lowest_level = 0; |
6702ed490 Btrfs: Add run ti... |
1585 |
lowest_level = p->lowest_level; |
323ac95bc Btrfs: don't read... |
1586 |
WARN_ON(lowest_level && ins_len > 0); |
22b0ebda6 Btrfs: hunting sl... |
1587 |
WARN_ON(p->nodes[0] != NULL); |
251792013 Btrfs: nuke fs wi... |
1588 |
|
bd681513f Btrfs: switch the... |
1589 |
if (ins_len < 0) { |
925baeddc Btrfs: Start btre... |
1590 |
lowest_unlock = 2; |
65b51a009 btrfs_search_slot... |
1591 |
|
bd681513f Btrfs: switch the... |
1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 |
/* when we are removing items, we might have to go up to level * two as we update tree pointers Make sure we keep write * for those levels as well */ write_lock_level = 2; } else if (ins_len > 0) { /* * for inserting items, make sure we have a write lock on * level 1 so we can update keys */ write_lock_level = 1; } if (!cow) write_lock_level = -1; if (cow && (p->keep_locks || p->lowest_level)) write_lock_level = BTRFS_MAX_LEVEL; |
bb8039515 Btrfs: merge on t... |
1610 |
again: |
bd681513f Btrfs: switch the... |
1611 1612 1613 1614 1615 |
/* * we try very hard to do read locks on the root */ root_lock = BTRFS_READ_LOCK; level = 0; |
5d4f98a28 Btrfs: Mixed back... |
1616 |
if (p->search_commit_root) { |
bd681513f Btrfs: switch the... |
1617 1618 1619 1620 |
/* * the commit roots are read only * so we always do read locks */ |
5d4f98a28 Btrfs: Mixed back... |
1621 1622 |
b = root->commit_root; extent_buffer_get(b); |
bd681513f Btrfs: switch the... |
1623 |
level = btrfs_header_level(b); |
5d4f98a28 Btrfs: Mixed back... |
1624 |
if (!p->skip_locking) |
bd681513f Btrfs: switch the... |
1625 |
btrfs_tree_read_lock(b); |
5d4f98a28 Btrfs: Mixed back... |
1626 |
} else { |
bd681513f Btrfs: switch the... |
1627 |
if (p->skip_locking) { |
5d4f98a28 Btrfs: Mixed back... |
1628 |
b = btrfs_root_node(root); |
bd681513f Btrfs: switch the... |
1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 |
level = btrfs_header_level(b); } else { /* we don't know the level of the root node * until we actually have it read locked */ b = btrfs_read_lock_root_node(root); level = btrfs_header_level(b); if (level <= write_lock_level) { /* whoops, must trade for write lock */ btrfs_tree_read_unlock(b); free_extent_buffer(b); b = btrfs_lock_root_node(root); root_lock = BTRFS_WRITE_LOCK; /* the level might have changed, check again */ level = btrfs_header_level(b); } } |
5d4f98a28 Btrfs: Mixed back... |
1647 |
} |
bd681513f Btrfs: switch the... |
1648 1649 1650 |
p->nodes[level] = b; if (!p->skip_locking) p->locks[level] = root_lock; |
925baeddc Btrfs: Start btre... |
1651 |
|
eb60ceac0 Btrfs: Add backin... |
1652 |
while (b) { |
5f39d397d Btrfs: Create ext... |
1653 |
level = btrfs_header_level(b); |
65b51a009 btrfs_search_slot... |
1654 1655 1656 1657 1658 |
/* * setup the path here so we can release it under lock * contention with the cow code */ |
02217ed29 Btrfs: early refe... |
1659 |
if (cow) { |
c8c42864f Btrfs: break up b... |
1660 1661 1662 1663 1664 |
/* * if we don't really need to cow this block * then we don't want to set the path blocking, * so we test it here */ |
5d4f98a28 Btrfs: Mixed back... |
1665 |
if (!should_cow_block(trans, root, b)) |
65b51a009 btrfs_search_slot... |
1666 |
goto cow_done; |
5d4f98a28 Btrfs: Mixed back... |
1667 |
|
b4ce94de9 Btrfs: Change btr... |
1668 |
btrfs_set_path_blocking(p); |
bd681513f Btrfs: switch the... |
1669 1670 1671 1672 1673 1674 1675 1676 1677 |
/* * must have write locks on this node and the * parent */ if (level + 1 > write_lock_level) { write_lock_level = level + 1; btrfs_release_path(p); goto again; } |
33c66f430 Btrfs: fix lockin... |
1678 1679 1680 1681 |
err = btrfs_cow_block(trans, root, b, p->nodes[level + 1], p->slots[level + 1], &b); if (err) { |
33c66f430 Btrfs: fix lockin... |
1682 |
ret = err; |
65b51a009 btrfs_search_slot... |
1683 |
goto done; |
54aa1f4df Btrfs: Audit call... |
1684 |
} |
02217ed29 Btrfs: early refe... |
1685 |
} |
65b51a009 btrfs_search_slot... |
1686 |
cow_done: |
02217ed29 Btrfs: early refe... |
1687 |
BUG_ON(!cow && ins_len); |
65b51a009 btrfs_search_slot... |
1688 |
|
eb60ceac0 Btrfs: Add backin... |
1689 |
p->nodes[level] = b; |
bd681513f Btrfs: switch the... |
1690 |
btrfs_clear_path_blocking(p, NULL, 0); |
b4ce94de9 Btrfs: Change btr... |
1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 |
/* * we have a lock on b and as long as we aren't changing * the tree, there is no way to for the items in b to change. * It is safe to drop the lock on our parent before we * go through the expensive btree search on b. * * If cow is true, then we might be changing slot zero, * which may require changing the parent. So, we can't * drop the lock until after we know which slot we're * operating on. */ if (!cow) btrfs_unlock_up_safe(p, level + 1); |
5f39d397d Btrfs: Create ext... |
1705 |
ret = bin_search(b, key, level, &slot); |
b4ce94de9 Btrfs: Change btr... |
1706 |
|
5f39d397d Btrfs: Create ext... |
1707 |
if (level != 0) { |
33c66f430 Btrfs: fix lockin... |
1708 1709 1710 |
int dec = 0; if (ret && slot > 0) { dec = 1; |
be0e5c097 Btrfs: Initial ch... |
1711 |
slot -= 1; |
33c66f430 Btrfs: fix lockin... |
1712 |
} |
be0e5c097 Btrfs: Initial ch... |
1713 |
p->slots[level] = slot; |
33c66f430 Btrfs: fix lockin... |
1714 |
err = setup_nodes_for_search(trans, root, p, b, level, |
bd681513f Btrfs: switch the... |
1715 |
ins_len, &write_lock_level); |
33c66f430 Btrfs: fix lockin... |
1716 |
if (err == -EAGAIN) |
c8c42864f Btrfs: break up b... |
1717 |
goto again; |
33c66f430 Btrfs: fix lockin... |
1718 1719 |
if (err) { ret = err; |
c8c42864f Btrfs: break up b... |
1720 |
goto done; |
33c66f430 Btrfs: fix lockin... |
1721 |
} |
c8c42864f Btrfs: break up b... |
1722 1723 |
b = p->nodes[level]; slot = p->slots[level]; |
b4ce94de9 Btrfs: Change btr... |
1724 |
|
bd681513f Btrfs: switch the... |
1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 |
/* * slot 0 is special, if we change the key * we have to update the parent pointer * which means we must have a write lock * on the parent */ if (slot == 0 && cow && write_lock_level < level + 1) { write_lock_level = level + 1; btrfs_release_path(p); goto again; } |
f9efa9c78 Btrfs: Reduce con... |
1737 |
unlock_up(p, level, lowest_unlock); |
925baeddc Btrfs: Start btre... |
1738 |
if (level == lowest_level) { |
33c66f430 Btrfs: fix lockin... |
1739 1740 |
if (dec) p->slots[level]++; |
5b21f2ed3 Btrfs: extent_map... |
1741 |
goto done; |
925baeddc Btrfs: Start btre... |
1742 |
} |
ca7a79ad8 Btrfs: Pass down ... |
1743 |
|
33c66f430 Btrfs: fix lockin... |
1744 |
err = read_block_for_search(trans, root, p, |
c8c42864f Btrfs: break up b... |
1745 |
&b, level, slot, key); |
33c66f430 Btrfs: fix lockin... |
1746 |
if (err == -EAGAIN) |
c8c42864f Btrfs: break up b... |
1747 |
goto again; |
33c66f430 Btrfs: fix lockin... |
1748 1749 |
if (err) { ret = err; |
76a05b35a Btrfs: Don't loop... |
1750 |
goto done; |
33c66f430 Btrfs: fix lockin... |
1751 |
} |
76a05b35a Btrfs: Don't loop... |
1752 |
|
b4ce94de9 Btrfs: Change btr... |
1753 |
if (!p->skip_locking) { |
bd681513f Btrfs: switch the... |
1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 |
level = btrfs_header_level(b); if (level <= write_lock_level) { err = btrfs_try_tree_write_lock(b); if (!err) { btrfs_set_path_blocking(p); btrfs_tree_lock(b); btrfs_clear_path_blocking(p, b, BTRFS_WRITE_LOCK); } p->locks[level] = BTRFS_WRITE_LOCK; } else { err = btrfs_try_tree_read_lock(b); if (!err) { btrfs_set_path_blocking(p); btrfs_tree_read_lock(b); btrfs_clear_path_blocking(p, b, BTRFS_READ_LOCK); } p->locks[level] = BTRFS_READ_LOCK; |
b4ce94de9 Btrfs: Change btr... |
1773 |
} |
bd681513f Btrfs: switch the... |
1774 |
p->nodes[level] = b; |
b4ce94de9 Btrfs: Change btr... |
1775 |
} |
be0e5c097 Btrfs: Initial ch... |
1776 1777 |
} else { p->slots[level] = slot; |
87b29b208 Btrfs: properly c... |
1778 1779 |
if (ins_len > 0 && btrfs_leaf_free_space(root, b) < ins_len) { |
bd681513f Btrfs: switch the... |
1780 1781 1782 1783 1784 |
if (write_lock_level < 1) { write_lock_level = 1; btrfs_release_path(p); goto again; } |
b4ce94de9 Btrfs: Change btr... |
1785 |
btrfs_set_path_blocking(p); |
33c66f430 Btrfs: fix lockin... |
1786 1787 |
err = split_leaf(trans, root, key, p, ins_len, ret == 0); |
bd681513f Btrfs: switch the... |
1788 |
btrfs_clear_path_blocking(p, NULL, 0); |
b4ce94de9 Btrfs: Change btr... |
1789 |
|
33c66f430 Btrfs: fix lockin... |
1790 1791 1792 |
BUG_ON(err > 0); if (err) { ret = err; |
65b51a009 btrfs_search_slot... |
1793 1794 |
goto done; } |
5c680ed62 Btrfs: switch to ... |
1795 |
} |
459931eca Btrfs: Delete csu... |
1796 1797 |
if (!p->search_for_split) unlock_up(p, level, lowest_unlock); |
65b51a009 btrfs_search_slot... |
1798 |
goto done; |
be0e5c097 Btrfs: Initial ch... |
1799 1800 |
} } |
65b51a009 btrfs_search_slot... |
1801 1802 |
ret = 1; done: |
b4ce94de9 Btrfs: Change btr... |
1803 1804 1805 1806 |
/* * we don't really know what they plan on doing with the path * from here on, so for now just mark it as blocking */ |
b9473439d Btrfs: leave btre... |
1807 1808 |
if (!p->leave_spinning) btrfs_set_path_blocking(p); |
76a05b35a Btrfs: Don't loop... |
1809 |
if (ret < 0) |
b3b4aa74b btrfs: drop unuse... |
1810 |
btrfs_release_path(p); |
65b51a009 btrfs_search_slot... |
1811 |
return ret; |
be0e5c097 Btrfs: Initial ch... |
1812 |
} |
74123bd72 Btrfs: Commenting... |
1813 1814 1815 1816 1817 1818 |
/* * adjust the pointers going up the tree, starting at level * making sure the right key of each node is points to 'key'. * This is used after shifting pointers to the left, so it stops * fixing up pointers when a given leaf/node is not in slot 0 of the * higher levels |
aa5d6bed2 Btrfs: return cod... |
1819 1820 1821 |
* * If this fails to write a tree block, it returns -1, but continues * fixing up the blocks in ram so the tree is consistent. |
74123bd72 Btrfs: Commenting... |
1822 |
*/ |
5f39d397d Btrfs: Create ext... |
1823 1824 1825 |
static int fixup_low_keys(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_disk_key *key, int level) |
be0e5c097 Btrfs: Initial ch... |
1826 1827 |
{ int i; |
aa5d6bed2 Btrfs: return cod... |
1828 |
int ret = 0; |
5f39d397d Btrfs: Create ext... |
1829 |
struct extent_buffer *t; |
234b63a09 rename funcs and ... |
1830 |
for (i = level; i < BTRFS_MAX_LEVEL; i++) { |
be0e5c097 Btrfs: Initial ch... |
1831 |
int tslot = path->slots[i]; |
eb60ceac0 Btrfs: Add backin... |
1832 |
if (!path->nodes[i]) |
be0e5c097 Btrfs: Initial ch... |
1833 |
break; |
5f39d397d Btrfs: Create ext... |
1834 1835 |
t = path->nodes[i]; btrfs_set_node_key(t, key, tslot); |
d60255795 Btrfs: corruption... |
1836 |
btrfs_mark_buffer_dirty(path->nodes[i]); |
be0e5c097 Btrfs: Initial ch... |
1837 1838 1839 |
if (tslot != 0) break; } |
aa5d6bed2 Btrfs: return cod... |
1840 |
return ret; |
be0e5c097 Btrfs: Initial ch... |
1841 |
} |
74123bd72 Btrfs: Commenting... |
1842 |
/* |
31840ae1a Btrfs: Full back ... |
1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 |
* update item key. * * This function isn't completely safe. It's the caller's responsibility * that the new key won't break the order */ int btrfs_set_item_key_safe(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *new_key) { struct btrfs_disk_key disk_key; struct extent_buffer *eb; int slot; eb = path->nodes[0]; slot = path->slots[0]; if (slot > 0) { btrfs_item_key(eb, &disk_key, slot - 1); if (comp_keys(&disk_key, new_key) >= 0) return -1; } if (slot < btrfs_header_nritems(eb) - 1) { btrfs_item_key(eb, &disk_key, slot + 1); if (comp_keys(&disk_key, new_key) <= 0) return -1; } btrfs_cpu_key_to_disk(&disk_key, new_key); btrfs_set_item_key(eb, &disk_key, slot); btrfs_mark_buffer_dirty(eb); if (slot == 0) fixup_low_keys(trans, root, path, &disk_key, 1); return 0; } /* |
74123bd72 Btrfs: Commenting... |
1878 |
* try to push data from one node into the next node left in the |
79f95c82d Btrfs: Fixup the ... |
1879 |
* tree. |
aa5d6bed2 Btrfs: return cod... |
1880 1881 1882 |
* * returns 0 if some ptrs were pushed left, < 0 if there was some horrible * error, and > 0 if there was no room in the left hand block. |
74123bd72 Btrfs: Commenting... |
1883 |
*/ |
98ed51747 Btrfs: Force inli... |
1884 1885 |
static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *dst, |
971a1f664 Btrfs: Don't empt... |
1886 |
struct extent_buffer *src, int empty) |
be0e5c097 Btrfs: Initial ch... |
1887 |
{ |
be0e5c097 Btrfs: Initial ch... |
1888 |
int push_items = 0; |
bb8039515 Btrfs: merge on t... |
1889 1890 |
int src_nritems; int dst_nritems; |
aa5d6bed2 Btrfs: return cod... |
1891 |
int ret = 0; |
be0e5c097 Btrfs: Initial ch... |
1892 |
|
5f39d397d Btrfs: Create ext... |
1893 1894 |
src_nritems = btrfs_header_nritems(src); dst_nritems = btrfs_header_nritems(dst); |
123abc88c Btrfs: variable b... |
1895 |
push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems; |
7bb86316c Btrfs: Add back p... |
1896 1897 |
WARN_ON(btrfs_header_generation(src) != trans->transid); WARN_ON(btrfs_header_generation(dst) != trans->transid); |
54aa1f4df Btrfs: Audit call... |
1898 |
|
bce4eae98 Btrfs: Fix balanc... |
1899 |
if (!empty && src_nritems <= 8) |
971a1f664 Btrfs: Don't empt... |
1900 |
return 1; |
d397712bc Btrfs: Fix checkp... |
1901 |
if (push_items <= 0) |
be0e5c097 Btrfs: Initial ch... |
1902 |
return 1; |
bce4eae98 Btrfs: Fix balanc... |
1903 |
if (empty) { |
971a1f664 Btrfs: Don't empt... |
1904 |
push_items = min(src_nritems, push_items); |
bce4eae98 Btrfs: Fix balanc... |
1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 |
if (push_items < src_nritems) { /* leave at least 8 pointers in the node if * we aren't going to empty it */ if (src_nritems - push_items < 8) { if (push_items <= 8) return 1; push_items -= 8; } } } else push_items = min(src_nritems - 8, push_items); |
79f95c82d Btrfs: Fixup the ... |
1917 |
|
5f39d397d Btrfs: Create ext... |
1918 1919 1920 |
copy_extent_buffer(dst, src, btrfs_node_key_ptr_offset(dst_nritems), btrfs_node_key_ptr_offset(0), |
d397712bc Btrfs: Fix checkp... |
1921 |
push_items * sizeof(struct btrfs_key_ptr)); |
5f39d397d Btrfs: Create ext... |
1922 |
|
bb8039515 Btrfs: merge on t... |
1923 |
if (push_items < src_nritems) { |
5f39d397d Btrfs: Create ext... |
1924 1925 1926 1927 1928 1929 1930 1931 1932 |
memmove_extent_buffer(src, btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(push_items), (src_nritems - push_items) * sizeof(struct btrfs_key_ptr)); } btrfs_set_header_nritems(src, src_nritems - push_items); btrfs_set_header_nritems(dst, dst_nritems + push_items); btrfs_mark_buffer_dirty(src); btrfs_mark_buffer_dirty(dst); |
31840ae1a Btrfs: Full back ... |
1933 |
|
79f95c82d Btrfs: Fixup the ... |
1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 |
return ret; } /* * try to push data from one node into the next node right in the * tree. * * returns 0 if some ptrs were pushed, < 0 if there was some horrible * error, and > 0 if there was no room in the right hand block. * * this will only push up to 1/2 the contents of the left node over */ |
5f39d397d Btrfs: Create ext... |
1946 1947 1948 1949 |
static int balance_node_right(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *dst, struct extent_buffer *src) |
79f95c82d Btrfs: Fixup the ... |
1950 |
{ |
79f95c82d Btrfs: Fixup the ... |
1951 1952 1953 1954 1955 |
int push_items = 0; int max_push; int src_nritems; int dst_nritems; int ret = 0; |
79f95c82d Btrfs: Fixup the ... |
1956 |
|
7bb86316c Btrfs: Add back p... |
1957 1958 |
WARN_ON(btrfs_header_generation(src) != trans->transid); WARN_ON(btrfs_header_generation(dst) != trans->transid); |
5f39d397d Btrfs: Create ext... |
1959 1960 |
src_nritems = btrfs_header_nritems(src); dst_nritems = btrfs_header_nritems(dst); |
123abc88c Btrfs: variable b... |
1961 |
push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems; |
d397712bc Btrfs: Fix checkp... |
1962 |
if (push_items <= 0) |
79f95c82d Btrfs: Fixup the ... |
1963 |
return 1; |
bce4eae98 Btrfs: Fix balanc... |
1964 |
|
d397712bc Btrfs: Fix checkp... |
1965 |
if (src_nritems < 4) |
bce4eae98 Btrfs: Fix balanc... |
1966 |
return 1; |
79f95c82d Btrfs: Fixup the ... |
1967 1968 1969 |
max_push = src_nritems / 2 + 1; /* don't try to empty the node */ |
d397712bc Btrfs: Fix checkp... |
1970 |
if (max_push >= src_nritems) |
79f95c82d Btrfs: Fixup the ... |
1971 |
return 1; |
252c38f06 Btrfs: ctree.c cl... |
1972 |
|
79f95c82d Btrfs: Fixup the ... |
1973 1974 |
if (max_push < push_items) push_items = max_push; |
5f39d397d Btrfs: Create ext... |
1975 1976 1977 1978 |
memmove_extent_buffer(dst, btrfs_node_key_ptr_offset(push_items), btrfs_node_key_ptr_offset(0), (dst_nritems) * sizeof(struct btrfs_key_ptr)); |
d60255795 Btrfs: corruption... |
1979 |
|
5f39d397d Btrfs: Create ext... |
1980 1981 1982 |
copy_extent_buffer(dst, src, btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(src_nritems - push_items), |
d397712bc Btrfs: Fix checkp... |
1983 |
push_items * sizeof(struct btrfs_key_ptr)); |
79f95c82d Btrfs: Fixup the ... |
1984 |
|
5f39d397d Btrfs: Create ext... |
1985 1986 |
btrfs_set_header_nritems(src, src_nritems - push_items); btrfs_set_header_nritems(dst, dst_nritems + push_items); |
79f95c82d Btrfs: Fixup the ... |
1987 |
|
5f39d397d Btrfs: Create ext... |
1988 1989 |
btrfs_mark_buffer_dirty(src); btrfs_mark_buffer_dirty(dst); |
31840ae1a Btrfs: Full back ... |
1990 |
|
aa5d6bed2 Btrfs: return cod... |
1991 |
return ret; |
be0e5c097 Btrfs: Initial ch... |
1992 |
} |
74123bd72 Btrfs: Commenting... |
1993 |
/* |
97571fd0c Btrfs: cleanup & ... |
1994 1995 1996 |
* helper function to insert a new root level in the tree. * A new node is allocated, and a single item is inserted to * point to the existing root |
aa5d6bed2 Btrfs: return cod... |
1997 1998 |
* * returns zero on success or < 0 on failure. |
97571fd0c Btrfs: cleanup & ... |
1999 |
*/ |
d397712bc Btrfs: Fix checkp... |
2000 |
static noinline int insert_new_root(struct btrfs_trans_handle *trans, |
5f39d397d Btrfs: Create ext... |
2001 2002 |
struct btrfs_root *root, struct btrfs_path *path, int level) |
5c680ed62 Btrfs: switch to ... |
2003 |
{ |
7bb86316c Btrfs: Add back p... |
2004 |
u64 lower_gen; |
5f39d397d Btrfs: Create ext... |
2005 2006 |
struct extent_buffer *lower; struct extent_buffer *c; |
925baeddc Btrfs: Start btre... |
2007 |
struct extent_buffer *old; |
5f39d397d Btrfs: Create ext... |
2008 |
struct btrfs_disk_key lower_key; |
5c680ed62 Btrfs: switch to ... |
2009 2010 2011 |
BUG_ON(path->nodes[level]); BUG_ON(path->nodes[level-1] != root->node); |
7bb86316c Btrfs: Add back p... |
2012 2013 2014 2015 2016 |
lower = path->nodes[level-1]; if (level == 1) btrfs_item_key(lower, &lower_key, 0); else btrfs_node_key(lower, &lower_key, 0); |
31840ae1a Btrfs: Full back ... |
2017 |
c = btrfs_alloc_free_block(trans, root, root->nodesize, 0, |
5d4f98a28 Btrfs: Mixed back... |
2018 |
root->root_key.objectid, &lower_key, |
ad3d81ba8 Btrfs: missing en... |
2019 |
level, root->node->start, 0); |
5f39d397d Btrfs: Create ext... |
2020 2021 |
if (IS_ERR(c)) return PTR_ERR(c); |
925baeddc Btrfs: Start btre... |
2022 |
|
f0486c68e Btrfs: Introduce ... |
2023 |
root_add_used(root, root->nodesize); |
5d4f98a28 Btrfs: Mixed back... |
2024 |
memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header)); |
5f39d397d Btrfs: Create ext... |
2025 2026 |
btrfs_set_header_nritems(c, 1); btrfs_set_header_level(c, level); |
db94535db Btrfs: Allow tree... |
2027 |
btrfs_set_header_bytenr(c, c->start); |
5f39d397d Btrfs: Create ext... |
2028 |
btrfs_set_header_generation(c, trans->transid); |
5d4f98a28 Btrfs: Mixed back... |
2029 |
btrfs_set_header_backref_rev(c, BTRFS_MIXED_BACKREF_REV); |
5f39d397d Btrfs: Create ext... |
2030 |
btrfs_set_header_owner(c, root->root_key.objectid); |
5f39d397d Btrfs: Create ext... |
2031 2032 2033 2034 |
write_extent_buffer(c, root->fs_info->fsid, (unsigned long)btrfs_header_fsid(c), BTRFS_FSID_SIZE); |
e17cade25 Btrfs: Add chunk ... |
2035 2036 2037 2038 |
write_extent_buffer(c, root->fs_info->chunk_tree_uuid, (unsigned long)btrfs_header_chunk_tree_uuid(c), BTRFS_UUID_SIZE); |
5f39d397d Btrfs: Create ext... |
2039 |
btrfs_set_node_key(c, &lower_key, 0); |
db94535db Btrfs: Allow tree... |
2040 |
btrfs_set_node_blockptr(c, 0, lower->start); |
7bb86316c Btrfs: Add back p... |
2041 |
lower_gen = btrfs_header_generation(lower); |
31840ae1a Btrfs: Full back ... |
2042 |
WARN_ON(lower_gen != trans->transid); |
7bb86316c Btrfs: Add back p... |
2043 2044 |
btrfs_set_node_ptr_generation(c, 0, lower_gen); |
d57197629 btrfs_create, btr... |
2045 |
|
5f39d397d Btrfs: Create ext... |
2046 |
btrfs_mark_buffer_dirty(c); |
d57197629 btrfs_create, btr... |
2047 |
|
925baeddc Btrfs: Start btre... |
2048 |
old = root->node; |
240f62c87 Btrfs: use RCU in... |
2049 |
rcu_assign_pointer(root->node, c); |
925baeddc Btrfs: Start btre... |
2050 2051 2052 |
/* the super has an extra ref to root->node */ free_extent_buffer(old); |
0b86a832a Btrfs: Add suppor... |
2053 |
add_root_to_dirty_list(root); |
5f39d397d Btrfs: Create ext... |
2054 2055 |
extent_buffer_get(c); path->nodes[level] = c; |
bd681513f Btrfs: switch the... |
2056 |
path->locks[level] = BTRFS_WRITE_LOCK; |
5c680ed62 Btrfs: switch to ... |
2057 2058 2059 |
path->slots[level] = 0; return 0; } |
74123bd72 Btrfs: Commenting... |
2060 2061 2062 |
/* * worker function to insert a single pointer in a node. * the node should have enough room for the pointer already |
97571fd0c Btrfs: cleanup & ... |
2063 |
* |
74123bd72 Btrfs: Commenting... |
2064 2065 |
* slot and level indicate where you want the key to go, and * blocknr is the block the key points to. |
aa5d6bed2 Btrfs: return cod... |
2066 2067 |
* * returns zero on success and < 0 on any error |
74123bd72 Btrfs: Commenting... |
2068 |
*/ |
e089f05c1 Btrfs: transactio... |
2069 2070 |
static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_disk_key |
db94535db Btrfs: Allow tree... |
2071 |
*key, u64 bytenr, int slot, int level) |
74123bd72 Btrfs: Commenting... |
2072 |
{ |
5f39d397d Btrfs: Create ext... |
2073 |
struct extent_buffer *lower; |
74123bd72 Btrfs: Commenting... |
2074 |
int nritems; |
5c680ed62 Btrfs: switch to ... |
2075 2076 |
BUG_ON(!path->nodes[level]); |
f0486c68e Btrfs: Introduce ... |
2077 |
btrfs_assert_tree_locked(path->nodes[level]); |
5f39d397d Btrfs: Create ext... |
2078 2079 |
lower = path->nodes[level]; nritems = btrfs_header_nritems(lower); |
c293498be Btrfs: BUG to BUG... |
2080 |
BUG_ON(slot > nritems); |
123abc88c Btrfs: variable b... |
2081 |
if (nritems == BTRFS_NODEPTRS_PER_BLOCK(root)) |
74123bd72 Btrfs: Commenting... |
2082 2083 |
BUG(); if (slot != nritems) { |
5f39d397d Btrfs: Create ext... |
2084 2085 2086 |
memmove_extent_buffer(lower, btrfs_node_key_ptr_offset(slot + 1), btrfs_node_key_ptr_offset(slot), |
d60255795 Btrfs: corruption... |
2087 |
(nritems - slot) * sizeof(struct btrfs_key_ptr)); |
74123bd72 Btrfs: Commenting... |
2088 |
} |
5f39d397d Btrfs: Create ext... |
2089 |
btrfs_set_node_key(lower, key, slot); |
db94535db Btrfs: Allow tree... |
2090 |
btrfs_set_node_blockptr(lower, slot, bytenr); |
74493f7a5 Btrfs: Implement ... |
2091 2092 |
WARN_ON(trans->transid == 0); btrfs_set_node_ptr_generation(lower, slot, trans->transid); |
5f39d397d Btrfs: Create ext... |
2093 2094 |
btrfs_set_header_nritems(lower, nritems + 1); btrfs_mark_buffer_dirty(lower); |
74123bd72 Btrfs: Commenting... |
2095 2096 |
return 0; } |
97571fd0c Btrfs: cleanup & ... |
2097 2098 2099 2100 2101 2102 |
/* * split the node at the specified level in path in two. * The path is corrected to point to the appropriate node after the split * * Before splitting this tries to make some room in the node by pushing * left and right, if either one works, it returns right away. |
aa5d6bed2 Btrfs: return cod... |
2103 2104 |
* * returns 0 on success and < 0 on failure |
97571fd0c Btrfs: cleanup & ... |
2105 |
*/ |
e02119d5a Btrfs: Add a writ... |
2106 2107 2108 |
static noinline int split_node(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int level) |
be0e5c097 Btrfs: Initial ch... |
2109 |
{ |
5f39d397d Btrfs: Create ext... |
2110 2111 2112 |
struct extent_buffer *c; struct extent_buffer *split; struct btrfs_disk_key disk_key; |
be0e5c097 Btrfs: Initial ch... |
2113 |
int mid; |
5c680ed62 Btrfs: switch to ... |
2114 |
int ret; |
aa5d6bed2 Btrfs: return cod... |
2115 |
int wret; |
7518a238e Btrfs: get/set fo... |
2116 |
u32 c_nritems; |
eb60ceac0 Btrfs: Add backin... |
2117 |
|
5f39d397d Btrfs: Create ext... |
2118 |
c = path->nodes[level]; |
7bb86316c Btrfs: Add back p... |
2119 |
WARN_ON(btrfs_header_generation(c) != trans->transid); |
5f39d397d Btrfs: Create ext... |
2120 |
if (c == root->node) { |
5c680ed62 Btrfs: switch to ... |
2121 |
/* trying to split the root, lets make a new one */ |
e089f05c1 Btrfs: transactio... |
2122 |
ret = insert_new_root(trans, root, path, level + 1); |
5c680ed62 Btrfs: switch to ... |
2123 2124 |
if (ret) return ret; |
b36124210 Btrfs: stop avoid... |
2125 |
} else { |
e66f709b1 Btrfs: write barr... |
2126 |
ret = push_nodes_for_insert(trans, root, path, level); |
5f39d397d Btrfs: Create ext... |
2127 2128 |
c = path->nodes[level]; if (!ret && btrfs_header_nritems(c) < |
c448acf0a Btrfs: Fix split_... |
2129 |
BTRFS_NODEPTRS_PER_BLOCK(root) - 3) |
e66f709b1 Btrfs: write barr... |
2130 |
return 0; |
54aa1f4df Btrfs: Audit call... |
2131 2132 |
if (ret < 0) return ret; |
be0e5c097 Btrfs: Initial ch... |
2133 |
} |
e66f709b1 Btrfs: write barr... |
2134 |
|
5f39d397d Btrfs: Create ext... |
2135 |
c_nritems = btrfs_header_nritems(c); |
5d4f98a28 Btrfs: Mixed back... |
2136 2137 |
mid = (c_nritems + 1) / 2; btrfs_node_key(c, &disk_key, mid); |
7bb86316c Btrfs: Add back p... |
2138 |
|
5d4f98a28 Btrfs: Mixed back... |
2139 |
split = btrfs_alloc_free_block(trans, root, root->nodesize, 0, |
31840ae1a Btrfs: Full back ... |
2140 |
root->root_key.objectid, |
5d4f98a28 Btrfs: Mixed back... |
2141 |
&disk_key, level, c->start, 0); |
5f39d397d Btrfs: Create ext... |
2142 2143 |
if (IS_ERR(split)) return PTR_ERR(split); |
f0486c68e Btrfs: Introduce ... |
2144 |
root_add_used(root, root->nodesize); |
5d4f98a28 Btrfs: Mixed back... |
2145 |
memset_extent_buffer(split, 0, 0, sizeof(struct btrfs_header)); |
5f39d397d Btrfs: Create ext... |
2146 |
btrfs_set_header_level(split, btrfs_header_level(c)); |
db94535db Btrfs: Allow tree... |
2147 |
btrfs_set_header_bytenr(split, split->start); |
5f39d397d Btrfs: Create ext... |
2148 |
btrfs_set_header_generation(split, trans->transid); |
5d4f98a28 Btrfs: Mixed back... |
2149 |
btrfs_set_header_backref_rev(split, BTRFS_MIXED_BACKREF_REV); |
5f39d397d Btrfs: Create ext... |
2150 2151 2152 2153 |
btrfs_set_header_owner(split, root->root_key.objectid); write_extent_buffer(split, root->fs_info->fsid, (unsigned long)btrfs_header_fsid(split), BTRFS_FSID_SIZE); |
e17cade25 Btrfs: Add chunk ... |
2154 2155 2156 |
write_extent_buffer(split, root->fs_info->chunk_tree_uuid, (unsigned long)btrfs_header_chunk_tree_uuid(split), BTRFS_UUID_SIZE); |
54aa1f4df Btrfs: Audit call... |
2157 |
|
5f39d397d Btrfs: Create ext... |
2158 2159 2160 2161 2162 2163 2164 |
copy_extent_buffer(split, c, btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(mid), (c_nritems - mid) * sizeof(struct btrfs_key_ptr)); btrfs_set_header_nritems(split, c_nritems - mid); btrfs_set_header_nritems(c, mid); |
aa5d6bed2 Btrfs: return cod... |
2165 |
ret = 0; |
5f39d397d Btrfs: Create ext... |
2166 2167 |
btrfs_mark_buffer_dirty(c); btrfs_mark_buffer_dirty(split); |
db94535db Btrfs: Allow tree... |
2168 |
wret = insert_ptr(trans, root, path, &disk_key, split->start, |
5f39d397d Btrfs: Create ext... |
2169 |
path->slots[level + 1] + 1, |
123abc88c Btrfs: variable b... |
2170 |
level + 1); |
aa5d6bed2 Btrfs: return cod... |
2171 2172 |
if (wret) ret = wret; |
5de08d7d5 Btrfs: Break up c... |
2173 |
if (path->slots[level] >= mid) { |
5c680ed62 Btrfs: switch to ... |
2174 |
path->slots[level] -= mid; |
925baeddc Btrfs: Start btre... |
2175 |
btrfs_tree_unlock(c); |
5f39d397d Btrfs: Create ext... |
2176 2177 |
free_extent_buffer(c); path->nodes[level] = split; |
5c680ed62 Btrfs: switch to ... |
2178 2179 |
path->slots[level + 1] += 1; } else { |
925baeddc Btrfs: Start btre... |
2180 |
btrfs_tree_unlock(split); |
5f39d397d Btrfs: Create ext... |
2181 |
free_extent_buffer(split); |
be0e5c097 Btrfs: Initial ch... |
2182 |
} |
aa5d6bed2 Btrfs: return cod... |
2183 |
return ret; |
be0e5c097 Btrfs: Initial ch... |
2184 |
} |
74123bd72 Btrfs: Commenting... |
2185 2186 2187 2188 2189 |
/* * how many bytes are required to store the items in a leaf. start * and nr indicate which items in the leaf to check. This totals up the * space used both by the item structs and the item data */ |
5f39d397d Btrfs: Create ext... |
2190 |
static int leaf_space_used(struct extent_buffer *l, int start, int nr) |
be0e5c097 Btrfs: Initial ch... |
2191 2192 |
{ int data_len; |
5f39d397d Btrfs: Create ext... |
2193 |
int nritems = btrfs_header_nritems(l); |
d4dbff953 Btrfs: support fo... |
2194 |
int end = min(nritems, start + nr) - 1; |
be0e5c097 Btrfs: Initial ch... |
2195 2196 2197 |
if (!nr) return 0; |
5f39d397d Btrfs: Create ext... |
2198 2199 |
data_len = btrfs_item_end_nr(l, start); data_len = data_len - btrfs_item_offset_nr(l, end); |
0783fcfc4 Btrfs: struct ite... |
2200 |
data_len += sizeof(struct btrfs_item) * nr; |
d4dbff953 Btrfs: support fo... |
2201 |
WARN_ON(data_len < 0); |
be0e5c097 Btrfs: Initial ch... |
2202 2203 |
return data_len; } |
74123bd72 Btrfs: Commenting... |
2204 |
/* |
d4dbff953 Btrfs: support fo... |
2205 2206 2207 2208 |
* The space between the end of the leaf items and * the start of the leaf data. IOW, how much room * the leaf has left for both items and data */ |
d397712bc Btrfs: Fix checkp... |
2209 |
noinline int btrfs_leaf_free_space(struct btrfs_root *root, |
e02119d5a Btrfs: Add a writ... |
2210 |
struct extent_buffer *leaf) |
d4dbff953 Btrfs: support fo... |
2211 |
{ |
5f39d397d Btrfs: Create ext... |
2212 2213 2214 2215 |
int nritems = btrfs_header_nritems(leaf); int ret; ret = BTRFS_LEAF_DATA_SIZE(root) - leaf_space_used(leaf, 0, nritems); if (ret < 0) { |
d397712bc Btrfs: Fix checkp... |
2216 2217 2218 |
printk(KERN_CRIT "leaf free space ret %d, leaf data size %lu, " "used %d nritems %d ", |
ae2f5411c btrfs: 32-bit typ... |
2219 |
ret, (unsigned long) BTRFS_LEAF_DATA_SIZE(root), |
5f39d397d Btrfs: Create ext... |
2220 2221 2222 |
leaf_space_used(leaf, 0, nritems), nritems); } return ret; |
d4dbff953 Btrfs: support fo... |
2223 |
} |
99d8f83c9 Btrfs: fix split_... |
2224 2225 2226 2227 |
/* * min slot controls the lowest index we're willing to push to the * right. We'll push up to and including min_slot, but no lower */ |
44871b1b2 Btrfs: reduce sta... |
2228 2229 2230 2231 2232 |
static noinline int __push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int data_size, int empty, struct extent_buffer *right, |
99d8f83c9 Btrfs: fix split_... |
2233 2234 |
int free_space, u32 left_nritems, u32 min_slot) |
00ec4c516 Btrfs: push_leaf_... |
2235 |
{ |
5f39d397d Btrfs: Create ext... |
2236 |
struct extent_buffer *left = path->nodes[0]; |
44871b1b2 Btrfs: reduce sta... |
2237 |
struct extent_buffer *upper = path->nodes[1]; |
5f39d397d Btrfs: Create ext... |
2238 |
struct btrfs_disk_key disk_key; |
00ec4c516 Btrfs: push_leaf_... |
2239 |
int slot; |
34a382187 Btrfs: Change pus... |
2240 |
u32 i; |
00ec4c516 Btrfs: push_leaf_... |
2241 2242 |
int push_space = 0; int push_items = 0; |
0783fcfc4 Btrfs: struct ite... |
2243 |
struct btrfs_item *item; |
34a382187 Btrfs: Change pus... |
2244 |
u32 nr; |
7518a238e Btrfs: get/set fo... |
2245 |
u32 right_nritems; |
5f39d397d Btrfs: Create ext... |
2246 |
u32 data_end; |
db94535db Btrfs: Allow tree... |
2247 |
u32 this_item_size; |
00ec4c516 Btrfs: push_leaf_... |
2248 |
|
34a382187 Btrfs: Change pus... |
2249 2250 2251 |
if (empty) nr = 0; else |
99d8f83c9 Btrfs: fix split_... |
2252 |
nr = max_t(u32, 1, min_slot); |
34a382187 Btrfs: Change pus... |
2253 |
|
31840ae1a Btrfs: Full back ... |
2254 |
if (path->slots[0] >= left_nritems) |
87b29b208 Btrfs: properly c... |
2255 |
push_space += data_size; |
31840ae1a Btrfs: Full back ... |
2256 |
|
44871b1b2 Btrfs: reduce sta... |
2257 |
slot = path->slots[1]; |
34a382187 Btrfs: Change pus... |
2258 2259 |
i = left_nritems - 1; while (i >= nr) { |
5f39d397d Btrfs: Create ext... |
2260 |
item = btrfs_item_nr(left, i); |
db94535db Btrfs: Allow tree... |
2261 |
|
31840ae1a Btrfs: Full back ... |
2262 2263 2264 2265 2266 2267 2268 2269 2270 |
if (!empty && push_items > 0) { if (path->slots[0] > i) break; if (path->slots[0] == i) { int space = btrfs_leaf_free_space(root, left); if (space + push_space * 2 > free_space) break; } } |
00ec4c516 Btrfs: push_leaf_... |
2271 |
if (path->slots[0] == i) |
87b29b208 Btrfs: properly c... |
2272 |
push_space += data_size; |
db94535db Btrfs: Allow tree... |
2273 |
|
db94535db Btrfs: Allow tree... |
2274 2275 |
this_item_size = btrfs_item_size(left, item); if (this_item_size + sizeof(*item) + push_space > free_space) |
00ec4c516 Btrfs: push_leaf_... |
2276 |
break; |
31840ae1a Btrfs: Full back ... |
2277 |
|
00ec4c516 Btrfs: push_leaf_... |
2278 |
push_items++; |
db94535db Btrfs: Allow tree... |
2279 |
push_space += this_item_size + sizeof(*item); |
34a382187 Btrfs: Change pus... |
2280 2281 2282 |
if (i == 0) break; i--; |
db94535db Btrfs: Allow tree... |
2283 |
} |
5f39d397d Btrfs: Create ext... |
2284 |
|
925baeddc Btrfs: Start btre... |
2285 2286 |
if (push_items == 0) goto out_unlock; |
5f39d397d Btrfs: Create ext... |
2287 |
|
34a382187 Btrfs: Change pus... |
2288 |
if (!empty && push_items == left_nritems) |
a429e5137 Btrfs: working fi... |
2289 |
WARN_ON(1); |
5f39d397d Btrfs: Create ext... |
2290 |
|
00ec4c516 Btrfs: push_leaf_... |
2291 |
/* push left to right */ |
5f39d397d Btrfs: Create ext... |
2292 |
right_nritems = btrfs_header_nritems(right); |
34a382187 Btrfs: Change pus... |
2293 |
|
5f39d397d Btrfs: Create ext... |
2294 |
push_space = btrfs_item_end_nr(left, left_nritems - push_items); |
123abc88c Btrfs: variable b... |
2295 |
push_space -= leaf_data_end(root, left); |
5f39d397d Btrfs: Create ext... |
2296 |
|
00ec4c516 Btrfs: push_leaf_... |
2297 |
/* make room in the right data area */ |
5f39d397d Btrfs: Create ext... |
2298 2299 2300 2301 2302 |
data_end = leaf_data_end(root, right); memmove_extent_buffer(right, btrfs_leaf_data(right) + data_end - push_space, btrfs_leaf_data(right) + data_end, BTRFS_LEAF_DATA_SIZE(root) - data_end); |
00ec4c516 Btrfs: push_leaf_... |
2303 |
/* copy from the left data area */ |
5f39d397d Btrfs: Create ext... |
2304 |
copy_extent_buffer(right, left, btrfs_leaf_data(right) + |
d60255795 Btrfs: corruption... |
2305 2306 2307 |
BTRFS_LEAF_DATA_SIZE(root) - push_space, btrfs_leaf_data(left) + leaf_data_end(root, left), push_space); |
5f39d397d Btrfs: Create ext... |
2308 2309 2310 2311 |
memmove_extent_buffer(right, btrfs_item_nr_offset(push_items), btrfs_item_nr_offset(0), right_nritems * sizeof(struct btrfs_item)); |
00ec4c516 Btrfs: push_leaf_... |
2312 |
/* copy the items from left to right */ |
5f39d397d Btrfs: Create ext... |
2313 2314 2315 |
copy_extent_buffer(right, left, btrfs_item_nr_offset(0), btrfs_item_nr_offset(left_nritems - push_items), push_items * sizeof(struct btrfs_item)); |
00ec4c516 Btrfs: push_leaf_... |
2316 2317 |
/* update the item pointers */ |
7518a238e Btrfs: get/set fo... |
2318 |
right_nritems += push_items; |
5f39d397d Btrfs: Create ext... |
2319 |
btrfs_set_header_nritems(right, right_nritems); |
123abc88c Btrfs: variable b... |
2320 |
push_space = BTRFS_LEAF_DATA_SIZE(root); |
7518a238e Btrfs: get/set fo... |
2321 |
for (i = 0; i < right_nritems; i++) { |
5f39d397d Btrfs: Create ext... |
2322 |
item = btrfs_item_nr(right, i); |
db94535db Btrfs: Allow tree... |
2323 2324 2325 |
push_space -= btrfs_item_size(right, item); btrfs_set_item_offset(right, item, push_space); } |
7518a238e Btrfs: get/set fo... |
2326 |
left_nritems -= push_items; |
5f39d397d Btrfs: Create ext... |
2327 |
btrfs_set_header_nritems(left, left_nritems); |
00ec4c516 Btrfs: push_leaf_... |
2328 |
|
34a382187 Btrfs: Change pus... |
2329 2330 |
if (left_nritems) btrfs_mark_buffer_dirty(left); |
f0486c68e Btrfs: Introduce ... |
2331 2332 |
else clean_tree_block(trans, root, left); |
5f39d397d Btrfs: Create ext... |
2333 |
btrfs_mark_buffer_dirty(right); |
a429e5137 Btrfs: working fi... |
2334 |
|
5f39d397d Btrfs: Create ext... |
2335 2336 |
btrfs_item_key(right, &disk_key, 0); btrfs_set_node_key(upper, &disk_key, slot + 1); |
d60255795 Btrfs: corruption... |
2337 |
btrfs_mark_buffer_dirty(upper); |
02217ed29 Btrfs: early refe... |
2338 |
|
00ec4c516 Btrfs: push_leaf_... |
2339 |
/* then fixup the leaf pointer in the path */ |
7518a238e Btrfs: get/set fo... |
2340 2341 |
if (path->slots[0] >= left_nritems) { path->slots[0] -= left_nritems; |
925baeddc Btrfs: Start btre... |
2342 2343 2344 |
if (btrfs_header_nritems(path->nodes[0]) == 0) clean_tree_block(trans, root, path->nodes[0]); btrfs_tree_unlock(path->nodes[0]); |
5f39d397d Btrfs: Create ext... |
2345 2346 |
free_extent_buffer(path->nodes[0]); path->nodes[0] = right; |
00ec4c516 Btrfs: push_leaf_... |
2347 2348 |
path->slots[1] += 1; } else { |
925baeddc Btrfs: Start btre... |
2349 |
btrfs_tree_unlock(right); |
5f39d397d Btrfs: Create ext... |
2350 |
free_extent_buffer(right); |
00ec4c516 Btrfs: push_leaf_... |
2351 2352 |
} return 0; |
925baeddc Btrfs: Start btre... |
2353 2354 2355 2356 2357 |
out_unlock: btrfs_tree_unlock(right); free_extent_buffer(right); return 1; |
00ec4c516 Btrfs: push_leaf_... |
2358 |
} |
925baeddc Btrfs: Start btre... |
2359 |
|
00ec4c516 Btrfs: push_leaf_... |
2360 |
/* |
44871b1b2 Btrfs: reduce sta... |
2361 2362 2363 2364 2365 |
* push some data in the path leaf to the right, trying to free up at * least data_size bytes. returns zero if the push worked, nonzero otherwise * * returns 1 if the push failed because the other node didn't have enough * room, 0 if everything worked out and < 0 if there were major errors. |
99d8f83c9 Btrfs: fix split_... |
2366 2367 2368 |
* * this will push starting from min_slot to the end of the leaf. It won't * push any slot lower than min_slot |
44871b1b2 Btrfs: reduce sta... |
2369 2370 |
*/ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root |
99d8f83c9 Btrfs: fix split_... |
2371 2372 2373 |
*root, struct btrfs_path *path, int min_data_size, int data_size, int empty, u32 min_slot) |
44871b1b2 Btrfs: reduce sta... |
2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 |
{ struct extent_buffer *left = path->nodes[0]; struct extent_buffer *right; struct extent_buffer *upper; int slot; int free_space; u32 left_nritems; int ret; if (!path->nodes[1]) return 1; slot = path->slots[1]; upper = path->nodes[1]; if (slot >= btrfs_header_nritems(upper) - 1) return 1; btrfs_assert_tree_locked(path->nodes[1]); right = read_node_slot(root, upper, slot + 1); |
91ca338d7 btrfs: check NULL... |
2394 2395 |
if (right == NULL) return 1; |
44871b1b2 Btrfs: reduce sta... |
2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 |
btrfs_tree_lock(right); btrfs_set_lock_blocking(right); free_space = btrfs_leaf_free_space(root, right); if (free_space < data_size) goto out_unlock; /* cow and double check */ ret = btrfs_cow_block(trans, root, right, upper, slot + 1, &right); if (ret) goto out_unlock; free_space = btrfs_leaf_free_space(root, right); if (free_space < data_size) goto out_unlock; left_nritems = btrfs_header_nritems(left); if (left_nritems == 0) goto out_unlock; |
99d8f83c9 Btrfs: fix split_... |
2416 2417 |
return __push_leaf_right(trans, root, path, min_data_size, empty, right, free_space, left_nritems, min_slot); |
44871b1b2 Btrfs: reduce sta... |
2418 2419 2420 2421 2422 2423 2424 |
out_unlock: btrfs_tree_unlock(right); free_extent_buffer(right); return 1; } /* |
74123bd72 Btrfs: Commenting... |
2425 2426 |
* push some data in the path leaf to the left, trying to free up at * least data_size bytes. returns zero if the push worked, nonzero otherwise |
99d8f83c9 Btrfs: fix split_... |
2427 2428 2429 2430 |
* * max_slot can put a limit on how far into the leaf we'll push items. The * item at 'max_slot' won't be touched. Use (u32)-1 to make us do all the * items |
74123bd72 Btrfs: Commenting... |
2431 |
*/ |
44871b1b2 Btrfs: reduce sta... |
2432 2433 2434 2435 |
static noinline int __push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int data_size, int empty, struct extent_buffer *left, |
99d8f83c9 Btrfs: fix split_... |
2436 2437 |
int free_space, u32 right_nritems, u32 max_slot) |
be0e5c097 Btrfs: Initial ch... |
2438 |
{ |
5f39d397d Btrfs: Create ext... |
2439 2440 |
struct btrfs_disk_key disk_key; struct extent_buffer *right = path->nodes[0]; |
be0e5c097 Btrfs: Initial ch... |
2441 |
int i; |
be0e5c097 Btrfs: Initial ch... |
2442 2443 |
int push_space = 0; int push_items = 0; |
0783fcfc4 Btrfs: struct ite... |
2444 |
struct btrfs_item *item; |
7518a238e Btrfs: get/set fo... |
2445 |
u32 old_left_nritems; |
34a382187 Btrfs: Change pus... |
2446 |
u32 nr; |
aa5d6bed2 Btrfs: return cod... |
2447 2448 |
int ret = 0; int wret; |
db94535db Btrfs: Allow tree... |
2449 2450 |
u32 this_item_size; u32 old_left_item_size; |
be0e5c097 Btrfs: Initial ch... |
2451 |
|
34a382187 Btrfs: Change pus... |
2452 |
if (empty) |
99d8f83c9 Btrfs: fix split_... |
2453 |
nr = min(right_nritems, max_slot); |
34a382187 Btrfs: Change pus... |
2454 |
else |
99d8f83c9 Btrfs: fix split_... |
2455 |
nr = min(right_nritems - 1, max_slot); |
34a382187 Btrfs: Change pus... |
2456 2457 |
for (i = 0; i < nr; i++) { |
5f39d397d Btrfs: Create ext... |
2458 |
item = btrfs_item_nr(right, i); |
db94535db Btrfs: Allow tree... |
2459 |
|
31840ae1a Btrfs: Full back ... |
2460 2461 2462 2463 2464 2465 2466 2467 2468 |
if (!empty && push_items > 0) { if (path->slots[0] < i) break; if (path->slots[0] == i) { int space = btrfs_leaf_free_space(root, right); if (space + push_space * 2 > free_space) break; } } |
be0e5c097 Btrfs: Initial ch... |
2469 |
if (path->slots[0] == i) |
87b29b208 Btrfs: properly c... |
2470 |
push_space += data_size; |
db94535db Btrfs: Allow tree... |
2471 2472 2473 |
this_item_size = btrfs_item_size(right, item); if (this_item_size + sizeof(*item) + push_space > free_space) |
be0e5c097 Btrfs: Initial ch... |
2474 |
break; |
db94535db Btrfs: Allow tree... |
2475 |
|
be0e5c097 Btrfs: Initial ch... |
2476 |
push_items++; |
db94535db Btrfs: Allow tree... |
2477 2478 |
push_space += this_item_size + sizeof(*item); } |
be0e5c097 Btrfs: Initial ch... |
2479 |
if (push_items == 0) { |
925baeddc Btrfs: Start btre... |
2480 2481 |
ret = 1; goto out; |
be0e5c097 Btrfs: Initial ch... |
2482 |
} |
34a382187 Btrfs: Change pus... |
2483 |
if (!empty && push_items == btrfs_header_nritems(right)) |
a429e5137 Btrfs: working fi... |
2484 |
WARN_ON(1); |
5f39d397d Btrfs: Create ext... |
2485 |
|
be0e5c097 Btrfs: Initial ch... |
2486 |
/* push data from right to left */ |
5f39d397d Btrfs: Create ext... |
2487 2488 2489 2490 |
copy_extent_buffer(left, right, btrfs_item_nr_offset(btrfs_header_nritems(left)), btrfs_item_nr_offset(0), push_items * sizeof(struct btrfs_item)); |
123abc88c Btrfs: variable b... |
2491 |
push_space = BTRFS_LEAF_DATA_SIZE(root) - |
d397712bc Btrfs: Fix checkp... |
2492 |
btrfs_item_offset_nr(right, push_items - 1); |
5f39d397d Btrfs: Create ext... |
2493 2494 |
copy_extent_buffer(left, right, btrfs_leaf_data(left) + |
d60255795 Btrfs: corruption... |
2495 2496 |
leaf_data_end(root, left) - push_space, btrfs_leaf_data(right) + |
5f39d397d Btrfs: Create ext... |
2497 |
btrfs_item_offset_nr(right, push_items - 1), |
d60255795 Btrfs: corruption... |
2498 |
push_space); |
5f39d397d Btrfs: Create ext... |
2499 |
old_left_nritems = btrfs_header_nritems(left); |
87b29b208 Btrfs: properly c... |
2500 |
BUG_ON(old_left_nritems <= 0); |
eb60ceac0 Btrfs: Add backin... |
2501 |
|
db94535db Btrfs: Allow tree... |
2502 |
old_left_item_size = btrfs_item_offset_nr(left, old_left_nritems - 1); |
0783fcfc4 Btrfs: struct ite... |
2503 |
for (i = old_left_nritems; i < old_left_nritems + push_items; i++) { |
5f39d397d Btrfs: Create ext... |
2504 |
u32 ioff; |
db94535db Btrfs: Allow tree... |
2505 |
|
5f39d397d Btrfs: Create ext... |
2506 |
item = btrfs_item_nr(left, i); |
db94535db Btrfs: Allow tree... |
2507 |
|
5f39d397d Btrfs: Create ext... |
2508 2509 |
ioff = btrfs_item_offset(left, item); btrfs_set_item_offset(left, item, |
db94535db Btrfs: Allow tree... |
2510 |
ioff - (BTRFS_LEAF_DATA_SIZE(root) - old_left_item_size)); |
be0e5c097 Btrfs: Initial ch... |
2511 |
} |
5f39d397d Btrfs: Create ext... |
2512 |
btrfs_set_header_nritems(left, old_left_nritems + push_items); |
be0e5c097 Btrfs: Initial ch... |
2513 2514 |
/* fixup right node */ |
34a382187 Btrfs: Change pus... |
2515 |
if (push_items > right_nritems) { |
d397712bc Btrfs: Fix checkp... |
2516 2517 2518 |
printk(KERN_CRIT "push items %d nr %u ", push_items, right_nritems); |
34a382187 Btrfs: Change pus... |
2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 |
WARN_ON(1); } if (push_items < right_nritems) { push_space = btrfs_item_offset_nr(right, push_items - 1) - leaf_data_end(root, right); memmove_extent_buffer(right, btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) - push_space, btrfs_leaf_data(right) + leaf_data_end(root, right), push_space); memmove_extent_buffer(right, btrfs_item_nr_offset(0), |
5f39d397d Btrfs: Create ext... |
2531 2532 2533 |
btrfs_item_nr_offset(push_items), (btrfs_header_nritems(right) - push_items) * sizeof(struct btrfs_item)); |
34a382187 Btrfs: Change pus... |
2534 |
} |
eef1c494a Btrfs: Properly u... |
2535 2536 |
right_nritems -= push_items; btrfs_set_header_nritems(right, right_nritems); |
123abc88c Btrfs: variable b... |
2537 |
push_space = BTRFS_LEAF_DATA_SIZE(root); |
5f39d397d Btrfs: Create ext... |
2538 2539 |
for (i = 0; i < right_nritems; i++) { item = btrfs_item_nr(right, i); |
db94535db Btrfs: Allow tree... |
2540 |
|
db94535db Btrfs: Allow tree... |
2541 2542 2543 |
push_space = push_space - btrfs_item_size(right, item); btrfs_set_item_offset(right, item, push_space); } |
eb60ceac0 Btrfs: Add backin... |
2544 |
|
5f39d397d Btrfs: Create ext... |
2545 |
btrfs_mark_buffer_dirty(left); |
34a382187 Btrfs: Change pus... |
2546 2547 |
if (right_nritems) btrfs_mark_buffer_dirty(right); |
f0486c68e Btrfs: Introduce ... |
2548 2549 |
else clean_tree_block(trans, root, right); |
098f59c25 Btrfs: patch queu... |
2550 |
|
5f39d397d Btrfs: Create ext... |
2551 2552 |
btrfs_item_key(right, &disk_key, 0); wret = fixup_low_keys(trans, root, path, &disk_key, 1); |
aa5d6bed2 Btrfs: return cod... |
2553 2554 |
if (wret) ret = wret; |
be0e5c097 Btrfs: Initial ch... |
2555 2556 2557 2558 |
/* then fixup the leaf pointer in the path */ if (path->slots[0] < push_items) { path->slots[0] += old_left_nritems; |
925baeddc Btrfs: Start btre... |
2559 |
btrfs_tree_unlock(path->nodes[0]); |
5f39d397d Btrfs: Create ext... |
2560 2561 |
free_extent_buffer(path->nodes[0]); path->nodes[0] = left; |
be0e5c097 Btrfs: Initial ch... |
2562 2563 |
path->slots[1] -= 1; } else { |
925baeddc Btrfs: Start btre... |
2564 |
btrfs_tree_unlock(left); |
5f39d397d Btrfs: Create ext... |
2565 |
free_extent_buffer(left); |
be0e5c097 Btrfs: Initial ch... |
2566 2567 |
path->slots[0] -= push_items; } |
eb60ceac0 Btrfs: Add backin... |
2568 |
BUG_ON(path->slots[0] < 0); |
aa5d6bed2 Btrfs: return cod... |
2569 |
return ret; |
925baeddc Btrfs: Start btre... |
2570 2571 2572 2573 |
out: btrfs_tree_unlock(left); free_extent_buffer(left); return ret; |
be0e5c097 Btrfs: Initial ch... |
2574 |
} |
74123bd72 Btrfs: Commenting... |
2575 |
/* |
44871b1b2 Btrfs: reduce sta... |
2576 2577 |
* push some data in the path leaf to the left, trying to free up at * least data_size bytes. returns zero if the push worked, nonzero otherwise |
99d8f83c9 Btrfs: fix split_... |
2578 2579 2580 2581 |
* * max_slot can put a limit on how far into the leaf we'll push items. The * item at 'max_slot' won't be touched. Use (u32)-1 to make us push all the * items |
44871b1b2 Btrfs: reduce sta... |
2582 2583 |
*/ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root |
99d8f83c9 Btrfs: fix split_... |
2584 2585 |
*root, struct btrfs_path *path, int min_data_size, int data_size, int empty, u32 max_slot) |
44871b1b2 Btrfs: reduce sta... |
2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 |
{ struct extent_buffer *right = path->nodes[0]; struct extent_buffer *left; int slot; int free_space; u32 right_nritems; int ret = 0; slot = path->slots[1]; if (slot == 0) return 1; if (!path->nodes[1]) return 1; right_nritems = btrfs_header_nritems(right); if (right_nritems == 0) return 1; btrfs_assert_tree_locked(path->nodes[1]); left = read_node_slot(root, path->nodes[1], slot - 1); |
91ca338d7 btrfs: check NULL... |
2607 2608 |
if (left == NULL) return 1; |
44871b1b2 Btrfs: reduce sta... |
2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 |
btrfs_tree_lock(left); btrfs_set_lock_blocking(left); free_space = btrfs_leaf_free_space(root, left); if (free_space < data_size) { ret = 1; goto out; } /* cow and double check */ ret = btrfs_cow_block(trans, root, left, path->nodes[1], slot - 1, &left); if (ret) { /* we hit -ENOSPC, but it isn't fatal here */ ret = 1; goto out; } free_space = btrfs_leaf_free_space(root, left); if (free_space < data_size) { ret = 1; goto out; } |
99d8f83c9 Btrfs: fix split_... |
2632 2633 2634 |
return __push_leaf_left(trans, root, path, min_data_size, empty, left, free_space, right_nritems, max_slot); |
44871b1b2 Btrfs: reduce sta... |
2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 |
out: btrfs_tree_unlock(left); free_extent_buffer(left); return ret; } /* * split the path's leaf in two, making sure there is at least data_size * available for the resulting leaf level of the path. * * returns 0 if all went well and < 0 on failure. */ static noinline int copy_for_split(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct extent_buffer *l, struct extent_buffer *right, int slot, int mid, int nritems) { int data_copy_size; int rt_data_off; int i; int ret = 0; int wret; struct btrfs_disk_key disk_key; nritems = nritems - mid; btrfs_set_header_nritems(right, nritems); data_copy_size = btrfs_item_end_nr(l, mid) - leaf_data_end(root, l); copy_extent_buffer(right, l, btrfs_item_nr_offset(0), btrfs_item_nr_offset(mid), nritems * sizeof(struct btrfs_item)); copy_extent_buffer(right, l, btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) - data_copy_size, btrfs_leaf_data(l) + leaf_data_end(root, l), data_copy_size); rt_data_off = BTRFS_LEAF_DATA_SIZE(root) - btrfs_item_end_nr(l, mid); for (i = 0; i < nritems; i++) { struct btrfs_item *item = btrfs_item_nr(right, i); u32 ioff; |
44871b1b2 Btrfs: reduce sta... |
2680 2681 2682 |
ioff = btrfs_item_offset(right, item); btrfs_set_item_offset(right, item, ioff + rt_data_off); } |
44871b1b2 Btrfs: reduce sta... |
2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 |
btrfs_set_header_nritems(l, mid); ret = 0; btrfs_item_key(right, &disk_key, 0); wret = insert_ptr(trans, root, path, &disk_key, right->start, path->slots[1] + 1, 1); if (wret) ret = wret; btrfs_mark_buffer_dirty(right); btrfs_mark_buffer_dirty(l); BUG_ON(path->slots[0] != slot); |
44871b1b2 Btrfs: reduce sta... |
2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 |
if (mid <= slot) { btrfs_tree_unlock(path->nodes[0]); free_extent_buffer(path->nodes[0]); path->nodes[0] = right; path->slots[0] -= mid; path->slots[1] += 1; } else { btrfs_tree_unlock(right); free_extent_buffer(right); } BUG_ON(path->slots[0] < 0); return ret; } /* |
99d8f83c9 Btrfs: fix split_... |
2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 |
* double splits happen when we need to insert a big item in the middle * of a leaf. A double split can leave us with 3 mostly empty leaves: * leaf: [ slots 0 - N] [ our target ] [ N + 1 - total in leaf ] * A B C * * We avoid this by trying to push the items on either side of our target * into the adjacent leaves. If all goes well we can avoid the double split * completely. */ static noinline int push_for_double_split(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int data_size) { int ret; int progress = 0; int slot; u32 nritems; slot = path->slots[0]; /* * try to push all the items after our slot into the * right leaf */ ret = push_leaf_right(trans, root, path, 1, data_size, 0, slot); if (ret < 0) return ret; if (ret == 0) progress++; nritems = btrfs_header_nritems(path->nodes[0]); /* * our goal is to get our slot at the start or end of a leaf. If * we've done so we're done */ if (path->slots[0] == 0 || path->slots[0] == nritems) return 0; if (btrfs_leaf_free_space(root, path->nodes[0]) >= data_size) return 0; /* try to push all the items before our slot into the next leaf */ slot = path->slots[0]; ret = push_leaf_left(trans, root, path, 1, data_size, 0, slot); if (ret < 0) return ret; if (ret == 0) progress++; if (progress) return 0; return 1; } /* |
74123bd72 Btrfs: Commenting... |
2769 2770 |
* split the path's leaf in two, making sure there is at least data_size * available for the resulting leaf level of the path. |
aa5d6bed2 Btrfs: return cod... |
2771 2772 |
* * returns 0 if all went well and < 0 on failure. |
74123bd72 Btrfs: Commenting... |
2773 |
*/ |
e02119d5a Btrfs: Add a writ... |
2774 2775 2776 2777 2778 |
static noinline int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *ins_key, struct btrfs_path *path, int data_size, int extend) |
be0e5c097 Btrfs: Initial ch... |
2779 |
{ |
5d4f98a28 Btrfs: Mixed back... |
2780 |
struct btrfs_disk_key disk_key; |
5f39d397d Btrfs: Create ext... |
2781 |
struct extent_buffer *l; |
7518a238e Btrfs: get/set fo... |
2782 |
u32 nritems; |
eb60ceac0 Btrfs: Add backin... |
2783 2784 |
int mid; int slot; |
5f39d397d Btrfs: Create ext... |
2785 |
struct extent_buffer *right; |
d4dbff953 Btrfs: support fo... |
2786 |
int ret = 0; |
aa5d6bed2 Btrfs: return cod... |
2787 |
int wret; |
5d4f98a28 Btrfs: Mixed back... |
2788 |
int split; |
cc0c55384 Btrfs: Fix split_... |
2789 |
int num_doubles = 0; |
99d8f83c9 Btrfs: fix split_... |
2790 |
int tried_avoid_double = 0; |
aa5d6bed2 Btrfs: return cod... |
2791 |
|
a57195214 Btrfs: check size... |
2792 2793 2794 2795 2796 |
l = path->nodes[0]; slot = path->slots[0]; if (extend && data_size + btrfs_item_size_nr(l, slot) + sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root)) return -EOVERFLOW; |
406894788 Btrfs: minor comm... |
2797 |
/* first try to make some room by pushing left and right */ |
99d8f83c9 Btrfs: fix split_... |
2798 2799 2800 |
if (data_size) { wret = push_leaf_right(trans, root, path, data_size, data_size, 0, 0); |
d397712bc Btrfs: Fix checkp... |
2801 |
if (wret < 0) |
eaee50e88 Btrfs: merge leav... |
2802 |
return wret; |
3685f7916 Btrfs: CPU usage ... |
2803 |
if (wret) { |
99d8f83c9 Btrfs: fix split_... |
2804 2805 |
wret = push_leaf_left(trans, root, path, data_size, data_size, 0, (u32)-1); |
3685f7916 Btrfs: CPU usage ... |
2806 2807 2808 2809 |
if (wret < 0) return wret; } l = path->nodes[0]; |
aa5d6bed2 Btrfs: return cod... |
2810 |
|
3685f7916 Btrfs: CPU usage ... |
2811 |
/* did the pushes work? */ |
87b29b208 Btrfs: properly c... |
2812 |
if (btrfs_leaf_free_space(root, l) >= data_size) |
3685f7916 Btrfs: CPU usage ... |
2813 |
return 0; |
3326d1b07 Btrfs: Allow tail... |
2814 |
} |
aa5d6bed2 Btrfs: return cod... |
2815 |
|
5c680ed62 Btrfs: switch to ... |
2816 |
if (!path->nodes[1]) { |
e089f05c1 Btrfs: transactio... |
2817 |
ret = insert_new_root(trans, root, path, 1); |
5c680ed62 Btrfs: switch to ... |
2818 2819 2820 |
if (ret) return ret; } |
cc0c55384 Btrfs: Fix split_... |
2821 |
again: |
5d4f98a28 Btrfs: Mixed back... |
2822 |
split = 1; |
cc0c55384 Btrfs: Fix split_... |
2823 |
l = path->nodes[0]; |
eb60ceac0 Btrfs: Add backin... |
2824 |
slot = path->slots[0]; |
5f39d397d Btrfs: Create ext... |
2825 |
nritems = btrfs_header_nritems(l); |
d397712bc Btrfs: Fix checkp... |
2826 |
mid = (nritems + 1) / 2; |
54aa1f4df Btrfs: Audit call... |
2827 |
|
5d4f98a28 Btrfs: Mixed back... |
2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 |
if (mid <= slot) { if (nritems == 1 || leaf_space_used(l, mid, nritems - mid) + data_size > BTRFS_LEAF_DATA_SIZE(root)) { if (slot >= nritems) { split = 0; } else { mid = slot; if (mid != nritems && leaf_space_used(l, mid, nritems - mid) + data_size > BTRFS_LEAF_DATA_SIZE(root)) { |
99d8f83c9 Btrfs: fix split_... |
2839 2840 |
if (data_size && !tried_avoid_double) goto push_for_double; |
5d4f98a28 Btrfs: Mixed back... |
2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 |
split = 2; } } } } else { if (leaf_space_used(l, 0, mid) + data_size > BTRFS_LEAF_DATA_SIZE(root)) { if (!extend && data_size && slot == 0) { split = 0; } else if ((extend || !data_size) && slot == 0) { mid = 1; } else { mid = slot; if (mid != nritems && leaf_space_used(l, mid, nritems - mid) + data_size > BTRFS_LEAF_DATA_SIZE(root)) { |
99d8f83c9 Btrfs: fix split_... |
2857 2858 |
if (data_size && !tried_avoid_double) goto push_for_double; |
5d4f98a28 Btrfs: Mixed back... |
2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 |
split = 2 ; } } } } if (split == 0) btrfs_cpu_key_to_disk(&disk_key, ins_key); else btrfs_item_key(l, &disk_key, mid); right = btrfs_alloc_free_block(trans, root, root->leafsize, 0, |
31840ae1a Btrfs: Full back ... |
2871 |
root->root_key.objectid, |
5d4f98a28 Btrfs: Mixed back... |
2872 |
&disk_key, 0, l->start, 0); |
f0486c68e Btrfs: Introduce ... |
2873 |
if (IS_ERR(right)) |
5f39d397d Btrfs: Create ext... |
2874 |
return PTR_ERR(right); |
f0486c68e Btrfs: Introduce ... |
2875 2876 |
root_add_used(root, root->leafsize); |
5f39d397d Btrfs: Create ext... |
2877 2878 |
memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header)); |
db94535db Btrfs: Allow tree... |
2879 |
btrfs_set_header_bytenr(right, right->start); |
5f39d397d Btrfs: Create ext... |
2880 |
btrfs_set_header_generation(right, trans->transid); |
5d4f98a28 Btrfs: Mixed back... |
2881 |
btrfs_set_header_backref_rev(right, BTRFS_MIXED_BACKREF_REV); |
5f39d397d Btrfs: Create ext... |
2882 2883 2884 2885 2886 |
btrfs_set_header_owner(right, root->root_key.objectid); btrfs_set_header_level(right, 0); write_extent_buffer(right, root->fs_info->fsid, (unsigned long)btrfs_header_fsid(right), BTRFS_FSID_SIZE); |
e17cade25 Btrfs: Add chunk ... |
2887 2888 2889 2890 |
write_extent_buffer(right, root->fs_info->chunk_tree_uuid, (unsigned long)btrfs_header_chunk_tree_uuid(right), BTRFS_UUID_SIZE); |
44871b1b2 Btrfs: reduce sta... |
2891 |
|
5d4f98a28 Btrfs: Mixed back... |
2892 2893 2894 2895 2896 2897 2898 2899 |
if (split == 0) { if (mid <= slot) { btrfs_set_header_nritems(right, 0); wret = insert_ptr(trans, root, path, &disk_key, right->start, path->slots[1] + 1, 1); if (wret) ret = wret; |
925baeddc Btrfs: Start btre... |
2900 |
|
5d4f98a28 Btrfs: Mixed back... |
2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 |
btrfs_tree_unlock(path->nodes[0]); free_extent_buffer(path->nodes[0]); path->nodes[0] = right; path->slots[0] = 0; path->slots[1] += 1; } else { btrfs_set_header_nritems(right, 0); wret = insert_ptr(trans, root, path, &disk_key, right->start, path->slots[1], 1); if (wret) ret = wret; btrfs_tree_unlock(path->nodes[0]); free_extent_buffer(path->nodes[0]); path->nodes[0] = right; path->slots[0] = 0; if (path->slots[1] == 0) { wret = fixup_low_keys(trans, root, path, &disk_key, 1); |
d4dbff953 Btrfs: support fo... |
2921 2922 |
if (wret) ret = wret; |
5ee78ac70 Btrfs: Fix split_... |
2923 |
} |
d4dbff953 Btrfs: support fo... |
2924 |
} |
5d4f98a28 Btrfs: Mixed back... |
2925 2926 |
btrfs_mark_buffer_dirty(right); return ret; |
d4dbff953 Btrfs: support fo... |
2927 |
} |
74123bd72 Btrfs: Commenting... |
2928 |
|
44871b1b2 Btrfs: reduce sta... |
2929 |
ret = copy_for_split(trans, root, path, l, right, slot, mid, nritems); |
31840ae1a Btrfs: Full back ... |
2930 |
BUG_ON(ret); |
5d4f98a28 Btrfs: Mixed back... |
2931 |
if (split == 2) { |
cc0c55384 Btrfs: Fix split_... |
2932 2933 2934 |
BUG_ON(num_doubles != 0); num_doubles++; goto again; |
a429e5137 Btrfs: working fi... |
2935 |
} |
44871b1b2 Btrfs: reduce sta... |
2936 |
|
be0e5c097 Btrfs: Initial ch... |
2937 |
return ret; |
99d8f83c9 Btrfs: fix split_... |
2938 2939 2940 2941 2942 2943 2944 |
push_for_double: push_for_double_split(trans, root, path, data_size); tried_avoid_double = 1; if (btrfs_leaf_free_space(root, path->nodes[0]) >= data_size) return 0; goto again; |
be0e5c097 Btrfs: Initial ch... |
2945 |
} |
ad48fd754 Btrfs: Add btrfs_... |
2946 2947 2948 |
static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int ins_len) |
459931eca Btrfs: Delete csu... |
2949 |
{ |
ad48fd754 Btrfs: Add btrfs_... |
2950 |
struct btrfs_key key; |
459931eca Btrfs: Delete csu... |
2951 |
struct extent_buffer *leaf; |
ad48fd754 Btrfs: Add btrfs_... |
2952 2953 2954 2955 |
struct btrfs_file_extent_item *fi; u64 extent_len = 0; u32 item_size; int ret; |
459931eca Btrfs: Delete csu... |
2956 2957 |
leaf = path->nodes[0]; |
ad48fd754 Btrfs: Add btrfs_... |
2958 2959 2960 2961 2962 2963 2964 |
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); BUG_ON(key.type != BTRFS_EXTENT_DATA_KEY && key.type != BTRFS_EXTENT_CSUM_KEY); if (btrfs_leaf_free_space(root, leaf) >= ins_len) return 0; |
459931eca Btrfs: Delete csu... |
2965 2966 |
item_size = btrfs_item_size_nr(leaf, path->slots[0]); |
ad48fd754 Btrfs: Add btrfs_... |
2967 2968 2969 2970 2971 |
if (key.type == BTRFS_EXTENT_DATA_KEY) { fi = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); extent_len = btrfs_file_extent_num_bytes(leaf, fi); } |
b3b4aa74b btrfs: drop unuse... |
2972 |
btrfs_release_path(path); |
459931eca Btrfs: Delete csu... |
2973 |
|
459931eca Btrfs: Delete csu... |
2974 |
path->keep_locks = 1; |
ad48fd754 Btrfs: Add btrfs_... |
2975 2976 |
path->search_for_split = 1; ret = btrfs_search_slot(trans, root, &key, path, 0, 1); |
459931eca Btrfs: Delete csu... |
2977 |
path->search_for_split = 0; |
ad48fd754 Btrfs: Add btrfs_... |
2978 2979 |
if (ret < 0) goto err; |
459931eca Btrfs: Delete csu... |
2980 |
|
ad48fd754 Btrfs: Add btrfs_... |
2981 2982 |
ret = -EAGAIN; leaf = path->nodes[0]; |
459931eca Btrfs: Delete csu... |
2983 |
/* if our item isn't there or got smaller, return now */ |
ad48fd754 Btrfs: Add btrfs_... |
2984 2985 |
if (ret > 0 || item_size != btrfs_item_size_nr(leaf, path->slots[0])) goto err; |
109f6aef5 Btrfs: add check ... |
2986 2987 2988 |
/* the leaf has changed, it now has room. return now */ if (btrfs_leaf_free_space(root, path->nodes[0]) >= ins_len) goto err; |
ad48fd754 Btrfs: Add btrfs_... |
2989 2990 2991 2992 2993 |
if (key.type == BTRFS_EXTENT_DATA_KEY) { fi = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); if (extent_len != btrfs_file_extent_num_bytes(leaf, fi)) goto err; |
459931eca Btrfs: Delete csu... |
2994 |
} |
b9473439d Btrfs: leave btre... |
2995 |
btrfs_set_path_blocking(path); |
ad48fd754 Btrfs: Add btrfs_... |
2996 |
ret = split_leaf(trans, root, &key, path, ins_len, 1); |
f0486c68e Btrfs: Introduce ... |
2997 2998 |
if (ret) goto err; |
459931eca Btrfs: Delete csu... |
2999 |
|
ad48fd754 Btrfs: Add btrfs_... |
3000 |
path->keep_locks = 0; |
b9473439d Btrfs: leave btre... |
3001 |
btrfs_unlock_up_safe(path, 1); |
ad48fd754 Btrfs: Add btrfs_... |
3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 |
return 0; err: path->keep_locks = 0; return ret; } static noinline int split_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *new_key, unsigned long split_offset) { struct extent_buffer *leaf; struct btrfs_item *item; struct btrfs_item *new_item; int slot; char *buf; u32 nritems; u32 item_size; u32 orig_offset; struct btrfs_disk_key disk_key; |
b9473439d Btrfs: leave btre... |
3023 3024 |
leaf = path->nodes[0]; BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item)); |
b4ce94de9 Btrfs: Change btr... |
3025 |
btrfs_set_path_blocking(path); |
459931eca Btrfs: Delete csu... |
3026 3027 3028 |
item = btrfs_item_nr(leaf, path->slots[0]); orig_offset = btrfs_item_offset(leaf, item); item_size = btrfs_item_size(leaf, item); |
459931eca Btrfs: Delete csu... |
3029 |
buf = kmalloc(item_size, GFP_NOFS); |
ad48fd754 Btrfs: Add btrfs_... |
3030 3031 |
if (!buf) return -ENOMEM; |
459931eca Btrfs: Delete csu... |
3032 3033 |
read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, path->slots[0]), item_size); |
459931eca Btrfs: Delete csu... |
3034 |
|
ad48fd754 Btrfs: Add btrfs_... |
3035 |
slot = path->slots[0] + 1; |
459931eca Btrfs: Delete csu... |
3036 |
nritems = btrfs_header_nritems(leaf); |
459931eca Btrfs: Delete csu... |
3037 3038 3039 |
if (slot != nritems) { /* shift the items */ memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + 1), |
ad48fd754 Btrfs: Add btrfs_... |
3040 3041 |
btrfs_item_nr_offset(slot), (nritems - slot) * sizeof(struct btrfs_item)); |
459931eca Btrfs: Delete csu... |
3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 |
} btrfs_cpu_key_to_disk(&disk_key, new_key); btrfs_set_item_key(leaf, &disk_key, slot); new_item = btrfs_item_nr(leaf, slot); btrfs_set_item_offset(leaf, new_item, orig_offset); btrfs_set_item_size(leaf, new_item, item_size - split_offset); btrfs_set_item_offset(leaf, item, orig_offset + item_size - split_offset); btrfs_set_item_size(leaf, item, split_offset); btrfs_set_header_nritems(leaf, nritems + 1); /* write the data for the start of the original item */ write_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, path->slots[0]), split_offset); /* write the data for the new item */ write_extent_buffer(leaf, buf + split_offset, btrfs_item_ptr_offset(leaf, slot), item_size - split_offset); btrfs_mark_buffer_dirty(leaf); |
ad48fd754 Btrfs: Add btrfs_... |
3068 |
BUG_ON(btrfs_leaf_free_space(root, leaf) < 0); |
459931eca Btrfs: Delete csu... |
3069 |
kfree(buf); |
ad48fd754 Btrfs: Add btrfs_... |
3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 |
return 0; } /* * This function splits a single item into two items, * giving 'new_key' to the new item and splitting the * old one at split_offset (from the start of the item). * * The path may be released by this operation. After * the split, the path is pointing to the old item. The * new item is going to be in the same node as the old one. * * Note, the item being split must be smaller enough to live alone on * a tree block with room for one extra struct btrfs_item * * This allows us to split the item in place, keeping a lock on the * leaf the entire time. */ int btrfs_split_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *new_key, unsigned long split_offset) { int ret; ret = setup_leaf_for_split(trans, root, path, sizeof(struct btrfs_item)); if (ret) return ret; ret = split_item(trans, root, path, new_key, split_offset); |
459931eca Btrfs: Delete csu... |
3101 3102 3103 3104 |
return ret; } /* |
ad48fd754 Btrfs: Add btrfs_... |
3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 |
* This function duplicate a item, giving 'new_key' to the new item. * It guarantees both items live in the same tree leaf and the new item * is contiguous with the original item. * * This allows us to split file extent in place, keeping a lock on the * leaf the entire time. */ int btrfs_duplicate_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *new_key) { struct extent_buffer *leaf; int ret; u32 item_size; leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); ret = setup_leaf_for_split(trans, root, path, item_size + sizeof(struct btrfs_item)); if (ret) return ret; path->slots[0]++; ret = setup_items_for_insert(trans, root, path, new_key, &item_size, item_size, item_size + sizeof(struct btrfs_item), 1); BUG_ON(ret); leaf = path->nodes[0]; memcpy_extent_buffer(leaf, btrfs_item_ptr_offset(leaf, path->slots[0]), btrfs_item_ptr_offset(leaf, path->slots[0] - 1), item_size); return 0; } /* |
d352ac681 Btrfs: add and im... |
3143 3144 3145 3146 3147 |
* make the item pointed to by the path smaller. new_size indicates * how small to make it, and from_end tells us if we just chop bytes * off the end of the item or if we shift the item to chop bytes off * the front. */ |
b18c66858 Btrfs: progress o... |
3148 3149 3150 |
int btrfs_truncate_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, |
179e29e48 Btrfs: Fix a numb... |
3151 |
u32 new_size, int from_end) |
b18c66858 Btrfs: progress o... |
3152 |
{ |
b18c66858 Btrfs: progress o... |
3153 |
int slot; |
5f39d397d Btrfs: Create ext... |
3154 3155 |
struct extent_buffer *leaf; struct btrfs_item *item; |
b18c66858 Btrfs: progress o... |
3156 3157 3158 3159 3160 3161 |
u32 nritems; unsigned int data_end; unsigned int old_data_start; unsigned int old_size; unsigned int size_diff; int i; |
5f39d397d Btrfs: Create ext... |
3162 |
leaf = path->nodes[0]; |
179e29e48 Btrfs: Fix a numb... |
3163 3164 3165 3166 3167 |
slot = path->slots[0]; old_size = btrfs_item_size_nr(leaf, slot); if (old_size == new_size) return 0; |
b18c66858 Btrfs: progress o... |
3168 |
|
5f39d397d Btrfs: Create ext... |
3169 |
nritems = btrfs_header_nritems(leaf); |
b18c66858 Btrfs: progress o... |
3170 |
data_end = leaf_data_end(root, leaf); |
5f39d397d Btrfs: Create ext... |
3171 |
old_data_start = btrfs_item_offset_nr(leaf, slot); |
179e29e48 Btrfs: Fix a numb... |
3172 |
|
b18c66858 Btrfs: progress o... |
3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 |
size_diff = old_size - new_size; BUG_ON(slot < 0); BUG_ON(slot >= nritems); /* * item0..itemN ... dataN.offset..dataN.size .. data0.size */ /* first correct the data pointers */ for (i = slot; i < nritems; i++) { |
5f39d397d Btrfs: Create ext... |
3183 3184 |
u32 ioff; item = btrfs_item_nr(leaf, i); |
db94535db Btrfs: Allow tree... |
3185 |
|
5f39d397d Btrfs: Create ext... |
3186 3187 |
ioff = btrfs_item_offset(leaf, item); btrfs_set_item_offset(leaf, item, ioff + size_diff); |
b18c66858 Btrfs: progress o... |
3188 |
} |
db94535db Btrfs: Allow tree... |
3189 |
|
b18c66858 Btrfs: progress o... |
3190 |
/* shift the data */ |
179e29e48 Btrfs: Fix a numb... |
3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 |
if (from_end) { memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + data_end + size_diff, btrfs_leaf_data(leaf) + data_end, old_data_start + new_size - data_end); } else { struct btrfs_disk_key disk_key; u64 offset; btrfs_item_key(leaf, &disk_key, slot); if (btrfs_disk_key_type(&disk_key) == BTRFS_EXTENT_DATA_KEY) { unsigned long ptr; struct btrfs_file_extent_item *fi; fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); fi = (struct btrfs_file_extent_item *)( (unsigned long)fi - size_diff); if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) { ptr = btrfs_item_ptr_offset(leaf, slot); memmove_extent_buffer(leaf, ptr, |
d397712bc Btrfs: Fix checkp... |
3214 3215 |
(unsigned long)fi, offsetof(struct btrfs_file_extent_item, |
179e29e48 Btrfs: Fix a numb... |
3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 |
disk_bytenr)); } } memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + data_end + size_diff, btrfs_leaf_data(leaf) + data_end, old_data_start - data_end); offset = btrfs_disk_key_offset(&disk_key); btrfs_set_disk_key_offset(&disk_key, offset + size_diff); btrfs_set_item_key(leaf, &disk_key, slot); if (slot == 0) fixup_low_keys(trans, root, path, &disk_key, 1); } |
5f39d397d Btrfs: Create ext... |
3230 3231 3232 3233 |
item = btrfs_item_nr(leaf, slot); btrfs_set_item_size(leaf, item, new_size); btrfs_mark_buffer_dirty(leaf); |
b18c66858 Btrfs: progress o... |
3234 |
|
5f39d397d Btrfs: Create ext... |
3235 3236 |
if (btrfs_leaf_free_space(root, leaf) < 0) { btrfs_print_leaf(root, leaf); |
b18c66858 Btrfs: progress o... |
3237 |
BUG(); |
5f39d397d Btrfs: Create ext... |
3238 |
} |
1cd307990 Btrfs: BUG_ON is ... |
3239 |
return 0; |
b18c66858 Btrfs: progress o... |
3240 |
} |
d352ac681 Btrfs: add and im... |
3241 3242 3243 |
/* * make the item pointed to by the path bigger, data_size is the new size. */ |
5f39d397d Btrfs: Create ext... |
3244 3245 3246 |
int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u32 data_size) |
6567e837d Btrfs: early work... |
3247 |
{ |
6567e837d Btrfs: early work... |
3248 |
int slot; |
5f39d397d Btrfs: Create ext... |
3249 3250 |
struct extent_buffer *leaf; struct btrfs_item *item; |
6567e837d Btrfs: early work... |
3251 3252 3253 3254 3255 |
u32 nritems; unsigned int data_end; unsigned int old_data; unsigned int old_size; int i; |
5f39d397d Btrfs: Create ext... |
3256 |
leaf = path->nodes[0]; |
6567e837d Btrfs: early work... |
3257 |
|
5f39d397d Btrfs: Create ext... |
3258 |
nritems = btrfs_header_nritems(leaf); |
6567e837d Btrfs: early work... |
3259 |
data_end = leaf_data_end(root, leaf); |
5f39d397d Btrfs: Create ext... |
3260 3261 |
if (btrfs_leaf_free_space(root, leaf) < data_size) { btrfs_print_leaf(root, leaf); |
6567e837d Btrfs: early work... |
3262 |
BUG(); |
5f39d397d Btrfs: Create ext... |
3263 |
} |
6567e837d Btrfs: early work... |
3264 |
slot = path->slots[0]; |
5f39d397d Btrfs: Create ext... |
3265 |
old_data = btrfs_item_end_nr(leaf, slot); |
6567e837d Btrfs: early work... |
3266 3267 |
BUG_ON(slot < 0); |
3326d1b07 Btrfs: Allow tail... |
3268 3269 |
if (slot >= nritems) { btrfs_print_leaf(root, leaf); |
d397712bc Btrfs: Fix checkp... |
3270 3271 3272 |
printk(KERN_CRIT "slot %d too large, nritems %d ", slot, nritems); |
3326d1b07 Btrfs: Allow tail... |
3273 3274 |
BUG_ON(1); } |
6567e837d Btrfs: early work... |
3275 3276 3277 3278 3279 3280 |
/* * item0..itemN ... dataN.offset..dataN.size .. data0.size */ /* first correct the data pointers */ for (i = slot; i < nritems; i++) { |
5f39d397d Btrfs: Create ext... |
3281 3282 |
u32 ioff; item = btrfs_item_nr(leaf, i); |
db94535db Btrfs: Allow tree... |
3283 |
|
5f39d397d Btrfs: Create ext... |
3284 3285 |
ioff = btrfs_item_offset(leaf, item); btrfs_set_item_offset(leaf, item, ioff - data_size); |
6567e837d Btrfs: early work... |
3286 |
} |
5f39d397d Btrfs: Create ext... |
3287 |
|
6567e837d Btrfs: early work... |
3288 |
/* shift the data */ |
5f39d397d Btrfs: Create ext... |
3289 |
memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + |
6567e837d Btrfs: early work... |
3290 3291 |
data_end - data_size, btrfs_leaf_data(leaf) + data_end, old_data - data_end); |
5f39d397d Btrfs: Create ext... |
3292 |
|
6567e837d Btrfs: early work... |
3293 |
data_end = old_data; |
5f39d397d Btrfs: Create ext... |
3294 3295 3296 3297 |
old_size = btrfs_item_size_nr(leaf, slot); item = btrfs_item_nr(leaf, slot); btrfs_set_item_size(leaf, item, old_size + data_size); btrfs_mark_buffer_dirty(leaf); |
6567e837d Btrfs: early work... |
3298 |
|
5f39d397d Btrfs: Create ext... |
3299 3300 |
if (btrfs_leaf_free_space(root, leaf) < 0) { btrfs_print_leaf(root, leaf); |
6567e837d Btrfs: early work... |
3301 |
BUG(); |
5f39d397d Btrfs: Create ext... |
3302 |
} |
1cd307990 Btrfs: BUG_ON is ... |
3303 |
return 0; |
6567e837d Btrfs: early work... |
3304 |
} |
74123bd72 Btrfs: Commenting... |
3305 |
/* |
d352ac681 Btrfs: add and im... |
3306 |
* Given a key and some data, insert items into the tree. |
74123bd72 Btrfs: Commenting... |
3307 |
* This does all the path init required, making room in the tree if needed. |
f3465ca44 Btrfs: batch exte... |
3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 |
* Returns the number of keys that were inserted. */ int btrfs_insert_some_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *cpu_key, u32 *data_size, int nr) { struct extent_buffer *leaf; struct btrfs_item *item; int ret = 0; int slot; |
f3465ca44 Btrfs: batch exte... |
3320 3321 3322 3323 3324 3325 3326 |
int i; u32 nritems; u32 total_data = 0; u32 total_size = 0; unsigned int data_end; struct btrfs_disk_key disk_key; struct btrfs_key found_key; |
87b29b208 Btrfs: properly c... |
3327 3328 3329 3330 3331 3332 |
for (i = 0; i < nr; i++) { if (total_size + data_size[i] + sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root)) { break; nr = i; } |
f3465ca44 Btrfs: batch exte... |
3333 |
total_data += data_size[i]; |
87b29b208 Btrfs: properly c... |
3334 3335 3336 |
total_size += data_size[i] + sizeof(struct btrfs_item); } BUG_ON(nr == 0); |
f3465ca44 Btrfs: batch exte... |
3337 |
|
f3465ca44 Btrfs: batch exte... |
3338 3339 3340 3341 3342 |
ret = btrfs_search_slot(trans, root, cpu_key, path, total_size, 1); if (ret == 0) return -EEXIST; if (ret < 0) goto out; |
f3465ca44 Btrfs: batch exte... |
3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 |
leaf = path->nodes[0]; nritems = btrfs_header_nritems(leaf); data_end = leaf_data_end(root, leaf); if (btrfs_leaf_free_space(root, leaf) < total_size) { for (i = nr; i >= 0; i--) { total_data -= data_size[i]; total_size -= data_size[i] + sizeof(struct btrfs_item); if (total_size < btrfs_leaf_free_space(root, leaf)) break; } nr = i; } slot = path->slots[0]; BUG_ON(slot < 0); if (slot != nritems) { unsigned int old_data = btrfs_item_end_nr(leaf, slot); item = btrfs_item_nr(leaf, slot); btrfs_item_key_to_cpu(leaf, &found_key, slot); /* figure out how many keys we can insert in here */ total_data = data_size[0]; for (i = 1; i < nr; i++) { |
5d4f98a28 Btrfs: Mixed back... |
3370 |
if (btrfs_comp_cpu_keys(&found_key, cpu_key + i) <= 0) |
f3465ca44 Btrfs: batch exte... |
3371 3372 3373 3374 3375 3376 3377 |
break; total_data += data_size[i]; } nr = i; if (old_data < data_end) { btrfs_print_leaf(root, leaf); |
d397712bc Btrfs: Fix checkp... |
3378 3379 |
printk(KERN_CRIT "slot %d old_data %d data_end %d ", |
f3465ca44 Btrfs: batch exte... |
3380 3381 3382 3383 3384 3385 3386 |
slot, old_data, data_end); BUG_ON(1); } /* * item0..itemN ... dataN.offset..dataN.size .. data0.size */ /* first correct the data pointers */ |
f3465ca44 Btrfs: batch exte... |
3387 3388 3389 3390 |
for (i = slot; i < nritems; i++) { u32 ioff; item = btrfs_item_nr(leaf, i); |
f3465ca44 Btrfs: batch exte... |
3391 3392 3393 |
ioff = btrfs_item_offset(leaf, item); btrfs_set_item_offset(leaf, item, ioff - total_data); } |
f3465ca44 Btrfs: batch exte... |
3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 |
/* shift the items */ memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + nr), btrfs_item_nr_offset(slot), (nritems - slot) * sizeof(struct btrfs_item)); /* shift the data */ memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + data_end - total_data, btrfs_leaf_data(leaf) + data_end, old_data - data_end); data_end = old_data; } else { /* * this sucks but it has to be done, if we are inserting at * the end of the leaf only insert 1 of the items, since we * have no way of knowing whats on the next leaf and we'd have * to drop our current locks to figure it out */ nr = 1; } /* setup the item for the new data */ for (i = 0; i < nr; i++) { btrfs_cpu_key_to_disk(&disk_key, cpu_key + i); btrfs_set_item_key(leaf, &disk_key, slot + i); item = btrfs_item_nr(leaf, slot + i); btrfs_set_item_offset(leaf, item, data_end - data_size[i]); data_end -= data_size[i]; btrfs_set_item_size(leaf, item, data_size[i]); } btrfs_set_header_nritems(leaf, nritems + nr); btrfs_mark_buffer_dirty(leaf); ret = 0; if (slot == 0) { btrfs_cpu_key_to_disk(&disk_key, cpu_key); ret = fixup_low_keys(trans, root, path, &disk_key, 1); } if (btrfs_leaf_free_space(root, leaf) < 0) { btrfs_print_leaf(root, leaf); BUG(); } out: if (!ret) ret = nr; return ret; } /* |
44871b1b2 Btrfs: reduce sta... |
3443 3444 3445 |
* this is a helper for btrfs_insert_empty_items, the main goal here is * to save stack depth by doing the bulk of the work in a function * that doesn't call btrfs_search_slot |
74123bd72 Btrfs: Commenting... |
3446 |
*/ |
16cdcec73 btrfs: implement ... |
3447 3448 3449 3450 |
int setup_items_for_insert(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *cpu_key, u32 *data_size, u32 total_data, u32 total_size, int nr) |
be0e5c097 Btrfs: Initial ch... |
3451 |
{ |
5f39d397d Btrfs: Create ext... |
3452 |
struct btrfs_item *item; |
9c58309d6 Btrfs: Add inode ... |
3453 |
int i; |
7518a238e Btrfs: get/set fo... |
3454 |
u32 nritems; |
be0e5c097 Btrfs: Initial ch... |
3455 |
unsigned int data_end; |
e2fa7227c Btrfs: struct key... |
3456 |
struct btrfs_disk_key disk_key; |
44871b1b2 Btrfs: reduce sta... |
3457 3458 3459 |
int ret; struct extent_buffer *leaf; int slot; |
e2fa7227c Btrfs: struct key... |
3460 |
|
5f39d397d Btrfs: Create ext... |
3461 |
leaf = path->nodes[0]; |
44871b1b2 Btrfs: reduce sta... |
3462 |
slot = path->slots[0]; |
74123bd72 Btrfs: Commenting... |
3463 |
|
5f39d397d Btrfs: Create ext... |
3464 |
nritems = btrfs_header_nritems(leaf); |
123abc88c Btrfs: variable b... |
3465 |
data_end = leaf_data_end(root, leaf); |
eb60ceac0 Btrfs: Add backin... |
3466 |
|
f25956cc5 Fix leaf overflow... |
3467 |
if (btrfs_leaf_free_space(root, leaf) < total_size) { |
3326d1b07 Btrfs: Allow tail... |
3468 |
btrfs_print_leaf(root, leaf); |
d397712bc Btrfs: Fix checkp... |
3469 3470 |
printk(KERN_CRIT "not enough freespace need %u have %d ", |
9c58309d6 Btrfs: Add inode ... |
3471 |
total_size, btrfs_leaf_free_space(root, leaf)); |
be0e5c097 Btrfs: Initial ch... |
3472 |
BUG(); |
d4dbff953 Btrfs: support fo... |
3473 |
} |
5f39d397d Btrfs: Create ext... |
3474 |
|
be0e5c097 Btrfs: Initial ch... |
3475 |
if (slot != nritems) { |
5f39d397d Btrfs: Create ext... |
3476 |
unsigned int old_data = btrfs_item_end_nr(leaf, slot); |
be0e5c097 Btrfs: Initial ch... |
3477 |
|
5f39d397d Btrfs: Create ext... |
3478 3479 |
if (old_data < data_end) { btrfs_print_leaf(root, leaf); |
d397712bc Btrfs: Fix checkp... |
3480 3481 |
printk(KERN_CRIT "slot %d old_data %d data_end %d ", |
5f39d397d Btrfs: Create ext... |
3482 3483 3484 |
slot, old_data, data_end); BUG_ON(1); } |
be0e5c097 Btrfs: Initial ch... |
3485 3486 3487 3488 |
/* * item0..itemN ... dataN.offset..dataN.size .. data0.size */ /* first correct the data pointers */ |
0783fcfc4 Btrfs: struct ite... |
3489 |
for (i = slot; i < nritems; i++) { |
5f39d397d Btrfs: Create ext... |
3490 |
u32 ioff; |
db94535db Btrfs: Allow tree... |
3491 |
|
5f39d397d Btrfs: Create ext... |
3492 3493 |
item = btrfs_item_nr(leaf, i); ioff = btrfs_item_offset(leaf, item); |
9c58309d6 Btrfs: Add inode ... |
3494 |
btrfs_set_item_offset(leaf, item, ioff - total_data); |
0783fcfc4 Btrfs: struct ite... |
3495 |
} |
be0e5c097 Btrfs: Initial ch... |
3496 |
/* shift the items */ |
9c58309d6 Btrfs: Add inode ... |
3497 |
memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + nr), |
5f39d397d Btrfs: Create ext... |
3498 |
btrfs_item_nr_offset(slot), |
d60255795 Btrfs: corruption... |
3499 |
(nritems - slot) * sizeof(struct btrfs_item)); |
be0e5c097 Btrfs: Initial ch... |
3500 3501 |
/* shift the data */ |
5f39d397d Btrfs: Create ext... |
3502 |
memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + |
9c58309d6 Btrfs: Add inode ... |
3503 |
data_end - total_data, btrfs_leaf_data(leaf) + |
d60255795 Btrfs: corruption... |
3504 |
data_end, old_data - data_end); |
be0e5c097 Btrfs: Initial ch... |
3505 3506 |
data_end = old_data; } |
5f39d397d Btrfs: Create ext... |
3507 |
|
62e2749e0 Btrfs: Use a chun... |
3508 |
/* setup the item for the new data */ |
9c58309d6 Btrfs: Add inode ... |
3509 3510 3511 3512 3513 3514 3515 3516 |
for (i = 0; i < nr; i++) { btrfs_cpu_key_to_disk(&disk_key, cpu_key + i); btrfs_set_item_key(leaf, &disk_key, slot + i); item = btrfs_item_nr(leaf, slot + i); btrfs_set_item_offset(leaf, item, data_end - data_size[i]); data_end -= data_size[i]; btrfs_set_item_size(leaf, item, data_size[i]); } |
44871b1b2 Btrfs: reduce sta... |
3517 |
|
9c58309d6 Btrfs: Add inode ... |
3518 |
btrfs_set_header_nritems(leaf, nritems + nr); |
aa5d6bed2 Btrfs: return cod... |
3519 3520 |
ret = 0; |
5a01a2e3a Btrfs: Copy corre... |
3521 3522 |
if (slot == 0) { btrfs_cpu_key_to_disk(&disk_key, cpu_key); |
e089f05c1 Btrfs: transactio... |
3523 |
ret = fixup_low_keys(trans, root, path, &disk_key, 1); |
5a01a2e3a Btrfs: Copy corre... |
3524 |
} |
b9473439d Btrfs: leave btre... |
3525 3526 |
btrfs_unlock_up_safe(path, 1); btrfs_mark_buffer_dirty(leaf); |
aa5d6bed2 Btrfs: return cod... |
3527 |
|
5f39d397d Btrfs: Create ext... |
3528 3529 |
if (btrfs_leaf_free_space(root, leaf) < 0) { btrfs_print_leaf(root, leaf); |
be0e5c097 Btrfs: Initial ch... |
3530 |
BUG(); |
5f39d397d Btrfs: Create ext... |
3531 |
} |
44871b1b2 Btrfs: reduce sta... |
3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 |
return ret; } /* * Given a key and some data, insert items into the tree. * This does all the path init required, making room in the tree if needed. */ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *cpu_key, u32 *data_size, int nr) { |
44871b1b2 Btrfs: reduce sta... |
3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 |
int ret = 0; int slot; int i; u32 total_size = 0; u32 total_data = 0; for (i = 0; i < nr; i++) total_data += data_size[i]; total_size = total_data + (nr * sizeof(struct btrfs_item)); ret = btrfs_search_slot(trans, root, cpu_key, path, total_size, 1); if (ret == 0) return -EEXIST; if (ret < 0) goto out; |
44871b1b2 Btrfs: reduce sta... |
3560 3561 3562 3563 3564 |
slot = path->slots[0]; BUG_ON(slot < 0); ret = setup_items_for_insert(trans, root, path, cpu_key, data_size, total_data, total_size, nr); |
ed2ff2cba Btrfs: pretend pa... |
3565 |
out: |
62e2749e0 Btrfs: Use a chun... |
3566 3567 3568 3569 3570 3571 3572 |
return ret; } /* * Given a key and some data, insert an item into the tree. * This does all the path init required, making room in the tree if needed. */ |
e089f05c1 Btrfs: transactio... |
3573 3574 3575 |
int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *cpu_key, void *data, u32 data_size) |
62e2749e0 Btrfs: Use a chun... |
3576 3577 |
{ int ret = 0; |
2c90e5d65 Btrfs: still corr... |
3578 |
struct btrfs_path *path; |
5f39d397d Btrfs: Create ext... |
3579 3580 |
struct extent_buffer *leaf; unsigned long ptr; |
62e2749e0 Btrfs: Use a chun... |
3581 |
|
2c90e5d65 Btrfs: still corr... |
3582 |
path = btrfs_alloc_path(); |
db5b493ac Btrfs: cleanup so... |
3583 3584 |
if (!path) return -ENOMEM; |
2c90e5d65 Btrfs: still corr... |
3585 |
ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); |
62e2749e0 Btrfs: Use a chun... |
3586 |
if (!ret) { |
5f39d397d Btrfs: Create ext... |
3587 3588 3589 3590 |
leaf = path->nodes[0]; ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); write_extent_buffer(leaf, data, ptr, data_size); btrfs_mark_buffer_dirty(leaf); |
62e2749e0 Btrfs: Use a chun... |
3591 |
} |
2c90e5d65 Btrfs: still corr... |
3592 |
btrfs_free_path(path); |
aa5d6bed2 Btrfs: return cod... |
3593 |
return ret; |
be0e5c097 Btrfs: Initial ch... |
3594 |
} |
74123bd72 Btrfs: Commenting... |
3595 |
/* |
5de08d7d5 Btrfs: Break up c... |
3596 |
* delete the pointer from a given node. |
74123bd72 Btrfs: Commenting... |
3597 |
* |
d352ac681 Btrfs: add and im... |
3598 3599 |
* the tree should have been previously balanced so the deletion does not * empty a node. |
74123bd72 Btrfs: Commenting... |
3600 |
*/ |
e089f05c1 Btrfs: transactio... |
3601 3602 |
static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int level, int slot) |
be0e5c097 Btrfs: Initial ch... |
3603 |
{ |
5f39d397d Btrfs: Create ext... |
3604 |
struct extent_buffer *parent = path->nodes[level]; |
7518a238e Btrfs: get/set fo... |
3605 |
u32 nritems; |
aa5d6bed2 Btrfs: return cod... |
3606 |
int ret = 0; |
bb8039515 Btrfs: merge on t... |
3607 |
int wret; |
be0e5c097 Btrfs: Initial ch... |
3608 |
|
5f39d397d Btrfs: Create ext... |
3609 |
nritems = btrfs_header_nritems(parent); |
d397712bc Btrfs: Fix checkp... |
3610 |
if (slot != nritems - 1) { |
5f39d397d Btrfs: Create ext... |
3611 3612 3613 |
memmove_extent_buffer(parent, btrfs_node_key_ptr_offset(slot), btrfs_node_key_ptr_offset(slot + 1), |
d60255795 Btrfs: corruption... |
3614 3615 |
sizeof(struct btrfs_key_ptr) * (nritems - slot - 1)); |
bb8039515 Btrfs: merge on t... |
3616 |
} |
7518a238e Btrfs: get/set fo... |
3617 |
nritems--; |
5f39d397d Btrfs: Create ext... |
3618 |
btrfs_set_header_nritems(parent, nritems); |
7518a238e Btrfs: get/set fo... |
3619 |
if (nritems == 0 && parent == root->node) { |
5f39d397d Btrfs: Create ext... |
3620 |
BUG_ON(btrfs_header_level(root->node) != 1); |
bb8039515 Btrfs: merge on t... |
3621 |
/* just turn the root into a leaf and break */ |
5f39d397d Btrfs: Create ext... |
3622 |
btrfs_set_header_level(root->node, 0); |
bb8039515 Btrfs: merge on t... |
3623 |
} else if (slot == 0) { |
5f39d397d Btrfs: Create ext... |
3624 3625 3626 3627 |
struct btrfs_disk_key disk_key; btrfs_node_key(parent, &disk_key, 0); wret = fixup_low_keys(trans, root, path, &disk_key, level + 1); |
0f70abe2b Btrfs: more retur... |
3628 3629 |
if (wret) ret = wret; |
be0e5c097 Btrfs: Initial ch... |
3630 |
} |
d60255795 Btrfs: corruption... |
3631 |
btrfs_mark_buffer_dirty(parent); |
aa5d6bed2 Btrfs: return cod... |
3632 |
return ret; |
be0e5c097 Btrfs: Initial ch... |
3633 |
} |
74123bd72 Btrfs: Commenting... |
3634 |
/* |
323ac95bc Btrfs: don't read... |
3635 |
* a helper function to delete the leaf pointed to by path->slots[1] and |
5d4f98a28 Btrfs: Mixed back... |
3636 |
* path->nodes[1]. |
323ac95bc Btrfs: don't read... |
3637 3638 3639 3640 3641 3642 3643 |
* * This deletes the pointer in path->nodes[1] and frees the leaf * block extent. zero is returned if it all worked out, < 0 otherwise. * * The path must have already been setup for deleting the leaf, including * all the proper balancing. path->nodes[1] must be locked. */ |
5d4f98a28 Btrfs: Mixed back... |
3644 3645 3646 3647 |
static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct extent_buffer *leaf) |
323ac95bc Btrfs: don't read... |
3648 3649 |
{ int ret; |
323ac95bc Btrfs: don't read... |
3650 |
|
5d4f98a28 Btrfs: Mixed back... |
3651 |
WARN_ON(btrfs_header_generation(leaf) != trans->transid); |
323ac95bc Btrfs: don't read... |
3652 3653 3654 |
ret = del_ptr(trans, root, path, 1, path->slots[1]); if (ret) return ret; |
4d081c41a Btrfs: change btr... |
3655 3656 3657 3658 3659 |
/* * btrfs_free_extent is expensive, we want to make sure we * aren't holding any locks when we call it */ btrfs_unlock_up_safe(path, 0); |
f0486c68e Btrfs: Introduce ... |
3660 3661 3662 3663 |
root_sub_used(root, leaf->len); btrfs_free_tree_block(trans, root, leaf, 0, 1); return 0; |
323ac95bc Btrfs: don't read... |
3664 3665 |
} /* |
74123bd72 Btrfs: Commenting... |
3666 3667 3668 |
* delete the item at the leaf level in path. If that empties * the leaf, remove it from the tree */ |
85e21bac1 Btrfs: During del... |
3669 3670 |
int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int slot, int nr) |
be0e5c097 Btrfs: Initial ch... |
3671 |
{ |
5f39d397d Btrfs: Create ext... |
3672 3673 |
struct extent_buffer *leaf; struct btrfs_item *item; |
85e21bac1 Btrfs: During del... |
3674 3675 |
int last_off; int dsize = 0; |
aa5d6bed2 Btrfs: return cod... |
3676 3677 |
int ret = 0; int wret; |
85e21bac1 Btrfs: During del... |
3678 |
int i; |
7518a238e Btrfs: get/set fo... |
3679 |
u32 nritems; |
be0e5c097 Btrfs: Initial ch... |
3680 |
|
5f39d397d Btrfs: Create ext... |
3681 |
leaf = path->nodes[0]; |
85e21bac1 Btrfs: During del... |
3682 3683 3684 3685 |
last_off = btrfs_item_offset_nr(leaf, slot + nr - 1); for (i = 0; i < nr; i++) dsize += btrfs_item_size_nr(leaf, slot + i); |
5f39d397d Btrfs: Create ext... |
3686 |
nritems = btrfs_header_nritems(leaf); |
be0e5c097 Btrfs: Initial ch... |
3687 |
|
85e21bac1 Btrfs: During del... |
3688 |
if (slot + nr != nritems) { |
123abc88c Btrfs: variable b... |
3689 |
int data_end = leaf_data_end(root, leaf); |
5f39d397d Btrfs: Create ext... |
3690 3691 |
memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + |
d60255795 Btrfs: corruption... |
3692 3693 |
data_end + dsize, btrfs_leaf_data(leaf) + data_end, |
85e21bac1 Btrfs: During del... |
3694 |
last_off - data_end); |
5f39d397d Btrfs: Create ext... |
3695 |
|
85e21bac1 Btrfs: During del... |
3696 |
for (i = slot + nr; i < nritems; i++) { |
5f39d397d Btrfs: Create ext... |
3697 |
u32 ioff; |
db94535db Btrfs: Allow tree... |
3698 |
|
5f39d397d Btrfs: Create ext... |
3699 3700 3701 |
item = btrfs_item_nr(leaf, i); ioff = btrfs_item_offset(leaf, item); btrfs_set_item_offset(leaf, item, ioff + dsize); |
0783fcfc4 Btrfs: struct ite... |
3702 |
} |
db94535db Btrfs: Allow tree... |
3703 |
|
5f39d397d Btrfs: Create ext... |
3704 |
memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot), |
85e21bac1 Btrfs: During del... |
3705 |
btrfs_item_nr_offset(slot + nr), |
d60255795 Btrfs: corruption... |
3706 |
sizeof(struct btrfs_item) * |
85e21bac1 Btrfs: During del... |
3707 |
(nritems - slot - nr)); |
be0e5c097 Btrfs: Initial ch... |
3708 |
} |
85e21bac1 Btrfs: During del... |
3709 3710 |
btrfs_set_header_nritems(leaf, nritems - nr); nritems -= nr; |
5f39d397d Btrfs: Create ext... |
3711 |
|
74123bd72 Btrfs: Commenting... |
3712 |
/* delete the leaf if we've emptied it */ |
7518a238e Btrfs: get/set fo... |
3713 |
if (nritems == 0) { |
5f39d397d Btrfs: Create ext... |
3714 3715 |
if (leaf == root->node) { btrfs_set_header_level(leaf, 0); |
9a8dd1502 Btrfs: Block size... |
3716 |
} else { |
f0486c68e Btrfs: Introduce ... |
3717 3718 |
btrfs_set_path_blocking(path); clean_tree_block(trans, root, leaf); |
5d4f98a28 Btrfs: Mixed back... |
3719 |
ret = btrfs_del_leaf(trans, root, path, leaf); |
323ac95bc Btrfs: don't read... |
3720 |
BUG_ON(ret); |
9a8dd1502 Btrfs: Block size... |
3721 |
} |
be0e5c097 Btrfs: Initial ch... |
3722 |
} else { |
7518a238e Btrfs: get/set fo... |
3723 |
int used = leaf_space_used(leaf, 0, nritems); |
aa5d6bed2 Btrfs: return cod... |
3724 |
if (slot == 0) { |
5f39d397d Btrfs: Create ext... |
3725 3726 3727 |
struct btrfs_disk_key disk_key; btrfs_item_key(leaf, &disk_key, 0); |
e089f05c1 Btrfs: transactio... |
3728 |
wret = fixup_low_keys(trans, root, path, |
5f39d397d Btrfs: Create ext... |
3729 |
&disk_key, 1); |
aa5d6bed2 Btrfs: return cod... |
3730 3731 3732 |
if (wret) ret = wret; } |
aa5d6bed2 Btrfs: return cod... |
3733 |
|
74123bd72 Btrfs: Commenting... |
3734 |
/* delete the leaf if it is mostly empty */ |
d717aa1d3 Btrfs: Avoid dela... |
3735 |
if (used < BTRFS_LEAF_DATA_SIZE(root) / 3) { |
be0e5c097 Btrfs: Initial ch... |
3736 3737 3738 3739 |
/* push_leaf_left fixes the path. * make sure the path still points to our leaf * for possible call to del_ptr below */ |
4920c9ac9 Btrfs: Faster del... |
3740 |
slot = path->slots[1]; |
5f39d397d Btrfs: Create ext... |
3741 |
extent_buffer_get(leaf); |
b9473439d Btrfs: leave btre... |
3742 |
btrfs_set_path_blocking(path); |
99d8f83c9 Btrfs: fix split_... |
3743 3744 |
wret = push_leaf_left(trans, root, path, 1, 1, 1, (u32)-1); |
54aa1f4df Btrfs: Audit call... |
3745 |
if (wret < 0 && wret != -ENOSPC) |
aa5d6bed2 Btrfs: return cod... |
3746 |
ret = wret; |
5f39d397d Btrfs: Create ext... |
3747 3748 3749 |
if (path->nodes[0] == leaf && btrfs_header_nritems(leaf)) { |
99d8f83c9 Btrfs: fix split_... |
3750 3751 |
wret = push_leaf_right(trans, root, path, 1, 1, 1, 0); |
54aa1f4df Btrfs: Audit call... |
3752 |
if (wret < 0 && wret != -ENOSPC) |
aa5d6bed2 Btrfs: return cod... |
3753 3754 |
ret = wret; } |
5f39d397d Btrfs: Create ext... |
3755 3756 |
if (btrfs_header_nritems(leaf) == 0) { |
323ac95bc Btrfs: don't read... |
3757 |
path->slots[1] = slot; |
5d4f98a28 Btrfs: Mixed back... |
3758 |
ret = btrfs_del_leaf(trans, root, path, leaf); |
323ac95bc Btrfs: don't read... |
3759 |
BUG_ON(ret); |
5f39d397d Btrfs: Create ext... |
3760 |
free_extent_buffer(leaf); |
5de08d7d5 Btrfs: Break up c... |
3761 |
} else { |
925baeddc Btrfs: Start btre... |
3762 3763 3764 3765 3766 3767 3768 |
/* if we're still in the path, make sure * we're dirty. Otherwise, one of the * push_leaf functions must have already * dirtied this buffer */ if (path->nodes[0] == leaf) btrfs_mark_buffer_dirty(leaf); |
5f39d397d Btrfs: Create ext... |
3769 |
free_extent_buffer(leaf); |
be0e5c097 Btrfs: Initial ch... |
3770 |
} |
d57197629 btrfs_create, btr... |
3771 |
} else { |
5f39d397d Btrfs: Create ext... |
3772 |
btrfs_mark_buffer_dirty(leaf); |
be0e5c097 Btrfs: Initial ch... |
3773 3774 |
} } |
aa5d6bed2 Btrfs: return cod... |
3775 |
return ret; |
be0e5c097 Btrfs: Initial ch... |
3776 |
} |
97571fd0c Btrfs: cleanup & ... |
3777 |
/* |
925baeddc Btrfs: Start btre... |
3778 |
* search the tree again to find a leaf with lesser keys |
7bb86316c Btrfs: Add back p... |
3779 3780 |
* returns 0 if it found something or 1 if there are no lesser leaves. * returns < 0 on io errors. |
d352ac681 Btrfs: add and im... |
3781 3782 3783 |
* * This may release the path, and so you may lose any locks held at the * time you call it. |
7bb86316c Btrfs: Add back p... |
3784 3785 3786 |
*/ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path) { |
925baeddc Btrfs: Start btre... |
3787 3788 3789 |
struct btrfs_key key; struct btrfs_disk_key found_key; int ret; |
7bb86316c Btrfs: Add back p... |
3790 |
|
925baeddc Btrfs: Start btre... |
3791 |
btrfs_item_key_to_cpu(path->nodes[0], &key, 0); |
7bb86316c Btrfs: Add back p... |
3792 |
|
925baeddc Btrfs: Start btre... |
3793 3794 3795 3796 3797 3798 3799 3800 |
if (key.offset > 0) key.offset--; else if (key.type > 0) key.type--; else if (key.objectid > 0) key.objectid--; else return 1; |
7bb86316c Btrfs: Add back p... |
3801 |
|
b3b4aa74b btrfs: drop unuse... |
3802 |
btrfs_release_path(path); |
925baeddc Btrfs: Start btre... |
3803 3804 3805 3806 3807 3808 3809 3810 |
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) return ret; btrfs_item_key(path->nodes[0], &found_key, 0); ret = comp_keys(&found_key, &key); if (ret < 0) return 0; return 1; |
7bb86316c Btrfs: Add back p... |
3811 |
} |
3f157a2fd Btrfs: Online btr... |
3812 3813 3814 |
/* * A helper function to walk down the tree starting at min_key, and looking * for nodes or leaves that are either in cache or have a minimum |
d352ac681 Btrfs: add and im... |
3815 |
* transaction id. This is used by the btree defrag code, and tree logging |
3f157a2fd Btrfs: Online btr... |
3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 |
* * This does not cow, but it does stuff the starting key it finds back * into min_key, so you can call btrfs_search_slot with cow=1 on the * key and get a writable path. * * This does lock as it descends, and path->keep_locks should be set * to 1 by the caller. * * This honors path->lowest_level to prevent descent past a given level * of the tree. * |
d352ac681 Btrfs: add and im... |
3827 3828 3829 3830 |
* min_trans indicates the oldest transaction that you are interested * in walking through. Any nodes or leaves older than min_trans are * skipped over (without reading them). * |
3f157a2fd Btrfs: Online btr... |
3831 3832 3833 3834 |
* returns zero if something useful was found, < 0 on error and 1 if there * was nothing in the tree that matched the search criteria. */ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, |
e02119d5a Btrfs: Add a writ... |
3835 |
struct btrfs_key *max_key, |
3f157a2fd Btrfs: Online btr... |
3836 3837 3838 3839 3840 3841 |
struct btrfs_path *path, int cache_only, u64 min_trans) { struct extent_buffer *cur; struct btrfs_key found_key; int slot; |
9652480bf Fix path slots se... |
3842 |
int sret; |
3f157a2fd Btrfs: Online btr... |
3843 3844 3845 |
u32 nritems; int level; int ret = 1; |
934d375ba Btrfs: Use map_pr... |
3846 |
WARN_ON(!path->keep_locks); |
3f157a2fd Btrfs: Online btr... |
3847 |
again: |
bd681513f Btrfs: switch the... |
3848 |
cur = btrfs_read_lock_root_node(root); |
3f157a2fd Btrfs: Online btr... |
3849 |
level = btrfs_header_level(cur); |
e02119d5a Btrfs: Add a writ... |
3850 |
WARN_ON(path->nodes[level]); |
3f157a2fd Btrfs: Online btr... |
3851 |
path->nodes[level] = cur; |
bd681513f Btrfs: switch the... |
3852 |
path->locks[level] = BTRFS_READ_LOCK; |
3f157a2fd Btrfs: Online btr... |
3853 3854 3855 3856 3857 |
if (btrfs_header_generation(cur) < min_trans) { ret = 1; goto out; } |
d397712bc Btrfs: Fix checkp... |
3858 |
while (1) { |
3f157a2fd Btrfs: Online btr... |
3859 3860 |
nritems = btrfs_header_nritems(cur); level = btrfs_header_level(cur); |
9652480bf Fix path slots se... |
3861 |
sret = bin_search(cur, min_key, level, &slot); |
3f157a2fd Btrfs: Online btr... |
3862 |
|
323ac95bc Btrfs: don't read... |
3863 3864 |
/* at the lowest level, we're done, setup the path and exit */ if (level == path->lowest_level) { |
e02119d5a Btrfs: Add a writ... |
3865 3866 |
if (slot >= nritems) goto find_next_key; |
3f157a2fd Btrfs: Online btr... |
3867 3868 3869 3870 3871 |
ret = 0; path->slots[level] = slot; btrfs_item_key_to_cpu(cur, &found_key, slot); goto out; } |
9652480bf Fix path slots se... |
3872 3873 |
if (sret && slot > 0) slot--; |
3f157a2fd Btrfs: Online btr... |
3874 3875 3876 3877 3878 |
/* * check this node pointer against the cache_only and * min_trans parameters. If it isn't in cache or is too * old, skip to the next one. */ |
d397712bc Btrfs: Fix checkp... |
3879 |
while (slot < nritems) { |
3f157a2fd Btrfs: Online btr... |
3880 3881 3882 |
u64 blockptr; u64 gen; struct extent_buffer *tmp; |
e02119d5a Btrfs: Add a writ... |
3883 |
struct btrfs_disk_key disk_key; |
3f157a2fd Btrfs: Online btr... |
3884 3885 3886 3887 3888 3889 3890 3891 |
blockptr = btrfs_node_blockptr(cur, slot); gen = btrfs_node_ptr_generation(cur, slot); if (gen < min_trans) { slot++; continue; } if (!cache_only) break; |
e02119d5a Btrfs: Add a writ... |
3892 3893 3894 3895 3896 3897 3898 |
if (max_key) { btrfs_node_key(cur, &disk_key, slot); if (comp_keys(&disk_key, max_key) >= 0) { ret = 1; goto out; } } |
3f157a2fd Btrfs: Online btr... |
3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 |
tmp = btrfs_find_tree_block(root, blockptr, btrfs_level_size(root, level - 1)); if (tmp && btrfs_buffer_uptodate(tmp, gen)) { free_extent_buffer(tmp); break; } if (tmp) free_extent_buffer(tmp); slot++; } |
e02119d5a Btrfs: Add a writ... |
3910 |
find_next_key: |
3f157a2fd Btrfs: Online btr... |
3911 3912 3913 3914 3915 |
/* * we didn't find a candidate key in this node, walk forward * and find another one */ if (slot >= nritems) { |
e02119d5a Btrfs: Add a writ... |
3916 |
path->slots[level] = slot; |
b4ce94de9 Btrfs: Change btr... |
3917 |
btrfs_set_path_blocking(path); |
e02119d5a Btrfs: Add a writ... |
3918 |
sret = btrfs_find_next_key(root, path, min_key, level, |
3f157a2fd Btrfs: Online btr... |
3919 |
cache_only, min_trans); |
e02119d5a Btrfs: Add a writ... |
3920 |
if (sret == 0) { |
b3b4aa74b btrfs: drop unuse... |
3921 |
btrfs_release_path(path); |
3f157a2fd Btrfs: Online btr... |
3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 |
goto again; } else { goto out; } } /* save our key for returning back */ btrfs_node_key_to_cpu(cur, &found_key, slot); path->slots[level] = slot; if (level == path->lowest_level) { ret = 0; unlock_up(path, level, 1); goto out; } |
b4ce94de9 Btrfs: Change btr... |
3935 |
btrfs_set_path_blocking(path); |
3f157a2fd Btrfs: Online btr... |
3936 |
cur = read_node_slot(root, cur, slot); |
97d9a8a42 Btrfs: check retu... |
3937 |
BUG_ON(!cur); |
3f157a2fd Btrfs: Online btr... |
3938 |
|
bd681513f Btrfs: switch the... |
3939 |
btrfs_tree_read_lock(cur); |
b4ce94de9 Btrfs: Change btr... |
3940 |
|
bd681513f Btrfs: switch the... |
3941 |
path->locks[level - 1] = BTRFS_READ_LOCK; |
3f157a2fd Btrfs: Online btr... |
3942 3943 |
path->nodes[level - 1] = cur; unlock_up(path, level, 1); |
bd681513f Btrfs: switch the... |
3944 |
btrfs_clear_path_blocking(path, NULL, 0); |
3f157a2fd Btrfs: Online btr... |
3945 3946 3947 3948 |
} out: if (ret == 0) memcpy(min_key, &found_key, sizeof(found_key)); |
b4ce94de9 Btrfs: Change btr... |
3949 |
btrfs_set_path_blocking(path); |
3f157a2fd Btrfs: Online btr... |
3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 |
return ret; } /* * this is similar to btrfs_next_leaf, but does not try to preserve * and fixup the path. It looks for and returns the next key in the * tree based on the current path and the cache_only and min_trans * parameters. * * 0 is returned if another key is found, < 0 if there are any errors * and 1 is returned if there are no higher keys in the tree * * path->keep_locks should be set to 1 on the search made before * calling this function. */ |
e7a84565b Btrfs: Add btree ... |
3965 |
int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, |
33c66f430 Btrfs: fix lockin... |
3966 |
struct btrfs_key *key, int level, |
3f157a2fd Btrfs: Online btr... |
3967 |
int cache_only, u64 min_trans) |
e7a84565b Btrfs: Add btree ... |
3968 |
{ |
e7a84565b Btrfs: Add btree ... |
3969 3970 |
int slot; struct extent_buffer *c; |
934d375ba Btrfs: Use map_pr... |
3971 |
WARN_ON(!path->keep_locks); |
d397712bc Btrfs: Fix checkp... |
3972 |
while (level < BTRFS_MAX_LEVEL) { |
e7a84565b Btrfs: Add btree ... |
3973 3974 3975 3976 3977 |
if (!path->nodes[level]) return 1; slot = path->slots[level] + 1; c = path->nodes[level]; |
3f157a2fd Btrfs: Online btr... |
3978 |
next: |
e7a84565b Btrfs: Add btree ... |
3979 |
if (slot >= btrfs_header_nritems(c)) { |
33c66f430 Btrfs: fix lockin... |
3980 3981 3982 3983 3984 |
int ret; int orig_lowest; struct btrfs_key cur_key; if (level + 1 >= BTRFS_MAX_LEVEL || !path->nodes[level + 1]) |
e7a84565b Btrfs: Add btree ... |
3985 |
return 1; |
33c66f430 Btrfs: fix lockin... |
3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 |
if (path->locks[level + 1]) { level++; continue; } slot = btrfs_header_nritems(c) - 1; if (level == 0) btrfs_item_key_to_cpu(c, &cur_key, slot); else btrfs_node_key_to_cpu(c, &cur_key, slot); orig_lowest = path->lowest_level; |
b3b4aa74b btrfs: drop unuse... |
3999 |
btrfs_release_path(path); |
33c66f430 Btrfs: fix lockin... |
4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 |
path->lowest_level = level; ret = btrfs_search_slot(NULL, root, &cur_key, path, 0, 0); path->lowest_level = orig_lowest; if (ret < 0) return ret; c = path->nodes[level]; slot = path->slots[level]; if (ret == 0) slot++; goto next; |
e7a84565b Btrfs: Add btree ... |
4012 |
} |
33c66f430 Btrfs: fix lockin... |
4013 |
|
e7a84565b Btrfs: Add btree ... |
4014 4015 |
if (level == 0) btrfs_item_key_to_cpu(c, key, slot); |
3f157a2fd Btrfs: Online btr... |
4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 |
else { u64 blockptr = btrfs_node_blockptr(c, slot); u64 gen = btrfs_node_ptr_generation(c, slot); if (cache_only) { struct extent_buffer *cur; cur = btrfs_find_tree_block(root, blockptr, btrfs_level_size(root, level - 1)); if (!cur || !btrfs_buffer_uptodate(cur, gen)) { slot++; if (cur) free_extent_buffer(cur); goto next; } free_extent_buffer(cur); } if (gen < min_trans) { slot++; goto next; } |
e7a84565b Btrfs: Add btree ... |
4036 |
btrfs_node_key_to_cpu(c, key, slot); |
3f157a2fd Btrfs: Online btr... |
4037 |
} |
e7a84565b Btrfs: Add btree ... |
4038 4039 4040 4041 |
return 0; } return 1; } |
7bb86316c Btrfs: Add back p... |
4042 |
/* |
925baeddc Btrfs: Start btre... |
4043 |
* search the tree again to find a leaf with greater keys |
0f70abe2b Btrfs: more retur... |
4044 4045 |
* returns 0 if it found something or 1 if there are no greater leaves. * returns < 0 on io errors. |
97571fd0c Btrfs: cleanup & ... |
4046 |
*/ |
234b63a09 rename funcs and ... |
4047 |
int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) |
d97e63b69 Btrfs: early exte... |
4048 4049 |
{ int slot; |
8e73f2750 Btrfs: Optimize l... |
4050 |
int level; |
5f39d397d Btrfs: Create ext... |
4051 |
struct extent_buffer *c; |
8e73f2750 Btrfs: Optimize l... |
4052 |
struct extent_buffer *next; |
925baeddc Btrfs: Start btre... |
4053 4054 4055 |
struct btrfs_key key; u32 nritems; int ret; |
8e73f2750 Btrfs: Optimize l... |
4056 |
int old_spinning = path->leave_spinning; |
bd681513f Btrfs: switch the... |
4057 |
int next_rw_lock = 0; |
925baeddc Btrfs: Start btre... |
4058 4059 |
nritems = btrfs_header_nritems(path->nodes[0]); |
d397712bc Btrfs: Fix checkp... |
4060 |
if (nritems == 0) |
925baeddc Btrfs: Start btre... |
4061 |
return 1; |
925baeddc Btrfs: Start btre... |
4062 |
|
8e73f2750 Btrfs: Optimize l... |
4063 4064 4065 4066 |
btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1); again: level = 1; next = NULL; |
bd681513f Btrfs: switch the... |
4067 |
next_rw_lock = 0; |
b3b4aa74b btrfs: drop unuse... |
4068 |
btrfs_release_path(path); |
8e73f2750 Btrfs: Optimize l... |
4069 |
|
a21350115 Btrfs: Replace th... |
4070 |
path->keep_locks = 1; |
31533fb26 Btrfs: remove loc... |
4071 |
path->leave_spinning = 1; |
8e73f2750 Btrfs: Optimize l... |
4072 |
|
925baeddc Btrfs: Start btre... |
4073 4074 4075 4076 4077 |
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); path->keep_locks = 0; if (ret < 0) return ret; |
a21350115 Btrfs: Replace th... |
4078 |
nritems = btrfs_header_nritems(path->nodes[0]); |
168fd7d27 Fix btrfs_next_le... |
4079 4080 4081 4082 4083 4084 |
/* * by releasing the path above we dropped all our locks. A balance * could have added more items next to the key that used to be * at the very end of the block. So, check again here and * advance the path if there are now more items available. */ |
a21350115 Btrfs: Replace th... |
4085 |
if (nritems > 0 && path->slots[0] < nritems - 1) { |
e457afec6 Btrfs: fix double... |
4086 4087 |
if (ret == 0) path->slots[0]++; |
8e73f2750 Btrfs: Optimize l... |
4088 |
ret = 0; |
925baeddc Btrfs: Start btre... |
4089 4090 |
goto done; } |
d97e63b69 Btrfs: early exte... |
4091 |
|
d397712bc Btrfs: Fix checkp... |
4092 |
while (level < BTRFS_MAX_LEVEL) { |
8e73f2750 Btrfs: Optimize l... |
4093 4094 4095 4096 |
if (!path->nodes[level]) { ret = 1; goto done; } |
5f39d397d Btrfs: Create ext... |
4097 |
|
d97e63b69 Btrfs: early exte... |
4098 4099 |
slot = path->slots[level] + 1; c = path->nodes[level]; |
5f39d397d Btrfs: Create ext... |
4100 |
if (slot >= btrfs_header_nritems(c)) { |
d97e63b69 Btrfs: early exte... |
4101 |
level++; |
8e73f2750 Btrfs: Optimize l... |
4102 4103 4104 4105 |
if (level == BTRFS_MAX_LEVEL) { ret = 1; goto done; } |
d97e63b69 Btrfs: early exte... |
4106 4107 |
continue; } |
5f39d397d Btrfs: Create ext... |
4108 |
|
925baeddc Btrfs: Start btre... |
4109 |
if (next) { |
bd681513f Btrfs: switch the... |
4110 |
btrfs_tree_unlock_rw(next, next_rw_lock); |
5f39d397d Btrfs: Create ext... |
4111 |
free_extent_buffer(next); |
925baeddc Btrfs: Start btre... |
4112 |
} |
5f39d397d Btrfs: Create ext... |
4113 |
|
8e73f2750 Btrfs: Optimize l... |
4114 |
next = c; |
bd681513f Btrfs: switch the... |
4115 |
next_rw_lock = path->locks[level]; |
8e73f2750 Btrfs: Optimize l... |
4116 4117 4118 4119 |
ret = read_block_for_search(NULL, root, path, &next, level, slot, &key); if (ret == -EAGAIN) goto again; |
5f39d397d Btrfs: Create ext... |
4120 |
|
76a05b35a Btrfs: Don't loop... |
4121 |
if (ret < 0) { |
b3b4aa74b btrfs: drop unuse... |
4122 |
btrfs_release_path(path); |
76a05b35a Btrfs: Don't loop... |
4123 4124 |
goto done; } |
5cd57b2cb Btrfs: Add a skip... |
4125 |
if (!path->skip_locking) { |
bd681513f Btrfs: switch the... |
4126 |
ret = btrfs_try_tree_read_lock(next); |
8e73f2750 Btrfs: Optimize l... |
4127 4128 |
if (!ret) { btrfs_set_path_blocking(path); |
bd681513f Btrfs: switch the... |
4129 |
btrfs_tree_read_lock(next); |
31533fb26 Btrfs: remove loc... |
4130 |
btrfs_clear_path_blocking(path, next, |
bd681513f Btrfs: switch the... |
4131 |
BTRFS_READ_LOCK); |
8e73f2750 Btrfs: Optimize l... |
4132 |
} |
31533fb26 Btrfs: remove loc... |
4133 |
next_rw_lock = BTRFS_READ_LOCK; |
5cd57b2cb Btrfs: Add a skip... |
4134 |
} |
d97e63b69 Btrfs: early exte... |
4135 4136 4137 |
break; } path->slots[level] = slot; |
d397712bc Btrfs: Fix checkp... |
4138 |
while (1) { |
d97e63b69 Btrfs: early exte... |
4139 4140 |
level--; c = path->nodes[level]; |
925baeddc Btrfs: Start btre... |
4141 |
if (path->locks[level]) |
bd681513f Btrfs: switch the... |
4142 |
btrfs_tree_unlock_rw(c, path->locks[level]); |
8e73f2750 Btrfs: Optimize l... |
4143 |
|
5f39d397d Btrfs: Create ext... |
4144 |
free_extent_buffer(c); |
d97e63b69 Btrfs: early exte... |
4145 4146 |
path->nodes[level] = next; path->slots[level] = 0; |
a74a4b97b Btrfs: Replace th... |
4147 |
if (!path->skip_locking) |
bd681513f Btrfs: switch the... |
4148 |
path->locks[level] = next_rw_lock; |
d97e63b69 Btrfs: early exte... |
4149 4150 |
if (!level) break; |
b4ce94de9 Btrfs: Change btr... |
4151 |
|
8e73f2750 Btrfs: Optimize l... |
4152 4153 4154 4155 |
ret = read_block_for_search(NULL, root, path, &next, level, 0, &key); if (ret == -EAGAIN) goto again; |
76a05b35a Btrfs: Don't loop... |
4156 |
if (ret < 0) { |
b3b4aa74b btrfs: drop unuse... |
4157 |
btrfs_release_path(path); |
76a05b35a Btrfs: Don't loop... |
4158 4159 |
goto done; } |
5cd57b2cb Btrfs: Add a skip... |
4160 |
if (!path->skip_locking) { |
bd681513f Btrfs: switch the... |
4161 |
ret = btrfs_try_tree_read_lock(next); |
8e73f2750 Btrfs: Optimize l... |
4162 4163 |
if (!ret) { btrfs_set_path_blocking(path); |
bd681513f Btrfs: switch the... |
4164 |
btrfs_tree_read_lock(next); |
31533fb26 Btrfs: remove loc... |
4165 |
btrfs_clear_path_blocking(path, next, |
bd681513f Btrfs: switch the... |
4166 4167 |
BTRFS_READ_LOCK); } |
31533fb26 Btrfs: remove loc... |
4168 |
next_rw_lock = BTRFS_READ_LOCK; |
5cd57b2cb Btrfs: Add a skip... |
4169 |
} |
d97e63b69 Btrfs: early exte... |
4170 |
} |
8e73f2750 Btrfs: Optimize l... |
4171 |
ret = 0; |
925baeddc Btrfs: Start btre... |
4172 4173 |
done: unlock_up(path, 0, 1); |
8e73f2750 Btrfs: Optimize l... |
4174 4175 4176 4177 4178 |
path->leave_spinning = old_spinning; if (!old_spinning) btrfs_set_path_blocking(path); return ret; |
d97e63b69 Btrfs: early exte... |
4179 |
} |
0b86a832a Btrfs: Add suppor... |
4180 |
|
3f157a2fd Btrfs: Online btr... |
4181 4182 4183 4184 4185 4186 |
/* * this uses btrfs_prev_leaf to walk backwards in the tree, and keeps * searching until it gets past min_objectid or finds an item of 'type' * * returns 0 if something is found, 1 if nothing was found and < 0 on error */ |
0b86a832a Btrfs: Add suppor... |
4187 4188 4189 4190 4191 4192 |
int btrfs_previous_item(struct btrfs_root *root, struct btrfs_path *path, u64 min_objectid, int type) { struct btrfs_key found_key; struct extent_buffer *leaf; |
e02119d5a Btrfs: Add a writ... |
4193 |
u32 nritems; |
0b86a832a Btrfs: Add suppor... |
4194 |
int ret; |
d397712bc Btrfs: Fix checkp... |
4195 |
while (1) { |
0b86a832a Btrfs: Add suppor... |
4196 |
if (path->slots[0] == 0) { |
b4ce94de9 Btrfs: Change btr... |
4197 |
btrfs_set_path_blocking(path); |
0b86a832a Btrfs: Add suppor... |
4198 4199 4200 4201 4202 4203 4204 |
ret = btrfs_prev_leaf(root, path); if (ret != 0) return ret; } else { path->slots[0]--; } leaf = path->nodes[0]; |
e02119d5a Btrfs: Add a writ... |
4205 4206 4207 4208 4209 |
nritems = btrfs_header_nritems(leaf); if (nritems == 0) return 1; if (path->slots[0] == nritems) path->slots[0]--; |
0b86a832a Btrfs: Add suppor... |
4210 |
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); |
e02119d5a Btrfs: Add a writ... |
4211 4212 |
if (found_key.objectid < min_objectid) break; |
0a4eefbb7 Btrfs: Fix orderi... |
4213 4214 |
if (found_key.type == type) return 0; |
e02119d5a Btrfs: Add a writ... |
4215 4216 4217 |
if (found_key.objectid == min_objectid && found_key.type < type) break; |
0b86a832a Btrfs: Add suppor... |
4218 4219 4220 |
} return 1; } |