diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2015-12-19 03:55:59 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-01-01 02:36:19 -0500 |
commit | 54dbc15172375641ef03399e8f911d7165eb90fb (patch) | |
tree | b85a2df3b98719f4cf6493d69409588886276833 /fs/read_write.c | |
parent | d79bdd52d8be70d0e7024ac6715eee860a19834a (diff) |
vfs: hoist the btrfs deduplication ioctl to the vfs
Hoist the btrfs EXTENT_SAME ioctl up to the VFS and make the name
more systematic (FIDEDUPERANGE).
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/read_write.c')
-rw-r--r-- | fs/read_write.c | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/fs/read_write.c b/fs/read_write.c index 60ee26941231..2116e74a83d3 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -1523,3 +1523,103 @@ int vfs_clone_file_range(struct file *file_in, loff_t pos_in, | |||
1523 | return ret; | 1523 | return ret; |
1524 | } | 1524 | } |
1525 | EXPORT_SYMBOL(vfs_clone_file_range); | 1525 | EXPORT_SYMBOL(vfs_clone_file_range); |
1526 | |||
1527 | int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same) | ||
1528 | { | ||
1529 | struct file_dedupe_range_info *info; | ||
1530 | struct inode *src = file_inode(file); | ||
1531 | u64 off; | ||
1532 | u64 len; | ||
1533 | int i; | ||
1534 | int ret; | ||
1535 | bool is_admin = capable(CAP_SYS_ADMIN); | ||
1536 | u16 count = same->dest_count; | ||
1537 | struct file *dst_file; | ||
1538 | loff_t dst_off; | ||
1539 | ssize_t deduped; | ||
1540 | |||
1541 | if (!(file->f_mode & FMODE_READ)) | ||
1542 | return -EINVAL; | ||
1543 | |||
1544 | if (same->reserved1 || same->reserved2) | ||
1545 | return -EINVAL; | ||
1546 | |||
1547 | off = same->src_offset; | ||
1548 | len = same->src_length; | ||
1549 | |||
1550 | ret = -EISDIR; | ||
1551 | if (S_ISDIR(src->i_mode)) | ||
1552 | goto out; | ||
1553 | |||
1554 | ret = -EINVAL; | ||
1555 | if (!S_ISREG(src->i_mode)) | ||
1556 | goto out; | ||
1557 | |||
1558 | ret = clone_verify_area(file, off, len, false); | ||
1559 | if (ret < 0) | ||
1560 | goto out; | ||
1561 | ret = 0; | ||
1562 | |||
1563 | /* pre-format output fields to sane values */ | ||
1564 | for (i = 0; i < count; i++) { | ||
1565 | same->info[i].bytes_deduped = 0ULL; | ||
1566 | same->info[i].status = FILE_DEDUPE_RANGE_SAME; | ||
1567 | } | ||
1568 | |||
1569 | for (i = 0, info = same->info; i < count; i++, info++) { | ||
1570 | struct inode *dst; | ||
1571 | struct fd dst_fd = fdget(info->dest_fd); | ||
1572 | |||
1573 | dst_file = dst_fd.file; | ||
1574 | if (!dst_file) { | ||
1575 | info->status = -EBADF; | ||
1576 | goto next_loop; | ||
1577 | } | ||
1578 | dst = file_inode(dst_file); | ||
1579 | |||
1580 | ret = mnt_want_write_file(dst_file); | ||
1581 | if (ret) { | ||
1582 | info->status = ret; | ||
1583 | goto next_loop; | ||
1584 | } | ||
1585 | |||
1586 | dst_off = info->dest_offset; | ||
1587 | ret = clone_verify_area(dst_file, dst_off, len, true); | ||
1588 | if (ret < 0) { | ||
1589 | info->status = ret; | ||
1590 | goto next_file; | ||
1591 | } | ||
1592 | ret = 0; | ||
1593 | |||
1594 | if (info->reserved) { | ||
1595 | info->status = -EINVAL; | ||
1596 | } else if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) { | ||
1597 | info->status = -EINVAL; | ||
1598 | } else if (file->f_path.mnt != dst_file->f_path.mnt) { | ||
1599 | info->status = -EXDEV; | ||
1600 | } else if (S_ISDIR(dst->i_mode)) { | ||
1601 | info->status = -EISDIR; | ||
1602 | } else if (dst_file->f_op->dedupe_file_range == NULL) { | ||
1603 | info->status = -EINVAL; | ||
1604 | } else { | ||
1605 | deduped = dst_file->f_op->dedupe_file_range(file, off, | ||
1606 | len, dst_file, | ||
1607 | info->dest_offset); | ||
1608 | if (deduped == -EBADE) | ||
1609 | info->status = FILE_DEDUPE_RANGE_DIFFERS; | ||
1610 | else if (deduped < 0) | ||
1611 | info->status = deduped; | ||
1612 | else | ||
1613 | info->bytes_deduped += deduped; | ||
1614 | } | ||
1615 | |||
1616 | next_file: | ||
1617 | mnt_drop_write_file(dst_file); | ||
1618 | next_loop: | ||
1619 | fdput(dst_fd); | ||
1620 | } | ||
1621 | |||
1622 | out: | ||
1623 | return ret; | ||
1624 | } | ||
1625 | EXPORT_SYMBOL(vfs_dedupe_file_range); | ||