diff options
author | Miklos Szeredi <mszeredi@redhat.com> | 2018-07-06 17:57:03 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2018-07-06 17:57:03 -0400 |
commit | 1b4f42a1e33fec999e94802df13dbd7521315742 (patch) | |
tree | 26d5dd0ea591a033931c8f118f43efd06aa0a06b /fs/read_write.c | |
parent | 87eb5eb2423213ac0e7315ce5d275f1ff80e0263 (diff) |
vfs: dedupe: extract helper for a single dedup
Extract vfs_dedupe_file_range_one() helper to deal with a single dedup
request.
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs/read_write.c')
-rw-r--r-- | fs/read_write.c | 89 |
1 files changed, 49 insertions, 40 deletions
diff --git a/fs/read_write.c b/fs/read_write.c index c31794f92c2c..cce4ebac34a8 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -1964,6 +1964,44 @@ out_error: | |||
1964 | } | 1964 | } |
1965 | EXPORT_SYMBOL(vfs_dedupe_file_range_compare); | 1965 | EXPORT_SYMBOL(vfs_dedupe_file_range_compare); |
1966 | 1966 | ||
1967 | static int vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos, | ||
1968 | struct file *dst_file, loff_t dst_pos, | ||
1969 | u64 len) | ||
1970 | { | ||
1971 | s64 ret; | ||
1972 | |||
1973 | ret = mnt_want_write_file(dst_file); | ||
1974 | if (ret) | ||
1975 | return ret; | ||
1976 | |||
1977 | ret = clone_verify_area(dst_file, dst_pos, len, true); | ||
1978 | if (ret < 0) | ||
1979 | goto out_drop_write; | ||
1980 | |||
1981 | ret = -EINVAL; | ||
1982 | if (!(capable(CAP_SYS_ADMIN) || (dst_file->f_mode & FMODE_WRITE))) | ||
1983 | goto out_drop_write; | ||
1984 | |||
1985 | ret = -EXDEV; | ||
1986 | if (src_file->f_path.mnt != dst_file->f_path.mnt) | ||
1987 | goto out_drop_write; | ||
1988 | |||
1989 | ret = -EISDIR; | ||
1990 | if (S_ISDIR(file_inode(dst_file)->i_mode)) | ||
1991 | goto out_drop_write; | ||
1992 | |||
1993 | ret = -EINVAL; | ||
1994 | if (!dst_file->f_op->dedupe_file_range) | ||
1995 | goto out_drop_write; | ||
1996 | |||
1997 | ret = dst_file->f_op->dedupe_file_range(src_file, src_pos, | ||
1998 | dst_file, dst_pos, len); | ||
1999 | out_drop_write: | ||
2000 | mnt_drop_write_file(dst_file); | ||
2001 | |||
2002 | return ret; | ||
2003 | } | ||
2004 | |||
1967 | int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same) | 2005 | int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same) |
1968 | { | 2006 | { |
1969 | struct file_dedupe_range_info *info; | 2007 | struct file_dedupe_range_info *info; |
@@ -1972,10 +2010,7 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same) | |||
1972 | u64 len; | 2010 | u64 len; |
1973 | int i; | 2011 | int i; |
1974 | int ret; | 2012 | int ret; |
1975 | bool is_admin = capable(CAP_SYS_ADMIN); | ||
1976 | u16 count = same->dest_count; | 2013 | u16 count = same->dest_count; |
1977 | struct file *dst_file; | ||
1978 | loff_t dst_off; | ||
1979 | int deduped; | 2014 | int deduped; |
1980 | 2015 | ||
1981 | if (!(file->f_mode & FMODE_READ)) | 2016 | if (!(file->f_mode & FMODE_READ)) |
@@ -2013,54 +2048,28 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same) | |||
2013 | } | 2048 | } |
2014 | 2049 | ||
2015 | for (i = 0, info = same->info; i < count; i++, info++) { | 2050 | for (i = 0, info = same->info; i < count; i++, info++) { |
2016 | struct inode *dst; | ||
2017 | struct fd dst_fd = fdget(info->dest_fd); | 2051 | struct fd dst_fd = fdget(info->dest_fd); |
2052 | struct file *dst_file = dst_fd.file; | ||
2018 | 2053 | ||
2019 | dst_file = dst_fd.file; | ||
2020 | if (!dst_file) { | 2054 | if (!dst_file) { |
2021 | info->status = -EBADF; | 2055 | info->status = -EBADF; |
2022 | goto next_loop; | 2056 | goto next_loop; |
2023 | } | 2057 | } |
2024 | dst = file_inode(dst_file); | ||
2025 | |||
2026 | ret = mnt_want_write_file(dst_file); | ||
2027 | if (ret) { | ||
2028 | info->status = ret; | ||
2029 | goto next_fdput; | ||
2030 | } | ||
2031 | |||
2032 | dst_off = info->dest_offset; | ||
2033 | ret = clone_verify_area(dst_file, dst_off, len, true); | ||
2034 | if (ret < 0) { | ||
2035 | info->status = ret; | ||
2036 | goto next_file; | ||
2037 | } | ||
2038 | ret = 0; | ||
2039 | 2058 | ||
2040 | if (info->reserved) { | 2059 | if (info->reserved) { |
2041 | info->status = -EINVAL; | 2060 | info->status = -EINVAL; |
2042 | } else if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) { | 2061 | goto next_fdput; |
2043 | info->status = -EINVAL; | ||
2044 | } else if (file->f_path.mnt != dst_file->f_path.mnt) { | ||
2045 | info->status = -EXDEV; | ||
2046 | } else if (S_ISDIR(dst->i_mode)) { | ||
2047 | info->status = -EISDIR; | ||
2048 | } else if (dst_file->f_op->dedupe_file_range == NULL) { | ||
2049 | info->status = -EINVAL; | ||
2050 | } else { | ||
2051 | deduped = dst_file->f_op->dedupe_file_range(file, off, | ||
2052 | dst_file, | ||
2053 | info->dest_offset, len); | ||
2054 | if (deduped == -EBADE) | ||
2055 | info->status = FILE_DEDUPE_RANGE_DIFFERS; | ||
2056 | else if (deduped < 0) | ||
2057 | info->status = deduped; | ||
2058 | else | ||
2059 | info->bytes_deduped += len; | ||
2060 | } | 2062 | } |
2061 | 2063 | ||
2062 | next_file: | 2064 | deduped = vfs_dedupe_file_range_one(file, off, dst_file, |
2063 | mnt_drop_write_file(dst_file); | 2065 | info->dest_offset, len); |
2066 | if (deduped == -EBADE) | ||
2067 | info->status = FILE_DEDUPE_RANGE_DIFFERS; | ||
2068 | else if (deduped < 0) | ||
2069 | info->status = deduped; | ||
2070 | else | ||
2071 | info->bytes_deduped = len; | ||
2072 | |||
2064 | next_fdput: | 2073 | next_fdput: |
2065 | fdput(dst_fd); | 2074 | fdput(dst_fd); |
2066 | next_loop: | 2075 | next_loop: |