diff options
| -rw-r--r-- | fs/btrfs/ctree.h | 7 | ||||
| -rw-r--r-- | fs/btrfs/disk-io.c | 14 | ||||
| -rw-r--r-- | fs/btrfs/inode.c | 50 | ||||
| -rw-r--r-- | fs/btrfs/ioctl.c | 71 | ||||
| -rw-r--r-- | fs/btrfs/ioctl.h | 7 | ||||
| -rw-r--r-- | fs/btrfs/super.c | 10 | ||||
| -rw-r--r-- | fs/btrfs/transaction.c | 66 | ||||
| -rw-r--r-- | fs/btrfs/transaction.h | 2 |
8 files changed, 162 insertions, 65 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 5ff74282a620..5611f8e035a4 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -606,6 +606,7 @@ struct btrfs_fs_info { | |||
| 606 | struct btrfs_root *tree_root; | 606 | struct btrfs_root *tree_root; |
| 607 | struct btrfs_root *chunk_root; | 607 | struct btrfs_root *chunk_root; |
| 608 | struct btrfs_root *dev_root; | 608 | struct btrfs_root *dev_root; |
| 609 | struct btrfs_root *fs_root; | ||
| 609 | 610 | ||
| 610 | /* the log root tree is a directory of all the other log roots */ | 611 | /* the log root tree is a directory of all the other log roots */ |
| 611 | struct btrfs_root *log_root_tree; | 612 | struct btrfs_root *log_root_tree; |
| @@ -758,7 +759,6 @@ struct btrfs_root { | |||
| 758 | struct btrfs_root_item root_item; | 759 | struct btrfs_root_item root_item; |
| 759 | struct btrfs_key root_key; | 760 | struct btrfs_key root_key; |
| 760 | struct btrfs_fs_info *fs_info; | 761 | struct btrfs_fs_info *fs_info; |
| 761 | struct inode *inode; | ||
| 762 | struct extent_io_tree dirty_log_pages; | 762 | struct extent_io_tree dirty_log_pages; |
| 763 | 763 | ||
| 764 | struct kobject root_kobj; | 764 | struct kobject root_kobj; |
| @@ -1876,6 +1876,8 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans, | |||
| 1876 | #define PageChecked PageFsMisc | 1876 | #define PageChecked PageFsMisc |
| 1877 | #endif | 1877 | #endif |
| 1878 | 1878 | ||
| 1879 | struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry); | ||
| 1880 | int btrfs_set_inode_index(struct inode *dir, u64 *index); | ||
| 1879 | int btrfs_unlink_inode(struct btrfs_trans_handle *trans, | 1881 | int btrfs_unlink_inode(struct btrfs_trans_handle *trans, |
| 1880 | struct btrfs_root *root, | 1882 | struct btrfs_root *root, |
| 1881 | struct inode *dir, struct inode *inode, | 1883 | struct inode *dir, struct inode *inode, |
| @@ -1896,9 +1898,6 @@ int btrfs_create_subvol_root(struct btrfs_root *new_root, struct dentry *dentry, | |||
| 1896 | struct btrfs_trans_handle *trans, u64 new_dirid, | 1898 | struct btrfs_trans_handle *trans, u64 new_dirid, |
| 1897 | struct btrfs_block_group_cache *block_group); | 1899 | struct btrfs_block_group_cache *block_group); |
| 1898 | 1900 | ||
| 1899 | void btrfs_invalidate_dcache_root(struct btrfs_root *root, char *name, | ||
| 1900 | int namelen); | ||
| 1901 | |||
| 1902 | int btrfs_merge_bio_hook(struct page *page, unsigned long offset, | 1901 | int btrfs_merge_bio_hook(struct page *page, unsigned long offset, |
| 1903 | size_t size, struct bio *bio, unsigned long bio_flags); | 1902 | size_t size, struct bio *bio, unsigned long bio_flags); |
| 1904 | 1903 | ||
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 82833e5d84b6..0a5350573f61 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -838,7 +838,6 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, | |||
| 838 | u64 objectid) | 838 | u64 objectid) |
| 839 | { | 839 | { |
| 840 | root->node = NULL; | 840 | root->node = NULL; |
| 841 | root->inode = NULL; | ||
| 842 | root->commit_root = NULL; | 841 | root->commit_root = NULL; |
| 843 | root->ref_tree = NULL; | 842 | root->ref_tree = NULL; |
| 844 | root->sectorsize = sectorsize; | 843 | root->sectorsize = sectorsize; |
| @@ -1430,6 +1429,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
| 1430 | u32 blocksize; | 1429 | u32 blocksize; |
| 1431 | u32 stripesize; | 1430 | u32 stripesize; |
| 1432 | u64 generation; | 1431 | u64 generation; |
| 1432 | struct btrfs_key location; | ||
| 1433 | struct buffer_head *bh; | 1433 | struct buffer_head *bh; |
| 1434 | struct btrfs_root *extent_root = kzalloc(sizeof(struct btrfs_root), | 1434 | struct btrfs_root *extent_root = kzalloc(sizeof(struct btrfs_root), |
| 1435 | GFP_NOFS); | 1435 | GFP_NOFS); |
| @@ -1729,7 +1729,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
| 1729 | goto fail_cleaner; | 1729 | goto fail_cleaner; |
| 1730 | 1730 | ||
| 1731 | if (sb->s_flags & MS_RDONLY) | 1731 | if (sb->s_flags & MS_RDONLY) |
| 1732 | return tree_root; | 1732 | goto read_fs_root; |
| 1733 | 1733 | ||
| 1734 | if (btrfs_super_log_root(disk_super) != 0) { | 1734 | if (btrfs_super_log_root(disk_super) != 0) { |
| 1735 | u32 blocksize; | 1735 | u32 blocksize; |
| @@ -1755,6 +1755,14 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
| 1755 | ret = btrfs_cleanup_reloc_trees(tree_root); | 1755 | ret = btrfs_cleanup_reloc_trees(tree_root); |
| 1756 | BUG_ON(ret); | 1756 | BUG_ON(ret); |
| 1757 | 1757 | ||
| 1758 | location.objectid = BTRFS_FS_TREE_OBJECTID; | ||
| 1759 | location.type = BTRFS_ROOT_ITEM_KEY; | ||
| 1760 | location.offset = (u64)-1; | ||
| 1761 | |||
| 1762 | read_fs_root: | ||
| 1763 | fs_info->fs_root = btrfs_read_fs_root_no_name(fs_info, &location); | ||
| 1764 | if (!fs_info->fs_root) | ||
| 1765 | goto fail_cleaner; | ||
| 1758 | return tree_root; | 1766 | return tree_root; |
| 1759 | 1767 | ||
| 1760 | fail_cleaner: | 1768 | fail_cleaner: |
| @@ -1944,8 +1952,6 @@ int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) | |||
| 1944 | (unsigned long)root->root_key.objectid); | 1952 | (unsigned long)root->root_key.objectid); |
| 1945 | if (root->in_sysfs) | 1953 | if (root->in_sysfs) |
| 1946 | btrfs_sysfs_del_root(root); | 1954 | btrfs_sysfs_del_root(root); |
| 1947 | if (root->inode) | ||
| 1948 | iput(root->inode); | ||
| 1949 | if (root->node) | 1955 | if (root->node) |
| 1950 | free_extent_buffer(root->node); | 1956 | free_extent_buffer(root->node); |
| 1951 | if (root->commit_root) | 1957 | if (root->commit_root) |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 3e3620e69bb9..e163b1b74707 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
| @@ -3038,8 +3038,7 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, | |||
| 3038 | return inode; | 3038 | return inode; |
| 3039 | } | 3039 | } |
| 3040 | 3040 | ||
| 3041 | static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | 3041 | struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) |
| 3042 | struct nameidata *nd) | ||
| 3043 | { | 3042 | { |
| 3044 | struct inode * inode; | 3043 | struct inode * inode; |
| 3045 | struct btrfs_inode *bi = BTRFS_I(dir); | 3044 | struct btrfs_inode *bi = BTRFS_I(dir); |
| @@ -3067,13 +3066,21 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 3067 | inode = btrfs_iget(dir->i_sb, &location, sub_root, &new); | 3066 | inode = btrfs_iget(dir->i_sb, &location, sub_root, &new); |
| 3068 | if (IS_ERR(inode)) | 3067 | if (IS_ERR(inode)) |
| 3069 | return ERR_CAST(inode); | 3068 | return ERR_CAST(inode); |
| 3070 | |||
| 3071 | /* the inode and parent dir are two different roots */ | ||
| 3072 | if (new && root != sub_root) { | ||
| 3073 | igrab(inode); | ||
| 3074 | sub_root->inode = inode; | ||
| 3075 | } | ||
| 3076 | } | 3069 | } |
| 3070 | return inode; | ||
| 3071 | } | ||
| 3072 | |||
| 3073 | static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | ||
| 3074 | struct nameidata *nd) | ||
| 3075 | { | ||
| 3076 | struct inode *inode; | ||
| 3077 | |||
| 3078 | if (dentry->d_name.len > BTRFS_NAME_LEN) | ||
| 3079 | return ERR_PTR(-ENAMETOOLONG); | ||
| 3080 | |||
| 3081 | inode = btrfs_lookup_dentry(dir, dentry); | ||
| 3082 | if (IS_ERR(inode)) | ||
| 3083 | return ERR_CAST(inode); | ||
| 3077 | 3084 | ||
| 3078 | return d_splice_alias(inode, dentry); | 3085 | return d_splice_alias(inode, dentry); |
| 3079 | } | 3086 | } |
| @@ -3129,7 +3136,6 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
| 3129 | return 0; | 3136 | return 0; |
| 3130 | filp->f_pos = 2; | 3137 | filp->f_pos = 2; |
| 3131 | } | 3138 | } |
| 3132 | |||
| 3133 | path = btrfs_alloc_path(); | 3139 | path = btrfs_alloc_path(); |
| 3134 | path->reada = 2; | 3140 | path->reada = 2; |
| 3135 | 3141 | ||
| @@ -3159,6 +3165,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
| 3159 | path->slots[0]++; | 3165 | path->slots[0]++; |
| 3160 | } | 3166 | } |
| 3161 | } | 3167 | } |
| 3168 | |||
| 3162 | advance = 1; | 3169 | advance = 1; |
| 3163 | item = btrfs_item_nr(leaf, slot); | 3170 | item = btrfs_item_nr(leaf, slot); |
| 3164 | btrfs_item_key_to_cpu(leaf, &found_key, slot); | 3171 | btrfs_item_key_to_cpu(leaf, &found_key, slot); |
| @@ -3194,16 +3201,25 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
| 3194 | 3201 | ||
| 3195 | d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)]; | 3202 | d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)]; |
| 3196 | btrfs_dir_item_key_to_cpu(leaf, di, &location); | 3203 | btrfs_dir_item_key_to_cpu(leaf, di, &location); |
| 3204 | |||
| 3205 | /* is this a reference to our own snapshot? If so | ||
| 3206 | * skip it | ||
| 3207 | */ | ||
| 3208 | if (location.type == BTRFS_ROOT_ITEM_KEY && | ||
| 3209 | location.objectid == root->root_key.objectid) { | ||
| 3210 | over = 0; | ||
| 3211 | goto skip; | ||
| 3212 | } | ||
| 3197 | over = filldir(dirent, name_ptr, name_len, | 3213 | over = filldir(dirent, name_ptr, name_len, |
| 3198 | found_key.offset, location.objectid, | 3214 | found_key.offset, location.objectid, |
| 3199 | d_type); | 3215 | d_type); |
| 3200 | 3216 | ||
| 3217 | skip: | ||
| 3201 | if (name_ptr != tmp_name) | 3218 | if (name_ptr != tmp_name) |
| 3202 | kfree(name_ptr); | 3219 | kfree(name_ptr); |
| 3203 | 3220 | ||
| 3204 | if (over) | 3221 | if (over) |
| 3205 | goto nopos; | 3222 | goto nopos; |
| 3206 | |||
| 3207 | di_len = btrfs_dir_name_len(leaf, di) + | 3223 | di_len = btrfs_dir_name_len(leaf, di) + |
| 3208 | btrfs_dir_data_len(leaf, di) + sizeof(*di); | 3224 | btrfs_dir_data_len(leaf, di) + sizeof(*di); |
| 3209 | di_cur += di_len; | 3225 | di_cur += di_len; |
| @@ -3318,8 +3334,7 @@ out: | |||
| 3318 | * helper to find a free sequence number in a given directory. This current | 3334 | * helper to find a free sequence number in a given directory. This current |
| 3319 | * code is very simple, later versions will do smarter things in the btree | 3335 | * code is very simple, later versions will do smarter things in the btree |
| 3320 | */ | 3336 | */ |
| 3321 | static int btrfs_set_inode_index(struct inode *dir, struct inode *inode, | 3337 | int btrfs_set_inode_index(struct inode *dir, u64 *index) |
| 3322 | u64 *index) | ||
| 3323 | { | 3338 | { |
| 3324 | int ret = 0; | 3339 | int ret = 0; |
| 3325 | 3340 | ||
| @@ -3365,7 +3380,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
| 3365 | return ERR_PTR(-ENOMEM); | 3380 | return ERR_PTR(-ENOMEM); |
| 3366 | 3381 | ||
| 3367 | if (dir) { | 3382 | if (dir) { |
| 3368 | ret = btrfs_set_inode_index(dir, inode, index); | 3383 | ret = btrfs_set_inode_index(dir, index); |
| 3369 | if (ret) | 3384 | if (ret) |
| 3370 | return ERR_PTR(ret); | 3385 | return ERR_PTR(ret); |
| 3371 | } | 3386 | } |
| @@ -3651,7 +3666,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, | |||
| 3651 | err = btrfs_check_free_space(root, 1, 0); | 3666 | err = btrfs_check_free_space(root, 1, 0); |
| 3652 | if (err) | 3667 | if (err) |
| 3653 | goto fail; | 3668 | goto fail; |
| 3654 | err = btrfs_set_inode_index(dir, inode, &index); | 3669 | err = btrfs_set_inode_index(dir, &index); |
| 3655 | if (err) | 3670 | if (err) |
| 3656 | goto fail; | 3671 | goto fail; |
| 3657 | 3672 | ||
| @@ -4349,13 +4364,13 @@ out: | |||
| 4349 | * Invalidate a single dcache entry at the root of the filesystem. | 4364 | * Invalidate a single dcache entry at the root of the filesystem. |
| 4350 | * Needed after creation of snapshot or subvolume. | 4365 | * Needed after creation of snapshot or subvolume. |
| 4351 | */ | 4366 | */ |
| 4352 | void btrfs_invalidate_dcache_root(struct btrfs_root *root, char *name, | 4367 | void btrfs_invalidate_dcache_root(struct inode *dir, char *name, |
| 4353 | int namelen) | 4368 | int namelen) |
| 4354 | { | 4369 | { |
| 4355 | struct dentry *alias, *entry; | 4370 | struct dentry *alias, *entry; |
| 4356 | struct qstr qstr; | 4371 | struct qstr qstr; |
| 4357 | 4372 | ||
| 4358 | alias = d_find_alias(root->fs_info->sb->s_root->d_inode); | 4373 | alias = d_find_alias(dir); |
| 4359 | if (alias) { | 4374 | if (alias) { |
| 4360 | qstr.name = name; | 4375 | qstr.name = name; |
| 4361 | qstr.len = namelen; | 4376 | qstr.len = namelen; |
| @@ -4387,7 +4402,6 @@ int btrfs_create_subvol_root(struct btrfs_root *new_root, struct dentry *dentry, | |||
| 4387 | return PTR_ERR(inode); | 4402 | return PTR_ERR(inode); |
| 4388 | inode->i_op = &btrfs_dir_inode_operations; | 4403 | inode->i_op = &btrfs_dir_inode_operations; |
| 4389 | inode->i_fop = &btrfs_dir_file_operations; | 4404 | inode->i_fop = &btrfs_dir_file_operations; |
| 4390 | new_root->inode = inode; | ||
| 4391 | 4405 | ||
| 4392 | inode->i_nlink = 1; | 4406 | inode->i_nlink = 1; |
| 4393 | btrfs_i_size_write(inode, 0); | 4407 | btrfs_i_size_write(inode, 0); |
| @@ -4590,7 +4604,7 @@ static int btrfs_rename(struct inode * old_dir, struct dentry *old_dentry, | |||
| 4590 | } | 4604 | } |
| 4591 | 4605 | ||
| 4592 | } | 4606 | } |
| 4593 | ret = btrfs_set_inode_index(new_dir, old_inode, &index); | 4607 | ret = btrfs_set_inode_index(new_dir, &index); |
| 4594 | if (ret) | 4608 | if (ret) |
| 4595 | goto out_fail; | 4609 | goto out_fail; |
| 4596 | 4610 | ||
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index f43df72b0e17..ec45b3086136 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
| @@ -67,6 +67,7 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
| 67 | int err; | 67 | int err; |
| 68 | u64 objectid; | 68 | u64 objectid; |
| 69 | u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; | 69 | u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; |
| 70 | u64 index = 0; | ||
| 70 | unsigned long nr = 1; | 71 | unsigned long nr = 1; |
| 71 | 72 | ||
| 72 | ret = btrfs_check_free_space(root, 1, 0); | 73 | ret = btrfs_check_free_space(root, 1, 0); |
| @@ -126,6 +127,7 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
| 126 | key.objectid = objectid; | 127 | key.objectid = objectid; |
| 127 | key.offset = 1; | 128 | key.offset = 1; |
| 128 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | 129 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); |
| 130 | printk("inserting root objectid %Lu\n", objectid); | ||
| 129 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, | 131 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, |
| 130 | &root_item); | 132 | &root_item); |
| 131 | if (ret) | 133 | if (ret) |
| @@ -135,24 +137,27 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
| 135 | * insert the directory item | 137 | * insert the directory item |
| 136 | */ | 138 | */ |
| 137 | key.offset = (u64)-1; | 139 | key.offset = (u64)-1; |
| 138 | dir = root->fs_info->sb->s_root->d_inode; | 140 | dir = dentry->d_parent->d_inode; |
| 139 | ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root, | 141 | ret = btrfs_set_inode_index(dir, &index); |
| 142 | BUG_ON(ret); | ||
| 143 | |||
| 144 | ret = btrfs_insert_dir_item(trans, root, | ||
| 140 | name, namelen, dir->i_ino, &key, | 145 | name, namelen, dir->i_ino, &key, |
| 141 | BTRFS_FT_DIR, 0); | 146 | BTRFS_FT_DIR, index); |
| 142 | if (ret) | 147 | if (ret) |
| 143 | goto fail; | 148 | goto fail; |
| 144 | 149 | #if 0 | |
| 145 | ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root, | 150 | ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root, |
| 146 | name, namelen, objectid, | 151 | name, namelen, objectid, |
| 147 | root->fs_info->sb->s_root->d_inode->i_ino, 0); | 152 | root->fs_info->sb->s_root->d_inode->i_ino, 0); |
| 148 | if (ret) | 153 | if (ret) |
| 149 | goto fail; | 154 | goto fail; |
| 150 | 155 | #endif | |
| 151 | ret = btrfs_commit_transaction(trans, root); | 156 | ret = btrfs_commit_transaction(trans, root); |
| 152 | if (ret) | 157 | if (ret) |
| 153 | goto fail_commit; | 158 | goto fail_commit; |
| 154 | 159 | ||
| 155 | new_root = btrfs_read_fs_root(root->fs_info, &key, name, namelen); | 160 | new_root = btrfs_read_fs_root_no_name(root->fs_info, &key); |
| 156 | BUG_ON(!new_root); | 161 | BUG_ON(!new_root); |
| 157 | 162 | ||
| 158 | trans = btrfs_start_transaction(new_root, 1); | 163 | trans = btrfs_start_transaction(new_root, 1); |
| @@ -170,14 +175,16 @@ fail: | |||
| 170 | ret = err; | 175 | ret = err; |
| 171 | fail_commit: | 176 | fail_commit: |
| 172 | btrfs_btree_balance_dirty(root, nr); | 177 | btrfs_btree_balance_dirty(root, nr); |
| 178 | printk("all done ret %d\n", ret); | ||
| 173 | return ret; | 179 | return ret; |
| 174 | } | 180 | } |
| 175 | 181 | ||
| 176 | static int create_snapshot(struct btrfs_root *root, char *name, int namelen) | 182 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, |
| 183 | char *name, int namelen) | ||
| 177 | { | 184 | { |
| 178 | struct btrfs_pending_snapshot *pending_snapshot; | 185 | struct btrfs_pending_snapshot *pending_snapshot; |
| 179 | struct btrfs_trans_handle *trans; | 186 | struct btrfs_trans_handle *trans; |
| 180 | int ret; | 187 | int ret = 0; |
| 181 | int err; | 188 | int err; |
| 182 | unsigned long nr = 0; | 189 | unsigned long nr = 0; |
| 183 | 190 | ||
| @@ -188,7 +195,7 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) | |||
| 188 | if (ret) | 195 | if (ret) |
| 189 | goto fail_unlock; | 196 | goto fail_unlock; |
| 190 | 197 | ||
| 191 | pending_snapshot = kmalloc(sizeof(*pending_snapshot), GFP_NOFS); | 198 | pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS); |
| 192 | if (!pending_snapshot) { | 199 | if (!pending_snapshot) { |
| 193 | ret = -ENOMEM; | 200 | ret = -ENOMEM; |
| 194 | goto fail_unlock; | 201 | goto fail_unlock; |
| @@ -201,12 +208,12 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) | |||
| 201 | } | 208 | } |
| 202 | memcpy(pending_snapshot->name, name, namelen); | 209 | memcpy(pending_snapshot->name, name, namelen); |
| 203 | pending_snapshot->name[namelen] = '\0'; | 210 | pending_snapshot->name[namelen] = '\0'; |
| 211 | pending_snapshot->dentry = dentry; | ||
| 204 | trans = btrfs_start_transaction(root, 1); | 212 | trans = btrfs_start_transaction(root, 1); |
| 205 | BUG_ON(!trans); | 213 | BUG_ON(!trans); |
| 206 | pending_snapshot->root = root; | 214 | pending_snapshot->root = root; |
| 207 | list_add(&pending_snapshot->list, | 215 | list_add(&pending_snapshot->list, |
| 208 | &trans->transaction->pending_snapshots); | 216 | &trans->transaction->pending_snapshots); |
| 209 | ret = btrfs_update_inode(trans, root, root->inode); | ||
| 210 | err = btrfs_commit_transaction(trans, root); | 217 | err = btrfs_commit_transaction(trans, root); |
| 211 | 218 | ||
| 212 | fail_unlock: | 219 | fail_unlock: |
| @@ -230,7 +237,8 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child) | |||
| 230 | * inside this filesystem so it's quite a bit simpler. | 237 | * inside this filesystem so it's quite a bit simpler. |
| 231 | */ | 238 | */ |
| 232 | static noinline int btrfs_mksubvol(struct path *parent, char *name, | 239 | static noinline int btrfs_mksubvol(struct path *parent, char *name, |
| 233 | int mode, int namelen) | 240 | int mode, int namelen, |
| 241 | struct btrfs_root *snap_src) | ||
| 234 | { | 242 | { |
| 235 | struct dentry *dentry; | 243 | struct dentry *dentry; |
| 236 | int error; | 244 | int error; |
| @@ -248,6 +256,7 @@ static noinline int btrfs_mksubvol(struct path *parent, char *name, | |||
| 248 | 256 | ||
| 249 | if (!IS_POSIXACL(parent->dentry->d_inode)) | 257 | if (!IS_POSIXACL(parent->dentry->d_inode)) |
| 250 | mode &= ~current->fs->umask; | 258 | mode &= ~current->fs->umask; |
| 259 | |||
| 251 | error = mnt_want_write(parent->mnt); | 260 | error = mnt_want_write(parent->mnt); |
| 252 | if (error) | 261 | if (error) |
| 253 | goto out_dput; | 262 | goto out_dput; |
| @@ -266,8 +275,12 @@ static noinline int btrfs_mksubvol(struct path *parent, char *name, | |||
| 266 | * Also we should pass on the mode eventually to allow creating new | 275 | * Also we should pass on the mode eventually to allow creating new |
| 267 | * subvolume with specific mode bits. | 276 | * subvolume with specific mode bits. |
| 268 | */ | 277 | */ |
| 269 | error = create_subvol(BTRFS_I(parent->dentry->d_inode)->root, dentry, | 278 | if (snap_src) { |
| 270 | name, namelen); | 279 | error = create_snapshot(snap_src, dentry, name, namelen); |
| 280 | } else { | ||
| 281 | error = create_subvol(BTRFS_I(parent->dentry->d_inode)->root, | ||
| 282 | dentry, name, namelen); | ||
| 283 | } | ||
| 271 | if (error) | 284 | if (error) |
| 272 | goto out_drop_write; | 285 | goto out_drop_write; |
| 273 | 286 | ||
| @@ -471,15 +484,16 @@ out: | |||
| 471 | } | 484 | } |
| 472 | 485 | ||
| 473 | static noinline int btrfs_ioctl_snap_create(struct file *file, | 486 | static noinline int btrfs_ioctl_snap_create(struct file *file, |
| 474 | void __user *arg) | 487 | void __user *arg, int subvol) |
| 475 | { | 488 | { |
| 476 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; | 489 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; |
| 477 | struct btrfs_ioctl_vol_args *vol_args; | 490 | struct btrfs_ioctl_vol_args *vol_args; |
| 478 | struct btrfs_dir_item *di; | 491 | struct btrfs_dir_item *di; |
| 479 | struct btrfs_path *path; | 492 | struct btrfs_path *path; |
| 493 | struct file *src_file; | ||
| 480 | u64 root_dirid; | 494 | u64 root_dirid; |
| 481 | int namelen; | 495 | int namelen; |
| 482 | int ret; | 496 | int ret = 0; |
| 483 | 497 | ||
| 484 | if (root->fs_info->sb->s_flags & MS_RDONLY) | 498 | if (root->fs_info->sb->s_flags & MS_RDONLY) |
| 485 | return -EROFS; | 499 | return -EROFS; |
| @@ -523,12 +537,29 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
| 523 | goto out; | 537 | goto out; |
| 524 | } | 538 | } |
| 525 | 539 | ||
| 526 | if (root == root->fs_info->tree_root) { | 540 | if (subvol) { |
| 527 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, | 541 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, |
| 528 | file->f_path.dentry->d_inode->i_mode, | 542 | file->f_path.dentry->d_inode->i_mode, |
| 529 | namelen); | 543 | namelen, NULL); |
| 530 | } else { | 544 | } else { |
| 531 | ret = create_snapshot(root, vol_args->name, namelen); | 545 | struct inode *src_inode; |
| 546 | src_file = fget(vol_args->fd); | ||
| 547 | if (!src_file) { | ||
| 548 | ret = -EINVAL; | ||
| 549 | goto out; | ||
| 550 | } | ||
| 551 | |||
| 552 | src_inode = src_file->f_path.dentry->d_inode; | ||
| 553 | if (src_inode->i_sb != file->f_path.dentry->d_inode->i_sb) { | ||
| 554 | printk("btrfs: Snapshot src from another FS\n"); | ||
| 555 | ret = -EINVAL; | ||
| 556 | fput(src_file); | ||
| 557 | goto out; | ||
| 558 | } | ||
| 559 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, | ||
| 560 | file->f_path.dentry->d_inode->i_mode, | ||
| 561 | namelen, BTRFS_I(src_inode)->root); | ||
| 562 | fput(src_file); | ||
| 532 | } | 563 | } |
| 533 | 564 | ||
| 534 | out: | 565 | out: |
| @@ -1030,7 +1061,9 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
| 1030 | 1061 | ||
| 1031 | switch (cmd) { | 1062 | switch (cmd) { |
| 1032 | case BTRFS_IOC_SNAP_CREATE: | 1063 | case BTRFS_IOC_SNAP_CREATE: |
| 1033 | return btrfs_ioctl_snap_create(file, (void __user *)arg); | 1064 | return btrfs_ioctl_snap_create(file, (void __user *)arg, 0); |
| 1065 | case BTRFS_IOC_SUBVOL_CREATE: | ||
| 1066 | return btrfs_ioctl_snap_create(file, (void __user *)arg, 1); | ||
| 1034 | case BTRFS_IOC_DEFRAG: | 1067 | case BTRFS_IOC_DEFRAG: |
| 1035 | return btrfs_ioctl_defrag(file); | 1068 | return btrfs_ioctl_defrag(file); |
| 1036 | case BTRFS_IOC_RESIZE: | 1069 | case BTRFS_IOC_RESIZE: |
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 989ba8a01215..78049ea208db 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h | |||
| @@ -22,9 +22,10 @@ | |||
| 22 | 22 | ||
| 23 | #define BTRFS_IOCTL_MAGIC 0x94 | 23 | #define BTRFS_IOCTL_MAGIC 0x94 |
| 24 | #define BTRFS_VOL_NAME_MAX 255 | 24 | #define BTRFS_VOL_NAME_MAX 255 |
| 25 | #define BTRFS_PATH_NAME_MAX 4095 | 25 | #define BTRFS_PATH_NAME_MAX 3072 |
| 26 | 26 | ||
| 27 | struct btrfs_ioctl_vol_args { | 27 | struct btrfs_ioctl_vol_args { |
| 28 | __s64 fd; | ||
| 28 | char name[BTRFS_PATH_NAME_MAX + 1]; | 29 | char name[BTRFS_PATH_NAME_MAX + 1]; |
| 29 | }; | 30 | }; |
| 30 | 31 | ||
| @@ -51,7 +52,6 @@ struct btrfs_ioctl_vol_args { | |||
| 51 | struct btrfs_ioctl_vol_args) | 52 | struct btrfs_ioctl_vol_args) |
| 52 | #define BTRFS_IOC_BALANCE _IOW(BTRFS_IOCTL_MAGIC, 12, \ | 53 | #define BTRFS_IOC_BALANCE _IOW(BTRFS_IOCTL_MAGIC, 12, \ |
| 53 | struct btrfs_ioctl_vol_args) | 54 | struct btrfs_ioctl_vol_args) |
| 54 | |||
| 55 | struct btrfs_ioctl_clone_range_args { | 55 | struct btrfs_ioctl_clone_range_args { |
| 56 | __s64 src_fd; | 56 | __s64 src_fd; |
| 57 | __u64 src_offset, src_length; | 57 | __u64 src_offset, src_length; |
| @@ -61,4 +61,7 @@ struct btrfs_ioctl_clone_range_args { | |||
| 61 | #define BTRFS_IOC_CLONE_RANGE _IOW(BTRFS_IOCTL_MAGIC, 13, \ | 61 | #define BTRFS_IOC_CLONE_RANGE _IOW(BTRFS_IOCTL_MAGIC, 13, \ |
| 62 | struct btrfs_ioctl_clone_range_args) | 62 | struct btrfs_ioctl_clone_range_args) |
| 63 | 63 | ||
| 64 | #define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \ | ||
| 65 | struct btrfs_ioctl_vol_args) | ||
| 66 | |||
| 64 | #endif | 67 | #endif |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 92393cc60d08..77c5eff3e209 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
| @@ -285,11 +285,11 @@ static int btrfs_parse_early_options(const char *options, int flags, | |||
| 285 | out: | 285 | out: |
| 286 | /* | 286 | /* |
| 287 | * If no subvolume name is specified we use the default one. Allocate | 287 | * If no subvolume name is specified we use the default one. Allocate |
| 288 | * a copy of the string "default" here so that code later in the | 288 | * a copy of the string "." here so that code later in the |
| 289 | * mount path doesn't care if it's the default volume or another one. | 289 | * mount path doesn't care if it's the default volume or another one. |
| 290 | */ | 290 | */ |
| 291 | if (!*subvol_name) { | 291 | if (!*subvol_name) { |
| 292 | *subvol_name = kstrdup("default", GFP_KERNEL); | 292 | *subvol_name = kstrdup(".", GFP_KERNEL); |
| 293 | if (!*subvol_name) | 293 | if (!*subvol_name) |
| 294 | return -ENOMEM; | 294 | return -ENOMEM; |
| 295 | } | 295 | } |
| @@ -323,12 +323,12 @@ static int btrfs_fill_super(struct super_block * sb, | |||
| 323 | } | 323 | } |
| 324 | sb->s_fs_info = tree_root; | 324 | sb->s_fs_info = tree_root; |
| 325 | disk_super = &tree_root->fs_info->super_copy; | 325 | disk_super = &tree_root->fs_info->super_copy; |
| 326 | inode = btrfs_iget_locked(sb, btrfs_super_root_dir(disk_super), | 326 | inode = btrfs_iget_locked(sb, BTRFS_FIRST_FREE_OBJECTID, |
| 327 | tree_root); | 327 | tree_root->fs_info->fs_root); |
| 328 | bi = BTRFS_I(inode); | 328 | bi = BTRFS_I(inode); |
| 329 | bi->location.objectid = inode->i_ino; | 329 | bi->location.objectid = inode->i_ino; |
| 330 | bi->location.offset = 0; | 330 | bi->location.offset = 0; |
| 331 | bi->root = tree_root; | 331 | bi->root = tree_root->fs_info->fs_root; |
| 332 | 332 | ||
| 333 | btrfs_set_key_type(&bi->location, BTRFS_INODE_ITEM_KEY); | 333 | btrfs_set_key_type(&bi->location, BTRFS_INODE_ITEM_KEY); |
| 334 | 334 | ||
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 202c1b6df4a4..eec8b2465039 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
| @@ -779,7 +779,6 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
| 779 | struct extent_buffer *tmp; | 779 | struct extent_buffer *tmp; |
| 780 | struct extent_buffer *old; | 780 | struct extent_buffer *old; |
| 781 | int ret; | 781 | int ret; |
| 782 | int namelen; | ||
| 783 | u64 objectid; | 782 | u64 objectid; |
| 784 | 783 | ||
| 785 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); | 784 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); |
| @@ -816,28 +815,48 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
| 816 | if (ret) | 815 | if (ret) |
| 817 | goto fail; | 816 | goto fail; |
| 818 | 817 | ||
| 818 | key.offset = (u64)-1; | ||
| 819 | memcpy(&pending->root_key, &key, sizeof(key)); | ||
| 820 | fail: | ||
| 821 | kfree(new_root_item); | ||
| 822 | return ret; | ||
| 823 | } | ||
| 824 | |||
| 825 | static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info, | ||
| 826 | struct btrfs_pending_snapshot *pending) | ||
| 827 | { | ||
| 828 | int ret; | ||
| 829 | int namelen; | ||
| 830 | u64 index = 0; | ||
| 831 | struct btrfs_trans_handle *trans; | ||
| 832 | struct inode *parent_inode; | ||
| 833 | struct inode *inode; | ||
| 834 | |||
| 835 | trans = btrfs_start_transaction(fs_info->fs_root, 1); | ||
| 836 | |||
| 819 | /* | 837 | /* |
| 820 | * insert the directory item | 838 | * insert the directory item |
| 821 | */ | 839 | */ |
| 822 | key.offset = (u64)-1; | ||
| 823 | namelen = strlen(pending->name); | 840 | namelen = strlen(pending->name); |
| 824 | ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root, | 841 | parent_inode = pending->dentry->d_parent->d_inode; |
| 825 | pending->name, namelen, | 842 | ret = btrfs_set_inode_index(parent_inode, &index); |
| 826 | root->fs_info->sb->s_root->d_inode->i_ino, | 843 | ret = btrfs_insert_dir_item(trans, |
| 827 | &key, BTRFS_FT_DIR, 0); | 844 | BTRFS_I(parent_inode)->root, |
| 845 | pending->name, namelen, | ||
| 846 | parent_inode->i_ino, | ||
| 847 | &pending->root_key, BTRFS_FT_DIR, index); | ||
| 828 | 848 | ||
| 829 | if (ret) | 849 | if (ret) |
| 830 | goto fail; | 850 | goto fail; |
| 831 | 851 | #if 0 | |
| 832 | ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root, | 852 | ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root, |
| 833 | pending->name, strlen(pending->name), objectid, | 853 | pending->name, strlen(pending->name), objectid, |
| 834 | root->fs_info->sb->s_root->d_inode->i_ino, 0); | 854 | root->fs_info->sb->s_root->d_inode->i_ino, 0); |
| 835 | 855 | #endif | |
| 836 | /* Invalidate existing dcache entry for new snapshot. */ | 856 | inode = btrfs_lookup_dentry(parent_inode, pending->dentry); |
| 837 | btrfs_invalidate_dcache_root(root, pending->name, namelen); | 857 | d_instantiate(pending->dentry, inode); |
| 838 | |||
| 839 | fail: | 858 | fail: |
| 840 | kfree(new_root_item); | 859 | btrfs_end_transaction(trans, fs_info->fs_root); |
| 841 | return ret; | 860 | return ret; |
| 842 | } | 861 | } |
| 843 | 862 | ||
| @@ -849,12 +868,28 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans, | |||
| 849 | { | 868 | { |
| 850 | struct btrfs_pending_snapshot *pending; | 869 | struct btrfs_pending_snapshot *pending; |
| 851 | struct list_head *head = &trans->transaction->pending_snapshots; | 870 | struct list_head *head = &trans->transaction->pending_snapshots; |
| 871 | struct list_head *cur; | ||
| 872 | int ret; | ||
| 873 | |||
| 874 | list_for_each(cur, head) { | ||
| 875 | pending = list_entry(cur, struct btrfs_pending_snapshot, list); | ||
| 876 | ret = create_pending_snapshot(trans, fs_info, pending); | ||
| 877 | BUG_ON(ret); | ||
| 878 | } | ||
| 879 | return 0; | ||
| 880 | } | ||
| 881 | |||
| 882 | static noinline int finish_pending_snapshots(struct btrfs_trans_handle *trans, | ||
| 883 | struct btrfs_fs_info *fs_info) | ||
| 884 | { | ||
| 885 | struct btrfs_pending_snapshot *pending; | ||
| 886 | struct list_head *head = &trans->transaction->pending_snapshots; | ||
| 852 | int ret; | 887 | int ret; |
| 853 | 888 | ||
| 854 | while(!list_empty(head)) { | 889 | while(!list_empty(head)) { |
| 855 | pending = list_entry(head->next, | 890 | pending = list_entry(head->next, |
| 856 | struct btrfs_pending_snapshot, list); | 891 | struct btrfs_pending_snapshot, list); |
| 857 | ret = create_pending_snapshot(trans, fs_info, pending); | 892 | ret = finish_pending_snapshot(fs_info, pending); |
| 858 | BUG_ON(ret); | 893 | BUG_ON(ret); |
| 859 | list_del(&pending->list); | 894 | list_del(&pending->list); |
| 860 | kfree(pending->name); | 895 | kfree(pending->name); |
| @@ -1033,11 +1068,15 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 1033 | btrfs_drop_dead_reloc_roots(root); | 1068 | btrfs_drop_dead_reloc_roots(root); |
| 1034 | mutex_unlock(&root->fs_info->tree_reloc_mutex); | 1069 | mutex_unlock(&root->fs_info->tree_reloc_mutex); |
| 1035 | 1070 | ||
| 1071 | /* do the directory inserts of any pending snapshot creations */ | ||
| 1072 | finish_pending_snapshots(trans, root->fs_info); | ||
| 1073 | |||
| 1036 | mutex_lock(&root->fs_info->trans_mutex); | 1074 | mutex_lock(&root->fs_info->trans_mutex); |
| 1037 | 1075 | ||
| 1038 | cur_trans->commit_done = 1; | 1076 | cur_trans->commit_done = 1; |
| 1039 | root->fs_info->last_trans_committed = cur_trans->transid; | 1077 | root->fs_info->last_trans_committed = cur_trans->transid; |
| 1040 | wake_up(&cur_trans->commit_wait); | 1078 | wake_up(&cur_trans->commit_wait); |
| 1079 | |||
| 1041 | put_transaction(cur_trans); | 1080 | put_transaction(cur_trans); |
| 1042 | put_transaction(cur_trans); | 1081 | put_transaction(cur_trans); |
| 1043 | 1082 | ||
| @@ -1046,6 +1085,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 1046 | list_splice_init(&root->fs_info->dead_roots, &dirty_fs_roots); | 1085 | list_splice_init(&root->fs_info->dead_roots, &dirty_fs_roots); |
| 1047 | 1086 | ||
| 1048 | mutex_unlock(&root->fs_info->trans_mutex); | 1087 | mutex_unlock(&root->fs_info->trans_mutex); |
| 1088 | |||
| 1049 | kmem_cache_free(btrfs_trans_handle_cachep, trans); | 1089 | kmem_cache_free(btrfs_trans_handle_cachep, trans); |
| 1050 | 1090 | ||
| 1051 | if (root->fs_info->closing) { | 1091 | if (root->fs_info->closing) { |
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index eef2cb7d7e78..202c8be6c05d 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
| @@ -47,8 +47,10 @@ struct btrfs_trans_handle { | |||
| 47 | }; | 47 | }; |
| 48 | 48 | ||
| 49 | struct btrfs_pending_snapshot { | 49 | struct btrfs_pending_snapshot { |
| 50 | struct dentry *dentry; | ||
| 50 | struct btrfs_root *root; | 51 | struct btrfs_root *root; |
| 51 | char *name; | 52 | char *name; |
| 53 | struct btrfs_key root_key; | ||
| 52 | struct list_head list; | 54 | struct list_head list; |
| 53 | }; | 55 | }; |
| 54 | 56 | ||
