.. | .. |
---|
21 | 21 | #include <linux/fs.h> |
---|
22 | 22 | #include <linux/net.h> |
---|
23 | 23 | #include <linux/string.h> |
---|
| 24 | +#include <linux/sched/mm.h> |
---|
24 | 25 | #include <linux/sched/signal.h> |
---|
25 | 26 | #include <linux/list.h> |
---|
26 | 27 | #include <linux/wait.h> |
---|
.. | .. |
---|
50 | 51 | #include "cifs_unicode.h" |
---|
51 | 52 | #include "cifs_debug.h" |
---|
52 | 53 | #include "cifs_fs_sb.h" |
---|
53 | | -#include "dns_resolve.h" |
---|
54 | 54 | #include "ntlmssp.h" |
---|
55 | 55 | #include "nterr.h" |
---|
56 | 56 | #include "rfc1002pdu.h" |
---|
57 | 57 | #include "fscache.h" |
---|
58 | 58 | #include "smb2proto.h" |
---|
59 | 59 | #include "smbdirect.h" |
---|
| 60 | +#include "dns_resolve.h" |
---|
| 61 | +#ifdef CONFIG_CIFS_DFS_UPCALL |
---|
| 62 | +#include "dfs_cache.h" |
---|
| 63 | +#endif |
---|
| 64 | +#include "fs_context.h" |
---|
60 | 65 | |
---|
61 | 66 | extern mempool_t *cifs_req_poolp; |
---|
62 | 67 | extern bool disable_legacy_dialects; |
---|
.. | .. |
---|
65 | 70 | #define TLINK_ERROR_EXPIRE (1 * HZ) |
---|
66 | 71 | #define TLINK_IDLE_EXPIRE (600 * HZ) |
---|
67 | 72 | |
---|
| 73 | +/* Drop the connection to not overload the server */ |
---|
| 74 | +#define NUM_STATUS_IO_TIMEOUT 5 |
---|
| 75 | + |
---|
68 | 76 | enum { |
---|
69 | 77 | /* Mount options that take no arguments */ |
---|
70 | 78 | Opt_user_xattr, Opt_nouser_xattr, |
---|
71 | 79 | Opt_forceuid, Opt_noforceuid, |
---|
72 | 80 | Opt_forcegid, Opt_noforcegid, |
---|
73 | 81 | Opt_noblocksend, Opt_noautotune, Opt_nolease, |
---|
74 | | - Opt_hard, Opt_soft, Opt_perm, Opt_noperm, |
---|
| 82 | + Opt_hard, Opt_soft, Opt_perm, Opt_noperm, Opt_nodelete, |
---|
75 | 83 | Opt_mapposix, Opt_nomapposix, |
---|
76 | 84 | Opt_mapchars, Opt_nomapchars, Opt_sfu, |
---|
77 | 85 | Opt_nosfu, Opt_nodfs, Opt_posixpaths, |
---|
.. | .. |
---|
87 | 95 | Opt_serverino, Opt_noserverino, |
---|
88 | 96 | Opt_rwpidforward, Opt_cifsacl, Opt_nocifsacl, |
---|
89 | 97 | Opt_acl, Opt_noacl, Opt_locallease, |
---|
90 | | - Opt_sign, Opt_seal, Opt_noac, |
---|
| 98 | + Opt_sign, Opt_ignore_signature, Opt_seal, Opt_noac, |
---|
91 | 99 | Opt_fsc, Opt_mfsymlinks, |
---|
92 | 100 | Opt_multiuser, Opt_sloppy, Opt_nosharesock, |
---|
93 | 101 | Opt_persistent, Opt_nopersistent, |
---|
94 | 102 | Opt_resilient, Opt_noresilient, |
---|
95 | | - Opt_domainauto, Opt_rdma, |
---|
| 103 | + Opt_domainauto, Opt_rdma, Opt_modesid, Opt_rootfs, |
---|
| 104 | + Opt_multichannel, Opt_nomultichannel, |
---|
| 105 | + Opt_compress, |
---|
96 | 106 | |
---|
97 | 107 | /* Mount options which take numeric value */ |
---|
98 | 108 | Opt_backupuid, Opt_backupgid, Opt_uid, |
---|
99 | 109 | Opt_cruid, Opt_gid, Opt_file_mode, |
---|
100 | 110 | Opt_dirmode, Opt_port, |
---|
101 | | - Opt_rsize, Opt_wsize, Opt_actimeo, |
---|
102 | | - Opt_echo_interval, Opt_max_credits, |
---|
103 | | - Opt_snapshot, |
---|
| 111 | + Opt_min_enc_offload, |
---|
| 112 | + Opt_blocksize, Opt_rsize, Opt_wsize, Opt_actimeo, |
---|
| 113 | + Opt_echo_interval, Opt_max_credits, Opt_handletimeout, |
---|
| 114 | + Opt_snapshot, Opt_max_channels, |
---|
104 | 115 | |
---|
105 | 116 | /* Mount options which take string value */ |
---|
106 | 117 | Opt_user, Opt_pass, Opt_ip, |
---|
.. | .. |
---|
134 | 145 | { Opt_soft, "soft" }, |
---|
135 | 146 | { Opt_perm, "perm" }, |
---|
136 | 147 | { Opt_noperm, "noperm" }, |
---|
| 148 | + { Opt_nodelete, "nodelete" }, |
---|
137 | 149 | { Opt_mapchars, "mapchars" }, /* SFU style */ |
---|
138 | 150 | { Opt_nomapchars, "nomapchars" }, |
---|
139 | 151 | { Opt_mapposix, "mapposix" }, /* SFM style */ |
---|
.. | .. |
---|
172 | 184 | { Opt_serverino, "serverino" }, |
---|
173 | 185 | { Opt_noserverino, "noserverino" }, |
---|
174 | 186 | { Opt_rwpidforward, "rwpidforward" }, |
---|
| 187 | + { Opt_modesid, "modefromsid" }, |
---|
175 | 188 | { Opt_cifsacl, "cifsacl" }, |
---|
176 | 189 | { Opt_nocifsacl, "nocifsacl" }, |
---|
177 | 190 | { Opt_acl, "acl" }, |
---|
178 | 191 | { Opt_noacl, "noacl" }, |
---|
179 | 192 | { Opt_locallease, "locallease" }, |
---|
180 | 193 | { Opt_sign, "sign" }, |
---|
| 194 | + { Opt_ignore_signature, "signloosely" }, |
---|
181 | 195 | { Opt_seal, "seal" }, |
---|
182 | 196 | { Opt_noac, "noac" }, |
---|
183 | 197 | { Opt_fsc, "fsc" }, |
---|
.. | .. |
---|
191 | 205 | { Opt_noresilient, "noresilienthandles"}, |
---|
192 | 206 | { Opt_domainauto, "domainauto"}, |
---|
193 | 207 | { Opt_rdma, "rdma"}, |
---|
| 208 | + { Opt_multichannel, "multichannel" }, |
---|
| 209 | + { Opt_nomultichannel, "nomultichannel" }, |
---|
194 | 210 | |
---|
195 | 211 | { Opt_backupuid, "backupuid=%s" }, |
---|
196 | 212 | { Opt_backupgid, "backupgid=%s" }, |
---|
.. | .. |
---|
201 | 217 | { Opt_dirmode, "dirmode=%s" }, |
---|
202 | 218 | { Opt_dirmode, "dir_mode=%s" }, |
---|
203 | 219 | { Opt_port, "port=%s" }, |
---|
| 220 | + { Opt_min_enc_offload, "esize=%s" }, |
---|
| 221 | + { Opt_blocksize, "bsize=%s" }, |
---|
204 | 222 | { Opt_rsize, "rsize=%s" }, |
---|
205 | 223 | { Opt_wsize, "wsize=%s" }, |
---|
206 | 224 | { Opt_actimeo, "actimeo=%s" }, |
---|
| 225 | + { Opt_handletimeout, "handletimeout=%s" }, |
---|
207 | 226 | { Opt_echo_interval, "echo_interval=%s" }, |
---|
208 | 227 | { Opt_max_credits, "max_credits=%s" }, |
---|
209 | 228 | { Opt_snapshot, "snapshot=%s" }, |
---|
| 229 | + { Opt_max_channels, "max_channels=%s" }, |
---|
| 230 | + { Opt_compress, "compress=%s" }, |
---|
210 | 231 | |
---|
211 | 232 | { Opt_blank_user, "user=" }, |
---|
212 | 233 | { Opt_blank_user, "username=" }, |
---|
.. | .. |
---|
252 | 273 | { Opt_ignore, "dev" }, |
---|
253 | 274 | { Opt_ignore, "mand" }, |
---|
254 | 275 | { Opt_ignore, "nomand" }, |
---|
| 276 | + { Opt_ignore, "relatime" }, |
---|
255 | 277 | { Opt_ignore, "_netdev" }, |
---|
| 278 | + { Opt_rootfs, "rootfs" }, |
---|
256 | 279 | |
---|
257 | 280 | { Opt_err, NULL } |
---|
258 | | -}; |
---|
259 | | - |
---|
260 | | -enum { |
---|
261 | | - Opt_sec_krb5, Opt_sec_krb5i, Opt_sec_krb5p, |
---|
262 | | - Opt_sec_ntlmsspi, Opt_sec_ntlmssp, |
---|
263 | | - Opt_ntlm, Opt_sec_ntlmi, Opt_sec_ntlmv2, |
---|
264 | | - Opt_sec_ntlmv2i, Opt_sec_lanman, |
---|
265 | | - Opt_sec_none, |
---|
266 | | - |
---|
267 | | - Opt_sec_err |
---|
268 | | -}; |
---|
269 | | - |
---|
270 | | -static const match_table_t cifs_secflavor_tokens = { |
---|
271 | | - { Opt_sec_krb5, "krb5" }, |
---|
272 | | - { Opt_sec_krb5i, "krb5i" }, |
---|
273 | | - { Opt_sec_krb5p, "krb5p" }, |
---|
274 | | - { Opt_sec_ntlmsspi, "ntlmsspi" }, |
---|
275 | | - { Opt_sec_ntlmssp, "ntlmssp" }, |
---|
276 | | - { Opt_ntlm, "ntlm" }, |
---|
277 | | - { Opt_sec_ntlmi, "ntlmi" }, |
---|
278 | | - { Opt_sec_ntlmv2, "nontlm" }, |
---|
279 | | - { Opt_sec_ntlmv2, "ntlmv2" }, |
---|
280 | | - { Opt_sec_ntlmv2i, "ntlmv2i" }, |
---|
281 | | - { Opt_sec_lanman, "lanman" }, |
---|
282 | | - { Opt_sec_none, "none" }, |
---|
283 | | - |
---|
284 | | - { Opt_sec_err, NULL } |
---|
285 | | -}; |
---|
286 | | - |
---|
287 | | -/* cache flavors */ |
---|
288 | | -enum { |
---|
289 | | - Opt_cache_loose, |
---|
290 | | - Opt_cache_strict, |
---|
291 | | - Opt_cache_none, |
---|
292 | | - Opt_cache_err |
---|
293 | | -}; |
---|
294 | | - |
---|
295 | | -static const match_table_t cifs_cacheflavor_tokens = { |
---|
296 | | - { Opt_cache_loose, "loose" }, |
---|
297 | | - { Opt_cache_strict, "strict" }, |
---|
298 | | - { Opt_cache_none, "none" }, |
---|
299 | | - { Opt_cache_err, NULL } |
---|
300 | | -}; |
---|
301 | | - |
---|
302 | | -static const match_table_t cifs_smb_version_tokens = { |
---|
303 | | - { Smb_1, SMB1_VERSION_STRING }, |
---|
304 | | - { Smb_20, SMB20_VERSION_STRING}, |
---|
305 | | - { Smb_21, SMB21_VERSION_STRING }, |
---|
306 | | - { Smb_30, SMB30_VERSION_STRING }, |
---|
307 | | - { Smb_302, SMB302_VERSION_STRING }, |
---|
308 | | - { Smb_311, SMB311_VERSION_STRING }, |
---|
309 | | - { Smb_311, ALT_SMB311_VERSION_STRING }, |
---|
310 | | - { Smb_3any, SMB3ANY_VERSION_STRING }, |
---|
311 | | - { Smb_default, SMBDEFAULT_VERSION_STRING }, |
---|
312 | | - { Smb_version_err, NULL } |
---|
313 | 281 | }; |
---|
314 | 282 | |
---|
315 | 283 | static int ip_connect(struct TCP_Server_Info *server); |
---|
316 | 284 | static int generic_ip_connect(struct TCP_Server_Info *server); |
---|
317 | 285 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); |
---|
318 | 286 | static void cifs_prune_tlinks(struct work_struct *work); |
---|
319 | | -static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, |
---|
320 | | - const char *devname, bool is_smb3); |
---|
| 287 | +static char *extract_hostname(const char *unc); |
---|
321 | 288 | |
---|
322 | 289 | /* |
---|
323 | 290 | * Resolve hostname and set ip addr in tcp ses. Useful for hostnames that may |
---|
.. | .. |
---|
342 | 309 | cifs_dbg(FYI, "%s: failed to create UNC path\n", __func__); |
---|
343 | 310 | return -ENOMEM; |
---|
344 | 311 | } |
---|
345 | | - snprintf(unc, len, "\\\\%s", server->hostname); |
---|
| 312 | + scnprintf(unc, len, "\\\\%s", server->hostname); |
---|
346 | 313 | |
---|
347 | 314 | rc = dns_resolve_server_name_to_ip(unc, &ipaddr); |
---|
348 | 315 | kfree(unc); |
---|
.. | .. |
---|
368 | 335 | } |
---|
369 | 336 | #endif |
---|
370 | 337 | |
---|
| 338 | +#ifdef CONFIG_CIFS_DFS_UPCALL |
---|
| 339 | +/* These functions must be called with server->srv_mutex held */ |
---|
| 340 | +static void reconn_set_next_dfs_target(struct TCP_Server_Info *server, |
---|
| 341 | + struct cifs_sb_info *cifs_sb, |
---|
| 342 | + struct dfs_cache_tgt_list *tgt_list, |
---|
| 343 | + struct dfs_cache_tgt_iterator **tgt_it) |
---|
| 344 | +{ |
---|
| 345 | + const char *name; |
---|
| 346 | + |
---|
| 347 | + if (!cifs_sb || !cifs_sb->origin_fullpath) |
---|
| 348 | + return; |
---|
| 349 | + |
---|
| 350 | + if (!*tgt_it) { |
---|
| 351 | + *tgt_it = dfs_cache_get_tgt_iterator(tgt_list); |
---|
| 352 | + } else { |
---|
| 353 | + *tgt_it = dfs_cache_get_next_tgt(tgt_list, *tgt_it); |
---|
| 354 | + if (!*tgt_it) |
---|
| 355 | + *tgt_it = dfs_cache_get_tgt_iterator(tgt_list); |
---|
| 356 | + } |
---|
| 357 | + |
---|
| 358 | + cifs_dbg(FYI, "%s: UNC: %s\n", __func__, cifs_sb->origin_fullpath); |
---|
| 359 | + |
---|
| 360 | + name = dfs_cache_get_tgt_name(*tgt_it); |
---|
| 361 | + |
---|
| 362 | + kfree(server->hostname); |
---|
| 363 | + |
---|
| 364 | + server->hostname = extract_hostname(name); |
---|
| 365 | + if (IS_ERR(server->hostname)) { |
---|
| 366 | + cifs_dbg(FYI, |
---|
| 367 | + "%s: failed to extract hostname from target: %ld\n", |
---|
| 368 | + __func__, PTR_ERR(server->hostname)); |
---|
| 369 | + } |
---|
| 370 | +} |
---|
| 371 | + |
---|
| 372 | +static inline int reconn_setup_dfs_targets(struct cifs_sb_info *cifs_sb, |
---|
| 373 | + struct dfs_cache_tgt_list *tl) |
---|
| 374 | +{ |
---|
| 375 | + if (!cifs_sb->origin_fullpath) |
---|
| 376 | + return -EOPNOTSUPP; |
---|
| 377 | + return dfs_cache_noreq_find(cifs_sb->origin_fullpath + 1, NULL, tl); |
---|
| 378 | +} |
---|
| 379 | +#endif |
---|
| 380 | + |
---|
371 | 381 | /* |
---|
372 | 382 | * cifs tcp session reconnection |
---|
373 | 383 | * |
---|
.. | .. |
---|
385 | 395 | struct cifs_tcon *tcon; |
---|
386 | 396 | struct mid_q_entry *mid_entry; |
---|
387 | 397 | struct list_head retry_list; |
---|
| 398 | +#ifdef CONFIG_CIFS_DFS_UPCALL |
---|
| 399 | + struct super_block *sb = NULL; |
---|
| 400 | + struct cifs_sb_info *cifs_sb = NULL; |
---|
| 401 | + struct dfs_cache_tgt_list tgt_list = {0}; |
---|
| 402 | + struct dfs_cache_tgt_iterator *tgt_it = NULL; |
---|
| 403 | +#endif |
---|
388 | 404 | |
---|
389 | 405 | spin_lock(&GlobalMid_Lock); |
---|
| 406 | + server->nr_targets = 1; |
---|
| 407 | +#ifdef CONFIG_CIFS_DFS_UPCALL |
---|
| 408 | + spin_unlock(&GlobalMid_Lock); |
---|
| 409 | + sb = cifs_get_tcp_super(server); |
---|
| 410 | + if (IS_ERR(sb)) { |
---|
| 411 | + rc = PTR_ERR(sb); |
---|
| 412 | + cifs_dbg(FYI, "%s: will not do DFS failover: rc = %d\n", |
---|
| 413 | + __func__, rc); |
---|
| 414 | + sb = NULL; |
---|
| 415 | + } else { |
---|
| 416 | + cifs_sb = CIFS_SB(sb); |
---|
| 417 | + rc = reconn_setup_dfs_targets(cifs_sb, &tgt_list); |
---|
| 418 | + if (rc) { |
---|
| 419 | + cifs_sb = NULL; |
---|
| 420 | + if (rc != -EOPNOTSUPP) { |
---|
| 421 | + cifs_server_dbg(VFS, "%s: no target servers for DFS failover\n", |
---|
| 422 | + __func__); |
---|
| 423 | + } |
---|
| 424 | + } else { |
---|
| 425 | + server->nr_targets = dfs_cache_get_nr_tgts(&tgt_list); |
---|
| 426 | + } |
---|
| 427 | + } |
---|
| 428 | + cifs_dbg(FYI, "%s: will retry %d target(s)\n", __func__, |
---|
| 429 | + server->nr_targets); |
---|
| 430 | + spin_lock(&GlobalMid_Lock); |
---|
| 431 | +#endif |
---|
390 | 432 | if (server->tcpStatus == CifsExiting) { |
---|
391 | 433 | /* the demux thread will exit normally |
---|
392 | 434 | next time through the loop */ |
---|
393 | 435 | spin_unlock(&GlobalMid_Lock); |
---|
| 436 | +#ifdef CONFIG_CIFS_DFS_UPCALL |
---|
| 437 | + dfs_cache_free_tgts(&tgt_list); |
---|
| 438 | + cifs_put_tcp_super(sb); |
---|
| 439 | +#endif |
---|
| 440 | + wake_up(&server->response_q); |
---|
394 | 441 | return rc; |
---|
395 | 442 | } else |
---|
396 | 443 | server->tcpStatus = CifsNeedReconnect; |
---|
.. | .. |
---|
398 | 445 | server->maxBuf = 0; |
---|
399 | 446 | server->max_read = 0; |
---|
400 | 447 | |
---|
401 | | - cifs_dbg(FYI, "Reconnecting tcp session\n"); |
---|
| 448 | + cifs_dbg(FYI, "Mark tcp session as need reconnect\n"); |
---|
402 | 449 | trace_smb3_reconnect(server->CurrentMid, server->hostname); |
---|
403 | 450 | |
---|
404 | 451 | /* before reconnecting the tcp session, mark the smb session (uid) |
---|
.. | .. |
---|
443 | 490 | spin_lock(&GlobalMid_Lock); |
---|
444 | 491 | list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { |
---|
445 | 492 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
---|
| 493 | + kref_get(&mid_entry->refcount); |
---|
446 | 494 | if (mid_entry->mid_state == MID_REQUEST_SUBMITTED) |
---|
447 | 495 | mid_entry->mid_state = MID_RETRY_NEEDED; |
---|
448 | 496 | list_move(&mid_entry->qhead, &retry_list); |
---|
| 497 | + mid_entry->mid_flags |= MID_DELETED; |
---|
449 | 498 | } |
---|
450 | 499 | spin_unlock(&GlobalMid_Lock); |
---|
451 | 500 | mutex_unlock(&server->srv_mutex); |
---|
.. | .. |
---|
455 | 504 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
---|
456 | 505 | list_del_init(&mid_entry->qhead); |
---|
457 | 506 | mid_entry->callback(mid_entry); |
---|
| 507 | + cifs_mid_q_entry_release(mid_entry); |
---|
| 508 | + } |
---|
| 509 | + |
---|
| 510 | + if (cifs_rdma_enabled(server)) { |
---|
| 511 | + mutex_lock(&server->srv_mutex); |
---|
| 512 | + smbd_destroy(server); |
---|
| 513 | + mutex_unlock(&server->srv_mutex); |
---|
458 | 514 | } |
---|
459 | 515 | |
---|
460 | 516 | do { |
---|
461 | 517 | try_to_freeze(); |
---|
462 | 518 | |
---|
463 | | - /* we should try only the port we connected to before */ |
---|
464 | 519 | mutex_lock(&server->srv_mutex); |
---|
| 520 | +#ifdef CONFIG_CIFS_DFS_UPCALL |
---|
| 521 | + /* |
---|
| 522 | + * Set up next DFS target server (if any) for reconnect. If DFS |
---|
| 523 | + * feature is disabled, then we will retry last server we |
---|
| 524 | + * connected to before. |
---|
| 525 | + */ |
---|
| 526 | + reconn_set_next_dfs_target(server, cifs_sb, &tgt_list, &tgt_it); |
---|
| 527 | +#endif |
---|
| 528 | + rc = reconn_set_ipaddr(server); |
---|
| 529 | + if (rc) { |
---|
| 530 | + cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n", |
---|
| 531 | + __func__, rc); |
---|
| 532 | + } |
---|
| 533 | + |
---|
465 | 534 | if (cifs_rdma_enabled(server)) |
---|
466 | 535 | rc = smbd_reconnect(server); |
---|
467 | 536 | else |
---|
468 | 537 | rc = generic_ip_connect(server); |
---|
469 | 538 | if (rc) { |
---|
470 | 539 | cifs_dbg(FYI, "reconnect error %d\n", rc); |
---|
471 | | - rc = reconn_set_ipaddr(server); |
---|
472 | | - if (rc) { |
---|
473 | | - cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n", |
---|
474 | | - __func__, rc); |
---|
475 | | - } |
---|
476 | 540 | mutex_unlock(&server->srv_mutex); |
---|
477 | 541 | msleep(3000); |
---|
478 | 542 | } else { |
---|
479 | 543 | atomic_inc(&tcpSesReconnectCount); |
---|
| 544 | + set_credits(server, 1); |
---|
480 | 545 | spin_lock(&GlobalMid_Lock); |
---|
481 | 546 | if (server->tcpStatus != CifsExiting) |
---|
482 | 547 | server->tcpStatus = CifsNeedNegotiate; |
---|
.. | .. |
---|
485 | 550 | } |
---|
486 | 551 | } while (server->tcpStatus == CifsNeedReconnect); |
---|
487 | 552 | |
---|
| 553 | +#ifdef CONFIG_CIFS_DFS_UPCALL |
---|
| 554 | + if (tgt_it) { |
---|
| 555 | + rc = dfs_cache_noreq_update_tgthint(cifs_sb->origin_fullpath + 1, |
---|
| 556 | + tgt_it); |
---|
| 557 | + if (rc) { |
---|
| 558 | + cifs_server_dbg(VFS, "%s: failed to update DFS target hint: rc = %d\n", |
---|
| 559 | + __func__, rc); |
---|
| 560 | + } |
---|
| 561 | + rc = dfs_cache_update_vol(cifs_sb->origin_fullpath, server); |
---|
| 562 | + if (rc) { |
---|
| 563 | + cifs_server_dbg(VFS, "%s: failed to update vol info in DFS cache: rc = %d\n", |
---|
| 564 | + __func__, rc); |
---|
| 565 | + } |
---|
| 566 | + dfs_cache_free_tgts(&tgt_list); |
---|
| 567 | + |
---|
| 568 | + } |
---|
| 569 | + |
---|
| 570 | + cifs_put_tcp_super(sb); |
---|
| 571 | +#endif |
---|
488 | 572 | if (server->tcpStatus == CifsNeedNegotiate) |
---|
489 | 573 | mod_delayed_work(cifsiod_wq, &server->echo, 0); |
---|
490 | 574 | |
---|
| 575 | + wake_up(&server->response_q); |
---|
491 | 576 | return rc; |
---|
492 | 577 | } |
---|
493 | 578 | |
---|
.. | .. |
---|
535 | 620 | if (!server->bigbuf) { |
---|
536 | 621 | server->bigbuf = (char *)cifs_buf_get(); |
---|
537 | 622 | if (!server->bigbuf) { |
---|
538 | | - cifs_dbg(VFS, "No memory for large SMB response\n"); |
---|
| 623 | + cifs_server_dbg(VFS, "No memory for large SMB response\n"); |
---|
539 | 624 | msleep(3000); |
---|
540 | 625 | /* retry will check if exiting */ |
---|
541 | 626 | return false; |
---|
.. | .. |
---|
548 | 633 | if (!server->smallbuf) { |
---|
549 | 634 | server->smallbuf = (char *)cifs_small_buf_get(); |
---|
550 | 635 | if (!server->smallbuf) { |
---|
551 | | - cifs_dbg(VFS, "No memory for SMB response\n"); |
---|
| 636 | + cifs_server_dbg(VFS, "No memory for SMB response\n"); |
---|
552 | 637 | msleep(1000); |
---|
553 | 638 | /* retry will check if exiting */ |
---|
554 | 639 | return false; |
---|
.. | .. |
---|
569 | 654 | * We need to wait 3 echo intervals to make sure we handle such |
---|
570 | 655 | * situations right: |
---|
571 | 656 | * 1s client sends a normal SMB request |
---|
572 | | - * 3s client gets a response |
---|
| 657 | + * 2s client gets a response |
---|
573 | 658 | * 30s echo workqueue job pops, and decides we got a response recently |
---|
574 | 659 | * and don't need to send another |
---|
575 | 660 | * ... |
---|
.. | .. |
---|
578 | 663 | */ |
---|
579 | 664 | if ((server->tcpStatus == CifsGood || |
---|
580 | 665 | server->tcpStatus == CifsNeedNegotiate) && |
---|
| 666 | + (!server->ops->can_echo || server->ops->can_echo(server)) && |
---|
581 | 667 | time_after(jiffies, server->lstrp + 3 * server->echo_interval)) { |
---|
582 | | - cifs_dbg(VFS, "Server %s has not responded in %lu seconds. Reconnecting...\n", |
---|
583 | | - server->hostname, (3 * server->echo_interval) / HZ); |
---|
| 668 | + cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n", |
---|
| 669 | + (3 * server->echo_interval) / HZ); |
---|
584 | 670 | cifs_reconnect(server); |
---|
585 | | - wake_up(&server->response_q); |
---|
586 | 671 | return true; |
---|
587 | 672 | } |
---|
588 | 673 | |
---|
.. | .. |
---|
609 | 694 | { |
---|
610 | 695 | int length = 0; |
---|
611 | 696 | int total_read; |
---|
612 | | - |
---|
613 | | - smb_msg->msg_control = NULL; |
---|
614 | | - smb_msg->msg_controllen = 0; |
---|
615 | 697 | |
---|
616 | 698 | for (total_read = 0; msg_data_left(smb_msg); total_read += length) { |
---|
617 | 699 | try_to_freeze(); |
---|
.. | .. |
---|
663 | 745 | cifs_read_from_socket(struct TCP_Server_Info *server, char *buf, |
---|
664 | 746 | unsigned int to_read) |
---|
665 | 747 | { |
---|
666 | | - struct msghdr smb_msg; |
---|
| 748 | + struct msghdr smb_msg = {}; |
---|
667 | 749 | struct kvec iov = {.iov_base = buf, .iov_len = to_read}; |
---|
668 | | - iov_iter_kvec(&smb_msg.msg_iter, READ | ITER_KVEC, &iov, 1, to_read); |
---|
| 750 | + iov_iter_kvec(&smb_msg.msg_iter, READ, &iov, 1, to_read); |
---|
| 751 | + |
---|
| 752 | + return cifs_readv_from_socket(server, &smb_msg); |
---|
| 753 | +} |
---|
| 754 | + |
---|
| 755 | +ssize_t |
---|
| 756 | +cifs_discard_from_socket(struct TCP_Server_Info *server, size_t to_read) |
---|
| 757 | +{ |
---|
| 758 | + struct msghdr smb_msg = {}; |
---|
| 759 | + |
---|
| 760 | + /* |
---|
| 761 | + * iov_iter_discard already sets smb_msg.type and count and iov_offset |
---|
| 762 | + * and cifs_readv_from_socket sets msg_control and msg_controllen |
---|
| 763 | + * so little to initialize in struct msghdr |
---|
| 764 | + */ |
---|
| 765 | + iov_iter_discard(&smb_msg.msg_iter, READ, to_read); |
---|
669 | 766 | |
---|
670 | 767 | return cifs_readv_from_socket(server, &smb_msg); |
---|
671 | 768 | } |
---|
.. | .. |
---|
674 | 771 | cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page, |
---|
675 | 772 | unsigned int page_offset, unsigned int to_read) |
---|
676 | 773 | { |
---|
677 | | - struct msghdr smb_msg; |
---|
| 774 | + struct msghdr smb_msg = {}; |
---|
678 | 775 | struct bio_vec bv = { |
---|
679 | 776 | .bv_page = page, .bv_len = to_read, .bv_offset = page_offset}; |
---|
680 | | - iov_iter_bvec(&smb_msg.msg_iter, READ | ITER_BVEC, &bv, 1, to_read); |
---|
| 777 | + iov_iter_bvec(&smb_msg.msg_iter, READ, &bv, 1, to_read); |
---|
681 | 778 | return cifs_readv_from_socket(server, &smb_msg); |
---|
682 | 779 | } |
---|
683 | 780 | |
---|
.. | .. |
---|
715 | 812 | */ |
---|
716 | 813 | cifs_set_port((struct sockaddr *)&server->dstaddr, CIFS_PORT); |
---|
717 | 814 | cifs_reconnect(server); |
---|
718 | | - wake_up(&server->response_q); |
---|
719 | 815 | break; |
---|
720 | 816 | default: |
---|
721 | | - cifs_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", type); |
---|
| 817 | + cifs_server_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", type); |
---|
722 | 818 | cifs_reconnect(server); |
---|
723 | 819 | } |
---|
724 | 820 | |
---|
.. | .. |
---|
741 | 837 | * function has finished processing it is a bug. |
---|
742 | 838 | */ |
---|
743 | 839 | if (mid->mid_flags & MID_DELETED) |
---|
744 | | - printk_once(KERN_WARNING |
---|
745 | | - "trying to dequeue a deleted mid\n"); |
---|
746 | | - else |
---|
| 840 | + pr_warn_once("trying to dequeue a deleted mid\n"); |
---|
| 841 | + else { |
---|
747 | 842 | list_del_init(&mid->qhead); |
---|
| 843 | + mid->mid_flags |= MID_DELETED; |
---|
| 844 | + } |
---|
748 | 845 | spin_unlock(&GlobalMid_Lock); |
---|
| 846 | +} |
---|
| 847 | + |
---|
| 848 | +static unsigned int |
---|
| 849 | +smb2_get_credits_from_hdr(char *buffer, struct TCP_Server_Info *server) |
---|
| 850 | +{ |
---|
| 851 | + struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer; |
---|
| 852 | + |
---|
| 853 | + /* |
---|
| 854 | + * SMB1 does not use credits. |
---|
| 855 | + */ |
---|
| 856 | + if (server->vals->header_preamble_size) |
---|
| 857 | + return 0; |
---|
| 858 | + |
---|
| 859 | + return le16_to_cpu(shdr->CreditRequest); |
---|
749 | 860 | } |
---|
750 | 861 | |
---|
751 | 862 | static void |
---|
.. | .. |
---|
755 | 866 | if (server->ops->check_trans2 && |
---|
756 | 867 | server->ops->check_trans2(mid, server, buf, malformed)) |
---|
757 | 868 | return; |
---|
| 869 | + mid->credits_received = smb2_get_credits_from_hdr(buf, server); |
---|
758 | 870 | mid->resp_buf = buf; |
---|
759 | 871 | mid->large_buf = server->large_buf; |
---|
760 | 872 | /* Was previous buf put in mpx struct for multi-rsp? */ |
---|
.. | .. |
---|
799 | 911 | wake_up_all(&server->request_q); |
---|
800 | 912 | /* give those requests time to exit */ |
---|
801 | 913 | msleep(125); |
---|
802 | | - if (cifs_rdma_enabled(server) && server->smbd_conn) { |
---|
803 | | - smbd_destroy(server->smbd_conn); |
---|
804 | | - server->smbd_conn = NULL; |
---|
805 | | - } |
---|
| 914 | + if (cifs_rdma_enabled(server)) |
---|
| 915 | + smbd_destroy(server); |
---|
806 | 916 | if (server->ssocket) { |
---|
807 | 917 | sock_release(server->ssocket); |
---|
808 | 918 | server->ssocket = NULL; |
---|
.. | .. |
---|
818 | 928 | list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { |
---|
819 | 929 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
---|
820 | 930 | cifs_dbg(FYI, "Clearing mid 0x%llx\n", mid_entry->mid); |
---|
| 931 | + kref_get(&mid_entry->refcount); |
---|
821 | 932 | mid_entry->mid_state = MID_SHUTDOWN; |
---|
822 | 933 | list_move(&mid_entry->qhead, &dispose_list); |
---|
| 934 | + mid_entry->mid_flags |= MID_DELETED; |
---|
823 | 935 | } |
---|
824 | 936 | spin_unlock(&GlobalMid_Lock); |
---|
825 | 937 | |
---|
.. | .. |
---|
829 | 941 | cifs_dbg(FYI, "Callback mid 0x%llx\n", mid_entry->mid); |
---|
830 | 942 | list_del_init(&mid_entry->qhead); |
---|
831 | 943 | mid_entry->callback(mid_entry); |
---|
| 944 | + cifs_mid_q_entry_release(mid_entry); |
---|
832 | 945 | } |
---|
833 | 946 | /* 1/8th of sec is more than enough time for them to exit */ |
---|
834 | 947 | msleep(125); |
---|
.. | .. |
---|
869 | 982 | /* make sure this will fit in a large buffer */ |
---|
870 | 983 | if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) - |
---|
871 | 984 | server->vals->header_preamble_size) { |
---|
872 | | - cifs_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length); |
---|
| 985 | + cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length); |
---|
873 | 986 | cifs_reconnect(server); |
---|
874 | | - wake_up(&server->response_q); |
---|
875 | 987 | return -ECONNABORTED; |
---|
876 | 988 | } |
---|
877 | 989 | |
---|
.. | .. |
---|
919 | 1031 | if (server->ops->is_session_expired && |
---|
920 | 1032 | server->ops->is_session_expired(buf)) { |
---|
921 | 1033 | cifs_reconnect(server); |
---|
922 | | - wake_up(&server->response_q); |
---|
923 | 1034 | return -1; |
---|
924 | 1035 | } |
---|
925 | 1036 | |
---|
926 | 1037 | if (server->ops->is_status_pending && |
---|
927 | | - server->ops->is_status_pending(buf, server, length)) |
---|
| 1038 | + server->ops->is_status_pending(buf, server)) |
---|
928 | 1039 | return -1; |
---|
929 | 1040 | |
---|
930 | 1041 | if (!mid) |
---|
.. | .. |
---|
965 | 1076 | struct task_struct *task_to_wake = NULL; |
---|
966 | 1077 | struct mid_q_entry *mids[MAX_COMPOUND]; |
---|
967 | 1078 | char *bufs[MAX_COMPOUND]; |
---|
| 1079 | + unsigned int noreclaim_flag, num_io_timeout = 0; |
---|
968 | 1080 | |
---|
969 | | - current->flags |= PF_MEMALLOC; |
---|
| 1081 | + noreclaim_flag = memalloc_noreclaim_save(); |
---|
970 | 1082 | cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current)); |
---|
971 | 1083 | |
---|
972 | 1084 | length = atomic_inc_return(&tcpSesAllocCount); |
---|
.. | .. |
---|
1010 | 1122 | /* make sure we have enough to get to the MID */ |
---|
1011 | 1123 | if (server->pdu_size < HEADER_SIZE(server) - 1 - |
---|
1012 | 1124 | server->vals->header_preamble_size) { |
---|
1013 | | - cifs_dbg(VFS, "SMB response too short (%u bytes)\n", |
---|
| 1125 | + cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n", |
---|
1014 | 1126 | server->pdu_size); |
---|
1015 | 1127 | cifs_reconnect(server); |
---|
1016 | | - wake_up(&server->response_q); |
---|
1017 | 1128 | continue; |
---|
1018 | 1129 | } |
---|
1019 | 1130 | |
---|
.. | .. |
---|
1061 | 1172 | continue; |
---|
1062 | 1173 | } |
---|
1063 | 1174 | |
---|
1064 | | - if (server->large_buf) |
---|
1065 | | - buf = server->bigbuf; |
---|
1066 | | - |
---|
| 1175 | + if (server->ops->is_status_io_timeout && |
---|
| 1176 | + server->ops->is_status_io_timeout(buf)) { |
---|
| 1177 | + num_io_timeout++; |
---|
| 1178 | + if (num_io_timeout > NUM_STATUS_IO_TIMEOUT) { |
---|
| 1179 | + cifs_reconnect(server); |
---|
| 1180 | + num_io_timeout = 0; |
---|
| 1181 | + continue; |
---|
| 1182 | + } |
---|
| 1183 | + } |
---|
1067 | 1184 | |
---|
1068 | 1185 | server->lstrp = jiffies; |
---|
1069 | 1186 | |
---|
1070 | 1187 | for (i = 0; i < num_mids; i++) { |
---|
1071 | 1188 | if (mids[i] != NULL) { |
---|
1072 | 1189 | mids[i]->resp_buf_size = server->pdu_size; |
---|
1073 | | - if ((mids[i]->mid_flags & MID_WAIT_CANCELLED) && |
---|
1074 | | - mids[i]->mid_state == MID_RESPONSE_RECEIVED && |
---|
1075 | | - server->ops->handle_cancelled_mid) |
---|
1076 | | - server->ops->handle_cancelled_mid( |
---|
1077 | | - mids[i]->resp_buf, |
---|
1078 | | - server); |
---|
1079 | 1190 | |
---|
1080 | 1191 | if (!mids[i]->multiRsp || mids[i]->multiEnd) |
---|
1081 | 1192 | mids[i]->callback(mids[i]); |
---|
.. | .. |
---|
1087 | 1198 | smb2_add_credits_from_hdr(bufs[i], server); |
---|
1088 | 1199 | cifs_dbg(FYI, "Received oplock break\n"); |
---|
1089 | 1200 | } else { |
---|
1090 | | - cifs_dbg(VFS, "No task to wake, unknown frame " |
---|
1091 | | - "received! NumMids %d\n", |
---|
1092 | | - atomic_read(&midCount)); |
---|
| 1201 | + cifs_server_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n", |
---|
| 1202 | + atomic_read(&midCount)); |
---|
1093 | 1203 | cifs_dump_mem("Received Data is: ", bufs[i], |
---|
1094 | 1204 | HEADER_SIZE(server)); |
---|
| 1205 | + smb2_add_credits_from_hdr(bufs[i], server); |
---|
1095 | 1206 | #ifdef CONFIG_CIFS_DEBUG2 |
---|
1096 | 1207 | if (server->ops->dump_detail) |
---|
1097 | 1208 | server->ops->dump_detail(bufs[i], |
---|
1098 | 1209 | server); |
---|
1099 | | - smb2_add_credits_from_hdr(bufs[i], server); |
---|
1100 | 1210 | cifs_dump_mids(server); |
---|
1101 | 1211 | #endif /* CIFS_DEBUG2 */ |
---|
1102 | 1212 | } |
---|
.. | .. |
---|
1131 | 1241 | set_current_state(TASK_RUNNING); |
---|
1132 | 1242 | } |
---|
1133 | 1243 | |
---|
| 1244 | + memalloc_noreclaim_restore(noreclaim_flag); |
---|
1134 | 1245 | module_put_and_exit(0); |
---|
1135 | 1246 | } |
---|
1136 | 1247 | |
---|
.. | .. |
---|
1144 | 1255 | |
---|
1145 | 1256 | /* skip double chars at beginning of string */ |
---|
1146 | 1257 | /* BB: check validity of these bytes? */ |
---|
1147 | | - src = unc + 2; |
---|
| 1258 | + if (strlen(unc) < 3) |
---|
| 1259 | + return ERR_PTR(-EINVAL); |
---|
| 1260 | + for (src = unc; *src && *src == '\\'; src++) |
---|
| 1261 | + ; |
---|
| 1262 | + if (!*src) |
---|
| 1263 | + return ERR_PTR(-EINVAL); |
---|
1148 | 1264 | |
---|
1149 | 1265 | /* delimiter between hostname and sharename is always '\\' now */ |
---|
1150 | 1266 | delim = strchr(src, '\\'); |
---|
.. | .. |
---|
1212 | 1328 | return 0; |
---|
1213 | 1329 | } |
---|
1214 | 1330 | |
---|
1215 | | -static int cifs_parse_security_flavors(char *value, |
---|
1216 | | - struct smb_vol *vol) |
---|
1217 | | -{ |
---|
1218 | | - |
---|
1219 | | - substring_t args[MAX_OPT_ARGS]; |
---|
1220 | | - |
---|
1221 | | - /* |
---|
1222 | | - * With mount options, the last one should win. Reset any existing |
---|
1223 | | - * settings back to default. |
---|
1224 | | - */ |
---|
1225 | | - vol->sectype = Unspecified; |
---|
1226 | | - vol->sign = false; |
---|
1227 | | - |
---|
1228 | | - switch (match_token(value, cifs_secflavor_tokens, args)) { |
---|
1229 | | - case Opt_sec_krb5p: |
---|
1230 | | - cifs_dbg(VFS, "sec=krb5p is not supported!\n"); |
---|
1231 | | - return 1; |
---|
1232 | | - case Opt_sec_krb5i: |
---|
1233 | | - vol->sign = true; |
---|
1234 | | - /* Fallthrough */ |
---|
1235 | | - case Opt_sec_krb5: |
---|
1236 | | - vol->sectype = Kerberos; |
---|
1237 | | - break; |
---|
1238 | | - case Opt_sec_ntlmsspi: |
---|
1239 | | - vol->sign = true; |
---|
1240 | | - /* Fallthrough */ |
---|
1241 | | - case Opt_sec_ntlmssp: |
---|
1242 | | - vol->sectype = RawNTLMSSP; |
---|
1243 | | - break; |
---|
1244 | | - case Opt_sec_ntlmi: |
---|
1245 | | - vol->sign = true; |
---|
1246 | | - /* Fallthrough */ |
---|
1247 | | - case Opt_ntlm: |
---|
1248 | | - vol->sectype = NTLM; |
---|
1249 | | - break; |
---|
1250 | | - case Opt_sec_ntlmv2i: |
---|
1251 | | - vol->sign = true; |
---|
1252 | | - /* Fallthrough */ |
---|
1253 | | - case Opt_sec_ntlmv2: |
---|
1254 | | - vol->sectype = NTLMv2; |
---|
1255 | | - break; |
---|
1256 | | -#ifdef CONFIG_CIFS_WEAK_PW_HASH |
---|
1257 | | - case Opt_sec_lanman: |
---|
1258 | | - vol->sectype = LANMAN; |
---|
1259 | | - break; |
---|
1260 | | -#endif |
---|
1261 | | - case Opt_sec_none: |
---|
1262 | | - vol->nullauth = 1; |
---|
1263 | | - break; |
---|
1264 | | - default: |
---|
1265 | | - cifs_dbg(VFS, "bad security option: %s\n", value); |
---|
1266 | | - return 1; |
---|
1267 | | - } |
---|
1268 | | - |
---|
1269 | | - return 0; |
---|
1270 | | -} |
---|
1271 | | - |
---|
1272 | | -static int |
---|
1273 | | -cifs_parse_cache_flavor(char *value, struct smb_vol *vol) |
---|
1274 | | -{ |
---|
1275 | | - substring_t args[MAX_OPT_ARGS]; |
---|
1276 | | - |
---|
1277 | | - switch (match_token(value, cifs_cacheflavor_tokens, args)) { |
---|
1278 | | - case Opt_cache_loose: |
---|
1279 | | - vol->direct_io = false; |
---|
1280 | | - vol->strict_io = false; |
---|
1281 | | - break; |
---|
1282 | | - case Opt_cache_strict: |
---|
1283 | | - vol->direct_io = false; |
---|
1284 | | - vol->strict_io = true; |
---|
1285 | | - break; |
---|
1286 | | - case Opt_cache_none: |
---|
1287 | | - vol->direct_io = true; |
---|
1288 | | - vol->strict_io = false; |
---|
1289 | | - break; |
---|
1290 | | - default: |
---|
1291 | | - cifs_dbg(VFS, "bad cache= option: %s\n", value); |
---|
1292 | | - return 1; |
---|
1293 | | - } |
---|
1294 | | - return 0; |
---|
1295 | | -} |
---|
1296 | | - |
---|
1297 | | -static int |
---|
1298 | | -cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3) |
---|
1299 | | -{ |
---|
1300 | | - substring_t args[MAX_OPT_ARGS]; |
---|
1301 | | - |
---|
1302 | | - switch (match_token(value, cifs_smb_version_tokens, args)) { |
---|
1303 | | -#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
---|
1304 | | - case Smb_1: |
---|
1305 | | - if (disable_legacy_dialects) { |
---|
1306 | | - cifs_dbg(VFS, "mount with legacy dialect disabled\n"); |
---|
1307 | | - return 1; |
---|
1308 | | - } |
---|
1309 | | - if (is_smb3) { |
---|
1310 | | - cifs_dbg(VFS, "vers=1.0 (cifs) not permitted when mounting with smb3\n"); |
---|
1311 | | - return 1; |
---|
1312 | | - } |
---|
1313 | | - vol->ops = &smb1_operations; |
---|
1314 | | - vol->vals = &smb1_values; |
---|
1315 | | - break; |
---|
1316 | | - case Smb_20: |
---|
1317 | | - if (disable_legacy_dialects) { |
---|
1318 | | - cifs_dbg(VFS, "mount with legacy dialect disabled\n"); |
---|
1319 | | - return 1; |
---|
1320 | | - } |
---|
1321 | | - if (is_smb3) { |
---|
1322 | | - cifs_dbg(VFS, "vers=2.0 not permitted when mounting with smb3\n"); |
---|
1323 | | - return 1; |
---|
1324 | | - } |
---|
1325 | | - vol->ops = &smb20_operations; |
---|
1326 | | - vol->vals = &smb20_values; |
---|
1327 | | - break; |
---|
1328 | | -#else |
---|
1329 | | - case Smb_1: |
---|
1330 | | - cifs_dbg(VFS, "vers=1.0 (cifs) mount not permitted when legacy dialects disabled\n"); |
---|
1331 | | - return 1; |
---|
1332 | | - case Smb_20: |
---|
1333 | | - cifs_dbg(VFS, "vers=2.0 mount not permitted when legacy dialects disabled\n"); |
---|
1334 | | - return 1; |
---|
1335 | | -#endif /* CIFS_ALLOW_INSECURE_LEGACY */ |
---|
1336 | | - case Smb_21: |
---|
1337 | | - vol->ops = &smb21_operations; |
---|
1338 | | - vol->vals = &smb21_values; |
---|
1339 | | - break; |
---|
1340 | | - case Smb_30: |
---|
1341 | | - vol->ops = &smb30_operations; |
---|
1342 | | - vol->vals = &smb30_values; |
---|
1343 | | - break; |
---|
1344 | | - case Smb_302: |
---|
1345 | | - vol->ops = &smb30_operations; /* currently identical with 3.0 */ |
---|
1346 | | - vol->vals = &smb302_values; |
---|
1347 | | - break; |
---|
1348 | | - case Smb_311: |
---|
1349 | | - vol->ops = &smb311_operations; |
---|
1350 | | - vol->vals = &smb311_values; |
---|
1351 | | - break; |
---|
1352 | | - case Smb_3any: |
---|
1353 | | - vol->ops = &smb30_operations; /* currently identical with 3.0 */ |
---|
1354 | | - vol->vals = &smb3any_values; |
---|
1355 | | - break; |
---|
1356 | | - case Smb_default: |
---|
1357 | | - vol->ops = &smb30_operations; /* currently identical with 3.0 */ |
---|
1358 | | - vol->vals = &smbdefault_values; |
---|
1359 | | - break; |
---|
1360 | | - default: |
---|
1361 | | - cifs_dbg(VFS, "Unknown vers= option specified: %s\n", value); |
---|
1362 | | - return 1; |
---|
1363 | | - } |
---|
1364 | | - return 0; |
---|
1365 | | -} |
---|
1366 | | - |
---|
1367 | 1331 | /* |
---|
1368 | 1332 | * Parse a devname into substrings and populate the vol->UNC and vol->prepath |
---|
1369 | 1333 | * fields with the result. Returns 0 on success and an error otherwise. |
---|
.. | .. |
---|
1376 | 1340 | size_t len; |
---|
1377 | 1341 | |
---|
1378 | 1342 | if (unlikely(!devname || !*devname)) { |
---|
1379 | | - cifs_dbg(VFS, "Device name not specified.\n"); |
---|
| 1343 | + cifs_dbg(VFS, "Device name not specified\n"); |
---|
1380 | 1344 | return -EINVAL; |
---|
1381 | 1345 | } |
---|
1382 | 1346 | |
---|
.. | .. |
---|
1465 | 1429 | vol->cred_uid = current_uid(); |
---|
1466 | 1430 | vol->linux_uid = current_uid(); |
---|
1467 | 1431 | vol->linux_gid = current_gid(); |
---|
1468 | | - |
---|
| 1432 | + vol->bsize = 1024 * 1024; /* can improve cp performance significantly */ |
---|
1469 | 1433 | /* |
---|
1470 | 1434 | * default to SFM style remapping of seven reserved characters |
---|
1471 | 1435 | * unless user overrides it or we negotiate CIFS POSIX where |
---|
.. | .. |
---|
1488 | 1452 | |
---|
1489 | 1453 | vol->actimeo = CIFS_DEF_ACTIMEO; |
---|
1490 | 1454 | |
---|
| 1455 | + /* Most clients set timeout to 0, allows server to use its default */ |
---|
| 1456 | + vol->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */ |
---|
| 1457 | + |
---|
1491 | 1458 | /* offer SMB2.1 and later (SMB3 etc). Secure and widely accepted */ |
---|
1492 | 1459 | vol->ops = &smb30_operations; |
---|
1493 | 1460 | vol->vals = &smbdefault_values; |
---|
1494 | 1461 | |
---|
1495 | 1462 | vol->echo_interval = SMB_ECHO_INTERVAL_DEFAULT; |
---|
| 1463 | + |
---|
| 1464 | + /* default to no multichannel (single server connection) */ |
---|
| 1465 | + vol->multichannel = false; |
---|
| 1466 | + vol->max_channels = 1; |
---|
1496 | 1467 | |
---|
1497 | 1468 | if (!mountdata) |
---|
1498 | 1469 | goto cifs_parse_mount_err; |
---|
.. | .. |
---|
1519 | 1490 | case 0: |
---|
1520 | 1491 | break; |
---|
1521 | 1492 | case -ENOMEM: |
---|
1522 | | - cifs_dbg(VFS, "Unable to allocate memory for devname.\n"); |
---|
| 1493 | + cifs_dbg(VFS, "Unable to allocate memory for devname\n"); |
---|
1523 | 1494 | goto cifs_parse_mount_err; |
---|
1524 | 1495 | case -EINVAL: |
---|
1525 | | - cifs_dbg(VFS, "Malformed UNC in devname.\n"); |
---|
| 1496 | + cifs_dbg(VFS, "Malformed UNC in devname\n"); |
---|
1526 | 1497 | goto cifs_parse_mount_err; |
---|
1527 | 1498 | default: |
---|
1528 | | - cifs_dbg(VFS, "Unknown error parsing devname.\n"); |
---|
| 1499 | + cifs_dbg(VFS, "Unknown error parsing devname\n"); |
---|
1529 | 1500 | goto cifs_parse_mount_err; |
---|
1530 | 1501 | } |
---|
1531 | 1502 | |
---|
.. | .. |
---|
1585 | 1556 | case Opt_noperm: |
---|
1586 | 1557 | vol->noperm = 1; |
---|
1587 | 1558 | break; |
---|
| 1559 | + case Opt_nodelete: |
---|
| 1560 | + vol->nodelete = 1; |
---|
| 1561 | + break; |
---|
1588 | 1562 | case Opt_mapchars: |
---|
1589 | 1563 | vol->sfu_remap = true; |
---|
1590 | 1564 | vol->remap = false; /* disable SFM mapping */ |
---|
.. | .. |
---|
1607 | 1581 | break; |
---|
1608 | 1582 | case Opt_nodfs: |
---|
1609 | 1583 | vol->nodfs = 1; |
---|
| 1584 | + break; |
---|
| 1585 | + case Opt_rootfs: |
---|
| 1586 | +#ifdef CONFIG_CIFS_ROOT |
---|
| 1587 | + vol->rootfs = true; |
---|
| 1588 | +#endif |
---|
1610 | 1589 | break; |
---|
1611 | 1590 | case Opt_posixpaths: |
---|
1612 | 1591 | vol->posix_paths = 1; |
---|
.. | .. |
---|
1694 | 1673 | case Opt_rwpidforward: |
---|
1695 | 1674 | vol->rwpidforward = 1; |
---|
1696 | 1675 | break; |
---|
| 1676 | + case Opt_modesid: |
---|
| 1677 | + vol->mode_ace = 1; |
---|
| 1678 | + break; |
---|
1697 | 1679 | case Opt_cifsacl: |
---|
1698 | 1680 | vol->cifs_acl = 1; |
---|
1699 | 1681 | break; |
---|
.. | .. |
---|
1712 | 1694 | case Opt_sign: |
---|
1713 | 1695 | vol->sign = true; |
---|
1714 | 1696 | break; |
---|
| 1697 | + case Opt_ignore_signature: |
---|
| 1698 | + vol->sign = true; |
---|
| 1699 | + vol->ignore_signature = true; |
---|
| 1700 | + break; |
---|
1715 | 1701 | case Opt_seal: |
---|
1716 | 1702 | /* we do not do the following in secFlags because seal |
---|
1717 | 1703 | * is a per tree connection (mount) not a per socket |
---|
.. | .. |
---|
1721 | 1707 | vol->seal = 1; |
---|
1722 | 1708 | break; |
---|
1723 | 1709 | case Opt_noac: |
---|
1724 | | - pr_warn("CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n"); |
---|
| 1710 | + pr_warn("Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n"); |
---|
1725 | 1711 | break; |
---|
1726 | 1712 | case Opt_fsc: |
---|
1727 | 1713 | #ifndef CONFIG_CIFS_FSCACHE |
---|
.. | .. |
---|
1774 | 1760 | break; |
---|
1775 | 1761 | case Opt_rdma: |
---|
1776 | 1762 | vol->rdma = true; |
---|
| 1763 | + break; |
---|
| 1764 | + case Opt_multichannel: |
---|
| 1765 | + vol->multichannel = true; |
---|
| 1766 | + /* if number of channels not specified, default to 2 */ |
---|
| 1767 | + if (vol->max_channels < 2) |
---|
| 1768 | + vol->max_channels = 2; |
---|
| 1769 | + break; |
---|
| 1770 | + case Opt_nomultichannel: |
---|
| 1771 | + vol->multichannel = false; |
---|
| 1772 | + vol->max_channels = 1; |
---|
| 1773 | + break; |
---|
| 1774 | + case Opt_compress: |
---|
| 1775 | + vol->compression = UNKNOWN_TYPE; |
---|
| 1776 | + cifs_dbg(VFS, |
---|
| 1777 | + "SMB3 compression support is experimental\n"); |
---|
1777 | 1778 | break; |
---|
1778 | 1779 | |
---|
1779 | 1780 | /* Numeric Values */ |
---|
.. | .. |
---|
1841 | 1842 | } |
---|
1842 | 1843 | port = (unsigned short)option; |
---|
1843 | 1844 | break; |
---|
| 1845 | + case Opt_min_enc_offload: |
---|
| 1846 | + if (get_option_ul(args, &option)) { |
---|
| 1847 | + cifs_dbg(VFS, "Invalid minimum encrypted read offload size (esize)\n"); |
---|
| 1848 | + goto cifs_parse_mount_err; |
---|
| 1849 | + } |
---|
| 1850 | + vol->min_offload = option; |
---|
| 1851 | + break; |
---|
| 1852 | + case Opt_blocksize: |
---|
| 1853 | + if (get_option_ul(args, &option)) { |
---|
| 1854 | + cifs_dbg(VFS, "%s: Invalid blocksize value\n", |
---|
| 1855 | + __func__); |
---|
| 1856 | + goto cifs_parse_mount_err; |
---|
| 1857 | + } |
---|
| 1858 | + /* |
---|
| 1859 | + * inode blocksize realistically should never need to be |
---|
| 1860 | + * less than 16K or greater than 16M and default is 1MB. |
---|
| 1861 | + * Note that small inode block sizes (e.g. 64K) can lead |
---|
| 1862 | + * to very poor performance of common tools like cp and scp |
---|
| 1863 | + */ |
---|
| 1864 | + if ((option < CIFS_MAX_MSGSIZE) || |
---|
| 1865 | + (option > (4 * SMB3_DEFAULT_IOSIZE))) { |
---|
| 1866 | + cifs_dbg(VFS, "%s: Invalid blocksize\n", |
---|
| 1867 | + __func__); |
---|
| 1868 | + goto cifs_parse_mount_err; |
---|
| 1869 | + } |
---|
| 1870 | + vol->bsize = option; |
---|
| 1871 | + break; |
---|
1844 | 1872 | case Opt_rsize: |
---|
1845 | 1873 | if (get_option_ul(args, &option)) { |
---|
1846 | 1874 | cifs_dbg(VFS, "%s: Invalid rsize value\n", |
---|
.. | .. |
---|
1869 | 1897 | goto cifs_parse_mount_err; |
---|
1870 | 1898 | } |
---|
1871 | 1899 | break; |
---|
| 1900 | + case Opt_handletimeout: |
---|
| 1901 | + if (get_option_ul(args, &option)) { |
---|
| 1902 | + cifs_dbg(VFS, "%s: Invalid handletimeout value\n", |
---|
| 1903 | + __func__); |
---|
| 1904 | + goto cifs_parse_mount_err; |
---|
| 1905 | + } |
---|
| 1906 | + vol->handle_timeout = option; |
---|
| 1907 | + if (vol->handle_timeout > SMB3_MAX_HANDLE_TIMEOUT) { |
---|
| 1908 | + cifs_dbg(VFS, "Invalid handle cache timeout, longer than 16 minutes\n"); |
---|
| 1909 | + goto cifs_parse_mount_err; |
---|
| 1910 | + } |
---|
| 1911 | + break; |
---|
1872 | 1912 | case Opt_echo_interval: |
---|
1873 | 1913 | if (get_option_ul(args, &option)) { |
---|
1874 | 1914 | cifs_dbg(VFS, "%s: Invalid echo interval value\n", |
---|
.. | .. |
---|
1894 | 1934 | } |
---|
1895 | 1935 | vol->max_credits = option; |
---|
1896 | 1936 | break; |
---|
| 1937 | + case Opt_max_channels: |
---|
| 1938 | + if (get_option_ul(args, &option) || option < 1 || |
---|
| 1939 | + option > CIFS_MAX_CHANNELS) { |
---|
| 1940 | + cifs_dbg(VFS, "%s: Invalid max_channels value, needs to be 1-%d\n", |
---|
| 1941 | + __func__, CIFS_MAX_CHANNELS); |
---|
| 1942 | + goto cifs_parse_mount_err; |
---|
| 1943 | + } |
---|
| 1944 | + vol->max_channels = option; |
---|
| 1945 | + break; |
---|
1897 | 1946 | |
---|
1898 | 1947 | /* String Arguments */ |
---|
1899 | 1948 | |
---|
.. | .. |
---|
1909 | 1958 | |
---|
1910 | 1959 | if (strnlen(string, CIFS_MAX_USERNAME_LEN) > |
---|
1911 | 1960 | CIFS_MAX_USERNAME_LEN) { |
---|
1912 | | - pr_warn("CIFS: username too long\n"); |
---|
| 1961 | + pr_warn("username too long\n"); |
---|
1913 | 1962 | goto cifs_parse_mount_err; |
---|
1914 | 1963 | } |
---|
1915 | 1964 | |
---|
.. | .. |
---|
1932 | 1981 | tmp_end++; |
---|
1933 | 1982 | if (!(tmp_end < end && tmp_end[1] == delim)) { |
---|
1934 | 1983 | /* No it is not. Set the password to NULL */ |
---|
1935 | | - kzfree(vol->password); |
---|
| 1984 | + kfree_sensitive(vol->password); |
---|
1936 | 1985 | vol->password = NULL; |
---|
1937 | 1986 | break; |
---|
1938 | 1987 | } |
---|
1939 | | - /* Yes it is. Drop down to Opt_pass below.*/ |
---|
| 1988 | + fallthrough; /* to Opt_pass below */ |
---|
1940 | 1989 | case Opt_pass: |
---|
1941 | 1990 | /* Obtain the value string */ |
---|
1942 | 1991 | value = strchr(data, '='); |
---|
.. | .. |
---|
1970 | 2019 | options = end; |
---|
1971 | 2020 | } |
---|
1972 | 2021 | |
---|
1973 | | - kzfree(vol->password); |
---|
| 2022 | + kfree_sensitive(vol->password); |
---|
1974 | 2023 | /* Now build new password string */ |
---|
1975 | 2024 | temp_len = strlen(value); |
---|
1976 | 2025 | vol->password = kzalloc(temp_len+1, GFP_KERNEL); |
---|
1977 | 2026 | if (vol->password == NULL) { |
---|
1978 | | - pr_warn("CIFS: no memory for password\n"); |
---|
| 2027 | + pr_warn("no memory for password\n"); |
---|
1979 | 2028 | goto cifs_parse_mount_err; |
---|
1980 | 2029 | } |
---|
1981 | 2030 | |
---|
.. | .. |
---|
1999 | 2048 | |
---|
2000 | 2049 | if (!cifs_convert_address(dstaddr, string, |
---|
2001 | 2050 | strlen(string))) { |
---|
2002 | | - pr_err("CIFS: bad ip= option (%s).\n", string); |
---|
| 2051 | + pr_err("bad ip= option (%s)\n", string); |
---|
2003 | 2052 | goto cifs_parse_mount_err; |
---|
2004 | 2053 | } |
---|
2005 | 2054 | got_ip = true; |
---|
.. | .. |
---|
2011 | 2060 | |
---|
2012 | 2061 | if (strnlen(string, CIFS_MAX_DOMAINNAME_LEN) |
---|
2013 | 2062 | == CIFS_MAX_DOMAINNAME_LEN) { |
---|
2014 | | - pr_warn("CIFS: domain name too long\n"); |
---|
| 2063 | + pr_warn("domain name too long\n"); |
---|
2015 | 2064 | goto cifs_parse_mount_err; |
---|
2016 | 2065 | } |
---|
2017 | 2066 | |
---|
2018 | 2067 | kfree(vol->domainname); |
---|
2019 | 2068 | vol->domainname = kstrdup(string, GFP_KERNEL); |
---|
2020 | 2069 | if (!vol->domainname) { |
---|
2021 | | - pr_warn("CIFS: no memory for domainname\n"); |
---|
| 2070 | + pr_warn("no memory for domainname\n"); |
---|
2022 | 2071 | goto cifs_parse_mount_err; |
---|
2023 | 2072 | } |
---|
2024 | 2073 | cifs_dbg(FYI, "Domain name set\n"); |
---|
.. | .. |
---|
2031 | 2080 | if (!cifs_convert_address( |
---|
2032 | 2081 | (struct sockaddr *)&vol->srcaddr, |
---|
2033 | 2082 | string, strlen(string))) { |
---|
2034 | | - pr_warn("CIFS: Could not parse srcaddr: %s\n", |
---|
| 2083 | + pr_warn("Could not parse srcaddr: %s\n", |
---|
2035 | 2084 | string); |
---|
2036 | 2085 | goto cifs_parse_mount_err; |
---|
2037 | 2086 | } |
---|
.. | .. |
---|
2042 | 2091 | goto out_nomem; |
---|
2043 | 2092 | |
---|
2044 | 2093 | if (strnlen(string, 1024) >= 65) { |
---|
2045 | | - pr_warn("CIFS: iocharset name too long.\n"); |
---|
| 2094 | + pr_warn("iocharset name too long\n"); |
---|
2046 | 2095 | goto cifs_parse_mount_err; |
---|
2047 | 2096 | } |
---|
2048 | 2097 | |
---|
.. | .. |
---|
2051 | 2100 | vol->iocharset = kstrdup(string, |
---|
2052 | 2101 | GFP_KERNEL); |
---|
2053 | 2102 | if (!vol->iocharset) { |
---|
2054 | | - pr_warn("CIFS: no memory for charset\n"); |
---|
| 2103 | + pr_warn("no memory for charset\n"); |
---|
2055 | 2104 | goto cifs_parse_mount_err; |
---|
2056 | 2105 | } |
---|
2057 | 2106 | } |
---|
.. | .. |
---|
2082 | 2131 | * set at top of the function |
---|
2083 | 2132 | */ |
---|
2084 | 2133 | if (i == RFC1001_NAME_LEN && string[i] != 0) |
---|
2085 | | - pr_warn("CIFS: netbiosname longer than 15 truncated.\n"); |
---|
| 2134 | + pr_warn("netbiosname longer than 15 truncated\n"); |
---|
2086 | 2135 | break; |
---|
2087 | 2136 | case Opt_servern: |
---|
2088 | 2137 | /* servernetbiosname specified override *SMBSERVER */ |
---|
.. | .. |
---|
2108 | 2157 | /* The string has 16th byte zero still from |
---|
2109 | 2158 | set at top of the function */ |
---|
2110 | 2159 | if (i == RFC1001_NAME_LEN && string[i] != 0) |
---|
2111 | | - pr_warn("CIFS: server netbiosname longer than 15 truncated.\n"); |
---|
| 2160 | + pr_warn("server netbiosname longer than 15 truncated\n"); |
---|
2112 | 2161 | break; |
---|
2113 | 2162 | case Opt_ver: |
---|
2114 | 2163 | /* version of mount userspace tools, not dialect */ |
---|
.. | .. |
---|
2119 | 2168 | /* If interface changes in mount.cifs bump to new ver */ |
---|
2120 | 2169 | if (strncasecmp(string, "1", 1) == 0) { |
---|
2121 | 2170 | if (strlen(string) > 1) { |
---|
2122 | | - pr_warn("Bad mount helper ver=%s. Did " |
---|
2123 | | - "you want SMB1 (CIFS) dialect " |
---|
2124 | | - "and mean to type vers=1.0 " |
---|
2125 | | - "instead?\n", string); |
---|
| 2171 | + pr_warn("Bad mount helper ver=%s. Did you want SMB1 (CIFS) dialect and mean to type vers=1.0 instead?\n", |
---|
| 2172 | + string); |
---|
2126 | 2173 | goto cifs_parse_mount_err; |
---|
2127 | 2174 | } |
---|
2128 | 2175 | /* This is the default */ |
---|
2129 | 2176 | break; |
---|
2130 | 2177 | } |
---|
2131 | 2178 | /* For all other value, error */ |
---|
2132 | | - pr_warn("CIFS: Invalid mount helper version specified\n"); |
---|
| 2179 | + pr_warn("Invalid mount helper version specified\n"); |
---|
2133 | 2180 | goto cifs_parse_mount_err; |
---|
2134 | 2181 | case Opt_vers: |
---|
2135 | 2182 | /* protocol version (dialect) */ |
---|
.. | .. |
---|
2172 | 2219 | } |
---|
2173 | 2220 | |
---|
2174 | 2221 | if (!sloppy && invalid) { |
---|
2175 | | - pr_err("CIFS: Unknown mount option \"%s\"\n", invalid); |
---|
| 2222 | + pr_err("Unknown mount option \"%s\"\n", invalid); |
---|
2176 | 2223 | goto cifs_parse_mount_err; |
---|
2177 | 2224 | } |
---|
2178 | 2225 | |
---|
.. | .. |
---|
2208 | 2255 | slash = strchr(&vol->UNC[2], '\\'); |
---|
2209 | 2256 | len = slash - &vol->UNC[2]; |
---|
2210 | 2257 | if (!cifs_convert_address(dstaddr, &vol->UNC[2], len)) { |
---|
2211 | | - pr_err("Unable to determine destination address.\n"); |
---|
| 2258 | + pr_err("Unable to determine destination address\n"); |
---|
2212 | 2259 | goto cifs_parse_mount_err; |
---|
2213 | 2260 | } |
---|
2214 | 2261 | } |
---|
.. | .. |
---|
2219 | 2266 | if (uid_specified) |
---|
2220 | 2267 | vol->override_uid = override_uid; |
---|
2221 | 2268 | else if (override_uid == 1) |
---|
2222 | | - pr_notice("CIFS: ignoring forceuid mount option specified with no uid= option.\n"); |
---|
| 2269 | + pr_notice("ignoring forceuid mount option specified with no uid= option\n"); |
---|
2223 | 2270 | |
---|
2224 | 2271 | if (gid_specified) |
---|
2225 | 2272 | vol->override_gid = override_gid; |
---|
2226 | 2273 | else if (override_gid == 1) |
---|
2227 | | - pr_notice("CIFS: ignoring forcegid mount option specified with no gid= option.\n"); |
---|
| 2274 | + pr_notice("ignoring forcegid mount option specified with no gid= option\n"); |
---|
2228 | 2275 | |
---|
2229 | 2276 | if (got_version == false) |
---|
2230 | | - pr_warn("No dialect specified on mount. Default has changed to " |
---|
2231 | | - "a more secure dialect, SMB2.1 or later (e.g. SMB3), from CIFS " |
---|
2232 | | - "(SMB1). To use the less secure SMB1 dialect to access " |
---|
2233 | | - "old servers which do not support SMB3 (or SMB2.1) specify vers=1.0" |
---|
2234 | | - " on mount.\n"); |
---|
| 2277 | + pr_warn_once("No dialect specified on mount. Default has changed to a more secure dialect, SMB2.1 or later (e.g. SMB3.1.1), from CIFS (SMB1). To use the less secure SMB1 dialect to access old servers which do not support SMB3.1.1 (or even SMB3 or SMB2.1) specify vers=1.0 on mount.\n"); |
---|
2235 | 2278 | |
---|
2236 | 2279 | kfree(mountdata_copy); |
---|
2237 | 2280 | return 0; |
---|
.. | .. |
---|
2248 | 2291 | * specified, or if srcaddr is specified and |
---|
2249 | 2292 | * matches the IP address of the rhs argument. |
---|
2250 | 2293 | */ |
---|
2251 | | -static bool |
---|
2252 | | -srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs) |
---|
| 2294 | +bool |
---|
| 2295 | +cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs) |
---|
2253 | 2296 | { |
---|
2254 | 2297 | switch (srcaddr->sa_family) { |
---|
2255 | 2298 | case AF_UNSPEC: |
---|
.. | .. |
---|
2279 | 2322 | match_port(struct TCP_Server_Info *server, struct sockaddr *addr) |
---|
2280 | 2323 | { |
---|
2281 | 2324 | __be16 port, *sport; |
---|
| 2325 | + |
---|
| 2326 | + /* SMBDirect manages its own ports, don't match it here */ |
---|
| 2327 | + if (server->rdma) |
---|
| 2328 | + return true; |
---|
2282 | 2329 | |
---|
2283 | 2330 | switch (addr->sa_family) { |
---|
2284 | 2331 | case AF_INET: |
---|
.. | .. |
---|
2336 | 2383 | return false; /* don't expect to be here */ |
---|
2337 | 2384 | } |
---|
2338 | 2385 | |
---|
2339 | | - if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr)) |
---|
| 2386 | + if (!cifs_match_ipaddr(srcaddr, (struct sockaddr *)&server->srcaddr)) |
---|
2340 | 2387 | return false; |
---|
2341 | 2388 | |
---|
2342 | 2389 | return true; |
---|
.. | .. |
---|
2372 | 2419 | if (vol->nosharesock) |
---|
2373 | 2420 | return 0; |
---|
2374 | 2421 | |
---|
2375 | | - /* BB update this for smb3any and default case */ |
---|
2376 | | - if ((server->vals != vol->vals) || (server->ops != vol->ops)) |
---|
| 2422 | + /* If multidialect negotiation see if existing sessions match one */ |
---|
| 2423 | + if (strcmp(vol->vals->version_string, SMB3ANY_VERSION_STRING) == 0) { |
---|
| 2424 | + if (server->vals->protocol_id < SMB30_PROT_ID) |
---|
| 2425 | + return 0; |
---|
| 2426 | + } else if (strcmp(vol->vals->version_string, |
---|
| 2427 | + SMBDEFAULT_VERSION_STRING) == 0) { |
---|
| 2428 | + if (server->vals->protocol_id < SMB21_PROT_ID) |
---|
| 2429 | + return 0; |
---|
| 2430 | + } else if ((server->vals != vol->vals) || (server->ops != vol->ops)) |
---|
2377 | 2431 | return 0; |
---|
2378 | 2432 | |
---|
2379 | 2433 | if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns)) |
---|
.. | .. |
---|
2395 | 2449 | if (server->rdma != vol->rdma) |
---|
2396 | 2450 | return 0; |
---|
2397 | 2451 | |
---|
| 2452 | + if (server->ignore_signature != vol->ignore_signature) |
---|
| 2453 | + return 0; |
---|
| 2454 | + |
---|
| 2455 | + if (server->min_offload != vol->min_offload) |
---|
| 2456 | + return 0; |
---|
| 2457 | + |
---|
2398 | 2458 | return 1; |
---|
2399 | 2459 | } |
---|
2400 | 2460 | |
---|
2401 | | -static struct TCP_Server_Info * |
---|
| 2461 | +struct TCP_Server_Info * |
---|
2402 | 2462 | cifs_find_tcp_session(struct smb_vol *vol) |
---|
2403 | 2463 | { |
---|
2404 | 2464 | struct TCP_Server_Info *server; |
---|
2405 | 2465 | |
---|
2406 | 2466 | spin_lock(&cifs_tcp_ses_lock); |
---|
2407 | 2467 | list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { |
---|
2408 | | - if (!match_server(server, vol)) |
---|
| 2468 | + /* |
---|
| 2469 | + * Skip ses channels since they're only handled in lower layers |
---|
| 2470 | + * (e.g. cifs_send_recv). |
---|
| 2471 | + */ |
---|
| 2472 | + if (server->is_channel || !match_server(server, vol)) |
---|
2409 | 2473 | continue; |
---|
2410 | 2474 | |
---|
2411 | 2475 | ++server->srv_count; |
---|
.. | .. |
---|
2462 | 2526 | send_sig(SIGKILL, task, 1); |
---|
2463 | 2527 | } |
---|
2464 | 2528 | |
---|
2465 | | -static struct TCP_Server_Info * |
---|
| 2529 | +struct TCP_Server_Info * |
---|
2466 | 2530 | cifs_get_tcp_session(struct smb_vol *volume_info) |
---|
2467 | 2531 | { |
---|
2468 | 2532 | struct TCP_Server_Info *tcp_ses = NULL; |
---|
.. | .. |
---|
2490 | 2554 | goto out_err_crypto_release; |
---|
2491 | 2555 | } |
---|
2492 | 2556 | |
---|
2493 | | - tcp_ses->noblocksnd = volume_info->noblocksnd; |
---|
| 2557 | + tcp_ses->noblockcnt = volume_info->rootfs; |
---|
| 2558 | + tcp_ses->noblocksnd = volume_info->noblocksnd || volume_info->rootfs; |
---|
2494 | 2559 | tcp_ses->noautotune = volume_info->noautotune; |
---|
2495 | 2560 | tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay; |
---|
2496 | 2561 | tcp_ses->rdma = volume_info->rdma; |
---|
2497 | 2562 | tcp_ses->in_flight = 0; |
---|
| 2563 | + tcp_ses->max_in_flight = 0; |
---|
2498 | 2564 | tcp_ses->credits = 1; |
---|
2499 | 2565 | init_waitqueue_head(&tcp_ses->response_q); |
---|
2500 | 2566 | init_waitqueue_head(&tcp_ses->request_q); |
---|
.. | .. |
---|
2506 | 2572 | volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); |
---|
2507 | 2573 | tcp_ses->session_estab = false; |
---|
2508 | 2574 | tcp_ses->sequence_number = 0; |
---|
| 2575 | + tcp_ses->reconnect_instance = 1; |
---|
2509 | 2576 | tcp_ses->lstrp = jiffies; |
---|
| 2577 | + tcp_ses->compress_algorithm = cpu_to_le16(volume_info->compression); |
---|
2510 | 2578 | spin_lock_init(&tcp_ses->req_lock); |
---|
2511 | 2579 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); |
---|
2512 | 2580 | INIT_LIST_HEAD(&tcp_ses->smb_ses_list); |
---|
.. | .. |
---|
2517 | 2585 | sizeof(tcp_ses->srcaddr)); |
---|
2518 | 2586 | memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr, |
---|
2519 | 2587 | sizeof(tcp_ses->dstaddr)); |
---|
2520 | | - generate_random_uuid(tcp_ses->client_guid); |
---|
| 2588 | + if (volume_info->use_client_guid) |
---|
| 2589 | + memcpy(tcp_ses->client_guid, volume_info->client_guid, |
---|
| 2590 | + SMB2_CLIENT_GUID_SIZE); |
---|
| 2591 | + else |
---|
| 2592 | + generate_random_uuid(tcp_ses->client_guid); |
---|
2521 | 2593 | /* |
---|
2522 | 2594 | * at this point we are the only ones with the pointer |
---|
2523 | 2595 | * to the struct since the kernel thread not created yet |
---|
.. | .. |
---|
2567 | 2639 | module_put(THIS_MODULE); |
---|
2568 | 2640 | goto out_err_crypto_release; |
---|
2569 | 2641 | } |
---|
| 2642 | + tcp_ses->min_offload = volume_info->min_offload; |
---|
2570 | 2643 | tcp_ses->tcpStatus = CifsNeedNegotiate; |
---|
2571 | 2644 | |
---|
| 2645 | + if ((volume_info->max_credits < 20) || (volume_info->max_credits > 60000)) |
---|
| 2646 | + tcp_ses->max_credits = SMB2_MAX_CREDITS_AVAILABLE; |
---|
| 2647 | + else |
---|
| 2648 | + tcp_ses->max_credits = volume_info->max_credits; |
---|
| 2649 | + |
---|
| 2650 | + tcp_ses->nr_targets = 1; |
---|
| 2651 | + tcp_ses->ignore_signature = volume_info->ignore_signature; |
---|
2572 | 2652 | /* thread spawned, put it on the list */ |
---|
2573 | 2653 | spin_lock(&cifs_tcp_ses_lock); |
---|
2574 | 2654 | list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); |
---|
.. | .. |
---|
2601 | 2681 | { |
---|
2602 | 2682 | if (vol->sectype != Unspecified && |
---|
2603 | 2683 | vol->sectype != ses->sectype) |
---|
| 2684 | + return 0; |
---|
| 2685 | + |
---|
| 2686 | + /* |
---|
| 2687 | + * If an existing session is limited to less channels than |
---|
| 2688 | + * requested, it should not be reused |
---|
| 2689 | + */ |
---|
| 2690 | + if (ses->chan_max < vol->max_channels) |
---|
2604 | 2691 | return 0; |
---|
2605 | 2692 | |
---|
2606 | 2693 | switch (ses->sectype) { |
---|
.. | .. |
---|
2645 | 2732 | struct nls_table *nls_codepage; |
---|
2646 | 2733 | char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0}; |
---|
2647 | 2734 | bool seal = false; |
---|
| 2735 | + struct TCP_Server_Info *server = ses->server; |
---|
2648 | 2736 | |
---|
2649 | 2737 | /* |
---|
2650 | 2738 | * If the mount request that resulted in the creation of the |
---|
2651 | 2739 | * session requires encryption, force IPC to be encrypted too. |
---|
2652 | 2740 | */ |
---|
2653 | 2741 | if (volume_info->seal) { |
---|
2654 | | - if (ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) |
---|
| 2742 | + if (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) |
---|
2655 | 2743 | seal = true; |
---|
2656 | 2744 | else { |
---|
2657 | | - cifs_dbg(VFS, |
---|
| 2745 | + cifs_server_dbg(VFS, |
---|
2658 | 2746 | "IPC: server doesn't support encryption\n"); |
---|
2659 | 2747 | return -EOPNOTSUPP; |
---|
2660 | 2748 | } |
---|
.. | .. |
---|
2664 | 2752 | if (tcon == NULL) |
---|
2665 | 2753 | return -ENOMEM; |
---|
2666 | 2754 | |
---|
2667 | | - snprintf(unc, sizeof(unc), "\\\\%s\\IPC$", ses->server->hostname); |
---|
| 2755 | + scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname); |
---|
2668 | 2756 | |
---|
2669 | 2757 | /* cannot fail */ |
---|
2670 | 2758 | nls_codepage = load_nls_default(); |
---|
.. | .. |
---|
2673 | 2761 | tcon->ses = ses; |
---|
2674 | 2762 | tcon->ipc = true; |
---|
2675 | 2763 | tcon->seal = seal; |
---|
2676 | | - rc = ses->server->ops->tree_connect(xid, ses, unc, tcon, nls_codepage); |
---|
| 2764 | + rc = server->ops->tree_connect(xid, ses, unc, tcon, nls_codepage); |
---|
2677 | 2765 | free_xid(xid); |
---|
2678 | 2766 | |
---|
2679 | 2767 | if (rc) { |
---|
2680 | | - cifs_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc); |
---|
| 2768 | + cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc); |
---|
2681 | 2769 | tconInfoFree(tcon); |
---|
2682 | 2770 | goto out; |
---|
2683 | 2771 | } |
---|
.. | .. |
---|
2737 | 2825 | return NULL; |
---|
2738 | 2826 | } |
---|
2739 | 2827 | |
---|
2740 | | -static void |
---|
2741 | | -cifs_put_smb_ses(struct cifs_ses *ses) |
---|
| 2828 | +void cifs_put_smb_ses(struct cifs_ses *ses) |
---|
2742 | 2829 | { |
---|
2743 | 2830 | unsigned int rc, xid; |
---|
2744 | 2831 | struct TCP_Server_Info *server = ses->server; |
---|
.. | .. |
---|
2754 | 2841 | spin_unlock(&cifs_tcp_ses_lock); |
---|
2755 | 2842 | return; |
---|
2756 | 2843 | } |
---|
| 2844 | + spin_unlock(&cifs_tcp_ses_lock); |
---|
| 2845 | + |
---|
| 2846 | + spin_lock(&GlobalMid_Lock); |
---|
2757 | 2847 | if (ses->status == CifsGood) |
---|
2758 | 2848 | ses->status = CifsExiting; |
---|
2759 | | - spin_unlock(&cifs_tcp_ses_lock); |
---|
| 2849 | + spin_unlock(&GlobalMid_Lock); |
---|
2760 | 2850 | |
---|
2761 | 2851 | cifs_free_ipc(ses); |
---|
2762 | 2852 | |
---|
.. | .. |
---|
2764 | 2854 | xid = get_xid(); |
---|
2765 | 2855 | rc = server->ops->logoff(xid, ses); |
---|
2766 | 2856 | if (rc) |
---|
2767 | | - cifs_dbg(VFS, "%s: Session Logoff failure rc=%d\n", |
---|
| 2857 | + cifs_server_dbg(VFS, "%s: Session Logoff failure rc=%d\n", |
---|
2768 | 2858 | __func__, rc); |
---|
2769 | 2859 | _free_xid(xid); |
---|
2770 | 2860 | } |
---|
.. | .. |
---|
2772 | 2862 | spin_lock(&cifs_tcp_ses_lock); |
---|
2773 | 2863 | list_del_init(&ses->smb_ses_list); |
---|
2774 | 2864 | spin_unlock(&cifs_tcp_ses_lock); |
---|
| 2865 | + |
---|
| 2866 | + /* close any extra channels */ |
---|
| 2867 | + if (ses->chan_count > 1) { |
---|
| 2868 | + int i; |
---|
| 2869 | + |
---|
| 2870 | + for (i = 1; i < ses->chan_count; i++) |
---|
| 2871 | + cifs_put_tcp_session(ses->chans[i].server, 0); |
---|
| 2872 | + } |
---|
2775 | 2873 | |
---|
2776 | 2874 | sesInfoFree(ses); |
---|
2777 | 2875 | cifs_put_tcp_session(server, 0); |
---|
.. | .. |
---|
2902 | 3000 | strlen(ses->domainName), |
---|
2903 | 3001 | GFP_KERNEL); |
---|
2904 | 3002 | if (!vol->domainname) { |
---|
2905 | | - cifs_dbg(FYI, "Unable to allocate %zd bytes for " |
---|
2906 | | - "domain\n", len); |
---|
| 3003 | + cifs_dbg(FYI, "Unable to allocate %zd bytes for domain\n", |
---|
| 3004 | + len); |
---|
2907 | 3005 | rc = -ENOMEM; |
---|
2908 | 3006 | kfree(vol->username); |
---|
2909 | 3007 | vol->username = NULL; |
---|
2910 | | - kzfree(vol->password); |
---|
| 3008 | + kfree_sensitive(vol->password); |
---|
2911 | 3009 | vol->password = NULL; |
---|
2912 | 3010 | goto out_key_put; |
---|
2913 | 3011 | } |
---|
.. | .. |
---|
2937 | 3035 | * already got a server reference (server refcount +1). See |
---|
2938 | 3036 | * cifs_get_tcon() for refcount explanations. |
---|
2939 | 3037 | */ |
---|
2940 | | -static struct cifs_ses * |
---|
| 3038 | +struct cifs_ses * |
---|
2941 | 3039 | cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) |
---|
2942 | 3040 | { |
---|
2943 | | - int rc = -ENOMEM; |
---|
| 3041 | + int rc = 0; |
---|
2944 | 3042 | unsigned int xid; |
---|
2945 | 3043 | struct cifs_ses *ses; |
---|
2946 | 3044 | struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; |
---|
.. | .. |
---|
2982 | 3080 | return ses; |
---|
2983 | 3081 | } |
---|
2984 | 3082 | |
---|
| 3083 | + rc = -ENOMEM; |
---|
| 3084 | + |
---|
2985 | 3085 | cifs_dbg(FYI, "Existing smb sess not found\n"); |
---|
2986 | 3086 | ses = sesInfoAlloc(); |
---|
2987 | 3087 | if (ses == NULL) |
---|
.. | .. |
---|
3018 | 3118 | |
---|
3019 | 3119 | ses->sectype = volume_info->sectype; |
---|
3020 | 3120 | ses->sign = volume_info->sign; |
---|
3021 | | - |
---|
3022 | 3121 | mutex_lock(&ses->session_mutex); |
---|
| 3122 | + |
---|
| 3123 | + /* add server as first channel */ |
---|
| 3124 | + ses->chans[0].server = server; |
---|
| 3125 | + ses->chan_count = 1; |
---|
| 3126 | + ses->chan_max = volume_info->multichannel ? volume_info->max_channels:1; |
---|
| 3127 | + |
---|
3023 | 3128 | rc = cifs_negotiate_protocol(xid, ses); |
---|
3024 | 3129 | if (!rc) |
---|
3025 | 3130 | rc = cifs_setup_session(xid, ses, volume_info->local_nls); |
---|
| 3131 | + |
---|
| 3132 | + /* each channel uses a different signing key */ |
---|
| 3133 | + memcpy(ses->chans[0].signkey, ses->smb3signingkey, |
---|
| 3134 | + sizeof(ses->smb3signingkey)); |
---|
| 3135 | + |
---|
3026 | 3136 | mutex_unlock(&ses->session_mutex); |
---|
3027 | 3137 | if (rc) |
---|
3028 | 3138 | goto get_ses_fail; |
---|
3029 | 3139 | |
---|
3030 | | - /* success, put it on the list */ |
---|
| 3140 | + /* success, put it on the list and add it as first channel */ |
---|
3031 | 3141 | spin_lock(&cifs_tcp_ses_lock); |
---|
3032 | 3142 | list_add(&ses->smb_ses_list, &server->smb_ses_list); |
---|
3033 | 3143 | spin_unlock(&cifs_tcp_ses_lock); |
---|
.. | .. |
---|
3054 | 3164 | return 0; |
---|
3055 | 3165 | if (tcon->snapshot_time != volume_info->snapshot_time) |
---|
3056 | 3166 | return 0; |
---|
| 3167 | + if (tcon->handle_timeout != volume_info->handle_timeout) |
---|
| 3168 | + return 0; |
---|
3057 | 3169 | if (tcon->no_lease != volume_info->no_lease) |
---|
| 3170 | + return 0; |
---|
| 3171 | + if (tcon->nodelete != volume_info->nodelete) |
---|
3058 | 3172 | return 0; |
---|
3059 | 3173 | return 1; |
---|
3060 | 3174 | } |
---|
.. | .. |
---|
3068 | 3182 | spin_lock(&cifs_tcp_ses_lock); |
---|
3069 | 3183 | list_for_each(tmp, &ses->tcon_list) { |
---|
3070 | 3184 | tcon = list_entry(tmp, struct cifs_tcon, tcon_list); |
---|
| 3185 | +#ifdef CONFIG_CIFS_DFS_UPCALL |
---|
| 3186 | + if (tcon->dfs_path) |
---|
| 3187 | + continue; |
---|
| 3188 | +#endif |
---|
3071 | 3189 | if (!match_tcon(tcon, volume_info)) |
---|
3072 | 3190 | continue; |
---|
3073 | 3191 | ++tcon->tc_count; |
---|
.. | .. |
---|
3170 | 3288 | tcon->snapshot_time = volume_info->snapshot_time; |
---|
3171 | 3289 | } |
---|
3172 | 3290 | |
---|
| 3291 | + if (volume_info->handle_timeout) { |
---|
| 3292 | + if (ses->server->vals->protocol_id == 0) { |
---|
| 3293 | + cifs_dbg(VFS, |
---|
| 3294 | + "Use SMB2.1 or later for handle timeout option\n"); |
---|
| 3295 | + rc = -EOPNOTSUPP; |
---|
| 3296 | + goto out_fail; |
---|
| 3297 | + } else |
---|
| 3298 | + tcon->handle_timeout = volume_info->handle_timeout; |
---|
| 3299 | + } |
---|
| 3300 | + |
---|
3173 | 3301 | tcon->ses = ses; |
---|
3174 | 3302 | if (volume_info->password) { |
---|
3175 | 3303 | tcon->password = kstrdup(volume_info->password, GFP_KERNEL); |
---|
.. | .. |
---|
3198 | 3326 | if (volume_info->linux_ext) { |
---|
3199 | 3327 | if (ses->server->posix_ext_supported) { |
---|
3200 | 3328 | tcon->posix_extensions = true; |
---|
3201 | | - printk_once(KERN_WARNING |
---|
3202 | | - "SMB3.11 POSIX Extensions are experimental\n"); |
---|
| 3329 | + pr_warn_once("SMB3.11 POSIX Extensions are experimental\n"); |
---|
3203 | 3330 | } else { |
---|
3204 | | - cifs_dbg(VFS, "Server does not support mounting with posix SMB3.11 extensions.\n"); |
---|
| 3331 | + cifs_dbg(VFS, "Server does not support mounting with posix SMB3.11 extensions\n"); |
---|
3205 | 3332 | rc = -EOPNOTSUPP; |
---|
3206 | 3333 | goto out_fail; |
---|
3207 | 3334 | } |
---|
.. | .. |
---|
3219 | 3346 | if (rc) |
---|
3220 | 3347 | goto out_fail; |
---|
3221 | 3348 | |
---|
3222 | | - if (volume_info->nodfs) { |
---|
3223 | | - tcon->Flags &= ~SMB_SHARE_IS_IN_DFS; |
---|
3224 | | - cifs_dbg(FYI, "DFS disabled (%d)\n", tcon->Flags); |
---|
3225 | | - } |
---|
3226 | 3349 | tcon->use_persistent = false; |
---|
3227 | 3350 | /* check if SMB2 or later, CIFS does not support persistent handles */ |
---|
3228 | 3351 | if (volume_info->persistent) { |
---|
.. | .. |
---|
3255 | 3378 | tcon->use_resilient = true; |
---|
3256 | 3379 | } |
---|
3257 | 3380 | |
---|
| 3381 | + /* If the user really knows what they are doing they can override */ |
---|
| 3382 | + if (tcon->share_flags & SMB2_SHAREFLAG_NO_CACHING) { |
---|
| 3383 | + if (volume_info->cache_ro) |
---|
| 3384 | + cifs_dbg(VFS, "cache=ro requested on mount but NO_CACHING flag set on share\n"); |
---|
| 3385 | + else if (volume_info->cache_rw) |
---|
| 3386 | + cifs_dbg(VFS, "cache=singleclient requested on mount but NO_CACHING flag set on share\n"); |
---|
| 3387 | + } |
---|
| 3388 | + |
---|
| 3389 | + if (volume_info->no_lease) { |
---|
| 3390 | + if (ses->server->vals->protocol_id == 0) { |
---|
| 3391 | + cifs_dbg(VFS, |
---|
| 3392 | + "SMB2 or later required for nolease option\n"); |
---|
| 3393 | + rc = -EOPNOTSUPP; |
---|
| 3394 | + goto out_fail; |
---|
| 3395 | + } else |
---|
| 3396 | + tcon->no_lease = volume_info->no_lease; |
---|
| 3397 | + } |
---|
| 3398 | + |
---|
3258 | 3399 | /* |
---|
3259 | 3400 | * We can have only one retry value for a connection to a share so for |
---|
3260 | 3401 | * resources mounted more than once to the same server share the last |
---|
.. | .. |
---|
3262 | 3403 | */ |
---|
3263 | 3404 | tcon->retry = volume_info->retry; |
---|
3264 | 3405 | tcon->nocase = volume_info->nocase; |
---|
3265 | | - tcon->nohandlecache = volume_info->nohandlecache; |
---|
| 3406 | + if (ses->server->capabilities & SMB2_GLOBAL_CAP_DIRECTORY_LEASING) |
---|
| 3407 | + tcon->nohandlecache = volume_info->nohandlecache; |
---|
| 3408 | + else |
---|
| 3409 | + tcon->nohandlecache = 1; |
---|
| 3410 | + tcon->nodelete = volume_info->nodelete; |
---|
3266 | 3411 | tcon->local_lease = volume_info->local_lease; |
---|
3267 | | - tcon->no_lease = volume_info->no_lease; |
---|
3268 | 3412 | INIT_LIST_HEAD(&tcon->pending_opens); |
---|
3269 | 3413 | |
---|
3270 | 3414 | spin_lock(&cifs_tcp_ses_lock); |
---|
.. | .. |
---|
3400 | 3544 | return rc; |
---|
3401 | 3545 | } |
---|
3402 | 3546 | |
---|
3403 | | -int |
---|
3404 | | -get_dfs_path(const unsigned int xid, struct cifs_ses *ses, const char *old_path, |
---|
3405 | | - const struct nls_table *nls_codepage, unsigned int *num_referrals, |
---|
3406 | | - struct dfs_info3_param **referrals, int remap) |
---|
3407 | | -{ |
---|
3408 | | - int rc = 0; |
---|
3409 | | - |
---|
3410 | | - if (!ses->server->ops->get_dfs_refer) |
---|
3411 | | - return -ENOSYS; |
---|
3412 | | - |
---|
3413 | | - *num_referrals = 0; |
---|
3414 | | - *referrals = NULL; |
---|
3415 | | - |
---|
3416 | | - rc = ses->server->ops->get_dfs_refer(xid, ses, old_path, |
---|
3417 | | - referrals, num_referrals, |
---|
3418 | | - nls_codepage, remap); |
---|
3419 | | - return rc; |
---|
3420 | | -} |
---|
3421 | | - |
---|
3422 | 3547 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
---|
3423 | 3548 | static struct lock_class_key cifs_key[2]; |
---|
3424 | 3549 | static struct lock_class_key cifs_slock_key[2]; |
---|
.. | .. |
---|
3482 | 3607 | saddr4 = (struct sockaddr_in *)&server->srcaddr; |
---|
3483 | 3608 | saddr6 = (struct sockaddr_in6 *)&server->srcaddr; |
---|
3484 | 3609 | if (saddr6->sin6_family == AF_INET6) |
---|
3485 | | - cifs_dbg(VFS, "Failed to bind to: %pI6c, error: %d\n", |
---|
| 3610 | + cifs_server_dbg(VFS, "Failed to bind to: %pI6c, error: %d\n", |
---|
3486 | 3611 | &saddr6->sin6_addr, rc); |
---|
3487 | 3612 | else |
---|
3488 | | - cifs_dbg(VFS, "Failed to bind to: %pI4, error: %d\n", |
---|
| 3613 | + cifs_server_dbg(VFS, "Failed to bind to: %pI4, error: %d\n", |
---|
3489 | 3614 | &saddr4->sin_addr.s_addr, rc); |
---|
3490 | 3615 | } |
---|
3491 | 3616 | } |
---|
.. | .. |
---|
3576 | 3701 | saddr = (struct sockaddr *) &server->dstaddr; |
---|
3577 | 3702 | |
---|
3578 | 3703 | if (server->dstaddr.ss_family == AF_INET6) { |
---|
3579 | | - sport = ((struct sockaddr_in6 *) saddr)->sin6_port; |
---|
| 3704 | + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&server->dstaddr; |
---|
| 3705 | + |
---|
| 3706 | + sport = ipv6->sin6_port; |
---|
3580 | 3707 | slen = sizeof(struct sockaddr_in6); |
---|
3581 | 3708 | sfamily = AF_INET6; |
---|
| 3709 | + cifs_dbg(FYI, "%s: connecting to [%pI6]:%d\n", __func__, &ipv6->sin6_addr, |
---|
| 3710 | + ntohs(sport)); |
---|
3582 | 3711 | } else { |
---|
3583 | | - sport = ((struct sockaddr_in *) saddr)->sin_port; |
---|
| 3712 | + struct sockaddr_in *ipv4 = (struct sockaddr_in *)&server->dstaddr; |
---|
| 3713 | + |
---|
| 3714 | + sport = ipv4->sin_port; |
---|
3584 | 3715 | slen = sizeof(struct sockaddr_in); |
---|
3585 | 3716 | sfamily = AF_INET; |
---|
| 3717 | + cifs_dbg(FYI, "%s: connecting to %pI4:%d\n", __func__, &ipv4->sin_addr, |
---|
| 3718 | + ntohs(sport)); |
---|
3586 | 3719 | } |
---|
3587 | 3720 | |
---|
3588 | 3721 | if (socket == NULL) { |
---|
3589 | 3722 | rc = __sock_create(cifs_net_ns(server), sfamily, SOCK_STREAM, |
---|
3590 | 3723 | IPPROTO_TCP, &socket, 1); |
---|
3591 | 3724 | if (rc < 0) { |
---|
3592 | | - cifs_dbg(VFS, "Error %d creating socket\n", rc); |
---|
| 3725 | + cifs_server_dbg(VFS, "Error %d creating socket\n", rc); |
---|
3593 | 3726 | server->ssocket = NULL; |
---|
3594 | 3727 | return rc; |
---|
3595 | 3728 | } |
---|
.. | .. |
---|
3624 | 3757 | socket->sk->sk_rcvbuf = 140 * 1024; |
---|
3625 | 3758 | } |
---|
3626 | 3759 | |
---|
3627 | | - if (server->tcp_nodelay) { |
---|
3628 | | - int val = 1; |
---|
3629 | | - rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY, |
---|
3630 | | - (char *)&val, sizeof(val)); |
---|
3631 | | - if (rc) |
---|
3632 | | - cifs_dbg(FYI, "set TCP_NODELAY socket option error %d\n", |
---|
3633 | | - rc); |
---|
3634 | | - } |
---|
| 3760 | + if (server->tcp_nodelay) |
---|
| 3761 | + tcp_sock_set_nodelay(socket->sk); |
---|
3635 | 3762 | |
---|
3636 | 3763 | cifs_dbg(FYI, "sndbuf %d rcvbuf %d rcvtimeo 0x%lx\n", |
---|
3637 | 3764 | socket->sk->sk_sndbuf, |
---|
3638 | 3765 | socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo); |
---|
3639 | 3766 | |
---|
3640 | | - rc = socket->ops->connect(socket, saddr, slen, 0); |
---|
| 3767 | + rc = socket->ops->connect(socket, saddr, slen, |
---|
| 3768 | + server->noblockcnt ? O_NONBLOCK : 0); |
---|
| 3769 | + /* |
---|
| 3770 | + * When mounting SMB root file systems, we do not want to block in |
---|
| 3771 | + * connect. Otherwise bail out and then let cifs_reconnect() perform |
---|
| 3772 | + * reconnect failover - if possible. |
---|
| 3773 | + */ |
---|
| 3774 | + if (server->noblockcnt && rc == -EINPROGRESS) |
---|
| 3775 | + rc = 0; |
---|
3641 | 3776 | if (rc < 0) { |
---|
3642 | 3777 | cifs_dbg(FYI, "Error %d connecting to server\n", rc); |
---|
3643 | 3778 | sock_release(socket); |
---|
.. | .. |
---|
3788 | 3923 | spin_lock_init(&cifs_sb->tlink_tree_lock); |
---|
3789 | 3924 | cifs_sb->tlink_tree = RB_ROOT; |
---|
3790 | 3925 | |
---|
| 3926 | + cifs_sb->bsize = pvolume_info->bsize; |
---|
3791 | 3927 | /* |
---|
3792 | 3928 | * Temporarily set r/wsize for matching superblock. If we end up using |
---|
3793 | 3929 | * new sb then client will later negotiate it downward if needed. |
---|
.. | .. |
---|
3805 | 3941 | cifs_sb->actimeo = pvolume_info->actimeo; |
---|
3806 | 3942 | cifs_sb->local_nls = pvolume_info->local_nls; |
---|
3807 | 3943 | |
---|
| 3944 | + if (pvolume_info->nodfs) |
---|
| 3945 | + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_DFS; |
---|
3808 | 3946 | if (pvolume_info->noperm) |
---|
3809 | 3947 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; |
---|
3810 | 3948 | if (pvolume_info->setuids) |
---|
.. | .. |
---|
3831 | 3969 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL; |
---|
3832 | 3970 | if (pvolume_info->rwpidforward) |
---|
3833 | 3971 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD; |
---|
| 3972 | + if (pvolume_info->mode_ace) |
---|
| 3973 | + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MODE_FROM_SID; |
---|
3834 | 3974 | if (pvolume_info->cifs_acl) |
---|
3835 | 3975 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; |
---|
3836 | 3976 | if (pvolume_info->backupuid_specified) { |
---|
.. | .. |
---|
3858 | 3998 | cifs_dbg(FYI, "mounting share using direct i/o\n"); |
---|
3859 | 3999 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; |
---|
3860 | 4000 | } |
---|
| 4001 | + if (pvolume_info->cache_ro) { |
---|
| 4002 | + cifs_dbg(VFS, "mounting share with read only caching. Ensure that the share will not be modified while in use.\n"); |
---|
| 4003 | + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RO_CACHE; |
---|
| 4004 | + } else if (pvolume_info->cache_rw) { |
---|
| 4005 | + cifs_dbg(VFS, "mounting share in single client RW caching mode. Ensure that no other systems will be accessing the share.\n"); |
---|
| 4006 | + cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_RO_CACHE | |
---|
| 4007 | + CIFS_MOUNT_RW_CACHE); |
---|
| 4008 | + } |
---|
3861 | 4009 | if (pvolume_info->mfsymlinks) { |
---|
3862 | 4010 | if (pvolume_info->sfu_emul) { |
---|
3863 | 4011 | /* |
---|
.. | .. |
---|
3883 | 4031 | cifs_sb->prepath = kstrdup(pvolume_info->prepath, GFP_KERNEL); |
---|
3884 | 4032 | if (cifs_sb->prepath == NULL) |
---|
3885 | 4033 | return -ENOMEM; |
---|
| 4034 | + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH; |
---|
3886 | 4035 | } |
---|
3887 | 4036 | |
---|
3888 | 4037 | return 0; |
---|
3889 | 4038 | } |
---|
3890 | 4039 | |
---|
3891 | | -static void |
---|
3892 | | -cleanup_volume_info_contents(struct smb_vol *volume_info) |
---|
| 4040 | +void |
---|
| 4041 | +cifs_cleanup_volume_info_contents(struct smb_vol *volume_info) |
---|
3893 | 4042 | { |
---|
3894 | 4043 | kfree(volume_info->username); |
---|
3895 | | - kzfree(volume_info->password); |
---|
| 4044 | + kfree_sensitive(volume_info->password); |
---|
3896 | 4045 | kfree(volume_info->UNC); |
---|
3897 | 4046 | kfree(volume_info->domainname); |
---|
3898 | 4047 | kfree(volume_info->iocharset); |
---|
.. | .. |
---|
3904 | 4053 | { |
---|
3905 | 4054 | if (!volume_info) |
---|
3906 | 4055 | return; |
---|
3907 | | - cleanup_volume_info_contents(volume_info); |
---|
| 4056 | + cifs_cleanup_volume_info_contents(volume_info); |
---|
3908 | 4057 | kfree(volume_info); |
---|
3909 | 4058 | } |
---|
3910 | 4059 | |
---|
| 4060 | +/* Release all succeed connections */ |
---|
| 4061 | +static inline void mount_put_conns(struct cifs_sb_info *cifs_sb, |
---|
| 4062 | + unsigned int xid, |
---|
| 4063 | + struct TCP_Server_Info *server, |
---|
| 4064 | + struct cifs_ses *ses, struct cifs_tcon *tcon) |
---|
| 4065 | +{ |
---|
| 4066 | + int rc = 0; |
---|
| 4067 | + |
---|
| 4068 | + if (tcon) |
---|
| 4069 | + cifs_put_tcon(tcon); |
---|
| 4070 | + else if (ses) |
---|
| 4071 | + cifs_put_smb_ses(ses); |
---|
| 4072 | + else if (server) |
---|
| 4073 | + cifs_put_tcp_session(server, 0); |
---|
| 4074 | + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_POSIX_PATHS; |
---|
| 4075 | + free_xid(xid); |
---|
| 4076 | +} |
---|
| 4077 | + |
---|
| 4078 | +/* Get connections for tcp, ses and tcon */ |
---|
| 4079 | +static int mount_get_conns(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, |
---|
| 4080 | + unsigned int *xid, |
---|
| 4081 | + struct TCP_Server_Info **nserver, |
---|
| 4082 | + struct cifs_ses **nses, struct cifs_tcon **ntcon) |
---|
| 4083 | +{ |
---|
| 4084 | + int rc = 0; |
---|
| 4085 | + struct TCP_Server_Info *server; |
---|
| 4086 | + struct cifs_ses *ses; |
---|
| 4087 | + struct cifs_tcon *tcon; |
---|
| 4088 | + |
---|
| 4089 | + *nserver = NULL; |
---|
| 4090 | + *nses = NULL; |
---|
| 4091 | + *ntcon = NULL; |
---|
| 4092 | + |
---|
| 4093 | + *xid = get_xid(); |
---|
| 4094 | + |
---|
| 4095 | + /* get a reference to a tcp session */ |
---|
| 4096 | + server = cifs_get_tcp_session(vol); |
---|
| 4097 | + if (IS_ERR(server)) { |
---|
| 4098 | + rc = PTR_ERR(server); |
---|
| 4099 | + return rc; |
---|
| 4100 | + } |
---|
| 4101 | + |
---|
| 4102 | + *nserver = server; |
---|
| 4103 | + |
---|
| 4104 | + /* get a reference to a SMB session */ |
---|
| 4105 | + ses = cifs_get_smb_ses(server, vol); |
---|
| 4106 | + if (IS_ERR(ses)) { |
---|
| 4107 | + rc = PTR_ERR(ses); |
---|
| 4108 | + return rc; |
---|
| 4109 | + } |
---|
| 4110 | + |
---|
| 4111 | + *nses = ses; |
---|
| 4112 | + |
---|
| 4113 | + if ((vol->persistent == true) && (!(ses->server->capabilities & |
---|
| 4114 | + SMB2_GLOBAL_CAP_PERSISTENT_HANDLES))) { |
---|
| 4115 | + cifs_server_dbg(VFS, "persistent handles not supported by server\n"); |
---|
| 4116 | + return -EOPNOTSUPP; |
---|
| 4117 | + } |
---|
| 4118 | + |
---|
| 4119 | + /* search for existing tcon to this server share */ |
---|
| 4120 | + tcon = cifs_get_tcon(ses, vol); |
---|
| 4121 | + if (IS_ERR(tcon)) { |
---|
| 4122 | + rc = PTR_ERR(tcon); |
---|
| 4123 | + return rc; |
---|
| 4124 | + } |
---|
| 4125 | + |
---|
| 4126 | + *ntcon = tcon; |
---|
| 4127 | + |
---|
| 4128 | + /* if new SMB3.11 POSIX extensions are supported do not remap / and \ */ |
---|
| 4129 | + if (tcon->posix_extensions) |
---|
| 4130 | + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS; |
---|
| 4131 | + |
---|
| 4132 | + /* tell server which Unix caps we support */ |
---|
| 4133 | + if (cap_unix(tcon->ses)) { |
---|
| 4134 | + /* |
---|
| 4135 | + * reset of caps checks mount to see if unix extensions disabled |
---|
| 4136 | + * for just this mount. |
---|
| 4137 | + */ |
---|
| 4138 | + reset_cifs_unix_caps(*xid, tcon, cifs_sb, vol); |
---|
| 4139 | + if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) && |
---|
| 4140 | + (le64_to_cpu(tcon->fsUnixInfo.Capability) & |
---|
| 4141 | + CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)) |
---|
| 4142 | + return -EACCES; |
---|
| 4143 | + } else |
---|
| 4144 | + tcon->unix_ext = 0; /* server does not support them */ |
---|
| 4145 | + |
---|
| 4146 | + /* do not care if a following call succeed - informational */ |
---|
| 4147 | + if (!tcon->pipe && server->ops->qfs_tcon) { |
---|
| 4148 | + server->ops->qfs_tcon(*xid, tcon, cifs_sb); |
---|
| 4149 | + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE) { |
---|
| 4150 | + if (tcon->fsDevInfo.DeviceCharacteristics & |
---|
| 4151 | + cpu_to_le32(FILE_READ_ONLY_DEVICE)) |
---|
| 4152 | + cifs_dbg(VFS, "mounted to read only share\n"); |
---|
| 4153 | + else if ((cifs_sb->mnt_cifs_flags & |
---|
| 4154 | + CIFS_MOUNT_RW_CACHE) == 0) |
---|
| 4155 | + cifs_dbg(VFS, "read only mount of RW share\n"); |
---|
| 4156 | + /* no need to log a RW mount of a typical RW share */ |
---|
| 4157 | + } |
---|
| 4158 | + } |
---|
| 4159 | + |
---|
| 4160 | + cifs_sb->wsize = server->ops->negotiate_wsize(tcon, vol); |
---|
| 4161 | + cifs_sb->rsize = server->ops->negotiate_rsize(tcon, vol); |
---|
| 4162 | + |
---|
| 4163 | + return 0; |
---|
| 4164 | +} |
---|
| 4165 | + |
---|
| 4166 | +static int mount_setup_tlink(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, |
---|
| 4167 | + struct cifs_tcon *tcon) |
---|
| 4168 | +{ |
---|
| 4169 | + struct tcon_link *tlink; |
---|
| 4170 | + |
---|
| 4171 | + /* hang the tcon off of the superblock */ |
---|
| 4172 | + tlink = kzalloc(sizeof(*tlink), GFP_KERNEL); |
---|
| 4173 | + if (tlink == NULL) |
---|
| 4174 | + return -ENOMEM; |
---|
| 4175 | + |
---|
| 4176 | + tlink->tl_uid = ses->linux_uid; |
---|
| 4177 | + tlink->tl_tcon = tcon; |
---|
| 4178 | + tlink->tl_time = jiffies; |
---|
| 4179 | + set_bit(TCON_LINK_MASTER, &tlink->tl_flags); |
---|
| 4180 | + set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); |
---|
| 4181 | + |
---|
| 4182 | + cifs_sb->master_tlink = tlink; |
---|
| 4183 | + spin_lock(&cifs_sb->tlink_tree_lock); |
---|
| 4184 | + tlink_rb_insert(&cifs_sb->tlink_tree, tlink); |
---|
| 4185 | + spin_unlock(&cifs_sb->tlink_tree_lock); |
---|
| 4186 | + |
---|
| 4187 | + queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks, |
---|
| 4188 | + TLINK_IDLE_EXPIRE); |
---|
| 4189 | + return 0; |
---|
| 4190 | +} |
---|
3911 | 4191 | |
---|
3912 | 4192 | #ifdef CONFIG_CIFS_DFS_UPCALL |
---|
3913 | 4193 | /* |
---|
.. | .. |
---|
3916 | 4196 | */ |
---|
3917 | 4197 | static char * |
---|
3918 | 4198 | build_unc_path_to_root(const struct smb_vol *vol, |
---|
3919 | | - const struct cifs_sb_info *cifs_sb) |
---|
| 4199 | + const struct cifs_sb_info *cifs_sb, bool useppath) |
---|
3920 | 4200 | { |
---|
3921 | 4201 | char *full_path, *pos; |
---|
3922 | | - unsigned int pplen = vol->prepath ? strlen(vol->prepath) + 1 : 0; |
---|
| 4202 | + unsigned int pplen = useppath && vol->prepath ? |
---|
| 4203 | + strlen(vol->prepath) + 1 : 0; |
---|
3923 | 4204 | unsigned int unc_len = strnlen(vol->UNC, MAX_TREE_SIZE + 1); |
---|
| 4205 | + |
---|
| 4206 | + if (unc_len > MAX_TREE_SIZE) |
---|
| 4207 | + return ERR_PTR(-EINVAL); |
---|
3924 | 4208 | |
---|
3925 | 4209 | full_path = kmalloc(unc_len + pplen + 1, GFP_KERNEL); |
---|
3926 | 4210 | if (full_path == NULL) |
---|
3927 | 4211 | return ERR_PTR(-ENOMEM); |
---|
3928 | 4212 | |
---|
3929 | | - strncpy(full_path, vol->UNC, unc_len); |
---|
| 4213 | + memcpy(full_path, vol->UNC, unc_len); |
---|
3930 | 4214 | pos = full_path + unc_len; |
---|
3931 | 4215 | |
---|
3932 | 4216 | if (pplen) { |
---|
3933 | 4217 | *pos = CIFS_DIR_SEP(cifs_sb); |
---|
3934 | | - strncpy(pos + 1, vol->prepath, pplen); |
---|
| 4218 | + memcpy(pos + 1, vol->prepath, pplen); |
---|
3935 | 4219 | pos += pplen; |
---|
3936 | 4220 | } |
---|
3937 | 4221 | |
---|
.. | .. |
---|
3941 | 4225 | return full_path; |
---|
3942 | 4226 | } |
---|
3943 | 4227 | |
---|
3944 | | -/* |
---|
3945 | | - * Perform a dfs referral query for a share and (optionally) prefix |
---|
| 4228 | +/** |
---|
| 4229 | + * expand_dfs_referral - Perform a dfs referral query and update the cifs_sb |
---|
| 4230 | + * |
---|
3946 | 4231 | * |
---|
3947 | 4232 | * If a referral is found, cifs_sb->mountdata will be (re-)allocated |
---|
3948 | 4233 | * to a string containing updated options for the submount. Otherwise it |
---|
.. | .. |
---|
3954 | 4239 | static int |
---|
3955 | 4240 | expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, |
---|
3956 | 4241 | struct smb_vol *volume_info, struct cifs_sb_info *cifs_sb, |
---|
3957 | | - int check_prefix) |
---|
| 4242 | + char *ref_path) |
---|
3958 | 4243 | { |
---|
3959 | 4244 | int rc; |
---|
3960 | | - unsigned int num_referrals = 0; |
---|
3961 | | - struct dfs_info3_param *referrals = NULL; |
---|
3962 | | - char *full_path = NULL, *ref_path = NULL, *mdata = NULL; |
---|
| 4245 | + struct dfs_info3_param referral = {0}; |
---|
| 4246 | + char *full_path = NULL, *mdata = NULL; |
---|
3963 | 4247 | |
---|
3964 | | - full_path = build_unc_path_to_root(volume_info, cifs_sb); |
---|
| 4248 | + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) |
---|
| 4249 | + return -EREMOTE; |
---|
| 4250 | + |
---|
| 4251 | + full_path = build_unc_path_to_root(volume_info, cifs_sb, true); |
---|
3965 | 4252 | if (IS_ERR(full_path)) |
---|
3966 | 4253 | return PTR_ERR(full_path); |
---|
3967 | 4254 | |
---|
3968 | | - /* For DFS paths, skip the first '\' of the UNC */ |
---|
3969 | | - ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1; |
---|
3970 | | - |
---|
3971 | | - rc = get_dfs_path(xid, ses, ref_path, cifs_sb->local_nls, |
---|
3972 | | - &num_referrals, &referrals, cifs_remap(cifs_sb)); |
---|
3973 | | - |
---|
3974 | | - if (!rc && num_referrals > 0) { |
---|
| 4255 | + rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), |
---|
| 4256 | + ref_path, &referral, NULL); |
---|
| 4257 | + if (!rc) { |
---|
3975 | 4258 | char *fake_devname = NULL; |
---|
3976 | 4259 | |
---|
3977 | 4260 | mdata = cifs_compose_mount_options(cifs_sb->mountdata, |
---|
3978 | | - full_path + 1, referrals, |
---|
| 4261 | + full_path + 1, &referral, |
---|
3979 | 4262 | &fake_devname); |
---|
3980 | | - |
---|
3981 | | - free_dfs_info_array(referrals, num_referrals); |
---|
| 4263 | + free_dfs_info_param(&referral); |
---|
3982 | 4264 | |
---|
3983 | 4265 | if (IS_ERR(mdata)) { |
---|
3984 | 4266 | rc = PTR_ERR(mdata); |
---|
3985 | 4267 | mdata = NULL; |
---|
3986 | 4268 | } else { |
---|
3987 | | - cleanup_volume_info_contents(volume_info); |
---|
| 4269 | + cifs_cleanup_volume_info_contents(volume_info); |
---|
3988 | 4270 | rc = cifs_setup_volume_info(volume_info, mdata, |
---|
3989 | | - fake_devname, false); |
---|
| 4271 | + fake_devname, false); |
---|
3990 | 4272 | } |
---|
3991 | 4273 | kfree(fake_devname); |
---|
3992 | 4274 | kfree(cifs_sb->mountdata); |
---|
.. | .. |
---|
3995 | 4277 | kfree(full_path); |
---|
3996 | 4278 | return rc; |
---|
3997 | 4279 | } |
---|
| 4280 | + |
---|
| 4281 | +static inline int get_next_dfs_tgt(const char *path, |
---|
| 4282 | + struct dfs_cache_tgt_list *tgt_list, |
---|
| 4283 | + struct dfs_cache_tgt_iterator **tgt_it) |
---|
| 4284 | +{ |
---|
| 4285 | + if (!*tgt_it) |
---|
| 4286 | + *tgt_it = dfs_cache_get_tgt_iterator(tgt_list); |
---|
| 4287 | + else |
---|
| 4288 | + *tgt_it = dfs_cache_get_next_tgt(tgt_list, *tgt_it); |
---|
| 4289 | + return !*tgt_it ? -EHOSTDOWN : 0; |
---|
| 4290 | +} |
---|
| 4291 | + |
---|
| 4292 | +static int update_vol_info(const struct dfs_cache_tgt_iterator *tgt_it, |
---|
| 4293 | + struct smb_vol *fake_vol, struct smb_vol *vol) |
---|
| 4294 | +{ |
---|
| 4295 | + const char *tgt = dfs_cache_get_tgt_name(tgt_it); |
---|
| 4296 | + int len = strlen(tgt) + 2; |
---|
| 4297 | + char *new_unc; |
---|
| 4298 | + |
---|
| 4299 | + new_unc = kmalloc(len, GFP_KERNEL); |
---|
| 4300 | + if (!new_unc) |
---|
| 4301 | + return -ENOMEM; |
---|
| 4302 | + scnprintf(new_unc, len, "\\%s", tgt); |
---|
| 4303 | + |
---|
| 4304 | + kfree(vol->UNC); |
---|
| 4305 | + vol->UNC = new_unc; |
---|
| 4306 | + |
---|
| 4307 | + if (fake_vol->prepath) { |
---|
| 4308 | + kfree(vol->prepath); |
---|
| 4309 | + vol->prepath = fake_vol->prepath; |
---|
| 4310 | + fake_vol->prepath = NULL; |
---|
| 4311 | + } |
---|
| 4312 | + memcpy(&vol->dstaddr, &fake_vol->dstaddr, sizeof(vol->dstaddr)); |
---|
| 4313 | + |
---|
| 4314 | + return 0; |
---|
| 4315 | +} |
---|
| 4316 | + |
---|
| 4317 | +static int setup_dfs_tgt_conn(const char *path, const char *full_path, |
---|
| 4318 | + const struct dfs_cache_tgt_iterator *tgt_it, |
---|
| 4319 | + struct cifs_sb_info *cifs_sb, struct smb_vol *vol, unsigned int *xid, |
---|
| 4320 | + struct TCP_Server_Info **server, struct cifs_ses **ses, |
---|
| 4321 | + struct cifs_tcon **tcon) |
---|
| 4322 | +{ |
---|
| 4323 | + int rc; |
---|
| 4324 | + struct dfs_info3_param ref = {0}; |
---|
| 4325 | + char *mdata = NULL, *fake_devname = NULL; |
---|
| 4326 | + struct smb_vol fake_vol = {NULL}; |
---|
| 4327 | + |
---|
| 4328 | + cifs_dbg(FYI, "%s: dfs path: %s\n", __func__, path); |
---|
| 4329 | + |
---|
| 4330 | + rc = dfs_cache_get_tgt_referral(path, tgt_it, &ref); |
---|
| 4331 | + if (rc) |
---|
| 4332 | + return rc; |
---|
| 4333 | + |
---|
| 4334 | + mdata = cifs_compose_mount_options(cifs_sb->mountdata, full_path + 1, &ref, &fake_devname); |
---|
| 4335 | + free_dfs_info_param(&ref); |
---|
| 4336 | + |
---|
| 4337 | + if (IS_ERR(mdata)) { |
---|
| 4338 | + rc = PTR_ERR(mdata); |
---|
| 4339 | + mdata = NULL; |
---|
| 4340 | + } else { |
---|
| 4341 | + cifs_dbg(FYI, "%s: fake_devname: %s\n", __func__, fake_devname); |
---|
| 4342 | + rc = cifs_setup_volume_info(&fake_vol, mdata, fake_devname, |
---|
| 4343 | + false); |
---|
| 4344 | + } |
---|
| 4345 | + kfree(mdata); |
---|
| 4346 | + kfree(fake_devname); |
---|
| 4347 | + |
---|
| 4348 | + if (!rc) { |
---|
| 4349 | + /* |
---|
| 4350 | + * We use a 'fake_vol' here because we need pass it down to the |
---|
| 4351 | + * mount_{get,put} functions to test connection against new DFS |
---|
| 4352 | + * targets. |
---|
| 4353 | + */ |
---|
| 4354 | + mount_put_conns(cifs_sb, *xid, *server, *ses, *tcon); |
---|
| 4355 | + rc = mount_get_conns(&fake_vol, cifs_sb, xid, server, ses, |
---|
| 4356 | + tcon); |
---|
| 4357 | + if (!rc || (*server && *ses)) { |
---|
| 4358 | + /* |
---|
| 4359 | + * We were able to connect to new target server. |
---|
| 4360 | + * Update current volume info with new target server. |
---|
| 4361 | + */ |
---|
| 4362 | + rc = update_vol_info(tgt_it, &fake_vol, vol); |
---|
| 4363 | + } |
---|
| 4364 | + } |
---|
| 4365 | + cifs_cleanup_volume_info_contents(&fake_vol); |
---|
| 4366 | + return rc; |
---|
| 4367 | +} |
---|
| 4368 | + |
---|
| 4369 | +static int do_dfs_failover(const char *path, const char *full_path, struct cifs_sb_info *cifs_sb, |
---|
| 4370 | + struct smb_vol *vol, struct cifs_ses *root_ses, unsigned int *xid, |
---|
| 4371 | + struct TCP_Server_Info **server, struct cifs_ses **ses, |
---|
| 4372 | + struct cifs_tcon **tcon) |
---|
| 4373 | +{ |
---|
| 4374 | + int rc; |
---|
| 4375 | + struct dfs_cache_tgt_list tgt_list; |
---|
| 4376 | + struct dfs_cache_tgt_iterator *tgt_it = NULL; |
---|
| 4377 | + |
---|
| 4378 | + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) |
---|
| 4379 | + return -EOPNOTSUPP; |
---|
| 4380 | + |
---|
| 4381 | + rc = dfs_cache_noreq_find(path, NULL, &tgt_list); |
---|
| 4382 | + if (rc) |
---|
| 4383 | + return rc; |
---|
| 4384 | + |
---|
| 4385 | + for (;;) { |
---|
| 4386 | + /* Get next DFS target server - if any */ |
---|
| 4387 | + rc = get_next_dfs_tgt(path, &tgt_list, &tgt_it); |
---|
| 4388 | + if (rc) |
---|
| 4389 | + break; |
---|
| 4390 | + /* Connect to next DFS target */ |
---|
| 4391 | + rc = setup_dfs_tgt_conn(path, full_path, tgt_it, cifs_sb, vol, xid, server, ses, |
---|
| 4392 | + tcon); |
---|
| 4393 | + if (!rc || (*server && *ses)) |
---|
| 4394 | + break; |
---|
| 4395 | + } |
---|
| 4396 | + if (!rc) { |
---|
| 4397 | + /* |
---|
| 4398 | + * Update DFS target hint in DFS referral cache with the target |
---|
| 4399 | + * server we successfully reconnected to. |
---|
| 4400 | + */ |
---|
| 4401 | + rc = dfs_cache_update_tgthint(*xid, root_ses ? root_ses : *ses, |
---|
| 4402 | + cifs_sb->local_nls, |
---|
| 4403 | + cifs_remap(cifs_sb), path, |
---|
| 4404 | + tgt_it); |
---|
| 4405 | + } |
---|
| 4406 | + dfs_cache_free_tgts(&tgt_list); |
---|
| 4407 | + return rc; |
---|
| 4408 | +} |
---|
3998 | 4409 | #endif |
---|
3999 | 4410 | |
---|
4000 | | -static int |
---|
| 4411 | +int |
---|
4001 | 4412 | cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, |
---|
4002 | 4413 | const char *devname, bool is_smb3) |
---|
4003 | 4414 | { |
---|
.. | .. |
---|
4060 | 4471 | unsigned int xid, |
---|
4061 | 4472 | struct cifs_tcon *tcon, |
---|
4062 | 4473 | struct cifs_sb_info *cifs_sb, |
---|
4063 | | - char *full_path) |
---|
| 4474 | + char *full_path, |
---|
| 4475 | + int added_treename) |
---|
4064 | 4476 | { |
---|
4065 | 4477 | int rc; |
---|
4066 | 4478 | char *s; |
---|
4067 | 4479 | char sep, tmp; |
---|
| 4480 | + int skip = added_treename ? 1 : 0; |
---|
4068 | 4481 | |
---|
4069 | 4482 | sep = CIFS_DIR_SEP(cifs_sb); |
---|
4070 | 4483 | s = full_path; |
---|
.. | .. |
---|
4079 | 4492 | /* next separator */ |
---|
4080 | 4493 | while (*s && *s != sep) |
---|
4081 | 4494 | s++; |
---|
4082 | | - |
---|
| 4495 | + /* |
---|
| 4496 | + * if the treename is added, we then have to skip the first |
---|
| 4497 | + * part within the separators |
---|
| 4498 | + */ |
---|
| 4499 | + if (skip) { |
---|
| 4500 | + skip = 0; |
---|
| 4501 | + continue; |
---|
| 4502 | + } |
---|
4083 | 4503 | /* |
---|
4084 | 4504 | * temporarily null-terminate the path at the end of |
---|
4085 | 4505 | * the current component |
---|
.. | .. |
---|
4093 | 4513 | return rc; |
---|
4094 | 4514 | } |
---|
4095 | 4515 | |
---|
4096 | | -int |
---|
4097 | | -cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) |
---|
| 4516 | +/* |
---|
| 4517 | + * Check if path is remote (e.g. a DFS share). Return -EREMOTE if it is, |
---|
| 4518 | + * otherwise 0. |
---|
| 4519 | + */ |
---|
| 4520 | +static int is_path_remote(struct cifs_sb_info *cifs_sb, struct smb_vol *vol, |
---|
| 4521 | + const unsigned int xid, |
---|
| 4522 | + struct TCP_Server_Info *server, |
---|
| 4523 | + struct cifs_tcon *tcon) |
---|
4098 | 4524 | { |
---|
4099 | 4525 | int rc; |
---|
| 4526 | + char *full_path; |
---|
| 4527 | + |
---|
| 4528 | + if (!server->ops->is_path_accessible) |
---|
| 4529 | + return -EOPNOTSUPP; |
---|
| 4530 | + |
---|
| 4531 | + /* |
---|
| 4532 | + * cifs_build_path_to_root works only when we have a valid tcon |
---|
| 4533 | + */ |
---|
| 4534 | + full_path = cifs_build_path_to_root(vol, cifs_sb, tcon, |
---|
| 4535 | + tcon->Flags & SMB_SHARE_IS_IN_DFS); |
---|
| 4536 | + if (full_path == NULL) |
---|
| 4537 | + return -ENOMEM; |
---|
| 4538 | + |
---|
| 4539 | + cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path); |
---|
| 4540 | + |
---|
| 4541 | + rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, |
---|
| 4542 | + full_path); |
---|
| 4543 | + if (rc != 0 && rc != -EREMOTE) { |
---|
| 4544 | + kfree(full_path); |
---|
| 4545 | + return rc; |
---|
| 4546 | + } |
---|
| 4547 | + |
---|
| 4548 | + if (rc != -EREMOTE) { |
---|
| 4549 | + rc = cifs_are_all_path_components_accessible(server, xid, tcon, |
---|
| 4550 | + cifs_sb, full_path, tcon->Flags & SMB_SHARE_IS_IN_DFS); |
---|
| 4551 | + if (rc != 0) { |
---|
| 4552 | + cifs_server_dbg(VFS, "cannot query dirs between root and final path, enabling CIFS_MOUNT_USE_PREFIX_PATH\n"); |
---|
| 4553 | + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH; |
---|
| 4554 | + rc = 0; |
---|
| 4555 | + } |
---|
| 4556 | + } |
---|
| 4557 | + |
---|
| 4558 | + kfree(full_path); |
---|
| 4559 | + return rc; |
---|
| 4560 | +} |
---|
| 4561 | + |
---|
| 4562 | +#ifdef CONFIG_CIFS_DFS_UPCALL |
---|
| 4563 | +static void set_root_ses(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, |
---|
| 4564 | + struct cifs_ses **root_ses) |
---|
| 4565 | +{ |
---|
| 4566 | + if (ses) { |
---|
| 4567 | + spin_lock(&cifs_tcp_ses_lock); |
---|
| 4568 | + ses->ses_count++; |
---|
| 4569 | + if (ses->tcon_ipc) |
---|
| 4570 | + ses->tcon_ipc->remap = cifs_remap(cifs_sb); |
---|
| 4571 | + spin_unlock(&cifs_tcp_ses_lock); |
---|
| 4572 | + } |
---|
| 4573 | + *root_ses = ses; |
---|
| 4574 | +} |
---|
| 4575 | + |
---|
| 4576 | +static void put_root_ses(struct cifs_ses *ses) |
---|
| 4577 | +{ |
---|
| 4578 | + if (ses) |
---|
| 4579 | + cifs_put_smb_ses(ses); |
---|
| 4580 | +} |
---|
| 4581 | + |
---|
| 4582 | +/* Check if a path component is remote and then update @dfs_path accordingly */ |
---|
| 4583 | +static int check_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb_vol *vol, |
---|
| 4584 | + const unsigned int xid, struct TCP_Server_Info *server, |
---|
| 4585 | + struct cifs_tcon *tcon, char **dfs_path) |
---|
| 4586 | +{ |
---|
| 4587 | + char *path, *s; |
---|
| 4588 | + char sep = CIFS_DIR_SEP(cifs_sb), tmp; |
---|
| 4589 | + char *npath; |
---|
| 4590 | + int rc = 0; |
---|
| 4591 | + int added_treename = tcon->Flags & SMB_SHARE_IS_IN_DFS; |
---|
| 4592 | + int skip = added_treename; |
---|
| 4593 | + |
---|
| 4594 | + path = cifs_build_path_to_root(vol, cifs_sb, tcon, added_treename); |
---|
| 4595 | + if (!path) |
---|
| 4596 | + return -ENOMEM; |
---|
| 4597 | + |
---|
| 4598 | + /* |
---|
| 4599 | + * Walk through the path components in @path and check if they're accessible. In case any of |
---|
| 4600 | + * the components is -EREMOTE, then update @dfs_path with the next DFS referral request path |
---|
| 4601 | + * (NOT including the remaining components). |
---|
| 4602 | + */ |
---|
| 4603 | + s = path; |
---|
| 4604 | + do { |
---|
| 4605 | + /* skip separators */ |
---|
| 4606 | + while (*s && *s == sep) |
---|
| 4607 | + s++; |
---|
| 4608 | + if (!*s) |
---|
| 4609 | + break; |
---|
| 4610 | + /* next separator */ |
---|
| 4611 | + while (*s && *s != sep) |
---|
| 4612 | + s++; |
---|
| 4613 | + /* |
---|
| 4614 | + * if the treename is added, we then have to skip the first |
---|
| 4615 | + * part within the separators |
---|
| 4616 | + */ |
---|
| 4617 | + if (skip) { |
---|
| 4618 | + skip = 0; |
---|
| 4619 | + continue; |
---|
| 4620 | + } |
---|
| 4621 | + tmp = *s; |
---|
| 4622 | + *s = 0; |
---|
| 4623 | + rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, path); |
---|
| 4624 | + if (rc && rc == -EREMOTE) { |
---|
| 4625 | + struct smb_vol v = {NULL}; |
---|
| 4626 | + /* if @path contains a tree name, skip it in the prefix path */ |
---|
| 4627 | + if (added_treename) { |
---|
| 4628 | + rc = cifs_parse_devname(path, &v); |
---|
| 4629 | + if (rc) |
---|
| 4630 | + break; |
---|
| 4631 | + rc = -EREMOTE; |
---|
| 4632 | + npath = build_unc_path_to_root(&v, cifs_sb, true); |
---|
| 4633 | + cifs_cleanup_volume_info_contents(&v); |
---|
| 4634 | + } else { |
---|
| 4635 | + v.UNC = vol->UNC; |
---|
| 4636 | + v.prepath = path + 1; |
---|
| 4637 | + npath = build_unc_path_to_root(&v, cifs_sb, true); |
---|
| 4638 | + } |
---|
| 4639 | + if (IS_ERR(npath)) { |
---|
| 4640 | + rc = PTR_ERR(npath); |
---|
| 4641 | + break; |
---|
| 4642 | + } |
---|
| 4643 | + kfree(*dfs_path); |
---|
| 4644 | + *dfs_path = npath; |
---|
| 4645 | + } |
---|
| 4646 | + *s = tmp; |
---|
| 4647 | + } while (rc == 0); |
---|
| 4648 | + |
---|
| 4649 | + kfree(path); |
---|
| 4650 | + return rc; |
---|
| 4651 | +} |
---|
| 4652 | + |
---|
| 4653 | +int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) |
---|
| 4654 | +{ |
---|
| 4655 | + int rc = 0; |
---|
| 4656 | + unsigned int xid; |
---|
| 4657 | + struct TCP_Server_Info *server = NULL; |
---|
| 4658 | + struct cifs_ses *ses = NULL, *root_ses = NULL; |
---|
| 4659 | + struct cifs_tcon *tcon = NULL; |
---|
| 4660 | + int count = 0; |
---|
| 4661 | + char *ref_path = NULL, *full_path = NULL; |
---|
| 4662 | + char *oldmnt = NULL; |
---|
| 4663 | + char *mntdata = NULL; |
---|
| 4664 | + |
---|
| 4665 | + rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon); |
---|
| 4666 | + /* |
---|
| 4667 | + * Unconditionally try to get an DFS referral (even cached) to determine whether it is an |
---|
| 4668 | + * DFS mount. |
---|
| 4669 | + * |
---|
| 4670 | + * Skip prefix path to provide support for DFS referrals from w2k8 servers which don't seem |
---|
| 4671 | + * to respond with PATH_NOT_COVERED to requests that include the prefix. |
---|
| 4672 | + */ |
---|
| 4673 | + if (dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), vol->UNC + 1, NULL, |
---|
| 4674 | + NULL)) { |
---|
| 4675 | + /* No DFS referral was returned. Looks like a regular share. */ |
---|
| 4676 | + if (rc) |
---|
| 4677 | + goto error; |
---|
| 4678 | + /* Check if it is fully accessible and then mount it */ |
---|
| 4679 | + rc = is_path_remote(cifs_sb, vol, xid, server, tcon); |
---|
| 4680 | + if (!rc) |
---|
| 4681 | + goto out; |
---|
| 4682 | + if (rc != -EREMOTE) |
---|
| 4683 | + goto error; |
---|
| 4684 | + } |
---|
| 4685 | + /* Save mount options */ |
---|
| 4686 | + mntdata = kstrndup(cifs_sb->mountdata, strlen(cifs_sb->mountdata), GFP_KERNEL); |
---|
| 4687 | + if (!mntdata) { |
---|
| 4688 | + rc = -ENOMEM; |
---|
| 4689 | + goto error; |
---|
| 4690 | + } |
---|
| 4691 | + /* Get path of DFS root */ |
---|
| 4692 | + ref_path = build_unc_path_to_root(vol, cifs_sb, false); |
---|
| 4693 | + if (IS_ERR(ref_path)) { |
---|
| 4694 | + rc = PTR_ERR(ref_path); |
---|
| 4695 | + ref_path = NULL; |
---|
| 4696 | + goto error; |
---|
| 4697 | + } |
---|
| 4698 | + |
---|
| 4699 | + set_root_ses(cifs_sb, ses, &root_ses); |
---|
| 4700 | + do { |
---|
| 4701 | + /* Save full path of last DFS path we used to resolve final target server */ |
---|
| 4702 | + kfree(full_path); |
---|
| 4703 | + full_path = build_unc_path_to_root(vol, cifs_sb, !!count); |
---|
| 4704 | + if (IS_ERR(full_path)) { |
---|
| 4705 | + rc = PTR_ERR(full_path); |
---|
| 4706 | + full_path = NULL; |
---|
| 4707 | + break; |
---|
| 4708 | + } |
---|
| 4709 | + /* Chase referral */ |
---|
| 4710 | + oldmnt = cifs_sb->mountdata; |
---|
| 4711 | + rc = expand_dfs_referral(xid, root_ses, vol, cifs_sb, ref_path + 1); |
---|
| 4712 | + if (rc) |
---|
| 4713 | + break; |
---|
| 4714 | + /* Connect to new DFS target only if we were redirected */ |
---|
| 4715 | + if (oldmnt != cifs_sb->mountdata) { |
---|
| 4716 | + mount_put_conns(cifs_sb, xid, server, ses, tcon); |
---|
| 4717 | + rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon); |
---|
| 4718 | + } |
---|
| 4719 | + if (rc && !server && !ses) { |
---|
| 4720 | + /* Failed to connect. Try to connect to other targets in the referral. */ |
---|
| 4721 | + rc = do_dfs_failover(ref_path + 1, full_path, cifs_sb, vol, root_ses, &xid, |
---|
| 4722 | + &server, &ses, &tcon); |
---|
| 4723 | + } |
---|
| 4724 | + if (rc == -EACCES || rc == -EOPNOTSUPP || !server || !ses) |
---|
| 4725 | + break; |
---|
| 4726 | + if (!tcon) |
---|
| 4727 | + continue; |
---|
| 4728 | + /* Make sure that requests go through new root servers */ |
---|
| 4729 | + if (is_tcon_dfs(tcon)) { |
---|
| 4730 | + put_root_ses(root_ses); |
---|
| 4731 | + set_root_ses(cifs_sb, ses, &root_ses); |
---|
| 4732 | + } |
---|
| 4733 | + /* Check for remaining path components and then continue chasing them (-EREMOTE) */ |
---|
| 4734 | + rc = check_dfs_prepath(cifs_sb, vol, xid, server, tcon, &ref_path); |
---|
| 4735 | + /* Prevent recursion on broken link referrals */ |
---|
| 4736 | + if (rc == -EREMOTE && ++count > MAX_NESTED_LINKS) |
---|
| 4737 | + rc = -ELOOP; |
---|
| 4738 | + } while (rc == -EREMOTE); |
---|
| 4739 | + |
---|
| 4740 | + if (rc) |
---|
| 4741 | + goto error; |
---|
| 4742 | + put_root_ses(root_ses); |
---|
| 4743 | + root_ses = NULL; |
---|
| 4744 | + kfree(ref_path); |
---|
| 4745 | + ref_path = NULL; |
---|
| 4746 | + /* |
---|
| 4747 | + * Store DFS full path in both superblock and tree connect structures. |
---|
| 4748 | + * |
---|
| 4749 | + * For DFS root mounts, the prefix path (cifs_sb->prepath) is preserved during reconnect so |
---|
| 4750 | + * only the root path is set in cifs_sb->origin_fullpath and tcon->dfs_path. And for DFS |
---|
| 4751 | + * links, the prefix path is included in both and may be changed during reconnect. See |
---|
| 4752 | + * cifs_tree_connect(). |
---|
| 4753 | + */ |
---|
| 4754 | + cifs_sb->origin_fullpath = kstrndup(full_path, strlen(full_path), GFP_KERNEL); |
---|
| 4755 | + if (!cifs_sb->origin_fullpath) { |
---|
| 4756 | + rc = -ENOMEM; |
---|
| 4757 | + goto error; |
---|
| 4758 | + } |
---|
| 4759 | + spin_lock(&cifs_tcp_ses_lock); |
---|
| 4760 | + tcon->dfs_path = full_path; |
---|
| 4761 | + full_path = NULL; |
---|
| 4762 | + tcon->remap = cifs_remap(cifs_sb); |
---|
| 4763 | + spin_unlock(&cifs_tcp_ses_lock); |
---|
| 4764 | + |
---|
| 4765 | + /* Add original volume information for DFS cache to be used when refreshing referrals */ |
---|
| 4766 | + rc = dfs_cache_add_vol(mntdata, vol, cifs_sb->origin_fullpath); |
---|
| 4767 | + if (rc) |
---|
| 4768 | + goto error; |
---|
| 4769 | + /* |
---|
| 4770 | + * After reconnecting to a different server, unique ids won't |
---|
| 4771 | + * match anymore, so we disable serverino. This prevents |
---|
| 4772 | + * dentry revalidation to think the dentry are stale (ESTALE). |
---|
| 4773 | + */ |
---|
| 4774 | + cifs_autodisable_serverino(cifs_sb); |
---|
| 4775 | + /* |
---|
| 4776 | + * Force the use of prefix path to support failover on DFS paths that |
---|
| 4777 | + * resolve to targets that have different prefix paths. |
---|
| 4778 | + */ |
---|
| 4779 | + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH; |
---|
| 4780 | + kfree(cifs_sb->prepath); |
---|
| 4781 | + cifs_sb->prepath = vol->prepath; |
---|
| 4782 | + vol->prepath = NULL; |
---|
| 4783 | + |
---|
| 4784 | +out: |
---|
| 4785 | + free_xid(xid); |
---|
| 4786 | + cifs_try_adding_channels(ses); |
---|
| 4787 | + return mount_setup_tlink(cifs_sb, ses, tcon); |
---|
| 4788 | + |
---|
| 4789 | +error: |
---|
| 4790 | + kfree(ref_path); |
---|
| 4791 | + kfree(full_path); |
---|
| 4792 | + kfree(mntdata); |
---|
| 4793 | + kfree(cifs_sb->origin_fullpath); |
---|
| 4794 | + put_root_ses(root_ses); |
---|
| 4795 | + mount_put_conns(cifs_sb, xid, server, ses, tcon); |
---|
| 4796 | + return rc; |
---|
| 4797 | +} |
---|
| 4798 | +#else |
---|
| 4799 | +int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) |
---|
| 4800 | +{ |
---|
| 4801 | + int rc = 0; |
---|
4100 | 4802 | unsigned int xid; |
---|
4101 | 4803 | struct cifs_ses *ses; |
---|
4102 | 4804 | struct cifs_tcon *tcon; |
---|
4103 | 4805 | struct TCP_Server_Info *server; |
---|
4104 | | - char *full_path; |
---|
4105 | | - struct tcon_link *tlink; |
---|
4106 | | -#ifdef CONFIG_CIFS_DFS_UPCALL |
---|
4107 | | - int referral_walks_count = 0; |
---|
4108 | | -#endif |
---|
4109 | 4806 | |
---|
4110 | | -#ifdef CONFIG_CIFS_DFS_UPCALL |
---|
4111 | | -try_mount_again: |
---|
4112 | | - /* cleanup activities if we're chasing a referral */ |
---|
4113 | | - if (referral_walks_count) { |
---|
4114 | | - if (tcon) |
---|
4115 | | - cifs_put_tcon(tcon); |
---|
4116 | | - else if (ses) |
---|
4117 | | - cifs_put_smb_ses(ses); |
---|
4118 | | - |
---|
4119 | | - cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_POSIX_PATHS; |
---|
4120 | | - |
---|
4121 | | - free_xid(xid); |
---|
4122 | | - } |
---|
4123 | | -#endif |
---|
4124 | | - rc = 0; |
---|
4125 | | - tcon = NULL; |
---|
4126 | | - ses = NULL; |
---|
4127 | | - server = NULL; |
---|
4128 | | - full_path = NULL; |
---|
4129 | | - tlink = NULL; |
---|
4130 | | - |
---|
4131 | | - xid = get_xid(); |
---|
4132 | | - |
---|
4133 | | - /* get a reference to a tcp session */ |
---|
4134 | | - server = cifs_get_tcp_session(volume_info); |
---|
4135 | | - if (IS_ERR(server)) { |
---|
4136 | | - rc = PTR_ERR(server); |
---|
4137 | | - goto out; |
---|
4138 | | - } |
---|
4139 | | - if ((volume_info->max_credits < 20) || |
---|
4140 | | - (volume_info->max_credits > 60000)) |
---|
4141 | | - server->max_credits = SMB2_MAX_CREDITS_AVAILABLE; |
---|
4142 | | - else |
---|
4143 | | - server->max_credits = volume_info->max_credits; |
---|
4144 | | - /* get a reference to a SMB session */ |
---|
4145 | | - ses = cifs_get_smb_ses(server, volume_info); |
---|
4146 | | - if (IS_ERR(ses)) { |
---|
4147 | | - rc = PTR_ERR(ses); |
---|
4148 | | - ses = NULL; |
---|
4149 | | - goto mount_fail_check; |
---|
4150 | | - } |
---|
4151 | | - |
---|
4152 | | - if ((volume_info->persistent == true) && ((ses->server->capabilities & |
---|
4153 | | - SMB2_GLOBAL_CAP_PERSISTENT_HANDLES) == 0)) { |
---|
4154 | | - cifs_dbg(VFS, "persistent handles not supported by server\n"); |
---|
4155 | | - rc = -EOPNOTSUPP; |
---|
4156 | | - goto mount_fail_check; |
---|
4157 | | - } |
---|
4158 | | - |
---|
4159 | | - /* search for existing tcon to this server share */ |
---|
4160 | | - tcon = cifs_get_tcon(ses, volume_info); |
---|
4161 | | - if (IS_ERR(tcon)) { |
---|
4162 | | - rc = PTR_ERR(tcon); |
---|
4163 | | - tcon = NULL; |
---|
4164 | | - if (rc == -EACCES) |
---|
4165 | | - goto mount_fail_check; |
---|
4166 | | - |
---|
4167 | | - goto remote_path_check; |
---|
4168 | | - } |
---|
4169 | | - |
---|
4170 | | - /* if new SMB3.11 POSIX extensions are supported do not remap / and \ */ |
---|
4171 | | - if (tcon->posix_extensions) |
---|
4172 | | - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS; |
---|
4173 | | - |
---|
4174 | | - /* tell server which Unix caps we support */ |
---|
4175 | | - if (cap_unix(tcon->ses)) { |
---|
4176 | | - /* reset of caps checks mount to see if unix extensions |
---|
4177 | | - disabled for just this mount */ |
---|
4178 | | - reset_cifs_unix_caps(xid, tcon, cifs_sb, volume_info); |
---|
4179 | | - if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) && |
---|
4180 | | - (le64_to_cpu(tcon->fsUnixInfo.Capability) & |
---|
4181 | | - CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)) { |
---|
4182 | | - rc = -EACCES; |
---|
4183 | | - goto mount_fail_check; |
---|
4184 | | - } |
---|
4185 | | - } else |
---|
4186 | | - tcon->unix_ext = 0; /* server does not support them */ |
---|
4187 | | - |
---|
4188 | | - /* do not care if a following call succeed - informational */ |
---|
4189 | | - if (!tcon->pipe && server->ops->qfs_tcon) |
---|
4190 | | - server->ops->qfs_tcon(xid, tcon); |
---|
4191 | | - |
---|
4192 | | - cifs_sb->wsize = server->ops->negotiate_wsize(tcon, volume_info); |
---|
4193 | | - cifs_sb->rsize = server->ops->negotiate_rsize(tcon, volume_info); |
---|
4194 | | - |
---|
4195 | | -remote_path_check: |
---|
4196 | | -#ifdef CONFIG_CIFS_DFS_UPCALL |
---|
4197 | | - /* |
---|
4198 | | - * Perform an unconditional check for whether there are DFS |
---|
4199 | | - * referrals for this path without prefix, to provide support |
---|
4200 | | - * for DFS referrals from w2k8 servers which don't seem to respond |
---|
4201 | | - * with PATH_NOT_COVERED to requests that include the prefix. |
---|
4202 | | - * Chase the referral if found, otherwise continue normally. |
---|
4203 | | - */ |
---|
4204 | | - if (referral_walks_count == 0) { |
---|
4205 | | - int refrc = expand_dfs_referral(xid, ses, volume_info, cifs_sb, |
---|
4206 | | - false); |
---|
4207 | | - if (!refrc) { |
---|
4208 | | - referral_walks_count++; |
---|
4209 | | - goto try_mount_again; |
---|
4210 | | - } |
---|
4211 | | - } |
---|
4212 | | -#endif |
---|
4213 | | - |
---|
4214 | | - /* check if a whole path is not remote */ |
---|
4215 | | - if (!rc && tcon) { |
---|
4216 | | - if (!server->ops->is_path_accessible) { |
---|
4217 | | - rc = -ENOSYS; |
---|
4218 | | - goto mount_fail_check; |
---|
4219 | | - } |
---|
4220 | | - /* |
---|
4221 | | - * cifs_build_path_to_root works only when we have a valid tcon |
---|
4222 | | - */ |
---|
4223 | | - full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon, |
---|
4224 | | - tcon->Flags & SMB_SHARE_IS_IN_DFS); |
---|
4225 | | - if (full_path == NULL) { |
---|
4226 | | - rc = -ENOMEM; |
---|
4227 | | - goto mount_fail_check; |
---|
4228 | | - } |
---|
4229 | | - rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, |
---|
4230 | | - full_path); |
---|
4231 | | - if (rc != 0 && rc != -EREMOTE) { |
---|
4232 | | - kfree(full_path); |
---|
4233 | | - goto mount_fail_check; |
---|
4234 | | - } |
---|
4235 | | - |
---|
4236 | | - if (rc != -EREMOTE) { |
---|
4237 | | - rc = cifs_are_all_path_components_accessible(server, |
---|
4238 | | - xid, tcon, cifs_sb, |
---|
4239 | | - full_path); |
---|
4240 | | - if (rc != 0) { |
---|
4241 | | - cifs_dbg(VFS, "cannot query dirs between root and final path, " |
---|
4242 | | - "enabling CIFS_MOUNT_USE_PREFIX_PATH\n"); |
---|
4243 | | - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH; |
---|
4244 | | - rc = 0; |
---|
4245 | | - } |
---|
4246 | | - } |
---|
4247 | | - kfree(full_path); |
---|
4248 | | - } |
---|
4249 | | - |
---|
4250 | | - /* get referral if needed */ |
---|
4251 | | - if (rc == -EREMOTE) { |
---|
4252 | | -#ifdef CONFIG_CIFS_DFS_UPCALL |
---|
4253 | | - if (referral_walks_count > MAX_NESTED_LINKS) { |
---|
4254 | | - /* |
---|
4255 | | - * BB: when we implement proper loop detection, |
---|
4256 | | - * we will remove this check. But now we need it |
---|
4257 | | - * to prevent an indefinite loop if 'DFS tree' is |
---|
4258 | | - * misconfigured (i.e. has loops). |
---|
4259 | | - */ |
---|
4260 | | - rc = -ELOOP; |
---|
4261 | | - goto mount_fail_check; |
---|
4262 | | - } |
---|
4263 | | - |
---|
4264 | | - rc = expand_dfs_referral(xid, ses, volume_info, cifs_sb, true); |
---|
4265 | | - |
---|
4266 | | - if (!rc) { |
---|
4267 | | - referral_walks_count++; |
---|
4268 | | - goto try_mount_again; |
---|
4269 | | - } |
---|
4270 | | - goto mount_fail_check; |
---|
4271 | | -#else /* No DFS support, return error on mount */ |
---|
4272 | | - rc = -EOPNOTSUPP; |
---|
4273 | | -#endif |
---|
4274 | | - } |
---|
4275 | | - |
---|
| 4807 | + rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon); |
---|
4276 | 4808 | if (rc) |
---|
4277 | | - goto mount_fail_check; |
---|
| 4809 | + goto error; |
---|
4278 | 4810 | |
---|
4279 | | - /* now, hang the tcon off of the superblock */ |
---|
4280 | | - tlink = kzalloc(sizeof *tlink, GFP_KERNEL); |
---|
4281 | | - if (tlink == NULL) { |
---|
4282 | | - rc = -ENOMEM; |
---|
4283 | | - goto mount_fail_check; |
---|
| 4811 | + if (tcon) { |
---|
| 4812 | + rc = is_path_remote(cifs_sb, vol, xid, server, tcon); |
---|
| 4813 | + if (rc == -EREMOTE) |
---|
| 4814 | + rc = -EOPNOTSUPP; |
---|
| 4815 | + if (rc) |
---|
| 4816 | + goto error; |
---|
4284 | 4817 | } |
---|
4285 | 4818 | |
---|
4286 | | - tlink->tl_uid = ses->linux_uid; |
---|
4287 | | - tlink->tl_tcon = tcon; |
---|
4288 | | - tlink->tl_time = jiffies; |
---|
4289 | | - set_bit(TCON_LINK_MASTER, &tlink->tl_flags); |
---|
4290 | | - set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); |
---|
4291 | | - |
---|
4292 | | - cifs_sb->master_tlink = tlink; |
---|
4293 | | - spin_lock(&cifs_sb->tlink_tree_lock); |
---|
4294 | | - tlink_rb_insert(&cifs_sb->tlink_tree, tlink); |
---|
4295 | | - spin_unlock(&cifs_sb->tlink_tree_lock); |
---|
4296 | | - |
---|
4297 | | - queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks, |
---|
4298 | | - TLINK_IDLE_EXPIRE); |
---|
4299 | | - |
---|
4300 | | -mount_fail_check: |
---|
4301 | | - /* on error free sesinfo and tcon struct if needed */ |
---|
4302 | | - if (rc) { |
---|
4303 | | - /* If find_unc succeeded then rc == 0 so we can not end */ |
---|
4304 | | - /* up accidentally freeing someone elses tcon struct */ |
---|
4305 | | - if (tcon) |
---|
4306 | | - cifs_put_tcon(tcon); |
---|
4307 | | - else if (ses) |
---|
4308 | | - cifs_put_smb_ses(ses); |
---|
4309 | | - else |
---|
4310 | | - cifs_put_tcp_session(server, 0); |
---|
4311 | | - } |
---|
4312 | | - |
---|
4313 | | -out: |
---|
4314 | 4819 | free_xid(xid); |
---|
| 4820 | + |
---|
| 4821 | + return mount_setup_tlink(cifs_sb, ses, tcon); |
---|
| 4822 | + |
---|
| 4823 | +error: |
---|
| 4824 | + mount_put_conns(cifs_sb, xid, server, ses, tcon); |
---|
4315 | 4825 | return rc; |
---|
4316 | 4826 | } |
---|
| 4827 | +#endif |
---|
4317 | 4828 | |
---|
4318 | 4829 | /* |
---|
4319 | 4830 | * Issue a TREE_CONNECT request. |
---|
.. | .. |
---|
4416 | 4927 | bcc_ptr += strlen("?????"); |
---|
4417 | 4928 | bcc_ptr += 1; |
---|
4418 | 4929 | count = bcc_ptr - &pSMB->Password[0]; |
---|
4419 | | - pSMB->hdr.smb_buf_length = cpu_to_be32(be32_to_cpu( |
---|
4420 | | - pSMB->hdr.smb_buf_length) + count); |
---|
| 4930 | + be32_add_cpu(&pSMB->hdr.smb_buf_length, count); |
---|
4421 | 4931 | pSMB->ByteCount = cpu_to_le16(count); |
---|
4422 | 4932 | |
---|
4423 | 4933 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, |
---|
.. | .. |
---|
4509 | 5019 | |
---|
4510 | 5020 | kfree(cifs_sb->mountdata); |
---|
4511 | 5021 | kfree(cifs_sb->prepath); |
---|
| 5022 | +#ifdef CONFIG_CIFS_DFS_UPCALL |
---|
| 5023 | + dfs_cache_del_vol(cifs_sb->origin_fullpath); |
---|
| 5024 | + kfree(cifs_sb->origin_fullpath); |
---|
| 5025 | +#endif |
---|
4512 | 5026 | call_rcu(&cifs_sb->rcu, delayed_free); |
---|
4513 | 5027 | } |
---|
4514 | 5028 | |
---|
.. | .. |
---|
4516 | 5030 | cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses) |
---|
4517 | 5031 | { |
---|
4518 | 5032 | int rc = 0; |
---|
4519 | | - struct TCP_Server_Info *server = ses->server; |
---|
| 5033 | + struct TCP_Server_Info *server = cifs_ses_server(ses); |
---|
4520 | 5034 | |
---|
4521 | 5035 | if (!server->ops->need_neg || !server->ops->negotiate) |
---|
4522 | 5036 | return -ENOSYS; |
---|
.. | .. |
---|
4524 | 5038 | /* only send once per connect */ |
---|
4525 | 5039 | if (!server->ops->need_neg(server)) |
---|
4526 | 5040 | return 0; |
---|
4527 | | - |
---|
4528 | | - set_credits(server, 1); |
---|
4529 | 5041 | |
---|
4530 | 5042 | rc = server->ops->negotiate(xid, ses); |
---|
4531 | 5043 | if (rc == 0) { |
---|
.. | .. |
---|
4545 | 5057 | struct nls_table *nls_info) |
---|
4546 | 5058 | { |
---|
4547 | 5059 | int rc = -ENOSYS; |
---|
4548 | | - struct TCP_Server_Info *server = ses->server; |
---|
| 5060 | + struct TCP_Server_Info *server = cifs_ses_server(ses); |
---|
4549 | 5061 | |
---|
4550 | | - ses->capabilities = server->capabilities; |
---|
4551 | | - if (linuxExtEnabled == 0) |
---|
4552 | | - ses->capabilities &= (~server->vals->cap_unix); |
---|
| 5062 | + if (!ses->binding) { |
---|
| 5063 | + ses->capabilities = server->capabilities; |
---|
| 5064 | + if (linuxExtEnabled == 0) |
---|
| 5065 | + ses->capabilities &= (~server->vals->cap_unix); |
---|
| 5066 | + |
---|
| 5067 | + if (ses->auth_key.response) { |
---|
| 5068 | + cifs_dbg(FYI, "Free previous auth_key.response = %p\n", |
---|
| 5069 | + ses->auth_key.response); |
---|
| 5070 | + kfree(ses->auth_key.response); |
---|
| 5071 | + ses->auth_key.response = NULL; |
---|
| 5072 | + ses->auth_key.len = 0; |
---|
| 5073 | + } |
---|
| 5074 | + } |
---|
4553 | 5075 | |
---|
4554 | 5076 | cifs_dbg(FYI, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d\n", |
---|
4555 | 5077 | server->sec_mode, server->capabilities, server->timeAdj); |
---|
4556 | | - |
---|
4557 | | - if (ses->auth_key.response) { |
---|
4558 | | - cifs_dbg(FYI, "Free previous auth_key.response = %p\n", |
---|
4559 | | - ses->auth_key.response); |
---|
4560 | | - kfree(ses->auth_key.response); |
---|
4561 | | - ses->auth_key.response = NULL; |
---|
4562 | | - ses->auth_key.len = 0; |
---|
4563 | | - } |
---|
4564 | 5078 | |
---|
4565 | 5079 | if (server->ops->sess_setup) |
---|
4566 | 5080 | rc = server->ops->sess_setup(xid, ses, nls_info); |
---|
4567 | 5081 | |
---|
4568 | 5082 | if (rc) |
---|
4569 | | - cifs_dbg(VFS, "Send error in SessSetup = %d\n", rc); |
---|
| 5083 | + cifs_server_dbg(VFS, "Send error in SessSetup = %d\n", rc); |
---|
4570 | 5084 | |
---|
4571 | 5085 | return rc; |
---|
4572 | 5086 | } |
---|
.. | .. |
---|
4607 | 5121 | vol_info->no_lease = master_tcon->no_lease; |
---|
4608 | 5122 | vol_info->resilient = master_tcon->use_resilient; |
---|
4609 | 5123 | vol_info->persistent = master_tcon->use_persistent; |
---|
| 5124 | + vol_info->handle_timeout = master_tcon->handle_timeout; |
---|
4610 | 5125 | vol_info->no_linux_ext = !master_tcon->unix_ext; |
---|
4611 | 5126 | vol_info->linux_ext = master_tcon->posix_extensions; |
---|
4612 | 5127 | vol_info->sectype = master_tcon->ses->sectype; |
---|
.. | .. |
---|
4642 | 5157 | |
---|
4643 | 5158 | out: |
---|
4644 | 5159 | kfree(vol_info->username); |
---|
4645 | | - kzfree(vol_info->password); |
---|
| 5160 | + kfree_sensitive(vol_info->password); |
---|
4646 | 5161 | kfree(vol_info); |
---|
4647 | 5162 | |
---|
4648 | 5163 | return tcon; |
---|
.. | .. |
---|
4830 | 5345 | queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks, |
---|
4831 | 5346 | TLINK_IDLE_EXPIRE); |
---|
4832 | 5347 | } |
---|
| 5348 | + |
---|
| 5349 | +#ifdef CONFIG_CIFS_DFS_UPCALL |
---|
| 5350 | +int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const struct nls_table *nlsc) |
---|
| 5351 | +{ |
---|
| 5352 | + int rc; |
---|
| 5353 | + struct TCP_Server_Info *server = tcon->ses->server; |
---|
| 5354 | + const struct smb_version_operations *ops = server->ops; |
---|
| 5355 | + struct dfs_cache_tgt_list tl; |
---|
| 5356 | + struct dfs_cache_tgt_iterator *it = NULL; |
---|
| 5357 | + char *tree; |
---|
| 5358 | + const char *tcp_host; |
---|
| 5359 | + size_t tcp_host_len; |
---|
| 5360 | + const char *dfs_host; |
---|
| 5361 | + size_t dfs_host_len; |
---|
| 5362 | + char *share = NULL, *prefix = NULL; |
---|
| 5363 | + struct dfs_info3_param ref = {0}; |
---|
| 5364 | + bool isroot; |
---|
| 5365 | + |
---|
| 5366 | + tree = kzalloc(MAX_TREE_SIZE, GFP_KERNEL); |
---|
| 5367 | + if (!tree) |
---|
| 5368 | + return -ENOMEM; |
---|
| 5369 | + |
---|
| 5370 | + /* If it is not dfs or there was no cached dfs referral, then reconnect to same share */ |
---|
| 5371 | + if (!tcon->dfs_path || dfs_cache_noreq_find(tcon->dfs_path + 1, &ref, &tl)) { |
---|
| 5372 | + if (tcon->ipc) { |
---|
| 5373 | + scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname); |
---|
| 5374 | + rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc); |
---|
| 5375 | + } else { |
---|
| 5376 | + rc = ops->tree_connect(xid, tcon->ses, tcon->treeName, tcon, nlsc); |
---|
| 5377 | + } |
---|
| 5378 | + goto out; |
---|
| 5379 | + } |
---|
| 5380 | + |
---|
| 5381 | + isroot = ref.server_type == DFS_TYPE_ROOT; |
---|
| 5382 | + free_dfs_info_param(&ref); |
---|
| 5383 | + |
---|
| 5384 | + extract_unc_hostname(server->hostname, &tcp_host, &tcp_host_len); |
---|
| 5385 | + |
---|
| 5386 | + for (it = dfs_cache_get_tgt_iterator(&tl); it; it = dfs_cache_get_next_tgt(&tl, it)) { |
---|
| 5387 | + bool target_match; |
---|
| 5388 | + |
---|
| 5389 | + kfree(share); |
---|
| 5390 | + kfree(prefix); |
---|
| 5391 | + share = NULL; |
---|
| 5392 | + prefix = NULL; |
---|
| 5393 | + |
---|
| 5394 | + rc = dfs_cache_get_tgt_share(tcon->dfs_path + 1, it, &share, &prefix); |
---|
| 5395 | + if (rc) { |
---|
| 5396 | + cifs_dbg(VFS, "%s: failed to parse target share %d\n", |
---|
| 5397 | + __func__, rc); |
---|
| 5398 | + continue; |
---|
| 5399 | + } |
---|
| 5400 | + |
---|
| 5401 | + extract_unc_hostname(share, &dfs_host, &dfs_host_len); |
---|
| 5402 | + |
---|
| 5403 | + if (dfs_host_len != tcp_host_len |
---|
| 5404 | + || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) { |
---|
| 5405 | + cifs_dbg(FYI, "%s: %.*s doesn't match %.*s\n", __func__, (int)dfs_host_len, |
---|
| 5406 | + dfs_host, (int)tcp_host_len, tcp_host); |
---|
| 5407 | + |
---|
| 5408 | + rc = match_target_ip(server, dfs_host, dfs_host_len, &target_match); |
---|
| 5409 | + if (rc) { |
---|
| 5410 | + cifs_dbg(VFS, "%s: failed to match target ip: %d\n", __func__, rc); |
---|
| 5411 | + break; |
---|
| 5412 | + } |
---|
| 5413 | + |
---|
| 5414 | + if (!target_match) { |
---|
| 5415 | + cifs_dbg(FYI, "%s: skipping target\n", __func__); |
---|
| 5416 | + continue; |
---|
| 5417 | + } |
---|
| 5418 | + } |
---|
| 5419 | + |
---|
| 5420 | + if (tcon->ipc) { |
---|
| 5421 | + scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", share); |
---|
| 5422 | + rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc); |
---|
| 5423 | + } else { |
---|
| 5424 | + scnprintf(tree, MAX_TREE_SIZE, "\\%s", share); |
---|
| 5425 | + rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc); |
---|
| 5426 | + /* Only handle prefix paths of DFS link targets */ |
---|
| 5427 | + if (!rc && !isroot) { |
---|
| 5428 | + rc = update_super_prepath(tcon, prefix); |
---|
| 5429 | + break; |
---|
| 5430 | + } |
---|
| 5431 | + } |
---|
| 5432 | + if (rc == -EREMOTE) |
---|
| 5433 | + break; |
---|
| 5434 | + } |
---|
| 5435 | + |
---|
| 5436 | + kfree(share); |
---|
| 5437 | + kfree(prefix); |
---|
| 5438 | + |
---|
| 5439 | + if (!rc) { |
---|
| 5440 | + if (it) |
---|
| 5441 | + rc = dfs_cache_noreq_update_tgthint(tcon->dfs_path + 1, it); |
---|
| 5442 | + else |
---|
| 5443 | + rc = -ENOENT; |
---|
| 5444 | + } |
---|
| 5445 | + dfs_cache_free_tgts(&tl); |
---|
| 5446 | +out: |
---|
| 5447 | + kfree(tree); |
---|
| 5448 | + return rc; |
---|
| 5449 | +} |
---|
| 5450 | +#else |
---|
| 5451 | +int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const struct nls_table *nlsc) |
---|
| 5452 | +{ |
---|
| 5453 | + const struct smb_version_operations *ops = tcon->ses->server->ops; |
---|
| 5454 | + |
---|
| 5455 | + return ops->tree_connect(xid, tcon->ses, tcon->treeName, tcon, nlsc); |
---|
| 5456 | +} |
---|
| 5457 | +#endif |
---|