Commit 5bb30a4d authored by Paulo Alcantara (SUSE)'s avatar Paulo Alcantara (SUSE) Committed by Steve French
Browse files

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: default avatarPaulo 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: default avatarMatthew Ruffell <matthew.ruffell@canonical.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 84a1f5b1
Loading
Loading
Loading
Loading
+22 −10
Original line number Diff line number Diff line
@@ -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)