Loading fs/read_write.c +49 −40 Original line number Diff line number Diff line Loading @@ -1964,6 +1964,44 @@ int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff, } 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; Loading @@ -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)) Loading Loading @@ -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; if (info->reserved) { info->status = -EINVAL; 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, 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; } info->bytes_deduped = len; next_file: mnt_drop_write_file(dst_file); next_fdput: fdput(dst_fd); next_loop: Loading Loading
fs/read_write.c +49 −40 Original line number Diff line number Diff line Loading @@ -1964,6 +1964,44 @@ int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff, } 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; Loading @@ -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)) Loading Loading @@ -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; if (info->reserved) { info->status = -EINVAL; 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, 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; } info->bytes_deduped = len; next_file: mnt_drop_write_file(dst_file); next_fdput: fdput(dst_fd); next_loop: Loading