xfsprogs: io/copy_range: cover corner case (fd_in == fd_out)
diff mbox series

Message ID 20190903105632.11667-1-yin-jianhong@163.com
State New
Headers show
Series
  • xfsprogs: io/copy_range: cover corner case (fd_in == fd_out)
Related show

Commit Message

Jianhong.Yin Sept. 3, 2019, 10:56 a.m. UTC
Related bug:
  copy_file_range return "Invalid argument" when copy in the same file
  https://bugzilla.kernel.org/show_bug.cgi?id=202935

if argument of option -f is "-", use current file->fd as fd_in

Usage:
  xfs_io -c 'copy_range -f -' some_file

Signed-off-by: Jianhong Yin <yin-jianhong@163.com>
---
 io/copy_file_range.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

Comments

Zorro Lang Sept. 3, 2019, 11:59 a.m. UTC | #1
On Tue, Sep 03, 2019 at 06:56:32PM +0800, Jianhong.Yin wrote:
> Related bug:
>   copy_file_range return "Invalid argument" when copy in the same file
>   https://bugzilla.kernel.org/show_bug.cgi?id=202935
> 
> if argument of option -f is "-", use current file->fd as fd_in
> 
> Usage:
>   xfs_io -c 'copy_range -f -' some_file
> 
> Signed-off-by: Jianhong Yin <yin-jianhong@163.com>
> ---

Hi,

Actually, I'm thinking about if you need same 'fd' or same file path?
If you just need same file path, I think

  # xfs_io -c "copy_range testfile" testfile

already can help that. The only one problem stop you doing that is
"copy_dst_truncate()".

If all above I suppose is right, we can turn to talk about if that
copy_dst_truncate() is necessary, or how can we skip it.

Thanks,
Zorro

>  io/copy_file_range.c | 27 ++++++++++++++++++---------
>  1 file changed, 18 insertions(+), 9 deletions(-)
> 
> diff --git a/io/copy_file_range.c b/io/copy_file_range.c
> index b7b9fd88..2dde8a31 100644
> --- a/io/copy_file_range.c
> +++ b/io/copy_file_range.c
> @@ -28,6 +28,7 @@ copy_range_help(void)
>                            at position 0\n\
>   'copy_range -f 2' - copies all bytes from open file 2 into the current open file\n\
>                            at position 0\n\
> + 'copy_range -f -' - copies all bytes from current open file append the current open file\n\
>  "));
>  }
>  
> @@ -114,11 +115,15 @@ copy_range_f(int argc, char **argv)
>  			}
>  			break;
>  		case 'f':
> -			src_file_nr = atoi(argv[1]);
> -			if (src_file_nr < 0 || src_file_nr >= filecount) {
> -				printf(_("file value %d is out of range (0-%d)\n"),
> -					src_file_nr, filecount - 1);
> -				return 0;
> +			if (strcmp(argv[1], "-"))
> +				src_file_nr = (file - &filetable[0]) / sizeof(fileio_t);
> +			else {
> +				src_file_nr = atoi(argv[1]);
> +				if (src_file_nr < 0 || src_file_nr >= filecount) {
> +					printf(_("file value %d is out of range (0-%d)\n"),
> +						src_file_nr, filecount - 1);
> +					return 0;
> +				}
>  			}
>  			/* Expect no src_path arg */
>  			src_path_arg = 0;
> @@ -147,10 +152,14 @@ copy_range_f(int argc, char **argv)
>  		}
>  		len = sz;
>  
> -		ret = copy_dst_truncate();
> -		if (ret < 0) {
> -			ret = 1;
> -			goto out;
> +		if (fd != file->fd) {
> +			ret = copy_dst_truncate();
> +			if (ret < 0) {
> +				ret = 1;
> +				goto out;
> +			}
> +		} else {
> +			dst = sz;
>  		}
>  	}
>  
> -- 
> 2.17.2
>
Zorro Lang Sept. 3, 2019, 1:19 p.m. UTC | #2
On Tue, Sep 03, 2019 at 07:59:43PM +0800, Zorro Lang wrote:
> On Tue, Sep 03, 2019 at 06:56:32PM +0800, Jianhong.Yin wrote:
> > Related bug:
> >   copy_file_range return "Invalid argument" when copy in the same file
> >   https://bugzilla.kernel.org/show_bug.cgi?id=202935
> > 
> > if argument of option -f is "-", use current file->fd as fd_in
> > 
> > Usage:
> >   xfs_io -c 'copy_range -f -' some_file
> > 
> > Signed-off-by: Jianhong Yin <yin-jianhong@163.com>
> > ---
> 
> Hi,
> 
> Actually, I'm thinking about if you need same 'fd' or same file path?
> If you just need same file path, I think
> 
>   # xfs_io -c "copy_range testfile" testfile
> 
> already can help that. The only one problem stop you doing that is
> "copy_dst_truncate()".
> 
> If all above I suppose is right, we can turn to talk about if that
> copy_dst_truncate() is necessary, or how can we skip it.

