forked from Minki/linux
fsdax: dedup file range to use a compare function
With dax we cannot deal with readpage() etc. So, we create a dax comparison function which is similar with vfs_dedupe_file_range_compare(). And introduce dax_remap_file_range_prep() for filesystem use. Link: https://lkml.kernel.org/r/20220603053738.1218681-13-ruansy.fnst@fujitsu.com Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com> Signed-off-by: Shiyang Ruan <ruansy.fnst@fujitsu.com> Reviewed-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Dan Williams <dan.j.wiliams@intel.com> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Dave Chinner <david@fromorbit.com> Cc: Goldwyn Rodrigues <rgoldwyn@suse.de> Cc: Jane Chu <jane.chu@oracle.com> Cc: Matthew Wilcox <willy@infradead.org> Cc: Miaohe Lin <linmiaohe@huawei.com> Cc: Naoya Horiguchi <naoya.horiguchi@nec.com> Cc: Ritesh Harjani <riteshh@linux.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
8dbfc76da3
commit
6f7db3894a
82
fs/dax.c
82
fs/dax.c
@ -1873,3 +1873,85 @@ vm_fault_t dax_finish_sync_fault(struct vm_fault *vmf,
|
||||
return dax_insert_pfn_mkwrite(vmf, pfn, order);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dax_finish_sync_fault);
|
||||
|
||||
static loff_t dax_range_compare_iter(struct iomap_iter *it_src,
|
||||
struct iomap_iter *it_dest, u64 len, bool *same)
|
||||
{
|
||||
const struct iomap *smap = &it_src->iomap;
|
||||
const struct iomap *dmap = &it_dest->iomap;
|
||||
loff_t pos1 = it_src->pos, pos2 = it_dest->pos;
|
||||
void *saddr, *daddr;
|
||||
int id, ret;
|
||||
|
||||
len = min(len, min(smap->length, dmap->length));
|
||||
|
||||
if (smap->type == IOMAP_HOLE && dmap->type == IOMAP_HOLE) {
|
||||
*same = true;
|
||||
return len;
|
||||
}
|
||||
|
||||
if (smap->type == IOMAP_HOLE || dmap->type == IOMAP_HOLE) {
|
||||
*same = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
id = dax_read_lock();
|
||||
ret = dax_iomap_direct_access(smap, pos1, ALIGN(pos1 + len, PAGE_SIZE),
|
||||
&saddr, NULL);
|
||||
if (ret < 0)
|
||||
goto out_unlock;
|
||||
|
||||
ret = dax_iomap_direct_access(dmap, pos2, ALIGN(pos2 + len, PAGE_SIZE),
|
||||
&daddr, NULL);
|
||||
if (ret < 0)
|
||||
goto out_unlock;
|
||||
|
||||
*same = !memcmp(saddr, daddr, len);
|
||||
if (!*same)
|
||||
len = 0;
|
||||
dax_read_unlock(id);
|
||||
return len;
|
||||
|
||||
out_unlock:
|
||||
dax_read_unlock(id);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
int dax_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
|
||||
struct inode *dst, loff_t dstoff, loff_t len, bool *same,
|
||||
const struct iomap_ops *ops)
|
||||
{
|
||||
struct iomap_iter src_iter = {
|
||||
.inode = src,
|
||||
.pos = srcoff,
|
||||
.len = len,
|
||||
.flags = IOMAP_DAX,
|
||||
};
|
||||
struct iomap_iter dst_iter = {
|
||||
.inode = dst,
|
||||
.pos = dstoff,
|
||||
.len = len,
|
||||
.flags = IOMAP_DAX,
|
||||
};
|
||||
int ret;
|
||||
|
||||
while ((ret = iomap_iter(&src_iter, ops)) > 0) {
|
||||
while ((ret = iomap_iter(&dst_iter, ops)) > 0) {
|
||||
dst_iter.processed = dax_range_compare_iter(&src_iter,
|
||||
&dst_iter, len, same);
|
||||
}
|
||||
if (ret <= 0)
|
||||
src_iter.processed = ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dax_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
||||
struct file *file_out, loff_t pos_out,
|
||||
loff_t *len, unsigned int remap_flags,
|
||||
const struct iomap_ops *ops)
|
||||
{
|
||||
return __generic_remap_file_range_prep(file_in, pos_in, file_out,
|
||||
pos_out, len, remap_flags, ops);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dax_remap_file_range_prep);
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/compat.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/dax.h>
|
||||
#include "internal.h"
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
@ -271,9 +272,11 @@ out_error:
|
||||
* If there's an error, then the usual negative error code is returned.
|
||||
* Otherwise returns 0 with *len set to the request length.
|
||||
*/
|
||||
int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
||||
struct file *file_out, loff_t pos_out,
|
||||
loff_t *len, unsigned int remap_flags)
|
||||
int
|
||||
__generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
||||
struct file *file_out, loff_t pos_out,
|
||||
loff_t *len, unsigned int remap_flags,
|
||||
const struct iomap_ops *dax_read_ops)
|
||||
{
|
||||
struct inode *inode_in = file_inode(file_in);
|
||||
struct inode *inode_out = file_inode(file_out);
|
||||
@ -333,8 +336,18 @@ int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
||||
if (remap_flags & REMAP_FILE_DEDUP) {
|
||||
bool is_same = false;
|
||||
|
||||
ret = vfs_dedupe_file_range_compare(file_in, pos_in,
|
||||
file_out, pos_out, *len, &is_same);
|
||||
if (*len == 0)
|
||||
return 0;
|
||||
|
||||
if (!IS_DAX(inode_in))
|
||||
ret = vfs_dedupe_file_range_compare(file_in, pos_in,
|
||||
file_out, pos_out, *len, &is_same);
|
||||
else if (dax_read_ops)
|
||||
ret = dax_dedupe_file_range_compare(inode_in, pos_in,
|
||||
inode_out, pos_out, *len, &is_same,
|
||||
dax_read_ops);
|
||||
else
|
||||
return -EINVAL;
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!is_same)
|
||||
@ -352,6 +365,14 @@ int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
||||
struct file *file_out, loff_t pos_out,
|
||||
loff_t *len, unsigned int remap_flags)
|
||||
{
|
||||
return __generic_remap_file_range_prep(file_in, pos_in, file_out,
|
||||
pos_out, len, remap_flags, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(generic_remap_file_range_prep);
|
||||
|
||||
loff_t do_clone_file_range(struct file *file_in, loff_t pos_in,
|
||||
|
@ -1367,8 +1367,12 @@ xfs_reflink_remap_prep(
|
||||
if (IS_DAX(inode_in) || IS_DAX(inode_out))
|
||||
goto out_unlock;
|
||||
|
||||
ret = generic_remap_file_range_prep(file_in, pos_in, file_out, pos_out,
|
||||
len, remap_flags);
|
||||
if (!IS_DAX(inode_in))
|
||||
ret = generic_remap_file_range_prep(file_in, pos_in, file_out,
|
||||
pos_out, len, remap_flags);
|
||||
else
|
||||
ret = dax_remap_file_range_prep(file_in, pos_in, file_out,
|
||||
pos_out, len, remap_flags, &xfs_read_iomap_ops);
|
||||
if (ret || *len == 0)
|
||||
goto out_unlock;
|
||||
|
||||
|
@ -246,6 +246,14 @@ vm_fault_t dax_finish_sync_fault(struct vm_fault *vmf,
|
||||
int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index);
|
||||
int dax_invalidate_mapping_entry_sync(struct address_space *mapping,
|
||||
pgoff_t index);
|
||||
int dax_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
|
||||
struct inode *dest, loff_t destoff,
|
||||
loff_t len, bool *is_same,
|
||||
const struct iomap_ops *ops);
|
||||
int dax_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
||||
struct file *file_out, loff_t pos_out,
|
||||
loff_t *len, unsigned int remap_flags,
|
||||
const struct iomap_ops *ops);
|
||||
static inline bool dax_mapping(struct address_space *mapping)
|
||||
{
|
||||
return mapping->host && IS_DAX(mapping->host);
|
||||
|
@ -74,6 +74,7 @@ struct fsverity_operations;
|
||||
struct fs_context;
|
||||
struct fs_parameter_spec;
|
||||
struct fileattr;
|
||||
struct iomap_ops;
|
||||
|
||||
extern void __init inode_init(void);
|
||||
extern void __init inode_init_early(void);
|
||||
@ -2070,10 +2071,13 @@ extern ssize_t vfs_copy_file_range(struct file *, loff_t , struct file *,
|
||||
extern ssize_t generic_copy_file_range(struct file *file_in, loff_t pos_in,
|
||||
struct file *file_out, loff_t pos_out,
|
||||
size_t len, unsigned int flags);
|
||||
extern int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
||||
struct file *file_out, loff_t pos_out,
|
||||
loff_t *count,
|
||||
unsigned int remap_flags);
|
||||
int __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
||||
struct file *file_out, loff_t pos_out,
|
||||
loff_t *len, unsigned int remap_flags,
|
||||
const struct iomap_ops *dax_read_ops);
|
||||
int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
||||
struct file *file_out, loff_t pos_out,
|
||||
loff_t *count, unsigned int remap_flags);
|
||||
extern loff_t do_clone_file_range(struct file *file_in, loff_t pos_in,
|
||||
struct file *file_out, loff_t pos_out,
|
||||
loff_t len, unsigned int remap_flags);
|
||||
|
Loading…
Reference in New Issue
Block a user