]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/btrfs/ioctl.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/josef/btrfs...
[linux.git] / fs / btrfs / ioctl.c
index 338f2597bf7f8da2215e0d87289b01c94f9cfe7c..059546aa8fdf963c46c9ff188237bdf947d0ea06 100644 (file)
 #include <linux/slab.h>
 #include <linux/blkdev.h>
 #include <linux/uuid.h>
+#include <linux/btrfs.h>
 #include "compat.h"
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
 #include "btrfs_inode.h"
-#include "ioctl.h"
 #include "print-tree.h"
 #include "volumes.h"
 #include "locking.h"
@@ -367,7 +367,7 @@ static noinline int create_subvol(struct btrfs_root *root,
                                  struct dentry *dentry,
                                  char *name, int namelen,
                                  u64 *async_transid,
-                                 struct btrfs_qgroup_inherit **inherit)
+                                 struct btrfs_qgroup_inherit *inherit)
 {
        struct btrfs_trans_handle *trans;
        struct btrfs_key key;
@@ -401,8 +401,7 @@ static noinline int create_subvol(struct btrfs_root *root,
        if (IS_ERR(trans))
                return PTR_ERR(trans);
 
-       ret = btrfs_qgroup_inherit(trans, root->fs_info, 0, objectid,
-                                  inherit ? *inherit : NULL);
+       ret = btrfs_qgroup_inherit(trans, root->fs_info, 0, objectid, inherit);
        if (ret)
                goto fail;
 
@@ -533,7 +532,7 @@ static noinline int create_subvol(struct btrfs_root *root,
 
 static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
                           char *name, int namelen, u64 *async_transid,
-                          bool readonly, struct btrfs_qgroup_inherit **inherit)
+                          bool readonly, struct btrfs_qgroup_inherit *inherit)
 {
        struct inode *inode;
        struct btrfs_pending_snapshot *pending_snapshot;
@@ -552,10 +551,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
        pending_snapshot->dentry = dentry;
        pending_snapshot->root = root;
        pending_snapshot->readonly = readonly;
-       if (inherit) {
-               pending_snapshot->inherit = *inherit;
-               *inherit = NULL;        /* take responsibility to free it */
-       }
+       pending_snapshot->inherit = inherit;
 
        trans = btrfs_start_transaction(root->fs_info->extent_root, 6);
        if (IS_ERR(trans)) {
@@ -695,7 +691,7 @@ static noinline int btrfs_mksubvol(struct path *parent,
                                   char *name, int namelen,
                                   struct btrfs_root *snap_src,
                                   u64 *async_transid, bool readonly,
-                                  struct btrfs_qgroup_inherit **inherit)
+                                  struct btrfs_qgroup_inherit *inherit)
 {
        struct inode *dir  = parent->dentry->d_inode;
        struct dentry *dentry;
@@ -818,7 +814,7 @@ static int find_new_extents(struct btrfs_root *root,
 
        while(1) {
                ret = btrfs_search_forward(root, &min_key, &max_key,
-                                          path, 0, newer_than);
+                                          path, newer_than);
                if (ret != 0)
                        goto none;
                if (min_key.objectid != ino)
@@ -1206,6 +1202,12 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
                if (!(inode->i_sb->s_flags & MS_ACTIVE))
                        break;
 
+               if (btrfs_defrag_cancelled(root->fs_info)) {
+                       printk(KERN_DEBUG "btrfs: defrag_file cancelled\n");
+                       ret = -EAGAIN;
+                       break;
+               }
+
                if (!should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT,
                                         extent_thresh, &last_len, &skip,
                                         &defrag_end, range->flags &
@@ -1329,9 +1331,6 @@ static noinline int btrfs_ioctl_resize(struct file *file,
        int ret = 0;
        int mod = 0;
 
-       if (root->fs_info->sb->s_flags & MS_RDONLY)
-               return -EROFS;
-
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
@@ -1363,6 +1362,10 @@ static noinline int btrfs_ioctl_resize(struct file *file,
                *devstr = '\0';
                devstr = vol_args->name;
                devid = simple_strtoull(devstr, &end, 10);
+               if (!devid) {
+                       ret = -EINVAL;
+                       goto out_free;
+               }
                printk(KERN_INFO "btrfs: resizing devid %llu\n",
                       (unsigned long long)devid);
        }
@@ -1371,7 +1374,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
        if (!device) {
                printk(KERN_INFO "btrfs: resizer unable to find device %llu\n",
                       (unsigned long long)devid);
-               ret = -EINVAL;
+               ret = -ENODEV;
                goto out_free;
        }
 
@@ -1379,7 +1382,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
                printk(KERN_INFO "btrfs: resizer unable to apply on "
                       "readonly device %llu\n",
                       (unsigned long long)devid);
-               ret = -EINVAL;
+               ret = -EPERM;
                goto out_free;
        }
 
@@ -1401,7 +1404,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
        }
 
        if (device->is_tgtdev_for_dev_replace) {
-               ret = -EINVAL;
+               ret = -EPERM;
                goto out_free;
        }
 
@@ -1457,7 +1460,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
 static noinline int btrfs_ioctl_snap_create_transid(struct file *file,
                                char *name, unsigned long fd, int subvol,
                                u64 *transid, bool readonly,
-                               struct btrfs_qgroup_inherit **inherit)
+                               struct btrfs_qgroup_inherit *inherit)
 {
        int namelen;
        int ret = 0;
@@ -1566,7 +1569,7 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file,
 
        ret = btrfs_ioctl_snap_create_transid(file, vol_args->name,
                                              vol_args->fd, subvol, ptr,
-                                             readonly, &inherit);
+                                             readonly, inherit);
 
        if (ret == 0 && ptr &&
            copy_to_user(arg +
@@ -1863,7 +1866,7 @@ static noinline int search_ioctl(struct inode *inode,
        path->keep_locks = 1;
 
        while(1) {
-               ret = btrfs_search_forward(root, &key, &max_key, path, 0,
+               ret = btrfs_search_forward(root, &key, &max_key, path,
                                           sk->min_transid);
                if (ret != 0) {
                        if (ret > 0)
@@ -2171,6 +2174,12 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                shrink_dcache_sb(root->fs_info->sb);
                btrfs_invalidate_inodes(dest);
                d_delete(dentry);
+
+               /* the last ref */
+               if (dest->cache_inode) {
+                       iput(dest->cache_inode);
+                       dest->cache_inode = NULL;
+               }
        }
 out_dput:
        dput(dentry);
@@ -2211,10 +2220,10 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
                        ret = -EPERM;
                        goto out;
                }
-               ret = btrfs_defrag_root(root, 0);
+               ret = btrfs_defrag_root(root);
                if (ret)
                        goto out;
-               ret = btrfs_defrag_root(root->fs_info->extent_root, 0);
+               ret = btrfs_defrag_root(root->fs_info->extent_root);
                break;
        case S_IFREG:
                if (!(file->f_mode & FMODE_WRITE)) {
@@ -3111,7 +3120,7 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
        u64 transid;
        int ret;
 
-       trans = btrfs_attach_transaction(root);
+       trans = btrfs_attach_transaction_barrier(root);
        if (IS_ERR(trans)) {
                if (PTR_ERR(trans) != -ENOENT)
                        return PTR_ERR(trans);
@@ -3289,7 +3298,7 @@ static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg)
        struct inode_fs_paths *ipath = NULL;
        struct btrfs_path *path;
 
-       if (!capable(CAP_SYS_ADMIN))
+       if (!capable(CAP_DAC_READ_SEARCH))
                return -EPERM;
 
        path = btrfs_alloc_path();
@@ -3914,6 +3923,65 @@ static long btrfs_ioctl_set_received_subvol(struct file *file,
        return ret;
 }
 
+static int btrfs_ioctl_get_fslabel(struct file *file, void __user *arg)
+{
+       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
+       const char *label = root->fs_info->super_copy->label;
+       size_t len = strnlen(label, BTRFS_LABEL_SIZE);
+       int ret;
+
+       if (len == BTRFS_LABEL_SIZE) {
+               pr_warn("btrfs: label is too long, return the first %zu bytes\n",
+                       --len);
+       }
+
+       mutex_lock(&root->fs_info->volume_mutex);
+       ret = copy_to_user(arg, label, len);
+       mutex_unlock(&root->fs_info->volume_mutex);
+
+       return ret ? -EFAULT : 0;
+}
+
+static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg)
+{
+       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
+       struct btrfs_super_block *super_block = root->fs_info->super_copy;
+       struct btrfs_trans_handle *trans;
+       char label[BTRFS_LABEL_SIZE];
+       int ret;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (copy_from_user(label, arg, sizeof(label)))
+               return -EFAULT;
+
+       if (strnlen(label, BTRFS_LABEL_SIZE) == BTRFS_LABEL_SIZE) {
+               pr_err("btrfs: unable to set label with more than %d bytes\n",
+                      BTRFS_LABEL_SIZE - 1);
+               return -EINVAL;
+       }
+
+       ret = mnt_want_write_file(file);
+       if (ret)
+               return ret;
+
+       mutex_lock(&root->fs_info->volume_mutex);
+       trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               ret = PTR_ERR(trans);
+               goto out_unlock;
+       }
+
+       strcpy(super_block->label, label);
+       ret = btrfs_end_transaction(trans, root);
+
+out_unlock:
+       mutex_unlock(&root->fs_info->volume_mutex);
+       mnt_drop_write_file(file);
+       return ret;
+}
+
 long btrfs_ioctl(struct file *file, unsigned int
                cmd, unsigned long arg)
 {
@@ -4014,6 +4082,10 @@ long btrfs_ioctl(struct file *file, unsigned int
                return btrfs_ioctl_qgroup_limit(file, argp);
        case BTRFS_IOC_DEV_REPLACE:
                return btrfs_ioctl_dev_replace(root, argp);
+       case BTRFS_IOC_GET_FSLABEL:
+               return btrfs_ioctl_get_fslabel(file, argp);
+       case BTRFS_IOC_SET_FSLABEL:
+               return btrfs_ioctl_set_fslabel(file, argp);
        }
 
        return -ENOTTY;