Message ID | 20241006100046.30772-2-pali@kernel.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | cifs: Improve mount option -o reparse and support for native Windows sockets | expand |
This is a good point about how to override the "native" symlink format when using reparse=nfs (a similar question could come up, if for security reasons you use "mfsymlinks" for symlinks - ie "client side symlinks" (which are safer) - but use reparse=nfs for everything else. But ... there is probably a better way to handle the mount option for default symlink creation format more clearly (perhaps use of "nativesymlinks" (default) or "mfsymlinks" if specified, overrides "reparse=wsl" or "reparse=nfs" for symlink format only. User can specify "nativesymlinks=no" if they want to use the "reparse=" format for symlinks. For the sfu case it might be trickier but could fall back to sfu symlinks if "nativesymlinks=no" or if they fail?! Thoughts? On Sun, Oct 6, 2024 at 5:01 AM Pali Rohár <pali@kernel.org> wrote: > > Currently the default option is -o reparse=default which is same as > -o reparse=nfs. Currently mount option -o reparse=nfs does not create > symlink in NFS reparse point style, which is misleading. > > Add new -o reparse= options "native", "native+nfs" and "native+wsl" to make > it more clear and allow to choose the expected reparse point types. > > "native" would mean to create new special files only with reparse point > tags which are natively supported by SMB or Windows. Types which are not > natively supported cannot be created. > > "native+nfs" would mean same as native, but fallback to "nfs" for > unsupported types. > > "native+wsl" would mean to fallback to "wsl". > > Change also meaning of "nfs" and "wsl" to always create special types with > nfs / wsl style. > > And change also the default option to "native+nfs", so the default behavior > stay same as without this change. Without this change were all symlinks > created in native Windows/SMB form and this stay same with this change too. > > Signed-off-by: Pali Rohár <pali@kernel.org> > --- > fs/smb/client/cifsglob.h | 15 ++++++++-- > fs/smb/client/fs_context.c | 12 ++++++++ > fs/smb/client/fs_context.h | 3 ++ > fs/smb/client/reparse.c | 58 +++++++++++++++++++++++++++++++------- > fs/smb/client/reparse.h | 2 ++ > 5 files changed, 77 insertions(+), 13 deletions(-) > > diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h > index 260b553283ef..367f0ac6400d 100644 > --- a/fs/smb/client/cifsglob.h > +++ b/fs/smb/client/cifsglob.h > @@ -154,14 +154,23 @@ enum securityEnum { > }; > > enum cifs_reparse_type { > - CIFS_REPARSE_TYPE_NFS, > - CIFS_REPARSE_TYPE_WSL, > - CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NFS, > + CIFS_REPARSE_TYPE_NATIVE, /* native symlinks only */ > + CIFS_REPARSE_TYPE_NATIVE_NFS, /* native for symlinks, nfs for others */ > + CIFS_REPARSE_TYPE_NATIVE_WSL, /* native for symlinks, wsl for others */ > + CIFS_REPARSE_TYPE_NFS, /* nfs for everything */ > + CIFS_REPARSE_TYPE_WSL, /* wsl for everything */ > + CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NATIVE_NFS, > }; > > static inline const char *cifs_reparse_type_str(enum cifs_reparse_type type) > { > switch (type) { > + case CIFS_REPARSE_TYPE_NATIVE: > + return "native"; > + case CIFS_REPARSE_TYPE_NATIVE_NFS: > + return "native+nfs"; > + case CIFS_REPARSE_TYPE_NATIVE_WSL: > + return "native+wsl"; > case CIFS_REPARSE_TYPE_NFS: > return "nfs"; > case CIFS_REPARSE_TYPE_WSL: > diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c > index 22b550860cc8..e5de84912e3d 100644 > --- a/fs/smb/client/fs_context.c > +++ b/fs/smb/client/fs_context.c > @@ -303,6 +303,9 @@ cifs_parse_cache_flavor(struct fs_context *fc, char *value, struct smb3_fs_conte > > static const match_table_t reparse_flavor_tokens = { > { Opt_reparse_default, "default" }, > + { Opt_reparse_native, "native" }, > + { Opt_reparse_native_nfs, "native+nfs" }, > + { Opt_reparse_native_wsl, "native+wsl" }, > { Opt_reparse_nfs, "nfs" }, > { Opt_reparse_wsl, "wsl" }, > { Opt_reparse_err, NULL }, > @@ -317,6 +320,15 @@ static int parse_reparse_flavor(struct fs_context *fc, char *value, > case Opt_reparse_default: > ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT; > break; > + case Opt_reparse_native: > + ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE; > + break; > + case Opt_reparse_native_nfs: > + ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE_NFS; > + break; > + case Opt_reparse_native_wsl: > + ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE_WSL; > + break; > case Opt_reparse_nfs: > ctx->reparse_type = CIFS_REPARSE_TYPE_NFS; > break; > diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h > index 8dd12498ffd8..1011176ba3b7 100644 > --- a/fs/smb/client/fs_context.h > +++ b/fs/smb/client/fs_context.h > @@ -43,6 +43,9 @@ enum { > > enum cifs_reparse_parm { > Opt_reparse_default, > + Opt_reparse_native, > + Opt_reparse_native_nfs, > + Opt_reparse_native_wsl, > Opt_reparse_nfs, > Opt_reparse_wsl, > Opt_reparse_err > diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c > index 6e9d914bac41..38fe0a710c65 100644 > --- a/fs/smb/client/reparse.c > +++ b/fs/smb/client/reparse.c > @@ -14,6 +14,20 @@ > #include "fs_context.h" > #include "reparse.h" > > +static int mknod_nfs(unsigned int xid, struct inode *inode, > + struct dentry *dentry, struct cifs_tcon *tcon, > + const char *full_path, umode_t mode, dev_t dev, > + const char *symname); > + > +static int mknod_wsl(unsigned int xid, struct inode *inode, > + struct dentry *dentry, struct cifs_tcon *tcon, > + const char *full_path, umode_t mode, dev_t dev, > + const char *symname); > + > +static int create_native_symlink(const unsigned int xid, struct inode *inode, > + struct dentry *dentry, struct cifs_tcon *tcon, > + const char *full_path, const char *symname); > + > static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb, > const unsigned int xid, > const char *full_path, > @@ -23,6 +37,26 @@ static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb, > int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode, > struct dentry *dentry, struct cifs_tcon *tcon, > const char *full_path, const char *symname) > +{ > + struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx; > + > + switch (ctx->reparse_type) { > + case CIFS_REPARSE_TYPE_NATIVE: > + case CIFS_REPARSE_TYPE_NATIVE_NFS: > + case CIFS_REPARSE_TYPE_NATIVE_WSL: > + return create_native_symlink(xid, inode, dentry, tcon, full_path, symname); > + case CIFS_REPARSE_TYPE_NFS: > + return mknod_nfs(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname); > + case CIFS_REPARSE_TYPE_WSL: > + return mknod_wsl(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname); > + default: > + return -EOPNOTSUPP; > + } > +} > + > +static int create_native_symlink(const unsigned int xid, struct inode *inode, > + struct dentry *dentry, struct cifs_tcon *tcon, > + const char *full_path, const char *symname) > { > struct reparse_symlink_data_buffer *buf = NULL; > struct cifs_open_info_data data = {}; > @@ -363,6 +397,7 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf, > case NFS_SPECFILE_SOCK: > dlen = 0; > break; > + case NFS_SPECFILE_LNK: /* TODO: add support for NFS symlinks */ > default: > return -EOPNOTSUPP; > } > @@ -381,7 +416,8 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf, > > static int mknod_nfs(unsigned int xid, struct inode *inode, > struct dentry *dentry, struct cifs_tcon *tcon, > - const char *full_path, umode_t mode, dev_t dev) > + const char *full_path, umode_t mode, dev_t dev, > + const char *symname) > { > struct cifs_open_info_data data; > struct reparse_posix_data *p; > @@ -421,6 +457,7 @@ static int wsl_set_reparse_buf(struct reparse_data_buffer *buf, > case IO_REPARSE_TAG_LX_FIFO: > case IO_REPARSE_TAG_AF_UNIX: > break; > + case IO_REPARSE_TAG_LX_SYMLINK: /* TODO: add support for WSL symlinks */ > default: > return -EOPNOTSUPP; > } > @@ -518,7 +555,8 @@ static int wsl_set_xattrs(struct inode *inode, umode_t _mode, > > static int mknod_wsl(unsigned int xid, struct inode *inode, > struct dentry *dentry, struct cifs_tcon *tcon, > - const char *full_path, umode_t mode, dev_t dev) > + const char *full_path, umode_t mode, dev_t dev, > + const char *symname) > { > struct cifs_open_info_data data; > struct reparse_data_buffer buf; > @@ -563,17 +601,17 @@ int smb2_mknod_reparse(unsigned int xid, struct inode *inode, > const char *full_path, umode_t mode, dev_t dev) > { > struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx; > - int rc = -EOPNOTSUPP; > > switch (ctx->reparse_type) { > + case CIFS_REPARSE_TYPE_NATIVE_NFS: > case CIFS_REPARSE_TYPE_NFS: > - rc = mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev); > - break; > + return mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev, NULL); > + case CIFS_REPARSE_TYPE_NATIVE_WSL: > case CIFS_REPARSE_TYPE_WSL: > - rc = mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev); > - break; > + return mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev, NULL); > + default: > + return -EOPNOTSUPP; > } > - return rc; > } > > /* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */ > @@ -848,7 +886,7 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len, > return rc; > } > > -static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym, > +static int parse_reparse_native_symlink(struct reparse_symlink_data_buffer *sym, > u32 plen, bool unicode, > struct cifs_sb_info *cifs_sb, > const char *full_path, > @@ -936,7 +974,7 @@ int parse_reparse_point(struct reparse_data_buffer *buf, > return parse_reparse_posix((struct reparse_posix_data *)buf, > cifs_sb, data); > case IO_REPARSE_TAG_SYMLINK: > - return parse_reparse_symlink( > + return parse_reparse_native_symlink( > (struct reparse_symlink_data_buffer *)buf, > plen, unicode, cifs_sb, full_path, data); > case IO_REPARSE_TAG_LX_SYMLINK: > diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h > index eb6854e65e08..a6bdf20ce1b0 100644 > --- a/fs/smb/client/reparse.h > +++ b/fs/smb/client/reparse.h > @@ -61,6 +61,7 @@ static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb, > static inline u64 reparse_mode_nfs_type(mode_t mode) > { > switch (mode & S_IFMT) { > + case S_IFLNK: return NFS_SPECFILE_LNK; > case S_IFBLK: return NFS_SPECFILE_BLK; > case S_IFCHR: return NFS_SPECFILE_CHR; > case S_IFIFO: return NFS_SPECFILE_FIFO; > @@ -72,6 +73,7 @@ static inline u64 reparse_mode_nfs_type(mode_t mode) > static inline u32 reparse_mode_wsl_tag(mode_t mode) > { > switch (mode & S_IFMT) { > + case S_IFLNK: return IO_REPARSE_TAG_LX_SYMLINK; > case S_IFBLK: return IO_REPARSE_TAG_LX_BLK; > case S_IFCHR: return IO_REPARSE_TAG_LX_CHR; > case S_IFIFO: return IO_REPARSE_TAG_LX_FIFO; > -- > 2.20.1 > >
Currently choosing how new symlinks are created is quite complicated. Without these patch series, by default new symlinks are created via native reparse points, even when reparse=nfs or reparse=wsl is specified. There is no possibility to create a NFS-style or WSL-style symlink yet, and this patch series address this missing functionality. When option -o sfu is specified then all new symlinks are created in SFU-style, independently of -o reparse option. And when -o mfsymlinks is specified then all new symlinks are created in mf style, independently of -o reparse and -o sfu options. This patch series does not change -o sfu and -o mfsymlinks overrides, it just changes the way how -o reparse is handled. I think that we have too many mount options which specify ability to choose symlink format and complicated overrides, which option has higher priority than other. What about rather introducing a new option like: -o symlinkformat=native|nfs|wsl|sfu|mf|unix|none which explicitly say which format will be chosen when creating a new symlink? IIRC in SMB we can create a new symlink via: - ioctl with native symlink reparse point - ioctl with nfs reparse point - ioctl with wsl symlink reparse point - create sfu system file - create mf file - SMB1 unix create symlink command (have I forgot for something?) On Sunday 06 October 2024 23:28:29 Steve French wrote: > This is a good point about how to override the "native" symlink format > when using reparse=nfs (a similar question could come up, if for > security reasons you use "mfsymlinks" for symlinks - ie "client side > symlinks" (which are safer) - but use reparse=nfs for everything else. > But ... there is probably a better way to handle the mount option > for default symlink creation format more clearly (perhaps use of > "nativesymlinks" (default) or "mfsymlinks" if specified, overrides > "reparse=wsl" or "reparse=nfs" for symlink format only. User can > specify "nativesymlinks=no" if they want to use the "reparse=" format > for symlinks. For the sfu case it might be trickier but could fall > back to sfu symlinks if "nativesymlinks=no" or if they fail?! > Thoughts? > > On Sun, Oct 6, 2024 at 5:01 AM Pali Rohár <pali@kernel.org> wrote: > > > > Currently the default option is -o reparse=default which is same as > > -o reparse=nfs. Currently mount option -o reparse=nfs does not create > > symlink in NFS reparse point style, which is misleading. > > > > Add new -o reparse= options "native", "native+nfs" and "native+wsl" to make > > it more clear and allow to choose the expected reparse point types. > > > > "native" would mean to create new special files only with reparse point > > tags which are natively supported by SMB or Windows. Types which are not > > natively supported cannot be created. > > > > "native+nfs" would mean same as native, but fallback to "nfs" for > > unsupported types. > > > > "native+wsl" would mean to fallback to "wsl". > > > > Change also meaning of "nfs" and "wsl" to always create special types with > > nfs / wsl style. > > > > And change also the default option to "native+nfs", so the default behavior > > stay same as without this change. Without this change were all symlinks > > created in native Windows/SMB form and this stay same with this change too. > > > > Signed-off-by: Pali Rohár <pali@kernel.org> > > --- > > fs/smb/client/cifsglob.h | 15 ++++++++-- > > fs/smb/client/fs_context.c | 12 ++++++++ > > fs/smb/client/fs_context.h | 3 ++ > > fs/smb/client/reparse.c | 58 +++++++++++++++++++++++++++++++------- > > fs/smb/client/reparse.h | 2 ++ > > 5 files changed, 77 insertions(+), 13 deletions(-) > > > > diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h > > index 260b553283ef..367f0ac6400d 100644 > > --- a/fs/smb/client/cifsglob.h > > +++ b/fs/smb/client/cifsglob.h > > @@ -154,14 +154,23 @@ enum securityEnum { > > }; > > > > enum cifs_reparse_type { > > - CIFS_REPARSE_TYPE_NFS, > > - CIFS_REPARSE_TYPE_WSL, > > - CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NFS, > > + CIFS_REPARSE_TYPE_NATIVE, /* native symlinks only */ > > + CIFS_REPARSE_TYPE_NATIVE_NFS, /* native for symlinks, nfs for others */ > > + CIFS_REPARSE_TYPE_NATIVE_WSL, /* native for symlinks, wsl for others */ > > + CIFS_REPARSE_TYPE_NFS, /* nfs for everything */ > > + CIFS_REPARSE_TYPE_WSL, /* wsl for everything */ > > + CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NATIVE_NFS, > > }; > > > > static inline const char *cifs_reparse_type_str(enum cifs_reparse_type type) > > { > > switch (type) { > > + case CIFS_REPARSE_TYPE_NATIVE: > > + return "native"; > > + case CIFS_REPARSE_TYPE_NATIVE_NFS: > > + return "native+nfs"; > > + case CIFS_REPARSE_TYPE_NATIVE_WSL: > > + return "native+wsl"; > > case CIFS_REPARSE_TYPE_NFS: > > return "nfs"; > > case CIFS_REPARSE_TYPE_WSL: > > diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c > > index 22b550860cc8..e5de84912e3d 100644 > > --- a/fs/smb/client/fs_context.c > > +++ b/fs/smb/client/fs_context.c > > @@ -303,6 +303,9 @@ cifs_parse_cache_flavor(struct fs_context *fc, char *value, struct smb3_fs_conte > > > > static const match_table_t reparse_flavor_tokens = { > > { Opt_reparse_default, "default" }, > > + { Opt_reparse_native, "native" }, > > + { Opt_reparse_native_nfs, "native+nfs" }, > > + { Opt_reparse_native_wsl, "native+wsl" }, > > { Opt_reparse_nfs, "nfs" }, > > { Opt_reparse_wsl, "wsl" }, > > { Opt_reparse_err, NULL }, > > @@ -317,6 +320,15 @@ static int parse_reparse_flavor(struct fs_context *fc, char *value, > > case Opt_reparse_default: > > ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT; > > break; > > + case Opt_reparse_native: > > + ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE; > > + break; > > + case Opt_reparse_native_nfs: > > + ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE_NFS; > > + break; > > + case Opt_reparse_native_wsl: > > + ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE_WSL; > > + break; > > case Opt_reparse_nfs: > > ctx->reparse_type = CIFS_REPARSE_TYPE_NFS; > > break; > > diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h > > index 8dd12498ffd8..1011176ba3b7 100644 > > --- a/fs/smb/client/fs_context.h > > +++ b/fs/smb/client/fs_context.h > > @@ -43,6 +43,9 @@ enum { > > > > enum cifs_reparse_parm { > > Opt_reparse_default, > > + Opt_reparse_native, > > + Opt_reparse_native_nfs, > > + Opt_reparse_native_wsl, > > Opt_reparse_nfs, > > Opt_reparse_wsl, > > Opt_reparse_err > > diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c > > index 6e9d914bac41..38fe0a710c65 100644 > > --- a/fs/smb/client/reparse.c > > +++ b/fs/smb/client/reparse.c > > @@ -14,6 +14,20 @@ > > #include "fs_context.h" > > #include "reparse.h" > > > > +static int mknod_nfs(unsigned int xid, struct inode *inode, > > + struct dentry *dentry, struct cifs_tcon *tcon, > > + const char *full_path, umode_t mode, dev_t dev, > > + const char *symname); > > + > > +static int mknod_wsl(unsigned int xid, struct inode *inode, > > + struct dentry *dentry, struct cifs_tcon *tcon, > > + const char *full_path, umode_t mode, dev_t dev, > > + const char *symname); > > + > > +static int create_native_symlink(const unsigned int xid, struct inode *inode, > > + struct dentry *dentry, struct cifs_tcon *tcon, > > + const char *full_path, const char *symname); > > + > > static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb, > > const unsigned int xid, > > const char *full_path, > > @@ -23,6 +37,26 @@ static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb, > > int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode, > > struct dentry *dentry, struct cifs_tcon *tcon, > > const char *full_path, const char *symname) > > +{ > > + struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx; > > + > > + switch (ctx->reparse_type) { > > + case CIFS_REPARSE_TYPE_NATIVE: > > + case CIFS_REPARSE_TYPE_NATIVE_NFS: > > + case CIFS_REPARSE_TYPE_NATIVE_WSL: > > + return create_native_symlink(xid, inode, dentry, tcon, full_path, symname); > > + case CIFS_REPARSE_TYPE_NFS: > > + return mknod_nfs(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname); > > + case CIFS_REPARSE_TYPE_WSL: > > + return mknod_wsl(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname); > > + default: > > + return -EOPNOTSUPP; > > + } > > +} > > + > > +static int create_native_symlink(const unsigned int xid, struct inode *inode, > > + struct dentry *dentry, struct cifs_tcon *tcon, > > + const char *full_path, const char *symname) > > { > > struct reparse_symlink_data_buffer *buf = NULL; > > struct cifs_open_info_data data = {}; > > @@ -363,6 +397,7 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf, > > case NFS_SPECFILE_SOCK: > > dlen = 0; > > break; > > + case NFS_SPECFILE_LNK: /* TODO: add support for NFS symlinks */ > > default: > > return -EOPNOTSUPP; > > } > > @@ -381,7 +416,8 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf, > > > > static int mknod_nfs(unsigned int xid, struct inode *inode, > > struct dentry *dentry, struct cifs_tcon *tcon, > > - const char *full_path, umode_t mode, dev_t dev) > > + const char *full_path, umode_t mode, dev_t dev, > > + const char *symname) > > { > > struct cifs_open_info_data data; > > struct reparse_posix_data *p; > > @@ -421,6 +457,7 @@ static int wsl_set_reparse_buf(struct reparse_data_buffer *buf, > > case IO_REPARSE_TAG_LX_FIFO: > > case IO_REPARSE_TAG_AF_UNIX: > > break; > > + case IO_REPARSE_TAG_LX_SYMLINK: /* TODO: add support for WSL symlinks */ > > default: > > return -EOPNOTSUPP; > > } > > @@ -518,7 +555,8 @@ static int wsl_set_xattrs(struct inode *inode, umode_t _mode, > > > > static int mknod_wsl(unsigned int xid, struct inode *inode, > > struct dentry *dentry, struct cifs_tcon *tcon, > > - const char *full_path, umode_t mode, dev_t dev) > > + const char *full_path, umode_t mode, dev_t dev, > > + const char *symname) > > { > > struct cifs_open_info_data data; > > struct reparse_data_buffer buf; > > @@ -563,17 +601,17 @@ int smb2_mknod_reparse(unsigned int xid, struct inode *inode, > > const char *full_path, umode_t mode, dev_t dev) > > { > > struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx; > > - int rc = -EOPNOTSUPP; > > > > switch (ctx->reparse_type) { > > + case CIFS_REPARSE_TYPE_NATIVE_NFS: > > case CIFS_REPARSE_TYPE_NFS: > > - rc = mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev); > > - break; > > + return mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev, NULL); > > + case CIFS_REPARSE_TYPE_NATIVE_WSL: > > case CIFS_REPARSE_TYPE_WSL: > > - rc = mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev); > > - break; > > + return mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev, NULL); > > + default: > > + return -EOPNOTSUPP; > > } > > - return rc; > > } > > > > /* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */ > > @@ -848,7 +886,7 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len, > > return rc; > > } > > > > -static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym, > > +static int parse_reparse_native_symlink(struct reparse_symlink_data_buffer *sym, > > u32 plen, bool unicode, > > struct cifs_sb_info *cifs_sb, > > const char *full_path, > > @@ -936,7 +974,7 @@ int parse_reparse_point(struct reparse_data_buffer *buf, > > return parse_reparse_posix((struct reparse_posix_data *)buf, > > cifs_sb, data); > > case IO_REPARSE_TAG_SYMLINK: > > - return parse_reparse_symlink( > > + return parse_reparse_native_symlink( > > (struct reparse_symlink_data_buffer *)buf, > > plen, unicode, cifs_sb, full_path, data); > > case IO_REPARSE_TAG_LX_SYMLINK: > > diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h > > index eb6854e65e08..a6bdf20ce1b0 100644 > > --- a/fs/smb/client/reparse.h > > +++ b/fs/smb/client/reparse.h > > @@ -61,6 +61,7 @@ static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb, > > static inline u64 reparse_mode_nfs_type(mode_t mode) > > { > > switch (mode & S_IFMT) { > > + case S_IFLNK: return NFS_SPECFILE_LNK; > > case S_IFBLK: return NFS_SPECFILE_BLK; > > case S_IFCHR: return NFS_SPECFILE_CHR; > > case S_IFIFO: return NFS_SPECFILE_FIFO; > > @@ -72,6 +73,7 @@ static inline u64 reparse_mode_nfs_type(mode_t mode) > > static inline u32 reparse_mode_wsl_tag(mode_t mode) > > { > > switch (mode & S_IFMT) { > > + case S_IFLNK: return IO_REPARSE_TAG_LX_SYMLINK; > > case S_IFBLK: return IO_REPARSE_TAG_LX_BLK; > > case S_IFCHR: return IO_REPARSE_TAG_LX_CHR; > > case S_IFIFO: return IO_REPARSE_TAG_LX_FIFO; > > -- > > 2.20.1 > > > > > > > -- > Thanks, > > Steve
On Thu, Oct 10, 2024 at 5:17 PM Steve French <smfrench@gmail.com> wrote: > > > > On Mon, Oct 7, 2024 at 1:36 PM Pali Rohár <pali@kernel.org> wrote: >> >> Currently choosing how new symlinks are created is quite complicated. >> >> Without these patch series, by default new symlinks are created via >> native reparse points, even when reparse=nfs or reparse=wsl is >> specified. There is no possibility to create a NFS-style or WSL-style >> symlink yet, and this patch series address this missing functionality. >> When option -o sfu is specified then all new symlinks are created in >> SFU-style, independently of -o reparse option. And when -o mfsymlinks is >> specified then all new symlinks are created in mf style, independently >> of -o reparse and -o sfu options. >> >> This patch series does not change -o sfu and -o mfsymlinks overrides, it >> just changes the way how -o reparse is handled. >> I lean toward something similar, and more intuitive - do not have "reparse=" control symlink creation - but instead use another mount parm (e.g. "symlink=") for that. It would be rarely used - only if you don't want the default (windows default format too) for server symlinks or "mfsymlinks" (for client only symlinks): 1) "symlink=" if specified can be set to one of five formats (with the default being the windows format) a) "mfsymlinks" (Mac style which is safer for many use cases since they are "client only" symlinks which the server will never use) Setting "symlink=mfsymlinks" will have the same effect as just specifying "mfsymlinks" so won't break anything b) "default" (or "windows") which uses the default symlink format when trying to create a new symlink c) "nfs" d) "wsl" e) "sfu" 2) "reparse=" will still control how special files are created (char, block, fifo, socket) and can be set to: a) "nfs" (default) b) or "wsl" c) If "sfu" set on mount will cause special files to be created with "sfu" format instead of using reparse points to create 3) reading reparse points will always be supported (unless you want to add a new parameter "reparse=none" to treat all reparse points as empty directories) 4) reading special files via the old "sfu" will only be supported if you mount with "sfu"
On Thursday 10 October 2024 17:21:59 Steve French wrote: > On Thu, Oct 10, 2024 at 5:17 PM Steve French <smfrench@gmail.com> wrote: > > > > > > > > On Mon, Oct 7, 2024 at 1:36 PM Pali Rohár <pali@kernel.org> wrote: > >> > >> Currently choosing how new symlinks are created is quite complicated. > >> > >> Without these patch series, by default new symlinks are created via > >> native reparse points, even when reparse=nfs or reparse=wsl is > >> specified. There is no possibility to create a NFS-style or WSL-style > >> symlink yet, and this patch series address this missing functionality. > >> When option -o sfu is specified then all new symlinks are created in > >> SFU-style, independently of -o reparse option. And when -o mfsymlinks is > >> specified then all new symlinks are created in mf style, independently > >> of -o reparse and -o sfu options. > >> > >> This patch series does not change -o sfu and -o mfsymlinks overrides, it > >> just changes the way how -o reparse is handled. > >> > > I lean toward something similar, and more intuitive - do not have > "reparse=" control symlink creation - but instead use another mount > parm (e.g. "symlink=") for that. It would be rarely used - only if > you don't want the default (windows default format too) for server > symlinks or "mfsymlinks" (for client only symlinks): > > 1) "symlink=" if specified can be set to one of five formats (with the > default being the windows format) > a) "mfsymlinks" (Mac style which is safer for many use cases since > they are "client only" symlinks which the server will never use) > Setting "symlink=mfsymlinks" will have the same effect as just > specifying "mfsymlinks" so won't break anything > b) "default" (or "windows") which uses the default symlink format > when trying to create a new symlink > c) "nfs" > d) "wsl" > e) "sfu" > 2) "reparse=" will still control how special files are created (char, > block, fifo, socket) and can be set to: > a) "nfs" (default) > b) or "wsl" > c) If "sfu" set on mount will cause special files to be created > with "sfu" format instead of using reparse points to create > 3) reading reparse points will always be supported (unless you want to > add a new parameter "reparse=none" to treat all reparse points as > empty directories) > 4) reading special files via the old "sfu" will only be supported if > you mount with "sfu" > > > > > -- > Thanks, > > Steve Ok, and how to handle creating new sockets? For me it makes sense to create new sockets in "native" AF_UNIX style - compatible with Windows WinAPI / WinSocks. Should be there also a new parameter?
On Thursday 10 October 2024 17:42:55 Steve French wrote: > On Thu, Oct 10, 2024, 5:39 PM Pali Rohár <pali@kernel.org> wrote: > > > On Thursday 10 October 2024 17:21:59 Steve French wrote: > > > On Thu, Oct 10, 2024 at 5:17 PM Steve French <smfrench@gmail.com> wrote: > > > > > > > > > > > > > > > > On Mon, Oct 7, 2024 at 1:36 PM Pali Rohár <pali@kernel.org> wrote: > > > >> > > > >> Currently choosing how new symlinks are created is quite complicated. > > > >> > > > >> Without these patch series, by default new symlinks are created via > > > >> native reparse points, even when reparse=nfs or reparse=wsl is > > > >> specified. There is no possibility to create a NFS-style or WSL-style > > > >> symlink yet, and this patch series address this missing functionality. > > > >> When option -o sfu is specified then all new symlinks are created in > > > >> SFU-style, independently of -o reparse option. And when -o mfsymlinks > > is > > > >> specified then all new symlinks are created in mf style, independently > > > >> of -o reparse and -o sfu options. > > > >> > > > >> This patch series does not change -o sfu and -o mfsymlinks overrides, > > it > > > >> just changes the way how -o reparse is handled. > > > >> > > > > > > I lean toward something similar, and more intuitive - do not have > > > "reparse=" control symlink creation - but instead use another mount > > > parm (e.g. "symlink=") for that. It would be rarely used - only if > > > you don't want the default (windows default format too) for server > > > symlinks or "mfsymlinks" (for client only symlinks): > > > > > > 1) "symlink=" if specified can be set to one of five formats (with the > > > default being the windows format) > > > a) "mfsymlinks" (Mac style which is safer for many use cases since > > > they are "client only" symlinks which the server will never use) > > > Setting "symlink=mfsymlinks" will have the same effect as just > > > specifying "mfsymlinks" so won't break anything > > > b) "default" (or "windows") which uses the default symlink format > > > when trying to create a new symlink > > > c) "nfs" > > > d) "wsl" > > > e) "sfu" > > > 2) "reparse=" will still control how special files are created (char, > > > block, fifo, socket) and can be set to: > > > a) "nfs" (default) > > > b) or "wsl" > > > c) If "sfu" set on mount will cause special files to be created > > > with "sfu" format instead of using reparse points to create > > > 3) reading reparse points will always be supported (unless you want to > > > add a new parameter "reparse=none" to treat all reparse points as > > > empty directories) > > > 4) reading special files via the old "sfu" will only be supported if > > > you mount with "sfu" > > > > > > > > > > > > > > > -- > > > Thanks, > > > > > > Steve > > > > Ok, and how to handle creating new sockets? For me it makes sense to > > create new sockets in "native" AF_UNIX style - compatible with Windows > > WinAPI / WinSocks. Should be there also a new parameter? > > > > Possibly, but we can decide that later. Aren't sockets typically more > transient short lives so less likely to cause issues no matter what format > we use?? > > > Yes, they are short lives.
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 260b553283ef..367f0ac6400d 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -154,14 +154,23 @@ enum securityEnum { }; enum cifs_reparse_type { - CIFS_REPARSE_TYPE_NFS, - CIFS_REPARSE_TYPE_WSL, - CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NFS, + CIFS_REPARSE_TYPE_NATIVE, /* native symlinks only */ + CIFS_REPARSE_TYPE_NATIVE_NFS, /* native for symlinks, nfs for others */ + CIFS_REPARSE_TYPE_NATIVE_WSL, /* native for symlinks, wsl for others */ + CIFS_REPARSE_TYPE_NFS, /* nfs for everything */ + CIFS_REPARSE_TYPE_WSL, /* wsl for everything */ + CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NATIVE_NFS, }; static inline const char *cifs_reparse_type_str(enum cifs_reparse_type type) { switch (type) { + case CIFS_REPARSE_TYPE_NATIVE: + return "native"; + case CIFS_REPARSE_TYPE_NATIVE_NFS: + return "native+nfs"; + case CIFS_REPARSE_TYPE_NATIVE_WSL: + return "native+wsl"; case CIFS_REPARSE_TYPE_NFS: return "nfs"; case CIFS_REPARSE_TYPE_WSL: diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index 22b550860cc8..e5de84912e3d 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -303,6 +303,9 @@ cifs_parse_cache_flavor(struct fs_context *fc, char *value, struct smb3_fs_conte static const match_table_t reparse_flavor_tokens = { { Opt_reparse_default, "default" }, + { Opt_reparse_native, "native" }, + { Opt_reparse_native_nfs, "native+nfs" }, + { Opt_reparse_native_wsl, "native+wsl" }, { Opt_reparse_nfs, "nfs" }, { Opt_reparse_wsl, "wsl" }, { Opt_reparse_err, NULL }, @@ -317,6 +320,15 @@ static int parse_reparse_flavor(struct fs_context *fc, char *value, case Opt_reparse_default: ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT; break; + case Opt_reparse_native: + ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE; + break; + case Opt_reparse_native_nfs: + ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE_NFS; + break; + case Opt_reparse_native_wsl: + ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE_WSL; + break; case Opt_reparse_nfs: ctx->reparse_type = CIFS_REPARSE_TYPE_NFS; break; diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h index 8dd12498ffd8..1011176ba3b7 100644 --- a/fs/smb/client/fs_context.h +++ b/fs/smb/client/fs_context.h @@ -43,6 +43,9 @@ enum { enum cifs_reparse_parm { Opt_reparse_default, + Opt_reparse_native, + Opt_reparse_native_nfs, + Opt_reparse_native_wsl, Opt_reparse_nfs, Opt_reparse_wsl, Opt_reparse_err diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c index 6e9d914bac41..38fe0a710c65 100644 --- a/fs/smb/client/reparse.c +++ b/fs/smb/client/reparse.c @@ -14,6 +14,20 @@ #include "fs_context.h" #include "reparse.h" +static int mknod_nfs(unsigned int xid, struct inode *inode, + struct dentry *dentry, struct cifs_tcon *tcon, + const char *full_path, umode_t mode, dev_t dev, + const char *symname); + +static int mknod_wsl(unsigned int xid, struct inode *inode, + struct dentry *dentry, struct cifs_tcon *tcon, + const char *full_path, umode_t mode, dev_t dev, + const char *symname); + +static int create_native_symlink(const unsigned int xid, struct inode *inode, + struct dentry *dentry, struct cifs_tcon *tcon, + const char *full_path, const char *symname); + static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb, const unsigned int xid, const char *full_path, @@ -23,6 +37,26 @@ static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb, int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode, struct dentry *dentry, struct cifs_tcon *tcon, const char *full_path, const char *symname) +{ + struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx; + + switch (ctx->reparse_type) { + case CIFS_REPARSE_TYPE_NATIVE: + case CIFS_REPARSE_TYPE_NATIVE_NFS: + case CIFS_REPARSE_TYPE_NATIVE_WSL: + return create_native_symlink(xid, inode, dentry, tcon, full_path, symname); + case CIFS_REPARSE_TYPE_NFS: + return mknod_nfs(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname); + case CIFS_REPARSE_TYPE_WSL: + return mknod_wsl(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname); + default: + return -EOPNOTSUPP; + } +} + +static int create_native_symlink(const unsigned int xid, struct inode *inode, + struct dentry *dentry, struct cifs_tcon *tcon, + const char *full_path, const char *symname) { struct reparse_symlink_data_buffer *buf = NULL; struct cifs_open_info_data data = {}; @@ -363,6 +397,7 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf, case NFS_SPECFILE_SOCK: dlen = 0; break; + case NFS_SPECFILE_LNK: /* TODO: add support for NFS symlinks */ default: return -EOPNOTSUPP; } @@ -381,7 +416,8 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf, static int mknod_nfs(unsigned int xid, struct inode *inode, struct dentry *dentry, struct cifs_tcon *tcon, - const char *full_path, umode_t mode, dev_t dev) + const char *full_path, umode_t mode, dev_t dev, + const char *symname) { struct cifs_open_info_data data; struct reparse_posix_data *p; @@ -421,6 +457,7 @@ static int wsl_set_reparse_buf(struct reparse_data_buffer *buf, case IO_REPARSE_TAG_LX_FIFO: case IO_REPARSE_TAG_AF_UNIX: break; + case IO_REPARSE_TAG_LX_SYMLINK: /* TODO: add support for WSL symlinks */ default: return -EOPNOTSUPP; } @@ -518,7 +555,8 @@ static int wsl_set_xattrs(struct inode *inode, umode_t _mode, static int mknod_wsl(unsigned int xid, struct inode *inode, struct dentry *dentry, struct cifs_tcon *tcon, - const char *full_path, umode_t mode, dev_t dev) + const char *full_path, umode_t mode, dev_t dev, + const char *symname) { struct cifs_open_info_data data; struct reparse_data_buffer buf; @@ -563,17 +601,17 @@ int smb2_mknod_reparse(unsigned int xid, struct inode *inode, const char *full_path, umode_t mode, dev_t dev) { struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx; - int rc = -EOPNOTSUPP; switch (ctx->reparse_type) { + case CIFS_REPARSE_TYPE_NATIVE_NFS: case CIFS_REPARSE_TYPE_NFS: - rc = mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev); - break; + return mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev, NULL); + case CIFS_REPARSE_TYPE_NATIVE_WSL: case CIFS_REPARSE_TYPE_WSL: - rc = mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev); - break; + return mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev, NULL); + default: + return -EOPNOTSUPP; } - return rc; } /* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */ @@ -848,7 +886,7 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len, return rc; } -static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym, +static int parse_reparse_native_symlink(struct reparse_symlink_data_buffer *sym, u32 plen, bool unicode, struct cifs_sb_info *cifs_sb, const char *full_path, @@ -936,7 +974,7 @@ int parse_reparse_point(struct reparse_data_buffer *buf, return parse_reparse_posix((struct reparse_posix_data *)buf, cifs_sb, data); case IO_REPARSE_TAG_SYMLINK: - return parse_reparse_symlink( + return parse_reparse_native_symlink( (struct reparse_symlink_data_buffer *)buf, plen, unicode, cifs_sb, full_path, data); case IO_REPARSE_TAG_LX_SYMLINK: diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h index eb6854e65e08..a6bdf20ce1b0 100644 --- a/fs/smb/client/reparse.h +++ b/fs/smb/client/reparse.h @@ -61,6 +61,7 @@ static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb, static inline u64 reparse_mode_nfs_type(mode_t mode) { switch (mode & S_IFMT) { + case S_IFLNK: return NFS_SPECFILE_LNK; case S_IFBLK: return NFS_SPECFILE_BLK; case S_IFCHR: return NFS_SPECFILE_CHR; case S_IFIFO: return NFS_SPECFILE_FIFO; @@ -72,6 +73,7 @@ static inline u64 reparse_mode_nfs_type(mode_t mode) static inline u32 reparse_mode_wsl_tag(mode_t mode) { switch (mode & S_IFMT) { + case S_IFLNK: return IO_REPARSE_TAG_LX_SYMLINK; case S_IFBLK: return IO_REPARSE_TAG_LX_BLK; case S_IFCHR: return IO_REPARSE_TAG_LX_CHR; case S_IFIFO: return IO_REPARSE_TAG_LX_FIFO;
Currently the default option is -o reparse=default which is same as -o reparse=nfs. Currently mount option -o reparse=nfs does not create symlink in NFS reparse point style, which is misleading. Add new -o reparse= options "native", "native+nfs" and "native+wsl" to make it more clear and allow to choose the expected reparse point types. "native" would mean to create new special files only with reparse point tags which are natively supported by SMB or Windows. Types which are not natively supported cannot be created. "native+nfs" would mean same as native, but fallback to "nfs" for unsupported types. "native+wsl" would mean to fallback to "wsl". Change also meaning of "nfs" and "wsl" to always create special types with nfs / wsl style. And change also the default option to "native+nfs", so the default behavior stay same as without this change. Without this change were all symlinks created in native Windows/SMB form and this stay same with this change too. Signed-off-by: Pali Rohár <pali@kernel.org> --- fs/smb/client/cifsglob.h | 15 ++++++++-- fs/smb/client/fs_context.c | 12 ++++++++ fs/smb/client/fs_context.h | 3 ++ fs/smb/client/reparse.c | 58 +++++++++++++++++++++++++++++++------- fs/smb/client/reparse.h | 2 ++ 5 files changed, 77 insertions(+), 13 deletions(-)