]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
smb: client: set symlink type as native for POSIX mounts
authorPaulo Alcantara <pc@manguebit.org>
Thu, 31 Jul 2025 23:46:41 +0000 (20:46 -0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 15 Aug 2025 14:39:32 +0000 (16:39 +0200)
commit a967e758f8e9d8ce5ef096743393df5e6e51644b upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/smb/client/cifsfs.c
fs/smb/client/fs_context.c
fs/smb/client/fs_context.h
fs/smb/client/link.c
fs/smb/client/reparse.c

index 0a5266ecfd157141b27d029f47af8acd0325c0c7..697badd0445a0dba24d507733f0e320f03b34035 100644 (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);
index 59ccc2229ab3008a0a0e580e3737f81c53b2720d..f9681f852d20129aa405b607e6f35427ac67e9e5 100644 (file)
@@ -1851,24 +1851,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;
index 9e83302ce4b80113193c85593c78da2e55b10c6c..b0fec6b9a23b4fb8cc71061066493b0d6182a0de 100644 (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);
index 769752ad2c5ce8d38f8cc735a88719c34881379d..e2075f1aebc96c71c43975625a60953b590c0c02 100644 (file)
@@ -606,14 +606,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) {
@@ -653,6 +646,8 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
                        goto symlink_exit;
                }
                break;
+       default:
+               break;
        }
 
        if (rc == 0) {
index 5fa29a97ac154b6b4a0c4709f1ad96c565c089f9..4f6c320b41c9710e1a3c53b097591e0c5d31e3f7 100644 (file)
@@ -38,7 +38,7 @@ 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)
 {
-       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: