Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 21 May 2014 20:40:13 +0000 (05:40 +0900)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 21 May 2014 20:40:13 +0000 (05:40 +0900)
Pull two btrfs fixes from Chris Mason:
 "This has two fixes that we've been testing for 3.16, but since both
  are safe and fix real bugs, it makes sense to send for 3.15 instead"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: send, fix incorrect ref access when using extrefs
  Btrfs: fix EIO on reading file after ioctl clone works on it

1  2 
fs/btrfs/ioctl.c

diff --combined fs/btrfs/ioctl.c
@@@ -2807,11 -2807,14 +2807,11 @@@ out_unlock
  #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;
        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;
        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);
                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);
@@@ -3120,6 -3142,8 +3120,8 @@@ process_slot
                        } else if (type == BTRFS_FILE_EXTENT_INLINE) {
                                u64 skip = 0;
                                u64 trim = 0;
+                               u64 aligned_end = 0;
                                if (off > key.offset) {
                                        skip = off - key.offset;
                                        new_key.offset += skip;
                                size -= skip + trim;
                                datal -= skip + trim;
  
+                               aligned_end = ALIGN(new_key.offset + datal,
+                                                   root->sectorsize);
                                ret = btrfs_drop_extents(trans, root, inode,
                                                         new_key.offset,
-                                                        new_key.offset + datal,
+                                                        aligned_end,
                                                         1);
                                if (ret) {
                                        if (ret != -EOPNOTSUPP)