Commit 5739375e authored by Paulo Alcantara (SUSE)'s avatar Paulo Alcantara (SUSE) Committed by Steve French

cifs: Fix mount options set in automount

Starting from 4a367dc0, we must set the mount options based on the
DFS full path rather than the resolved target, that is, cifs_mount()
will be responsible for resolving the DFS link (cached) as well as
performing failover to any other targets in the referral.
Signed-off-by: default avatarPaulo Alcantara (SUSE) <pc@cjr.nz>
Reported-by: default avatarMartijn de Gouw <martijn.de.gouw@prodrive-technologies.com>
Fixes: 4a367dc0 ("cifs: Add support for failover in cifs_mount()")
Link: https://lore.kernel.org/linux-cifs/39643d7d-2abb-14d3-ced6-c394fab9a777@prodrive-technologies.comTested-by: default avatarMartijn de Gouw <martijn.de.gouw@prodrive-technologies.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 463a7b45
...@@ -120,17 +120,17 @@ cifs_build_devname(char *nodename, const char *prepath) ...@@ -120,17 +120,17 @@ cifs_build_devname(char *nodename, const char *prepath)
/** /**
* cifs_compose_mount_options - creates mount options for refferral * cifs_compose_mount_options - creates mount options for referral
* @sb_mountdata: parent/root DFS mount options (template) * @sb_mountdata: parent/root DFS mount options (template)
* @fullpath: full path in UNC format * @fullpath: full path in UNC format
* @ref: server's referral * @ref: optional server's referral
* @devname: optional pointer for saving device name * @devname: optional pointer for saving device name
* *
* creates mount options for submount based on template options sb_mountdata * creates mount options for submount based on template options sb_mountdata
* and replacing unc,ip,prefixpath options with ones we've got form ref_unc. * and replacing unc,ip,prefixpath options with ones we've got form ref_unc.
* *
* Returns: pointer to new mount options or ERR_PTR. * Returns: pointer to new mount options or ERR_PTR.
* Caller is responcible for freeing retunrned value if it is not error. * Caller is responsible for freeing returned value if it is not error.
*/ */
char *cifs_compose_mount_options(const char *sb_mountdata, char *cifs_compose_mount_options(const char *sb_mountdata,
const char *fullpath, const char *fullpath,
...@@ -150,18 +150,27 @@ char *cifs_compose_mount_options(const char *sb_mountdata, ...@@ -150,18 +150,27 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
if (sb_mountdata == NULL) if (sb_mountdata == NULL)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
if (strlen(fullpath) - ref->path_consumed) { if (ref) {
prepath = fullpath + ref->path_consumed; if (strlen(fullpath) - ref->path_consumed) {
/* skip initial delimiter */ prepath = fullpath + ref->path_consumed;
if (*prepath == '/' || *prepath == '\\') /* skip initial delimiter */
prepath++; if (*prepath == '/' || *prepath == '\\')
} prepath++;
}
name = cifs_build_devname(ref->node_name, prepath); name = cifs_build_devname(ref->node_name, prepath);
if (IS_ERR(name)) { if (IS_ERR(name)) {
rc = PTR_ERR(name); rc = PTR_ERR(name);
name = NULL; name = NULL;
goto compose_mount_options_err; goto compose_mount_options_err;
}
} else {
name = cifs_build_devname((char *)fullpath, NULL);
if (IS_ERR(name)) {
rc = PTR_ERR(name);
name = NULL;
goto compose_mount_options_err;
}
} }
rc = dns_resolve_server_name_to_ip(name, &srvIP); rc = dns_resolve_server_name_to_ip(name, &srvIP);
...@@ -225,6 +234,8 @@ char *cifs_compose_mount_options(const char *sb_mountdata, ...@@ -225,6 +234,8 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
if (devname) if (devname)
*devname = name; *devname = name;
else
kfree(name);
/*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/ /*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/
/*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/ /*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/
...@@ -241,23 +252,23 @@ char *cifs_compose_mount_options(const char *sb_mountdata, ...@@ -241,23 +252,23 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
} }
/** /**
* cifs_dfs_do_refmount - mounts specified path using provided refferal * cifs_dfs_do_mount - mounts specified path using DFS full path
*
* Always pass down @fullpath to smb3_do_mount() so we can use the root server
* to perform failover in case we failed to connect to the first target in the
* referral.
*
* @cifs_sb: parent/root superblock * @cifs_sb: parent/root superblock
* @fullpath: full path in UNC format * @fullpath: full path in UNC format
* @ref: server's referral
*/ */
static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt, static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt,
struct cifs_sb_info *cifs_sb, struct cifs_sb_info *cifs_sb,
const char *fullpath, const struct dfs_info3_param *ref) const char *fullpath)
{ {
struct vfsmount *mnt; struct vfsmount *mnt;
char *mountdata; char *mountdata;
char *devname; char *devname;
/*
* Always pass down the DFS full path to smb3_do_mount() so we
* can use it later for failover.
*/
devname = kstrndup(fullpath, strlen(fullpath), GFP_KERNEL); devname = kstrndup(fullpath, strlen(fullpath), GFP_KERNEL);
if (!devname) if (!devname)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -266,7 +277,7 @@ static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt, ...@@ -266,7 +277,7 @@ static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt,
/* strip first '\' from fullpath */ /* strip first '\' from fullpath */
mountdata = cifs_compose_mount_options(cifs_sb->mountdata, mountdata = cifs_compose_mount_options(cifs_sb->mountdata,
fullpath + 1, ref, NULL); fullpath + 1, NULL, NULL);
if (IS_ERR(mountdata)) { if (IS_ERR(mountdata)) {
kfree(devname); kfree(devname);
return (struct vfsmount *)mountdata; return (struct vfsmount *)mountdata;
...@@ -278,28 +289,16 @@ static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt, ...@@ -278,28 +289,16 @@ static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt,
return mnt; return mnt;
} }
static void dump_referral(const struct dfs_info3_param *ref)
{
cifs_dbg(FYI, "DFS: ref path: %s\n", ref->path_name);
cifs_dbg(FYI, "DFS: node path: %s\n", ref->node_name);
cifs_dbg(FYI, "DFS: fl: %d, srv_type: %d\n",
ref->flags, ref->server_type);
cifs_dbg(FYI, "DFS: ref_flags: %d, path_consumed: %d\n",
ref->ref_flag, ref->path_consumed);
}
/* /*
* Create a vfsmount that we can automount * Create a vfsmount that we can automount
*/ */
static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
{ {
struct dfs_info3_param referral = {0};
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifs_ses *ses; struct cifs_ses *ses;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
char *full_path, *root_path; char *full_path, *root_path;
unsigned int xid; unsigned int xid;
int len;
int rc; int rc;
struct vfsmount *mnt; struct vfsmount *mnt;
...@@ -357,7 +356,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) ...@@ -357,7 +356,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
if (!rc) { if (!rc) {
rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, rc = dfs_cache_find(xid, ses, cifs_sb->local_nls,
cifs_remap(cifs_sb), full_path + 1, cifs_remap(cifs_sb), full_path + 1,
&referral, NULL); NULL, NULL);
} }
free_xid(xid); free_xid(xid);
...@@ -366,26 +365,16 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) ...@@ -366,26 +365,16 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
mnt = ERR_PTR(rc); mnt = ERR_PTR(rc);
goto free_root_path; goto free_root_path;
} }
dump_referral(&referral);
len = strlen(referral.node_name);
if (len < 2) {
cifs_dbg(VFS, "%s: Net Address path too short: %s\n",
__func__, referral.node_name);
mnt = ERR_PTR(-EINVAL);
goto free_dfs_ref;
}
/* /*
* cifs_mount() will retry every available node server in case * OK - we were able to get and cache a referral for @full_path.
* of failures. *
* Now, pass it down to cifs_mount() and it will retry every available
* node server in case of failures - no need to do it here.
*/ */
mnt = cifs_dfs_do_refmount(mntpt, cifs_sb, full_path, &referral); mnt = cifs_dfs_do_mount(mntpt, cifs_sb, full_path);
cifs_dbg(FYI, "%s: cifs_dfs_do_refmount:%s , mnt:%p\n", __func__, cifs_dbg(FYI, "%s: cifs_dfs_do_mount:%s , mnt:%p\n", __func__,
referral.node_name, mnt); full_path + 1, mnt);
free_dfs_ref:
free_dfs_info_param(&referral);
free_root_path: free_root_path:
kfree(root_path); kfree(root_path);
free_full_path: free_full_path:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment