summaryrefslogtreecommitdiffstats
path: root/fs/cifs/connect.c
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2020-07-21 09:36:38 -0300
committerSteve French <stfrench@microsoft.com>2020-08-02 18:00:26 -0500
commit565674d613d7f45d87284ba9f0be730ce4b335d0 (patch)
tree35564083783eecacb652f014f2971215a36c5a8b /fs/cifs/connect.c
parent1a0e7f7c3c573a79bcd787d8a05e80651041b815 (diff)
cifs: merge __{cifs,smb2}_reconnect[_tcon]() into cifs_tree_connect()
They were identical execpt to CIFSTCon() vs. SMB2_tcon(). These are also available via ops->tree_connect(). Signed-off-by: Stefan Metzmacher <metze@samba.org> Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz> Reviewed-by: Aurelien Aptel <aaptel@suse.com> Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r--fs/cifs/connect.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index fe4b55977dd8..727d676c7fb9 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -5532,3 +5532,103 @@ cifs_prune_tlinks(struct work_struct *work)
queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
TLINK_IDLE_EXPIRE);
}
+
+#ifdef CONFIG_CIFS_DFS_UPCALL
+int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const struct nls_table *nlsc)
+{
+ int rc;
+ struct TCP_Server_Info *server = tcon->ses->server;
+ const struct smb_version_operations *ops = server->ops;
+ struct dfs_cache_tgt_list tl;
+ struct dfs_cache_tgt_iterator *it = NULL;
+ char *tree;
+ const char *tcp_host;
+ size_t tcp_host_len;
+ const char *dfs_host;
+ size_t dfs_host_len;
+
+ tree = kzalloc(MAX_TREE_SIZE, GFP_KERNEL);
+ if (!tree)
+ return -ENOMEM;
+
+ if (!tcon->dfs_path) {
+ if (tcon->ipc) {
+ scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname);
+ rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
+ } else {
+ rc = ops->tree_connect(xid, tcon->ses, tcon->treeName, tcon, nlsc);
+ }
+ goto out;
+ }
+
+ rc = dfs_cache_noreq_find(tcon->dfs_path + 1, NULL, &tl);
+ if (rc)
+ goto out;
+
+ extract_unc_hostname(server->hostname, &tcp_host, &tcp_host_len);
+
+ for (it = dfs_cache_get_tgt_iterator(&tl); it; it = dfs_cache_get_next_tgt(&tl, it)) {
+ const char *share, *prefix;
+ size_t share_len, prefix_len;
+ bool target_match;
+
+ rc = dfs_cache_get_tgt_share(it, &share, &share_len, &prefix, &prefix_len);
+ if (rc) {
+ cifs_dbg(VFS, "%s: failed to parse target share %d\n",
+ __func__, rc);
+ continue;
+ }
+
+ extract_unc_hostname(share, &dfs_host, &dfs_host_len);
+
+ if (dfs_host_len != tcp_host_len
+ || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
+ cifs_dbg(FYI, "%s: %.*s doesn't match %.*s\n", __func__, (int)dfs_host_len,
+ dfs_host, (int)tcp_host_len, tcp_host);
+
+ rc = match_target_ip(server, dfs_host, dfs_host_len, &target_match);
+ if (rc) {
+ cifs_dbg(VFS, "%s: failed to match target ip: %d\n", __func__, rc);
+ break;
+ }
+
+ if (!target_match) {
+ cifs_dbg(FYI, "%s: skipping target\n", __func__);
+ continue;
+ }
+ }
+
+ if (tcon->ipc) {
+ scnprintf(tree, MAX_TREE_SIZE, "\\\\%.*s\\IPC$", (int)share_len, share);
+ rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
+ } else {
+ scnprintf(tree, MAX_TREE_SIZE, "\\%.*s", (int)share_len, share);
+ rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
+ if (!rc) {
+ rc = update_super_prepath(tcon, prefix, prefix_len);
+ break;
+ }
+ }
+ if (rc == -EREMOTE)
+ break;
+ }
+
+ if (!rc) {
+ if (it)
+ rc = dfs_cache_noreq_update_tgthint(tcon->dfs_path + 1, it);
+ else
+ rc = -ENOENT;
+ }
+ dfs_cache_free_tgts(&tl);
+out:
+ kfree(tree);
+ return rc;
+}
+#else
+int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const struct nls_table *nlsc)
+{
+ const struct smb_version_operations *ops = tcon->ses->server->ops;
+
+ return ops->tree_connect(xid, tcon->ses, tcon->treeName, tcon, nlsc);
+}
+#endif