cifs: use origin fullpath for automounts

commit 7ad54b98fc 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>
This commit is contained in:
Paulo Alcantara
2022-12-18 14:37:32 -03:00
committed by Greg Kroah-Hartman
parent ec28c35029
commit 7d8bb979f6
3 changed files with 68 additions and 8 deletions

View File

@@ -258,6 +258,31 @@ compose_mount_options_err:
goto compose_mount_options_out; 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 * 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); ctx = smb3_fc2context(fc);
page = alloc_dentry_path(); page = alloc_dentry_path();
/* always use tree name prefix */ full_path = dfs_get_automount_devname(mntpt, page);
full_path = build_path_from_dentry_optional_prefix(mntpt, page, true);
if (IS_ERR(full_path)) { if (IS_ERR(full_path)) {
mnt = ERR_CAST(full_path); mnt = ERR_CAST(full_path);
goto out; goto out;
@@ -315,6 +339,12 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
goto out; goto out;
} }
rc = set_dest_addr(ctx, full_path);
if (rc) {
mnt = ERR_PTR(rc);
goto out;
}
rc = smb3_parse_devname(full_path, ctx); rc = smb3_parse_devname(full_path, ctx);
if (!rc) if (!rc)
mnt = fc_mount(fc); mnt = fc_mount(fc);

View File

@@ -57,8 +57,29 @@ extern void exit_cifs_idmap(void);
extern int init_cifs_spnego(void); extern int init_cifs_spnego(void);
extern void exit_cifs_spnego(void); extern void exit_cifs_spnego(void);
extern const char *build_path_from_dentry(struct dentry *, 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, extern char *build_path_from_dentry_optional_prefix(struct dentry *direntry,
void *page, bool prefix); 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) static inline void *alloc_dentry_path(void)
{ {
return __getname(); return __getname();

View File

@@ -78,14 +78,13 @@ build_path_from_dentry(struct dentry *direntry, void *page)
prefix); prefix);
} }
char * char *__build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page, const char *tree, int tree_len,
bool prefix) bool prefix)
{ {
int dfsplen; int dfsplen;
int pplen = 0; int pplen = 0;
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); 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 dirsep = CIFS_DIR_SEP(cifs_sb);
char *s; char *s;
@@ -93,7 +92,7 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
if (prefix) if (prefix)
dfsplen = strnlen(tcon->tree_name, MAX_TREE_SIZE + 1); dfsplen = strnlen(tree, tree_len + 1);
else else
dfsplen = 0; dfsplen = 0;
@@ -123,7 +122,7 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
} }
if (dfsplen) { if (dfsplen) {
s -= dfsplen; s -= dfsplen;
memcpy(s, tcon->tree_name, dfsplen); memcpy(s, tree, dfsplen);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
int i; int i;
for (i = 0; i < dfsplen; i++) { for (i = 0; i < dfsplen; i++) {
@@ -135,6 +134,16 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
return s; 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 path components longer than the server max.
* Don't allow the separator character in a path component. * Don't allow the separator character in a path component.