aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2008-10-09 13:39:39 -0400
committerChris Mason <chris.mason@oracle.com>2008-10-09 13:39:39 -0400
commitcb8e70901d36f32017614f16d2cf7cc089544574 (patch)
treebc31116dcb5bcdd6f2677a0c83b824e77c1ef097
parent833023e46c2a0180ff07d90252c24cb3fdea811d (diff)
Btrfs: Fix subvolume creation locking rules
Creating a subvolume is in many ways like a normal VFS ->mkdir, and we really need to play with the VFS topology locking rules. So instead of just creating the snapshot on disk and then later getting rid of confliting aliases do it correctly from the start. This will become especially important once we allow for subvolumes anywhere in the tree, and not just below a hidden root. Note that snapshots will need the same treatment, but do to the delay in creating them we can't do it currently. Chris promised to fix that issue, so I'll wait on that. Signed-off-by: Christoph Hellwig <hch@lst.de>
-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: