cifs: Fix retrieval of DFS referrals in cifs_mount()

Make sure that DFS referrals are sent to newly resolved root targets
as in a multi tier DFS setup.

Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Link: https://lkml.kernel.org/r/05aa2995-e85e-0ff4-d003-5bb08bd17a22@canonical.com
Cc: stable@vger.kernel.org
Tested-by: Matthew Ruffell <matthew.ruffell@canonical.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
Paulo Alcantara (SUSE) 2019-11-22 12:30:56 -03:00 committed by Steve French
parent 84a1f5b1cc
commit 5bb30a4dd6

View File

@ -4786,6 +4786,17 @@ static int is_path_remote(struct cifs_sb_info *cifs_sb, struct smb_vol *vol,
}
#ifdef CONFIG_CIFS_DFS_UPCALL
static inline void set_root_tcon(struct cifs_sb_info *cifs_sb,
struct cifs_tcon *tcon,
struct cifs_tcon **root)
{
spin_lock(&cifs_tcp_ses_lock);
tcon->tc_count++;
tcon->remap = cifs_remap(cifs_sb);
spin_unlock(&cifs_tcp_ses_lock);
*root = tcon;
}
int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
{
int rc = 0;
@ -4887,18 +4898,10 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
/* Cache out resolved root server */
(void)dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb),
root_path + 1, NULL, NULL);
/*
* Save root tcon for additional DFS requests to update or create a new
* DFS cache entry, or even perform DFS failover.
*/
spin_lock(&cifs_tcp_ses_lock);
tcon->tc_count++;
tcon->dfs_path = root_path;
kfree(root_path);
root_path = NULL;
tcon->remap = cifs_remap(cifs_sb);
spin_unlock(&cifs_tcp_ses_lock);
root_tcon = tcon;
set_root_tcon(cifs_sb, tcon, &root_tcon);
for (count = 1; ;) {
if (!rc && tcon) {
@ -4935,6 +4938,15 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
mount_put_conns(cifs_sb, xid, server, ses, tcon);
rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses,
&tcon);
/*
* Ensure that DFS referrals go through new root server.
*/
if (!rc && tcon &&
(tcon->share_flags & (SHI1005_FLAGS_DFS |
SHI1005_FLAGS_DFS_ROOT))) {
cifs_put_tcon(root_tcon);
set_root_tcon(cifs_sb, tcon, &root_tcon);
}
}
if (rc) {
if (rc == -EACCES || rc == -EOPNOTSUPP)