aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.h2
-rw-r--r--fs/btrfs/inode.c10
-rw-r--r--fs/btrfs/ioctl.c102
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);
1791int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end); 1791int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end);
1792int btrfs_writepages(struct address_space *mapping, 1792int btrfs_writepages(struct address_space *mapping,
1793 struct writeback_control *wbc); 1793 struct writeback_control *wbc);
1794int btrfs_create_subvol_root(struct btrfs_root *new_root, 1794int 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 */
3423int btrfs_create_subvol_root(struct btrfs_root *new_root, 3423int 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
51static noinline int create_subvol(struct btrfs_root *root, char *name, 55static 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
162fail: 164fail:
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() */
216static 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 */
230static 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);
278out_drop_write:
279 mnt_drop_write(parent->mnt);
280out_dput:
281 dput(dentry);
282out_unlock:
283 mutex_unlock(&parent->dentry->d_inode->i_mutex);
284 return error;
285}
286
287
213int btrfs_defrag_file(struct file *file) 288int 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
398static noinline int btrfs_ioctl_snap_create(struct btrfs_root *root, 473static 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
451out: 531out:
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: