diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
| -rw-r--r-- | fs/btrfs/ioctl.c | 71 |
1 files changed, 52 insertions, 19 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index f43df72b0e1..ec45b308613 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: |
