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@xxxxxxxxxx> 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@xxxxxxxxxx> > --- > 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