Skip to content

Commit 36008fe

Browse files
pcacjrSteve French
authored and
Steve French
committed
smb: client: don't try following DFS links in cifs_tree_connect()
We can't properly support chasing DFS links in cifs_tree_connect() because (1) We don't support creating new sessions while we're reconnecting, which would be required for DFS interlinks. (2) ->is_path_accessible() can't be called from cifs_tree_connect() as it would deadlock with smb2_reconnect(). This is required for checking if new DFS target is a nested DFS link. By unconditionally trying to get an DFS referral from new DFS target isn't correct because if the new DFS target (interlink) is an DFS standalone namespace, then we would end up getting -ELOOP and then potentially leaving tcon disconnected. Signed-off-by: Paulo Alcantara (Red Hat) <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent e148107 commit 36008fe

File tree

1 file changed

+17
-171
lines changed

1 file changed

+17
-171
lines changed

fs/smb/client/dfs.c

+17-171
Original file line numberDiff line numberDiff line change
@@ -321,49 +321,6 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
321321
return rc;
322322
}
323323

324-
/* Update dfs referral path of superblock */
325-
static int update_server_fullpath(struct TCP_Server_Info *server, struct cifs_sb_info *cifs_sb,
326-
const char *target)
327-
{
328-
int rc = 0;
329-
size_t len = strlen(target);
330-
char *refpath, *npath;
331-
332-
if (unlikely(len < 2 || *target != '\\'))
333-
return -EINVAL;
334-
335-
if (target[1] == '\\') {
336-
len += 1;
337-
refpath = kmalloc(len, GFP_KERNEL);
338-
if (!refpath)
339-
return -ENOMEM;
340-
341-
scnprintf(refpath, len, "%s", target);
342-
} else {
343-
len += sizeof("\\");
344-
refpath = kmalloc(len, GFP_KERNEL);
345-
if (!refpath)
346-
return -ENOMEM;
347-
348-
scnprintf(refpath, len, "\\%s", target);
349-
}
350-
351-
npath = dfs_cache_canonical_path(refpath, cifs_sb->local_nls, cifs_remap(cifs_sb));
352-
kfree(refpath);
353-
354-
if (IS_ERR(npath)) {
355-
rc = PTR_ERR(npath);
356-
} else {
357-
mutex_lock(&server->refpath_lock);
358-
spin_lock(&server->srv_lock);
359-
kfree(server->leaf_fullpath);
360-
server->leaf_fullpath = npath;
361-
spin_unlock(&server->srv_lock);
362-
mutex_unlock(&server->refpath_lock);
363-
}
364-
return rc;
365-
}
366-
367324
static int target_share_matches_server(struct TCP_Server_Info *server, char *share,
368325
bool *target_match)
369326
{
@@ -388,77 +345,22 @@ static int target_share_matches_server(struct TCP_Server_Info *server, char *sha
388345
return rc;
389346
}
390347

391-
static void __tree_connect_ipc(const unsigned int xid, char *tree,
392-
struct cifs_sb_info *cifs_sb,
393-
struct cifs_ses *ses)
394-
{
395-
struct TCP_Server_Info *server = ses->server;
396-
struct cifs_tcon *tcon = ses->tcon_ipc;
397-
int rc;
398-
399-
spin_lock(&ses->ses_lock);
400-
spin_lock(&ses->chan_lock);
401-
if (cifs_chan_needs_reconnect(ses, server) ||
402-
ses->ses_status != SES_GOOD) {
403-
spin_unlock(&ses->chan_lock);
404-
spin_unlock(&ses->ses_lock);
405-
cifs_server_dbg(FYI, "%s: skipping ipc reconnect due to disconnected ses\n",
406-
__func__);
407-
return;
408-
}
409-
spin_unlock(&ses->chan_lock);
410-
spin_unlock(&ses->ses_lock);
411-
412-
cifs_server_lock(server);
413-
scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname);
414-
cifs_server_unlock(server);
415-
416-
rc = server->ops->tree_connect(xid, ses, tree, tcon,
417-
cifs_sb->local_nls);
418-
cifs_server_dbg(FYI, "%s: tree_reconnect %s: %d\n", __func__, tree, rc);
419-
spin_lock(&tcon->tc_lock);
420-
if (rc) {
421-
tcon->status = TID_NEED_TCON;
422-
} else {
423-
tcon->status = TID_GOOD;
424-
tcon->need_reconnect = false;
425-
}
426-
spin_unlock(&tcon->tc_lock);
427-
}
428-
429-
static void tree_connect_ipc(const unsigned int xid, char *tree,
430-
struct cifs_sb_info *cifs_sb,
431-
struct cifs_tcon *tcon)
432-
{
433-
struct cifs_ses *ses = tcon->ses;
434-
435-
__tree_connect_ipc(xid, tree, cifs_sb, ses);
436-
__tree_connect_ipc(xid, tree, cifs_sb, CIFS_DFS_ROOT_SES(ses));
437-
}
438-
439-
static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *tcon,
440-
struct cifs_sb_info *cifs_sb, char *tree, bool islink,
441-
struct dfs_cache_tgt_list *tl)
348+
static int tree_connect_dfs_target(const unsigned int xid,
349+
struct cifs_tcon *tcon,
350+
struct cifs_sb_info *cifs_sb,
351+
char *tree, bool islink,
352+
struct dfs_cache_tgt_list *tl)
442353
{
443-
int rc;
354+
const struct smb_version_operations *ops = tcon->ses->server->ops;
444355
struct TCP_Server_Info *server = tcon->ses->server;
445-
const struct smb_version_operations *ops = server->ops;
446-
struct cifs_ses *root_ses = CIFS_DFS_ROOT_SES(tcon->ses);
447-
char *share = NULL, *prefix = NULL;
448356
struct dfs_cache_tgt_iterator *tit;
357+
char *share = NULL, *prefix = NULL;
449358
bool target_match;
450-
451-
tit = dfs_cache_get_tgt_iterator(tl);
452-
if (!tit) {
453-
rc = -ENOENT;
454-
goto out;
455-
}
359+
int rc = -ENOENT;
456360

457361
/* Try to tree connect to all dfs targets */
458-
for (; tit; tit = dfs_cache_get_next_tgt(tl, tit)) {
459-
const char *target = dfs_cache_get_tgt_name(tit);
460-
DFS_CACHE_TGT_LIST(ntl);
461-
362+
for (tit = dfs_cache_get_tgt_iterator(tl);
363+
tit; tit = dfs_cache_get_next_tgt(tl, tit)) {
462364
kfree(share);
463365
kfree(prefix);
464366
share = prefix = NULL;
@@ -479,69 +381,16 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t
479381
}
480382

481383
dfs_cache_noreq_update_tgthint(server->leaf_fullpath + 1, tit);
482-
tree_connect_ipc(xid, tree, cifs_sb, tcon);
483-
484384
scnprintf(tree, MAX_TREE_SIZE, "\\%s", share);
485-
if (!islink) {
486-
rc = ops->tree_connect(xid, tcon->ses, tree, tcon, cifs_sb->local_nls);
487-
break;
488-
}
489-
490-
/*
491-
* If no dfs referrals were returned from link target, then just do a TREE_CONNECT
492-
* to it. Otherwise, cache the dfs referral and then mark current tcp ses for
493-
* reconnect so either the demultiplex thread or the echo worker will reconnect to
494-
* newly resolved target.
495-
*/
496-
if (dfs_cache_find(xid, root_ses, cifs_sb->local_nls, cifs_remap(cifs_sb), target,
497-
NULL, &ntl)) {
498-
rc = ops->tree_connect(xid, tcon->ses, tree, tcon, cifs_sb->local_nls);
499-
if (rc)
500-
continue;
501-
385+
rc = ops->tree_connect(xid, tcon->ses, tree,
386+
tcon, tcon->ses->local_nls);
387+
if (islink && !rc && cifs_sb)
502388
rc = cifs_update_super_prepath(cifs_sb, prefix);
503-
} else {
504-
/* Target is another dfs share */
505-
rc = update_server_fullpath(server, cifs_sb, target);
506-
dfs_cache_free_tgts(tl);
507-
508-
if (!rc) {
509-
rc = -EREMOTE;
510-
list_replace_init(&ntl.tl_list, &tl->tl_list);
511-
} else
512-
dfs_cache_free_tgts(&ntl);
513-
}
514389
break;
515390
}
516391

517-
out:
518392
kfree(share);
519393
kfree(prefix);
520-
521-
return rc;
522-
}
523-
524-
static int tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *tcon,
525-
struct cifs_sb_info *cifs_sb, char *tree, bool islink,
526-
struct dfs_cache_tgt_list *tl)
527-
{
528-
int rc;
529-
int num_links = 0;
530-
struct TCP_Server_Info *server = tcon->ses->server;
531-
char *old_fullpath = server->leaf_fullpath;
532-
533-
do {
534-
rc = __tree_connect_dfs_target(xid, tcon, cifs_sb, tree, islink, tl);
535-
if (!rc || rc != -EREMOTE)
536-
break;
537-
} while (rc = -ELOOP, ++num_links < MAX_NESTED_LINKS);
538-
/*
539-
* If we couldn't tree connect to any targets from last referral path, then
540-
* retry it from newly resolved dfs referral.
541-
*/
542-
if (rc && server->leaf_fullpath != old_fullpath)
543-
cifs_signal_cifsd_for_reconnect(server, true);
544-
545394
dfs_cache_free_tgts(tl);
546395
return rc;
547396
}
@@ -597,14 +446,11 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon)
597446
if (!IS_ERR(sb))
598447
cifs_sb = CIFS_SB(sb);
599448

600-
/*
601-
* Tree connect to last share in @tcon->tree_name whether dfs super or
602-
* cached dfs referral was not found.
603-
*/
604-
if (!cifs_sb || !server->leaf_fullpath ||
449+
/* Tree connect to last share in @tcon->tree_name if no DFS referral */
450+
if (!server->leaf_fullpath ||
605451
dfs_cache_noreq_find(server->leaf_fullpath + 1, &ref, &tl)) {
606-
rc = ops->tree_connect(xid, tcon->ses, tcon->tree_name, tcon,
607-
cifs_sb ? cifs_sb->local_nls : nlsc);
452+
rc = ops->tree_connect(xid, tcon->ses, tcon->tree_name,
453+
tcon, tcon->ses->local_nls);
608454
goto out;
609455
}
610456

0 commit comments

Comments
 (0)