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

Merge tag '5.12-smb3-part1' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs updates from Steve French:

- improvements to mode bit conversion, chmod and chown when using
cifsacl mount option

- two new mount options for controlling attribute caching

- improvements to crediting and reconnect, improved debugging

- reconnect fix

- add SMB3.1.1 dialect to default dialects for vers=3

* tag '5.12-smb3-part1' of git://git.samba.org/sfrench/cifs-2.6: (27 commits)
cifs: update internal version number
cifs: use discard iterator to discard unneeded network data more efficiently
cifs: introduce helper for finding referral server to improve DFS target resolution
cifs: check all path components in resolved dfs target
cifs: fix DFS failover
cifs: fix nodfs mount option
cifs: fix handling of escaped ',' in the password mount argument
cifs: Add new parameter "acregmax" for distinct file and directory metadata timeout
cifs: convert revalidate of directories to using directory metadata cache timeout
cifs: Add new mount parameter "acdirmax" to allow caching directory metadata
cifs: If a corrupted DACL is returned by the server, bail out.
cifs: minor simplification to smb2_is_network_name_deleted
TCON Reconnect during STATUS_NETWORK_NAME_DELETED
cifs: cleanup a few le16 vs. le32 uses in cifsacl.c
cifs: Change SIDs in ACEs while transferring file ownership.
cifs: Retain old ACEs when converting between mode bits and ACL.
cifs: Fix cifsacl ACE mask for group and others.
cifs: clarify hostname vs ip address in /proc/fs/cifs/DebugData
cifs: change confusing field serverName (to ip_addr)
cifs: Fix inconsistent IS_ERR and PTR_ERR
...

