diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 23 |
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, |