smb: client: set symlink type as native for POSIX mounts

SMB3.1.1 POSIX mounts require symlinks to be created natively with
IO_REPARSE_TAG_SYMLINK reparse point.

Cc: linux-cifs@vger.kernel.org
Cc: Ralph Boehme <slow@samba.org>
Cc: David Howells <dhowells@redhat.com>
Cc: <stable@vger.kernel.org>
Reported-by: Matthew Richardson <m.richardson@ed.ac.uk>
Closes: https://marc.info/?i=1124e7cd-6a46-40a6-9f44-b7664a66654b@ed.ac.uk
Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
Paulo Alcantara 2025-07-31 20:46:41 -03:00 committed by Steve French
parent db68e4c80d
commit a967e758f8
5 changed files with 22 additions and 29 deletions

View File

@ -723,7 +723,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
else
seq_puts(s, ",nativesocket");
seq_show_option(s, "symlink",
cifs_symlink_type_str(get_cifs_symlink_type(cifs_sb)));
cifs_symlink_type_str(cifs_symlink_type(cifs_sb)));
seq_printf(s, ",rsize=%u", cifs_sb->ctx->rsize);
seq_printf(s, ",wsize=%u", cifs_sb->ctx->wsize);

View File

@ -1829,24 +1829,6 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
return -EINVAL;
}
enum cifs_symlink_type get_cifs_symlink_type(struct cifs_sb_info *cifs_sb)
{
if (cifs_sb->ctx->symlink_type == CIFS_SYMLINK_TYPE_DEFAULT) {
if (cifs_sb->ctx->mfsymlinks)
return CIFS_SYMLINK_TYPE_MFSYMLINKS;
else if (cifs_sb->ctx->sfu_emul)
return CIFS_SYMLINK_TYPE_SFU;
else if (cifs_sb->ctx->linux_ext && !cifs_sb->ctx->no_linux_ext)
return CIFS_SYMLINK_TYPE_UNIX;
else if (cifs_sb->ctx->reparse_type != CIFS_REPARSE_TYPE_NONE)
return CIFS_SYMLINK_TYPE_NATIVE;
else
return CIFS_SYMLINK_TYPE_NONE;
} else {
return cifs_sb->ctx->symlink_type;
}
}
int smb3_init_fs_context(struct fs_context *fc)
{
struct smb3_fs_context *ctx;

View File

@ -341,7 +341,23 @@ struct smb3_fs_context {
extern const struct fs_parameter_spec smb3_fs_parameters[];
extern enum cifs_symlink_type get_cifs_symlink_type(struct cifs_sb_info *cifs_sb);
static inline enum cifs_symlink_type cifs_symlink_type(struct cifs_sb_info *cifs_sb)
{
bool posix = cifs_sb_master_tcon(cifs_sb)->posix_extensions;
if (cifs_sb->ctx->symlink_type != CIFS_SYMLINK_TYPE_DEFAULT)
return cifs_sb->ctx->symlink_type;
if (cifs_sb->ctx->mfsymlinks)
return CIFS_SYMLINK_TYPE_MFSYMLINKS;
else if (cifs_sb->ctx->sfu_emul)
return CIFS_SYMLINK_TYPE_SFU;
else if (cifs_sb->ctx->linux_ext && !cifs_sb->ctx->no_linux_ext)
return posix ? CIFS_SYMLINK_TYPE_NATIVE : CIFS_SYMLINK_TYPE_UNIX;
else if (cifs_sb->ctx->reparse_type != CIFS_REPARSE_TYPE_NONE)
return CIFS_SYMLINK_TYPE_NATIVE;
return CIFS_SYMLINK_TYPE_NONE;
}
extern int smb3_init_fs_context(struct fs_context *fc);
extern void smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx);

View File

@ -605,14 +605,7 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
/* BB what if DFS and this volume is on different share? BB */
rc = -EOPNOTSUPP;
switch (get_cifs_symlink_type(cifs_sb)) {
case CIFS_SYMLINK_TYPE_DEFAULT:
/* should not happen, get_cifs_symlink_type() resolves the default */
break;
case CIFS_SYMLINK_TYPE_NONE:
break;
switch (cifs_symlink_type(cifs_sb)) {
case CIFS_SYMLINK_TYPE_UNIX:
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
if (pTcon->unix_ext) {
@ -648,6 +641,8 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
goto symlink_exit;
}
break;
default:
break;
}
if (rc == 0) {

View File

@ -38,7 +38,7 @@ int create_reparse_symlink(const unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
const char *full_path, const char *symname)
{
switch (get_cifs_symlink_type(CIFS_SB(inode->i_sb))) {
switch (cifs_symlink_type(CIFS_SB(inode->i_sb))) {
case CIFS_SYMLINK_TYPE_NATIVE:
return create_native_symlink(xid, inode, dentry, tcon, full_path, symname);
case CIFS_SYMLINK_TYPE_NFS: