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:
Родитель
71e6864eac
Коммит
c88f7dcd6d
|
@ -307,12 +307,8 @@ static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt,
|
||||||
static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
|
static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
|
||||||
{
|
{
|
||||||
struct cifs_sb_info *cifs_sb;
|
struct cifs_sb_info *cifs_sb;
|
||||||
struct cifs_ses *ses;
|
|
||||||
struct cifs_tcon *tcon;
|
|
||||||
void *page;
|
void *page;
|
||||||
char *full_path, *root_path;
|
char *full_path;
|
||||||
unsigned int xid;
|
|
||||||
int rc;
|
|
||||||
struct vfsmount *mnt;
|
struct vfsmount *mnt;
|
||||||
|
|
||||||
cifs_dbg(FYI, "in %s\n", __func__);
|
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
|
* the double backslashes usually used in the UNC. This function
|
||||||
* gives us the latter, so we must adjust the result.
|
* gives us the latter, so we must adjust the result.
|
||||||
*/
|
*/
|
||||||
mnt = ERR_PTR(-ENOMEM);
|
|
||||||
|
|
||||||
cifs_sb = CIFS_SB(mntpt->d_sb);
|
cifs_sb = CIFS_SB(mntpt->d_sb);
|
||||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) {
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) {
|
||||||
mnt = ERR_PTR(-EREMOTE);
|
mnt = ERR_PTR(-EREMOTE);
|
||||||
|
@ -341,60 +335,11 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
|
||||||
}
|
}
|
||||||
|
|
||||||
convert_delimiter(full_path, '\\');
|
convert_delimiter(full_path, '\\');
|
||||||
|
|
||||||
cifs_dbg(FYI, "%s: full_path: %s\n", __func__, 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);
|
mnt = cifs_dfs_do_mount(mntpt, cifs_sb, full_path);
|
||||||
cifs_dbg(FYI, "%s: cifs_dfs_do_mount:%s , mnt:%p\n", __func__,
|
cifs_dbg(FYI, "%s: cifs_dfs_do_mount:%s , mnt:%p\n", __func__, full_path + 1, mnt);
|
||||||
full_path + 1, mnt);
|
|
||||||
|
|
||||||
free_root_path:
|
|
||||||
kfree(root_path);
|
|
||||||
free_full_path:
|
free_full_path:
|
||||||
free_dentry_path(page);
|
free_dentry_path(page);
|
||||||
cdda_exit:
|
cdda_exit:
|
||||||
|
|
|
@ -61,11 +61,6 @@ struct cifs_sb_info {
|
||||||
/* only used when CIFS_MOUNT_USE_PREFIX_PATH is set */
|
/* only used when CIFS_MOUNT_USE_PREFIX_PATH is set */
|
||||||
char *prepath;
|
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 */
|
/* randomly generated 128-bit number for indexing dfs mount groups in referral cache */
|
||||||
uuid_t dfs_mount_id;
|
uuid_t dfs_mount_id;
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -697,6 +697,19 @@ struct TCP_Server_Info {
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
bool is_dfs_conn; /* if a dfs connection */
|
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
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1097,7 +1110,6 @@ struct cifs_tcon {
|
||||||
struct cached_fid crfid; /* Cached root fid */
|
struct cached_fid crfid; /* Cached root fid */
|
||||||
/* BB add field for back pointer to sb struct(s)? */
|
/* BB add field for back pointer to sb struct(s)? */
|
||||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
char *dfs_path; /* canonical DFS path */
|
|
||||||
struct list_head ulist; /* cache update list */
|
struct list_head ulist; /* cache update list */
|
||||||
#endif
|
#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);
|
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 */
|
#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);
|
struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server);
|
||||||
void cifs_put_tcp_super(struct super_block *sb);
|
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_hostname(const char *unc);
|
||||||
char *extract_sharename(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;
|
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 */
|
#endif /* _CIFSPROTO_H */
|
||||||
|
|
1146
fs/cifs/connect.c
1146
fs/cifs/connect.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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 */
|
/* 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 cifs_ses *ses;
|
||||||
struct cache_entry *ce;
|
struct cache_entry *ce;
|
||||||
struct dfs_info3_param *refs = NULL;
|
struct dfs_info3_param *refs = NULL;
|
||||||
|
@ -1422,6 +1422,20 @@ out:
|
||||||
return rc;
|
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
|
* dfs_cache_remount_fs - remount a DFS share
|
||||||
*
|
*
|
||||||
|
@ -1435,6 +1449,7 @@ out:
|
||||||
int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
|
int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
|
||||||
{
|
{
|
||||||
struct cifs_tcon *tcon;
|
struct cifs_tcon *tcon;
|
||||||
|
struct TCP_Server_Info *server;
|
||||||
struct mount_group *mg;
|
struct mount_group *mg;
|
||||||
struct cifs_ses *sessions[CACHE_MAX_ENTRIES + 1] = {NULL};
|
struct cifs_ses *sessions[CACHE_MAX_ENTRIES + 1] = {NULL};
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -1443,13 +1458,15 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
tcon = cifs_sb_master_tcon(cifs_sb);
|
tcon = cifs_sb_master_tcon(cifs_sb);
|
||||||
if (!tcon->dfs_path) {
|
server = tcon->ses->server;
|
||||||
cifs_dbg(FYI, "%s: not a dfs tcon\n", __func__);
|
|
||||||
|
if (!server->origin_fullpath) {
|
||||||
|
cifs_dbg(FYI, "%s: not a dfs mount\n", __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uuid_is_null(&cifs_sb->dfs_mount_id)) {
|
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;
|
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);
|
mg = find_mount_group_locked(&cifs_sb->dfs_mount_id);
|
||||||
if (IS_ERR(mg)) {
|
if (IS_ERR(mg)) {
|
||||||
mutex_unlock(&mount_group_list_lock);
|
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);
|
return PTR_ERR(mg);
|
||||||
}
|
}
|
||||||
kref_get(&mg->refcount);
|
kref_get(&mg->refcount);
|
||||||
|
@ -1498,9 +1515,12 @@ static void refresh_mounts(struct cifs_ses **sessions)
|
||||||
|
|
||||||
spin_lock(&cifs_tcp_ses_lock);
|
spin_lock(&cifs_tcp_ses_lock);
|
||||||
list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
|
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(ses, &server->smb_ses_list, smb_ses_list) {
|
||||||
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
|
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
|
||||||
if (tcon->dfs_path) {
|
if (!tcon->ipc && !tcon->need_reconnect) {
|
||||||
tcon->tc_count++;
|
tcon->tc_count++;
|
||||||
list_add_tail(&tcon->ulist, &tcons);
|
list_add_tail(&tcon->ulist, &tcons);
|
||||||
}
|
}
|
||||||
|
@ -1510,8 +1530,16 @@ static void refresh_mounts(struct cifs_ses **sessions)
|
||||||
spin_unlock(&cifs_tcp_ses_lock);
|
spin_unlock(&cifs_tcp_ses_lock);
|
||||||
|
|
||||||
list_for_each_entry_safe(tcon, ntcon, &tcons, ulist) {
|
list_for_each_entry_safe(tcon, ntcon, &tcons, ulist) {
|
||||||
|
struct TCP_Server_Info *server = tcon->ses->server;
|
||||||
|
|
||||||
list_del_init(&tcon->ulist);
|
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);
|
cifs_put_tcon(tcon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,9 +139,6 @@ tconInfoFree(struct cifs_tcon *buf_to_free)
|
||||||
kfree(buf_to_free->nativeFileSystem);
|
kfree(buf_to_free->nativeFileSystem);
|
||||||
kfree_sensitive(buf_to_free->password);
|
kfree_sensitive(buf_to_free->password);
|
||||||
kfree(buf_to_free->crfid.fid);
|
kfree(buf_to_free->crfid.fid);
|
||||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
|
||||||
kfree(buf_to_free->dfs_path);
|
|
||||||
#endif
|
|
||||||
kfree(buf_to_free);
|
kfree(buf_to_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1288,69 +1285,20 @@ out:
|
||||||
return rc;
|
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);
|
kfree(cifs_sb->prepath);
|
||||||
|
|
||||||
if (prefix && *prefix) {
|
if (prefix && *prefix) {
|
||||||
cifs_sb->prepath = kstrdup(prefix, GFP_ATOMIC);
|
cifs_sb->prepath = kstrdup(prefix, GFP_ATOMIC);
|
||||||
if (!cifs_sb->prepath) {
|
if (!cifs_sb->prepath)
|
||||||
rc = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
|
convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
|
||||||
} else
|
} else
|
||||||
cifs_sb->prepath = NULL;
|
cifs_sb->prepath = NULL;
|
||||||
|
|
||||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
|
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
|
||||||
|
return 0;
|
||||||
out:
|
|
||||||
cifs_put_tcon_super(sb);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
#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 fsctl_get_dfs_referral_req *dfs_req = NULL;
|
||||||
struct get_dfs_referral_rsp *dfs_rsp = NULL;
|
struct get_dfs_referral_rsp *dfs_rsp = NULL;
|
||||||
u32 dfs_req_size = 0, dfs_rsp_size = 0;
|
u32 dfs_req_size = 0, dfs_rsp_size = 0;
|
||||||
|
int retry_count = 0;
|
||||||
|
|
||||||
cifs_dbg(FYI, "%s: path: %s\n", __func__, search_name);
|
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 */,
|
true /* is_fsctl */,
|
||||||
(char *)dfs_req, dfs_req_size, CIFSMaxBufSize,
|
(char *)dfs_req, dfs_req_size, CIFSMaxBufSize,
|
||||||
(char **)&dfs_rsp, &dfs_rsp_size);
|
(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) {
|
||||||
if ((rc != -ENOENT) && (rc != -EOPNOTSUPP))
|
if (!is_retryable_error(rc) && rc != -ENOENT && rc != -EOPNOTSUPP)
|
||||||
cifs_tcon_dbg(VFS, "ioctl error in %s rc=%d\n", __func__, rc);
|
cifs_tcon_dbg(VFS, "%s: ioctl error: rc=%d\n", __func__, rc);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,11 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
||||||
if (tcon == NULL)
|
if (tcon == NULL)
|
||||||
return 0;
|
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;
|
return 0;
|
||||||
|
|
||||||
if (tcon->tidStatus == CifsExiting) {
|
if (tcon->tidStatus == CifsExiting) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче