Merge branch 'for-linus-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/mason...
[linux-drm-fsl-dcu.git] / fs / btrfs / ioctl.c
index 74609b931ba5564da01de0955b8aa1d3142512d7..1c22c65185045c61b170db3f1db8f2c3627bbd84 100644 (file)
@@ -456,6 +456,13 @@ static noinline int create_subvol(struct inode *dir,
        if (ret)
                return ret;
 
+       /*
+        * Don't create subvolume whose level is not zero. Or qgroup will be
+        * screwed up since it assume subvolme qgroup's level to be 0.
+        */
+       if (btrfs_qgroup_level(objectid))
+               return -ENOSPC;
+
        btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);
        /*
         * The same as the snapshot creation, please see the comment
@@ -717,7 +724,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
        if (ret)
                goto fail;
 
-       inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry);
+       inode = btrfs_lookup_dentry(d_inode(dentry->d_parent), dentry);
        if (IS_ERR(inode)) {
                ret = PTR_ERR(inode);
                goto fail;
@@ -761,10 +768,10 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir)
 {
        int error;
 
-       if (!victim->d_inode)
+       if (d_really_is_negative(victim))
                return -ENOENT;
 
-       BUG_ON(victim->d_parent->d_inode != dir);
+       BUG_ON(d_inode(victim->d_parent) != dir);
        audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
 
        error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
@@ -772,8 +779,8 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir)
                return error;
        if (IS_APPEND(dir))
                return -EPERM;
-       if (check_sticky(dir, victim->d_inode) || IS_APPEND(victim->d_inode) ||
-           IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode))
+       if (check_sticky(dir, d_inode(victim)) || IS_APPEND(d_inode(victim)) ||
+           IS_IMMUTABLE(d_inode(victim)) || IS_SWAPFILE(d_inode(victim)))
                return -EPERM;
        if (isdir) {
                if (!d_is_dir(victim))
@@ -792,7 +799,7 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir)
 /* copy of may_create in fs/namei.c() */
 static inline int btrfs_may_create(struct inode *dir, struct dentry *child)
 {
-       if (child->d_inode)
+       if (d_really_is_positive(child))
                return -EEXIST;
        if (IS_DEADDIR(dir))
                return -ENOENT;
@@ -810,7 +817,7 @@ static noinline int btrfs_mksubvol(struct path *parent,
                                   u64 *async_transid, bool readonly,
                                   struct btrfs_qgroup_inherit *inherit)
 {
-       struct inode *dir  = parent->dentry->d_inode;
+       struct inode *dir  = d_inode(parent->dentry);
        struct dentry *dentry;
        int error;
 
@@ -824,7 +831,7 @@ static noinline int btrfs_mksubvol(struct path *parent,
                goto out_unlock;
 
        error = -EEXIST;
-       if (dentry->d_inode)
+       if (d_really_is_positive(dentry))
                goto out_dput;
 
        error = btrfs_may_create(dir, dentry);
@@ -1564,7 +1571,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
                goto out_free;
        }
 
-       do_div(new_size, root->sectorsize);
+       new_size = div_u64(new_size, root->sectorsize);
        new_size *= root->sectorsize;
 
        printk_in_rcu(KERN_INFO "BTRFS: new size for %s is %llu\n",
@@ -2294,7 +2301,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
 {
        struct dentry *parent = file->f_path.dentry;
        struct dentry *dentry;
-       struct inode *dir = parent->d_inode;
+       struct inode *dir = d_inode(parent);
        struct inode *inode;
        struct btrfs_root *root = BTRFS_I(dir)->root;
        struct btrfs_root *dest = NULL;
@@ -2333,12 +2340,12 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                goto out_unlock_dir;
        }
 
-       if (!dentry->d_inode) {
+       if (d_really_is_negative(dentry)) {
                err = -ENOENT;
                goto out_dput;
        }
 
-       inode = dentry->d_inode;
+       inode = d_inode(dentry);
        dest = BTRFS_I(inode)->root;
        if (!capable(CAP_SYS_ADMIN)) {
                /*
@@ -2403,7 +2410,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                        "Attempt to delete subvolume %llu during send",
                        dest->root_key.objectid);
                err = -EPERM;
-               goto out_dput;
+               goto out_unlock_inode;
        }
 
        d_invalidate(dentry);
@@ -2498,6 +2505,7 @@ out_up_write:
                                root_flags & ~BTRFS_ROOT_SUBVOL_DEAD);
                spin_unlock(&dest->root_item_lock);
        }
+out_unlock_inode:
        mutex_unlock(&inode->i_mutex);
        if (!err) {
                shrink_dcache_sb(root->fs_info->sb);
@@ -2897,6 +2905,9 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 len,
        if (src == dst)
                return -EINVAL;
 
+       if (len == 0)
+               return 0;
+
        btrfs_double_lock(src, loff, dst, dst_loff, len);
 
        ret = extent_same_check_offsets(src, loff, len);
@@ -3039,7 +3050,7 @@ out:
 static int check_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                     u64 disko)
 {
-       struct seq_list tree_mod_seq_elem = {};
+       struct seq_list tree_mod_seq_elem = SEQ_LIST_INIT(tree_mod_seq_elem);
        struct ulist *roots;
        struct ulist_iterator uiter;
        struct ulist_node *root_node = NULL;
@@ -3202,6 +3213,8 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
        key.offset = off;
 
        while (1) {
+               u64 next_key_min_offset = key.offset + 1;
+
                /*
                 * note the key will change type as we walk through the
                 * tree.
@@ -3282,7 +3295,7 @@ process_slot:
                        } else if (key.offset >= off + len) {
                                break;
                        }
-
+                       next_key_min_offset = key.offset + datal;
                        size = btrfs_item_size_nr(leaf, slot);
                        read_extent_buffer(leaf, buf,
                                           btrfs_item_ptr_offset(leaf, slot),
@@ -3497,7 +3510,7 @@ process_slot:
                                break;
                }
                btrfs_release_path(path);
-               key.offset++;
+               key.offset = next_key_min_offset;
        }
        ret = 0;
 
@@ -3626,6 +3639,11 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
        if (off + len == src->i_size)
                len = ALIGN(src->i_size, bs) - off;
 
+       if (len == 0) {
+               ret = 0;
+               goto out_unlock;
+       }
+
        /* verify the end result is block aligned */
        if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs) ||
            !IS_ALIGNED(destoff, bs))
@@ -4624,6 +4642,11 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg)
                                                sa->src, sa->dst);
        }
 
+       /* update qgroup status and info */
+       err = btrfs_run_qgroups(trans, root->fs_info);
+       if (err < 0)
+               btrfs_error(root->fs_info, ret,
+                           "failed to update qgroup status and info\n");
        err = btrfs_end_transaction(trans, root);
        if (err && !ret)
                ret = err;
@@ -4669,8 +4692,7 @@ static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg)
 
        /* FIXME: check if the IDs really exist */
        if (sa->create) {
-               ret = btrfs_create_qgroup(trans, root->fs_info, sa->qgroupid,
-                                         NULL);
+               ret = btrfs_create_qgroup(trans, root->fs_info, sa->qgroupid);
        } else {
                ret = btrfs_remove_qgroup(trans, root->fs_info, sa->qgroupid);
        }