aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2013-02-28 05:04:33 -0500
committerJosef Bacik <jbacik@fusionio.com>2013-02-28 13:33:54 -0500
commitd5c1207017cd8387b4d3224dd7ab6cf5cd7f1c9a (patch)
tree7208d1c89aa625fa6eb349fdafa2e49a00bbe078 /fs
parente9662f701c85ebc99f532bf8bb53208c0648846a (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.h9
-rw-r--r--fs/btrfs/extent-tree.c65
-rw-r--r--fs/btrfs/ioctl.c62
-rw-r--r--fs/btrfs/transaction.c4
-rw-r--r--fs/btrfs/transaction.h1
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,
3106int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans, 3106int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
3107 struct inode *inode); 3107 struct inode *inode);
3108void btrfs_orphan_release_metadata(struct inode *inode); 3108void btrfs_orphan_release_metadata(struct inode *inode);
3109int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans, 3109int 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);
3113void btrfs_subvolume_release_metadata(struct btrfs_root *root,
3114 struct btrfs_block_rsv *rsv,
3115 u64 qgroup_reserved);
3111int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes); 3116int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes);
3112void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes); 3117void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes);
3113int btrfs_delalloc_reserve_space(struct inode *inode, u64 num_bytes); 3118int 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
4563int 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 */
4577int 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
4610void 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
366static noinline int create_subvol(struct btrfs_root *root, 366static 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
517fail: 524fail:
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 538out:
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;
602fail: 622fail:
623 btrfs_subvolume_release_metadata(BTRFS_I(dir)->root,
624 &pending_snapshot->block_rsv,
625 pending_snapshot->qgroup_reserved);
626out:
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);
1280root_item_alloc_fail: 1280root_item_alloc_fail:
1281 btrfs_free_path(path); 1281 btrfs_free_path(path);
1282path_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;