diff options
author | Miao Xie <miaox@cn.fujitsu.com> | 2013-02-28 05:04:33 -0500 |
---|---|---|
committer | Josef Bacik <jbacik@fusionio.com> | 2013-02-28 13:33:54 -0500 |
commit | d5c1207017cd8387b4d3224dd7ab6cf5cd7f1c9a (patch) | |
tree | 7208d1c89aa625fa6eb349fdafa2e49a00bbe078 /fs | |
parent | e9662f701c85ebc99f532bf8bb53208c0648846a (diff) |
Btrfs: fix wrong reserved space in qgroup during snap/subv creation
There are two problems in the space reservation of the snapshot/
subvolume creation.
- don't reserve the space for the root item insertion
- the space which is reserved in the qgroup is different with
the free space reservation. we need reserve free space for
7 items, but in qgroup reservation, we need reserve space only
for 3 items.
So we implement new metadata reservation functions for the
snapshot/subvolume creation.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.h | 9 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 65 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 62 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 4 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 1 |
5 files changed, 105 insertions, 36 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index ae8dcc406805..0d82922179db 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -3106,8 +3106,13 @@ void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans, | |||
3106 | int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans, | 3106 | int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans, |
3107 | struct inode *inode); | 3107 | struct inode *inode); |
3108 | void btrfs_orphan_release_metadata(struct inode *inode); | 3108 | void btrfs_orphan_release_metadata(struct inode *inode); |
3109 | int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans, | 3109 | int btrfs_subvolume_reserve_metadata(struct btrfs_root *root, |
3110 | struct btrfs_pending_snapshot *pending); | 3110 | struct btrfs_block_rsv *rsv, |
3111 | int nitems, | ||
3112 | u64 *qgroup_reserved); | ||
3113 | void btrfs_subvolume_release_metadata(struct btrfs_root *root, | ||
3114 | struct btrfs_block_rsv *rsv, | ||
3115 | u64 qgroup_reserved); | ||
3111 | int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes); | 3116 | int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes); |
3112 | void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes); | 3117 | void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes); |
3113 | int btrfs_delalloc_reserve_space(struct inode *inode, u64 num_bytes); | 3118 | int btrfs_delalloc_reserve_space(struct inode *inode, u64 num_bytes); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 5681a91ed400..7cb9d734f6e5 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -4560,19 +4560,60 @@ void btrfs_orphan_release_metadata(struct inode *inode) | |||
4560 | btrfs_block_rsv_release(root, root->orphan_block_rsv, num_bytes); | 4560 | btrfs_block_rsv_release(root, root->orphan_block_rsv, num_bytes); |
4561 | } | 4561 | } |
4562 | 4562 | ||
4563 | int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans, | 4563 | /* |
4564 | struct btrfs_pending_snapshot *pending) | 4564 | * btrfs_subvolume_reserve_metadata() - reserve space for subvolume operation |
4565 | * root: the root of the parent directory | ||
4566 | * rsv: block reservation | ||
4567 | * items: the number of items that we need do reservation | ||
4568 | * qgroup_reserved: used to return the reserved size in qgroup | ||
4569 | * | ||
4570 | * This function is used to reserve the space for snapshot/subvolume | ||
4571 | * creation and deletion. Those operations are different with the | ||
4572 | * common file/directory operations, they change two fs/file trees | ||
4573 | * and root tree, the number of items that the qgroup reserves is | ||
4574 | * different with the free space reservation. So we can not use | ||
4575 | * the space reseravtion mechanism in start_transaction(). | ||
4576 | */ | ||
4577 | int btrfs_subvolume_reserve_metadata(struct btrfs_root *root, | ||
4578 | struct btrfs_block_rsv *rsv, | ||
4579 | int items, | ||
4580 | u64 *qgroup_reserved) | ||
4565 | { | 4581 | { |
4566 | struct btrfs_root *root = pending->root; | 4582 | u64 num_bytes; |
4567 | struct btrfs_block_rsv *src_rsv = get_block_rsv(trans, root); | 4583 | int ret; |
4568 | struct btrfs_block_rsv *dst_rsv = &pending->block_rsv; | 4584 | |
4569 | /* | 4585 | if (root->fs_info->quota_enabled) { |
4570 | * two for root back/forward refs, two for directory entries, | 4586 | /* One for parent inode, two for dir entries */ |
4571 | * one for root of the snapshot and one for parent inode. | 4587 | num_bytes = 3 * root->leafsize; |
4572 | */ | 4588 | ret = btrfs_qgroup_reserve(root, num_bytes); |
4573 | u64 num_bytes = btrfs_calc_trans_metadata_size(root, 6); | 4589 | if (ret) |
4574 | dst_rsv->space_info = src_rsv->space_info; | 4590 | return ret; |
4575 | return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes); | 4591 | } else { |
4592 | num_bytes = 0; | ||
4593 | } | ||
4594 | |||
4595 | *qgroup_reserved = num_bytes; | ||
4596 | |||
4597 | num_bytes = btrfs_calc_trans_metadata_size(root, items); | ||
4598 | rsv->space_info = __find_space_info(root->fs_info, | ||
4599 | BTRFS_BLOCK_GROUP_METADATA); | ||
4600 | ret = btrfs_block_rsv_add(root, rsv, num_bytes, | ||
4601 | BTRFS_RESERVE_FLUSH_ALL); | ||
4602 | if (ret) { | ||
4603 | if (*qgroup_reserved) | ||
4604 | btrfs_qgroup_free(root, *qgroup_reserved); | ||
4605 | } | ||
4606 | |||
4607 | return ret; | ||
4608 | } | ||
4609 | |||
4610 | void btrfs_subvolume_release_metadata(struct btrfs_root *root, | ||
4611 | struct btrfs_block_rsv *rsv, | ||
4612 | u64 qgroup_reserved) | ||
4613 | { | ||
4614 | btrfs_block_rsv_release(root, rsv, (u64)-1); | ||
4615 | if (qgroup_reserved) | ||
4616 | btrfs_qgroup_free(root, qgroup_reserved); | ||
4576 | } | 4617 | } |
4577 | 4618 | ||
4578 | /** | 4619 | /** |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 8dcd4ff0c3a5..56d92549389c 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -363,7 +363,7 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) | |||
363 | return 0; | 363 | return 0; |
364 | } | 364 | } |
365 | 365 | ||
366 | static noinline int create_subvol(struct btrfs_root *root, | 366 | static noinline int create_subvol(struct inode *dir, |
367 | struct dentry *dentry, | 367 | struct dentry *dentry, |
368 | char *name, int namelen, | 368 | char *name, int namelen, |
369 | u64 *async_transid, | 369 | u64 *async_transid, |
@@ -374,32 +374,39 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
374 | struct btrfs_root_item root_item; | 374 | struct btrfs_root_item root_item; |
375 | struct btrfs_inode_item *inode_item; | 375 | struct btrfs_inode_item *inode_item; |
376 | struct extent_buffer *leaf; | 376 | struct extent_buffer *leaf; |
377 | struct btrfs_root *root = BTRFS_I(dir)->root; | ||
377 | struct btrfs_root *new_root; | 378 | struct btrfs_root *new_root; |
378 | struct dentry *parent = dentry->d_parent; | 379 | struct btrfs_block_rsv block_rsv; |
379 | struct inode *dir; | ||
380 | struct timespec cur_time = CURRENT_TIME; | 380 | struct timespec cur_time = CURRENT_TIME; |
381 | int ret; | 381 | int ret; |
382 | int err; | 382 | int err; |
383 | u64 objectid; | 383 | u64 objectid; |
384 | u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; | 384 | u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; |
385 | u64 index = 0; | 385 | u64 index = 0; |
386 | u64 qgroup_reserved; | ||
386 | uuid_le new_uuid; | 387 | uuid_le new_uuid; |
387 | 388 | ||
388 | ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid); | 389 | ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid); |
389 | if (ret) | 390 | if (ret) |
390 | return ret; | 391 | return ret; |
391 | 392 | ||
392 | dir = parent->d_inode; | 393 | btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP); |
393 | |||
394 | /* | 394 | /* |
395 | * 1 - inode item | 395 | * The same as the snapshot creation, please see the comment |
396 | * 2 - refs | 396 | * of create_snapshot(). |
397 | * 1 - root item | ||
398 | * 2 - dir items | ||
399 | */ | 397 | */ |
400 | trans = btrfs_start_transaction(root, 6); | 398 | ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, |
401 | if (IS_ERR(trans)) | 399 | 7, &qgroup_reserved); |
402 | return PTR_ERR(trans); | 400 | if (ret) |
401 | return ret; | ||
402 | |||
403 | trans = btrfs_start_transaction(root, 0); | ||
404 | if (IS_ERR(trans)) { | ||
405 | ret = PTR_ERR(trans); | ||
406 | goto out; | ||
407 | } | ||
408 | trans->block_rsv = &block_rsv; | ||
409 | trans->bytes_reserved = block_rsv.size; | ||
403 | 410 | ||
404 | ret = btrfs_qgroup_inherit(trans, root->fs_info, 0, objectid, inherit); | 411 | ret = btrfs_qgroup_inherit(trans, root->fs_info, 0, objectid, inherit); |
405 | if (ret) | 412 | if (ret) |
@@ -515,6 +522,8 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
515 | BUG_ON(ret); | 522 | BUG_ON(ret); |
516 | 523 | ||
517 | fail: | 524 | fail: |
525 | trans->block_rsv = NULL; | ||
526 | trans->bytes_reserved = 0; | ||
518 | if (async_transid) { | 527 | if (async_transid) { |
519 | *async_transid = trans->transid; | 528 | *async_transid = trans->transid; |
520 | err = btrfs_commit_transaction_async(trans, root, 1); | 529 | err = btrfs_commit_transaction_async(trans, root, 1); |
@@ -526,7 +535,8 @@ fail: | |||
526 | 535 | ||
527 | if (!ret) | 536 | if (!ret) |
528 | d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); | 537 | d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); |
529 | 538 | out: | |
539 | btrfs_subvolume_release_metadata(root, &block_rsv, qgroup_reserved); | ||
530 | return ret; | 540 | return ret; |
531 | } | 541 | } |
532 | 542 | ||
@@ -549,21 +559,31 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, | |||
549 | 559 | ||
550 | btrfs_init_block_rsv(&pending_snapshot->block_rsv, | 560 | btrfs_init_block_rsv(&pending_snapshot->block_rsv, |
551 | BTRFS_BLOCK_RSV_TEMP); | 561 | BTRFS_BLOCK_RSV_TEMP); |
562 | /* | ||
563 | * 1 - parent dir inode | ||
564 | * 2 - dir entries | ||
565 | * 1 - root item | ||
566 | * 2 - root ref/backref | ||
567 | * 1 - root of snapshot | ||
568 | */ | ||
569 | ret = btrfs_subvolume_reserve_metadata(BTRFS_I(dir)->root, | ||
570 | &pending_snapshot->block_rsv, 7, | ||
571 | &pending_snapshot->qgroup_reserved); | ||
572 | if (ret) | ||
573 | goto out; | ||
574 | |||
552 | pending_snapshot->dentry = dentry; | 575 | pending_snapshot->dentry = dentry; |
553 | pending_snapshot->root = root; | 576 | pending_snapshot->root = root; |
554 | pending_snapshot->readonly = readonly; | 577 | pending_snapshot->readonly = readonly; |
555 | pending_snapshot->dir = dir; | 578 | pending_snapshot->dir = dir; |
556 | pending_snapshot->inherit = inherit; | 579 | pending_snapshot->inherit = inherit; |
557 | 580 | ||
558 | trans = btrfs_start_transaction(root->fs_info->extent_root, 6); | 581 | trans = btrfs_start_transaction(root, 0); |
559 | if (IS_ERR(trans)) { | 582 | if (IS_ERR(trans)) { |
560 | ret = PTR_ERR(trans); | 583 | ret = PTR_ERR(trans); |
561 | goto fail; | 584 | goto fail; |
562 | } | 585 | } |
563 | 586 | ||
564 | ret = btrfs_snap_reserve_metadata(trans, pending_snapshot); | ||
565 | BUG_ON(ret); | ||
566 | |||
567 | spin_lock(&root->fs_info->trans_lock); | 587 | spin_lock(&root->fs_info->trans_lock); |
568 | list_add(&pending_snapshot->list, | 588 | list_add(&pending_snapshot->list, |
569 | &trans->transaction->pending_snapshots); | 589 | &trans->transaction->pending_snapshots); |
@@ -600,6 +620,10 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, | |||
600 | d_instantiate(dentry, inode); | 620 | d_instantiate(dentry, inode); |
601 | ret = 0; | 621 | ret = 0; |
602 | fail: | 622 | fail: |
623 | btrfs_subvolume_release_metadata(BTRFS_I(dir)->root, | ||
624 | &pending_snapshot->block_rsv, | ||
625 | pending_snapshot->qgroup_reserved); | ||
626 | out: | ||
603 | kfree(pending_snapshot); | 627 | kfree(pending_snapshot); |
604 | return ret; | 628 | return ret; |
605 | } | 629 | } |
@@ -733,8 +757,8 @@ static noinline int btrfs_mksubvol(struct path *parent, | |||
733 | error = create_snapshot(snap_src, dir, dentry, name, namelen, | 757 | error = create_snapshot(snap_src, dir, dentry, name, namelen, |
734 | async_transid, readonly, inherit); | 758 | async_transid, readonly, inherit); |
735 | } else { | 759 | } else { |
736 | error = create_subvol(BTRFS_I(dir)->root, dentry, | 760 | error = create_subvol(dir, dentry, name, namelen, |
737 | name, namelen, async_transid, inherit); | 761 | async_transid, inherit); |
738 | } | 762 | } |
739 | if (!error) | 763 | if (!error) |
740 | fsnotify_mkdir(dir, dentry); | 764 | fsnotify_mkdir(dir, dentry); |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 71de435a291e..f11c2e0a3746 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -1082,7 +1082,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1082 | path = btrfs_alloc_path(); | 1082 | path = btrfs_alloc_path(); |
1083 | if (!path) { | 1083 | if (!path) { |
1084 | ret = pending->error = -ENOMEM; | 1084 | ret = pending->error = -ENOMEM; |
1085 | goto path_alloc_fail; | 1085 | return ret; |
1086 | } | 1086 | } |
1087 | 1087 | ||
1088 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); | 1088 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); |
@@ -1279,8 +1279,6 @@ no_free_objectid: | |||
1279 | kfree(new_root_item); | 1279 | kfree(new_root_item); |
1280 | root_item_alloc_fail: | 1280 | root_item_alloc_fail: |
1281 | btrfs_free_path(path); | 1281 | btrfs_free_path(path); |
1282 | path_alloc_fail: | ||
1283 | btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1); | ||
1284 | return ret; | 1282 | return ret; |
1285 | } | 1283 | } |
1286 | 1284 | ||
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 5f67fba07ab4..3c8e0d25c8e4 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -90,6 +90,7 @@ struct btrfs_pending_snapshot { | |||
90 | struct btrfs_qgroup_inherit *inherit; | 90 | struct btrfs_qgroup_inherit *inherit; |
91 | /* block reservation for the operation */ | 91 | /* block reservation for the operation */ |
92 | struct btrfs_block_rsv block_rsv; | 92 | struct btrfs_block_rsv block_rsv; |
93 | u64 qgroup_reserved; | ||
93 | /* extra metadata reseration for relocation */ | 94 | /* extra metadata reseration for relocation */ |
94 | int error; | 95 | int error; |
95 | bool readonly; | 96 | bool readonly; |