diff options
Diffstat (limited to 'fs/btrfs/root-tree.c')
-rw-r--r-- | fs/btrfs/root-tree.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 22124122728c..47733fb55df7 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c | |||
@@ -9,6 +9,8 @@ | |||
9 | #include "transaction.h" | 9 | #include "transaction.h" |
10 | #include "disk-io.h" | 10 | #include "disk-io.h" |
11 | #include "print-tree.h" | 11 | #include "print-tree.h" |
12 | #include "qgroup.h" | ||
13 | #include "space-info.h" | ||
12 | 14 | ||
13 | /* | 15 | /* |
14 | * Read a root item from the tree. In case we detect a root item smaller then | 16 | * Read a root item from the tree. In case we detect a root item smaller then |
@@ -497,3 +499,57 @@ void btrfs_update_root_times(struct btrfs_trans_handle *trans, | |||
497 | btrfs_set_stack_timespec_nsec(&item->ctime, ct.tv_nsec); | 499 | btrfs_set_stack_timespec_nsec(&item->ctime, ct.tv_nsec); |
498 | spin_unlock(&root->root_item_lock); | 500 | spin_unlock(&root->root_item_lock); |
499 | } | 501 | } |
502 | |||
503 | /* | ||
504 | * btrfs_subvolume_reserve_metadata() - reserve space for subvolume operation | ||
505 | * root: the root of the parent directory | ||
506 | * rsv: block reservation | ||
507 | * items: the number of items that we need do reservation | ||
508 | * use_global_rsv: allow fallback to the global block reservation | ||
509 | * | ||
510 | * This function is used to reserve the space for snapshot/subvolume | ||
511 | * creation and deletion. Those operations are different with the | ||
512 | * common file/directory operations, they change two fs/file trees | ||
513 | * and root tree, the number of items that the qgroup reserves is | ||
514 | * different with the free space reservation. So we can not use | ||
515 | * the space reservation mechanism in start_transaction(). | ||
516 | */ | ||
517 | int btrfs_subvolume_reserve_metadata(struct btrfs_root *root, | ||
518 | struct btrfs_block_rsv *rsv, int items, | ||
519 | bool use_global_rsv) | ||
520 | { | ||
521 | u64 qgroup_num_bytes = 0; | ||
522 | u64 num_bytes; | ||
523 | int ret; | ||
524 | struct btrfs_fs_info *fs_info = root->fs_info; | ||
525 | struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv; | ||
526 | |||
527 | if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) { | ||
528 | /* One for parent inode, two for dir entries */ | ||
529 | qgroup_num_bytes = 3 * fs_info->nodesize; | ||
530 | ret = btrfs_qgroup_reserve_meta_prealloc(root, | ||
531 | qgroup_num_bytes, true); | ||
532 | if (ret) | ||
533 | return ret; | ||
534 | } | ||
535 | |||
536 | num_bytes = btrfs_calc_trans_metadata_size(fs_info, items); | ||
537 | rsv->space_info = btrfs_find_space_info(fs_info, | ||
538 | BTRFS_BLOCK_GROUP_METADATA); | ||
539 | ret = btrfs_block_rsv_add(root, rsv, num_bytes, | ||
540 | BTRFS_RESERVE_FLUSH_ALL); | ||
541 | |||
542 | if (ret == -ENOSPC && use_global_rsv) | ||
543 | ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes, true); | ||
544 | |||
545 | if (ret && qgroup_num_bytes) | ||
546 | btrfs_qgroup_free_meta_prealloc(root, qgroup_num_bytes); | ||
547 | |||
548 | return ret; | ||
549 | } | ||
550 | |||
551 | void btrfs_subvolume_release_metadata(struct btrfs_fs_info *fs_info, | ||
552 | struct btrfs_block_rsv *rsv) | ||
553 | { | ||
554 | btrfs_block_rsv_release(fs_info, rsv, (u64)-1); | ||
555 | } | ||