diff options
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/ctree.h | 2 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 10 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 102 |
3 files changed, 100 insertions, 14 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 3fa9b8d6751d..8559f39fd47f 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1791,7 +1791,7 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root); | |||
1791 | int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end); | 1791 | int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end); |
1792 | int btrfs_writepages(struct address_space *mapping, | 1792 | int btrfs_writepages(struct address_space *mapping, |
1793 | struct writeback_control *wbc); | 1793 | struct writeback_control *wbc); |
1794 | int btrfs_create_subvol_root(struct btrfs_root *new_root, | 1794 | int btrfs_create_subvol_root(struct btrfs_root *new_root, struct dentry *dentry, |
1795 | struct btrfs_trans_handle *trans, u64 new_dirid, | 1795 | struct btrfs_trans_handle *trans, u64 new_dirid, |
1796 | struct btrfs_block_group_cache *block_group); | 1796 | struct btrfs_block_group_cache *block_group); |
1797 | 1797 | ||
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 11bfe131fde6..bf4bed6ca4d6 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -3420,11 +3420,12 @@ void btrfs_invalidate_dcache_root(struct btrfs_root *root, char *name, | |||
3420 | /* | 3420 | /* |
3421 | * create a new subvolume directory/inode (helper for the ioctl). | 3421 | * create a new subvolume directory/inode (helper for the ioctl). |
3422 | */ | 3422 | */ |
3423 | int btrfs_create_subvol_root(struct btrfs_root *new_root, | 3423 | int btrfs_create_subvol_root(struct btrfs_root *new_root, struct dentry *dentry, |
3424 | struct btrfs_trans_handle *trans, u64 new_dirid, | 3424 | struct btrfs_trans_handle *trans, u64 new_dirid, |
3425 | struct btrfs_block_group_cache *block_group) | 3425 | struct btrfs_block_group_cache *block_group) |
3426 | { | 3426 | { |
3427 | struct inode *inode; | 3427 | struct inode *inode; |
3428 | int error; | ||
3428 | u64 index = 0; | 3429 | u64 index = 0; |
3429 | 3430 | ||
3430 | inode = btrfs_new_inode(trans, new_root, NULL, "..", 2, new_dirid, | 3431 | inode = btrfs_new_inode(trans, new_root, NULL, "..", 2, new_dirid, |
@@ -3438,7 +3439,12 @@ int btrfs_create_subvol_root(struct btrfs_root *new_root, | |||
3438 | inode->i_nlink = 1; | 3439 | inode->i_nlink = 1; |
3439 | btrfs_i_size_write(inode, 0); | 3440 | btrfs_i_size_write(inode, 0); |
3440 | 3441 | ||
3441 | return btrfs_update_inode(trans, new_root, inode); | 3442 | error = btrfs_update_inode(trans, new_root, inode); |
3443 | if (error) | ||
3444 | return error; | ||
3445 | |||
3446 | d_instantiate(dentry, inode); | ||
3447 | return 0; | ||
3442 | } | 3448 | } |
3443 | 3449 | ||
3444 | /* helper function for file defrag and space balancing. This | 3450 | /* helper function for file defrag and space balancing. This |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 50c8a066d1f0..3d85f18bbba6 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/buffer_head.h> | 21 | #include <linux/buffer_head.h> |
22 | #include <linux/file.h> | 22 | #include <linux/file.h> |
23 | #include <linux/fs.h> | 23 | #include <linux/fs.h> |
24 | #include <linux/fsnotify.h> | ||
24 | #include <linux/pagemap.h> | 25 | #include <linux/pagemap.h> |
25 | #include <linux/highmem.h> | 26 | #include <linux/highmem.h> |
26 | #include <linux/time.h> | 27 | #include <linux/time.h> |
@@ -28,12 +29,15 @@ | |||
28 | #include <linux/string.h> | 29 | #include <linux/string.h> |
29 | #include <linux/smp_lock.h> | 30 | #include <linux/smp_lock.h> |
30 | #include <linux/backing-dev.h> | 31 | #include <linux/backing-dev.h> |
32 | #include <linux/mount.h> | ||
31 | #include <linux/mpage.h> | 33 | #include <linux/mpage.h> |
34 | #include <linux/namei.h> | ||
32 | #include <linux/swap.h> | 35 | #include <linux/swap.h> |
33 | #include <linux/writeback.h> | 36 | #include <linux/writeback.h> |
34 | #include <linux/statfs.h> | 37 | #include <linux/statfs.h> |
35 | #include <linux/compat.h> | 38 | #include <linux/compat.h> |
36 | #include <linux/bit_spinlock.h> | 39 | #include <linux/bit_spinlock.h> |
40 | #include <linux/security.h> | ||
37 | #include <linux/version.h> | 41 | #include <linux/version.h> |
38 | #include <linux/xattr.h> | 42 | #include <linux/xattr.h> |
39 | #include <linux/vmalloc.h> | 43 | #include <linux/vmalloc.h> |
@@ -48,8 +52,9 @@ | |||
48 | 52 | ||
49 | 53 | ||
50 | 54 | ||
51 | static noinline int create_subvol(struct btrfs_root *root, char *name, | 55 | static noinline int create_subvol(struct btrfs_root *root, |
52 | int namelen) | 56 | struct dentry *dentry, |
57 | char *name, int namelen) | ||
53 | { | 58 | { |
54 | struct btrfs_trans_handle *trans; | 59 | struct btrfs_trans_handle *trans; |
55 | struct btrfs_key key; | 60 | struct btrfs_key key; |
@@ -151,14 +156,11 @@ static noinline int create_subvol(struct btrfs_root *root, char *name, | |||
151 | trans = btrfs_start_transaction(new_root, 1); | 156 | trans = btrfs_start_transaction(new_root, 1); |
152 | BUG_ON(!trans); | 157 | BUG_ON(!trans); |
153 | 158 | ||
154 | ret = btrfs_create_subvol_root(new_root, trans, new_dirid, | 159 | ret = btrfs_create_subvol_root(new_root, dentry, trans, new_dirid, |
155 | BTRFS_I(dir)->block_group); | 160 | BTRFS_I(dir)->block_group); |
156 | if (ret) | 161 | if (ret) |
157 | goto fail; | 162 | goto fail; |
158 | 163 | ||
159 | /* Invalidate existing dcache entry for new subvolume. */ | ||
160 | btrfs_invalidate_dcache_root(root, name, namelen); | ||
161 | |||
162 | fail: | 164 | fail: |
163 | nr = trans->blocks_used; | 165 | nr = trans->blocks_used; |
164 | err = btrfs_commit_transaction(trans, new_root); | 166 | err = btrfs_commit_transaction(trans, new_root); |
@@ -210,6 +212,79 @@ fail_unlock: | |||
210 | return ret; | 212 | return ret; |
211 | } | 213 | } |
212 | 214 | ||
215 | /* copy of may_create in fs/namei.c() */ | ||
216 | static inline int btrfs_may_create(struct inode *dir, struct dentry *child) | ||
217 | { | ||
218 | if (child->d_inode) | ||
219 | return -EEXIST; | ||
220 | if (IS_DEADDIR(dir)) | ||
221 | return -ENOENT; | ||
222 | return inode_permission(dir, MAY_WRITE | MAY_EXEC); | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * Create a new subvolume below @parent. This is largely modeled after | ||
227 | * sys_mkdirat and vfs_mkdir, but we only do a single component lookup | ||
228 | * inside this filesystem so it's quite a bit simpler. | ||
229 | */ | ||
230 | static noinline int btrfs_mksubvol(struct path *parent, char *name, | ||
231 | int mode, int namelen) | ||
232 | { | ||
233 | struct dentry *dentry; | ||
234 | int error; | ||
235 | |||
236 | mutex_lock_nested(&parent->dentry->d_inode->i_mutex, I_MUTEX_PARENT); | ||
237 | |||
238 | dentry = lookup_one_len(name, parent->dentry, namelen); | ||
239 | error = PTR_ERR(dentry); | ||
240 | if (IS_ERR(dentry)) | ||
241 | goto out_unlock; | ||
242 | |||
243 | error = -EEXIST; | ||
244 | if (dentry->d_inode) | ||
245 | goto out_dput; | ||
246 | |||
247 | if (!IS_POSIXACL(parent->dentry->d_inode)) | ||
248 | mode &= ~current->fs->umask; | ||
249 | error = mnt_want_write(parent->mnt); | ||
250 | if (error) | ||
251 | goto out_dput; | ||
252 | |||
253 | error = btrfs_may_create(parent->dentry->d_inode, dentry); | ||
254 | if (error) | ||
255 | goto out_drop_write; | ||
256 | |||
257 | mode &= (S_IRWXUGO|S_ISVTX); | ||
258 | error = security_inode_mkdir(parent->dentry->d_inode, dentry, mode); | ||
259 | if (error) | ||
260 | goto out_drop_write; | ||
261 | |||
262 | /* | ||
263 | * Actually perform the low-level subvolume creation after all | ||
264 | * this VFS fuzz. | ||
265 | * | ||
266 | * Eventually we want to pass in an inode under which we create this | ||
267 | * subvolume, but for now all are under the filesystem root. | ||
268 | * | ||
269 | * Also we should pass on the mode eventually to allow creating new | ||
270 | * subvolume with specific mode bits. | ||
271 | */ | ||
272 | error = create_subvol(BTRFS_I(parent->dentry->d_inode)->root, dentry, | ||
273 | name, namelen); | ||
274 | if (error) | ||
275 | goto out_drop_write; | ||
276 | |||
277 | fsnotify_mkdir(parent->dentry->d_inode, dentry); | ||
278 | out_drop_write: | ||
279 | mnt_drop_write(parent->mnt); | ||
280 | out_dput: | ||
281 | dput(dentry); | ||
282 | out_unlock: | ||
283 | mutex_unlock(&parent->dentry->d_inode->i_mutex); | ||
284 | return error; | ||
285 | } | ||
286 | |||
287 | |||
213 | int btrfs_defrag_file(struct file *file) | 288 | int btrfs_defrag_file(struct file *file) |
214 | { | 289 | { |
215 | struct inode *inode = fdentry(file)->d_inode; | 290 | struct inode *inode = fdentry(file)->d_inode; |
@@ -395,9 +470,10 @@ out: | |||
395 | return ret; | 470 | return ret; |
396 | } | 471 | } |
397 | 472 | ||
398 | static noinline int btrfs_ioctl_snap_create(struct btrfs_root *root, | 473 | static noinline int btrfs_ioctl_snap_create(struct file *file, |
399 | void __user *arg) | 474 | void __user *arg) |
400 | { | 475 | { |
476 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; | ||
401 | struct btrfs_ioctl_vol_args *vol_args; | 477 | struct btrfs_ioctl_vol_args *vol_args; |
402 | struct btrfs_dir_item *di; | 478 | struct btrfs_dir_item *di; |
403 | struct btrfs_path *path; | 479 | struct btrfs_path *path; |
@@ -444,10 +520,14 @@ static noinline int btrfs_ioctl_snap_create(struct btrfs_root *root, | |||
444 | goto out; | 520 | goto out; |
445 | } | 521 | } |
446 | 522 | ||
447 | if (root == root->fs_info->tree_root) | 523 | if (root == root->fs_info->tree_root) { |
448 | ret = create_subvol(root, vol_args->name, namelen); | 524 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, |
449 | else | 525 | file->f_path.dentry->d_inode->i_mode, |
526 | namelen); | ||
527 | } else { | ||
450 | ret = create_snapshot(root, vol_args->name, namelen); | 528 | ret = create_snapshot(root, vol_args->name, namelen); |
529 | } | ||
530 | |||
451 | out: | 531 | out: |
452 | kfree(vol_args); | 532 | kfree(vol_args); |
453 | return ret; | 533 | return ret; |
@@ -761,7 +841,7 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
761 | 841 | ||
762 | switch (cmd) { | 842 | switch (cmd) { |
763 | case BTRFS_IOC_SNAP_CREATE: | 843 | case BTRFS_IOC_SNAP_CREATE: |
764 | return btrfs_ioctl_snap_create(root, (void __user *)arg); | 844 | return btrfs_ioctl_snap_create(file, (void __user *)arg); |
765 | case BTRFS_IOC_DEFRAG: | 845 | case BTRFS_IOC_DEFRAG: |
766 | return btrfs_ioctl_defrag(file); | 846 | return btrfs_ioctl_defrag(file); |
767 | case BTRFS_IOC_RESIZE: | 847 | case BTRFS_IOC_RESIZE: |