I just checked, the copy_dst_truncate() is only called when:

  if (src == 0 && dst == 0 && len == 0) {

So if you can give your reproducer a "length"(or offset), likes:

  # xfs_io -c "copy_range -l 64k testfile" testfile

You can avoid the copy_dst_truncate() too.

Is that helpful?

Thanks,
Zorro

> 
> Thanks,
> Zorro
> 
> >  io/copy_file_range.c | 27 ++++++++++++++++++---------
> >  1 file changed, 18 insertions(+), 9 deletions(-)
> > 
> > diff --git a/io/copy_file_range.c b/io/copy_file_range.c
> > index b7b9fd88..2dde8a31 100644
> > --- a/io/copy_file_range.c
> > +++ b/io/copy_file_range.c
> > @@ -28,6 +28,7 @@ copy_range_help(void)
> >                            at position 0\n\
> >   'copy_range -f 2' - copies all bytes from open file 2 into the current open file\n\
> >                            at position 0\n\
> > + 'copy_range -f -' - copies all bytes from current open file append the current open file\n\
> >  "));
> >  }
> >  
> > @@ -114,11 +115,15 @@ copy_range_f(int argc, char **argv)
> >  			}
> >  			break;
> >  		case 'f':
> > -			src_file_nr = atoi(argv[1]);
> > -			if (src_file_nr < 0 || src_file_nr >= filecount) {
> > -				printf(_("file value %d is out of range (0-%d)\n"),
> > -					src_file_nr, filecount - 1);
> > -				return 0;
> > +			if (strcmp(argv[1], "-"))
> > +				src_file_nr = (file - &filetable[0]) / sizeof(fileio_t);
> > +			else {
> > +				src_file_nr = atoi(argv[1]);
> > +				if (src_file_nr < 0 || src_file_nr >= filecount) {
> > +					printf(_("file value %d is out of range (0-%d)\n"),
> > +						src_file_nr, filecount - 1);
> > +					return 0;
> > +				}
> >  			}
> >  			/* Expect no src_path arg */
> >  			src_path_arg = 0;
> > @@ -147,10 +152,14 @@ copy_range_f(int argc, char **argv)
> >  		}
> >  		len = sz;
> >  
> > -		ret = copy_dst_truncate();
> > -		if (ret < 0) {
> > -			ret = 1;
> > -			goto out;
> > +		if (fd != file->fd) {
> > +			ret = copy_dst_truncate();
> > +			if (ret < 0) {
> > +				ret = 1;
> > +				goto out;
> > +			}
> > +		} else {
> > +			dst = sz;
> >  		}
> >  	}
> >  
> > -- 
> > 2.17.2
> >
Zorro Lang Sept. 4, 2019, 2:03 a.m. UTC | #3
On Wed, Sep 04, 2019 at 12:31:16AM +0800, 尹剑虹 wrote:
> We need cover the scenario that fd_in == fd_out
> not just same path.

Please reply to mail list, not 'me' only, to get more review:)

The patch which you're trying to cover is commit 9ab70ca653 as below[1].
From the code, I really doubt if you need same `struct file`, looks like
you need same `struct inode`.

Have you tried to test on same inode but not same 'fd'? I'm not a CIFS
expert, can CIFS have same file with different inode?

Thanks,
Zorro

[1]
commit 9ab70ca653307771589e1414102c552d8dbdbbef
Author: Kovtunenko Oleksandr <alexander198961@gmail.com>
Date:   Tue May 14 05:52:34 2019 +0000

    Fixed https://bugzilla.kernel.org/show_bug.cgi?id=202935 allow write on the same file
    
    Copychunk allows source and target to be on the same file.
    For details on restrictions see MS-SMB2 3.3.5.15.6
    
    Signed-off-by: Kovtunenko Oleksandr <alexander198961@gmail.com>
    Signed-off-by: Steve French <stfrench@microsoft.com>

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index b1a5fcfa3ce1..d0cb042732cb 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -1070,11 +1070,6 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
 
        cifs_dbg(FYI, "copychunk range\n");
 
