aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r--fs/btrfs/ioctl.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 4dbaf89b1337..9254b3d58dbe 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1458,7 +1458,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
1458 */ 1458 */
1459 1459
1460 /* the destination must be opened for writing */ 1460 /* the destination must be opened for writing */
1461 if (!(file->f_mode & FMODE_WRITE)) 1461 if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND))
1462 return -EINVAL; 1462 return -EINVAL;
1463 1463
1464 ret = mnt_want_write(file->f_path.mnt); 1464 ret = mnt_want_write(file->f_path.mnt);
@@ -1511,7 +1511,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
1511 1511
1512 /* determine range to clone */ 1512 /* determine range to clone */
1513 ret = -EINVAL; 1513 ret = -EINVAL;
1514 if (off >= src->i_size || off + len > src->i_size) 1514 if (off + len > src->i_size || off + len < off)
1515 goto out_unlock; 1515 goto out_unlock;
1516 if (len == 0) 1516 if (len == 0)
1517 olen = len = src->i_size - off; 1517 olen = len = src->i_size - off;
@@ -1578,6 +1578,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
1578 u64 disko = 0, diskl = 0; 1578 u64 disko = 0, diskl = 0;
1579 u64 datao = 0, datal = 0; 1579 u64 datao = 0, datal = 0;
1580 u8 comp; 1580 u8 comp;
1581 u64 endoff;
1581 1582
1582 size = btrfs_item_size_nr(leaf, slot); 1583 size = btrfs_item_size_nr(leaf, slot);
1583 read_extent_buffer(leaf, buf, 1584 read_extent_buffer(leaf, buf,
@@ -1712,9 +1713,18 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
1712 btrfs_release_path(root, path); 1713 btrfs_release_path(root, path);
1713 1714
1714 inode->i_mtime = inode->i_ctime = CURRENT_TIME; 1715 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
1715 if (new_key.offset + datal > inode->i_size) 1716
1716 btrfs_i_size_write(inode, 1717 /*
1717 new_key.offset + datal); 1718 * we round up to the block size at eof when
1719 * determining which extents to clone above,
1720 * but shouldn't round up the file size
1721 */
1722 endoff = new_key.offset + datal;
1723 if (endoff > off+olen)
1724 endoff = off+olen;
1725 if (endoff > inode->i_size)
1726 btrfs_i_size_write(inode, endoff);
1727
1718 BTRFS_I(inode)->flags = BTRFS_I(src)->flags; 1728 BTRFS_I(inode)->flags = BTRFS_I(src)->flags;
1719 ret = btrfs_update_inode(trans, root, inode); 1729 ret = btrfs_update_inode(trans, root, inode);
1720 BUG_ON(ret); 1730 BUG_ON(ret);