]> git.ipfire.org Git - thirdparty/kernel/linux.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)
committerSteve French <stfrench@microsoft.com>
Fri, 1 Aug 2025 05:16:19 +0000 (00:16 -0500)
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>
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 0fdadd668a815fcfb5cc26bf3a87132996eb8683..31930b7266db564bb335f8c320ad805753607d3f 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 3f34bb07997b9bfe8c1671e1248778f8a534bb32..cc8bd79ebca93a72f2be7c7d5a23ecddf715c500 100644 (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;
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 2ecd705e9e8c1bae64bb1b648c9f5c226f5021a3..afe76367d2c8f82de41830793e3aa8876e6d9f90 100644 (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) {
index 33c1d970747cd609b5437cc3f9b170b52fe0ad4a..7869cec58f529a1afda6ecb8bb062bf8438994a1 100644 (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: