mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	cifs: support nested dfs links over reconnect
Mounting a dfs link that has nested links was already supported at mount(2), so make it work over reconnect as well. Make the following case work: * mount //root/dfs/link /mnt -o ... - final share: /server/share * in server settings - change target folder of /root/dfs/link3 to /server/share2 - change target folder of /root/dfs/link2 to /root/dfs/link3 - change target folder of /root/dfs/link to /root/dfs/link2 * mount -o remount,... /mnt - refresh all dfs referrals - mark current connection for failover - cifs_reconnect() reconnects to root server - tree_connect() * checks that /root/dfs/link2 is a link, then chase it * checks that root/dfs/link3 is a link, then chase it * finally tree connect to /server/share2 If the mounted share is no longer accessible and a reconnect had been triggered, the client will retry it from both last referral path (/root/dfs/link3) and original referral path (/root/dfs/link). Any new referral paths found while chasing dfs links over reconnect, it will be updated to TCP_Server_Info::leaf_fullpath, accordingly. Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
		
							parent
							
								
									71e6864eac
								
							
						
					
					
						commit
						c88f7dcd6d
					
				
					 9 changed files with 684 additions and 717 deletions
				
			
		| 
						 | 
				
			
			@ -307,12 +307,8 @@ static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt,
 | 
			
		|||