-       if (src_inode == target_inode) {
-               rc = -EINVAL;
-               goto out;
-       }
-
        if (!src_file->private_data || !dst_file->private_data) {
                rc = -EBADF;
                cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n");

> 
> #Did you read the summary and commit log?
> 
> 
> | |
> 尹剑虹
> |
> |
> 邮箱:yin-jianhong@163.com
> |
> 
> 签名由 网易邮箱大师 定制
> 
> On 09/03/2019 21:19, Zorro Lang wrote:
> On Tue, Sep 03, 2019 at 07:59:43PM +0800, Zorro Lang wrote:
> > On Tue, Sep 03, 2019 at 06:56:32PM +0800, Jianhong.Yin wrote:
> > > Related bug:
> > >   copy_file_range return "Invalid argument" when copy in the same file
> > >   https://bugzilla.kernel.org/show_bug.cgi?id=202935
> > >
> > > if argument of option -f is "-", use current file->fd as fd_in
> > >
> > > Usage:
> > >   xfs_io -c 'copy_range -f -' some_file
> > >
> > > Signed-off-by: Jianhong Yin <yin-jianhong@163.com>
> > > ---
> >
> > Hi,
> >
> > Actually, I'm thinking about if you need same 'fd' or same file path?
> > If you just need same file path, I think
> >
> >   # xfs_io -c "copy_range testfile" testfile
> >
> > already can help that. The only one problem stop you doing that is
> > "copy_dst_truncate()".
> >
> > If all above I suppose is right, we can turn to talk about if that
> > copy_dst_truncate() is necessary, or how can we skip it.
> 
> I just checked, the copy_dst_truncate() is only called when:
> 
>  if (src == 0 && dst == 0 && len == 0) {
> 
> So if you can give your reproducer a "length"(or offset), likes:
> 
>  # xfs_io -c "copy_range -l 64k testfile" testfile
> 
> You can avoid the copy_dst_truncate() too.
> 
> Is that helpful?
> 
> Thanks,
> Zorro
> 
> >
> > Thanks,
> > Zorro
> >
> > >  io/copy_file_range.c | 27 ++++++++++++++++++---------
> > >  1 file changed, 18 insertions(+), 9 deletions(-)
> > >
> > > diff --git a/io/copy_file_range.c b/io/copy_file_range.c
> > > index b7b9fd88..2dde8a31 100644
> > > --- a/io/copy_file_range.c
> > > +++ b/io/copy_file_range.c
> > > @@ -28,6 +28,7 @@ copy_range_help(void)
> > >                            at position 0\n\
> > >   'copy_range -f 2' - copies all bytes from open file 2 into the current open file\n\
> > >                            at position 0\n\
> > > + 'copy_range -f -' - copies all bytes from current open file append the current open file\n\
> > >  "));
> > >  }
> > >  
> > > @@ -114,11 +115,15 @@ copy_range_f(int argc, char **argv)
> > >                 }
> > >                 break;
> > >            case 'f':
> > > -               src_file_nr = atoi(argv[1]);
> > > -               if (src_file_nr < 0 || src_file_nr >= filecount) {
> > > -                    printf(_("file value %d is out of range (0-%d)\n"),
> > > -                         src_file_nr, filecount - 1);
> > > -                    return 0;
> > > +               if (strcmp(argv[1], "-"))
> > > +                    src_file_nr = (file - &filetable[0]) / sizeof(fileio_t);
> > > +               else {
> > > +                    src_file_nr = atoi(argv[1]);
> > > +                    if (src_file_nr < 0 || src_file_nr >= filecount) {
> > > +                         printf(_("file value %d is out of range (0-%d)\n"),
> > > +                              src_file_nr, filecount - 1);
> > > +                         return 0;
> > > +                    }
> > >                 }
> > >                 /* Expect no src_path arg */
> > >                 src_path_arg = 0;
> > > @@ -147,10 +152,14 @@ copy_range_f(int argc, char **argv)
> > >            }
> > >            len = sz;
> > >  
> > > -          ret = copy_dst_truncate();
> > > -          if (ret < 0) {
> > > -               ret = 1;
> > > -               goto out;
> > > +          if (fd != file->fd) {
> > > +               ret = copy_dst_truncate();
> > > +               if (ret < 0) {
> > > +                    ret = 1;
> > > +                    goto out;
> > > +               }
> > > +          } else {
> > > +               dst = sz;
> > >            }
> > >       }
> > >  
> > > --
> > > 2.17.2
> > >
Jianhong.Yin Sept. 4, 2019, 3:30 a.m. UTC | #4
At 2019-09-04 10:03:57, "Zorro Lang" <zlang@redhat.com> wrote:
>On Wed, Sep 04, 2019 at 12:31:16AM +0800, 尹剑虹 wrote:
>> We need cover the scenario that fd_in == fd_out
>> not just same path.
>
>Please reply to mail list, not 'me' only, to get more review:)
>
>The patch which you're trying to cover is commit 9ab70ca653 as below[1].
>From the code, I really doubt if you need same `struct file`, looks like
>you need same `struct inode`.
>
>Have you tried to test on same inode but not same 'fd'? I'm not a CIFS
>expert, can CIFS have same file with different inode?

