diff mbox series

ksmbd: clear RENAME_NOREPLACE before calling vfs_rename

Message ID 20240313130708.2915988-1-mmakassikis@freebox.fr (mailing list archive)
State New, archived
Headers show
Series ksmbd: clear RENAME_NOREPLACE before calling vfs_rename | expand

Commit Message

Marios Makassikis March 13, 2024, 1:07 p.m. UTC
File overwrite case is explicitly handled, so it is not necessary to
pass RENAME_NOREPLACE to vfs_rename.

Clearing the flag fixes rename operations when the share is a ntfs-3g
mount. The latter uses an older version of fuse with no support for
flags in the ->rename op.

Signed-off-by: Marios Makassikis <mmakassikis@freebox.fr>
---
 fs/smb/server/vfs.c | 3 +++
 1 file changed, 3 insertions(+)

Comments

Marios Makassikis April 15, 2024, 9 a.m. UTC | #1
On Wed, Mar 13, 2024 at 2:07 PM Marios Makassikis
<mmakassikis@freebox.fr> wrote:
>
> File overwrite case is explicitly handled, so it is not necessary to
> pass RENAME_NOREPLACE to vfs_rename.
>
> Clearing the flag fixes rename operations when the share is a ntfs-3g
> mount. The latter uses an older version of fuse with no support for
> flags in the ->rename op.
>
> Signed-off-by: Marios Makassikis <mmakassikis@freebox.fr>
> ---
>  fs/smb/server/vfs.c | 3 +++
>  1 file changed, 3 insertions(+)
>

Bumping this as I haven't received any feedback.
Are there any issues with the patch ?
Namjae Jeon April 15, 2024, 10:51 a.m. UTC | #2
2024년 4월 15일 (월) 오후 6:01, Marios Makassikis <mmakassikis@freebox.fr>님이 작성:
>
> On Wed, Mar 13, 2024 at 2:07 PM Marios Makassikis
> <mmakassikis@freebox.fr> wrote:
> >
> > File overwrite case is explicitly handled, so it is not necessary to
> > pass RENAME_NOREPLACE to vfs_rename.
> >
> > Clearing the flag fixes rename operations when the share is a ntfs-3g
> > mount. The latter uses an older version of fuse with no support for
> > flags in the ->rename op.
> >
> > Signed-off-by: Marios Makassikis <mmakassikis@freebox.fr>
> > ---
> >  fs/smb/server/vfs.c | 3 +++
> >  1 file changed, 3 insertions(+)
> >
>
> Bumping this as I haven't received any feedback.
> Are there any issues with the patch ?
Sorry for missing this patch. Please cc me when submitting the patch
to the list next time.
I didn't understand why it is a problem with ntfs-3g yet.
Is it just clean-up patch ? or this flags cause some issue with ntfs-3g ?
Could you please elaborate more ?

Thanks!
Marios Makassikis April 15, 2024, 12:36 p.m. UTC | #3
On Mon, Apr 15, 2024 at 12:51 PM Namjae Jeon <linkinjeon@kernel.org> wrote:
>
> 2024년 4월 15일 (월) 오후 6:01, Marios Makassikis <mmakassikis@freebox.fr>님이 작성:
> >
> > On Wed, Mar 13, 2024 at 2:07 PM Marios Makassikis
> > <mmakassikis@freebox.fr> wrote:
> > >
> > > File overwrite case is explicitly handled, so it is not necessary to
> > > pass RENAME_NOREPLACE to vfs_rename.
> > >
> > > Clearing the flag fixes rename operations when the share is a ntfs-3g
> > > mount. The latter uses an older version of fuse with no support for
> > > flags in the ->rename op.
> > >
> > > Signed-off-by: Marios Makassikis <mmakassikis@freebox.fr>
> > > ---
> > >  fs/smb/server/vfs.c | 3 +++
> > >  1 file changed, 3 insertions(+)
> > >
> >
> > Bumping this as I haven't received any feedback.
> > Are there any issues with the patch ?
> Sorry for missing this patch. Please cc me when submitting the patch
> to the list next time.
> I didn't understand why it is a problem with ntfs-3g yet.
> Is it just clean-up patch ? or this flags cause some issue with ntfs-3g ?
> Could you please elaborate more ?
>
> Thanks!