static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
 | 
			
		||||
{
 | 
			
		||||
	struct cifs_sb_info *cifs_sb;
 | 
			
		||||
	struct cifs_ses *ses;
 | 
			
		||||
	struct cifs_tcon *tcon;
 | 
			
		||||
	void *page;
 | 
			
		||||
	char *full_path, *root_path;
 | 
			
		||||
	unsigned int xid;
 | 
			
		||||
	int rc;
 | 
			
		||||
	char *full_path;
 | 
			
		||||
	struct vfsmount *mnt;
 | 
			
		||||
 | 
			
		||||
	cifs_dbg(FYI, "in %s\n", __func__);
 | 
			
		||||
| 
						 | 
				
			
			@ -324,8 +320,6 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
 | 
			
		|||
	 * the double backslashes usually used in the UNC. This function
 | 
			
		||||
	 * gives us the latter, so we must adjust the result.
 | 
			
		||||
	 */
 | 
			
		||||
	mnt = ERR_PTR(-ENOMEM);
 | 
			
		||||
 | 
			
		||||
	cifs_sb = CIFS_SB(mntpt->d_sb);
 | 
			
		||||
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) {
 | 
			
		||||
		mnt = ERR_PTR(-EREMOTE);
 | 
			
		||||
| 
						 | 
				
			
			@ -341,60 +335,11 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	convert_delimiter(full_path, '\\');
 | 
			
		||||
 | 
			
		||||
	cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
 | 
			
		||||
 | 
			
		||||
	if (!cifs_sb_master_tlink(cifs_sb)) {
 | 
			
		||||
		cifs_dbg(FYI, "%s: master tlink is NULL\n", __func__);
 | 
			
		||||
		goto free_full_path;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tcon = cifs_sb_master_tcon(cifs_sb);
 | 
			
		||||
	if (!tcon) {
 | 
			
		||||
		cifs_dbg(FYI, "%s: master tcon is NULL\n", __func__);
 | 
			
		||||
		goto free_full_path;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	root_path = kstrdup(tcon->treeName, GFP_KERNEL);
 | 
			
		||||
	if (!root_path) {
 | 
			
		||||
		mnt = ERR_PTR(-ENOMEM);
 | 
			
		||||
		goto free_full_path;
 | 
			
		||||
	}
 | 
			
		||||
	cifs_dbg(FYI, "%s: root path: %s\n", __func__, root_path);
 | 
			
		||||
 | 
			
		||||
	ses = tcon->ses;
 | 
			
		||||
	xid = get_xid();
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If DFS root has been expired, then unconditionally fetch it again to
 | 
			
		||||
	 * refresh DFS referral cache.
 | 
			
		||||
	 */
 | 
			
		||||
	rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb),
 | 
			
		||||
			    root_path + 1, NULL, NULL);
 | 
			
		||||
	if (!rc) {
 | 
			
		||||
		rc = dfs_cache_find(xid, ses, cifs_sb->local_nls,
 | 
			
		||||
				    cifs_remap(cifs_sb), full_path + 1,
 | 
			
		||||
				    NULL, NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	free_xid(xid);
 | 
			
		||||
 | 
			
		||||
	if (rc) {
 | 
			
		||||
		mnt = ERR_PTR(rc);
 | 
			
		||||
		goto free_root_path;
 | 
			
		||||
	}
 | 
			
		||||
	/*
 | 
			
		||||
	 * OK - we were able to get and cache a referral for @full_path.
 | 
			
		||||
	 *
 | 
			
		||||
	 * 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_mount(mntpt, cifs_sb, full_path);
 | 
			
		||||
	cifs_dbg(FYI, "%s: cifs_dfs_do_mount:%s , mnt:%p\n", __func__,
 | 
			
		||||
		 full_path + 1, mnt);
 | 
			
		||||
	cifs_dbg(FYI, "%s: cifs_dfs_do_mount:%s , mnt:%p\n", __func__, full_path + 1, mnt);
 | 
			
		||||
 | 
			
		||||
free_root_path:
 | 
			
		||||
	kfree(root_path);
 | 
			
		||||
free_full_path:
 | 
			
		||||
	free_dentry_path(page);
 | 
			
		||||
cdda_exit:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,11 +61,6 @@ struct cifs_sb_info {
 | 
			
		|||
	/* only used when CIFS_MOUNT_USE_PREFIX_PATH is set */
 | 
			
		||||
	char *prepath;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Canonical DFS path initially provided by the mount call. We might connect to something
 | 
			
		||||
	 * different via DFS but we want to keep it to do failover properly.
 | 
			
		||||
	 */
 | 
			
		||||
	char *origin_fullpath; /* \\HOST\SHARE\[OPTIONAL PATH] */
 | 
			
		||||
	/* randomly generated 128-bit number for indexing dfs mount groups in referral cache */
 | 
			
		||||
	uuid_t dfs_mount_id;
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -697,6 +697,19 @@ struct TCP_Server_Info {
 | 
			
		|||
#endif
 | 
			
		||||
#ifdef CONFIG_CIFS_DFS_UPCALL
 | 
			
		||||
	bool is_dfs_conn; /* if a dfs connection */
 | 
			
		||||
	struct mutex refpath_lock; /* protects leaf_fullpath */
 | 
			
		||||
	/*
 | 
			
		||||
	 * Canonical DFS full paths that were used to chase referrals in mount and reconnect.
 | 
			
		||||
	 *
 | 
			
		||||
	 * origin_fullpath: first or original referral path
 | 
			
		||||
	 * leaf_fullpath: last referral path (might be changed due to nested links in reconnect)
 | 
			
		||||
	 *
 | 
			
		||||
	 * current_fullpath: pointer to either origin_fullpath or leaf_fullpath
 | 
			
		||||
	 * NOTE: cannot be accessed outside cifs_reconnect() and smb2_reconnect()
 | 
			
		||||
	 *
 | 
			
		||||
	 * format: \\HOST\SHARE\[OPTIONAL PATH]
 | 
			
		||||
	 */
 | 
			
		||||
	char *origin_fullpath, *leaf_fullpath, *current_fullpath;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1097,7 +1110,6 @@ struct cifs_tcon {
 | 
			
		|||
	struct cached_fid crfid; /* Cached root fid */
 | 
			
		||||
	/* BB add field for back pointer to sb struct(s)? */
 | 
			
		||||
#ifdef CONFIG_CIFS_DFS_UPCALL
 | 
			
		||||
	char *dfs_path; /* canonical DFS path */
 | 
			
		||||
	struct list_head ulist; /* cache update list */
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1948,4 +1960,14 @@ static inline bool is_tcon_dfs(struct cifs_tcon *tcon)
 | 
			
		|||
		tcon->share_flags & (SHI1005_FLAGS_DFS | SHI1005_FLAGS_DFS_ROOT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline bool cifs_is_referral_server(struct cifs_tcon *tcon,
 | 
			
		||||
					   const struct dfs_info3_param *ref)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * Check if all targets are capable of handling DFS referrals as per
 | 
			
		||||
	 * MS-DFSC 2.2.4 RESP_GET_DFS_REFERRAL.
 | 
			
		||||
	 */
 | 
			
		||||
	return is_tcon_dfs(tcon) || (ref && (ref->flags & DFSREF_REFERRAL_SERVER));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif	/* _CIFS_GLOB_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -607,7 +607,7 @@ int smb2_parse_query_directory(struct cifs_tcon *tcon, struct kvec *rsp_iov,
 | 
			
		|||
 | 
			
		||||
struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server);
 | 
			
		||||
void cifs_put_tcp_super(struct super_block *sb);
 | 
			
		||||
int update_super_prepath(struct cifs_tcon *tcon, char *prefix);
 | 
			
		||||
int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix);
 | 
			
		||||
char *extract_hostname(const char *unc);
 | 
			
		||||
char *extract_sharename(const char *unc);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -634,4 +634,7 @@ static inline int cifs_create_options(struct cifs_sb_info *cifs_sb, int options)
 | 
			
		|||
		return options;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon);
 | 
			
		||||
void cifs_put_tcon_super(struct super_block *sb);
 | 
			
		||||
 | 
			
		||||
#endif			/* _CIFSPROTO_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1186
									
								
								fs/cifs/connect.c
									
									
									
									
									
								
							
							
						
						
									
										1186
									
								
								fs/cifs/connect.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -1364,9 +1364,9 @@ static void mark_for_reconnect_if_needed(struct cifs_tcon *tcon, struct dfs_cach
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
/* Refresh dfs referral of tcon and mark it for reconnect if needed */
 | 
			
		||||
static int refresh_tcon(struct cifs_ses **sessions, struct cifs_tcon *tcon, bool force_refresh)
 | 
			
		||||
static int __refresh_tcon(const char *path, struct cifs_ses **sessions, struct cifs_tcon *tcon,
 | 
			
		||||
			  bool force_refresh)
 | 
			
		||||
{
 | 
			
		||||
	const char *path = tcon->dfs_path + 1;
 | 
			
		||||
	struct cifs_ses *ses;
 | 
			
		||||
	struct cache_entry *ce;
 | 
			
		||||
	struct dfs_info3_param *refs = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -1422,6 +1422,20 @@ static int refresh_tcon(struct cifs_ses **sessions, struct cifs_tcon *tcon, bool
 | 
			
		|||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int refresh_tcon(struct cifs_ses **sessions, struct cifs_tcon *tcon, bool force_refresh)
 | 
			
		||||
{
 | 
			
		||||
	struct TCP_Server_Info *server = tcon->ses->server;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&server->refpath_lock);
 | 
			
		||||
	if (strcasecmp(server->leaf_fullpath, server->origin_fullpath))
 | 
			
		||||
		__refresh_tcon(server->leaf_fullpath + 1, sessions, tcon, force_refresh);
 | 
			
		||||
	mutex_unlock(&server->refpath_lock);
 | 
			
		||||
 | 
			
		||||
	__refresh_tcon(server->origin_fullpath + 1, sessions, tcon, force_refresh);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * dfs_cache_remount_fs - remount a DFS share
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -1435,6 +1449,7 @@ static int refresh_tcon(struct cifs_ses **sessions, struct cifs_tcon *tcon, bool
 | 
			
		|||
int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
 | 
			
		||||
{
 | 
			
		||||
	struct cifs_tcon *tcon;
 | 
			
		||||
	struct TCP_Server_Info *server;
 | 
			
		||||
	struct mount_group *mg;
 | 
			
		||||
	struct cifs_ses *sessions[CACHE_MAX_ENTRIES + 1] = {NULL};
 | 
			
		||||
	int rc;
 | 
			
		||||
| 
						 | 
				
			
			@ -1443,13 +1458,15 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
 | 
			
		|||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	tcon = cifs_sb_master_tcon(cifs_sb);
 | 
			
		||||
	if (!tcon->dfs_path) {
 | 
			
		||||
		cifs_dbg(FYI, "%s: not a dfs tcon\n", __func__);
 | 
			
		||||
	server = tcon->ses->server;
 | 
			
		||||
 | 
			
		||||
	if (!server->origin_fullpath) {
 | 
			
		||||
		cifs_dbg(FYI, "%s: not a dfs mount\n", __func__);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (uuid_is_null(&cifs_sb->dfs_mount_id)) {
 | 
			
		||||
		cifs_dbg(FYI, "%s: tcon has no dfs mount group id\n", __func__);
 | 
			
		||||
		cifs_dbg(FYI, "%s: no dfs mount group id\n", __func__);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1457,7 +1474,7 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
 | 
			
		|||
	mg = find_mount_group_locked(&cifs_sb->dfs_mount_id);
 | 
			
		||||
	if (IS_ERR(mg)) {
 | 
			
		||||
		mutex_unlock(&mount_group_list_lock);
 | 
			
		||||
		cifs_dbg(FYI, "%s: tcon has ipc session to refresh referral\n", __func__);
 | 
			
		||||
		cifs_dbg(FYI, "%s: no ipc session for refreshing referral\n", __func__);
 | 
			
		||||
		return PTR_ERR(mg);
 | 
			
		||||
	}
 | 
			
		||||
	kref_get(&mg->refcount);
 | 
			
		||||
| 
						 | 
				
			
			@ -1498,9 +1515,12 @@ static void refresh_mounts(struct cifs_ses **sessions)
 | 
			
		|||
 | 
			
		||||
	spin_lock(&cifs_tcp_ses_lock);
 | 
			
		||||
	list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
 | 
			
		||||
		if (!server->is_dfs_conn)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
 | 
			
		||||
			list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
 | 
			
		||||
				if (tcon->dfs_path) {
 | 
			
		||||
				if (!tcon->ipc && !tcon->need_reconnect) {
 | 
			
		||||
					tcon->tc_count++;
 | 
			
		||||
					list_add_tail(&tcon->ulist, &tcons);
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			@ -1510,8 +1530,16 @@ static void refresh_mounts(struct cifs_ses **sessions)
 | 
			
		|||
	spin_unlock(&cifs_tcp_ses_lock);
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry_safe(tcon, ntcon, &tcons, ulist) {
 | 
			
		||||
		struct TCP_Server_Info *server = tcon->ses->server;
 | 
			
		||||
 | 
			
		||||
		list_del_init(&tcon->ulist);
 | 
			
		||||
		refresh_tcon(sessions, tcon, false);
 | 
			
		||||
 | 
			
		||||
		mutex_lock(&server->refpath_lock);
 | 
			
		||||
		if (strcasecmp(server->leaf_fullpath, server->origin_fullpath))
 | 
			
		||||
			__refresh_tcon(server->leaf_fullpath + 1, sessions, tcon, false);
 | 
			
		||||
		mutex_unlock(&server->refpath_lock);
 | 
			
		||||
 | 
			
		||||
		__refresh_tcon(server->origin_fullpath + 1, sessions, tcon, false);
 | 
			
		||||
		cifs_put_tcon(tcon);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -139,9 +139,6 @@ tconInfoFree(struct cifs_tcon *buf_to_free)
 | 
			
		|||
	kfree(buf_to_free->nativeFileSystem);
 | 
			
		||||
	kfree_sensitive(buf_to_free->password);
 | 
			
		||||
	kfree(buf_to_free->crfid.fid);
 | 
			
		||||
#ifdef CONFIG_CIFS_DFS_UPCALL
 | 
			
		||||
	kfree(buf_to_free->dfs_path);
 | 
			
		||||
#endif
 | 
			
		||||
	kfree(buf_to_free);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1288,69 +1285,20 @@ int match_target_ip(struct TCP_Server_Info *server,
 | 
			
		|||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void tcon_super_cb(struct super_block *sb, void *arg)
 | 
			
		||||
int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix)
 | 
			
		||||
{
 | 
			
		||||
	struct super_cb_data *sd = arg;
 | 
			
		||||
	struct cifs_tcon *tcon = sd->data;
 | 
			
		||||
	struct cifs_sb_info *cifs_sb;
 | 
			
		||||
 | 
			
		||||
	if (sd->sb)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	cifs_sb = CIFS_SB(sb);
 | 
			
		||||
	if (tcon->dfs_path && cifs_sb->origin_fullpath &&
 | 
			
		||||
	    !strcasecmp(tcon->dfs_path, cifs_sb->origin_fullpath))
 | 
			
		||||
		sd->sb = sb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon)
 | 
			
		||||
{
 | 
			
		||||
	return __cifs_get_super(tcon_super_cb, tcon);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void cifs_put_tcon_super(struct super_block *sb)
 | 
			
		||||
{
 | 
			
		||||
	__cifs_put_super(sb);
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static inline struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon)
 | 
			
		||||
{
 | 
			
		||||
	return ERR_PTR(-EOPNOTSUPP);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void cifs_put_tcon_super(struct super_block *sb)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int update_super_prepath(struct cifs_tcon *tcon, char *prefix)
 | 
			
		||||
{
 | 
			
		||||
	struct super_block *sb;
 | 
			
		||||
	struct cifs_sb_info *cifs_sb;
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
 | 
			
		||||
	sb = cifs_get_tcon_super(tcon);
 | 
			
		||||
	if (IS_ERR(sb))
 | 
			
		||||
		return PTR_ERR(sb);
 | 
			
		||||
 | 
			
		||||
	cifs_sb = CIFS_SB(sb);
 | 
			
		||||
 | 
			
		||||
	kfree(cifs_sb->prepath);
 | 
			
		||||
 | 
			
		||||
	if (prefix && *prefix) {
 | 
			
		||||
		cifs_sb->prepath = kstrdup(prefix, GFP_ATOMIC);
 | 
			
		||||
		if (!cifs_sb->prepath) {
 | 
			
		||||
			rc = -ENOMEM;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
		if (!cifs_sb->prepath)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
		convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
 | 
			
		||||
	} else
 | 
			
		||||
		cifs_sb->prepath = NULL;
 | 
			
		||||
 | 
			
		||||
	cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	cifs_put_tcon_super(sb);
 | 
			
		||||
	return rc;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2844,6 +2844,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
 | 
			
		|||
	struct fsctl_get_dfs_referral_req *dfs_req = NULL;
 | 
			
		||||
	struct get_dfs_referral_rsp *dfs_rsp = NULL;
 | 
			
		||||
	u32 dfs_req_size = 0, dfs_rsp_size = 0;
 | 
			
		||||
	int retry_count = 0;
 | 
			
		||||
 | 
			
		||||
	cifs_dbg(FYI, "%s: path: %s\n", __func__, search_name);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2895,11 +2896,14 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
 | 
			
		|||
				true /* is_fsctl */,
 | 
			
		||||
				(char *)dfs_req, dfs_req_size, CIFSMaxBufSize,
 | 
			
		||||
				(char **)&dfs_rsp, &dfs_rsp_size);
 | 
			
		||||
	} while (rc == -EAGAIN);
 | 
			
		||||
		if (!is_retryable_error(rc))
 | 
			
		||||
			break;
 | 
			
		||||
		usleep_range(512, 2048);
 | 
			
		||||
	} while (++retry_count < 5);
 | 
			
		||||
 | 
			
		||||
	if (rc) {
 | 
			
		||||
		if ((rc != -ENOENT) && (rc != -EOPNOTSUPP))
 | 
			
		||||
			cifs_tcon_dbg(VFS, "ioctl error in %s rc=%d\n", __func__, rc);
 | 
			
		||||
		if (!is_retryable_error(rc) && rc != -ENOENT && rc != -EOPNOTSUPP)
 | 
			
		||||
			cifs_tcon_dbg(VFS, "%s: ioctl error: rc=%d\n", __func__, rc);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -155,7 +155,11 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
 | 
			
		|||
	if (tcon == NULL)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (smb2_command == SMB2_TREE_CONNECT)
 | 
			
		||||
	/*
 | 
			
		||||
	 * Need to also skip SMB2_IOCTL because it is used for checking nested dfs links in
 | 
			
		||||
	 * cifs_tree_connect().
 | 
			
		||||
	 */
 | 
			
		||||
	if (smb2_command == SMB2_TREE_CONNECT || smb2_command == SMB2_IOCTL)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (tcon->tidStatus == CifsExiting) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue