summaryrefslogtreecommitdiffstats
path: root/fs/overlayfs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/overlayfs/file.c')
-rw-r--r--fs/overlayfs/file.c43
1 files changed, 24 insertions, 19 deletions
diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
index 986313da0c88..84dd957efa24 100644
--- a/fs/overlayfs/file.c
+++ b/fs/overlayfs/file.c
@@ -434,14 +434,14 @@ enum ovl_copyop {
434 OVL_DEDUPE, 434 OVL_DEDUPE,
435}; 435};
436 436
437static ssize_t ovl_copyfile(struct file *file_in, loff_t pos_in, 437static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in,
438 struct file *file_out, loff_t pos_out, 438 struct file *file_out, loff_t pos_out,
439 u64 len, unsigned int flags, enum ovl_copyop op) 439 loff_t len, unsigned int flags, enum ovl_copyop op)
440{ 440{
441 struct inode *inode_out = file_inode(file_out); 441 struct inode *inode_out = file_inode(file_out);
442 struct fd real_in, real_out; 442 struct fd real_in, real_out;
443 const struct cred *old_cred; 443 const struct cred *old_cred;
444 ssize_t ret; 444 loff_t ret;
445 445
446 ret = ovl_real_fdget(file_out, &real_out); 446 ret = ovl_real_fdget(file_out, &real_out);
447 if (ret) 447 if (ret)
@@ -462,12 +462,13 @@ static ssize_t ovl_copyfile(struct file *file_in, loff_t pos_in,
462 462
463 case OVL_CLONE: 463 case OVL_CLONE:
464 ret = vfs_clone_file_range(real_in.file, pos_in, 464 ret = vfs_clone_file_range(real_in.file, pos_in,
465 real_out.file, pos_out, len); 465 real_out.file, pos_out, len, flags);
466 break; 466 break;
467 467
468 case OVL_DEDUPE: 468 case OVL_DEDUPE:
469 ret = vfs_dedupe_file_range_one(real_in.file, pos_in, 469 ret = vfs_dedupe_file_range_one(real_in.file, pos_in,
470 real_out.file, pos_out, len); 470 real_out.file, pos_out, len,
471 flags);
471 break; 472 break;
472 } 473 }
473 revert_creds(old_cred); 474 revert_creds(old_cred);
@@ -489,26 +490,31 @@ static ssize_t ovl_copy_file_range(struct file *file_in, loff_t pos_in,
489 OVL_COPY); 490 OVL_COPY);
490} 491}
491 492
492static int ovl_clone_file_range(struct file *file_in, loff_t pos_in, 493static loff_t ovl_remap_file_range(struct file *file_in, loff_t pos_in,
493 struct file *file_out, loff_t pos_out, u64 len) 494 struct file *file_out, loff_t pos_out,
495 loff_t len, unsigned int remap_flags)
494{ 496{
495 return ovl_copyfile(file_in, pos_in, file_out, pos_out, len, 0, 497 enum ovl_copyop op;
496 OVL_CLONE); 498
497} 499 if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
500 return -EINVAL;
501
502 if (remap_flags & REMAP_FILE_DEDUP)
503 op = OVL_DEDUPE;
504 else
505 op = OVL_CLONE;
498 506
499static int ovl_dedupe_file_range(struct file *file_in, loff_t pos_in,
500 struct file *file_out, loff_t pos_out, u64 len)
501{
502 /* 507 /*
503 * Don't copy up because of a dedupe request, this wouldn't make sense 508 * Don't copy up because of a dedupe request, this wouldn't make sense
504 * most of the time (data would be duplicated instead of deduplicated). 509 * most of the time (data would be duplicated instead of deduplicated).
505 */ 510 */
506 if (!ovl_inode_upper(file_inode(file_in)) || 511 if (op == OVL_DEDUPE &&
507 !ovl_inode_upper(file_inode(file_out))) 512 (!ovl_inode_upper(file_inode(file_in)) ||
513 !ovl_inode_upper(file_inode(file_out))))
508 return -EPERM; 514 return -EPERM;
509 515
510 return ovl_copyfile(file_in, pos_in, file_out, pos_out, len, 0, 516 return ovl_copyfile(file_in, pos_in, file_out, pos_out, len,
511 OVL_DEDUPE); 517 remap_flags, op);
512} 518}
513 519
514const struct file_operations ovl_file_operations = { 520const struct file_operations ovl_file_operations = {
@@ -525,6 +531,5 @@ const struct file_operations ovl_file_operations = {
525 .compat_ioctl = ovl_compat_ioctl, 531 .compat_ioctl = ovl_compat_ioctl,
526 532
527 .copy_file_range = ovl_copy_file_range, 533 .copy_file_range = ovl_copy_file_range,
528 .clone_file_range = ovl_clone_file_range, 534 .remap_file_range = ovl_remap_file_range,
529 .dedupe_file_range = ovl_dedupe_file_range,
530}; 535};