]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
cifs: use origin fullpath for automounts
authorPaulo Alcantara <pc@cjr.nz>
Sun, 18 Dec 2022 17:37:32 +0000 (14:37 -0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 25 Apr 2025 08:44:03 +0000 (10:44 +0200)
commit 7ad54b98fc1f141cfb70cfe2a3d6def5a85169ff upstream.

Use TCP_Server_Info::origin_fullpath instead of cifs_tcon::tree_name
when building source paths for automounts as it will be useful for
domain-based DFS referrals where the connections and referrals would
get either re-used from the cache or re-created when chasing the dfs
link.

Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
[apanyaki: backport to v6.1-stable]
Signed-off-by: Andrew Paniakin <apanyaki@amazon.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/smb/client/cifs_dfs_ref.c
fs/smb/client/cifsproto.h
fs/smb/client/dir.c

index 020e71fe1454edaf39251fb836b9ebadfeb79442..876f9a43a99db90f902f86ac9199129cb2c2ea66 100644 (file)
@@ -258,6 +258,31 @@ compose_mount_options_err:
        goto compose_mount_options_out;
 }
 
+static int set_dest_addr(struct smb3_fs_context *ctx, const char *full_path)
+{
+       struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;
+       char *str_addr = NULL;
+       int rc;
+
+       rc = dns_resolve_server_name_to_ip(full_path, &str_addr, NULL);
+       if (rc < 0)
+               goto out;
+
+       rc = cifs_convert_address(addr, str_addr, strlen(str_addr));
+       if (!rc) {
+               cifs_dbg(FYI, "%s: failed to convert ip address\n", __func__);
+               rc = -EINVAL;
+               goto out;
+       }
+
+       cifs_set_port(addr, ctx->port);
+       rc = 0;
+
+out:
+       kfree(str_addr);
+       return rc;
+}
+
 /*
  * Create a vfsmount that we can automount
  */
@@ -295,8 +320,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
        ctx = smb3_fc2context(fc);
 
        page = alloc_dentry_path();
-       /* always use tree name prefix */
-       full_path = build_path_from_dentry_optional_prefix(mntpt, page, true);
+       full_path = dfs_get_automount_devname(mntpt, page);
        if (IS_ERR(full_path)) {
                mnt = ERR_CAST(full_path);
                goto out;
@@ -315,6 +339,12 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
                goto out;
        }
 
+       rc = set_dest_addr(ctx, full_path);
+       if (rc) {
+               mnt = ERR_PTR(rc);
+               goto out;
+       }
+
        rc = smb3_parse_devname(full_path, ctx);
        if (!rc)
                mnt = fc_mount(fc);
index aca197d69769bf6ab4d2acba36b19d7f512827d5..d1fd54fb3cc14ea74df4e751cdd69b3e184edbae 100644 (file)
@@ -57,8 +57,29 @@ extern void exit_cifs_idmap(void);
 extern int init_cifs_spnego(void);
 extern void exit_cifs_spnego(void);
 extern const char *build_path_from_dentry(struct dentry *, void *);
+char *__build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
+                                              const char *tree, int tree_len,
+                                              bool prefix);
 extern char *build_path_from_dentry_optional_prefix(struct dentry *direntry,
                                                    void *page, bool prefix);
+
+#ifdef CONFIG_CIFS_DFS_UPCALL
+static inline char *dfs_get_automount_devname(struct dentry *dentry, void *page)
+{
+       struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
+       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+       struct TCP_Server_Info *server = tcon->ses->server;
+
+       if (unlikely(!server->origin_fullpath))
+               return ERR_PTR(-EREMOTE);
+
+       return __build_path_from_dentry_optional_prefix(dentry, page,
+                                                       server->origin_fullpath,
+                                                       strlen(server->origin_fullpath),
+                                                       true);
+}
+#endif
+
 static inline void *alloc_dentry_path(void)
 {
        return __getname();
index 863c7bc3db86f842e220ddca6c7ff3cce1c21492..477302157ab3d4b36f44d040afd18b9703681c4b 100644 (file)
@@ -78,14 +78,13 @@ build_path_from_dentry(struct dentry *direntry, void *page)
                                                      prefix);
 }
 
-char *
-build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
-                                      bool prefix)
+char *__build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
+                                              const char *tree, int tree_len,
+                                              bool prefix)
 {
        int dfsplen;
        int pplen = 0;
        struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
-       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
        char dirsep = CIFS_DIR_SEP(cifs_sb);
        char *s;
 
@@ -93,7 +92,7 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
                return ERR_PTR(-ENOMEM);
 
        if (prefix)
-               dfsplen = strnlen(tcon->tree_name, MAX_TREE_SIZE + 1);
+               dfsplen = strnlen(tree, tree_len + 1);
        else
                dfsplen = 0;
 
@@ -123,7 +122,7 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
        }
        if (dfsplen) {
                s -= dfsplen;
-               memcpy(s, tcon->tree_name, dfsplen);
+               memcpy(s, tree, dfsplen);
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
                        int i;
                        for (i = 0; i < dfsplen; i++) {
@@ -135,6 +134,16 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
        return s;
 }
 
+char *build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
+                                            bool prefix)
+{
+       struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
+       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+
+       return __build_path_from_dentry_optional_prefix(direntry, page, tcon->tree_name,
+                                                       MAX_TREE_SIZE, prefix);
+}
+
 /*
  * Don't allow path components longer than the server max.
  * Don't allow the separator character in a path component.