RE: [PATCH v3 08/10] fsdax: Dedup file range to use a compare function

"[email protected]" <[email protected]>
Newsgroups org.01.lists.linux-nvdimm,dev.linux.lists.nvdimm,dev.linux.lists.ocfs2-devel,org.kernel.vger.linux-btrfs,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-xfs
Message-ID <TY2PR01MB2921EBF98C2AC2900799FB85F4749@TY2PR01MB2921.jpnprd01.prod.outlook.com>
> -----Original Message-----
> From: Ritesh Harjani <[email protected]>
> Subject: Re: [PATCH v3 08/10] fsdax: Dedup file range to use a compare function
> 
> On 21/03/19 09:52AM, Shiyang Ruan wrote:
> > With dax we cannot deal with readpage() etc. So, we create a dax
> > comparison funciton which is similar with
> > vfs_dedupe_file_range_compare().
> > And introduce dax_remap_file_range_prep() for filesystem use.
> >
> > Signed-off-by: Goldwyn Rodrigues <[email protected]>
> > Signed-off-by: Shiyang Ruan <[email protected]>
> > ---
> >  fs/dax.c             | 56
> ++++++++++++++++++++++++++++++++++++++++++++
> >  fs/remap_range.c     | 45 ++++++++++++++++++++++++++++-------
> >  fs/xfs/xfs_reflink.c |  9 +++++--
> >  include/linux/dax.h  |  4 ++++
> >  include/linux/fs.h   | 15 ++++++++----
> >  5 files changed, 115 insertions(+), 14 deletions(-)
> >
> > diff --git a/fs/dax.c b/fs/dax.c
> > index 348297b38f76..76f81f1d76ec 100644
> > --- a/fs/dax.c
> > +++ b/fs/dax.c
> > @@ -1833,3 +1833,59 @@ 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_actor(struct inode *ino1, loff_t pos1,
> > +		struct inode *ino2, loff_t pos2, loff_t len, void *data,
> > +		struct iomap *smap, struct iomap *dmap) {
> > +	void *saddr, *daddr;
> > +	bool *same = data;
> > +	int ret;
> > +
> > +	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;
> > +	}
> > +
> > +	ret = dax_iomap_direct_access(smap, pos1, ALIGN(pos1 + len, PAGE_SIZE),
> > +				      &saddr, NULL);
> 
> shouldn't it take len as the second argument?

The second argument of dax_iomap_direct_access() means offset, and the third one means length.  So, I think this is right.

