Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 128977
b: refs/heads/master
c: cb8e709
h: refs/heads/master
i:
  128975: e1f60a7
v: v3
  • Loading branch information
Christoph Hellwig authored and Chris Mason committed Oct 9, 2008
1 parent bea529f commit 3077bb4
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 15 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 833023e46c2a0180ff07d90252c24cb3fdea811d
refs/heads/master: cb8e70901d36f32017614f16d2cf7cc089544574
2 changes: 1 addition & 1 deletion trunk/fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -1791,7 +1791,7 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root);
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end);
int btrfs_writepages(struct address_space *mapping,
struct writeback_control *wbc);
int btrfs_create_subvol_root(struct btrfs_root *new_root,
int btrfs_create_subvol_root(struct btrfs_root *new_root, struct dentry *dentry,
struct btrfs_trans_handle *trans, u64 new_dirid,
struct btrfs_block_group_cache *block_group);

Expand Down
10 changes: 8 additions & 2 deletions trunk/fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -3420,11 +3420,12 @@ void btrfs_invalidate_dcache_root(struct btrfs_root *root, char *name,
/*
* create a new subvolume directory/inode (helper for the ioctl).
*/
int btrfs_create_subvol_root(struct btrfs_root *new_root,
int btrfs_create_subvol_root(struct btrfs_root *new_root, struct dentry *dentry,
struct btrfs_trans_handle *trans, u64 new_dirid,
struct btrfs_block_group_cache *block_group)
{
struct inode *inode;
int error;
u64 index = 0;

inode = btrfs_new_inode(trans, new_root, NULL, "..", 2, new_dirid,
Expand All @@ -3438,7 +3439,12 @@ int btrfs_create_subvol_root(struct btrfs_root *new_root,
inode->i_nlink = 1;
btrfs_i_size_write(inode, 0);

return btrfs_update_inode(trans, new_root, inode);
error = btrfs_update_inode(trans, new_root, inode);
if (error)
return error;

d_instantiate(dentry, inode);
return 0;
}

/* helper function for file defrag and space balancing. This
Expand Down
102 changes: 91 additions & 11 deletions trunk/fs/btrfs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,23 @@
#include <linux/buffer_head.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/fsnotify.h>
#include <linux/pagemap.h>
#include <linux/highmem.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/smp_lock.h>
#include <linux/backing-dev.h>
#include <linux/mount.h>
#include <linux/mpage.h>
#include <linux/namei.h>
#include <linux/swap.h>
#include <linux/writeback.h>
#include <linux/statfs.h>
#include <linux/compat.h>
#include <linux/bit_spinlock.h>
#include <linux/security.h>
#include <linux/version.h>
#include <linux/xattr.h>
#include <linux/vmalloc.h>
Expand All @@ -48,8 +52,9 @@



static noinline int create_subvol(struct btrfs_root *root, char *name,
int namelen)
static noinline int create_subvol(struct btrfs_root *root,
struct dentry *dentry,
char *name, int namelen)
{
struct btrfs_trans_handle *trans;
struct btrfs_key key;
Expand Down Expand Up @@ -151,14 +156,11 @@ static noinline int create_subvol(struct btrfs_root *root, char *name,
trans = btrfs_start_transaction(new_root, 1);
BUG_ON(!trans);

ret = btrfs_create_subvol_root(new_root, trans, new_dirid,
ret = btrfs_create_subvol_root(new_root, dentry, trans, new_dirid,
BTRFS_I(dir)->block_group);
if (ret)
goto fail;

/* Invalidate existing dcache entry for new subvolume. */
btrfs_invalidate_dcache_root(root, name, namelen);

fail:
nr = trans->blocks_used;
err = btrfs_commit_transaction(trans, new_root);
Expand Down Expand Up @@ -210,6 +212,79 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
return ret;
}

/* copy of may_create in fs/namei.c() */
static inline int btrfs_may_create(struct inode *dir, struct dentry *child)
{
if (child->d_inode)
return -EEXIST;
if (IS_DEADDIR(dir))
return -ENOENT;
return inode_permission(dir, MAY_WRITE | MAY_EXEC);
}

/*
* Create a new subvolume below @parent. This is largely modeled after
* sys_mkdirat and vfs_mkdir, but we only do a single component lookup
* inside this filesystem so it's quite a bit simpler.
*/
static noinline int btrfs_mksubvol(struct path *parent, char *name,
int mode, int namelen)
{
struct dentry *dentry;
int error;

mutex_lock_nested(&parent->dentry->d_inode->i_mutex, I_MUTEX_PARENT);

dentry = lookup_one_len(name, parent->dentry, namelen);
error = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto out_unlock;

error = -EEXIST;
if (dentry->d_inode)
goto out_dput;

if (!IS_POSIXACL(parent->dentry->d_inode))
mode &= ~current->fs->umask;
error = mnt_want_write(parent->mnt);
if (error)
goto out_dput;

error = btrfs_may_create(parent->dentry->d_inode, dentry);
if (error)
goto out_drop_write;

mode &= (S_IRWXUGO|S_ISVTX);
error = security_inode_mkdir(parent->dentry->d_inode, dentry, mode);
if (error)
goto out_drop_write;

/*
* Actually perform the low-level subvolume creation after all
* this VFS fuzz.
*
* Eventually we want to pass in an inode under which we create this
* subvolume, but for now all are under the filesystem root.
*
* Also we should pass on the mode eventually to allow creating new
* subvolume with specific mode bits.
*/
error = create_subvol(BTRFS_I(parent->dentry->d_inode)->root, dentry,
name, namelen);
if (error)
goto out_drop_write;

fsnotify_mkdir(parent->dentry->d_inode, dentry);
out_drop_write:
mnt_drop_write(parent->mnt);
out_dput:
dput(dentry);
out_unlock:
mutex_unlock(&parent->dentry->d_inode->i_mutex);
return error;
}


int btrfs_defrag_file(struct file *file)
{
struct inode *inode = fdentry(file)->d_inode;
Expand Down Expand Up @@ -395,9 +470,10 @@ static int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg)
return ret;
}

static noinline int btrfs_ioctl_snap_create(struct btrfs_root *root,
static noinline int btrfs_ioctl_snap_create(struct file *file,
void __user *arg)
{
struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
struct btrfs_ioctl_vol_args *vol_args;
struct btrfs_dir_item *di;
struct btrfs_path *path;
Expand Down Expand Up @@ -444,10 +520,14 @@ static noinline int btrfs_ioctl_snap_create(struct btrfs_root *root,
goto out;
}

if (root == root->fs_info->tree_root)
ret = create_subvol(root, vol_args->name, namelen);
else
if (root == root->fs_info->tree_root) {
ret = btrfs_mksubvol(&file->f_path, vol_args->name,
file->f_path.dentry->d_inode->i_mode,
namelen);
} else {
ret = create_snapshot(root, vol_args->name, namelen);
}

out:
kfree(vol_args);
return ret;
Expand Down Expand Up @@ -761,7 +841,7 @@ long btrfs_ioctl(struct file *file, unsigned int

switch (cmd) {
case BTRFS_IOC_SNAP_CREATE:
return btrfs_ioctl_snap_create(root, (void __user *)arg);
return btrfs_ioctl_snap_create(file, (void __user *)arg);
case BTRFS_IOC_DEFRAG:
return btrfs_ioctl_defrag(file);
case BTRFS_IOC_RESIZE:
Expand Down

0 comments on commit 3077bb4

Please sign in to comment.