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.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 7cf013349941..3351b1b24574 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2220,6 +2220,12 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
2220 !IS_ALIGNED(destoff, bs)) 2220 !IS_ALIGNED(destoff, bs))
2221 goto out_unlock; 2221 goto out_unlock;
2222 2222
2223 if (destoff > inode->i_size) {
2224 ret = btrfs_cont_expand(inode, inode->i_size, destoff);
2225 if (ret)
2226 goto out_unlock;
2227 }
2228
2223 /* do any pending delalloc/csum calc on src, one way or 2229 /* do any pending delalloc/csum calc on src, one way or
2224 another, and lock file content */ 2230 another, and lock file content */
2225 while (1) { 2231 while (1) {
@@ -2236,6 +2242,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
2236 btrfs_wait_ordered_range(src, off, len); 2242 btrfs_wait_ordered_range(src, off, len);
2237 } 2243 }
2238 2244
2245 /* truncate page cache pages from target inode range */
2246 truncate_inode_pages_range(&inode->i_data, off,
2247 ALIGN(off + len, PAGE_CACHE_SIZE) - 1);
2248
2239 /* clone data */ 2249 /* clone data */
2240 key.objectid = btrfs_ino(src); 2250 key.objectid = btrfs_ino(src);
2241 key.type = BTRFS_EXTENT_DATA_KEY; 2251 key.type = BTRFS_EXTENT_DATA_KEY;
@@ -2321,14 +2331,21 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
2321 2331
2322 if (type == BTRFS_FILE_EXTENT_REG || 2332 if (type == BTRFS_FILE_EXTENT_REG ||
2323 type == BTRFS_FILE_EXTENT_PREALLOC) { 2333 type == BTRFS_FILE_EXTENT_PREALLOC) {
2334 /*
2335 * a | --- range to clone ---| b
2336 * | ------------- extent ------------- |
2337 */
2338
2339 /* substract range b */
2340 if (key.offset + datal > off + len)
2341 datal = off + len - key.offset;
2342
2343 /* substract range a */
2324 if (off > key.offset) { 2344 if (off > key.offset) {
2325 datao += off - key.offset; 2345 datao += off - key.offset;
2326 datal -= off - key.offset; 2346 datal -= off - key.offset;
2327 } 2347 }
2328 2348
2329 if (key.offset + datal > off + len)
2330 datal = off + len - key.offset;
2331
2332 ret = btrfs_drop_extents(trans, inode, 2349 ret = btrfs_drop_extents(trans, inode,
2333 new_key.offset, 2350 new_key.offset,
2334 new_key.offset + datal, 2351 new_key.offset + datal,