Until commit 74d7970febf ("ksmbd: fix racy issue from using ->d_parent
and ->d_name"),
the logic to overwrite a file or fail depending on the ReplaceIfExists
flag was open-coded.
This is the same as calling vfs_rename() with the RENAME_NOREPLACE flag, so it
makes sense to use that instead.

When using FUSE, the behaviour depends on the userland application implementing
the fs. On the kernel side, this is the function that ends up being called:

fs/fuse/dir.c:
static int fuse_rename2(struct mnt_idmap *idmap, struct inode *olddir,
                        struct dentry *oldent, struct inode *newdir,
                        struct dentry *newent, unsigned int flags)
{
        struct fuse_conn *fc = get_fuse_conn(olddir);
        int err;

        if (fuse_is_bad(olddir))
                return -EIO;

        if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
                return -EINVAL;

        if (flags) {
                if (fc->no_rename2 || fc->minor < 23)
                        return -EINVAL;

                err = fuse_rename_common(olddir, oldent, newdir, newent, flags,
                                         FUSE_RENAME2,
                                         sizeof(struct fuse_rename2_in));
                if (err == -ENOSYS) {
                        fc->no_rename2 = 1;
                        err = -EINVAL;
                }
        } else {
                err = fuse_rename_common(olddir, oldent, newdir, newent, 0,
                                         FUSE_RENAME,
                                         sizeof(struct fuse_rename_in));
        }

        return err;
}

Because ntfs-3g uses an older version of the FUSE API and flags are
passed by ksmbd,
rename attempts fail because of this bit:

        if (flags) {
                if (fc->no_rename2 || fc->minor < 23)
                        return -EINVAL;

ksmbd already handles the overwrite case before even calling
vfs_rename(). So passing
the flag doesn't add much.

--
Marios
Namjae Jeon April 15, 2024, 12:55 p.m. UTC | #4
2024년 4월 15일 (월) 오후 9:36, Marios Makassikis <mmakassikis@freebox.fr>님이 작성:
>
> On Mon, Apr 15, 2024 at 12:51 PM Namjae Jeon <linkinjeon@kernel.org> wrote:
> >
> > 2024년 4월 15일 (월) 오후 6:01, Marios Makassikis <mmakassikis@freebox.fr>님이 작성:
> > >
> > > On Wed, Mar 13, 2024 at 2:07 PM Marios Makassikis
> > > <mmakassikis@freebox.fr> wrote:
> > > >
> > > > File overwrite case is explicitly handled, so it is not necessary to
> > > > pass RENAME_NOREPLACE to vfs_rename.
> > > >
> > > > Clearing the flag fixes rename operations when the share is a ntfs-3g
> > > > mount. The latter uses an older version of fuse with no support for
> > > > flags in the ->rename op.
> > > >
> > > > Signed-off-by: Marios Makassikis <mmakassikis@freebox.fr>
> > > > ---
> > > >  fs/smb/server/vfs.c | 3 +++
> > > >  1 file changed, 3 insertions(+)
> > > >
> > >
> > > Bumping this as I haven't received any feedback.
> > > Are there any issues with the patch ?
> > Sorry for missing this patch. Please cc me when submitting the patch
> > to the list next time.
> > I didn't understand why it is a problem with ntfs-3g yet.
> > Is it just clean-up patch ? or this flags cause some issue with ntfs-3g ?
> > Could you please elaborate more ?
> >
> > Thanks!
>
> Until commit 74d7970febf ("ksmbd: fix racy issue from using ->d_parent
> and ->d_name"),
> the logic to overwrite a file or fail depending on the ReplaceIfExists
> flag was open-coded.
> This is the same as calling vfs_rename() with the RENAME_NOREPLACE flag, so it
> makes sense to use that instead.
>
> When using FUSE, the behaviour depends on the userland application implementing
> the fs. On the kernel side, this is the function that ends up being called:
>
> fs/fuse/dir.c:
> static int fuse_rename2(struct mnt_idmap *idmap, struct inode *olddir,
>                         struct dentry *oldent, struct inode *newdir,
>                         struct dentry *newent, unsigned int flags)
> {
>         struct fuse_conn *fc = get_fuse_conn(olddir);
>         int err;
>
>         if (fuse_is_bad(olddir))
>                 return -EIO;
>
>         if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
>                 return -EINVAL;
>
>         if (flags) {
>                 if (fc->no_rename2 || fc->minor < 23)
>                         return -EINVAL;
>
>                 err = fuse_rename_common(olddir, oldent, newdir, newent, flags,
>                                          FUSE_RENAME2,
>                                          sizeof(struct fuse_rename2_in));
>                 if (err == -ENOSYS) {
>                         fc->no_rename2 = 1;
>                         err = -EINVAL;
>                 }
>         } else {
>                 err = fuse_rename_common(olddir, oldent, newdir, newent, 0,
>                                          FUSE_RENAME,
>                                          sizeof(struct fuse_rename_in));
>         }
>
>         return err;
> }
>
> Because ntfs-3g uses an older version of the FUSE API and flags are
> passed by ksmbd,
> rename attempts fail because of this bit:
>
>         if (flags) {
>                 if (fc->no_rename2 || fc->minor < 23)
>                         return -EINVAL;
>
> ksmbd already handles the overwrite case before even calling
> vfs_rename(). So passing
> the flag doesn't add much.
Okay, Thanks for your detailed explanation:)

Can you fix a warning from checkpatch.pl ?

WARNING: Block comments use a trailing */ on a separate line
#123: FILE: fs/smb/server/vfs.c:758:
+ * filesystems that may not support rename flags (e.g: fuse) */

total: 0 errors, 1 warnings, 13 lines checked

Thanks.

>
> --
> Marios
diff mbox series

Patch

diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index c487e834331a..d7fbea2ed0bf 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -754,10 +754,13 @@  int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
 		goto out4;
 	}
 
+	/* explicitly handle file overwrite case, for compatibility with
+	 * filesystems that may not support rename flags (e.g: fuse) */
 	if ((flags & RENAME_NOREPLACE) && d_is_positive(new_dentry)) {
 		err = -EEXIST;
 		goto out4;
 	}
+	flags &= ~(RENAME_NOREPLACE);
 
 	if (old_child == trap) {
 		err = -EINVAL;