Commit c19798af authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents efba6d3a 8369dfd7
...@@ -5,10 +5,10 @@ Authors ...@@ -5,10 +5,10 @@ Authors
Original Author Original Author
--------------- ---------------
Steve French (sfrench@samba.org) Steve French (smfrench@gmail.com, sfrench@samba.org)
The author wishes to express his appreciation and thanks to: The author wishes to express his appreciation and thanks to:
Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS Andrew Tridgell (Samba team) for his early suggestions about SMB/CIFS VFS
improvements. Thanks to IBM for allowing me time and test resources to pursue improvements. Thanks to IBM for allowing me time and test resources to pursue
this project, to Jim McDonough from IBM (and the Samba Team) for his help, to this project, to Jim McDonough from IBM (and the Samba Team) for his help, to
the IBM Linux JFS team for explaining many esoteric Linux filesystem features. the IBM Linux JFS team for explaining many esoteric Linux filesystem features.
...@@ -51,7 +51,7 @@ Patch Contributors ...@@ -51,7 +51,7 @@ Patch Contributors
- Ronnie Sahlberg (for SMB3 xattr work, bug fixes, and lots of great work on compounding) - Ronnie Sahlberg (for SMB3 xattr work, bug fixes, and lots of great work on compounding)
- Shirish Pargaonkar (for many ACL patches over the years) - Shirish Pargaonkar (for many ACL patches over the years)
- Sachin Prabhu (many bug fixes, including for reconnect, copy offload and security) - Sachin Prabhu (many bug fixes, including for reconnect, copy offload and security)
- Paulo Alcantara - Paulo Alcantara (for some excellent work in DFS, and in booting from SMB3)
- Long Li (some great work on RDMA, SMB Direct) - Long Li (some great work on RDMA, SMB Direct)
......
...@@ -3,6 +3,7 @@ Changes ...@@ -3,6 +3,7 @@ Changes
======= =======
See https://wiki.samba.org/index.php/LinuxCIFSKernel for summary See https://wiki.samba.org/index.php/LinuxCIFSKernel for summary
information (that may be easier to read than parsing the output of information about fixes/improvements to CIFS/SMB2/SMB3 support (changes
"git log fs/cifs") about fixes/improvements to CIFS/SMB2/SMB3 support (changes
to cifs.ko module) by kernel version (and cifs internal module version). to cifs.ko module) by kernel version (and cifs internal module version).
This may be easier to read than parsing the output of "git log fs/cifs"
by release.
...@@ -7,19 +7,19 @@ Introduction ...@@ -7,19 +7,19 @@ Introduction
protocol which was the successor to the Server Message Block protocol which was the successor to the Server Message Block
(SMB) protocol, the native file sharing mechanism for most early (SMB) protocol, the native file sharing mechanism for most early
PC operating systems. New and improved versions of CIFS are now PC operating systems. New and improved versions of CIFS are now
called SMB2 and SMB3. Use of SMB3 (and later, including SMB3.1.1) called SMB2 and SMB3. Use of SMB3 (and later, including SMB3.1.1
is strongly preferred over using older dialects like CIFS due to the most current dialect) is strongly preferred over using older
security reasons. All modern dialects, including the most recent, dialects like CIFS due to security reasons. All modern dialects,
SMB3.1.1 are supported by the CIFS VFS module. The SMB3 protocol including the most recent, SMB3.1.1, are supported by the CIFS VFS
is implemented and supported by all major file servers module. The SMB3 protocol is implemented and supported by all major
such as all modern versions of Windows (including Windows 2016 file servers such as Windows (including Windows 2019 Server), as
Server), as well as by Samba (which provides excellent well as by Samba (which provides excellent CIFS/SMB2/SMB3 server
CIFS/SMB2/SMB3 server support and tools for Linux and many other support and tools for Linux and many other operating systems).
operating systems). Apple systems also support SMB3 well, as Apple systems also support SMB3 well, as do most Network Attached
do most Network Attached Storage vendors, so this network Storage vendors, so this network filesystem client can mount to a
filesystem client can mount to a wide variety of systems. wide variety of systems. It also supports mounting to the cloud
It also supports mounting to the cloud (for example (for example Microsoft Azure), including the necessary security
Microsoft Azure), including the necessary security features. features.
The intent of this module is to provide the most advanced network The intent of this module is to provide the most advanced network
file system function for SMB3 compliant servers, including advanced file system function for SMB3 compliant servers, including advanced
...@@ -27,8 +27,8 @@ Introduction ...@@ -27,8 +27,8 @@ Introduction
POSIX compliance, secure per-user session establishment, encryption, POSIX compliance, secure per-user session establishment, encryption,
high performance safe distributed caching (leases/oplocks), optional packet high performance safe distributed caching (leases/oplocks), optional packet
signing, large files, Unicode support and other internationalization signing, large files, Unicode support and other internationalization
improvements. Since both Samba server and this filesystem client support improvements. Since both Samba server and this filesystem client support the
the CIFS Unix extensions (and in the future SMB3 POSIX extensions), CIFS Unix extensions, and the Linux client also suppors SMB3 POSIX extensions,
the combination can provide a reasonable alternative to other network and the combination can provide a reasonable alternative to other network and
cluster file systems for fileserving in some Linux to Linux environments, cluster file systems for fileserving in some Linux to Linux environments,
not just in Linux to Windows (or Linux to Mac) environments. not just in Linux to Windows (or Linux to Mac) environments.
......
...@@ -13,24 +13,26 @@ is a partial list of the known problems and missing features: ...@@ -13,24 +13,26 @@ is a partial list of the known problems and missing features:
a) SMB3 (and SMB3.1.1) missing optional features: a) SMB3 (and SMB3.1.1) missing optional features:
- multichannel (started), integration with RDMA - multichannel (partially integrated), integration of multichannel with RDMA
- directory leases (improved metadata caching), started (root dir only) - directory leases (improved metadata caching). Currently only implemented for root dir
- T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl - T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl
currently the only two server side copy mechanisms supported) currently the only two server side copy mechanisms supported)
b) improved sparse file support (fiemap and SEEK_HOLE are implemented b) improved sparse file support (fiemap and SEEK_HOLE are implemented
but additional features would be supportable by the protocol). but additional features would be supportable by the protocol such
as FALLOC_FL_COLLAPSE_RANGE and FALLOC_FL_INSERT_RANGE)
c) Directory entry caching relies on a 1 second timer, rather than c) Directory entry caching relies on a 1 second timer, rather than
using Directory Leases, currently only the root file handle is cached longer using Directory Leases, currently only the root file handle is cached longer
by leveraging Directory Leases
d) quota support (needs minor kernel change since quota calls d) quota support (needs minor kernel change since quota calls otherwise
to make it to network filesystems or deviceless filesystems) won't make it to network filesystems or deviceless filesystems).
e) Additional use cases can be optimized to use "compounding" (e.g. e) Additional use cases can be optimized to use "compounding" (e.g.
open/query/close and open/setinfo/close) to reduce the number of open/query/close and open/setinfo/close) to reduce the number of
roundtrips to the server and improve performance. Various cases roundtrips to the server and improve performance. Various cases
(stat, statfs, create, unlink, mkdir) already have been improved by (stat, statfs, create, unlink, mkdir, xattrs) already have been improved by
using compounding but more can be done. In addition we could using compounding but more can be done. In addition we could
significantly reduce redundant opens by using deferred close (with significantly reduce redundant opens by using deferred close (with
handle caching leases) and better using reference counters on file handle caching leases) and better using reference counters on file
...@@ -60,7 +62,9 @@ k) Add tools to take advantage of more smb3 specific ioctls and features ...@@ -60,7 +62,9 @@ k) Add tools to take advantage of more smb3 specific ioctls and features
metadata attributes easier from tools (e.g. extending what was done metadata attributes easier from tools (e.g. extending what was done
in smb-info tool). in smb-info tool).
l) encrypted file support l) encrypted file support (currently the attribute showing the file is
encrypted on the server is reported, but changing the attribute is not
supported).
m) improved stats gathering tools (perhaps integration with nfsometer?) m) improved stats gathering tools (perhaps integration with nfsometer?)
to extend and make easier to use what is currently in /proc/fs/cifs/Stats to extend and make easier to use what is currently in /proc/fs/cifs/Stats
...@@ -69,14 +73,13 @@ n) Add support for claims based ACLs ("DAC") ...@@ -69,14 +73,13 @@ n) Add support for claims based ACLs ("DAC")
o) mount helper GUI (to simplify the various configuration options on mount) o) mount helper GUI (to simplify the various configuration options on mount)
p) Add support for witness protocol (perhaps ioctl to cifs.ko from user space p) Expand support for witness protocol to allow for notification of share
tool listening on witness protocol RPC) to allow for notification of share move, and server network adapter changes. Currently only notifications by
move, server failover, and server adapter changes. And also improve other the witness protocol for server move is supported by the Linux client.
failover scenarios, e.g. when client knows multiple DFS entries point to
different servers, and the server we are connected to has gone down.
q) Allow mount.cifs to be more verbose in reporting errors with dialect q) Allow mount.cifs to be more verbose in reporting errors with dialect
or unsupported feature errors. or unsupported feature errors. This would now be easier due to the
implementation of the new mount API.
r) updating cifs documentation, and user guide. r) updating cifs documentation, and user guide.
...@@ -87,11 +90,10 @@ t) split cifs and smb3 support into separate modules so legacy (and less ...@@ -87,11 +90,10 @@ t) split cifs and smb3 support into separate modules so legacy (and less
secure) CIFS dialect can be disabled in environments that don't need it secure) CIFS dialect can be disabled in environments that don't need it
and simplify the code. and simplify the code.
v) POSIX Extensions for SMB3.1.1 (started, create and mkdir support added v) Additional testing of POSIX Extensions for SMB3.1.1
so far).
w) Add support for additional strong encryption types, and additional spnego w) Add support for additional strong encryption types, and additional spnego
authentication mechanisms (see MS-SMB2) authentication mechanisms (see MS-SMB2). GCM-256 is now partially implemented.
x) Finish support for SMB3.1.1 compression x) Finish support for SMB3.1.1 compression
......
...@@ -83,7 +83,7 @@ and encrypted shares and stronger signing and authentication algorithms. ...@@ -83,7 +83,7 @@ and encrypted shares and stronger signing and authentication algorithms.
There are additional mount options that may be helpful for SMB3 to get There are additional mount options that may be helpful for SMB3 to get
improved POSIX behavior (NB: can use vers=3.0 to force only SMB3, never 2.1): improved POSIX behavior (NB: can use vers=3.0 to force only SMB3, never 2.1):
``mfsymlinks`` and ``cifsacl`` and ``idsfromsid`` ``mfsymlinks`` and either ``cifsacl`` or ``modefromsid`` (usually with ``idsfromsid``)
Allowing User Mounts Allowing User Mounts
==================== ====================
......
...@@ -133,11 +133,12 @@ cifs_dump_channel(struct seq_file *m, int i, struct cifs_chan *chan) ...@@ -133,11 +133,12 @@ cifs_dump_channel(struct seq_file *m, int i, struct cifs_chan *chan)
{ {
struct TCP_Server_Info *server = chan->server; struct TCP_Server_Info *server = chan->server;
seq_printf(m, "\t\tChannel %d Number of credits: %d Dialect 0x%x " seq_printf(m, "\n\n\t\tChannel: %d ConnectionId: 0x%llx"
"TCP status: %d Instance: %d Local Users To Server: %d " "\n\t\tNumber of credits: %d Dialect 0x%x"
"SecMode: 0x%x Req On Wire: %d In Send: %d " "\n\t\tTCP status: %d Instance: %d"
"In MaxReq Wait: %d\n", "\n\t\tLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d"
i+1, "\n\t\tIn Send: %d In MaxReq Wait: %d",
i+1, server->conn_id,
server->credits, server->credits,
server->dialect, server->dialect,
server->tcpStatus, server->tcpStatus,
...@@ -227,7 +228,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) ...@@ -227,7 +228,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
struct TCP_Server_Info *server; struct TCP_Server_Info *server;
struct cifs_ses *ses; struct cifs_ses *ses;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
int i, j; int c, i, j;
seq_puts(m, seq_puts(m,
"Display Internal CIFS Data Structures for Debugging\n" "Display Internal CIFS Data Structures for Debugging\n"
...@@ -275,14 +276,25 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) ...@@ -275,14 +276,25 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
seq_putc(m, '\n'); seq_putc(m, '\n');
seq_printf(m, "CIFSMaxBufSize: %d\n", CIFSMaxBufSize); seq_printf(m, "CIFSMaxBufSize: %d\n", CIFSMaxBufSize);
seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid); seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
seq_printf(m, "Servers:");
i = 0; seq_printf(m, "\nServers: ");
c = 0;
spin_lock(&cifs_tcp_ses_lock); spin_lock(&cifs_tcp_ses_lock);
list_for_each(tmp1, &cifs_tcp_ses_list) { list_for_each(tmp1, &cifs_tcp_ses_list) {
server = list_entry(tmp1, struct TCP_Server_Info, server = list_entry(tmp1, struct TCP_Server_Info,
tcp_ses_list); tcp_ses_list);
/* channel info will be printed as a part of sessions below */
if (server->is_channel)
continue;
c++;
seq_printf(m, "\n%d) ConnectionId: 0x%llx ",
c, server->conn_id);
if (server->hostname)
seq_printf(m, "Hostname: %s ", server->hostname);
#ifdef CONFIG_CIFS_SMB_DIRECT #ifdef CONFIG_CIFS_SMB_DIRECT
if (!server->rdma) if (!server->rdma)
goto skip_rdma; goto skip_rdma;
...@@ -362,46 +374,48 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) ...@@ -362,46 +374,48 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
if (server->posix_ext_supported) if (server->posix_ext_supported)
seq_printf(m, " posix"); seq_printf(m, " posix");
i++; if (server->rdma)
seq_printf(m, "\nRDMA ");
seq_printf(m, "\nTCP status: %d Instance: %d"
"\nLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d",
server->tcpStatus,
server->reconnect_instance,
server->srv_count,
server->sec_mode, in_flight(server));
seq_printf(m, "\nIn Send: %d In MaxReq Wait: %d",
atomic_read(&server->in_send),
atomic_read(&server->num_waiters));
seq_printf(m, "\n\n\tSessions: ");
i = 0;
list_for_each(tmp2, &server->smb_ses_list) { list_for_each(tmp2, &server->smb_ses_list) {
ses = list_entry(tmp2, struct cifs_ses, ses = list_entry(tmp2, struct cifs_ses,
smb_ses_list); smb_ses_list);
i++;
if ((ses->serverDomain == NULL) || if ((ses->serverDomain == NULL) ||
(ses->serverOS == NULL) || (ses->serverOS == NULL) ||
(ses->serverNOS == NULL)) { (ses->serverNOS == NULL)) {
seq_printf(m, "\n%d) Name: %s Uses: %d Capability: 0x%x\tSession Status: %d ", seq_printf(m, "\n\t%d) Address: %s Uses: %d Capability: 0x%x\tSession Status: %d ",
i, ses->serverName, ses->ses_count, i, ses->ip_addr, ses->ses_count,
ses->capabilities, ses->status); ses->capabilities, ses->status);
if (ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST) if (ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST)
seq_printf(m, "Guest\t"); seq_printf(m, "Guest ");
else if (ses->session_flags & SMB2_SESSION_FLAG_IS_NULL) else if (ses->session_flags & SMB2_SESSION_FLAG_IS_NULL)
seq_printf(m, "Anonymous\t"); seq_printf(m, "Anonymous ");
} else { } else {
seq_printf(m, seq_printf(m,
"\n%d) Name: %s Domain: %s Uses: %d OS:" "\n\t%d) Name: %s Domain: %s Uses: %d OS: %s "
" %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB" "\n\tNOS: %s\tCapability: 0x%x"
" session status: %d ", "\n\tSMB session status: %d ",
i, ses->serverName, ses->serverDomain, i, ses->ip_addr, ses->serverDomain,
ses->ses_count, ses->serverOS, ses->serverNOS, ses->ses_count, ses->serverOS, ses->serverNOS,
ses->capabilities, ses->status); ses->capabilities, ses->status);
} }
seq_printf(m,"Security type: %s\n", seq_printf(m, "\n\tSecurity type: %s ",
get_security_type_str(server->ops->select_sectype(server, ses->sectype))); get_security_type_str(server->ops->select_sectype(server, ses->sectype)));
if (server->rdma)
seq_printf(m, "RDMA\n\t");
seq_printf(m, "TCP status: %d Instance: %d\n\tLocal Users To "
"Server: %d SecMode: 0x%x Req On Wire: %d",
server->tcpStatus,
server->reconnect_instance,
server->srv_count,
server->sec_mode, in_flight(server));
seq_printf(m, " In Send: %d In MaxReq Wait: %d",
atomic_read(&server->in_send),
atomic_read(&server->num_waiters));
/* dump session id helpful for use with network trace */ /* dump session id helpful for use with network trace */
seq_printf(m, " SessionId: 0x%llx", ses->Suid); seq_printf(m, " SessionId: 0x%llx", ses->Suid);
if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
...@@ -414,13 +428,13 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) ...@@ -414,13 +428,13 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
from_kuid(&init_user_ns, ses->cred_uid)); from_kuid(&init_user_ns, ses->cred_uid));
if (ses->chan_count > 1) { if (ses->chan_count > 1) {
seq_printf(m, "\n\n\tExtra Channels: %zu\n", seq_printf(m, "\n\n\tExtra Channels: %zu ",
ses->chan_count-1); ses->chan_count-1);
for (j = 1; j < ses->chan_count; j++) for (j = 1; j < ses->chan_count; j++)
cifs_dump_channel(m, j, &ses->chans[j]); cifs_dump_channel(m, j, &ses->chans[j]);
} }
seq_puts(m, "\n\n\tShares:"); seq_puts(m, "\n\n\tShares: ");
j = 0; j = 0;
seq_printf(m, "\n\t%d) IPC: ", j); seq_printf(m, "\n\t%d) IPC: ", j);
...@@ -437,38 +451,43 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) ...@@ -437,38 +451,43 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
cifs_debug_tcon(m, tcon); cifs_debug_tcon(m, tcon);
} }
seq_puts(m, "\n\tMIDs:\n");
spin_lock(&GlobalMid_Lock);
list_for_each(tmp3, &server->pending_mid_q) {
mid_entry = list_entry(tmp3, struct mid_q_entry,
qhead);
seq_printf(m, "\tState: %d com: %d pid:"
" %d cbdata: %p mid %llu\n",
mid_entry->mid_state,
le16_to_cpu(mid_entry->command),
mid_entry->pid,
mid_entry->callback_data,
mid_entry->mid);
}
spin_unlock(&GlobalMid_Lock);
spin_lock(&ses->iface_lock); spin_lock(&ses->iface_lock);
if (ses->iface_count) if (ses->iface_count)
seq_printf(m, "\n\tServer interfaces: %zu\n", seq_printf(m, "\n\n\tServer interfaces: %zu",
ses->iface_count); ses->iface_count);
for (j = 0; j < ses->iface_count; j++) { for (j = 0; j < ses->iface_count; j++) {
struct cifs_server_iface *iface; struct cifs_server_iface *iface;
iface = &ses->iface_list[j]; iface = &ses->iface_list[j];
seq_printf(m, "\t%d)", j); seq_printf(m, "\n\t%d)", j+1);
cifs_dump_iface(m, iface); cifs_dump_iface(m, iface);
if (is_ses_using_iface(ses, iface)) if (is_ses_using_iface(ses, iface))
seq_puts(m, "\t\t[CONNECTED]\n"); seq_puts(m, "\t\t[CONNECTED]\n");
} }
spin_unlock(&ses->iface_lock); spin_unlock(&ses->iface_lock);
} }
if (i == 0)
seq_printf(m, "\n\t\t[NONE]");
seq_puts(m, "\n\n\tMIDs: ");
spin_lock(&GlobalMid_Lock);
list_for_each(tmp3, &server->pending_mid_q) {
mid_entry = list_entry(tmp3, struct mid_q_entry,
qhead);
seq_printf(m, "\n\tState: %d com: %d pid:"
" %d cbdata: %p mid %llu\n",
mid_entry->mid_state,
le16_to_cpu(mid_entry->command),
mid_entry->pid,
mid_entry->callback_data,
mid_entry->mid);
}
spin_unlock(&GlobalMid_Lock);
seq_printf(m, "\n--\n");
} }
if (c == 0)
seq_printf(m, "\n\t[NONE]");
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
seq_putc(m, '\n'); seq_putc(m, '\n');
......
...@@ -272,7 +272,7 @@ static struct cifs_swn_reg *cifs_find_swn_reg(struct cifs_tcon *tcon) ...@@ -272,7 +272,7 @@ static struct cifs_swn_reg *cifs_find_swn_reg(struct cifs_tcon *tcon)
if (IS_ERR(share_name)) { if (IS_ERR(share_name)) {
int ret; int ret;
ret = PTR_ERR(net_name); ret = PTR_ERR(share_name);
cifs_dbg(VFS, "%s: failed to extract share name from target '%s': %d\n", cifs_dbg(VFS, "%s: failed to extract share name from target '%s': %d\n",
__func__, tcon->treeName, ret); __func__, tcon->treeName, ret);
kfree(net_name); kfree(net_name);
......
This diff is collapsed.
...@@ -31,8 +31,8 @@ ...@@ -31,8 +31,8 @@
#define EXEC_BIT 0x1 #define EXEC_BIT 0x1
#define ACL_OWNER_MASK 0700 #define ACL_OWNER_MASK 0700
#define ACL_GROUP_MASK 0770 #define ACL_GROUP_MASK 0070
#define ACL_EVERYONE_MASK 0777 #define ACL_EVERYONE_MASK 0007
#define UBITSHIFT 6 #define UBITSHIFT 6
#define GBITSHIFT 3 #define GBITSHIFT 3
......
...@@ -568,15 +568,15 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, ...@@ -568,15 +568,15 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
return rc; return rc;
} }
} else { } else {
/* We use ses->serverName if no domain name available */ /* We use ses->ip_addr if no domain name available */
len = strlen(ses->serverName); len = strlen(ses->ip_addr);
server = kmalloc(2 + (len * 2), GFP_KERNEL); server = kmalloc(2 + (len * 2), GFP_KERNEL);
if (server == NULL) { if (server == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
return rc; return rc;
} }
len = cifs_strtoUTF16((__le16 *)server, ses->serverName, len, len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len,
nls_cp); nls_cp);
rc = rc =
crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
......
...@@ -638,8 +638,18 @@ cifs_show_options(struct seq_file *s, struct dentry *root) ...@@ -638,8 +638,18 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
seq_printf(s, ",snapshot=%llu", tcon->snapshot_time); seq_printf(s, ",snapshot=%llu", tcon->snapshot_time);
if (tcon->handle_timeout) if (tcon->handle_timeout)
seq_printf(s, ",handletimeout=%u", tcon->handle_timeout); seq_printf(s, ",handletimeout=%u", tcon->handle_timeout);
/* convert actimeo and display it in seconds */
seq_printf(s, ",actimeo=%lu", cifs_sb->ctx->actimeo / HZ); /*
* Display file and directory attribute timeout in seconds.
* If file and directory attribute timeout the same then actimeo
* was likely specified on mount
*/
if (cifs_sb->ctx->acdirmax == cifs_sb->ctx->acregmax)
seq_printf(s, ",actimeo=%lu", cifs_sb->ctx->acregmax / HZ);
else {
seq_printf(s, ",acdirmax=%lu", cifs_sb->ctx->acdirmax / HZ);
seq_printf(s, ",acregmax=%lu", cifs_sb->ctx->acregmax / HZ);
}
if (tcon->ses->chan_max > 1) if (tcon->ses->chan_max > 1)
seq_printf(s, ",multichannel,max_channels=%zu", seq_printf(s, ",multichannel,max_channels=%zu",
...@@ -1526,6 +1536,7 @@ init_cifs(void) ...@@ -1526,6 +1536,7 @@ init_cifs(void)
*/ */
atomic_set(&sesInfoAllocCount, 0); atomic_set(&sesInfoAllocCount, 0);
atomic_set(&tconInfoAllocCount, 0); atomic_set(&tconInfoAllocCount, 0);
atomic_set(&tcpSesNextId, 0);
atomic_set(&tcpSesAllocCount, 0); atomic_set(&tcpSesAllocCount, 0);
atomic_set(&tcpSesReconnectCount, 0); atomic_set(&tcpSesReconnectCount, 0);
atomic_set(&tconInfoReconnectCount, 0); atomic_set(&tconInfoReconnectCount, 0);
......
...@@ -165,5 +165,5 @@ extern struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type, ...@@ -165,5 +165,5 @@ extern struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type,
extern const struct export_operations cifs_export_ops; extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */ #endif /* CONFIG_CIFS_NFSD_EXPORT */
#define CIFS_VERSION "2.30" #define CIFS_VERSION "2.31"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/in.h> #include <linux/in.h>
#include <linux/in6.h> #include <linux/in6.h>
#include <linux/inet.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mempool.h> #include <linux/mempool.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
...@@ -504,6 +505,8 @@ struct smb_version_operations { ...@@ -504,6 +505,8 @@ struct smb_version_operations {
loff_t (*llseek)(struct file *, struct cifs_tcon *, loff_t, int); loff_t (*llseek)(struct file *, struct cifs_tcon *, loff_t, int);
/* Check for STATUS_IO_TIMEOUT */ /* Check for STATUS_IO_TIMEOUT */
bool (*is_status_io_timeout)(char *buf); bool (*is_status_io_timeout)(char *buf);
/* Check for STATUS_NETWORK_NAME_DELETED */
void (*is_network_name_deleted)(char *buf, struct TCP_Server_Info *srv);
}; };
struct smb_version_values { struct smb_version_values {
...@@ -577,6 +580,7 @@ inc_rfc1001_len(void *buf, int count) ...@@ -577,6 +580,7 @@ inc_rfc1001_len(void *buf, int count)
struct TCP_Server_Info { struct TCP_Server_Info {
struct list_head tcp_ses_list; struct list_head tcp_ses_list;
struct list_head smb_ses_list; struct list_head smb_ses_list;
__u64 conn_id; /* connection identifier (useful for debugging) */
int srv_count; /* reference counter */ int srv_count; /* reference counter */
/* 15 character server name + 0x20 16th byte indicating type = srv */ /* 15 character server name + 0x20 16th byte indicating type = srv */
char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
...@@ -901,7 +905,7 @@ struct cifs_ses { ...@@ -901,7 +905,7 @@ struct cifs_ses {
kuid_t linux_uid; /* overriding owner of files on the mount */ kuid_t linux_uid; /* overriding owner of files on the mount */
kuid_t cred_uid; /* owner of credentials */ kuid_t cred_uid; /* owner of credentials */
unsigned int capabilities; unsigned int capabilities;
char serverName[SERVER_NAME_LEN_WITH_NULL]; char ip_addr[INET6_ADDRSTRLEN + 1]; /* Max ipv6 (or v4) addr string len */
char *user_name; /* must not be null except during init of sess char *user_name; /* must not be null except during init of sess
and after mount option parsing we fill it */ and after mount option parsing we fill it */
char *domainName; char *domainName;
...@@ -1704,7 +1708,9 @@ static inline bool is_retryable_error(int error) ...@@ -1704,7 +1708,9 @@ static inline bool is_retryable_error(int error)
#define CIFS_ECHO_OP 0x080 /* echo request */ #define CIFS_ECHO_OP 0x080 /* echo request */
#define CIFS_OBREAK_OP 0x0100 /* oplock break request */ #define CIFS_OBREAK_OP 0x0100 /* oplock break request */
#define CIFS_NEG_OP 0x0200 /* negotiate request */ #define CIFS_NEG_OP 0x0200 /* negotiate request */
#define CIFS_OP_MASK 0x0380 /* mask request type */ /* Lower bitmask values are reserved by others below. */
#define CIFS_SESS_OP 0x2000 /* session setup request */
#define CIFS_OP_MASK 0x2380 /* mask request type */
#define CIFS_HAS_CREDITS 0x0400 /* already has credits */ #define CIFS_HAS_CREDITS 0x0400 /* already has credits */
#define CIFS_TRANSFORM_REQ 0x0800 /* transform request before sending */ #define CIFS_TRANSFORM_REQ 0x0800 /* transform request before sending */
...@@ -1844,6 +1850,7 @@ GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above & list operations */ ...@@ -1844,6 +1850,7 @@ GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above & list operations */
*/ */
GLOBAL_EXTERN atomic_t sesInfoAllocCount; GLOBAL_EXTERN atomic_t sesInfoAllocCount;
GLOBAL_EXTERN atomic_t tconInfoAllocCount; GLOBAL_EXTERN atomic_t tconInfoAllocCount;
GLOBAL_EXTERN atomic_t tcpSesNextId;
GLOBAL_EXTERN atomic_t tcpSesAllocCount; GLOBAL_EXTERN atomic_t tcpSesAllocCount;
GLOBAL_EXTERN atomic_t tcpSesReconnectCount; GLOBAL_EXTERN atomic_t tcpSesReconnectCount;
GLOBAL_EXTERN atomic_t tconInfoReconnectCount; GLOBAL_EXTERN atomic_t tconInfoReconnectCount;
......
...@@ -232,6 +232,8 @@ extern unsigned int setup_special_user_owner_ACE(struct cifs_ace *pace); ...@@ -232,6 +232,8 @@ extern unsigned int setup_special_user_owner_ACE(struct cifs_ace *pace);
extern void dequeue_mid(struct mid_q_entry *mid, bool malformed); extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf, extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
unsigned int to_read); unsigned int to_read);
extern ssize_t cifs_discard_from_socket(struct TCP_Server_Info *server,
size_t to_read);
extern int cifs_read_page_from_socket(struct TCP_Server_Info *server, extern int cifs_read_page_from_socket(struct TCP_Server_Info *server,
struct page *page, struct page *page,
unsigned int page_offset, unsigned int page_offset,
......
...@@ -1451,9 +1451,9 @@ cifs_discard_remaining_data(struct TCP_Server_Info *server) ...@@ -1451,9 +1451,9 @@ cifs_discard_remaining_data(struct TCP_Server_Info *server)
while (remaining > 0) { while (remaining > 0) {
int length; int length;
length = cifs_read_from_socket(server, server->bigbuf, length = cifs_discard_from_socket(server,
min_t(unsigned int, remaining, min_t(size_t, remaining,
CIFSMaxBufSize + MAX_HEADER_SIZE(server))); CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
if (length < 0) if (length < 0)
return length; return length;
server->total_read += length; server->total_read += length;
......
This diff is collapsed.
...@@ -37,11 +37,12 @@ struct cache_dfs_tgt { ...@@ -37,11 +37,12 @@ struct cache_dfs_tgt {
struct cache_entry { struct cache_entry {
struct hlist_node hlist; struct hlist_node hlist;
const char *path; const char *path;
int ttl; int hdr_flags; /* RESP_GET_DFS_REFERRAL.ReferralHeaderFlags */
int srvtype; int ttl; /* DFS_REREFERRAL_V3.TimeToLive */
int flags; int srvtype; /* DFS_REREFERRAL_V3.ServerType */
int ref_flags; /* DFS_REREFERRAL_V3.ReferralEntryFlags */
struct timespec64 etime; struct timespec64 etime;
int path_consumed; int path_consumed; /* RESP_GET_DFS_REFERRAL.PathConsumed */
int numtgts; int numtgts;
struct list_head tlist; struct list_head tlist;
struct cache_dfs_tgt *tgthint; struct cache_dfs_tgt *tgthint;
...@@ -166,14 +167,11 @@ static int dfscache_proc_show(struct seq_file *m, void *v) ...@@ -166,14 +167,11 @@ static int dfscache_proc_show(struct seq_file *m, void *v)
continue; continue;
seq_printf(m, seq_printf(m,
"cache entry: path=%s,type=%s,ttl=%d,etime=%ld," "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",
"interlink=%s,path_consumed=%d,expired=%s\n", ce->path, ce->srvtype == DFS_TYPE_ROOT ? "root" : "link",
ce->path, ce->ttl, ce->etime.tv_nsec, ce->ref_flags, ce->hdr_flags,
ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", IS_INTERLINK_SET(ce->hdr_flags) ? "yes" : "no",
ce->ttl, ce->etime.tv_nsec, ce->path_consumed, cache_entry_expired(ce) ? "yes" : "no");
IS_INTERLINK_SET(ce->flags) ? "yes" : "no",
ce->path_consumed,
cache_entry_expired(ce) ? "yes" : "no");
list_for_each_entry(t, &ce->tlist, list) { list_for_each_entry(t, &ce->tlist, list) {
seq_printf(m, " %s%s\n", seq_printf(m, " %s%s\n",
...@@ -236,11 +234,12 @@ static inline void dump_tgts(const struct cache_entry *ce) ...@@ -236,11 +234,12 @@ static inline void dump_tgts(const struct cache_entry *ce)
static inline void dump_ce(const struct cache_entry *ce) static inline void dump_ce(const struct cache_entry *ce)
{ {
cifs_dbg(FYI, "cache entry: path=%s,type=%s,ttl=%d,etime=%ld,interlink=%s,path_consumed=%d,expired=%s\n", 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",
ce->path, ce->path,
ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", ce->ttl, ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", ce->ttl,
ce->etime.tv_nsec, ce->etime.tv_nsec,
IS_INTERLINK_SET(ce->flags) ? "yes" : "no", ce->hdr_flags, ce->ref_flags,
IS_INTERLINK_SET(ce->hdr_flags) ? "yes" : "no",
ce->path_consumed, ce->path_consumed,
cache_entry_expired(ce) ? "yes" : "no"); cache_entry_expired(ce) ? "yes" : "no");
dump_tgts(ce); dump_tgts(ce);
...@@ -381,7 +380,8 @@ static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs, ...@@ -381,7 +380,8 @@ static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs,
ce->ttl = refs[0].ttl; ce->ttl = refs[0].ttl;
ce->etime = get_expire_time(ce->ttl); ce->etime = get_expire_time(ce->ttl);
ce->srvtype = refs[0].server_type; ce->srvtype = refs[0].server_type;
ce->flags = refs[0].ref_flag; ce->hdr_flags = refs[0].flags;
ce->ref_flags = refs[0].ref_flag;
ce->path_consumed = refs[0].path_consumed; ce->path_consumed = refs[0].path_consumed;
for (i = 0; i < numrefs; i++) { for (i = 0; i < numrefs; i++) {
...@@ -799,7 +799,8 @@ static int setup_referral(const char *path, struct cache_entry *ce, ...@@ -799,7 +799,8 @@ static int setup_referral(const char *path, struct cache_entry *ce,
ref->path_consumed = ce->path_consumed; ref->path_consumed = ce->path_consumed;
ref->ttl = ce->ttl; ref->ttl = ce->ttl;
ref->server_type = ce->srvtype; ref->server_type = ce->srvtype;
ref->ref_flag = ce->flags; ref->ref_flag = ce->ref_flags;
ref->flags = ce->hdr_flags;
return 0; return 0;
......
...@@ -580,7 +580,7 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -580,7 +580,7 @@ int cifs_open(struct inode *inode, struct file *file)
} else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
if (tcon->ses->serverNOS) if (tcon->ses->serverNOS)
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", 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",
tcon->ses->serverName, tcon->ses->ip_addr,
tcon->ses->serverNOS); tcon->ses->serverNOS);
tcon->broken_posix_open = true; tcon->broken_posix_open = true;
} else if ((rc != -EIO) && (rc != -EREMOTE) && } else if ((rc != -EIO) && (rc != -EREMOTE) &&
......
...@@ -140,6 +140,8 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { ...@@ -140,6 +140,8 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
fsparam_u32("rsize", Opt_rsize), fsparam_u32("rsize", Opt_rsize),
fsparam_u32("wsize", Opt_wsize), fsparam_u32("wsize", Opt_wsize),
fsparam_u32("actimeo", Opt_actimeo), fsparam_u32("actimeo", Opt_actimeo),
fsparam_u32("acdirmax", Opt_acdirmax),
fsparam_u32("acregmax", Opt_acregmax),
fsparam_u32("echo_interval", Opt_echo_interval), fsparam_u32("echo_interval", Opt_echo_interval),
fsparam_u32("max_credits", Opt_max_credits), fsparam_u32("max_credits", Opt_max_credits),
fsparam_u32("handletimeout", Opt_handletimeout), fsparam_u32("handletimeout", Opt_handletimeout),
...@@ -397,7 +399,7 @@ cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3) ...@@ -397,7 +399,7 @@ cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3)
ctx->vals = &smb3any_values; ctx->vals = &smb3any_values;
break; break;
case Smb_default: case Smb_default:
ctx->ops = &smb30_operations; /* currently identical with 3.0 */ ctx->ops = &smb30_operations;
ctx->vals = &smbdefault_values; ctx->vals = &smbdefault_values;
break; break;
default: default:
...@@ -542,20 +544,37 @@ static int smb3_fs_context_parse_monolithic(struct fs_context *fc, ...@@ -542,20 +544,37 @@ static int smb3_fs_context_parse_monolithic(struct fs_context *fc,
/* BB Need to add support for sep= here TBD */ /* BB Need to add support for sep= here TBD */
while ((key = strsep(&options, ",")) != NULL) { while ((key = strsep(&options, ",")) != NULL) {
if (*key) { size_t len;
size_t v_len = 0; char *value;
char *value = strchr(key, '=');
if (*key == 0)
if (value) { break;
if (value == key)
continue; /* Check if following character is the deliminator If yes,
*value++ = 0; * we have encountered a double deliminator reset the NULL
v_len = strlen(value); * character to the deliminator
} */
ret = vfs_parse_fs_string(fc, key, value, v_len); while (options && options[0] == ',') {
if (ret < 0) len = strlen(key);
break; strcpy(key + len, options);
options = strchr(options, ',');
if (options)
*options++ = 0;
}
len = 0;
value = strchr(key, '=');
if (value) {
if (value == key)
continue;
*value++ = 0;
len = strlen(value);
} }
ret = vfs_parse_fs_string(fc, key, value, len);
if (ret < 0)
break;
} }
return ret; return ret;
...@@ -929,12 +948,31 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, ...@@ -929,12 +948,31 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
ctx->wsize = result.uint_32; ctx->wsize = result.uint_32;
ctx->got_wsize = true; ctx->got_wsize = true;
break; break;
case Opt_acregmax:
ctx->acregmax = HZ * result.uint_32;
if (ctx->acregmax > CIFS_MAX_ACTIMEO) {
cifs_dbg(VFS, "acregmax too large\n");
goto cifs_parse_mount_err;
}
break;
case Opt_acdirmax:
ctx->acdirmax = HZ * result.uint_32;
if (ctx->acdirmax > CIFS_MAX_ACTIMEO) {
cifs_dbg(VFS, "acdirmax too large\n");
goto cifs_parse_mount_err;
}
break;
case Opt_actimeo: case Opt_actimeo:
ctx->actimeo = HZ * result.uint_32; if (HZ * result.uint_32 > CIFS_MAX_ACTIMEO) {
if (ctx->actimeo > CIFS_MAX_ACTIMEO) { cifs_dbg(VFS, "timeout too large\n");
cifs_dbg(VFS, "attribute cache timeout too large\n");
goto cifs_parse_mount_err; goto cifs_parse_mount_err;
} }
if ((ctx->acdirmax != CIFS_DEF_ACTIMEO) ||
(ctx->acregmax != CIFS_DEF_ACTIMEO)) {
cifs_dbg(VFS, "actimeo ignored since acregmax or acdirmax specified\n");
break;
}
ctx->acdirmax = ctx->acregmax = HZ * result.uint_32;
break; break;
case Opt_echo_interval: case Opt_echo_interval:
ctx->echo_interval = result.uint_32; ctx->echo_interval = result.uint_32;
...@@ -1361,7 +1399,8 @@ int smb3_init_fs_context(struct fs_context *fc) ...@@ -1361,7 +1399,8 @@ int smb3_init_fs_context(struct fs_context *fc)
/* default is to use strict cifs caching semantics */ /* default is to use strict cifs caching semantics */
ctx->strict_io = true; ctx->strict_io = true;
ctx->actimeo = CIFS_DEF_ACTIMEO; ctx->acregmax = CIFS_DEF_ACTIMEO;
ctx->acdirmax = CIFS_DEF_ACTIMEO;
/* Most clients set timeout to 0, allows server to use its default */ /* Most clients set timeout to 0, allows server to use its default */
ctx->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */ ctx->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */
......
...@@ -118,6 +118,8 @@ enum cifs_param { ...@@ -118,6 +118,8 @@ enum cifs_param {
Opt_rsize, Opt_rsize,
Opt_wsize, Opt_wsize,
Opt_actimeo, Opt_actimeo,
Opt_acdirmax,
Opt_acregmax,
Opt_echo_interval, Opt_echo_interval,
Opt_max_credits, Opt_max_credits,
Opt_snapshot, Opt_snapshot,
...@@ -232,7 +234,9 @@ struct smb3_fs_context { ...@@ -232,7 +234,9 @@ struct smb3_fs_context {
unsigned int wsize; unsigned int wsize;
unsigned int min_offload; unsigned int min_offload;
bool sockopt_tcp_nodelay:1; bool sockopt_tcp_nodelay:1;
unsigned long actimeo; /* attribute cache timeout (jiffies) */ /* attribute cache timemout for files and directories in jiffies */
unsigned long acregmax;
unsigned long acdirmax;
struct smb_version_operations *ops; struct smb_version_operations *ops;
struct smb_version_values *vals; struct smb_version_values *vals;
char *prepath; char *prepath;
......
...@@ -2199,12 +2199,23 @@ cifs_inode_needs_reval(struct inode *inode) ...@@ -2199,12 +2199,23 @@ cifs_inode_needs_reval(struct inode *inode)
if (!lookupCacheEnabled) if (!lookupCacheEnabled)
return true; return true;
if (!cifs_sb->ctx->actimeo) /*
return true; * depending on inode type, check if attribute caching disabled for
* files or directories
if (!time_in_range(jiffies, cifs_i->time, */
cifs_i->time + cifs_sb->ctx->actimeo)) if (S_ISDIR(inode->i_mode)) {
return true; if (!cifs_sb->ctx->acdirmax)
return true;
if (!time_in_range(jiffies, cifs_i->time,
cifs_i->time + cifs_sb->ctx->acdirmax))
return true;
} else { /* file */
if (!cifs_sb->ctx->acregmax)
return true;
if (!time_in_range(jiffies, cifs_i->time,
cifs_i->time + cifs_sb->ctx->acregmax))
return true;
}
/* hardlinked files w/ noserverino get "special" treatment */ /* hardlinked files w/ noserverino get "special" treatment */
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
......
...@@ -218,7 +218,7 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, ...@@ -218,7 +218,7 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
/* UNC and paths */ /* UNC and paths */
/* XXX: Use ses->server->hostname? */ /* XXX: Use ses->server->hostname? */
sprintf(unc, unc_fmt, ses->serverName); sprintf(unc, unc_fmt, ses->ip_addr);
ctx.UNC = unc; ctx.UNC = unc;
ctx.prepath = ""; ctx.prepath = "";
......
...@@ -63,17 +63,19 @@ smb2_add_credits(struct TCP_Server_Info *server, ...@@ -63,17 +63,19 @@ smb2_add_credits(struct TCP_Server_Info *server,
const struct cifs_credits *credits, const int optype) const struct cifs_credits *credits, const int optype)
{ {
int *val, rc = -1; int *val, rc = -1;
int scredits, in_flight;
unsigned int add = credits->value; unsigned int add = credits->value;
unsigned int instance = credits->instance; unsigned int instance = credits->instance;
bool reconnect_detected = false; bool reconnect_detected = false;
bool reconnect_with_invalid_credits = false;
spin_lock(&server->req_lock); spin_lock(&server->req_lock);
val = server->ops->get_credits_field(server, optype); val = server->ops->get_credits_field(server, optype);
/* eg found case where write overlapping reconnect messed up credits */ /* eg found case where write overlapping reconnect messed up credits */
if (((optype & CIFS_OP_MASK) == CIFS_NEG_OP) && (*val != 0)) if (((optype & CIFS_OP_MASK) == CIFS_NEG_OP) && (*val != 0))
trace_smb3_reconnect_with_invalid_credits(server->CurrentMid, reconnect_with_invalid_credits = true;
server->hostname, *val, add);
if ((instance == 0) || (instance == server->reconnect_instance)) if ((instance == 0) || (instance == server->reconnect_instance))
*val += add; *val += add;
else else
...@@ -84,7 +86,9 @@ smb2_add_credits(struct TCP_Server_Info *server, ...@@ -84,7 +86,9 @@ smb2_add_credits(struct TCP_Server_Info *server,
pr_warn_once("server overflowed SMB3 credits\n"); pr_warn_once("server overflowed SMB3 credits\n");
} }
server->in_flight--; server->in_flight--;
if (server->in_flight == 0 && (optype & CIFS_OP_MASK) != CIFS_NEG_OP) if (server->in_flight == 0 &&
((optype & CIFS_OP_MASK) != CIFS_NEG_OP) &&
((optype & CIFS_OP_MASK) != CIFS_SESS_OP))
rc = change_conf(server); rc = change_conf(server);
/* /*
* Sometimes server returns 0 credits on oplock break ack - we need to * Sometimes server returns 0 credits on oplock break ack - we need to
...@@ -97,14 +101,26 @@ smb2_add_credits(struct TCP_Server_Info *server, ...@@ -97,14 +101,26 @@ smb2_add_credits(struct TCP_Server_Info *server,
server->oplock_credits++; server->oplock_credits++;
} }
} }
scredits = *val;
in_flight = server->in_flight;
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
wake_up(&server->request_q); wake_up(&server->request_q);
if (reconnect_detected) { if (reconnect_detected) {
trace_smb3_reconnect_detected(server->CurrentMid,
server->conn_id, server->hostname, scredits, add, in_flight);
cifs_dbg(FYI, "trying to put %d credits from the old server instance %d\n", cifs_dbg(FYI, "trying to put %d credits from the old server instance %d\n",
add, instance); add, instance);
} }
if (reconnect_with_invalid_credits) {
trace_smb3_reconnect_with_invalid_credits(server->CurrentMid,
server->conn_id, server->hostname, scredits, add, in_flight);
cifs_dbg(FYI, "Negotiate operation when server credits is non-zero. Optype: %d, server credits: %d, credits added: %d\n",
optype, scredits, add);
}
if (server->tcpStatus == CifsNeedReconnect if (server->tcpStatus == CifsNeedReconnect
|| server->tcpStatus == CifsExiting) || server->tcpStatus == CifsExiting)
return; return;
...@@ -123,23 +139,30 @@ smb2_add_credits(struct TCP_Server_Info *server, ...@@ -123,23 +139,30 @@ smb2_add_credits(struct TCP_Server_Info *server,
cifs_dbg(FYI, "disabling oplocks\n"); cifs_dbg(FYI, "disabling oplocks\n");
break; break;
default: default:
trace_smb3_add_credits(server->CurrentMid, /* change_conf rebalanced credits for different types */
server->hostname, rc, add); break;
cifs_dbg(FYI, "%s: added %u credits total=%d\n", __func__, add, rc);
} }
trace_smb3_add_credits(server->CurrentMid,
server->conn_id, server->hostname, scredits, add, in_flight);
cifs_dbg(FYI, "%s: added %u credits total=%d\n", __func__, add, scredits);
} }
static void static void
smb2_set_credits(struct TCP_Server_Info *server, const int val) smb2_set_credits(struct TCP_Server_Info *server, const int val)
{ {
int scredits, in_flight;
spin_lock(&server->req_lock); spin_lock(&server->req_lock);
server->credits = val; server->credits = val;
if (val == 1) if (val == 1)
server->reconnect_instance++; server->reconnect_instance++;
scredits = server->credits;
in_flight = server->in_flight;
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
trace_smb3_set_credits(server->CurrentMid, trace_smb3_set_credits(server->CurrentMid,
server->hostname, val, val); server->conn_id, server->hostname, scredits, val, in_flight);
cifs_dbg(FYI, "%s: set %u credits\n", __func__, val); cifs_dbg(FYI, "%s: set %u credits\n", __func__, val);
/* don't log while holding the lock */ /* don't log while holding the lock */
...@@ -171,7 +194,7 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, ...@@ -171,7 +194,7 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
unsigned int *num, struct cifs_credits *credits) unsigned int *num, struct cifs_credits *credits)
{ {
int rc = 0; int rc = 0;
unsigned int scredits; unsigned int scredits, in_flight;
spin_lock(&server->req_lock); spin_lock(&server->req_lock);
while (1) { while (1) {
...@@ -208,17 +231,18 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, ...@@ -208,17 +231,18 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE); DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE);
credits->instance = server->reconnect_instance; credits->instance = server->reconnect_instance;
server->credits -= credits->value; server->credits -= credits->value;
scredits = server->credits;
server->in_flight++; server->in_flight++;
if (server->in_flight > server->max_in_flight) if (server->in_flight > server->max_in_flight)
server->max_in_flight = server->in_flight; server->max_in_flight = server->in_flight;
break; break;
} }
} }
scredits = server->credits;
in_flight = server->in_flight;
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
trace_smb3_add_credits(server->CurrentMid, trace_smb3_add_credits(server->CurrentMid,
server->hostname, scredits, -(credits->value)); server->conn_id, server->hostname, scredits, -(credits->value), in_flight);
cifs_dbg(FYI, "%s: removed %u credits total=%d\n", cifs_dbg(FYI, "%s: removed %u credits total=%d\n",
__func__, credits->value, scredits); __func__, credits->value, scredits);
...@@ -231,14 +255,14 @@ smb2_adjust_credits(struct TCP_Server_Info *server, ...@@ -231,14 +255,14 @@ smb2_adjust_credits(struct TCP_Server_Info *server,
const unsigned int payload_size) const unsigned int payload_size)
{ {
int new_val = DIV_ROUND_UP(payload_size, SMB2_MAX_BUFFER_SIZE); int new_val = DIV_ROUND_UP(payload_size, SMB2_MAX_BUFFER_SIZE);
int scredits; int scredits, in_flight;
if (!credits->value || credits->value == new_val) if (!credits->value || credits->value == new_val)
return 0; return 0;
if (credits->value < new_val) { if (credits->value < new_val) {
trace_smb3_too_many_credits(server->CurrentMid, trace_smb3_too_many_credits(server->CurrentMid,
server->hostname, 0, credits->value - new_val); server->conn_id, server->hostname, 0, credits->value - new_val, 0);
cifs_server_dbg(VFS, "request has less credits (%d) than required (%d)", cifs_server_dbg(VFS, "request has less credits (%d) than required (%d)",
credits->value, new_val); credits->value, new_val);
...@@ -248,9 +272,13 @@ smb2_adjust_credits(struct TCP_Server_Info *server, ...@@ -248,9 +272,13 @@ smb2_adjust_credits(struct TCP_Server_Info *server,
spin_lock(&server->req_lock); spin_lock(&server->req_lock);
if (server->reconnect_instance != credits->instance) { if (server->reconnect_instance != credits->instance) {
scredits = server->credits;
in_flight = server->in_flight;
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
trace_smb3_reconnect_detected(server->CurrentMid, trace_smb3_reconnect_detected(server->CurrentMid,
server->hostname, 0, 0); server->conn_id, server->hostname, scredits,
credits->value - new_val, in_flight);
cifs_server_dbg(VFS, "trying to return %d credits to old session\n", cifs_server_dbg(VFS, "trying to return %d credits to old session\n",
credits->value - new_val); credits->value - new_val);
return -EAGAIN; return -EAGAIN;
...@@ -258,15 +286,18 @@ smb2_adjust_credits(struct TCP_Server_Info *server, ...@@ -258,15 +286,18 @@ smb2_adjust_credits(struct TCP_Server_Info *server,
server->credits += credits->value - new_val; server->credits += credits->value - new_val;
scredits = server->credits; scredits = server->credits;
in_flight = server->in_flight;
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
wake_up(&server->request_q); wake_up(&server->request_q);
credits->value = new_val;
trace_smb3_add_credits(server->CurrentMid, trace_smb3_add_credits(server->CurrentMid,
server->hostname, scredits, credits->value - new_val); server->conn_id, server->hostname, scredits,
credits->value - new_val, in_flight);
cifs_dbg(FYI, "%s: adjust added %u credits total=%d\n", cifs_dbg(FYI, "%s: adjust added %u credits total=%d\n",
__func__, credits->value - new_val, scredits); __func__, credits->value - new_val, scredits);
credits->value = new_val;
return 0; return 0;
} }
...@@ -2369,7 +2400,7 @@ static bool ...@@ -2369,7 +2400,7 @@ static bool
smb2_is_status_pending(char *buf, struct TCP_Server_Info *server) smb2_is_status_pending(char *buf, struct TCP_Server_Info *server)
{ {
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
int scredits; int scredits, in_flight;
if (shdr->Status != STATUS_PENDING) if (shdr->Status != STATUS_PENDING)
return false; return false;
...@@ -2378,11 +2409,13 @@ smb2_is_status_pending(char *buf, struct TCP_Server_Info *server) ...@@ -2378,11 +2409,13 @@ smb2_is_status_pending(char *buf, struct TCP_Server_Info *server)
spin_lock(&server->req_lock); spin_lock(&server->req_lock);
server->credits += le16_to_cpu(shdr->CreditRequest); server->credits += le16_to_cpu(shdr->CreditRequest);
scredits = server->credits; scredits = server->credits;
in_flight = server->in_flight;
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
wake_up(&server->request_q); wake_up(&server->request_q);
trace_smb3_add_credits(server->CurrentMid, trace_smb3_add_credits(server->CurrentMid,
server->hostname, scredits, le16_to_cpu(shdr->CreditRequest)); server->conn_id, server->hostname, scredits,
le16_to_cpu(shdr->CreditRequest), in_flight);
cifs_dbg(FYI, "%s: status pending add %u credits total=%d\n", cifs_dbg(FYI, "%s: status pending add %u credits total=%d\n",
__func__, le16_to_cpu(shdr->CreditRequest), scredits); __func__, le16_to_cpu(shdr->CreditRequest), scredits);
} }
...@@ -2418,6 +2451,34 @@ smb2_is_status_io_timeout(char *buf) ...@@ -2418,6 +2451,34 @@ smb2_is_status_io_timeout(char *buf)
return false; return false;
} }
static void
smb2_is_network_name_deleted(char *buf, struct TCP_Server_Info *server)
{
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
struct list_head *tmp, *tmp1;
struct cifs_ses *ses;
struct cifs_tcon *tcon;
if (shdr->Status != STATUS_NETWORK_NAME_DELETED)
return;
spin_lock(&cifs_tcp_ses_lock);
list_for_each(tmp, &server->smb_ses_list) {
ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
list_for_each(tmp1, &ses->tcon_list) {
tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
if (tcon->tid == shdr->TreeId) {
tcon->need_reconnect = true;
spin_unlock(&cifs_tcp_ses_lock);
pr_warn_once("Server share %s deleted.\n",
tcon->treeName);
return;
}
}
}
spin_unlock(&cifs_tcp_ses_lock);
}
static int static int
smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid, smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
struct cifsInodeInfo *cinode) struct cifsInodeInfo *cinode)
...@@ -4605,6 +4666,10 @@ static void smb2_decrypt_offload(struct work_struct *work) ...@@ -4605,6 +4666,10 @@ static void smb2_decrypt_offload(struct work_struct *work)
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
mid->when_received = jiffies; mid->when_received = jiffies;
#endif #endif
if (dw->server->ops->is_network_name_deleted)
dw->server->ops->is_network_name_deleted(dw->buf,
dw->server);
mid->callback(mid); mid->callback(mid);
} else { } else {
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
...@@ -4723,6 +4788,12 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, ...@@ -4723,6 +4788,12 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid,
rc = handle_read_data(server, *mid, buf, rc = handle_read_data(server, *mid, buf,
server->vals->read_rsp_size, server->vals->read_rsp_size,
pages, npages, len, false); pages, npages, len, false);
if (rc >= 0) {
if (server->ops->is_network_name_deleted) {
server->ops->is_network_name_deleted(buf,
server);
}
}
} }
free_pages: free_pages:
...@@ -5072,6 +5143,7 @@ struct smb_version_operations smb20_operations = { ...@@ -5072,6 +5143,7 @@ struct smb_version_operations smb20_operations = {
.fiemap = smb3_fiemap, .fiemap = smb3_fiemap,
.llseek = smb3_llseek, .llseek = smb3_llseek,
.is_status_io_timeout = smb2_is_status_io_timeout, .is_status_io_timeout = smb2_is_status_io_timeout,
.is_network_name_deleted = smb2_is_network_name_deleted,
}; };
struct smb_version_operations smb21_operations = { struct smb_version_operations smb21_operations = {
...@@ -5173,6 +5245,7 @@ struct smb_version_operations smb21_operations = { ...@@ -5173,6 +5245,7 @@ struct smb_version_operations smb21_operations = {
.fiemap = smb3_fiemap, .fiemap = smb3_fiemap,
.llseek = smb3_llseek, .llseek = smb3_llseek,
.is_status_io_timeout = smb2_is_status_io_timeout, .is_status_io_timeout = smb2_is_status_io_timeout,
.is_network_name_deleted = smb2_is_network_name_deleted,
}; };
struct smb_version_operations smb30_operations = { struct smb_version_operations smb30_operations = {
...@@ -5286,6 +5359,7 @@ struct smb_version_operations smb30_operations = { ...@@ -5286,6 +5359,7 @@ struct smb_version_operations smb30_operations = {
.fiemap = smb3_fiemap, .fiemap = smb3_fiemap,
.llseek = smb3_llseek, .llseek = smb3_llseek,
.is_status_io_timeout = smb2_is_status_io_timeout, .is_status_io_timeout = smb2_is_status_io_timeout,
.is_network_name_deleted = smb2_is_network_name_deleted,
}; };
struct smb_version_operations smb311_operations = { struct smb_version_operations smb311_operations = {
...@@ -5399,6 +5473,7 @@ struct smb_version_operations smb311_operations = { ...@@ -5399,6 +5473,7 @@ struct smb_version_operations smb311_operations = {
.fiemap = smb3_fiemap, .fiemap = smb3_fiemap,
.llseek = smb3_llseek, .llseek = smb3_llseek,
.is_status_io_timeout = smb2_is_status_io_timeout, .is_status_io_timeout = smb2_is_status_io_timeout,
.is_network_name_deleted = smb2_is_network_name_deleted,
}; };
struct smb_version_values smb20_values = { struct smb_version_values smb20_values = {
......
...@@ -814,8 +814,9 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) ...@@ -814,8 +814,9 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
SMB3ANY_VERSION_STRING) == 0) { SMB3ANY_VERSION_STRING) == 0) {
req->Dialects[0] = cpu_to_le16(SMB30_PROT_ID); req->Dialects[0] = cpu_to_le16(SMB30_PROT_ID);
req->Dialects[1] = cpu_to_le16(SMB302_PROT_ID); req->Dialects[1] = cpu_to_le16(SMB302_PROT_ID);
req->DialectCount = cpu_to_le16(2); req->Dialects[2] = cpu_to_le16(SMB311_PROT_ID);
total_len += 4; req->DialectCount = cpu_to_le16(3);
total_len += 6;
} else if (strcmp(server->vals->version_string, } else if (strcmp(server->vals->version_string,
SMBDEFAULT_VERSION_STRING) == 0) { SMBDEFAULT_VERSION_STRING) == 0) {
req->Dialects[0] = cpu_to_le16(SMB21_PROT_ID); req->Dialects[0] = cpu_to_le16(SMB21_PROT_ID);
...@@ -848,6 +849,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) ...@@ -848,6 +849,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
memcpy(req->ClientGUID, server->client_guid, memcpy(req->ClientGUID, server->client_guid,
SMB2_CLIENT_GUID_SIZE); SMB2_CLIENT_GUID_SIZE);
if ((server->vals->protocol_id == SMB311_PROT_ID) || if ((server->vals->protocol_id == SMB311_PROT_ID) ||
(strcmp(server->vals->version_string,
SMB3ANY_VERSION_STRING) == 0) ||
(strcmp(server->vals->version_string, (strcmp(server->vals->version_string,
SMBDEFAULT_VERSION_STRING) == 0)) SMBDEFAULT_VERSION_STRING) == 0))
assemble_neg_contexts(req, server, &total_len); assemble_neg_contexts(req, server, &total_len);
...@@ -883,6 +886,10 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) ...@@ -883,6 +886,10 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
cifs_server_dbg(VFS, cifs_server_dbg(VFS,
"SMB2.1 dialect returned but not requested\n"); "SMB2.1 dialect returned but not requested\n");
return -EIO; return -EIO;
} else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
/* ops set to 3.0 by default for default so update */
server->ops = &smb311_operations;
server->vals = &smb311_values;
} }
} else if (strcmp(server->vals->version_string, } else if (strcmp(server->vals->version_string,
SMBDEFAULT_VERSION_STRING) == 0) { SMBDEFAULT_VERSION_STRING) == 0) {
...@@ -1042,10 +1049,11 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) ...@@ -1042,10 +1049,11 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
SMB3ANY_VERSION_STRING) == 0) { SMB3ANY_VERSION_STRING) == 0) {
pneg_inbuf->Dialects[0] = cpu_to_le16(SMB30_PROT_ID); pneg_inbuf->Dialects[0] = cpu_to_le16(SMB30_PROT_ID);
pneg_inbuf->Dialects[1] = cpu_to_le16(SMB302_PROT_ID); pneg_inbuf->Dialects[1] = cpu_to_le16(SMB302_PROT_ID);
pneg_inbuf->DialectCount = cpu_to_le16(2); pneg_inbuf->Dialects[2] = cpu_to_le16(SMB311_PROT_ID);
/* structure is big enough for 3 dialects, sending only 2 */ pneg_inbuf->DialectCount = cpu_to_le16(3);
/* SMB 2.1 not included so subtract one dialect from len */
inbuflen = sizeof(*pneg_inbuf) - inbuflen = sizeof(*pneg_inbuf) -
(2 * sizeof(pneg_inbuf->Dialects[0])); (sizeof(pneg_inbuf->Dialects[0]));
} else if (strcmp(server->vals->version_string, } else if (strcmp(server->vals->version_string,
SMBDEFAULT_VERSION_STRING) == 0) { SMBDEFAULT_VERSION_STRING) == 0) {
pneg_inbuf->Dialects[0] = cpu_to_le16(SMB21_PROT_ID); pneg_inbuf->Dialects[0] = cpu_to_le16(SMB21_PROT_ID);
...@@ -1053,7 +1061,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) ...@@ -1053,7 +1061,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
pneg_inbuf->Dialects[2] = cpu_to_le16(SMB302_PROT_ID); pneg_inbuf->Dialects[2] = cpu_to_le16(SMB302_PROT_ID);
pneg_inbuf->Dialects[3] = cpu_to_le16(SMB311_PROT_ID); pneg_inbuf->Dialects[3] = cpu_to_le16(SMB311_PROT_ID);
pneg_inbuf->DialectCount = cpu_to_le16(4); pneg_inbuf->DialectCount = cpu_to_le16(4);
/* structure is big enough for 3 dialects */ /* structure is big enough for 4 dialects */
inbuflen = sizeof(*pneg_inbuf); inbuflen = sizeof(*pneg_inbuf);
} else { } else {
/* otherwise specific dialect was requested */ /* otherwise specific dialect was requested */
...@@ -1253,7 +1261,7 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data) ...@@ -1253,7 +1261,7 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
cifs_ses_server(sess_data->ses), cifs_ses_server(sess_data->ses),
&rqst, &rqst,
&sess_data->buf0_type, &sess_data->buf0_type,
CIFS_LOG_ERROR | CIFS_NEG_OP, &rsp_iov); CIFS_LOG_ERROR | CIFS_SESS_OP, &rsp_iov);
cifs_small_buf_release(sess_data->iov[0].iov_base); cifs_small_buf_release(sess_data->iov[0].iov_base);
memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec)); memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec));
......
...@@ -851,17 +851,21 @@ DEFINE_SMB3_LEASE_ERR_EVENT(lease_err); ...@@ -851,17 +851,21 @@ DEFINE_SMB3_LEASE_ERR_EVENT(lease_err);
DECLARE_EVENT_CLASS(smb3_reconnect_class, DECLARE_EVENT_CLASS(smb3_reconnect_class,
TP_PROTO(__u64 currmid, TP_PROTO(__u64 currmid,
__u64 conn_id,
char *hostname), char *hostname),
TP_ARGS(currmid, hostname), TP_ARGS(currmid, conn_id, hostname),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(__u64, currmid) __field(__u64, currmid)
__field(__u64, conn_id)
__field(char *, hostname) __field(char *, hostname)
), ),
TP_fast_assign( TP_fast_assign(
__entry->currmid = currmid; __entry->currmid = currmid;
__entry->conn_id = conn_id;
__entry->hostname = hostname; __entry->hostname = hostname;
), ),
TP_printk("server=%s current_mid=0x%llx", TP_printk("conn_id=0x%llx server=%s current_mid=%llu",
__entry->conn_id,
__entry->hostname, __entry->hostname,
__entry->currmid) __entry->currmid)
) )
...@@ -869,44 +873,56 @@ DECLARE_EVENT_CLASS(smb3_reconnect_class, ...@@ -869,44 +873,56 @@ DECLARE_EVENT_CLASS(smb3_reconnect_class,
#define DEFINE_SMB3_RECONNECT_EVENT(name) \ #define DEFINE_SMB3_RECONNECT_EVENT(name) \
DEFINE_EVENT(smb3_reconnect_class, smb3_##name, \ DEFINE_EVENT(smb3_reconnect_class, smb3_##name, \
TP_PROTO(__u64 currmid, \ TP_PROTO(__u64 currmid, \
char *hostname), \ __u64 conn_id, \
TP_ARGS(currmid, hostname)) char *hostname), \
TP_ARGS(currmid, conn_id, hostname))
DEFINE_SMB3_RECONNECT_EVENT(reconnect); DEFINE_SMB3_RECONNECT_EVENT(reconnect);
DEFINE_SMB3_RECONNECT_EVENT(partial_send_reconnect); DEFINE_SMB3_RECONNECT_EVENT(partial_send_reconnect);
DECLARE_EVENT_CLASS(smb3_credit_class, DECLARE_EVENT_CLASS(smb3_credit_class,
TP_PROTO(__u64 currmid, TP_PROTO(__u64 currmid,
__u64 conn_id,
char *hostname, char *hostname,
int credits, int credits,
int credits_to_add), int credits_to_add,
TP_ARGS(currmid, hostname, credits, credits_to_add), int in_flight),
TP_ARGS(currmid, conn_id, hostname, credits, credits_to_add, in_flight),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(__u64, currmid) __field(__u64, currmid)
__field(__u64, conn_id)
__field(char *, hostname) __field(char *, hostname)
__field(int, credits) __field(int, credits)
__field(int, credits_to_add) __field(int, credits_to_add)
__field(int, in_flight)
), ),
TP_fast_assign( TP_fast_assign(
__entry->currmid = currmid; __entry->currmid = currmid;
__entry->conn_id = conn_id;
__entry->hostname = hostname; __entry->hostname = hostname;
__entry->credits = credits; __entry->credits = credits;
__entry->credits_to_add = credits_to_add; __entry->credits_to_add = credits_to_add;
__entry->in_flight = in_flight;
), ),
TP_printk("server=%s current_mid=0x%llx credits=%d credits_to_add=%d", TP_printk("conn_id=0x%llx server=%s current_mid=%llu "
"credits=%d credit_change=%d in_flight=%d",
__entry->conn_id,
__entry->hostname, __entry->hostname,
__entry->currmid, __entry->currmid,
__entry->credits, __entry->credits,
__entry->credits_to_add) __entry->credits_to_add,
__entry->in_flight)
) )
#define DEFINE_SMB3_CREDIT_EVENT(name) \ #define DEFINE_SMB3_CREDIT_EVENT(name) \
DEFINE_EVENT(smb3_credit_class, smb3_##name, \ DEFINE_EVENT(smb3_credit_class, smb3_##name, \
TP_PROTO(__u64 currmid, \ TP_PROTO(__u64 currmid, \
__u64 conn_id, \
char *hostname, \ char *hostname, \
int credits, \ int credits, \
int credits_to_add), \ int credits_to_add, \
TP_ARGS(currmid, hostname, credits, credits_to_add)) int in_flight), \
TP_ARGS(currmid, conn_id, hostname, credits, credits_to_add, in_flight))
DEFINE_SMB3_CREDIT_EVENT(reconnect_with_invalid_credits); DEFINE_SMB3_CREDIT_EVENT(reconnect_with_invalid_credits);
DEFINE_SMB3_CREDIT_EVENT(reconnect_detected); DEFINE_SMB3_CREDIT_EVENT(reconnect_detected);
......
...@@ -445,7 +445,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, ...@@ -445,7 +445,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
*/ */
server->tcpStatus = CifsNeedReconnect; server->tcpStatus = CifsNeedReconnect;
trace_smb3_partial_send_reconnect(server->CurrentMid, trace_smb3_partial_send_reconnect(server->CurrentMid,
server->hostname); server->conn_id, server->hostname);
} }
smbd_done: smbd_done:
if (rc < 0 && rc != -EINTR) if (rc < 0 && rc != -EINTR)
...@@ -527,7 +527,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits, ...@@ -527,7 +527,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
int *credits; int *credits;
int optype; int optype;
long int t; long int t;
int scredits = server->credits; int scredits, in_flight;
if (timeout < 0) if (timeout < 0)
t = MAX_JIFFY_OFFSET; t = MAX_JIFFY_OFFSET;
...@@ -551,23 +551,39 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits, ...@@ -551,23 +551,39 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
server->max_in_flight = server->in_flight; server->max_in_flight = server->in_flight;
*credits -= 1; *credits -= 1;
*instance = server->reconnect_instance; *instance = server->reconnect_instance;
scredits = *credits;
in_flight = server->in_flight;
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
trace_smb3_add_credits(server->CurrentMid,
server->conn_id, server->hostname, scredits, -1, in_flight);
cifs_dbg(FYI, "%s: remove %u credits total=%d\n",
__func__, 1, scredits);
return 0; return 0;
} }
while (1) { while (1) {
if (*credits < num_credits) { if (*credits < num_credits) {
scredits = *credits;
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
cifs_num_waiters_inc(server); cifs_num_waiters_inc(server);
rc = wait_event_killable_timeout(server->request_q, rc = wait_event_killable_timeout(server->request_q,
has_credits(server, credits, num_credits), t); has_credits(server, credits, num_credits), t);
cifs_num_waiters_dec(server); cifs_num_waiters_dec(server);
if (!rc) { if (!rc) {
spin_lock(&server->req_lock);
scredits = *credits;
in_flight = server->in_flight;
spin_unlock(&server->req_lock);
trace_smb3_credit_timeout(server->CurrentMid, trace_smb3_credit_timeout(server->CurrentMid,
server->hostname, num_credits, 0); server->conn_id, server->hostname, scredits,
num_credits, in_flight);
cifs_server_dbg(VFS, "wait timed out after %d ms\n", cifs_server_dbg(VFS, "wait timed out after %d ms\n",
timeout); timeout);
return -ENOTSUPP; return -EBUSY;
} }
if (rc == -ERESTARTSYS) if (rc == -ERESTARTSYS)
return -ERESTARTSYS; return -ERESTARTSYS;
...@@ -595,6 +611,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits, ...@@ -595,6 +611,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
server->in_flight > 2 * MAX_COMPOUND && server->in_flight > 2 * MAX_COMPOUND &&
*credits <= MAX_COMPOUND) { *credits <= MAX_COMPOUND) {
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
cifs_num_waiters_inc(server); cifs_num_waiters_inc(server);
rc = wait_event_killable_timeout( rc = wait_event_killable_timeout(
server->request_q, server->request_q,
...@@ -603,13 +620,18 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits, ...@@ -603,13 +620,18 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
t); t);
cifs_num_waiters_dec(server); cifs_num_waiters_dec(server);
if (!rc) { if (!rc) {
spin_lock(&server->req_lock);
scredits = *credits;
in_flight = server->in_flight;
spin_unlock(&server->req_lock);
trace_smb3_credit_timeout( trace_smb3_credit_timeout(
server->CurrentMid, server->CurrentMid,
server->hostname, num_credits, server->conn_id, server->hostname,
0); scredits, num_credits, in_flight);
cifs_server_dbg(VFS, "wait timed out after %d ms\n", cifs_server_dbg(VFS, "wait timed out after %d ms\n",
timeout); timeout);
return -ENOTSUPP; return -EBUSY;
} }
if (rc == -ERESTARTSYS) if (rc == -ERESTARTSYS)
return -ERESTARTSYS; return -ERESTARTSYS;
...@@ -625,16 +647,18 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits, ...@@ -625,16 +647,18 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
/* update # of requests on the wire to server */ /* update # of requests on the wire to server */
if ((flags & CIFS_TIMEOUT_MASK) != CIFS_BLOCKING_OP) { if ((flags & CIFS_TIMEOUT_MASK) != CIFS_BLOCKING_OP) {
*credits -= num_credits; *credits -= num_credits;
scredits = *credits;
server->in_flight += num_credits; server->in_flight += num_credits;
if (server->in_flight > server->max_in_flight) if (server->in_flight > server->max_in_flight)
server->max_in_flight = server->in_flight; server->max_in_flight = server->in_flight;
*instance = server->reconnect_instance; *instance = server->reconnect_instance;
} }
scredits = *credits;
in_flight = server->in_flight;
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
trace_smb3_add_credits(server->CurrentMid, trace_smb3_add_credits(server->CurrentMid,
server->hostname, scredits, -(num_credits)); server->conn_id, server->hostname, scredits,
-(num_credits), in_flight);
cifs_dbg(FYI, "%s: remove %u credits total=%d\n", cifs_dbg(FYI, "%s: remove %u credits total=%d\n",
__func__, num_credits, scredits); __func__, num_credits, scredits);
break; break;
...@@ -656,13 +680,13 @@ wait_for_compound_request(struct TCP_Server_Info *server, int num, ...@@ -656,13 +680,13 @@ wait_for_compound_request(struct TCP_Server_Info *server, int num,
const int flags, unsigned int *instance) const int flags, unsigned int *instance)
{ {
int *credits; int *credits;
int scredits, sin_flight; int scredits, in_flight;
credits = server->ops->get_credits_field(server, flags & CIFS_OP_MASK); credits = server->ops->get_credits_field(server, flags & CIFS_OP_MASK);
spin_lock(&server->req_lock); spin_lock(&server->req_lock);
scredits = *credits; scredits = *credits;
sin_flight = server->in_flight; in_flight = server->in_flight;
if (*credits < num) { if (*credits < num) {
/* /*
...@@ -684,10 +708,11 @@ wait_for_compound_request(struct TCP_Server_Info *server, int num, ...@@ -684,10 +708,11 @@ wait_for_compound_request(struct TCP_Server_Info *server, int num,
if (server->in_flight == 0) { if (server->in_flight == 0) {
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
trace_smb3_insufficient_credits(server->CurrentMid, trace_smb3_insufficient_credits(server->CurrentMid,
server->hostname, scredits, sin_flight); server->conn_id, server->hostname, scredits,
num, in_flight);
cifs_dbg(FYI, "%s: %d requests in flight, needed %d total=%d\n", cifs_dbg(FYI, "%s: %d requests in flight, needed %d total=%d\n",
__func__, sin_flight, num, scredits); __func__, in_flight, num, scredits);
return -ENOTSUPP; return -EDEADLK;
} }
} }
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
...@@ -1171,7 +1196,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -1171,7 +1196,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
/* /*
* Compounding is never used during session establish. * Compounding is never used during session establish.
*/ */
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP))
smb311_update_preauth_hash(ses, rqst[0].rq_iov, smb311_update_preauth_hash(ses, rqst[0].rq_iov,
rqst[0].rq_nvec); rqst[0].rq_nvec);
...@@ -1236,7 +1261,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -1236,7 +1261,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
/* /*
* Compounding is never used during session establish. * Compounding is never used during session establish.
*/ */
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) { if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) {
struct kvec iov = { struct kvec iov = {
.iov_base = resp_iov[0].iov_base, .iov_base = resp_iov[0].iov_base,
.iov_len = resp_iov[0].iov_len .iov_len = resp_iov[0].iov_len
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment