Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'v6.14-rc-smb3-client-fixes-part' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client updates from Steve French:

- Fix oops in DebugData when link speed 0

- Two reparse point fixes

- Ten DFS (global namespace) fixes

- Symlink error handling fix

- Two SMB1 fixes

- Four cleanup fixes

- Improved debugging of status codes

- Fix incorrect output of tracepoints for compounding, and add missing
compounding tracepoint

* tag 'v6.14-rc-smb3-client-fixes-part' of git://git.samba.org/sfrench/cifs-2.6: (23 commits)
smb: client: handle lack of EA support in smb2_query_path_info()
smb: client: don't check for @leaf_fullpath in match_server()
smb: client: get rid of TCP_Server_Info::refpath_lock
cifs: Remove duplicate struct reparse_symlink_data and SYMLINK_FLAG_RELATIVE
cifs: Do not attempt to call CIFSGetSrvInodeNumber() without CAP_INFOLEVEL_PASSTHRU
cifs: Do not attempt to call CIFSSMBRenameOpenFile() without CAP_INFOLEVEL_PASSTHRU
cifs: Remove declaration of dead CIFSSMBQuerySymLink function
cifs: Fix printing Status code into dmesg
cifs: Add missing NT_STATUS_* codes from nterr.h to nterr.c
cifs: Fix endian types in struct rfc1002_session_packet
cifs: Use cifs_autodisable_serverino() for disabling CIFS_MOUNT_SERVER_INUM in readdir.c
smb3: add missing tracepoint for querying wsl EAs
smb: client: fix order of arguments of tracepoints
smb: client: fix oops due to unset link speed
smb: client: correctly handle ErrorContextData as a flexible array
smb: client: don't retry DFS targets on server shutdown
smb: client: fix return value of parse_dfs_referrals()
smb: client: optimize referral walk on failed link targets
smb: client: provide dns_resolve_{unc,name} helpers
smb: client: parse DNS domain name from domain= option
...

