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
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:
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
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.
......@@ -51,7 +51,7 @@ Patch Contributors
- Ronnie Sahlberg (for SMB3 xattr work, bug fixes, and lots of great work on compounding)
- Shirish Pargaonkar (for many ACL patches over the years)
- 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)
......
......@@ -3,6 +3,7 @@ Changes
=======
See https://wiki.samba.org/index.php/LinuxCIFSKernel for summary
information (that may be easier to read than parsing the output of
"git log fs/cifs") about fixes/improvements to CIFS/SMB2/SMB3 support (changes
information about fixes/improvements to CIFS/SMB2/SMB3 support (changes
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
protocol which was the successor to the Server Message Block
(SMB) protocol, the native file sharing mechanism for most early
PC operating systems. New and improved versions of CIFS are now
called SMB2 and SMB3. Use of SMB3 (and later, including SMB3.1.1)
is strongly preferred over using older dialects like CIFS due to
security reasons. All modern dialects, including the most recent,
SMB3.1.1 are supported by the CIFS VFS module. The SMB3 protocol
is implemented and supported by all major file servers
such as all modern versions of Windows (including Windows 2016
Server), as well as by Samba (which provides excellent
CIFS/SMB2/SMB3 server support and tools for Linux and many other
operating systems). Apple systems also support SMB3 well, as
do most Network Attached Storage vendors, so this network
filesystem client can mount to a wide variety of systems.
It also supports mounting to the cloud (for example
Microsoft Azure), including the necessary security features.
called SMB2 and SMB3. Use of SMB3 (and later, including SMB3.1.1
the most current dialect) is strongly preferred over using older
dialects like CIFS due to security reasons. All modern dialects,
including the most recent, SMB3.1.1, are supported by the CIFS VFS
module. The SMB3 protocol is implemented and supported by all major
file servers such as Windows (including Windows 2019 Server), as
well as by Samba (which provides excellent CIFS/SMB2/SMB3 server
support and tools for Linux and many other operating systems).
Apple systems also support SMB3 well, as do most Network Attached
Storage vendors, so this network filesystem client can mount to a
wide variety of systems. It also supports mounting to the cloud
(for example Microsoft Azure), including the necessary security
features.
The intent of this module is to provide the most advanced network
file system function for SMB3 compliant servers, including advanced
......@@ -27,8 +27,8 @@ Introduction
POSIX compliance, secure per-user session establishment, encryption,
high performance safe distributed caching (leases/oplocks), optional packet
signing, large files, Unicode support and other internationalization
improvements. Since both Samba server and this filesystem client support
the CIFS Unix extensions (and in the future SMB3 POSIX extensions),
improvements. Since both Samba server and this filesystem client support the
CIFS Unix extensions, and the Linux client also suppors SMB3 POSIX extensions,
the combination can provide a reasonable alternative to other network and
cluster file systems for fileserving in some Linux to Linux 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:
a) SMB3 (and SMB3.1.1) missing optional features:
- multichannel (started), integration with RDMA
- directory leases (improved metadata caching), started (root dir only)
- multichannel (partially integrated), integration of multichannel with RDMA
- directory leases (improved metadata caching). Currently only implemented for root dir
- T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl
currently the only two server side copy mechanisms supported)
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
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
to make it to network filesystems or deviceless filesystems)
d) quota support (needs minor kernel change since quota calls otherwise
won't make it to network filesystems or deviceless filesystems).
e) Additional use cases can be optimized to use "compounding" (e.g.
open/query/close and open/setinfo/close) to reduce the number of
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
significantly reduce redundant opens by using deferred close (with
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
metadata attributes easier from tools (e.g. extending what was done
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?)
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")
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
tool listening on witness protocol RPC) to allow for notification of share
move, server failover, and server adapter changes. And also improve other
failover scenarios, e.g. when client knows multiple DFS entries point to
different servers, and the server we are connected to has gone down.
p) Expand support for witness protocol to allow for notification of share
move, and server network adapter changes. Currently only notifications by
the witness protocol for server move is supported by the Linux client.
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.
......@@ -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
and simplify the code.
v) POSIX Extensions for SMB3.1.1 (started, create and mkdir support added
so far).
v) Additional testing of POSIX Extensions for SMB3.1.1
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
......
......@@ -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
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
====================
......
......@@ -133,11 +133,12 @@ cifs_dump_channel(struct seq_file *m, int i, struct cifs_chan *chan)
{
struct TCP_Server_Info *server = chan->server;
seq_printf(m, "\t\tChannel %d Number of credits: %d Dialect 0x%x "
"TCP status: %d Instance: %d Local Users To Server: %d "
"SecMode: 0x%x Req On Wire: %d In Send: %d "
"In MaxReq Wait: %d\n",
i+1,
seq_printf(m, "\n\n\t\tChannel: %d ConnectionId: 0x%llx"
"\n\t\tNumber of credits: %d Dialect 0x%x"
"\n\t\tTCP status: %d Instance: %d"
"\n\t\tLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d"
"\n\t\tIn Send: %d In MaxReq Wait: %d",
i+1, server->conn_id,
server->credits,
server->dialect,
server->tcpStatus,
......@@ -227,7 +228,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
struct TCP_Server_Info *server;
struct cifs_ses *ses;
struct cifs_tcon *tcon;
int i, j;
int c, i, j;
seq_puts(m,
"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)
seq_putc(m, '\n');
seq_printf(m, "CIFSMaxBufSize: %d\n", CIFSMaxBufSize);
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);
list_for_each(tmp1, &cifs_tcp_ses_list) {
server = list_entry(tmp1, struct TCP_Server_Info,
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
if (!server->rdma)
goto skip_rdma;
......@@ -362,46 +374,48 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
if (server->posix_ext_supported)
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) {
ses = list_entry(tmp2, struct cifs_ses,
smb_ses_list);
i++;
if ((ses->serverDomain == NULL) ||
(ses->serverOS == NULL) ||
(ses->serverNOS == NULL)) {
seq_printf(m, "\n%d) Name: %s Uses: %d Capability: 0x%x\tSession Status: %d ",
i, ses->serverName, ses->ses_count,
seq_printf(m, "\n\t%d) Address: %s Uses: %d Capability: 0x%x\tSession Status: %d ",
i, ses->ip_addr, ses->ses_count,
ses->capabilities, ses->status);
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)
seq_printf(m, "Anonymous\t");
seq_printf(m, "Anonymous ");
} else {
seq_printf(m,
"\n%d) Name: %s Domain: %s Uses: %d OS:"
" %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB"
" session status: %d ",
i, ses->serverName, ses->serverDomain,
"\n\t%d) Name: %s Domain: %s Uses: %d OS: %s "
"\n\tNOS: %s\tCapability: 0x%x"
"\n\tSMB session status: %d ",
i, ses->ip_addr, ses->serverDomain,
ses->ses_count, ses->serverOS, ses->serverNOS,
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)));
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 */
seq_printf(m, " SessionId: 0x%llx", ses->Suid);
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)
from_kuid(&init_user_ns, ses->cred_uid));
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);
for (j = 1; j < ses->chan_count; j++)
cifs_dump_channel(m, j, &ses->chans[j]);
}
seq_puts(m, "\n\n\tShares:");
seq_puts(m, "\n\n\tShares: ");
j = 0;
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)
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);
if (ses->iface_count)
seq_printf(m, "\n\tServer interfaces: %zu\n",
seq_printf(m, "\n\n\tServer interfaces: %zu",
ses->iface_count);
for (j = 0; j < ses->iface_count; j++) {
struct cifs_server_iface *iface;
iface = &ses->iface_list[j];
seq_printf(m, "\t%d)", j);
seq_printf(m, "\n\t%d)", j+1);
cifs_dump_iface(m, iface);
if (is_ses_using_iface(ses, iface))
seq_puts(m, "\t\t[CONNECTED]\n");
}
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);
seq_putc(m, '\n');
......
......@@ -272,7 +272,7 @@ static struct cifs_swn_reg *cifs_find_swn_reg(struct cifs_tcon *tcon)
if (IS_ERR(share_name)) {
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",
__func__, tcon->treeName, ret);
kfree(net_name);
......
This diff is collapsed.
......@@ -31,8 +31,8 @@
#define EXEC_BIT 0x1
#define ACL_OWNER_MASK 0700
#define ACL_GROUP_MASK 0770
#define ACL_EVERYONE_MASK 0777
#define ACL_GROUP_MASK 0070
#define ACL_EVERYONE_MASK 0007
#define UBITSHIFT 6
#define GBITSHIFT 3
......
......@@ -568,15 +568,15 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
return rc;
}
} else {
/* We use ses->serverName if no domain name available */
len = strlen(ses->serverName);
/* We use ses->ip_addr if no domain name available */
len = strlen(ses->ip_addr);
server = kmalloc(2 + (len * 2), GFP_KERNEL);
if (server == NULL) {
rc = -ENOMEM;
return rc;
}
len = cifs_strtoUTF16((__le16 *)server, ses->serverName, len,
len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len,
nls_cp);
rc =
crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
......
......@@ -638,8 +638,18 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
seq_printf(s, ",snapshot=%llu", tcon->snapshot_time);
if (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)
seq_printf(s, ",multichannel,max_channels=%zu",
......@@ -1526,6 +1536,7 @@ init_cifs(void)
*/
atomic_set(&sesInfoAllocCount, 0);
atomic_set(&tconInfoAllocCount, 0);
atomic_set(&tcpSesNextId, 0);
atomic_set(&tcpSesAllocCount, 0);
atomic_set(&tcpSesReconnectCount, 0);
atomic_set(&tconInfoReconnectCount, 0);
......
......@@ -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;
#endif /* CONFIG_CIFS_NFSD_EXPORT */
#define CIFS_VERSION "2.30"
#define CIFS_VERSION "2.31"
#endif /* _CIFSFS_H */
......@@ -21,6 +21,7 @@
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/inet.h>
#include <linux/slab.h>
#include <linux/mempool.h>
#include <linux/workqueue.h>
......@@ -504,6 +505,8 @@ struct smb_version_operations {
loff_t (*llseek)(struct file *, struct cifs_tcon *, loff_t, int);
/* Check for STATUS_IO_TIMEOUT */
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 {
......@@ -577,6 +580,7 @@ inc_rfc1001_len(void *buf, int count)
struct TCP_Server_Info {
struct list_head tcp_ses_list;
struct list_head smb_ses_list;
__u64 conn_id; /* connection identifier (useful for debugging) */
int srv_count; /* reference counter */
/* 15 character server name + 0x20 16th byte indicating type = srv */
char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
......@@ -901,7 +905,7 @@ struct cifs_ses {
kuid_t linux_uid; /* overriding owner of files on the mount */
kuid_t cred_uid; /* owner of credentials */
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
and after mount option parsing we fill it */
char *domainName;
......@@ -1704,7 +1708,9 @@ static inline bool is_retryable_error(int error)
#define CIFS_ECHO_OP 0x080 /* echo request */
#define CIFS_OBREAK_OP 0x0100 /* oplock break 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_TRANSFORM_REQ 0x0800 /* transform request before sending */
......@@ -1844,6 +1850,7 @@ GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above & list operations */
*/
GLOBAL_EXTERN atomic_t sesInfoAllocCount;
GLOBAL_EXTERN atomic_t tconInfoAllocCount;
GLOBAL_EXTERN atomic_t tcpSesNextId;
GLOBAL_EXTERN atomic_t tcpSesAllocCount;
GLOBAL_EXTERN atomic_t tcpSesReconnectCount;
GLOBAL_EXTERN atomic_t tconInfoReconnectCount;
......
......@@ -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 int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
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,
struct page *page,
unsigned int page_offset,
......
......@@ -1451,9 +1451,9 @@ cifs_discard_remaining_data(struct TCP_Server_Info *server)
while (remaining > 0) {
int length;
length = cifs_read_from_socket(server, server->bigbuf,
min_t(unsigned int, remaining,
CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
length = cifs_discard_from_socket(server,
min_t(size_t, remaining,
CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
if (length < 0)
return length;
server->total_read += length;
......
This diff is collapsed.
......@@ -37,11 +37,12 @@ struct cache_dfs_tgt {
struct cache_entry {
struct hlist_node hlist;
const char *path;
int ttl;
int srvtype;
int flags;
int hdr_flags; /* RESP_GET_DFS_REFERRAL.ReferralHeaderFlags */
int ttl; /* DFS_REREFERRAL_V3.TimeToLive */
int srvtype; /* DFS_REREFERRAL_V3.ServerType */
int ref_flags; /* DFS_REREFERRAL_V3.ReferralEntryFlags */
struct timespec64 etime;
int path_consumed;
int path_consumed; /* RESP_GET_DFS_REFERRAL.PathConsumed */
int numtgts;
struct list_head tlist;
struct cache_dfs_tgt *tgthint;
......@@ -166,14 +167,11 @@ static int dfscache_proc_show(struct seq_file *m, void *v)
continue;
seq_printf(m,
"cache entry: path=%s,type=%s,ttl=%d,etime=%ld,"
"interlink=%s,path_consumed=%d,expired=%s\n",
ce->path,
ce->srvtype == DFS_TYPE_ROOT ? "root" : "link",
ce->ttl, ce->etime.tv_nsec,
IS_INTERLINK_SET(ce->flags) ? "yes" : "no",
ce->path_consumed,
cache_entry_expired(ce) ? "yes" : "no");
"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->srvtype == DFS_TYPE_ROOT ? "root" : "link",
ce->ttl, ce->etime.tv_nsec, ce->ref_flags, ce->hdr_flags,
IS_INTERLINK_SET(ce->hdr_flags) ? "yes" : "no",
ce->path_consumed, cache_entry_expired(ce) ? "yes" : "no");
list_for_each_entry(t, &ce->tlist, list) {
seq_printf(m, " %s%s\n",
......@@ -236,11 +234,12 @@ static inline void dump_tgts(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->srvtype == DFS_TYPE_ROOT ? "root" : "link", ce->ttl,
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,
cache_entry_expired(ce) ? "yes" : "no");
dump_tgts(ce);
......@@ -381,7 +380,8 @@ static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs,
ce->ttl = refs[0].ttl;
ce->etime = get_expire_time(ce->ttl);
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;
for (i = 0; i < numrefs; i++) {
......@@ -799,7 +799,8 @@ static int setup_referral(const char *path, struct cache_entry *ce,
ref->path_consumed = ce->path_consumed;
ref->ttl = ce->ttl;
ref->server_type = ce->srvtype;
ref->ref_flag = ce->flags;
ref->ref_flag = ce->ref_flags;
ref->flags = ce->hdr_flags;
return 0;
......
......@@ -580,7 +580,7 @@ int cifs_open(struct inode *inode, struct file *file)
} else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
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",
tcon->ses->serverName,
tcon->ses->ip_addr,
tcon->ses->serverNOS);
tcon->broken_posix_open = true;
} else if ((rc != -EIO) && (rc != -EREMOTE) &&
......
......@@ -140,6 +140,8 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
fsparam_u32("rsize", Opt_rsize),
fsparam_u32("wsize", Opt_wsize),
fsparam_u32("actimeo", Opt_actimeo),
fsparam_u32("acdirmax", Opt_acdirmax),
fsparam_u32("acregmax", Opt_acregmax),
fsparam_u32("echo_interval", Opt_echo_interval),
fsparam_u32("max_credits", Opt_max_credits),
fsparam_u32("handletimeout", Opt_handletimeout),
......@@ -397,7 +399,7 @@ cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3)
ctx->vals = &smb3any_values;
break;
case Smb_default:
ctx->ops = &smb30_operations; /* currently identical with 3.0 */
ctx->ops = &smb30_operations;
ctx->vals = &smbdefault_values;
break;
default:
......@@ -542,20 +544,37 @@ static int smb3_fs_context_parse_monolithic(struct fs_context *fc,
/* BB Need to add support for sep= here TBD */
while ((key = strsep(&options, ",")) != NULL) {
if (*key) {
size_t v_len = 0;
char *value = strchr(key, '=');
if (value) {
if (value == key)
continue;
*value++ = 0;
v_len = strlen(value);
}
ret = vfs_parse_fs_string(fc, key, value, v_len);
if (ret < 0)
break;
size_t len;
char *value;
if (*key == 0)
break;
/* Check if following character is the deliminator If yes,
* we have encountered a double deliminator reset the NULL
* character to the deliminator
*/
while (options && options[0] == ',') {
len = strlen(key);
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;
......@@ -929,12 +948,31 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
ctx->wsize = result.uint_32;
ctx->got_wsize = true;
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:
ctx->actimeo = HZ * result.uint_32;
if (ctx->actimeo > CIFS_MAX_ACTIMEO) {
cifs_dbg(VFS, "attribute cache timeout too large\n");
if (HZ * result.uint_32 > CIFS_MAX_ACTIMEO) {
cifs_dbg(VFS, "timeout too large\n");
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;
case Opt_echo_interval:
ctx->echo_interval = result.uint_32;
......@@ -1361,7 +1399,8 @@ int smb3_init_fs_context(struct fs_context *fc)
/* default is to use strict cifs caching semantics */
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 */
ctx->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */
......
......@@ -118,6 +118,8 @@ enum cifs_param {
Opt_rsize,
Opt_wsize,
Opt_actimeo,
Opt_acdirmax,
Opt_acregmax,
Opt_echo_interval,
Opt_max_credits,
Opt_snapshot,
......@@ -232,7 +234,9 @@ struct smb3_fs_context {
unsigned int wsize;
unsigned int min_offload;
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_values *vals;
char *prepath;
......
......@@ -2199,12 +2199,23 @@ cifs_inode_needs_reval(struct inode *inode)
if (!lookupCacheEnabled)
return true;
if (!cifs_sb->ctx->actimeo)
return true;
if (!time_in_range(jiffies, cifs_i->time,
cifs_i->time + cifs_sb->ctx->actimeo))
return true;
/*
* depending on inode type, check if attribute caching disabled for
* files or directories
*/
if (S_ISDIR(inode->i_mode)) {
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 */
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,
/* UNC and paths */
/* XXX: Use ses->server->hostname? */
sprintf(unc, unc_fmt, ses->serverName);
sprintf(unc, unc_fmt, ses->ip_addr);
ctx.UNC = unc;
ctx.prepath = "";
......
......@@ -63,17 +63,19 @@ smb2_add_credits(struct TCP_Server_Info *server,
const struct cifs_credits *credits, const int optype)
{
int *val, rc = -1;
int scredits, in_flight;
unsigned int add = credits->value;
unsigned int instance = credits->instance;
bool reconnect_detected = false;
bool reconnect_with_invalid_credits = false;
spin_lock(&server->req_lock);
val = server->ops->get_credits_field(server, optype);
/* eg found case where write overlapping reconnect messed up credits */
if (((optype & CIFS_OP_MASK) == CIFS_NEG_OP) && (*val != 0))
trace_smb3_reconnect_with_invalid_credits(server->CurrentMid,
server->hostname, *val, add);
reconnect_with_invalid_credits = true;
if ((instance == 0) || (instance == server->reconnect_instance))
*val += add;
else
......@@ -84,7 +86,9 @@ smb2_add_credits(struct TCP_Server_Info *server,
pr_warn_once("server overflowed SMB3 credits\n");
}
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);
/*
* Sometimes server returns 0 credits on oplock break ack - we need to
......@@ -97,14 +101,26 @@ smb2_add_credits(struct TCP_Server_Info *server,
server->oplock_credits++;
}
}
scredits = *val;
in_flight = server->in_flight;
spin_unlock(&server->req_lock);
wake_up(&server->request_q);
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",
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
|| server->tcpStatus == CifsExiting)
return;
......@@ -123,23 +139,30 @@ smb2_add_credits(struct TCP_Server_Info *server,
cifs_dbg(FYI, "disabling oplocks\n");
break;
default:
trace_smb3_add_credits(server->CurrentMid,
server->hostname, rc, add);
cifs_dbg(FYI, "%s: added %u credits total=%d\n", __func__, add, rc);
/* change_conf rebalanced credits for different types */
break;
}
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
smb2_set_credits(struct TCP_Server_Info *server, const int val)
{
int scredits, in_flight;
spin_lock(&server->req_lock);
server->credits = val;
if (val == 1)
server->reconnect_instance++;
scredits = server->credits;
in_flight = server->in_flight;
spin_unlock(&server->req_lock);
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);
/* don't log while holding the lock */
......@@ -171,7 +194,7 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
unsigned int *num, struct cifs_credits *credits)
{
int rc = 0;
unsigned int scredits;
unsigned int scredits, in_flight;
spin_lock(&server->req_lock);
while (1) {
......@@ -208,17 +231,18 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE);
credits->instance = server->reconnect_instance;
server->credits -= credits->value;
scredits = server->credits;
server->in_flight++;
if (server->in_flight > server->max_in_flight)
server->max_in_flight = server->in_flight;
break;
}
}
scredits = server->credits;
in_flight = server->in_flight;
spin_unlock(&server->req_lock);
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",
__func__, credits->value, scredits);
......@@ -231,14 +255,14 @@ smb2_adjust_credits(struct TCP_Server_Info *server,
const unsigned int payload_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)
return 0;
if (credits->value < new_val) {
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)",
credits->value, new_val);
......@@ -248,9 +272,13 @@ smb2_adjust_credits(struct TCP_Server_Info *server,
spin_lock(&server->req_lock);
if (server->reconnect_instance != credits->instance) {
scredits = server->credits;
in_flight = server->in_flight;
spin_unlock(&server->req_lock);
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",
credits->value - new_val);
return -EAGAIN;
......@@ -258,15 +286,18 @@ smb2_adjust_credits(struct TCP_Server_Info *server,
server->credits += credits->value - new_val;
scredits = server->credits;
in_flight = server->in_flight;
spin_unlock(&server->req_lock);
wake_up(&server->request_q);
credits->value = new_val;
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",
__func__, credits->value - new_val, scredits);
credits->value = new_val;
return 0;
}
......@@ -2369,7 +2400,7 @@ static bool
smb2_is_status_pending(char *buf, struct TCP_Server_Info *server)
{
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
int scredits;
int scredits, in_flight;
if (shdr->Status != STATUS_PENDING)
return false;
......@@ -2378,11 +2409,13 @@ smb2_is_status_pending(char *buf, struct TCP_Server_Info *server)
spin_lock(&server->req_lock);
server->credits += le16_to_cpu(shdr->CreditRequest);
scredits = server->credits;
in_flight = server->in_flight;
spin_unlock(&server->req_lock);
wake_up(&server->request_q);
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",
__func__, le16_to_cpu(shdr->CreditRequest), scredits);
}
......@@ -2418,6 +2451,34 @@ smb2_is_status_io_timeout(char *buf)
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
smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
struct cifsInodeInfo *cinode)
......@@ -4605,6 +4666,10 @@ static void smb2_decrypt_offload(struct work_struct *work)
#ifdef CONFIG_CIFS_STATS2
mid->when_received = jiffies;
#endif
if (dw->server->ops->is_network_name_deleted)
dw->server->ops->is_network_name_deleted(dw->buf,
dw->server);
mid->callback(mid);
} else {
spin_lock(&GlobalMid_Lock);
......@@ -4723,6 +4788,12 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid,
rc = handle_read_data(server, *mid, buf,
server->vals->read_rsp_size,
pages, npages, len, false);
if (rc >= 0) {
if (server->ops->is_network_name_deleted) {
server->ops->is_network_name_deleted(buf,
server);
}
}
}
free_pages:
......@@ -5072,6 +5143,7 @@ struct smb_version_operations smb20_operations = {
.fiemap = smb3_fiemap,
.llseek = smb3_llseek,
.is_status_io_timeout = smb2_is_status_io_timeout,
.is_network_name_deleted = smb2_is_network_name_deleted,
};
struct smb_version_operations smb21_operations = {
......@@ -5173,6 +5245,7 @@ struct smb_version_operations smb21_operations = {
.fiemap = smb3_fiemap,
.llseek = smb3_llseek,
.is_status_io_timeout = smb2_is_status_io_timeout,
.is_network_name_deleted = smb2_is_network_name_deleted,
};
struct smb_version_operations smb30_operations = {
......@@ -5286,6 +5359,7 @@ struct smb_version_operations smb30_operations = {
.fiemap = smb3_fiemap,
.llseek = smb3_llseek,
.is_status_io_timeout = smb2_is_status_io_timeout,
.is_network_name_deleted = smb2_is_network_name_deleted,
};
struct smb_version_operations smb311_operations = {
......@@ -5399,6 +5473,7 @@ struct smb_version_operations smb311_operations = {
.fiemap = smb3_fiemap,
.llseek = smb3_llseek,
.is_status_io_timeout = smb2_is_status_io_timeout,
.is_network_name_deleted = smb2_is_network_name_deleted,
};
struct smb_version_values smb20_values = {
......
......@@ -814,8 +814,9 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
SMB3ANY_VERSION_STRING) == 0) {
req->Dialects[0] = cpu_to_le16(SMB30_PROT_ID);
req->Dialects[1] = cpu_to_le16(SMB302_PROT_ID);
req->DialectCount = cpu_to_le16(2);
total_len += 4;
req->Dialects[2] = cpu_to_le16(SMB311_PROT_ID);
req->DialectCount = cpu_to_le16(3);
total_len += 6;
} else if (strcmp(server->vals->version_string,
SMBDEFAULT_VERSION_STRING) == 0) {
req->Dialects[0] = cpu_to_le16(SMB21_PROT_ID);
......@@ -848,6 +849,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
memcpy(req->ClientGUID, server->client_guid,
SMB2_CLIENT_GUID_SIZE);
if ((server->vals->protocol_id == SMB311_PROT_ID) ||
(strcmp(server->vals->version_string,
SMB3ANY_VERSION_STRING) == 0) ||
(strcmp(server->vals->version_string,
SMBDEFAULT_VERSION_STRING) == 0))
assemble_neg_contexts(req, server, &total_len);
......@@ -883,6 +886,10 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
cifs_server_dbg(VFS,
"SMB2.1 dialect returned but not requested\n");
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,
SMBDEFAULT_VERSION_STRING) == 0) {
......@@ -1042,10 +1049,11 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
SMB3ANY_VERSION_STRING) == 0) {
pneg_inbuf->Dialects[0] = cpu_to_le16(SMB30_PROT_ID);
pneg_inbuf->Dialects[1] = cpu_to_le16(SMB302_PROT_ID);
pneg_inbuf->DialectCount = cpu_to_le16(2);
/* structure is big enough for 3 dialects, sending only 2 */
pneg_inbuf->Dialects[2] = cpu_to_le16(SMB311_PROT_ID);
pneg_inbuf->DialectCount = cpu_to_le16(3);
/* SMB 2.1 not included so subtract one dialect from len */
inbuflen = sizeof(*pneg_inbuf) -
(2 * sizeof(pneg_inbuf->Dialects[0]));
(sizeof(pneg_inbuf->Dialects[0]));
} else if (strcmp(server->vals->version_string,
SMBDEFAULT_VERSION_STRING) == 0) {
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)
pneg_inbuf->Dialects[2] = cpu_to_le16(SMB302_PROT_ID);
pneg_inbuf->Dialects[3] = cpu_to_le16(SMB311_PROT_ID);
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);
} else {
/* otherwise specific dialect was requested */
......@@ -1253,7 +1261,7 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
cifs_ses_server(sess_data->ses),
&rqst,
&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);
memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec));
......
......@@ -851,17 +851,21 @@ DEFINE_SMB3_LEASE_ERR_EVENT(lease_err);
DECLARE_EVENT_CLASS(smb3_reconnect_class,
TP_PROTO(__u64 currmid,
__u64 conn_id,
char *hostname),
TP_ARGS(currmid, hostname),
TP_ARGS(currmid, conn_id, hostname),
TP_STRUCT__entry(
__field(__u64, currmid)
__field(__u64, conn_id)
__field(char *, hostname)
),
TP_fast_assign(
__entry->currmid = currmid;
__entry->conn_id = conn_id;
__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->currmid)
)
......@@ -869,44 +873,56 @@ DECLARE_EVENT_CLASS(smb3_reconnect_class,
#define DEFINE_SMB3_RECONNECT_EVENT(name) \
DEFINE_EVENT(smb3_reconnect_class, smb3_##name, \
TP_PROTO(__u64 currmid, \
char *hostname), \
TP_ARGS(currmid, hostname))
__u64 conn_id, \
char *hostname), \
TP_ARGS(currmid, conn_id, hostname))
DEFINE_SMB3_RECONNECT_EVENT(reconnect);
DEFINE_SMB3_RECONNECT_EVENT(partial_send_reconnect);
DECLARE_EVENT_CLASS(smb3_credit_class,
TP_PROTO(__u64 currmid,
__u64 conn_id,
char *hostname,
int credits,
int credits_to_add),
TP_ARGS(currmid, hostname, credits, credits_to_add),
int credits_to_add,
int in_flight),
TP_ARGS(currmid, conn_id, hostname, credits, credits_to_add, in_flight),
TP_STRUCT__entry(
__field(__u64, currmid)
__field(__u64, conn_id)
__field(char *, hostname)
__field(int, credits)
__field(int, credits_to_add)
__field(int, in_flight)
),
TP_fast_assign(
__entry->currmid = currmid;
__entry->conn_id = conn_id;
__entry->hostname = hostname;
__entry->credits = credits;
__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->currmid,
__entry->credits,
__entry->credits_to_add)
__entry->credits_to_add,
__entry->in_flight)
)
#define DEFINE_SMB3_CREDIT_EVENT(name) \
DEFINE_EVENT(smb3_credit_class, smb3_##name, \
TP_PROTO(__u64 currmid, \
__u64 conn_id, \
char *hostname, \
int credits, \
int credits_to_add), \
TP_ARGS(currmid, hostname, credits, credits_to_add))
int 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_detected);
......
......@@ -445,7 +445,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
*/
server->tcpStatus = CifsNeedReconnect;
trace_smb3_partial_send_reconnect(server->CurrentMid,
server->hostname);
server->conn_id, server->hostname);
}
smbd_done:
if (rc < 0 && rc != -EINTR)
......@@ -527,7 +527,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
int *credits;
int optype;
long int t;
int scredits = server->credits;
int scredits, in_flight;
if (timeout < 0)
t = MAX_JIFFY_OFFSET;
......@@ -551,23 +551,39 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
server->max_in_flight = server->in_flight;
*credits -= 1;
*instance = server->reconnect_instance;
scredits = *credits;
in_flight = server->in_flight;
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;
}
while (1) {
if (*credits < num_credits) {
scredits = *credits;
spin_unlock(&server->req_lock);
cifs_num_waiters_inc(server);
rc = wait_event_killable_timeout(server->request_q,
has_credits(server, credits, num_credits), t);
cifs_num_waiters_dec(server);
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,
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",
timeout);
return -ENOTSUPP;
timeout);
return -EBUSY;
}
if (rc == -ERESTARTSYS)
return -ERESTARTSYS;
......@@ -595,6 +611,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
server->in_flight > 2 * MAX_COMPOUND &&
*credits <= MAX_COMPOUND) {
spin_unlock(&server->req_lock);
cifs_num_waiters_inc(server);
rc = wait_event_killable_timeout(
server->request_q,
......@@ -603,13 +620,18 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
t);
cifs_num_waiters_dec(server);
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,
server->hostname, num_credits,
0);
server->CurrentMid,
server->conn_id, server->hostname,
scredits, num_credits, in_flight);
cifs_server_dbg(VFS, "wait timed out after %d ms\n",
timeout);
return -ENOTSUPP;
timeout);
return -EBUSY;
}
if (rc == -ERESTARTSYS)
return -ERESTARTSYS;
......@@ -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 */
if ((flags & CIFS_TIMEOUT_MASK) != CIFS_BLOCKING_OP) {
*credits -= num_credits;
scredits = *credits;
server->in_flight += num_credits;
if (server->in_flight > server->max_in_flight)
server->max_in_flight = server->in_flight;
*instance = server->reconnect_instance;
}
scredits = *credits;
in_flight = server->in_flight;
spin_unlock(&server->req_lock);
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",
__func__, num_credits, scredits);
break;
......@@ -656,13 +680,13 @@ wait_for_compound_request(struct TCP_Server_Info *server, int num,
const int flags, unsigned int *instance)
{
int *credits;
int scredits, sin_flight;
int scredits, in_flight;
credits = server->ops->get_credits_field(server, flags & CIFS_OP_MASK);
spin_lock(&server->req_lock);
scredits = *credits;
sin_flight = server->in_flight;
in_flight = server->in_flight;
if (*credits < num) {
/*
......@@ -684,10 +708,11 @@ wait_for_compound_request(struct TCP_Server_Info *server, int num,
if (server->in_flight == 0) {
spin_unlock(&server->req_lock);
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",
__func__, sin_flight, num, scredits);
return -ENOTSUPP;
__func__, in_flight, num, scredits);
return -EDEADLK;
}
}
spin_unlock(&server->req_lock);
......@@ -1171,7 +1196,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
/*
* 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,
rqst[0].rq_nvec);
......@@ -1236,7 +1261,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
/*
* 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 = {
.iov_base = resp_iov[0].iov_base,
.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