--- /dev/null
+From d5a863a153e90996ab2aef6b9e08d509f4d5662b Mon Sep 17 00:00:00 2001
+From: Paulo Alcantara <pc@manguebit.com>
+Date: Sun, 16 Apr 2023 15:38:28 -0300
+Subject: cifs: avoid dup prefix path in dfs_get_automount_devname()
+
+From: Paulo Alcantara <pc@manguebit.com>
+
+commit d5a863a153e90996ab2aef6b9e08d509f4d5662b upstream.
+
+@server->origin_fullpath already contains the tree name + optional
+prefix, so avoid calling __build_path_from_dentry_optional_prefix() as
+it might end up duplicating prefix path from @cifs_sb->prepath into
+final full path.
+
+Instead, generate DFS full path by simply merging
+@server->origin_fullpath with dentry's path.
+
+This fixes the following case
+
+ mount.cifs //root/dfs/dir /mnt/ -o ...
+ ls /mnt/link
+
+where cifs_dfs_do_automount() will call smb3_parse_devname() with
+@devname set to "//root/dfs/dir/link" instead of
+"//root/dfs/dir/dir/link".
+
+Fixes: 7ad54b98fc1f ("cifs: use origin fullpath for automounts")
+Cc: <stable@vger.kernel.org> # 6.2+
+Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Cc: Andrew Paniakin <apanyaki@amazon.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/client/cifs_dfs_ref.c | 2 --
+ fs/smb/client/cifsproto.h | 18 ++++++++++++++++++
+ 2 files changed, 18 insertions(+), 2 deletions(-)
+
+--- a/fs/smb/client/cifs_dfs_ref.c
++++ b/fs/smb/client/cifs_dfs_ref.c
+@@ -325,8 +325,6 @@ static struct vfsmount *cifs_dfs_do_auto
+ mnt = ERR_CAST(full_path);
+ goto out;
+ }
+-
+- convert_delimiter(full_path, '/');
+ cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
+
+ tmp = *cur_ctx;
+--- a/fs/smb/client/cifsproto.h
++++ b/fs/smb/client/cifsproto.h
+@@ -62,11 +62,14 @@ char *__build_path_from_dentry_optional_
+ bool prefix);
+ extern char *build_path_from_dentry_optional_prefix(struct dentry *direntry,
+ void *page, bool prefix);
++/* Return DFS full path out of a dentry set for automount */
+ 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;
++ size_t len;
++ char *s;
+
+ if (unlikely(!server->origin_fullpath))
+ return ERR_PTR(-EREMOTE);
+@@ -75,6 +78,21 @@ static inline char *dfs_get_automount_de
+ server->origin_fullpath,
+ strlen(server->origin_fullpath),
+ true);
++ s = dentry_path_raw(dentry, page, PATH_MAX);
++ if (IS_ERR(s))
++ return s;
++ /* for root, we want "" */
++ if (!s[1])
++ s++;
++
++ len = strlen(server->origin_fullpath);
++ if (s < (char *)page + len)
++ return ERR_PTR(-ENAMETOOLONG);
++
++ s -= len;
++ memcpy(s, server->origin_fullpath, len);
++ convert_delimiter(s, '/');
++ return s;
+ }
+
+ static inline void *alloc_dentry_path(void)