diff options
author | Yan, Zheng <zheng.yan@oracle.com> | 2009-09-21 16:00:26 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-09-21 16:00:26 -0400 |
commit | 76dda93c6ae2c1dc3e6cde34569d6aca26b0c918 (patch) | |
tree | f5ca46ec89d4ae2c762952d5f35e2c6f95ac046a /fs/btrfs/inode.c | |
parent | 4df27c4d5cc1dda54ed7d0a8389347f2df359cf9 (diff) |
Btrfs: add snapshot/subvolume destroy ioctl
This patch adds snapshot/subvolume destroy ioctl. A subvolume that isn't being
used and doesn't contains links to other subvolumes can be destroyed.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 134 |
1 files changed, 127 insertions, 7 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6036b36789cc..db9cbd91eb4c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -3089,6 +3089,11 @@ void btrfs_delete_inode(struct inode *inode) | |||
3089 | } | 3089 | } |
3090 | btrfs_wait_ordered_range(inode, 0, (u64)-1); | 3090 | btrfs_wait_ordered_range(inode, 0, (u64)-1); |
3091 | 3091 | ||
3092 | if (inode->i_nlink > 0) { | ||
3093 | BUG_ON(btrfs_root_refs(&root->root_item) != 0); | ||
3094 | goto no_delete; | ||
3095 | } | ||
3096 | |||
3092 | btrfs_i_size_write(inode, 0); | 3097 | btrfs_i_size_write(inode, 0); |
3093 | trans = btrfs_join_transaction(root, 1); | 3098 | trans = btrfs_join_transaction(root, 1); |
3094 | 3099 | ||
@@ -3225,11 +3230,13 @@ static void inode_tree_add(struct inode *inode) | |||
3225 | struct btrfs_inode *entry; | 3230 | struct btrfs_inode *entry; |
3226 | struct rb_node **p; | 3231 | struct rb_node **p; |
3227 | struct rb_node *parent; | 3232 | struct rb_node *parent; |
3228 | |||
3229 | again: | 3233 | again: |
3230 | p = &root->inode_tree.rb_node; | 3234 | p = &root->inode_tree.rb_node; |
3231 | parent = NULL; | 3235 | parent = NULL; |
3232 | 3236 | ||
3237 | if (hlist_unhashed(&inode->i_hash)) | ||
3238 | return; | ||
3239 | |||
3233 | spin_lock(&root->inode_lock); | 3240 | spin_lock(&root->inode_lock); |
3234 | while (*p) { | 3241 | while (*p) { |
3235 | parent = *p; | 3242 | parent = *p; |
@@ -3256,13 +3263,87 @@ again: | |||
3256 | static void inode_tree_del(struct inode *inode) | 3263 | static void inode_tree_del(struct inode *inode) |
3257 | { | 3264 | { |
3258 | struct btrfs_root *root = BTRFS_I(inode)->root; | 3265 | struct btrfs_root *root = BTRFS_I(inode)->root; |
3266 | int empty = 0; | ||
3259 | 3267 | ||
3260 | spin_lock(&root->inode_lock); | 3268 | spin_lock(&root->inode_lock); |
3261 | if (!RB_EMPTY_NODE(&BTRFS_I(inode)->rb_node)) { | 3269 | if (!RB_EMPTY_NODE(&BTRFS_I(inode)->rb_node)) { |
3262 | rb_erase(&BTRFS_I(inode)->rb_node, &root->inode_tree); | 3270 | rb_erase(&BTRFS_I(inode)->rb_node, &root->inode_tree); |
3263 | RB_CLEAR_NODE(&BTRFS_I(inode)->rb_node); | 3271 | RB_CLEAR_NODE(&BTRFS_I(inode)->rb_node); |
3272 | empty = RB_EMPTY_ROOT(&root->inode_tree); | ||
3264 | } | 3273 | } |
3265 | spin_unlock(&root->inode_lock); | 3274 | spin_unlock(&root->inode_lock); |
3275 | |||
3276 | if (empty && btrfs_root_refs(&root->root_item) == 0) { | ||
3277 | synchronize_srcu(&root->fs_info->subvol_srcu); | ||
3278 | spin_lock(&root->inode_lock); | ||
3279 | empty = RB_EMPTY_ROOT(&root->inode_tree); | ||
3280 | spin_unlock(&root->inode_lock); | ||
3281 | if (empty) | ||
3282 | btrfs_add_dead_root(root); | ||
3283 | } | ||
3284 | } | ||
3285 | |||
3286 | int btrfs_invalidate_inodes(struct btrfs_root *root) | ||
3287 | { | ||
3288 | struct rb_node *node; | ||
3289 | struct rb_node *prev; | ||
3290 | struct btrfs_inode *entry; | ||
3291 | struct inode *inode; | ||
3292 | u64 objectid = 0; | ||
3293 | |||
3294 | WARN_ON(btrfs_root_refs(&root->root_item) != 0); | ||
3295 | |||
3296 | spin_lock(&root->inode_lock); | ||
3297 | again: | ||
3298 | node = root->inode_tree.rb_node; | ||
3299 | prev = NULL; | ||
3300 | while (node) { | ||
3301 | prev = node; | ||
3302 | entry = rb_entry(node, struct btrfs_inode, rb_node); | ||
3303 | |||
3304 | if (objectid < entry->vfs_inode.i_ino) | ||
3305 | node = node->rb_left; | ||
3306 | else if (objectid > entry->vfs_inode.i_ino) | ||
3307 | node = node->rb_right; | ||
3308 | else | ||
3309 | break; | ||
3310 | } | ||
3311 | if (!node) { | ||
3312 | while (prev) { | ||
3313 | entry = rb_entry(prev, struct btrfs_inode, rb_node); | ||
3314 | if (objectid <= entry->vfs_inode.i_ino) { | ||
3315 | node = prev; | ||
3316 | break; | ||
3317 | } | ||
3318 | prev = rb_next(prev); | ||
3319 | } | ||
3320 | } | ||
3321 | while (node) { | ||
3322 | entry = rb_entry(node, struct btrfs_inode, rb_node); | ||
3323 | objectid = entry->vfs_inode.i_ino + 1; | ||
3324 | inode = igrab(&entry->vfs_inode); | ||
3325 | if (inode) { | ||
3326 | spin_unlock(&root->inode_lock); | ||
3327 | if (atomic_read(&inode->i_count) > 1) | ||
3328 | d_prune_aliases(inode); | ||
3329 | /* | ||
3330 | * btrfs_drop_inode will remove it from | ||
3331 | * the inode cache when its usage count | ||
3332 | * hits zero. | ||
3333 | */ | ||
3334 | iput(inode); | ||
3335 | cond_resched(); | ||
3336 | spin_lock(&root->inode_lock); | ||
3337 | goto again; | ||
3338 | } | ||
3339 | |||
3340 | if (cond_resched_lock(&root->inode_lock)) | ||
3341 | goto again; | ||
3342 | |||
3343 | node = rb_next(node); | ||
3344 | } | ||
3345 | spin_unlock(&root->inode_lock); | ||
3346 | return 0; | ||
3266 | } | 3347 | } |
3267 | 3348 | ||
3268 | static noinline void init_btrfs_i(struct inode *inode) | 3349 | static noinline void init_btrfs_i(struct inode *inode) |
@@ -3379,8 +3460,11 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) | |||
3379 | struct btrfs_root *root = BTRFS_I(dir)->root; | 3460 | struct btrfs_root *root = BTRFS_I(dir)->root; |
3380 | struct btrfs_root *sub_root = root; | 3461 | struct btrfs_root *sub_root = root; |
3381 | struct btrfs_key location; | 3462 | struct btrfs_key location; |
3463 | int index; | ||
3382 | int ret; | 3464 | int ret; |
3383 | 3465 | ||
3466 | dentry->d_op = &btrfs_dentry_operations; | ||
3467 | |||
3384 | if (dentry->d_name.len > BTRFS_NAME_LEN) | 3468 | if (dentry->d_name.len > BTRFS_NAME_LEN) |
3385 | return ERR_PTR(-ENAMETOOLONG); | 3469 | return ERR_PTR(-ENAMETOOLONG); |
3386 | 3470 | ||
@@ -3399,6 +3483,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) | |||
3399 | 3483 | ||
3400 | BUG_ON(location.type != BTRFS_ROOT_ITEM_KEY); | 3484 | BUG_ON(location.type != BTRFS_ROOT_ITEM_KEY); |
3401 | 3485 | ||
3486 | index = srcu_read_lock(&root->fs_info->subvol_srcu); | ||
3402 | ret = fixup_tree_root_location(root, dir, dentry, | 3487 | ret = fixup_tree_root_location(root, dir, dentry, |
3403 | &location, &sub_root); | 3488 | &location, &sub_root); |
3404 | if (ret < 0) { | 3489 | if (ret < 0) { |
@@ -3409,9 +3494,24 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) | |||
3409 | } else { | 3494 | } else { |
3410 | inode = btrfs_iget(dir->i_sb, &location, sub_root); | 3495 | inode = btrfs_iget(dir->i_sb, &location, sub_root); |
3411 | } | 3496 | } |
3497 | srcu_read_unlock(&root->fs_info->subvol_srcu, index); | ||
3498 | |||
3412 | return inode; | 3499 | return inode; |
3413 | } | 3500 | } |
3414 | 3501 | ||
3502 | static int btrfs_dentry_delete(struct dentry *dentry) | ||
3503 | { | ||
3504 | struct btrfs_root *root; | ||
3505 | |||
3506 | if (!dentry->d_inode) | ||
3507 | return 0; | ||
3508 | |||
3509 | root = BTRFS_I(dentry->d_inode)->root; | ||
3510 | if (btrfs_root_refs(&root->root_item) == 0) | ||
3511 | return 1; | ||
3512 | return 0; | ||
3513 | } | ||
3514 | |||
3415 | static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | 3515 | static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, |
3416 | struct nameidata *nd) | 3516 | struct nameidata *nd) |
3417 | { | 3517 | { |
@@ -4773,11 +4873,11 @@ out: | |||
4773 | * create a new subvolume directory/inode (helper for the ioctl). | 4873 | * create a new subvolume directory/inode (helper for the ioctl). |
4774 | */ | 4874 | */ |
4775 | int btrfs_create_subvol_root(struct btrfs_trans_handle *trans, | 4875 | int btrfs_create_subvol_root(struct btrfs_trans_handle *trans, |
4776 | struct btrfs_root *new_root, struct dentry *dentry, | 4876 | struct btrfs_root *new_root, |
4777 | u64 new_dirid, u64 alloc_hint) | 4877 | u64 new_dirid, u64 alloc_hint) |
4778 | { | 4878 | { |
4779 | struct inode *inode; | 4879 | struct inode *inode; |
4780 | int error; | 4880 | int err; |
4781 | u64 index = 0; | 4881 | u64 index = 0; |
4782 | 4882 | ||
4783 | inode = btrfs_new_inode(trans, new_root, NULL, "..", 2, new_dirid, | 4883 | inode = btrfs_new_inode(trans, new_root, NULL, "..", 2, new_dirid, |
@@ -4790,11 +4890,10 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans, | |||
4790 | inode->i_nlink = 1; | 4890 | inode->i_nlink = 1; |
4791 | btrfs_i_size_write(inode, 0); | 4891 | btrfs_i_size_write(inode, 0); |
4792 | 4892 | ||
4793 | error = btrfs_update_inode(trans, new_root, inode); | 4893 | err = btrfs_update_inode(trans, new_root, inode); |
4794 | if (error) | 4894 | BUG_ON(err); |
4795 | return error; | ||
4796 | 4895 | ||
4797 | d_instantiate(dentry, inode); | 4896 | iput(inode); |
4798 | return 0; | 4897 | return 0; |
4799 | } | 4898 | } |
4800 | 4899 | ||
@@ -4872,6 +4971,16 @@ void btrfs_destroy_inode(struct inode *inode) | |||
4872 | kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); | 4971 | kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); |
4873 | } | 4972 | } |
4874 | 4973 | ||
4974 | void btrfs_drop_inode(struct inode *inode) | ||
4975 | { | ||
4976 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
4977 | |||
4978 | if (inode->i_nlink > 0 && btrfs_root_refs(&root->root_item) == 0) | ||
4979 | generic_delete_inode(inode); | ||
4980 | else | ||
4981 | generic_drop_inode(inode); | ||
4982 | } | ||
4983 | |||
4875 | static void init_once(void *foo) | 4984 | static void init_once(void *foo) |
4876 | { | 4985 | { |
4877 | struct btrfs_inode *ei = (struct btrfs_inode *) foo; | 4986 | struct btrfs_inode *ei = (struct btrfs_inode *) foo; |
@@ -4973,6 +5082,10 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
4973 | old_inode->i_size > BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT) | 5082 | old_inode->i_size > BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT) |
4974 | filemap_flush(old_inode->i_mapping); | 5083 | filemap_flush(old_inode->i_mapping); |
4975 | 5084 | ||
5085 | /* close the racy window with snapshot create/destroy ioctl */ | ||
5086 | if (old_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) | ||
5087 | down_read(&root->fs_info->subvol_sem); | ||
5088 | |||
4976 | trans = btrfs_start_transaction(root, 1); | 5089 | trans = btrfs_start_transaction(root, 1); |
4977 | 5090 | ||
4978 | if (dest != root) | 5091 | if (dest != root) |
@@ -5062,6 +5175,8 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
5062 | 5175 | ||
5063 | btrfs_end_transaction_throttle(trans, root); | 5176 | btrfs_end_transaction_throttle(trans, root); |
5064 | 5177 | ||
5178 | if (old_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) | ||
5179 | up_read(&root->fs_info->subvol_sem); | ||
5065 | return ret; | 5180 | return ret; |
5066 | } | 5181 | } |
5067 | 5182 | ||
@@ -5420,6 +5535,7 @@ static struct inode_operations btrfs_dir_ro_inode_operations = { | |||
5420 | .lookup = btrfs_lookup, | 5535 | .lookup = btrfs_lookup, |
5421 | .permission = btrfs_permission, | 5536 | .permission = btrfs_permission, |
5422 | }; | 5537 | }; |
5538 | |||
5423 | static struct file_operations btrfs_dir_file_operations = { | 5539 | static struct file_operations btrfs_dir_file_operations = { |
5424 | .llseek = generic_file_llseek, | 5540 | .llseek = generic_file_llseek, |
5425 | .read = generic_read_dir, | 5541 | .read = generic_read_dir, |
@@ -5506,3 +5622,7 @@ static struct inode_operations btrfs_symlink_inode_operations = { | |||
5506 | .listxattr = btrfs_listxattr, | 5622 | .listxattr = btrfs_listxattr, |
5507 | .removexattr = btrfs_removexattr, | 5623 | .removexattr = btrfs_removexattr, |
5508 | }; | 5624 | }; |
5625 | |||
5626 | struct dentry_operations btrfs_dentry_operations = { | ||
5627 | .d_delete = btrfs_dentry_delete, | ||
5628 | }; | ||