]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/btrfs/ioctl.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[linux.git] / fs / btrfs / ioctl.c
index 89d5db7eb452c20f309d93fceaed2cc34eeff5da..e79ff6b90cb71bb131426b97838c369ae0e6f48c 100644 (file)
@@ -2807,14 +2807,11 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 len,
 #define BTRFS_MAX_DEDUPE_LEN   (16 * 1024 * 1024)
 
 static long btrfs_ioctl_file_extent_same(struct file *file,
-                                        void __user *argp)
+                       struct btrfs_ioctl_same_args __user *argp)
 {
-       struct btrfs_ioctl_same_args tmp;
        struct btrfs_ioctl_same_args *same;
        struct btrfs_ioctl_same_extent_info *info;
-       struct inode *src = file->f_dentry->d_inode;
-       struct file *dst_file = NULL;
-       struct inode *dst;
+       struct inode *src = file_inode(file);
        u64 off;
        u64 len;
        int i;
@@ -2822,6 +2819,7 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
        unsigned long size;
        u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize;
        bool is_admin = capable(CAP_SYS_ADMIN);
+       u16 count;
 
        if (!(file->f_mode & FMODE_READ))
                return -EINVAL;
@@ -2830,17 +2828,14 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
        if (ret)
                return ret;
 
-       if (copy_from_user(&tmp,
-                          (struct btrfs_ioctl_same_args __user *)argp,
-                          sizeof(tmp))) {
+       if (get_user(count, &argp->dest_count)) {
                ret = -EFAULT;
                goto out;
        }
 
-       size = sizeof(tmp) +
-               tmp.dest_count * sizeof(struct btrfs_ioctl_same_extent_info);
+       size = offsetof(struct btrfs_ioctl_same_args __user, info[count]);
 
-       same = memdup_user((struct btrfs_ioctl_same_args __user *)argp, size);
+       same = memdup_user(argp, size);
 
        if (IS_ERR(same)) {
                ret = PTR_ERR(same);
@@ -2877,52 +2872,35 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
                goto out;
 
        /* pre-format output fields to sane values */
-       for (i = 0; i < same->dest_count; i++) {
+       for (i = 0; i < count; i++) {
                same->info[i].bytes_deduped = 0ULL;
                same->info[i].status = 0;
        }
 
-       ret = 0;
-       for (i = 0; i < same->dest_count; i++) {
-               info = &same->info[i];
-
-               dst_file = fget(info->fd);
-               if (!dst_file) {
+       for (i = 0, info = same->info; i < count; i++, info++) {
+               struct inode *dst;
+               struct fd dst_file = fdget(info->fd);
+               if (!dst_file.file) {
                        info->status = -EBADF;
-                       goto next;
+                       continue;
                }
+               dst = file_inode(dst_file.file);
 
-               if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) {
+               if (!(is_admin || (dst_file.file->f_mode & FMODE_WRITE))) {
                        info->status = -EINVAL;
-                       goto next;
-               }
-
-               info->status = -EXDEV;
-               if (file->f_path.mnt != dst_file->f_path.mnt)
-                       goto next;
-
-               dst = dst_file->f_dentry->d_inode;
-               if (src->i_sb != dst->i_sb)
-                       goto next;
-
-               if (S_ISDIR(dst->i_mode)) {
+               } else if (file->f_path.mnt != dst_file.file->f_path.mnt) {
+                       info->status = -EXDEV;
+               } else if (S_ISDIR(dst->i_mode)) {
                        info->status = -EISDIR;
-                       goto next;
-               }
-
-               if (!S_ISREG(dst->i_mode)) {
+               } else if (!S_ISREG(dst->i_mode)) {
                        info->status = -EACCES;
-                       goto next;
+               } else {
+                       info->status = btrfs_extent_same(src, off, len, dst,
+                                                       info->logical_offset);
+                       if (info->status == 0)
+                               info->bytes_deduped += len;
                }
-
-               info->status = btrfs_extent_same(src, off, len, dst,
-                                               info->logical_offset);
-               if (info->status == 0)
-                       info->bytes_deduped += len;
-
-next:
-               if (dst_file)
-                       fput(dst_file);
+               fdput(dst_file);
        }
 
        ret = copy_to_user(argp, same, size);
@@ -3562,6 +3540,11 @@ static long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
                up_read(&info->groups_sem);
        }
 
+       /*
+        * Global block reserve, exported as a space_info
+        */
+       slot_count++;
+
        /* space_slots == 0 means they are asking for a count */
        if (space_args.space_slots == 0) {
                space_args.total_spaces = slot_count;
@@ -3620,6 +3603,21 @@ static long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
                up_read(&info->groups_sem);
        }
 
+       /*
+        * Add global block reserve
+        */
+       if (slot_count) {
+               struct btrfs_block_rsv *block_rsv = &root->fs_info->global_block_rsv;
+
+               spin_lock(&block_rsv->lock);
+               space.total_bytes = block_rsv->size;
+               space.used_bytes = block_rsv->size - block_rsv->reserved;
+               spin_unlock(&block_rsv->lock);
+               space.flags = BTRFS_SPACE_INFO_GLOBAL_RSV;
+               memcpy(dest, &space, sizeof(space));
+               space_args.total_spaces++;
+       }
+
        user_dest = (struct btrfs_ioctl_space_info __user *)
                (arg + sizeof(struct btrfs_ioctl_space_args));