Commit | Line | Data |
---|---|---|
929be906 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
1da177e4 | 2 | /* |
1da177e4 | 3 | * |
1080ef75 | 4 | * Copyright (C) International Business Machines Corp., 2002,2011 |
1da177e4 LT |
5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | * | |
1da177e4 LT |
7 | */ |
8 | #include <linux/fs.h> | |
9 | #include <linux/net.h> | |
10 | #include <linux/string.h> | |
dc920277 | 11 | #include <linux/sched/mm.h> |
3f07c014 | 12 | #include <linux/sched/signal.h> |
1da177e4 LT |
13 | #include <linux/list.h> |
14 | #include <linux/wait.h> | |
5a0e3ad6 | 15 | #include <linux/slab.h> |
1da177e4 LT |
16 | #include <linux/pagemap.h> |
17 | #include <linux/ctype.h> | |
18 | #include <linux/utsname.h> | |
19 | #include <linux/mempool.h> | |
b8643e1b | 20 | #include <linux/delay.h> |
f191401f | 21 | #include <linux/completion.h> |
aaf737ad | 22 | #include <linux/kthread.h> |
0ae0efad | 23 | #include <linux/pagevec.h> |
7dfb7103 | 24 | #include <linux/freezer.h> |
5c2503a8 | 25 | #include <linux/namei.h> |
c6e970a0 | 26 | #include <linux/uuid.h> |
7c0f6ba6 | 27 | #include <linux/uaccess.h> |
1da177e4 | 28 | #include <asm/processor.h> |
50b64e3b | 29 | #include <linux/inet.h> |
143cb494 | 30 | #include <linux/module.h> |
8a8798a5 | 31 | #include <keys/user-type.h> |
0e2bedaa | 32 | #include <net/ipv6.h> |
8830d7e0 | 33 | #include <linux/parser.h> |
2f8b5444 | 34 | #include <linux/bvec.h> |
1da177e4 LT |
35 | #include "cifspdu.h" |
36 | #include "cifsglob.h" | |
37 | #include "cifsproto.h" | |
38 | #include "cifs_unicode.h" | |
39 | #include "cifs_debug.h" | |
40 | #include "cifs_fs_sb.h" | |
41 | #include "ntlmssp.h" | |
42 | #include "nterr.h" | |
43 | #include "rfc1002pdu.h" | |
488f1d2d | 44 | #include "fscache.h" |
53e0e11e | 45 | #include "smb2proto.h" |
2f894646 | 46 | #include "smbdirect.h" |
1c780228 PA |
47 | #include "dns_resolve.h" |
48 | #ifdef CONFIG_CIFS_DFS_UPCALL | |
abdb1742 | 49 | #include "dfs.h" |
1c780228 PA |
50 | #include "dfs_cache.h" |
51 | #endif | |
5c6e5aa4 | 52 | #include "fs_context.h" |
bf80e5d4 | 53 | #include "cifs_swn.h" |
1da177e4 | 54 | |
1da177e4 | 55 | extern mempool_t *cifs_req_poolp; |
f92a720e | 56 | extern bool disable_legacy_dialects; |
1da177e4 | 57 | |
2de970ff | 58 | /* FIXME: should these be tunable? */ |
9d002df4 | 59 | #define TLINK_ERROR_EXPIRE (1 * HZ) |
2de970ff | 60 | #define TLINK_IDLE_EXPIRE (600 * HZ) |
9d002df4 | 61 | |
8e670f77 | 62 | /* Drop the connection to not overload the server */ |
69cba9d3 | 63 | #define MAX_STATUS_IO_TIMEOUT 5 |
8e670f77 | 64 | |
a9f1b85e PS |
65 | static int ip_connect(struct TCP_Server_Info *server); |
66 | static int generic_ip_connect(struct TCP_Server_Info *server); | |
b647c35f | 67 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); |
2de970ff | 68 | static void cifs_prune_tlinks(struct work_struct *work); |
93d5cb51 | 69 | |
28eb24ff PA |
70 | /* |
71 | * Resolve hostname and set ip addr in tcp ses. Useful for hostnames that may | |
72 | * get their ip addresses changed at some point. | |
73 | * | |
74 | * This should be called with server->srv_mutex held. | |
75 | */ | |
7d6535b7 | 76 | static int reconn_set_ipaddr_from_hostname(struct TCP_Server_Info *server) |
28eb24ff PA |
77 | { |
78 | int rc; | |
79 | int len; | |
6d740164 PA |
80 | char *unc; |
81 | struct sockaddr_storage ss; | |
28eb24ff PA |
82 | |
83 | if (!server->hostname) | |
84 | return -EINVAL; | |
85 | ||
4c14d704 SP |
86 | /* if server hostname isn't populated, there's nothing to do here */ |
87 | if (server->hostname[0] == '\0') | |
88 | return 0; | |
89 | ||
28eb24ff PA |
90 | len = strlen(server->hostname) + 3; |
91 | ||
92 | unc = kmalloc(len, GFP_KERNEL); | |
93 | if (!unc) { | |
94 | cifs_dbg(FYI, "%s: failed to create UNC path\n", __func__); | |
95 | return -ENOMEM; | |
96 | } | |
74ea5f98 | 97 | scnprintf(unc, len, "\\\\%s", server->hostname); |
28eb24ff | 98 | |
6d740164 PA |
99 | spin_lock(&server->srv_lock); |
100 | ss = server->dstaddr; | |
101 | spin_unlock(&server->srv_lock); | |
102 | ||
0e9bd27b | 103 | rc = dns_resolve_server_name_to_ip(unc, (struct sockaddr *)&ss, NULL); |
28eb24ff PA |
104 | kfree(unc); |
105 | ||
106 | if (rc < 0) { | |
107 | cifs_dbg(FYI, "%s: failed to resolve server part of %s to IP: %d\n", | |
108 | __func__, server->hostname, rc); | |
0e9bd27b PA |
109 | } else { |
110 | spin_lock(&server->srv_lock); | |
111 | memcpy(&server->dstaddr, &ss, sizeof(server->dstaddr)); | |
112 | spin_unlock(&server->srv_lock); | |
113 | rc = 0; | |
28eb24ff PA |
114 | } |
115 | ||
506c1da4 SP |
116 | return rc; |
117 | } | |
118 | ||
6e1c1c08 SP |
119 | static void smb2_query_server_interfaces(struct work_struct *work) |
120 | { | |
121 | int rc; | |
122 | struct cifs_tcon *tcon = container_of(work, | |
123 | struct cifs_tcon, | |
124 | query_interfaces.work); | |
125 | ||
126 | /* | |
127 | * query server network interfaces, in case they change | |
128 | */ | |
4659f01e | 129 | rc = SMB3_request_interfaces(0, tcon, false); |
6e1c1c08 SP |
130 | if (rc) { |
131 | cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n", | |
132 | __func__, rc); | |
133 | } | |
134 | ||
135 | queue_delayed_work(cifsiod_wq, &tcon->query_interfaces, | |
136 | (SMB_INTERFACE_POLL_INTERVAL * HZ)); | |
137 | } | |
506c1da4 | 138 | |
dca65818 SP |
139 | /* |
140 | * Update the tcpStatus for the server. | |
141 | * This is used to signal the cifsd thread to call cifs_reconnect | |
142 | * ONLY cifsd thread should call cifs_reconnect. For any other | |
143 | * thread, use this function | |
144 | * | |
145 | * @server: the tcp ses for which reconnect is needed | |
146 | * @all_channels: if this needs to be done for all channels | |
147 | */ | |
148 | void | |
149 | cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server, | |
150 | bool all_channels) | |
151 | { | |
152 | struct TCP_Server_Info *pserver; | |
153 | struct cifs_ses *ses; | |
154 | int i; | |
155 | ||
156 | /* If server is a channel, select the primary channel */ | |
b3773b19 | 157 | pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; |
dca65818 | 158 | |
d7d7a66a | 159 | spin_lock(&pserver->srv_lock); |
dca65818 SP |
160 | if (!all_channels) { |
161 | pserver->tcpStatus = CifsNeedReconnect; | |
d7d7a66a | 162 | spin_unlock(&pserver->srv_lock); |
dca65818 SP |
163 | return; |
164 | } | |
d7d7a66a | 165 | spin_unlock(&pserver->srv_lock); |
dca65818 | 166 | |
d7d7a66a | 167 | spin_lock(&cifs_tcp_ses_lock); |
dca65818 SP |
168 | list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { |
169 | spin_lock(&ses->chan_lock); | |
d7d7a66a SP |
170 | for (i = 0; i < ses->chan_count; i++) { |
171 | spin_lock(&ses->chans[i].server->srv_lock); | |
dca65818 | 172 | ses->chans[i].server->tcpStatus = CifsNeedReconnect; |
d7d7a66a SP |
173 | spin_unlock(&ses->chans[i].server->srv_lock); |
174 | } | |
dca65818 SP |
175 | spin_unlock(&ses->chan_lock); |
176 | } | |
177 | spin_unlock(&cifs_tcp_ses_lock); | |
178 | } | |
179 | ||
483529f3 | 180 | /* |
43b459aa | 181 | * Mark all sessions and tcons for reconnect. |
dca65818 SP |
182 | * IMPORTANT: make sure that this gets called only from |
183 | * cifsd thread. For any other thread, use | |
184 | * cifs_signal_cifsd_for_reconnect | |
d5c5605c | 185 | * |
dca65818 | 186 | * @server: the tcp ses for which reconnect is needed |
43b459aa | 187 | * @server needs to be previously set to CifsNeedReconnect. |
dca65818 | 188 | * @mark_smb_session: whether even sessions need to be marked |
d5c5605c | 189 | */ |
ba978e83 | 190 | void |
183eea2e SP |
191 | cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server, |
192 | bool mark_smb_session) | |
1da177e4 | 193 | { |
bda487ac | 194 | struct TCP_Server_Info *pserver; |
8da33fd1 | 195 | struct cifs_ses *ses, *nses; |
96daf2b0 | 196 | struct cifs_tcon *tcon; |
1da177e4 | 197 | |
43b459aa PA |
198 | /* |
199 | * before reconnecting the tcp session, mark the smb session (uid) and the tid bad so they | |
200 | * are not used until reconnected. | |
201 | */ | |
a05885ce | 202 | cifs_dbg(FYI, "%s: marking necessary sessions and tcons for reconnect\n", __func__); |
0f2b305a SP |
203 | |
204 | /* If server is a channel, select the primary channel */ | |
b3773b19 | 205 | pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; |
0f2b305a | 206 | |
a05885ce | 207 | |
3f9bcca7 | 208 | spin_lock(&cifs_tcp_ses_lock); |
8da33fd1 | 209 | list_for_each_entry_safe(ses, nses, &pserver->smb_ses_list, smb_ses_list) { |
b54034a7 | 210 | /* check if iface is still active */ |
d7d7a66a | 211 | if (!cifs_chan_is_iface_active(ses, server)) |
b54034a7 SP |
212 | cifs_chan_update_iface(ses, server); |
213 | ||
d1a931ce | 214 | spin_lock(&ses->chan_lock); |
bc962159 SP |
215 | if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server)) { |
216 | spin_unlock(&ses->chan_lock); | |
217 | continue; | |
218 | } | |
d1a931ce | 219 | |
ba978e83 SP |
220 | if (mark_smb_session) |
221 | CIFS_SET_ALL_CHANS_NEED_RECONNECT(ses); | |
222 | else | |
223 | cifs_chan_set_need_reconnect(ses, server); | |
d1a931ce | 224 | |
bc962159 SP |
225 | cifs_dbg(FYI, "%s: channel connect bitmap: 0x%lx\n", |
226 | __func__, ses->chans_need_reconnect); | |
227 | ||
d1a931ce | 228 | /* If all channels need reconnect, then tcon needs reconnect */ |
bc962159 SP |
229 | if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT(ses)) { |
230 | spin_unlock(&ses->chan_lock); | |
231 | continue; | |
232 | } | |
233 | spin_unlock(&ses->chan_lock); | |
d1a931ce | 234 | |
bc962159 | 235 | spin_lock(&ses->ses_lock); |
dd3cd870 | 236 | ses->ses_status = SES_NEED_RECON; |
bc962159 | 237 | spin_unlock(&ses->ses_lock); |
f486ef8e | 238 | |
73f9bfbe | 239 | list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { |
3b795210 | 240 | tcon->need_reconnect = true; |
bc962159 | 241 | spin_lock(&tcon->tc_lock); |
fdf59eb5 | 242 | tcon->status = TID_NEED_RECON; |
bc962159 | 243 | spin_unlock(&tcon->tc_lock); |
73f9bfbe | 244 | } |
25cf01b7 | 245 | if (ses->tcon_ipc) { |
b327a717 | 246 | ses->tcon_ipc->need_reconnect = true; |
bc962159 | 247 | spin_lock(&ses->tcon_ipc->tc_lock); |
25cf01b7 | 248 | ses->tcon_ipc->status = TID_NEED_RECON; |
bc962159 | 249 | spin_unlock(&ses->tcon_ipc->tc_lock); |
25cf01b7 | 250 | } |
1da177e4 | 251 | } |
3f9bcca7 | 252 | spin_unlock(&cifs_tcp_ses_lock); |
2a05137a SP |
253 | } |
254 | ||
255 | static void | |
256 | cifs_abort_connection(struct TCP_Server_Info *server) | |
257 | { | |
258 | struct mid_q_entry *mid, *nmid; | |
259 | struct list_head retry_list; | |
260 | ||
261 | server->maxBuf = 0; | |
262 | server->max_read = 0; | |
2b84a36c | 263 | |
1da177e4 | 264 | /* do not want to be sending data on a socket we are freeing */ |
a05885ce | 265 | cifs_dbg(FYI, "%s: tearing down socket\n", __func__); |
cc391b69 | 266 | cifs_server_lock(server); |
1d2a4f57 | 267 | if (server->ssocket) { |
43b459aa PA |
268 | cifs_dbg(FYI, "State: 0x%x Flags: 0x%lx\n", server->ssocket->state, |
269 | server->ssocket->flags); | |
1d2a4f57 | 270 | kernel_sock_shutdown(server->ssocket, SHUT_WR); |
43b459aa PA |
271 | cifs_dbg(FYI, "Post shutdown state: 0x%x Flags: 0x%lx\n", server->ssocket->state, |
272 | server->ssocket->flags); | |
1d2a4f57 LL |
273 | sock_release(server->ssocket); |
274 | server->ssocket = NULL; | |
275 | } | |
276 | server->sequence_number = 0; | |
277 | server->session_estab = false; | |
a4e430c8 | 278 | kfree_sensitive(server->session_key.response); |
1d2a4f57 LL |
279 | server->session_key.response = NULL; |
280 | server->session_key.len = 0; | |
281 | server->lstrp = jiffies; | |
1da177e4 | 282 | |
2b84a36c | 283 | /* mark submitted MIDs for retry and issue callback */ |
3c1105df | 284 | INIT_LIST_HEAD(&retry_list); |
f96637be | 285 | cifs_dbg(FYI, "%s: moving mids to private list\n", __func__); |
d7d7a66a | 286 | spin_lock(&server->mid_lock); |
ae0abb4d PA |
287 | list_for_each_entry_safe(mid, nmid, &server->pending_mid_q, qhead) { |
288 | kref_get(&mid->refcount); | |
289 | if (mid->mid_state == MID_REQUEST_SUBMITTED) | |
290 | mid->mid_state = MID_RETRY_NEEDED; | |
291 | list_move(&mid->qhead, &retry_list); | |
292 | mid->mid_flags |= MID_DELETED; | |
3c1105df | 293 | } |
d7d7a66a | 294 | spin_unlock(&server->mid_lock); |
cc391b69 | 295 | cifs_server_unlock(server); |
3c1105df | 296 | |
f96637be | 297 | cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__); |
ae0abb4d PA |
298 | list_for_each_entry_safe(mid, nmid, &retry_list, qhead) { |
299 | list_del_init(&mid->qhead); | |
300 | mid->callback(mid); | |
70f08f91 | 301 | release_mid(mid); |
1da177e4 | 302 | } |
1da177e4 | 303 | |
1d2a4f57 | 304 | if (cifs_rdma_enabled(server)) { |
cc391b69 | 305 | cifs_server_lock(server); |
214bab44 | 306 | smbd_destroy(server); |
cc391b69 | 307 | cifs_server_unlock(server); |
1d2a4f57 | 308 | } |
43b459aa PA |
309 | } |
310 | ||
bbcce368 PA |
311 | static bool cifs_tcp_ses_needs_reconnect(struct TCP_Server_Info *server, int num_targets) |
312 | { | |
d7d7a66a | 313 | spin_lock(&server->srv_lock); |
bbcce368 PA |
314 | server->nr_targets = num_targets; |
315 | if (server->tcpStatus == CifsExiting) { | |
316 | /* the demux thread will exit normally next time through the loop */ | |
d7d7a66a | 317 | spin_unlock(&server->srv_lock); |
bbcce368 PA |
318 | wake_up(&server->response_q); |
319 | return false; | |
320 | } | |
a05885ce SP |
321 | |
322 | cifs_dbg(FYI, "Mark tcp session as need reconnect\n"); | |
323 | trace_smb3_reconnect(server->CurrentMid, server->conn_id, | |
324 | server->hostname); | |
bbcce368 | 325 | server->tcpStatus = CifsNeedReconnect; |
a05885ce | 326 | |
d7d7a66a | 327 | spin_unlock(&server->srv_lock); |
bbcce368 PA |
328 | return true; |
329 | } | |
330 | ||
43b459aa PA |
331 | /* |
332 | * cifs tcp session reconnection | |
333 | * | |
334 | * mark tcp session as reconnecting so temporarily locked | |
335 | * mark all smb sessions as reconnecting for tcp session | |
336 | * reconnect tcp session | |
337 | * wake up waiters on reconnection? - (not needed currently) | |
183eea2e SP |
338 | * |
339 | * if mark_smb_session is passed as true, unconditionally mark | |
340 | * the smb session (and tcon) for reconnect as well. This value | |
341 | * doesn't really matter for non-multichannel scenario. | |
342 | * | |
43b459aa | 343 | */ |
183eea2e SP |
344 | static int __cifs_reconnect(struct TCP_Server_Info *server, |
345 | bool mark_smb_session) | |
43b459aa PA |
346 | { |
347 | int rc = 0; | |
43b459aa | 348 | |
bbcce368 PA |
349 | if (!cifs_tcp_ses_needs_reconnect(server, 1)) |
350 | return 0; | |
43b459aa | 351 | |
183eea2e | 352 | cifs_mark_tcp_ses_conns_for_reconnect(server, mark_smb_session); |
214bab44 | 353 | |
2a05137a SP |
354 | cifs_abort_connection(server); |
355 | ||
7fdbaa1b | 356 | do { |
6c3d8909 | 357 | try_to_freeze(); |
cc391b69 | 358 | cifs_server_lock(server); |
121d947d | 359 | |
b7fd0fa0 | 360 | if (!cifs_swn_set_server_dstaddr(server)) { |
bbcce368 | 361 | /* resolve the hostname again to make sure that IP address is up-to-date */ |
4e456b30 | 362 | rc = reconn_set_ipaddr_from_hostname(server); |
bbcce368 | 363 | cifs_dbg(FYI, "%s: reconn_set_ipaddr_from_hostname: rc=%d\n", __func__, rc); |
121d947d | 364 | } |
aaa3aef3 | 365 | |
781a8050 LL |
366 | if (cifs_rdma_enabled(server)) |
367 | rc = smbd_reconnect(server); | |
368 | else | |
369 | rc = generic_ip_connect(server); | |
fb8c4b14 | 370 | if (rc) { |
cc391b69 | 371 | cifs_server_unlock(server); |
bbcce368 | 372 | cifs_dbg(FYI, "%s: reconnect error %d\n", __func__, rc); |
0cb766ae | 373 | msleep(3000); |
1da177e4 LT |
374 | } else { |
375 | atomic_inc(&tcpSesReconnectCount); | |
335b7b62 | 376 | set_credits(server, 1); |
d7d7a66a | 377 | spin_lock(&server->srv_lock); |
469ee614 | 378 | if (server->tcpStatus != CifsExiting) |
fd88ce93 | 379 | server->tcpStatus = CifsNeedNegotiate; |
d7d7a66a | 380 | spin_unlock(&server->srv_lock); |
b7fd0fa0 | 381 | cifs_swn_reset_server_dstaddr(server); |
cc391b69 | 382 | cifs_server_unlock(server); |
3663c904 | 383 | mod_delayed_work(cifsiod_wq, &server->reconnect, 0); |
1da177e4 | 384 | } |
7fdbaa1b | 385 | } while (server->tcpStatus == CifsNeedReconnect); |
2b84a36c | 386 | |
d7d7a66a | 387 | spin_lock(&server->srv_lock); |
bbcce368 PA |
388 | if (server->tcpStatus == CifsNeedNegotiate) |
389 | mod_delayed_work(cifsiod_wq, &server->echo, 0); | |
d7d7a66a | 390 | spin_unlock(&server->srv_lock); |
bbcce368 PA |
391 | |
392 | wake_up(&server->response_q); | |
393 | return rc; | |
394 | } | |
395 | ||
93d5cb51 | 396 | #ifdef CONFIG_CIFS_DFS_UPCALL |
c88f7dcd PA |
397 | static int __reconnect_target_unlocked(struct TCP_Server_Info *server, const char *target) |
398 | { | |
399 | int rc; | |
400 | char *hostname; | |
401 | ||
402 | if (!cifs_swn_set_server_dstaddr(server)) { | |
403 | if (server->hostname != target) { | |
404 | hostname = extract_hostname(target); | |
405 | if (!IS_ERR(hostname)) { | |
90c49fce | 406 | spin_lock(&server->srv_lock); |
c88f7dcd PA |
407 | kfree(server->hostname); |
408 | server->hostname = hostname; | |
90c49fce | 409 | spin_unlock(&server->srv_lock); |
c88f7dcd PA |
410 | } else { |
411 | cifs_dbg(FYI, "%s: couldn't extract hostname or address from dfs target: %ld\n", | |
412 | __func__, PTR_ERR(hostname)); | |
413 | cifs_dbg(FYI, "%s: default to last target server: %s\n", __func__, | |
414 | server->hostname); | |
415 | } | |
416 | } | |
417 | /* resolve the hostname again to make sure that IP address is up-to-date. */ | |
418 | rc = reconn_set_ipaddr_from_hostname(server); | |
419 | cifs_dbg(FYI, "%s: reconn_set_ipaddr_from_hostname: rc=%d\n", __func__, rc); | |
420 | } | |
421 | /* Reconnect the socket */ | |
422 | if (cifs_rdma_enabled(server)) | |
423 | rc = smbd_reconnect(server); | |
424 | else | |
425 | rc = generic_ip_connect(server); | |
426 | ||
427 | return rc; | |
428 | } | |
429 | ||
430 | static int reconnect_target_unlocked(struct TCP_Server_Info *server, struct dfs_cache_tgt_list *tl, | |
431 | struct dfs_cache_tgt_iterator **target_hint) | |
432 | { | |
433 | int rc; | |
434 | struct dfs_cache_tgt_iterator *tit; | |
435 | ||
436 | *target_hint = NULL; | |
437 | ||
438 | /* If dfs target list is empty, then reconnect to last server */ | |
439 | tit = dfs_cache_get_tgt_iterator(tl); | |
440 | if (!tit) | |
441 | return __reconnect_target_unlocked(server, server->hostname); | |
442 | ||
443 | /* Otherwise, try every dfs target in @tl */ | |
444 | for (; tit; tit = dfs_cache_get_next_tgt(tl, tit)) { | |
445 | rc = __reconnect_target_unlocked(server, dfs_cache_get_tgt_name(tit)); | |
446 | if (!rc) { | |
447 | *target_hint = tit; | |
448 | break; | |
449 | } | |
450 | } | |
451 | return rc; | |
452 | } | |
453 | ||
fb39d30e | 454 | static int reconnect_dfs_server(struct TCP_Server_Info *server) |
bbcce368 | 455 | { |
c88f7dcd | 456 | struct dfs_cache_tgt_iterator *target_hint = NULL; |
3fea12f3 | 457 | DFS_CACHE_TGT_LIST(tl); |
c88f7dcd | 458 | int num_targets = 0; |
3fea12f3 | 459 | int rc = 0; |
bbcce368 PA |
460 | |
461 | /* | |
462 | * Determine the number of dfs targets the referral path in @cifs_sb resolves to. | |
463 | * | |
464 | * smb2_reconnect() needs to know how long it should wait based upon the number of dfs | |
465 | * targets (server->nr_targets). It's also possible that the cached referral was cleared | |
466 | * through /proc/fs/cifs/dfscache or the target list is empty due to server settings after | |
467 | * refreshing the referral, so, in this case, default it to 1. | |
468 | */ | |
3dc9c433 PA |
469 | mutex_lock(&server->refpath_lock); |
470 | if (!dfs_cache_noreq_find(server->leaf_fullpath + 1, NULL, &tl)) | |
bbcce368 | 471 | num_targets = dfs_cache_get_nr_tgts(&tl); |
3dc9c433 | 472 | mutex_unlock(&server->refpath_lock); |
c88f7dcd PA |
473 | if (!num_targets) |
474 | num_targets = 1; | |
bbcce368 PA |
475 | |
476 | if (!cifs_tcp_ses_needs_reconnect(server, num_targets)) | |
477 | return 0; | |
478 | ||
fb39d30e PA |
479 | /* |
480 | * Unconditionally mark all sessions & tcons for reconnect as we might be connecting to a | |
481 | * different server or share during failover. It could be improved by adding some logic to | |
482 | * only do that in case it connects to a different server or share, though. | |
483 | */ | |
484 | cifs_mark_tcp_ses_conns_for_reconnect(server, true); | |
bbcce368 | 485 | |
2a05137a SP |
486 | cifs_abort_connection(server); |
487 | ||
bbcce368 | 488 | do { |
bbcce368 | 489 | try_to_freeze(); |
cc391b69 | 490 | cifs_server_lock(server); |
bbcce368 | 491 | |
c88f7dcd | 492 | rc = reconnect_target_unlocked(server, &tl, &target_hint); |
93d5cb51 | 493 | if (rc) { |
c88f7dcd | 494 | /* Failed to reconnect socket */ |
cc391b69 | 495 | cifs_server_unlock(server); |
bbcce368 PA |
496 | cifs_dbg(FYI, "%s: reconnect error %d\n", __func__, rc); |
497 | msleep(3000); | |
498 | continue; | |
93d5cb51 | 499 | } |
bbcce368 PA |
500 | /* |
501 | * Socket was created. Update tcp session status to CifsNeedNegotiate so that a | |
502 | * process waiting for reconnect will know it needs to re-establish session and tcon | |
503 | * through the reconnected target server. | |
504 | */ | |
505 | atomic_inc(&tcpSesReconnectCount); | |
506 | set_credits(server, 1); | |
d7d7a66a | 507 | spin_lock(&server->srv_lock); |
bbcce368 PA |
508 | if (server->tcpStatus != CifsExiting) |
509 | server->tcpStatus = CifsNeedNegotiate; | |
d7d7a66a | 510 | spin_unlock(&server->srv_lock); |
bbcce368 | 511 | cifs_swn_reset_server_dstaddr(server); |
cc391b69 | 512 | cifs_server_unlock(server); |
e154cb7b | 513 | mod_delayed_work(cifsiod_wq, &server->reconnect, 0); |
bbcce368 PA |
514 | } while (server->tcpStatus == CifsNeedReconnect); |
515 | ||
3dc9c433 PA |
516 | mutex_lock(&server->refpath_lock); |
517 | dfs_cache_noreq_update_tgthint(server->leaf_fullpath + 1, target_hint); | |
518 | mutex_unlock(&server->refpath_lock); | |
bbcce368 PA |
519 | dfs_cache_free_tgts(&tl); |
520 | ||
521 | /* Need to set up echo worker again once connection has been established */ | |
d7d7a66a | 522 | spin_lock(&server->srv_lock); |
b8c60012 SP |
523 | if (server->tcpStatus == CifsNeedNegotiate) |
524 | mod_delayed_work(cifsiod_wq, &server->echo, 0); | |
d7d7a66a | 525 | spin_unlock(&server->srv_lock); |
080dc5e5 | 526 | |
e2e87519 | 527 | wake_up(&server->response_q); |
1da177e4 LT |
528 | return rc; |
529 | } | |
530 | ||
183eea2e | 531 | int cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session) |
bbcce368 | 532 | { |
cd70a3e8 | 533 | mutex_lock(&server->refpath_lock); |
a1c0d005 | 534 | if (!server->leaf_fullpath) { |
cd70a3e8 PA |
535 | mutex_unlock(&server->refpath_lock); |
536 | return __cifs_reconnect(server, mark_smb_session); | |
537 | } | |
538 | mutex_unlock(&server->refpath_lock); | |
539 | ||
fb39d30e | 540 | return reconnect_dfs_server(server); |
bbcce368 PA |
541 | } |
542 | #else | |
183eea2e | 543 | int cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session) |
bbcce368 | 544 | { |
183eea2e | 545 | return __cifs_reconnect(server, mark_smb_session); |
bbcce368 PA |
546 | } |
547 | #endif | |
548 | ||
c74093b6 JL |
549 | static void |
550 | cifs_echo_request(struct work_struct *work) | |
551 | { | |
552 | int rc; | |
553 | struct TCP_Server_Info *server = container_of(work, | |
554 | struct TCP_Server_Info, echo.work); | |
555 | ||
247ec9b4 | 556 | /* |
b8c60012 SP |
557 | * We cannot send an echo if it is disabled. |
558 | * Also, no need to ping if we got a response recently. | |
247ec9b4 | 559 | */ |
4fcd1813 SF |
560 | |
561 | if (server->tcpStatus == CifsNeedReconnect || | |
b8c60012 SP |
562 | server->tcpStatus == CifsExiting || |
563 | server->tcpStatus == CifsNew || | |
f6d76178 | 564 | (server->ops->can_echo && !server->ops->can_echo(server)) || |
5b2abdaf | 565 | time_before(jiffies, server->lstrp + server->echo_interval - HZ)) |
c74093b6 JL |
566 | goto requeue_echo; |
567 | ||
f6d76178 | 568 | rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS; |
90c49fce | 569 | cifs_server_dbg(FYI, "send echo request: rc = %d\n", rc); |
c74093b6 | 570 | |
21077c62 SC |
571 | /* Check witness registrations */ |
572 | cifs_swn_check(); | |
21077c62 | 573 | |
c74093b6 | 574 | requeue_echo: |
b8c60012 | 575 | queue_delayed_work(cifsiod_wq, &server->echo, server->echo_interval); |
c74093b6 JL |
576 | } |
577 | ||
3d9c2472 | 578 | static bool |
2a37ef94 | 579 | allocate_buffers(struct TCP_Server_Info *server) |
3d9c2472 | 580 | { |
2a37ef94 JL |
581 | if (!server->bigbuf) { |
582 | server->bigbuf = (char *)cifs_buf_get(); | |
583 | if (!server->bigbuf) { | |
afe6f653 | 584 | cifs_server_dbg(VFS, "No memory for large SMB response\n"); |
3d9c2472 PS |
585 | msleep(3000); |
586 | /* retry will check if exiting */ | |
587 | return false; | |
588 | } | |
2a37ef94 | 589 | } else if (server->large_buf) { |
3d9c2472 | 590 | /* we are reusing a dirty large buf, clear its start */ |
1887f601 | 591 | memset(server->bigbuf, 0, HEADER_SIZE(server)); |
3d9c2472 PS |
592 | } |
593 | ||
2a37ef94 JL |
594 | if (!server->smallbuf) { |
595 | server->smallbuf = (char *)cifs_small_buf_get(); | |
596 | if (!server->smallbuf) { | |
afe6f653 | 597 | cifs_server_dbg(VFS, "No memory for SMB response\n"); |
3d9c2472 PS |
598 | msleep(1000); |
599 | /* retry will check if exiting */ | |
600 | return false; | |
601 | } | |
602 | /* beginning of smb buffer is cleared in our buf_get */ | |
603 | } else { | |
604 | /* if existing small buf clear beginning */ | |
1887f601 | 605 | memset(server->smallbuf, 0, HEADER_SIZE(server)); |
3d9c2472 PS |
606 | } |
607 | ||
3d9c2472 PS |
608 | return true; |
609 | } | |
610 | ||
ba749e6d JL |
611 | static bool |
612 | server_unresponsive(struct TCP_Server_Info *server) | |
613 | { | |
6dae51a5 | 614 | /* |
f2caf901 | 615 | * We need to wait 3 echo intervals to make sure we handle such |
6dae51a5 PS |
616 | * situations right: |
617 | * 1s client sends a normal SMB request | |
becc2ba2 | 618 | * 2s client gets a response |
6dae51a5 PS |
619 | * 30s echo workqueue job pops, and decides we got a response recently |
620 | * and don't need to send another | |
621 | * ... | |
622 | * 65s kernel_recvmsg times out, and we see that we haven't gotten | |
623 | * a response in >60s. | |
624 | */ | |
d7d7a66a | 625 | spin_lock(&server->srv_lock); |
76e75270 SC |
626 | if ((server->tcpStatus == CifsGood || |
627 | server->tcpStatus == CifsNeedNegotiate) && | |
f4916649 | 628 | (!server->ops->can_echo || server->ops->can_echo(server)) && |
f2caf901 | 629 | time_after(jiffies, server->lstrp + 3 * server->echo_interval)) { |
d7d7a66a | 630 | spin_unlock(&server->srv_lock); |
afe6f653 RS |
631 | cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n", |
632 | (3 * server->echo_interval) / HZ); | |
183eea2e | 633 | cifs_reconnect(server, false); |
ba749e6d JL |
634 | return true; |
635 | } | |
d7d7a66a | 636 | spin_unlock(&server->srv_lock); |
ba749e6d JL |
637 | |
638 | return false; | |
639 | } | |
640 | ||
ef68e831 PS |
641 | static inline bool |
642 | zero_credits(struct TCP_Server_Info *server) | |
643 | { | |
644 | int val; | |
645 | ||
646 | spin_lock(&server->req_lock); | |
647 | val = server->credits + server->echo_credits + server->oplock_credits; | |
648 | if (server->in_flight == 0 && val == 0) { | |
649 | spin_unlock(&server->req_lock); | |
650 | return true; | |
651 | } | |
652 | spin_unlock(&server->req_lock); | |
653 | return false; | |
654 | } | |
655 | ||
71335664 AV |
656 | static int |
657 | cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg) | |
e7015fb1 | 658 | { |
a52c1eb7 JL |
659 | int length = 0; |
660 | int total_read; | |
e7015fb1 | 661 | |
71335664 | 662 | for (total_read = 0; msg_data_left(smb_msg); total_read += length) { |
95edcff4 JL |
663 | try_to_freeze(); |
664 | ||
ef68e831 PS |
665 | /* reconnect if no credits and no requests in flight */ |
666 | if (zero_credits(server)) { | |
183eea2e | 667 | cifs_reconnect(server, false); |
ef68e831 PS |
668 | return -ECONNABORTED; |
669 | } | |
670 | ||
71335664 AV |
671 | if (server_unresponsive(server)) |
672 | return -ECONNABORTED; | |
2fef137a LL |
673 | if (cifs_rdma_enabled(server) && server->smbd_conn) |
674 | length = smbd_recv(server->smbd_conn, smb_msg); | |
675 | else | |
676 | length = sock_recvmsg(server->ssocket, smb_msg, 0); | |
42c4dfc2 | 677 | |
d7d7a66a | 678 | spin_lock(&server->srv_lock); |
080dc5e5 | 679 | if (server->tcpStatus == CifsExiting) { |
d7d7a66a | 680 | spin_unlock(&server->srv_lock); |
71335664 | 681 | return -ESHUTDOWN; |
080dc5e5 | 682 | } |
e7015fb1 | 683 | |
71335664 | 684 | if (server->tcpStatus == CifsNeedReconnect) { |
d7d7a66a | 685 | spin_unlock(&server->srv_lock); |
a81da65f | 686 | cifs_reconnect(server, false); |
71335664 AV |
687 | return -ECONNABORTED; |
688 | } | |
d7d7a66a | 689 | spin_unlock(&server->srv_lock); |
71335664 AV |
690 | |
691 | if (length == -ERESTARTSYS || | |
692 | length == -EAGAIN || | |
693 | length == -EINTR) { | |
e7015fb1 PS |
694 | /* |
695 | * Minimum sleep to prevent looping, allowing socket | |
696 | * to clear and app threads to set tcpStatus | |
697 | * CifsNeedReconnect if server hung. | |
698 | */ | |
699 | usleep_range(1000, 2000); | |
700 | length = 0; | |
a52c1eb7 | 701 | continue; |
71335664 AV |
702 | } |
703 | ||
704 | if (length <= 0) { | |
09aab880 | 705 | cifs_dbg(FYI, "Received no data or error: %d\n", length); |
183eea2e | 706 | cifs_reconnect(server, false); |
71335664 | 707 | return -ECONNABORTED; |
e7015fb1 PS |
708 | } |
709 | } | |
a52c1eb7 | 710 | return total_read; |
e7015fb1 | 711 | } |
e7015fb1 | 712 | |
e28bc5b1 JL |
713 | int |
714 | cifs_read_from_socket(struct TCP_Server_Info *server, char *buf, | |
715 | unsigned int to_read) | |
42c4dfc2 | 716 | { |
bedc8f76 | 717 | struct msghdr smb_msg = {}; |
71335664 | 718 | struct kvec iov = {.iov_base = buf, .iov_len = to_read}; |
de4eda9d | 719 | iov_iter_kvec(&smb_msg.msg_iter, ITER_DEST, &iov, 1, to_read); |
42c4dfc2 | 720 | |
71335664 AV |
721 | return cifs_readv_from_socket(server, &smb_msg); |
722 | } | |
42c4dfc2 | 723 | |
cf0604a6 DH |
724 | ssize_t |
725 | cifs_discard_from_socket(struct TCP_Server_Info *server, size_t to_read) | |
726 | { | |
bedc8f76 | 727 | struct msghdr smb_msg = {}; |
cf0604a6 DH |
728 | |
729 | /* | |
730 | * iov_iter_discard already sets smb_msg.type and count and iov_offset | |
731 | * and cifs_readv_from_socket sets msg_control and msg_controllen | |
732 | * so little to initialize in struct msghdr | |
733 | */ | |
de4eda9d | 734 | iov_iter_discard(&smb_msg.msg_iter, ITER_DEST, to_read); |
cf0604a6 DH |
735 | |
736 | return cifs_readv_from_socket(server, &smb_msg); | |
737 | } | |
738 | ||
71335664 AV |
739 | int |
740 | cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page, | |
1dbe3466 | 741 | unsigned int page_offset, unsigned int to_read) |
71335664 | 742 | { |
bedc8f76 | 743 | struct msghdr smb_msg = {}; |
220ae4a5 CH |
744 | struct bio_vec bv; |
745 | ||
746 | bvec_set_page(&bv, page, to_read, page_offset); | |
de4eda9d | 747 | iov_iter_bvec(&smb_msg.msg_iter, ITER_DEST, &bv, 1, to_read); |
71335664 | 748 | return cifs_readv_from_socket(server, &smb_msg); |
e7015fb1 PS |
749 | } |
750 | ||
16541195 DH |
751 | int |
752 | cifs_read_iter_from_socket(struct TCP_Server_Info *server, struct iov_iter *iter, | |
753 | unsigned int to_read) | |
754 | { | |
755 | struct msghdr smb_msg = { .msg_iter = *iter }; | |
756 | int ret; | |
757 | ||
758 | iov_iter_truncate(&smb_msg.msg_iter, to_read); | |
759 | ret = cifs_readv_from_socket(server, &smb_msg); | |
760 | if (ret > 0) | |
761 | iov_iter_advance(iter, ret); | |
762 | return ret; | |
763 | } | |
764 | ||
98bac62c | 765 | static bool |
fe11e4cc | 766 | is_smb_response(struct TCP_Server_Info *server, unsigned char type) |
98bac62c | 767 | { |
98bac62c PS |
768 | /* |
769 | * The first byte big endian of the length field, | |
770 | * is actually not part of the length but the type | |
771 | * with the most common, zero, as regular data. | |
772 | */ | |
fe11e4cc JL |
773 | switch (type) { |
774 | case RFC1002_SESSION_MESSAGE: | |
775 | /* Regular SMB response */ | |
776 | return true; | |
777 | case RFC1002_SESSION_KEEP_ALIVE: | |
f96637be | 778 | cifs_dbg(FYI, "RFC 1002 session keep alive\n"); |
fe11e4cc JL |
779 | break; |
780 | case RFC1002_POSITIVE_SESSION_RESPONSE: | |
f96637be | 781 | cifs_dbg(FYI, "RFC 1002 positive session response\n"); |
fe11e4cc JL |
782 | break; |
783 | case RFC1002_NEGATIVE_SESSION_RESPONSE: | |
98bac62c PS |
784 | /* |
785 | * We get this from Windows 98 instead of an error on | |
786 | * SMB negprot response. | |
787 | */ | |
f96637be | 788 | cifs_dbg(FYI, "RFC 1002 negative session response\n"); |
98bac62c PS |
789 | /* give server a second to clean up */ |
790 | msleep(1000); | |
791 | /* | |
792 | * Always try 445 first on reconnect since we get NACK | |
793 | * on some if we ever connected to port 139 (the NACK | |
794 | * is since we do not begin with RFC1001 session | |
795 | * initialize frame). | |
796 | */ | |
fe11e4cc | 797 | cifs_set_port((struct sockaddr *)&server->dstaddr, CIFS_PORT); |
183eea2e | 798 | cifs_reconnect(server, true); |
fe11e4cc JL |
799 | break; |
800 | default: | |
afe6f653 | 801 | cifs_server_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", type); |
183eea2e | 802 | cifs_reconnect(server, true); |
98bac62c PS |
803 | } |
804 | ||
fe11e4cc | 805 | return false; |
98bac62c PS |
806 | } |
807 | ||
e28bc5b1 JL |
808 | void |
809 | dequeue_mid(struct mid_q_entry *mid, bool malformed) | |
ea1f4502 | 810 | { |
ad69bae1 | 811 | #ifdef CONFIG_CIFS_STATS2 |
ea1f4502 | 812 | mid->when_received = jiffies; |
ad69bae1 | 813 | #endif |
d7d7a66a | 814 | spin_lock(&mid->server->mid_lock); |
ea1f4502 | 815 | if (!malformed) |
7c9421e1 | 816 | mid->mid_state = MID_RESPONSE_RECEIVED; |
ea1f4502 | 817 | else |
7c9421e1 | 818 | mid->mid_state = MID_RESPONSE_MALFORMED; |
ddf83afb RS |
819 | /* |
820 | * Trying to handle/dequeue a mid after the send_recv() | |
821 | * function has finished processing it is a bug. | |
822 | */ | |
9e7ffa77 | 823 | if (mid->mid_flags & MID_DELETED) { |
d7d7a66a | 824 | spin_unlock(&mid->server->mid_lock); |
a0a3036b | 825 | pr_warn_once("trying to dequeue a deleted mid\n"); |
9e7ffa77 | 826 | } else { |
ddf83afb | 827 | list_del_init(&mid->qhead); |
abe57073 | 828 | mid->mid_flags |= MID_DELETED; |
d7d7a66a | 829 | spin_unlock(&mid->server->mid_lock); |
abe57073 | 830 | } |
ea1f4502 | 831 | } |
ad69bae1 | 832 | |
86a7964b PS |
833 | static unsigned int |
834 | smb2_get_credits_from_hdr(char *buffer, struct TCP_Server_Info *server) | |
835 | { | |
0d35e382 | 836 | struct smb2_hdr *shdr = (struct smb2_hdr *)buffer; |
86a7964b PS |
837 | |
838 | /* | |
839 | * SMB1 does not use credits. | |
840 | */ | |
d291e703 | 841 | if (is_smb1(server)) |
86a7964b PS |
842 | return 0; |
843 | ||
844 | return le16_to_cpu(shdr->CreditRequest); | |
845 | } | |
846 | ||
c8054ebd JL |
847 | static void |
848 | handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server, | |
d4e4854f | 849 | char *buf, int malformed) |
ea1f4502 | 850 | { |
316cf94a PS |
851 | if (server->ops->check_trans2 && |
852 | server->ops->check_trans2(mid, server, buf, malformed)) | |
c8054ebd | 853 | return; |
86a7964b | 854 | mid->credits_received = smb2_get_credits_from_hdr(buf, server); |
ea1f4502 | 855 | mid->resp_buf = buf; |
7c9421e1 | 856 | mid->large_buf = server->large_buf; |
2a37ef94 JL |
857 | /* Was previous buf put in mpx struct for multi-rsp? */ |
858 | if (!mid->multiRsp) { | |
859 | /* smb buffer will be freed by user thread */ | |
860 | if (server->large_buf) | |
861 | server->bigbuf = NULL; | |
862 | else | |
863 | server->smallbuf = NULL; | |
864 | } | |
ffc00e27 | 865 | dequeue_mid(mid, malformed); |
ad69bae1 PS |
866 | } |
867 | ||
fb157ed2 SF |
868 | int |
869 | cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required) | |
870 | { | |
871 | bool srv_sign_required = server->sec_mode & server->vals->signing_required; | |
872 | bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled; | |
873 | bool mnt_sign_enabled; | |
874 | ||
875 | /* | |
876 | * Is signing required by mnt options? If not then check | |
877 | * global_secflags to see if it is there. | |
878 | */ | |
879 | if (!mnt_sign_required) | |
880 | mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) == | |
881 | CIFSSEC_MUST_SIGN); | |
882 | ||
883 | /* | |
884 | * If signing is required then it's automatically enabled too, | |
885 | * otherwise, check to see if the secflags allow it. | |
886 | */ | |
887 | mnt_sign_enabled = mnt_sign_required ? mnt_sign_required : | |
888 | (global_secflags & CIFSSEC_MAY_SIGN); | |
889 | ||
890 | /* If server requires signing, does client allow it? */ | |
891 | if (srv_sign_required) { | |
892 | if (!mnt_sign_enabled) { | |
893 | cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!\n"); | |
894 | return -EOPNOTSUPP; | |
895 | } | |
896 | server->sign = true; | |
897 | } | |
898 | ||
899 | /* If client requires signing, does server allow it? */ | |
900 | if (mnt_sign_required) { | |
901 | if (!srv_sign_enabled) { | |
902 | cifs_dbg(VFS, "Server does not support signing!\n"); | |
903 | return -EOPNOTSUPP; | |
904 | } | |
905 | server->sign = true; | |
906 | } | |
907 | ||
908 | if (cifs_rdma_enabled(server) && server->sign) | |
909 | cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled\n"); | |
910 | ||
911 | return 0; | |
912 | } | |
913 | ||
946ad1b8 PA |
914 | static noinline_for_stack void |
915 | clean_demultiplex_info(struct TCP_Server_Info *server) | |
762dfd10 PS |
916 | { |
917 | int length; | |
918 | ||
919 | /* take it off the list, if it's not already */ | |
d7d7a66a | 920 | spin_lock(&server->srv_lock); |
762dfd10 | 921 | list_del_init(&server->tcp_ses_list); |
d7d7a66a | 922 | spin_unlock(&server->srv_lock); |
762dfd10 | 923 | |
21225336 PA |
924 | cancel_delayed_work_sync(&server->echo); |
925 | ||
d7d7a66a | 926 | spin_lock(&server->srv_lock); |
762dfd10 | 927 | server->tcpStatus = CifsExiting; |
d7d7a66a | 928 | spin_unlock(&server->srv_lock); |
762dfd10 PS |
929 | wake_up_all(&server->response_q); |
930 | ||
2d86dbc9 | 931 | /* check if we have blocked requests that need to free */ |
fc40f9cf | 932 | spin_lock(&server->req_lock); |
2d86dbc9 PS |
933 | if (server->credits <= 0) |
934 | server->credits = 1; | |
fc40f9cf | 935 | spin_unlock(&server->req_lock); |
762dfd10 PS |
936 | /* |
937 | * Although there should not be any requests blocked on this queue it | |
938 | * can not hurt to be paranoid and try to wake up requests that may | |
939 | * haven been blocked when more than 50 at time were on the wire to the | |
940 | * same server - they now will see the session is in exit state and get | |
941 | * out of SendReceive. | |
942 | */ | |
943 | wake_up_all(&server->request_q); | |
944 | /* give those requests time to exit */ | |
945 | msleep(125); | |
050b8c37 LL |
946 | if (cifs_rdma_enabled(server)) |
947 | smbd_destroy(server); | |
762dfd10 PS |
948 | if (server->ssocket) { |
949 | sock_release(server->ssocket); | |
950 | server->ssocket = NULL; | |
951 | } | |
952 | ||
953 | if (!list_empty(&server->pending_mid_q)) { | |
954 | struct list_head dispose_list; | |
955 | struct mid_q_entry *mid_entry; | |
956 | struct list_head *tmp, *tmp2; | |
957 | ||
958 | INIT_LIST_HEAD(&dispose_list); | |
d7d7a66a | 959 | spin_lock(&server->mid_lock); |
762dfd10 PS |
960 | list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { |
961 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | |
bf1bc694 | 962 | cifs_dbg(FYI, "Clearing mid %llu\n", mid_entry->mid); |
abe57073 | 963 | kref_get(&mid_entry->refcount); |
7c9421e1 | 964 | mid_entry->mid_state = MID_SHUTDOWN; |
762dfd10 | 965 | list_move(&mid_entry->qhead, &dispose_list); |
abe57073 | 966 | mid_entry->mid_flags |= MID_DELETED; |
762dfd10 | 967 | } |
d7d7a66a | 968 | spin_unlock(&server->mid_lock); |
762dfd10 PS |
969 | |
970 | /* now walk dispose list and issue callbacks */ | |
971 | list_for_each_safe(tmp, tmp2, &dispose_list) { | |
972 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | |
bf1bc694 | 973 | cifs_dbg(FYI, "Callback mid %llu\n", mid_entry->mid); |
762dfd10 PS |
974 | list_del_init(&mid_entry->qhead); |
975 | mid_entry->callback(mid_entry); | |
70f08f91 | 976 | release_mid(mid_entry); |
762dfd10 PS |
977 | } |
978 | /* 1/8th of sec is more than enough time for them to exit */ | |
979 | msleep(125); | |
980 | } | |
981 | ||
982 | if (!list_empty(&server->pending_mid_q)) { | |
983 | /* | |
984 | * mpx threads have not exited yet give them at least the smb | |
985 | * send timeout time for long ops. | |
986 | * | |
987 | * Due to delays on oplock break requests, we need to wait at | |
988 | * least 45 seconds before giving up on a request getting a | |
989 | * response and going ahead and killing cifsd. | |
990 | */ | |
f96637be | 991 | cifs_dbg(FYI, "Wait for exit from demultiplex thread\n"); |
762dfd10 PS |
992 | msleep(46000); |
993 | /* | |
994 | * If threads still have not exited they are probably never | |
995 | * coming home not much else we can do but free the memory. | |
996 | */ | |
997 | } | |
998 | ||
c88f7dcd | 999 | kfree(server->leaf_fullpath); |
762dfd10 PS |
1000 | kfree(server); |
1001 | ||
1002 | length = atomic_dec_return(&tcpSesAllocCount); | |
1003 | if (length > 0) | |
11d83360 | 1004 | mempool_resize(cifs_req_poolp, length + cifs_min_rcv); |
762dfd10 PS |
1005 | } |
1006 | ||
e9097ab4 JL |
1007 | static int |
1008 | standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |
1009 | { | |
1010 | int length; | |
1011 | char *buf = server->smallbuf; | |
2e96467d | 1012 | unsigned int pdu_length = server->pdu_size; |
e9097ab4 JL |
1013 | |
1014 | /* make sure this will fit in a large buffer */ | |
93012bf9 | 1015 | if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) - |
9789de8b | 1016 | HEADER_PREAMBLE_SIZE(server)) { |
afe6f653 | 1017 | cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length); |
183eea2e | 1018 | cifs_reconnect(server, true); |
3fabaa27 | 1019 | return -ECONNABORTED; |
e9097ab4 JL |
1020 | } |
1021 | ||
1022 | /* switch to large buffer if too big for a small one */ | |
1023 | if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) { | |
1024 | server->large_buf = true; | |
d4e4854f | 1025 | memcpy(server->bigbuf, buf, server->total_read); |
e9097ab4 | 1026 | buf = server->bigbuf; |
e9097ab4 JL |
1027 | } |
1028 | ||
1029 | /* now read the rest */ | |
1887f601 | 1030 | length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, |
b6b3624d | 1031 | pdu_length - MID_HEADER_SIZE(server)); |
93012bf9 | 1032 | |
e9097ab4 JL |
1033 | if (length < 0) |
1034 | return length; | |
1035 | server->total_read += length; | |
1036 | ||
d4e4854f | 1037 | dump_smb(buf, server->total_read); |
e9097ab4 | 1038 | |
4326ed2f PS |
1039 | return cifs_handle_standard(server, mid); |
1040 | } | |
1041 | ||
1042 | int | |
1043 | cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |
1044 | { | |
1045 | char *buf = server->large_buf ? server->bigbuf : server->smallbuf; | |
da384789 | 1046 | int rc; |
4326ed2f | 1047 | |
e9097ab4 JL |
1048 | /* |
1049 | * We know that we received enough to get to the MID as we | |
1050 | * checked the pdu_length earlier. Now check to see | |
da384789 | 1051 | * if the rest of the header is OK. |
e9097ab4 JL |
1052 | * |
1053 | * 48 bytes is enough to display the header and a little bit | |
1054 | * into the payload for debugging purposes. | |
1055 | */ | |
da384789 EM |
1056 | rc = server->ops->check_message(buf, server->total_read, server); |
1057 | if (rc) | |
e9097ab4 JL |
1058 | cifs_dump_mem("Bad SMB: ", buf, |
1059 | min_t(unsigned int, server->total_read, 48)); | |
1060 | ||
511c54a2 PS |
1061 | if (server->ops->is_session_expired && |
1062 | server->ops->is_session_expired(buf)) { | |
183eea2e | 1063 | cifs_reconnect(server, true); |
511c54a2 PS |
1064 | return -1; |
1065 | } | |
1066 | ||
2e44b288 | 1067 | if (server->ops->is_status_pending && |
66265f13 | 1068 | server->ops->is_status_pending(buf, server)) |
2e44b288 PS |
1069 | return -1; |
1070 | ||
ff4fa4a2 | 1071 | if (!mid) |
da384789 | 1072 | return rc; |
e9097ab4 | 1073 | |
da384789 | 1074 | handle_mid(mid, server, buf, rc); |
ff4fa4a2 | 1075 | return 0; |
e9097ab4 JL |
1076 | } |
1077 | ||
eca00452 RS |
1078 | static void |
1079 | smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server) | |
1080 | { | |
0d35e382 | 1081 | struct smb2_hdr *shdr = (struct smb2_hdr *)buffer; |
6d82c27a | 1082 | int scredits, in_flight; |
eca00452 RS |
1083 | |
1084 | /* | |
1085 | * SMB1 does not use credits. | |
1086 | */ | |
d291e703 | 1087 | if (is_smb1(server)) |
eca00452 RS |
1088 | return; |
1089 | ||
1090 | if (shdr->CreditRequest) { | |
1091 | spin_lock(&server->req_lock); | |
1092 | server->credits += le16_to_cpu(shdr->CreditRequest); | |
6d82c27a SP |
1093 | scredits = server->credits; |
1094 | in_flight = server->in_flight; | |
eca00452 RS |
1095 | spin_unlock(&server->req_lock); |
1096 | wake_up(&server->request_q); | |
cd7b699b | 1097 | |
1ddff774 | 1098 | trace_smb3_hdr_credits(server->CurrentMid, |
6d82c27a SP |
1099 | server->conn_id, server->hostname, scredits, |
1100 | le16_to_cpu(shdr->CreditRequest), in_flight); | |
cd7b699b SP |
1101 | cifs_server_dbg(FYI, "%s: added %u credits total=%d\n", |
1102 | __func__, le16_to_cpu(shdr->CreditRequest), | |
1103 | scredits); | |
eca00452 RS |
1104 | } |
1105 | } | |
1106 | ||
1107 | ||
1da177e4 | 1108 | static int |
7c97c200 | 1109 | cifs_demultiplex_thread(void *p) |
1da177e4 | 1110 | { |
b24df3e3 | 1111 | int i, num_mids, length; |
7c97c200 | 1112 | struct TCP_Server_Info *server = p; |
2a37ef94 | 1113 | unsigned int pdu_length; |
8ce79ec3 | 1114 | unsigned int next_offset; |
2a37ef94 | 1115 | char *buf = NULL; |
a5c3e1c7 | 1116 | struct task_struct *task_to_wake = NULL; |
b24df3e3 RS |
1117 | struct mid_q_entry *mids[MAX_COMPOUND]; |
1118 | char *bufs[MAX_COMPOUND]; | |
8e670f77 | 1119 | unsigned int noreclaim_flag, num_io_timeout = 0; |
69cba9d3 | 1120 | bool pending_reconnect = false; |
1da177e4 | 1121 | |
dc920277 | 1122 | noreclaim_flag = memalloc_noreclaim_save(); |
f96637be | 1123 | cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current)); |
93d0ec85 JL |
1124 | |
1125 | length = atomic_inc_return(&tcpSesAllocCount); | |
1126 | if (length > 1) | |
11d83360 | 1127 | mempool_resize(cifs_req_poolp, length + cifs_min_rcv); |
1da177e4 | 1128 | |
83144186 | 1129 | set_freezable(); |
33da8e7c | 1130 | allow_kernel_signal(SIGKILL); |
469ee614 | 1131 | while (server->tcpStatus != CifsExiting) { |
ede1327e SF |
1132 | if (try_to_freeze()) |
1133 | continue; | |
b8643e1b | 1134 | |
2a37ef94 | 1135 | if (!allocate_buffers(server)) |
3d9c2472 | 1136 | continue; |
b8643e1b | 1137 | |
2a37ef94 | 1138 | server->large_buf = false; |
2a37ef94 | 1139 | buf = server->smallbuf; |
f01d5e14 | 1140 | pdu_length = 4; /* enough to get RFC1001 header */ |
fda35943 | 1141 | |
e28bc5b1 | 1142 | length = cifs_read_from_socket(server, buf, pdu_length); |
a52c1eb7 | 1143 | if (length < 0) |
1da177e4 | 1144 | continue; |
977b6170 | 1145 | |
d291e703 | 1146 | if (is_smb1(server)) |
977b6170 | 1147 | server->total_read = length; |
d291e703 ZX |
1148 | else |
1149 | server->total_read = 0; | |
1da177e4 | 1150 | |
98bac62c PS |
1151 | /* |
1152 | * The right amount was read from socket - 4 bytes, | |
1153 | * so we can now interpret the length field. | |
1154 | */ | |
d4e4854f | 1155 | pdu_length = get_rfc1002_length(buf); |
70ca734a | 1156 | |
f96637be | 1157 | cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length); |
fe11e4cc | 1158 | if (!is_smb_response(server, buf[0])) |
fb8c4b14 | 1159 | continue; |
69cba9d3 SP |
1160 | |
1161 | pending_reconnect = false; | |
8ce79ec3 RS |
1162 | next_pdu: |
1163 | server->pdu_size = pdu_length; | |
e4eb295d | 1164 | |
89482a56 | 1165 | /* make sure we have enough to get to the MID */ |
b6b3624d | 1166 | if (server->pdu_size < MID_HEADER_SIZE(server)) { |
afe6f653 | 1167 | cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n", |
8ce79ec3 | 1168 | server->pdu_size); |
183eea2e | 1169 | cifs_reconnect(server, true); |
89482a56 | 1170 | continue; |
e4eb295d | 1171 | } |
e7015fb1 | 1172 | |
89482a56 | 1173 | /* read down to the MID */ |
93012bf9 | 1174 | length = cifs_read_from_socket(server, |
9789de8b | 1175 | buf + HEADER_PREAMBLE_SIZE(server), |
b6b3624d | 1176 | MID_HEADER_SIZE(server)); |
89482a56 | 1177 | if (length < 0) |
e4eb295d | 1178 | continue; |
2a37ef94 | 1179 | server->total_read += length; |
1da177e4 | 1180 | |
8ce79ec3 RS |
1181 | if (server->ops->next_header) { |
1182 | next_offset = server->ops->next_header(buf); | |
1183 | if (next_offset) | |
1184 | server->pdu_size = next_offset; | |
1185 | } | |
1186 | ||
b24df3e3 RS |
1187 | memset(mids, 0, sizeof(mids)); |
1188 | memset(bufs, 0, sizeof(bufs)); | |
1189 | num_mids = 0; | |
1190 | ||
9bb17e09 PS |
1191 | if (server->ops->is_transform_hdr && |
1192 | server->ops->receive_transform && | |
1193 | server->ops->is_transform_hdr(buf)) { | |
1194 | length = server->ops->receive_transform(server, | |
b24df3e3 RS |
1195 | mids, |
1196 | bufs, | |
1197 | &num_mids); | |
9bb17e09 | 1198 | } else { |
b24df3e3 RS |
1199 | mids[0] = server->ops->find_mid(server, buf); |
1200 | bufs[0] = buf; | |
7af929d6 | 1201 | num_mids = 1; |
50c2f753 | 1202 | |
b24df3e3 RS |
1203 | if (!mids[0] || !mids[0]->receive) |
1204 | length = standard_receive3(server, mids[0]); | |
9bb17e09 | 1205 | else |
b24df3e3 | 1206 | length = mids[0]->receive(server, mids[0]); |
9bb17e09 | 1207 | } |
71823baf | 1208 | |
696e420b | 1209 | if (length < 0) { |
b24df3e3 RS |
1210 | for (i = 0; i < num_mids; i++) |
1211 | if (mids[i]) | |
70f08f91 | 1212 | release_mid(mids[i]); |
fe11e4cc | 1213 | continue; |
696e420b | 1214 | } |
1da177e4 | 1215 | |
8e670f77 RS |
1216 | if (server->ops->is_status_io_timeout && |
1217 | server->ops->is_status_io_timeout(buf)) { | |
1218 | num_io_timeout++; | |
69cba9d3 SP |
1219 | if (num_io_timeout > MAX_STATUS_IO_TIMEOUT) { |
1220 | cifs_server_dbg(VFS, | |
1221 | "Number of request timeouts exceeded %d. Reconnecting", | |
1222 | MAX_STATUS_IO_TIMEOUT); | |
1223 | ||
1224 | pending_reconnect = true; | |
8e670f77 | 1225 | num_io_timeout = 0; |
8e670f77 RS |
1226 | } |
1227 | } | |
1228 | ||
fda35943 | 1229 | server->lstrp = jiffies; |
38bd4906 | 1230 | |
b24df3e3 RS |
1231 | for (i = 0; i < num_mids; i++) { |
1232 | if (mids[i] != NULL) { | |
1233 | mids[i]->resp_buf_size = server->pdu_size; | |
696e420b | 1234 | |
c071b34f SP |
1235 | if (bufs[i] != NULL) { |
1236 | if (server->ops->is_network_name_deleted && | |
1237 | server->ops->is_network_name_deleted(bufs[i], | |
1238 | server)) { | |
1239 | cifs_server_dbg(FYI, | |
1240 | "Share deleted. Reconnect needed"); | |
1241 | } | |
1242 | } | |
9e550b08 | 1243 | |
b24df3e3 RS |
1244 | if (!mids[i]->multiRsp || mids[i]->multiEnd) |
1245 | mids[i]->callback(mids[i]); | |
1246 | ||
70f08f91 | 1247 | release_mid(mids[i]); |
b24df3e3 RS |
1248 | } else if (server->ops->is_oplock_break && |
1249 | server->ops->is_oplock_break(bufs[i], | |
1250 | server)) { | |
eca00452 | 1251 | smb2_add_credits_from_hdr(bufs[i], server); |
b24df3e3 RS |
1252 | cifs_dbg(FYI, "Received oplock break\n"); |
1253 | } else { | |
a0a3036b | 1254 | cifs_server_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n", |
c2c17ddb | 1255 | atomic_read(&mid_count)); |
b24df3e3 RS |
1256 | cifs_dump_mem("Received Data is: ", bufs[i], |
1257 | HEADER_SIZE(server)); | |
3e272579 | 1258 | smb2_add_credits_from_hdr(bufs[i], server); |
3979877e | 1259 | #ifdef CONFIG_CIFS_DEBUG2 |
b24df3e3 RS |
1260 | if (server->ops->dump_detail) |
1261 | server->ops->dump_detail(bufs[i], | |
1262 | server); | |
1263 | cifs_dump_mids(server); | |
3979877e | 1264 | #endif /* CIFS_DEBUG2 */ |
b24df3e3 | 1265 | } |
8ce79ec3 | 1266 | } |
b24df3e3 | 1267 | |
8ce79ec3 RS |
1268 | if (pdu_length > server->pdu_size) { |
1269 | if (!allocate_buffers(server)) | |
1270 | continue; | |
1271 | pdu_length -= server->pdu_size; | |
1272 | server->total_read = 0; | |
1273 | server->large_buf = false; | |
1274 | buf = server->smallbuf; | |
1275 | goto next_pdu; | |
e4eb295d | 1276 | } |
69cba9d3 SP |
1277 | |
1278 | /* do this reconnect at the very end after processing all MIDs */ | |
1279 | if (pending_reconnect) | |
1280 | cifs_reconnect(server, true); | |
1281 | ||
e4eb295d SF |
1282 | } /* end while !EXITING */ |
1283 | ||
fd62cb7e | 1284 | /* buffer usually freed in free_mid - need to free it here on exit */ |
2a37ef94 JL |
1285 | cifs_buf_release(server->bigbuf); |
1286 | if (server->smallbuf) /* no sense logging a debug message if NULL */ | |
1287 | cifs_small_buf_release(server->smallbuf); | |
1da177e4 | 1288 | |
a5c3e1c7 | 1289 | task_to_wake = xchg(&server->tsk, NULL); |
762dfd10 | 1290 | clean_demultiplex_info(server); |
a5c3e1c7 SF |
1291 | |
1292 | /* if server->tsk was NULL then wait for a signal before exiting */ | |
1293 | if (!task_to_wake) { | |
1294 | set_current_state(TASK_INTERRUPTIBLE); | |
1295 | while (!signal_pending(current)) { | |
1296 | schedule(); | |
1297 | set_current_state(TASK_INTERRUPTIBLE); | |
1298 | } | |
1299 | set_current_state(TASK_RUNNING); | |
1300 | } | |
1301 | ||
dc920277 | 1302 | memalloc_noreclaim_restore(noreclaim_flag); |
ca3574bd | 1303 | module_put_and_kthread_exit(0); |
1da177e4 LT |
1304 | } |
1305 | ||
2991b774 SP |
1306 | int |
1307 | cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs) | |
1308 | { | |
1309 | struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr; | |
1310 | struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs; | |
1311 | struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr; | |
1312 | struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)rhs; | |
1313 | ||
1314 | switch (srcaddr->sa_family) { | |
1315 | case AF_UNSPEC: | |
1316 | switch (rhs->sa_family) { | |
1317 | case AF_UNSPEC: | |
1318 | return 0; | |
1319 | case AF_INET: | |
1320 | case AF_INET6: | |
1321 | return 1; | |
1322 | default: | |
1323 | return -1; | |
1324 | } | |
1325 | case AF_INET: { | |
1326 | switch (rhs->sa_family) { | |
1327 | case AF_UNSPEC: | |
1328 | return -1; | |
1329 | case AF_INET: | |
1330 | return memcmp(saddr4, vaddr4, | |
1331 | sizeof(struct sockaddr_in)); | |
1332 | case AF_INET6: | |
1333 | return 1; | |
1334 | default: | |
1335 | return -1; | |
1336 | } | |
1337 | } | |
1338 | case AF_INET6: { | |
1339 | switch (rhs->sa_family) { | |
1340 | case AF_UNSPEC: | |
1341 | case AF_INET: | |
1342 | return -1; | |
1343 | case AF_INET6: | |
1344 | return memcmp(saddr6, | |
1345 | vaddr6, | |
1346 | sizeof(struct sockaddr_in6)); | |
1347 | default: | |
1348 | return -1; | |
1349 | } | |
1350 | } | |
1351 | default: | |
1352 | return -1; /* don't expect to be here */ | |
1353 | } | |
1354 | } | |
1355 | ||
4c51de1e | 1356 | /* |
bc044994 SF |
1357 | * Returns true if srcaddr isn't specified and rhs isn't specified, or |
1358 | * if srcaddr is specified and matches the IP address of the rhs argument | |
3eb9a889 | 1359 | */ |
e4af35fa PA |
1360 | bool |
1361 | cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs) | |
3eb9a889 BG |
1362 | { |
1363 | switch (srcaddr->sa_family) { | |
1364 | case AF_UNSPEC: | |
1365 | return (rhs->sa_family == AF_UNSPEC); | |
1366 | case AF_INET: { | |
1367 | struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr; | |
1368 | struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs; | |
1369 | return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr); | |
1370 | } | |
1371 | case AF_INET6: { | |
1372 | struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr; | |
e3e2775c | 1373 | struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)rhs; |
a21be1f5 SP |
1374 | return (ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr) |
1375 | && saddr6->sin6_scope_id == vaddr6->sin6_scope_id); | |
3eb9a889 BG |
1376 | } |
1377 | default: | |
1378 | WARN_ON(1); | |
1379 | return false; /* don't expect to be here */ | |
1380 | } | |
1381 | } | |
1382 | ||
4b886136 PS |
1383 | /* |
1384 | * If no port is specified in addr structure, we try to match with 445 port | |
1385 | * and if it fails - with 139 ports. It should be called only if address | |
1386 | * families of server and addr are equal. | |
1387 | */ | |
1388 | static bool | |
1389 | match_port(struct TCP_Server_Info *server, struct sockaddr *addr) | |
1390 | { | |
6da97910 | 1391 | __be16 port, *sport; |
4b886136 | 1392 | |
3b249115 LL |
1393 | /* SMBDirect manages its own ports, don't match it here */ |
1394 | if (server->rdma) | |
1395 | return true; | |
1396 | ||
4b886136 PS |
1397 | switch (addr->sa_family) { |
1398 | case AF_INET: | |
1399 | sport = &((struct sockaddr_in *) &server->dstaddr)->sin_port; | |
1400 | port = ((struct sockaddr_in *) addr)->sin_port; | |
1401 | break; | |
1402 | case AF_INET6: | |
1403 | sport = &((struct sockaddr_in6 *) &server->dstaddr)->sin6_port; | |
1404 | port = ((struct sockaddr_in6 *) addr)->sin6_port; | |
1405 | break; | |
1406 | default: | |
1407 | WARN_ON(1); | |
1408 | return false; | |
1409 | } | |
1410 | ||
1411 | if (!port) { | |
1412 | port = htons(CIFS_PORT); | |
1413 | if (port == *sport) | |
1414 | return true; | |
1415 | ||
1416 | port = htons(RFC1001_PORT); | |
1417 | } | |
1418 | ||
1419 | return port == *sport; | |
1420 | } | |
3eb9a889 | 1421 | |
a1c0d005 | 1422 | static bool match_server_address(struct TCP_Server_Info *server, struct sockaddr *addr) |
4515148e | 1423 | { |
410612b0 SP |
1424 | if (!cifs_match_ipaddr(addr, (struct sockaddr *)&server->dstaddr)) |
1425 | return false; | |
4515148e JL |
1426 | |
1427 | return true; | |
1428 | } | |
1429 | ||
daf5b0b6 | 1430 | static bool |
3fa1c6d1 | 1431 | match_security(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) |
daf5b0b6 | 1432 | { |
3f618223 | 1433 | /* |
3fa1c6d1 | 1434 | * The select_sectype function should either return the ctx->sectype |
3f618223 JL |
1435 | * that was specified, or "Unspecified" if that sectype was not |
1436 | * compatible with the given NEGOTIATE request. | |
1437 | */ | |
3fa1c6d1 | 1438 | if (server->ops->select_sectype(server, ctx->sectype) |
ef65aaed | 1439 | == Unspecified) |
daf5b0b6 | 1440 | return false; |
daf5b0b6 | 1441 | |
3f618223 JL |
1442 | /* |
1443 | * Now check if signing mode is acceptable. No need to check | |
1444 | * global_secflags at this point since if MUST_SIGN is set then | |
1445 | * the server->sign had better be too. | |
1446 | */ | |
3fa1c6d1 | 1447 | if (ctx->sign && !server->sign) |
38d77c50 | 1448 | return false; |
daf5b0b6 JL |
1449 | |
1450 | return true; | |
1451 | } | |
1452 | ||
d7d7a66a | 1453 | /* this function must be called with srv_lock held */ |
3ae872de PA |
1454 | static int match_server(struct TCP_Server_Info *server, |
1455 | struct smb3_fs_context *ctx, | |
1456 | bool match_super) | |
37bb04e5 | 1457 | { |
3fa1c6d1 | 1458 | struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr; |
9fa114f7 | 1459 | |
90c49fce PA |
1460 | lockdep_assert_held(&server->srv_lock); |
1461 | ||
b9ad6b5b | 1462 | if (ctx->nosharesock) |
c9f1c19c | 1463 | return 0; |
c9f1c19c SP |
1464 | |
1465 | /* this server does not share socket */ | |
1466 | if (server->nosharesock) | |
a0b3df5c JL |
1467 | return 0; |
1468 | ||
43cdae88 | 1469 | /* If multidialect negotiation see if existing sessions match one */ |
3fa1c6d1 | 1470 | if (strcmp(ctx->vals->version_string, SMB3ANY_VERSION_STRING) == 0) { |
43cdae88 SF |
1471 | if (server->vals->protocol_id < SMB30_PROT_ID) |
1472 | return 0; | |
3fa1c6d1 | 1473 | } else if (strcmp(ctx->vals->version_string, |
43cdae88 SF |
1474 | SMBDEFAULT_VERSION_STRING) == 0) { |
1475 | if (server->vals->protocol_id < SMB21_PROT_ID) | |
1476 | return 0; | |
3fa1c6d1 | 1477 | } else if ((server->vals != ctx->vals) || (server->ops != ctx->ops)) |
23db65f5 JL |
1478 | return 0; |
1479 | ||
37bb04e5 PS |
1480 | if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns)) |
1481 | return 0; | |
1482 | ||
a1c0d005 PA |
1483 | if (!cifs_match_ipaddr((struct sockaddr *)&ctx->srcaddr, |
1484 | (struct sockaddr *)&server->srcaddr)) | |
37bb04e5 | 1485 | return 0; |
a1c0d005 | 1486 | /* |
3ae872de PA |
1487 | * When matching cifs.ko superblocks (@match_super == true), we can't |
1488 | * really match either @server->leaf_fullpath or @server->dstaddr | |
1489 | * directly since this @server might belong to a completely different | |
1490 | * server -- in case of domain-based DFS referrals or DFS links -- as | |
1491 | * provided earlier by mount(2) through 'source' and 'ip' options. | |
1492 | * | |
1493 | * Otherwise, match the DFS referral in @server->leaf_fullpath or the | |
1494 | * destination address in @server->dstaddr. | |
1495 | * | |
1496 | * When using 'nodfs' mount option, we avoid sharing it with DFS | |
1497 | * connections as they might failover. | |
a1c0d005 | 1498 | */ |
3ae872de PA |
1499 | if (!match_super) { |
1500 | if (!ctx->nodfs) { | |
1501 | if (server->leaf_fullpath) { | |
1502 | if (!ctx->leaf_fullpath || | |
1503 | strcasecmp(server->leaf_fullpath, | |
1504 | ctx->leaf_fullpath)) | |
1505 | return 0; | |
1506 | } else if (ctx->leaf_fullpath) { | |
8e355415 | 1507 | return 0; |
3ae872de | 1508 | } |
8e355415 | 1509 | } else if (server->leaf_fullpath) { |
a1c0d005 PA |
1510 | return 0; |
1511 | } | |
1512 | } | |
37bb04e5 | 1513 | |
8e355415 PA |
1514 | /* |
1515 | * Match for a regular connection (address/hostname/port) which has no | |
1516 | * DFS referrals set. | |
1517 | */ | |
3ae872de | 1518 | if (!server->leaf_fullpath && |
8e355415 PA |
1519 | (strcasecmp(server->hostname, ctx->server_hostname) || |
1520 | !match_server_address(server, addr) || | |
1521 | !match_port(server, addr))) | |
1522 | return 0; | |
1523 | ||
3fa1c6d1 | 1524 | if (!match_security(server, ctx)) |
37bb04e5 PS |
1525 | return 0; |
1526 | ||
3fa1c6d1 | 1527 | if (server->echo_interval != ctx->echo_interval * HZ) |
adfeb3e0 SF |
1528 | return 0; |
1529 | ||
3fa1c6d1 | 1530 | if (server->rdma != ctx->rdma) |
8339dd32 LL |
1531 | return 0; |
1532 | ||
3fa1c6d1 | 1533 | if (server->ignore_signature != ctx->ignore_signature) |
4f5c10f1 SF |
1534 | return 0; |
1535 | ||
3fa1c6d1 | 1536 | if (server->min_offload != ctx->min_offload) |
563317ec SF |
1537 | return 0; |
1538 | ||
37bb04e5 PS |
1539 | return 1; |
1540 | } | |
1541 | ||
54be1f6c | 1542 | struct TCP_Server_Info * |
3fa1c6d1 | 1543 | cifs_find_tcp_session(struct smb3_fs_context *ctx) |
1da177e4 | 1544 | { |
e7ddee90 | 1545 | struct TCP_Server_Info *server; |
e7ddee90 | 1546 | |
3f9bcca7 | 1547 | spin_lock(&cifs_tcp_ses_lock); |
4515148e | 1548 | list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { |
d7d7a66a | 1549 | spin_lock(&server->srv_lock); |
3345bb44 PAS |
1550 | /* |
1551 | * Skip ses channels since they're only handled in lower layers | |
1552 | * (e.g. cifs_send_recv). | |
1553 | */ | |
b3773b19 | 1554 | if (SERVER_IS_CHAN(server) || |
3ae872de | 1555 | !match_server(server, ctx, false)) { |
d7d7a66a | 1556 | spin_unlock(&server->srv_lock); |
daf5b0b6 | 1557 | continue; |
d7d7a66a SP |
1558 | } |
1559 | spin_unlock(&server->srv_lock); | |
daf5b0b6 | 1560 | |
e7ddee90 | 1561 | ++server->srv_count; |
3f9bcca7 | 1562 | spin_unlock(&cifs_tcp_ses_lock); |
f96637be | 1563 | cifs_dbg(FYI, "Existing tcp session with server found\n"); |
e7ddee90 | 1564 | return server; |
1da177e4 | 1565 | } |
3f9bcca7 | 1566 | spin_unlock(&cifs_tcp_ses_lock); |
1da177e4 LT |
1567 | return NULL; |
1568 | } | |
1b20d672 | 1569 | |
53e0e11e PS |
1570 | void |
1571 | cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) | |
1da177e4 | 1572 | { |
a5c3e1c7 SF |
1573 | struct task_struct *task; |
1574 | ||
3f9bcca7 | 1575 | spin_lock(&cifs_tcp_ses_lock); |
e7ddee90 | 1576 | if (--server->srv_count > 0) { |
3f9bcca7 | 1577 | spin_unlock(&cifs_tcp_ses_lock); |
e7ddee90 | 1578 | return; |
1da177e4 | 1579 | } |
1b20d672 | 1580 | |
16dd9b8c SP |
1581 | /* srv_count can never go negative */ |
1582 | WARN_ON(server->srv_count < 0); | |
1583 | ||
f1d0c998 RL |
1584 | put_net(cifs_net_ns(server)); |
1585 | ||
e7ddee90 | 1586 | list_del_init(&server->tcp_ses_list); |
3f9bcca7 | 1587 | spin_unlock(&cifs_tcp_ses_lock); |
dea570e0 | 1588 | |
0f2b305a | 1589 | /* For secondary channels, we pick up ref-count on the primary server */ |
b3773b19 | 1590 | if (SERVER_IS_CHAN(server)) |
0f2b305a SP |
1591 | cifs_put_tcp_session(server->primary_server, from_reconnect); |
1592 | ||
c74093b6 JL |
1593 | cancel_delayed_work_sync(&server->echo); |
1594 | ||
53e0e11e PS |
1595 | if (from_reconnect) |
1596 | /* | |
1597 | * Avoid deadlock here: reconnect work calls | |
1598 | * cifs_put_tcp_session() at its end. Need to be sure | |
1599 | * that reconnect work does nothing with server pointer after | |
1600 | * that step. | |
1601 | */ | |
1602 | cancel_delayed_work(&server->reconnect); | |
1603 | else | |
1604 | cancel_delayed_work_sync(&server->reconnect); | |
53e0e11e | 1605 | |
d7d7a66a | 1606 | spin_lock(&server->srv_lock); |
e7ddee90 | 1607 | server->tcpStatus = CifsExiting; |
d7d7a66a | 1608 | spin_unlock(&server->srv_lock); |
dea570e0 | 1609 | |
026e93dc | 1610 | cifs_crypto_secmech_release(server); |
46bb1b94 | 1611 | |
a4e430c8 | 1612 | kfree_sensitive(server->session_key.response); |
21e73393 SP |
1613 | server->session_key.response = NULL; |
1614 | server->session_key.len = 0; | |
7be3248f | 1615 | kfree(server->hostname); |
153695d3 | 1616 | server->hostname = NULL; |
a5c3e1c7 SF |
1617 | |
1618 | task = xchg(&server->tsk, NULL); | |
1619 | if (task) | |
72abe3bc | 1620 | send_sig(SIGKILL, task, 1); |
1da177e4 LT |
1621 | } |
1622 | ||
d70e9fa5 | 1623 | struct TCP_Server_Info * |
0f2b305a SP |
1624 | cifs_get_tcp_session(struct smb3_fs_context *ctx, |
1625 | struct TCP_Server_Info *primary_server) | |
63c038c2 JL |
1626 | { |
1627 | struct TCP_Server_Info *tcp_ses = NULL; | |
63c038c2 JL |
1628 | int rc; |
1629 | ||
3fa1c6d1 | 1630 | cifs_dbg(FYI, "UNC: %s\n", ctx->UNC); |
63c038c2 JL |
1631 | |
1632 | /* see if we already have a matching tcp_ses */ | |
3fa1c6d1 | 1633 | tcp_ses = cifs_find_tcp_session(ctx); |
63c038c2 JL |
1634 | if (tcp_ses) |
1635 | return tcp_ses; | |
1636 | ||
1637 | tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL); | |
1638 | if (!tcp_ses) { | |
1639 | rc = -ENOMEM; | |
1640 | goto out_err; | |
1641 | } | |
1642 | ||
7be3248f SP |
1643 | tcp_ses->hostname = kstrdup(ctx->server_hostname, GFP_KERNEL); |
1644 | if (!tcp_ses->hostname) { | |
1645 | rc = -ENOMEM; | |
1646 | goto out_err; | |
1647 | } | |
1648 | ||
a1c0d005 PA |
1649 | if (ctx->leaf_fullpath) { |
1650 | tcp_ses->leaf_fullpath = kstrdup(ctx->leaf_fullpath, GFP_KERNEL); | |
1651 | if (!tcp_ses->leaf_fullpath) { | |
1652 | rc = -ENOMEM; | |
1653 | goto out_err; | |
1654 | } | |
a1c0d005 PA |
1655 | } |
1656 | ||
b9ad6b5b SP |
1657 | if (ctx->nosharesock) |
1658 | tcp_ses->nosharesock = true; | |
1659 | ||
3fa1c6d1 RS |
1660 | tcp_ses->ops = ctx->ops; |
1661 | tcp_ses->vals = ctx->vals; | |
f1d0c998 | 1662 | cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns)); |
63c038c2 | 1663 | |
6d82c27a | 1664 | tcp_ses->conn_id = atomic_inc_return(&tcpSesNextId); |
3fa1c6d1 RS |
1665 | tcp_ses->noblockcnt = ctx->rootfs; |
1666 | tcp_ses->noblocksnd = ctx->noblocksnd || ctx->rootfs; | |
1667 | tcp_ses->noautotune = ctx->noautotune; | |
1668 | tcp_ses->tcp_nodelay = ctx->sockopt_tcp_nodelay; | |
1669 | tcp_ses->rdma = ctx->rdma; | |
fc40f9cf | 1670 | tcp_ses->in_flight = 0; |
1b63f184 | 1671 | tcp_ses->max_in_flight = 0; |
2d86dbc9 | 1672 | tcp_ses->credits = 1; |
0f2b305a | 1673 | if (primary_server) { |
446e2148 | 1674 | spin_lock(&cifs_tcp_ses_lock); |
0f2b305a | 1675 | ++primary_server->srv_count; |
446e2148 | 1676 | spin_unlock(&cifs_tcp_ses_lock); |
d7d7a66a | 1677 | tcp_ses->primary_server = primary_server; |
0f2b305a | 1678 | } |
63c038c2 JL |
1679 | init_waitqueue_head(&tcp_ses->response_q); |
1680 | init_waitqueue_head(&tcp_ses->request_q); | |
1681 | INIT_LIST_HEAD(&tcp_ses->pending_mid_q); | |
cc391b69 | 1682 | mutex_init(&tcp_ses->_srv_mutex); |
63c038c2 | 1683 | memcpy(tcp_ses->workstation_RFC1001_name, |
3fa1c6d1 | 1684 | ctx->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); |
63c038c2 | 1685 | memcpy(tcp_ses->server_RFC1001_name, |
3fa1c6d1 | 1686 | ctx->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); |
5d0d2882 | 1687 | tcp_ses->session_estab = false; |
63c038c2 | 1688 | tcp_ses->sequence_number = 0; |
09ee7a3b | 1689 | tcp_ses->channel_sequence_num = 0; /* only tracked for primary channel */ |
5b964852 | 1690 | tcp_ses->reconnect_instance = 1; |
fda35943 | 1691 | tcp_ses->lstrp = jiffies; |
3fa1c6d1 | 1692 | tcp_ses->compress_algorithm = cpu_to_le16(ctx->compression); |
58fa015f | 1693 | spin_lock_init(&tcp_ses->req_lock); |
d7d7a66a SP |
1694 | spin_lock_init(&tcp_ses->srv_lock); |
1695 | spin_lock_init(&tcp_ses->mid_lock); | |
63c038c2 JL |
1696 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); |
1697 | INIT_LIST_HEAD(&tcp_ses->smb_ses_list); | |
c74093b6 | 1698 | INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); |
53e0e11e PS |
1699 | INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server); |
1700 | mutex_init(&tcp_ses->reconnect_mutex); | |
c88f7dcd PA |
1701 | #ifdef CONFIG_CIFS_DFS_UPCALL |
1702 | mutex_init(&tcp_ses->refpath_lock); | |
1703 | #endif | |
3fa1c6d1 | 1704 | memcpy(&tcp_ses->srcaddr, &ctx->srcaddr, |
9fa114f7 | 1705 | sizeof(tcp_ses->srcaddr)); |
3fa1c6d1 | 1706 | memcpy(&tcp_ses->dstaddr, &ctx->dstaddr, |
9fa114f7 | 1707 | sizeof(tcp_ses->dstaddr)); |
3fa1c6d1 RS |
1708 | if (ctx->use_client_guid) |
1709 | memcpy(tcp_ses->client_guid, ctx->client_guid, | |
bcc88801 AA |
1710 | SMB2_CLIENT_GUID_SIZE); |
1711 | else | |
1712 | generate_random_uuid(tcp_ses->client_guid); | |
63c038c2 JL |
1713 | /* |
1714 | * at this point we are the only ones with the pointer | |
1715 | * to the struct since the kernel thread not created yet | |
1716 | * no need to spinlock this init of tcpStatus or srv_count | |
1717 | */ | |
1718 | tcp_ses->tcpStatus = CifsNew; | |
1719 | ++tcp_ses->srv_count; | |
1720 | ||
3fa1c6d1 RS |
1721 | if (ctx->echo_interval >= SMB_ECHO_INTERVAL_MIN && |
1722 | ctx->echo_interval <= SMB_ECHO_INTERVAL_MAX) | |
1723 | tcp_ses->echo_interval = ctx->echo_interval * HZ; | |
adfeb3e0 SF |
1724 | else |
1725 | tcp_ses->echo_interval = SMB_ECHO_INTERVAL_DEFAULT * HZ; | |
2f894646 LL |
1726 | if (tcp_ses->rdma) { |
1727 | #ifndef CONFIG_CIFS_SMB_DIRECT | |
1728 | cifs_dbg(VFS, "CONFIG_CIFS_SMB_DIRECT is not enabled\n"); | |
1729 | rc = -ENOENT; | |
1730 | goto out_err_crypto_release; | |
1731 | #endif | |
1732 | tcp_ses->smbd_conn = smbd_get_connection( | |
3fa1c6d1 | 1733 | tcp_ses, (struct sockaddr *)&ctx->dstaddr); |
2f894646 LL |
1734 | if (tcp_ses->smbd_conn) { |
1735 | cifs_dbg(VFS, "RDMA transport established\n"); | |
1736 | rc = 0; | |
1737 | goto smbd_connected; | |
1738 | } else { | |
1739 | rc = -ENOENT; | |
1740 | goto out_err_crypto_release; | |
1741 | } | |
1742 | } | |
a9f1b85e | 1743 | rc = ip_connect(tcp_ses); |
63c038c2 | 1744 | if (rc < 0) { |
f96637be | 1745 | cifs_dbg(VFS, "Error connecting to socket. Aborting operation.\n"); |
f7c5445a | 1746 | goto out_err_crypto_release; |
63c038c2 | 1747 | } |
2f894646 | 1748 | smbd_connected: |
63c038c2 JL |
1749 | /* |
1750 | * since we're in a cifs function already, we know that | |
1751 | * this will succeed. No need for try_module_get(). | |
1752 | */ | |
1753 | __module_get(THIS_MODULE); | |
7c97c200 | 1754 | tcp_ses->tsk = kthread_run(cifs_demultiplex_thread, |
63c038c2 JL |
1755 | tcp_ses, "cifsd"); |
1756 | if (IS_ERR(tcp_ses->tsk)) { | |
1757 | rc = PTR_ERR(tcp_ses->tsk); | |
f96637be | 1758 | cifs_dbg(VFS, "error %d create cifsd thread\n", rc); |
63c038c2 | 1759 | module_put(THIS_MODULE); |
f7c5445a | 1760 | goto out_err_crypto_release; |
63c038c2 | 1761 | } |
3fa1c6d1 | 1762 | tcp_ses->min_offload = ctx->min_offload; |
01cf3082 SF |
1763 | /* |
1764 | * at this point we are the only ones with the pointer | |
1765 | * to the struct since the kernel thread not created yet | |
1766 | * no need to spinlock this update of tcpStatus | |
1767 | */ | |
d7d7a66a | 1768 | spin_lock(&tcp_ses->srv_lock); |
fd88ce93 | 1769 | tcp_ses->tcpStatus = CifsNeedNegotiate; |
d7d7a66a | 1770 | spin_unlock(&tcp_ses->srv_lock); |
63c038c2 | 1771 | |
a249cc8b AA |
1772 | if ((ctx->max_credits < 20) || (ctx->max_credits > 60000)) |
1773 | tcp_ses->max_credits = SMB2_MAX_CREDITS_AVAILABLE; | |
1774 | else | |
1775 | tcp_ses->max_credits = ctx->max_credits; | |
1776 | ||
93d5cb51 | 1777 | tcp_ses->nr_targets = 1; |
3fa1c6d1 | 1778 | tcp_ses->ignore_signature = ctx->ignore_signature; |
63c038c2 | 1779 | /* thread spawned, put it on the list */ |
3f9bcca7 | 1780 | spin_lock(&cifs_tcp_ses_lock); |
63c038c2 | 1781 | list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); |
3f9bcca7 | 1782 | spin_unlock(&cifs_tcp_ses_lock); |
63c038c2 | 1783 | |
c74093b6 | 1784 | /* queue echo request delayed work */ |
adfeb3e0 | 1785 | queue_delayed_work(cifsiod_wq, &tcp_ses->echo, tcp_ses->echo_interval); |
c74093b6 | 1786 | |
63c038c2 JL |
1787 | return tcp_ses; |
1788 | ||
f7c5445a | 1789 | out_err_crypto_release: |
026e93dc | 1790 | cifs_crypto_secmech_release(tcp_ses); |
d2b91521 | 1791 | |
f1d0c998 RL |
1792 | put_net(cifs_net_ns(tcp_ses)); |
1793 | ||
63c038c2 JL |
1794 | out_err: |
1795 | if (tcp_ses) { | |
b3773b19 | 1796 | if (SERVER_IS_CHAN(tcp_ses)) |
0f2b305a | 1797 | cifs_put_tcp_session(tcp_ses->primary_server, false); |
7be3248f | 1798 | kfree(tcp_ses->hostname); |
a1c0d005 | 1799 | kfree(tcp_ses->leaf_fullpath); |
63c038c2 JL |
1800 | if (tcp_ses->ssocket) |
1801 | sock_release(tcp_ses->ssocket); | |
1802 | kfree(tcp_ses); | |
1803 | } | |
1804 | return ERR_PTR(rc); | |
1805 | } | |
1806 | ||
2f4e429c | 1807 | /* this function must be called with ses_lock and chan_lock held */ |
3fa1c6d1 | 1808 | static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx) |
37bb04e5 | 1809 | { |
3fa1c6d1 RS |
1810 | if (ctx->sectype != Unspecified && |
1811 | ctx->sectype != ses->sectype) | |
3f618223 JL |
1812 | return 0; |
1813 | ||
bcc88801 AA |
1814 | /* |
1815 | * If an existing session is limited to less channels than | |
1816 | * requested, it should not be reused | |
1817 | */ | |
2f4e429c | 1818 | if (ses->chan_max < ctx->max_channels) |
bcc88801 AA |
1819 | return 0; |
1820 | ||
3f618223 | 1821 | switch (ses->sectype) { |
37bb04e5 | 1822 | case Kerberos: |
3fa1c6d1 | 1823 | if (!uid_eq(ctx->cred_uid, ses->cred_uid)) |
37bb04e5 PS |
1824 | return 0; |
1825 | break; | |
1826 | default: | |
04febabc JL |
1827 | /* NULL username means anonymous session */ |
1828 | if (ses->user_name == NULL) { | |
3fa1c6d1 | 1829 | if (!ctx->nullauth) |
04febabc JL |
1830 | return 0; |
1831 | break; | |
1832 | } | |
1833 | ||
37bb04e5 | 1834 | /* anything else takes username/password */ |
04febabc | 1835 | if (strncmp(ses->user_name, |
3fa1c6d1 | 1836 | ctx->username ? ctx->username : "", |
8c3a2b4c | 1837 | CIFS_MAX_USERNAME_LEN)) |
37bb04e5 | 1838 | return 0; |
3fa1c6d1 | 1839 | if ((ctx->username && strlen(ctx->username) != 0) && |
37bb04e5 PS |
1840 | ses->password != NULL && |
1841 | strncmp(ses->password, | |
3fa1c6d1 | 1842 | ctx->password ? ctx->password : "", |
8c3a2b4c | 1843 | CIFS_MAX_PASSWORD_LEN)) |
37bb04e5 PS |
1844 | return 0; |
1845 | } | |
a43f95fd WW |
1846 | |
1847 | if (strcmp(ctx->local_nls->charset, ses->local_nls->charset)) | |
1848 | return 0; | |
1849 | ||
37bb04e5 PS |
1850 | return 1; |
1851 | } | |
1852 | ||
b327a717 AA |
1853 | /** |
1854 | * cifs_setup_ipc - helper to setup the IPC tcon for the session | |
4c51de1e SF |
1855 | * @ses: smb session to issue the request on |
1856 | * @ctx: the superblock configuration context to use for building the | |
1857 | * new tree connection for the IPC (interprocess communication RPC) | |
b327a717 AA |
1858 | * |
1859 | * A new IPC connection is made and stored in the session | |
1860 | * tcon_ipc. The IPC tcon has the same lifetime as the session. | |
1861 | */ | |
1862 | static int | |
3fa1c6d1 | 1863 | cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx) |
b327a717 AA |
1864 | { |
1865 | int rc = 0, xid; | |
1866 | struct cifs_tcon *tcon; | |
b327a717 AA |
1867 | char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0}; |
1868 | bool seal = false; | |
afe6f653 | 1869 | struct TCP_Server_Info *server = ses->server; |
b327a717 AA |
1870 | |
1871 | /* | |
1872 | * If the mount request that resulted in the creation of the | |
1873 | * session requires encryption, force IPC to be encrypted too. | |
1874 | */ | |
3fa1c6d1 | 1875 | if (ctx->seal) { |
afe6f653 | 1876 | if (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) |
b327a717 AA |
1877 | seal = true; |
1878 | else { | |
afe6f653 | 1879 | cifs_server_dbg(VFS, |
b327a717 AA |
1880 | "IPC: server doesn't support encryption\n"); |
1881 | return -EOPNOTSUPP; | |
1882 | } | |
1883 | } | |
1884 | ||
2da338ff SF |
1885 | /* no need to setup directory caching on IPC share, so pass in false */ |
1886 | tcon = tcon_info_alloc(false); | |
b327a717 AA |
1887 | if (tcon == NULL) |
1888 | return -ENOMEM; | |
1889 | ||
90c49fce | 1890 | spin_lock(&server->srv_lock); |
afe6f653 | 1891 | scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname); |
90c49fce | 1892 | spin_unlock(&server->srv_lock); |
b327a717 | 1893 | |
b327a717 AA |
1894 | xid = get_xid(); |
1895 | tcon->ses = ses; | |
1896 | tcon->ipc = true; | |
1897 | tcon->seal = seal; | |
6fd4ea88 | 1898 | rc = server->ops->tree_connect(xid, ses, unc, tcon, ctx->local_nls); |
b327a717 AA |
1899 | free_xid(xid); |
1900 | ||
1901 | if (rc) { | |
afe6f653 | 1902 | cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc); |
b327a717 AA |
1903 | tconInfoFree(tcon); |
1904 | goto out; | |
1905 | } | |
1906 | ||
71081e7a | 1907 | cifs_dbg(FYI, "IPC tcon rc=%d ipc tid=0x%x\n", rc, tcon->tid); |
b327a717 | 1908 | |
86fe0fa8 PA |
1909 | spin_lock(&tcon->tc_lock); |
1910 | tcon->status = TID_GOOD; | |
1911 | spin_unlock(&tcon->tc_lock); | |
b327a717 AA |
1912 | ses->tcon_ipc = tcon; |
1913 | out: | |
b327a717 AA |
1914 | return rc; |
1915 | } | |
1916 | ||
1917 | /** | |
1918 | * cifs_free_ipc - helper to release the session IPC tcon | |
4c51de1e | 1919 | * @ses: smb session to unmount the IPC from |
b327a717 | 1920 | * |
f3191fc8 PA |
1921 | * Needs to be called everytime a session is destroyed. |
1922 | * | |
1923 | * On session close, the IPC is closed and the server must release all tcons of the session. | |
1924 | * No need to send a tree disconnect here. | |
1925 | * | |
1926 | * Besides, it will make the server to not close durable and resilient files on session close, as | |
1927 | * specified in MS-SMB2 3.3.5.6 Receiving an SMB2 LOGOFF Request. | |
b327a717 AA |
1928 | */ |
1929 | static int | |
1930 | cifs_free_ipc(struct cifs_ses *ses) | |
1931 | { | |
b327a717 AA |
1932 | struct cifs_tcon *tcon = ses->tcon_ipc; |
1933 | ||
1934 | if (tcon == NULL) | |
1935 | return 0; | |
1936 | ||
b327a717 AA |
1937 | tconInfoFree(tcon); |
1938 | ses->tcon_ipc = NULL; | |
f3191fc8 | 1939 | return 0; |
b327a717 AA |
1940 | } |
1941 | ||
96daf2b0 | 1942 | static struct cifs_ses * |
3fa1c6d1 | 1943 | cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) |
1da177e4 | 1944 | { |
8e355415 | 1945 | struct cifs_ses *ses, *ret = NULL; |
dea570e0 | 1946 | |
3f9bcca7 | 1947 | spin_lock(&cifs_tcp_ses_lock); |
4ff67b72 | 1948 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { |
d7d7a66a SP |
1949 | spin_lock(&ses->ses_lock); |
1950 | if (ses->ses_status == SES_EXITING) { | |
1951 | spin_unlock(&ses->ses_lock); | |
7f48558e | 1952 | continue; |
d7d7a66a | 1953 | } |
2f4e429c | 1954 | spin_lock(&ses->chan_lock); |
8e355415 | 1955 | if (match_session(ses, ctx)) { |
2f4e429c | 1956 | spin_unlock(&ses->chan_lock); |
d7d7a66a | 1957 | spin_unlock(&ses->ses_lock); |
8e355415 PA |
1958 | ret = ses; |
1959 | break; | |
d7d7a66a | 1960 | } |
2f4e429c | 1961 | spin_unlock(&ses->chan_lock); |
d7d7a66a | 1962 | spin_unlock(&ses->ses_lock); |
14fbf50d | 1963 | } |
8e355415 PA |
1964 | if (ret) |
1965 | cifs_smb_ses_inc_refcount(ret); | |
3f9bcca7 | 1966 | spin_unlock(&cifs_tcp_ses_lock); |
8e355415 | 1967 | return ret; |
14fbf50d | 1968 | } |
dea570e0 | 1969 | |
8e355415 | 1970 | void __cifs_put_smb_ses(struct cifs_ses *ses) |
14fbf50d | 1971 | { |
7f48558e | 1972 | unsigned int rc, xid; |
724244cd | 1973 | unsigned int chan_count; |
14fbf50d | 1974 | struct TCP_Server_Info *server = ses->server; |
7f48558e | 1975 | |
d7d7a66a | 1976 | spin_lock(&ses->ses_lock); |
dd3cd870 | 1977 | if (ses->ses_status == SES_EXITING) { |
d7d7a66a | 1978 | spin_unlock(&ses->ses_lock); |
7f48558e SP |
1979 | return; |
1980 | } | |
d7d7a66a | 1981 | spin_unlock(&ses->ses_lock); |
c9f71103 PA |
1982 | |
1983 | cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count); | |
68e14569 SF |
1984 | cifs_dbg(FYI, |
1985 | "%s: ses ipc: %s\n", __func__, ses->tcon_ipc ? ses->tcon_ipc->tree_name : "NONE"); | |
c9f71103 | 1986 | |
d7d7a66a | 1987 | spin_lock(&cifs_tcp_ses_lock); |
14fbf50d | 1988 | if (--ses->ses_count > 0) { |
3f9bcca7 | 1989 | spin_unlock(&cifs_tcp_ses_lock); |
14fbf50d JL |
1990 | return; |
1991 | } | |
ff7d80a9 WW |
1992 | spin_lock(&ses->ses_lock); |
1993 | if (ses->ses_status == SES_GOOD) | |
1994 | ses->ses_status = SES_EXITING; | |
1995 | spin_unlock(&ses->ses_lock); | |
d7d7a66a | 1996 | spin_unlock(&cifs_tcp_ses_lock); |
0060a4f2 | 1997 | |
16dd9b8c SP |
1998 | /* ses_count can never go negative */ |
1999 | WARN_ON(ses->ses_count < 0); | |
2000 | ||
943fb67b | 2001 | spin_lock(&ses->ses_lock); |
dd3cd870 | 2002 | if (ses->ses_status == SES_EXITING && server->ops->logoff) { |
943fb67b SF |
2003 | spin_unlock(&ses->ses_lock); |
2004 | cifs_free_ipc(ses); | |
6d5786a3 | 2005 | xid = get_xid(); |
7f48558e SP |
2006 | rc = server->ops->logoff(xid, ses); |
2007 | if (rc) | |
afe6f653 | 2008 | cifs_server_dbg(VFS, "%s: Session Logoff failure rc=%d\n", |
7f48558e | 2009 | __func__, rc); |
6d5786a3 | 2010 | _free_xid(xid); |
943fb67b SF |
2011 | } else { |
2012 | spin_unlock(&ses->ses_lock); | |
2013 | cifs_free_ipc(ses); | |
14fbf50d | 2014 | } |
7f48558e SP |
2015 | |
2016 | spin_lock(&cifs_tcp_ses_lock); | |
2017 | list_del_init(&ses->smb_ses_list); | |
2018 | spin_unlock(&cifs_tcp_ses_lock); | |
2019 | ||
724244cd | 2020 | chan_count = ses->chan_count; |
724244cd | 2021 | |
d70e9fa5 | 2022 | /* close any extra channels */ |
724244cd | 2023 | if (chan_count > 1) { |
d70e9fa5 AA |
2024 | int i; |
2025 | ||
724244cd | 2026 | for (i = 1; i < chan_count; i++) { |
aa45dadd SP |
2027 | if (ses->chans[i].iface) { |
2028 | kref_put(&ses->chans[i].iface->refcount, release_iface); | |
2029 | ses->chans[i].iface = NULL; | |
2030 | } | |
d70e9fa5 | 2031 | cifs_put_tcp_session(ses->chans[i].server, 0); |
724244cd SP |
2032 | ses->chans[i].server = NULL; |
2033 | } | |
d70e9fa5 AA |
2034 | } |
2035 | ||
14fbf50d | 2036 | sesInfoFree(ses); |
53e0e11e | 2037 | cifs_put_tcp_session(server, 0); |
14fbf50d | 2038 | } |
dea570e0 | 2039 | |
8a8798a5 JL |
2040 | #ifdef CONFIG_KEYS |
2041 | ||
057d6332 CG |
2042 | /* strlen("cifs:a:") + CIFS_MAX_DOMAINNAME_LEN + 1 */ |
2043 | #define CIFSCREDS_DESC_SIZE (7 + CIFS_MAX_DOMAINNAME_LEN + 1) | |
8a8798a5 JL |
2044 | |
2045 | /* Populate username and pw fields from keyring if possible */ | |
2046 | static int | |
3fa1c6d1 | 2047 | cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses) |
8a8798a5 JL |
2048 | { |
2049 | int rc = 0; | |
f2aee329 | 2050 | int is_domain = 0; |
146aa8b1 DH |
2051 | const char *delim, *payload; |
2052 | char *desc; | |
8a8798a5 JL |
2053 | ssize_t len; |
2054 | struct key *key; | |
2055 | struct TCP_Server_Info *server = ses->server; | |
2056 | struct sockaddr_in *sa; | |
2057 | struct sockaddr_in6 *sa6; | |
146aa8b1 | 2058 | const struct user_key_payload *upayload; |
8a8798a5 JL |
2059 | |
2060 | desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL); | |
2061 | if (!desc) | |
2062 | return -ENOMEM; | |
2063 | ||
2064 | /* try to find an address key first */ | |
2065 | switch (server->dstaddr.ss_family) { | |
2066 | case AF_INET: | |
2067 | sa = (struct sockaddr_in *)&server->dstaddr; | |
2068 | sprintf(desc, "cifs:a:%pI4", &sa->sin_addr.s_addr); | |
2069 | break; | |
2070 | case AF_INET6: | |
2071 | sa6 = (struct sockaddr_in6 *)&server->dstaddr; | |
2072 | sprintf(desc, "cifs:a:%pI6c", &sa6->sin6_addr.s6_addr); | |
2073 | break; | |
2074 | default: | |
f96637be JP |
2075 | cifs_dbg(FYI, "Bad ss_family (%hu)\n", |
2076 | server->dstaddr.ss_family); | |
8a8798a5 JL |
2077 | rc = -EINVAL; |
2078 | goto out_err; | |
2079 | } | |
2080 | ||
f96637be | 2081 | cifs_dbg(FYI, "%s: desc=%s\n", __func__, desc); |
028db3e2 | 2082 | key = request_key(&key_type_logon, desc, ""); |
8a8798a5 JL |
2083 | if (IS_ERR(key)) { |
2084 | if (!ses->domainName) { | |
f96637be | 2085 | cifs_dbg(FYI, "domainName is NULL\n"); |
8a8798a5 JL |
2086 | rc = PTR_ERR(key); |
2087 | goto out_err; | |
2088 | } | |
2089 | ||
2090 | /* didn't work, try to find a domain key */ | |
2091 | sprintf(desc, "cifs:d:%s", ses->domainName); | |
f96637be | 2092 | cifs_dbg(FYI, "%s: desc=%s\n", __func__, desc); |
028db3e2 | 2093 | key = request_key(&key_type_logon, desc, ""); |
8a8798a5 JL |
2094 | if (IS_ERR(key)) { |
2095 | rc = PTR_ERR(key); | |
2096 | goto out_err; | |
2097 | } | |
f2aee329 | 2098 | is_domain = 1; |
8a8798a5 JL |
2099 | } |
2100 | ||
2101 | down_read(&key->sem); | |
0837e49a | 2102 | upayload = user_key_payload_locked(key); |
8a8798a5 | 2103 | if (IS_ERR_OR_NULL(upayload)) { |
4edc53c1 | 2104 | rc = upayload ? PTR_ERR(upayload) : -EINVAL; |
8a8798a5 JL |
2105 | goto out_key_put; |
2106 | } | |
2107 | ||
2108 | /* find first : in payload */ | |
146aa8b1 | 2109 | payload = upayload->data; |
8a8798a5 | 2110 | delim = strnchr(payload, upayload->datalen, ':'); |
f96637be | 2111 | cifs_dbg(FYI, "payload=%s\n", payload); |
8a8798a5 | 2112 | if (!delim) { |
f96637be JP |
2113 | cifs_dbg(FYI, "Unable to find ':' in payload (datalen=%d)\n", |
2114 | upayload->datalen); | |
8a8798a5 JL |
2115 | rc = -EINVAL; |
2116 | goto out_key_put; | |
2117 | } | |
2118 | ||
2119 | len = delim - payload; | |
8c3a2b4c | 2120 | if (len > CIFS_MAX_USERNAME_LEN || len <= 0) { |
f96637be JP |
2121 | cifs_dbg(FYI, "Bad value from username search (len=%zd)\n", |
2122 | len); | |
8a8798a5 JL |
2123 | rc = -EINVAL; |
2124 | goto out_key_put; | |
2125 | } | |
2126 | ||
3fa1c6d1 RS |
2127 | ctx->username = kstrndup(payload, len, GFP_KERNEL); |
2128 | if (!ctx->username) { | |
f96637be JP |
2129 | cifs_dbg(FYI, "Unable to allocate %zd bytes for username\n", |
2130 | len); | |
8a8798a5 JL |
2131 | rc = -ENOMEM; |
2132 | goto out_key_put; | |
2133 | } | |
3fa1c6d1 | 2134 | cifs_dbg(FYI, "%s: username=%s\n", __func__, ctx->username); |
8a8798a5 JL |
2135 | |
2136 | len = key->datalen - (len + 1); | |
8c3a2b4c | 2137 | if (len > CIFS_MAX_PASSWORD_LEN || len <= 0) { |
f96637be | 2138 | cifs_dbg(FYI, "Bad len for password search (len=%zd)\n", len); |
8a8798a5 | 2139 | rc = -EINVAL; |
3fa1c6d1 RS |
2140 | kfree(ctx->username); |
2141 | ctx->username = NULL; | |
8a8798a5 JL |
2142 | goto out_key_put; |
2143 | } | |
2144 | ||
2145 | ++delim; | |
3fa1c6d1 RS |
2146 | ctx->password = kstrndup(delim, len, GFP_KERNEL); |
2147 | if (!ctx->password) { | |
f96637be JP |
2148 | cifs_dbg(FYI, "Unable to allocate %zd bytes for password\n", |
2149 | len); | |
8a8798a5 | 2150 | rc = -ENOMEM; |
3fa1c6d1 RS |
2151 | kfree(ctx->username); |
2152 | ctx->username = NULL; | |
8a8798a5 JL |
2153 | goto out_key_put; |
2154 | } | |
2155 | ||
f2aee329 RS |
2156 | /* |
2157 | * If we have a domain key then we must set the domainName in the | |
2158 | * for the request. | |
2159 | */ | |
2160 | if (is_domain && ses->domainName) { | |
8d767223 | 2161 | ctx->domainname = kstrdup(ses->domainName, GFP_KERNEL); |
3fa1c6d1 | 2162 | if (!ctx->domainname) { |
a0a3036b JP |
2163 | cifs_dbg(FYI, "Unable to allocate %zd bytes for domain\n", |
2164 | len); | |
f2aee329 | 2165 | rc = -ENOMEM; |
3fa1c6d1 RS |
2166 | kfree(ctx->username); |
2167 | ctx->username = NULL; | |
2168 | kfree_sensitive(ctx->password); | |
2169 | ctx->password = NULL; | |
f2aee329 RS |
2170 | goto out_key_put; |
2171 | } | |
2172 | } | |
2173 | ||
de3a9e94 | 2174 | strscpy(ctx->workstation_name, ses->workstation_name, sizeof(ctx->workstation_name)); |
d3b331fb | 2175 | |
8a8798a5 JL |
2176 | out_key_put: |
2177 | up_read(&key->sem); | |
2178 | key_put(key); | |
2179 | out_err: | |
2180 | kfree(desc); | |
f96637be | 2181 | cifs_dbg(FYI, "%s: returning %d\n", __func__, rc); |
8a8798a5 JL |
2182 | return rc; |
2183 | } | |
2184 | #else /* ! CONFIG_KEYS */ | |
2185 | static inline int | |
3fa1c6d1 | 2186 | cifs_set_cifscreds(struct smb3_fs_context *ctx __attribute__((unused)), |
8a8798a5 JL |
2187 | struct cifs_ses *ses __attribute__((unused))) |
2188 | { | |
2189 | return -ENOSYS; | |
2190 | } | |
2191 | #endif /* CONFIG_KEYS */ | |
2192 | ||
4a1360d0 | 2193 | /** |
3fa1c6d1 | 2194 | * cifs_get_smb_ses - get a session matching @ctx data from @server |
4c51de1e SF |
2195 | * @server: server to setup the session to |
2196 | * @ctx: superblock configuration context to use to setup the session | |
4a1360d0 AA |
2197 | * |
2198 | * This function assumes it is being called from cifs_mount() where we | |
2199 | * already got a server reference (server refcount +1). See | |
2200 | * cifs_get_tcon() for refcount explanations. | |
2201 | */ | |
5072010c | 2202 | struct cifs_ses * |
3fa1c6d1 | 2203 | cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) |
36988c76 | 2204 | { |
a85ceafd | 2205 | int rc = 0; |
286170aa | 2206 | unsigned int xid; |
96daf2b0 | 2207 | struct cifs_ses *ses; |
a9f1b85e PS |
2208 | struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; |
2209 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; | |
36988c76 | 2210 | |
6d5786a3 | 2211 | xid = get_xid(); |
36988c76 | 2212 | |
3fa1c6d1 | 2213 | ses = cifs_find_smb_ses(server, ctx); |
36988c76 | 2214 | if (ses) { |
f96637be | 2215 | cifs_dbg(FYI, "Existing smb sess found (status=%d)\n", |
dd3cd870 | 2216 | ses->ses_status); |
36988c76 | 2217 | |
d1a931ce SP |
2218 | spin_lock(&ses->chan_lock); |
2219 | if (cifs_chan_needs_reconnect(ses, server)) { | |
2220 | spin_unlock(&ses->chan_lock); | |
f96637be | 2221 | cifs_dbg(FYI, "Session needs reconnect\n"); |
8e07757b | 2222 | |
73f9bfbe | 2223 | mutex_lock(&ses->session_mutex); |
f486ef8e | 2224 | rc = cifs_negotiate_protocol(xid, ses, server); |
8e07757b SP |
2225 | if (rc) { |
2226 | mutex_unlock(&ses->session_mutex); | |
2227 | /* problem -- put our ses reference */ | |
2228 | cifs_put_smb_ses(ses); | |
2229 | free_xid(xid); | |
2230 | return ERR_PTR(rc); | |
2231 | } | |
2232 | ||
f486ef8e | 2233 | rc = cifs_setup_session(xid, ses, server, |
3fa1c6d1 | 2234 | ctx->local_nls); |
36988c76 JL |
2235 | if (rc) { |
2236 | mutex_unlock(&ses->session_mutex); | |
2237 | /* problem -- put our reference */ | |
2238 | cifs_put_smb_ses(ses); | |
6d5786a3 | 2239 | free_xid(xid); |
36988c76 JL |
2240 | return ERR_PTR(rc); |
2241 | } | |
73f9bfbe SP |
2242 | mutex_unlock(&ses->session_mutex); |
2243 | ||
d1a931ce | 2244 | spin_lock(&ses->chan_lock); |
36988c76 | 2245 | } |
d1a931ce | 2246 | spin_unlock(&ses->chan_lock); |
460cf341 JL |
2247 | |
2248 | /* existing SMB ses has a server reference already */ | |
53e0e11e | 2249 | cifs_put_tcp_session(server, 0); |
6d5786a3 | 2250 | free_xid(xid); |
36988c76 JL |
2251 | return ses; |
2252 | } | |
2253 | ||
a85ceafd PA |
2254 | rc = -ENOMEM; |
2255 | ||
f96637be | 2256 | cifs_dbg(FYI, "Existing smb sess not found\n"); |
36988c76 JL |
2257 | ses = sesInfoAlloc(); |
2258 | if (ses == NULL) | |
2259 | goto get_ses_fail; | |
2260 | ||
2261 | /* new SMB session uses our server ref */ | |
2262 | ses->server = server; | |
a9f1b85e | 2263 | if (server->dstaddr.ss_family == AF_INET6) |
b438fcf1 | 2264 | sprintf(ses->ip_addr, "%pI6", &addr6->sin6_addr); |
36988c76 | 2265 | else |
b438fcf1 | 2266 | sprintf(ses->ip_addr, "%pI4", &addr->sin_addr); |
36988c76 | 2267 | |
3fa1c6d1 RS |
2268 | if (ctx->username) { |
2269 | ses->user_name = kstrdup(ctx->username, GFP_KERNEL); | |
8727c8a8 SF |
2270 | if (!ses->user_name) |
2271 | goto get_ses_fail; | |
2272 | } | |
36988c76 | 2273 | |
3fa1c6d1 RS |
2274 | /* ctx->password freed at unmount */ |
2275 | if (ctx->password) { | |
2276 | ses->password = kstrdup(ctx->password, GFP_KERNEL); | |
36988c76 JL |
2277 | if (!ses->password) |
2278 | goto get_ses_fail; | |
2279 | } | |
3fa1c6d1 RS |
2280 | if (ctx->domainname) { |
2281 | ses->domainName = kstrdup(ctx->domainname, GFP_KERNEL); | |
d3686d54 SP |
2282 | if (!ses->domainName) |
2283 | goto get_ses_fail; | |
36988c76 | 2284 | } |
de3a9e94 PA |
2285 | |
2286 | strscpy(ses->workstation_name, ctx->workstation_name, sizeof(ses->workstation_name)); | |
2287 | ||
3fa1c6d1 RS |
2288 | if (ctx->domainauto) |
2289 | ses->domainAuto = ctx->domainauto; | |
2290 | ses->cred_uid = ctx->cred_uid; | |
2291 | ses->linux_uid = ctx->linux_uid; | |
d9b94201 | 2292 | |
3fa1c6d1 RS |
2293 | ses->sectype = ctx->sectype; |
2294 | ses->sign = ctx->sign; | |
a43f95fd | 2295 | ses->local_nls = load_nls(ctx->local_nls->charset); |
d70e9fa5 AA |
2296 | |
2297 | /* add server as first channel */ | |
724244cd | 2298 | spin_lock(&ses->chan_lock); |
d70e9fa5 AA |
2299 | ses->chans[0].server = server; |
2300 | ses->chan_count = 1; | |
3fa1c6d1 | 2301 | ses->chan_max = ctx->multichannel ? ctx->max_channels:1; |
d1a931ce | 2302 | ses->chans_need_reconnect = 1; |
724244cd | 2303 | spin_unlock(&ses->chan_lock); |
d70e9fa5 | 2304 | |
73f9bfbe | 2305 | mutex_lock(&ses->session_mutex); |
f486ef8e | 2306 | rc = cifs_negotiate_protocol(xid, ses, server); |
198b5682 | 2307 | if (!rc) |
f486ef8e | 2308 | rc = cifs_setup_session(xid, ses, server, ctx->local_nls); |
73f9bfbe | 2309 | mutex_unlock(&ses->session_mutex); |
d70e9fa5 AA |
2310 | |
2311 | /* each channel uses a different signing key */ | |
88b024f5 | 2312 | spin_lock(&ses->chan_lock); |
d70e9fa5 AA |
2313 | memcpy(ses->chans[0].signkey, ses->smb3signingkey, |
2314 | sizeof(ses->smb3signingkey)); | |
88b024f5 | 2315 | spin_unlock(&ses->chan_lock); |
d70e9fa5 | 2316 | |
c8e56f1f | 2317 | if (rc) |
36988c76 JL |
2318 | goto get_ses_fail; |
2319 | ||
d1a931ce SP |
2320 | /* |
2321 | * success, put it on the list and add it as first channel | |
2322 | * note: the session becomes active soon after this. So you'll | |
2323 | * need to lock before changing something in the session. | |
2324 | */ | |
3f9bcca7 | 2325 | spin_lock(&cifs_tcp_ses_lock); |
b56bce50 | 2326 | ses->dfs_root_ses = ctx->dfs_root_ses; |
8e355415 PA |
2327 | if (ses->dfs_root_ses) |
2328 | ses->dfs_root_ses->ses_count++; | |
36988c76 | 2329 | list_add(&ses->smb_ses_list, &server->smb_ses_list); |
3f9bcca7 | 2330 | spin_unlock(&cifs_tcp_ses_lock); |
36988c76 | 2331 | |
3fa1c6d1 | 2332 | cifs_setup_ipc(ses, ctx); |
b327a717 | 2333 | |
86fe0fa8 PA |
2334 | free_xid(xid); |
2335 | ||
36988c76 JL |
2336 | return ses; |
2337 | ||
2338 | get_ses_fail: | |
2339 | sesInfoFree(ses); | |
6d5786a3 | 2340 | free_xid(xid); |
36988c76 JL |
2341 | return ERR_PTR(rc); |
2342 | } | |
2343 | ||
d7d7a66a | 2344 | /* this function must be called with tc_lock held */ |
8e355415 | 2345 | static int match_tcon(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) |
37bb04e5 | 2346 | { |
8e355415 PA |
2347 | struct TCP_Server_Info *server = tcon->ses->server; |
2348 | ||
fdf59eb5 | 2349 | if (tcon->status == TID_EXITING) |
37bb04e5 | 2350 | return 0; |
3ae872de PA |
2351 | |
2352 | if (tcon->origin_fullpath) { | |
2353 | if (!ctx->source || | |
2354 | !dfs_src_pathname_equal(ctx->source, | |
2355 | tcon->origin_fullpath)) | |
2356 | return 0; | |
2357 | } else if (!server->leaf_fullpath && | |
2358 | strncmp(tcon->tree_name, ctx->UNC, MAX_TREE_SIZE)) { | |
37bb04e5 | 2359 | return 0; |
3ae872de | 2360 | } |
3fa1c6d1 | 2361 | if (tcon->seal != ctx->seal) |
ae6f8dd4 | 2362 | return 0; |
3fa1c6d1 | 2363 | if (tcon->snapshot_time != ctx->snapshot_time) |
ae6f8dd4 | 2364 | return 0; |
3fa1c6d1 | 2365 | if (tcon->handle_timeout != ctx->handle_timeout) |
ca567eb2 | 2366 | return 0; |
3fa1c6d1 | 2367 | if (tcon->no_lease != ctx->no_lease) |
3e7a02d4 | 2368 | return 0; |
3fa1c6d1 | 2369 | if (tcon->nodelete != ctx->nodelete) |
82e9367c | 2370 | return 0; |
37bb04e5 PS |
2371 | return 1; |
2372 | } | |
2373 | ||
96daf2b0 | 2374 | static struct cifs_tcon * |
3fa1c6d1 | 2375 | cifs_find_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) |
f1987b44 | 2376 | { |
96daf2b0 | 2377 | struct cifs_tcon *tcon; |
f1987b44 | 2378 | |
3f9bcca7 | 2379 | spin_lock(&cifs_tcp_ses_lock); |
9543c8ab | 2380 | list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { |
d7d7a66a | 2381 | spin_lock(&tcon->tc_lock); |
8e355415 | 2382 | if (!match_tcon(tcon, ctx)) { |
d7d7a66a | 2383 | spin_unlock(&tcon->tc_lock); |
f1987b44 | 2384 | continue; |
d7d7a66a | 2385 | } |
f1987b44 | 2386 | ++tcon->tc_count; |
d7d7a66a | 2387 | spin_unlock(&tcon->tc_lock); |
3f9bcca7 | 2388 | spin_unlock(&cifs_tcp_ses_lock); |
dea570e0 | 2389 | return tcon; |
1da177e4 | 2390 | } |
3f9bcca7 | 2391 | spin_unlock(&cifs_tcp_ses_lock); |
1da177e4 LT |
2392 | return NULL; |
2393 | } | |
2394 | ||
53e0e11e | 2395 | void |
96daf2b0 | 2396 | cifs_put_tcon(struct cifs_tcon *tcon) |
f1987b44 | 2397 | { |
2e6e02ab | 2398 | unsigned int xid; |
b327a717 | 2399 | struct cifs_ses *ses; |
f1987b44 | 2400 | |
b327a717 AA |
2401 | /* |
2402 | * IPC tcon share the lifetime of their session and are | |
2403 | * destroyed in the session put function | |
2404 | */ | |
2405 | if (tcon == NULL || tcon->ipc) | |
2406 | return; | |
2407 | ||
2408 | ses = tcon->ses; | |
f96637be | 2409 | cifs_dbg(FYI, "%s: tc_count=%d\n", __func__, tcon->tc_count); |
3f9bcca7 | 2410 | spin_lock(&cifs_tcp_ses_lock); |
621a41ae | 2411 | spin_lock(&tcon->tc_lock); |
f1987b44 | 2412 | if (--tcon->tc_count > 0) { |
621a41ae | 2413 | spin_unlock(&tcon->tc_lock); |
3f9bcca7 | 2414 | spin_unlock(&cifs_tcp_ses_lock); |
f1987b44 JL |
2415 | return; |
2416 | } | |
2417 | ||
16dd9b8c SP |
2418 | /* tc_count can never go negative */ |
2419 | WARN_ON(tcon->tc_count < 0); | |
2420 | ||
d1a931ce | 2421 | list_del_init(&tcon->tcon_list); |
491eafce | 2422 | tcon->status = TID_EXITING; |
621a41ae | 2423 | spin_unlock(&tcon->tc_lock); |
d1a931ce SP |
2424 | spin_unlock(&cifs_tcp_ses_lock); |
2425 | ||
6e1c1c08 SP |
2426 | /* cancel polling of interfaces */ |
2427 | cancel_delayed_work_sync(&tcon->query_interfaces); | |
6be2ea33 PA |
2428 | #ifdef CONFIG_CIFS_DFS_UPCALL |
2429 | cancel_delayed_work_sync(&tcon->dfs_cache_work); | |
2430 | #endif | |
6e1c1c08 | 2431 | |
bf80e5d4 SC |
2432 | if (tcon->use_witness) { |
2433 | int rc; | |
2434 | ||
2435 | rc = cifs_swn_unregister(tcon); | |
2436 | if (rc < 0) { | |
2437 | cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n", | |
2438 | __func__, rc); | |
2439 | } | |
2440 | } | |
0ac4e291 | 2441 | |
6d5786a3 | 2442 | xid = get_xid(); |
2e6e02ab PS |
2443 | if (ses->server->ops->tree_disconnect) |
2444 | ses->server->ops->tree_disconnect(xid, tcon); | |
6d5786a3 | 2445 | _free_xid(xid); |
f1987b44 | 2446 | |
d03382ce | 2447 | cifs_fscache_release_super_cookie(tcon); |
9f841593 | 2448 | tconInfoFree(tcon); |
f1987b44 JL |
2449 | cifs_put_smb_ses(ses); |
2450 | } | |
2451 | ||
4a1360d0 | 2452 | /** |
3fa1c6d1 | 2453 | * cifs_get_tcon - get a tcon matching @ctx data from @ses |
4c51de1e SF |
2454 | * @ses: smb session to issue the request on |
2455 | * @ctx: the superblock configuration context to use for building the | |
4a1360d0 AA |
2456 | * |
2457 | * - tcon refcount is the number of mount points using the tcon. | |
2458 | * - ses refcount is the number of tcon using the session. | |
2459 | * | |
2460 | * 1. This function assumes it is being called from cifs_mount() where | |
2461 | * we already got a session reference (ses refcount +1). | |
2462 | * | |
2463 | * 2. Since we're in the context of adding a mount point, the end | |
2464 | * result should be either: | |
2465 | * | |
2466 | * a) a new tcon already allocated with refcount=1 (1 mount point) and | |
2467 | * its session refcount incremented (1 new tcon). This +1 was | |
2468 | * already done in (1). | |
2469 | * | |
2470 | * b) an existing tcon with refcount+1 (add a mount point to it) and | |
2471 | * identical ses refcount (no new tcon). Because of (1) we need to | |
2472 | * decrement the ses refcount. | |
2473 | */ | |
96daf2b0 | 2474 | static struct cifs_tcon * |
3fa1c6d1 | 2475 | cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) |
d00c28de | 2476 | { |
96daf2b0 | 2477 | struct cifs_tcon *tcon; |
3b8bb317 PA |
2478 | bool nohandlecache; |
2479 | int rc, xid; | |
d00c28de | 2480 | |
3fa1c6d1 | 2481 | tcon = cifs_find_tcon(ses, ctx); |
d00c28de | 2482 | if (tcon) { |
4a1360d0 AA |
2483 | /* |
2484 | * tcon has refcount already incremented but we need to | |
2485 | * decrement extra ses reference gotten by caller (case b) | |
2486 | */ | |
f96637be | 2487 | cifs_dbg(FYI, "Found match on UNC path\n"); |
d00c28de | 2488 | cifs_put_smb_ses(ses); |
d00c28de JL |
2489 | return tcon; |
2490 | } | |
2491 | ||
2e6e02ab PS |
2492 | if (!ses->server->ops->tree_connect) { |
2493 | rc = -ENOSYS; | |
2494 | goto out_fail; | |
2495 | } | |
2496 | ||
3b8bb317 PA |
2497 | if (ses->server->dialect >= SMB20_PROT_ID && |
2498 | (ses->server->capabilities & SMB2_GLOBAL_CAP_DIRECTORY_LEASING)) | |
2499 | nohandlecache = ctx->nohandlecache; | |
2da338ff | 2500 | else |
3b8bb317 PA |
2501 | nohandlecache = true; |
2502 | tcon = tcon_info_alloc(!nohandlecache); | |
d00c28de JL |
2503 | if (tcon == NULL) { |
2504 | rc = -ENOMEM; | |
2505 | goto out_fail; | |
2506 | } | |
3b8bb317 | 2507 | tcon->nohandlecache = nohandlecache; |
d00c28de | 2508 | |
3fa1c6d1 | 2509 | if (ctx->snapshot_time) { |
8b217fe7 SF |
2510 | if (ses->server->vals->protocol_id == 0) { |
2511 | cifs_dbg(VFS, | |
2512 | "Use SMB2 or later for snapshot mount option\n"); | |
2513 | rc = -EOPNOTSUPP; | |
2514 | goto out_fail; | |
2515 | } else | |
3fa1c6d1 | 2516 | tcon->snapshot_time = ctx->snapshot_time; |
8b217fe7 SF |
2517 | } |
2518 | ||
3fa1c6d1 | 2519 | if (ctx->handle_timeout) { |
ca567eb2 SF |
2520 | if (ses->server->vals->protocol_id == 0) { |
2521 | cifs_dbg(VFS, | |
2522 | "Use SMB2.1 or later for handle timeout option\n"); | |
2523 | rc = -EOPNOTSUPP; | |
2524 | goto out_fail; | |
2525 | } else | |
3fa1c6d1 | 2526 | tcon->handle_timeout = ctx->handle_timeout; |
ca567eb2 SF |
2527 | } |
2528 | ||
d00c28de | 2529 | tcon->ses = ses; |
3fa1c6d1 RS |
2530 | if (ctx->password) { |
2531 | tcon->password = kstrdup(ctx->password, GFP_KERNEL); | |
d00c28de JL |
2532 | if (!tcon->password) { |
2533 | rc = -ENOMEM; | |
2534 | goto out_fail; | |
2535 | } | |
2536 | } | |
2537 | ||
3fa1c6d1 | 2538 | if (ctx->seal) { |
23657ad7 SF |
2539 | if (ses->server->vals->protocol_id == 0) { |
2540 | cifs_dbg(VFS, | |
2541 | "SMB3 or later required for encryption\n"); | |
2542 | rc = -EOPNOTSUPP; | |
2543 | goto out_fail; | |
2544 | } else if (tcon->ses->server->capabilities & | |
2545 | SMB2_GLOBAL_CAP_ENCRYPTION) | |
2546 | tcon->seal = true; | |
2547 | else { | |
2548 | cifs_dbg(VFS, "Encryption is not supported on share\n"); | |
2549 | rc = -EOPNOTSUPP; | |
2550 | goto out_fail; | |
2551 | } | |
2552 | } | |
2553 | ||
3fa1c6d1 | 2554 | if (ctx->linux_ext) { |
8505c8bf | 2555 | if (ses->server->posix_ext_supported) { |
b326614e | 2556 | tcon->posix_extensions = true; |
a0a3036b | 2557 | pr_warn_once("SMB3.11 POSIX Extensions are experimental\n"); |
d0cbe56a SF |
2558 | } else if ((ses->server->vals->protocol_id == SMB311_PROT_ID) || |
2559 | (strcmp(ses->server->vals->version_string, | |
2560 | SMB3ANY_VERSION_STRING) == 0) || | |
2561 | (strcmp(ses->server->vals->version_string, | |
2562 | SMBDEFAULT_VERSION_STRING) == 0)) { | |
a0a3036b | 2563 | cifs_dbg(VFS, "Server does not support mounting with posix SMB3.11 extensions\n"); |
8505c8bf SF |
2564 | rc = -EOPNOTSUPP; |
2565 | goto out_fail; | |
d0cbe56a SF |
2566 | } else { |
2567 | cifs_dbg(VFS, "Check vers= mount option. SMB3.11 " | |
2568 | "disabled but required for POSIX extensions\n"); | |
2569 | rc = -EOPNOTSUPP; | |
2570 | goto out_fail; | |
2fbb5644 | 2571 | } |
b326614e | 2572 | } |
b326614e | 2573 | |
6d5786a3 | 2574 | xid = get_xid(); |
3fa1c6d1 RS |
2575 | rc = ses->server->ops->tree_connect(xid, ses, ctx->UNC, tcon, |
2576 | ctx->local_nls); | |
6d5786a3 | 2577 | free_xid(xid); |
f96637be | 2578 | cifs_dbg(FYI, "Tcon rc = %d\n", rc); |
d00c28de JL |
2579 | if (rc) |
2580 | goto out_fail; | |
2581 | ||
b618f001 SF |
2582 | tcon->use_persistent = false; |
2583 | /* check if SMB2 or later, CIFS does not support persistent handles */ | |
3fa1c6d1 | 2584 | if (ctx->persistent) { |
b618f001 SF |
2585 | if (ses->server->vals->protocol_id == 0) { |
2586 | cifs_dbg(VFS, | |
2587 | "SMB3 or later required for persistent handles\n"); | |
2588 | rc = -EOPNOTSUPP; | |
2589 | goto out_fail; | |
2590 | } else if (ses->server->capabilities & | |
2591 | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES) | |
2592 | tcon->use_persistent = true; | |
2593 | else /* persistent handles requested but not supported */ { | |
2594 | cifs_dbg(VFS, | |
2595 | "Persistent handles not supported on share\n"); | |
2596 | rc = -EOPNOTSUPP; | |
2597 | goto out_fail; | |
2598 | } | |
2599 | } else if ((tcon->capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY) | |
2600 | && (ses->server->capabilities & SMB2_GLOBAL_CAP_PERSISTENT_HANDLES) | |
3fa1c6d1 | 2601 | && (ctx->nopersistent == false)) { |
b618f001 SF |
2602 | cifs_dbg(FYI, "enabling persistent handles\n"); |
2603 | tcon->use_persistent = true; | |
3fa1c6d1 | 2604 | } else if (ctx->resilient) { |
592fafe6 SF |
2605 | if (ses->server->vals->protocol_id == 0) { |
2606 | cifs_dbg(VFS, | |
2607 | "SMB2.1 or later required for resilient handles\n"); | |
2608 | rc = -EOPNOTSUPP; | |
2609 | goto out_fail; | |
2610 | } | |
2611 | tcon->use_resilient = true; | |
b618f001 | 2612 | } |
b7fd0fa0 | 2613 | |
0ac4e291 | 2614 | tcon->use_witness = false; |
b7fd0fa0 | 2615 | if (IS_ENABLED(CONFIG_CIFS_SWN_UPCALL) && ctx->witness) { |
0ac4e291 SC |
2616 | if (ses->server->vals->protocol_id >= SMB30_PROT_ID) { |
2617 | if (tcon->capabilities & SMB2_SHARE_CAP_CLUSTER) { | |
bf80e5d4 SC |
2618 | /* |
2619 | * Set witness in use flag in first place | |
2620 | * to retry registration in the echo task | |
2621 | */ | |
0ac4e291 | 2622 | tcon->use_witness = true; |
bf80e5d4 SC |
2623 | /* And try to register immediately */ |
2624 | rc = cifs_swn_register(tcon); | |
2625 | if (rc < 0) { | |
2626 | cifs_dbg(VFS, "Failed to register for witness notifications: %d\n", rc); | |
2627 | goto out_fail; | |
2628 | } | |
0ac4e291 SC |
2629 | } else { |
2630 | /* TODO: try to extend for non-cluster uses (eg multichannel) */ | |
2631 | cifs_dbg(VFS, "witness requested on mount but no CLUSTER capability on share\n"); | |
2632 | rc = -EOPNOTSUPP; | |
2633 | goto out_fail; | |
2634 | } | |
2635 | } else { | |
2636 | cifs_dbg(VFS, "SMB3 or later required for witness option\n"); | |
2637 | rc = -EOPNOTSUPP; | |
2638 | goto out_fail; | |
2639 | } | |
2640 | } | |
b618f001 | 2641 | |
cae53f70 SF |
2642 | /* If the user really knows what they are doing they can override */ |
2643 | if (tcon->share_flags & SMB2_SHAREFLAG_NO_CACHING) { | |
3fa1c6d1 | 2644 | if (ctx->cache_ro) |
cae53f70 | 2645 | cifs_dbg(VFS, "cache=ro requested on mount but NO_CACHING flag set on share\n"); |
3fa1c6d1 | 2646 | else if (ctx->cache_rw) |
cae53f70 SF |
2647 | cifs_dbg(VFS, "cache=singleclient requested on mount but NO_CACHING flag set on share\n"); |
2648 | } | |
2649 | ||
3fa1c6d1 | 2650 | if (ctx->no_lease) { |
8fd6e1d6 K |
2651 | if (ses->server->vals->protocol_id == 0) { |
2652 | cifs_dbg(VFS, | |
2653 | "SMB2 or later required for nolease option\n"); | |
2654 | rc = -EOPNOTSUPP; | |
2655 | goto out_fail; | |
2656 | } else | |
3fa1c6d1 | 2657 | tcon->no_lease = ctx->no_lease; |
8fd6e1d6 K |
2658 | } |
2659 | ||
2e6e02ab PS |
2660 | /* |
2661 | * We can have only one retry value for a connection to a share so for | |
2662 | * resources mounted more than once to the same server share the last | |
2663 | * value passed in for the retry flag is used. | |
2664 | */ | |
3fa1c6d1 RS |
2665 | tcon->retry = ctx->retry; |
2666 | tcon->nocase = ctx->nocase; | |
52832252 | 2667 | tcon->broken_sparse_sup = ctx->no_sparse; |
6a50d71d | 2668 | tcon->max_cached_dirs = ctx->max_cached_dirs; |
3fa1c6d1 RS |
2669 | tcon->nodelete = ctx->nodelete; |
2670 | tcon->local_lease = ctx->local_lease; | |
233839b1 | 2671 | INIT_LIST_HEAD(&tcon->pending_opens); |
b248586a | 2672 | tcon->status = TID_GOOD; |
d00c28de | 2673 | |
6e1c1c08 SP |
2674 | INIT_DELAYED_WORK(&tcon->query_interfaces, |
2675 | smb2_query_server_interfaces); | |
22aeb01d PA |
2676 | if (ses->server->dialect >= SMB30_PROT_ID && |
2677 | (ses->server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) { | |
2678 | /* schedule query interfaces poll */ | |
2679 | queue_delayed_work(cifsiod_wq, &tcon->query_interfaces, | |
2680 | (SMB_INTERFACE_POLL_INTERVAL * HZ)); | |
2681 | } | |
6be2ea33 PA |
2682 | #ifdef CONFIG_CIFS_DFS_UPCALL |
2683 | INIT_DELAYED_WORK(&tcon->dfs_cache_work, dfs_cache_refresh); | |
2684 | #endif | |
3f9bcca7 | 2685 | spin_lock(&cifs_tcp_ses_lock); |
d00c28de | 2686 | list_add(&tcon->tcon_list, &ses->tcon_list); |
3f9bcca7 | 2687 | spin_unlock(&cifs_tcp_ses_lock); |
d00c28de JL |
2688 | |
2689 | return tcon; | |
2690 | ||
2691 | out_fail: | |
2692 | tconInfoFree(tcon); | |
2693 | return ERR_PTR(rc); | |
2694 | } | |
2695 | ||
9d002df4 JL |
2696 | void |
2697 | cifs_put_tlink(struct tcon_link *tlink) | |
2698 | { | |
2699 | if (!tlink || IS_ERR(tlink)) | |
2700 | return; | |
2701 | ||
2702 | if (!atomic_dec_and_test(&tlink->tl_count) || | |
2703 | test_bit(TCON_LINK_IN_TREE, &tlink->tl_flags)) { | |
2704 | tlink->tl_time = jiffies; | |
2705 | return; | |
2706 | } | |
2707 | ||
2708 | if (!IS_ERR(tlink_tcon(tlink))) | |
2709 | cifs_put_tcon(tlink_tcon(tlink)); | |
2710 | kfree(tlink); | |
2711 | return; | |
2712 | } | |
d00c28de | 2713 | |
25c7f41e PS |
2714 | static int |
2715 | compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data) | |
2716 | { | |
2717 | struct cifs_sb_info *old = CIFS_SB(sb); | |
2718 | struct cifs_sb_info *new = mnt_data->cifs_sb; | |
29fbeb7a PAS |
2719 | unsigned int oldflags = old->mnt_cifs_flags & CIFS_MOUNT_MASK; |
2720 | unsigned int newflags = new->mnt_cifs_flags & CIFS_MOUNT_MASK; | |
25c7f41e PS |
2721 | |
2722 | if ((sb->s_flags & CIFS_MS_MASK) != (mnt_data->flags & CIFS_MS_MASK)) | |
2723 | return 0; | |
2724 | ||
29fbeb7a PAS |
2725 | if (old->mnt_cifs_serverino_autodisabled) |
2726 | newflags &= ~CIFS_MOUNT_SERVER_INUM; | |
2727 | ||
2728 | if (oldflags != newflags) | |
25c7f41e PS |
2729 | return 0; |
2730 | ||
25c7f41e | 2731 | /* |
5eba8ab3 JL |
2732 | * We want to share sb only if we don't specify an r/wsize or |
2733 | * specified r/wsize is greater than or equal to existing one. | |
25c7f41e | 2734 | */ |
522aa3b5 | 2735 | if (new->ctx->wsize && new->ctx->wsize < old->ctx->wsize) |
25c7f41e PS |
2736 | return 0; |
2737 | ||
522aa3b5 | 2738 | if (new->ctx->rsize && new->ctx->rsize < old->ctx->rsize) |
5eba8ab3 JL |
2739 | return 0; |
2740 | ||
8401e936 RS |
2741 | if (!uid_eq(old->ctx->linux_uid, new->ctx->linux_uid) || |
2742 | !gid_eq(old->ctx->linux_gid, new->ctx->linux_gid)) | |
25c7f41e PS |
2743 | return 0; |
2744 | ||
8401e936 RS |
2745 | if (old->ctx->file_mode != new->ctx->file_mode || |
2746 | old->ctx->dir_mode != new->ctx->dir_mode) | |
25c7f41e PS |
2747 | return 0; |
2748 | ||
2749 | if (strcmp(old->local_nls->charset, new->local_nls->charset)) | |
2750 | return 0; | |
2751 | ||
57804646 | 2752 | if (old->ctx->acregmax != new->ctx->acregmax) |
25c7f41e | 2753 | return 0; |
4c9f9481 SF |
2754 | if (old->ctx->acdirmax != new->ctx->acdirmax) |
2755 | return 0; | |
5efdd912 SF |
2756 | if (old->ctx->closetimeo != new->ctx->closetimeo) |
2757 | return 0; | |
25c7f41e PS |
2758 | |
2759 | return 1; | |
2760 | } | |
2761 | ||
8e355415 | 2762 | static int match_prepath(struct super_block *sb, |
3ae872de | 2763 | struct cifs_tcon *tcon, |
8e355415 | 2764 | struct cifs_mnt_data *mnt_data) |
c1d8b24d | 2765 | { |
8e355415 | 2766 | struct smb3_fs_context *ctx = mnt_data->ctx; |
c1d8b24d SP |
2767 | struct cifs_sb_info *old = CIFS_SB(sb); |
2768 | struct cifs_sb_info *new = mnt_data->cifs_sb; | |
fe129268 RS |
2769 | bool old_set = (old->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) && |
2770 | old->prepath; | |
2771 | bool new_set = (new->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) && | |
2772 | new->prepath; | |
c1d8b24d | 2773 | |
3ae872de PA |
2774 | if (tcon->origin_fullpath && |
2775 | dfs_src_pathname_equal(tcon->origin_fullpath, ctx->source)) | |
8e355415 PA |
2776 | return 1; |
2777 | ||
cd8c4296 | 2778 | if (old_set && new_set && !strcmp(new->prepath, old->prepath)) |
c1d8b24d | 2779 | return 1; |
cd8c4296 SP |
2780 | else if (!old_set && !new_set) |
2781 | return 1; | |
2782 | ||
c1d8b24d SP |
2783 | return 0; |
2784 | } | |
2785 | ||
25c7f41e PS |
2786 | int |
2787 | cifs_match_super(struct super_block *sb, void *data) | |
2788 | { | |
0f46608a | 2789 | struct cifs_mnt_data *mnt_data = data; |
3fa1c6d1 | 2790 | struct smb3_fs_context *ctx; |
25c7f41e PS |
2791 | struct cifs_sb_info *cifs_sb; |
2792 | struct TCP_Server_Info *tcp_srv; | |
96daf2b0 SF |
2793 | struct cifs_ses *ses; |
2794 | struct cifs_tcon *tcon; | |
25c7f41e | 2795 | struct tcon_link *tlink; |
25c7f41e PS |
2796 | int rc = 0; |
2797 | ||
25c7f41e PS |
2798 | spin_lock(&cifs_tcp_ses_lock); |
2799 | cifs_sb = CIFS_SB(sb); | |
716a3cf3 SF |
2800 | |
2801 | /* We do not want to use a superblock that has been shutdown */ | |
2802 | if (CIFS_MOUNT_SHUTDOWN & cifs_sb->mnt_cifs_flags) { | |
2803 | spin_unlock(&cifs_tcp_ses_lock); | |
2804 | return 0; | |
2805 | } | |
2806 | ||
25c7f41e | 2807 | tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); |
fc1bd51d PA |
2808 | if (IS_ERR_OR_NULL(tlink)) { |
2809 | pr_warn_once("%s: skip super matching due to bad tlink(%p)\n", | |
2810 | __func__, tlink); | |
25c7f41e | 2811 | spin_unlock(&cifs_tcp_ses_lock); |
9ed38fd4 | 2812 | return 0; |
25c7f41e PS |
2813 | } |
2814 | tcon = tlink_tcon(tlink); | |
2815 | ses = tcon->ses; | |
2816 | tcp_srv = ses->server; | |
2817 | ||
3fa1c6d1 | 2818 | ctx = mnt_data->ctx; |
25c7f41e | 2819 | |
d7d7a66a SP |
2820 | spin_lock(&tcp_srv->srv_lock); |
2821 | spin_lock(&ses->ses_lock); | |
2f4e429c | 2822 | spin_lock(&ses->chan_lock); |
d7d7a66a | 2823 | spin_lock(&tcon->tc_lock); |
3ae872de | 2824 | if (!match_server(tcp_srv, ctx, true) || |
3fa1c6d1 | 2825 | !match_session(ses, ctx) || |
8e355415 | 2826 | !match_tcon(tcon, ctx) || |
3ae872de | 2827 | !match_prepath(sb, tcon, mnt_data)) { |
25c7f41e PS |
2828 | rc = 0; |
2829 | goto out; | |
2830 | } | |
2831 | ||
2832 | rc = compare_mount_options(sb, mnt_data); | |
2833 | out: | |
d7d7a66a | 2834 | spin_unlock(&tcon->tc_lock); |
2f4e429c | 2835 | spin_unlock(&ses->chan_lock); |
d7d7a66a SP |
2836 | spin_unlock(&ses->ses_lock); |
2837 | spin_unlock(&tcp_srv->srv_lock); | |
2838 | ||
25c7f41e | 2839 | spin_unlock(&cifs_tcp_ses_lock); |
f484b5d0 | 2840 | cifs_put_tlink(tlink); |
25c7f41e PS |
2841 | return rc; |
2842 | } | |
2843 | ||
09e50d55 JL |
2844 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
2845 | static struct lock_class_key cifs_key[2]; | |
2846 | static struct lock_class_key cifs_slock_key[2]; | |
2847 | ||
2848 | static inline void | |
2849 | cifs_reclassify_socket4(struct socket *sock) | |
2850 | { | |
2851 | struct sock *sk = sock->sk; | |
fafc4e1e | 2852 | BUG_ON(!sock_allow_reclassification(sk)); |
09e50d55 JL |
2853 | sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS", |
2854 | &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]); | |
2855 | } | |
2856 | ||
2857 | static inline void | |
2858 | cifs_reclassify_socket6(struct socket *sock) | |
2859 | { | |
2860 | struct sock *sk = sock->sk; | |
fafc4e1e | 2861 | BUG_ON(!sock_allow_reclassification(sk)); |
09e50d55 JL |
2862 | sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS", |
2863 | &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]); | |
2864 | } | |
2865 | #else | |
2866 | static inline void | |
2867 | cifs_reclassify_socket4(struct socket *sock) | |
2868 | { | |
2869 | } | |
2870 | ||
2871 | static inline void | |
2872 | cifs_reclassify_socket6(struct socket *sock) | |
2873 | { | |
2874 | } | |
2875 | #endif | |
2876 | ||
1da177e4 | 2877 | /* See RFC1001 section 14 on representation of Netbios names */ |
50c2f753 | 2878 | static void rfc1002mangle(char *target, char *source, unsigned int length) |
1da177e4 | 2879 | { |
50c2f753 | 2880 | unsigned int i, j; |
1da177e4 | 2881 | |
50c2f753 | 2882 | for (i = 0, j = 0; i < (length); i++) { |
1da177e4 LT |
2883 | /* mask a nibble at a time and encode */ |
2884 | target[j] = 'A' + (0x0F & (source[i] >> 4)); | |
2885 | target[j+1] = 'A' + (0x0F & source[i]); | |
50c2f753 | 2886 | j += 2; |
1da177e4 LT |
2887 | } |
2888 | ||
2889 | } | |
2890 | ||
3eb9a889 BG |
2891 | static int |
2892 | bind_socket(struct TCP_Server_Info *server) | |
2893 | { | |
2894 | int rc = 0; | |
2895 | if (server->srcaddr.ss_family != AF_UNSPEC) { | |
2896 | /* Bind to the specified local IP address */ | |
2897 | struct socket *socket = server->ssocket; | |
cedc019b JR |
2898 | rc = kernel_bind(socket, |
2899 | (struct sockaddr *) &server->srcaddr, | |
2900 | sizeof(server->srcaddr)); | |
3eb9a889 BG |
2901 | if (rc < 0) { |
2902 | struct sockaddr_in *saddr4; | |
2903 | struct sockaddr_in6 *saddr6; | |
2904 | saddr4 = (struct sockaddr_in *)&server->srcaddr; | |
2905 | saddr6 = (struct sockaddr_in6 *)&server->srcaddr; | |
2906 | if (saddr6->sin6_family == AF_INET6) | |
afe6f653 | 2907 | cifs_server_dbg(VFS, "Failed to bind to: %pI6c, error: %d\n", |
f96637be | 2908 | &saddr6->sin6_addr, rc); |
3eb9a889 | 2909 | else |
afe6f653 | 2910 | cifs_server_dbg(VFS, "Failed to bind to: %pI4, error: %d\n", |
f96637be | 2911 | &saddr4->sin_addr.s_addr, rc); |
3eb9a889 BG |
2912 | } |
2913 | } | |
2914 | return rc; | |
2915 | } | |
1da177e4 LT |
2916 | |
2917 | static int | |
a9f1b85e | 2918 | ip_rfc1001_connect(struct TCP_Server_Info *server) |
1da177e4 LT |
2919 | { |
2920 | int rc = 0; | |
a9f1b85e PS |
2921 | /* |
2922 | * some servers require RFC1001 sessinit before sending | |
2923 | * negprot - BB check reconnection in case where second | |
2924 | * sessinit is sent but no second negprot | |
2925 | */ | |
d99e86eb PA |
2926 | struct rfc1002_session_packet req = {}; |
2927 | struct smb_hdr *smb_buf = (struct smb_hdr *)&req; | |
2928 | unsigned int len; | |
d7173623 | 2929 | |
d99e86eb | 2930 | req.trailer.session_req.called_len = sizeof(req.trailer.session_req.called_name); |
d7173623 | 2931 | |
d99e86eb PA |
2932 | if (server->server_RFC1001_name[0] != 0) |
2933 | rfc1002mangle(req.trailer.session_req.called_name, | |
2934 | server->server_RFC1001_name, | |
2935 | RFC1001_NAME_LEN_WITH_NULL); | |
2936 | else | |
2937 | rfc1002mangle(req.trailer.session_req.called_name, | |
2938 | DEFAULT_CIFS_CALLED_NAME, | |
2939 | RFC1001_NAME_LEN_WITH_NULL); | |
a9f1b85e | 2940 | |
d99e86eb | 2941 | req.trailer.session_req.calling_len = sizeof(req.trailer.session_req.calling_name); |
a9f1b85e | 2942 | |
d99e86eb PA |
2943 | /* calling name ends in null (byte 16) from old smb convention */ |
2944 | if (server->workstation_RFC1001_name[0] != 0) | |
2945 | rfc1002mangle(req.trailer.session_req.calling_name, | |
2946 | server->workstation_RFC1001_name, | |
2947 | RFC1001_NAME_LEN_WITH_NULL); | |
2948 | else | |
2949 | rfc1002mangle(req.trailer.session_req.calling_name, | |
2950 | "LINUX_CIFS_CLNT", | |
2951 | RFC1001_NAME_LEN_WITH_NULL); | |
a9f1b85e | 2952 | |
a9f1b85e | 2953 | /* |
d99e86eb PA |
2954 | * As per rfc1002, @len must be the number of bytes that follows the |
2955 | * length field of a rfc1002 session request payload. | |
2956 | */ | |
2957 | len = sizeof(req) - offsetof(struct rfc1002_session_packet, trailer.session_req); | |
2958 | ||
2959 | smb_buf->smb_buf_length = cpu_to_be32((RFC1002_SESSION_REQUEST << 24) | len); | |
2960 | rc = smb_send(server, smb_buf, len); | |
2961 | /* | |
2962 | * RFC1001 layer in at least one server requires very short break before | |
2963 | * negprot presumably because not expecting negprot to follow so fast. | |
2964 | * This is a simple solution that works without complicating the code | |
2965 | * and causes no significant slowing down on mount for everyone else | |
a9f1b85e | 2966 | */ |
d99e86eb | 2967 | usleep_range(1000, 2000); |
a9f1b85e PS |
2968 | |
2969 | return rc; | |
2970 | } | |
2971 | ||
2972 | static int | |
2973 | generic_ip_connect(struct TCP_Server_Info *server) | |
2974 | { | |
a9f1b85e | 2975 | struct sockaddr *saddr; |
f0b6a834 PA |
2976 | struct socket *socket; |
2977 | int slen, sfamily; | |
2978 | __be16 sport; | |
2979 | int rc = 0; | |
a9f1b85e PS |
2980 | |
2981 | saddr = (struct sockaddr *) &server->dstaddr; | |
2982 | ||
2983 | if (server->dstaddr.ss_family == AF_INET6) { | |
def6e1dc SC |
2984 | struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&server->dstaddr; |
2985 | ||
2986 | sport = ipv6->sin6_port; | |
a9f1b85e PS |
2987 | slen = sizeof(struct sockaddr_in6); |
2988 | sfamily = AF_INET6; | |
def6e1dc SC |
2989 | cifs_dbg(FYI, "%s: connecting to [%pI6]:%d\n", __func__, &ipv6->sin6_addr, |
2990 | ntohs(sport)); | |
a9f1b85e | 2991 | } else { |
def6e1dc SC |
2992 | struct sockaddr_in *ipv4 = (struct sockaddr_in *)&server->dstaddr; |
2993 | ||
2994 | sport = ipv4->sin_port; | |
a9f1b85e PS |
2995 | slen = sizeof(struct sockaddr_in); |
2996 | sfamily = AF_INET; | |
def6e1dc SC |
2997 | cifs_dbg(FYI, "%s: connecting to %pI4:%d\n", __func__, &ipv4->sin_addr, |
2998 | ntohs(sport)); | |
a9f1b85e | 2999 | } |
1da177e4 | 3000 | |
f0b6a834 PA |
3001 | if (server->ssocket) { |
3002 | socket = server->ssocket; | |
3003 | } else { | |
f1d0c998 | 3004 | rc = __sock_create(cifs_net_ns(server), sfamily, SOCK_STREAM, |
f0b6a834 | 3005 | IPPROTO_TCP, &server->ssocket, 1); |
1da177e4 | 3006 | if (rc < 0) { |
afe6f653 | 3007 | cifs_server_dbg(VFS, "Error %d creating socket\n", rc); |
1da177e4 | 3008 | return rc; |
1da177e4 | 3009 | } |
bcf4b106 JL |
3010 | |
3011 | /* BB other socket options to set KEEPALIVE, NODELAY? */ | |
f96637be | 3012 | cifs_dbg(FYI, "Socket created\n"); |
f0b6a834 | 3013 | socket = server->ssocket; |
bcf4b106 | 3014 | socket->sk->sk_allocation = GFP_NOFS; |
98123866 | 3015 | socket->sk->sk_use_task_frag = false; |
a9f1b85e PS |
3016 | if (sfamily == AF_INET6) |
3017 | cifs_reclassify_socket6(socket); | |
3018 | else | |
3019 | cifs_reclassify_socket4(socket); | |
1da177e4 LT |
3020 | } |
3021 | ||
3eb9a889 BG |
3022 | rc = bind_socket(server); |
3023 | if (rc < 0) | |
3024 | return rc; | |
3025 | ||
bcf4b106 JL |
3026 | /* |
3027 | * Eventually check for other socket options to change from | |
a9f1b85e PS |
3028 | * the default. sock_setsockopt not used because it expects |
3029 | * user space buffer | |
bcf4b106 JL |
3030 | */ |
3031 | socket->sk->sk_rcvtimeo = 7 * HZ; | |
da505c38 | 3032 | socket->sk->sk_sndtimeo = 5 * HZ; |
edf1ae40 | 3033 | |
b387eaeb | 3034 | /* make the bufsizes depend on wsize/rsize and max requests */ |
bcf4b106 JL |
3035 | if (server->noautotune) { |
3036 | if (socket->sk->sk_sndbuf < (200 * 1024)) | |
3037 | socket->sk->sk_sndbuf = 200 * 1024; | |
3038 | if (socket->sk->sk_rcvbuf < (140 * 1024)) | |
3039 | socket->sk->sk_rcvbuf = 140 * 1024; | |
edf1ae40 | 3040 | } |
1da177e4 | 3041 | |
12abc5ee CH |
3042 | if (server->tcp_nodelay) |
3043 | tcp_sock_set_nodelay(socket->sk); | |
6a5fa236 | 3044 | |
f96637be | 3045 | cifs_dbg(FYI, "sndbuf %d rcvbuf %d rcvtimeo 0x%lx\n", |
bcf4b106 | 3046 | socket->sk->sk_sndbuf, |
b6b38f70 | 3047 | socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo); |
bcf4b106 | 3048 | |
cedc019b JR |
3049 | rc = kernel_connect(socket, saddr, slen, |
3050 | server->noblockcnt ? O_NONBLOCK : 0); | |
d532cc7e PAS |
3051 | /* |
3052 | * When mounting SMB root file systems, we do not want to block in | |
3053 | * connect. Otherwise bail out and then let cifs_reconnect() perform | |
3054 | * reconnect failover - if possible. | |
3055 | */ | |
3056 | if (server->noblockcnt && rc == -EINPROGRESS) | |
8eecd1c2 | 3057 | rc = 0; |
ee1b3ea9 | 3058 | if (rc < 0) { |
f96637be | 3059 | cifs_dbg(FYI, "Error %d connecting to server\n", rc); |
d7171cd1 | 3060 | trace_smb3_connect_err(server->hostname, server->conn_id, &server->dstaddr, rc); |
ee1b3ea9 JL |
3061 | sock_release(socket); |
3062 | server->ssocket = NULL; | |
3063 | return rc; | |
3064 | } | |
d7171cd1 | 3065 | trace_smb3_connect_done(server->hostname, server->conn_id, &server->dstaddr); |
a9f1b85e PS |
3066 | if (sport == htons(RFC1001_PORT)) |
3067 | rc = ip_rfc1001_connect(server); | |
50c2f753 | 3068 | |
1da177e4 LT |
3069 | return rc; |
3070 | } | |
3071 | ||
3072 | static int | |
a9f1b85e | 3073 | ip_connect(struct TCP_Server_Info *server) |
1da177e4 | 3074 | { |
6da97910 | 3075 | __be16 *sport; |
a9f1b85e PS |
3076 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; |
3077 | struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; | |
1da177e4 | 3078 | |
a9f1b85e PS |
3079 | if (server->dstaddr.ss_family == AF_INET6) |
3080 | sport = &addr6->sin6_port; | |
3081 | else | |
3082 | sport = &addr->sin_port; | |
1da177e4 | 3083 | |
a9f1b85e PS |
3084 | if (*sport == 0) { |
3085 | int rc; | |
1da177e4 | 3086 | |
a9f1b85e PS |
3087 | /* try with 445 port at first */ |
3088 | *sport = htons(CIFS_PORT); | |
3eb9a889 | 3089 | |
a9f1b85e | 3090 | rc = generic_ip_connect(server); |
1da177e4 | 3091 | if (rc >= 0) |
a9f1b85e | 3092 | return rc; |
6a5fa236 | 3093 | |
a9f1b85e PS |
3094 | /* if it failed, try with 139 port */ |
3095 | *sport = htons(RFC1001_PORT); | |
6a5fa236 SF |
3096 | } |
3097 | ||
a9f1b85e | 3098 | return generic_ip_connect(server); |
1da177e4 LT |
3099 | } |
3100 | ||
fb157ed2 | 3101 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
6d5786a3 | 3102 | void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, |
3fa1c6d1 | 3103 | struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) |
8af18971 | 3104 | { |
bc044994 SF |
3105 | /* |
3106 | * If we are reconnecting then should we check to see if | |
8af18971 SF |
3107 | * any requested capabilities changed locally e.g. via |
3108 | * remount but we can not do much about it here | |
3109 | * if they have (even if we could detect it by the following) | |
3110 | * Perhaps we could add a backpointer to array of sb from tcon | |
3111 | * or if we change to make all sb to same share the same | |
3112 | * sb as NFS - then we only have one backpointer to sb. | |
3113 | * What if we wanted to mount the server share twice once with | |
bc044994 SF |
3114 | * and once without posixacls or posix paths? |
3115 | */ | |
8af18971 | 3116 | __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); |
50c2f753 | 3117 | |
3fa1c6d1 | 3118 | if (ctx && ctx->no_linux_ext) { |
c18c842b SF |
3119 | tcon->fsUnixInfo.Capability = 0; |
3120 | tcon->unix_ext = 0; /* Unix Extensions disabled */ | |
f96637be | 3121 | cifs_dbg(FYI, "Linux protocol extensions disabled\n"); |
c18c842b | 3122 | return; |
3fa1c6d1 | 3123 | } else if (ctx) |
c18c842b SF |
3124 | tcon->unix_ext = 1; /* Unix Extensions supported */ |
3125 | ||
16a78851 | 3126 | if (!tcon->unix_ext) { |
f96637be | 3127 | cifs_dbg(FYI, "Unix extensions disabled so not set on reconnect\n"); |
c18c842b SF |
3128 | return; |
3129 | } | |
50c2f753 | 3130 | |
fb8c4b14 | 3131 | if (!CIFSSMBQFSUnixInfo(xid, tcon)) { |
8af18971 | 3132 | __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability); |
f96637be | 3133 | cifs_dbg(FYI, "unix caps which server supports %lld\n", cap); |
bc044994 SF |
3134 | /* |
3135 | * check for reconnect case in which we do not | |
3136 | * want to change the mount behavior if we can avoid it | |
3137 | */ | |
3fa1c6d1 | 3138 | if (ctx == NULL) { |
bc044994 SF |
3139 | /* |
3140 | * turn off POSIX ACL and PATHNAMES if not set | |
3141 | * originally at mount time | |
3142 | */ | |
8af18971 SF |
3143 | if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0) |
3144 | cap &= ~CIFS_UNIX_POSIX_ACL_CAP; | |
11b6d645 IM |
3145 | if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) { |
3146 | if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) | |
f96637be | 3147 | cifs_dbg(VFS, "POSIXPATH support change\n"); |
8af18971 | 3148 | cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; |
11b6d645 | 3149 | } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) { |
f96637be JP |
3150 | cifs_dbg(VFS, "possible reconnect error\n"); |
3151 | cifs_dbg(VFS, "server disabled POSIX path support\n"); | |
11b6d645 | 3152 | } |
8af18971 | 3153 | } |
50c2f753 | 3154 | |
6848b733 | 3155 | if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) |
f96637be | 3156 | cifs_dbg(VFS, "per-share encryption not supported yet\n"); |
6848b733 | 3157 | |
8af18971 | 3158 | cap &= CIFS_UNIX_CAP_MASK; |
3fa1c6d1 | 3159 | if (ctx && ctx->no_psx_acl) |
8af18971 | 3160 | cap &= ~CIFS_UNIX_POSIX_ACL_CAP; |
75865f8c | 3161 | else if (CIFS_UNIX_POSIX_ACL_CAP & cap) { |
f96637be | 3162 | cifs_dbg(FYI, "negotiated posix acl support\n"); |
2c6292ae AV |
3163 | if (cifs_sb) |
3164 | cifs_sb->mnt_cifs_flags |= | |
3165 | CIFS_MOUNT_POSIXACL; | |
8af18971 SF |
3166 | } |
3167 | ||
3fa1c6d1 | 3168 | if (ctx && ctx->posix_paths == 0) |
8af18971 | 3169 | cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; |
75865f8c | 3170 | else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) { |
f96637be | 3171 | cifs_dbg(FYI, "negotiate posix pathnames\n"); |
2c6292ae AV |
3172 | if (cifs_sb) |
3173 | cifs_sb->mnt_cifs_flags |= | |
8af18971 SF |
3174 | CIFS_MOUNT_POSIX_PATHS; |
3175 | } | |
50c2f753 | 3176 | |
f96637be | 3177 | cifs_dbg(FYI, "Negotiate caps 0x%x\n", (int)cap); |
8af18971 | 3178 | #ifdef CONFIG_CIFS_DEBUG2 |
75865f8c | 3179 | if (cap & CIFS_UNIX_FCNTL_CAP) |
f96637be | 3180 | cifs_dbg(FYI, "FCNTL cap\n"); |
75865f8c | 3181 | if (cap & CIFS_UNIX_EXTATTR_CAP) |
f96637be | 3182 | cifs_dbg(FYI, "EXTATTR cap\n"); |
75865f8c | 3183 | if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) |
f96637be | 3184 | cifs_dbg(FYI, "POSIX path cap\n"); |
75865f8c | 3185 | if (cap & CIFS_UNIX_XATTR_CAP) |
f96637be | 3186 | cifs_dbg(FYI, "XATTR cap\n"); |
75865f8c | 3187 | if (cap & CIFS_UNIX_POSIX_ACL_CAP) |
f96637be | 3188 | cifs_dbg(FYI, "POSIX ACL cap\n"); |
75865f8c | 3189 | if (cap & CIFS_UNIX_LARGE_READ_CAP) |
f96637be | 3190 | cifs_dbg(FYI, "very large read cap\n"); |
75865f8c | 3191 | if (cap & CIFS_UNIX_LARGE_WRITE_CAP) |
f96637be | 3192 | cifs_dbg(FYI, "very large write cap\n"); |
6848b733 | 3193 | if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP) |
f96637be | 3194 | cifs_dbg(FYI, "transport encryption cap\n"); |
6848b733 | 3195 | if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) |
f96637be | 3196 | cifs_dbg(FYI, "mandatory transport encryption cap\n"); |
8af18971 SF |
3197 | #endif /* CIFS_DEBUG2 */ |
3198 | if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) { | |
3fa1c6d1 | 3199 | if (ctx == NULL) |
f96637be | 3200 | cifs_dbg(FYI, "resetting capabilities failed\n"); |
3fa1c6d1 | 3201 | else |
f96637be | 3202 | cifs_dbg(VFS, "Negotiating Unix capabilities with the server failed. Consider mounting with the Unix Extensions disabled if problems are found by specifying the nounix mount option.\n"); |
5a44b319 | 3203 | |
8af18971 SF |
3204 | } |
3205 | } | |
3206 | } | |
fb157ed2 | 3207 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
8af18971 | 3208 | |
51acd208 | 3209 | int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb) |
b1c8d2b4 | 3210 | { |
51acd208 RS |
3211 | struct smb3_fs_context *ctx = cifs_sb->ctx; |
3212 | ||
2de970ff JL |
3213 | INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks); |
3214 | ||
2ced6f69 AV |
3215 | spin_lock_init(&cifs_sb->tlink_tree_lock); |
3216 | cifs_sb->tlink_tree = RB_ROOT; | |
3217 | ||
f52aa79d | 3218 | cifs_dbg(FYI, "file mode: %04ho dir mode: %04ho\n", |
51acd208 | 3219 | ctx->file_mode, ctx->dir_mode); |
3b795210 | 3220 | |
387ec58f RS |
3221 | /* this is needed for ASCII cp to Unicode converts */ |
3222 | if (ctx->iocharset == NULL) { | |
3223 | /* load_nls_default cannot return null */ | |
3224 | cifs_sb->local_nls = load_nls_default(); | |
3225 | } else { | |
3226 | cifs_sb->local_nls = load_nls(ctx->iocharset); | |
3227 | if (cifs_sb->local_nls == NULL) { | |
3228 | cifs_dbg(VFS, "CIFS mount error: iocharset %s not found\n", | |
3229 | ctx->iocharset); | |
3230 | return -ELIBACC; | |
3231 | } | |
3232 | } | |
3233 | ctx->local_nls = cifs_sb->local_nls; | |
6d20e840 | 3234 | |
2d39f50c RS |
3235 | smb3_update_mnt_flags(cifs_sb); |
3236 | ||
3237 | if (ctx->direct_io) | |
f96637be | 3238 | cifs_dbg(FYI, "mounting share using direct i/o\n"); |
3fa1c6d1 | 3239 | if (ctx->cache_ro) { |
83bbfa70 SF |
3240 | cifs_dbg(VFS, "mounting share with read only caching. Ensure that the share will not be modified while in use.\n"); |
3241 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RO_CACHE; | |
3fa1c6d1 | 3242 | } else if (ctx->cache_rw) { |
41e033fe SF |
3243 | cifs_dbg(VFS, "mounting share in single client RW caching mode. Ensure that no other systems will be accessing the share.\n"); |
3244 | cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_RO_CACHE | | |
3245 | CIFS_MOUNT_RW_CACHE); | |
83bbfa70 | 3246 | } |
3b795210 | 3247 | |
3fa1c6d1 | 3248 | if ((ctx->cifs_acl) && (ctx->dynperm)) |
f96637be | 3249 | cifs_dbg(VFS, "mount option dynperm ignored if cifsacl mount option supported\n"); |
4214ebf4 | 3250 | |
3fa1c6d1 RS |
3251 | if (ctx->prepath) { |
3252 | cifs_sb->prepath = kstrdup(ctx->prepath, GFP_KERNEL); | |
4214ebf4 SP |
3253 | if (cifs_sb->prepath == NULL) |
3254 | return -ENOMEM; | |
a738c93f | 3255 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH; |
4214ebf4 SP |
3256 | } |
3257 | ||
3258 | return 0; | |
b1c8d2b4 JL |
3259 | } |
3260 | ||
56c762eb | 3261 | /* Release all succeed connections */ |
a1c0d005 | 3262 | void cifs_mount_put_conns(struct cifs_mount_ctx *mnt_ctx) |
56c762eb PA |
3263 | { |
3264 | int rc = 0; | |
3265 | ||
c88f7dcd PA |
3266 | if (mnt_ctx->tcon) |
3267 | cifs_put_tcon(mnt_ctx->tcon); | |
3268 | else if (mnt_ctx->ses) | |
3269 | cifs_put_smb_ses(mnt_ctx->ses); | |
3270 | else if (mnt_ctx->server) | |
3271 | cifs_put_tcp_session(mnt_ctx->server, 0); | |
3272 | mnt_ctx->cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_POSIX_PATHS; | |
3273 | free_xid(mnt_ctx->xid); | |
56c762eb PA |
3274 | } |
3275 | ||
a73a26d9 | 3276 | int cifs_mount_get_session(struct cifs_mount_ctx *mnt_ctx) |
56c762eb | 3277 | { |
c88f7dcd | 3278 | struct TCP_Server_Info *server = NULL; |
a73a26d9 | 3279 | struct smb3_fs_context *ctx; |
c88f7dcd | 3280 | struct cifs_ses *ses = NULL; |
c88f7dcd | 3281 | unsigned int xid; |
a73a26d9 | 3282 | int rc = 0; |
56c762eb | 3283 | |
c88f7dcd | 3284 | xid = get_xid(); |
56c762eb | 3285 | |
a73a26d9 PA |
3286 | if (WARN_ON_ONCE(!mnt_ctx || !mnt_ctx->fs_ctx)) { |
3287 | rc = -EINVAL; | |
3288 | goto out; | |
3289 | } | |
3290 | ctx = mnt_ctx->fs_ctx; | |
3291 | ||
56c762eb | 3292 | /* get a reference to a tcp session */ |
0f2b305a | 3293 | server = cifs_get_tcp_session(ctx, NULL); |
56c762eb PA |
3294 | if (IS_ERR(server)) { |
3295 | rc = PTR_ERR(server); | |
c88f7dcd PA |
3296 | server = NULL; |
3297 | goto out; | |
56c762eb PA |
3298 | } |
3299 | ||
56c762eb | 3300 | /* get a reference to a SMB session */ |
3fa1c6d1 | 3301 | ses = cifs_get_smb_ses(server, ctx); |
56c762eb PA |
3302 | if (IS_ERR(ses)) { |
3303 | rc = PTR_ERR(ses); | |
c88f7dcd PA |
3304 | ses = NULL; |
3305 | goto out; | |
56c762eb PA |
3306 | } |
3307 | ||
3fa1c6d1 | 3308 | if ((ctx->persistent == true) && (!(ses->server->capabilities & |
56c762eb | 3309 | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES))) { |
afe6f653 | 3310 | cifs_server_dbg(VFS, "persistent handles not supported by server\n"); |
c88f7dcd | 3311 | rc = -EOPNOTSUPP; |
a73a26d9 PA |
3312 | } |
3313 | ||
3314 | out: | |
3315 | mnt_ctx->xid = xid; | |
3316 | mnt_ctx->server = server; | |
3317 | mnt_ctx->ses = ses; | |
3318 | mnt_ctx->tcon = NULL; | |
3319 | ||
3320 | return rc; | |
3321 | } | |
3322 | ||
3323 | int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx) | |
3324 | { | |
3325 | struct TCP_Server_Info *server; | |
3326 | struct cifs_sb_info *cifs_sb; | |
3327 | struct smb3_fs_context *ctx; | |
3328 | struct cifs_tcon *tcon = NULL; | |
3329 | int rc = 0; | |
3330 | ||
3331 | if (WARN_ON_ONCE(!mnt_ctx || !mnt_ctx->server || !mnt_ctx->ses || !mnt_ctx->fs_ctx || | |
3332 | !mnt_ctx->cifs_sb)) { | |
3333 | rc = -EINVAL; | |
c88f7dcd | 3334 | goto out; |
56c762eb | 3335 | } |
a73a26d9 PA |
3336 | server = mnt_ctx->server; |
3337 | ctx = mnt_ctx->fs_ctx; | |
3338 | cifs_sb = mnt_ctx->cifs_sb; | |
56c762eb PA |
3339 | |
3340 | /* search for existing tcon to this server share */ | |
a73a26d9 | 3341 | tcon = cifs_get_tcon(mnt_ctx->ses, ctx); |
56c762eb PA |
3342 | if (IS_ERR(tcon)) { |
3343 | rc = PTR_ERR(tcon); | |
c88f7dcd PA |
3344 | tcon = NULL; |
3345 | goto out; | |
56c762eb PA |
3346 | } |
3347 | ||
56c762eb PA |
3348 | /* if new SMB3.11 POSIX extensions are supported do not remap / and \ */ |
3349 | if (tcon->posix_extensions) | |
3350 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS; | |
3351 | ||
fb157ed2 | 3352 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
56c762eb PA |
3353 | /* tell server which Unix caps we support */ |
3354 | if (cap_unix(tcon->ses)) { | |
3355 | /* | |
3356 | * reset of caps checks mount to see if unix extensions disabled | |
3357 | * for just this mount. | |
3358 | */ | |
a73a26d9 | 3359 | reset_cifs_unix_caps(mnt_ctx->xid, tcon, cifs_sb, ctx); |
d7d7a66a | 3360 | spin_lock(&tcon->ses->server->srv_lock); |
56c762eb PA |
3361 | if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) && |
3362 | (le64_to_cpu(tcon->fsUnixInfo.Capability) & | |
c88f7dcd | 3363 | CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)) { |
d7d7a66a | 3364 | spin_unlock(&tcon->ses->server->srv_lock); |
c88f7dcd PA |
3365 | rc = -EACCES; |
3366 | goto out; | |
3367 | } | |
d7d7a66a | 3368 | spin_unlock(&tcon->ses->server->srv_lock); |
56c762eb | 3369 | } else |
fb157ed2 | 3370 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
56c762eb PA |
3371 | tcon->unix_ext = 0; /* server does not support them */ |
3372 | ||
3373 | /* do not care if a following call succeed - informational */ | |
1981ebaa | 3374 | if (!tcon->pipe && server->ops->qfs_tcon) { |
a73a26d9 | 3375 | server->ops->qfs_tcon(mnt_ctx->xid, tcon, cifs_sb); |
1981ebaa SF |
3376 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE) { |
3377 | if (tcon->fsDevInfo.DeviceCharacteristics & | |
52870d50 | 3378 | cpu_to_le32(FILE_READ_ONLY_DEVICE)) |
1981ebaa | 3379 | cifs_dbg(VFS, "mounted to read only share\n"); |
41e033fe SF |
3380 | else if ((cifs_sb->mnt_cifs_flags & |
3381 | CIFS_MOUNT_RW_CACHE) == 0) | |
1981ebaa | 3382 | cifs_dbg(VFS, "read only mount of RW share\n"); |
41e033fe | 3383 | /* no need to log a RW mount of a typical RW share */ |
1981ebaa SF |
3384 | } |
3385 | } | |
56c762eb | 3386 | |
522aa3b5 RS |
3387 | /* |
3388 | * Clamp the rsize/wsize mount arguments if they are too big for the server | |
0c2b5f7c SF |
3389 | * and set the rsize/wsize to the negotiated values if not passed in by |
3390 | * the user on mount | |
522aa3b5 | 3391 | */ |
0c2b5f7c SF |
3392 | if ((cifs_sb->ctx->wsize == 0) || |
3393 | (cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx))) | |
522aa3b5 | 3394 | cifs_sb->ctx->wsize = server->ops->negotiate_wsize(tcon, ctx); |
0c2b5f7c SF |
3395 | if ((cifs_sb->ctx->rsize == 0) || |
3396 | (cifs_sb->ctx->rsize > server->ops->negotiate_rsize(tcon, ctx))) | |
522aa3b5 | 3397 | cifs_sb->ctx->rsize = server->ops->negotiate_rsize(tcon, ctx); |
56c762eb | 3398 | |
b774302e SP |
3399 | /* |
3400 | * The cookie is initialized from volume info returned above. | |
3401 | * Inside cifs_fscache_get_super_cookie it checks | |
3402 | * that we do not get super cookie twice. | |
3403 | */ | |
70431bfd DH |
3404 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) |
3405 | cifs_fscache_get_super_cookie(tcon); | |
b774302e | 3406 | |
c88f7dcd | 3407 | out: |
c88f7dcd | 3408 | mnt_ctx->tcon = tcon; |
c88f7dcd | 3409 | return rc; |
56c762eb PA |
3410 | } |
3411 | ||
3412 | static int mount_setup_tlink(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, | |
3413 | struct cifs_tcon *tcon) | |
3414 | { | |
3415 | struct tcon_link *tlink; | |
3416 | ||
3417 | /* hang the tcon off of the superblock */ | |
3418 | tlink = kzalloc(sizeof(*tlink), GFP_KERNEL); | |
3419 | if (tlink == NULL) | |
3420 | return -ENOMEM; | |
3421 | ||
3422 | tlink->tl_uid = ses->linux_uid; | |
3423 | tlink->tl_tcon = tcon; | |
3424 | tlink->tl_time = jiffies; | |
3425 | set_bit(TCON_LINK_MASTER, &tlink->tl_flags); | |
3426 | set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); | |
3427 | ||
3428 | cifs_sb->master_tlink = tlink; | |
3429 | spin_lock(&cifs_sb->tlink_tree_lock); | |
3430 | tlink_rb_insert(&cifs_sb->tlink_tree, tlink); | |
3431 | spin_unlock(&cifs_sb->tlink_tree_lock); | |
3432 | ||
3433 | queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks, | |
3434 | TLINK_IDLE_EXPIRE); | |
3435 | return 0; | |
3436 | } | |
b9bce2e9 | 3437 | |
a6b5058f AA |
3438 | static int |
3439 | cifs_are_all_path_components_accessible(struct TCP_Server_Info *server, | |
3440 | unsigned int xid, | |
3441 | struct cifs_tcon *tcon, | |
3442 | struct cifs_sb_info *cifs_sb, | |
ce465bf9 RS |
3443 | char *full_path, |
3444 | int added_treename) | |
a6b5058f AA |
3445 | { |
3446 | int rc; | |
3447 | char *s; | |
3448 | char sep, tmp; | |
ce465bf9 | 3449 | int skip = added_treename ? 1 : 0; |
a6b5058f AA |
3450 | |
3451 | sep = CIFS_DIR_SEP(cifs_sb); | |
3452 | s = full_path; | |
3453 | ||
3454 | rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, ""); | |
3455 | while (rc == 0) { | |
3456 | /* skip separators */ | |
3457 | while (*s == sep) | |
3458 | s++; | |
3459 | if (!*s) | |
3460 | break; | |
3461 | /* next separator */ | |
3462 | while (*s && *s != sep) | |
3463 | s++; | |
ce465bf9 RS |
3464 | /* |
3465 | * if the treename is added, we then have to skip the first | |
3466 | * part within the separators | |
3467 | */ | |
3468 | if (skip) { | |
3469 | skip = 0; | |
3470 | continue; | |
3471 | } | |
a6b5058f AA |
3472 | /* |
3473 | * temporarily null-terminate the path at the end of | |
3474 | * the current component | |
3475 | */ | |
3476 | tmp = *s; | |
3477 | *s = 0; | |
3478 | rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, | |
3479 | full_path); | |
3480 | *s = tmp; | |
3481 | } | |
3482 | return rc; | |
3483 | } | |
3484 | ||
56c762eb | 3485 | /* |
337b8b0e EM |
3486 | * Check if path is remote (i.e. a DFS share). |
3487 | * | |
3488 | * Return -EREMOTE if it is, otherwise 0 or -errno. | |
56c762eb | 3489 | */ |
a1c0d005 | 3490 | int cifs_is_path_remote(struct cifs_mount_ctx *mnt_ctx) |
724d9f1c | 3491 | { |
1daaae8f | 3492 | int rc; |
c88f7dcd PA |
3493 | struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb; |
3494 | struct TCP_Server_Info *server = mnt_ctx->server; | |
3495 | unsigned int xid = mnt_ctx->xid; | |
3496 | struct cifs_tcon *tcon = mnt_ctx->tcon; | |
3497 | struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; | |
56c762eb | 3498 | char *full_path; |
dd854466 | 3499 | |
56c762eb PA |
3500 | if (!server->ops->is_path_accessible) |
3501 | return -EOPNOTSUPP; | |
724d9f1c | 3502 | |
56c762eb PA |
3503 | /* |
3504 | * cifs_build_path_to_root works only when we have a valid tcon | |
3505 | */ | |
3fa1c6d1 | 3506 | full_path = cifs_build_path_to_root(ctx, cifs_sb, tcon, |
56c762eb PA |
3507 | tcon->Flags & SMB_SHARE_IS_IN_DFS); |
3508 | if (full_path == NULL) | |
3509 | return -ENOMEM; | |
724d9f1c | 3510 | |
56c762eb | 3511 | cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path); |
1da177e4 | 3512 | |
56c762eb PA |
3513 | rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, |
3514 | full_path); | |
421ef3d5 EM |
3515 | if (rc != 0 && rc != -EREMOTE) |
3516 | goto out; | |
592fafe6 | 3517 | |
56c762eb PA |
3518 | if (rc != -EREMOTE) { |
3519 | rc = cifs_are_all_path_components_accessible(server, xid, tcon, | |
ce465bf9 | 3520 | cifs_sb, full_path, tcon->Flags & SMB_SHARE_IS_IN_DFS); |
56c762eb | 3521 | if (rc != 0) { |
a0a3036b | 3522 | cifs_server_dbg(VFS, "cannot query dirs between root and final path, enabling CIFS_MOUNT_USE_PREFIX_PATH\n"); |
56c762eb PA |
3523 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH; |
3524 | rc = 0; | |
3525 | } | |
d00c28de | 3526 | } |
1bfe73c2 | 3527 | |
421ef3d5 | 3528 | out: |
56c762eb PA |
3529 | kfree(full_path); |
3530 | return rc; | |
3531 | } | |
ce558b0e | 3532 | |
56c762eb | 3533 | #ifdef CONFIG_CIFS_DFS_UPCALL |
c88f7dcd PA |
3534 | int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) |
3535 | { | |
a73a26d9 | 3536 | struct cifs_mount_ctx mnt_ctx = { .cifs_sb = cifs_sb, .fs_ctx = ctx, }; |
c88f7dcd | 3537 | bool isdfs; |
a1c0d005 | 3538 | int rc; |
c88f7dcd | 3539 | |
396935de PA |
3540 | INIT_LIST_HEAD(&mnt_ctx.dfs_ses_list); |
3541 | ||
a1c0d005 | 3542 | rc = dfs_mount_share(&mnt_ctx, &isdfs); |
c88f7dcd | 3543 | if (rc) |
56c762eb | 3544 | goto error; |
c88f7dcd PA |
3545 | if (!isdfs) |
3546 | goto out; | |
c9f71103 | 3547 | |
5fc7fcd0 | 3548 | /* |
c88f7dcd PA |
3549 | * After reconnecting to a different server, unique ids won't match anymore, so we disable |
3550 | * serverino. This prevents dentry revalidation to think the dentry are stale (ESTALE). | |
5fc7fcd0 AA |
3551 | */ |
3552 | cifs_autodisable_serverino(cifs_sb); | |
bacd704a | 3553 | /* |
c88f7dcd PA |
3554 | * Force the use of prefix path to support failover on DFS paths that resolve to targets |
3555 | * that have different prefix paths. | |
bacd704a PAS |
3556 | */ |
3557 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH; | |
3558 | kfree(cifs_sb->prepath); | |
3fa1c6d1 RS |
3559 | cifs_sb->prepath = ctx->prepath; |
3560 | ctx->prepath = NULL; | |
bacd704a | 3561 | |
56c762eb | 3562 | out: |
c88f7dcd | 3563 | cifs_try_adding_channels(cifs_sb, mnt_ctx.ses); |
1dcdf5f5 ZX |
3564 | rc = mount_setup_tlink(cifs_sb, mnt_ctx.ses, mnt_ctx.tcon); |
3565 | if (rc) | |
3566 | goto error; | |
3567 | ||
3568 | free_xid(mnt_ctx.xid); | |
3569 | return rc; | |
9d002df4 | 3570 | |
56c762eb | 3571 | error: |
396935de | 3572 | dfs_put_root_smb_sessions(&mnt_ctx.dfs_ses_list); |
a1c0d005 | 3573 | cifs_mount_put_conns(&mnt_ctx); |
56c762eb PA |
3574 | return rc; |
3575 | } | |
3576 | #else | |
3fa1c6d1 | 3577 | int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) |
56c762eb PA |
3578 | { |
3579 | int rc = 0; | |
a73a26d9 | 3580 | struct cifs_mount_ctx mnt_ctx = { .cifs_sb = cifs_sb, .fs_ctx = ctx, }; |
413e661c | 3581 | |
a1c0d005 | 3582 | rc = cifs_mount_get_session(&mnt_ctx); |
56c762eb PA |
3583 | if (rc) |
3584 | goto error; | |
2de970ff | 3585 | |
a1c0d005 PA |
3586 | rc = cifs_mount_get_tcon(&mnt_ctx); |
3587 | if (rc) | |
3588 | goto error; | |
3589 | ||
3590 | rc = cifs_is_path_remote(&mnt_ctx); | |
3591 | if (rc == -EREMOTE) | |
3592 | rc = -EOPNOTSUPP; | |
3593 | if (rc) | |
3594 | goto error; | |
1bfe73c2 | 3595 | |
1dcdf5f5 ZX |
3596 | rc = mount_setup_tlink(cifs_sb, mnt_ctx.ses, mnt_ctx.tcon); |
3597 | if (rc) | |
3598 | goto error; | |
3599 | ||
c88f7dcd | 3600 | free_xid(mnt_ctx.xid); |
1dcdf5f5 | 3601 | return rc; |
56c762eb PA |
3602 | |
3603 | error: | |
a1c0d005 | 3604 | cifs_mount_put_conns(&mnt_ctx); |
1da177e4 LT |
3605 | return rc; |
3606 | } | |
56c762eb | 3607 | #endif |
1da177e4 | 3608 | |
8d1bca32 | 3609 | /* |
b327a717 | 3610 | * Issue a TREE_CONNECT request. |
8d1bca32 | 3611 | */ |
1da177e4 | 3612 | int |
2e6e02ab | 3613 | CIFSTCon(const unsigned int xid, struct cifs_ses *ses, |
96daf2b0 | 3614 | const char *tree, struct cifs_tcon *tcon, |
1da177e4 LT |
3615 | const struct nls_table *nls_codepage) |
3616 | { | |
3617 | struct smb_hdr *smb_buffer; | |
3618 | struct smb_hdr *smb_buffer_response; | |
3619 | TCONX_REQ *pSMB; | |
3620 | TCONX_RSP *pSMBr; | |
3621 | unsigned char *bcc_ptr; | |
3622 | int rc = 0; | |
690c522f JL |
3623 | int length; |
3624 | __u16 bytes_left, count; | |
1da177e4 LT |
3625 | |
3626 | if (ses == NULL) | |
3627 | return -EIO; | |
3628 | ||
3629 | smb_buffer = cifs_buf_get(); | |
ca43e3be | 3630 | if (smb_buffer == NULL) |
1da177e4 | 3631 | return -ENOMEM; |
ca43e3be | 3632 | |
1da177e4 LT |
3633 | smb_buffer_response = smb_buffer; |
3634 | ||
3635 | header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, | |
3636 | NULL /*no tid */ , 4 /*wct */ ); | |
1982c344 | 3637 | |
88257360 | 3638 | smb_buffer->Mid = get_next_mid(ses->server); |
1da177e4 LT |
3639 | smb_buffer->Uid = ses->Suid; |
3640 | pSMB = (TCONX_REQ *) smb_buffer; | |
3641 | pSMBr = (TCONX_RSP *) smb_buffer_response; | |
3642 | ||
3643 | pSMB->AndXCommand = 0xFF; | |
3644 | pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); | |
1da177e4 | 3645 | bcc_ptr = &pSMB->Password[0]; |
2f6f19c7 RS |
3646 | |
3647 | pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ | |
3648 | *bcc_ptr = 0; /* password is null byte */ | |
3649 | bcc_ptr++; /* skip password */ | |
3650 | /* already aligned so no need to do it below */ | |
1da177e4 | 3651 | |
38d77c50 | 3652 | if (ses->server->sign) |
1da177e4 LT |
3653 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
3654 | ||
3655 | if (ses->capabilities & CAP_STATUS32) { | |
3656 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | |
3657 | } | |
3658 | if (ses->capabilities & CAP_DFS) { | |
3659 | smb_buffer->Flags2 |= SMBFLG2_DFS; | |
3660 | } | |
3661 | if (ses->capabilities & CAP_UNICODE) { | |
3662 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | |
3663 | length = | |
acbbb76a | 3664 | cifs_strtoUTF16((__le16 *) bcc_ptr, tree, |
50c2f753 | 3665 | 6 /* max utf8 char length in bytes */ * |
a878fb22 SF |
3666 | (/* server len*/ + 256 /* share len */), nls_codepage); |
3667 | bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */ | |
1da177e4 LT |
3668 | bcc_ptr += 2; /* skip trailing null */ |
3669 | } else { /* ASCII */ | |
1da177e4 LT |
3670 | strcpy(bcc_ptr, tree); |
3671 | bcc_ptr += strlen(tree) + 1; | |
3672 | } | |
3673 | strcpy(bcc_ptr, "?????"); | |
3674 | bcc_ptr += strlen("?????"); | |
3675 | bcc_ptr += 1; | |
3676 | count = bcc_ptr - &pSMB->Password[0]; | |
1a0e7f7c | 3677 | be32_add_cpu(&pSMB->hdr.smb_buf_length, count); |
1da177e4 LT |
3678 | pSMB->ByteCount = cpu_to_le16(count); |
3679 | ||
133672ef | 3680 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, |
7749981e | 3681 | 0); |
1da177e4 | 3682 | |
1da177e4 | 3683 | /* above now done in SendReceive */ |
b327a717 | 3684 | if (rc == 0) { |
0e0d2cf3 SF |
3685 | bool is_unicode; |
3686 | ||
1da177e4 LT |
3687 | tcon->tid = smb_buffer_response->Tid; |
3688 | bcc_ptr = pByteArea(smb_buffer_response); | |
690c522f | 3689 | bytes_left = get_bcc(smb_buffer_response); |
cc20c031 | 3690 | length = strnlen(bcc_ptr, bytes_left - 2); |
0e0d2cf3 SF |
3691 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) |
3692 | is_unicode = true; | |
3693 | else | |
3694 | is_unicode = false; | |
3695 | ||
cc20c031 | 3696 | |
50c2f753 | 3697 | /* skip service field (NB: this field is always ASCII) */ |
7f8ed420 SF |
3698 | if (length == 3) { |
3699 | if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && | |
3700 | (bcc_ptr[2] == 'C')) { | |
f96637be | 3701 | cifs_dbg(FYI, "IPC connection\n"); |
b327a717 AA |
3702 | tcon->ipc = true; |
3703 | tcon->pipe = true; | |
7f8ed420 SF |
3704 | } |
3705 | } else if (length == 2) { | |
3706 | if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) { | |
3707 | /* the most common case */ | |
f96637be | 3708 | cifs_dbg(FYI, "disk share connection\n"); |
7f8ed420 SF |
3709 | } |
3710 | } | |
50c2f753 | 3711 | bcc_ptr += length + 1; |
cc20c031 | 3712 | bytes_left -= (length + 1); |
68e14569 | 3713 | strscpy(tcon->tree_name, tree, sizeof(tcon->tree_name)); |
cc20c031 JL |
3714 | |
3715 | /* mostly informational -- no need to fail on error here */ | |
90a98b2f | 3716 | kfree(tcon->nativeFileSystem); |
acbbb76a | 3717 | tcon->nativeFileSystem = cifs_strndup_from_utf16(bcc_ptr, |
0e0d2cf3 | 3718 | bytes_left, is_unicode, |
cc20c031 JL |
3719 | nls_codepage); |
3720 | ||
f96637be | 3721 | cifs_dbg(FYI, "nativeFileSystem=%s\n", tcon->nativeFileSystem); |
cc20c031 | 3722 | |
fb8c4b14 | 3723 | if ((smb_buffer_response->WordCount == 3) || |
1a4e15a0 SF |
3724 | (smb_buffer_response->WordCount == 7)) |
3725 | /* field is in same location */ | |
3979877e SF |
3726 | tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); |
3727 | else | |
3728 | tcon->Flags = 0; | |
f96637be | 3729 | cifs_dbg(FYI, "Tcon flags: 0x%x\n", tcon->Flags); |
1da177e4 LT |
3730 | } |
3731 | ||
a8a11d39 | 3732 | cifs_buf_release(smb_buffer); |
1da177e4 LT |
3733 | return rc; |
3734 | } | |
3735 | ||
2e32cf5e AV |
3736 | static void delayed_free(struct rcu_head *p) |
3737 | { | |
d17abdf7 RS |
3738 | struct cifs_sb_info *cifs_sb = container_of(p, struct cifs_sb_info, rcu); |
3739 | ||
3740 | unload_nls(cifs_sb->local_nls); | |
c741cba2 | 3741 | smb3_cleanup_fs_context(cifs_sb->ctx); |
d17abdf7 | 3742 | kfree(cifs_sb); |
2e32cf5e AV |
3743 | } |
3744 | ||
2a9b9951 AV |
3745 | void |
3746 | cifs_umount(struct cifs_sb_info *cifs_sb) | |
1da177e4 | 3747 | { |
b647c35f JL |
3748 | struct rb_root *root = &cifs_sb->tlink_tree; |
3749 | struct rb_node *node; | |
3750 | struct tcon_link *tlink; | |
9d002df4 | 3751 | |
2de970ff JL |
3752 | cancel_delayed_work_sync(&cifs_sb->prune_tlinks); |
3753 | ||
b647c35f JL |
3754 | spin_lock(&cifs_sb->tlink_tree_lock); |
3755 | while ((node = rb_first(root))) { | |
3756 | tlink = rb_entry(node, struct tcon_link, tl_rbnode); | |
3757 | cifs_get_tlink(tlink); | |
3758 | clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); | |
3759 | rb_erase(node, root); | |
1da177e4 | 3760 | |
b647c35f JL |
3761 | spin_unlock(&cifs_sb->tlink_tree_lock); |
3762 | cifs_put_tlink(tlink); | |
3763 | spin_lock(&cifs_sb->tlink_tree_lock); | |
3764 | } | |
3765 | spin_unlock(&cifs_sb->tlink_tree_lock); | |
50c2f753 | 3766 | |
a6b5058f | 3767 | kfree(cifs_sb->prepath); |
2e32cf5e | 3768 | call_rcu(&cifs_sb->rcu, delayed_free); |
50c2f753 | 3769 | } |
1da177e4 | 3770 | |
286170aa | 3771 | int |
f486ef8e SP |
3772 | cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses, |
3773 | struct TCP_Server_Info *server) | |
1da177e4 LT |
3774 | { |
3775 | int rc = 0; | |
1da177e4 | 3776 | |
286170aa PS |
3777 | if (!server->ops->need_neg || !server->ops->negotiate) |
3778 | return -ENOSYS; | |
3779 | ||
198b5682 | 3780 | /* only send once per connect */ |
d7d7a66a | 3781 | spin_lock(&server->srv_lock); |
bc962159 SP |
3782 | if (server->tcpStatus != CifsGood && |
3783 | server->tcpStatus != CifsNew && | |
73f9bfbe | 3784 | server->tcpStatus != CifsNeedNegotiate) { |
bc962159 SP |
3785 | spin_unlock(&server->srv_lock); |
3786 | return -EHOSTDOWN; | |
3787 | } | |
3788 | ||
3789 | if (!server->ops->need_neg(server) && | |
3790 | server->tcpStatus == CifsGood) { | |
d7d7a66a | 3791 | spin_unlock(&server->srv_lock); |
198b5682 | 3792 | return 0; |
73f9bfbe | 3793 | } |
bc962159 | 3794 | |
73f9bfbe | 3795 | server->tcpStatus = CifsInNegotiate; |
d7d7a66a | 3796 | spin_unlock(&server->srv_lock); |
198b5682 | 3797 | |
f486ef8e | 3798 | rc = server->ops->negotiate(xid, ses, server); |
198b5682 | 3799 | if (rc == 0) { |
d7d7a66a | 3800 | spin_lock(&server->srv_lock); |
73f9bfbe | 3801 | if (server->tcpStatus == CifsInNegotiate) |
1a6a41d4 | 3802 | server->tcpStatus = CifsGood; |
198b5682 JL |
3803 | else |
3804 | rc = -EHOSTDOWN; | |
d7d7a66a | 3805 | spin_unlock(&server->srv_lock); |
a05885ce | 3806 | } else { |
d7d7a66a | 3807 | spin_lock(&server->srv_lock); |
a05885ce SP |
3808 | if (server->tcpStatus == CifsInNegotiate) |
3809 | server->tcpStatus = CifsNeedNegotiate; | |
d7d7a66a | 3810 | spin_unlock(&server->srv_lock); |
198b5682 JL |
3811 | } |
3812 | ||
3813 | return rc; | |
3814 | } | |
3815 | ||
58c45c58 PS |
3816 | int |
3817 | cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, | |
f486ef8e | 3818 | struct TCP_Server_Info *server, |
58c45c58 | 3819 | struct nls_table *nls_info) |
198b5682 | 3820 | { |
58c45c58 | 3821 | int rc = -ENOSYS; |
b3773b19 | 3822 | struct TCP_Server_Info *pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; |
e77978de SP |
3823 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&pserver->dstaddr; |
3824 | struct sockaddr_in *addr = (struct sockaddr_in *)&pserver->dstaddr; | |
f486ef8e | 3825 | bool is_binding = false; |
26b994fa | 3826 | |
d7d7a66a | 3827 | spin_lock(&ses->ses_lock); |
bc962159 SP |
3828 | cifs_dbg(FYI, "%s: channel connect bitmap: 0x%lx\n", |
3829 | __func__, ses->chans_need_reconnect); | |
3830 | ||
5752bf64 SP |
3831 | if (ses->ses_status != SES_GOOD && |
3832 | ses->ses_status != SES_NEW && | |
3833 | ses->ses_status != SES_NEED_RECON) { | |
d7d7a66a | 3834 | spin_unlock(&ses->ses_lock); |
bc962159 | 3835 | return -EHOSTDOWN; |
73f9bfbe | 3836 | } |
dd3cd870 | 3837 | |
5752bf64 SP |
3838 | /* only send once per connect */ |
3839 | spin_lock(&ses->chan_lock); | |
bc962159 SP |
3840 | if (CIFS_ALL_CHANS_GOOD(ses)) { |
3841 | if (ses->ses_status == SES_NEED_RECON) | |
3842 | ses->ses_status = SES_GOOD; | |
5752bf64 | 3843 | spin_unlock(&ses->chan_lock); |
d7d7a66a | 3844 | spin_unlock(&ses->ses_lock); |
5752bf64 SP |
3845 | return 0; |
3846 | } | |
bc962159 | 3847 | |
5752bf64 | 3848 | cifs_chan_set_in_reconnect(ses, server); |
bc962159 | 3849 | is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses); |
5752bf64 SP |
3850 | spin_unlock(&ses->chan_lock); |
3851 | ||
dd3cd870 SP |
3852 | if (!is_binding) |
3853 | ses->ses_status = SES_IN_SETUP; | |
d7d7a66a | 3854 | spin_unlock(&ses->ses_lock); |
73f9bfbe | 3855 | |
e77978de SP |
3856 | /* update ses ip_addr only for primary chan */ |
3857 | if (server == pserver) { | |
3858 | if (server->dstaddr.ss_family == AF_INET6) | |
3859 | scnprintf(ses->ip_addr, sizeof(ses->ip_addr), "%pI6", &addr6->sin6_addr); | |
3860 | else | |
3861 | scnprintf(ses->ip_addr, sizeof(ses->ip_addr), "%pI4", &addr->sin_addr); | |
3862 | } | |
3863 | ||
f486ef8e | 3864 | if (!is_binding) { |
d70e9fa5 | 3865 | ses->capabilities = server->capabilities; |
ed6b1920 | 3866 | if (!linuxExtEnabled) |
d70e9fa5 AA |
3867 | ses->capabilities &= (~server->vals->cap_unix); |
3868 | ||
3869 | if (ses->auth_key.response) { | |
3870 | cifs_dbg(FYI, "Free previous auth_key.response = %p\n", | |
3871 | ses->auth_key.response); | |
a4e430c8 | 3872 | kfree_sensitive(ses->auth_key.response); |
d70e9fa5 AA |
3873 | ses->auth_key.response = NULL; |
3874 | ses->auth_key.len = 0; | |
3875 | } | |
3876 | } | |
20418acd | 3877 | |
f96637be | 3878 | cifs_dbg(FYI, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d\n", |
96daf2b0 | 3879 | server->sec_mode, server->capabilities, server->timeAdj); |
cb7691b6 | 3880 | |
58c45c58 | 3881 | if (server->ops->sess_setup) |
f486ef8e | 3882 | rc = server->ops->sess_setup(xid, ses, server, nls_info); |
58c45c58 | 3883 | |
a05885ce | 3884 | if (rc) { |
afe6f653 | 3885 | cifs_server_dbg(VFS, "Send error in SessSetup = %d\n", rc); |
d7d7a66a | 3886 | spin_lock(&ses->ses_lock); |
dd3cd870 SP |
3887 | if (ses->ses_status == SES_IN_SETUP) |
3888 | ses->ses_status = SES_NEED_RECON; | |
5752bf64 SP |
3889 | spin_lock(&ses->chan_lock); |
3890 | cifs_chan_clear_in_reconnect(ses, server); | |
3891 | spin_unlock(&ses->chan_lock); | |
d7d7a66a | 3892 | spin_unlock(&ses->ses_lock); |
a05885ce | 3893 | } else { |
d7d7a66a | 3894 | spin_lock(&ses->ses_lock); |
dd3cd870 SP |
3895 | if (ses->ses_status == SES_IN_SETUP) |
3896 | ses->ses_status = SES_GOOD; | |
c1604da7 | 3897 | spin_lock(&ses->chan_lock); |
5752bf64 | 3898 | cifs_chan_clear_in_reconnect(ses, server); |
c1604da7 SP |
3899 | cifs_chan_clear_need_reconnect(ses, server); |
3900 | spin_unlock(&ses->chan_lock); | |
d7d7a66a | 3901 | spin_unlock(&ses->ses_lock); |
a05885ce | 3902 | } |
21e73393 | 3903 | |
1da177e4 LT |
3904 | return rc; |
3905 | } | |
3906 | ||
8a8798a5 | 3907 | static int |
3fa1c6d1 | 3908 | cifs_set_vol_auth(struct smb3_fs_context *ctx, struct cifs_ses *ses) |
8a8798a5 | 3909 | { |
3fa1c6d1 | 3910 | ctx->sectype = ses->sectype; |
3f618223 JL |
3911 | |
3912 | /* krb5 is special, since we don't need username or pw */ | |
3fa1c6d1 | 3913 | if (ctx->sectype == Kerberos) |
8a8798a5 | 3914 | return 0; |
8a8798a5 | 3915 | |
3fa1c6d1 | 3916 | return cifs_set_cifscreds(ctx, ses); |
8a8798a5 JL |
3917 | } |
3918 | ||
96daf2b0 | 3919 | static struct cifs_tcon * |
6d4a0832 | 3920 | cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) |
9d002df4 | 3921 | { |
8a8798a5 | 3922 | int rc; |
96daf2b0 SF |
3923 | struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb); |
3924 | struct cifs_ses *ses; | |
3925 | struct cifs_tcon *tcon = NULL; | |
3fa1c6d1 | 3926 | struct smb3_fs_context *ctx; |
9d002df4 | 3927 | |
3fa1c6d1 RS |
3928 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); |
3929 | if (ctx == NULL) | |
803ab977 | 3930 | return ERR_PTR(-ENOMEM); |
9d002df4 | 3931 | |
3fa1c6d1 RS |
3932 | ctx->local_nls = cifs_sb->local_nls; |
3933 | ctx->linux_uid = fsuid; | |
3934 | ctx->cred_uid = fsuid; | |
68e14569 | 3935 | ctx->UNC = master_tcon->tree_name; |
3fa1c6d1 RS |
3936 | ctx->retry = master_tcon->retry; |
3937 | ctx->nocase = master_tcon->nocase; | |
3938 | ctx->nohandlecache = master_tcon->nohandlecache; | |
3939 | ctx->local_lease = master_tcon->local_lease; | |
3940 | ctx->no_lease = master_tcon->no_lease; | |
3941 | ctx->resilient = master_tcon->use_resilient; | |
3942 | ctx->persistent = master_tcon->use_persistent; | |
3943 | ctx->handle_timeout = master_tcon->handle_timeout; | |
3944 | ctx->no_linux_ext = !master_tcon->unix_ext; | |
3945 | ctx->linux_ext = master_tcon->posix_extensions; | |
3946 | ctx->sectype = master_tcon->ses->sectype; | |
3947 | ctx->sign = master_tcon->ses->sign; | |
3948 | ctx->seal = master_tcon->seal; | |
0ac4e291 | 3949 | ctx->witness = master_tcon->use_witness; |
3fa1c6d1 RS |
3950 | |
3951 | rc = cifs_set_vol_auth(ctx, master_tcon->ses); | |
8a8798a5 JL |
3952 | if (rc) { |
3953 | tcon = ERR_PTR(rc); | |
3954 | goto out; | |
3955 | } | |
9d002df4 JL |
3956 | |
3957 | /* get a reference for the same TCP session */ | |
3f9bcca7 | 3958 | spin_lock(&cifs_tcp_ses_lock); |
9d002df4 | 3959 | ++master_tcon->ses->server->srv_count; |
3f9bcca7 | 3960 | spin_unlock(&cifs_tcp_ses_lock); |
9d002df4 | 3961 | |
3fa1c6d1 | 3962 | ses = cifs_get_smb_ses(master_tcon->ses->server, ctx); |
9d002df4 | 3963 | if (IS_ERR(ses)) { |
96daf2b0 | 3964 | tcon = (struct cifs_tcon *)ses; |
53e0e11e | 3965 | cifs_put_tcp_session(master_tcon->ses->server, 0); |
9d002df4 JL |
3966 | goto out; |
3967 | } | |
3968 | ||
3fa1c6d1 | 3969 | tcon = cifs_get_tcon(ses, ctx); |
9d002df4 JL |
3970 | if (IS_ERR(tcon)) { |
3971 | cifs_put_smb_ses(ses); | |
3972 | goto out; | |
3973 | } | |
3974 | ||
fb157ed2 | 3975 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
29e20f9c | 3976 | if (cap_unix(ses)) |
3fa1c6d1 | 3977 | reset_cifs_unix_caps(0, tcon, NULL, ctx); |
fb157ed2 | 3978 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
b326614e | 3979 | |
9d002df4 | 3980 | out: |
3fa1c6d1 RS |
3981 | kfree(ctx->username); |
3982 | kfree_sensitive(ctx->password); | |
3983 | kfree(ctx); | |
9d002df4 JL |
3984 | |
3985 | return tcon; | |
3986 | } | |
3987 | ||
96daf2b0 | 3988 | struct cifs_tcon * |
9d002df4 JL |
3989 | cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb) |
3990 | { | |
3991 | return tlink_tcon(cifs_sb_master_tlink(cifs_sb)); | |
3992 | } | |
3993 | ||
b647c35f JL |
3994 | /* find and return a tlink with given uid */ |
3995 | static struct tcon_link * | |
6d4a0832 | 3996 | tlink_rb_search(struct rb_root *root, kuid_t uid) |
b647c35f JL |
3997 | { |
3998 | struct rb_node *node = root->rb_node; | |
3999 | struct tcon_link *tlink; | |
4000 | ||
4001 | while (node) { | |
4002 | tlink = rb_entry(node, struct tcon_link, tl_rbnode); | |
4003 | ||
6d4a0832 | 4004 | if (uid_gt(tlink->tl_uid, uid)) |
b647c35f | 4005 | node = node->rb_left; |
6d4a0832 | 4006 | else if (uid_lt(tlink->tl_uid, uid)) |
b647c35f JL |
4007 | node = node->rb_right; |
4008 | else | |
4009 | return tlink; | |
4010 | } | |
4011 | return NULL; | |
4012 | } | |
4013 | ||
4014 | /* insert a tcon_link into the tree */ | |
4015 | static void | |
4016 | tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink) | |
4017 | { | |
4018 | struct rb_node **new = &(root->rb_node), *parent = NULL; | |
4019 | struct tcon_link *tlink; | |
4020 | ||
4021 | while (*new) { | |
4022 | tlink = rb_entry(*new, struct tcon_link, tl_rbnode); | |
4023 | parent = *new; | |
4024 | ||
6d4a0832 | 4025 | if (uid_gt(tlink->tl_uid, new_tlink->tl_uid)) |
b647c35f JL |
4026 | new = &((*new)->rb_left); |
4027 | else | |
4028 | new = &((*new)->rb_right); | |
4029 | } | |
4030 | ||
4031 | rb_link_node(&new_tlink->tl_rbnode, parent, new); | |
4032 | rb_insert_color(&new_tlink->tl_rbnode, root); | |
4033 | } | |
4034 | ||
9d002df4 JL |
4035 | /* |
4036 | * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the | |
4037 | * current task. | |
4038 | * | |
4039 | * If the superblock doesn't refer to a multiuser mount, then just return | |
4040 | * the master tcon for the mount. | |
4041 | * | |
6ef933a3 | 4042 | * First, search the rbtree for an existing tcon for this fsuid. If one |
9d002df4 JL |
4043 | * exists, then check to see if it's pending construction. If it is then wait |
4044 | * for construction to complete. Once it's no longer pending, check to see if | |
4045 | * it failed and either return an error or retry construction, depending on | |
4046 | * the timeout. | |
4047 | * | |
4048 | * If one doesn't exist then insert a new tcon_link struct into the tree and | |
4049 | * try to construct a new one. | |
4050 | */ | |
4051 | struct tcon_link * | |
4052 | cifs_sb_tlink(struct cifs_sb_info *cifs_sb) | |
4053 | { | |
4054 | int ret; | |
6d4a0832 | 4055 | kuid_t fsuid = current_fsuid(); |
9d002df4 JL |
4056 | struct tcon_link *tlink, *newtlink; |
4057 | ||
4058 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) | |
4059 | return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); | |
4060 | ||
4061 | spin_lock(&cifs_sb->tlink_tree_lock); | |
b647c35f | 4062 | tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid); |
9d002df4 JL |
4063 | if (tlink) |
4064 | cifs_get_tlink(tlink); | |
4065 | spin_unlock(&cifs_sb->tlink_tree_lock); | |
4066 | ||
4067 | if (tlink == NULL) { | |
4068 | newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL); | |
4069 | if (newtlink == NULL) | |
4070 | return ERR_PTR(-ENOMEM); | |
b647c35f | 4071 | newtlink->tl_uid = fsuid; |
9d002df4 JL |
4072 | newtlink->tl_tcon = ERR_PTR(-EACCES); |
4073 | set_bit(TCON_LINK_PENDING, &newtlink->tl_flags); | |
4074 | set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags); | |
4075 | cifs_get_tlink(newtlink); | |
4076 | ||
9d002df4 JL |
4077 | spin_lock(&cifs_sb->tlink_tree_lock); |
4078 | /* was one inserted after previous search? */ | |
b647c35f | 4079 | tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid); |
9d002df4 JL |
4080 | if (tlink) { |
4081 | cifs_get_tlink(tlink); | |
4082 | spin_unlock(&cifs_sb->tlink_tree_lock); | |
9d002df4 JL |
4083 | kfree(newtlink); |
4084 | goto wait_for_construction; | |
4085 | } | |
9d002df4 | 4086 | tlink = newtlink; |
b647c35f JL |
4087 | tlink_rb_insert(&cifs_sb->tlink_tree, tlink); |
4088 | spin_unlock(&cifs_sb->tlink_tree_lock); | |
9d002df4 JL |
4089 | } else { |
4090 | wait_for_construction: | |
4091 | ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING, | |
9d002df4 JL |
4092 | TASK_INTERRUPTIBLE); |
4093 | if (ret) { | |
4094 | cifs_put_tlink(tlink); | |
74316201 | 4095 | return ERR_PTR(-ERESTARTSYS); |
9d002df4 JL |
4096 | } |
4097 | ||
4098 | /* if it's good, return it */ | |
4099 | if (!IS_ERR(tlink->tl_tcon)) | |
4100 | return tlink; | |
4101 | ||
4102 | /* return error if we tried this already recently */ | |
4103 | if (time_before(jiffies, tlink->tl_time + TLINK_ERROR_EXPIRE)) { | |
4104 | cifs_put_tlink(tlink); | |
4105 | return ERR_PTR(-EACCES); | |
4106 | } | |
4107 | ||
4108 | if (test_and_set_bit(TCON_LINK_PENDING, &tlink->tl_flags)) | |
4109 | goto wait_for_construction; | |
4110 | } | |
4111 | ||
4112 | tlink->tl_tcon = cifs_construct_tcon(cifs_sb, fsuid); | |
4113 | clear_bit(TCON_LINK_PENDING, &tlink->tl_flags); | |
4114 | wake_up_bit(&tlink->tl_flags, TCON_LINK_PENDING); | |
4115 | ||
4116 | if (IS_ERR(tlink->tl_tcon)) { | |
4117 | cifs_put_tlink(tlink); | |
4118 | return ERR_PTR(-EACCES); | |
4119 | } | |
4120 | ||
4121 | return tlink; | |
4122 | } | |
2de970ff JL |
4123 | |
4124 | /* | |
4125 | * periodic workqueue job that scans tcon_tree for a superblock and closes | |
4126 | * out tcons. | |
4127 | */ | |
4128 | static void | |
4129 | cifs_prune_tlinks(struct work_struct *work) | |
4130 | { | |
4131 | struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info, | |
4132 | prune_tlinks.work); | |
b647c35f | 4133 | struct rb_root *root = &cifs_sb->tlink_tree; |
37e12f55 | 4134 | struct rb_node *node; |
b647c35f JL |
4135 | struct rb_node *tmp; |
4136 | struct tcon_link *tlink; | |
2de970ff | 4137 | |
b647c35f JL |
4138 | /* |
4139 | * Because we drop the spinlock in the loop in order to put the tlink | |
4140 | * it's not guarded against removal of links from the tree. The only | |
4141 | * places that remove entries from the tree are this function and | |
4142 | * umounts. Because this function is non-reentrant and is canceled | |
4143 | * before umount can proceed, this is safe. | |
4144 | */ | |
4145 | spin_lock(&cifs_sb->tlink_tree_lock); | |
4146 | node = rb_first(root); | |
4147 | while (node != NULL) { | |
4148 | tmp = node; | |
4149 | node = rb_next(tmp); | |
4150 | tlink = rb_entry(tmp, struct tcon_link, tl_rbnode); | |
4151 | ||
4152 | if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) || | |
4153 | atomic_read(&tlink->tl_count) != 0 || | |
4154 | time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies)) | |
4155 | continue; | |
2de970ff | 4156 | |
b647c35f JL |
4157 | cifs_get_tlink(tlink); |
4158 | clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); | |
4159 | rb_erase(tmp, root); | |
4160 | ||
4161 | spin_unlock(&cifs_sb->tlink_tree_lock); | |
4162 | cifs_put_tlink(tlink); | |
4163 | spin_lock(&cifs_sb->tlink_tree_lock); | |
4164 | } | |
4165 | spin_unlock(&cifs_sb->tlink_tree_lock); | |
2de970ff | 4166 | |
da472fc8 | 4167 | queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks, |
2de970ff JL |
4168 | TLINK_IDLE_EXPIRE); |
4169 | } | |
565674d6 | 4170 | |
1d04a6fe | 4171 | #ifndef CONFIG_CIFS_DFS_UPCALL |
565674d6 SM |
4172 | int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const struct nls_table *nlsc) |
4173 | { | |
3663c904 | 4174 | int rc; |
565674d6 SM |
4175 | const struct smb_version_operations *ops = tcon->ses->server->ops; |
4176 | ||
73f9bfbe | 4177 | /* only send once per connect */ |
d7d7a66a | 4178 | spin_lock(&tcon->tc_lock); |
91f4480c SP |
4179 | if (tcon->status == TID_GOOD) { |
4180 | spin_unlock(&tcon->tc_lock); | |
4181 | return 0; | |
4182 | } | |
4183 | ||
2f0e4f03 SP |
4184 | if (tcon->status != TID_NEW && |
4185 | tcon->status != TID_NEED_TCON) { | |
4186 | spin_unlock(&tcon->tc_lock); | |
4187 | return -EHOSTDOWN; | |
4188 | } | |
4189 | ||
fdf59eb5 | 4190 | tcon->status = TID_IN_TCON; |
d7d7a66a | 4191 | spin_unlock(&tcon->tc_lock); |
73f9bfbe | 4192 | |
68e14569 | 4193 | rc = ops->tree_connect(xid, tcon->ses, tcon->tree_name, tcon, nlsc); |
3663c904 | 4194 | if (rc) { |
d7d7a66a | 4195 | spin_lock(&tcon->tc_lock); |
fdf59eb5 SF |
4196 | if (tcon->status == TID_IN_TCON) |
4197 | tcon->status = TID_NEED_TCON; | |
d7d7a66a | 4198 | spin_unlock(&tcon->tc_lock); |
c1604da7 | 4199 | } else { |
d7d7a66a | 4200 | spin_lock(&tcon->tc_lock); |
fdf59eb5 SF |
4201 | if (tcon->status == TID_IN_TCON) |
4202 | tcon->status = TID_GOOD; | |
c1604da7 | 4203 | tcon->need_reconnect = false; |
d7d7a66a | 4204 | spin_unlock(&tcon->tc_lock); |
3663c904 SP |
4205 | } |
4206 | ||
4207 | return rc; | |
565674d6 SM |
4208 | } |
4209 | #endif |