+886 -417
+3 -3
Documentation/admin-guide/cifs/authors.rst
··· 5 5 Original Author 6 6 --------------- 7 7 8 - Steve French (sfrench@samba.org) 8 + Steve French (smfrench@gmail.com, sfrench@samba.org) 9 9 10 10 The author wishes to express his appreciation and thanks to: 11 - Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS 11 + Andrew Tridgell (Samba team) for his early suggestions about SMB/CIFS VFS 12 12 improvements. Thanks to IBM for allowing me time and test resources to pursue 13 13 this project, to Jim McDonough from IBM (and the Samba Team) for his help, to 14 14 the IBM Linux JFS team for explaining many esoteric Linux filesystem features. ··· 51 51 - Ronnie Sahlberg (for SMB3 xattr work, bug fixes, and lots of great work on compounding) 52 52 - Shirish Pargaonkar (for many ACL patches over the years) 53 53 - Sachin Prabhu (many bug fixes, including for reconnect, copy offload and security) 54 - - Paulo Alcantara 54 + - Paulo Alcantara (for some excellent work in DFS, and in booting from SMB3) 55 55 - Long Li (some great work on RDMA, SMB Direct) 56 56 57 57
+3 -2
Documentation/admin-guide/cifs/changes.rst
··· 3 3 ======= 4 4 5 5 See https://wiki.samba.org/index.php/LinuxCIFSKernel for summary 6 - information (that may be easier to read than parsing the output of 7 - "git log fs/cifs") about fixes/improvements to CIFS/SMB2/SMB3 support (changes 6 + information about fixes/improvements to CIFS/SMB2/SMB3 support (changes 8 7 to cifs.ko module) by kernel version (and cifs internal module version). 8 + This may be easier to read than parsing the output of "git log fs/cifs" 9 + by release.
+15 -15
Documentation/admin-guide/cifs/introduction.rst
··· 7 7 protocol which was the successor to the Server Message Block 8 8 (SMB) protocol, the native file sharing mechanism for most early 9 9 PC operating systems. New and improved versions of CIFS are now 10 - called SMB2 and SMB3. Use of SMB3 (and later, including SMB3.1.1) 11 - is strongly preferred over using older dialects like CIFS due to 12 - security reasons. All modern dialects, including the most recent, 13 - SMB3.1.1 are supported by the CIFS VFS module. The SMB3 protocol 14 - is implemented and supported by all major file servers 15 - such as all modern versions of Windows (including Windows 2016 16 - Server), as well as by Samba (which provides excellent 17 - CIFS/SMB2/SMB3 server support and tools for Linux and many other 18 - operating systems). Apple systems also support SMB3 well, as 19 - do most Network Attached Storage vendors, so this network 20 - filesystem client can mount to a wide variety of systems. 21 - It also supports mounting to the cloud (for example 22 - Microsoft Azure), including the necessary security features. 10 + called SMB2 and SMB3. Use of SMB3 (and later, including SMB3.1.1 11 + the most current dialect) is strongly preferred over using older 12 + dialects like CIFS due to security reasons. All modern dialects, 13 + including the most recent, SMB3.1.1, are supported by the CIFS VFS 14 + module. The SMB3 protocol is implemented and supported by all major 15 + file servers such as Windows (including Windows 2019 Server), as 16 + well as by Samba (which provides excellent CIFS/SMB2/SMB3 server 17 + support and tools for Linux and many other operating systems). 18 + Apple systems also support SMB3 well, as do most Network Attached 19 + Storage vendors, so this network filesystem client can mount to a 20 + wide variety of systems. It also supports mounting to the cloud 21 + (for example Microsoft Azure), including the necessary security 22 + features. 23 23 24 24 The intent of this module is to provide the most advanced network 25 25 file system function for SMB3 compliant servers, including advanced ··· 27 27 POSIX compliance, secure per-user session establishment, encryption, 28 28 high performance safe distributed caching (leases/oplocks), optional packet 29 29 signing, large files, Unicode support and other internationalization 30 - improvements. Since both Samba server and this filesystem client support 31 - the CIFS Unix extensions (and in the future SMB3 POSIX extensions), 30 + improvements. Since both Samba server and this filesystem client support the 31 + CIFS Unix extensions, and the Linux client also suppors SMB3 POSIX extensions, 32 32 the combination can provide a reasonable alternative to other network and 33 33 cluster file systems for fileserving in some Linux to Linux environments, 34 34 not just in Linux to Windows (or Linux to Mac) environments.
+18 -16
Documentation/admin-guide/cifs/todo.rst
··· 13 13 14 14 a) SMB3 (and SMB3.1.1) missing optional features: 15 15 16 - - multichannel (started), integration with RDMA 17 - - directory leases (improved metadata caching), started (root dir only) 16 + - multichannel (partially integrated), integration of multichannel with RDMA 17 + - directory leases (improved metadata caching). Currently only implemented for root dir 18 18 - T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl 19 19 currently the only two server side copy mechanisms supported) 20 20 21 21 b) improved sparse file support (fiemap and SEEK_HOLE are implemented 22 - but additional features would be supportable by the protocol). 22 + but additional features would be supportable by the protocol such 23 + as FALLOC_FL_COLLAPSE_RANGE and FALLOC_FL_INSERT_RANGE) 23 24 24 25 c) Directory entry caching relies on a 1 second timer, rather than 25 26 using Directory Leases, currently only the root file handle is cached longer 27 + by leveraging Directory Leases 26 28 27 - d) quota support (needs minor kernel change since quota calls 28 - to make it to network filesystems or deviceless filesystems) 29 + d) quota support (needs minor kernel change since quota calls otherwise 30 + won't make it to network filesystems or deviceless filesystems). 29 31 30 32 e) Additional use cases can be optimized to use "compounding" (e.g. 31 33 open/query/close and open/setinfo/close) to reduce the number of 32 34 roundtrips to the server and improve performance. Various cases 33 - (stat, statfs, create, unlink, mkdir) already have been improved by 35 + (stat, statfs, create, unlink, mkdir, xattrs) already have been improved by 34 36 using compounding but more can be done. In addition we could 35 37 significantly reduce redundant opens by using deferred close (with 36 38 handle caching leases) and better using reference counters on file ··· 62 60 metadata attributes easier from tools (e.g. extending what was done 63 61 in smb-info tool). 64 62 65 - l) encrypted file support 63 + l) encrypted file support (currently the attribute showing the file is 64 + encrypted on the server is reported, but changing the attribute is not 65 + supported). 66 66 67 67 m) improved stats gathering tools (perhaps integration with nfsometer?) 68 68 to extend and make easier to use what is currently in /proc/fs/cifs/Stats ··· 73 69 74 70 o) mount helper GUI (to simplify the various configuration options on mount) 75 71 76 - p) Add support for witness protocol (perhaps ioctl to cifs.ko from user space 77 - tool listening on witness protocol RPC) to allow for notification of share 78 - move, server failover, and server adapter changes. And also improve other 79 - failover scenarios, e.g. when client knows multiple DFS entries point to 80 - different servers, and the server we are connected to has gone down. 72 + p) Expand support for witness protocol to allow for notification of share 73 + move, and server network adapter changes. Currently only notifications by 74 + the witness protocol for server move is supported by the Linux client. 81 75 82 76 q) Allow mount.cifs to be more verbose in reporting errors with dialect 83 - or unsupported feature errors. 77 + or unsupported feature errors. This would now be easier due to the 78 + implementation of the new mount API. 84 79 85 80 r) updating cifs documentation, and user guide. 86 81 ··· 90 87 secure) CIFS dialect can be disabled in environments that don't need it 91 88 and simplify the code. 92 89 93 - v) POSIX Extensions for SMB3.1.1 (started, create and mkdir support added 94 - so far). 90 + v) Additional testing of POSIX Extensions for SMB3.1.1 95 91 96 92 w) Add support for additional strong encryption types, and additional spnego 97 - authentication mechanisms (see MS-SMB2) 93 + authentication mechanisms (see MS-SMB2). GCM-256 is now partially implemented. 98 94 99 95 x) Finish support for SMB3.1.1 compression 100 96
+1 -1
Documentation/admin-guide/cifs/usage.rst
··· 83 83 There are additional mount options that may be helpful for SMB3 to get 84 84 improved POSIX behavior (NB: can use vers=3.0 to force only SMB3, never 2.1): 85 85 86 - ``mfsymlinks`` and ``cifsacl`` and ``idsfromsid`` 86 + ``mfsymlinks`` and either ``cifsacl`` or ``modefromsid`` (usually with ``idsfromsid``) 87 87 88 88 Allowing User Mounts 89 89 ====================
+70 -51
fs/cifs/cifs_debug.c
··· 133 133 { 134 134 struct TCP_Server_Info *server = chan->server; 135 135 136 - seq_printf(m, "\t\tChannel %d Number of credits: %d Dialect 0x%x " 137 - "TCP status: %d Instance: %d Local Users To Server: %d " 138 - "SecMode: 0x%x Req On Wire: %d In Send: %d " 139 - "In MaxReq Wait: %d\n", 140 - i+1, 136 + seq_printf(m, "\n\n\t\tChannel: %d ConnectionId: 0x%llx" 137 + "\n\t\tNumber of credits: %d Dialect 0x%x" 138 + "\n\t\tTCP status: %d Instance: %d" 139 + "\n\t\tLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d" 140 + "\n\t\tIn Send: %d In MaxReq Wait: %d", 141 + i+1, server->conn_id, 141 142 server->credits, 142 143 server->dialect, 143 144 server->tcpStatus, ··· 228 227 struct TCP_Server_Info *server; 229 228 struct cifs_ses *ses; 230 229 struct cifs_tcon *tcon; 231 - int i, j; 230 + int c, i, j; 232 231 233 232 seq_puts(m, 234 233 "Display Internal CIFS Data Structures for Debugging\n" ··· 276 275 seq_putc(m, '\n'); 277 276 seq_printf(m, "CIFSMaxBufSize: %d\n", CIFSMaxBufSize); 278 277 seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid); 279 - seq_printf(m, "Servers:"); 280 278 281 - i = 0; 279 + seq_printf(m, "\nServers: "); 280 + 281 + c = 0; 282 282 spin_lock(&cifs_tcp_ses_lock); 283 283 list_for_each(tmp1, &cifs_tcp_ses_list) { 284 284 server = list_entry(tmp1, struct TCP_Server_Info, 285 285 tcp_ses_list); 286 286 287 + /* channel info will be printed as a part of sessions below */ 288 + if (server->is_channel) 289 + continue; 290 + 291 + c++; 292 + seq_printf(m, "\n%d) ConnectionId: 0x%llx ", 293 + c, server->conn_id); 294 + 295 + if (server->hostname) 296 + seq_printf(m, "Hostname: %s ", server->hostname); 287 297 #ifdef CONFIG_CIFS_SMB_DIRECT 288 298 if (!server->rdma) 289 299 goto skip_rdma; ··· 374 362 if (server->posix_ext_supported) 375 363 seq_printf(m, " posix"); 376 364 377 - i++; 365 + if (server->rdma) 366 + seq_printf(m, "\nRDMA "); 367 + seq_printf(m, "\nTCP status: %d Instance: %d" 368 + "\nLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d", 369 + server->tcpStatus, 370 + server->reconnect_instance, 371 + server->srv_count, 372 + server->sec_mode, in_flight(server)); 373 + 374 + seq_printf(m, "\nIn Send: %d In MaxReq Wait: %d", 375 + atomic_read(&server->in_send), 376 + atomic_read(&server->num_waiters)); 377 + 378 + seq_printf(m, "\n\n\tSessions: "); 379 + i = 0; 378 380 list_for_each(tmp2, &server->smb_ses_list) { 379 381 ses = list_entry(tmp2, struct cifs_ses, 380 382 smb_ses_list); 383 + i++; 381 384 if ((ses->serverDomain == NULL) || 382 385 (ses->serverOS == NULL) || 383 386 (ses->serverNOS == NULL)) { 384 - seq_printf(m, "\n%d) Name: %s Uses: %d Capability: 0x%x\tSession Status: %d ", 385 - i, ses->serverName, ses->ses_count, 387 + seq_printf(m, "\n\t%d) Address: %s Uses: %d Capability: 0x%x\tSession Status: %d ", 388 + i, ses->ip_addr, ses->ses_count, 386 389 ses->capabilities, ses->status); 387 390 if (ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST) 388 - seq_printf(m, "Guest\t"); 391 + seq_printf(m, "Guest "); 389 392 else if (ses->session_flags & SMB2_SESSION_FLAG_IS_NULL) 390 - seq_printf(m, "Anonymous\t"); 393 + seq_printf(m, "Anonymous "); 391 394 } else { 392 395 seq_printf(m, 393 - "\n%d) Name: %s Domain: %s Uses: %d OS:" 394 - " %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB" 395 - " session status: %d ", 396 - i, ses->serverName, ses->serverDomain, 396 + "\n\t%d) Name: %s Domain: %s Uses: %d OS: %s " 397 + "\n\tNOS: %s\tCapability: 0x%x" 398 + "\n\tSMB session status: %d ", 399 + i, ses->ip_addr, ses->serverDomain, 397 400 ses->ses_count, ses->serverOS, ses->serverNOS, 398 401 ses->capabilities, ses->status); 399 402 } 400 403 401 - seq_printf(m,"Security type: %s\n", 404 + seq_printf(m, "\n\tSecurity type: %s ", 402 405 get_security_type_str(server->ops->select_sectype(server, ses->sectype))); 403 - 404 - if (server->rdma) 405 - seq_printf(m, "RDMA\n\t"); 406 - seq_printf(m, "TCP status: %d Instance: %d\n\tLocal Users To " 407 - "Server: %d SecMode: 0x%x Req On Wire: %d", 408 - server->tcpStatus, 409 - server->reconnect_instance, 410 - server->srv_count, 411 - server->sec_mode, in_flight(server)); 412 - 413 - seq_printf(m, " In Send: %d In MaxReq Wait: %d", 414 - atomic_read(&server->in_send), 415 - atomic_read(&server->num_waiters)); 416 406 417 407 /* dump session id helpful for use with network trace */ 418 408 seq_printf(m, " SessionId: 0x%llx", ses->Suid); ··· 428 414 from_kuid(&init_user_ns, ses->cred_uid)); 429 415 430 416 if (ses->chan_count > 1) { 431 - seq_printf(m, "\n\n\tExtra Channels: %zu\n", 417 + seq_printf(m, "\n\n\tExtra Channels: %zu ", 432 418 ses->chan_count-1); 433 419 for (j = 1; j < ses->chan_count; j++) 434 420 cifs_dump_channel(m, j, &ses->chans[j]); 435 421 } 436 422 437 - seq_puts(m, "\n\n\tShares:"); 423 + seq_puts(m, "\n\n\tShares: "); 438 424 j = 0; 439 425 440 426 seq_printf(m, "\n\t%d) IPC: ", j); ··· 451 437 cifs_debug_tcon(m, tcon); 452 438 } 453 439 454 - seq_puts(m, "\n\tMIDs:\n"); 455 - 456 - spin_lock(&GlobalMid_Lock); 457 - list_for_each(tmp3, &server->pending_mid_q) { 458 - mid_entry = list_entry(tmp3, struct mid_q_entry, 459 - qhead); 460 - seq_printf(m, "\tState: %d com: %d pid:" 461 - " %d cbdata: %p mid %llu\n", 462 - mid_entry->mid_state, 463 - le16_to_cpu(mid_entry->command), 464 - mid_entry->pid, 465 - mid_entry->callback_data, 466 - mid_entry->mid); 467 - } 468 - spin_unlock(&GlobalMid_Lock); 469 - 470 440 spin_lock(&ses->iface_lock); 471 441 if (ses->iface_count) 472 - seq_printf(m, "\n\tServer interfaces: %zu\n", 442 + seq_printf(m, "\n\n\tServer interfaces: %zu", 473 443 ses->iface_count); 474 444 for (j = 0; j < ses->iface_count; j++) { 475 445 struct cifs_server_iface *iface; 476 446 477 447 iface = &ses->iface_list[j]; 478 - seq_printf(m, "\t%d)", j); 448 + seq_printf(m, "\n\t%d)", j+1); 479 449 cifs_dump_iface(m, iface); 480 450 if (is_ses_using_iface(ses, iface)) 481 451 seq_puts(m, "\t\t[CONNECTED]\n"); 482 452 } 483 453 spin_unlock(&ses->iface_lock); 484 454 } 455 + if (i == 0) 456 + seq_printf(m, "\n\t\t[NONE]"); 457 + 458 + seq_puts(m, "\n\n\tMIDs: "); 459 + spin_lock(&GlobalMid_Lock); 460 + list_for_each(tmp3, &server->pending_mid_q) { 461 + mid_entry = list_entry(tmp3, struct mid_q_entry, 462 + qhead); 463 + seq_printf(m, "\n\tState: %d com: %d pid:" 464 + " %d cbdata: %p mid %llu\n", 465 + mid_entry->mid_state, 466 + le16_to_cpu(mid_entry->command), 467 + mid_entry->pid, 468 + mid_entry->callback_data, 469 + mid_entry->mid); 470 + } 471 + spin_unlock(&GlobalMid_Lock); 472 + seq_printf(m, "\n--\n"); 485 473 } 474 + if (c == 0) 475 + seq_printf(m, "\n\t[NONE]"); 476 + 486 477 spin_unlock(&cifs_tcp_ses_lock); 487 478 seq_putc(m, '\n'); 488 479
+1 -1
fs/cifs/cifs_swn.c
··· 272 272 if (IS_ERR(share_name)) { 273 273 int ret; 274 274 275 - ret = PTR_ERR(net_name); 275 + ret = PTR_ERR(share_name); 276 276 cifs_dbg(VFS, "%s: failed to extract share name from target '%s': %d\n", 277 277 __func__, tcon->treeName, ret); 278 278 kfree(net_name);
+302 -81
fs/cifs/cifsacl.c
··· 267 267 return true; /* well known sid found, uid returned */ 268 268 } 269 269 270 - static void 270 + static __u16 271 271 cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src) 272 272 { 273 273 int i; 274 + __u16 size = 1 + 1 + 6; 274 275 275 276 dst->revision = src->revision; 276 277 dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES); ··· 279 278 dst->authority[i] = src->authority[i]; 280 279 for (i = 0; i < dst->num_subauth; ++i) 281 280 dst->sub_auth[i] = src->sub_auth[i]; 281 + size += (dst->num_subauth * 4); 282 + 283 + return size; 282 284 } 283 285 284 286 static int ··· 525 521 } 526 522 527 523 /* copy ntsd, owner sid, and group sid from a security descriptor to another */ 528 - static void copy_sec_desc(const struct cifs_ntsd *pntsd, 529 - struct cifs_ntsd *pnntsd, __u32 sidsoffset) 524 + static __u32 copy_sec_desc(const struct cifs_ntsd *pntsd, 525 + struct cifs_ntsd *pnntsd, 526 + __u32 sidsoffset, 527 + struct cifs_sid *pownersid, 528 + struct cifs_sid *pgrpsid) 530 529 { 531 530 struct cifs_sid *owner_sid_ptr, *group_sid_ptr; 532 531 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr; ··· 543 536 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid)); 544 537 545 538 /* copy owner sid */ 546 - owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + 539 + if (pownersid) 540 + owner_sid_ptr = pownersid; 541 + else 542 + owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + 547 543 le32_to_cpu(pntsd->osidoffset)); 548 544 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset); 549 545 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr); 550 546 551 547 /* copy group sid */ 552 - group_sid_ptr = (struct cifs_sid *)((char *)pntsd + 548 + if (pgrpsid) 549 + group_sid_ptr = pgrpsid; 550 + else 551 + group_sid_ptr = (struct cifs_sid *)((char *)pntsd + 553 552 le32_to_cpu(pntsd->gsidoffset)); 554 553 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset + 555 554 sizeof(struct cifs_sid)); 556 555 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr); 557 556 558 - return; 557 + return sidsoffset + (2 * sizeof(struct cifs_sid)); 559 558 } 560 559 561 560 ··· 674 661 cifs_dbg(NOISY, "mode: %04o, access flags now 0x%x\n", 675 662 mode, *pace_flags); 676 663 return; 664 + } 665 + 666 + static __u16 cifs_copy_ace(struct cifs_ace *dst, struct cifs_ace *src, struct cifs_sid *psid) 667 + { 668 + __u16 size = 1 + 1 + 2 + 4; 669 + 670 + dst->type = src->type; 671 + dst->flags = src->flags; 672 + dst->access_req = src->access_req; 673 + 674 + /* Check if there's a replacement sid specified */ 675 + if (psid) 676 + size += cifs_copy_sid(&dst->sid, psid); 677 + else 678 + size += cifs_copy_sid(&dst->sid, &src->sid); 679 + 680 + dst->size = cpu_to_le16(size); 681 + 682 + return size; 677 683 } 678 684 679 685 static __u16 fill_ace_for_sid(struct cifs_ace *pntace, ··· 939 907 return ace_size; 940 908 } 941 909 942 - static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid, 943 - struct cifs_sid *pgrpsid, __u64 *pnmode, bool modefromsid) 910 + static void populate_new_aces(char *nacl_base, 911 + struct cifs_sid *pownersid, 912 + struct cifs_sid *pgrpsid, 913 + __u64 *pnmode, u32 *pnum_aces, u16 *pnsize, 914 + bool modefromsid) 944 915 { 945 - u16 size = 0; 946 - u32 num_aces = 0; 947 - struct cifs_acl *pnndacl; 948 916 __u64 nmode; 917 + u32 num_aces = 0; 918 + u16 nsize = 0; 949 919 __u64 user_mode; 950 920 __u64 group_mode; 951 921 __u64 other_mode; 952 922 __u64 deny_user_mode = 0; 953 923 __u64 deny_group_mode = 0; 954 924 bool sticky_set = false; 955 - 956 - pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl)); 925 + struct cifs_ace *pnntace = NULL; 957 926 958 927 nmode = *pnmode; 928 + num_aces = *pnum_aces; 929 + nsize = *pnsize; 959 930 960 931 if (modefromsid) { 961 - struct cifs_ace *pntace = 962 - (struct cifs_ace *)((char *)pnndacl + size); 963 - 964 - size += setup_special_mode_ACE(pntace, nmode); 932 + pnntace = (struct cifs_ace *) (nacl_base + nsize); 933 + nsize += setup_special_mode_ACE(pnntace, nmode); 965 934 num_aces++; 966 935 goto set_size; 967 936 } ··· 999 966 sticky_set = true; 1000 967 1001 968 if (deny_user_mode) { 1002 - size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), 1003 - pownersid, deny_user_mode, 0700, ACCESS_DENIED, false); 969 + pnntace = (struct cifs_ace *) (nacl_base + nsize); 970 + nsize += fill_ace_for_sid(pnntace, pownersid, deny_user_mode, 971 + 0700, ACCESS_DENIED, false); 1004 972 num_aces++; 1005 973 } 974 + 1006 975 /* Group DENY ACE does not conflict with owner ALLOW ACE. Keep in preferred order*/ 1007 976 if (deny_group_mode && !(deny_group_mode & (user_mode >> 3))) { 1008 - size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), 1009 - pgrpsid, deny_group_mode, 0070, ACCESS_DENIED, false); 977 + pnntace = (struct cifs_ace *) (nacl_base + nsize); 978 + nsize += fill_ace_for_sid(pnntace, pgrpsid, deny_group_mode, 979 + 0070, ACCESS_DENIED, false); 1010 980 num_aces++; 1011 981 } 1012 - size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size), 1013 - pownersid, user_mode, 0700, ACCESS_ALLOWED, true); 982 + 983 + pnntace = (struct cifs_ace *) (nacl_base + nsize); 984 + nsize += fill_ace_for_sid(pnntace, pownersid, user_mode, 985 + 0700, ACCESS_ALLOWED, true); 1014 986 num_aces++; 987 + 1015 988 /* Group DENY ACE conflicts with owner ALLOW ACE. So keep it after. */ 1016 989 if (deny_group_mode && (deny_group_mode & (user_mode >> 3))) { 1017 - size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), 1018 - pgrpsid, deny_group_mode, 0070, ACCESS_DENIED, false); 990 + pnntace = (struct cifs_ace *) (nacl_base + nsize); 991 + nsize += fill_ace_for_sid(pnntace, pgrpsid, deny_group_mode, 992 + 0070, ACCESS_DENIED, false); 1019 993 num_aces++; 1020 994 } 1021 - size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), 1022 - pgrpsid, group_mode, 0070, ACCESS_ALLOWED, !sticky_set); 995 + 996 + pnntace = (struct cifs_ace *) (nacl_base + nsize); 997 + nsize += fill_ace_for_sid(pnntace, pgrpsid, group_mode, 998 + 0070, ACCESS_ALLOWED, !sticky_set); 1023 999 num_aces++; 1024 - size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), 1025 - &sid_everyone, other_mode, 0007, ACCESS_ALLOWED, !sticky_set); 1000 + 1001 + pnntace = (struct cifs_ace *) (nacl_base + nsize); 1002 + nsize += fill_ace_for_sid(pnntace, &sid_everyone, other_mode, 1003 + 0007, ACCESS_ALLOWED, !sticky_set); 1026 1004 num_aces++; 1027 1005 1028 1006 set_size: 1007 + *pnum_aces = num_aces; 1008 + *pnsize = nsize; 1009 + } 1010 + 1011 + static __u16 replace_sids_and_copy_aces(struct cifs_acl *pdacl, struct cifs_acl *pndacl, 1012 + struct cifs_sid *pownersid, struct cifs_sid *pgrpsid, 1013 + struct cifs_sid *pnownersid, struct cifs_sid *pngrpsid) 1014 + { 1015 + int i; 1016 + u16 size = 0; 1017 + struct cifs_ace *pntace = NULL; 1018 + char *acl_base = NULL; 1019 + u32 src_num_aces = 0; 1020 + u16 nsize = 0; 1021 + struct cifs_ace *pnntace = NULL; 1022 + char *nacl_base = NULL; 1023 + u16 ace_size = 0; 1024 + 1025 + acl_base = (char *)pdacl; 1026 + size = sizeof(struct cifs_acl); 1027 + src_num_aces = le32_to_cpu(pdacl->num_aces); 1028 + 1029 + nacl_base = (char *)pndacl; 1030 + nsize = sizeof(struct cifs_acl); 1031 + 1032 + /* Go through all the ACEs */ 1033 + for (i = 0; i < src_num_aces; ++i) { 1034 + pntace = (struct cifs_ace *) (acl_base + size); 1035 + pnntace = (struct cifs_ace *) (nacl_base + nsize); 1036 + 1037 + if (pnownersid && compare_sids(&pntace->sid, pownersid) == 0) 1038 + ace_size = cifs_copy_ace(pnntace, pntace, pnownersid); 1039 + else if (pngrpsid && compare_sids(&pntace->sid, pgrpsid) == 0) 1040 + ace_size = cifs_copy_ace(pnntace, pntace, pngrpsid); 1041 + else 1042 + ace_size = cifs_copy_ace(pnntace, pntace, NULL); 1043 + 1044 + size += le16_to_cpu(pntace->size); 1045 + nsize += ace_size; 1046 + } 1047 + 1048 + return nsize; 1049 + } 1050 + 1051 + static int set_chmod_dacl(struct cifs_acl *pdacl, struct cifs_acl *pndacl, 1052 + struct cifs_sid *pownersid, struct cifs_sid *pgrpsid, 1053 + __u64 *pnmode, bool mode_from_sid) 1054 + { 1055 + int i; 1056 + u16 size = 0; 1057 + struct cifs_ace *pntace = NULL; 1058 + char *acl_base = NULL; 1059 + u32 src_num_aces = 0; 1060 + u16 nsize = 0; 1061 + struct cifs_ace *pnntace = NULL; 1062 + char *nacl_base = NULL; 1063 + u32 num_aces = 0; 1064 + __u64 nmode; 1065 + bool new_aces_set = false; 1066 + 1067 + /* Assuming that pndacl and pnmode are never NULL */ 1068 + nmode = *pnmode; 1069 + nacl_base = (char *)pndacl; 1070 + nsize = sizeof(struct cifs_acl); 1071 + 1072 + /* If pdacl is NULL, we don't have a src. Simply populate new ACL. */ 1073 + if (!pdacl) { 1074 + populate_new_aces(nacl_base, 1075 + pownersid, pgrpsid, 1076 + pnmode, &num_aces, &nsize, 1077 + mode_from_sid); 1078 + goto finalize_dacl; 1079 + } 1080 + 1081 + acl_base = (char *)pdacl; 1082 + size = sizeof(struct cifs_acl); 1083 + src_num_aces = le32_to_cpu(pdacl->num_aces); 1084 + 1085 + /* Retain old ACEs which we can retain */ 1086 + for (i = 0; i < src_num_aces; ++i) { 1087 + pntace = (struct cifs_ace *) (acl_base + size); 1088 + pnntace = (struct cifs_ace *) (nacl_base + nsize); 1089 + 1090 + if (!new_aces_set && (pntace->flags & INHERITED_ACE)) { 1091 + /* Place the new ACEs in between existing explicit and inherited */ 1092 + populate_new_aces(nacl_base, 1093 + pownersid, pgrpsid, 1094 + pnmode, &num_aces, &nsize, 1095 + mode_from_sid); 1096 + 1097 + new_aces_set = true; 1098 + } 1099 + 1100 + /* If it's any one of the ACE we're replacing, skip! */ 1101 + if ((compare_sids(&pntace->sid, &sid_unix_NFS_mode) == 0) || 1102 + (compare_sids(&pntace->sid, pownersid) == 0) || 1103 + (compare_sids(&pntace->sid, pgrpsid) == 0) || 1104 + (compare_sids(&pntace->sid, &sid_everyone) == 0) || 1105 + (compare_sids(&pntace->sid, &sid_authusers) == 0)) { 1106 + goto next_ace; 1107 + } 1108 + 1109 + nsize += cifs_copy_ace(pnntace, pntace, NULL); 1110 + num_aces++; 1111 + 1112 + next_ace: 1113 + size += le16_to_cpu(pntace->size); 1114 + } 1115 + 1116 + /* If inherited ACEs are not present, place the new ones at the tail */ 1117 + if (!new_aces_set) { 1118 + populate_new_aces(nacl_base, 1119 + pownersid, pgrpsid, 1120 + pnmode, &num_aces, &nsize, 1121 + mode_from_sid); 1122 + 1123 + new_aces_set = true; 1124 + } 1125 + 1126 + finalize_dacl: 1029 1127 pndacl->num_aces = cpu_to_le32(num_aces); 1030 - pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl)); 1128 + pndacl->size = cpu_to_le16(nsize); 1031 1129 1032 1130 return 0; 1033 1131 } 1034 - 1035 1132 1036 1133 static int parse_sid(struct cifs_sid *psid, char *end_of_acl) 1037 1134 { ··· 1257 1094 1258 1095 /* Convert permission bits from mode to equivalent CIFS ACL */ 1259 1096 static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, 1260 - __u32 secdesclen, __u64 *pnmode, kuid_t uid, kgid_t gid, 1097 + __u32 secdesclen, __u32 *pnsecdesclen, __u64 *pnmode, kuid_t uid, kgid_t gid, 1261 1098 bool mode_from_sid, bool id_from_sid, int *aclflag) 1262 1099 { 1263 1100 int rc = 0; ··· 1265 1102 __u32 ndacloffset; 1266 1103 __u32 sidsoffset; 1267 1104 struct cifs_sid *owner_sid_ptr, *group_sid_ptr; 1268 - struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr; 1105 + struct cifs_sid *nowner_sid_ptr = NULL, *ngroup_sid_ptr = NULL; 1269 1106 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */ 1270 1107 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */ 1108 + char *end_of_acl = ((char *)pntsd) + secdesclen; 1109 + u16 size = 0; 1110 + 1111 + dacloffset = le32_to_cpu(pntsd->dacloffset); 1112 + if (dacloffset) { 1113 + dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset); 1114 + if (end_of_acl < (char *)dacl_ptr + le16_to_cpu(dacl_ptr->size)) { 1115 + cifs_dbg(VFS, "Server returned illegal ACL size\n"); 1116 + return -EINVAL; 1117 + } 1118 + } 1119 + 1120 + owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + 1121 + le32_to_cpu(pntsd->osidoffset)); 1122 + group_sid_ptr = (struct cifs_sid *)((char *)pntsd + 1123 + le32_to_cpu(pntsd->gsidoffset)); 1271 1124 1272 1125 if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */ 1273 - owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + 1274 - le32_to_cpu(pntsd->osidoffset)); 1275 - group_sid_ptr = (struct cifs_sid *)((char *)pntsd + 1276 - le32_to_cpu(pntsd->gsidoffset)); 1277 - dacloffset = le32_to_cpu(pntsd->dacloffset); 1278 - dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset); 1279 1126 ndacloffset = sizeof(struct cifs_ntsd); 1280 1127 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset); 1281 - ndacl_ptr->revision = dacl_ptr->revision; 1282 - ndacl_ptr->size = 0; 1283 - ndacl_ptr->num_aces = 0; 1128 + ndacl_ptr->revision = 1129 + dacloffset ? dacl_ptr->revision : cpu_to_le16(ACL_REVISION); 1284 1130 1285 - rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, 1131 + ndacl_ptr->size = cpu_to_le16(0); 1132 + ndacl_ptr->num_aces = cpu_to_le32(0); 1133 + 1134 + rc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr, 1286 1135 pnmode, mode_from_sid); 1136 + 1287 1137 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size); 1288 - /* copy sec desc control portion & owner and group sids */ 1289 - copy_sec_desc(pntsd, pnntsd, sidsoffset); 1290 - *aclflag = CIFS_ACL_DACL; 1138 + /* copy the non-dacl portion of secdesc */ 1139 + *pnsecdesclen = copy_sec_desc(pntsd, pnntsd, sidsoffset, 1140 + NULL, NULL); 1141 + 1142 + *aclflag |= CIFS_ACL_DACL; 1291 1143 } else { 1292 - memcpy(pnntsd, pntsd, secdesclen); 1144 + ndacloffset = sizeof(struct cifs_ntsd); 1145 + ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset); 1146 + ndacl_ptr->revision = 1147 + dacloffset ? dacl_ptr->revision : cpu_to_le16(ACL_REVISION); 1148 + ndacl_ptr->num_aces = dacl_ptr->num_aces; 1149 + 1293 1150 if (uid_valid(uid)) { /* chown */ 1294 1151 uid_t id; 1295 - owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + 1296 - le32_to_cpu(pnntsd->osidoffset)); 1297 1152 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid), 1298 1153 GFP_KERNEL); 1299 - if (!nowner_sid_ptr) 1300 - return -ENOMEM; 1154 + if (!nowner_sid_ptr) { 1155 + rc = -ENOMEM; 1156 + goto chown_chgrp_exit; 1157 + } 1301 1158 id = from_kuid(&init_user_ns, uid); 1302 1159 if (id_from_sid) { 1303 1160 struct owner_sid *osid = (struct owner_sid *)nowner_sid_ptr; ··· 1328 1145 osid->SubAuthorities[0] = cpu_to_le32(88); 1329 1146 osid->SubAuthorities[1] = cpu_to_le32(1); 1330 1147 osid->SubAuthorities[2] = cpu_to_le32(id); 1148 + 1331 1149 } else { /* lookup sid with upcall */ 1332 1150 rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr); 1333 1151 if (rc) { 1334 1152 cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n", 1335 1153 __func__, rc, id); 1336 - kfree(nowner_sid_ptr); 1337 - return rc; 1154 + goto chown_chgrp_exit; 1338 1155 } 1339 1156 } 1340 - cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr); 1341 - kfree(nowner_sid_ptr); 1342 - *aclflag = CIFS_ACL_OWNER; 1157 + *aclflag |= CIFS_ACL_OWNER; 1343 1158 } 1344 1159 if (gid_valid(gid)) { /* chgrp */ 1345 1160 gid_t id; 1346 - group_sid_ptr = (struct cifs_sid *)((char *)pnntsd + 1347 - le32_to_cpu(pnntsd->gsidoffset)); 1348 1161 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid), 1349 1162 GFP_KERNEL); 1350 - if (!ngroup_sid_ptr) 1351 - return -ENOMEM; 1163 + if (!ngroup_sid_ptr) { 1164 + rc = -ENOMEM; 1165 + goto chown_chgrp_exit; 1166 + } 1352 1167 id = from_kgid(&init_user_ns, gid); 1353 1168 if (id_from_sid) { 1354 1169 struct owner_sid *gsid = (struct owner_sid *)ngroup_sid_ptr; ··· 1357 1176 gsid->SubAuthorities[0] = cpu_to_le32(88); 1358 1177 gsid->SubAuthorities[1] = cpu_to_le32(2); 1359 1178 gsid->SubAuthorities[2] = cpu_to_le32(id); 1179 + 1360 1180 } else { /* lookup sid with upcall */ 1361 1181 rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr); 1362 1182 if (rc) { 1363 1183 cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n", 1364 1184 __func__, rc, id); 1365 - kfree(ngroup_sid_ptr); 1366 - return rc; 1185 + goto chown_chgrp_exit; 1367 1186 } 1368 1187 } 1369 - cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr); 1370 - kfree(ngroup_sid_ptr); 1371 - *aclflag = CIFS_ACL_GROUP; 1188 + *aclflag |= CIFS_ACL_GROUP; 1372 1189 } 1190 + 1191 + if (dacloffset) { 1192 + /* Replace ACEs for old owner with new one */ 1193 + size = replace_sids_and_copy_aces(dacl_ptr, ndacl_ptr, 1194 + owner_sid_ptr, group_sid_ptr, 1195 + nowner_sid_ptr, ngroup_sid_ptr); 1196 + ndacl_ptr->size = cpu_to_le16(size); 1197 + } 1198 + 1199 + sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size); 1200 + /* copy the non-dacl portion of secdesc */ 1201 + *pnsecdesclen = copy_sec_desc(pntsd, pnntsd, sidsoffset, 1202 + nowner_sid_ptr, ngroup_sid_ptr); 1203 + 1204 + chown_chgrp_exit: 1205 + /* errors could jump here. So make sure we return soon after this */ 1206 + kfree(nowner_sid_ptr); 1207 + kfree(ngroup_sid_ptr); 1373 1208 } 1374 1209 1375 1210 return rc; ··· 1581 1384 int rc = 0; 1582 1385 int aclflag = CIFS_ACL_DACL; /* default flag to set */ 1583 1386 __u32 secdesclen = 0; 1387 + __u32 nsecdesclen = 0; 1388 + __u32 dacloffset = 0; 1389 + struct cifs_acl *dacl_ptr = NULL; 1584 1390 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */ 1585 1391 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */ 1586 1392 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); ··· 1614 1414 return rc; 1615 1415 } 1616 1416 1617 - /* 1618 - * Add three ACEs for owner, group, everyone getting rid of other ACEs 1619 - * as chmod disables ACEs and set the security descriptor. Allocate 1620 - * memory for the smb header, set security descriptor request security 1621 - * descriptor parameters, and secuirty descriptor itself 1622 - */ 1623 - secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN); 1624 - pnntsd = kmalloc(secdesclen, GFP_KERNEL); 1625 - if (!pnntsd) { 1626 - kfree(pntsd); 1627 - cifs_put_tlink(tlink); 1628 - return -ENOMEM; 1629 - } 1630 - 1631 1417 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) 1632 1418 mode_from_sid = true; 1633 1419 else ··· 1624 1438 else 1625 1439 id_from_sid = false; 1626 1440 1627 - rc = build_sec_desc(pntsd, pnntsd, secdesclen, pnmode, uid, gid, 1441 + /* Potentially, five new ACEs can be added to the ACL for U,G,O mapping */ 1442 + nsecdesclen = secdesclen; 1443 + if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */ 1444 + if (mode_from_sid) 1445 + nsecdesclen += sizeof(struct cifs_ace); 1446 + else /* cifsacl */ 1447 + nsecdesclen += 5 * sizeof(struct cifs_ace); 1448 + } else { /* chown */ 1449 + /* When ownership changes, changes new owner sid length could be different */ 1450 + nsecdesclen = sizeof(struct cifs_ntsd) + (sizeof(struct cifs_sid) * 2); 1451 + dacloffset = le32_to_cpu(pntsd->dacloffset); 1452 + if (dacloffset) { 1453 + dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset); 1454 + if (mode_from_sid) 1455 + nsecdesclen += 1456 + le32_to_cpu(dacl_ptr->num_aces) * sizeof(struct cifs_ace); 1457 + else /* cifsacl */ 1458 + nsecdesclen += le16_to_cpu(dacl_ptr->size); 1459 + } 1460 + } 1461 + 1462 + /* 1463 + * Add three ACEs for owner, group, everyone getting rid of other ACEs 1464 + * as chmod disables ACEs and set the security descriptor. Allocate 1465 + * memory for the smb header, set security descriptor request security 1466 + * descriptor parameters, and secuirty descriptor itself 1467 + */ 1468 + nsecdesclen = max_t(u32, nsecdesclen, DEFAULT_SEC_DESC_LEN); 1469 + pnntsd = kmalloc(nsecdesclen, GFP_KERNEL); 1470 + if (!pnntsd) { 1471 + kfree(pntsd); 1472 + cifs_put_tlink(tlink); 1473 + return -ENOMEM; 1474 + } 1475 + 1476 + rc = build_sec_desc(pntsd, pnntsd, secdesclen, &nsecdesclen, pnmode, uid, gid, 1628 1477 mode_from_sid, id_from_sid, &aclflag); 1629 1478 1630 1479 cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc); ··· 1669 1448 1670 1449 if (!rc) { 1671 1450 /* Set the security descriptor */ 1672 - rc = ops->set_acl(pnntsd, secdesclen, inode, path, aclflag); 1451 + rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag); 1673 1452 cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc); 1674 1453 } 1675 1454 cifs_put_tlink(tlink);
+2 -2
fs/cifs/cifsacl.h
··· 31 31 #define EXEC_BIT 0x1 32 32 33 33 #define ACL_OWNER_MASK 0700 34 - #define ACL_GROUP_MASK 0770 35 - #define ACL_EVERYONE_MASK 0777 34 + #define ACL_GROUP_MASK 0070 35 + #define ACL_EVERYONE_MASK 0007 36 36 37 37 #define UBITSHIFT 6 38 38 #define GBITSHIFT 3
+3 -3
fs/cifs/cifsencrypt.c
··· 568 568 return rc; 569 569 } 570 570 } else { 571 - /* We use ses->serverName if no domain name available */ 572 - len = strlen(ses->serverName); 571 + /* We use ses->ip_addr if no domain name available */ 572 + len = strlen(ses->ip_addr); 573 573 574 574 server = kmalloc(2 + (len * 2), GFP_KERNEL); 575 575 if (server == NULL) { 576 576 rc = -ENOMEM; 577 577 return rc; 578 578 } 579 - len = cifs_strtoUTF16((__le16 *)server, ses->serverName, len, 579 + len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len, 580 580 nls_cp); 581 581 rc = 582 582 crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
+13 -2
fs/cifs/cifsfs.c
··· 638 638 seq_printf(s, ",snapshot=%llu", tcon->snapshot_time); 639 639 if (tcon->handle_timeout) 640 640 seq_printf(s, ",handletimeout=%u", tcon->handle_timeout); 641 - /* convert actimeo and display it in seconds */ 642 - seq_printf(s, ",actimeo=%lu", cifs_sb->ctx->actimeo / HZ); 641 + 642 + /* 643 + * Display file and directory attribute timeout in seconds. 644 + * If file and directory attribute timeout the same then actimeo 645 + * was likely specified on mount 646 + */ 647 + if (cifs_sb->ctx->acdirmax == cifs_sb->ctx->acregmax) 648 + seq_printf(s, ",actimeo=%lu", cifs_sb->ctx->acregmax / HZ); 649 + else { 650 + seq_printf(s, ",acdirmax=%lu", cifs_sb->ctx->acdirmax / HZ); 651 + seq_printf(s, ",acregmax=%lu", cifs_sb->ctx->acregmax / HZ); 652 + } 643 653 644 654 if (tcon->ses->chan_max > 1) 645 655 seq_printf(s, ",multichannel,max_channels=%zu", ··· 1536 1526 */ 1537 1527 atomic_set(&sesInfoAllocCount, 0); 1538 1528 atomic_set(&tconInfoAllocCount, 0); 1529 + atomic_set(&tcpSesNextId, 0); 1539 1530 atomic_set(&tcpSesAllocCount, 0); 1540 1531 atomic_set(&tcpSesReconnectCount, 0); 1541 1532 atomic_set(&tconInfoReconnectCount, 0);
+1 -1
fs/cifs/cifsfs.h
··· 165 165 extern const struct export_operations cifs_export_ops; 166 166 #endif /* CONFIG_CIFS_NFSD_EXPORT */ 167 167 168 - #define CIFS_VERSION "2.30" 168 + #define CIFS_VERSION "2.31" 169 169 #endif /* _CIFSFS_H */
+9 -2
fs/cifs/cifsglob.h
··· 21 21 22 22 #include <linux/in.h> 23 23 #include <linux/in6.h> 24 + #include <linux/inet.h> 24 25 #include <linux/slab.h> 25 26 #include <linux/mempool.h> 26 27 #include <linux/workqueue.h> ··· 505 504 loff_t (*llseek)(struct file *, struct cifs_tcon *, loff_t, int); 506 505 /* Check for STATUS_IO_TIMEOUT */ 507 506 bool (*is_status_io_timeout)(char *buf); 507 + /* Check for STATUS_NETWORK_NAME_DELETED */ 508 + void (*is_network_name_deleted)(char *buf, struct TCP_Server_Info *srv); 508 509 }; 509 510 510 511 struct smb_version_values { ··· 580 577 struct TCP_Server_Info { 581 578 struct list_head tcp_ses_list; 582 579 struct list_head smb_ses_list; 580 + __u64 conn_id; /* connection identifier (useful for debugging) */ 583 581 int srv_count; /* reference counter */ 584 582 /* 15 character server name + 0x20 16th byte indicating type = srv */ 585 583 char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; ··· 905 901 kuid_t linux_uid; /* overriding owner of files on the mount */ 906 902 kuid_t cred_uid; /* owner of credentials */ 907 903 unsigned int capabilities; 908 - char serverName[SERVER_NAME_LEN_WITH_NULL]; 904 + char ip_addr[INET6_ADDRSTRLEN + 1]; /* Max ipv6 (or v4) addr string len */ 909 905 char *user_name; /* must not be null except during init of sess 910 906 and after mount option parsing we fill it */ 911 907 char *domainName; ··· 1708 1704 #define CIFS_ECHO_OP 0x080 /* echo request */ 1709 1705 #define CIFS_OBREAK_OP 0x0100 /* oplock break request */ 1710 1706 #define CIFS_NEG_OP 0x0200 /* negotiate request */ 1711 - #define CIFS_OP_MASK 0x0380 /* mask request type */ 1707 + /* Lower bitmask values are reserved by others below. */ 1708 + #define CIFS_SESS_OP 0x2000 /* session setup request */ 1709 + #define CIFS_OP_MASK 0x2380 /* mask request type */ 1712 1710 1713 1711 #define CIFS_HAS_CREDITS 0x0400 /* already has credits */ 1714 1712 #define CIFS_TRANSFORM_REQ 0x0800 /* transform request before sending */ ··· 1850 1844 */ 1851 1845 GLOBAL_EXTERN atomic_t sesInfoAllocCount; 1852 1846 GLOBAL_EXTERN atomic_t tconInfoAllocCount; 1847 + GLOBAL_EXTERN atomic_t tcpSesNextId; 1853 1848 GLOBAL_EXTERN atomic_t tcpSesAllocCount; 1854 1849 GLOBAL_EXTERN atomic_t tcpSesReconnectCount; 1855 1850 GLOBAL_EXTERN atomic_t tconInfoReconnectCount;
+2
fs/cifs/cifsproto.h
··· 232 232 extern void dequeue_mid(struct mid_q_entry *mid, bool malformed); 233 233 extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf, 234 234 unsigned int to_read); 235 + extern ssize_t cifs_discard_from_socket(struct TCP_Server_Info *server, 236 + size_t to_read); 235 237 extern int cifs_read_page_from_socket(struct TCP_Server_Info *server, 236 238 struct page *page, 237 239 unsigned int page_offset,
+3 -3
fs/cifs/cifssmb.c
··· 1451 1451 while (remaining > 0) { 1452 1452 int length; 1453 1453 1454 - length = cifs_read_from_socket(server, server->bigbuf, 1455 - min_t(unsigned int, remaining, 1456 - CIFSMaxBufSize + MAX_HEADER_SIZE(server))); 1454 + length = cifs_discard_from_socket(server, 1455 + min_t(size_t, remaining, 1456 + CIFSMaxBufSize + MAX_HEADER_SIZE(server))); 1457 1457 if (length < 0) 1458 1458 return length; 1459 1459 server->total_read += length;
+165 -138
fs/cifs/connect.c
··· 242 242 server->max_read = 0; 243 243 244 244 cifs_dbg(FYI, "Mark tcp session as need reconnect\n"); 245 - trace_smb3_reconnect(server->CurrentMid, server->hostname); 245 + trace_smb3_reconnect(server->CurrentMid, server->conn_id, server->hostname); 246 246 247 247 /* before reconnecting the tcp session, mark the smb session (uid) 248 248 and the tid bad so they are not used until reconnected */ ··· 564 564 return cifs_readv_from_socket(server, &smb_msg); 565 565 } 566 566 567 + ssize_t 568 + cifs_discard_from_socket(struct TCP_Server_Info *server, size_t to_read) 569 + { 570 + struct msghdr smb_msg; 571 + 572 + /* 573 + * iov_iter_discard already sets smb_msg.type and count and iov_offset 574 + * and cifs_readv_from_socket sets msg_control and msg_controllen 575 + * so little to initialize in struct msghdr 576 + */ 577 + smb_msg.msg_name = NULL; 578 + smb_msg.msg_namelen = 0; 579 + iov_iter_discard(&smb_msg.msg_iter, READ, to_read); 580 + 581 + return cifs_readv_from_socket(server, &smb_msg); 582 + } 583 + 567 584 int 568 585 cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page, 569 586 unsigned int page_offset, unsigned int to_read) ··· 863 846 smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server) 864 847 { 865 848 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer; 866 - int scredits = server->credits; 849 + int scredits, in_flight; 867 850 868 851 /* 869 852 * SMB1 does not use credits. ··· 874 857 if (shdr->CreditRequest) { 875 858 spin_lock(&server->req_lock); 876 859 server->credits += le16_to_cpu(shdr->CreditRequest); 860 + scredits = server->credits; 861 + in_flight = server->in_flight; 877 862 spin_unlock(&server->req_lock); 878 863 wake_up(&server->request_q); 879 864 880 865 trace_smb3_add_credits(server->CurrentMid, 881 - server->hostname, scredits, 882 - le16_to_cpu(shdr->CreditRequest)); 866 + server->conn_id, server->hostname, scredits, 867 + le16_to_cpu(shdr->CreditRequest), in_flight); 883 868 cifs_server_dbg(FYI, "%s: added %u credits total=%d\n", 884 869 __func__, le16_to_cpu(shdr->CreditRequest), 885 870 scredits); ··· 1011 992 for (i = 0; i < num_mids; i++) { 1012 993 if (mids[i] != NULL) { 1013 994 mids[i]->resp_buf_size = server->pdu_size; 995 + 996 + if (bufs[i] && server->ops->is_network_name_deleted) 997 + server->ops->is_network_name_deleted(bufs[i], 998 + server); 1014 999 1015 1000 if (!mids[i]->multiRsp || mids[i]->multiEnd) 1016 1001 mids[i]->callback(mids[i]); ··· 1340 1317 goto out_err_crypto_release; 1341 1318 } 1342 1319 1320 + tcp_ses->conn_id = atomic_inc_return(&tcpSesNextId); 1343 1321 tcp_ses->noblockcnt = ctx->rootfs; 1344 1322 tcp_ses->noblocksnd = ctx->noblocksnd || ctx->rootfs; 1345 1323 tcp_ses->noautotune = ctx->noautotune; ··· 1862 1838 /* new SMB session uses our server ref */ 1863 1839 ses->server = server; 1864 1840 if (server->dstaddr.ss_family == AF_INET6) 1865 - sprintf(ses->serverName, "%pI6", &addr6->sin6_addr); 1841 + sprintf(ses->ip_addr, "%pI6", &addr6->sin6_addr); 1866 1842 else 1867 - sprintf(ses->serverName, "%pI4", &addr->sin_addr); 1843 + sprintf(ses->ip_addr, "%pI4", &addr->sin_addr); 1868 1844 1869 1845 if (ctx->username) { 1870 1846 ses->user_name = kstrdup(ctx->username, GFP_KERNEL); ··· 2293 2269 if (strcmp(old->local_nls->charset, new->local_nls->charset)) 2294 2270 return 0; 2295 2271 2296 - if (old->ctx->actimeo != new->ctx->actimeo) 2272 + if (old->ctx->acregmax != new->ctx->acregmax) 2273 + return 0; 2274 + if (old->ctx->acdirmax != new->ctx->acdirmax) 2297 2275 return 0; 2298 2276 2299 2277 return 1; ··· 2937 2911 #ifdef CONFIG_CIFS_DFS_UPCALL 2938 2912 /* 2939 2913 * cifs_build_path_to_root returns full path to root when we do not have an 2940 - * exiting connection (tcon) 2914 + * existing connection (tcon) 2941 2915 */ 2942 2916 static char * 2943 2917 build_unc_path_to_root(const struct smb3_fs_context *ctx, ··· 3064 3038 return 0; 3065 3039 } 3066 3040 3067 - static int setup_dfs_tgt_conn(const char *path, const char *full_path, 3068 - const struct dfs_cache_tgt_iterator *tgt_it, 3069 - struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx, 3070 - unsigned int *xid, struct TCP_Server_Info **server, 3071 - struct cifs_ses **ses, struct cifs_tcon **tcon) 3072 - { 3073 - int rc; 3074 - struct dfs_info3_param ref = {0}; 3075 - char *mdata = NULL; 3076 - struct smb3_fs_context fake_ctx = {NULL}; 3077 - char *fake_devname = NULL; 3078 - 3079 - cifs_dbg(FYI, "%s: dfs path: %s\n", __func__, path); 3080 - 3081 - rc = dfs_cache_get_tgt_referral(path, tgt_it, &ref); 3082 - if (rc) 3083 - return rc; 3084 - 3085 - mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options, 3086 - full_path + 1, &ref, 3087 - &fake_devname); 3088 - free_dfs_info_param(&ref); 3089 - 3090 - if (IS_ERR(mdata)) { 3091 - rc = PTR_ERR(mdata); 3092 - mdata = NULL; 3093 - } else 3094 - rc = cifs_setup_volume_info(&fake_ctx, mdata, fake_devname); 3095 - 3096 - kfree(mdata); 3097 - kfree(fake_devname); 3098 - 3099 - if (!rc) { 3100 - /* 3101 - * We use a 'fake_ctx' here because we need pass it down to the 3102 - * mount_{get,put} functions to test connection against new DFS 3103 - * targets. 3104 - */ 3105 - mount_put_conns(cifs_sb, *xid, *server, *ses, *tcon); 3106 - rc = mount_get_conns(&fake_ctx, cifs_sb, xid, server, ses, 3107 - tcon); 3108 - if (!rc || (*server && *ses)) { 3109 - /* 3110 - * We were able to connect to new target server. 3111 - * Update current context with new target server. 3112 - */ 3113 - rc = update_vol_info(tgt_it, &fake_ctx, ctx); 3114 - } 3115 - } 3116 - smb3_cleanup_fs_context_contents(&fake_ctx); 3117 - return rc; 3118 - } 3119 - 3120 3041 static int do_dfs_failover(const char *path, const char *full_path, struct cifs_sb_info *cifs_sb, 3121 3042 struct smb3_fs_context *ctx, struct cifs_ses *root_ses, 3122 3043 unsigned int *xid, struct TCP_Server_Info **server, 3123 3044 struct cifs_ses **ses, struct cifs_tcon **tcon) 3124 3045 { 3125 3046 int rc; 3126 - struct dfs_cache_tgt_list tgt_list; 3047 + struct dfs_cache_tgt_list tgt_list = {0}; 3127 3048 struct dfs_cache_tgt_iterator *tgt_it = NULL; 3049 + struct smb3_fs_context tmp_ctx = {NULL}; 3128 3050 3129 3051 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) 3130 3052 return -EOPNOTSUPP; 3131 3053 3054 + cifs_dbg(FYI, "%s: path=%s full_path=%s\n", __func__, path, full_path); 3055 + 3132 3056 rc = dfs_cache_noreq_find(path, NULL, &tgt_list); 3133 3057 if (rc) 3134 3058 return rc; 3059 + /* 3060 + * We use a 'tmp_ctx' here because we need pass it down to the mount_{get,put} functions to 3061 + * test connection against new DFS targets. 3062 + */ 3063 + rc = smb3_fs_context_dup(&tmp_ctx, ctx); 3064 + if (rc) 3065 + goto out; 3135 3066 3136 3067 for (;;) { 3068 + struct dfs_info3_param ref = {0}; 3069 + char *fake_devname = NULL, *mdata = NULL; 3070 + 3137 3071 /* Get next DFS target server - if any */ 3138 3072 rc = get_next_dfs_tgt(path, &tgt_list, &tgt_it); 3139 3073 if (rc) 3140 3074 break; 3141 - /* Connect to next DFS target */ 3142 - rc = setup_dfs_tgt_conn(path, full_path, tgt_it, cifs_sb, ctx, xid, server, ses, 3143 - tcon); 3144 - if (!rc || (*server && *ses)) 3075 + 3076 + rc = dfs_cache_get_tgt_referral(path, tgt_it, &ref); 3077 + if (rc) 3145 3078 break; 3079 + 3080 + cifs_dbg(FYI, "%s: old ctx: UNC=%s prepath=%s\n", __func__, tmp_ctx.UNC, 3081 + tmp_ctx.prepath); 3082 + 3083 + mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options, full_path + 1, &ref, 3084 + &fake_devname); 3085 + free_dfs_info_param(&ref); 3086 + 3087 + if (IS_ERR(mdata)) { 3088 + rc = PTR_ERR(mdata); 3089 + mdata = NULL; 3090 + } else 3091 + rc = cifs_setup_volume_info(&tmp_ctx, mdata, fake_devname); 3092 + 3093 + kfree(mdata); 3094 + kfree(fake_devname); 3095 + 3096 + if (rc) 3097 + break; 3098 + 3099 + cifs_dbg(FYI, "%s: new ctx: UNC=%s prepath=%s\n", __func__, tmp_ctx.UNC, 3100 + tmp_ctx.prepath); 3101 + 3102 + mount_put_conns(cifs_sb, *xid, *server, *ses, *tcon); 3103 + rc = mount_get_conns(&tmp_ctx, cifs_sb, xid, server, ses, tcon); 3104 + if (!rc || (*server && *ses)) { 3105 + /* 3106 + * We were able to connect to new target server. Update current context with 3107 + * new target server. 3108 + */ 3109 + rc = update_vol_info(tgt_it, &tmp_ctx, ctx); 3110 + break; 3111 + } 3146 3112 } 3147 3113 if (!rc) { 3114 + cifs_dbg(FYI, "%s: final ctx: UNC=%s prepath=%s\n", __func__, tmp_ctx.UNC, 3115 + tmp_ctx.prepath); 3148 3116 /* 3149 - * Update DFS target hint in DFS referral cache with the target 3150 - * server we successfully reconnected to. 3117 + * Update DFS target hint in DFS referral cache with the target server we 3118 + * successfully reconnected to. 3151 3119 */ 3152 - rc = dfs_cache_update_tgthint(*xid, root_ses ? root_ses : *ses, 3153 - cifs_sb->local_nls, 3154 - cifs_remap(cifs_sb), path, 3155 - tgt_it); 3120 + rc = dfs_cache_update_tgthint(*xid, root_ses ? root_ses : *ses, cifs_sb->local_nls, 3121 + cifs_remap(cifs_sb), path, tgt_it); 3156 3122 } 3123 + 3124 + out: 3125 + smb3_cleanup_fs_context_contents(&tmp_ctx); 3157 3126 dfs_cache_free_tgts(&tgt_list); 3158 3127 return rc; 3159 3128 } ··· 3306 3285 cifs_put_smb_ses(ses); 3307 3286 } 3308 3287 3309 - /* Check if a path component is remote and then update @dfs_path accordingly */ 3310 - static int check_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx, 3311 - const unsigned int xid, struct TCP_Server_Info *server, 3312 - struct cifs_tcon *tcon, char **dfs_path) 3288 + /* Set up next dfs prefix path in @dfs_path */ 3289 + static int next_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx, 3290 + const unsigned int xid, struct TCP_Server_Info *server, 3291 + struct cifs_tcon *tcon, char **dfs_path) 3313 3292 { 3314 - char *path, *s; 3315 - char sep = CIFS_DIR_SEP(cifs_sb), tmp; 3316 - char *npath; 3317 - int rc = 0; 3318 - int added_treename = tcon->Flags & SMB_SHARE_IS_IN_DFS; 3319 - int skip = added_treename; 3293 + char *path, *npath; 3294 + int added_treename = is_tcon_dfs(tcon); 3295 + int rc; 3320 3296 3321 3297 path = cifs_build_path_to_root(ctx, cifs_sb, tcon, added_treename); 3322 3298 if (!path) 3323 3299 return -ENOMEM; 3324 3300 3325 - /* 3326 - * Walk through the path components in @path and check if they're accessible. In case any of 3327 - * the components is -EREMOTE, then update @dfs_path with the next DFS referral request path 3328 - * (NOT including the remaining components). 3329 - */ 3330 - s = path; 3331 - do { 3332 - /* skip separators */ 3333 - while (*s && *s == sep) 3334 - s++; 3335 - if (!*s) 3336 - break; 3337 - /* next separator */ 3338 - while (*s && *s != sep) 3339 - s++; 3340 - /* 3341 - * if the treename is added, we then have to skip the first 3342 - * part within the separators 3343 - */ 3344 - if (skip) { 3345 - skip = 0; 3346 - continue; 3301 + rc = is_path_remote(cifs_sb, ctx, xid, server, tcon); 3302 + if (rc == -EREMOTE) { 3303 + struct smb3_fs_context v = {NULL}; 3304 + /* if @path contains a tree name, skip it in the prefix path */ 3305 + if (added_treename) { 3306 + rc = smb3_parse_devname(path, &v); 3307 + if (rc) 3308 + goto out; 3309 + npath = build_unc_path_to_root(&v, cifs_sb, true); 3310 + smb3_cleanup_fs_context_contents(&v); 3311 + } else { 3312 + v.UNC = ctx->UNC; 3313 + v.prepath = path + 1; 3314 + npath = build_unc_path_to_root(&v, cifs_sb, true); 3347 3315 } 3348 - tmp = *s; 3349 - *s = 0; 3350 - rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, path); 3351 - if (rc && rc == -EREMOTE) { 3352 - struct smb3_fs_context v = {NULL}; 3353 - /* if @path contains a tree name, skip it in the prefix path */ 3354 - if (added_treename) { 3355 - rc = smb3_parse_devname(path, &v); 3356 - if (rc) 3357 - break; 3358 - rc = -EREMOTE; 3359 - npath = build_unc_path_to_root(&v, cifs_sb, true); 3360 - smb3_cleanup_fs_context_contents(&v); 3361 - } else { 3362 - v.UNC = ctx->UNC; 3363 - v.prepath = path + 1; 3364 - npath = build_unc_path_to_root(&v, cifs_sb, true); 3365 - } 3366 - if (IS_ERR(npath)) { 3367 - rc = PTR_ERR(npath); 3368 - break; 3369 - } 3370 - kfree(*dfs_path); 3371 - *dfs_path = npath; 3372 - } 3373 - *s = tmp; 3374 - } while (rc == 0); 3375 3316 3317 + if (IS_ERR(npath)) { 3318 + rc = PTR_ERR(npath); 3319 + goto out; 3320 + } 3321 + 3322 + kfree(*dfs_path); 3323 + *dfs_path = npath; 3324 + rc = -EREMOTE; 3325 + } 3326 + 3327 + out: 3376 3328 kfree(path); 3377 3329 return rc; 3330 + } 3331 + 3332 + /* Check if resolved targets can handle any DFS referrals */ 3333 + static int is_referral_server(const char *ref_path, struct cifs_tcon *tcon, bool *ref_server) 3334 + { 3335 + int rc; 3336 + struct dfs_info3_param ref = {0}; 3337 + 3338 + if (is_tcon_dfs(tcon)) { 3339 + *ref_server = true; 3340 + } else { 3341 + cifs_dbg(FYI, "%s: ref_path=%s\n", __func__, ref_path); 3342 + 3343 + rc = dfs_cache_noreq_find(ref_path, &ref, NULL); 3344 + if (rc) { 3345 + cifs_dbg(VFS, "%s: dfs_cache_noreq_find: failed (rc=%d)\n", __func__, rc); 3346 + return rc; 3347 + } 3348 + cifs_dbg(FYI, "%s: ref.flags=0x%x\n", __func__, ref.flags); 3349 + /* 3350 + * Check if all targets are capable of handling DFS referrals as per 3351 + * MS-DFSC 2.2.4 RESP_GET_DFS_REFERRAL. 3352 + */ 3353 + *ref_server = !!(ref.flags & DFSREF_REFERRAL_SERVER); 3354 + free_dfs_info_param(&ref); 3355 + } 3356 + return 0; 3378 3357 } 3379 3358 3380 3359 int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) ··· 3388 3367 char *ref_path = NULL, *full_path = NULL; 3389 3368 char *oldmnt = NULL; 3390 3369 char *mntdata = NULL; 3370 + bool ref_server = false; 3391 3371 3392 3372 rc = mount_get_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon); 3393 3373 /* 3394 - * Unconditionally try to get an DFS referral (even cached) to determine whether it is an 3395 - * DFS mount. 3374 + * If called with 'nodfs' mount option, then skip DFS resolving. Otherwise unconditionally 3375 + * try to get an DFS referral (even cached) to determine whether it is an DFS mount. 3396 3376 * 3397 3377 * Skip prefix path to provide support for DFS referrals from w2k8 servers which don't seem 3398 3378 * to respond with PATH_NOT_COVERED to requests that include the prefix. 3399 3379 */ 3400 - if (dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), ctx->UNC + 1, NULL, 3380 + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) || 3381 + dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), ctx->UNC + 1, NULL, 3401 3382 NULL)) { 3402 - /* No DFS referral was returned. Looks like a regular share. */ 3403 3383 if (rc) 3404 3384 goto error; 3405 3385 /* Check if it is fully accessible and then mount it */ ··· 3454 3432 break; 3455 3433 if (!tcon) 3456 3434 continue; 3435 + 3457 3436 /* Make sure that requests go through new root servers */ 3458 - if (is_tcon_dfs(tcon)) { 3437 + rc = is_referral_server(ref_path + 1, tcon, &ref_server); 3438 + if (rc) 3439 + break; 3440 + if (ref_server) { 3459 3441 put_root_ses(root_ses); 3460 3442 set_root_ses(cifs_sb, ses, &root_ses); 3461 3443 } 3462 - /* Check for remaining path components and then continue chasing them (-EREMOTE) */ 3463 - rc = check_dfs_prepath(cifs_sb, ctx, xid, server, tcon, &ref_path); 3444 + 3445 + /* Get next dfs path and then continue chasing them if -EREMOTE */ 3446 + rc = next_dfs_prepath(cifs_sb, ctx, xid, server, tcon, &ref_path); 3464 3447 /* Prevent recursion on broken link referrals */ 3465 3448 if (rc == -EREMOTE && ++count > MAX_NESTED_LINKS) 3466 3449 rc = -ELOOP;
+17 -16
fs/cifs/dfs_cache.c
··· 37 37 struct cache_entry { 38 38 struct hlist_node hlist; 39 39 const char *path; 40 - int ttl; 41 - int srvtype; 42 - int flags; 40 + int hdr_flags; /* RESP_GET_DFS_REFERRAL.ReferralHeaderFlags */ 41 + int ttl; /* DFS_REREFERRAL_V3.TimeToLive */ 42 + int srvtype; /* DFS_REREFERRAL_V3.ServerType */ 43 + int ref_flags; /* DFS_REREFERRAL_V3.ReferralEntryFlags */ 43 44 struct timespec64 etime; 44 - int path_consumed; 45 + int path_consumed; /* RESP_GET_DFS_REFERRAL.PathConsumed */ 45 46 int numtgts; 46 47 struct list_head tlist; 47 48 struct cache_dfs_tgt *tgthint; ··· 167 166 continue; 168 167 169 168 seq_printf(m, 170 - "cache entry: path=%s,type=%s,ttl=%d,etime=%ld," 171 - "interlink=%s,path_consumed=%d,expired=%s\n", 172 - ce->path, 173 - ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", 174 - ce->ttl, ce->etime.tv_nsec, 175 - IS_INTERLINK_SET(ce->flags) ? "yes" : "no", 176 - ce->path_consumed, 177 - cache_entry_expired(ce) ? "yes" : "no"); 169 + "cache entry: path=%s,type=%s,ttl=%d,etime=%ld,hdr_flags=0x%x,ref_flags=0x%x,interlink=%s,path_consumed=%d,expired=%s\n", 170 + ce->path, ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", 171 + ce->ttl, ce->etime.tv_nsec, ce->ref_flags, ce->hdr_flags, 172 + IS_INTERLINK_SET(ce->hdr_flags) ? "yes" : "no", 173 + ce->path_consumed, cache_entry_expired(ce) ? "yes" : "no"); 178 174 179 175 list_for_each_entry(t, &ce->tlist, list) { 180 176 seq_printf(m, " %s%s\n", ··· 234 236 235 237 static inline void dump_ce(const struct cache_entry *ce) 236 238 { 237 - cifs_dbg(FYI, "cache entry: path=%s,type=%s,ttl=%d,etime=%ld,interlink=%s,path_consumed=%d,expired=%s\n", 239 + cifs_dbg(FYI, "cache entry: path=%s,type=%s,ttl=%d,etime=%ld,hdr_flags=0x%x,ref_flags=0x%x,interlink=%s,path_consumed=%d,expired=%s\n", 238 240 ce->path, 239 241 ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", ce->ttl, 240 242 ce->etime.tv_nsec, 241 - IS_INTERLINK_SET(ce->flags) ? "yes" : "no", 243 + ce->hdr_flags, ce->ref_flags, 244 + IS_INTERLINK_SET(ce->hdr_flags) ? "yes" : "no", 242 245 ce->path_consumed, 243 246 cache_entry_expired(ce) ? "yes" : "no"); 244 247 dump_tgts(ce); ··· 380 381 ce->ttl = refs[0].ttl; 381 382 ce->etime = get_expire_time(ce->ttl); 382 383 ce->srvtype = refs[0].server_type; 383 - ce->flags = refs[0].ref_flag; 384 + ce->hdr_flags = refs[0].flags; 385 + ce->ref_flags = refs[0].ref_flag; 384 386 ce->path_consumed = refs[0].path_consumed; 385 387 386 388 for (i = 0; i < numrefs; i++) { ··· 799 799 ref->path_consumed = ce->path_consumed; 800 800 ref->ttl = ce->ttl; 801 801 ref->server_type = ce->srvtype; 802 - ref->ref_flag = ce->flags; 802 + ref->ref_flag = ce->ref_flags; 803 + ref->flags = ce->hdr_flags; 803 804 804 805 return 0; 805 806
+1 -1
fs/cifs/file.c
··· 580 580 } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { 581 581 if (tcon->ses->serverNOS) 582 582 cifs_dbg(VFS, "server %s of type %s returned unexpected error on SMB posix open, disabling posix open support. Check if server update available.\n", 583 - tcon->ses->serverName, 583 + tcon->ses->ip_addr, 584 584 tcon->ses->serverNOS); 585 585 tcon->broken_posix_open = true; 586 586 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
+57 -18
fs/cifs/fs_context.c
··· 140 140 fsparam_u32("rsize", Opt_rsize), 141 141 fsparam_u32("wsize", Opt_wsize), 142 142 fsparam_u32("actimeo", Opt_actimeo), 143 + fsparam_u32("acdirmax", Opt_acdirmax), 144 + fsparam_u32("acregmax", Opt_acregmax), 143 145 fsparam_u32("echo_interval", Opt_echo_interval), 144 146 fsparam_u32("max_credits", Opt_max_credits), 145 147 fsparam_u32("handletimeout", Opt_handletimeout), ··· 399 397 ctx->vals = &smb3any_values; 400 398 break; 401 399 case Smb_default: 402 - ctx->ops = &smb30_operations; /* currently identical with 3.0 */ 400 + ctx->ops = &smb30_operations; 403 401 ctx->vals = &smbdefault_values; 404 402 break; 405 403 default: ··· 544 542 545 543 /* BB Need to add support for sep= here TBD */ 546 544 while ((key = strsep(&options, ",")) != NULL) { 547 - if (*key) { 548 - size_t v_len = 0; 549 - char *value = strchr(key, '='); 545 + size_t len; 546 + char *value; 550 547 551 - if (value) { 552 - if (value == key) 553 - continue; 554 - *value++ = 0; 555 - v_len = strlen(value); 556 - } 557 - ret = vfs_parse_fs_string(fc, key, value, v_len); 558 - if (ret < 0) 559 - break; 548 + if (*key == 0) 549 + break; 550 + 551 + /* Check if following character is the deliminator If yes, 552 + * we have encountered a double deliminator reset the NULL 553 + * character to the deliminator 554 + */ 555 + while (options && options[0] == ',') { 556 + len = strlen(key); 557 + strcpy(key + len, options); 558 + options = strchr(options, ','); 559 + if (options) 560 + *options++ = 0; 560 561 } 562 + 563 + 564 + len = 0; 565 + value = strchr(key, '='); 566 + if (value) { 567 + if (value == key) 568 + continue; 569 + *value++ = 0; 570 + len = strlen(value); 571 + } 572 + 573 + ret = vfs_parse_fs_string(fc, key, value, len); 574 + if (ret < 0) 575 + break; 561 576 } 562 577 563 578 return ret; ··· 948 929 ctx->wsize = result.uint_32; 949 930 ctx->got_wsize = true; 950 931 break; 951 - case Opt_actimeo: 952 - ctx->actimeo = HZ * result.uint_32; 953 - if (ctx->actimeo > CIFS_MAX_ACTIMEO) { 954 - cifs_dbg(VFS, "attribute cache timeout too large\n"); 932 + case Opt_acregmax: 933 + ctx->acregmax = HZ * result.uint_32; 934 + if (ctx->acregmax > CIFS_MAX_ACTIMEO) { 935 + cifs_dbg(VFS, "acregmax too large\n"); 955 936 goto cifs_parse_mount_err; 956 937 } 938 + break; 939 + case Opt_acdirmax: 940 + ctx->acdirmax = HZ * result.uint_32; 941 + if (ctx->acdirmax > CIFS_MAX_ACTIMEO) { 942 + cifs_dbg(VFS, "acdirmax too large\n"); 943 + goto cifs_parse_mount_err; 944 + } 945 + break; 946 + case Opt_actimeo: 947 + if (HZ * result.uint_32 > CIFS_MAX_ACTIMEO) { 948 + cifs_dbg(VFS, "timeout too large\n"); 949 + goto cifs_parse_mount_err; 950 + } 951 + if ((ctx->acdirmax != CIFS_DEF_ACTIMEO) || 952 + (ctx->acregmax != CIFS_DEF_ACTIMEO)) { 953 + cifs_dbg(VFS, "actimeo ignored since acregmax or acdirmax specified\n"); 954 + break; 955 + } 956 + ctx->acdirmax = ctx->acregmax = HZ * result.uint_32; 957 957 break; 958 958 case Opt_echo_interval: 959 959 ctx->echo_interval = result.uint_32; ··· 1399 1361 /* default is to use strict cifs caching semantics */ 1400 1362 ctx->strict_io = true; 1401 1363 1402 - ctx->actimeo = CIFS_DEF_ACTIMEO; 1364 + ctx->acregmax = CIFS_DEF_ACTIMEO; 1365 + ctx->acdirmax = CIFS_DEF_ACTIMEO; 1403 1366 1404 1367 /* Most clients set timeout to 0, allows server to use its default */ 1405 1368 ctx->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */
+5 -1
fs/cifs/fs_context.h
··· 118 118 Opt_rsize, 119 119 Opt_wsize, 120 120 Opt_actimeo, 121 + Opt_acdirmax, 122 + Opt_acregmax, 121 123 Opt_echo_interval, 122 124 Opt_max_credits, 123 125 Opt_snapshot, ··· 234 232 unsigned int wsize; 235 233 unsigned int min_offload; 236 234 bool sockopt_tcp_nodelay:1; 237 - unsigned long actimeo; /* attribute cache timeout (jiffies) */ 235 + /* attribute cache timemout for files and directories in jiffies */ 236 + unsigned long acregmax; 237 + unsigned long acdirmax; 238 238 struct smb_version_operations *ops; 239 239 struct smb_version_values *vals; 240 240 char *prepath;
+17 -6
fs/cifs/inode.c
··· 2199 2199 if (!lookupCacheEnabled) 2200 2200 return true; 2201 2201 2202 - if (!cifs_sb->ctx->actimeo) 2203 - return true; 2204 - 2205 - if (!time_in_range(jiffies, cifs_i->time, 2206 - cifs_i->time + cifs_sb->ctx->actimeo)) 2207 - return true; 2202 + /* 2203 + * depending on inode type, check if attribute caching disabled for 2204 + * files or directories 2205 + */ 2206 + if (S_ISDIR(inode->i_mode)) { 2207 + if (!cifs_sb->ctx->acdirmax) 2208 + return true; 2209 + if (!time_in_range(jiffies, cifs_i->time, 2210 + cifs_i->time + cifs_sb->ctx->acdirmax)) 2211 + return true; 2212 + } else { /* file */ 2213 + if (!cifs_sb->ctx->acregmax) 2214 + return true; 2215 + if (!time_in_range(jiffies, cifs_i->time, 2216 + cifs_i->time + cifs_sb->ctx->acregmax)) 2217 + return true; 2218 + } 2208 2219 2209 2220 /* hardlinked files w/ noserverino get "special" treatment */ 2210 2221 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
+1 -1
fs/cifs/sess.c
··· 218 218 219 219 /* UNC and paths */ 220 220 /* XXX: Use ses->server->hostname? */ 221 - sprintf(unc, unc_fmt, ses->serverName); 221 + sprintf(unc, unc_fmt, ses->ip_addr); 222 222 ctx.UNC = unc; 223 223 ctx.prepath = ""; 224 224
+92 -17
fs/cifs/smb2ops.c
··· 63 63 const struct cifs_credits *credits, const int optype) 64 64 { 65 65 int *val, rc = -1; 66 + int scredits, in_flight; 66 67 unsigned int add = credits->value; 67 68 unsigned int instance = credits->instance; 68 69 bool reconnect_detected = false; 70 + bool reconnect_with_invalid_credits = false; 69 71 70 72 spin_lock(&server->req_lock); 71 73 val = server->ops->get_credits_field(server, optype); 72 74 73 75 /* eg found case where write overlapping reconnect messed up credits */ 74 76 if (((optype & CIFS_OP_MASK) == CIFS_NEG_OP) && (*val != 0)) 75 - trace_smb3_reconnect_with_invalid_credits(server->CurrentMid, 76 - server->hostname, *val, add); 77 + reconnect_with_invalid_credits = true; 78 + 77 79 if ((instance == 0) || (instance == server->reconnect_instance)) 78 80 *val += add; 79 81 else ··· 86 84 pr_warn_once("server overflowed SMB3 credits\n"); 87 85 } 88 86 server->in_flight--; 89 - if (server->in_flight == 0 && (optype & CIFS_OP_MASK) != CIFS_NEG_OP) 87 + if (server->in_flight == 0 && 88 + ((optype & CIFS_OP_MASK) != CIFS_NEG_OP) && 89 + ((optype & CIFS_OP_MASK) != CIFS_SESS_OP)) 90 90 rc = change_conf(server); 91 91 /* 92 92 * Sometimes server returns 0 credits on oplock break ack - we need to ··· 101 97 server->oplock_credits++; 102 98 } 103 99 } 100 + scredits = *val; 101 + in_flight = server->in_flight; 104 102 spin_unlock(&server->req_lock); 105 103 wake_up(&server->request_q); 106 104 107 105 if (reconnect_detected) { 106 + trace_smb3_reconnect_detected(server->CurrentMid, 107 + server->conn_id, server->hostname, scredits, add, in_flight); 108 + 108 109 cifs_dbg(FYI, "trying to put %d credits from the old server instance %d\n", 109 110 add, instance); 111 + } 112 + 113 + if (reconnect_with_invalid_credits) { 114 + trace_smb3_reconnect_with_invalid_credits(server->CurrentMid, 115 + server->conn_id, server->hostname, scredits, add, in_flight); 116 + cifs_dbg(FYI, "Negotiate operation when server credits is non-zero. Optype: %d, server credits: %d, credits added: %d\n", 117 + optype, scredits, add); 110 118 } 111 119 112 120 if (server->tcpStatus == CifsNeedReconnect ··· 139 123 cifs_dbg(FYI, "disabling oplocks\n"); 140 124 break; 141 125 default: 142 - trace_smb3_add_credits(server->CurrentMid, 143 - server->hostname, rc, add); 144 - cifs_dbg(FYI, "%s: added %u credits total=%d\n", __func__, add, rc); 126 + /* change_conf rebalanced credits for different types */ 127 + break; 145 128 } 129 + 130 + trace_smb3_add_credits(server->CurrentMid, 131 + server->conn_id, server->hostname, scredits, add, in_flight); 132 + cifs_dbg(FYI, "%s: added %u credits total=%d\n", __func__, add, scredits); 146 133 } 147 134 148 135 static void 149 136 smb2_set_credits(struct TCP_Server_Info *server, const int val) 150 137 { 138 + int scredits, in_flight; 139 + 151 140 spin_lock(&server->req_lock); 152 141 server->credits = val; 153 142 if (val == 1) 154 143 server->reconnect_instance++; 144 + scredits = server->credits; 145 + in_flight = server->in_flight; 155 146 spin_unlock(&server->req_lock); 156 147 157 148 trace_smb3_set_credits(server->CurrentMid, 158 - server->hostname, val, val); 149 + server->conn_id, server->hostname, scredits, val, in_flight); 159 150 cifs_dbg(FYI, "%s: set %u credits\n", __func__, val); 160 151 161 152 /* don't log while holding the lock */ ··· 194 171 unsigned int *num, struct cifs_credits *credits) 195 172 { 196 173 int rc = 0; 197 - unsigned int scredits; 174 + unsigned int scredits, in_flight; 198 175 199 176 spin_lock(&server->req_lock); 200 177 while (1) { ··· 231 208 DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE); 232 209 credits->instance = server->reconnect_instance; 233 210 server->credits -= credits->value; 234 - scredits = server->credits; 235 211 server->in_flight++; 236 212 if (server->in_flight > server->max_in_flight) 237 213 server->max_in_flight = server->in_flight; 238 214 break; 239 215 } 240 216 } 217 + scredits = server->credits; 218 + in_flight = server->in_flight; 241 219 spin_unlock(&server->req_lock); 242 220 243 221 trace_smb3_add_credits(server->CurrentMid, 244 - server->hostname, scredits, -(credits->value)); 222 + server->conn_id, server->hostname, scredits, -(credits->value), in_flight); 245 223 cifs_dbg(FYI, "%s: removed %u credits total=%d\n", 246 224 __func__, credits->value, scredits); 247 225 ··· 255 231 const unsigned int payload_size) 256 232 { 257 233 int new_val = DIV_ROUND_UP(payload_size, SMB2_MAX_BUFFER_SIZE); 258 - int scredits; 234 + int scredits, in_flight; 259 235 260 236 if (!credits->value || credits->value == new_val) 261 237 return 0; 262 238 263 239 if (credits->value < new_val) { 264 240 trace_smb3_too_many_credits(server->CurrentMid, 265 - server->hostname, 0, credits->value - new_val); 241 + server->conn_id, server->hostname, 0, credits->value - new_val, 0); 266 242 cifs_server_dbg(VFS, "request has less credits (%d) than required (%d)", 267 243 credits->value, new_val); 268 244 ··· 272 248 spin_lock(&server->req_lock); 273 249 274 250 if (server->reconnect_instance != credits->instance) { 251 + scredits = server->credits; 252 + in_flight = server->in_flight; 275 253 spin_unlock(&server->req_lock); 254 + 276 255 trace_smb3_reconnect_detected(server->CurrentMid, 277 - server->hostname, 0, 0); 256 + server->conn_id, server->hostname, scredits, 257 + credits->value - new_val, in_flight); 278 258 cifs_server_dbg(VFS, "trying to return %d credits to old session\n", 279 259 credits->value - new_val); 280 260 return -EAGAIN; ··· 286 258 287 259 server->credits += credits->value - new_val; 288 260 scredits = server->credits; 261 + in_flight = server->in_flight; 289 262 spin_unlock(&server->req_lock); 290 263 wake_up(&server->request_q); 291 - credits->value = new_val; 292 264 293 265 trace_smb3_add_credits(server->CurrentMid, 294 - server->hostname, scredits, credits->value - new_val); 266 + server->conn_id, server->hostname, scredits, 267 + credits->value - new_val, in_flight); 295 268 cifs_dbg(FYI, "%s: adjust added %u credits total=%d\n", 296 269 __func__, credits->value - new_val, scredits); 270 + 271 + credits->value = new_val; 297 272 298 273 return 0; 299 274 } ··· 2400 2369 smb2_is_status_pending(char *buf, struct TCP_Server_Info *server) 2401 2370 { 2402 2371 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; 2403 - int scredits; 2372 + int scredits, in_flight; 2404 2373 2405 2374 if (shdr->Status != STATUS_PENDING) 2406 2375 return false; ··· 2409 2378 spin_lock(&server->req_lock); 2410 2379 server->credits += le16_to_cpu(shdr->CreditRequest); 2411 2380 scredits = server->credits; 2381 + in_flight = server->in_flight; 2412 2382 spin_unlock(&server->req_lock); 2413 2383 wake_up(&server->request_q); 2414 2384 2415 2385 trace_smb3_add_credits(server->CurrentMid, 2416 - server->hostname, scredits, le16_to_cpu(shdr->CreditRequest)); 2386 + server->conn_id, server->hostname, scredits, 2387 + le16_to_cpu(shdr->CreditRequest), in_flight); 2417 2388 cifs_dbg(FYI, "%s: status pending add %u credits total=%d\n", 2418 2389 __func__, le16_to_cpu(shdr->CreditRequest), scredits); 2419 2390 } ··· 2449 2416 return true; 2450 2417 else 2451 2418 return false; 2419 + } 2420 + 2421 + static void 2422 + smb2_is_network_name_deleted(char *buf, struct TCP_Server_Info *server) 2423 + { 2424 + struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; 2425 + struct list_head *tmp, *tmp1; 2426 + struct cifs_ses *ses; 2427 + struct cifs_tcon *tcon; 2428 + 2429 + if (shdr->Status != STATUS_NETWORK_NAME_DELETED) 2430 + return; 2431 + 2432 + spin_lock(&cifs_tcp_ses_lock); 2433 + list_for_each(tmp, &server->smb_ses_list) { 2434 + ses = list_entry(tmp, struct cifs_ses, smb_ses_list); 2435 + list_for_each(tmp1, &ses->tcon_list) { 2436 + tcon = list_entry(tmp1, struct cifs_tcon, tcon_list); 2437 + if (tcon->tid == shdr->TreeId) { 2438 + tcon->need_reconnect = true; 2439 + spin_unlock(&cifs_tcp_ses_lock); 2440 + pr_warn_once("Server share %s deleted.\n", 2441 + tcon->treeName); 2442 + return; 2443 + } 2444 + } 2445 + } 2446 + spin_unlock(&cifs_tcp_ses_lock); 2452 2447 } 2453 2448 2454 2449 static int ··· 4666 4605 #ifdef CONFIG_CIFS_STATS2 4667 4606 mid->when_received = jiffies; 4668 4607 #endif 4608 + if (dw->server->ops->is_network_name_deleted) 4609 + dw->server->ops->is_network_name_deleted(dw->buf, 4610 + dw->server); 4611 + 4669 4612 mid->callback(mid); 4670 4613 } else { 4671 4614 spin_lock(&GlobalMid_Lock); ··· 4788 4723 rc = handle_read_data(server, *mid, buf, 4789 4724 server->vals->read_rsp_size, 4790 4725 pages, npages, len, false); 4726 + if (rc >= 0) { 4727 + if (server->ops->is_network_name_deleted) { 4728 + server->ops->is_network_name_deleted(buf, 4729 + server); 4730 + } 4731 + } 4791 4732 } 4792 4733 4793 4734 free_pages: ··· 5143 5072 .fiemap = smb3_fiemap, 5144 5073 .llseek = smb3_llseek, 5145 5074 .is_status_io_timeout = smb2_is_status_io_timeout, 5075 + .is_network_name_deleted = smb2_is_network_name_deleted, 5146 5076 }; 5147 5077 5148 5078 struct smb_version_operations smb21_operations = { ··· 5245 5173 .fiemap = smb3_fiemap, 5246 5174 .llseek = smb3_llseek, 5247 5175 .is_status_io_timeout = smb2_is_status_io_timeout, 5176 + .is_network_name_deleted = smb2_is_network_name_deleted, 5248 5177 }; 5249 5178 5250 5179 struct smb_version_operations smb30_operations = { ··· 5359 5286 .fiemap = smb3_fiemap, 5360 5287 .llseek = smb3_llseek, 5361 5288 .is_status_io_timeout = smb2_is_status_io_timeout, 5289 + .is_network_name_deleted = smb2_is_network_name_deleted, 5362 5290 }; 5363 5291 5364 5292 struct smb_version_operations smb311_operations = { ··· 5473 5399 .fiemap = smb3_fiemap, 5474 5400 .llseek = smb3_llseek, 5475 5401 .is_status_io_timeout = smb2_is_status_io_timeout, 5402 + .is_network_name_deleted = smb2_is_network_name_deleted, 5476 5403 }; 5477 5404 5478 5405 struct smb_version_values smb20_values = {
+15 -7
fs/cifs/smb2pdu.c
··· 814 814 SMB3ANY_VERSION_STRING) == 0) { 815 815 req->Dialects[0] = cpu_to_le16(SMB30_PROT_ID); 816 816 req->Dialects[1] = cpu_to_le16(SMB302_PROT_ID); 817 - req->DialectCount = cpu_to_le16(2); 818 - total_len += 4; 817 + req->Dialects[2] = cpu_to_le16(SMB311_PROT_ID); 818 + req->DialectCount = cpu_to_le16(3); 819 + total_len += 6; 819 820 } else if (strcmp(server->vals->version_string, 820 821 SMBDEFAULT_VERSION_STRING) == 0) { 821 822 req->Dialects[0] = cpu_to_le16(SMB21_PROT_ID); ··· 849 848 memcpy(req->ClientGUID, server->client_guid, 850 849 SMB2_CLIENT_GUID_SIZE); 851 850 if ((server->vals->protocol_id == SMB311_PROT_ID) || 851 + (strcmp(server->vals->version_string, 852 + SMB3ANY_VERSION_STRING) == 0) || 852 853 (strcmp(server->vals->version_string, 853 854 SMBDEFAULT_VERSION_STRING) == 0)) 854 855 assemble_neg_contexts(req, server, &total_len); ··· 886 883 cifs_server_dbg(VFS, 887 884 "SMB2.1 dialect returned but not requested\n"); 888 885 return -EIO; 886 + } else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) { 887 + /* ops set to 3.0 by default for default so update */ 888 + server->ops = &smb311_operations; 889 + server->vals = &smb311_values; 889 890 } 890 891 } else if (strcmp(server->vals->version_string, 891 892 SMBDEFAULT_VERSION_STRING) == 0) { ··· 1049 1042 SMB3ANY_VERSION_STRING) == 0) { 1050 1043 pneg_inbuf->Dialects[0] = cpu_to_le16(SMB30_PROT_ID); 1051 1044 pneg_inbuf->Dialects[1] = cpu_to_le16(SMB302_PROT_ID); 1052 - pneg_inbuf->DialectCount = cpu_to_le16(2); 1053 - /* structure is big enough for 3 dialects, sending only 2 */ 1045 + pneg_inbuf->Dialects[2] = cpu_to_le16(SMB311_PROT_ID); 1046 + pneg_inbuf->DialectCount = cpu_to_le16(3); 1047 + /* SMB 2.1 not included so subtract one dialect from len */ 1054 1048 inbuflen = sizeof(*pneg_inbuf) - 1055 - (2 * sizeof(pneg_inbuf->Dialects[0])); 1049 + (sizeof(pneg_inbuf->Dialects[0])); 1056 1050 } else if (strcmp(server->vals->version_string, 1057 1051 SMBDEFAULT_VERSION_STRING) == 0) { 1058 1052 pneg_inbuf->Dialects[0] = cpu_to_le16(SMB21_PROT_ID); ··· 1061 1053 pneg_inbuf->Dialects[2] = cpu_to_le16(SMB302_PROT_ID); 1062 1054 pneg_inbuf->Dialects[3] = cpu_to_le16(SMB311_PROT_ID); 1063 1055 pneg_inbuf->DialectCount = cpu_to_le16(4); 1064 - /* structure is big enough for 3 dialects */ 1056 + /* structure is big enough for 4 dialects */ 1065 1057 inbuflen = sizeof(*pneg_inbuf); 1066 1058 } else { 1067 1059 /* otherwise specific dialect was requested */ ··· 1261 1253 cifs_ses_server(sess_data->ses), 1262 1254 &rqst, 1263 1255 &sess_data->buf0_type, 1264 - CIFS_LOG_ERROR | CIFS_NEG_OP, &rsp_iov); 1256 + CIFS_LOG_ERROR | CIFS_SESS_OP, &rsp_iov); 1265 1257 cifs_small_buf_release(sess_data->iov[0].iov_base); 1266 1258 memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec)); 1267 1259
+26 -10
fs/cifs/trace.h
··· 851 851 852 852 DECLARE_EVENT_CLASS(smb3_reconnect_class, 853 853 TP_PROTO(__u64 currmid, 854 + __u64 conn_id, 854 855 char *hostname), 855 - TP_ARGS(currmid, hostname), 856 + TP_ARGS(currmid, conn_id, hostname), 856 857 TP_STRUCT__entry( 857 858 __field(__u64, currmid) 859 + __field(__u64, conn_id) 858 860 __field(char *, hostname) 859 861 ), 860 862 TP_fast_assign( 861 863 __entry->currmid = currmid; 864 + __entry->conn_id = conn_id; 862 865 __entry->hostname = hostname; 863 866 ), 864 - TP_printk("server=%s current_mid=0x%llx", 867 + TP_printk("conn_id=0x%llx server=%s current_mid=%llu", 868 + __entry->conn_id, 865 869 __entry->hostname, 866 870 __entry->currmid) 867 871 ) ··· 873 869 #define DEFINE_SMB3_RECONNECT_EVENT(name) \ 874 870 DEFINE_EVENT(smb3_reconnect_class, smb3_##name, \ 875 871 TP_PROTO(__u64 currmid, \ 876 - char *hostname), \ 877 - TP_ARGS(currmid, hostname)) 872 + __u64 conn_id, \ 873 + char *hostname), \ 874 + TP_ARGS(currmid, conn_id, hostname)) 878 875 879 876 DEFINE_SMB3_RECONNECT_EVENT(reconnect); 880 877 DEFINE_SMB3_RECONNECT_EVENT(partial_send_reconnect); 881 878 882 879 DECLARE_EVENT_CLASS(smb3_credit_class, 883 880 TP_PROTO(__u64 currmid, 881 + __u64 conn_id, 884 882 char *hostname, 885 883 int credits, 886 - int credits_to_add), 887 - TP_ARGS(currmid, hostname, credits, credits_to_add), 884 + int credits_to_add, 885 + int in_flight), 886 + TP_ARGS(currmid, conn_id, hostname, credits, credits_to_add, in_flight), 888 887 TP_STRUCT__entry( 889 888 __field(__u64, currmid) 889 + __field(__u64, conn_id) 890 890 __field(char *, hostname) 891 891 __field(int, credits) 892 892 __field(int, credits_to_add) 893 + __field(int, in_flight) 893 894 ), 894 895 TP_fast_assign( 895 896 __entry->currmid = currmid; 897 + __entry->conn_id = conn_id; 896 898 __entry->hostname = hostname; 897 899 __entry->credits = credits; 898 900 __entry->credits_to_add = credits_to_add; 901 + __entry->in_flight = in_flight; 899 902 ), 900 - TP_printk("server=%s current_mid=0x%llx credits=%d credits_to_add=%d", 903 + TP_printk("conn_id=0x%llx server=%s current_mid=%llu " 904 + "credits=%d credit_change=%d in_flight=%d", 905 + __entry->conn_id, 901 906 __entry->hostname, 902 907 __entry->currmid, 903 908 __entry->credits, 904 - __entry->credits_to_add) 909 + __entry->credits_to_add, 910 + __entry->in_flight) 905 911 ) 906 912 907 913 #define DEFINE_SMB3_CREDIT_EVENT(name) \ 908 914 DEFINE_EVENT(smb3_credit_class, smb3_##name, \ 909 915 TP_PROTO(__u64 currmid, \ 916 + __u64 conn_id, \ 910 917 char *hostname, \ 911 918 int credits, \ 912 - int credits_to_add), \ 913 - TP_ARGS(currmid, hostname, credits, credits_to_add)) 919 + int credits_to_add, \ 920 + int in_flight), \ 921 + TP_ARGS(currmid, conn_id, hostname, credits, credits_to_add, in_flight)) 914 922 915 923 DEFINE_SMB3_CREDIT_EVENT(reconnect_with_invalid_credits); 916 924 DEFINE_SMB3_CREDIT_EVENT(reconnect_detected);
+44 -19
fs/cifs/transport.c
··· 445 445 */ 446 446 server->tcpStatus = CifsNeedReconnect; 447 447 trace_smb3_partial_send_reconnect(server->CurrentMid, 448 - server->hostname); 448 + server->conn_id, server->hostname); 449 449 } 450 450 smbd_done: 451 451 if (rc < 0 && rc != -EINTR) ··· 527 527 int *credits; 528 528 int optype; 529 529 long int t; 530 - int scredits = server->credits; 530 + int scredits, in_flight; 531 531 532 532 if (timeout < 0) 533 533 t = MAX_JIFFY_OFFSET; ··· 551 551 server->max_in_flight = server->in_flight; 552 552 *credits -= 1; 553 553 *instance = server->reconnect_instance; 554 + scredits = *credits; 555 + in_flight = server->in_flight; 554 556 spin_unlock(&server->req_lock); 557 + 558 + trace_smb3_add_credits(server->CurrentMid, 559 + server->conn_id, server->hostname, scredits, -1, in_flight); 560 + cifs_dbg(FYI, "%s: remove %u credits total=%d\n", 561 + __func__, 1, scredits); 562 + 555 563 return 0; 556 564 } 557 565 558 566 while (1) { 559 567 if (*credits < num_credits) { 568 + scredits = *credits; 560 569 spin_unlock(&server->req_lock); 570 + 561 571 cifs_num_waiters_inc(server); 562 572 rc = wait_event_killable_timeout(server->request_q, 563 573 has_credits(server, credits, num_credits), t); 564 574 cifs_num_waiters_dec(server); 565 575 if (!rc) { 576 + spin_lock(&server->req_lock); 577 + scredits = *credits; 578 + in_flight = server->in_flight; 579 + spin_unlock(&server->req_lock); 580 + 566 581 trace_smb3_credit_timeout(server->CurrentMid, 567 - server->hostname, num_credits, 0); 582 + server->conn_id, server->hostname, scredits, 583 + num_credits, in_flight); 568 584 cifs_server_dbg(VFS, "wait timed out after %d ms\n", 569 - timeout); 570 - return -ENOTSUPP; 585 + timeout); 586 + return -EBUSY; 571 587 } 572 588 if (rc == -ERESTARTSYS) 573 589 return -ERESTARTSYS; ··· 611 595 server->in_flight > 2 * MAX_COMPOUND && 612 596 *credits <= MAX_COMPOUND) { 613 597 spin_unlock(&server->req_lock); 598 + 614 599 cifs_num_waiters_inc(server); 615 600 rc = wait_event_killable_timeout( 616 601 server->request_q, ··· 620 603 t); 621 604 cifs_num_waiters_dec(server); 622 605 if (!rc) { 606 + spin_lock(&server->req_lock); 607 + scredits = *credits; 608 + in_flight = server->in_flight; 609 + spin_unlock(&server->req_lock); 610 + 623 611 trace_smb3_credit_timeout( 624 - server->CurrentMid, 625 - server->hostname, num_credits, 626 - 0); 612 + server->CurrentMid, 613 + server->conn_id, server->hostname, 614 + scredits, num_credits, in_flight); 627 615 cifs_server_dbg(VFS, "wait timed out after %d ms\n", 628 - timeout); 629 - return -ENOTSUPP; 616 + timeout); 617 + return -EBUSY; 630 618 } 631 619 if (rc == -ERESTARTSYS) 632 620 return -ERESTARTSYS; ··· 647 625 /* update # of requests on the wire to server */ 648 626 if ((flags & CIFS_TIMEOUT_MASK) != CIFS_BLOCKING_OP) { 649 627 *credits -= num_credits; 650 - scredits = *credits; 651 628 server->in_flight += num_credits; 652 629 if (server->in_flight > server->max_in_flight) 653 630 server->max_in_flight = server->in_flight; 654 631 *instance = server->reconnect_instance; 655 632 } 633 + scredits = *credits; 634 + in_flight = server->in_flight; 656 635 spin_unlock(&server->req_lock); 657 636 658 637 trace_smb3_add_credits(server->CurrentMid, 659 - server->hostname, scredits, -(num_credits)); 638 + server->conn_id, server->hostname, scredits, 639 + -(num_credits), in_flight); 660 640 cifs_dbg(FYI, "%s: remove %u credits total=%d\n", 661 641 __func__, num_credits, scredits); 662 642 break; ··· 680 656 const int flags, unsigned int *instance) 681 657 { 682 658 int *credits; 683 - int scredits, sin_flight; 659 + int scredits, in_flight; 684 660 685 661 credits = server->ops->get_credits_field(server, flags & CIFS_OP_MASK); 686 662 687 663 spin_lock(&server->req_lock); 688 664 scredits = *credits; 689 - sin_flight = server->in_flight; 665 + in_flight = server->in_flight; 690 666 691 667 if (*credits < num) { 692 668 /* ··· 708 684 if (server->in_flight == 0) { 709 685 spin_unlock(&server->req_lock); 710 686 trace_smb3_insufficient_credits(server->CurrentMid, 711 - server->hostname, scredits, sin_flight); 687 + server->conn_id, server->hostname, scredits, 688 + num, in_flight); 712 689 cifs_dbg(FYI, "%s: %d requests in flight, needed %d total=%d\n", 713 - __func__, sin_flight, num, scredits); 714 - return -ENOTSUPP; 690 + __func__, in_flight, num, scredits); 691 + return -EDEADLK; 715 692 } 716 693 } 717 694 spin_unlock(&server->req_lock); ··· 1196 1171 /* 1197 1172 * Compounding is never used during session establish. 1198 1173 */ 1199 - if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) 1174 + if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) 1200 1175 smb311_update_preauth_hash(ses, rqst[0].rq_iov, 1201 1176 rqst[0].rq_nvec); 1202 1177 ··· 1261 1236 /* 1262 1237 * Compounding is never used during session establish. 1263 1238 */ 1264 - if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) { 1239 + if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) { 1265 1240 struct kvec iov = { 1266 1241 .iov_base = resp_iov[0].iov_base, 1267 1242 .iov_len = resp_iov[0].iov_len