diff options
Diffstat (limited to 'fs/btrfs/root-tree.c')
| -rw-r--r-- | fs/btrfs/root-tree.c | 201 |
1 files changed, 80 insertions, 121 deletions
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 5bf1ed57f178..ffb1036ef10d 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c | |||
| @@ -64,52 +64,59 @@ void btrfs_read_root_item(struct extent_buffer *eb, int slot, | |||
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | /* | 66 | /* |
| 67 | * lookup the root with the highest offset for a given objectid. The key we do | 67 | * btrfs_find_root - lookup the root by the key. |
| 68 | * find is copied into 'key'. If we find something return 0, otherwise 1, < 0 | 68 | * root: the root of the root tree |
| 69 | * on error. | 69 | * search_key: the key to search |
| 70 | * path: the path we search | ||
| 71 | * root_item: the root item of the tree we look for | ||
| 72 | * root_key: the reak key of the tree we look for | ||
| 73 | * | ||
| 74 | * If ->offset of 'seach_key' is -1ULL, it means we are not sure the offset | ||
| 75 | * of the search key, just lookup the root with the highest offset for a | ||
| 76 | * given objectid. | ||
| 77 | * | ||
| 78 | * If we find something return 0, otherwise > 0, < 0 on error. | ||
| 70 | */ | 79 | */ |
| 71 | int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, | 80 | int btrfs_find_root(struct btrfs_root *root, struct btrfs_key *search_key, |
| 72 | struct btrfs_root_item *item, struct btrfs_key *key) | 81 | struct btrfs_path *path, struct btrfs_root_item *root_item, |
| 82 | struct btrfs_key *root_key) | ||
| 73 | { | 83 | { |
| 74 | struct btrfs_path *path; | ||
| 75 | struct btrfs_key search_key; | ||
| 76 | struct btrfs_key found_key; | 84 | struct btrfs_key found_key; |
| 77 | struct extent_buffer *l; | 85 | struct extent_buffer *l; |
| 78 | int ret; | 86 | int ret; |
| 79 | int slot; | 87 | int slot; |
| 80 | 88 | ||
| 81 | search_key.objectid = objectid; | 89 | ret = btrfs_search_slot(NULL, root, search_key, path, 0, 0); |
| 82 | search_key.type = BTRFS_ROOT_ITEM_KEY; | ||
| 83 | search_key.offset = (u64)-1; | ||
| 84 | |||
| 85 | path = btrfs_alloc_path(); | ||
| 86 | if (!path) | ||
| 87 | return -ENOMEM; | ||
| 88 | ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); | ||
| 89 | if (ret < 0) | 90 | if (ret < 0) |
| 90 | goto out; | 91 | return ret; |
| 91 | 92 | ||
| 92 | BUG_ON(ret == 0); | 93 | if (search_key->offset != -1ULL) { /* the search key is exact */ |
| 93 | if (path->slots[0] == 0) { | 94 | if (ret > 0) |
| 94 | ret = 1; | 95 | goto out; |
| 95 | goto out; | 96 | } else { |
| 97 | BUG_ON(ret == 0); /* Logical error */ | ||
| 98 | if (path->slots[0] == 0) | ||
| 99 | goto out; | ||
| 100 | path->slots[0]--; | ||
| 101 | ret = 0; | ||
| 96 | } | 102 | } |
| 103 | |||
| 97 | l = path->nodes[0]; | 104 | l = path->nodes[0]; |
| 98 | slot = path->slots[0] - 1; | 105 | slot = path->slots[0]; |
| 106 | |||
| 99 | btrfs_item_key_to_cpu(l, &found_key, slot); | 107 | btrfs_item_key_to_cpu(l, &found_key, slot); |
| 100 | if (found_key.objectid != objectid || | 108 | if (found_key.objectid != search_key->objectid || |
| 101 | found_key.type != BTRFS_ROOT_ITEM_KEY) { | 109 | found_key.type != BTRFS_ROOT_ITEM_KEY) { |
| 102 | ret = 1; | 110 | ret = 1; |
| 103 | goto out; | 111 | goto out; |
| 104 | } | 112 | } |
| 105 | if (item) | ||
| 106 | btrfs_read_root_item(l, slot, item); | ||
| 107 | if (key) | ||
| 108 | memcpy(key, &found_key, sizeof(found_key)); | ||
| 109 | 113 | ||
| 110 | ret = 0; | 114 | if (root_item) |
| 115 | btrfs_read_root_item(l, slot, root_item); | ||
| 116 | if (root_key) | ||
| 117 | memcpy(root_key, &found_key, sizeof(found_key)); | ||
| 111 | out: | 118 | out: |
| 112 | btrfs_free_path(path); | 119 | btrfs_release_path(path); |
| 113 | return ret; | 120 | return ret; |
| 114 | } | 121 | } |
| 115 | 122 | ||
| @@ -212,86 +219,6 @@ int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
| 212 | return btrfs_insert_item(trans, root, key, item, sizeof(*item)); | 219 | return btrfs_insert_item(trans, root, key, item, sizeof(*item)); |
| 213 | } | 220 | } |
| 214 | 221 | ||
| 215 | /* | ||
| 216 | * at mount time we want to find all the old transaction snapshots that were in | ||
| 217 | * the process of being deleted if we crashed. This is any root item with an | ||
| 218 | * offset lower than the latest root. They need to be queued for deletion to | ||
| 219 | * finish what was happening when we crashed. | ||
| 220 | */ | ||
| 221 | int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid) | ||
| 222 | { | ||
| 223 | struct btrfs_root *dead_root; | ||
| 224 | struct btrfs_root_item *ri; | ||
| 225 | struct btrfs_key key; | ||
| 226 | struct btrfs_key found_key; | ||
| 227 | struct btrfs_path *path; | ||
| 228 | int ret; | ||
| 229 | u32 nritems; | ||
| 230 | struct extent_buffer *leaf; | ||
| 231 | int slot; | ||
| 232 | |||
| 233 | key.objectid = objectid; | ||
| 234 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | ||
| 235 | key.offset = 0; | ||
| 236 | path = btrfs_alloc_path(); | ||
| 237 | if (!path) | ||
| 238 | return -ENOMEM; | ||
| 239 | |||
| 240 | again: | ||
| 241 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | ||
| 242 | if (ret < 0) | ||
| 243 | goto err; | ||
| 244 | while (1) { | ||
| 245 | leaf = path->nodes[0]; | ||
| 246 | nritems = btrfs_header_nritems(leaf); | ||
| 247 | slot = path->slots[0]; | ||
| 248 | if (slot >= nritems) { | ||
| 249 | ret = btrfs_next_leaf(root, path); | ||
| 250 | if (ret) | ||
| 251 | break; | ||
| 252 | leaf = path->nodes[0]; | ||
| 253 | nritems = btrfs_header_nritems(leaf); | ||
| 254 | slot = path->slots[0]; | ||
| 255 | } | ||
| 256 | btrfs_item_key_to_cpu(leaf, &key, slot); | ||
| 257 | if (btrfs_key_type(&key) != BTRFS_ROOT_ITEM_KEY) | ||
| 258 | goto next; | ||
| 259 | |||
| 260 | if (key.objectid < objectid) | ||
| 261 | goto next; | ||
| 262 | |||
| 263 | if (key.objectid > objectid) | ||
| 264 | break; | ||
| 265 | |||
| 266 | ri = btrfs_item_ptr(leaf, slot, struct btrfs_root_item); | ||
| 267 | if (btrfs_disk_root_refs(leaf, ri) != 0) | ||
| 268 | goto next; | ||
| 269 | |||
| 270 | memcpy(&found_key, &key, sizeof(key)); | ||
| 271 | key.offset++; | ||
| 272 | btrfs_release_path(path); | ||
| 273 | dead_root = | ||
| 274 | btrfs_read_fs_root_no_radix(root->fs_info->tree_root, | ||
| 275 | &found_key); | ||
| 276 | if (IS_ERR(dead_root)) { | ||
| 277 | ret = PTR_ERR(dead_root); | ||
| 278 | goto err; | ||
| 279 | } | ||
| 280 | |||
| 281 | ret = btrfs_add_dead_root(dead_root); | ||
| 282 | if (ret) | ||
| 283 | goto err; | ||
| 284 | goto again; | ||
| 285 | next: | ||
| 286 | slot++; | ||
| 287 | path->slots[0]++; | ||
| 288 | } | ||
| 289 | ret = 0; | ||
| 290 | err: | ||
| 291 | btrfs_free_path(path); | ||
| 292 | return ret; | ||
| 293 | } | ||
| 294 | |||
| 295 | int btrfs_find_orphan_roots(struct btrfs_root *tree_root) | 222 | int btrfs_find_orphan_roots(struct btrfs_root *tree_root) |
| 296 | { | 223 | { |
| 297 | struct extent_buffer *leaf; | 224 | struct extent_buffer *leaf; |
| @@ -301,6 +228,10 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root) | |||
| 301 | struct btrfs_root *root; | 228 | struct btrfs_root *root; |
| 302 | int err = 0; | 229 | int err = 0; |
| 303 | int ret; | 230 | int ret; |
| 231 | bool can_recover = true; | ||
| 232 | |||
| 233 | if (tree_root->fs_info->sb->s_flags & MS_RDONLY) | ||
| 234 | can_recover = false; | ||
| 304 | 235 | ||
| 305 | path = btrfs_alloc_path(); | 236 | path = btrfs_alloc_path(); |
| 306 | if (!path) | 237 | if (!path) |
| @@ -340,20 +271,52 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root) | |||
| 340 | root_key.objectid = key.offset; | 271 | root_key.objectid = key.offset; |
| 341 | key.offset++; | 272 | key.offset++; |
| 342 | 273 | ||
| 343 | root = btrfs_read_fs_root_no_name(tree_root->fs_info, | 274 | root = btrfs_read_fs_root(tree_root, &root_key); |
| 344 | &root_key); | 275 | err = PTR_RET(root); |
| 345 | if (!IS_ERR(root)) | 276 | if (err && err != -ENOENT) { |
| 277 | break; | ||
| 278 | } else if (err == -ENOENT) { | ||
| 279 | struct btrfs_trans_handle *trans; | ||
| 280 | |||
| 281 | btrfs_release_path(path); | ||
| 282 | |||
| 283 | trans = btrfs_join_transaction(tree_root); | ||
| 284 | if (IS_ERR(trans)) { | ||
| 285 | err = PTR_ERR(trans); | ||
| 286 | btrfs_error(tree_root->fs_info, err, | ||
| 287 | "Failed to start trans to delete " | ||
| 288 | "orphan item"); | ||
| 289 | break; | ||
| 290 | } | ||
| 291 | err = btrfs_del_orphan_item(trans, tree_root, | ||
| 292 | root_key.objectid); | ||
| 293 | btrfs_end_transaction(trans, tree_root); | ||
| 294 | if (err) { | ||
| 295 | btrfs_error(tree_root->fs_info, err, | ||
| 296 | "Failed to delete root orphan " | ||
| 297 | "item"); | ||
| 298 | break; | ||
| 299 | } | ||
| 346 | continue; | 300 | continue; |
| 301 | } | ||
| 347 | 302 | ||
| 348 | ret = PTR_ERR(root); | 303 | if (btrfs_root_refs(&root->root_item) == 0) { |
| 349 | if (ret != -ENOENT) { | 304 | btrfs_add_dead_root(root); |
| 350 | err = ret; | 305 | continue; |
| 306 | } | ||
| 307 | |||
| 308 | err = btrfs_init_fs_root(root); | ||
| 309 | if (err) { | ||
| 310 | btrfs_free_fs_root(root); | ||
| 351 | break; | 311 | break; |
| 352 | } | 312 | } |
| 353 | 313 | ||
| 354 | ret = btrfs_find_dead_roots(tree_root, root_key.objectid); | 314 | root->orphan_item_inserted = 1; |
| 355 | if (ret) { | 315 | |
| 356 | err = ret; | 316 | err = btrfs_insert_fs_root(root->fs_info, root); |
| 317 | if (err) { | ||
| 318 | BUG_ON(err == -EEXIST); | ||
| 319 | btrfs_free_fs_root(root); | ||
| 357 | break; | 320 | break; |
| 358 | } | 321 | } |
| 359 | } | 322 | } |
| @@ -368,8 +331,6 @@ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
| 368 | { | 331 | { |
| 369 | struct btrfs_path *path; | 332 | struct btrfs_path *path; |
| 370 | int ret; | 333 | int ret; |
| 371 | struct btrfs_root_item *ri; | ||
| 372 | struct extent_buffer *leaf; | ||
| 373 | 334 | ||
| 374 | path = btrfs_alloc_path(); | 335 | path = btrfs_alloc_path(); |
| 375 | if (!path) | 336 | if (!path) |
| @@ -379,8 +340,6 @@ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
| 379 | goto out; | 340 | goto out; |
| 380 | 341 | ||
| 381 | BUG_ON(ret != 0); | 342 | BUG_ON(ret != 0); |
| 382 | leaf = path->nodes[0]; | ||
| 383 | ri = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_item); | ||
| 384 | 343 | ||
| 385 | ret = btrfs_del_item(trans, root, path); | 344 | ret = btrfs_del_item(trans, root, path); |
| 386 | out: | 345 | out: |
