]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/commitdiff
vfs: dedupe: extract helper for a single dedup
authorMiklos Szeredi <mszeredi@redhat.com>
Fri, 6 Jul 2018 21:57:03 +0000 (23:57 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Fri, 6 Jul 2018 21:57:03 +0000 (23:57 +0200)
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>
fs/read_write.c

index c31794f92c2c3712f2087e74b20b2992a84dbf00..cce4ebac34a83671f3777cb4b52026c035c1aca6 100644 (file)
@@ -1964,6 +1964,44 @@ out_error:
 }
 EXPORT_SYMBOL(vfs_dedupe_file_range_compare);
 
+static int vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,
+                                    struct file *dst_file, loff_t dst_pos,
+                                    u64 len)
+{
+       s64 ret;
+
+       ret = mnt_want_write_file(dst_file);
+       if (ret)
+               return ret;
+
+       ret = clone_verify_area(dst_file, dst_pos, len, true);
+       if (ret < 0)
+               goto out_drop_write;
+
+       ret = -EINVAL;
+       if (!(capable(CAP_SYS_ADMIN) || (dst_file->f_mode & FMODE_WRITE)))
+               goto out_drop_write;
+
+       ret = -EXDEV;
+       if (src_file->f_path.mnt != dst_file->f_path.mnt)
+               goto out_drop_write;
+
+       ret = -EISDIR;
+       if (S_ISDIR(file_inode(dst_file)->i_mode))
+               goto out_drop_write;
+
+       ret = -EINVAL;
+       if (!dst_file->f_op->dedupe_file_range)
+               goto out_drop_write;
+
+       ret = dst_file->f_op->dedupe_file_range(src_file, src_pos,
+                                               dst_file, dst_pos, len);
+out_drop_write:
+       mnt_drop_write_file(dst_file);
+
+       return ret;
+}
+
 int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
 {
        struct file_dedupe_range_info *info;
@@ -1972,10 +2010,7 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
        u64 len;
        int i;
        int ret;
-       bool is_admin = capable(CAP_SYS_ADMIN);
        u16 count = same->dest_count;
-       struct file *dst_file;
-       loff_t dst_off;
        int deduped;
 
        if (!(file->f_mode & FMODE_READ))
@@ -2013,54 +2048,28 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
        }
 
        for (i = 0, info = same->info; i < count; i++, info++) {
-               struct inode *dst;
                struct fd dst_fd = fdget(info->dest_fd);
+               struct file *dst_file = dst_fd.file;
 
-               dst_file = dst_fd.file;
                if (!dst_file) {
                        info->status = -EBADF;
                        goto next_loop;
                }
-               dst = file_inode(dst_file);
-
-               ret = mnt_want_write_file(dst_file);
-               if (ret) {
-                       info->status = ret;
-                       goto next_fdput;
-               }
-
-               dst_off = info->dest_offset;
-               ret = clone_verify_area(dst_file, dst_off, len, true);
-               if (ret < 0) {
-                       info->status = ret;
-                       goto next_file;
-               }
-               ret = 0;
 
                if (info->reserved) {
                        info->status = -EINVAL;
-               } else if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) {
-                       info->status = -EINVAL;
-               } else if (file->f_path.mnt != dst_file->f_path.mnt) {
-                       info->status = -EXDEV;
-               } else if (S_ISDIR(dst->i_mode)) {
-                       info->status = -EISDIR;
-               } else if (dst_file->f_op->dedupe_file_range == NULL) {
-                       info->status = -EINVAL;
-               } else {
-                       deduped = dst_file->f_op->dedupe_file_range(file, off,
-                                                       dst_file,
-                                                       info->dest_offset, len);
-                       if (deduped == -EBADE)
-                               info->status = FILE_DEDUPE_RANGE_DIFFERS;
-                       else if (deduped < 0)
-                               info->status = deduped;
-                       else
-                               info->bytes_deduped += len;
+                       goto next_fdput;
                }
 
-next_file:
-               mnt_drop_write_file(dst_file);
+               deduped = vfs_dedupe_file_range_one(file, off, dst_file,
+                                                   info->dest_offset, len);
+               if (deduped == -EBADE)
+                       info->status = FILE_DEDUPE_RANGE_DIFFERS;
+               else if (deduped < 0)
+                       info->status = deduped;
+               else
+                       info->bytes_deduped = len;
+
 next_fdput:
                fdput(dst_fd);
 next_loop: