smb3/cifs fixes (including 8 for stable). Improved tracing, stats, snapshots (previous version mounts work now), performance (compounding enabled for statfs)
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAltwwVkACgkQiiy9cAdy T1H06gv/d+b52w2X05YlLBB1GboJjv1dl3sVrFisJrMrCCr6Hotk+4+RtC8CJHh6 /9Joq6iY8B/XLl7HrWr61vJhn8vlWOGhOQaUmHCBGeiIMX93RbaP8KvkPfHAKQiJ T6+7v70z/WL7mUQA2TEQ3Iz6kpCuP2y/XT6eQglTFXasqsWHy08TbsbnmP9yX2i4 E1B6zMwpn6m4PFxEURg14eBJTrQomb/UBSLHNwxwwOQjnKzsmeH3pyiFCJSPJNFF Xv/lyBibgvQAsuWtLTi82fqei+c60as2LVrsFLdoWXeD6JMlx1O+SHSz0NNJL/Lk oxMNx9NI+LsYmekIBHgoX01PzVgCpcn6ThfoQv3JLHtqiZuk3Wlai7bPvJMIApoM 8fgHGR9xvhRCfHgYvxx4MmP3e7xewajSe7fh8/y8BqreO+fLeoyqho5G9zDpn6bU wGFPtVYW/fgTEM5E3NOjsuC1zE35bjwU7U40jqjGHP1VsTs3hkLFy9fZNNq4EP1M ytfJPlTG =gzZK -----END PGP SIGNATURE----- Merge tag '4.19-smb3' of git://git.samba.org/sfrench/cifs-2.6 Pull cifs updates from Steve French: "smb3/cifs fixes (including 8 for stable). Other improvements include: - improved tracing, improved stats - snapshots (previous version mounts work now over SMB3) - performance (compounding enabled for statfs, ~40% faster). - security (make it possible to build cifs.ko with insecure vers=1.0 disabled in Kconfig)" * tag '4.19-smb3' of git://git.samba.org/sfrench/cifs-2.6: (43 commits) smb3: create smb3 equivalent alias for cifs pseudo-xattrs smb3: allow previous versions to be mounted with snapshot= mount parm cifs: don't show domain= in mount output when domain is empty cifs: add missing support for ACLs in SMB 3.11 smb3: enumerating snapshots was leaving part of the data off end cifs: update smb2_queryfs() to use compounding cifs: update receive_encrypted_standard to handle compounded responses cifs: create SMB2_open_init()/SMB2_open_free() helpers. cifs: add SMB2_query_info_[init|free]() cifs: add SMB2_close_init()/SMB2_close_free() smb3: display stats counters for number of slow commands CIFS: fix uninitialized ptr deref in smb2 signing smb3: Do not send SMB3 SET_INFO if nothing changed smb3: fix minor debug output for CONFIG_CIFS_STATS smb3: add tracepoint for slow responses cifs: add compound_send_recv() cifs: make smb_send_rqst take an array of requests cifs: update init_sg, crypt_message to take an array of rqst smb3: update readme to correct information about /proc/fs/cifs/Stats smb3: fix reset of bytes read and written stats ...
This commit is contained in:
commit
3bb37da509
File diff suppressed because it is too large
Load Diff
|
@ -603,8 +603,7 @@ DebugData Displays information about active CIFS sessions and
|
|||
shares, features enabled as well as the cifs.ko
|
||||
version.
|
||||
Stats Lists summary resource usage information as well as per
|
||||
share statistics, if CONFIG_CIFS_STATS in enabled
|
||||
in the kernel configuration.
|
||||
share statistics.
|
||||
|
||||
Configuration pseudo-files:
|
||||
SecurityFlags Flags which control security negotiation and
|
||||
|
@ -687,23 +686,22 @@ cifsFYI functions as a bit mask. Setting it to 1 enables additional kernel
|
|||
logging of various informational messages. 2 enables logging of non-zero
|
||||
SMB return codes while 4 enables logging of requests that take longer
|
||||
than one second to complete (except for byte range lock requests).
|
||||
Setting it to 4 requires defining CONFIG_CIFS_STATS2 manually in the
|
||||
source code (typically by setting it in the beginning of cifsglob.h),
|
||||
and setting it to seven enables all three. Finally, tracing
|
||||
Setting it to 4 requires CONFIG_CIFS_STATS2 to be set in kernel configuration
|
||||
(.config). Setting it to seven enables all three. Finally, tracing
|
||||
the start of smb requests and responses can be enabled via:
|
||||
|
||||
echo 1 > /proc/fs/cifs/traceSMB
|
||||
|
||||
Per share (per client mount) statistics are available in /proc/fs/cifs/Stats
|
||||
if the kernel was configured with cifs statistics enabled. The statistics
|
||||
represent the number of successful (ie non-zero return code from the server)
|
||||
SMB responses to some of the more common commands (open, delete, mkdir etc.).
|
||||
Per share (per client mount) statistics are available in /proc/fs/cifs/Stats.
|
||||
Additional information is available if CONFIG_CIFS_STATS2 is enabled in the
|
||||
kernel configuration (.config). The statistics returned include counters which
|
||||
represent the number of attempted and failed (ie non-zero return code from the
|
||||
server) SMB3 (or cifs) requests grouped by request type (read, write, close etc.).
|
||||
Also recorded is the total bytes read and bytes written to the server for
|
||||
that share. Note that due to client caching effects this can be less than the
|
||||
number of bytes read and written by the application running on the client.
|
||||
The statistics for the number of total SMBs and oplock breaks are different in
|
||||
that they represent all for that share, not just those for which the server
|
||||
returned success.
|
||||
Statistics can be reset to zero by "echo 0 > /proc/fs/cifs/Stats" which may be
|
||||
useful if comparing performance of two different scenarios.
|
||||
|
||||
Also note that "cat /proc/fs/cifs/DebugData" will display information about
|
||||
the active sessions and the shares that are mounted.
|
||||
|
|
|
@ -16,24 +16,28 @@ config CIFS
|
|||
select CRYPTO_DES
|
||||
help
|
||||
This is the client VFS module for the SMB3 family of NAS protocols,
|
||||
as well as for earlier dialects such as SMB2.1, SMB2 and the
|
||||
(including support for the most recent, most secure dialect SMB3.1.1)
|
||||
as well as for earlier dialects such as SMB2.1, SMB2 and the older
|
||||
Common Internet File System (CIFS) protocol. CIFS was the successor
|
||||
to the original dialect, the Server Message Block (SMB) protocol, the
|
||||
native file sharing mechanism for most early PC operating systems.
|
||||
|
||||
The SMB3 protocol is supported by most modern operating systems and
|
||||
NAS appliances (e.g. Samba, Windows 8, Windows 2012, MacOS).
|
||||
The SMB3 protocol is supported by most modern operating systems
|
||||
and NAS appliances (e.g. Samba, Windows 10, Windows Server 2016,
|
||||
MacOS) and even in the cloud (e.g. Microsoft Azure).
|
||||
The older CIFS protocol was included in Windows NT4, 2000 and XP (and
|
||||
later) as well by Samba (which provides excellent CIFS and SMB3
|
||||
server support for Linux and many other operating systems). Limited
|
||||
support for OS/2 and Windows ME and similar very old servers is
|
||||
provided as well.
|
||||
server support for Linux and many other operating systems). Use of
|
||||
dialects older than SMB2.1 is often discouraged on public networks.
|
||||
This module also provides limited support for OS/2 and Windows ME
|
||||
and similar very old servers.
|
||||
|
||||
The cifs module provides an advanced network file system client
|
||||
This module provides an advanced network file system client
|
||||
for mounting to SMB3 (and CIFS) compliant servers. It includes
|
||||
support for DFS (hierarchical name space), secure per-user
|
||||
session establishment via Kerberos or NTLM or NTLMv2,
|
||||
safe distributed caching (oplock), optional packet
|
||||
session establishment via Kerberos or NTLM or NTLMv2, RDMA
|
||||
(smbdirect), advanced security features, per-share encryption,
|
||||
directory leases, safe distributed caching (oplock), optional packet
|
||||
signing, Unicode and other internationalization improvements.
|
||||
|
||||
In general, the default dialects, SMB3 and later, enable better
|
||||
|
@ -43,18 +47,11 @@ config CIFS
|
|||
than SMB3 mounts. SMB2/SMB3 mount options are also
|
||||
slightly simpler (compared to CIFS) due to protocol improvements.
|
||||
|
||||
If you need to mount to Samba, Macs or Windows from this machine, say Y.
|
||||
|
||||
config CIFS_STATS
|
||||
bool "CIFS statistics"
|
||||
depends on CIFS
|
||||
help
|
||||
Enabling this option will cause statistics for each server share
|
||||
mounted by the cifs client to be displayed in /proc/fs/cifs/Stats
|
||||
If you need to mount to Samba, Azure, Macs or Windows from this machine, say Y.
|
||||
|
||||
config CIFS_STATS2
|
||||
bool "Extended statistics"
|
||||
depends on CIFS_STATS
|
||||
depends on CIFS
|
||||
help
|
||||
Enabling this option will allow more detailed statistics on SMB
|
||||
request timing to be displayed in /proc/fs/cifs/DebugData and also
|
||||
|
@ -66,9 +63,24 @@ config CIFS_STATS2
|
|||
Unless you are a developer or are doing network performance analysis
|
||||
or tuning, say N.
|
||||
|
||||
config CIFS_ALLOW_INSECURE_LEGACY
|
||||
bool "Support legacy servers which use less secure dialects"
|
||||
depends on CIFS
|
||||
default y
|
||||
help
|
||||
Modern dialects, SMB2.1 and later (including SMB3 and 3.1.1), have
|
||||
additional security features, including protection against
|
||||
man-in-the-middle attacks and stronger crypto hashes, so the use
|
||||
of legacy dialects (SMB1/CIFS and SMB2.0) is discouraged.
|
||||
|
||||
Disabling this option prevents users from using vers=1.0 or vers=2.0
|
||||
on mounts with cifs.ko
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config CIFS_WEAK_PW_HASH
|
||||
bool "Support legacy servers which use weaker LANMAN security"
|
||||
depends on CIFS
|
||||
depends on CIFS && CIFS_ALLOW_INSECURE_LEGACY
|
||||
help
|
||||
Modern CIFS servers including Samba and most Windows versions
|
||||
(since 1997) support stronger NTLM (and even NTLMv2 and Kerberos)
|
||||
|
@ -186,15 +198,6 @@ config CIFS_NFSD_EXPORT
|
|||
help
|
||||
Allows NFS server to export a CIFS mounted share (nfsd over cifs)
|
||||
|
||||
config CIFS_SMB311
|
||||
bool "SMB3.1.1 network file system support"
|
||||
depends on CIFS
|
||||
select CRYPTO_SHA512
|
||||
|
||||
help
|
||||
This enables support for the newest, and most secure dialect, SMB3.11.
|
||||
If unsure, say Y
|
||||
|
||||
config CIFS_SMB_DIRECT
|
||||
bool "SMB Direct support (Experimental)"
|
||||
depends on CIFS=m && INFINIBAND && INFINIBAND_ADDR_TRANS || CIFS=y && INFINIBAND=y && INFINIBAND_ADDR_TRANS=y
|
||||
|
|
|
@ -128,8 +128,10 @@ fscache_checkaux cifs_fscache_inode_check_aux(void *cookie_netfs_data,
|
|||
|
||||
memset(&auxdata, 0, sizeof(auxdata));
|
||||
auxdata.eof = cifsi->server_eof;
|
||||
auxdata.last_write_time = timespec64_to_timespec(cifsi->vfs_inode.i_mtime);
|
||||
auxdata.last_change_time = timespec64_to_timespec(cifsi->vfs_inode.i_ctime);
|
||||
auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec;
|
||||
auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec;
|
||||
auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec;
|
||||
auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec;
|
||||
|
||||
if (memcmp(data, &auxdata, datalen) != 0)
|
||||
return FSCACHE_CHECKAUX_OBSOLETE;
|
||||
|
|
|
@ -160,25 +160,41 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
|
|||
seq_printf(m, "CIFS Version %s\n", CIFS_VERSION);
|
||||
seq_printf(m, "Features:");
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
seq_printf(m, " dfs");
|
||||
seq_printf(m, " DFS");
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_FSCACHE
|
||||
seq_printf(m, " fscache");
|
||||
seq_printf(m, ",FSCACHE");
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
seq_printf(m, ",SMB_DIRECT");
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
seq_printf(m, ",STATS2");
|
||||
#else
|
||||
seq_printf(m, ",STATS");
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
seq_printf(m, ",DEBUG2");
|
||||
#elif defined(CONFIG_CIFS_DEBUG)
|
||||
seq_printf(m, ",DEBUG");
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
|
||||
seq_printf(m, ",ALLOW_INSECURE_LEGACY");
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
seq_printf(m, " lanman");
|
||||
seq_printf(m, ",WEAK_PW_HASH");
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_POSIX
|
||||
seq_printf(m, " posix");
|
||||
seq_printf(m, ",CIFS_POSIX");
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
seq_printf(m, " spnego");
|
||||
seq_printf(m, ",UPCALL(SPNEGO)");
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_XATTR
|
||||
seq_printf(m, " xattr");
|
||||
seq_printf(m, ",XATTR");
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
seq_printf(m, " acl");
|
||||
seq_printf(m, ",ACL");
|
||||
#endif
|
||||
seq_putc(m, '\n');
|
||||
seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
|
||||
|
@ -259,10 +275,9 @@ skip_rdma:
|
|||
server->credits, server->dialect);
|
||||
if (server->sign)
|
||||
seq_printf(m, " signed");
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if (server->posix_ext_supported)
|
||||
seq_printf(m, " posix");
|
||||
#endif /* 3.1.1 */
|
||||
|
||||
i++;
|
||||
list_for_each(tmp2, &server->smb_ses_list) {
|
||||
ses = list_entry(tmp2, struct cifs_ses,
|
||||
|
@ -350,7 +365,6 @@ skip_rdma:
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
static ssize_t cifs_stats_proc_write(struct file *file,
|
||||
const char __user *buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
|
@ -364,13 +378,23 @@ static ssize_t cifs_stats_proc_write(struct file *file,
|
|||
rc = kstrtobool_from_user(buffer, count, &bv);
|
||||
if (rc == 0) {
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
int i;
|
||||
|
||||
atomic_set(&totBufAllocCount, 0);
|
||||
atomic_set(&totSmBufAllocCount, 0);
|
||||
#endif /* CONFIG_CIFS_STATS2 */
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
GlobalMaxActiveXid = 0;
|
||||
GlobalCurrentXid = 0;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
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);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++)
|
||||
atomic_set(&server->smb2slowcmd[i], 0);
|
||||
#endif /* CONFIG_CIFS_STATS2 */
|
||||
list_for_each(tmp2, &server->smb_ses_list) {
|
||||
ses = list_entry(tmp2, struct cifs_ses,
|
||||
smb_ses_list);
|
||||
|
@ -379,6 +403,10 @@ static ssize_t cifs_stats_proc_write(struct file *file,
|
|||
struct cifs_tcon,
|
||||
tcon_list);
|
||||
atomic_set(&tcon->num_smbs_sent, 0);
|
||||
spin_lock(&tcon->stat_lock);
|
||||
tcon->bytes_read = 0;
|
||||
tcon->bytes_written = 0;
|
||||
spin_unlock(&tcon->stat_lock);
|
||||
if (server->ops->clear_stats)
|
||||
server->ops->clear_stats(tcon);
|
||||
}
|
||||
|
@ -395,13 +423,15 @@ static ssize_t cifs_stats_proc_write(struct file *file,
|
|||
static int cifs_stats_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
int i;
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
int j;
|
||||
#endif /* STATS2 */
|
||||
struct list_head *tmp1, *tmp2, *tmp3;
|
||||
struct TCP_Server_Info *server;
|
||||
struct cifs_ses *ses;
|
||||
struct cifs_tcon *tcon;
|
||||
|
||||
seq_printf(m,
|
||||
"Resources in use\nCIFS Session: %d\n",
|
||||
seq_printf(m, "Resources in use\nCIFS Session: %d\n",
|
||||
sesInfoAllocCount.counter);
|
||||
seq_printf(m, "Share (unique mount targets): %d\n",
|
||||
tconInfoAllocCount.counter);
|
||||
|
@ -430,6 +460,13 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
|
|||
list_for_each(tmp1, &cifs_tcp_ses_list) {
|
||||
server = list_entry(tmp1, struct TCP_Server_Info,
|
||||
tcp_ses_list);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
for (j = 0; j < NUMBER_OF_SMB2_COMMANDS; j++)
|
||||
if (atomic_read(&server->smb2slowcmd[j]))
|
||||
seq_printf(m, "%d slow responses from %s for command %d\n",
|
||||
atomic_read(&server->smb2slowcmd[j]),
|
||||
server->hostname, j);
|
||||
#endif /* STATS2 */
|
||||
list_for_each(tmp2, &server->smb_ses_list) {
|
||||
ses = list_entry(tmp2, struct cifs_ses,
|
||||
smb_ses_list);
|
||||
|
@ -466,7 +503,6 @@ static const struct file_operations cifs_stats_proc_fops = {
|
|||
.release = single_release,
|
||||
.write = cifs_stats_proc_write,
|
||||
};
|
||||
#endif /* STATS */
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
#define PROC_FILE_DEFINE(name) \
|
||||
|
@ -524,9 +560,7 @@ cifs_proc_init(void)
|
|||
proc_create_single("DebugData", 0, proc_fs_cifs,
|
||||
cifs_debug_data_proc_show);
|
||||
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
proc_create("Stats", 0644, proc_fs_cifs, &cifs_stats_proc_fops);
|
||||
#endif /* STATS */
|
||||
proc_create("cifsFYI", 0644, proc_fs_cifs, &cifsFYI_proc_fops);
|
||||
proc_create("traceSMB", 0644, proc_fs_cifs, &traceSMB_proc_fops);
|
||||
proc_create("LinuxExtensionsEnabled", 0644, proc_fs_cifs,
|
||||
|
@ -564,9 +598,7 @@ cifs_proc_clean(void)
|
|||
remove_proc_entry("DebugData", proc_fs_cifs);
|
||||
remove_proc_entry("cifsFYI", proc_fs_cifs);
|
||||
remove_proc_entry("traceSMB", proc_fs_cifs);
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
remove_proc_entry("Stats", proc_fs_cifs);
|
||||
#endif
|
||||
remove_proc_entry("SecurityFlags", proc_fs_cifs);
|
||||
remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
|
||||
remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
|
||||
|
|
|
@ -83,7 +83,13 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
|
|||
|
||||
kaddr = (char *) kmap(rqst->rq_pages[i]) + offset;
|
||||
|
||||
crypto_shash_update(shash, kaddr, len);
|
||||
rc = crypto_shash_update(shash, kaddr, len);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not update with payload\n",
|
||||
__func__);
|
||||
kunmap(rqst->rq_pages[i]);
|
||||
return rc;
|
||||
}
|
||||
|
||||
kunmap(rqst->rq_pages[i]);
|
||||
}
|
||||
|
@ -452,7 +458,7 @@ find_timestamp(struct cifs_ses *ses)
|
|||
unsigned char *blobptr;
|
||||
unsigned char *blobend;
|
||||
struct ntlmssp2_name *attrptr;
|
||||
struct timespec ts;
|
||||
struct timespec64 ts;
|
||||
|
||||
if (!ses->auth_key.len || !ses->auth_key.response)
|
||||
return 0;
|
||||
|
@ -477,7 +483,7 @@ find_timestamp(struct cifs_ses *ses)
|
|||
blobptr += attrsize; /* advance attr value */
|
||||
}
|
||||
|
||||
ktime_get_real_ts(&ts);
|
||||
ktime_get_real_ts64(&ts);
|
||||
return cpu_to_le64(cifs_UnixTimeToNT(ts));
|
||||
}
|
||||
|
||||
|
|
|
@ -139,6 +139,9 @@ cifs_read_super(struct super_block *sb)
|
|||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL)
|
||||
sb->s_flags |= SB_POSIXACL;
|
||||
|
||||
if (tcon->snapshot_time)
|
||||
sb->s_flags |= SB_RDONLY;
|
||||
|
||||
if (tcon->ses->capabilities & tcon->ses->server->vals->cap_large_files)
|
||||
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
||||
else
|
||||
|
@ -209,14 +212,16 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
|
||||
xid = get_xid();
|
||||
|
||||
/*
|
||||
* PATH_MAX may be too long - it would presumably be total path,
|
||||
* but note that some servers (includinng Samba 3) have a shorter
|
||||
* maximum path.
|
||||
*
|
||||
* Instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO.
|
||||
*/
|
||||
if (le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength) > 0)
|
||||
buf->f_namelen =
|
||||
le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength);
|
||||
else
|
||||
buf->f_namelen = PATH_MAX;
|
||||
|
||||
buf->f_fsid.val[0] = tcon->vol_serial_number;
|
||||
/* are using part of create time for more randomness, see man statfs */
|
||||
buf->f_fsid.val[1] = (int)le64_to_cpu(tcon->vol_create_time);
|
||||
|
||||
buf->f_files = 0; /* undefined */
|
||||
buf->f_ffree = 0; /* unlimited */
|
||||
|
||||
|
@ -427,7 +432,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
|
|||
else if (tcon->ses->user_name)
|
||||
seq_show_option(s, "username", tcon->ses->user_name);
|
||||
|
||||
if (tcon->ses->domainName)
|
||||
if (tcon->ses->domainName && tcon->ses->domainName[0] != 0)
|
||||
seq_show_option(s, "domain", tcon->ses->domainName);
|
||||
|
||||
if (srcaddr->sa_family != AF_UNSPEC) {
|
||||
|
@ -481,20 +486,12 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
|
|||
seq_puts(s, ",persistenthandles");
|
||||
else if (tcon->use_resilient)
|
||||
seq_puts(s, ",resilienthandles");
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if (tcon->posix_extensions)
|
||||
seq_puts(s, ",posix");
|
||||
else if (tcon->unix_ext)
|
||||
seq_puts(s, ",unix");
|
||||
else
|
||||
seq_puts(s, ",nounix");
|
||||
#else
|
||||
if (tcon->unix_ext)
|
||||
seq_puts(s, ",unix");
|
||||
else
|
||||
seq_puts(s, ",nounix");
|
||||
#endif /* SMB311 */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
|
||||
seq_puts(s, ",posixpaths");
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
|
||||
|
@ -546,6 +543,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
|
|||
seq_printf(s, ",wsize=%u", cifs_sb->wsize);
|
||||
seq_printf(s, ",echo_interval=%lu",
|
||||
tcon->ses->server->echo_interval / HZ);
|
||||
if (tcon->snapshot_time)
|
||||
seq_printf(s, ",snapshot=%llu", tcon->snapshot_time);
|
||||
/* convert actimeo and display it in seconds */
|
||||
seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ);
|
||||
|
||||
|
|
|
@ -76,6 +76,9 @@
|
|||
#define SMB_ECHO_INTERVAL_MAX 600
|
||||
#define SMB_ECHO_INTERVAL_DEFAULT 60
|
||||
|
||||
/* maximum number of PDUs in one compound */
|
||||
#define MAX_COMPOUND 5
|
||||
|
||||
/*
|
||||
* Default number of credits to keep available for SMB3.
|
||||
* This value is chosen somewhat arbitrarily. The Windows client
|
||||
|
@ -191,9 +194,7 @@ enum smb_version {
|
|||
Smb_21,
|
||||
Smb_30,
|
||||
Smb_302,
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
Smb_311,
|
||||
#endif /* SMB311 */
|
||||
Smb_3any,
|
||||
Smb_default,
|
||||
Smb_version_err
|
||||
|
@ -456,13 +457,11 @@ struct smb_version_operations {
|
|||
long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t,
|
||||
loff_t);
|
||||
/* init transform request - used for encryption for now */
|
||||
int (*init_transform_rq)(struct TCP_Server_Info *, struct smb_rqst *,
|
||||
struct smb_rqst *);
|
||||
/* free transform request */
|
||||
void (*free_transform_rq)(struct smb_rqst *);
|
||||
int (*init_transform_rq)(struct TCP_Server_Info *, int num_rqst,
|
||||
struct smb_rqst *, struct smb_rqst *);
|
||||
int (*is_transform_hdr)(void *buf);
|
||||
int (*receive_transform)(struct TCP_Server_Info *,
|
||||
struct mid_q_entry **);
|
||||
struct mid_q_entry **, char **, int *);
|
||||
enum securityEnum (*select_sectype)(struct TCP_Server_Info *,
|
||||
enum securityEnum);
|
||||
int (*next_header)(char *);
|
||||
|
@ -684,15 +683,14 @@ struct TCP_Server_Info {
|
|||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_t in_send; /* requests trying to send */
|
||||
atomic_t num_waiters; /* blocked waiting to get in sendrecv */
|
||||
#endif
|
||||
atomic_t smb2slowcmd[NUMBER_OF_SMB2_COMMANDS]; /* count resps > 1 sec */
|
||||
#endif /* STATS2 */
|
||||
unsigned int max_read;
|
||||
unsigned int max_write;
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
__le16 cipher_type;
|
||||
/* save initital negprot hash */
|
||||
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
|
||||
bool posix_ext_supported;
|
||||
#endif /* 3.1.1 */
|
||||
struct delayed_work reconnect; /* reconnect workqueue job */
|
||||
struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
|
||||
unsigned long echo_interval;
|
||||
|
@ -886,9 +884,7 @@ struct cifs_ses {
|
|||
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
|
||||
__u8 smb3encryptionkey[SMB3_SIGN_KEY_SIZE];
|
||||
__u8 smb3decryptionkey[SMB3_SIGN_KEY_SIZE];
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
|
||||
#endif /* 3.1.1 */
|
||||
|
||||
/*
|
||||
* Network interfaces available on the server this session is
|
||||
|
@ -913,6 +909,7 @@ cap_unix(struct cifs_ses *ses)
|
|||
|
||||
struct cached_fid {
|
||||
bool is_valid:1; /* Do we have a useable root fid */
|
||||
struct kref refcount;
|
||||
struct cifs_fid *fid;
|
||||
struct mutex fid_mutex;
|
||||
struct cifs_tcon *tcon;
|
||||
|
@ -936,7 +933,6 @@ struct cifs_tcon {
|
|||
__u32 tid; /* The 4 byte tree id */
|
||||
__u16 Flags; /* optional support bits */
|
||||
enum statusEnum tidStatus;
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
atomic_t num_smbs_sent;
|
||||
union {
|
||||
struct {
|
||||
|
@ -967,24 +963,9 @@ struct cifs_tcon {
|
|||
atomic_t smb2_com_failed[NUMBER_OF_SMB2_COMMANDS];
|
||||
} smb2_stats;
|
||||
} stats;
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
unsigned long long time_writes;
|
||||
unsigned long long time_reads;
|
||||
unsigned long long time_opens;
|
||||
unsigned long long time_deletes;
|
||||
unsigned long long time_closes;
|
||||
unsigned long long time_mkdirs;
|
||||
unsigned long long time_rmdirs;
|
||||
unsigned long long time_renames;
|
||||
unsigned long long time_t2renames;
|
||||
unsigned long long time_ffirst;
|
||||
unsigned long long time_fnext;
|
||||
unsigned long long time_fclose;
|
||||
#endif /* CONFIG_CIFS_STATS2 */
|
||||
__u64 bytes_read;
|
||||
__u64 bytes_written;
|
||||
spinlock_t stat_lock; /* protects the two fields above */
|
||||
#endif /* CONFIG_CIFS_STATS */
|
||||
FILE_SYSTEM_DEVICE_INFO fsDevInfo;
|
||||
FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */
|
||||
FILE_SYSTEM_UNIX_INFO fsUnixInfo;
|
||||
|
@ -997,9 +978,7 @@ struct cifs_tcon {
|
|||
bool seal:1; /* transport encryption for this mounted share */
|
||||
bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol
|
||||
for this mount even if server would support */
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
bool posix_extensions; /* if true SMB3.11 posix extensions enabled */
|
||||
#endif /* CIFS_311 */
|
||||
bool local_lease:1; /* check leases (only) on local system not remote */
|
||||
bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
|
||||
bool broken_sparse_sup; /* if server or share does not support sparse */
|
||||
|
@ -1046,6 +1025,7 @@ struct tcon_link {
|
|||
};
|
||||
|
||||
extern struct tcon_link *cifs_sb_tlink(struct cifs_sb_info *cifs_sb);
|
||||
extern void smb3_free_compound_rqst(int num_rqst, struct smb_rqst *rqst);
|
||||
|
||||
static inline struct cifs_tcon *
|
||||
tlink_tcon(struct tcon_link *tlink)
|
||||
|
@ -1352,7 +1332,6 @@ convert_delimiter(char *path, char delim)
|
|||
*pos = delim;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
#define cifs_stats_inc atomic_inc
|
||||
|
||||
static inline void cifs_stats_bytes_written(struct cifs_tcon *tcon,
|
||||
|
@ -1372,13 +1351,6 @@ static inline void cifs_stats_bytes_read(struct cifs_tcon *tcon,
|
|||
tcon->bytes_read += bytes;
|
||||
spin_unlock(&tcon->stat_lock);
|
||||
}
|
||||
#else
|
||||
|
||||
#define cifs_stats_inc(field) do {} while (0)
|
||||
#define cifs_stats_bytes_written(tcon, bytes) do {} while (0)
|
||||
#define cifs_stats_bytes_read(tcon, bytes) do {} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
|
@ -1544,9 +1516,9 @@ struct cifs_fattr {
|
|||
dev_t cf_rdev;
|
||||
unsigned int cf_nlink;
|
||||
unsigned int cf_dtype;
|
||||
struct timespec cf_atime;
|
||||
struct timespec cf_mtime;
|
||||
struct timespec cf_ctime;
|
||||
struct timespec64 cf_atime;
|
||||
struct timespec64 cf_mtime;
|
||||
struct timespec64 cf_ctime;
|
||||
};
|
||||
|
||||
static inline void free_dfs_info_param(struct dfs_info3_param *param)
|
||||
|
|
|
@ -94,6 +94,10 @@ extern int cifs_call_async(struct TCP_Server_Info *server,
|
|||
extern int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
struct smb_rqst *rqst, int *resp_buf_type,
|
||||
const int flags, struct kvec *resp_iov);
|
||||
extern int compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
const int flags, const int num_rqst,
|
||||
struct smb_rqst *rqst, int *resp_buf_type,
|
||||
struct kvec *resp_iov);
|
||||
extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
|
||||
struct smb_hdr * /* input */ ,
|
||||
struct smb_hdr * /* out */ ,
|
||||
|
@ -143,9 +147,9 @@ extern enum securityEnum select_sectype(struct TCP_Server_Info *server,
|
|||
enum securityEnum requested);
|
||||
extern int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
|
||||
const struct nls_table *nls_cp);
|
||||
extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
|
||||
extern u64 cifs_UnixTimeToNT(struct timespec);
|
||||
extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
|
||||
extern struct timespec64 cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
|
||||
extern u64 cifs_UnixTimeToNT(struct timespec64);
|
||||
extern struct timespec64 cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
|
||||
int offset);
|
||||
extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
|
||||
extern int cifs_get_writer(struct cifsInodeInfo *cinode);
|
||||
|
|
|
@ -508,13 +508,13 @@ decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
|
|||
* this requirement.
|
||||
*/
|
||||
int val, seconds, remain, result;
|
||||
struct timespec ts;
|
||||
unsigned long utc = ktime_get_real_seconds();
|
||||
struct timespec64 ts;
|
||||
time64_t utc = ktime_get_real_seconds();
|
||||
ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
|
||||
rsp->SrvTime.Time, 0);
|
||||
cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
|
||||
(int)ts.tv_sec, (int)utc,
|
||||
(int)(utc - ts.tv_sec));
|
||||
cifs_dbg(FYI, "SrvTime %lld sec since 1970 (utc: %lld) diff: %lld\n",
|
||||
ts.tv_sec, utc,
|
||||
utc - ts.tv_sec);
|
||||
val = (int)(utc - ts.tv_sec);
|
||||
seconds = abs(val);
|
||||
result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
|
||||
|
@ -4082,7 +4082,7 @@ QInfRetry:
|
|||
if (rc) {
|
||||
cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
|
||||
} else if (data) {
|
||||
struct timespec ts;
|
||||
struct timespec64 ts;
|
||||
__u32 time = le32_to_cpu(pSMBr->last_write_time);
|
||||
|
||||
/* decode response */
|
||||
|
|
|
@ -303,10 +303,8 @@ static const match_table_t cifs_smb_version_tokens = {
|
|||
{ Smb_21, SMB21_VERSION_STRING },
|
||||
{ Smb_30, SMB30_VERSION_STRING },
|
||||
{ Smb_302, SMB302_VERSION_STRING },
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
{ Smb_311, SMB311_VERSION_STRING },
|
||||
{ Smb_311, ALT_SMB311_VERSION_STRING },
|
||||
#endif /* SMB311 */
|
||||
{ Smb_3any, SMB3ANY_VERSION_STRING },
|
||||
{ Smb_default, SMBDEFAULT_VERSION_STRING },
|
||||
{ Smb_version_err, NULL }
|
||||
|
@ -350,6 +348,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
|||
server->max_read = 0;
|
||||
|
||||
cifs_dbg(FYI, "Reconnecting tcp session\n");
|
||||
trace_smb3_reconnect(server->CurrentMid, server->hostname);
|
||||
|
||||
/* before reconnecting the tcp session, mark the smb session (uid)
|
||||
and the tid bad so they are not used until reconnected */
|
||||
|
@ -851,13 +850,14 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
static int
|
||||
cifs_demultiplex_thread(void *p)
|
||||
{
|
||||
int length;
|
||||
int i, num_mids, length;
|
||||
struct TCP_Server_Info *server = p;
|
||||
unsigned int pdu_length;
|
||||
unsigned int next_offset;
|
||||
char *buf = NULL;
|
||||
struct task_struct *task_to_wake = NULL;
|
||||
struct mid_q_entry *mid_entry;
|
||||
struct mid_q_entry *mids[MAX_COMPOUND];
|
||||
char *bufs[MAX_COMPOUND];
|
||||
|
||||
current->flags |= PF_MEMALLOC;
|
||||
cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current));
|
||||
|
@ -924,58 +924,75 @@ next_pdu:
|
|||
server->pdu_size = next_offset;
|
||||
}
|
||||
|
||||
mid_entry = NULL;
|
||||
memset(mids, 0, sizeof(mids));
|
||||
memset(bufs, 0, sizeof(bufs));
|
||||
num_mids = 0;
|
||||
|
||||
if (server->ops->is_transform_hdr &&
|
||||
server->ops->receive_transform &&
|
||||
server->ops->is_transform_hdr(buf)) {
|
||||
length = server->ops->receive_transform(server,
|
||||
&mid_entry);
|
||||
mids,
|
||||
bufs,
|
||||
&num_mids);
|
||||
} else {
|
||||
mid_entry = server->ops->find_mid(server, buf);
|
||||
mids[0] = server->ops->find_mid(server, buf);
|
||||
bufs[0] = buf;
|
||||
if (mids[0])
|
||||
num_mids = 1;
|
||||
|
||||
if (!mid_entry || !mid_entry->receive)
|
||||
length = standard_receive3(server, mid_entry);
|
||||
if (!mids[0] || !mids[0]->receive)
|
||||
length = standard_receive3(server, mids[0]);
|
||||
else
|
||||
length = mid_entry->receive(server, mid_entry);
|
||||
length = mids[0]->receive(server, mids[0]);
|
||||
}
|
||||
|
||||
if (length < 0) {
|
||||
if (mid_entry)
|
||||
cifs_mid_q_entry_release(mid_entry);
|
||||
for (i = 0; i < num_mids; i++)
|
||||
if (mids[i])
|
||||
cifs_mid_q_entry_release(mids[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (server->large_buf)
|
||||
buf = server->bigbuf;
|
||||
|
||||
|
||||
server->lstrp = jiffies;
|
||||
if (mid_entry != NULL) {
|
||||
mid_entry->resp_buf_size = server->pdu_size;
|
||||
if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) &&
|
||||
mid_entry->mid_state == MID_RESPONSE_RECEIVED &&
|
||||
|
||||
for (i = 0; i < num_mids; i++) {
|
||||
if (mids[i] != NULL) {
|
||||
mids[i]->resp_buf_size = server->pdu_size;
|
||||
if ((mids[i]->mid_flags & MID_WAIT_CANCELLED) &&
|
||||
mids[i]->mid_state == MID_RESPONSE_RECEIVED &&
|
||||
server->ops->handle_cancelled_mid)
|
||||
server->ops->handle_cancelled_mid(
|
||||
mid_entry->resp_buf,
|
||||
mids[i]->resp_buf,
|
||||
server);
|
||||
|
||||
if (!mid_entry->multiRsp || mid_entry->multiEnd)
|
||||
mid_entry->callback(mid_entry);
|
||||
if (!mids[i]->multiRsp || mids[i]->multiEnd)
|
||||
mids[i]->callback(mids[i]);
|
||||
|
||||
cifs_mid_q_entry_release(mid_entry);
|
||||
cifs_mid_q_entry_release(mids[i]);
|
||||
} else if (server->ops->is_oplock_break &&
|
||||
server->ops->is_oplock_break(buf, server)) {
|
||||
server->ops->is_oplock_break(bufs[i],
|
||||
server)) {
|
||||
cifs_dbg(FYI, "Received oplock break\n");
|
||||
} else {
|
||||
cifs_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n",
|
||||
cifs_dbg(VFS, "No task to wake, unknown frame "
|
||||
"received! NumMids %d\n",
|
||||
atomic_read(&midCount));
|
||||
cifs_dump_mem("Received Data is: ", buf,
|
||||
cifs_dump_mem("Received Data is: ", bufs[i],
|
||||
HEADER_SIZE(server));
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
if (server->ops->dump_detail)
|
||||
server->ops->dump_detail(buf, server);
|
||||
server->ops->dump_detail(bufs[i],
|
||||
server);
|
||||
cifs_dump_mids(server);
|
||||
#endif /* CIFS_DEBUG2 */
|
||||
}
|
||||
}
|
||||
|
||||
if (pdu_length > server->pdu_size) {
|
||||
if (!allocate_buffers(server))
|
||||
continue;
|
||||
|
@ -1174,6 +1191,7 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3)
|
|||
substring_t args[MAX_OPT_ARGS];
|
||||
|
||||
switch (match_token(value, cifs_smb_version_tokens, args)) {
|
||||
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
|
||||
case Smb_1:
|
||||
if (disable_legacy_dialects) {
|
||||
cifs_dbg(VFS, "mount with legacy dialect disabled\n");
|
||||
|
@ -1198,6 +1216,14 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3)
|
|||
vol->ops = &smb20_operations;
|
||||
vol->vals = &smb20_values;
|
||||
break;
|
||||
#else
|
||||
case Smb_1:
|
||||
cifs_dbg(VFS, "vers=1.0 (cifs) mount not permitted when legacy dialects disabled\n");
|
||||
return 1;
|
||||
case Smb_20:
|
||||
cifs_dbg(VFS, "vers=2.0 mount not permitted when legacy dialects disabled\n");
|
||||
return 1;
|
||||
#endif /* CIFS_ALLOW_INSECURE_LEGACY */
|
||||
case Smb_21:
|
||||
vol->ops = &smb21_operations;
|
||||
vol->vals = &smb21_values;
|
||||
|
@ -1210,12 +1236,10 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3)
|
|||
vol->ops = &smb30_operations; /* currently identical with 3.0 */
|
||||
vol->vals = &smb302_values;
|
||||
break;
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
case Smb_311:
|
||||
vol->ops = &smb311_operations;
|
||||
vol->vals = &smb311_values;
|
||||
break;
|
||||
#endif /* SMB311 */
|
||||
case Smb_3any:
|
||||
vol->ops = &smb30_operations; /* currently identical with 3.0 */
|
||||
vol->vals = &smb3any_values;
|
||||
|
@ -3030,15 +3054,17 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if ((volume_info->linux_ext) && (ses->server->posix_ext_supported)) {
|
||||
if (ses->server->vals->protocol_id == SMB311_PROT_ID) {
|
||||
if (volume_info->linux_ext) {
|
||||
if (ses->server->posix_ext_supported) {
|
||||
tcon->posix_extensions = true;
|
||||
printk_once(KERN_WARNING
|
||||
"SMB3.11 POSIX Extensions are experimental\n");
|
||||
} else {
|
||||
cifs_dbg(VFS, "Server does not support mounting with posix SMB3.11 extensions.\n");
|
||||
rc = -EOPNOTSUPP;
|
||||
goto out_fail;
|
||||
}
|
||||
}
|
||||
#endif /* 311 */
|
||||
|
||||
/*
|
||||
* BB Do we need to wrap session_mutex around this TCon call and Unix
|
||||
|
@ -3992,11 +4018,9 @@ try_mount_again:
|
|||
goto remote_path_check;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
/* if new SMB3.11 POSIX extensions are supported do not remap / and \ */
|
||||
if (tcon->posix_extensions)
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
|
||||
#endif /* SMB3.11 */
|
||||
|
||||
/* tell server which Unix caps we support */
|
||||
if (cap_unix(tcon->ses)) {
|
||||
|
@ -4459,11 +4483,10 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
|
|||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
/* if new SMB3.11 POSIX extensions are supported do not remap / and \ */
|
||||
if (tcon->posix_extensions)
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
|
||||
#endif /* SMB3.11 */
|
||||
|
||||
if (cap_unix(ses))
|
||||
reset_cifs_unix_caps(0, tcon, NULL, vol_info);
|
||||
|
||||
|
|
|
@ -129,8 +129,10 @@ static void cifs_fscache_acquire_inode_cookie(struct cifsInodeInfo *cifsi,
|
|||
|
||||
memset(&auxdata, 0, sizeof(auxdata));
|
||||
auxdata.eof = cifsi->server_eof;
|
||||
auxdata.last_write_time = timespec64_to_timespec(cifsi->vfs_inode.i_mtime);
|
||||
auxdata.last_change_time = timespec64_to_timespec(cifsi->vfs_inode.i_ctime);
|
||||
auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec;
|
||||
auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec;
|
||||
auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec;
|
||||
auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec;
|
||||
|
||||
cifsi->fscache =
|
||||
fscache_acquire_cookie(tcon->fscache,
|
||||
|
@ -166,8 +168,10 @@ void cifs_fscache_release_inode_cookie(struct inode *inode)
|
|||
if (cifsi->fscache) {
|
||||
memset(&auxdata, 0, sizeof(auxdata));
|
||||
auxdata.eof = cifsi->server_eof;
|
||||
auxdata.last_write_time = timespec64_to_timespec(cifsi->vfs_inode.i_mtime);
|
||||
auxdata.last_change_time = timespec64_to_timespec(cifsi->vfs_inode.i_ctime);
|
||||
auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec;
|
||||
auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec;
|
||||
auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec;
|
||||
auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec;
|
||||
|
||||
cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache);
|
||||
fscache_relinquish_cookie(cifsi->fscache, &auxdata, false);
|
||||
|
|
|
@ -31,8 +31,10 @@
|
|||
* Auxiliary data attached to CIFS inode within the cache
|
||||
*/
|
||||
struct cifs_fscache_inode_auxdata {
|
||||
struct timespec last_write_time;
|
||||
struct timespec last_change_time;
|
||||
u64 last_write_time_sec;
|
||||
u64 last_change_time_sec;
|
||||
u32 last_write_time_nsec;
|
||||
u32 last_change_time_nsec;
|
||||
u64 eof;
|
||||
};
|
||||
|
||||
|
|
|
@ -95,7 +95,6 @@ static void
|
|||
cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
|
||||
{
|
||||
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
|
||||
struct timespec ts;
|
||||
|
||||
cifs_dbg(FYI, "%s: revalidating inode %llu\n",
|
||||
__func__, cifs_i->uniqueid);
|
||||
|
@ -114,8 +113,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
|
|||
}
|
||||
|
||||
/* revalidate if mtime or size have changed */
|
||||
ts = timespec64_to_timespec(inode->i_mtime);
|
||||
if (timespec_equal(&ts, &fattr->cf_mtime) &&
|
||||
if (timespec64_equal(&inode->i_mtime, &fattr->cf_mtime) &&
|
||||
cifs_i->server_eof == fattr->cf_eof) {
|
||||
cifs_dbg(FYI, "%s: inode %llu is unchanged\n",
|
||||
__func__, cifs_i->uniqueid);
|
||||
|
@ -164,9 +162,9 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
|||
cifs_revalidate_cache(inode, fattr);
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
inode->i_atime = timespec_to_timespec64(fattr->cf_atime);
|
||||
inode->i_mtime = timespec_to_timespec64(fattr->cf_mtime);
|
||||
inode->i_ctime = timespec_to_timespec64(fattr->cf_ctime);
|
||||
inode->i_atime = fattr->cf_atime;
|
||||
inode->i_mtime = fattr->cf_mtime;
|
||||
inode->i_ctime = fattr->cf_ctime;
|
||||
inode->i_rdev = fattr->cf_rdev;
|
||||
cifs_nlink_fattr_to_inode(inode, fattr);
|
||||
inode->i_uid = fattr->cf_uid;
|
||||
|
@ -327,8 +325,8 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
|
|||
fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
|
||||
fattr->cf_uid = cifs_sb->mnt_uid;
|
||||
fattr->cf_gid = cifs_sb->mnt_gid;
|
||||
ktime_get_real_ts(&fattr->cf_mtime);
|
||||
fattr->cf_mtime = timespec_trunc(fattr->cf_mtime, sb->s_time_gran);
|
||||
ktime_get_real_ts64(&fattr->cf_mtime);
|
||||
fattr->cf_mtime = timespec64_trunc(fattr->cf_mtime, sb->s_time_gran);
|
||||
fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime;
|
||||
fattr->cf_nlink = 2;
|
||||
fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
|
||||
|
@ -604,8 +602,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
|
|||
if (info->LastAccessTime)
|
||||
fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
|
||||
else {
|
||||
ktime_get_real_ts(&fattr->cf_atime);
|
||||
fattr->cf_atime = timespec_trunc(fattr->cf_atime, sb->s_time_gran);
|
||||
ktime_get_real_ts64(&fattr->cf_atime);
|
||||
fattr->cf_atime = timespec64_trunc(fattr->cf_atime, sb->s_time_gran);
|
||||
}
|
||||
|
||||
fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
|
||||
|
@ -1122,17 +1120,19 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
|
|||
if (!server->ops->set_file_info)
|
||||
return -ENOSYS;
|
||||
|
||||
info_buf.Pad = 0;
|
||||
|
||||
if (attrs->ia_valid & ATTR_ATIME) {
|
||||
set_time = true;
|
||||
info_buf.LastAccessTime =
|
||||
cpu_to_le64(cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_atime)));
|
||||
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
|
||||
} else
|
||||
info_buf.LastAccessTime = 0;
|
||||
|
||||
if (attrs->ia_valid & ATTR_MTIME) {
|
||||
set_time = true;
|
||||
info_buf.LastWriteTime =
|
||||
cpu_to_le64(cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_mtime)));
|
||||
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
|
||||
} else
|
||||
info_buf.LastWriteTime = 0;
|
||||
|
||||
|
@ -1145,7 +1145,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
|
|||
if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
|
||||
cifs_dbg(FYI, "CIFS - CTIME changed\n");
|
||||
info_buf.ChangeTime =
|
||||
cpu_to_le64(cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_ctime)));
|
||||
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
|
||||
} else
|
||||
info_buf.ChangeTime = 0;
|
||||
|
||||
|
@ -1577,14 +1577,12 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
|
|||
|
||||
server = tcon->ses->server;
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if ((server->ops->posix_mkdir) && (tcon->posix_extensions)) {
|
||||
rc = server->ops->posix_mkdir(xid, inode, mode, tcon, full_path,
|
||||
cifs_sb);
|
||||
d_drop(direntry); /* for time being always refresh inode info */
|
||||
goto mkdir_out;
|
||||
}
|
||||
#endif /* SMB311 */
|
||||
|
||||
if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
|
||||
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
||||
|
@ -2071,8 +2069,8 @@ int cifs_getattr(const struct path *path, struct kstat *stat,
|
|||
/* old CIFS Unix Extensions doesn't return create time */
|
||||
if (CIFS_I(inode)->createtime) {
|
||||
stat->result_mask |= STATX_BTIME;
|
||||
stat->btime = timespec_to_timespec64(
|
||||
cifs_NTtimeToUnix(cpu_to_le64(CIFS_I(inode)->createtime)));
|
||||
stat->btime =
|
||||
cifs_NTtimeToUnix(cpu_to_le64(CIFS_I(inode)->createtime));
|
||||
}
|
||||
|
||||
stat->attributes_mask |= (STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED);
|
||||
|
@ -2278,17 +2276,17 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
|
|||
args->gid = INVALID_GID; /* no change */
|
||||
|
||||
if (attrs->ia_valid & ATTR_ATIME)
|
||||
args->atime = cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_atime));
|
||||
args->atime = cifs_UnixTimeToNT(attrs->ia_atime);
|
||||
else
|
||||
args->atime = NO_CHANGE_64;
|
||||
|
||||
if (attrs->ia_valid & ATTR_MTIME)
|
||||
args->mtime = cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_mtime));
|
||||
args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime);
|
||||
else
|
||||
args->mtime = NO_CHANGE_64;
|
||||
|
||||
if (attrs->ia_valid & ATTR_CTIME)
|
||||
args->ctime = cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_ctime));
|
||||
args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime);
|
||||
else
|
||||
args->ctime = NO_CHANGE_64;
|
||||
|
||||
|
|
|
@ -396,7 +396,7 @@ smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
|
|||
struct cifs_io_parms io_parms;
|
||||
int buf_type = CIFS_NO_BUFFER;
|
||||
__le16 *utf16_path;
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_II;
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct smb2_file_all_info *pfile_info = NULL;
|
||||
|
||||
oparms.tcon = tcon;
|
||||
|
@ -459,7 +459,7 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
|
|||
struct cifs_io_parms io_parms;
|
||||
int create_options = CREATE_NOT_DIR;
|
||||
__le16 *utf16_path;
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct kvec iov[2];
|
||||
|
||||
if (backup_cred(cifs_sb))
|
||||
|
|
|
@ -122,9 +122,7 @@ tconInfoAlloc(void)
|
|||
mutex_init(&ret_buf->crfid.fid_mutex);
|
||||
ret_buf->crfid.fid = kzalloc(sizeof(struct cifs_fid),
|
||||
GFP_KERNEL);
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
spin_lock_init(&ret_buf->stat_lock);
|
||||
#endif
|
||||
}
|
||||
return ret_buf;
|
||||
}
|
||||
|
|
|
@ -918,10 +918,10 @@ smbCalcSize(void *buf, struct TCP_Server_Info *server)
|
|||
* Convert the NT UTC (based 1601-01-01, in hundred nanosecond units)
|
||||
* into Unix UTC (based 1970-01-01, in seconds).
|
||||
*/
|
||||
struct timespec
|
||||
struct timespec64
|
||||
cifs_NTtimeToUnix(__le64 ntutc)
|
||||
{
|
||||
struct timespec ts;
|
||||
struct timespec64 ts;
|
||||
/* BB what about the timezone? BB */
|
||||
|
||||
/* Subtract the NTFS time offset, then convert to 1s intervals. */
|
||||
|
@ -935,12 +935,12 @@ cifs_NTtimeToUnix(__le64 ntutc)
|
|||
*/
|
||||
if (t < 0) {
|
||||
abs_t = -t;
|
||||
ts.tv_nsec = (long)(do_div(abs_t, 10000000) * 100);
|
||||
ts.tv_nsec = (time64_t)(do_div(abs_t, 10000000) * 100);
|
||||
ts.tv_nsec = -ts.tv_nsec;
|
||||
ts.tv_sec = -abs_t;
|
||||
} else {
|
||||
abs_t = t;
|
||||
ts.tv_nsec = (long)do_div(abs_t, 10000000) * 100;
|
||||
ts.tv_nsec = (time64_t)do_div(abs_t, 10000000) * 100;
|
||||
ts.tv_sec = abs_t;
|
||||
}
|
||||
|
||||
|
@ -949,7 +949,7 @@ cifs_NTtimeToUnix(__le64 ntutc)
|
|||
|
||||
/* Convert the Unix UTC into NT UTC. */
|
||||
u64
|
||||
cifs_UnixTimeToNT(struct timespec t)
|
||||
cifs_UnixTimeToNT(struct timespec64 t)
|
||||
{
|
||||
/* Convert to 100ns intervals and then add the NTFS time offset. */
|
||||
return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET;
|
||||
|
@ -959,10 +959,11 @@ static const int total_days_of_prev_months[] = {
|
|||
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
|
||||
};
|
||||
|
||||
struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset)
|
||||
struct timespec64 cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset)
|
||||
{
|
||||
struct timespec ts;
|
||||
int sec, min, days, month, year;
|
||||
struct timespec64 ts;
|
||||
time64_t sec;
|
||||
int min, days, month, year;
|
||||
u16 date = le16_to_cpu(le_date);
|
||||
u16 time = le16_to_cpu(le_time);
|
||||
SMB_TIME *st = (SMB_TIME *)&time;
|
||||
|
@ -973,7 +974,7 @@ struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset)
|
|||
sec = 2 * st->TwoSeconds;
|
||||
min = st->Minutes;
|
||||
if ((sec > 59) || (min > 59))
|
||||
cifs_dbg(VFS, "illegal time min %d sec %d\n", min, sec);
|
||||
cifs_dbg(VFS, "illegal time min %d sec %lld\n", min, sec);
|
||||
sec += (min * 60);
|
||||
sec += 60 * 60 * st->Hours;
|
||||
if (st->Hours > 24)
|
||||
|
|
|
@ -624,7 +624,6 @@ cifs_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
static void
|
||||
cifs_clear_stats(struct cifs_tcon *tcon)
|
||||
{
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
atomic_set(&tcon->stats.cifs_stats.num_writes, 0);
|
||||
atomic_set(&tcon->stats.cifs_stats.num_reads, 0);
|
||||
atomic_set(&tcon->stats.cifs_stats.num_flushes, 0);
|
||||
|
@ -646,13 +645,11 @@ cifs_clear_stats(struct cifs_tcon *tcon)
|
|||
atomic_set(&tcon->stats.cifs_stats.num_locks, 0);
|
||||
atomic_set(&tcon->stats.cifs_stats.num_acl_get, 0);
|
||||
atomic_set(&tcon->stats.cifs_stats.num_acl_set, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
cifs_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
|
||||
{
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
seq_printf(m, " Oplocks breaks: %d",
|
||||
atomic_read(&tcon->stats.cifs_stats.num_oplock_brks));
|
||||
seq_printf(m, "\nReads: %d Bytes: %llu",
|
||||
|
@ -684,7 +681,6 @@ cifs_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
|
|||
atomic_read(&tcon->stats.cifs_stats.num_ffirst),
|
||||
atomic_read(&tcon->stats.cifs_stats.num_fnext),
|
||||
atomic_read(&tcon->stats.cifs_stats.num_fclose));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -120,7 +120,9 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
break;
|
||||
}
|
||||
|
||||
if (use_cached_root_handle == false)
|
||||
if (use_cached_root_handle)
|
||||
close_shroot(&tcon->crfid);
|
||||
else
|
||||
rc = SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
if (tmprc)
|
||||
rc = tmprc;
|
||||
|
@ -281,7 +283,7 @@ smb2_set_file_info(struct inode *inode, const char *full_path,
|
|||
int rc;
|
||||
|
||||
if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
|
||||
(buf->LastWriteTime == 0) && (buf->ChangeTime) &&
|
||||
(buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
|
||||
(buf->Attributes == 0))
|
||||
return 0; /* would be a no op, no sense sending this */
|
||||
|
||||
|
|
|
@ -93,7 +93,6 @@ static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {
|
|||
/* SMB2_OPLOCK_BREAK */ cpu_to_le16(24)
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
static __u32 get_neg_ctxt_len(struct smb2_sync_hdr *hdr, __u32 len,
|
||||
__u32 non_ctxlen)
|
||||
{
|
||||
|
@ -127,7 +126,6 @@ static __u32 get_neg_ctxt_len(struct smb2_sync_hdr *hdr, __u32 len,
|
|||
/* length of negcontexts including pad from end of sec blob to them */
|
||||
return (len - nc_offset) + size_of_pad_before_neg_ctxts;
|
||||
}
|
||||
#endif /* CIFS_SMB311 */
|
||||
|
||||
int
|
||||
smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *srvr)
|
||||
|
@ -222,10 +220,9 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *srvr)
|
|||
|
||||
clc_len = smb2_calc_size(buf, srvr);
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if (shdr->Command == SMB2_NEGOTIATE)
|
||||
clc_len += get_neg_ctxt_len(shdr, len, clc_len);
|
||||
#endif /* SMB311 */
|
||||
|
||||
if (len != clc_len) {
|
||||
cifs_dbg(FYI, "Calculated size %u length %u mismatch mid %llu\n",
|
||||
clc_len, len, mid);
|
||||
|
@ -451,15 +448,13 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
|
|||
/* Windows doesn't allow paths beginning with \ */
|
||||
if (from[0] == '\\')
|
||||
start_of_path = from + 1;
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
|
||||
/* SMB311 POSIX extensions paths do not include leading slash */
|
||||
else if (cifs_sb_master_tlink(cifs_sb) &&
|
||||
cifs_sb_master_tcon(cifs_sb)->posix_extensions &&
|
||||
(from[0] == '/')) {
|
||||
start_of_path = from + 1;
|
||||
}
|
||||
#endif /* 311 */
|
||||
else
|
||||
} else
|
||||
start_of_path = from;
|
||||
|
||||
to = cifs_strndup_to_utf16(start_of_path, PATH_MAX, &len,
|
||||
|
@ -759,7 +754,6 @@ smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
/**
|
||||
* smb311_update_preauth_hash - update @ses hash with the packet data in @iov
|
||||
*
|
||||
|
@ -821,4 +815,3 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct kvec *iov, int nvec)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -444,7 +444,11 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
|
|||
FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */,
|
||||
NULL /* no data input */, 0 /* no data input */,
|
||||
(char **)&out_buf, &ret_data_len);
|
||||
if (rc != 0) {
|
||||
if (rc == -EOPNOTSUPP) {
|
||||
cifs_dbg(FYI,
|
||||
"server does not support query network interfaces\n");
|
||||
goto out;
|
||||
} else if (rc != 0) {
|
||||
cifs_dbg(VFS, "error %d on ioctl to get interface list\n", rc);
|
||||
goto out;
|
||||
}
|
||||
|
@ -466,21 +470,36 @@ out:
|
|||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
smb2_cached_lease_break(struct work_struct *work)
|
||||
static void
|
||||
smb2_close_cached_fid(struct kref *ref)
|
||||
{
|
||||
struct cached_fid *cfid = container_of(work,
|
||||
struct cached_fid, lease_break);
|
||||
mutex_lock(&cfid->fid_mutex);
|
||||
struct cached_fid *cfid = container_of(ref, struct cached_fid,
|
||||
refcount);
|
||||
|
||||
if (cfid->is_valid) {
|
||||
cifs_dbg(FYI, "clear cached root file handle\n");
|
||||
SMB2_close(0, cfid->tcon, cfid->fid->persistent_fid,
|
||||
cfid->fid->volatile_fid);
|
||||
cfid->is_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
void close_shroot(struct cached_fid *cfid)
|
||||
{
|
||||
mutex_lock(&cfid->fid_mutex);
|
||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
||||
mutex_unlock(&cfid->fid_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
smb2_cached_lease_break(struct work_struct *work)
|
||||
{
|
||||
struct cached_fid *cfid = container_of(work,
|
||||
struct cached_fid, lease_break);
|
||||
|
||||
close_shroot(cfid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the directory at the root of a share
|
||||
*/
|
||||
|
@ -495,6 +514,7 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
|||
if (tcon->crfid.is_valid) {
|
||||
cifs_dbg(FYI, "found a cached root file handle\n");
|
||||
memcpy(pfid, tcon->crfid.fid, sizeof(struct cifs_fid));
|
||||
kref_get(&tcon->crfid.refcount);
|
||||
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
@ -511,6 +531,8 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
|||
memcpy(tcon->crfid.fid, pfid, sizeof(struct cifs_fid));
|
||||
tcon->crfid.tcon = tcon;
|
||||
tcon->crfid.is_valid = true;
|
||||
kref_init(&tcon->crfid.refcount);
|
||||
kref_get(&tcon->crfid.refcount);
|
||||
}
|
||||
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||
return rc;
|
||||
|
@ -548,10 +570,15 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
|
|||
FS_ATTRIBUTE_INFORMATION);
|
||||
SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
|
||||
FS_DEVICE_INFORMATION);
|
||||
SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
|
||||
FS_VOLUME_INFORMATION);
|
||||
SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
|
||||
FS_SECTOR_SIZE_INFORMATION); /* SMB3 specific */
|
||||
if (no_cached_open)
|
||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
else
|
||||
close_shroot(&tcon->crfid);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -873,13 +900,11 @@ smb2_can_echo(struct TCP_Server_Info *server)
|
|||
static void
|
||||
smb2_clear_stats(struct cifs_tcon *tcon)
|
||||
{
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
int i;
|
||||
for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) {
|
||||
atomic_set(&tcon->stats.smb2_stats.smb2_com_sent[i], 0);
|
||||
atomic_set(&tcon->stats.smb2_stats.smb2_com_failed[i], 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -918,67 +943,58 @@ smb2_dump_share_caps(struct seq_file *m, struct cifs_tcon *tcon)
|
|||
static void
|
||||
smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
|
||||
{
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
atomic_t *sent = tcon->stats.smb2_stats.smb2_com_sent;
|
||||
atomic_t *failed = tcon->stats.smb2_stats.smb2_com_failed;
|
||||
seq_printf(m, "\nNegotiates: %d sent %d failed",
|
||||
atomic_read(&sent[SMB2_NEGOTIATE_HE]),
|
||||
atomic_read(&failed[SMB2_NEGOTIATE_HE]));
|
||||
seq_printf(m, "\nSessionSetups: %d sent %d failed",
|
||||
atomic_read(&sent[SMB2_SESSION_SETUP_HE]),
|
||||
atomic_read(&failed[SMB2_SESSION_SETUP_HE]));
|
||||
seq_printf(m, "\nLogoffs: %d sent %d failed",
|
||||
atomic_read(&sent[SMB2_LOGOFF_HE]),
|
||||
atomic_read(&failed[SMB2_LOGOFF_HE]));
|
||||
seq_printf(m, "\nTreeConnects: %d sent %d failed",
|
||||
|
||||
/*
|
||||
* Can't display SMB2_NEGOTIATE, SESSION_SETUP, LOGOFF, CANCEL and ECHO
|
||||
* totals (requests sent) since those SMBs are per-session not per tcon
|
||||
*/
|
||||
seq_printf(m, "\nBytes read: %llu Bytes written: %llu",
|
||||
(long long)(tcon->bytes_read),
|
||||
(long long)(tcon->bytes_written));
|
||||
seq_printf(m, "\nTreeConnects: %d total %d failed",
|
||||
atomic_read(&sent[SMB2_TREE_CONNECT_HE]),
|
||||
atomic_read(&failed[SMB2_TREE_CONNECT_HE]));
|
||||
seq_printf(m, "\nTreeDisconnects: %d sent %d failed",
|
||||
seq_printf(m, "\nTreeDisconnects: %d total %d failed",
|
||||
atomic_read(&sent[SMB2_TREE_DISCONNECT_HE]),
|
||||
atomic_read(&failed[SMB2_TREE_DISCONNECT_HE]));
|
||||
seq_printf(m, "\nCreates: %d sent %d failed",
|
||||
seq_printf(m, "\nCreates: %d total %d failed",
|
||||
atomic_read(&sent[SMB2_CREATE_HE]),
|
||||
atomic_read(&failed[SMB2_CREATE_HE]));
|
||||
seq_printf(m, "\nCloses: %d sent %d failed",
|
||||
seq_printf(m, "\nCloses: %d total %d failed",
|
||||
atomic_read(&sent[SMB2_CLOSE_HE]),
|
||||
atomic_read(&failed[SMB2_CLOSE_HE]));
|
||||
seq_printf(m, "\nFlushes: %d sent %d failed",
|
||||
seq_printf(m, "\nFlushes: %d total %d failed",
|
||||
atomic_read(&sent[SMB2_FLUSH_HE]),
|
||||
atomic_read(&failed[SMB2_FLUSH_HE]));
|
||||
seq_printf(m, "\nReads: %d sent %d failed",
|
||||
seq_printf(m, "\nReads: %d total %d failed",
|
||||
atomic_read(&sent[SMB2_READ_HE]),
|
||||
atomic_read(&failed[SMB2_READ_HE]));
|
||||
seq_printf(m, "\nWrites: %d sent %d failed",
|
||||
seq_printf(m, "\nWrites: %d total %d failed",
|
||||
atomic_read(&sent[SMB2_WRITE_HE]),
|
||||
atomic_read(&failed[SMB2_WRITE_HE]));
|
||||
seq_printf(m, "\nLocks: %d sent %d failed",
|
||||
seq_printf(m, "\nLocks: %d total %d failed",
|
||||
atomic_read(&sent[SMB2_LOCK_HE]),
|
||||
atomic_read(&failed[SMB2_LOCK_HE]));
|
||||
seq_printf(m, "\nIOCTLs: %d sent %d failed",
|
||||
seq_printf(m, "\nIOCTLs: %d total %d failed",
|
||||
atomic_read(&sent[SMB2_IOCTL_HE]),
|
||||
atomic_read(&failed[SMB2_IOCTL_HE]));
|
||||
seq_printf(m, "\nCancels: %d sent %d failed",
|
||||
atomic_read(&sent[SMB2_CANCEL_HE]),
|
||||
atomic_read(&failed[SMB2_CANCEL_HE]));
|
||||
seq_printf(m, "\nEchos: %d sent %d failed",
|
||||
atomic_read(&sent[SMB2_ECHO_HE]),
|
||||
atomic_read(&failed[SMB2_ECHO_HE]));
|
||||
seq_printf(m, "\nQueryDirectories: %d sent %d failed",
|
||||
seq_printf(m, "\nQueryDirectories: %d total %d failed",
|
||||
atomic_read(&sent[SMB2_QUERY_DIRECTORY_HE]),
|
||||
atomic_read(&failed[SMB2_QUERY_DIRECTORY_HE]));
|
||||
seq_printf(m, "\nChangeNotifies: %d sent %d failed",
|
||||
seq_printf(m, "\nChangeNotifies: %d total %d failed",
|
||||
atomic_read(&sent[SMB2_CHANGE_NOTIFY_HE]),
|
||||
atomic_read(&failed[SMB2_CHANGE_NOTIFY_HE]));
|
||||
seq_printf(m, "\nQueryInfos: %d sent %d failed",
|
||||
seq_printf(m, "\nQueryInfos: %d total %d failed",
|
||||
atomic_read(&sent[SMB2_QUERY_INFO_HE]),
|
||||
atomic_read(&failed[SMB2_QUERY_INFO_HE]));
|
||||
seq_printf(m, "\nSetInfos: %d sent %d failed",
|
||||
seq_printf(m, "\nSetInfos: %d total %d failed",
|
||||
atomic_read(&sent[SMB2_SET_INFO_HE]),
|
||||
atomic_read(&failed[SMB2_SET_INFO_HE]));
|
||||
seq_printf(m, "\nOplockBreaks: %d sent %d failed",
|
||||
atomic_read(&sent[SMB2_OPLOCK_BREAK_HE]),
|
||||
atomic_read(&failed[SMB2_OPLOCK_BREAK_HE]));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1353,6 +1369,13 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
}
|
||||
|
||||
/* GMT Token is @GMT-YYYY.MM.DD-HH.MM.SS Unicode which is 48 bytes + null */
|
||||
#define GMT_TOKEN_SIZE 50
|
||||
|
||||
/*
|
||||
* Input buffer contains (empty) struct smb_snapshot array with size filled in
|
||||
* For output see struct SRV_SNAPSHOT_ARRAY in MS-SMB2 section 2.2.32.2
|
||||
*/
|
||||
static int
|
||||
smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifsFileInfo *cfile, void __user *ioc_buf)
|
||||
|
@ -1382,14 +1405,27 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
kfree(retbuf);
|
||||
return rc;
|
||||
}
|
||||
if (snapshot_in.snapshot_array_size < sizeof(struct smb_snapshot_array)) {
|
||||
rc = -ERANGE;
|
||||
kfree(retbuf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (ret_data_len > snapshot_in.snapshot_array_size)
|
||||
ret_data_len = snapshot_in.snapshot_array_size;
|
||||
/*
|
||||
* Check for min size, ie not large enough to fit even one GMT
|
||||
* token (snapshot). On the first ioctl some users may pass in
|
||||
* smaller size (or zero) to simply get the size of the array
|
||||
* so the user space caller can allocate sufficient memory
|
||||
* and retry the ioctl again with larger array size sufficient
|
||||
* to hold all of the snapshot GMT tokens on the second try.
|
||||
*/
|
||||
if (snapshot_in.snapshot_array_size < GMT_TOKEN_SIZE)
|
||||
ret_data_len = sizeof(struct smb_snapshot_array);
|
||||
|
||||
/*
|
||||
* We return struct SRV_SNAPSHOT_ARRAY, followed by
|
||||
* the snapshot array (of 50 byte GMT tokens) each
|
||||
* representing an available previous version of the data
|
||||
*/
|
||||
if (ret_data_len > (snapshot_in.snapshot_array_size +
|
||||
sizeof(struct smb_snapshot_array)))
|
||||
ret_data_len = snapshot_in.snapshot_array_size +
|
||||
sizeof(struct smb_snapshot_array);
|
||||
|
||||
if (copy_to_user(ioc_buf, retbuf, ret_data_len))
|
||||
rc = -EFAULT;
|
||||
|
@ -1487,7 +1523,11 @@ smb2_is_session_expired(char *buf)
|
|||
shdr->Status != STATUS_USER_SESSION_DELETED)
|
||||
return false;
|
||||
|
||||
trace_smb3_ses_expired(shdr->TreeId, shdr->SessionId,
|
||||
le16_to_cpu(shdr->Command),
|
||||
le64_to_cpu(shdr->MessageId));
|
||||
cifs_dbg(FYI, "Session expired or deleted\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1504,9 +1544,130 @@ smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
|
|||
CIFS_CACHE_READ(cinode) ? 1 : 0);
|
||||
}
|
||||
|
||||
static void
|
||||
smb2_set_related(struct smb_rqst *rqst)
|
||||
{
|
||||
struct smb2_sync_hdr *shdr;
|
||||
|
||||
shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base);
|
||||
shdr->Flags |= SMB2_FLAGS_RELATED_OPERATIONS;
|
||||
}
|
||||
|
||||
char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
static void
|
||||
smb2_set_next_command(struct TCP_Server_Info *server, struct smb_rqst *rqst)
|
||||
{
|
||||
struct smb2_sync_hdr *shdr;
|
||||
unsigned long len = smb_rqst_len(server, rqst);
|
||||
|
||||
/* SMB headers in a compound are 8 byte aligned. */
|
||||
if (len & 7) {
|
||||
rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding;
|
||||
rqst->rq_iov[rqst->rq_nvec].iov_len = 8 - (len & 7);
|
||||
rqst->rq_nvec++;
|
||||
len = smb_rqst_len(server, rqst);
|
||||
}
|
||||
|
||||
shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base);
|
||||
shdr->NextCommand = cpu_to_le32(len);
|
||||
}
|
||||
|
||||
static int
|
||||
smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct kstatfs *buf)
|
||||
{
|
||||
struct smb2_query_info_rsp *rsp;
|
||||
struct smb2_fs_full_size_info *info = NULL;
|
||||
struct smb_rqst rqst[3];
|
||||
int resp_buftype[3];
|
||||
struct kvec rsp_iov[3];
|
||||
struct kvec open_iov[5]; /* 4 + potential padding. */
|
||||
struct kvec qi_iov[1];
|
||||
struct kvec close_iov[1];
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
__le16 srch_path = 0; /* Null - open root of share */
|
||||
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_fid fid;
|
||||
int flags = 0;
|
||||
int rc;
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
memset(rqst, 0, sizeof(rqst));
|
||||
memset(resp_buftype, 0, sizeof(resp_buftype));
|
||||
memset(rsp_iov, 0, sizeof(rsp_iov));
|
||||
|
||||
memset(&open_iov, 0, sizeof(open_iov));
|
||||
rqst[0].rq_iov = open_iov;
|
||||
rqst[0].rq_nvec = 4;
|
||||
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = FILE_READ_ATTRIBUTES;
|
||||
oparms.disposition = FILE_OPEN;
|
||||
oparms.create_options = 0;
|
||||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, &srch_path);
|
||||
if (rc)
|
||||
goto qfs_exit;
|
||||
smb2_set_next_command(server, &rqst[0]);
|
||||
|
||||
memset(&qi_iov, 0, sizeof(qi_iov));
|
||||
rqst[1].rq_iov = qi_iov;
|
||||
rqst[1].rq_nvec = 1;
|
||||
|
||||
rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID,
|
||||
FS_FULL_SIZE_INFORMATION,
|
||||
SMB2_O_INFO_FILESYSTEM, 0,
|
||||
sizeof(struct smb2_fs_full_size_info));
|
||||
if (rc)
|
||||
goto qfs_exit;
|
||||
smb2_set_next_command(server, &rqst[1]);
|
||||
smb2_set_related(&rqst[1]);
|
||||
|
||||
memset(&close_iov, 0, sizeof(close_iov));
|
||||
rqst[2].rq_iov = close_iov;
|
||||
rqst[2].rq_nvec = 1;
|
||||
|
||||
rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
|
||||
if (rc)
|
||||
goto qfs_exit;
|
||||
smb2_set_related(&rqst[2]);
|
||||
|
||||
rc = compound_send_recv(xid, ses, flags, 3, rqst,
|
||||
resp_buftype, rsp_iov);
|
||||
if (rc)
|
||||
goto qfs_exit;
|
||||
|
||||
rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
|
||||
buf->f_type = SMB2_MAGIC_NUMBER;
|
||||
info = (struct smb2_fs_full_size_info *)(
|
||||
le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
|
||||
rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength),
|
||||
&rsp_iov[1],
|
||||
sizeof(struct smb2_fs_full_size_info));
|
||||
if (!rc)
|
||||
smb2_copy_fs_info_to_kstatfs(info, buf);
|
||||
|
||||
qfs_exit:
|
||||
SMB2_open_free(&rqst[0]);
|
||||
SMB2_query_info_free(&rqst[1]);
|
||||
SMB2_close_free(&rqst[2]);
|
||||
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
||||
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
||||
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
smb311_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct kstatfs *buf)
|
||||
{
|
||||
int rc;
|
||||
__le16 srch_path = 0; /* Null - open root of share */
|
||||
|
@ -1514,6 +1675,9 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
struct cifs_open_parms oparms;
|
||||
struct cifs_fid fid;
|
||||
|
||||
if (!tcon->posix_extensions)
|
||||
return smb2_queryfs(xid, tcon, buf);
|
||||
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = FILE_READ_ATTRIBUTES;
|
||||
oparms.disposition = FILE_OPEN;
|
||||
|
@ -1524,9 +1688,10 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = SMB311_posix_qfs_info(xid, tcon, fid.persistent_fid,
|
||||
fid.volatile_fid, buf);
|
||||
buf->f_type = SMB2_MAGIC_NUMBER;
|
||||
rc = SMB2_QFS_info(xid, tcon, fid.persistent_fid, fid.volatile_fid,
|
||||
buf);
|
||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
return rc;
|
||||
}
|
||||
|
@ -1700,7 +1865,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
&resp_buftype);
|
||||
if (!rc || !err_iov.iov_base) {
|
||||
rc = -ENOENT;
|
||||
goto querty_exit;
|
||||
goto free_path;
|
||||
}
|
||||
|
||||
err_buf = err_iov.iov_base;
|
||||
|
@ -1741,6 +1906,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
querty_exit:
|
||||
free_rsp_buf(resp_buftype, err_buf);
|
||||
free_path:
|
||||
kfree(utf16_path);
|
||||
return rc;
|
||||
}
|
||||
|
@ -2326,35 +2492,51 @@ static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf,
|
|||
sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf));
|
||||
}
|
||||
|
||||
/* Assumes:
|
||||
* rqst->rq_iov[0] is transform header
|
||||
* rqst->rq_iov[1+] data to be encrypted/decrypted
|
||||
/* Assumes the first rqst has a transform header as the first iov.
|
||||
* I.e.
|
||||
* rqst[0].rq_iov[0] is transform header
|
||||
* rqst[0].rq_iov[1+] data to be encrypted/decrypted
|
||||
* rqst[1+].rq_iov[0+] data to be encrypted/decrypted
|
||||
*/
|
||||
static struct scatterlist *
|
||||
init_sg(struct smb_rqst *rqst, u8 *sign)
|
||||
init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign)
|
||||
{
|
||||
unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages + 1;
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
|
||||
unsigned int sg_len;
|
||||
struct scatterlist *sg;
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
unsigned int idx = 0;
|
||||
int skip;
|
||||
|
||||
sg_len = 1;
|
||||
for (i = 0; i < num_rqst; i++)
|
||||
sg_len += rqst[i].rq_nvec + rqst[i].rq_npages;
|
||||
|
||||
sg = kmalloc_array(sg_len, sizeof(struct scatterlist), GFP_KERNEL);
|
||||
if (!sg)
|
||||
return NULL;
|
||||
|
||||
sg_init_table(sg, sg_len);
|
||||
smb2_sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 20, assoc_data_len);
|
||||
for (i = 1; i < rqst->rq_nvec; i++)
|
||||
smb2_sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base,
|
||||
rqst->rq_iov[i].iov_len);
|
||||
for (j = 0; i < sg_len - 1; i++, j++) {
|
||||
for (i = 0; i < num_rqst; i++) {
|
||||
for (j = 0; j < rqst[i].rq_nvec; j++) {
|
||||
/*
|
||||
* The first rqst has a transform header where the
|
||||
* first 20 bytes are not part of the encrypted blob
|
||||
*/
|
||||
skip = (i == 0) && (j == 0) ? 20 : 0;
|
||||
smb2_sg_set_buf(&sg[idx++],
|
||||
rqst[i].rq_iov[j].iov_base + skip,
|
||||
rqst[i].rq_iov[j].iov_len - skip);
|
||||
}
|
||||
|
||||
for (j = 0; j < rqst[i].rq_npages; j++) {
|
||||
unsigned int len, offset;
|
||||
|
||||
rqst_page_get_length(rqst, j, &len, &offset);
|
||||
sg_set_page(&sg[i], rqst->rq_pages[j], len, offset);
|
||||
rqst_page_get_length(&rqst[i], j, &len, &offset);
|
||||
sg_set_page(&sg[idx++], rqst[i].rq_pages[j], len, offset);
|
||||
}
|
||||
smb2_sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE);
|
||||
}
|
||||
smb2_sg_set_buf(&sg[idx], sign, SMB2_SIGNATURE_SIZE);
|
||||
return sg;
|
||||
}
|
||||
|
||||
|
@ -2386,10 +2568,11 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
|
|||
* untouched.
|
||||
*/
|
||||
static int
|
||||
crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc)
|
||||
crypt_message(struct TCP_Server_Info *server, int num_rqst,
|
||||
struct smb_rqst *rqst, int enc)
|
||||
{
|
||||
struct smb2_transform_hdr *tr_hdr =
|
||||
(struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base;
|
||||
(struct smb2_transform_hdr *)rqst[0].rq_iov[0].iov_base;
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
|
||||
int rc = 0;
|
||||
struct scatterlist *sg;
|
||||
|
@ -2440,7 +2623,7 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc)
|
|||
crypt_len += SMB2_SIGNATURE_SIZE;
|
||||
}
|
||||
|
||||
sg = init_sg(rqst, sign);
|
||||
sg = init_sg(num_rqst, rqst, sign);
|
||||
if (!sg) {
|
||||
cifs_dbg(VFS, "%s: Failed to init sg", __func__);
|
||||
rc = -ENOMEM;
|
||||
|
@ -2477,103 +2660,98 @@ free_req:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
|
||||
struct smb_rqst *old_rq)
|
||||
void
|
||||
smb3_free_compound_rqst(int num_rqst, struct smb_rqst *rqst)
|
||||
{
|
||||
struct kvec *iov;
|
||||
struct page **pages;
|
||||
struct smb2_transform_hdr *tr_hdr;
|
||||
unsigned int npages = old_rq->rq_npages;
|
||||
unsigned int orig_len;
|
||||
int i;
|
||||
int rc = -ENOMEM;
|
||||
int i, j;
|
||||
|
||||
pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
|
||||
if (!pages)
|
||||
return rc;
|
||||
|
||||
new_rq->rq_pages = pages;
|
||||
new_rq->rq_offset = old_rq->rq_offset;
|
||||
new_rq->rq_npages = old_rq->rq_npages;
|
||||
new_rq->rq_pagesz = old_rq->rq_pagesz;
|
||||
new_rq->rq_tailsz = old_rq->rq_tailsz;
|
||||
|
||||
for (i = 0; i < npages; i++) {
|
||||
pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
|
||||
if (!pages[i])
|
||||
goto err_free_pages;
|
||||
for (i = 0; i < num_rqst; i++) {
|
||||
if (rqst[i].rq_pages) {
|
||||
for (j = rqst[i].rq_npages - 1; j >= 0; j--)
|
||||
put_page(rqst[i].rq_pages[j]);
|
||||
kfree(rqst[i].rq_pages);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iov = kmalloc_array(old_rq->rq_nvec + 1, sizeof(struct kvec),
|
||||
/*
|
||||
* This function will initialize new_rq and encrypt the content.
|
||||
* The first entry, new_rq[0], only contains a single iov which contains
|
||||
* a smb2_transform_hdr and is pre-allocated by the caller.
|
||||
* This function then populates new_rq[1+] with the content from olq_rq[0+].
|
||||
*
|
||||
* The end result is an array of smb_rqst structures where the first structure
|
||||
* only contains a single iov for the transform header which we then can pass
|
||||
* to crypt_message().
|
||||
*
|
||||
* new_rq[0].rq_iov[0] : smb2_transform_hdr pre-allocated by the caller
|
||||
* new_rq[1+].rq_iov[*] == old_rq[0+].rq_iov[*] : SMB2/3 requests
|
||||
*/
|
||||
static int
|
||||
smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
|
||||
struct smb_rqst *new_rq, struct smb_rqst *old_rq)
|
||||
{
|
||||
struct page **pages;
|
||||
struct smb2_transform_hdr *tr_hdr = new_rq[0].rq_iov[0].iov_base;
|
||||
unsigned int npages;
|
||||
unsigned int orig_len = 0;
|
||||
int i, j;
|
||||
int rc = -ENOMEM;
|
||||
|
||||
for (i = 1; i < num_rqst; i++) {
|
||||
npages = old_rq[i - 1].rq_npages;
|
||||
pages = kmalloc_array(npages, sizeof(struct page *),
|
||||
GFP_KERNEL);
|
||||
if (!iov)
|
||||
goto err_free_pages;
|
||||
if (!pages)
|
||||
goto err_free;
|
||||
|
||||
/* copy all iovs from the old */
|
||||
memcpy(&iov[1], &old_rq->rq_iov[0],
|
||||
sizeof(struct kvec) * old_rq->rq_nvec);
|
||||
new_rq[i].rq_pages = pages;
|
||||
new_rq[i].rq_npages = npages;
|
||||
new_rq[i].rq_offset = old_rq[i - 1].rq_offset;
|
||||
new_rq[i].rq_pagesz = old_rq[i - 1].rq_pagesz;
|
||||
new_rq[i].rq_tailsz = old_rq[i - 1].rq_tailsz;
|
||||
new_rq[i].rq_iov = old_rq[i - 1].rq_iov;
|
||||
new_rq[i].rq_nvec = old_rq[i - 1].rq_nvec;
|
||||
|
||||
new_rq->rq_iov = iov;
|
||||
new_rq->rq_nvec = old_rq->rq_nvec + 1;
|
||||
orig_len += smb_rqst_len(server, &old_rq[i - 1]);
|
||||
|
||||
tr_hdr = kmalloc(sizeof(struct smb2_transform_hdr), GFP_KERNEL);
|
||||
if (!tr_hdr)
|
||||
goto err_free_iov;
|
||||
|
||||
orig_len = smb_rqst_len(server, old_rq);
|
||||
|
||||
/* fill the 2nd iov with a transform header */
|
||||
fill_transform_hdr(tr_hdr, orig_len, old_rq);
|
||||
new_rq->rq_iov[0].iov_base = tr_hdr;
|
||||
new_rq->rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr);
|
||||
for (j = 0; j < npages; j++) {
|
||||
pages[j] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
|
||||
if (!pages[j])
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
/* copy pages form the old */
|
||||
for (i = 0; i < npages; i++) {
|
||||
for (j = 0; j < npages; j++) {
|
||||
char *dst, *src;
|
||||
unsigned int offset, len;
|
||||
|
||||
rqst_page_get_length(new_rq, i, &len, &offset);
|
||||
rqst_page_get_length(&new_rq[i], j, &len, &offset);
|
||||
|
||||
dst = (char *) kmap(new_rq->rq_pages[i]) + offset;
|
||||
src = (char *) kmap(old_rq->rq_pages[i]) + offset;
|
||||
dst = (char *) kmap(new_rq[i].rq_pages[j]) + offset;
|
||||
src = (char *) kmap(old_rq[i - 1].rq_pages[j]) + offset;
|
||||
|
||||
memcpy(dst, src, len);
|
||||
kunmap(new_rq->rq_pages[i]);
|
||||
kunmap(old_rq->rq_pages[i]);
|
||||
kunmap(new_rq[i].rq_pages[j]);
|
||||
kunmap(old_rq[i - 1].rq_pages[j]);
|
||||
}
|
||||
}
|
||||
|
||||
rc = crypt_message(server, new_rq, 1);
|
||||
/* fill the 1st iov with a transform header */
|
||||
fill_transform_hdr(tr_hdr, orig_len, old_rq);
|
||||
|
||||
rc = crypt_message(server, num_rqst, new_rq, 1);
|
||||
cifs_dbg(FYI, "encrypt message returned %d", rc);
|
||||
if (rc)
|
||||
goto err_free_tr_hdr;
|
||||
goto err_free;
|
||||
|
||||
return rc;
|
||||
|
||||
err_free_tr_hdr:
|
||||
kfree(tr_hdr);
|
||||
err_free_iov:
|
||||
kfree(iov);
|
||||
err_free_pages:
|
||||
for (i = i - 1; i >= 0; i--)
|
||||
put_page(pages[i]);
|
||||
kfree(pages);
|
||||
err_free:
|
||||
smb3_free_compound_rqst(num_rqst - 1, &new_rq[1]);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
smb3_free_transform_rq(struct smb_rqst *rqst)
|
||||
{
|
||||
int i = rqst->rq_npages - 1;
|
||||
|
||||
for (; i >= 0; i--)
|
||||
put_page(rqst->rq_pages[i]);
|
||||
kfree(rqst->rq_pages);
|
||||
/* free transform header */
|
||||
kfree(rqst->rq_iov[0].iov_base);
|
||||
kfree(rqst->rq_iov);
|
||||
}
|
||||
|
||||
static int
|
||||
smb3_is_transform_hdr(void *buf)
|
||||
{
|
||||
|
@ -2603,7 +2781,7 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
|
|||
rqst.rq_pagesz = PAGE_SIZE;
|
||||
rqst.rq_tailsz = (page_data_size % PAGE_SIZE) ? : PAGE_SIZE;
|
||||
|
||||
rc = crypt_message(server, &rqst, 0);
|
||||
rc = crypt_message(server, 1, &rqst, 0);
|
||||
cifs_dbg(FYI, "decrypt message returned %d\n", rc);
|
||||
|
||||
if (rc)
|
||||
|
@ -2878,13 +3056,20 @@ discard_data:
|
|||
|
||||
static int
|
||||
receive_encrypted_standard(struct TCP_Server_Info *server,
|
||||
struct mid_q_entry **mid)
|
||||
struct mid_q_entry **mids, char **bufs,
|
||||
int *num_mids)
|
||||
{
|
||||
int length;
|
||||
int ret, length;
|
||||
char *buf = server->smallbuf;
|
||||
char *tmpbuf;
|
||||
struct smb2_sync_hdr *shdr;
|
||||
unsigned int pdu_length = server->pdu_size;
|
||||
unsigned int buf_size;
|
||||
struct mid_q_entry *mid_entry;
|
||||
int next_is_large;
|
||||
char *next_buffer = NULL;
|
||||
|
||||
*num_mids = 0;
|
||||
|
||||
/* switch to large buffer if too big for a small one */
|
||||
if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE) {
|
||||
|
@ -2905,24 +3090,61 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
|
|||
if (length)
|
||||
return length;
|
||||
|
||||
next_is_large = server->large_buf;
|
||||
one_more:
|
||||
shdr = (struct smb2_sync_hdr *)buf;
|
||||
if (shdr->NextCommand) {
|
||||
if (next_is_large) {
|
||||
tmpbuf = server->bigbuf;
|
||||
next_buffer = (char *)cifs_buf_get();
|
||||
} else {
|
||||
tmpbuf = server->smallbuf;
|
||||
next_buffer = (char *)cifs_small_buf_get();
|
||||
}
|
||||
memcpy(next_buffer,
|
||||
tmpbuf + le32_to_cpu(shdr->NextCommand),
|
||||
pdu_length - le32_to_cpu(shdr->NextCommand));
|
||||
}
|
||||
|
||||
mid_entry = smb2_find_mid(server, buf);
|
||||
if (mid_entry == NULL)
|
||||
cifs_dbg(FYI, "mid not found\n");
|
||||
else {
|
||||
cifs_dbg(FYI, "mid found\n");
|
||||
mid_entry->decrypted = true;
|
||||
mid_entry->resp_buf_size = server->pdu_size;
|
||||
}
|
||||
|
||||
*mid = mid_entry;
|
||||
if (*num_mids >= MAX_COMPOUND) {
|
||||
cifs_dbg(VFS, "too many PDUs in compound\n");
|
||||
return -1;
|
||||
}
|
||||
bufs[*num_mids] = buf;
|
||||
mids[(*num_mids)++] = mid_entry;
|
||||
|
||||
if (mid_entry && mid_entry->handle)
|
||||
return mid_entry->handle(server, mid_entry);
|
||||
ret = mid_entry->handle(server, mid_entry);
|
||||
else
|
||||
ret = cifs_handle_standard(server, mid_entry);
|
||||
|
||||
return cifs_handle_standard(server, mid_entry);
|
||||
if (ret == 0 && shdr->NextCommand) {
|
||||
pdu_length -= le32_to_cpu(shdr->NextCommand);
|
||||
server->large_buf = next_is_large;
|
||||
if (next_is_large)
|
||||
server->bigbuf = next_buffer;
|
||||
else
|
||||
server->smallbuf = next_buffer;
|
||||
|
||||
buf += le32_to_cpu(shdr->NextCommand);
|
||||
goto one_more;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid)
|
||||
smb3_receive_transform(struct TCP_Server_Info *server,
|
||||
struct mid_q_entry **mids, char **bufs, int *num_mids)
|
||||
{
|
||||
char *buf = server->smallbuf;
|
||||
unsigned int pdu_length = server->pdu_size;
|
||||
|
@ -2945,10 +3167,11 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid)
|
|||
return -ECONNABORTED;
|
||||
}
|
||||
|
||||
/* TODO: add support for compounds containing READ. */
|
||||
if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server))
|
||||
return receive_encrypted_read(server, mid);
|
||||
return receive_encrypted_read(server, &mids[0]);
|
||||
|
||||
return receive_encrypted_standard(server, mid);
|
||||
return receive_encrypted_standard(server, mids, bufs, num_mids);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -3250,7 +3473,6 @@ struct smb_version_operations smb30_operations = {
|
|||
.fallocate = smb3_fallocate,
|
||||
.enum_snapshots = smb3_enum_snapshots,
|
||||
.init_transform_rq = smb3_init_transform_rq,
|
||||
.free_transform_rq = smb3_free_transform_rq,
|
||||
.is_transform_hdr = smb3_is_transform_hdr,
|
||||
.receive_transform = smb3_receive_transform,
|
||||
.get_dfs_refer = smb2_get_dfs_refer,
|
||||
|
@ -3267,7 +3489,6 @@ struct smb_version_operations smb30_operations = {
|
|||
.next_header = smb2_next_header,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
struct smb_version_operations smb311_operations = {
|
||||
.compare_fids = smb2_compare_fids,
|
||||
.setup_request = smb2_setup_request,
|
||||
|
@ -3335,7 +3556,7 @@ struct smb_version_operations smb311_operations = {
|
|||
.is_status_pending = smb2_is_status_pending,
|
||||
.is_session_expired = smb2_is_session_expired,
|
||||
.oplock_response = smb2_oplock_response,
|
||||
.queryfs = smb2_queryfs,
|
||||
.queryfs = smb311_queryfs,
|
||||
.mand_lock = smb2_mand_lock,
|
||||
.mand_unlock_range = smb2_unlock_range,
|
||||
.push_mand_locks = smb2_push_mandatory_locks,
|
||||
|
@ -3357,7 +3578,6 @@ struct smb_version_operations smb311_operations = {
|
|||
.fallocate = smb3_fallocate,
|
||||
.enum_snapshots = smb3_enum_snapshots,
|
||||
.init_transform_rq = smb3_init_transform_rq,
|
||||
.free_transform_rq = smb3_free_transform_rq,
|
||||
.is_transform_hdr = smb3_is_transform_hdr,
|
||||
.receive_transform = smb3_receive_transform,
|
||||
.get_dfs_refer = smb2_get_dfs_refer,
|
||||
|
@ -3366,9 +3586,13 @@ struct smb_version_operations smb311_operations = {
|
|||
.query_all_EAs = smb2_query_eas,
|
||||
.set_EA = smb2_set_ea,
|
||||
#endif /* CIFS_XATTR */
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
.get_acl = get_smb2_acl,
|
||||
.get_acl_by_fid = get_smb2_acl_by_fid,
|
||||
.set_acl = set_smb2_acl,
|
||||
#endif /* CIFS_ACL */
|
||||
.next_header = smb2_next_header,
|
||||
};
|
||||
#endif /* CIFS_SMB311 */
|
||||
|
||||
struct smb_version_values smb20_values = {
|
||||
.version_string = SMB20_VERSION_STRING,
|
||||
|
@ -3496,7 +3720,6 @@ struct smb_version_values smb302_values = {
|
|||
.create_lease_size = sizeof(struct create_lease_v2),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
struct smb_version_values smb311_values = {
|
||||
.version_string = SMB311_VERSION_STRING,
|
||||
.protocol_id = SMB311_PROT_ID,
|
||||
|
@ -3517,4 +3740,3 @@ struct smb_version_values smb311_values = {
|
|||
.signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
|
||||
.create_lease_size = sizeof(struct create_lease_v2),
|
||||
};
|
||||
#endif /* SMB311 */
|
||||
|
|
|
@ -80,7 +80,7 @@ static const int smb2_req_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {
|
|||
/* SMB2_OPLOCK_BREAK */ 24 /* BB this is 36 for LEASE_BREAK variant */
|
||||
};
|
||||
|
||||
static int smb3_encryption_required(const struct cifs_tcon *tcon)
|
||||
int smb3_encryption_required(const struct cifs_tcon *tcon)
|
||||
{
|
||||
if (!tcon)
|
||||
return 0;
|
||||
|
@ -360,17 +360,15 @@ smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
|
|||
total_len);
|
||||
|
||||
if (tcon != NULL) {
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
uint16_t com_code = le16_to_cpu(smb2_command);
|
||||
cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[com_code]);
|
||||
#endif
|
||||
cifs_stats_inc(&tcon->num_smbs_sent);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
|
||||
/* offset is sizeof smb2_negotiate_req but rounded up to 8 bytes */
|
||||
#define OFFSET_OF_NEG_CONTEXT 0x68 /* sizeof(struct smb2_negotiate_req) */
|
||||
|
||||
|
@ -585,13 +583,6 @@ add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
static void assemble_neg_contexts(struct smb2_negotiate_req *req,
|
||||
unsigned int *total_len)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* SMB311 */
|
||||
|
||||
/*
|
||||
*
|
||||
|
@ -636,10 +627,9 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||
return rc;
|
||||
|
||||
req->sync_hdr.SessionId = 0;
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
|
||||
memset(server->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE);
|
||||
memset(ses->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE);
|
||||
#endif
|
||||
|
||||
if (strcmp(ses->server->vals->version_string,
|
||||
SMB3ANY_VERSION_STRING) == 0) {
|
||||
|
@ -741,10 +731,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||
cifs_dbg(FYI, "negotiated smb3.0 dialect\n");
|
||||
else if (rsp->DialectRevision == cpu_to_le16(SMB302_PROT_ID))
|
||||
cifs_dbg(FYI, "negotiated smb3.02 dialect\n");
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID))
|
||||
cifs_dbg(FYI, "negotiated smb3.1.1 dialect\n");
|
||||
#endif /* SMB311 */
|
||||
else {
|
||||
cifs_dbg(VFS, "Illegal dialect returned by server 0x%x\n",
|
||||
le16_to_cpu(rsp->DialectRevision));
|
||||
|
@ -753,9 +741,6 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||
}
|
||||
server->dialect = le16_to_cpu(rsp->DialectRevision);
|
||||
|
||||
/* BB: add check that dialect was valid given dialect(s) we asked for */
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
/*
|
||||
* Keep a copy of the hash after negprot. This hash will be
|
||||
* the starting hash value for all sessions made from this
|
||||
|
@ -763,7 +748,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||
*/
|
||||
memcpy(server->preauth_sha_hash, ses->preauth_sha_hash,
|
||||
SMB2_PREAUTH_HASH_SIZE);
|
||||
#endif
|
||||
|
||||
/* SMB2 only has an extended negflavor */
|
||||
server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
|
||||
/* set it to the maximum buffer size value we can send with 1 credit */
|
||||
|
@ -804,7 +789,6 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||
rc = -EIO;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
|
||||
if (rsp->NegotiateContextCount)
|
||||
rc = smb311_decode_neg_context(rsp, server,
|
||||
|
@ -812,7 +796,6 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||
else
|
||||
cifs_dbg(VFS, "Missing expected negotiate contexts\n");
|
||||
}
|
||||
#endif /* CONFIG_CIFS_SMB311 */
|
||||
neg_exit:
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
return rc;
|
||||
|
@ -1373,13 +1356,11 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
|
|||
sess_data->nls_cp = (struct nls_table *) nls_cp;
|
||||
sess_data->previous_session = ses->Suid;
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
/*
|
||||
* Initialize the session hash with the server one.
|
||||
*/
|
||||
memcpy(ses->preauth_sha_hash, ses->server->preauth_sha_hash,
|
||||
SMB2_PREAUTH_HASH_SIZE);
|
||||
#endif
|
||||
|
||||
while (sess_data->func)
|
||||
sess_data->func(sess_data);
|
||||
|
@ -1875,6 +1856,51 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* See MS-SMB2 2.2.13.2.7 */
|
||||
static struct crt_twarp_ctxt *
|
||||
create_twarp_buf(__u64 timewarp)
|
||||
{
|
||||
struct crt_twarp_ctxt *buf;
|
||||
|
||||
buf = kzalloc(sizeof(struct crt_twarp_ctxt), GFP_KERNEL);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
buf->ccontext.DataOffset = cpu_to_le16(offsetof
|
||||
(struct crt_twarp_ctxt, Timestamp));
|
||||
buf->ccontext.DataLength = cpu_to_le32(8);
|
||||
buf->ccontext.NameOffset = cpu_to_le16(offsetof
|
||||
(struct crt_twarp_ctxt, Name));
|
||||
buf->ccontext.NameLength = cpu_to_le16(4);
|
||||
/* SMB2_CREATE_TIMEWARP_TOKEN is "TWrp" */
|
||||
buf->Name[0] = 'T';
|
||||
buf->Name[1] = 'W';
|
||||
buf->Name[2] = 'r';
|
||||
buf->Name[3] = 'p';
|
||||
buf->Timestamp = cpu_to_le64(timewarp);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* See MS-SMB2 2.2.13.2.7 */
|
||||
static int
|
||||
add_twarp_context(struct kvec *iov, unsigned int *num_iovec, __u64 timewarp)
|
||||
{
|
||||
struct smb2_create_req *req = iov[0].iov_base;
|
||||
unsigned int num = *num_iovec;
|
||||
|
||||
iov[num].iov_base = create_twarp_buf(timewarp);
|
||||
if (iov[num].iov_base == NULL)
|
||||
return -ENOMEM;
|
||||
iov[num].iov_len = sizeof(struct crt_twarp_ctxt);
|
||||
if (!req->CreateContextsOffset)
|
||||
req->CreateContextsOffset = cpu_to_le32(
|
||||
sizeof(struct smb2_create_req) +
|
||||
iov[num - 1].iov_len);
|
||||
le32_add_cpu(&req->CreateContextsLength, sizeof(struct crt_twarp_ctxt));
|
||||
*num_iovec = num + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
|
||||
const char *treename, const __le16 *path)
|
||||
|
@ -1920,7 +1946,6 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
|
||||
umode_t mode, struct cifs_tcon *tcon,
|
||||
const char *full_path,
|
||||
|
@ -1928,7 +1953,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
|
|||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_create_req *req;
|
||||
struct smb2_create_rsp *rsp;
|
||||
struct smb2_create_rsp *rsp = NULL;
|
||||
struct TCP_Server_Info *server;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct kvec iov[3]; /* make sure at least one for each open context */
|
||||
|
@ -1943,27 +1968,31 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
|
|||
char *pc_buf = NULL;
|
||||
int flags = 0;
|
||||
unsigned int total_len;
|
||||
__le16 *path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
||||
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
__le16 *utf16_path = NULL;
|
||||
|
||||
cifs_dbg(FYI, "mkdir\n");
|
||||
|
||||
/* resource #1: path allocation */
|
||||
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
||||
if (!utf16_path)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ses && (ses->server))
|
||||
server = ses->server;
|
||||
else
|
||||
return -EIO;
|
||||
else {
|
||||
rc = -EIO;
|
||||
goto err_free_path;
|
||||
}
|
||||
|
||||
/* resource #2: request */
|
||||
rc = smb2_plain_req_init(SMB2_CREATE, tcon, (void **) &req, &total_len);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
goto err_free_path;
|
||||
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
|
||||
req->ImpersonationLevel = IL_IMPERSONATION;
|
||||
req->DesiredAccess = cpu_to_le32(FILE_WRITE_ATTRIBUTES);
|
||||
/* File attributes ignored on open (used in create though) */
|
||||
|
@ -1992,50 +2021,44 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
|
|||
req->sync_hdr.Flags |= SMB2_FLAGS_DFS_OPERATIONS;
|
||||
rc = alloc_path_with_tree_prefix(©_path, ©_size,
|
||||
&name_len,
|
||||
tcon->treeName, path);
|
||||
if (rc) {
|
||||
cifs_small_buf_release(req);
|
||||
return rc;
|
||||
}
|
||||
tcon->treeName, utf16_path);
|
||||
if (rc)
|
||||
goto err_free_req;
|
||||
|
||||
req->NameLength = cpu_to_le16(name_len * 2);
|
||||
uni_path_len = copy_size;
|
||||
path = copy_path;
|
||||
/* free before overwriting resource */
|
||||
kfree(utf16_path);
|
||||
utf16_path = copy_path;
|
||||
} else {
|
||||
uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2;
|
||||
uni_path_len = (2 * UniStrnlen((wchar_t *)utf16_path, PATH_MAX)) + 2;
|
||||
/* MUST set path len (NameLength) to 0 opening root of share */
|
||||
req->NameLength = cpu_to_le16(uni_path_len - 2);
|
||||
if (uni_path_len % 8 != 0) {
|
||||
copy_size = roundup(uni_path_len, 8);
|
||||
copy_path = kzalloc(copy_size, GFP_KERNEL);
|
||||
if (!copy_path) {
|
||||
cifs_small_buf_release(req);
|
||||
return -ENOMEM;
|
||||
rc = -ENOMEM;
|
||||
goto err_free_req;
|
||||
}
|
||||
memcpy((char *)copy_path, (const char *)path,
|
||||
memcpy((char *)copy_path, (const char *)utf16_path,
|
||||
uni_path_len);
|
||||
uni_path_len = copy_size;
|
||||
path = copy_path;
|
||||
/* free before overwriting resource */
|
||||
kfree(utf16_path);
|
||||
utf16_path = copy_path;
|
||||
}
|
||||
}
|
||||
|
||||
iov[1].iov_len = uni_path_len;
|
||||
iov[1].iov_base = path;
|
||||
iov[1].iov_base = utf16_path;
|
||||
req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
|
||||
|
||||
if (tcon->posix_extensions) {
|
||||
if (n_iov > 2) {
|
||||
struct create_context *ccontext =
|
||||
(struct create_context *)iov[n_iov-1].iov_base;
|
||||
ccontext->Next =
|
||||
cpu_to_le32(iov[n_iov-1].iov_len);
|
||||
}
|
||||
|
||||
/* resource #3: posix buf */
|
||||
rc = add_posix_context(iov, &n_iov, mode);
|
||||
if (rc) {
|
||||
cifs_small_buf_release(req);
|
||||
kfree(copy_path);
|
||||
return rc;
|
||||
}
|
||||
if (rc)
|
||||
goto err_free_req;
|
||||
pc_buf = iov[n_iov-1].iov_base;
|
||||
}
|
||||
|
||||
|
@ -2044,18 +2067,17 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
|
|||
rqst.rq_iov = iov;
|
||||
rqst.rq_nvec = n_iov;
|
||||
|
||||
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags,
|
||||
&rsp_iov);
|
||||
|
||||
cifs_small_buf_release(req);
|
||||
rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
|
||||
|
||||
if (rc != 0) {
|
||||
/* resource #4: response buffer */
|
||||
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
|
||||
if (rc) {
|
||||
cifs_stats_fail_inc(tcon, SMB2_CREATE_HE);
|
||||
trace_smb3_posix_mkdir_err(xid, tcon->tid, ses->Suid,
|
||||
CREATE_NOT_FILE, FILE_WRITE_ATTRIBUTES, rc);
|
||||
goto smb311_mkdir_exit;
|
||||
} else
|
||||
CREATE_NOT_FILE,
|
||||
FILE_WRITE_ATTRIBUTES, rc);
|
||||
goto err_free_rsp_buf;
|
||||
}
|
||||
|
||||
rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
|
||||
trace_smb3_posix_mkdir_done(xid, rsp->PersistentFileId, tcon->tid,
|
||||
ses->Suid, CREATE_NOT_FILE,
|
||||
FILE_WRITE_ATTRIBUTES);
|
||||
|
@ -2064,53 +2086,38 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
|
|||
|
||||
/* Eventually save off posix specific response info and timestaps */
|
||||
|
||||
smb311_mkdir_exit:
|
||||
kfree(copy_path);
|
||||
kfree(pc_buf);
|
||||
err_free_rsp_buf:
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
kfree(pc_buf);
|
||||
err_free_req:
|
||||
cifs_small_buf_release(req);
|
||||
err_free_path:
|
||||
kfree(utf16_path);
|
||||
return rc;
|
||||
|
||||
}
|
||||
#endif /* SMB311 */
|
||||
|
||||
int
|
||||
SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
||||
__u8 *oplock, struct smb2_file_all_info *buf,
|
||||
struct kvec *err_iov, int *buftype)
|
||||
SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock,
|
||||
struct cifs_open_parms *oparms, __le16 *path)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
struct smb2_create_req *req;
|
||||
struct smb2_create_rsp *rsp;
|
||||
struct TCP_Server_Info *server;
|
||||
struct cifs_tcon *tcon = oparms->tcon;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct kvec iov[5]; /* make sure at least one for each open context */
|
||||
struct kvec rsp_iov = {NULL, 0};
|
||||
int resp_buftype;
|
||||
int uni_path_len;
|
||||
__le16 *copy_path = NULL;
|
||||
int copy_size;
|
||||
int rc = 0;
|
||||
unsigned int n_iov = 2;
|
||||
__u32 file_attributes = 0;
|
||||
char *dhc_buf = NULL, *lc_buf = NULL, *pc_buf = NULL;
|
||||
int flags = 0;
|
||||
int copy_size;
|
||||
int uni_path_len;
|
||||
unsigned int total_len;
|
||||
|
||||
cifs_dbg(FYI, "create/open\n");
|
||||
|
||||
if (ses && (ses->server))
|
||||
server = ses->server;
|
||||
else
|
||||
return -EIO;
|
||||
struct kvec *iov = rqst->rq_iov;
|
||||
__le16 *copy_path;
|
||||
int rc;
|
||||
|
||||
rc = smb2_plain_req_init(SMB2_CREATE, tcon, (void **) &req, &total_len);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
iov[0].iov_base = (char *)req;
|
||||
/* -1 since last byte is buf[0] which is sent below (path) */
|
||||
iov[0].iov_len = total_len - 1;
|
||||
|
||||
if (oparms->create_options & CREATE_OPTION_READONLY)
|
||||
file_attributes |= ATTR_READONLY;
|
||||
|
@ -2124,11 +2131,6 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
|||
req->ShareAccess = FILE_SHARE_ALL_LE;
|
||||
req->CreateDisposition = cpu_to_le32(oparms->disposition);
|
||||
req->CreateOptions = cpu_to_le32(oparms->create_options & CREATE_OPTIONS_MASK);
|
||||
|
||||
iov[0].iov_base = (char *)req;
|
||||
/* -1 since last byte is buf[0] which is sent below (path) */
|
||||
iov[0].iov_len = total_len - 1;
|
||||
|
||||
req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req));
|
||||
|
||||
/* [MS-SMB2] 2.2.13 NameOffset:
|
||||
|
@ -2146,10 +2148,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
|||
rc = alloc_path_with_tree_prefix(©_path, ©_size,
|
||||
&name_len,
|
||||
tcon->treeName, path);
|
||||
if (rc) {
|
||||
cifs_small_buf_release(req);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
req->NameLength = cpu_to_le16(name_len * 2);
|
||||
uni_path_len = copy_size;
|
||||
path = copy_path;
|
||||
|
@ -2157,19 +2157,17 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
|||
uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2;
|
||||
/* MUST set path len (NameLength) to 0 opening root of share */
|
||||
req->NameLength = cpu_to_le16(uni_path_len - 2);
|
||||
if (uni_path_len % 8 != 0) {
|
||||
copy_size = roundup(uni_path_len, 8);
|
||||
copy_size = uni_path_len;
|
||||
if (copy_size % 8 != 0)
|
||||
copy_size = roundup(copy_size, 8);
|
||||
copy_path = kzalloc(copy_size, GFP_KERNEL);
|
||||
if (!copy_path) {
|
||||
cifs_small_buf_release(req);
|
||||
if (!copy_path)
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy((char *)copy_path, (const char *)path,
|
||||
uni_path_len);
|
||||
uni_path_len = copy_size;
|
||||
path = copy_path;
|
||||
}
|
||||
}
|
||||
|
||||
iov[1].iov_len = uni_path_len;
|
||||
iov[1].iov_base = path;
|
||||
|
@ -2183,13 +2181,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
|||
else {
|
||||
rc = add_lease_context(server, iov, &n_iov,
|
||||
oparms->fid->lease_key, oplock);
|
||||
if (rc) {
|
||||
cifs_small_buf_release(req);
|
||||
kfree(copy_path);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
lc_buf = iov[n_iov-1].iov_base;
|
||||
}
|
||||
|
||||
if (*oplock == SMB2_OPLOCK_LEVEL_BATCH) {
|
||||
/* need to set Next field of lease context if we request it */
|
||||
|
@ -2202,16 +2196,10 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
|||
|
||||
rc = add_durable_context(iov, &n_iov, oparms,
|
||||
tcon->use_persistent);
|
||||
if (rc) {
|
||||
cifs_small_buf_release(req);
|
||||
kfree(copy_path);
|
||||
kfree(lc_buf);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
dhc_buf = iov[n_iov-1].iov_base;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if (tcon->posix_extensions) {
|
||||
if (n_iov > 2) {
|
||||
struct create_context *ccontext =
|
||||
|
@ -2221,24 +2209,79 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
|||
}
|
||||
|
||||
rc = add_posix_context(iov, &n_iov, oparms->mode);
|
||||
if (rc) {
|
||||
cifs_small_buf_release(req);
|
||||
kfree(copy_path);
|
||||
kfree(lc_buf);
|
||||
kfree(dhc_buf);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
pc_buf = iov[n_iov-1].iov_base;
|
||||
|
||||
if (tcon->snapshot_time) {
|
||||
cifs_dbg(FYI, "adding snapshot context\n");
|
||||
if (n_iov > 2) {
|
||||
struct create_context *ccontext =
|
||||
(struct create_context *)iov[n_iov-1].iov_base;
|
||||
ccontext->Next =
|
||||
cpu_to_le32(iov[n_iov-1].iov_len);
|
||||
}
|
||||
#endif /* SMB311 */
|
||||
|
||||
rc = add_twarp_context(iov, &n_iov, tcon->snapshot_time);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
rqst->rq_nvec = n_iov;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* rq_iov[0] is the request and is released by cifs_small_buf_release().
|
||||
* All other vectors are freed by kfree().
|
||||
*/
|
||||
void
|
||||
SMB2_open_free(struct smb_rqst *rqst)
|
||||
{
|
||||
int i;
|
||||
|
||||
cifs_small_buf_release(rqst->rq_iov[0].iov_base);
|
||||
for (i = 1; i < rqst->rq_nvec; i++)
|
||||
if (rqst->rq_iov[i].iov_base != smb2_padding)
|
||||
kfree(rqst->rq_iov[i].iov_base);
|
||||
}
|
||||
|
||||
int
|
||||
SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
||||
__u8 *oplock, struct smb2_file_all_info *buf,
|
||||
struct kvec *err_iov, int *buftype)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_create_rsp *rsp = NULL;
|
||||
struct TCP_Server_Info *server;
|
||||
struct cifs_tcon *tcon = oparms->tcon;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct kvec iov[5]; /* make sure at least one for each open context */
|
||||
struct kvec rsp_iov = {NULL, 0};
|
||||
int resp_buftype;
|
||||
int rc = 0;
|
||||
int flags = 0;
|
||||
|
||||
cifs_dbg(FYI, "create/open\n");
|
||||
if (ses && (ses->server))
|
||||
server = ses->server;
|
||||
else
|
||||
return -EIO;
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
memset(&rqst, 0, sizeof(struct smb_rqst));
|
||||
memset(&iov, 0, sizeof(iov));
|
||||
rqst.rq_iov = iov;
|
||||
rqst.rq_nvec = n_iov;
|
||||
rqst.rq_nvec = 5;
|
||||
|
||||
rc = SMB2_open_init(tcon, &rqst, oplock, oparms, path);
|
||||
if (rc)
|
||||
goto creat_exit;
|
||||
|
||||
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags,
|
||||
&rsp_iov);
|
||||
cifs_small_buf_release(req);
|
||||
rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
|
||||
|
||||
if (rc != 0) {
|
||||
|
@ -2275,10 +2318,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
|||
else
|
||||
*oplock = rsp->OplockLevel;
|
||||
creat_exit:
|
||||
kfree(copy_path);
|
||||
kfree(lc_buf);
|
||||
kfree(dhc_buf);
|
||||
kfree(pc_buf);
|
||||
SMB2_open_free(&rqst);
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
return rc;
|
||||
}
|
||||
|
@ -2468,44 +2508,63 @@ SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
|
||||
u64 persistent_fid, u64 volatile_fid)
|
||||
{
|
||||
struct smb2_close_req *req;
|
||||
struct kvec *iov = rqst->rq_iov;
|
||||
unsigned int total_len;
|
||||
int rc;
|
||||
|
||||
rc = smb2_plain_req_init(SMB2_CLOSE, tcon, (void **) &req, &total_len);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
req->PersistentFileId = persistent_fid;
|
||||
req->VolatileFileId = volatile_fid;
|
||||
iov[0].iov_base = (char *)req;
|
||||
iov[0].iov_len = total_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
SMB2_close_free(struct smb_rqst *rqst)
|
||||
{
|
||||
cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */
|
||||
}
|
||||
|
||||
int
|
||||
SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, int flags)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_close_req *req;
|
||||
struct smb2_close_rsp *rsp;
|
||||
struct smb2_close_rsp *rsp = NULL;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct kvec iov[1];
|
||||
struct kvec rsp_iov;
|
||||
int resp_buftype;
|
||||
int rc = 0;
|
||||
unsigned int total_len;
|
||||
|
||||
cifs_dbg(FYI, "Close\n");
|
||||
|
||||
if (!ses || !(ses->server))
|
||||
return -EIO;
|
||||
|
||||
rc = smb2_plain_req_init(SMB2_CLOSE, tcon, (void **) &req, &total_len);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
req->PersistentFileId = persistent_fid;
|
||||
req->VolatileFileId = volatile_fid;
|
||||
|
||||
iov[0].iov_base = (char *)req;
|
||||
iov[0].iov_len = total_len;
|
||||
|
||||
memset(&rqst, 0, sizeof(struct smb_rqst));
|
||||
memset(&iov, 0, sizeof(iov));
|
||||
rqst.rq_iov = iov;
|
||||
rqst.rq_nvec = 1;
|
||||
|
||||
rc = SMB2_close_init(tcon, &rqst, persistent_fid, volatile_fid);
|
||||
if (rc)
|
||||
goto close_exit;
|
||||
|
||||
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
|
||||
cifs_small_buf_release(req);
|
||||
rsp = (struct smb2_close_rsp *)rsp_iov.iov_base;
|
||||
|
||||
if (rc != 0) {
|
||||
|
@ -2518,6 +2577,7 @@ SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
/* BB FIXME - decode close response, update inode for caching */
|
||||
|
||||
close_exit:
|
||||
SMB2_close_free(&rqst);
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
return rc;
|
||||
}
|
||||
|
@ -2529,8 +2589,8 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
return SMB2_close_flags(xid, tcon, persistent_fid, volatile_fid, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
validate_iov(unsigned int offset, unsigned int buffer_length,
|
||||
int
|
||||
smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
|
||||
struct kvec *iov, unsigned int min_buf_size)
|
||||
{
|
||||
unsigned int smb_len = iov->iov_len;
|
||||
|
@ -2575,7 +2635,7 @@ validate_and_copy_iov(unsigned int offset, unsigned int buffer_length,
|
|||
if (!data)
|
||||
return -EINVAL;
|
||||
|
||||
rc = validate_iov(offset, buffer_length, iov, minbufsize);
|
||||
rc = smb2_validate_iov(offset, buffer_length, iov, minbufsize);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -2584,36 +2644,22 @@ validate_and_copy_iov(unsigned int offset, unsigned int buffer_length,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, u8 info_class, u8 info_type,
|
||||
u32 additional_info, size_t output_len, size_t min_len, void **data,
|
||||
u32 *dlen)
|
||||
int
|
||||
SMB2_query_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
u8 info_class, u8 info_type, u32 additional_info,
|
||||
size_t output_len)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_query_info_req *req;
|
||||
struct smb2_query_info_rsp *rsp = NULL;
|
||||
struct kvec iov[2];
|
||||
struct kvec rsp_iov;
|
||||
int rc = 0;
|
||||
int resp_buftype;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
int flags = 0;
|
||||
struct kvec *iov = rqst->rq_iov;
|
||||
unsigned int total_len;
|
||||
|
||||
cifs_dbg(FYI, "Query Info\n");
|
||||
|
||||
if (!ses || !(ses->server))
|
||||
return -EIO;
|
||||
int rc;
|
||||
|
||||
rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, (void **) &req,
|
||||
&total_len);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
req->InfoType = info_type;
|
||||
req->FileInfoClass = info_class;
|
||||
req->PersistentFileId = persistent_fid;
|
||||
|
@ -2630,13 +2676,50 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
iov[0].iov_base = (char *)req;
|
||||
/* 1 for Buffer */
|
||||
iov[0].iov_len = total_len - 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
SMB2_query_info_free(struct smb_rqst *rqst)
|
||||
{
|
||||
cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */
|
||||
}
|
||||
|
||||
static int
|
||||
query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, u8 info_class, u8 info_type,
|
||||
u32 additional_info, size_t output_len, size_t min_len, void **data,
|
||||
u32 *dlen)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_query_info_rsp *rsp = NULL;
|
||||
struct kvec iov[1];
|
||||
struct kvec rsp_iov;
|
||||
int rc = 0;
|
||||
int resp_buftype;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
int flags = 0;
|
||||
|
||||
cifs_dbg(FYI, "Query Info\n");
|
||||
|
||||
if (!ses || !(ses->server))
|
||||
return -EIO;
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
memset(&rqst, 0, sizeof(struct smb_rqst));
|
||||
memset(&iov, 0, sizeof(iov));
|
||||
rqst.rq_iov = iov;
|
||||
rqst.rq_nvec = 1;
|
||||
|
||||
rc = SMB2_query_info_init(tcon, &rqst, persistent_fid, volatile_fid,
|
||||
info_class, info_type, additional_info,
|
||||
output_len);
|
||||
if (rc)
|
||||
goto qinf_exit;
|
||||
|
||||
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
|
||||
cifs_small_buf_release(req);
|
||||
rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
|
||||
|
||||
if (rc) {
|
||||
|
@ -2665,6 +2748,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
&rsp_iov, min_len, *data);
|
||||
|
||||
qinf_exit:
|
||||
SMB2_query_info_free(&rqst);
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
return rc;
|
||||
}
|
||||
|
@ -3623,7 +3707,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
goto qdir_exit;
|
||||
}
|
||||
|
||||
rc = validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength), &rsp_iov,
|
||||
info_buf_size);
|
||||
if (rc)
|
||||
|
@ -3927,8 +4011,8 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf,
|
||||
void
|
||||
smb2_copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf,
|
||||
struct kstatfs *kst)
|
||||
{
|
||||
kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) *
|
||||
|
@ -3939,6 +4023,25 @@ copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf,
|
|||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
copy_posix_fs_info_to_kstatfs(FILE_SYSTEM_POSIX_INFO *response_data,
|
||||
struct kstatfs *kst)
|
||||
{
|
||||
kst->f_bsize = le32_to_cpu(response_data->BlockSize);
|
||||
kst->f_blocks = le64_to_cpu(response_data->TotalBlocks);
|
||||
kst->f_bfree = le64_to_cpu(response_data->BlocksAvail);
|
||||
if (response_data->UserBlocksAvail == cpu_to_le64(-1))
|
||||
kst->f_bavail = kst->f_bfree;
|
||||
else
|
||||
kst->f_bavail = le64_to_cpu(response_data->UserBlocksAvail);
|
||||
if (response_data->TotalFileNodes != cpu_to_le64(-1))
|
||||
kst->f_files = le64_to_cpu(response_data->TotalFileNodes);
|
||||
if (response_data->FreeFileNodes != cpu_to_le64(-1))
|
||||
kst->f_ffree = le64_to_cpu(response_data->FreeFileNodes);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
|
||||
int outbuf_len, u64 persistent_fid, u64 volatile_fid)
|
||||
|
@ -3975,6 +4078,54 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct smb2_query_info_rsp *rsp = NULL;
|
||||
struct kvec iov;
|
||||
struct kvec rsp_iov;
|
||||
int rc = 0;
|
||||
int resp_buftype;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
FILE_SYSTEM_POSIX_INFO *info = NULL;
|
||||
int flags = 0;
|
||||
|
||||
rc = build_qfs_info_req(&iov, tcon, FS_POSIX_INFORMATION,
|
||||
sizeof(FILE_SYSTEM_POSIX_INFO),
|
||||
persistent_fid, volatile_fid);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
memset(&rqst, 0, sizeof(struct smb_rqst));
|
||||
rqst.rq_iov = &iov;
|
||||
rqst.rq_nvec = 1;
|
||||
|
||||
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
|
||||
cifs_small_buf_release(iov.iov_base);
|
||||
if (rc) {
|
||||
cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
|
||||
goto posix_qfsinf_exit;
|
||||
}
|
||||
rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
|
||||
|
||||
info = (FILE_SYSTEM_POSIX_INFO *)(
|
||||
le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
|
||||
rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength), &rsp_iov,
|
||||
sizeof(FILE_SYSTEM_POSIX_INFO));
|
||||
if (!rc)
|
||||
copy_posix_fs_info_to_kstatfs(info, fsdata);
|
||||
|
||||
posix_qfsinf_exit:
|
||||
free_rsp_buf(resp_buftype, rsp_iov.iov_base);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata)
|
||||
|
@ -4012,11 +4163,11 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
info = (struct smb2_fs_full_size_info *)(
|
||||
le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
|
||||
rc = validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength), &rsp_iov,
|
||||
sizeof(struct smb2_fs_full_size_info));
|
||||
if (!rc)
|
||||
copy_fs_info_to_kstatfs(info, fsdata);
|
||||
smb2_copy_fs_info_to_kstatfs(info, fsdata);
|
||||
|
||||
qfsinf_exit:
|
||||
free_rsp_buf(resp_buftype, rsp_iov.iov_base);
|
||||
|
@ -4046,6 +4197,9 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
} else if (level == FS_SECTOR_SIZE_INFORMATION) {
|
||||
max_len = sizeof(struct smb3_fs_ss_info);
|
||||
min_len = sizeof(struct smb3_fs_ss_info);
|
||||
} else if (level == FS_VOLUME_INFORMATION) {
|
||||
max_len = sizeof(struct smb3_fs_vol_info) + MAX_VOL_LABEL_LEN;
|
||||
min_len = sizeof(struct smb3_fs_vol_info);
|
||||
} else {
|
||||
cifs_dbg(FYI, "Invalid qfsinfo level %d\n", level);
|
||||
return -EINVAL;
|
||||
|
@ -4073,7 +4227,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
rsp_len = le32_to_cpu(rsp->OutputBufferLength);
|
||||
offset = le16_to_cpu(rsp->OutputBufferOffset);
|
||||
rc = validate_iov(offset, rsp_len, &rsp_iov, min_len);
|
||||
rc = smb2_validate_iov(offset, rsp_len, &rsp_iov, min_len);
|
||||
if (rc)
|
||||
goto qfsattr_exit;
|
||||
|
||||
|
@ -4090,6 +4244,11 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
tcon->ss_flags = le32_to_cpu(ss_info->Flags);
|
||||
tcon->perf_sector_size =
|
||||
le32_to_cpu(ss_info->PhysicalBytesPerSectorForPerf);
|
||||
} else if (level == FS_VOLUME_INFORMATION) {
|
||||
struct smb3_fs_vol_info *vol_info = (struct smb3_fs_vol_info *)
|
||||
(offset + (char *)rsp);
|
||||
tcon->vol_serial_number = vol_info->VolumeSerialNumber;
|
||||
tcon->vol_create_time = vol_info->VolumeCreationTime;
|
||||
}
|
||||
|
||||
qfsattr_exit:
|
||||
|
|
|
@ -153,6 +153,8 @@ struct smb2_transform_hdr {
|
|||
*
|
||||
*/
|
||||
|
||||
#define COMPOUND_FID 0xFFFFFFFFFFFFFFFFULL
|
||||
|
||||
#define SMB2_ERROR_STRUCTURE_SIZE2 cpu_to_le16(9)
|
||||
|
||||
struct smb2_err_rsp {
|
||||
|
@ -765,6 +767,14 @@ struct create_durable_handle_reconnect_v2 {
|
|||
struct durable_reconnect_context_v2 dcontext;
|
||||
} __packed;
|
||||
|
||||
/* See MS-SMB2 2.2.13.2.5 */
|
||||
struct crt_twarp_ctxt {
|
||||
struct create_context ccontext;
|
||||
__u8 Name[8];
|
||||
__le64 Timestamp;
|
||||
|
||||
} __packed;
|
||||
|
||||
#define COPY_CHUNK_RES_KEY_SIZE 24
|
||||
struct resume_key_req {
|
||||
char ResumeKey[COPY_CHUNK_RES_KEY_SIZE];
|
||||
|
@ -1223,6 +1233,7 @@ struct smb2_lease_ack {
|
|||
#define FS_DRIVER_PATH_INFORMATION 9 /* Local only */
|
||||
#define FS_VOLUME_FLAGS_INFORMATION 10 /* Local only */
|
||||
#define FS_SECTOR_SIZE_INFORMATION 11 /* SMB3 or later. Query */
|
||||
#define FS_POSIX_INFORMATION 100 /* SMB3.1.1 POSIX. Query */
|
||||
|
||||
struct smb2_fs_full_size_info {
|
||||
__le64 TotalAllocationUnits;
|
||||
|
@ -1248,6 +1259,17 @@ struct smb3_fs_ss_info {
|
|||
__le32 ByteOffsetForPartitionAlignment;
|
||||
} __packed;
|
||||
|
||||
/* volume info struct - see MS-FSCC 2.5.9 */
|
||||
#define MAX_VOL_LABEL_LEN 32
|
||||
struct smb3_fs_vol_info {
|
||||
__le64 VolumeCreationTime;
|
||||
__u32 VolumeSerialNumber;
|
||||
__le32 VolumeLabelLength; /* includes trailing null */
|
||||
__u8 SupportsObjects; /* True if eg like NTFS, supports objects */
|
||||
__u8 Reserved;
|
||||
__u8 VolumeLabel[0]; /* variable len */
|
||||
} __packed;
|
||||
|
||||
/* partial list of QUERY INFO levels */
|
||||
#define FILE_DIRECTORY_INFORMATION 1
|
||||
#define FILE_FULL_DIRECTORY_INFORMATION 2
|
||||
|
@ -1361,4 +1383,6 @@ struct smb2_file_eof_info { /* encoding of request for level 10 */
|
|||
__le64 EndOfFile; /* new end of file value */
|
||||
} __packed; /* level 20 Set */
|
||||
|
||||
extern char smb2_padding[7];
|
||||
|
||||
#endif /* _SMB2PDU_H */
|
||||
|
|
|
@ -68,6 +68,7 @@ extern int smb3_handle_read_data(struct TCP_Server_Info *server,
|
|||
|
||||
extern int open_shroot(unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_fid *pfid);
|
||||
extern void close_shroot(struct cached_fid *cfid);
|
||||
extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
|
||||
struct smb2_file_all_info *src);
|
||||
extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
@ -132,6 +133,10 @@ extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms,
|
|||
__le16 *path, __u8 *oplock,
|
||||
struct smb2_file_all_info *buf,
|
||||
struct kvec *err_iov, int *resp_buftype);
|
||||
extern int SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
|
||||
__u8 *oplock, struct cifs_open_parms *oparms,
|
||||
__le16 *path);
|
||||
extern void SMB2_open_free(struct smb_rqst *rqst);
|
||||
extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, u32 opcode,
|
||||
bool is_fsctl, char *in_data, u32 indatalen,
|
||||
|
@ -140,6 +145,9 @@ extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
u64 persistent_file_id, u64 volatile_file_id);
|
||||
extern int SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, int flags);
|
||||
extern int SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
|
||||
u64 persistent_file_id, u64 volatile_file_id);
|
||||
extern void SMB2_close_free(struct smb_rqst *rqst);
|
||||
extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_file_id, u64 volatile_file_id);
|
||||
extern int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
@ -149,6 +157,11 @@ extern int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_file_id, u64 volatile_file_id,
|
||||
struct smb2_file_all_info *data);
|
||||
extern int SMB2_query_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
u8 info_class, u8 info_type,
|
||||
u32 additional_info, size_t output_len);
|
||||
extern void SMB2_query_info_free(struct smb_rqst *rqst);
|
||||
extern int SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_file_id, u64 volatile_file_id,
|
||||
void **data, unsigned int *plen);
|
||||
|
@ -197,6 +210,9 @@ void smb2_cancelled_close_fid(struct work_struct *work);
|
|||
extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_file_id, u64 volatile_file_id,
|
||||
struct kstatfs *FSData);
|
||||
extern int SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_file_id, u64 volatile_file_id,
|
||||
struct kstatfs *FSData);
|
||||
extern int SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_file_id, u64 volatile_file_id, int lvl);
|
||||
extern int SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
@ -213,9 +229,13 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *);
|
|||
|
||||
extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
|
||||
enum securityEnum);
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
extern int smb3_encryption_required(const struct cifs_tcon *tcon);
|
||||
extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
|
||||
struct kvec *iov, unsigned int min_buf_size);
|
||||
extern void smb2_copy_fs_info_to_kstatfs(
|
||||
struct smb2_fs_full_size_info *pfs_inf,
|
||||
struct kstatfs *kst);
|
||||
extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server);
|
||||
extern int smb311_update_preauth_hash(struct cifs_ses *ses,
|
||||
struct kvec *iov, int nvec);
|
||||
#endif
|
||||
#endif /* _SMB2PROTO_H */
|
||||
|
|
|
@ -70,7 +70,6 @@ err:
|
|||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
int
|
||||
smb311_crypto_shash_allocate(struct TCP_Server_Info *server)
|
||||
{
|
||||
|
@ -98,7 +97,6 @@ err:
|
|||
cifs_free_hash(&p->hmacsha256, &p->sdeschmacsha256);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct cifs_ses *
|
||||
smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id)
|
||||
|
@ -173,7 +171,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
|||
struct kvec *iov = rqst->rq_iov;
|
||||
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base;
|
||||
struct cifs_ses *ses;
|
||||
struct shash_desc *shash = &server->secmech.sdeschmacsha256->shash;
|
||||
struct shash_desc *shash;
|
||||
struct smb_rqst drqst;
|
||||
|
||||
ses = smb2_find_smb_ses(server, shdr->SessionId);
|
||||
|
@ -187,7 +185,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
|||
|
||||
rc = smb2_crypto_shash_allocate(server);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: shah256 alloc failed\n", __func__);
|
||||
cifs_dbg(VFS, "%s: sha256 alloc failed\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -198,6 +196,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
|||
return rc;
|
||||
}
|
||||
|
||||
shash = &server->secmech.sdeschmacsha256->shash;
|
||||
rc = crypto_shash_init(shash);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not init sha256", __func__);
|
||||
|
@ -395,7 +394,6 @@ generate_smb30signingkey(struct cifs_ses *ses)
|
|||
return generate_smb3signingkey(ses, &triplet);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
int
|
||||
generate_smb311signingkey(struct cifs_ses *ses)
|
||||
|
||||
|
@ -423,7 +421,6 @@ generate_smb311signingkey(struct cifs_ses *ses)
|
|||
|
||||
return generate_smb3signingkey(ses, &triplet);
|
||||
}
|
||||
#endif /* 311 */
|
||||
|
||||
int
|
||||
smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
||||
|
|
|
@ -281,6 +281,44 @@ DEFINE_EVENT(smb3_cmd_done_class, smb3_##name, \
|
|||
TP_ARGS(tid, sesid, cmd, mid))
|
||||
|
||||
DEFINE_SMB3_CMD_DONE_EVENT(cmd_done);
|
||||
DEFINE_SMB3_CMD_DONE_EVENT(ses_expired);
|
||||
|
||||
DECLARE_EVENT_CLASS(smb3_mid_class,
|
||||
TP_PROTO(__u16 cmd,
|
||||
__u64 mid,
|
||||
__u32 pid,
|
||||
unsigned long when_sent,
|
||||
unsigned long when_received),
|
||||
TP_ARGS(cmd, mid, pid, when_sent, when_received),
|
||||
TP_STRUCT__entry(
|
||||
__field(__u16, cmd)
|
||||
__field(__u64, mid)
|
||||
__field(__u32, pid)
|
||||
__field(unsigned long, when_sent)
|
||||
__field(unsigned long, when_received)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->cmd = cmd;
|
||||
__entry->mid = mid;
|
||||
__entry->pid = pid;
|
||||
__entry->when_sent = when_sent;
|
||||
__entry->when_received = when_received;
|
||||
),
|
||||
TP_printk("\tcmd=%u mid=%llu pid=%u, when_sent=%lu when_rcv=%lu",
|
||||
__entry->cmd, __entry->mid, __entry->pid, __entry->when_sent,
|
||||
__entry->when_received)
|
||||
)
|
||||
|
||||
#define DEFINE_SMB3_MID_EVENT(name) \
|
||||
DEFINE_EVENT(smb3_mid_class, smb3_##name, \
|
||||
TP_PROTO(__u16 cmd, \
|
||||
__u64 mid, \
|
||||
__u32 pid, \
|
||||
unsigned long when_sent, \
|
||||
unsigned long when_received), \
|
||||
TP_ARGS(cmd, mid, pid, when_sent, when_received))
|
||||
|
||||
DEFINE_SMB3_MID_EVENT(slow_rsp);
|
||||
|
||||
DECLARE_EVENT_CLASS(smb3_exit_err_class,
|
||||
TP_PROTO(unsigned int xid,
|
||||
|
@ -422,6 +460,32 @@ DEFINE_EVENT(smb3_open_done_class, smb3_##name, \
|
|||
DEFINE_SMB3_OPEN_DONE_EVENT(open_done);
|
||||
DEFINE_SMB3_OPEN_DONE_EVENT(posix_mkdir_done);
|
||||
|
||||
DECLARE_EVENT_CLASS(smb3_reconnect_class,
|
||||
TP_PROTO(__u64 currmid,
|
||||
char *hostname),
|
||||
TP_ARGS(currmid, hostname),
|
||||
TP_STRUCT__entry(
|
||||
__field(__u64, currmid)
|
||||
__field(char *, hostname)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->currmid = currmid;
|
||||
__entry->hostname = hostname;
|
||||
),
|
||||
TP_printk("server=%s current_mid=0x%llx",
|
||||
__entry->hostname,
|
||||
__entry->currmid)
|
||||
)
|
||||
|
||||
#define DEFINE_SMB3_RECONNECT_EVENT(name) \
|
||||
DEFINE_EVENT(smb3_reconnect_class, smb3_##name, \
|
||||
TP_PROTO(__u64 currmid, \
|
||||
char *hostname), \
|
||||
TP_ARGS(currmid, hostname))
|
||||
|
||||
DEFINE_SMB3_RECONNECT_EVENT(reconnect);
|
||||
DEFINE_SMB3_RECONNECT_EVENT(partial_send_reconnect);
|
||||
|
||||
#endif /* _CIFS_TRACE_H */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
|
|
|
@ -115,8 +115,17 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
|
|||
now = jiffies;
|
||||
/* commands taking longer than one second are indications that
|
||||
something is wrong, unless it is quite a slow link or server */
|
||||
if (time_after(now, midEntry->when_alloc + HZ)) {
|
||||
if ((cifsFYI & CIFS_TIMER) && (midEntry->command != command)) {
|
||||
if (time_after(now, midEntry->when_alloc + HZ) &&
|
||||
(midEntry->command != command)) {
|
||||
/* smb2slowcmd[NUMBER_OF_SMB2_COMMANDS] counts by command */
|
||||
if ((le16_to_cpu(midEntry->command) < NUMBER_OF_SMB2_COMMANDS) &&
|
||||
(le16_to_cpu(midEntry->command) >= 0))
|
||||
cifs_stats_inc(&midEntry->server->smb2slowcmd[le16_to_cpu(midEntry->command)]);
|
||||
|
||||
trace_smb3_slow_rsp(le16_to_cpu(midEntry->command),
|
||||
midEntry->mid, midEntry->pid,
|
||||
midEntry->when_sent, midEntry->when_received);
|
||||
if (cifsFYI & CIFS_TIMER) {
|
||||
pr_debug(" CIFS slow rsp: cmd %d mid %llu",
|
||||
midEntry->command, midEntry->mid);
|
||||
pr_info(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
|
||||
|
@ -361,6 +370,8 @@ uncork:
|
|||
* socket so the server throws away the partial SMB
|
||||
*/
|
||||
server->tcpStatus = CifsNeedReconnect;
|
||||
trace_smb3_partial_send_reconnect(server->CurrentMid,
|
||||
server->hostname);
|
||||
}
|
||||
smbd_done:
|
||||
if (rc < 0 && rc != -EINTR)
|
||||
|
@ -373,26 +384,42 @@ smbd_done:
|
|||
}
|
||||
|
||||
static int
|
||||
smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags)
|
||||
smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
||||
struct smb_rqst *rqst, int flags)
|
||||
{
|
||||
struct smb_rqst cur_rqst;
|
||||
struct kvec iov;
|
||||
struct smb2_transform_hdr tr_hdr;
|
||||
struct smb_rqst cur_rqst[MAX_COMPOUND];
|
||||
int rc;
|
||||
|
||||
if (!(flags & CIFS_TRANSFORM_REQ))
|
||||
return __smb_send_rqst(server, 1, rqst);
|
||||
return __smb_send_rqst(server, num_rqst, rqst);
|
||||
|
||||
if (!server->ops->init_transform_rq ||
|
||||
!server->ops->free_transform_rq) {
|
||||
cifs_dbg(VFS, "Encryption requested but transform callbacks are missed\n");
|
||||
if (num_rqst > MAX_COMPOUND - 1)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(&cur_rqst[0], 0, sizeof(cur_rqst));
|
||||
memset(&iov, 0, sizeof(iov));
|
||||
memset(&tr_hdr, 0, sizeof(tr_hdr));
|
||||
|
||||
iov.iov_base = &tr_hdr;
|
||||
iov.iov_len = sizeof(tr_hdr);
|
||||
cur_rqst[0].rq_iov = &iov;
|
||||
cur_rqst[0].rq_nvec = 1;
|
||||
|
||||
if (!server->ops->init_transform_rq) {
|
||||
cifs_dbg(VFS, "Encryption requested but transform callback "
|
||||
"is missing\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
rc = server->ops->init_transform_rq(server, &cur_rqst, rqst);
|
||||
rc = server->ops->init_transform_rq(server, num_rqst + 1,
|
||||
&cur_rqst[0], rqst);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = __smb_send_rqst(server, 1, &cur_rqst);
|
||||
server->ops->free_transform_rq(&cur_rqst);
|
||||
rc = __smb_send_rqst(server, num_rqst + 1, &cur_rqst[0]);
|
||||
smb3_free_compound_rqst(num_rqst, &cur_rqst[1]);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -606,7 +633,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
|
|||
*/
|
||||
cifs_save_when_sent(mid);
|
||||
cifs_in_send_inc(server);
|
||||
rc = smb_send_rqst(server, rqst, flags);
|
||||
rc = smb_send_rqst(server, 1, rqst, flags);
|
||||
cifs_in_send_dec(server);
|
||||
|
||||
if (rc < 0) {
|
||||
|
@ -746,20 +773,21 @@ cifs_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
|
|||
}
|
||||
|
||||
int
|
||||
cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
struct smb_rqst *rqst, int *resp_buf_type, const int flags,
|
||||
struct kvec *resp_iov)
|
||||
compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
const int flags, const int num_rqst, struct smb_rqst *rqst,
|
||||
int *resp_buf_type, struct kvec *resp_iov)
|
||||
{
|
||||
int rc = 0;
|
||||
int i, j, rc = 0;
|
||||
int timeout, optype;
|
||||
struct mid_q_entry *midQ;
|
||||
struct mid_q_entry *midQ[MAX_COMPOUND];
|
||||
unsigned int credits = 1;
|
||||
char *buf;
|
||||
|
||||
timeout = flags & CIFS_TIMEOUT_MASK;
|
||||
optype = flags & CIFS_OP_MASK;
|
||||
|
||||
*resp_buf_type = CIFS_NO_BUFFER; /* no response buf yet */
|
||||
for (i = 0; i < num_rqst; i++)
|
||||
resp_buf_type[i] = CIFS_NO_BUFFER; /* no response buf yet */
|
||||
|
||||
if ((ses == NULL) || (ses->server == NULL)) {
|
||||
cifs_dbg(VFS, "Null session\n");
|
||||
|
@ -786,44 +814,52 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
|||
|
||||
mutex_lock(&ses->server->srv_mutex);
|
||||
|
||||
midQ = ses->server->ops->setup_request(ses, rqst);
|
||||
if (IS_ERR(midQ)) {
|
||||
for (i = 0; i < num_rqst; i++) {
|
||||
midQ[i] = ses->server->ops->setup_request(ses, &rqst[i]);
|
||||
if (IS_ERR(midQ[i])) {
|
||||
for (j = 0; j < i; j++)
|
||||
cifs_delete_mid(midQ[j]);
|
||||
mutex_unlock(&ses->server->srv_mutex);
|
||||
/* Update # of requests on wire to server */
|
||||
add_credits(ses->server, 1, optype);
|
||||
return PTR_ERR(midQ);
|
||||
return PTR_ERR(midQ[i]);
|
||||
}
|
||||
|
||||
midQ[i]->mid_state = MID_REQUEST_SUBMITTED;
|
||||
}
|
||||
|
||||
midQ->mid_state = MID_REQUEST_SUBMITTED;
|
||||
cifs_in_send_inc(ses->server);
|
||||
rc = smb_send_rqst(ses->server, rqst, flags);
|
||||
rc = smb_send_rqst(ses->server, num_rqst, rqst, flags);
|
||||
cifs_in_send_dec(ses->server);
|
||||
cifs_save_when_sent(midQ);
|
||||
|
||||
for (i = 0; i < num_rqst; i++)
|
||||
cifs_save_when_sent(midQ[i]);
|
||||
|
||||
if (rc < 0)
|
||||
ses->server->sequence_number -= 2;
|
||||
|
||||
mutex_unlock(&ses->server->srv_mutex);
|
||||
|
||||
for (i = 0; i < num_rqst; i++) {
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP))
|
||||
smb311_update_preauth_hash(ses, rqst->rq_iov,
|
||||
rqst->rq_nvec);
|
||||
#endif
|
||||
smb311_update_preauth_hash(ses, rqst[i].rq_iov,
|
||||
rqst[i].rq_nvec);
|
||||
|
||||
if (timeout == CIFS_ASYNC_OP)
|
||||
goto out;
|
||||
|
||||
rc = wait_for_response(ses->server, midQ);
|
||||
rc = wait_for_response(ses->server, midQ[i]);
|
||||
if (rc != 0) {
|
||||
cifs_dbg(FYI, "Cancelling wait for mid %llu\n", midQ->mid);
|
||||
send_cancel(ses->server, rqst, midQ);
|
||||
cifs_dbg(FYI, "Cancelling wait for mid %llu\n",
|
||||
midQ[i]->mid);
|
||||
send_cancel(ses->server, &rqst[i], midQ[i]);
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
|
||||
midQ->mid_flags |= MID_WAIT_CANCELLED;
|
||||
midQ->callback = DeleteMidQEntry;
|
||||
if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) {
|
||||
midQ[i]->mid_flags |= MID_WAIT_CANCELLED;
|
||||
midQ[i]->callback = DeleteMidQEntry;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
add_credits(ses->server, 1, optype);
|
||||
return rc;
|
||||
|
@ -831,52 +867,63 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
|||
spin_unlock(&GlobalMid_Lock);
|
||||
}
|
||||
|
||||
rc = cifs_sync_mid_result(midQ, ses->server);
|
||||
rc = cifs_sync_mid_result(midQ[i], ses->server);
|
||||
if (rc != 0) {
|
||||
add_credits(ses->server, 1, optype);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!midQ->resp_buf || midQ->mid_state != MID_RESPONSE_RECEIVED) {
|
||||
if (!midQ[i]->resp_buf ||
|
||||
midQ[i]->mid_state != MID_RESPONSE_RECEIVED) {
|
||||
rc = -EIO;
|
||||
cifs_dbg(FYI, "Bad MID state?\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf = (char *)midQ->resp_buf;
|
||||
resp_iov->iov_base = buf;
|
||||
resp_iov->iov_len = midQ->resp_buf_size +
|
||||
buf = (char *)midQ[i]->resp_buf;
|
||||
resp_iov[i].iov_base = buf;
|
||||
resp_iov[i].iov_len = midQ[i]->resp_buf_size +
|
||||
ses->server->vals->header_preamble_size;
|
||||
if (midQ->large_buf)
|
||||
*resp_buf_type = CIFS_LARGE_BUFFER;
|
||||
else
|
||||
*resp_buf_type = CIFS_SMALL_BUFFER;
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if (midQ[i]->large_buf)
|
||||
resp_buf_type[i] = CIFS_LARGE_BUFFER;
|
||||
else
|
||||
resp_buf_type[i] = CIFS_SMALL_BUFFER;
|
||||
|
||||
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) {
|
||||
struct kvec iov = {
|
||||
.iov_base = resp_iov->iov_base,
|
||||
.iov_len = resp_iov->iov_len
|
||||
.iov_base = resp_iov[i].iov_base,
|
||||
.iov_len = resp_iov[i].iov_len
|
||||
};
|
||||
smb311_update_preauth_hash(ses, &iov, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
credits = ses->server->ops->get_credits(midQ);
|
||||
credits = ses->server->ops->get_credits(midQ[i]);
|
||||
|
||||
rc = ses->server->ops->check_receive(midQ, ses->server,
|
||||
rc = ses->server->ops->check_receive(midQ[i], ses->server,
|
||||
flags & CIFS_LOG_ERROR);
|
||||
|
||||
/* mark it so buf will not be freed by cifs_delete_mid */
|
||||
if ((flags & CIFS_NO_RESP) == 0)
|
||||
midQ->resp_buf = NULL;
|
||||
midQ[i]->resp_buf = NULL;
|
||||
}
|
||||
out:
|
||||
cifs_delete_mid(midQ);
|
||||
for (i = 0; i < num_rqst; i++)
|
||||
cifs_delete_mid(midQ[i]);
|
||||
add_credits(ses->server, credits, optype);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
struct smb_rqst *rqst, int *resp_buf_type, const int flags,
|
||||
struct kvec *resp_iov)
|
||||
{
|
||||
return compound_send_recv(xid, ses, flags, 1, rqst, resp_buf_type,
|
||||
resp_iov);
|
||||
}
|
||||
|
||||
int
|
||||
SendReceive2(const unsigned int xid, struct cifs_ses *ses,
|
||||
struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
|
||||
|
|
|
@ -35,6 +35,14 @@
|
|||
#define CIFS_XATTR_CIFS_ACL "system.cifs_acl"
|
||||
#define CIFS_XATTR_ATTRIB "cifs.dosattrib" /* full name: user.cifs.dosattrib */
|
||||
#define CIFS_XATTR_CREATETIME "cifs.creationtime" /* user.cifs.creationtime */
|
||||
/*
|
||||
* Although these three are just aliases for the above, need to move away from
|
||||
* confusing users and using the 20+ year old term 'cifs' when it is no longer
|
||||
* secure, replaced by SMB2 (then even more highly secure SMB3) many years ago
|
||||
*/
|
||||
#define SMB3_XATTR_CIFS_ACL "system.smb3_acl"
|
||||
#define SMB3_XATTR_ATTRIB "smb3.dosattrib" /* full name: user.smb3.dosattrib */
|
||||
#define SMB3_XATTR_CREATETIME "smb3.creationtime" /* user.smb3.creationtime */
|
||||
/* BB need to add server (Samba e.g) support for security and trusted prefix */
|
||||
|
||||
enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT };
|
||||
|
@ -220,10 +228,12 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
|
|||
switch (handler->flags) {
|
||||
case XATTR_USER:
|
||||
cifs_dbg(FYI, "%s:querying user xattr %s\n", __func__, name);
|
||||
if (strcmp(name, CIFS_XATTR_ATTRIB) == 0) {
|
||||
if ((strcmp(name, CIFS_XATTR_ATTRIB) == 0) ||
|
||||
(strcmp(name, SMB3_XATTR_ATTRIB) == 0)) {
|
||||
rc = cifs_attrib_get(dentry, inode, value, size);
|
||||
break;
|
||||
} else if (strcmp(name, CIFS_XATTR_CREATETIME) == 0) {
|
||||
} else if ((strcmp(name, CIFS_XATTR_CREATETIME) == 0) ||
|
||||
(strcmp(name, SMB3_XATTR_CREATETIME) == 0)) {
|
||||
rc = cifs_creation_time_get(dentry, inode, value, size);
|
||||
break;
|
||||
}
|
||||
|
@ -363,6 +373,19 @@ static const struct xattr_handler cifs_cifs_acl_xattr_handler = {
|
|||
.set = cifs_xattr_set,
|
||||
};
|
||||
|
||||
/*
|
||||
* Although this is just an alias for the above, need to move away from
|
||||
* confusing users and using the 20 year old term 'cifs' when it is no
|
||||
* longer secure and was replaced by SMB2/SMB3 a long time ago, and
|
||||
* SMB3 and later are highly secure.
|
||||
*/
|
||||
static const struct xattr_handler smb3_acl_xattr_handler = {
|
||||
.name = SMB3_XATTR_CIFS_ACL,
|
||||
.flags = XATTR_CIFS_ACL,
|
||||
.get = cifs_xattr_get,
|
||||
.set = cifs_xattr_set,
|
||||
};
|
||||
|
||||
static const struct xattr_handler cifs_posix_acl_access_xattr_handler = {
|
||||
.name = XATTR_NAME_POSIX_ACL_ACCESS,
|
||||
.flags = XATTR_ACL_ACCESS,
|
||||
|
@ -381,6 +404,7 @@ const struct xattr_handler *cifs_xattr_handlers[] = {
|
|||
&cifs_user_xattr_handler,
|
||||
&cifs_os2_xattr_handler,
|
||||
&cifs_cifs_acl_xattr_handler,
|
||||
&smb3_acl_xattr_handler, /* alias for above since avoiding "cifs" */
|
||||
&cifs_posix_acl_access_xattr_handler,
|
||||
&cifs_posix_acl_default_xattr_handler,
|
||||
NULL
|
||||
|
|
Loading…
Reference in New Issue