Thanks Zorro, you are right. same fd is not necessary;

drop this patch.

>
>Thanks,
>Zorro
>
>[1]
>commit 9ab70ca653307771589e1414102c552d8dbdbbef
>Author: Kovtunenko Oleksandr <alexander198961@gmail.com>
>Date:   Tue May 14 05:52:34 2019 +0000
>
>    Fixed https://bugzilla.kernel.org/show_bug.cgi?id=202935 allow write on the same file
>    
>    Copychunk allows source and target to be on the same file.
>    For details on restrictions see MS-SMB2 3.3.5.15.6
>    
>    Signed-off-by: Kovtunenko Oleksandr <alexander198961@gmail.com>
>    Signed-off-by: Steve French <stfrench@microsoft.com>
>
>diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
>index b1a5fcfa3ce1..d0cb042732cb 100644
>--- a/fs/cifs/cifsfs.c
>+++ b/fs/cifs/cifsfs.c
>@@ -1070,11 +1070,6 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
> 
>        cifs_dbg(FYI, "copychunk range\n");
> 
>-       if (src_inode == target_inode) {
>-               rc = -EINVAL;
>-               goto out;
>-       }
>-
>        if (!src_file->private_data || !dst_file->private_data) {
>                rc = -EBADF;
>                cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n");
>
>> 
>> #Did you read the summary and commit log?
>> 
>> 
>> | |
>> 尹剑虹
>> |
>> |
>> 邮箱:yin-jianhong@163.com
>> |
>> 
>> 签名由 网易邮箱大师 定制
>> 
>> On 09/03/2019 21:19, Zorro Lang wrote:
>> On Tue, Sep 03, 2019 at 07:59:43PM +0800, Zorro Lang wrote:
>> > On Tue, Sep 03, 2019 at 06:56:32PM +0800, Jianhong.Yin wrote:
>> > > Related bug:
>> > >   copy_file_range return "Invalid argument" when copy in the same file
>> > >   https://bugzilla.kernel.org/show_bug.cgi?id=202935
>> > >
>> > > if argument of option -f is "-", use current file->fd as fd_in
>> > >
>> > > Usage:
>> > >   xfs_io -c 'copy_range -f -' some_file
>> > >
>> > > Signed-off-by: Jianhong Yin <yin-jianhong@163.com>
>> > > ---
>> >
>> > Hi,
>> >
>> > Actually, I'm thinking about if you need same 'fd' or same file path?
>> > If you just need same file path, I think
>> >
>> >   # xfs_io -c "copy_range testfile" testfile
>> >
>> > already can help that. The only one problem stop you doing that is
>> > "copy_dst_truncate()".
>> >
>> > If all above I suppose is right, we can turn to talk about if that
>> > copy_dst_truncate() is necessary, or how can we skip it.
>> 
>> I just checked, the copy_dst_truncate() is only called when:
>> 
>>  if (src == 0 && dst == 0 && len == 0) {
>> 
>> So if you can give your reproducer a "length"(or offset), likes:
>> 
>>  # xfs_io -c "copy_range -l 64k testfile" testfile
>> 
>> You can avoid the copy_dst_truncate() too.
>> 
>> Is that helpful?
>> 
>> Thanks,
>> Zorro
>> 
>> >
>> > Thanks,
>> > Zorro
>> >
>> > >  io/copy_file_range.c | 27 ++++++++++++++++++---------
>> > >  1 file changed, 18 insertions(+), 9 deletions(-)
>> > >
>> > > diff --git a/io/copy_file_range.c b/io/copy_file_range.c
>> > > index b7b9fd88..2dde8a31 100644
>> > > --- a/io/copy_file_range.c
>> > > +++ b/io/copy_file_range.c
>> > > @@ -28,6 +28,7 @@ copy_range_help(void)
>> > >                            at position 0\n\
>> > >   'copy_range -f 2' - copies all bytes from open file 2 into the current open file\n\
>> > >                            at position 0\n\
>> > > + 'copy_range -f -' - copies all bytes from current open file append the current open file\n\
>> > >  "));
>> > >  }
>> > >  
>> > > @@ -114,11 +115,15 @@ copy_range_f(int argc, char **argv)
>> > >                 }
>> > >                 break;
>> > >            case 'f':
>> > > -               src_file_nr = atoi(argv[1]);
>> > > -               if (src_file_nr < 0 || src_file_nr >= filecount) {
>> > > -                    printf(_("file value %d is out of range (0-%d)\n"),
>> > > -                         src_file_nr, filecount - 1);
>> > > -                    return 0;
>> > > +               if (strcmp(argv[1], "-"))
>> > > +                    src_file_nr = (file - &filetable[0]) / sizeof(fileio_t);
>> > > +               else {
>> > > +                    src_file_nr = atoi(argv[1]);
>> > > +                    if (src_file_nr < 0 || src_file_nr >= filecount) {
>> > > +                         printf(_("file value %d is out of range (0-%d)\n"),
>> > > +                              src_file_nr, filecount - 1);
>> > > +                         return 0;
>> > > +                    }
>> > >                 }
>> > >                 /* Expect no src_path arg */
>> > >                 src_path_arg = 0;
>> > > @@ -147,10 +152,14 @@ copy_range_f(int argc, char **argv)
>> > >            }
>> > >            len = sz;
>> > >  
>> > > -          ret = copy_dst_truncate();
>> > > -          if (ret < 0) {
>> > > -               ret = 1;
>> > > -               goto out;
>> > > +          if (fd != file->fd) {
>> > > +               ret = copy_dst_truncate();
>> > > +               if (ret < 0) {
>> > > +                    ret = 1;
>> > > +                    goto out;
>> > > +               }
>> > > +          } else {
>> > > +               dst = sz;
>> > >            }
>> > >       }
>> > >  
>> > > --
>> > > 2.17.2
>> > >

