Blame view
fs/btrfs/root-tree.c
10.7 KB
6cbd55707 Btrfs: add GPLv2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* * Copyright (C) 2007 Oracle. All rights reserved. * * 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. */ |
3768f3689 Btrfs: Change the... |
18 |
#include "ctree.h" |
5eda7b5e9 Btrfs: Add the ab... |
19 |
#include "transaction.h" |
3768f3689 Btrfs: Change the... |
20 21 |
#include "disk-io.h" #include "print-tree.h" |
bf4ef6792 Btrfs: Properly f... |
22 |
/* |
d352ac681 Btrfs: add and im... |
23 24 25 26 |
* lookup the root with the highest offset for a given objectid. The key we do * find is copied into 'key'. If we find something return 0, otherwise 1, < 0 * on error. */ |
3768f3689 Btrfs: Change the... |
27 28 29 |
int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct btrfs_root_item *item, struct btrfs_key *key) { |
5caf2a002 Btrfs: dynamic al... |
30 |
struct btrfs_path *path; |
3768f3689 Btrfs: Change the... |
31 |
struct btrfs_key search_key; |
5f39d397d Btrfs: Create ext... |
32 33 |
struct btrfs_key found_key; struct extent_buffer *l; |
3768f3689 Btrfs: Change the... |
34 35 36 37 |
int ret; int slot; search_key.objectid = objectid; |
0660b5af3 Btrfs: Add backre... |
38 |
search_key.type = BTRFS_ROOT_ITEM_KEY; |
5eda7b5e9 Btrfs: Add the ab... |
39 |
search_key.offset = (u64)-1; |
3768f3689 Btrfs: Change the... |
40 |
|
5caf2a002 Btrfs: dynamic al... |
41 |
path = btrfs_alloc_path(); |
db5b493ac Btrfs: cleanup so... |
42 43 |
if (!path) return -ENOMEM; |
5caf2a002 Btrfs: dynamic al... |
44 |
ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); |
3768f3689 Btrfs: Change the... |
45 46 |
if (ret < 0) goto out; |
5f39d397d Btrfs: Create ext... |
47 |
|
3768f3689 Btrfs: Change the... |
48 |
BUG_ON(ret == 0); |
76dda93c6 Btrfs: add snapsh... |
49 50 51 52 |
if (path->slots[0] == 0) { ret = 1; goto out; } |
5f39d397d Btrfs: Create ext... |
53 |
l = path->nodes[0]; |
5caf2a002 Btrfs: dynamic al... |
54 |
slot = path->slots[0] - 1; |
5f39d397d Btrfs: Create ext... |
55 |
btrfs_item_key_to_cpu(l, &found_key, slot); |
76dda93c6 Btrfs: add snapsh... |
56 57 |
if (found_key.objectid != objectid || found_key.type != BTRFS_ROOT_ITEM_KEY) { |
3768f3689 Btrfs: Change the... |
58 59 60 |
ret = 1; goto out; } |
76dda93c6 Btrfs: add snapsh... |
61 62 63 64 65 |
if (item) read_extent_buffer(l, item, btrfs_item_ptr_offset(l, slot), sizeof(*item)); if (key) memcpy(key, &found_key, sizeof(found_key)); |
3768f3689 Btrfs: Change the... |
66 67 |
ret = 0; out: |
5caf2a002 Btrfs: dynamic al... |
68 |
btrfs_free_path(path); |
3768f3689 Btrfs: Change the... |
69 70 |
return ret; } |
bf5f32ecb btrfs: make btrfs... |
71 72 |
void btrfs_set_root_node(struct btrfs_root_item *item, struct extent_buffer *node) |
5d4f98a28 Btrfs: Mixed back... |
73 74 75 76 |
{ btrfs_set_root_bytenr(item, node->start); btrfs_set_root_level(item, btrfs_header_level(node)); btrfs_set_root_generation(item, btrfs_header_generation(node)); |
5d4f98a28 Btrfs: Mixed back... |
77 |
} |
d352ac681 Btrfs: add and im... |
78 79 80 |
/* * copy the data in 'item' into the btree */ |
e089f05c1 Btrfs: transactio... |
81 82 83 |
int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key, struct btrfs_root_item *item) |
3768f3689 Btrfs: Change the... |
84 |
{ |
5caf2a002 Btrfs: dynamic al... |
85 |
struct btrfs_path *path; |
5f39d397d Btrfs: Create ext... |
86 |
struct extent_buffer *l; |
3768f3689 Btrfs: Change the... |
87 88 |
int ret; int slot; |
5f39d397d Btrfs: Create ext... |
89 |
unsigned long ptr; |
3768f3689 Btrfs: Change the... |
90 |
|
5caf2a002 Btrfs: dynamic al... |
91 92 |
path = btrfs_alloc_path(); BUG_ON(!path); |
5caf2a002 Btrfs: dynamic al... |
93 |
ret = btrfs_search_slot(trans, root, key, path, 0, 1); |
3768f3689 Btrfs: Change the... |
94 95 |
if (ret < 0) goto out; |
d66674620 Btrfs: Change st_... |
96 97 98 |
if (ret != 0) { btrfs_print_leaf(root, path->nodes[0]); |
d397712bc Btrfs: Fix checkp... |
99 100 101 102 |
printk(KERN_CRIT "unable to update root key %llu %u %llu ", (unsigned long long)key->objectid, key->type, (unsigned long long)key->offset); |
d66674620 Btrfs: Change st_... |
103 104 |
BUG_ON(1); } |
5f39d397d Btrfs: Create ext... |
105 |
l = path->nodes[0]; |
5caf2a002 Btrfs: dynamic al... |
106 |
slot = path->slots[0]; |
5f39d397d Btrfs: Create ext... |
107 108 |
ptr = btrfs_item_ptr_offset(l, slot); write_extent_buffer(l, item, ptr, sizeof(*item)); |
5caf2a002 Btrfs: dynamic al... |
109 |
btrfs_mark_buffer_dirty(path->nodes[0]); |
3768f3689 Btrfs: Change the... |
110 |
out: |
5caf2a002 Btrfs: dynamic al... |
111 |
btrfs_free_path(path); |
3768f3689 Btrfs: Change the... |
112 113 |
return ret; } |
e089f05c1 Btrfs: transactio... |
114 115 116 |
int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key, struct btrfs_root_item *item) |
3768f3689 Btrfs: Change the... |
117 118 |
{ int ret; |
e089f05c1 Btrfs: transactio... |
119 |
ret = btrfs_insert_item(trans, root, key, item, sizeof(*item)); |
3768f3689 Btrfs: Change the... |
120 121 |
return ret; } |
d352ac681 Btrfs: add and im... |
122 123 |
/* * at mount time we want to find all the old transaction snapshots that were in |
d397712bc Btrfs: Fix checkp... |
124 125 126 |
* the process of being deleted if we crashed. This is any root item with an * offset lower than the latest root. They need to be queued for deletion to * finish what was happening when we crashed. |
d352ac681 Btrfs: add and im... |
127 |
*/ |
5d4f98a28 Btrfs: Mixed back... |
128 |
int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid) |
5eda7b5e9 Btrfs: Add the ab... |
129 130 |
{ struct btrfs_root *dead_root; |
5eda7b5e9 Btrfs: Add the ab... |
131 132 |
struct btrfs_root_item *ri; struct btrfs_key key; |
a7a16fd77 Btrfs: Fix deadlo... |
133 |
struct btrfs_key found_key; |
5eda7b5e9 Btrfs: Add the ab... |
134 135 136 |
struct btrfs_path *path; int ret; u32 nritems; |
5f39d397d Btrfs: Create ext... |
137 |
struct extent_buffer *leaf; |
5eda7b5e9 Btrfs: Add the ab... |
138 |
int slot; |
5ce14bbcd Btrfs: Find and r... |
139 |
key.objectid = objectid; |
5eda7b5e9 Btrfs: Add the ab... |
140 141 142 143 144 |
btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); key.offset = 0; path = btrfs_alloc_path(); if (!path) return -ENOMEM; |
a7a16fd77 Btrfs: Fix deadlo... |
145 146 |
again: |
5eda7b5e9 Btrfs: Add the ab... |
147 148 149 |
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto err; |
d397712bc Btrfs: Fix checkp... |
150 |
while (1) { |
5f39d397d Btrfs: Create ext... |
151 152 |
leaf = path->nodes[0]; nritems = btrfs_header_nritems(leaf); |
5eda7b5e9 Btrfs: Add the ab... |
153 154 155 156 157 |
slot = path->slots[0]; if (slot >= nritems) { ret = btrfs_next_leaf(root, path); if (ret) break; |
5f39d397d Btrfs: Create ext... |
158 159 |
leaf = path->nodes[0]; nritems = btrfs_header_nritems(leaf); |
5eda7b5e9 Btrfs: Add the ab... |
160 161 |
slot = path->slots[0]; } |
5f39d397d Btrfs: Create ext... |
162 |
btrfs_item_key_to_cpu(leaf, &key, slot); |
5eda7b5e9 Btrfs: Add the ab... |
163 164 |
if (btrfs_key_type(&key) != BTRFS_ROOT_ITEM_KEY) goto next; |
5ce14bbcd Btrfs: Find and r... |
165 166 167 168 169 170 |
if (key.objectid < objectid) goto next; if (key.objectid > objectid) break; |
5eda7b5e9 Btrfs: Add the ab... |
171 |
ri = btrfs_item_ptr(leaf, slot, struct btrfs_root_item); |
5f39d397d Btrfs: Create ext... |
172 |
if (btrfs_disk_root_refs(leaf, ri) != 0) |
5eda7b5e9 Btrfs: Add the ab... |
173 |
goto next; |
5ce14bbcd Btrfs: Find and r... |
174 |
|
a7a16fd77 Btrfs: Fix deadlo... |
175 176 |
memcpy(&found_key, &key, sizeof(key)); key.offset++; |
b3b4aa74b btrfs: drop unuse... |
177 |
btrfs_release_path(path); |
e02119d5a Btrfs: Add a writ... |
178 179 180 |
dead_root = btrfs_read_fs_root_no_radix(root->fs_info->tree_root, &found_key); |
a1f396304 Btrfs: Some code ... |
181 182 |
if (IS_ERR(dead_root)) { ret = PTR_ERR(dead_root); |
5eda7b5e9 Btrfs: Add the ab... |
183 184 |
goto err; } |
5ce14bbcd Btrfs: Find and r... |
185 |
|
5d4f98a28 Btrfs: Mixed back... |
186 |
ret = btrfs_add_dead_root(dead_root); |
5eda7b5e9 Btrfs: Add the ab... |
187 188 |
if (ret) goto err; |
a7a16fd77 Btrfs: Fix deadlo... |
189 |
goto again; |
5eda7b5e9 Btrfs: Add the ab... |
190 191 192 193 194 195 196 197 198 |
next: slot++; path->slots[0]++; } ret = 0; err: btrfs_free_path(path); return ret; } |
76dda93c6 Btrfs: add snapsh... |
199 200 201 202 203 |
int btrfs_find_orphan_roots(struct btrfs_root *tree_root) { struct extent_buffer *leaf; struct btrfs_path *path; struct btrfs_key key; |
d68fc57b7 Btrfs: Metadata r... |
204 205 |
struct btrfs_key root_key; struct btrfs_root *root; |
76dda93c6 Btrfs: add snapsh... |
206 207 208 209 210 211 212 213 214 215 |
int err = 0; int ret; path = btrfs_alloc_path(); if (!path) return -ENOMEM; key.objectid = BTRFS_ORPHAN_OBJECTID; key.type = BTRFS_ORPHAN_ITEM_KEY; key.offset = 0; |
d68fc57b7 Btrfs: Metadata r... |
216 217 |
root_key.type = BTRFS_ROOT_ITEM_KEY; root_key.offset = (u64)-1; |
76dda93c6 Btrfs: add snapsh... |
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
while (1) { ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0); if (ret < 0) { err = ret; break; } leaf = path->nodes[0]; if (path->slots[0] >= btrfs_header_nritems(leaf)) { ret = btrfs_next_leaf(tree_root, path); if (ret < 0) err = ret; if (ret != 0) break; leaf = path->nodes[0]; } btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); |
b3b4aa74b btrfs: drop unuse... |
236 |
btrfs_release_path(path); |
76dda93c6 Btrfs: add snapsh... |
237 238 239 240 |
if (key.objectid != BTRFS_ORPHAN_OBJECTID || key.type != BTRFS_ORPHAN_ITEM_KEY) break; |
d68fc57b7 Btrfs: Metadata r... |
241 242 243 244 245 246 247 248 249 250 |
root_key.objectid = key.offset; key.offset++; root = btrfs_read_fs_root_no_name(tree_root->fs_info, &root_key); if (!IS_ERR(root)) continue; ret = PTR_ERR(root); if (ret != -ENOENT) { |
76dda93c6 Btrfs: add snapsh... |
251 252 253 |
err = ret; break; } |
d68fc57b7 Btrfs: Metadata r... |
254 255 256 257 258 |
ret = btrfs_find_dead_roots(tree_root, root_key.objectid); if (ret) { err = ret; break; } |
76dda93c6 Btrfs: add snapsh... |
259 260 261 262 263 |
} btrfs_free_path(path); return err; } |
d352ac681 Btrfs: add and im... |
264 |
/* drop the root item for 'key' from 'root' */ |
e089f05c1 Btrfs: transactio... |
265 266 |
int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key) |
3768f3689 Btrfs: Change the... |
267 |
{ |
5caf2a002 Btrfs: dynamic al... |
268 |
struct btrfs_path *path; |
3768f3689 Btrfs: Change the... |
269 |
int ret; |
c5739bba5 Btrfs: snapshot p... |
270 |
struct btrfs_root_item *ri; |
5f39d397d Btrfs: Create ext... |
271 |
struct extent_buffer *leaf; |
3768f3689 Btrfs: Change the... |
272 |
|
5caf2a002 Btrfs: dynamic al... |
273 |
path = btrfs_alloc_path(); |
db5b493ac Btrfs: cleanup so... |
274 275 |
if (!path) return -ENOMEM; |
5caf2a002 Btrfs: dynamic al... |
276 |
ret = btrfs_search_slot(trans, root, key, path, -1, 1); |
3768f3689 Btrfs: Change the... |
277 278 |
if (ret < 0) goto out; |
edbd8d4ef Btrfs: Support fo... |
279 |
|
3768f3689 Btrfs: Change the... |
280 |
BUG_ON(ret != 0); |
5f39d397d Btrfs: Create ext... |
281 282 |
leaf = path->nodes[0]; ri = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_item); |
c5739bba5 Btrfs: snapshot p... |
283 |
|
5eda7b5e9 Btrfs: Add the ab... |
284 |
ret = btrfs_del_item(trans, root, path); |
3768f3689 Btrfs: Change the... |
285 |
out: |
5caf2a002 Btrfs: dynamic al... |
286 |
btrfs_free_path(path); |
3768f3689 Btrfs: Change the... |
287 288 |
return ret; } |
0660b5af3 Btrfs: Add backre... |
289 290 291 |
int btrfs_del_root_ref(struct btrfs_trans_handle *trans, struct btrfs_root *tree_root, |
4df27c4d5 Btrfs: change how... |
292 293 |
u64 root_id, u64 ref_id, u64 dirid, u64 *sequence, const char *name, int name_len) |
0660b5af3 Btrfs: Add backre... |
294 |
{ |
4df27c4d5 Btrfs: change how... |
295 296 297 |
struct btrfs_path *path; struct btrfs_root_ref *ref; struct extent_buffer *leaf; |
0660b5af3 Btrfs: Add backre... |
298 |
struct btrfs_key key; |
4df27c4d5 Btrfs: change how... |
299 300 |
unsigned long ptr; int err = 0; |
0660b5af3 Btrfs: Add backre... |
301 |
int ret; |
0660b5af3 Btrfs: Add backre... |
302 303 |
path = btrfs_alloc_path(); |
4df27c4d5 Btrfs: change how... |
304 305 |
if (!path) return -ENOMEM; |
0660b5af3 Btrfs: Add backre... |
306 307 |
key.objectid = root_id; |
4df27c4d5 Btrfs: change how... |
308 |
key.type = BTRFS_ROOT_BACKREF_KEY; |
0660b5af3 Btrfs: Add backre... |
309 |
key.offset = ref_id; |
4df27c4d5 Btrfs: change how... |
310 |
again: |
0660b5af3 Btrfs: Add backre... |
311 |
ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1); |
4df27c4d5 Btrfs: change how... |
312 313 314 315 316 317 318 319 320 321 322 323 324 |
BUG_ON(ret < 0); if (ret == 0) { leaf = path->nodes[0]; ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref); WARN_ON(btrfs_root_ref_dirid(leaf, ref) != dirid); WARN_ON(btrfs_root_ref_name_len(leaf, ref) != name_len); ptr = (unsigned long)(ref + 1); WARN_ON(memcmp_extent_buffer(leaf, name, ptr, name_len)); *sequence = btrfs_root_ref_sequence(leaf, ref); ret = btrfs_del_item(trans, tree_root, path); |
65a246c5f Btrfs: return err... |
325 326 327 328 |
if (ret) { err = ret; goto out; } |
4df27c4d5 Btrfs: change how... |
329 330 331 332 |
} else err = -ENOENT; if (key.type == BTRFS_ROOT_BACKREF_KEY) { |
b3b4aa74b btrfs: drop unuse... |
333 |
btrfs_release_path(path); |
4df27c4d5 Btrfs: change how... |
334 335 336 337 338 |
key.objectid = ref_id; key.type = BTRFS_ROOT_REF_KEY; key.offset = root_id; goto again; } |
0660b5af3 Btrfs: Add backre... |
339 |
|
65a246c5f Btrfs: return err... |
340 |
out: |
0660b5af3 Btrfs: Add backre... |
341 |
btrfs_free_path(path); |
4df27c4d5 Btrfs: change how... |
342 |
return err; |
0660b5af3 Btrfs: Add backre... |
343 |
} |
ea9e8b11b Btrfs: prevent lo... |
344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
int btrfs_find_root_ref(struct btrfs_root *tree_root, struct btrfs_path *path, u64 root_id, u64 ref_id) { struct btrfs_key key; int ret; key.objectid = root_id; key.type = BTRFS_ROOT_REF_KEY; key.offset = ref_id; ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0); return ret; } |
0660b5af3 Btrfs: Add backre... |
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
/* * add a btrfs_root_ref item. type is either BTRFS_ROOT_REF_KEY * or BTRFS_ROOT_BACKREF_KEY. * * The dirid, sequence, name and name_len refer to the directory entry * that is referencing the root. * * For a forward ref, the root_id is the id of the tree referencing * the root and ref_id is the id of the subvol or snapshot. * * For a back ref the root_id is the id of the subvol or snapshot and * ref_id is the id of the tree referencing it. */ int btrfs_add_root_ref(struct btrfs_trans_handle *trans, struct btrfs_root *tree_root, |
4df27c4d5 Btrfs: change how... |
373 |
u64 root_id, u64 ref_id, u64 dirid, u64 sequence, |
0660b5af3 Btrfs: Add backre... |
374 375 376 377 378 379 380 381 |
const char *name, int name_len) { struct btrfs_key key; int ret; struct btrfs_path *path; struct btrfs_root_ref *ref; struct extent_buffer *leaf; unsigned long ptr; |
0660b5af3 Btrfs: Add backre... |
382 |
path = btrfs_alloc_path(); |
4df27c4d5 Btrfs: change how... |
383 384 |
if (!path) return -ENOMEM; |
0660b5af3 Btrfs: Add backre... |
385 386 |
key.objectid = root_id; |
4df27c4d5 Btrfs: change how... |
387 |
key.type = BTRFS_ROOT_BACKREF_KEY; |
0660b5af3 Btrfs: Add backre... |
388 |
key.offset = ref_id; |
4df27c4d5 Btrfs: change how... |
389 |
again: |
0660b5af3 Btrfs: Add backre... |
390 391 392 393 394 395 396 397 398 399 400 401 |
ret = btrfs_insert_empty_item(trans, tree_root, path, &key, sizeof(*ref) + name_len); BUG_ON(ret); leaf = path->nodes[0]; ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref); btrfs_set_root_ref_dirid(leaf, ref, dirid); btrfs_set_root_ref_sequence(leaf, ref, sequence); btrfs_set_root_ref_name_len(leaf, ref, name_len); ptr = (unsigned long)(ref + 1); write_extent_buffer(leaf, name, ptr, name_len); btrfs_mark_buffer_dirty(leaf); |
4df27c4d5 Btrfs: change how... |
402 |
if (key.type == BTRFS_ROOT_BACKREF_KEY) { |
b3b4aa74b btrfs: drop unuse... |
403 |
btrfs_release_path(path); |
4df27c4d5 Btrfs: change how... |
404 405 406 407 408 |
key.objectid = ref_id; key.type = BTRFS_ROOT_REF_KEY; key.offset = root_id; goto again; } |
0660b5af3 Btrfs: Add backre... |
409 |
btrfs_free_path(path); |
4df27c4d5 Btrfs: change how... |
410 |
return 0; |
0660b5af3 Btrfs: Add backre... |
411 |
} |
08fe4db17 Btrfs: Fix uninit... |
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
/* * Old btrfs forgets to init root_item->flags and root_item->byte_limit * for subvolumes. To work around this problem, we steal a bit from * root_item->inode_item->flags, and use it to indicate if those fields * have been properly initialized. */ void btrfs_check_and_init_root_item(struct btrfs_root_item *root_item) { u64 inode_flags = le64_to_cpu(root_item->inode.flags); if (!(inode_flags & BTRFS_INODE_ROOT_ITEM_INIT)) { inode_flags |= BTRFS_INODE_ROOT_ITEM_INIT; root_item->inode.flags = cpu_to_le64(inode_flags); root_item->flags = 0; root_item->byte_limit = 0; } } |