> 
> > +	if (ret < 0)
> > +		return -EIO;
> > +
> > +	ret = dax_iomap_direct_access(dmap, pos2, ALIGN(pos2 + len, PAGE_SIZE),
> > +				      &daddr, NULL);
> 
> ditto.
> > +	if (ret < 0)
> > +		return -EIO;
> > +
> > +	*same = !memcmp(saddr, daddr, len);
> > +	return len;
> > +}
> > +
> > +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 id, ret = 0;
> > +
> > +	id = dax_read_lock();
> > +	while (len) {
> > +		ret = iomap_apply2(src, srcoff, dest, destoff, len, 0, ops,
> > +				   is_same, dax_range_compare_actor);
> > +		if (ret < 0 || !*is_same)
> > +			goto out;
> > +
> > +		len -= ret;
> > +		srcoff += ret;
> > +		destoff += ret;
> > +	}
> > +	ret = 0;
> > +out:
> > +	dax_read_unlock(id);
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(dax_dedupe_file_range_compare);
> > diff --git a/fs/remap_range.c b/fs/remap_range.c index
> > 77dba3a49e65..9079390edaf3 100644
> > --- a/fs/remap_range.c
> > +++ b/fs/remap_range.c
> > @@ -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>
> > @@ -199,9 +200,9 @@ static void vfs_unlock_two_pages(struct page *page1,
> struct page *page2)
> >   * Compare extents of two files to see if they are the same.
> >   * Caller must have locked both inodes to prevent write races.
> >   */
> > -static int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
> > -					 struct inode *dest, loff_t destoff,
> > -					 loff_t len, bool *is_same)
> > +int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
> > +				  struct inode *dest, loff_t destoff,
> > +				  loff_t len, bool *is_same)
> >  {
> >  	loff_t src_poff;
> >  	loff_t dest_poff;
> > @@ -280,6 +281,7 @@ static int vfs_dedupe_file_range_compare(struct
> > inode *src, loff_t srcoff,
> >  out_error:
> >  	return error;
> >  }
> > +EXPORT_SYMBOL(vfs_dedupe_file_range_compare);
> >
> >  /*
> >   * Check that the two inodes are eligible for cloning, the ranges
> > make @@ -289,9 +291,11 @@ static int
> vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
> >   * 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)
> > +static 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 *ops)
> >  {
> >  	struct inode *inode_in = file_inode(file_in);
> >  	struct inode *inode_out = file_inode(file_out); @@ -351,8 +355,15 @@
> > 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(inode_in, pos_in,
> > -				inode_out, pos_out, *len, &is_same);
> > +		if (!IS_DAX(inode_in) && !IS_DAX(inode_out))
> > +			ret = vfs_dedupe_file_range_compare(inode_in, pos_in,
> > +					inode_out, pos_out, *len, &is_same);
> > +		else if (IS_DAX(inode_in) && IS_DAX(inode_out) && ops)
> > +			ret = dax_dedupe_file_range_compare(inode_in, pos_in,
> > +					inode_out, pos_out, *len, &is_same,
> > +					ops);
> > +		else
> > +			return -EINVAL;
> >  		if (ret)
> >  			return ret;
> >  		if (!is_same)
> 
> should we consider to check !is_same check b4?
> you should maybe relook at this error handling side of code.
> we still return len from actor function but is_same is set to false.
> So we are essentially returning ret (positive value), instead should be returning
> -EBADE because of !memcmp

The ret from compare function will not be positive, it will always be 0 or negative.  
In addition, if something wrong happens, is_same will always be false.  The caller could not get correct errno if check !is_same firstly.

> 
> > @@ -370,6 +381,24 @@ int generic_remap_file_range_prep(struct file
> > *file_in, loff_t pos_in,
> >
> >  	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(dax_remap_file_range_prep);
> > +
> > +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, diff
> > --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index
> > 6fa05fb78189..f5b3a3da36b7 100644
> > --- a/fs/xfs/xfs_reflink.c
> > +++ b/fs/xfs/xfs_reflink.c
> > @@ -1308,8 +1308,13 @@ 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))
> 
> if (!IS_DAX(inode_in)) no?
My mistake...
> 
> > +		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;
> >
> > diff --git a/include/linux/dax.h b/include/linux/dax.h index
> > 3275e01ed33d..32e1c34349f2 100644
> > --- a/include/linux/dax.h
> > +++ b/include/linux/dax.h
> > @@ -239,6 +239,10 @@ int dax_invalidate_mapping_entry_sync(struct
> address_space *mapping,
> >  				      pgoff_t index);
> >  s64 dax_iomap_zero(loff_t pos, u64 length, struct iomap *iomap,
> >  		struct iomap *srcmap);
> > +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);
> >  static inline bool dax_mapping(struct address_space *mapping)  {
> >  	return mapping->host && IS_DAX(mapping->host); diff --git
> > a/include/linux/fs.h b/include/linux/fs.h index
> > fd47deea7c17..2e6ec5bdf82a 100644
> > --- a/include/linux/fs.h
> > +++ b/include/linux/fs.h
> > @@ -68,6 +68,7 @@ struct fsverity_info;  struct fsverity_operations;
> > struct fs_context;  struct fs_parameter_spec;
> > +struct iomap_ops;
> >
> >  extern void __init inode_init(void);
> >  extern void __init inode_init_early(void); @@ -1910,13 +1911,19 @@
> > extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t
> > *);  extern ssize_t vfs_write(struct file *, const char __user *,
> > size_t, loff_t *);  extern ssize_t vfs_copy_file_range(struct file *, loff_t , struct
> file *,
> >  				   loff_t, size_t, unsigned int);
> > +typedef int (*compare_range_t)(struct inode *src, loff_t srcpos,
> > +			       struct inode *dest, loff_t destpos,
> > +			       loff_t len, bool *is_same);
> 
> Is this used anywhere?

No, I forgot to remove it...


--
Thanks,
Ruan Shiyang.
> 
> >  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 *count, unsigned int remap_flags); 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);
> >  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);
> > --
> > 2.30.1
> >
> >
> >
_______________________________________________
Linux-nvdimm mailing list -- [email protected]
To unsubscribe send an email to [email protected]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.