Patch
diff mbox series

diff --git a/io/copy_file_range.c b/io/copy_file_range.c
index b7b9fd88..2dde8a31 100644
--- a/io/copy_file_range.c
+++ b/io/copy_file_range.c
@@ -28,6 +28,7 @@  copy_range_help(void)
                           at position 0\n\
  'copy_range -f 2' - copies all bytes from open file 2 into the current open file\n\
                           at position 0\n\
+ 'copy_range -f -' - copies all bytes from current open file append the current open file\n\
 "));
 }
 
@@ -114,11 +115,15 @@  copy_range_f(int argc, char **argv)
 			}
 			break;
 		case 'f':
-			src_file_nr = atoi(argv[1]);
-			if (src_file_nr < 0 || src_file_nr >= filecount) {
-				printf(_("file value %d is out of range (0-%d)\n"),
-					src_file_nr, filecount - 1);
-				return 0;
+			if (strcmp(argv[1], "-"))
+				src_file_nr = (file - &filetable[0]) / sizeof(fileio_t);
+			else {
+				src_file_nr = atoi(argv[1]);
+				if (src_file_nr < 0 || src_file_nr >= filecount) {
+					printf(_("file value %d is out of range (0-%d)\n"),
+						src_file_nr, filecount - 1);
+					return 0;
+				}
 			}
 			/* Expect no src_path arg */
 			src_path_arg = 0;
@@ -147,10 +152,14 @@  copy_range_f(int argc, char **argv)
 		}
 		len = sz;
 
-		ret = copy_dst_truncate();
-		if (ret < 0) {
-			ret = 1;
-			goto out;
+		if (fd != file->fd) {
+			ret = copy_dst_truncate();
+			if (ret < 0) {
+				ret = 1;
+				goto out;
+			}
+		} else {
+			dst = sz;
 		}
 	}