.. | .. |
---|
9 | 9 | #include "transaction.h" |
---|
10 | 10 | #include "disk-io.h" |
---|
11 | 11 | #include "print-tree.h" |
---|
| 12 | +#include "qgroup.h" |
---|
| 13 | +#include "space-info.h" |
---|
12 | 14 | |
---|
13 | 15 | /* |
---|
14 | 16 | * Read a root item from the tree. In case we detect a root item smaller then |
---|
.. | .. |
---|
20 | 22 | static void btrfs_read_root_item(struct extent_buffer *eb, int slot, |
---|
21 | 23 | struct btrfs_root_item *item) |
---|
22 | 24 | { |
---|
23 | | - uuid_le uuid; |
---|
24 | | - int len; |
---|
| 25 | + u32 len; |
---|
25 | 26 | int need_reset = 0; |
---|
26 | 27 | |
---|
27 | 28 | len = btrfs_item_size_nr(eb, slot); |
---|
28 | 29 | read_extent_buffer(eb, item, btrfs_item_ptr_offset(eb, slot), |
---|
29 | | - min_t(int, len, (int)sizeof(*item))); |
---|
| 30 | + min_t(u32, len, sizeof(*item))); |
---|
30 | 31 | if (len < sizeof(*item)) |
---|
31 | 32 | need_reset = 1; |
---|
32 | 33 | if (!need_reset && btrfs_root_generation(item) |
---|
.. | .. |
---|
42 | 43 | sizeof(*item) - offsetof(struct btrfs_root_item, |
---|
43 | 44 | generation_v2)); |
---|
44 | 45 | |
---|
45 | | - uuid_le_gen(&uuid); |
---|
46 | | - memcpy(item->uuid, uuid.b, BTRFS_UUID_SIZE); |
---|
| 46 | + generate_random_guid(item->uuid); |
---|
47 | 47 | } |
---|
48 | 48 | } |
---|
49 | 49 | |
---|
.. | .. |
---|
210 | 210 | struct extent_buffer *leaf; |
---|
211 | 211 | struct btrfs_path *path; |
---|
212 | 212 | struct btrfs_key key; |
---|
213 | | - struct btrfs_key root_key; |
---|
214 | 213 | struct btrfs_root *root; |
---|
215 | 214 | int err = 0; |
---|
216 | 215 | int ret; |
---|
.. | .. |
---|
223 | 222 | key.type = BTRFS_ORPHAN_ITEM_KEY; |
---|
224 | 223 | key.offset = 0; |
---|
225 | 224 | |
---|
226 | | - root_key.type = BTRFS_ROOT_ITEM_KEY; |
---|
227 | | - root_key.offset = (u64)-1; |
---|
228 | | - |
---|
229 | 225 | while (1) { |
---|
| 226 | + u64 root_objectid; |
---|
| 227 | + |
---|
230 | 228 | ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0); |
---|
231 | 229 | if (ret < 0) { |
---|
232 | 230 | err = ret; |
---|
.. | .. |
---|
250 | 248 | key.type != BTRFS_ORPHAN_ITEM_KEY) |
---|
251 | 249 | break; |
---|
252 | 250 | |
---|
253 | | - root_key.objectid = key.offset; |
---|
| 251 | + root_objectid = key.offset; |
---|
254 | 252 | key.offset++; |
---|
255 | 253 | |
---|
256 | | - /* |
---|
257 | | - * The root might have been inserted already, as before we look |
---|
258 | | - * for orphan roots, log replay might have happened, which |
---|
259 | | - * triggers a transaction commit and qgroup accounting, which |
---|
260 | | - * in turn reads and inserts fs roots while doing backref |
---|
261 | | - * walking. |
---|
262 | | - */ |
---|
263 | | - root = btrfs_lookup_fs_root(fs_info, root_key.objectid); |
---|
264 | | - if (root) { |
---|
265 | | - WARN_ON(!test_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, |
---|
266 | | - &root->state)); |
---|
267 | | - if (btrfs_root_refs(&root->root_item) == 0) |
---|
268 | | - btrfs_add_dead_root(root); |
---|
269 | | - continue; |
---|
270 | | - } |
---|
271 | | - |
---|
272 | | - root = btrfs_read_fs_root(tree_root, &root_key); |
---|
| 254 | + root = btrfs_get_fs_root(fs_info, root_objectid, false); |
---|
273 | 255 | err = PTR_ERR_OR_ZERO(root); |
---|
274 | 256 | if (err && err != -ENOENT) { |
---|
275 | 257 | break; |
---|
.. | .. |
---|
286 | 268 | break; |
---|
287 | 269 | } |
---|
288 | 270 | err = btrfs_del_orphan_item(trans, tree_root, |
---|
289 | | - root_key.objectid); |
---|
| 271 | + root_objectid); |
---|
290 | 272 | btrfs_end_transaction(trans); |
---|
291 | 273 | if (err) { |
---|
292 | 274 | btrfs_handle_fs_error(fs_info, err, |
---|
.. | .. |
---|
296 | 278 | continue; |
---|
297 | 279 | } |
---|
298 | 280 | |
---|
299 | | - err = btrfs_init_fs_root(root); |
---|
300 | | - if (err) { |
---|
301 | | - btrfs_free_fs_root(root); |
---|
302 | | - break; |
---|
303 | | - } |
---|
304 | | - |
---|
305 | | - set_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &root->state); |
---|
306 | | - |
---|
307 | | - err = btrfs_insert_fs_root(fs_info, root); |
---|
308 | | - if (err) { |
---|
309 | | - BUG_ON(err == -EEXIST); |
---|
310 | | - btrfs_free_fs_root(root); |
---|
311 | | - break; |
---|
312 | | - } |
---|
313 | | - |
---|
314 | | - if (btrfs_root_refs(&root->root_item) == 0) |
---|
| 281 | + WARN_ON(!test_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &root->state)); |
---|
| 282 | + if (btrfs_root_refs(&root->root_item) == 0) { |
---|
| 283 | + set_bit(BTRFS_ROOT_DEAD_TREE, &root->state); |
---|
315 | 284 | btrfs_add_dead_root(root); |
---|
| 285 | + } |
---|
| 286 | + btrfs_put_root(root); |
---|
316 | 287 | } |
---|
317 | 288 | |
---|
318 | 289 | btrfs_free_path(path); |
---|
.. | .. |
---|
365 | 336 | key.offset = ref_id; |
---|
366 | 337 | again: |
---|
367 | 338 | ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1); |
---|
368 | | - BUG_ON(ret < 0); |
---|
369 | | - if (ret == 0) { |
---|
| 339 | + if (ret < 0) { |
---|
| 340 | + err = ret; |
---|
| 341 | + goto out; |
---|
| 342 | + } else if (ret == 0) { |
---|
370 | 343 | leaf = path->nodes[0]; |
---|
371 | 344 | ref = btrfs_item_ptr(leaf, path->slots[0], |
---|
372 | 345 | struct btrfs_root_ref); |
---|
.. | .. |
---|
495 | 468 | btrfs_set_stack_timespec_nsec(&item->ctime, ct.tv_nsec); |
---|
496 | 469 | spin_unlock(&root->root_item_lock); |
---|
497 | 470 | } |
---|
| 471 | + |
---|
| 472 | +/* |
---|
| 473 | + * btrfs_subvolume_reserve_metadata() - reserve space for subvolume operation |
---|
| 474 | + * root: the root of the parent directory |
---|
| 475 | + * rsv: block reservation |
---|
| 476 | + * items: the number of items that we need do reservation |
---|
| 477 | + * use_global_rsv: allow fallback to the global block reservation |
---|
| 478 | + * |
---|
| 479 | + * This function is used to reserve the space for snapshot/subvolume |
---|
| 480 | + * creation and deletion. Those operations are different with the |
---|
| 481 | + * common file/directory operations, they change two fs/file trees |
---|
| 482 | + * and root tree, the number of items that the qgroup reserves is |
---|
| 483 | + * different with the free space reservation. So we can not use |
---|
| 484 | + * the space reservation mechanism in start_transaction(). |
---|
| 485 | + */ |
---|
| 486 | +int btrfs_subvolume_reserve_metadata(struct btrfs_root *root, |
---|
| 487 | + struct btrfs_block_rsv *rsv, int items, |
---|
| 488 | + bool use_global_rsv) |
---|
| 489 | +{ |
---|
| 490 | + u64 qgroup_num_bytes = 0; |
---|
| 491 | + u64 num_bytes; |
---|
| 492 | + int ret; |
---|
| 493 | + struct btrfs_fs_info *fs_info = root->fs_info; |
---|
| 494 | + struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv; |
---|
| 495 | + |
---|
| 496 | + if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) { |
---|
| 497 | + /* One for parent inode, two for dir entries */ |
---|
| 498 | + qgroup_num_bytes = 3 * fs_info->nodesize; |
---|
| 499 | + ret = btrfs_qgroup_reserve_meta_prealloc(root, |
---|
| 500 | + qgroup_num_bytes, true); |
---|
| 501 | + if (ret) |
---|
| 502 | + return ret; |
---|
| 503 | + } |
---|
| 504 | + |
---|
| 505 | + num_bytes = btrfs_calc_insert_metadata_size(fs_info, items); |
---|
| 506 | + rsv->space_info = btrfs_find_space_info(fs_info, |
---|
| 507 | + BTRFS_BLOCK_GROUP_METADATA); |
---|
| 508 | + ret = btrfs_block_rsv_add(root, rsv, num_bytes, |
---|
| 509 | + BTRFS_RESERVE_FLUSH_ALL); |
---|
| 510 | + |
---|
| 511 | + if (ret == -ENOSPC && use_global_rsv) |
---|
| 512 | + ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes, true); |
---|
| 513 | + |
---|
| 514 | + if (ret && qgroup_num_bytes) |
---|
| 515 | + btrfs_qgroup_free_meta_prealloc(root, qgroup_num_bytes); |
---|
| 516 | + |
---|
| 517 | + if (!ret) { |
---|
| 518 | + spin_lock(&rsv->lock); |
---|
| 519 | + rsv->qgroup_rsv_reserved += qgroup_num_bytes; |
---|
| 520 | + spin_unlock(&rsv->lock); |
---|
| 521 | + } |
---|
| 522 | + return ret; |
---|
| 523 | +} |
---|
| 524 | + |
---|
| 525 | +void btrfs_subvolume_release_metadata(struct btrfs_root *root, |
---|
| 526 | + struct btrfs_block_rsv *rsv) |
---|
| 527 | +{ |
---|
| 528 | + struct btrfs_fs_info *fs_info = root->fs_info; |
---|
| 529 | + u64 qgroup_to_release; |
---|
| 530 | + |
---|
| 531 | + btrfs_block_rsv_release(fs_info, rsv, (u64)-1, &qgroup_to_release); |
---|
| 532 | + btrfs_qgroup_convert_reserved_meta(root, qgroup_to_release); |
---|
| 533 | +} |
---|