+493 -446
+86 -84
fs/smb/client/cifsencrypt.c
··· 315 315 return 0; 316 316 } 317 317 318 - /* Server has provided av pairs/target info in the type 2 challenge 319 - * packet and we have plucked it and stored within smb session. 320 - * We parse that blob here to find netbios domain name to be used 321 - * as part of ntlmv2 authentication (in Target String), if not already 322 - * specified on the command line. 323 - * If this function returns without any error but without fetching 324 - * domain name, authentication may fail against some server but 325 - * may not fail against other (those who are not very particular 326 - * about target string i.e. for some, just user name might suffice. 327 - */ 328 - static int 329 - find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp) 318 + #define AV_TYPE(av) (le16_to_cpu(av->type)) 319 + #define AV_LEN(av) (le16_to_cpu(av->length)) 320 + #define AV_DATA_PTR(av) ((void *)av->data) 321 + 322 + #define av_for_each_entry(ses, av) \ 323 + for (av = NULL; (av = find_next_av(ses, av));) 324 + 325 + static struct ntlmssp2_name *find_next_av(struct cifs_ses *ses, 326 + struct ntlmssp2_name *av) 330 327 { 331 - unsigned int attrsize; 332 - unsigned int type; 333 - unsigned int onesize = sizeof(struct ntlmssp2_name); 334 - unsigned char *blobptr; 335 - unsigned char *blobend; 336 - struct ntlmssp2_name *attrptr; 328 + u16 len; 329 + u8 *end; 337 330 338 - if (!ses->auth_key.len || !ses->auth_key.response) 339 - return 0; 340 - 341 - blobptr = ses->auth_key.response; 342 - blobend = blobptr + ses->auth_key.len; 343 - 344 - while (blobptr + onesize < blobend) { 345 - attrptr = (struct ntlmssp2_name *) blobptr; 346 - type = le16_to_cpu(attrptr->type); 347 - if (type == NTLMSSP_AV_EOL) 348 - break; 349 - blobptr += 2; /* advance attr type */ 350 - attrsize = le16_to_cpu(attrptr->length); 351 - blobptr += 2; /* advance attr size */ 352 - if (blobptr + attrsize > blobend) 353 - break; 354 - if (type == NTLMSSP_AV_NB_DOMAIN_NAME) { 355 - if (!attrsize || attrsize >= CIFS_MAX_DOMAINNAME_LEN) 356 - break; 357 - if (!ses->domainName) { 358 - ses->domainName = 359 - kmalloc(attrsize + 1, GFP_KERNEL); 360 - if (!ses->domainName) 361 - return -ENOMEM; 362 - cifs_from_utf16(ses->domainName, 363 - (__le16 *)blobptr, attrsize, attrsize, 364 - nls_cp, NO_MAP_UNI_RSVD); 365 - break; 366 - } 367 - } 368 - blobptr += attrsize; /* advance attr value */ 331 + end = (u8 *)ses->auth_key.response + ses->auth_key.len; 332 + if (!av) { 333 + if (unlikely(!ses->auth_key.response || !ses->auth_key.len)) 334 + return NULL; 335 + av = (void *)ses->auth_key.response; 336 + } else { 337 + av = (void *)((u8 *)av + sizeof(*av) + AV_LEN(av)); 369 338 } 370 339 340 + if ((u8 *)av + sizeof(*av) > end) 341 + return NULL; 342 + 343 + len = AV_LEN(av); 344 + if (AV_TYPE(av) == NTLMSSP_AV_EOL) 345 + return NULL; 346 + if (!len || (u8 *)av + sizeof(*av) + len > end) 347 + return NULL; 348 + return av; 349 + } 350 + 351 + /* 352 + * Check if server has provided av pair of @type in the NTLMSSP 353 + * CHALLENGE_MESSAGE blob. 354 + */ 355 + static int find_av_name(struct cifs_ses *ses, u16 type, char **name, u16 maxlen) 356 + { 357 + const struct nls_table *nlsc = ses->local_nls; 358 + struct ntlmssp2_name *av; 359 + u16 len, nlen; 360 + 361 + if (*name) 362 + return 0; 363 + 364 + av_for_each_entry(ses, av) { 365 + len = AV_LEN(av); 366 + if (AV_TYPE(av) != type) 367 + continue; 368 + if (!IS_ALIGNED(len, sizeof(__le16))) { 369 + cifs_dbg(VFS | ONCE, "%s: bad length(%u) for type %u\n", 370 + __func__, len, type); 371 + continue; 372 + } 373 + nlen = len / sizeof(__le16); 374 + if (nlen <= maxlen) { 375 + ++nlen; 376 + *name = kmalloc(nlen, GFP_KERNEL); 377 + if (!*name) 378 + return -ENOMEM; 379 + cifs_from_utf16(*name, AV_DATA_PTR(av), nlen, 380 + len, nlsc, NO_MAP_UNI_RSVD); 381 + break; 382 + } 383 + } 371 384 return 0; 372 385 } 373 386 ··· 390 377 * as part of ntlmv2 authentication (or local current time as 391 378 * default in case of failure) 392 379 */ 393 - static __le64 394 - find_timestamp(struct cifs_ses *ses) 380 + static __le64 find_timestamp(struct cifs_ses *ses) 395 381 { 396 - unsigned int attrsize; 397 - unsigned int type; 398 - unsigned int onesize = sizeof(struct ntlmssp2_name); 399 - unsigned char *blobptr; 400 - unsigned char *blobend; 401 - struct ntlmssp2_name *attrptr; 382 + struct ntlmssp2_name *av; 402 383 struct timespec64 ts; 403 384 404 - if (!ses->auth_key.len || !ses->auth_key.response) 405 - return 0; 406 - 407 - blobptr = ses->auth_key.response; 408 - blobend = blobptr + ses->auth_key.len; 409 - 410 - while (blobptr + onesize < blobend) { 411 - attrptr = (struct ntlmssp2_name *) blobptr; 412 - type = le16_to_cpu(attrptr->type); 413 - if (type == NTLMSSP_AV_EOL) 414 - break; 415 - blobptr += 2; /* advance attr type */ 416 - attrsize = le16_to_cpu(attrptr->length); 417 - blobptr += 2; /* advance attr size */ 418 - if (blobptr + attrsize > blobend) 419 - break; 420 - if (type == NTLMSSP_AV_TIMESTAMP) { 421 - if (attrsize == sizeof(u64)) 422 - return *((__le64 *)blobptr); 423 - } 424 - blobptr += attrsize; /* advance attr value */ 385 + av_for_each_entry(ses, av) { 386 + if (AV_TYPE(av) == NTLMSSP_AV_TIMESTAMP && 387 + AV_LEN(av) == sizeof(u64)) 388 + return *((__le64 *)AV_DATA_PTR(av)); 425 389 } 426 - 427 390 ktime_get_real_ts64(&ts); 428 391 return cpu_to_le64(cifs_UnixTimeToNT(ts)); 429 392 } ··· 552 563 if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) { 553 564 if (!ses->domainName) { 554 565 if (ses->domainAuto) { 555 - rc = find_domain_name(ses, nls_cp); 556 - if (rc) { 557 - cifs_dbg(VFS, "error %d finding domain name\n", 558 - rc); 566 + /* 567 + * Domain (workgroup) hasn't been specified in 568 + * mount options, so try to find it in 569 + * CHALLENGE_MESSAGE message and then use it as 570 + * part of NTLMv2 authentication. 571 + */ 572 + rc = find_av_name(ses, NTLMSSP_AV_NB_DOMAIN_NAME, 573 + &ses->domainName, 574 + CIFS_MAX_DOMAINNAME_LEN); 575 + if (rc) 559 576 goto setup_ntlmv2_rsp_ret; 560 - } 561 577 } else { 562 578 ses->domainName = kstrdup("", GFP_KERNEL); 579 + if (!ses->domainName) { 580 + rc = -ENOMEM; 581 + goto setup_ntlmv2_rsp_ret; 582 + } 563 583 } 564 584 } 585 + rc = find_av_name(ses, NTLMSSP_AV_DNS_DOMAIN_NAME, 586 + &ses->dns_dom, CIFS_MAX_DOMAINNAME_LEN); 587 + if (rc) 588 + goto setup_ntlmv2_rsp_ret; 565 589 } else { 566 590 rc = build_avpair_blob(ses, nls_cp); 567 591 if (rc) {
+24 -11
fs/smb/client/cifsglob.h
··· 811 811 bool use_swn_dstaddr; 812 812 struct sockaddr_storage swn_dstaddr; 813 813 #endif 814 - struct mutex refpath_lock; /* protects leaf_fullpath */ 815 814 /* 816 - * leaf_fullpath: Canonical DFS referral path related to this 817 - * connection. 818 - * It is used in DFS cache refresher, reconnect and may 819 - * change due to nested DFS links. 820 - * 821 - * Protected by @refpath_lock and @srv_lock. The @refpath_lock is 822 - * mostly used for not requiring a copy of @leaf_fullpath when getting 823 - * cached or new DFS referrals (which might also sleep during I/O). 824 - * While @srv_lock is held for making string and NULL comparisons against 825 - * both fields as in mount(2) and cache refresh. 815 + * Canonical DFS referral path used in cifs_reconnect() for failover as 816 + * well as in DFS cache refresher. 826 817 * 827 818 * format: \\HOST\SHARE[\OPTIONAL PATH] 828 819 */ 829 820 char *leaf_fullpath; 830 821 bool dfs_conn:1; 822 + char dns_dom[CIFS_MAX_DOMAINNAME_LEN + 1]; 831 823 }; 832 824 833 825 static inline bool is_smb1(struct TCP_Server_Info *server) ··· 1146 1154 /* ========= end: protected by chan_lock ======== */ 1147 1155 struct cifs_ses *dfs_root_ses; 1148 1156 struct nls_table *local_nls; 1157 + char *dns_dom; /* FQDN of the domain */ 1149 1158 }; 1150 1159 1151 1160 static inline bool ··· 2301 2308 spin_lock(&ses->ses_lock); 2302 2309 ret = ses->ses_status == SES_EXITING; 2303 2310 spin_unlock(&ses->ses_lock); 2311 + return ret; 2312 + } 2313 + 2314 + static inline bool cifs_netbios_name(const char *name, size_t namelen) 2315 + { 2316 + bool ret = false; 2317 + size_t i; 2318 + 2319 + if (namelen >= 1 && namelen <= RFC1001_NAME_LEN) { 2320 + for (i = 0; i < namelen; i++) { 2321 + const unsigned char c = name[i]; 2322 + 2323 + if (c == '\\' || c == '/' || c == ':' || c == '*' || 2324 + c == '?' || c == '"' || c == '<' || c == '>' || 2325 + c == '|' || c == '.') 2326 + return false; 2327 + if (!ret && isalpha(c)) 2328 + ret = true; 2329 + } 2330 + } 2304 2331 return ret; 2305 2332 } 2306 2333
+1 -17
fs/smb/client/cifspdu.h
··· 649 649 struct ntlmssp2_name { 650 650 __le16 type; 651 651 __le16 length; 652 - /* char name[length]; */ 652 + __u8 data[]; 653 653 } __attribute__((packed)); 654 654 655 655 struct ntlmv2_resp { ··· 1483 1483 __le32 FileNameLength; 1484 1484 __u8 FileName[]; 1485 1485 } __attribute__((packed)); 1486 - 1487 - /* For IO_REPARSE_TAG_SYMLINK */ 1488 - struct reparse_symlink_data { 1489 - __le32 ReparseTag; 1490 - __le16 ReparseDataLength; 1491 - __u16 Reserved; 1492 - __le16 SubstituteNameOffset; 1493 - __le16 SubstituteNameLength; 1494 - __le16 PrintNameOffset; 1495 - __le16 PrintNameLength; 1496 - __le32 Flags; 1497 - char PathBuffer[]; 1498 - } __attribute__((packed)); 1499 - 1500 - /* Flag above */ 1501 - #define SYMLINK_FLAG_RELATIVE 0x00000001 1502 1486 1503 1487 /* For IO_REPARSE_TAG_NFS */ 1504 1488 #define NFS_SPECFILE_LNK 0x00000000014B4E4C
+1 -4
fs/smb/client/cifsproto.h
··· 474 474 const char *full_path, 475 475 u32 *tag, struct kvec *rsp, 476 476 int *rsp_buftype); 477 - extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, 478 - __u16 fid, char **symlinkinfo, 479 - const struct nls_table *nls_codepage); 480 477 extern int CIFSSMB_set_compression(const unsigned int xid, 481 478 struct cifs_tcon *tcon, __u16 fid); 482 479 extern int CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, ··· 677 680 } 678 681 679 682 int match_target_ip(struct TCP_Server_Info *server, 680 - const char *share, size_t share_len, 683 + const char *host, size_t hostlen, 681 684 bool *result); 682 685 int cifs_inval_name_dfs_link_error(const unsigned int xid, 683 686 struct cifs_tcon *tcon,
+47 -86
fs/smb/client/connect.c
··· 72 72 */ 73 73 static int reconn_set_ipaddr_from_hostname(struct TCP_Server_Info *server) 74 74 { 75 - int rc; 76 - int len; 77 - char *unc; 78 75 struct sockaddr_storage ss; 76 + int rc; 79 77 80 78 if (!server->hostname) 81 79 return -EINVAL; ··· 82 84 if (server->hostname[0] == '\0') 83 85 return 0; 84 86 85 - len = strlen(server->hostname) + 3; 86 - 87 - unc = kmalloc(len, GFP_KERNEL); 88 - if (!unc) { 89 - cifs_dbg(FYI, "%s: failed to create UNC path\n", __func__); 90 - return -ENOMEM; 91 - } 92 - scnprintf(unc, len, "\\\\%s", server->hostname); 93 - 94 87 spin_lock(&server->srv_lock); 95 88 ss = server->dstaddr; 96 89 spin_unlock(&server->srv_lock); 97 90 98 - rc = dns_resolve_server_name_to_ip(unc, (struct sockaddr *)&ss, NULL); 99 - kfree(unc); 100 - 101 - if (rc < 0) { 102 - cifs_dbg(FYI, "%s: failed to resolve server part of %s to IP: %d\n", 103 - __func__, server->hostname, rc); 104 - } else { 91 + rc = dns_resolve_name(server->dns_dom, server->hostname, 92 + strlen(server->hostname), 93 + (struct sockaddr *)&ss); 94 + if (!rc) { 105 95 spin_lock(&server->srv_lock); 106 96 memcpy(&server->dstaddr, &ss, sizeof(server->dstaddr)); 107 97 spin_unlock(&server->srv_lock); 108 - rc = 0; 109 98 } 110 - 111 99 return rc; 112 100 } 113 101 ··· 422 438 } 423 439 424 440 #ifdef CONFIG_CIFS_DFS_UPCALL 425 - static int __reconnect_target_unlocked(struct TCP_Server_Info *server, const char *target) 441 + static int __reconnect_target_locked(struct TCP_Server_Info *server, 442 + const char *target) 426 443 { 427 444 int rc; 428 445 char *hostname; ··· 456 471 return rc; 457 472 } 458 473 459 - static int reconnect_target_unlocked(struct TCP_Server_Info *server, struct dfs_cache_tgt_list *tl, 460 - struct dfs_cache_tgt_iterator **target_hint) 474 + static int reconnect_target_locked(struct TCP_Server_Info *server, 475 + struct dfs_cache_tgt_list *tl, 476 + struct dfs_cache_tgt_iterator **target_hint) 461 477 { 462 - int rc; 463 478 struct dfs_cache_tgt_iterator *tit; 479 + int rc; 464 480 465 481 *target_hint = NULL; 466 482 467 483 /* If dfs target list is empty, then reconnect to last server */ 468 484 tit = dfs_cache_get_tgt_iterator(tl); 469 485 if (!tit) 470 - return __reconnect_target_unlocked(server, server->hostname); 486 + return __reconnect_target_locked(server, server->hostname); 471 487 472 488 /* Otherwise, try every dfs target in @tl */ 473 - for (; tit; tit = dfs_cache_get_next_tgt(tl, tit)) { 474 - rc = __reconnect_target_unlocked(server, dfs_cache_get_tgt_name(tit)); 489 + do { 490 + const char *target = dfs_cache_get_tgt_name(tit); 491 + 492 + spin_lock(&server->srv_lock); 493 + if (server->tcpStatus != CifsNeedReconnect) { 494 + spin_unlock(&server->srv_lock); 495 + return -ECONNRESET; 496 + } 497 + spin_unlock(&server->srv_lock); 498 + rc = __reconnect_target_locked(server, target); 475 499 if (!rc) { 476 500 *target_hint = tit; 477 501 break; 478 502 } 479 - } 503 + } while ((tit = dfs_cache_get_next_tgt(tl, tit))); 480 504 return rc; 481 505 } 482 506 483 507 static int reconnect_dfs_server(struct TCP_Server_Info *server) 484 508 { 485 509 struct dfs_cache_tgt_iterator *target_hint = NULL; 486 - 510 + const char *ref_path = server->leaf_fullpath + 1; 487 511 DFS_CACHE_TGT_LIST(tl); 488 512 int num_targets = 0; 489 513 int rc = 0; ··· 505 511 * through /proc/fs/cifs/dfscache or the target list is empty due to server settings after 506 512 * refreshing the referral, so, in this case, default it to 1. 507 513 */ 508 - mutex_lock(&server->refpath_lock); 509 - if (!dfs_cache_noreq_find(server->leaf_fullpath + 1, NULL, &tl)) 514 + if (!dfs_cache_noreq_find(ref_path, NULL, &tl)) 510 515 num_targets = dfs_cache_get_nr_tgts(&tl); 511 - mutex_unlock(&server->refpath_lock); 512 516 if (!num_targets) 513 517 num_targets = 1; 514 518 ··· 526 534 try_to_freeze(); 527 535 cifs_server_lock(server); 528 536 529 - rc = reconnect_target_unlocked(server, &tl, &target_hint); 537 + rc = reconnect_target_locked(server, &tl, &target_hint); 530 538 if (rc) { 531 539 /* Failed to reconnect socket */ 532 540 cifs_server_unlock(server); ··· 550 558 mod_delayed_work(cifsiod_wq, &server->reconnect, 0); 551 559 } while (server->tcpStatus == CifsNeedReconnect); 552 560 553 - mutex_lock(&server->refpath_lock); 554 - dfs_cache_noreq_update_tgthint(server->leaf_fullpath + 1, target_hint); 555 - mutex_unlock(&server->refpath_lock); 561 + dfs_cache_noreq_update_tgthint(ref_path, target_hint); 556 562 dfs_cache_free_tgts(&tl); 557 563 558 564 /* Need to set up echo worker again once connection has been established */ ··· 565 575 566 576 int cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session) 567 577 { 568 - mutex_lock(&server->refpath_lock); 569 - if (!server->leaf_fullpath) { 570 - mutex_unlock(&server->refpath_lock); 578 + if (!server->leaf_fullpath) 571 579 return __cifs_reconnect(server, mark_smb_session); 572 - } 573 - mutex_unlock(&server->refpath_lock); 574 - 575 580 return reconnect_dfs_server(server); 576 581 } 577 582 #else ··· 1526 1541 if (!cifs_match_ipaddr((struct sockaddr *)&ctx->srcaddr, 1527 1542 (struct sockaddr *)&server->srcaddr)) 1528 1543 return 0; 1529 - /* 1530 - * When matching cifs.ko superblocks (@match_super == true), we can't 1531 - * really match either @server->leaf_fullpath or @server->dstaddr 1532 - * directly since this @server might belong to a completely different 1533 - * server -- in case of domain-based DFS referrals or DFS links -- as 1534 - * provided earlier by mount(2) through 'source' and 'ip' options. 1535 - * 1536 - * Otherwise, match the DFS referral in @server->leaf_fullpath or the 1537 - * destination address in @server->dstaddr. 1538 - * 1539 - * When using 'nodfs' mount option, we avoid sharing it with DFS 1540 - * connections as they might failover. 1541 - */ 1542 - if (!match_super) { 1543 - if (!ctx->nodfs) { 1544 - if (server->leaf_fullpath) { 1545 - if (!ctx->leaf_fullpath || 1546 - strcasecmp(server->leaf_fullpath, 1547 - ctx->leaf_fullpath)) 1548 - return 0; 1549 - } else if (ctx->leaf_fullpath) { 1550 - return 0; 1551 - } 1552 - } else if (server->leaf_fullpath) { 1553 - return 0; 1554 - } 1555 - } 1556 1544 1557 - /* 1558 - * Match for a regular connection (address/hostname/port) which has no 1559 - * DFS referrals set. 1560 - */ 1561 - if (!server->leaf_fullpath && 1562 - (strcasecmp(server->hostname, ctx->server_hostname) || 1563 - !match_server_address(server, addr) || 1564 - !match_port(server, addr))) 1545 + if (strcasecmp(server->hostname, ctx->server_hostname) || 1546 + !match_server_address(server, addr) || 1547 + !match_port(server, addr)) 1565 1548 return 0; 1566 1549 1567 1550 if (!match_security(server, ctx)) ··· 1663 1710 goto out_err; 1664 1711 } 1665 1712 } 1713 + if (ctx->dns_dom) 1714 + strscpy(tcp_ses->dns_dom, ctx->dns_dom); 1666 1715 1667 1716 if (ctx->nosharesock) 1668 1717 tcp_ses->nosharesock = true; ··· 1713 1758 INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); 1714 1759 INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server); 1715 1760 mutex_init(&tcp_ses->reconnect_mutex); 1716 - #ifdef CONFIG_CIFS_DFS_UPCALL 1717 - mutex_init(&tcp_ses->refpath_lock); 1718 - #endif 1719 1761 memcpy(&tcp_ses->srcaddr, &ctx->srcaddr, 1720 1762 sizeof(tcp_ses->srcaddr)); 1721 1763 memcpy(&tcp_ses->dstaddr, &ctx->dstaddr, ··· 2228 2276 struct cifs_ses * 2229 2277 cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) 2230 2278 { 2231 - int rc = 0; 2232 - int retries = 0; 2233 - unsigned int xid; 2234 - struct cifs_ses *ses; 2235 - struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; 2236 2279 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; 2280 + struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; 2281 + struct cifs_ses *ses; 2282 + unsigned int xid; 2283 + int retries = 0; 2284 + size_t len; 2285 + int rc = 0; 2237 2286 2238 2287 xid = get_xid(); 2239 2288 ··· 2324 2371 ses->domainName = kstrdup(ctx->domainname, GFP_KERNEL); 2325 2372 if (!ses->domainName) 2326 2373 goto get_ses_fail; 2374 + 2375 + len = strnlen(ctx->domainname, CIFS_MAX_DOMAINNAME_LEN); 2376 + if (!cifs_netbios_name(ctx->domainname, len)) { 2377 + ses->dns_dom = kstrndup(ctx->domainname, 2378 + len, GFP_KERNEL); 2379 + if (!ses->dns_dom) 2380 + goto get_ses_fail; 2381 + } 2327 2382 } 2328 2383 2329 2384 strscpy(ses->workstation_name, ctx->workstation_name, sizeof(ses->workstation_name));
+33 -47
fs/smb/client/dfs.c
··· 9 9 #include "fs_context.h" 10 10 #include "dfs.h" 11 11 12 + #define DFS_DOM(ctx) (ctx->dfs_root_ses ? ctx->dfs_root_ses->dns_dom : NULL) 13 + 12 14 /** 13 15 * dfs_parse_target_referral - set fs context for dfs target referral 14 16 * ··· 48 46 if (rc) 49 47 goto out; 50 48 51 - rc = dns_resolve_server_name_to_ip(path, (struct sockaddr *)&ctx->dstaddr, NULL); 52 - 49 + rc = dns_resolve_unc(DFS_DOM(ctx), path, 50 + (struct sockaddr *)&ctx->dstaddr); 53 51 out: 54 52 kfree(path); 55 53 return rc; ··· 61 59 int rc; 62 60 63 61 ctx->leaf_fullpath = (char *)full_path; 62 + ctx->dns_dom = DFS_DOM(ctx); 64 63 rc = cifs_mount_get_session(mnt_ctx); 65 - ctx->leaf_fullpath = NULL; 64 + ctx->leaf_fullpath = ctx->dns_dom = NULL; 66 65 67 66 return rc; 68 67 } ··· 98 95 return rc; 99 96 } 100 97 101 - static int setup_dfs_ref(struct cifs_mount_ctx *mnt_ctx, 102 - struct dfs_info3_param *tgt, 103 - struct dfs_ref_walk *rw) 98 + static int setup_dfs_ref(struct dfs_info3_param *tgt, struct dfs_ref_walk *rw) 104 99 { 105 - struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; 106 - struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb; 100 + struct cifs_sb_info *cifs_sb = rw->mnt_ctx->cifs_sb; 101 + struct smb3_fs_context *ctx = rw->mnt_ctx->fs_ctx; 107 102 char *ref_path, *full_path; 108 103 int rc; 104 + 105 + set_root_smb_session(rw->mnt_ctx); 106 + ref_walk_ses(rw) = ctx->dfs_root_ses; 109 107 110 108 full_path = smb3_fs_context_fullpath(ctx, CIFS_DIR_SEP(cifs_sb)); 111 109 if (IS_ERR(full_path)) ··· 124 120 } 125 121 ref_walk_path(rw) = ref_path; 126 122 ref_walk_fpath(rw) = full_path; 127 - ref_walk_ses(rw) = ctx->dfs_root_ses; 128 - return 0; 123 + 124 + return dfs_get_referral(rw->mnt_ctx, 125 + ref_walk_path(rw) + 1, 126 + ref_walk_tl(rw)); 129 127 } 130 128 131 - static int __dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx, 132 - struct dfs_ref_walk *rw) 129 + static int __dfs_referral_walk(struct dfs_ref_walk *rw) 133 130 { 134 - struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; 131 + struct smb3_fs_context *ctx = rw->mnt_ctx->fs_ctx; 132 + struct cifs_mount_ctx *mnt_ctx = rw->mnt_ctx; 135 133 struct dfs_info3_param tgt = {}; 136 134 int rc = -ENOENT; 137 135 138 136 again: 139 137 do { 140 138 ctx->dfs_root_ses = ref_walk_ses(rw); 141 - if (ref_walk_empty(rw)) { 142 - rc = dfs_get_referral(mnt_ctx, ref_walk_path(rw) + 1, 143 - NULL, ref_walk_tl(rw)); 144 - if (rc) { 145 - rc = cifs_mount_get_tcon(mnt_ctx); 146 - if (!rc) 147 - rc = cifs_is_path_remote(mnt_ctx); 148 - continue; 149 - } 150 - if (!ref_walk_num_tgts(rw)) { 151 - rc = -ENOENT; 152 - continue; 153 - } 154 - } 155 - 156 139 while (ref_walk_next_tgt(rw)) { 157 140 rc = parse_dfs_target(ctx, rw, &tgt); 158 141 if (rc) ··· 150 159 if (rc) 151 160 continue; 152 161 153 - ref_walk_set_tgt_hint(rw); 154 162 if (tgt.flags & DFSREF_STORAGE_SERVER) { 155 163 rc = cifs_mount_get_tcon(mnt_ctx); 156 164 if (!rc) 157 165 rc = cifs_is_path_remote(mnt_ctx); 158 - if (!rc) 166 + if (!rc) { 167 + ref_walk_set_tgt_hint(rw); 159 168 break; 169 + } 160 170 if (rc != -EREMOTE) 161 171 continue; 162 172 } 163 173 164 - set_root_smb_session(mnt_ctx); 165 174 rc = ref_walk_advance(rw); 166 175 if (!rc) { 167 - rc = setup_dfs_ref(mnt_ctx, &tgt, rw); 168 - if (!rc) { 169 - rc = -EREMOTE; 170 - goto again; 171 - } 176 + rc = setup_dfs_ref(&tgt, rw); 177 + if (rc) 178 + break; 179 + ref_walk_mark_end(rw); 180 + goto again; 172 181 } 173 - if (rc != -ELOOP) 174 - goto out; 175 182 } 176 183 } while (rc && ref_walk_descend(rw)); 177 184 178 - out: 179 185 free_dfs_info_param(&tgt); 180 186 return rc; 181 187 } ··· 189 201 return rc; 190 202 } 191 203 192 - ref_walk_init(*rw); 193 - rc = setup_dfs_ref(mnt_ctx, NULL, *rw); 204 + ref_walk_init(*rw, mnt_ctx); 205 + rc = setup_dfs_ref(NULL, *rw); 194 206 if (!rc) 195 - rc = __dfs_referral_walk(mnt_ctx, *rw); 207 + rc = __dfs_referral_walk(*rw); 196 208 return rc; 197 209 } 198 210 ··· 252 264 int rc = 0; 253 265 254 266 if (!ctx->nodfs && ctx->dfs_automount) { 255 - rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL); 267 + rc = dns_resolve_unc(NULL, ctx->source, addr); 256 268 if (!rc) 257 269 cifs_set_port(addr, ctx->port); 258 270 ctx->dfs_automount = false; ··· 282 294 * to respond with PATH_NOT_COVERED to requests that include the prefix. 283 295 */ 284 296 if (!nodfs) { 285 - rc = dfs_get_referral(mnt_ctx, ctx->UNC + 1, NULL, NULL); 297 + rc = dfs_get_referral(mnt_ctx, ctx->UNC + 1, NULL); 286 298 if (rc) { 287 299 cifs_dbg(FYI, "%s: no dfs referral for %s: %d\n", 288 300 __func__, ctx->UNC + 1, rc); ··· 302 314 cifs_mount_put_conns(mnt_ctx); 303 315 rc = get_session(mnt_ctx, NULL); 304 316 } 305 - if (!rc) { 306 - set_root_smb_session(mnt_ctx); 317 + if (!rc) 307 318 rc = __dfs_mount_share(mnt_ctx); 308 - } 309 319 return rc; 310 320 } 311 321
+30 -14
fs/smb/client/dfs.h
··· 12 12 #include "dfs_cache.h" 13 13 #include "cifs_unicode.h" 14 14 #include <linux/namei.h> 15 + #include <linux/errno.h> 15 16 16 17 #define DFS_INTERLINK(v) \ 17 18 (((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER)) ··· 26 25 }; 27 26 28 27 struct dfs_ref_walk { 29 - struct dfs_ref *ref; 30 - struct dfs_ref refs[MAX_NESTED_LINKS]; 28 + struct cifs_mount_ctx *mnt_ctx; 29 + struct dfs_ref *ref; 30 + struct dfs_ref refs[MAX_NESTED_LINKS]; 31 31 }; 32 32 33 33 #define ref_walk_start(w) ((w)->refs) ··· 37 35 #define ref_walk_descend(w) (--ref_walk_cur(w) >= ref_walk_start(w)) 38 36 39 37 #define ref_walk_tit(w) (ref_walk_cur(w)->tit) 40 - #define ref_walk_empty(w) (!ref_walk_tit(w)) 41 38 #define ref_walk_path(w) (ref_walk_cur(w)->path) 42 39 #define ref_walk_fpath(w) (ref_walk_cur(w)->full_path) 43 40 #define ref_walk_tl(w) (&ref_walk_cur(w)->tl) ··· 52 51 return rw; 53 52 } 54 53 55 - static inline void ref_walk_init(struct dfs_ref_walk *rw) 54 + static inline void ref_walk_init(struct dfs_ref_walk *rw, 55 + struct cifs_mount_ctx *mnt_ctx) 56 56 { 57 57 memset(rw, 0, sizeof(*rw)); 58 + rw->mnt_ctx = mnt_ctx; 58 59 ref_walk_cur(rw) = ref_walk_start(rw); 59 60 } 60 61 ··· 96 93 static inline struct dfs_cache_tgt_iterator * 97 94 ref_walk_next_tgt(struct dfs_ref_walk *rw) 98 95 { 99 - struct dfs_cache_tgt_iterator *tit; 100 96 struct dfs_ref *ref = ref_walk_cur(rw); 97 + struct dfs_cache_tgt_iterator *tit; 98 + 99 + if (IS_ERR(ref->tit)) 100 + return NULL; 101 101 102 102 if (!ref->tit) 103 103 tit = dfs_cache_get_tgt_iterator(&ref->tl); 104 104 else 105 105 tit = dfs_cache_get_next_tgt(&ref->tl, ref->tit); 106 + 107 + if (!tit) { 108 + ref->tit = ERR_PTR(-ENOENT); 109 + return NULL; 110 + } 106 111 ref->tit = tit; 107 - return tit; 112 + return ref->tit; 108 113 } 109 114 110 115 static inline int ref_walk_get_tgt(struct dfs_ref_walk *rw, ··· 121 110 zfree_dfs_info_param(tgt); 122 111 return dfs_cache_get_tgt_referral(ref_walk_path(rw) + 1, 123 112 ref_walk_tit(rw), tgt); 124 - } 125 - 126 - static inline int ref_walk_num_tgts(struct dfs_ref_walk *rw) 127 - { 128 - return dfs_cache_get_nr_tgts(ref_walk_tl(rw)); 129 113 } 130 114 131 115 static inline void ref_walk_set_tgt_hint(struct dfs_ref_walk *rw) ··· 142 136 } 143 137 } 144 138 139 + static inline void ref_walk_mark_end(struct dfs_ref_walk *rw) 140 + { 141 + struct dfs_ref *ref = ref_walk_cur(rw) - 1; 142 + 143 + WARN_ON_ONCE(ref < ref_walk_start(rw)); 144 + dfs_cache_noreq_update_tgthint(ref->path + 1, ref->tit); 145 + ref->tit = ERR_PTR(-ENOENT); /* end marker */ 146 + } 147 + 145 148 int dfs_parse_target_referral(const char *full_path, const struct dfs_info3_param *ref, 146 149 struct smb3_fs_context *ctx); 147 150 int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx); ··· 160 145 return dfs_cache_canonical_path(path, cifs_sb->local_nls, cifs_remap(cifs_sb)); 161 146 } 162 147 163 - static inline int dfs_get_referral(struct cifs_mount_ctx *mnt_ctx, const char *path, 164 - struct dfs_info3_param *ref, struct dfs_cache_tgt_list *tl) 148 + static inline int dfs_get_referral(struct cifs_mount_ctx *mnt_ctx, 149 + const char *path, 150 + struct dfs_cache_tgt_list *tl) 165 151 { 166 152 struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; 167 153 struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb; 168 154 struct cifs_ses *rses = ctx->dfs_root_ses ?: mnt_ctx->ses; 169 155 170 156 return dfs_cache_find(mnt_ctx->xid, rses, cifs_sb->local_nls, 171 - cifs_remap(cifs_sb), path, ref, tl); 157 + cifs_remap(cifs_sb), path, NULL, tl); 172 158 } 173 159 174 160 /*
+5 -15
fs/smb/client/dfs_cache.c
··· 1096 1096 static bool target_share_equal(struct cifs_tcon *tcon, const char *s1) 1097 1097 { 1098 1098 struct TCP_Server_Info *server = tcon->ses->server; 1099 - struct sockaddr_storage ss; 1100 - const char *host; 1101 1099 const char *s2 = &tcon->tree_name[1]; 1102 - size_t hostlen; 1103 - char unc[sizeof("\\\\") + SERVER_NAME_LENGTH] = {0}; 1100 + struct sockaddr_storage ss; 1104 1101 bool match; 1105 1102 int rc; 1106 1103 ··· 1108 1111 * Resolve share's hostname and check if server address matches. Otherwise just ignore it 1109 1112 * as we could not have upcall to resolve hostname or failed to convert ip address. 1110 1113 */ 1111 - extract_unc_hostname(s1, &host, &hostlen); 1112 - scnprintf(unc, sizeof(unc), "\\\\%.*s", (int)hostlen, host); 1113 - 1114 - rc = dns_resolve_server_name_to_ip(unc, (struct sockaddr *)&ss, NULL); 1115 - if (rc < 0) { 1116 - cifs_dbg(FYI, "%s: could not resolve %.*s. assuming server address matches.\n", 1117 - __func__, (int)hostlen, host); 1114 + rc = dns_resolve_unc(server->dns_dom, s1, (struct sockaddr *)&ss); 1115 + if (rc < 0) 1118 1116 return true; 1119 - } 1120 1117 1121 1118 cifs_server_lock(server); 1122 1119 match = cifs_match_ipaddr((struct sockaddr *)&server->dstaddr, (struct sockaddr *)&ss); 1120 + cifs_dbg(FYI, "%s: [share=%s] ipaddr matched: %s\n", __func__, s1, str_yes_no(match)); 1123 1121 cifs_server_unlock(server); 1124 1122 1125 1123 return match; ··· 1141 1149 struct TCP_Server_Info *server = ses->server; 1142 1150 char *path = ERR_PTR(-ENOENT); 1143 1151 1144 - mutex_lock(&server->refpath_lock); 1145 1152 if (server->leaf_fullpath) { 1146 - path = kstrdup(server->leaf_fullpath + 1, GFP_ATOMIC); 1153 + path = kstrdup(server->leaf_fullpath + 1, GFP_KERNEL); 1147 1154 if (!path) 1148 1155 path = ERR_PTR(-ENOMEM); 1149 1156 } 1150 - mutex_unlock(&server->refpath_lock); 1151 1157 return path; 1152 1158 } 1153 1159
+3 -3
fs/smb/client/dir.c
··· 627 627 goto mknod_out; 628 628 } 629 629 630 - trace_smb3_mknod_enter(xid, tcon->ses->Suid, tcon->tid, full_path); 630 + trace_smb3_mknod_enter(xid, tcon->tid, tcon->ses->Suid, full_path); 631 631 632 632 rc = tcon->ses->server->ops->make_node(xid, inode, direntry, tcon, 633 633 full_path, mode, ··· 635 635 636 636 mknod_out: 637 637 if (rc) 638 - trace_smb3_mknod_err(xid, tcon->ses->Suid, tcon->tid, rc); 638 + trace_smb3_mknod_err(xid, tcon->tid, tcon->ses->Suid, rc); 639 639 else 640 - trace_smb3_mknod_done(xid, tcon->ses->Suid, tcon->tid); 640 + trace_smb3_mknod_done(xid, tcon->tid, tcon->ses->Suid); 641 641 642 642 free_dentry_path(page); 643 643 free_xid(xid);
+58 -50
fs/smb/client/dns_resolve.c
··· 20 20 #include "cifsproto.h" 21 21 #include "cifs_debug.h" 22 22 23 - /** 24 - * dns_resolve_server_name_to_ip - Resolve UNC server name to ip address. 25 - * @unc: UNC path specifying the server (with '/' as delimiter) 26 - * @ip_addr: Where to return the IP address. 27 - * @expiry: Where to return the expiry time for the dns record. 28 - * 29 - * Returns zero success, -ve on error. 30 - */ 31 - int 32 - dns_resolve_server_name_to_ip(const char *unc, struct sockaddr *ip_addr, time64_t *expiry) 23 + static int resolve_name(const char *name, size_t namelen, struct sockaddr *addr) 33 24 { 34 - const char *hostname, *sep; 35 25 char *ip; 36 - int len, rc; 26 + int rc; 37 27 38 - if (!ip_addr || !unc) 39 - return -EINVAL; 28 + rc = dns_query(current->nsproxy->net_ns, NULL, name, 29 + namelen, NULL, &ip, NULL, false); 30 + if (rc < 0) { 31 + cifs_dbg(FYI, "%s: unable to resolve: %*.*s\n", 32 + __func__, (int)namelen, (int)namelen, name); 33 + } else { 34 + cifs_dbg(FYI, "%s: resolved: %*.*s to %s\n", 35 + __func__, (int)namelen, (int)namelen, name, ip); 40 36 41 - len = strlen(unc); 42 - if (len < 3) { 43 - cifs_dbg(FYI, "%s: unc is too short: %s\n", __func__, unc); 44 - return -EINVAL; 37 + rc = cifs_convert_address(addr, ip, strlen(ip)); 38 + kfree(ip); 39 + if (!rc) { 40 + cifs_dbg(FYI, "%s: unable to determine ip address\n", 41 + __func__); 42 + rc = -EHOSTUNREACH; 43 + } else { 44 + rc = 0; 45 + } 45 46 } 47 + return rc; 48 + } 46 49 47 - /* Discount leading slashes for cifs */ 48 - len -= 2; 49 - hostname = unc + 2; 50 + /** 51 + * dns_resolve_name - Perform an upcall to resolve hostname to an ip address. 52 + * @dom: DNS domain name (or NULL) 53 + * @name: Name to look up 54 + * @namelen: Length of name 55 + * @ip_addr: Where to return the IP address 56 + * 57 + * Returns zero on success, -ve code otherwise. 58 + */ 59 + int dns_resolve_name(const char *dom, const char *name, 60 + size_t namelen, struct sockaddr *ip_addr) 61 + { 62 + size_t len; 63 + char *s; 64 + int rc; 50 65 51 - /* Search for server name delimiter */ 52 - sep = memchr(hostname, '/', len); 53 - if (sep) 54 - len = sep - hostname; 55 - else 56 - cifs_dbg(FYI, "%s: probably server name is whole unc: %s\n", 57 - __func__, unc); 66 + cifs_dbg(FYI, "%s: dom=%s name=%.*s\n", __func__, dom, (int)namelen, name); 67 + if (!ip_addr || !name || !*name || !namelen) 68 + return -EINVAL; 58 69 70 + cifs_dbg(FYI, "%s: hostname=%.*s\n", __func__, (int)namelen, name); 59 71 /* Try to interpret hostname as an IPv4 or IPv6 address */ 60 - rc = cifs_convert_address(ip_addr, hostname, len); 72 + rc = cifs_convert_address(ip_addr, name, namelen); 61 73 if (rc > 0) { 62 - cifs_dbg(FYI, "%s: unc is IP, skipping dns upcall: %*.*s\n", __func__, len, len, 63 - hostname); 74 + cifs_dbg(FYI, "%s: unc is IP, skipping dns upcall: %*.*s\n", 75 + __func__, (int)namelen, (int)namelen, name); 64 76 return 0; 65 77 } 66 78 67 - /* Perform the upcall */ 68 - rc = dns_query(current->nsproxy->net_ns, NULL, hostname, len, 69 - NULL, &ip, expiry, false); 70 - if (rc < 0) { 71 - cifs_dbg(FYI, "%s: unable to resolve: %*.*s\n", 72 - __func__, len, len, hostname); 73 - } else { 74 - cifs_dbg(FYI, "%s: resolved: %*.*s to %s expiry %llu\n", 75 - __func__, len, len, hostname, ip, 76 - expiry ? (*expiry) : 0); 79 + /* 80 + * If @name contains a NetBIOS name and @dom has been specified, then 81 + * convert @name to an FQDN and try resolving it first. 82 + */ 83 + if (dom && *dom && cifs_netbios_name(name, namelen)) { 84 + len = strnlen(dom, CIFS_MAX_DOMAINNAME_LEN) + namelen + 2; 85 + s = kmalloc(len, GFP_KERNEL); 86 + if (!s) 87 + return -ENOMEM; 77 88 78 - rc = cifs_convert_address(ip_addr, ip, strlen(ip)); 79 - kfree(ip); 80 - 81 - if (!rc) { 82 - cifs_dbg(FYI, "%s: unable to determine ip address\n", __func__); 83 - rc = -EHOSTUNREACH; 84 - } else 85 - rc = 0; 89 + scnprintf(s, len, "%.*s.%s", (int)namelen, name, dom); 90 + rc = resolve_name(s, len - 1, ip_addr); 91 + kfree(s); 92 + if (!rc) 93 + return 0; 86 94 } 87 - return rc; 95 + return resolve_name(name, namelen, ip_addr); 88 96 }
+22 -1
fs/smb/client/dns_resolve.h
··· 12 12 #define _DNS_RESOLVE_H 13 13 14 14 #include <linux/net.h> 15 + #include "cifsglob.h" 16 + #include "cifsproto.h" 15 17 16 18 #ifdef __KERNEL__ 17 - int dns_resolve_server_name_to_ip(const char *unc, struct sockaddr *ip_addr, time64_t *expiry); 19 + 20 + int dns_resolve_name(const char *dom, const char *name, 21 + size_t namelen, struct sockaddr *ip_addr); 22 + 23 + static inline int dns_resolve_unc(const char *dom, const char *unc, 24 + struct sockaddr *ip_addr) 25 + { 26 + const char *name; 27 + size_t namelen; 28 + 29 + if (!unc || strlen(unc) < 3) 30 + return -EINVAL; 31 + 32 + extract_unc_hostname(unc, &name, &namelen); 33 + if (!namelen) 34 + return -EINVAL; 35 + 36 + return dns_resolve_name(dom, name, namelen, ip_addr); 37 + } 38 + 18 39 #endif /* KERNEL */ 19 40 20 41 #endif /* _DNS_RESOLVE_H */
+4
fs/smb/client/fs_context.c
··· 385 385 new_ctx->source = NULL; 386 386 new_ctx->iocharset = NULL; 387 387 new_ctx->leaf_fullpath = NULL; 388 + new_ctx->dns_dom = NULL; 388 389 /* 389 390 * Make sure to stay in sync with smb3_cleanup_fs_context_contents() 390 391 */ ··· 400 399 DUP_CTX_STR(nodename); 401 400 DUP_CTX_STR(iocharset); 402 401 DUP_CTX_STR(leaf_fullpath); 402 + DUP_CTX_STR(dns_dom); 403 403 404 404 return 0; 405 405 } ··· 1865 1863 ctx->prepath = NULL; 1866 1864 kfree(ctx->leaf_fullpath); 1867 1865 ctx->leaf_fullpath = NULL; 1866 + kfree(ctx->dns_dom); 1867 + ctx->dns_dom = NULL; 1868 1868 } 1869 1869 1870 1870 void
+1
fs/smb/client/fs_context.h
··· 295 295 bool dfs_automount:1; /* set for dfs automount only */ 296 296 enum cifs_reparse_type reparse_type; 297 297 bool dfs_conn:1; /* set for dfs mounts */ 298 + char *dns_dom; 298 299 }; 299 300 300 301 extern const struct fs_parameter_spec smb3_fs_parameters[];
+7
fs/smb/client/inode.c
··· 2392 2392 if (to_dentry->d_parent != from_dentry->d_parent) 2393 2393 goto do_rename_exit; 2394 2394 2395 + /* 2396 + * CIFSSMBRenameOpenFile() uses SMB_SET_FILE_RENAME_INFORMATION 2397 + * which is SMB PASSTHROUGH level. 2398 + */ 2399 + if (!(tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)) 2400 + goto do_rename_exit; 2401 + 2395 2402 oparms = (struct cifs_open_parms) { 2396 2403 .tcon = tcon, 2397 2404 .cifs_sb = cifs_sb,
+11 -18
fs/smb/client/misc.c
··· 101 101 kfree_sensitive(buf_to_free->password2); 102 102 kfree(buf_to_free->user_name); 103 103 kfree(buf_to_free->domainName); 104 + kfree(buf_to_free->dns_dom); 104 105 kfree_sensitive(buf_to_free->auth_key.response); 105 106 spin_lock(&buf_to_free->iface_lock); 106 107 list_for_each_entry_safe(iface, niface, &buf_to_free->iface_list, ··· 909 908 *num_of_nodes = le16_to_cpu(rsp->NumberOfReferrals); 910 909 911 910 if (*num_of_nodes < 1) { 912 - cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n", 913 - *num_of_nodes); 914 - rc = -EINVAL; 911 + cifs_dbg(VFS | ONCE, "%s: [path=%s] num_referrals must be at least > 0, but we got %d\n", 912 + __func__, searchName, *num_of_nodes); 913 + rc = -ENOENT; 915 914 goto parse_DFS_referrals_exit; 916 915 } 917 916 ··· 1172 1171 1173 1172 #ifdef CONFIG_CIFS_DFS_UPCALL 1174 1173 int match_target_ip(struct TCP_Server_Info *server, 1175 - const char *share, size_t share_len, 1174 + const char *host, size_t hostlen, 1176 1175 bool *result) 1177 1176 { 1178 - int rc; 1179 - char *target; 1180 1177 struct sockaddr_storage ss; 1178 + int rc; 1179 + 1180 + cifs_dbg(FYI, "%s: hostname=%.*s\n", __func__, (int)hostlen, host); 1181 1181 1182 1182 *result = false; 1183 1183 1184 - target = kzalloc(share_len + 3, GFP_KERNEL); 1185 - if (!target) 1186 - return -ENOMEM; 1187 - 1188 - scnprintf(target, share_len + 3, "\\\\%.*s", (int)share_len, share); 1189 - 1190 - cifs_dbg(FYI, "%s: target name: %s\n", __func__, target + 2); 1191 - 1192 - rc = dns_resolve_server_name_to_ip(target, (struct sockaddr *)&ss, NULL); 1193 - kfree(target); 1194 - 1184 + rc = dns_resolve_name(server->dns_dom, host, hostlen, 1185 + (struct sockaddr *)&ss); 1195 1186 if (rc < 0) 1196 1187 return rc; 1197 1188 1198 1189 spin_lock(&server->srv_lock); 1199 1190 *result = cifs_match_ipaddr((struct sockaddr *)&server->dstaddr, (struct sockaddr *)&ss); 1200 1191 spin_unlock(&server->srv_lock); 1201 - cifs_dbg(FYI, "%s: ip addresses match: %u\n", __func__, *result); 1192 + cifs_dbg(FYI, "%s: ip addresses matched: %s\n", __func__, str_yes_no(*result)); 1202 1193 return 0; 1203 1194 } 1204 1195
+2 -2
fs/smb/client/netmisc.c
··· 775 775 int idx = 0; 776 776 777 777 while (nt_errs[idx].nt_errstr != NULL) { 778 - if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) == 779 - (status_code & 0xFFFFFF)) { 778 + if (nt_errs[idx].nt_errcode == status_code) { 780 779 pr_notice("Status code returned 0x%08x %s\n", 781 780 status_code, nt_errs[idx].nt_errstr); 781 + return; 782 782 } 783 783 idx++; 784 784 }
+8
fs/smb/client/nterr.c
··· 13 13 14 14 const struct nt_err_code_struct nt_errs[] = { 15 15 {"NT_STATUS_OK", NT_STATUS_OK}, 16 + {"NT_STATUS_MEDIA_CHANGED", NT_STATUS_MEDIA_CHANGED}, 17 + {"NT_STATUS_END_OF_MEDIA", NT_STATUS_END_OF_MEDIA}, 18 + {"NT_STATUS_MEDIA_CHECK", NT_STATUS_MEDIA_CHECK}, 19 + {"NT_STATUS_NO_DATA_DETECTED", NT_STATUS_NO_DATA_DETECTED}, 20 + {"NT_STATUS_STOPPED_ON_SYMLINK", NT_STATUS_STOPPED_ON_SYMLINK}, 21 + {"NT_STATUS_DEVICE_REQUIRES_CLEANING", NT_STATUS_DEVICE_REQUIRES_CLEANING}, 22 + {"NT_STATUS_DEVICE_DOOR_OPEN", NT_STATUS_DEVICE_DOOR_OPEN}, 16 23 {"NT_STATUS_UNSUCCESSFUL", NT_STATUS_UNSUCCESSFUL}, 17 24 {"NT_STATUS_NOT_IMPLEMENTED", NT_STATUS_NOT_IMPLEMENTED}, 18 25 {"NT_STATUS_INVALID_INFO_CLASS", NT_STATUS_INVALID_INFO_CLASS}, ··· 677 670 {"NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES}, 678 671 {"NT_STATUS_MORE_ENTRIES", NT_STATUS_MORE_ENTRIES}, 679 672 {"NT_STATUS_SOME_UNMAPPED", NT_STATUS_SOME_UNMAPPED}, 673 + {"NT_STATUS_NO_SUCH_JOB", NT_STATUS_NO_SUCH_JOB}, 680 674 {NULL, 0} 681 675 };
+1 -1
fs/smb/client/readdir.c
··· 413 413 cifsFile->invalidHandle = false; 414 414 } else if ((rc == -EOPNOTSUPP) && 415 415 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { 416 - cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; 416 + cifs_autodisable_serverino(cifs_sb); 417 417 goto ffirst_retry; 418 418 } 419 419 error_exit:
+3 -3
fs/smb/client/rfc1002pdu.h
··· 24 24 struct rfc1002_session_packet { 25 25 __u8 type; 26 26 __u8 flags; 27 - __u16 length; 27 + __be16 length; 28 28 union { 29 29 struct { 30 30 __u8 called_len; ··· 35 35 __u8 scope2; /* null */ 36 36 } __attribute__((packed)) session_req; 37 37 struct { 38 - __u32 retarget_ip_addr; 39 - __u16 port; 38 + __be32 retarget_ip_addr; 39 + __be16 port; 40 40 } __attribute__((packed)) retarget_resp; 41 41 __u8 neg_ses_resp_error_code; 42 42 /* POSITIVE_SESSION_RESPONSE packet does not include trailer.
+6
fs/smb/client/smb1ops.c
··· 614 614 * There may be higher info levels that work but are there Windows 615 615 * server or network appliances for which IndexNumber field is not 616 616 * guaranteed unique? 617 + * 618 + * CIFSGetSrvInodeNumber() uses SMB_QUERY_FILE_INTERNAL_INFO 619 + * which is SMB PASSTHROUGH level therefore check for capability. 620 + * Note that this function can be called with tcon == NULL. 617 621 */ 622 + if (tcon && !(tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)) 623 + return -EOPNOTSUPP; 618 624 return CIFSGetSrvInodeNumber(xid, tcon, full_path, uniqueid, 619 625 cifs_sb->local_nls, 620 626 cifs_remap(cifs_sb));
+2 -2
fs/smb/client/smb2file.c
··· 42 42 end = (struct smb2_error_context_rsp *)((u8 *)err + iov->iov_len); 43 43 do { 44 44 if (le32_to_cpu(p->ErrorId) == SMB2_ERROR_ID_DEFAULT) { 45 - sym = (struct smb2_symlink_err_rsp *)&p->ErrorContextData; 45 + sym = (struct smb2_symlink_err_rsp *)p->ErrorContextData; 46 46 break; 47 47 } 48 48 cifs_dbg(FYI, "%s: skipping unhandled error context: 0x%x\n", 49 49 __func__, le32_to_cpu(p->ErrorId)); 50 50 51 51 len = ALIGN(le32_to_cpu(p->ErrorDataLength), 8); 52 - p = (struct smb2_error_context_rsp *)((u8 *)&p->ErrorContextData + len); 52 + p = (struct smb2_error_context_rsp *)(p->ErrorContextData + len); 53 53 } while (p < end); 54 54 } else if (le32_to_cpu(err->ByteCount) >= sizeof(*sym) && 55 55 iov->iov_len >= SMB2_SYMLINK_STRUCT_SIZE) {
+131 -83
fs/smb/client/smb2inode.c
··· 176 176 struct kvec *out_iov, int *out_buftype, struct dentry *dentry) 177 177 { 178 178 179 - struct reparse_data_buffer *rbuf; 180 - struct smb2_compound_vars *vars = NULL; 181 - struct kvec *rsp_iov, *iov; 182 - struct smb_rqst *rqst; 183 - int rc; 184 - __le16 *utf16_path = NULL; 185 - __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 186 - struct cifs_fid fid; 187 - struct cifs_ses *ses = tcon->ses; 188 - struct TCP_Server_Info *server; 189 - int num_rqst = 0, i; 190 - int resp_buftype[MAX_COMPOUND]; 191 179 struct smb2_query_info_rsp *qi_rsp = NULL; 180 + struct smb2_compound_vars *vars = NULL; 181 + __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 192 182 struct cifs_open_info_data *idata; 193 - struct inode *inode = NULL; 194 - int flags = 0; 195 - __u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0}; 196 - unsigned int size[2]; 197 - void *data[2]; 198 - unsigned int len; 183 + struct cifs_ses *ses = tcon->ses; 184 + struct reparse_data_buffer *rbuf; 185 + struct TCP_Server_Info *server; 186 + int resp_buftype[MAX_COMPOUND]; 199 187 int retries = 0, cur_sleep = 1; 188 + __u8 delete_pending[8] = {1,}; 189 + struct kvec *rsp_iov, *iov; 190 + struct inode *inode = NULL; 191 + __le16 *utf16_path = NULL; 192 + struct smb_rqst *rqst; 193 + unsigned int size[2]; 194 + struct cifs_fid fid; 195 + int num_rqst = 0, i; 196 + unsigned int len; 197 + int tmp_rc, rc; 198 + int flags = 0; 199 + void *data[2]; 200 200 201 201 replay_again: 202 202 /* reinitialize for possible replay */ ··· 298 298 goto finished; 299 299 } 300 300 num_rqst++; 301 - trace_smb3_query_info_compound_enter(xid, ses->Suid, 302 - tcon->tid, full_path); 301 + trace_smb3_query_info_compound_enter(xid, tcon->tid, 302 + ses->Suid, full_path); 303 303 break; 304 304 case SMB2_OP_POSIX_QUERY_INFO: 305 305 rqst[num_rqst].rq_iov = &vars->qi_iov; ··· 334 334 goto finished; 335 335 } 336 336 num_rqst++; 337 - trace_smb3_posix_query_info_compound_enter(xid, ses->Suid, 338 - tcon->tid, full_path); 337 + trace_smb3_posix_query_info_compound_enter(xid, tcon->tid, 338 + ses->Suid, full_path); 339 339 break; 340 340 case SMB2_OP_DELETE: 341 - trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path); 341 + trace_smb3_delete_enter(xid, tcon->tid, ses->Suid, full_path); 342 342 break; 343 343 case SMB2_OP_MKDIR: 344 344 /* 345 345 * Directories are created through parameters in the 346 346 * SMB2_open() call. 347 347 */ 348 - trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path); 348 + trace_smb3_mkdir_enter(xid, tcon->tid, ses->Suid, full_path); 349 349 break; 350 350 case SMB2_OP_RMDIR: 351 351 rqst[num_rqst].rq_iov = &vars->si_iov[0]; ··· 363 363 goto finished; 364 364 smb2_set_next_command(tcon, &rqst[num_rqst]); 365 365 smb2_set_related(&rqst[num_rqst++]); 366 - trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path); 366 + trace_smb3_rmdir_enter(xid, tcon->tid, ses->Suid, full_path); 367 367 break; 368 368 case SMB2_OP_SET_EOF: 369 369 rqst[num_rqst].rq_iov = &vars->si_iov[0]; ··· 398 398 goto finished; 399 399 } 400 400 num_rqst++; 401 - trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path); 401 + trace_smb3_set_eof_enter(xid, tcon->tid, ses->Suid, full_path); 402 402 break; 403 403 case SMB2_OP_SET_INFO: 404 404 rqst[num_rqst].rq_iov = &vars->si_iov[0]; ··· 429 429 goto finished; 430 430 } 431 431 num_rqst++; 432 - trace_smb3_set_info_compound_enter(xid, ses->Suid, 433 - tcon->tid, full_path); 432 + trace_smb3_set_info_compound_enter(xid, tcon->tid, 433 + ses->Suid, full_path); 434 434 break; 435 435 case SMB2_OP_RENAME: 436 436 rqst[num_rqst].rq_iov = &vars->si_iov[0]; ··· 469 469 goto finished; 470 470 } 471 471 num_rqst++; 472 - trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path); 472 + trace_smb3_rename_enter(xid, tcon->tid, ses->Suid, full_path); 473 473 break; 474 474 case SMB2_OP_HARDLINK: 475 475 rqst[num_rqst].rq_iov = &vars->si_iov[0]; ··· 496 496 goto finished; 497 497 smb2_set_next_command(tcon, &rqst[num_rqst]); 498 498 smb2_set_related(&rqst[num_rqst++]); 499 - trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path); 499 + trace_smb3_hardlink_enter(xid, tcon->tid, ses->Suid, full_path); 500 500 break; 501 501 case SMB2_OP_SET_REPARSE: 502 502 rqst[num_rqst].rq_iov = vars->io_iov; ··· 523 523 goto finished; 524 524 } 525 525 num_rqst++; 526 - trace_smb3_set_reparse_compound_enter(xid, ses->Suid, 527 - tcon->tid, full_path); 526 + trace_smb3_set_reparse_compound_enter(xid, tcon->tid, 527 + ses->Suid, full_path); 528 528 break; 529 529 case SMB2_OP_GET_REPARSE: 530 530 rqst[num_rqst].rq_iov = vars->io_iov; ··· 549 549 goto finished; 550 550 } 551 551 num_rqst++; 552 - trace_smb3_get_reparse_compound_enter(xid, ses->Suid, 553 - tcon->tid, full_path); 552 + trace_smb3_get_reparse_compound_enter(xid, tcon->tid, 553 + ses->Suid, full_path); 554 554 break; 555 555 case SMB2_OP_QUERY_WSL_EA: 556 556 rqst[num_rqst].rq_iov = &vars->ea_iov; ··· 584 584 goto finished; 585 585 } 586 586 num_rqst++; 587 + trace_smb3_query_wsl_ea_compound_enter(xid, tcon->tid, 588 + ses->Suid, full_path); 587 589 break; 588 590 default: 589 591 cifs_dbg(VFS, "Invalid command\n"); ··· 639 637 tcon->need_reconnect = true; 640 638 } 641 639 640 + tmp_rc = rc; 642 641 for (i = 0; i < num_cmds; i++) { 642 + char *buf = rsp_iov[i + i].iov_base; 643 + 644 + if (buf && resp_buftype[i + 1] != CIFS_NO_BUFFER) 645 + rc = server->ops->map_error(buf, false); 646 + else 647 + rc = tmp_rc; 643 648 switch (cmds[i]) { 644 649 case SMB2_OP_QUERY_INFO: 645 650 idata = in_iov[i].iov_base; ··· 665 656 } 666 657 SMB2_query_info_free(&rqst[num_rqst++]); 667 658 if (rc) 668 - trace_smb3_query_info_compound_err(xid, ses->Suid, 669 - tcon->tid, rc); 659 + trace_smb3_query_info_compound_err(xid, tcon->tid, 660 + ses->Suid, rc); 670 661 else 671 - trace_smb3_query_info_compound_done(xid, ses->Suid, 672 - tcon->tid); 662 + trace_smb3_query_info_compound_done(xid, tcon->tid, 663 + ses->Suid); 673 664 break; 674 665 case SMB2_OP_POSIX_QUERY_INFO: 675 666 idata = in_iov[i].iov_base; ··· 692 683 693 684 SMB2_query_info_free(&rqst[num_rqst++]); 694 685 if (rc) 695 - trace_smb3_posix_query_info_compound_err(xid, ses->Suid, 696 - tcon->tid, rc); 686 + trace_smb3_posix_query_info_compound_err(xid, tcon->tid, 687 + ses->Suid, rc); 697 688 else 698 - trace_smb3_posix_query_info_compound_done(xid, ses->Suid, 699 - tcon->tid); 689 + trace_smb3_posix_query_info_compound_done(xid, tcon->tid, 690 + ses->Suid); 700 691 break; 701 692 case SMB2_OP_DELETE: 702 693 if (rc) 703 - trace_smb3_delete_err(xid, ses->Suid, tcon->tid, rc); 694 + trace_smb3_delete_err(xid, tcon->tid, ses->Suid, rc); 704 695 else { 705 696 /* 706 697 * If dentry (hence, inode) is NULL, lease break is going to ··· 708 699 */ 709 700 if (inode) 710 701 cifs_mark_open_handles_for_deleted_file(inode, full_path); 711 - trace_smb3_delete_done(xid, ses->Suid, tcon->tid); 702 + trace_smb3_delete_done(xid, tcon->tid, ses->Suid); 712 703 } 713 704 break; 714 705 case SMB2_OP_MKDIR: 715 706 if (rc) 716 - trace_smb3_mkdir_err(xid, ses->Suid, tcon->tid, rc); 707 + trace_smb3_mkdir_err(xid, tcon->tid, ses->Suid, rc); 717 708 else 718 - trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid); 709 + trace_smb3_mkdir_done(xid, tcon->tid, ses->Suid); 719 710 break; 720 711 case SMB2_OP_HARDLINK: 721 712 if (rc) 722 - trace_smb3_hardlink_err(xid, ses->Suid, tcon->tid, rc); 713 + trace_smb3_hardlink_err(xid, tcon->tid, ses->Suid, rc); 723 714 else 724 - trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid); 715 + trace_smb3_hardlink_done(xid, tcon->tid, ses->Suid); 725 716 SMB2_set_info_free(&rqst[num_rqst++]); 726 717 break; 727 718 case SMB2_OP_RENAME: 728 719 if (rc) 729 - trace_smb3_rename_err(xid, ses->Suid, tcon->tid, rc); 720 + trace_smb3_rename_err(xid, tcon->tid, ses->Suid, rc); 730 721 else 731 - trace_smb3_rename_done(xid, ses->Suid, tcon->tid); 722 + trace_smb3_rename_done(xid, tcon->tid, ses->Suid); 732 723 SMB2_set_info_free(&rqst[num_rqst++]); 733 724 break; 734 725 case SMB2_OP_RMDIR: 735 726 if (rc) 736 - trace_smb3_rmdir_err(xid, ses->Suid, tcon->tid, rc); 727 + trace_smb3_rmdir_err(xid, tcon->tid, ses->Suid, rc); 737 728 else 738 - trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid); 729 + trace_smb3_rmdir_done(xid, tcon->tid, ses->Suid); 739 730 SMB2_set_info_free(&rqst[num_rqst++]); 740 731 break; 741 732 case SMB2_OP_SET_EOF: 742 733 if (rc) 743 - trace_smb3_set_eof_err(xid, ses->Suid, tcon->tid, rc); 734 + trace_smb3_set_eof_err(xid, tcon->tid, ses->Suid, rc); 744 735 else 745 - trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid); 736 + trace_smb3_set_eof_done(xid, tcon->tid, ses->Suid); 746 737 SMB2_set_info_free(&rqst[num_rqst++]); 747 738 break; 748 739 case SMB2_OP_SET_INFO: 749 740 if (rc) 750 - trace_smb3_set_info_compound_err(xid, ses->Suid, 751 - tcon->tid, rc); 741 + trace_smb3_set_info_compound_err(xid, tcon->tid, 742 + ses->Suid, rc); 752 743 else 753 - trace_smb3_set_info_compound_done(xid, ses->Suid, 754 - tcon->tid); 744 + trace_smb3_set_info_compound_done(xid, tcon->tid, 745 + ses->Suid); 755 746 SMB2_set_info_free(&rqst[num_rqst++]); 756 747 break; 757 748 case SMB2_OP_SET_REPARSE: 758 749 if (rc) { 759 - trace_smb3_set_reparse_compound_err(xid, ses->Suid, 760 - tcon->tid, rc); 750 + trace_smb3_set_reparse_compound_err(xid, tcon->tid, 751 + ses->Suid, rc); 761 752 } else { 762 - trace_smb3_set_reparse_compound_done(xid, ses->Suid, 763 - tcon->tid); 753 + trace_smb3_set_reparse_compound_done(xid, tcon->tid, 754 + ses->Suid); 764 755 } 765 756 SMB2_ioctl_free(&rqst[num_rqst++]); 766 757 break; ··· 773 764 rbuf = reparse_buf_ptr(iov); 774 765 if (IS_ERR(rbuf)) { 775 766 rc = PTR_ERR(rbuf); 776 - trace_smb3_set_reparse_compound_err(xid, ses->Suid, 777 - tcon->tid, rc); 767 + trace_smb3_get_reparse_compound_err(xid, tcon->tid, 768 + ses->Suid, rc); 778 769 } else { 779 770 idata->reparse.tag = le32_to_cpu(rbuf->ReparseTag); 780 - trace_smb3_set_reparse_compound_done(xid, ses->Suid, 781 - tcon->tid); 771 + trace_smb3_get_reparse_compound_done(xid, tcon->tid, 772 + ses->Suid); 782 773 } 783 774 memset(iov, 0, sizeof(*iov)); 784 775 resp_buftype[i + 1] = CIFS_NO_BUFFER; 785 776 } else { 786 - trace_smb3_set_reparse_compound_err(xid, ses->Suid, 787 - tcon->tid, rc); 777 + trace_smb3_get_reparse_compound_err(xid, tcon->tid, 778 + ses->Suid, rc); 788 779 } 789 780 SMB2_ioctl_free(&rqst[num_rqst++]); 790 781 break; ··· 801 792 } 802 793 } 803 794 if (!rc) { 804 - trace_smb3_query_wsl_ea_compound_done(xid, ses->Suid, 805 - tcon->tid); 795 + trace_smb3_query_wsl_ea_compound_done(xid, tcon->tid, 796 + ses->Suid); 806 797 } else { 807 - trace_smb3_query_wsl_ea_compound_err(xid, ses->Suid, 808 - tcon->tid, rc); 798 + trace_smb3_query_wsl_ea_compound_err(xid, tcon->tid, 799 + ses->Suid, rc); 809 800 } 810 801 SMB2_query_info_free(&rqst[num_rqst++]); 811 802 break; 812 803 } 813 804 } 814 805 SMB2_close_free(&rqst[num_rqst]); 806 + rc = tmp_rc; 815 807 816 808 num_cmds += 2; 817 809 if (out_iov && out_buftype) { ··· 868 858 return rc; 869 859 } 870 860 861 + /* Check only if SMB2_OP_QUERY_WSL_EA command failed in the compound chain */ 862 + static bool ea_unsupported(int *cmds, int num_cmds, 863 + struct kvec *out_iov, int *out_buftype) 864 + { 865 + int i; 866 + 867 + if (cmds[num_cmds - 1] != SMB2_OP_QUERY_WSL_EA) 868 + return false; 869 + 870 + for (i = 1; i < num_cmds - 1; i++) { 871 + struct smb2_hdr *hdr = out_iov[i].iov_base; 872 + 873 + if (out_buftype[i] == CIFS_NO_BUFFER || !hdr || 874 + hdr->Status != STATUS_SUCCESS) 875 + return false; 876 + } 877 + return true; 878 + } 879 + 880 + static inline void free_rsp_iov(struct kvec *iovs, int *buftype, int count) 881 + { 882 + int i; 883 + 884 + for (i = 0; i < count; i++) { 885 + free_rsp_buf(buftype[i], iovs[i].iov_base); 886 + memset(&iovs[i], 0, sizeof(*iovs)); 887 + buftype[i] = CIFS_NO_BUFFER; 888 + } 889 + } 890 + 871 891 int smb2_query_path_info(const unsigned int xid, 872 892 struct cifs_tcon *tcon, 873 893 struct cifs_sb_info *cifs_sb, 874 894 const char *full_path, 875 895 struct cifs_open_info_data *data) 876 896 { 877 - struct cifs_open_parms oparms; 878 - __u32 create_options = 0; 879 - struct cifsFileInfo *cfile; 897 + struct kvec in_iov[3], out_iov[5] = {}; 880 898 struct cached_fid *cfid = NULL; 899 + struct cifs_open_parms oparms; 900 + struct cifsFileInfo *cfile; 901 + __u32 create_options = 0; 902 + int out_buftype[5] = {}; 881 903 struct smb2_hdr *hdr; 882 - struct kvec in_iov[3], out_iov[3] = {}; 883 - int out_buftype[3] = {}; 904 + int num_cmds = 0; 884 905 int cmds[3]; 885 906 bool islink; 886 - int i, num_cmds = 0; 887 907 int rc, rc2; 888 908 889 909 data->adjust_tz = false; ··· 983 943 if (rc || !data->reparse_point) 984 944 goto out; 985 945 986 - if (!tcon->posix_extensions) 987 - cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA; 988 946 /* 989 947 * Skip SMB2_OP_GET_REPARSE if symlink already parsed in create 990 948 * response. 991 949 */ 992 950 if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK) 993 951 cmds[num_cmds++] = SMB2_OP_GET_REPARSE; 952 + if (!tcon->posix_extensions) 953 + cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA; 994 954 995 955 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, 996 956 FILE_READ_ATTRIBUTES | ··· 998 958 FILE_OPEN, create_options | 999 959 OPEN_REPARSE_POINT, ACL_NO_MODE); 1000 960 cifs_get_readable_path(tcon, full_path, &cfile); 961 + free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov)); 1001 962 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 1002 963 &oparms, in_iov, cmds, num_cmds, 1003 - cfile, NULL, NULL, NULL); 964 + cfile, out_iov, out_buftype, NULL); 965 + if (rc && ea_unsupported(cmds, num_cmds, 966 + out_iov, out_buftype)) { 967 + if (data->reparse.tag != IO_REPARSE_TAG_LX_BLK && 968 + data->reparse.tag != IO_REPARSE_TAG_LX_CHR) 969 + rc = 0; 970 + else 971 + rc = -EOPNOTSUPP; 972 + } 1004 973 break; 1005 974 case -EREMOTE: 1006 975 break; ··· 1027 978 } 1028 979 1029 980 out: 1030 - for (i = 0; i < ARRAY_SIZE(out_buftype); i++) 1031 - free_rsp_buf(out_buftype[i], out_iov[i].iov_base); 981 + free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov)); 1032 982 return rc; 1033 983 } 1034 984
+5 -4
fs/smb/client/smb2ops.c
··· 658 658 659 659 while (bytes_left >= (ssize_t)sizeof(*p)) { 660 660 memset(&tmp_iface, 0, sizeof(tmp_iface)); 661 - tmp_iface.speed = le64_to_cpu(p->LinkSpeed); 661 + /* default to 1Gbps when link speed is unset */ 662 + tmp_iface.speed = le64_to_cpu(p->LinkSpeed) ?: 1000000000; 662 663 tmp_iface.rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE) ? 1 : 0; 663 664 tmp_iface.rss_capable = le32_to_cpu(p->Capability & RSS_CAPABLE) ? 1 : 0; 664 665 ··· 3008 3007 num_of_nodes, target_nodes, 3009 3008 nls_codepage, remap, search_name, 3010 3009 true /* is_unicode */); 3011 - if (rc) { 3012 - cifs_tcon_dbg(VFS, "parse error in %s rc=%d\n", __func__, rc); 3013 - goto out; 3010 + if (rc && rc != -ENOENT) { 3011 + cifs_tcon_dbg(VFS, "%s: failed to parse DFS referral %s: %d\n", 3012 + __func__, search_name, rc); 3014 3013 } 3015 3014 3016 3015 out:
+1 -1
fs/smb/client/smb2pdu.h
··· 79 79 struct smb2_error_context_rsp { 80 80 __le32 ErrorDataLength; 81 81 __le32 ErrorId; 82 - __u8 ErrorContextData; /* ErrorDataLength long array */ 82 + __u8 ErrorContextData[] __counted_by_le(ErrorDataLength); 83 83 } __packed; 84 84 85 85 /* ErrorId values */
+1
fs/smb/client/trace.h
··· 674 674 DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_info_compound_enter); 675 675 DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_reparse_compound_enter); 676 676 DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(get_reparse_compound_enter); 677 + DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(query_wsl_ea_compound_enter); 677 678 DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(delete_enter); 678 679 DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(mkdir_enter); 679 680 DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(tdis_enter);