forked from Minki/linux
various cifs/smb3 fixes (including for share deleted cases) and features including improved encrypted read performance, and various debugging improvements
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAl2Dq7wACgkQiiy9cAdy T1H5Kgv+NdJCBEfMjYzDPCci0plAFjurbPh5GvlrgkrYuRyCEw7KcG0/DltQSoCk TOQ0JTVYulyKPd8uwha2p8ylscKwEi3BPHa0+CMg6qRmCtrRMMhh85TF2pScy8Jz s1s9RskEvdJMpZ0disu1uge9O4JHNFB3LnfM7bDMxGTDUYMtuAXYIXTqMpLX3KVq 8NzcXUD0gAdjqo8iYZ/BtdeE7MBUCTvjp4O7pJh0cq+EV7p2G2DzaPhLJ3U5dL/y IlMgMBfyuYNH6wZueB+R2ZO1GeiPe6M4sq/Beh2/5dXKGaNECxo3feDFOHsvsasT WTllXAe8rz9AH8g8+QT4mxPQYBYw0IcJaQk5y/12gTiD2CR4BiTcNmgYv49tqiTH b4Gl6KbjTvyT0iieStUBywCpU93qD04nwuzBOPqT0FG0T6Papx4sTvvYM3ThGs16 X891RLxdvj9QOjpPnQ4vw9yAd1s7PDjVm7BA5CRhRf0Yvdc7q2YVyitzGYBzjqF0 K2f/4HRJ =4/w5 -----END PGP SIGNATURE----- Merge tag '5.4-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull cifs updates from Steve French: "Various cifs/smb3 fixes (including for share deleted cases) and features including improved encrypted read performance, and various debugging improvements. Note that since I am at a test event this week with the Samba team, and at the annual Storage Developer Conference/SMB3 Plugfest test event next week a higher than usual number of fixes is expected later next week as other features in progress get additional testing and review during these two events" * tag '5.4-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6: (38 commits) cifs: update internal module version number cifs: modefromsid: write mode ACE first cifs: cifsroot: add more err checking smb3: add missing worker function for SMB3 change notify cifs: Add support for root file systems cifs: modefromsid: make room for 4 ACE smb3: fix potential null dereference in decrypt offload smb3: fix unmount hang in open_shroot smb3: allow disabling requesting leases smb3: improve handling of share deleted (and share recreated) smb3: display max smb3 requests in flight at any one time smb3: only offload decryption of read responses if multiple requests cifs: add a helper to find an existing readable handle to a file smb3: enable offload of decryption of large reads via mount option smb3: allow parallelizing decryption of reads cifs: add a debug macro that prints \\server\share for errors smb3: fix signing verification of large reads smb3: allow skipping signature verification for perf sensitive configurations smb3: add dynamic tracepoints for flush and close smb3: log warning if CSC policy conflicts with cache mount option ...
This commit is contained in:
commit
7e3d2c8210
97
Documentation/filesystems/cifs/cifsroot.txt
Normal file
97
Documentation/filesystems/cifs/cifsroot.txt
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
Mounting root file system via SMB (cifs.ko)
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
Written 2019 by Paulo Alcantara <palcantara@suse.de>
|
||||||
|
Written 2019 by Aurelien Aptel <aaptel@suse.com>
|
||||||
|
|
||||||
|
The CONFIG_CIFS_ROOT option enables experimental root file system
|
||||||
|
support over the SMB protocol via cifs.ko.
|
||||||
|
|
||||||
|
It introduces a new kernel command-line option called 'cifsroot='
|
||||||
|
which will tell the kernel to mount the root file system over the
|
||||||
|
network by utilizing SMB or CIFS protocol.
|
||||||
|
|
||||||
|
In order to mount, the network stack will also need to be set up by
|
||||||
|
using 'ip=' config option. For more details, see
|
||||||
|
Documentation/filesystems/nfs/nfsroot.txt.
|
||||||
|
|
||||||
|
A CIFS root mount currently requires the use of SMB1+UNIX Extensions
|
||||||
|
which is only supported by the Samba server. SMB1 is the older
|
||||||
|
deprecated version of the protocol but it has been extended to support
|
||||||
|
POSIX features (See [1]). The equivalent extensions for the newer
|
||||||
|
recommended version of the protocol (SMB3) have not been fully
|
||||||
|
implemented yet which means SMB3 doesn't support some required POSIX
|
||||||
|
file system objects (e.g. block devices, pipes, sockets).
|
||||||
|
|
||||||
|
As a result, a CIFS root will default to SMB1 for now but the version
|
||||||
|
to use can nonetheless be changed via the 'vers=' mount option. This
|
||||||
|
default will change once the SMB3 POSIX extensions are fully
|
||||||
|
implemented.
|
||||||
|
|
||||||
|
Server configuration
|
||||||
|
====================
|
||||||
|
|
||||||
|
To enable SMB1+UNIX extensions you will need to set these global
|
||||||
|
settings in Samba smb.conf:
|
||||||
|
|
||||||
|
[global]
|
||||||
|
server min protocol = NT1
|
||||||
|
unix extension = yes # default
|
||||||
|
|
||||||
|
Kernel command line
|
||||||
|
===================
|
||||||
|
|
||||||
|
root=/dev/cifs
|
||||||
|
|
||||||
|
This is just a virtual device that basically tells the kernel to mount
|
||||||
|
the root file system via SMB protocol.
|
||||||
|
|
||||||
|
cifsroot=//<server-ip>/<share>[,options]
|
||||||
|
|
||||||
|
Enables the kernel to mount the root file system via SMB that are
|
||||||
|
located in the <server-ip> and <share> specified in this option.
|
||||||
|
|
||||||
|
The default mount options are set in fs/cifs/cifsroot.c.
|
||||||
|
|
||||||
|
server-ip
|
||||||
|
IPv4 address of the server.
|
||||||
|
|
||||||
|
share
|
||||||
|
Path to SMB share (rootfs).
|
||||||
|
|
||||||
|
options
|
||||||
|
Optional mount options. For more information, see mount.cifs(8).
|
||||||
|
|
||||||
|
Examples
|
||||||
|
========
|
||||||
|
|
||||||
|
Export root file system as a Samba share in smb.conf file.
|
||||||
|
|
||||||
|
...
|
||||||
|
[linux]
|
||||||
|
path = /path/to/rootfs
|
||||||
|
read only = no
|
||||||
|
guest ok = yes
|
||||||
|
force user = root
|
||||||
|
force group = root
|
||||||
|
browseable = yes
|
||||||
|
writeable = yes
|
||||||
|
admin users = root
|
||||||
|
public = yes
|
||||||
|
create mask = 0777
|
||||||
|
directory mask = 0777
|
||||||
|
...
|
||||||
|
|
||||||
|
Restart smb service.
|
||||||
|
|
||||||
|
# systemctl restart smb
|
||||||
|
|
||||||
|
Test it under QEMU on a kernel built with CONFIG_CIFS_ROOT and
|
||||||
|
CONFIG_IP_PNP options enabled.
|
||||||
|
|
||||||
|
# qemu-system-x86_64 -enable-kvm -cpu host -m 1024 \
|
||||||
|
-kernel /path/to/linux/arch/x86/boot/bzImage -nographic \
|
||||||
|
-append "root=/dev/cifs rw ip=dhcp cifsroot=//10.0.2.2/linux,username=foo,password=bar console=ttyS0 3"
|
||||||
|
|
||||||
|
|
||||||
|
1: https://wiki.samba.org/index.php/UNIX_Extensions
|
@ -211,3 +211,11 @@ config CIFS_FSCACHE
|
|||||||
Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data
|
Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data
|
||||||
to be cached locally on disk through the general filesystem cache
|
to be cached locally on disk through the general filesystem cache
|
||||||
manager. If unsure, say N.
|
manager. If unsure, say N.
|
||||||
|
|
||||||
|
config CIFS_ROOT
|
||||||
|
bool "SMB root file system (Experimental)"
|
||||||
|
depends on CIFS=y && IP_PNP
|
||||||
|
help
|
||||||
|
Enables root file system support over SMB protocol.
|
||||||
|
|
||||||
|
Most people say N here.
|
||||||
|
@ -21,3 +21,5 @@ cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o dfs_cache.o
|
|||||||
cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
|
cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
|
||||||
|
|
||||||
cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o
|
cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o
|
||||||
|
|
||||||
|
cifs-$(CONFIG_CIFS_ROOT) += cifsroot.o
|
||||||
|
@ -452,6 +452,7 @@ static ssize_t cifs_stats_proc_write(struct file *file,
|
|||||||
list_for_each(tmp1, &cifs_tcp_ses_list) {
|
list_for_each(tmp1, &cifs_tcp_ses_list) {
|
||||||
server = list_entry(tmp1, struct TCP_Server_Info,
|
server = list_entry(tmp1, struct TCP_Server_Info,
|
||||||
tcp_ses_list);
|
tcp_ses_list);
|
||||||
|
server->max_in_flight = 0;
|
||||||
#ifdef CONFIG_CIFS_STATS2
|
#ifdef CONFIG_CIFS_STATS2
|
||||||
for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) {
|
for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) {
|
||||||
atomic_set(&server->num_cmds[i], 0);
|
atomic_set(&server->num_cmds[i], 0);
|
||||||
@ -526,6 +527,7 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
|
|||||||
list_for_each(tmp1, &cifs_tcp_ses_list) {
|
list_for_each(tmp1, &cifs_tcp_ses_list) {
|
||||||
server = list_entry(tmp1, struct TCP_Server_Info,
|
server = list_entry(tmp1, struct TCP_Server_Info,
|
||||||
tcp_ses_list);
|
tcp_ses_list);
|
||||||
|
seq_printf(m, "\nMax requests in flight: %d", server->max_in_flight);
|
||||||
#ifdef CONFIG_CIFS_STATS2
|
#ifdef CONFIG_CIFS_STATS2
|
||||||
seq_puts(m, "\nTotal time spent processing by command. Time ");
|
seq_puts(m, "\nTotal time spent processing by command. Time ");
|
||||||
seq_printf(m, "units are jiffies (%d per second)\n", HZ);
|
seq_printf(m, "units are jiffies (%d per second)\n", HZ);
|
||||||
|
@ -80,6 +80,60 @@ do { \
|
|||||||
type, fmt, ##__VA_ARGS__); \
|
type, fmt, ##__VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define cifs_server_dbg_func(ratefunc, type, fmt, ...) \
|
||||||
|
do { \
|
||||||
|
const char *sn = ""; \
|
||||||
|
if (server && server->hostname) \
|
||||||
|
sn = server->hostname; \
|
||||||
|
if ((type) & FYI && cifsFYI & CIFS_INFO) { \
|
||||||
|
pr_debug_ ## ratefunc("%s: \\\\%s " fmt, \
|
||||||
|
__FILE__, sn, ##__VA_ARGS__); \
|
||||||
|
} else if ((type) & VFS) { \
|
||||||
|
pr_err_ ## ratefunc("CIFS VFS: \\\\%s " fmt, \
|
||||||
|
sn, ##__VA_ARGS__); \
|
||||||
|
} else if ((type) & NOISY && (NOISY != 0)) { \
|
||||||
|
pr_debug_ ## ratefunc("\\\\%s " fmt, \
|
||||||
|
sn, ##__VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define cifs_server_dbg(type, fmt, ...) \
|
||||||
|
do { \
|
||||||
|
if ((type) & ONCE) \
|
||||||
|
cifs_server_dbg_func(once, \
|
||||||
|
type, fmt, ##__VA_ARGS__); \
|
||||||
|
else \
|
||||||
|
cifs_server_dbg_func(ratelimited, \
|
||||||
|
type, fmt, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define cifs_tcon_dbg_func(ratefunc, type, fmt, ...) \
|
||||||
|
do { \
|
||||||
|
const char *tn = ""; \
|
||||||
|
if (tcon && tcon->treeName) \
|
||||||
|
tn = tcon->treeName; \
|
||||||
|
if ((type) & FYI && cifsFYI & CIFS_INFO) { \
|
||||||
|
pr_debug_ ## ratefunc("%s: %s " fmt, \
|
||||||
|
__FILE__, tn, ##__VA_ARGS__); \
|
||||||
|
} else if ((type) & VFS) { \
|
||||||
|
pr_err_ ## ratefunc("CIFS VFS: %s " fmt, \
|
||||||
|
tn, ##__VA_ARGS__); \
|
||||||
|
} else if ((type) & NOISY && (NOISY != 0)) { \
|
||||||
|
pr_debug_ ## ratefunc("%s " fmt, \
|
||||||
|
tn, ##__VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define cifs_tcon_dbg(type, fmt, ...) \
|
||||||
|
do { \
|
||||||
|
if ((type) & ONCE) \
|
||||||
|
cifs_tcon_dbg_func(once, \
|
||||||
|
type, fmt, ##__VA_ARGS__); \
|
||||||
|
else \
|
||||||
|
cifs_tcon_dbg_func(ratelimited, \
|
||||||
|
type, fmt, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* debug OFF
|
* debug OFF
|
||||||
* ---------
|
* ---------
|
||||||
@ -91,6 +145,19 @@ do { \
|
|||||||
pr_debug(fmt, ##__VA_ARGS__); \
|
pr_debug(fmt, ##__VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define cifs_server_dbg(type, fmt, ...) \
|
||||||
|
do { \
|
||||||
|
if (0) \
|
||||||
|
pr_debug("\\\\%s " fmt, \
|
||||||
|
server->hostname, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define cifs_tcon_dbg(type, fmt, ...) \
|
||||||
|
do { \
|
||||||
|
if (0) \
|
||||||
|
pr_debug("%s " fmt, tcon->treeName, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define cifs_info(fmt, ...) \
|
#define cifs_info(fmt, ...) \
|
||||||
do { \
|
do { \
|
||||||
pr_info("CIFS: "fmt, ##__VA_ARGS__); \
|
pr_info("CIFS: "fmt, ##__VA_ARGS__); \
|
||||||
|
@ -53,6 +53,8 @@
|
|||||||
#define CIFS_MOUNT_NO_HANDLE_CACHE 0x4000000 /* disable caching dir handles */
|
#define CIFS_MOUNT_NO_HANDLE_CACHE 0x4000000 /* disable caching dir handles */
|
||||||
#define CIFS_MOUNT_NO_DFS 0x8000000 /* disable DFS resolving */
|
#define CIFS_MOUNT_NO_DFS 0x8000000 /* disable DFS resolving */
|
||||||
#define CIFS_MOUNT_MODE_FROM_SID 0x10000000 /* retrieve mode from special ACE */
|
#define CIFS_MOUNT_MODE_FROM_SID 0x10000000 /* retrieve mode from special ACE */
|
||||||
|
#define CIFS_MOUNT_RO_CACHE 0x20000000 /* assumes share will not change */
|
||||||
|
#define CIFS_MOUNT_RW_CACHE 0x40000000 /* assumes only client accessing */
|
||||||
|
|
||||||
struct cifs_sb_info {
|
struct cifs_sb_info {
|
||||||
struct rb_root tlink_tree;
|
struct rb_root tlink_tree;
|
||||||
|
@ -46,6 +46,7 @@ struct smb_snapshot_array {
|
|||||||
/* query_info flags */
|
/* query_info flags */
|
||||||
#define PASSTHRU_QUERY_INFO 0x00000000
|
#define PASSTHRU_QUERY_INFO 0x00000000
|
||||||
#define PASSTHRU_FSCTL 0x00000001
|
#define PASSTHRU_FSCTL 0x00000001
|
||||||
|
#define PASSTHRU_SET_INFO 0x00000002
|
||||||
struct smb_query_info {
|
struct smb_query_info {
|
||||||
__u32 info_type;
|
__u32 info_type;
|
||||||
__u32 file_info_class;
|
__u32 file_info_class;
|
||||||
|
@ -701,10 +701,9 @@ static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
||||||
struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
|
struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
|
||||||
struct cifs_fattr *fattr)
|
struct cifs_fattr *fattr, bool mode_from_special_sid)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int num_aces = 0;
|
int num_aces = 0;
|
||||||
@ -757,22 +756,34 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
|||||||
#ifdef CONFIG_CIFS_DEBUG2
|
#ifdef CONFIG_CIFS_DEBUG2
|
||||||
dump_ace(ppace[i], end_of_acl);
|
dump_ace(ppace[i], end_of_acl);
|
||||||
#endif
|
#endif
|
||||||
if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
|
if (mode_from_special_sid &&
|
||||||
|
(compare_sids(&(ppace[i]->sid),
|
||||||
|
&sid_unix_NFS_mode) == 0)) {
|
||||||
|
/*
|
||||||
|
* Full permissions are:
|
||||||
|
* 07777 = S_ISUID | S_ISGID | S_ISVTX |
|
||||||
|
* S_IRWXU | S_IRWXG | S_IRWXO
|
||||||
|
*/
|
||||||
|
fattr->cf_mode &= ~07777;
|
||||||
|
fattr->cf_mode |=
|
||||||
|
le32_to_cpu(ppace[i]->sid.sub_auth[2]);
|
||||||
|
break;
|
||||||
|
} else if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
|
||||||
access_flags_to_mode(ppace[i]->access_req,
|
access_flags_to_mode(ppace[i]->access_req,
|
||||||
ppace[i]->type,
|
ppace[i]->type,
|
||||||
&fattr->cf_mode,
|
&fattr->cf_mode,
|
||||||
&user_mask);
|
&user_mask);
|
||||||
if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
|
else if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
|
||||||
access_flags_to_mode(ppace[i]->access_req,
|
access_flags_to_mode(ppace[i]->access_req,
|
||||||
ppace[i]->type,
|
ppace[i]->type,
|
||||||
&fattr->cf_mode,
|
&fattr->cf_mode,
|
||||||
&group_mask);
|
&group_mask);
|
||||||
if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
|
else if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
|
||||||
access_flags_to_mode(ppace[i]->access_req,
|
access_flags_to_mode(ppace[i]->access_req,
|
||||||
ppace[i]->type,
|
ppace[i]->type,
|
||||||
&fattr->cf_mode,
|
&fattr->cf_mode,
|
||||||
&other_mask);
|
&other_mask);
|
||||||
if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
|
else if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
|
||||||
access_flags_to_mode(ppace[i]->access_req,
|
access_flags_to_mode(ppace[i]->access_req,
|
||||||
ppace[i]->type,
|
ppace[i]->type,
|
||||||
&fattr->cf_mode,
|
&fattr->cf_mode,
|
||||||
@ -795,22 +806,49 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
|||||||
|
|
||||||
|
|
||||||
static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
|
static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
|
||||||
struct cifs_sid *pgrpsid, __u64 nmode)
|
struct cifs_sid *pgrpsid, __u64 nmode, bool modefromsid)
|
||||||
{
|
{
|
||||||
u16 size = 0;
|
u16 size = 0;
|
||||||
|
u32 num_aces = 0;
|
||||||
struct cifs_acl *pnndacl;
|
struct cifs_acl *pnndacl;
|
||||||
|
|
||||||
pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
|
pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
|
||||||
|
|
||||||
|
if (modefromsid) {
|
||||||
|
struct cifs_ace *pntace =
|
||||||
|
(struct cifs_ace *)((char *)pnndacl + size);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
pntace->type = ACCESS_ALLOWED;
|
||||||
|
pntace->flags = 0x0;
|
||||||
|
pntace->access_req = 0;
|
||||||
|
pntace->sid.num_subauth = 3;
|
||||||
|
pntace->sid.revision = 1;
|
||||||
|
for (i = 0; i < NUM_AUTHS; i++)
|
||||||
|
pntace->sid.authority[i] =
|
||||||
|
sid_unix_NFS_mode.authority[i];
|
||||||
|
pntace->sid.sub_auth[0] = sid_unix_NFS_mode.sub_auth[0];
|
||||||
|
pntace->sid.sub_auth[1] = sid_unix_NFS_mode.sub_auth[1];
|
||||||
|
pntace->sid.sub_auth[2] = cpu_to_le32(nmode & 07777);
|
||||||
|
|
||||||
|
/* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
|
||||||
|
pntace->size = cpu_to_le16(28);
|
||||||
|
size += 28;
|
||||||
|
num_aces++;
|
||||||
|
}
|
||||||
|
|
||||||
size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
|
size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
|
||||||
pownersid, nmode, S_IRWXU);
|
pownersid, nmode, S_IRWXU);
|
||||||
|
num_aces++;
|
||||||
size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
|
size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
|
||||||
pgrpsid, nmode, S_IRWXG);
|
pgrpsid, nmode, S_IRWXG);
|
||||||
|
num_aces++;
|
||||||
size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
|
size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
|
||||||
&sid_everyone, nmode, S_IRWXO);
|
&sid_everyone, nmode, S_IRWXO);
|
||||||
|
num_aces++;
|
||||||
|
|
||||||
|
pndacl->num_aces = cpu_to_le32(num_aces);
|
||||||
pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
|
pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
|
||||||
pndacl->num_aces = cpu_to_le32(3);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -851,7 +889,8 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
|
|||||||
|
|
||||||
/* Convert CIFS ACL to POSIX form */
|
/* Convert CIFS ACL to POSIX form */
|
||||||
static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
|
static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
|
||||||
struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
|
struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr,
|
||||||
|
bool get_mode_from_special_sid)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
|
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
|
||||||
@ -900,7 +939,7 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
|
|||||||
|
|
||||||
if (dacloffset)
|
if (dacloffset)
|
||||||
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
|
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
|
||||||
group_sid_ptr, fattr);
|
group_sid_ptr, fattr, get_mode_from_special_sid);
|
||||||
else
|
else
|
||||||
cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
|
cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
|
||||||
|
|
||||||
@ -909,7 +948,8 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
|
|||||||
|
|
||||||
/* Convert permission bits from mode to equivalent CIFS ACL */
|
/* Convert permission bits from mode to equivalent CIFS ACL */
|
||||||
static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
|
static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
|
||||||
__u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, int *aclflag)
|
__u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid,
|
||||||
|
bool mode_from_sid, int *aclflag)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
__u32 dacloffset;
|
__u32 dacloffset;
|
||||||
@ -934,7 +974,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
|
|||||||
ndacl_ptr->num_aces = 0;
|
ndacl_ptr->num_aces = 0;
|
||||||
|
|
||||||
rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
|
rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
|
||||||
nmode);
|
nmode, mode_from_sid);
|
||||||
sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
|
sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
|
||||||
/* copy sec desc control portion & owner and group sids */
|
/* copy sec desc control portion & owner and group sids */
|
||||||
copy_sec_desc(pntsd, pnntsd, sidsoffset);
|
copy_sec_desc(pntsd, pnntsd, sidsoffset);
|
||||||
@ -1128,8 +1168,8 @@ out:
|
|||||||
/* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */
|
/* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */
|
||||||
int
|
int
|
||||||
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
||||||
struct inode *inode, const char *path,
|
struct inode *inode, bool mode_from_special_sid,
|
||||||
const struct cifs_fid *pfid)
|
const char *path, const struct cifs_fid *pfid)
|
||||||
{
|
{
|
||||||
struct cifs_ntsd *pntsd = NULL;
|
struct cifs_ntsd *pntsd = NULL;
|
||||||
u32 acllen = 0;
|
u32 acllen = 0;
|
||||||
@ -1156,8 +1196,11 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
|||||||
if (IS_ERR(pntsd)) {
|
if (IS_ERR(pntsd)) {
|
||||||
rc = PTR_ERR(pntsd);
|
rc = PTR_ERR(pntsd);
|
||||||
cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
|
cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
|
||||||
|
} else if (mode_from_special_sid) {
|
||||||
|
rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, true);
|
||||||
} else {
|
} else {
|
||||||
rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
|
/* get approximated mode from ACL */
|
||||||
|
rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, false);
|
||||||
kfree(pntsd);
|
kfree(pntsd);
|
||||||
if (rc)
|
if (rc)
|
||||||
cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
|
cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
|
||||||
@ -1181,6 +1224,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
|
|||||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||||
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
||||||
struct smb_version_operations *ops;
|
struct smb_version_operations *ops;
|
||||||
|
bool mode_from_sid;
|
||||||
|
|
||||||
if (IS_ERR(tlink))
|
if (IS_ERR(tlink))
|
||||||
return PTR_ERR(tlink);
|
return PTR_ERR(tlink);
|
||||||
@ -1218,8 +1262,13 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)
|
||||||
|
mode_from_sid = true;
|
||||||
|
else
|
||||||
|
mode_from_sid = false;
|
||||||
|
|
||||||
rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
|
rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
|
||||||
&aclflag);
|
mode_from_sid, &aclflag);
|
||||||
|
|
||||||
cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
|
cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
*/
|
*/
|
||||||
#define DEFAULT_SEC_DESC_LEN (sizeof(struct cifs_ntsd) + \
|
#define DEFAULT_SEC_DESC_LEN (sizeof(struct cifs_ntsd) + \
|
||||||
sizeof(struct cifs_acl) + \
|
sizeof(struct cifs_acl) + \
|
||||||
(sizeof(struct cifs_ace) * 3))
|
(sizeof(struct cifs_ace) * 4))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Maximum size of a string representation of a SID:
|
* Maximum size of a string representation of a SID:
|
||||||
|
@ -118,6 +118,7 @@ extern mempool_t *cifs_req_poolp;
|
|||||||
extern mempool_t *cifs_mid_poolp;
|
extern mempool_t *cifs_mid_poolp;
|
||||||
|
|
||||||
struct workqueue_struct *cifsiod_wq;
|
struct workqueue_struct *cifsiod_wq;
|
||||||
|
struct workqueue_struct *decrypt_wq;
|
||||||
struct workqueue_struct *cifsoplockd_wq;
|
struct workqueue_struct *cifsoplockd_wq;
|
||||||
__u32 cifs_lock_secret;
|
__u32 cifs_lock_secret;
|
||||||
|
|
||||||
@ -422,6 +423,10 @@ cifs_show_cache_flavor(struct seq_file *s, struct cifs_sb_info *cifs_sb)
|
|||||||
seq_puts(s, "strict");
|
seq_puts(s, "strict");
|
||||||
else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
|
else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
|
||||||
seq_puts(s, "none");
|
seq_puts(s, "none");
|
||||||
|
else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE)
|
||||||
|
seq_puts(s, "singleclient"); /* assume only one client access */
|
||||||
|
else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE)
|
||||||
|
seq_puts(s, "ro"); /* read only caching assumed */
|
||||||
else
|
else
|
||||||
seq_puts(s, "loose");
|
seq_puts(s, "loose");
|
||||||
}
|
}
|
||||||
@ -455,6 +460,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
|
|||||||
cifs_show_security(s, tcon->ses);
|
cifs_show_security(s, tcon->ses);
|
||||||
cifs_show_cache_flavor(s, cifs_sb);
|
cifs_show_cache_flavor(s, cifs_sb);
|
||||||
|
|
||||||
|
if (tcon->no_lease)
|
||||||
|
seq_puts(s, ",nolease");
|
||||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)
|
||||||
seq_puts(s, ",multiuser");
|
seq_puts(s, ",multiuser");
|
||||||
else if (tcon->ses->user_name)
|
else if (tcon->ses->user_name)
|
||||||
@ -576,6 +583,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
|
|||||||
seq_printf(s, ",rsize=%u", cifs_sb->rsize);
|
seq_printf(s, ",rsize=%u", cifs_sb->rsize);
|
||||||
seq_printf(s, ",wsize=%u", cifs_sb->wsize);
|
seq_printf(s, ",wsize=%u", cifs_sb->wsize);
|
||||||
seq_printf(s, ",bsize=%u", cifs_sb->bsize);
|
seq_printf(s, ",bsize=%u", cifs_sb->bsize);
|
||||||
|
if (tcon->ses->server->min_offload)
|
||||||
|
seq_printf(s, ",esize=%u", tcon->ses->server->min_offload);
|
||||||
seq_printf(s, ",echo_interval=%lu",
|
seq_printf(s, ",echo_interval=%lu",
|
||||||
tcon->ses->server->echo_interval / HZ);
|
tcon->ses->server->echo_interval / HZ);
|
||||||
|
|
||||||
@ -1517,11 +1526,25 @@ init_cifs(void)
|
|||||||
goto out_clean_proc;
|
goto out_clean_proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Consider in future setting limit!=0 maybe to min(num_of_cores - 1, 3)
|
||||||
|
* so that we don't launch too many worker threads but
|
||||||
|
* Documentation/workqueue.txt recommends setting it to 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* WQ_UNBOUND allows decrypt tasks to run on any CPU */
|
||||||
|
decrypt_wq = alloc_workqueue("smb3decryptd",
|
||||||
|
WQ_UNBOUND|WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
|
||||||
|
if (!decrypt_wq) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto out_destroy_cifsiod_wq;
|
||||||
|
}
|
||||||
|
|
||||||
cifsoplockd_wq = alloc_workqueue("cifsoplockd",
|
cifsoplockd_wq = alloc_workqueue("cifsoplockd",
|
||||||
WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
|
WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
|
||||||
if (!cifsoplockd_wq) {
|
if (!cifsoplockd_wq) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto out_destroy_cifsiod_wq;
|
goto out_destroy_decrypt_wq;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = cifs_fscache_register();
|
rc = cifs_fscache_register();
|
||||||
@ -1587,6 +1610,8 @@ out_unreg_fscache:
|
|||||||
cifs_fscache_unregister();
|
cifs_fscache_unregister();
|
||||||
out_destroy_cifsoplockd_wq:
|
out_destroy_cifsoplockd_wq:
|
||||||
destroy_workqueue(cifsoplockd_wq);
|
destroy_workqueue(cifsoplockd_wq);
|
||||||
|
out_destroy_decrypt_wq:
|
||||||
|
destroy_workqueue(decrypt_wq);
|
||||||
out_destroy_cifsiod_wq:
|
out_destroy_cifsiod_wq:
|
||||||
destroy_workqueue(cifsiod_wq);
|
destroy_workqueue(cifsiod_wq);
|
||||||
out_clean_proc:
|
out_clean_proc:
|
||||||
@ -1613,6 +1638,7 @@ exit_cifs(void)
|
|||||||
cifs_destroy_inodecache();
|
cifs_destroy_inodecache();
|
||||||
cifs_fscache_unregister();
|
cifs_fscache_unregister();
|
||||||
destroy_workqueue(cifsoplockd_wq);
|
destroy_workqueue(cifsoplockd_wq);
|
||||||
|
destroy_workqueue(decrypt_wq);
|
||||||
destroy_workqueue(cifsiod_wq);
|
destroy_workqueue(cifsiod_wq);
|
||||||
cifs_proc_clean();
|
cifs_proc_clean();
|
||||||
}
|
}
|
||||||
|
@ -152,5 +152,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
|||||||
extern const struct export_operations cifs_export_ops;
|
extern const struct export_operations cifs_export_ops;
|
||||||
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
||||||
|
|
||||||
#define CIFS_VERSION "2.22"
|
#define CIFS_VERSION "2.23"
|
||||||
#endif /* _CIFSFS_H */
|
#endif /* _CIFSFS_H */
|
||||||
|
@ -542,6 +542,7 @@ struct smb_vol {
|
|||||||
umode_t dir_mode;
|
umode_t dir_mode;
|
||||||
enum securityEnum sectype; /* sectype requested via mnt opts */
|
enum securityEnum sectype; /* sectype requested via mnt opts */
|
||||||
bool sign; /* was signing requested via mnt opts? */
|
bool sign; /* was signing requested via mnt opts? */
|
||||||
|
bool ignore_signature:1;
|
||||||
bool retry:1;
|
bool retry:1;
|
||||||
bool intr:1;
|
bool intr:1;
|
||||||
bool setuids:1;
|
bool setuids:1;
|
||||||
@ -559,6 +560,8 @@ struct smb_vol {
|
|||||||
bool server_ino:1; /* use inode numbers from server ie UniqueId */
|
bool server_ino:1; /* use inode numbers from server ie UniqueId */
|
||||||
bool direct_io:1;
|
bool direct_io:1;
|
||||||
bool strict_io:1; /* strict cache behavior */
|
bool strict_io:1; /* strict cache behavior */
|
||||||
|
bool cache_ro:1;
|
||||||
|
bool cache_rw:1;
|
||||||
bool remap:1; /* set to remap seven reserved chars in filenames */
|
bool remap:1; /* set to remap seven reserved chars in filenames */
|
||||||
bool sfu_remap:1; /* remap seven reserved chars ala SFU */
|
bool sfu_remap:1; /* remap seven reserved chars ala SFU */
|
||||||
bool posix_paths:1; /* unset to not ask for posix pathnames. */
|
bool posix_paths:1; /* unset to not ask for posix pathnames. */
|
||||||
@ -576,6 +579,7 @@ struct smb_vol {
|
|||||||
bool noblocksnd:1;
|
bool noblocksnd:1;
|
||||||
bool noautotune:1;
|
bool noautotune:1;
|
||||||
bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
|
bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
|
||||||
|
bool no_lease:1; /* disable requesting leases */
|
||||||
bool fsc:1; /* enable fscache */
|
bool fsc:1; /* enable fscache */
|
||||||
bool mfsymlinks:1; /* use Minshall+French Symlinks */
|
bool mfsymlinks:1; /* use Minshall+French Symlinks */
|
||||||
bool multiuser:1;
|
bool multiuser:1;
|
||||||
@ -589,6 +593,7 @@ struct smb_vol {
|
|||||||
unsigned int bsize;
|
unsigned int bsize;
|
||||||
unsigned int rsize;
|
unsigned int rsize;
|
||||||
unsigned int wsize;
|
unsigned int wsize;
|
||||||
|
unsigned int min_offload;
|
||||||
bool sockopt_tcp_nodelay:1;
|
bool sockopt_tcp_nodelay:1;
|
||||||
unsigned long actimeo; /* attribute cache timeout (jiffies) */
|
unsigned long actimeo; /* attribute cache timeout (jiffies) */
|
||||||
struct smb_version_operations *ops;
|
struct smb_version_operations *ops;
|
||||||
@ -602,6 +607,7 @@ struct smb_vol {
|
|||||||
__u32 handle_timeout; /* persistent and durable handle timeout in ms */
|
__u32 handle_timeout; /* persistent and durable handle timeout in ms */
|
||||||
unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
|
unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
|
||||||
__u16 compression; /* compression algorithm 0xFFFF default 0=disabled */
|
__u16 compression; /* compression algorithm 0xFFFF default 0=disabled */
|
||||||
|
bool rootfs:1; /* if it's a SMB root file system */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -620,7 +626,8 @@ struct smb_vol {
|
|||||||
CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO | \
|
CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO | \
|
||||||
CIFS_MOUNT_CIFS_BACKUPUID | CIFS_MOUNT_CIFS_BACKUPGID | \
|
CIFS_MOUNT_CIFS_BACKUPUID | CIFS_MOUNT_CIFS_BACKUPGID | \
|
||||||
CIFS_MOUNT_UID_FROM_ACL | CIFS_MOUNT_NO_HANDLE_CACHE | \
|
CIFS_MOUNT_UID_FROM_ACL | CIFS_MOUNT_NO_HANDLE_CACHE | \
|
||||||
CIFS_MOUNT_NO_DFS | CIFS_MOUNT_MODE_FROM_SID)
|
CIFS_MOUNT_NO_DFS | CIFS_MOUNT_MODE_FROM_SID | \
|
||||||
|
CIFS_MOUNT_RO_CACHE | CIFS_MOUNT_RW_CACHE)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic VFS superblock mount flags (s_flags) to consider when
|
* Generic VFS superblock mount flags (s_flags) to consider when
|
||||||
@ -672,12 +679,14 @@ struct TCP_Server_Info {
|
|||||||
unsigned int credits; /* send no more requests at once */
|
unsigned int credits; /* send no more requests at once */
|
||||||
unsigned int max_credits; /* can override large 32000 default at mnt */
|
unsigned int max_credits; /* can override large 32000 default at mnt */
|
||||||
unsigned int in_flight; /* number of requests on the wire to server */
|
unsigned int in_flight; /* number of requests on the wire to server */
|
||||||
|
unsigned int max_in_flight; /* max number of requests that were on wire */
|
||||||
spinlock_t req_lock; /* protect the two values above */
|
spinlock_t req_lock; /* protect the two values above */
|
||||||
struct mutex srv_mutex;
|
struct mutex srv_mutex;
|
||||||
struct task_struct *tsk;
|
struct task_struct *tsk;
|
||||||
char server_GUID[16];
|
char server_GUID[16];
|
||||||
__u16 sec_mode;
|
__u16 sec_mode;
|
||||||
bool sign; /* is signing enabled on this connection? */
|
bool sign; /* is signing enabled on this connection? */
|
||||||
|
bool ignore_signature:1; /* skip validation of signatures in SMB2/3 rsp */
|
||||||
bool session_estab; /* mark when very first sess is established */
|
bool session_estab; /* mark when very first sess is established */
|
||||||
int echo_credits; /* echo reserved slots */
|
int echo_credits; /* echo reserved slots */
|
||||||
int oplock_credits; /* oplock break reserved slots */
|
int oplock_credits; /* oplock break reserved slots */
|
||||||
@ -740,6 +749,7 @@ struct TCP_Server_Info {
|
|||||||
#endif /* STATS2 */
|
#endif /* STATS2 */
|
||||||
unsigned int max_read;
|
unsigned int max_read;
|
||||||
unsigned int max_write;
|
unsigned int max_write;
|
||||||
|
unsigned int min_offload;
|
||||||
__le16 compress_algorithm;
|
__le16 compress_algorithm;
|
||||||
__le16 cipher_type;
|
__le16 cipher_type;
|
||||||
/* save initital negprot hash */
|
/* save initital negprot hash */
|
||||||
@ -755,6 +765,7 @@ struct TCP_Server_Info {
|
|||||||
* reconnect.
|
* reconnect.
|
||||||
*/
|
*/
|
||||||
int nr_targets;
|
int nr_targets;
|
||||||
|
bool noblockcnt; /* use non-blocking connect() */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cifs_credits {
|
struct cifs_credits {
|
||||||
@ -1082,6 +1093,7 @@ struct cifs_tcon {
|
|||||||
bool need_reopen_files:1; /* need to reopen tcon file handles */
|
bool need_reopen_files:1; /* need to reopen tcon file handles */
|
||||||
bool use_resilient:1; /* use resilient instead of durable handles */
|
bool use_resilient:1; /* use resilient instead of durable handles */
|
||||||
bool use_persistent:1; /* use persistent instead of durable handles */
|
bool use_persistent:1; /* use persistent instead of durable handles */
|
||||||
|
bool no_lease:1; /* Do not request leases on files or directories */
|
||||||
__le32 capabilities;
|
__le32 capabilities;
|
||||||
__u32 share_flags;
|
__u32 share_flags;
|
||||||
__u32 maximal_access;
|
__u32 maximal_access;
|
||||||
@ -1366,9 +1378,9 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
|
|||||||
#define CIFS_CACHE_RW_FLG (CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG)
|
#define CIFS_CACHE_RW_FLG (CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG)
|
||||||
#define CIFS_CACHE_RHW_FLG (CIFS_CACHE_RW_FLG | CIFS_CACHE_HANDLE_FLG)
|
#define CIFS_CACHE_RHW_FLG (CIFS_CACHE_RW_FLG | CIFS_CACHE_HANDLE_FLG)
|
||||||
|
|
||||||
#define CIFS_CACHE_READ(cinode) (cinode->oplock & CIFS_CACHE_READ_FLG)
|
#define CIFS_CACHE_READ(cinode) ((cinode->oplock & CIFS_CACHE_READ_FLG) || (CIFS_SB(cinode->vfs_inode.i_sb)->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE))
|
||||||
#define CIFS_CACHE_HANDLE(cinode) (cinode->oplock & CIFS_CACHE_HANDLE_FLG)
|
#define CIFS_CACHE_HANDLE(cinode) (cinode->oplock & CIFS_CACHE_HANDLE_FLG)
|
||||||
#define CIFS_CACHE_WRITE(cinode) (cinode->oplock & CIFS_CACHE_WRITE_FLG)
|
#define CIFS_CACHE_WRITE(cinode) ((cinode->oplock & CIFS_CACHE_WRITE_FLG) || (CIFS_SB(cinode->vfs_inode.i_sb)->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* One of these for each file inode
|
* One of these for each file inode
|
||||||
@ -1887,6 +1899,7 @@ void cifs_queue_oplock_break(struct cifsFileInfo *cfile);
|
|||||||
|
|
||||||
extern const struct slow_work_ops cifs_oplock_break_ops;
|
extern const struct slow_work_ops cifs_oplock_break_ops;
|
||||||
extern struct workqueue_struct *cifsiod_wq;
|
extern struct workqueue_struct *cifsiod_wq;
|
||||||
|
extern struct workqueue_struct *decrypt_wq;
|
||||||
extern struct workqueue_struct *cifsoplockd_wq;
|
extern struct workqueue_struct *cifsoplockd_wq;
|
||||||
extern __u32 cifs_lock_secret;
|
extern __u32 cifs_lock_secret;
|
||||||
|
|
||||||
|
@ -137,7 +137,11 @@ extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
|
|||||||
extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
|
extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
|
||||||
bool fsuid_only,
|
bool fsuid_only,
|
||||||
struct cifsFileInfo **ret_file);
|
struct cifsFileInfo **ret_file);
|
||||||
|
extern int cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
|
||||||
|
struct cifsFileInfo **ret_file);
|
||||||
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
|
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
|
||||||
|
extern int cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
|
||||||
|
struct cifsFileInfo **ret_file);
|
||||||
extern unsigned int smbCalcSize(void *buf, struct TCP_Server_Info *server);
|
extern unsigned int smbCalcSize(void *buf, struct TCP_Server_Info *server);
|
||||||
extern int decode_negTokenInit(unsigned char *security_blob, int length,
|
extern int decode_negTokenInit(unsigned char *security_blob, int length,
|
||||||
struct TCP_Server_Info *server);
|
struct TCP_Server_Info *server);
|
||||||
@ -197,6 +201,7 @@ extern int cifs_rename_pending_delete(const char *full_path,
|
|||||||
const unsigned int xid);
|
const unsigned int xid);
|
||||||
extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
|
extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
|
||||||
struct cifs_fattr *fattr, struct inode *inode,
|
struct cifs_fattr *fattr, struct inode *inode,
|
||||||
|
bool get_mode_from_special_sid,
|
||||||
const char *path, const struct cifs_fid *pfid);
|
const char *path, const struct cifs_fid *pfid);
|
||||||
extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64,
|
extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64,
|
||||||
kuid_t, kgid_t);
|
kuid_t, kgid_t);
|
||||||
|
94
fs/cifs/cifsroot.c
Normal file
94
fs/cifs/cifsroot.c
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* SMB root file system support
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Paulo Alcantara <palcantara@suse.de>
|
||||||
|
*/
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/ctype.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/root_dev.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/in.h>
|
||||||
|
#include <linux/inet.h>
|
||||||
|
#include <net/ipconfig.h>
|
||||||
|
|
||||||
|
#define DEFAULT_MNT_OPTS \
|
||||||
|
"vers=1.0,cifsacl,mfsymlinks,rsize=1048576,wsize=65536,uid=0,gid=0," \
|
||||||
|
"hard,rootfs"
|
||||||
|
|
||||||
|
static char root_dev[2048] __initdata = "";
|
||||||
|
static char root_opts[1024] __initdata = DEFAULT_MNT_OPTS;
|
||||||
|
|
||||||
|
static __be32 __init parse_srvaddr(char *start, char *end)
|
||||||
|
{
|
||||||
|
/* TODO: ipv6 support */
|
||||||
|
char addr[sizeof("aaa.bbb.ccc.ddd")];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (start < end && i < sizeof(addr) - 1) {
|
||||||
|
if (isdigit(*start) || *start == '.')
|
||||||
|
addr[i++] = *start;
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
addr[i] = '\0';
|
||||||
|
return in_aton(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cifsroot=//<server-ip>/<share>[,options] */
|
||||||
|
static int __init cifs_root_setup(char *line)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
int len;
|
||||||
|
__be32 srvaddr = htonl(INADDR_NONE);
|
||||||
|
|
||||||
|
ROOT_DEV = Root_CIFS;
|
||||||
|
|
||||||
|
if (strlen(line) > 3 && line[0] == '/' && line[1] == '/') {
|
||||||
|
s = strchr(&line[2], '/');
|
||||||
|
if (!s || s[1] == '\0')
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* make s point to ',' or '\0' at end of line */
|
||||||
|
s = strchrnul(s, ',');
|
||||||
|
/* len is strlen(unc) + '\0' */
|
||||||
|
len = s - line + 1;
|
||||||
|
if (len > sizeof(root_dev)) {
|
||||||
|
printk(KERN_ERR "Root-CIFS: UNC path too long\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
strlcpy(root_dev, line, len);
|
||||||
|
srvaddr = parse_srvaddr(&line[2], s);
|
||||||
|
if (*s) {
|
||||||
|
int n = snprintf(root_opts,
|
||||||
|
sizeof(root_opts), "%s,%s",
|
||||||
|
DEFAULT_MNT_OPTS, s + 1);
|
||||||
|
if (n >= sizeof(root_opts)) {
|
||||||
|
printk(KERN_ERR "Root-CIFS: mount options string too long\n");
|
||||||
|
root_opts[sizeof(root_opts)-1] = '\0';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root_server_addr = srvaddr;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
__setup("cifsroot=", cifs_root_setup);
|
||||||
|
|
||||||
|
int __init cifs_root_data(char **dev, char **opts)
|
||||||
|
{
|
||||||
|
if (!root_dev[0] || root_server_addr == htonl(INADDR_NONE)) {
|
||||||
|
printk(KERN_ERR "Root-CIFS: no SMB server address\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dev = root_dev;
|
||||||
|
*opts = root_opts;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1393,7 +1393,7 @@ int
|
|||||||
CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
|
CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
|
||||||
FILE_ALL_INFO *buf)
|
FILE_ALL_INFO *buf)
|
||||||
{
|
{
|
||||||
int rc = -EACCES;
|
int rc;
|
||||||
OPEN_REQ *req = NULL;
|
OPEN_REQ *req = NULL;
|
||||||
OPEN_RSP *rsp = NULL;
|
OPEN_RSP *rsp = NULL;
|
||||||
int bytes_returned;
|
int bytes_returned;
|
||||||
|
@ -74,7 +74,7 @@ enum {
|
|||||||
Opt_user_xattr, Opt_nouser_xattr,
|
Opt_user_xattr, Opt_nouser_xattr,
|
||||||
Opt_forceuid, Opt_noforceuid,
|
Opt_forceuid, Opt_noforceuid,
|
||||||
Opt_forcegid, Opt_noforcegid,
|
Opt_forcegid, Opt_noforcegid,
|
||||||
Opt_noblocksend, Opt_noautotune,
|
Opt_noblocksend, Opt_noautotune, Opt_nolease,
|
||||||
Opt_hard, Opt_soft, Opt_perm, Opt_noperm,
|
Opt_hard, Opt_soft, Opt_perm, Opt_noperm,
|
||||||
Opt_mapposix, Opt_nomapposix,
|
Opt_mapposix, Opt_nomapposix,
|
||||||
Opt_mapchars, Opt_nomapchars, Opt_sfu,
|
Opt_mapchars, Opt_nomapchars, Opt_sfu,
|
||||||
@ -91,18 +91,19 @@ enum {
|
|||||||
Opt_serverino, Opt_noserverino,
|
Opt_serverino, Opt_noserverino,
|
||||||
Opt_rwpidforward, Opt_cifsacl, Opt_nocifsacl,
|
Opt_rwpidforward, Opt_cifsacl, Opt_nocifsacl,
|
||||||
Opt_acl, Opt_noacl, Opt_locallease,
|
Opt_acl, Opt_noacl, Opt_locallease,
|
||||||
Opt_sign, Opt_seal, Opt_noac,
|
Opt_sign, Opt_ignore_signature, Opt_seal, Opt_noac,
|
||||||
Opt_fsc, Opt_mfsymlinks,
|
Opt_fsc, Opt_mfsymlinks,
|
||||||
Opt_multiuser, Opt_sloppy, Opt_nosharesock,
|
Opt_multiuser, Opt_sloppy, Opt_nosharesock,
|
||||||
Opt_persistent, Opt_nopersistent,
|
Opt_persistent, Opt_nopersistent,
|
||||||
Opt_resilient, Opt_noresilient,
|
Opt_resilient, Opt_noresilient,
|
||||||
Opt_domainauto, Opt_rdma, Opt_modesid,
|
Opt_domainauto, Opt_rdma, Opt_modesid, Opt_rootfs,
|
||||||
Opt_compress,
|
Opt_compress,
|
||||||
|
|
||||||
/* Mount options which take numeric value */
|
/* Mount options which take numeric value */
|
||||||
Opt_backupuid, Opt_backupgid, Opt_uid,
|
Opt_backupuid, Opt_backupgid, Opt_uid,
|
||||||
Opt_cruid, Opt_gid, Opt_file_mode,
|
Opt_cruid, Opt_gid, Opt_file_mode,
|
||||||
Opt_dirmode, Opt_port,
|
Opt_dirmode, Opt_port,
|
||||||
|
Opt_min_enc_offload,
|
||||||
Opt_blocksize, Opt_rsize, Opt_wsize, Opt_actimeo,
|
Opt_blocksize, Opt_rsize, Opt_wsize, Opt_actimeo,
|
||||||
Opt_echo_interval, Opt_max_credits, Opt_handletimeout,
|
Opt_echo_interval, Opt_max_credits, Opt_handletimeout,
|
||||||
Opt_snapshot,
|
Opt_snapshot,
|
||||||
@ -134,6 +135,7 @@ static const match_table_t cifs_mount_option_tokens = {
|
|||||||
{ Opt_noforcegid, "noforcegid" },
|
{ Opt_noforcegid, "noforcegid" },
|
||||||
{ Opt_noblocksend, "noblocksend" },
|
{ Opt_noblocksend, "noblocksend" },
|
||||||
{ Opt_noautotune, "noautotune" },
|
{ Opt_noautotune, "noautotune" },
|
||||||
|
{ Opt_nolease, "nolease" },
|
||||||
{ Opt_hard, "hard" },
|
{ Opt_hard, "hard" },
|
||||||
{ Opt_soft, "soft" },
|
{ Opt_soft, "soft" },
|
||||||
{ Opt_perm, "perm" },
|
{ Opt_perm, "perm" },
|
||||||
@ -183,6 +185,7 @@ static const match_table_t cifs_mount_option_tokens = {
|
|||||||
{ Opt_noacl, "noacl" },
|
{ Opt_noacl, "noacl" },
|
||||||
{ Opt_locallease, "locallease" },
|
{ Opt_locallease, "locallease" },
|
||||||
{ Opt_sign, "sign" },
|
{ Opt_sign, "sign" },
|
||||||
|
{ Opt_ignore_signature, "signloosely" },
|
||||||
{ Opt_seal, "seal" },
|
{ Opt_seal, "seal" },
|
||||||
{ Opt_noac, "noac" },
|
{ Opt_noac, "noac" },
|
||||||
{ Opt_fsc, "fsc" },
|
{ Opt_fsc, "fsc" },
|
||||||
@ -206,6 +209,7 @@ static const match_table_t cifs_mount_option_tokens = {
|
|||||||
{ Opt_dirmode, "dirmode=%s" },
|
{ Opt_dirmode, "dirmode=%s" },
|
||||||
{ Opt_dirmode, "dir_mode=%s" },
|
{ Opt_dirmode, "dir_mode=%s" },
|
||||||
{ Opt_port, "port=%s" },
|
{ Opt_port, "port=%s" },
|
||||||
|
{ Opt_min_enc_offload, "esize=%s" },
|
||||||
{ Opt_blocksize, "bsize=%s" },
|
{ Opt_blocksize, "bsize=%s" },
|
||||||
{ Opt_rsize, "rsize=%s" },
|
{ Opt_rsize, "rsize=%s" },
|
||||||
{ Opt_wsize, "wsize=%s" },
|
{ Opt_wsize, "wsize=%s" },
|
||||||
@ -262,6 +266,7 @@ static const match_table_t cifs_mount_option_tokens = {
|
|||||||
{ Opt_ignore, "nomand" },
|
{ Opt_ignore, "nomand" },
|
||||||
{ Opt_ignore, "relatime" },
|
{ Opt_ignore, "relatime" },
|
||||||
{ Opt_ignore, "_netdev" },
|
{ Opt_ignore, "_netdev" },
|
||||||
|
{ Opt_rootfs, "rootfs" },
|
||||||
|
|
||||||
{ Opt_err, NULL }
|
{ Opt_err, NULL }
|
||||||
};
|
};
|
||||||
@ -298,6 +303,8 @@ enum {
|
|||||||
Opt_cache_loose,
|
Opt_cache_loose,
|
||||||
Opt_cache_strict,
|
Opt_cache_strict,
|
||||||
Opt_cache_none,
|
Opt_cache_none,
|
||||||
|
Opt_cache_ro,
|
||||||
|
Opt_cache_rw,
|
||||||
Opt_cache_err
|
Opt_cache_err
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -305,6 +312,8 @@ static const match_table_t cifs_cacheflavor_tokens = {
|
|||||||
{ Opt_cache_loose, "loose" },
|
{ Opt_cache_loose, "loose" },
|
||||||
{ Opt_cache_strict, "strict" },
|
{ Opt_cache_strict, "strict" },
|
||||||
{ Opt_cache_none, "none" },
|
{ Opt_cache_none, "none" },
|
||||||
|
{ Opt_cache_ro, "ro" },
|
||||||
|
{ Opt_cache_rw, "singleclient" },
|
||||||
{ Opt_cache_err, NULL }
|
{ Opt_cache_err, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -489,7 +498,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
|||||||
} else {
|
} else {
|
||||||
rc = reconn_setup_dfs_targets(cifs_sb, &tgt_list, &tgt_it);
|
rc = reconn_setup_dfs_targets(cifs_sb, &tgt_list, &tgt_it);
|
||||||
if (rc && (rc != -EOPNOTSUPP)) {
|
if (rc && (rc != -EOPNOTSUPP)) {
|
||||||
cifs_dbg(VFS, "%s: no target servers for DFS failover\n",
|
cifs_server_dbg(VFS, "%s: no target servers for DFS failover\n",
|
||||||
__func__);
|
__func__);
|
||||||
} else {
|
} else {
|
||||||
server->nr_targets = dfs_cache_get_nr_tgts(&tgt_list);
|
server->nr_targets = dfs_cache_get_nr_tgts(&tgt_list);
|
||||||
@ -617,12 +626,12 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
|||||||
rc = dfs_cache_noreq_update_tgthint(cifs_sb->origin_fullpath + 1,
|
rc = dfs_cache_noreq_update_tgthint(cifs_sb->origin_fullpath + 1,
|
||||||
tgt_it);
|
tgt_it);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: failed to update DFS target hint: rc = %d\n",
|
cifs_server_dbg(VFS, "%s: failed to update DFS target hint: rc = %d\n",
|
||||||
__func__, rc);
|
__func__, rc);
|
||||||
}
|
}
|
||||||
rc = dfs_cache_update_vol(cifs_sb->origin_fullpath, server);
|
rc = dfs_cache_update_vol(cifs_sb->origin_fullpath, server);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: failed to update vol info in DFS cache: rc = %d\n",
|
cifs_server_dbg(VFS, "%s: failed to update vol info in DFS cache: rc = %d\n",
|
||||||
__func__, rc);
|
__func__, rc);
|
||||||
}
|
}
|
||||||
dfs_cache_free_tgts(&tgt_list);
|
dfs_cache_free_tgts(&tgt_list);
|
||||||
@ -678,7 +687,7 @@ allocate_buffers(struct TCP_Server_Info *server)
|
|||||||
if (!server->bigbuf) {
|
if (!server->bigbuf) {
|
||||||
server->bigbuf = (char *)cifs_buf_get();
|
server->bigbuf = (char *)cifs_buf_get();
|
||||||
if (!server->bigbuf) {
|
if (!server->bigbuf) {
|
||||||
cifs_dbg(VFS, "No memory for large SMB response\n");
|
cifs_server_dbg(VFS, "No memory for large SMB response\n");
|
||||||
msleep(3000);
|
msleep(3000);
|
||||||
/* retry will check if exiting */
|
/* retry will check if exiting */
|
||||||
return false;
|
return false;
|
||||||
@ -691,7 +700,7 @@ allocate_buffers(struct TCP_Server_Info *server)
|
|||||||
if (!server->smallbuf) {
|
if (!server->smallbuf) {
|
||||||
server->smallbuf = (char *)cifs_small_buf_get();
|
server->smallbuf = (char *)cifs_small_buf_get();
|
||||||
if (!server->smallbuf) {
|
if (!server->smallbuf) {
|
||||||
cifs_dbg(VFS, "No memory for SMB response\n");
|
cifs_server_dbg(VFS, "No memory for SMB response\n");
|
||||||
msleep(1000);
|
msleep(1000);
|
||||||
/* retry will check if exiting */
|
/* retry will check if exiting */
|
||||||
return false;
|
return false;
|
||||||
@ -712,7 +721,7 @@ server_unresponsive(struct TCP_Server_Info *server)
|
|||||||
* We need to wait 3 echo intervals to make sure we handle such
|
* We need to wait 3 echo intervals to make sure we handle such
|
||||||
* situations right:
|
* situations right:
|
||||||
* 1s client sends a normal SMB request
|
* 1s client sends a normal SMB request
|
||||||
* 3s client gets a response
|
* 2s client gets a response
|
||||||
* 30s echo workqueue job pops, and decides we got a response recently
|
* 30s echo workqueue job pops, and decides we got a response recently
|
||||||
* and don't need to send another
|
* and don't need to send another
|
||||||
* ...
|
* ...
|
||||||
@ -722,8 +731,8 @@ server_unresponsive(struct TCP_Server_Info *server)
|
|||||||
if ((server->tcpStatus == CifsGood ||
|
if ((server->tcpStatus == CifsGood ||
|
||||||
server->tcpStatus == CifsNeedNegotiate) &&
|
server->tcpStatus == CifsNeedNegotiate) &&
|
||||||
time_after(jiffies, server->lstrp + 3 * server->echo_interval)) {
|
time_after(jiffies, server->lstrp + 3 * server->echo_interval)) {
|
||||||
cifs_dbg(VFS, "Server %s has not responded in %lu seconds. Reconnecting...\n",
|
cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n",
|
||||||
server->hostname, (3 * server->echo_interval) / HZ);
|
(3 * server->echo_interval) / HZ);
|
||||||
cifs_reconnect(server);
|
cifs_reconnect(server);
|
||||||
wake_up(&server->response_q);
|
wake_up(&server->response_q);
|
||||||
return true;
|
return true;
|
||||||
@ -861,7 +870,7 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
|
|||||||
wake_up(&server->response_q);
|
wake_up(&server->response_q);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cifs_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", type);
|
cifs_server_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", type);
|
||||||
cifs_reconnect(server);
|
cifs_reconnect(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1008,7 +1017,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||||||
/* make sure this will fit in a large buffer */
|
/* make sure this will fit in a large buffer */
|
||||||
if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
|
if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
|
||||||
server->vals->header_preamble_size) {
|
server->vals->header_preamble_size) {
|
||||||
cifs_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
|
cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
|
||||||
cifs_reconnect(server);
|
cifs_reconnect(server);
|
||||||
wake_up(&server->response_q);
|
wake_up(&server->response_q);
|
||||||
return -ECONNABORTED;
|
return -ECONNABORTED;
|
||||||
@ -1149,7 +1158,7 @@ next_pdu:
|
|||||||
/* make sure we have enough to get to the MID */
|
/* make sure we have enough to get to the MID */
|
||||||
if (server->pdu_size < HEADER_SIZE(server) - 1 -
|
if (server->pdu_size < HEADER_SIZE(server) - 1 -
|
||||||
server->vals->header_preamble_size) {
|
server->vals->header_preamble_size) {
|
||||||
cifs_dbg(VFS, "SMB response too short (%u bytes)\n",
|
cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n",
|
||||||
server->pdu_size);
|
server->pdu_size);
|
||||||
cifs_reconnect(server);
|
cifs_reconnect(server);
|
||||||
wake_up(&server->response_q);
|
wake_up(&server->response_q);
|
||||||
@ -1222,7 +1231,7 @@ next_pdu:
|
|||||||
smb2_add_credits_from_hdr(bufs[i], server);
|
smb2_add_credits_from_hdr(bufs[i], server);
|
||||||
cifs_dbg(FYI, "Received oplock break\n");
|
cifs_dbg(FYI, "Received oplock break\n");
|
||||||
} else {
|
} else {
|
||||||
cifs_dbg(VFS, "No task to wake, unknown frame "
|
cifs_server_dbg(VFS, "No task to wake, unknown frame "
|
||||||
"received! NumMids %d\n",
|
"received! NumMids %d\n",
|
||||||
atomic_read(&midCount));
|
atomic_read(&midCount));
|
||||||
cifs_dump_mem("Received Data is: ", bufs[i],
|
cifs_dump_mem("Received Data is: ", bufs[i],
|
||||||
@ -1418,14 +1427,32 @@ cifs_parse_cache_flavor(char *value, struct smb_vol *vol)
|
|||||||
case Opt_cache_loose:
|
case Opt_cache_loose:
|
||||||
vol->direct_io = false;
|
vol->direct_io = false;
|
||||||
vol->strict_io = false;
|
vol->strict_io = false;
|
||||||
|
vol->cache_ro = false;
|
||||||
|
vol->cache_rw = false;
|
||||||
break;
|
break;
|
||||||
case Opt_cache_strict:
|
case Opt_cache_strict:
|
||||||
vol->direct_io = false;
|
vol->direct_io = false;
|
||||||
vol->strict_io = true;
|
vol->strict_io = true;
|
||||||
|
vol->cache_ro = false;
|
||||||
|
vol->cache_rw = false;
|
||||||
break;
|
break;
|
||||||
case Opt_cache_none:
|
case Opt_cache_none:
|
||||||
vol->direct_io = true;
|
vol->direct_io = true;
|
||||||
vol->strict_io = false;
|
vol->strict_io = false;
|
||||||
|
vol->cache_ro = false;
|
||||||
|
vol->cache_rw = false;
|
||||||
|
break;
|
||||||
|
case Opt_cache_ro:
|
||||||
|
vol->direct_io = false;
|
||||||
|
vol->strict_io = false;
|
||||||
|
vol->cache_ro = true;
|
||||||
|
vol->cache_rw = false;
|
||||||
|
break;
|
||||||
|
case Opt_cache_rw:
|
||||||
|
vol->direct_io = false;
|
||||||
|
vol->strict_io = false;
|
||||||
|
vol->cache_ro = false;
|
||||||
|
vol->cache_rw = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cifs_dbg(VFS, "bad cache= option: %s\n", value);
|
cifs_dbg(VFS, "bad cache= option: %s\n", value);
|
||||||
@ -1713,6 +1740,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
|
|||||||
case Opt_noautotune:
|
case Opt_noautotune:
|
||||||
vol->noautotune = 1;
|
vol->noautotune = 1;
|
||||||
break;
|
break;
|
||||||
|
case Opt_nolease:
|
||||||
|
vol->no_lease = 1;
|
||||||
|
break;
|
||||||
case Opt_hard:
|
case Opt_hard:
|
||||||
vol->retry = 1;
|
vol->retry = 1;
|
||||||
break;
|
break;
|
||||||
@ -1748,6 +1778,11 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
|
|||||||
case Opt_nodfs:
|
case Opt_nodfs:
|
||||||
vol->nodfs = 1;
|
vol->nodfs = 1;
|
||||||
break;
|
break;
|
||||||
|
case Opt_rootfs:
|
||||||
|
#ifdef CONFIG_CIFS_ROOT
|
||||||
|
vol->rootfs = true;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
case Opt_posixpaths:
|
case Opt_posixpaths:
|
||||||
vol->posix_paths = 1;
|
vol->posix_paths = 1;
|
||||||
break;
|
break;
|
||||||
@ -1855,6 +1890,10 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
|
|||||||
case Opt_sign:
|
case Opt_sign:
|
||||||
vol->sign = true;
|
vol->sign = true;
|
||||||
break;
|
break;
|
||||||
|
case Opt_ignore_signature:
|
||||||
|
vol->sign = true;
|
||||||
|
vol->ignore_signature = true;
|
||||||
|
break;
|
||||||
case Opt_seal:
|
case Opt_seal:
|
||||||
/* we do not do the following in secFlags because seal
|
/* we do not do the following in secFlags because seal
|
||||||
* is a per tree connection (mount) not a per socket
|
* is a per tree connection (mount) not a per socket
|
||||||
@ -1989,6 +2028,13 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
|
|||||||
}
|
}
|
||||||
port = (unsigned short)option;
|
port = (unsigned short)option;
|
||||||
break;
|
break;
|
||||||
|
case Opt_min_enc_offload:
|
||||||
|
if (get_option_ul(args, &option)) {
|
||||||
|
cifs_dbg(VFS, "Invalid minimum encrypted read offload size (esize)\n");
|
||||||
|
goto cifs_parse_mount_err;
|
||||||
|
}
|
||||||
|
vol->min_offload = option;
|
||||||
|
break;
|
||||||
case Opt_blocksize:
|
case Opt_blocksize:
|
||||||
if (get_option_ul(args, &option)) {
|
if (get_option_ul(args, &option)) {
|
||||||
cifs_dbg(VFS, "%s: Invalid blocksize value\n",
|
cifs_dbg(VFS, "%s: Invalid blocksize value\n",
|
||||||
@ -2586,6 +2632,12 @@ static int match_server(struct TCP_Server_Info *server, struct smb_vol *vol)
|
|||||||
if (server->rdma != vol->rdma)
|
if (server->rdma != vol->rdma)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (server->ignore_signature != vol->ignore_signature)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (server->min_offload != vol->min_offload)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2681,11 +2733,13 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
|
|||||||
goto out_err_crypto_release;
|
goto out_err_crypto_release;
|
||||||
}
|
}
|
||||||
|
|
||||||
tcp_ses->noblocksnd = volume_info->noblocksnd;
|
tcp_ses->noblockcnt = volume_info->rootfs;
|
||||||
|
tcp_ses->noblocksnd = volume_info->noblocksnd || volume_info->rootfs;
|
||||||
tcp_ses->noautotune = volume_info->noautotune;
|
tcp_ses->noautotune = volume_info->noautotune;
|
||||||
tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
|
tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
|
||||||
tcp_ses->rdma = volume_info->rdma;
|
tcp_ses->rdma = volume_info->rdma;
|
||||||
tcp_ses->in_flight = 0;
|
tcp_ses->in_flight = 0;
|
||||||
|
tcp_ses->max_in_flight = 0;
|
||||||
tcp_ses->credits = 1;
|
tcp_ses->credits = 1;
|
||||||
init_waitqueue_head(&tcp_ses->response_q);
|
init_waitqueue_head(&tcp_ses->response_q);
|
||||||
init_waitqueue_head(&tcp_ses->request_q);
|
init_waitqueue_head(&tcp_ses->request_q);
|
||||||
@ -2760,10 +2814,11 @@ smbd_connected:
|
|||||||
module_put(THIS_MODULE);
|
module_put(THIS_MODULE);
|
||||||
goto out_err_crypto_release;
|
goto out_err_crypto_release;
|
||||||
}
|
}
|
||||||
|
tcp_ses->min_offload = volume_info->min_offload;
|
||||||
tcp_ses->tcpStatus = CifsNeedNegotiate;
|
tcp_ses->tcpStatus = CifsNeedNegotiate;
|
||||||
|
|
||||||
tcp_ses->nr_targets = 1;
|
tcp_ses->nr_targets = 1;
|
||||||
|
tcp_ses->ignore_signature = volume_info->ignore_signature;
|
||||||
/* thread spawned, put it on the list */
|
/* thread spawned, put it on the list */
|
||||||
spin_lock(&cifs_tcp_ses_lock);
|
spin_lock(&cifs_tcp_ses_lock);
|
||||||
list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
|
list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
|
||||||
@ -2840,16 +2895,17 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb_vol *volume_info)
|
|||||||
struct nls_table *nls_codepage;
|
struct nls_table *nls_codepage;
|
||||||
char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0};
|
char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0};
|
||||||
bool seal = false;
|
bool seal = false;
|
||||||
|
struct TCP_Server_Info *server = ses->server;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the mount request that resulted in the creation of the
|
* If the mount request that resulted in the creation of the
|
||||||
* session requires encryption, force IPC to be encrypted too.
|
* session requires encryption, force IPC to be encrypted too.
|
||||||
*/
|
*/
|
||||||
if (volume_info->seal) {
|
if (volume_info->seal) {
|
||||||
if (ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)
|
if (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)
|
||||||
seal = true;
|
seal = true;
|
||||||
else {
|
else {
|
||||||
cifs_dbg(VFS,
|
cifs_server_dbg(VFS,
|
||||||
"IPC: server doesn't support encryption\n");
|
"IPC: server doesn't support encryption\n");
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
@ -2859,7 +2915,7 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb_vol *volume_info)
|
|||||||
if (tcon == NULL)
|
if (tcon == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", ses->server->hostname);
|
scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname);
|
||||||
|
|
||||||
/* cannot fail */
|
/* cannot fail */
|
||||||
nls_codepage = load_nls_default();
|
nls_codepage = load_nls_default();
|
||||||
@ -2868,11 +2924,11 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb_vol *volume_info)
|
|||||||
tcon->ses = ses;
|
tcon->ses = ses;
|
||||||
tcon->ipc = true;
|
tcon->ipc = true;
|
||||||
tcon->seal = seal;
|
tcon->seal = seal;
|
||||||
rc = ses->server->ops->tree_connect(xid, ses, unc, tcon, nls_codepage);
|
rc = server->ops->tree_connect(xid, ses, unc, tcon, nls_codepage);
|
||||||
free_xid(xid);
|
free_xid(xid);
|
||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc);
|
cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc);
|
||||||
tconInfoFree(tcon);
|
tconInfoFree(tcon);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -2958,7 +3014,7 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
|
|||||||
xid = get_xid();
|
xid = get_xid();
|
||||||
rc = server->ops->logoff(xid, ses);
|
rc = server->ops->logoff(xid, ses);
|
||||||
if (rc)
|
if (rc)
|
||||||
cifs_dbg(VFS, "%s: Session Logoff failure rc=%d\n",
|
cifs_server_dbg(VFS, "%s: Session Logoff failure rc=%d\n",
|
||||||
__func__, rc);
|
__func__, rc);
|
||||||
_free_xid(xid);
|
_free_xid(xid);
|
||||||
}
|
}
|
||||||
@ -3212,7 +3268,6 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
|
|||||||
|
|
||||||
ses->sectype = volume_info->sectype;
|
ses->sectype = volume_info->sectype;
|
||||||
ses->sign = volume_info->sign;
|
ses->sign = volume_info->sign;
|
||||||
|
|
||||||
mutex_lock(&ses->session_mutex);
|
mutex_lock(&ses->session_mutex);
|
||||||
rc = cifs_negotiate_protocol(xid, ses);
|
rc = cifs_negotiate_protocol(xid, ses);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
@ -3250,6 +3305,8 @@ static int match_tcon(struct cifs_tcon *tcon, struct smb_vol *volume_info)
|
|||||||
return 0;
|
return 0;
|
||||||
if (tcon->handle_timeout != volume_info->handle_timeout)
|
if (tcon->handle_timeout != volume_info->handle_timeout)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (tcon->no_lease != volume_info->no_lease)
|
||||||
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3455,6 +3512,14 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
|
|||||||
tcon->use_resilient = true;
|
tcon->use_resilient = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the user really knows what they are doing they can override */
|
||||||
|
if (tcon->share_flags & SMB2_SHAREFLAG_NO_CACHING) {
|
||||||
|
if (volume_info->cache_ro)
|
||||||
|
cifs_dbg(VFS, "cache=ro requested on mount but NO_CACHING flag set on share\n");
|
||||||
|
else if (volume_info->cache_rw)
|
||||||
|
cifs_dbg(VFS, "cache=singleclient requested on mount but NO_CACHING flag set on share\n");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can have only one retry value for a connection to a share so for
|
* We can have only one retry value for a connection to a share so for
|
||||||
* resources mounted more than once to the same server share the last
|
* resources mounted more than once to the same server share the last
|
||||||
@ -3464,6 +3529,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
|
|||||||
tcon->nocase = volume_info->nocase;
|
tcon->nocase = volume_info->nocase;
|
||||||
tcon->nohandlecache = volume_info->nohandlecache;
|
tcon->nohandlecache = volume_info->nohandlecache;
|
||||||
tcon->local_lease = volume_info->local_lease;
|
tcon->local_lease = volume_info->local_lease;
|
||||||
|
tcon->no_lease = volume_info->no_lease;
|
||||||
INIT_LIST_HEAD(&tcon->pending_opens);
|
INIT_LIST_HEAD(&tcon->pending_opens);
|
||||||
|
|
||||||
spin_lock(&cifs_tcp_ses_lock);
|
spin_lock(&cifs_tcp_ses_lock);
|
||||||
@ -3659,10 +3725,10 @@ bind_socket(struct TCP_Server_Info *server)
|
|||||||
saddr4 = (struct sockaddr_in *)&server->srcaddr;
|
saddr4 = (struct sockaddr_in *)&server->srcaddr;
|
||||||
saddr6 = (struct sockaddr_in6 *)&server->srcaddr;
|
saddr6 = (struct sockaddr_in6 *)&server->srcaddr;
|
||||||
if (saddr6->sin6_family == AF_INET6)
|
if (saddr6->sin6_family == AF_INET6)
|
||||||
cifs_dbg(VFS, "Failed to bind to: %pI6c, error: %d\n",
|
cifs_server_dbg(VFS, "Failed to bind to: %pI6c, error: %d\n",
|
||||||
&saddr6->sin6_addr, rc);
|
&saddr6->sin6_addr, rc);
|
||||||
else
|
else
|
||||||
cifs_dbg(VFS, "Failed to bind to: %pI4, error: %d\n",
|
cifs_server_dbg(VFS, "Failed to bind to: %pI4, error: %d\n",
|
||||||
&saddr4->sin_addr.s_addr, rc);
|
&saddr4->sin_addr.s_addr, rc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3766,7 +3832,7 @@ generic_ip_connect(struct TCP_Server_Info *server)
|
|||||||
rc = __sock_create(cifs_net_ns(server), sfamily, SOCK_STREAM,
|
rc = __sock_create(cifs_net_ns(server), sfamily, SOCK_STREAM,
|
||||||
IPPROTO_TCP, &socket, 1);
|
IPPROTO_TCP, &socket, 1);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
cifs_dbg(VFS, "Error %d creating socket\n", rc);
|
cifs_server_dbg(VFS, "Error %d creating socket\n", rc);
|
||||||
server->ssocket = NULL;
|
server->ssocket = NULL;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -3814,7 +3880,11 @@ generic_ip_connect(struct TCP_Server_Info *server)
|
|||||||
socket->sk->sk_sndbuf,
|
socket->sk->sk_sndbuf,
|
||||||
socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo);
|
socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo);
|
||||||
|
|
||||||
rc = socket->ops->connect(socket, saddr, slen, 0);
|
rc = socket->ops->connect(socket, saddr, slen,
|
||||||
|
server->noblockcnt ? O_NONBLOCK : 0);
|
||||||
|
|
||||||
|
if (rc == -EINPROGRESS)
|
||||||
|
rc = 0;
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
cifs_dbg(FYI, "Error %d connecting to server\n", rc);
|
cifs_dbg(FYI, "Error %d connecting to server\n", rc);
|
||||||
sock_release(socket);
|
sock_release(socket);
|
||||||
@ -4040,6 +4110,14 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
|
|||||||
cifs_dbg(FYI, "mounting share using direct i/o\n");
|
cifs_dbg(FYI, "mounting share using direct i/o\n");
|
||||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
|
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
|
||||||
}
|
}
|
||||||
|
if (pvolume_info->cache_ro) {
|
||||||
|
cifs_dbg(VFS, "mounting share with read only caching. Ensure that the share will not be modified while in use.\n");
|
||||||
|
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RO_CACHE;
|
||||||
|
} else if (pvolume_info->cache_rw) {
|
||||||
|
cifs_dbg(VFS, "mounting share in single client RW caching mode. Ensure that no other systems will be accessing the share.\n");
|
||||||
|
cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_RO_CACHE |
|
||||||
|
CIFS_MOUNT_RW_CACHE);
|
||||||
|
}
|
||||||
if (pvolume_info->mfsymlinks) {
|
if (pvolume_info->mfsymlinks) {
|
||||||
if (pvolume_info->sfu_emul) {
|
if (pvolume_info->sfu_emul) {
|
||||||
/*
|
/*
|
||||||
@ -4150,7 +4228,7 @@ static int mount_get_conns(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
|
|||||||
|
|
||||||
if ((vol->persistent == true) && (!(ses->server->capabilities &
|
if ((vol->persistent == true) && (!(ses->server->capabilities &
|
||||||
SMB2_GLOBAL_CAP_PERSISTENT_HANDLES))) {
|
SMB2_GLOBAL_CAP_PERSISTENT_HANDLES))) {
|
||||||
cifs_dbg(VFS, "persistent handles not supported by server\n");
|
cifs_server_dbg(VFS, "persistent handles not supported by server\n");
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4182,8 +4260,18 @@ static int mount_get_conns(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
|
|||||||
tcon->unix_ext = 0; /* server does not support them */
|
tcon->unix_ext = 0; /* server does not support them */
|
||||||
|
|
||||||
/* do not care if a following call succeed - informational */
|
/* do not care if a following call succeed - informational */
|
||||||
if (!tcon->pipe && server->ops->qfs_tcon)
|
if (!tcon->pipe && server->ops->qfs_tcon) {
|
||||||
server->ops->qfs_tcon(*xid, tcon);
|
server->ops->qfs_tcon(*xid, tcon);
|
||||||
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE) {
|
||||||
|
if (tcon->fsDevInfo.DeviceCharacteristics &
|
||||||
|
FILE_READ_ONLY_DEVICE)
|
||||||
|
cifs_dbg(VFS, "mounted to read only share\n");
|
||||||
|
else if ((cifs_sb->mnt_cifs_flags &
|
||||||
|
CIFS_MOUNT_RW_CACHE) == 0)
|
||||||
|
cifs_dbg(VFS, "read only mount of RW share\n");
|
||||||
|
/* no need to log a RW mount of a typical RW share */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cifs_sb->wsize = server->ops->negotiate_wsize(tcon, vol);
|
cifs_sb->wsize = server->ops->negotiate_wsize(tcon, vol);
|
||||||
cifs_sb->rsize = server->ops->negotiate_rsize(tcon, vol);
|
cifs_sb->rsize = server->ops->negotiate_rsize(tcon, vol);
|
||||||
@ -4588,7 +4676,7 @@ static int is_path_remote(struct cifs_sb_info *cifs_sb, struct smb_vol *vol,
|
|||||||
rc = cifs_are_all_path_components_accessible(server, xid, tcon,
|
rc = cifs_are_all_path_components_accessible(server, xid, tcon,
|
||||||
cifs_sb, full_path, tcon->Flags & SMB_SHARE_IS_IN_DFS);
|
cifs_sb, full_path, tcon->Flags & SMB_SHARE_IS_IN_DFS);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
cifs_dbg(VFS, "cannot query dirs between root and final path, "
|
cifs_server_dbg(VFS, "cannot query dirs between root and final path, "
|
||||||
"enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
|
"enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
|
||||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
|
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
@ -5090,7 +5178,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
|
|||||||
rc = server->ops->sess_setup(xid, ses, nls_info);
|
rc = server->ops->sess_setup(xid, ses, nls_info);
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
cifs_dbg(VFS, "Send error in SessSetup = %d\n", rc);
|
cifs_server_dbg(VFS, "Send error in SessSetup = %d\n", rc);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ cifs_bp_rename_retry:
|
|||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
full_path = kmalloc(namelen+1, GFP_KERNEL);
|
full_path = kmalloc(namelen+1, GFP_ATOMIC);
|
||||||
if (full_path == NULL)
|
if (full_path == NULL)
|
||||||
return full_path;
|
return full_path;
|
||||||
full_path[namelen] = 0; /* trailing null */
|
full_path[namelen] = 0; /* trailing null */
|
||||||
|
@ -1693,9 +1693,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
|
|||||||
bool posix_lck = false;
|
bool posix_lck = false;
|
||||||
struct cifs_sb_info *cifs_sb;
|
struct cifs_sb_info *cifs_sb;
|
||||||
struct cifs_tcon *tcon;
|
struct cifs_tcon *tcon;
|
||||||
struct cifsInodeInfo *cinode;
|
|
||||||
struct cifsFileInfo *cfile;
|
struct cifsFileInfo *cfile;
|
||||||
__u16 netfid;
|
|
||||||
__u32 type;
|
__u32 type;
|
||||||
|
|
||||||
rc = -EACCES;
|
rc = -EACCES;
|
||||||
@ -1711,8 +1709,6 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
|
|||||||
cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag,
|
cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag,
|
||||||
tcon->ses->server);
|
tcon->ses->server);
|
||||||
cifs_sb = CIFS_FILE_SB(file);
|
cifs_sb = CIFS_FILE_SB(file);
|
||||||
netfid = cfile->fid.netfid;
|
|
||||||
cinode = CIFS_I(file_inode(file));
|
|
||||||
|
|
||||||
if (cap_unix(tcon->ses) &&
|
if (cap_unix(tcon->ses) &&
|
||||||
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
|
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
|
||||||
@ -1764,7 +1760,6 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data,
|
|||||||
int rc = 0;
|
int rc = 0;
|
||||||
unsigned int bytes_written = 0;
|
unsigned int bytes_written = 0;
|
||||||
unsigned int total_written;
|
unsigned int total_written;
|
||||||
struct cifs_sb_info *cifs_sb;
|
|
||||||
struct cifs_tcon *tcon;
|
struct cifs_tcon *tcon;
|
||||||
struct TCP_Server_Info *server;
|
struct TCP_Server_Info *server;
|
||||||
unsigned int xid;
|
unsigned int xid;
|
||||||
@ -1772,8 +1767,6 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data,
|
|||||||
struct cifsInodeInfo *cifsi = CIFS_I(d_inode(dentry));
|
struct cifsInodeInfo *cifsi = CIFS_I(d_inode(dentry));
|
||||||
struct cifs_io_parms io_parms;
|
struct cifs_io_parms io_parms;
|
||||||
|
|
||||||
cifs_sb = CIFS_SB(dentry->d_sb);
|
|
||||||
|
|
||||||
cifs_dbg(FYI, "write %zd bytes to offset %lld of %pd\n",
|
cifs_dbg(FYI, "write %zd bytes to offset %lld of %pd\n",
|
||||||
write_size, *offset, dentry);
|
write_size, *offset, dentry);
|
||||||
|
|
||||||
@ -1980,6 +1973,77 @@ find_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only)
|
|||||||
return cfile;
|
return cfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
|
||||||
|
struct cifsFileInfo **ret_file)
|
||||||
|
{
|
||||||
|
struct list_head *tmp;
|
||||||
|
struct cifsFileInfo *cfile;
|
||||||
|
struct cifsInodeInfo *cinode;
|
||||||
|
char *full_path;
|
||||||
|
|
||||||
|
*ret_file = NULL;
|
||||||
|
|
||||||
|
spin_lock(&tcon->open_file_lock);
|
||||||
|
list_for_each(tmp, &tcon->openFileList) {
|
||||||
|
cfile = list_entry(tmp, struct cifsFileInfo,
|
||||||
|
tlist);
|
||||||
|
full_path = build_path_from_dentry(cfile->dentry);
|
||||||
|
if (full_path == NULL) {
|
||||||
|
spin_unlock(&tcon->open_file_lock);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
if (strcmp(full_path, name)) {
|
||||||
|
kfree(full_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(full_path);
|
||||||
|
cinode = CIFS_I(d_inode(cfile->dentry));
|
||||||
|
spin_unlock(&tcon->open_file_lock);
|
||||||
|
return cifs_get_writable_file(cinode, 0, ret_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock(&tcon->open_file_lock);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
|
||||||
|
struct cifsFileInfo **ret_file)
|
||||||
|
{
|
||||||
|
struct list_head *tmp;
|
||||||
|
struct cifsFileInfo *cfile;
|
||||||
|
struct cifsInodeInfo *cinode;
|
||||||
|
char *full_path;
|
||||||
|
|
||||||
|
*ret_file = NULL;
|
||||||
|
|
||||||
|
spin_lock(&tcon->open_file_lock);
|
||||||
|
list_for_each(tmp, &tcon->openFileList) {
|
||||||
|
cfile = list_entry(tmp, struct cifsFileInfo,
|
||||||
|
tlist);
|
||||||
|
full_path = build_path_from_dentry(cfile->dentry);
|
||||||
|
if (full_path == NULL) {
|
||||||
|
spin_unlock(&tcon->open_file_lock);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
if (strcmp(full_path, name)) {
|
||||||
|
kfree(full_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(full_path);
|
||||||
|
cinode = CIFS_I(d_inode(cfile->dentry));
|
||||||
|
spin_unlock(&tcon->open_file_lock);
|
||||||
|
*ret_file = find_readable_file(cinode, 0);
|
||||||
|
return *ret_file ? 0 : -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock(&tcon->open_file_lock);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
|
static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
|
||||||
{
|
{
|
||||||
struct address_space *mapping = page->mapping;
|
struct address_space *mapping = page->mapping;
|
||||||
@ -3577,10 +3641,8 @@ collect_uncached_read_data(struct cifs_aio_ctx *ctx)
|
|||||||
struct cifs_readdata *rdata, *tmp;
|
struct cifs_readdata *rdata, *tmp;
|
||||||
struct iov_iter *to = &ctx->iter;
|
struct iov_iter *to = &ctx->iter;
|
||||||
struct cifs_sb_info *cifs_sb;
|
struct cifs_sb_info *cifs_sb;
|
||||||
struct cifs_tcon *tcon;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
tcon = tlink_tcon(ctx->cfile->tlink);
|
|
||||||
cifs_sb = CIFS_SB(ctx->cfile->dentry->d_sb);
|
cifs_sb = CIFS_SB(ctx->cfile->dentry->d_sb);
|
||||||
|
|
||||||
mutex_lock(&ctx->aio_mutex);
|
mutex_lock(&ctx->aio_mutex);
|
||||||
|
@ -893,8 +893,17 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* fill in 0777 bits from ACL */
|
/* fill in 0777 bits from ACL */
|
||||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) {
|
||||||
rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, full_path, fid);
|
rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, true,
|
||||||
|
full_path, fid);
|
||||||
|
if (rc) {
|
||||||
|
cifs_dbg(FYI, "%s: Get mode from SID failed. rc=%d\n",
|
||||||
|
__func__, rc);
|
||||||
|
goto cgii_exit;
|
||||||
|
}
|
||||||
|
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
|
||||||
|
rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, false,
|
||||||
|
full_path, fid);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(FYI, "%s: Getting ACL failed with error: %d\n",
|
cifs_dbg(FYI, "%s: Getting ACL failed with error: %d\n",
|
||||||
__func__, rc);
|
__func__, rc);
|
||||||
@ -2480,7 +2489,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
|||||||
if (attrs->ia_valid & ATTR_GID)
|
if (attrs->ia_valid & ATTR_GID)
|
||||||
gid = attrs->ia_gid;
|
gid = attrs->ia_gid;
|
||||||
|
|
||||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
|
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
|
||||||
|
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
|
||||||
if (uid_valid(uid) || gid_valid(gid)) {
|
if (uid_valid(uid) || gid_valid(gid)) {
|
||||||
rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64,
|
rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64,
|
||||||
uid, gid);
|
uid, gid);
|
||||||
@ -2501,7 +2511,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
|||||||
if (attrs->ia_valid & ATTR_MODE) {
|
if (attrs->ia_valid & ATTR_MODE) {
|
||||||
mode = attrs->ia_mode;
|
mode = attrs->ia_mode;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
|
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
|
||||||
|
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
|
||||||
rc = id_mode_to_cifs_acl(inode, full_path, mode,
|
rc = id_mode_to_cifs_acl(inode, full_path, mode,
|
||||||
INVALID_UID, INVALID_GID);
|
INVALID_UID, INVALID_GID);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
@ -51,7 +51,8 @@ static int
|
|||||||
smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
struct cifs_sb_info *cifs_sb, const char *full_path,
|
struct cifs_sb_info *cifs_sb, const char *full_path,
|
||||||
__u32 desired_access, __u32 create_disposition,
|
__u32 desired_access, __u32 create_disposition,
|
||||||
__u32 create_options, void *ptr, int command)
|
__u32 create_options, void *ptr, int command,
|
||||||
|
struct cifsFileInfo *cfile)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
__le16 *utf16_path = NULL;
|
__le16 *utf16_path = NULL;
|
||||||
@ -83,10 +84,16 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
||||||
memset(rsp_iov, 0, sizeof(rsp_iov));
|
memset(rsp_iov, 0, sizeof(rsp_iov));
|
||||||
|
|
||||||
|
/* We already have a handle so we can skip the open */
|
||||||
|
if (cfile)
|
||||||
|
goto after_open;
|
||||||
|
|
||||||
/* Open */
|
/* Open */
|
||||||
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
||||||
if (!utf16_path)
|
if (!utf16_path) {
|
||||||
return -ENOMEM;
|
rc = -ENOMEM;
|
||||||
|
goto finished;
|
||||||
|
}
|
||||||
|
|
||||||
oparms.tcon = tcon;
|
oparms.tcon = tcon;
|
||||||
oparms.desired_access = desired_access;
|
oparms.desired_access = desired_access;
|
||||||
@ -106,7 +113,10 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
if (rc)
|
if (rc)
|
||||||
goto finished;
|
goto finished;
|
||||||
|
|
||||||
smb2_set_next_command(tcon, &rqst[num_rqst++]);
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
||||||
|
after_open:
|
||||||
|
num_rqst++;
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
/* Operation */
|
/* Operation */
|
||||||
switch (command) {
|
switch (command) {
|
||||||
@ -115,15 +125,31 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
rqst[num_rqst].rq_iov = qi_iov;
|
rqst[num_rqst].rq_iov = qi_iov;
|
||||||
rqst[num_rqst].rq_nvec = 1;
|
rqst[num_rqst].rq_nvec = 1;
|
||||||
|
|
||||||
rc = SMB2_query_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
|
if (cfile)
|
||||||
COMPOUND_FID, FILE_ALL_INFORMATION,
|
rc = SMB2_query_info_init(tcon, &rqst[num_rqst],
|
||||||
|
cfile->fid.persistent_fid,
|
||||||
|
cfile->fid.volatile_fid,
|
||||||
|
FILE_ALL_INFORMATION,
|
||||||
SMB2_O_INFO_FILE, 0,
|
SMB2_O_INFO_FILE, 0,
|
||||||
sizeof(struct smb2_file_all_info) +
|
sizeof(struct smb2_file_all_info) +
|
||||||
PATH_MAX * 2, 0, NULL);
|
PATH_MAX * 2, 0, NULL);
|
||||||
|
else {
|
||||||
|
rc = SMB2_query_info_init(tcon, &rqst[num_rqst],
|
||||||
|
COMPOUND_FID,
|
||||||
|
COMPOUND_FID,
|
||||||
|
FILE_ALL_INFORMATION,
|
||||||
|
SMB2_O_INFO_FILE, 0,
|
||||||
|
sizeof(struct smb2_file_all_info) +
|
||||||
|
PATH_MAX * 2, 0, NULL);
|
||||||
|
if (!rc) {
|
||||||
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
||||||
|
smb2_set_related(&rqst[num_rqst]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
goto finished;
|
goto finished;
|
||||||
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
num_rqst++;
|
||||||
smb2_set_related(&rqst[num_rqst++]);
|
|
||||||
trace_smb3_query_info_compound_enter(xid, ses->Suid, tcon->tid,
|
trace_smb3_query_info_compound_enter(xid, ses->Suid, tcon->tid,
|
||||||
full_path);
|
full_path);
|
||||||
break;
|
break;
|
||||||
@ -182,14 +208,27 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
size[0] = sizeof(FILE_BASIC_INFO);
|
size[0] = sizeof(FILE_BASIC_INFO);
|
||||||
data[0] = ptr;
|
data[0] = ptr;
|
||||||
|
|
||||||
rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
|
if (cfile)
|
||||||
COMPOUND_FID, current->tgid,
|
rc = SMB2_set_info_init(tcon, &rqst[num_rqst],
|
||||||
FILE_BASIC_INFORMATION,
|
cfile->fid.persistent_fid,
|
||||||
SMB2_O_INFO_FILE, 0, data, size);
|
cfile->fid.volatile_fid, current->tgid,
|
||||||
|
FILE_BASIC_INFORMATION,
|
||||||
|
SMB2_O_INFO_FILE, 0, data, size);
|
||||||
|
else {
|
||||||
|
rc = SMB2_set_info_init(tcon, &rqst[num_rqst],
|
||||||
|
COMPOUND_FID,
|
||||||
|
COMPOUND_FID, current->tgid,
|
||||||
|
FILE_BASIC_INFORMATION,
|
||||||
|
SMB2_O_INFO_FILE, 0, data, size);
|
||||||
|
if (!rc) {
|
||||||
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
||||||
|
smb2_set_related(&rqst[num_rqst]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
goto finished;
|
goto finished;
|
||||||
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
num_rqst++;
|
||||||
smb2_set_related(&rqst[num_rqst++]);
|
|
||||||
trace_smb3_set_info_compound_enter(xid, ses->Suid, tcon->tid,
|
trace_smb3_set_info_compound_enter(xid, ses->Suid, tcon->tid,
|
||||||
full_path);
|
full_path);
|
||||||
break;
|
break;
|
||||||
@ -210,14 +249,25 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
size[1] = len + 2 /* null */;
|
size[1] = len + 2 /* null */;
|
||||||
data[1] = (__le16 *)ptr;
|
data[1] = (__le16 *)ptr;
|
||||||
|
|
||||||
rc = SMB2_set_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
|
if (cfile)
|
||||||
COMPOUND_FID, current->tgid,
|
rc = SMB2_set_info_init(tcon, &rqst[num_rqst],
|
||||||
FILE_RENAME_INFORMATION,
|
cfile->fid.persistent_fid,
|
||||||
|
cfile->fid.volatile_fid,
|
||||||
|
current->tgid, FILE_RENAME_INFORMATION,
|
||||||
SMB2_O_INFO_FILE, 0, data, size);
|
SMB2_O_INFO_FILE, 0, data, size);
|
||||||
|
else {
|
||||||
|
rc = SMB2_set_info_init(tcon, &rqst[num_rqst],
|
||||||
|
COMPOUND_FID, COMPOUND_FID,
|
||||||
|
current->tgid, FILE_RENAME_INFORMATION,
|
||||||
|
SMB2_O_INFO_FILE, 0, data, size);
|
||||||
|
if (!rc) {
|
||||||
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
||||||
|
smb2_set_related(&rqst[num_rqst]);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (rc)
|
if (rc)
|
||||||
goto finished;
|
goto finished;
|
||||||
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
num_rqst++;
|
||||||
smb2_set_related(&rqst[num_rqst++]);
|
|
||||||
trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path);
|
trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path);
|
||||||
break;
|
break;
|
||||||
case SMB2_OP_HARDLINK:
|
case SMB2_OP_HARDLINK:
|
||||||
@ -254,21 +304,43 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
if (rc)
|
if (rc)
|
||||||
goto finished;
|
goto finished;
|
||||||
|
|
||||||
|
/* We already have a handle so we can skip the close */
|
||||||
|
if (cfile)
|
||||||
|
goto after_close;
|
||||||
/* Close */
|
/* Close */
|
||||||
memset(&close_iov, 0, sizeof(close_iov));
|
memset(&close_iov, 0, sizeof(close_iov));
|
||||||
rqst[num_rqst].rq_iov = close_iov;
|
rqst[num_rqst].rq_iov = close_iov;
|
||||||
rqst[num_rqst].rq_nvec = 1;
|
rqst[num_rqst].rq_nvec = 1;
|
||||||
rc = SMB2_close_init(tcon, &rqst[num_rqst], COMPOUND_FID,
|
rc = SMB2_close_init(tcon, &rqst[num_rqst], COMPOUND_FID,
|
||||||
COMPOUND_FID);
|
COMPOUND_FID);
|
||||||
smb2_set_related(&rqst[num_rqst++]);
|
smb2_set_related(&rqst[num_rqst]);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto finished;
|
goto finished;
|
||||||
|
after_close:
|
||||||
|
num_rqst++;
|
||||||
|
|
||||||
rc = compound_send_recv(xid, ses, flags, num_rqst, rqst,
|
if (cfile) {
|
||||||
resp_buftype, rsp_iov);
|
cifsFileInfo_put(cfile);
|
||||||
|
cfile = NULL;
|
||||||
|
rc = compound_send_recv(xid, ses, flags, num_rqst - 2,
|
||||||
|
&rqst[1], &resp_buftype[1],
|
||||||
|
&rsp_iov[1]);
|
||||||
|
} else
|
||||||
|
rc = compound_send_recv(xid, ses, flags, num_rqst,
|
||||||
|
rqst, resp_buftype,
|
||||||
|
rsp_iov);
|
||||||
|
|
||||||
finished:
|
finished:
|
||||||
|
if (cfile)
|
||||||
|
cifsFileInfo_put(cfile);
|
||||||
|
|
||||||
SMB2_open_free(&rqst[0]);
|
SMB2_open_free(&rqst[0]);
|
||||||
|
if (rc == -EREMCHG) {
|
||||||
|
printk_once(KERN_WARNING "server share %s deleted\n",
|
||||||
|
tcon->treeName);
|
||||||
|
tcon->need_reconnect = true;
|
||||||
|
}
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case SMB2_OP_QUERY_INFO:
|
case SMB2_OP_QUERY_INFO:
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
@ -371,6 +443,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
__u32 create_options = 0;
|
__u32 create_options = 0;
|
||||||
struct cifs_fid fid;
|
struct cifs_fid fid;
|
||||||
bool no_cached_open = tcon->nohandlecache;
|
bool no_cached_open = tcon->nohandlecache;
|
||||||
|
struct cifsFileInfo *cfile;
|
||||||
|
|
||||||
*adjust_tz = false;
|
*adjust_tz = false;
|
||||||
*symlink = false;
|
*symlink = false;
|
||||||
@ -402,9 +475,10 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
if (backup_cred(cifs_sb))
|
if (backup_cred(cifs_sb))
|
||||||
create_options |= CREATE_OPEN_BACKUP_INTENT;
|
create_options |= CREATE_OPEN_BACKUP_INTENT;
|
||||||
|
|
||||||
|
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||||
FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
|
FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
|
||||||
smb2_data, SMB2_OP_QUERY_INFO);
|
smb2_data, SMB2_OP_QUERY_INFO, cfile);
|
||||||
if (rc == -EOPNOTSUPP) {
|
if (rc == -EOPNOTSUPP) {
|
||||||
*symlink = true;
|
*symlink = true;
|
||||||
create_options |= OPEN_REPARSE_POINT;
|
create_options |= OPEN_REPARSE_POINT;
|
||||||
@ -413,7 +487,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||||
create_options, smb2_data,
|
create_options, smb2_data,
|
||||||
SMB2_OP_QUERY_INFO);
|
SMB2_OP_QUERY_INFO, NULL);
|
||||||
}
|
}
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out;
|
goto out;
|
||||||
@ -430,7 +504,7 @@ smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
|||||||
{
|
{
|
||||||
return smb2_compound_op(xid, tcon, cifs_sb, name,
|
return smb2_compound_op(xid, tcon, cifs_sb, name,
|
||||||
FILE_WRITE_ATTRIBUTES, FILE_CREATE,
|
FILE_WRITE_ATTRIBUTES, FILE_CREATE,
|
||||||
CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR);
|
CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -440,6 +514,7 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
|
|||||||
{
|
{
|
||||||
FILE_BASIC_INFO data;
|
FILE_BASIC_INFO data;
|
||||||
struct cifsInodeInfo *cifs_i;
|
struct cifsInodeInfo *cifs_i;
|
||||||
|
struct cifsFileInfo *cfile;
|
||||||
u32 dosattrs;
|
u32 dosattrs;
|
||||||
int tmprc;
|
int tmprc;
|
||||||
|
|
||||||
@ -447,9 +522,11 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
|
|||||||
cifs_i = CIFS_I(inode);
|
cifs_i = CIFS_I(inode);
|
||||||
dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
|
dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
|
||||||
data.Attributes = cpu_to_le32(dosattrs);
|
data.Attributes = cpu_to_le32(dosattrs);
|
||||||
|
cifs_get_writable_path(tcon, name, &cfile);
|
||||||
tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
|
tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
|
||||||
FILE_WRITE_ATTRIBUTES, FILE_CREATE,
|
FILE_WRITE_ATTRIBUTES, FILE_CREATE,
|
||||||
CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO);
|
CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO,
|
||||||
|
cfile);
|
||||||
if (tmprc == 0)
|
if (tmprc == 0)
|
||||||
cifs_i->cifsAttrs = dosattrs;
|
cifs_i->cifsAttrs = dosattrs;
|
||||||
}
|
}
|
||||||
@ -460,7 +537,7 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
|||||||
{
|
{
|
||||||
return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
|
return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
|
||||||
CREATE_NOT_FILE,
|
CREATE_NOT_FILE,
|
||||||
NULL, SMB2_OP_RMDIR);
|
NULL, SMB2_OP_RMDIR, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -469,13 +546,14 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
|||||||
{
|
{
|
||||||
return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
|
return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
|
||||||
CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
|
CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
|
||||||
NULL, SMB2_OP_DELETE);
|
NULL, SMB2_OP_DELETE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
const char *from_name, const char *to_name,
|
const char *from_name, const char *to_name,
|
||||||
struct cifs_sb_info *cifs_sb, __u32 access, int command)
|
struct cifs_sb_info *cifs_sb, __u32 access, int command,
|
||||||
|
struct cifsFileInfo *cfile)
|
||||||
{
|
{
|
||||||
__le16 *smb2_to_name = NULL;
|
__le16 *smb2_to_name = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
@ -486,7 +564,7 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
goto smb2_rename_path;
|
goto smb2_rename_path;
|
||||||
}
|
}
|
||||||
rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
|
rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
|
||||||
FILE_OPEN, 0, smb2_to_name, command);
|
FILE_OPEN, 0, smb2_to_name, command, cfile);
|
||||||
smb2_rename_path:
|
smb2_rename_path:
|
||||||
kfree(smb2_to_name);
|
kfree(smb2_to_name);
|
||||||
return rc;
|
return rc;
|
||||||
@ -497,8 +575,12 @@ smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
const char *from_name, const char *to_name,
|
const char *from_name, const char *to_name,
|
||||||
struct cifs_sb_info *cifs_sb)
|
struct cifs_sb_info *cifs_sb)
|
||||||
{
|
{
|
||||||
return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
|
struct cifsFileInfo *cfile;
|
||||||
DELETE, SMB2_OP_RENAME);
|
|
||||||
|
cifs_get_writable_path(tcon, from_name, &cfile);
|
||||||
|
|
||||||
|
return smb2_set_path_attr(xid, tcon, from_name, to_name,
|
||||||
|
cifs_sb, DELETE, SMB2_OP_RENAME, cfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -507,7 +589,8 @@ smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
struct cifs_sb_info *cifs_sb)
|
struct cifs_sb_info *cifs_sb)
|
||||||
{
|
{
|
||||||
return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
|
return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
|
||||||
FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK);
|
FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -519,7 +602,7 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
|
|
||||||
return smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
return smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||||
FILE_WRITE_DATA, FILE_OPEN, 0, &eof,
|
FILE_WRITE_DATA, FILE_OPEN, 0, &eof,
|
||||||
SMB2_OP_SET_EOF);
|
SMB2_OP_SET_EOF, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -541,7 +624,7 @@ smb2_set_file_info(struct inode *inode, const char *full_path,
|
|||||||
|
|
||||||
rc = smb2_compound_op(xid, tlink_tcon(tlink), cifs_sb, full_path,
|
rc = smb2_compound_op(xid, tlink_tcon(tlink), cifs_sb, full_path,
|
||||||
FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, buf,
|
FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, buf,
|
||||||
SMB2_OP_SET_INFO);
|
SMB2_OP_SET_INFO, NULL);
|
||||||
cifs_put_tlink(tlink);
|
cifs_put_tlink(tlink);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -511,7 +511,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
|
|||||||
{STATUS_PRINT_QUEUE_FULL, -EIO, "STATUS_PRINT_QUEUE_FULL"},
|
{STATUS_PRINT_QUEUE_FULL, -EIO, "STATUS_PRINT_QUEUE_FULL"},
|
||||||
{STATUS_NO_SPOOL_SPACE, -EIO, "STATUS_NO_SPOOL_SPACE"},
|
{STATUS_NO_SPOOL_SPACE, -EIO, "STATUS_NO_SPOOL_SPACE"},
|
||||||
{STATUS_PRINT_CANCELLED, -EIO, "STATUS_PRINT_CANCELLED"},
|
{STATUS_PRINT_CANCELLED, -EIO, "STATUS_PRINT_CANCELLED"},
|
||||||
{STATUS_NETWORK_NAME_DELETED, -EIO, "STATUS_NETWORK_NAME_DELETED"},
|
{STATUS_NETWORK_NAME_DELETED, -EREMCHG, "STATUS_NETWORK_NAME_DELETED"},
|
||||||
{STATUS_NETWORK_ACCESS_DENIED, -EACCES, "STATUS_NETWORK_ACCESS_DENIED"},
|
{STATUS_NETWORK_ACCESS_DENIED, -EACCES, "STATUS_NETWORK_ACCESS_DENIED"},
|
||||||
{STATUS_BAD_DEVICE_TYPE, -EIO, "STATUS_BAD_DEVICE_TYPE"},
|
{STATUS_BAD_DEVICE_TYPE, -EIO, "STATUS_BAD_DEVICE_TYPE"},
|
||||||
{STATUS_BAD_NETWORK_NAME, -ENOENT, "STATUS_BAD_NETWORK_NAME"},
|
{STATUS_BAD_NETWORK_NAME, -ENOENT, "STATUS_BAD_NETWORK_NAME"},
|
||||||
|
@ -109,10 +109,10 @@ smb2_add_credits(struct TCP_Server_Info *server,
|
|||||||
/* change_conf hasn't been executed */
|
/* change_conf hasn't been executed */
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
cifs_dbg(VFS, "Possible client or server bug - zero credits\n");
|
cifs_server_dbg(VFS, "Possible client or server bug - zero credits\n");
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
cifs_dbg(VFS, "disabling echoes and oplocks\n");
|
cifs_server_dbg(VFS, "disabling echoes and oplocks\n");
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
cifs_dbg(FYI, "disabling oplocks\n");
|
cifs_dbg(FYI, "disabling oplocks\n");
|
||||||
@ -203,6 +203,8 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
|
|||||||
credits->instance = server->reconnect_instance;
|
credits->instance = server->reconnect_instance;
|
||||||
server->credits -= credits->value;
|
server->credits -= credits->value;
|
||||||
server->in_flight++;
|
server->in_flight++;
|
||||||
|
if (server->in_flight > server->max_in_flight)
|
||||||
|
server->max_in_flight = server->in_flight;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,7 +232,7 @@ smb2_adjust_credits(struct TCP_Server_Info *server,
|
|||||||
|
|
||||||
if (server->reconnect_instance != credits->instance) {
|
if (server->reconnect_instance != credits->instance) {
|
||||||
spin_unlock(&server->req_lock);
|
spin_unlock(&server->req_lock);
|
||||||
cifs_dbg(VFS, "trying to return %d credits to old session\n",
|
cifs_server_dbg(VFS, "trying to return %d credits to old session\n",
|
||||||
credits->value - new_val);
|
credits->value - new_val);
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
@ -270,7 +272,7 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
|
|||||||
__u64 wire_mid = le64_to_cpu(shdr->MessageId);
|
__u64 wire_mid = le64_to_cpu(shdr->MessageId);
|
||||||
|
|
||||||
if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
|
if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
|
||||||
cifs_dbg(VFS, "Encrypted frame parsing not supported yet\n");
|
cifs_server_dbg(VFS, "Encrypted frame parsing not supported yet\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,10 +296,10 @@ smb2_dump_detail(void *buf, struct TCP_Server_Info *server)
|
|||||||
#ifdef CONFIG_CIFS_DEBUG2
|
#ifdef CONFIG_CIFS_DEBUG2
|
||||||
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
|
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
|
||||||
|
|
||||||
cifs_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d\n",
|
cifs_server_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d\n",
|
||||||
shdr->Command, shdr->Status, shdr->Flags, shdr->MessageId,
|
shdr->Command, shdr->Status, shdr->Flags, shdr->MessageId,
|
||||||
shdr->ProcessId);
|
shdr->ProcessId);
|
||||||
cifs_dbg(VFS, "smb buf %p len %u\n", buf,
|
cifs_server_dbg(VFS, "smb buf %p len %u\n", buf,
|
||||||
server->ops->calc_smb_size(buf, server));
|
server->ops->calc_smb_size(buf, server));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -576,7 +578,7 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
|
|||||||
"server does not support query network interfaces\n");
|
"server does not support query network interfaces\n");
|
||||||
goto out;
|
goto out;
|
||||||
} else if (rc != 0) {
|
} else if (rc != 0) {
|
||||||
cifs_dbg(VFS, "error %d on ioctl to get interface list\n", rc);
|
cifs_tcon_dbg(VFS, "error %d on ioctl to get interface list\n", rc);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -656,6 +658,15 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We do not hold the lock for the open because in case
|
||||||
|
* SMB2_open needs to reconnect, it will end up calling
|
||||||
|
* cifs_mark_open_files_invalid() which takes the lock again
|
||||||
|
* thus causing a deadlock
|
||||||
|
*/
|
||||||
|
|
||||||
|
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||||
|
|
||||||
if (smb3_encryption_required(tcon))
|
if (smb3_encryption_required(tcon))
|
||||||
flags |= CIFS_TRANSFORM_REQ;
|
flags |= CIFS_TRANSFORM_REQ;
|
||||||
|
|
||||||
@ -677,7 +688,7 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
|||||||
|
|
||||||
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, &utf16_path);
|
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, &utf16_path);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto oshr_exit;
|
goto oshr_free;
|
||||||
smb2_set_next_command(tcon, &rqst[0]);
|
smb2_set_next_command(tcon, &rqst[0]);
|
||||||
|
|
||||||
memset(&qi_iov, 0, sizeof(qi_iov));
|
memset(&qi_iov, 0, sizeof(qi_iov));
|
||||||
@ -690,18 +701,10 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
|||||||
sizeof(struct smb2_file_all_info) +
|
sizeof(struct smb2_file_all_info) +
|
||||||
PATH_MAX * 2, 0, NULL);
|
PATH_MAX * 2, 0, NULL);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto oshr_exit;
|
goto oshr_free;
|
||||||
|
|
||||||
smb2_set_related(&rqst[1]);
|
smb2_set_related(&rqst[1]);
|
||||||
|
|
||||||
/*
|
|
||||||
* We do not hold the lock for the open because in case
|
|
||||||
* SMB2_open needs to reconnect, it will end up calling
|
|
||||||
* cifs_mark_open_files_invalid() which takes the lock again
|
|
||||||
* thus causing a deadlock
|
|
||||||
*/
|
|
||||||
|
|
||||||
mutex_unlock(&tcon->crfid.fid_mutex);
|
|
||||||
rc = compound_send_recv(xid, ses, flags, 2, rqst,
|
rc = compound_send_recv(xid, ses, flags, 2, rqst,
|
||||||
resp_buftype, rsp_iov);
|
resp_buftype, rsp_iov);
|
||||||
mutex_lock(&tcon->crfid.fid_mutex);
|
mutex_lock(&tcon->crfid.fid_mutex);
|
||||||
@ -739,8 +742,14 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
|||||||
|
|
||||||
/* Cached root is still invalid, continue normaly */
|
/* Cached root is still invalid, continue normaly */
|
||||||
|
|
||||||
if (rc)
|
if (rc) {
|
||||||
|
if (rc == -EREMCHG) {
|
||||||
|
tcon->need_reconnect = true;
|
||||||
|
printk_once(KERN_WARNING "server share %s deleted\n",
|
||||||
|
tcon->treeName);
|
||||||
|
}
|
||||||
goto oshr_exit;
|
goto oshr_exit;
|
||||||
|
}
|
||||||
|
|
||||||
o_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base;
|
o_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base;
|
||||||
oparms.fid->persistent_fid = o_rsp->PersistentFileId;
|
oparms.fid->persistent_fid = o_rsp->PersistentFileId;
|
||||||
@ -1330,11 +1339,11 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
(char **)&res_key, &ret_data_len);
|
(char **)&res_key, &ret_data_len);
|
||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "refcpy ioctl error %d getting resume key\n", rc);
|
cifs_tcon_dbg(VFS, "refcpy ioctl error %d getting resume key\n", rc);
|
||||||
goto req_res_key_exit;
|
goto req_res_key_exit;
|
||||||
}
|
}
|
||||||
if (ret_data_len < sizeof(struct resume_key_req)) {
|
if (ret_data_len < sizeof(struct resume_key_req)) {
|
||||||
cifs_dbg(VFS, "Invalid refcopy resume key length\n");
|
cifs_tcon_dbg(VFS, "Invalid refcopy resume key length\n");
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
goto req_res_key_exit;
|
goto req_res_key_exit;
|
||||||
}
|
}
|
||||||
@ -1369,7 +1378,10 @@ smb2_ioctl_query_info(const unsigned int xid,
|
|||||||
struct cifs_fid fid;
|
struct cifs_fid fid;
|
||||||
struct kvec qi_iov[1];
|
struct kvec qi_iov[1];
|
||||||
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
|
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
|
||||||
|
struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
|
||||||
struct kvec close_iov[1];
|
struct kvec close_iov[1];
|
||||||
|
unsigned int size[2];
|
||||||
|
void *data[2];
|
||||||
|
|
||||||
memset(rqst, 0, sizeof(rqst));
|
memset(rqst, 0, sizeof(rqst));
|
||||||
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
||||||
@ -1404,7 +1416,6 @@ smb2_ioctl_query_info(const unsigned int xid,
|
|||||||
|
|
||||||
memset(&oparms, 0, sizeof(oparms));
|
memset(&oparms, 0, sizeof(oparms));
|
||||||
oparms.tcon = tcon;
|
oparms.tcon = tcon;
|
||||||
oparms.desired_access = FILE_READ_ATTRIBUTES | READ_CONTROL;
|
|
||||||
oparms.disposition = FILE_OPEN;
|
oparms.disposition = FILE_OPEN;
|
||||||
if (is_dir)
|
if (is_dir)
|
||||||
oparms.create_options = CREATE_NOT_FILE;
|
oparms.create_options = CREATE_NOT_FILE;
|
||||||
@ -1413,9 +1424,6 @@ smb2_ioctl_query_info(const unsigned int xid,
|
|||||||
oparms.fid = &fid;
|
oparms.fid = &fid;
|
||||||
oparms.reconnect = false;
|
oparms.reconnect = false;
|
||||||
|
|
||||||
/*
|
|
||||||
* FSCTL codes encode the special access they need in the fsctl code.
|
|
||||||
*/
|
|
||||||
if (qi.flags & PASSTHRU_FSCTL) {
|
if (qi.flags & PASSTHRU_FSCTL) {
|
||||||
switch (qi.info_type & FSCTL_DEVICE_ACCESS_MASK) {
|
switch (qi.info_type & FSCTL_DEVICE_ACCESS_MASK) {
|
||||||
case FSCTL_DEVICE_ACCESS_FILE_READ_WRITE_ACCESS:
|
case FSCTL_DEVICE_ACCESS_FILE_READ_WRITE_ACCESS:
|
||||||
@ -1431,6 +1439,10 @@ smb2_ioctl_query_info(const unsigned int xid,
|
|||||||
oparms.desired_access = GENERIC_WRITE;
|
oparms.desired_access = GENERIC_WRITE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else if (qi.flags & PASSTHRU_SET_INFO) {
|
||||||
|
oparms.desired_access = GENERIC_WRITE;
|
||||||
|
} else {
|
||||||
|
oparms.desired_access = FILE_READ_ATTRIBUTES | READ_CONTROL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path);
|
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path);
|
||||||
@ -1454,6 +1466,24 @@ smb2_ioctl_query_info(const unsigned int xid,
|
|||||||
qi.output_buffer_length,
|
qi.output_buffer_length,
|
||||||
CIFSMaxBufSize);
|
CIFSMaxBufSize);
|
||||||
}
|
}
|
||||||
|
} else if (qi.flags == PASSTHRU_SET_INFO) {
|
||||||
|
/* Can eventually relax perm check since server enforces too */
|
||||||
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
|
rc = -EPERM;
|
||||||
|
else {
|
||||||
|
memset(&si_iov, 0, sizeof(si_iov));
|
||||||
|
rqst[1].rq_iov = si_iov;
|
||||||
|
rqst[1].rq_nvec = 1;
|
||||||
|
|
||||||
|
size[0] = 8;
|
||||||
|
data[0] = buffer;
|
||||||
|
|
||||||
|
rc = SMB2_set_info_init(tcon, &rqst[1],
|
||||||
|
COMPOUND_FID, COMPOUND_FID,
|
||||||
|
current->tgid,
|
||||||
|
FILE_END_OF_FILE_INFORMATION,
|
||||||
|
SMB2_O_INFO_FILE, 0, data, size);
|
||||||
|
}
|
||||||
} else if (qi.flags == PASSTHRU_QUERY_INFO) {
|
} else if (qi.flags == PASSTHRU_QUERY_INFO) {
|
||||||
memset(&qi_iov, 0, sizeof(qi_iov));
|
memset(&qi_iov, 0, sizeof(qi_iov));
|
||||||
rqst[1].rq_iov = qi_iov;
|
rqst[1].rq_iov = qi_iov;
|
||||||
@ -1465,7 +1495,7 @@ smb2_ioctl_query_info(const unsigned int xid,
|
|||||||
qi.input_buffer_length,
|
qi.input_buffer_length,
|
||||||
qi.output_buffer_length, buffer);
|
qi.output_buffer_length, buffer);
|
||||||
} else { /* unknown flags */
|
} else { /* unknown flags */
|
||||||
cifs_dbg(VFS, "invalid passthru query flags: 0x%x\n", qi.flags);
|
cifs_tcon_dbg(VFS, "invalid passthru query flags: 0x%x\n", qi.flags);
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1592,7 +1622,7 @@ smb2_copychunk_range(const unsigned int xid,
|
|||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
if (ret_data_len !=
|
if (ret_data_len !=
|
||||||
sizeof(struct copychunk_ioctl_rsp)) {
|
sizeof(struct copychunk_ioctl_rsp)) {
|
||||||
cifs_dbg(VFS, "invalid cchunk response size\n");
|
cifs_tcon_dbg(VFS, "invalid cchunk response size\n");
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
goto cchunk_out;
|
goto cchunk_out;
|
||||||
}
|
}
|
||||||
@ -1606,12 +1636,12 @@ smb2_copychunk_range(const unsigned int xid,
|
|||||||
*/
|
*/
|
||||||
if (le32_to_cpu(retbuf->TotalBytesWritten) >
|
if (le32_to_cpu(retbuf->TotalBytesWritten) >
|
||||||
le32_to_cpu(pcchunk->Length)) {
|
le32_to_cpu(pcchunk->Length)) {
|
||||||
cifs_dbg(VFS, "invalid copy chunk response\n");
|
cifs_tcon_dbg(VFS, "invalid copy chunk response\n");
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
goto cchunk_out;
|
goto cchunk_out;
|
||||||
}
|
}
|
||||||
if (le32_to_cpu(retbuf->ChunksWritten) != 1) {
|
if (le32_to_cpu(retbuf->ChunksWritten) != 1) {
|
||||||
cifs_dbg(VFS, "invalid num chunks written\n");
|
cifs_tcon_dbg(VFS, "invalid num chunks written\n");
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
goto cchunk_out;
|
goto cchunk_out;
|
||||||
}
|
}
|
||||||
@ -2214,6 +2244,11 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
resp_buftype, rsp_iov);
|
resp_buftype, rsp_iov);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
||||||
|
if (rc == -EREMCHG) {
|
||||||
|
tcon->need_reconnect = true;
|
||||||
|
printk_once(KERN_WARNING "server share %s deleted\n",
|
||||||
|
tcon->treeName);
|
||||||
|
}
|
||||||
goto qic_exit;
|
goto qic_exit;
|
||||||
}
|
}
|
||||||
*rsp = rsp_iov[1];
|
*rsp = rsp_iov[1];
|
||||||
@ -2401,7 +2436,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
|
|||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
if ((rc != -ENOENT) && (rc != -EOPNOTSUPP))
|
if ((rc != -ENOENT) && (rc != -EOPNOTSUPP))
|
||||||
cifs_dbg(VFS, "ioctl error in %s rc=%d\n", __func__, rc);
|
cifs_tcon_dbg(VFS, "ioctl error in %s rc=%d\n", __func__, rc);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2410,7 +2445,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
|
|||||||
nls_codepage, remap, search_name,
|
nls_codepage, remap, search_name,
|
||||||
true /* is_unicode */);
|
true /* is_unicode */);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "parse error in %s rc=%d\n", __func__, rc);
|
cifs_tcon_dbg(VFS, "parse error in %s rc=%d\n", __func__, rc);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2640,7 +2675,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
|
|
||||||
if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) >
|
if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) >
|
||||||
rsp_iov[1].iov_len) {
|
rsp_iov[1].iov_len) {
|
||||||
cifs_dbg(VFS, "srv returned invalid ioctl len: %d\n",
|
cifs_tcon_dbg(VFS, "srv returned invalid ioctl len: %d\n",
|
||||||
plen);
|
plen);
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
goto querty_exit;
|
goto querty_exit;
|
||||||
@ -2939,7 +2974,6 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
|
|||||||
loff_t offset, loff_t len)
|
loff_t offset, loff_t len)
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct cifsInodeInfo *cifsi;
|
|
||||||
struct cifsFileInfo *cfile = file->private_data;
|
struct cifsFileInfo *cfile = file->private_data;
|
||||||
struct file_zero_data_information fsctl_buf;
|
struct file_zero_data_information fsctl_buf;
|
||||||
long rc;
|
long rc;
|
||||||
@ -2949,7 +2983,6 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
|
|||||||
xid = get_xid();
|
xid = get_xid();
|
||||||
|
|
||||||
inode = d_inode(cfile->dentry);
|
inode = d_inode(cfile->dentry);
|
||||||
cifsi = CIFS_I(inode);
|
|
||||||
|
|
||||||
/* Need to make file sparse, if not already, before freeing range. */
|
/* Need to make file sparse, if not already, before freeing range. */
|
||||||
/* Consider adding equivalent for compressed since it could also work */
|
/* Consider adding equivalent for compressed since it could also work */
|
||||||
@ -3595,14 +3628,14 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
|
|||||||
|
|
||||||
rc = smb2_get_enc_key(server, tr_hdr->SessionId, enc, key);
|
rc = smb2_get_enc_key(server, tr_hdr->SessionId, enc, key);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Could not get %scryption key\n", __func__,
|
cifs_server_dbg(VFS, "%s: Could not get %scryption key\n", __func__,
|
||||||
enc ? "en" : "de");
|
enc ? "en" : "de");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = smb3_crypto_aead_allocate(server);
|
rc = smb3_crypto_aead_allocate(server);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
|
cifs_server_dbg(VFS, "%s: crypto alloc failed\n", __func__);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3610,19 +3643,19 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
|
|||||||
server->secmech.ccmaesdecrypt;
|
server->secmech.ccmaesdecrypt;
|
||||||
rc = crypto_aead_setkey(tfm, key, SMB3_SIGN_KEY_SIZE);
|
rc = crypto_aead_setkey(tfm, key, SMB3_SIGN_KEY_SIZE);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc);
|
cifs_server_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE);
|
rc = crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc);
|
cifs_server_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
req = aead_request_alloc(tfm, GFP_KERNEL);
|
req = aead_request_alloc(tfm, GFP_KERNEL);
|
||||||
if (!req) {
|
if (!req) {
|
||||||
cifs_dbg(VFS, "%s: Failed to alloc aead request\n", __func__);
|
cifs_server_dbg(VFS, "%s: Failed to alloc aead request\n", __func__);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3633,7 +3666,7 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
|
|||||||
|
|
||||||
sg = init_sg(num_rqst, rqst, sign);
|
sg = init_sg(num_rqst, rqst, sign);
|
||||||
if (!sg) {
|
if (!sg) {
|
||||||
cifs_dbg(VFS, "%s: Failed to init sg\n", __func__);
|
cifs_server_dbg(VFS, "%s: Failed to init sg\n", __func__);
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto free_req;
|
goto free_req;
|
||||||
}
|
}
|
||||||
@ -3641,7 +3674,7 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
|
|||||||
iv_len = crypto_aead_ivsize(tfm);
|
iv_len = crypto_aead_ivsize(tfm);
|
||||||
iv = kzalloc(iv_len, GFP_KERNEL);
|
iv = kzalloc(iv_len, GFP_KERNEL);
|
||||||
if (!iv) {
|
if (!iv) {
|
||||||
cifs_dbg(VFS, "%s: Failed to alloc iv\n", __func__);
|
cifs_server_dbg(VFS, "%s: Failed to alloc iv\n", __func__);
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto free_sg;
|
goto free_sg;
|
||||||
}
|
}
|
||||||
@ -3883,7 +3916,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
|||||||
bool use_rdma_mr = false;
|
bool use_rdma_mr = false;
|
||||||
|
|
||||||
if (shdr->Command != SMB2_READ) {
|
if (shdr->Command != SMB2_READ) {
|
||||||
cifs_dbg(VFS, "only big read responses are supported\n");
|
cifs_server_dbg(VFS, "only big read responses are supported\n");
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3998,8 +4031,55 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
|||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct smb2_decrypt_work {
|
||||||
|
struct work_struct decrypt;
|
||||||
|
struct TCP_Server_Info *server;
|
||||||
|
struct page **ppages;
|
||||||
|
char *buf;
|
||||||
|
unsigned int npages;
|
||||||
|
unsigned int len;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void smb2_decrypt_offload(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct smb2_decrypt_work *dw = container_of(work,
|
||||||
|
struct smb2_decrypt_work, decrypt);
|
||||||
|
int i, rc;
|
||||||
|
struct mid_q_entry *mid;
|
||||||
|
|
||||||
|
rc = decrypt_raw_data(dw->server, dw->buf, dw->server->vals->read_rsp_size,
|
||||||
|
dw->ppages, dw->npages, dw->len);
|
||||||
|
if (rc) {
|
||||||
|
cifs_dbg(VFS, "error decrypting rc=%d\n", rc);
|
||||||
|
goto free_pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
dw->server->lstrp = jiffies;
|
||||||
|
mid = smb2_find_mid(dw->server, dw->buf);
|
||||||
|
if (mid == NULL)
|
||||||
|
cifs_dbg(FYI, "mid not found\n");
|
||||||
|
else {
|
||||||
|
mid->decrypted = true;
|
||||||
|
rc = handle_read_data(dw->server, mid, dw->buf,
|
||||||
|
dw->server->vals->read_rsp_size,
|
||||||
|
dw->ppages, dw->npages, dw->len);
|
||||||
|
mid->callback(mid);
|
||||||
|
cifs_mid_q_entry_release(mid);
|
||||||
|
}
|
||||||
|
|
||||||
|
free_pages:
|
||||||
|
for (i = dw->npages-1; i >= 0; i--)
|
||||||
|
put_page(dw->ppages[i]);
|
||||||
|
|
||||||
|
kfree(dw->ppages);
|
||||||
|
cifs_small_buf_release(dw->buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
|
receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid,
|
||||||
|
int *num_mids)
|
||||||
{
|
{
|
||||||
char *buf = server->smallbuf;
|
char *buf = server->smallbuf;
|
||||||
struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
|
struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
|
||||||
@ -4009,7 +4089,9 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
|
|||||||
unsigned int buflen = server->pdu_size;
|
unsigned int buflen = server->pdu_size;
|
||||||
int rc;
|
int rc;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
struct smb2_decrypt_work *dw;
|
||||||
|
|
||||||
|
*num_mids = 1;
|
||||||
len = min_t(unsigned int, buflen, server->vals->read_rsp_size +
|
len = min_t(unsigned int, buflen, server->vals->read_rsp_size +
|
||||||
sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1;
|
sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1;
|
||||||
|
|
||||||
@ -4045,6 +4127,32 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
|
|||||||
if (rc)
|
if (rc)
|
||||||
goto free_pages;
|
goto free_pages;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For large reads, offload to different thread for better performance,
|
||||||
|
* use more cores decrypting which can be expensive
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((server->min_offload) && (server->in_flight > 1) &&
|
||||||
|
(server->pdu_size >= server->min_offload)) {
|
||||||
|
dw = kmalloc(sizeof(struct smb2_decrypt_work), GFP_KERNEL);
|
||||||
|
if (dw == NULL)
|
||||||
|
goto non_offloaded_decrypt;
|
||||||
|
|
||||||
|
dw->buf = server->smallbuf;
|
||||||
|
server->smallbuf = (char *)cifs_small_buf_get();
|
||||||
|
|
||||||
|
INIT_WORK(&dw->decrypt, smb2_decrypt_offload);
|
||||||
|
|
||||||
|
dw->npages = npages;
|
||||||
|
dw->server = server;
|
||||||
|
dw->ppages = pages;
|
||||||
|
dw->len = len;
|
||||||
|
queue_work(cifsiod_wq, &dw->decrypt);
|
||||||
|
*num_mids = 0; /* worker thread takes care of finding mid */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
non_offloaded_decrypt:
|
||||||
rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size,
|
rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size,
|
||||||
pages, npages, len);
|
pages, npages, len);
|
||||||
if (rc)
|
if (rc)
|
||||||
@ -4129,7 +4237,7 @@ one_more:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (*num_mids >= MAX_COMPOUND) {
|
if (*num_mids >= MAX_COMPOUND) {
|
||||||
cifs_dbg(VFS, "too many PDUs in compound\n");
|
cifs_server_dbg(VFS, "too many PDUs in compound\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
bufs[*num_mids] = buf;
|
bufs[*num_mids] = buf;
|
||||||
@ -4175,7 +4283,7 @@ smb3_receive_transform(struct TCP_Server_Info *server,
|
|||||||
|
|
||||||
if (pdu_length < sizeof(struct smb2_transform_hdr) +
|
if (pdu_length < sizeof(struct smb2_transform_hdr) +
|
||||||
sizeof(struct smb2_sync_hdr)) {
|
sizeof(struct smb2_sync_hdr)) {
|
||||||
cifs_dbg(VFS, "Transform message is too small (%u)\n",
|
cifs_server_dbg(VFS, "Transform message is too small (%u)\n",
|
||||||
pdu_length);
|
pdu_length);
|
||||||
cifs_reconnect(server);
|
cifs_reconnect(server);
|
||||||
wake_up(&server->response_q);
|
wake_up(&server->response_q);
|
||||||
@ -4183,7 +4291,7 @@ smb3_receive_transform(struct TCP_Server_Info *server,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pdu_length < orig_len + sizeof(struct smb2_transform_hdr)) {
|
if (pdu_length < orig_len + sizeof(struct smb2_transform_hdr)) {
|
||||||
cifs_dbg(VFS, "Transform message is broken\n");
|
cifs_server_dbg(VFS, "Transform message is broken\n");
|
||||||
cifs_reconnect(server);
|
cifs_reconnect(server);
|
||||||
wake_up(&server->response_q);
|
wake_up(&server->response_q);
|
||||||
return -ECONNABORTED;
|
return -ECONNABORTED;
|
||||||
@ -4191,8 +4299,7 @@ smb3_receive_transform(struct TCP_Server_Info *server,
|
|||||||
|
|
||||||
/* TODO: add support for compounds containing READ. */
|
/* TODO: add support for compounds containing READ. */
|
||||||
if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) {
|
if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) {
|
||||||
*num_mids = 1;
|
return receive_encrypted_read(server, &mids[0], num_mids);
|
||||||
return receive_encrypted_read(server, &mids[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return receive_encrypted_standard(server, mids, bufs, num_mids);
|
return receive_encrypted_standard(server, mids, bufs, num_mids);
|
||||||
|
@ -503,8 +503,7 @@ build_netname_ctxt(struct smb2_netname_neg_context *pneg_ctxt, char *hostname)
|
|||||||
pneg_ctxt->ContextType = SMB2_NETNAME_NEGOTIATE_CONTEXT_ID;
|
pneg_ctxt->ContextType = SMB2_NETNAME_NEGOTIATE_CONTEXT_ID;
|
||||||
|
|
||||||
/* copy up to max of first 100 bytes of server name to NetName field */
|
/* copy up to max of first 100 bytes of server name to NetName field */
|
||||||
pneg_ctxt->DataLength = cpu_to_le16(2 +
|
pneg_ctxt->DataLength = cpu_to_le16(2 * cifs_strtoUTF16(pneg_ctxt->NetName, hostname, 100, cp));
|
||||||
(2 * cifs_strtoUTF16(pneg_ctxt->NetName, hostname, 100, cp)));
|
|
||||||
/* context size is DataLength + minimal smb2_neg_context */
|
/* context size is DataLength + minimal smb2_neg_context */
|
||||||
return DIV_ROUND_UP(le16_to_cpu(pneg_ctxt->DataLength) +
|
return DIV_ROUND_UP(le16_to_cpu(pneg_ctxt->DataLength) +
|
||||||
sizeof(struct smb2_neg_context), 8) * 8;
|
sizeof(struct smb2_neg_context), 8) * 8;
|
||||||
@ -543,7 +542,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
|
|||||||
|
|
||||||
if (*total_len > 200) {
|
if (*total_len > 200) {
|
||||||
/* In case length corrupted don't want to overrun smb buffer */
|
/* In case length corrupted don't want to overrun smb buffer */
|
||||||
cifs_dbg(VFS, "Bad frame length assembling neg contexts\n");
|
cifs_server_dbg(VFS, "Bad frame length assembling neg contexts\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -661,7 +660,7 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
|
|||||||
|
|
||||||
cifs_dbg(FYI, "decoding %d negotiate contexts\n", ctxt_cnt);
|
cifs_dbg(FYI, "decoding %d negotiate contexts\n", ctxt_cnt);
|
||||||
if (len_of_smb <= offset) {
|
if (len_of_smb <= offset) {
|
||||||
cifs_dbg(VFS, "Invalid response: negotiate context offset\n");
|
cifs_server_dbg(VFS, "Invalid response: negotiate context offset\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -693,7 +692,7 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
|
|||||||
else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE)
|
else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE)
|
||||||
server->posix_ext_supported = true;
|
server->posix_ext_supported = true;
|
||||||
else
|
else
|
||||||
cifs_dbg(VFS, "unknown negcontext of type %d ignored\n",
|
cifs_server_dbg(VFS, "unknown negcontext of type %d ignored\n",
|
||||||
le16_to_cpu(pctx->ContextType));
|
le16_to_cpu(pctx->ContextType));
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
@ -818,7 +817,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||||||
req->Dialects[1] = cpu_to_le16(SMB302_PROT_ID);
|
req->Dialects[1] = cpu_to_le16(SMB302_PROT_ID);
|
||||||
req->DialectCount = cpu_to_le16(2);
|
req->DialectCount = cpu_to_le16(2);
|
||||||
total_len += 4;
|
total_len += 4;
|
||||||
} else if (strcmp(ses->server->vals->version_string,
|
} else if (strcmp(server->vals->version_string,
|
||||||
SMBDEFAULT_VERSION_STRING) == 0) {
|
SMBDEFAULT_VERSION_STRING) == 0) {
|
||||||
req->Dialects[0] = cpu_to_le16(SMB21_PROT_ID);
|
req->Dialects[0] = cpu_to_le16(SMB21_PROT_ID);
|
||||||
req->Dialects[1] = cpu_to_le16(SMB30_PROT_ID);
|
req->Dialects[1] = cpu_to_le16(SMB30_PROT_ID);
|
||||||
@ -841,16 +840,16 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||||||
else
|
else
|
||||||
req->SecurityMode = 0;
|
req->SecurityMode = 0;
|
||||||
|
|
||||||
req->Capabilities = cpu_to_le32(ses->server->vals->req_capabilities);
|
req->Capabilities = cpu_to_le32(server->vals->req_capabilities);
|
||||||
|
|
||||||
/* ClientGUID must be zero for SMB2.02 dialect */
|
/* ClientGUID must be zero for SMB2.02 dialect */
|
||||||
if (ses->server->vals->protocol_id == SMB20_PROT_ID)
|
if (server->vals->protocol_id == SMB20_PROT_ID)
|
||||||
memset(req->ClientGUID, 0, SMB2_CLIENT_GUID_SIZE);
|
memset(req->ClientGUID, 0, SMB2_CLIENT_GUID_SIZE);
|
||||||
else {
|
else {
|
||||||
memcpy(req->ClientGUID, server->client_guid,
|
memcpy(req->ClientGUID, server->client_guid,
|
||||||
SMB2_CLIENT_GUID_SIZE);
|
SMB2_CLIENT_GUID_SIZE);
|
||||||
if ((ses->server->vals->protocol_id == SMB311_PROT_ID) ||
|
if ((server->vals->protocol_id == SMB311_PROT_ID) ||
|
||||||
(strcmp(ses->server->vals->version_string,
|
(strcmp(server->vals->version_string,
|
||||||
SMBDEFAULT_VERSION_STRING) == 0))
|
SMBDEFAULT_VERSION_STRING) == 0))
|
||||||
assemble_neg_contexts(req, server, &total_len);
|
assemble_neg_contexts(req, server, &total_len);
|
||||||
}
|
}
|
||||||
@ -869,42 +868,42 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||||||
* cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
|
* cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
|
||||||
*/
|
*/
|
||||||
if (rc == -EOPNOTSUPP) {
|
if (rc == -EOPNOTSUPP) {
|
||||||
cifs_dbg(VFS, "Dialect not supported by server. Consider "
|
cifs_server_dbg(VFS, "Dialect not supported by server. Consider "
|
||||||
"specifying vers=1.0 or vers=2.0 on mount for accessing"
|
"specifying vers=1.0 or vers=2.0 on mount for accessing"
|
||||||
" older servers\n");
|
" older servers\n");
|
||||||
goto neg_exit;
|
goto neg_exit;
|
||||||
} else if (rc != 0)
|
} else if (rc != 0)
|
||||||
goto neg_exit;
|
goto neg_exit;
|
||||||
|
|
||||||
if (strcmp(ses->server->vals->version_string,
|
if (strcmp(server->vals->version_string,
|
||||||
SMB3ANY_VERSION_STRING) == 0) {
|
SMB3ANY_VERSION_STRING) == 0) {
|
||||||
if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) {
|
if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) {
|
||||||
cifs_dbg(VFS,
|
cifs_server_dbg(VFS,
|
||||||
"SMB2 dialect returned but not requested\n");
|
"SMB2 dialect returned but not requested\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
} else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) {
|
} else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) {
|
||||||
cifs_dbg(VFS,
|
cifs_server_dbg(VFS,
|
||||||
"SMB2.1 dialect returned but not requested\n");
|
"SMB2.1 dialect returned but not requested\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
} else if (strcmp(ses->server->vals->version_string,
|
} else if (strcmp(server->vals->version_string,
|
||||||
SMBDEFAULT_VERSION_STRING) == 0) {
|
SMBDEFAULT_VERSION_STRING) == 0) {
|
||||||
if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) {
|
if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) {
|
||||||
cifs_dbg(VFS,
|
cifs_server_dbg(VFS,
|
||||||
"SMB2 dialect returned but not requested\n");
|
"SMB2 dialect returned but not requested\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
} else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) {
|
} else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) {
|
||||||
/* ops set to 3.0 by default for default so update */
|
/* ops set to 3.0 by default for default so update */
|
||||||
ses->server->ops = &smb21_operations;
|
server->ops = &smb21_operations;
|
||||||
ses->server->vals = &smb21_values;
|
server->vals = &smb21_values;
|
||||||
} else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
|
} else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
|
||||||
ses->server->ops = &smb311_operations;
|
server->ops = &smb311_operations;
|
||||||
ses->server->vals = &smb311_values;
|
server->vals = &smb311_values;
|
||||||
}
|
}
|
||||||
} else if (le16_to_cpu(rsp->DialectRevision) !=
|
} else if (le16_to_cpu(rsp->DialectRevision) !=
|
||||||
ses->server->vals->protocol_id) {
|
server->vals->protocol_id) {
|
||||||
/* if requested single dialect ensure returned dialect matched */
|
/* if requested single dialect ensure returned dialect matched */
|
||||||
cifs_dbg(VFS, "Illegal 0x%x dialect returned: not requested\n",
|
cifs_server_dbg(VFS, "Illegal 0x%x dialect returned: not requested\n",
|
||||||
le16_to_cpu(rsp->DialectRevision));
|
le16_to_cpu(rsp->DialectRevision));
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
@ -922,7 +921,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||||||
else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID))
|
else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID))
|
||||||
cifs_dbg(FYI, "negotiated smb3.1.1 dialect\n");
|
cifs_dbg(FYI, "negotiated smb3.1.1 dialect\n");
|
||||||
else {
|
else {
|
||||||
cifs_dbg(VFS, "Illegal dialect returned by server 0x%x\n",
|
cifs_server_dbg(VFS, "Illegal dialect returned by server 0x%x\n",
|
||||||
le16_to_cpu(rsp->DialectRevision));
|
le16_to_cpu(rsp->DialectRevision));
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
goto neg_exit;
|
goto neg_exit;
|
||||||
@ -982,7 +981,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||||||
rc = smb311_decode_neg_context(rsp, server,
|
rc = smb311_decode_neg_context(rsp, server,
|
||||||
rsp_iov.iov_len);
|
rsp_iov.iov_len);
|
||||||
else
|
else
|
||||||
cifs_dbg(VFS, "Missing expected negotiate contexts\n");
|
cifs_server_dbg(VFS, "Missing expected negotiate contexts\n");
|
||||||
}
|
}
|
||||||
neg_exit:
|
neg_exit:
|
||||||
free_rsp_buf(resp_buftype, rsp);
|
free_rsp_buf(resp_buftype, rsp);
|
||||||
@ -996,11 +995,12 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
|
|||||||
struct validate_negotiate_info_rsp *pneg_rsp = NULL;
|
struct validate_negotiate_info_rsp *pneg_rsp = NULL;
|
||||||
u32 rsplen;
|
u32 rsplen;
|
||||||
u32 inbuflen; /* max of 4 dialects */
|
u32 inbuflen; /* max of 4 dialects */
|
||||||
|
struct TCP_Server_Info *server = tcon->ses->server;
|
||||||
|
|
||||||
cifs_dbg(FYI, "validate negotiate\n");
|
cifs_dbg(FYI, "validate negotiate\n");
|
||||||
|
|
||||||
/* In SMB3.11 preauth integrity supersedes validate negotiate */
|
/* In SMB3.11 preauth integrity supersedes validate negotiate */
|
||||||
if (tcon->ses->server->dialect == SMB311_PROT_ID)
|
if (server->dialect == SMB311_PROT_ID)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1019,15 +1019,15 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_NULL)
|
if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_NULL)
|
||||||
cifs_dbg(VFS, "Unexpected null user (anonymous) auth flag sent by server\n");
|
cifs_tcon_dbg(VFS, "Unexpected null user (anonymous) auth flag sent by server\n");
|
||||||
|
|
||||||
pneg_inbuf = kmalloc(sizeof(*pneg_inbuf), GFP_NOFS);
|
pneg_inbuf = kmalloc(sizeof(*pneg_inbuf), GFP_NOFS);
|
||||||
if (!pneg_inbuf)
|
if (!pneg_inbuf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
pneg_inbuf->Capabilities =
|
pneg_inbuf->Capabilities =
|
||||||
cpu_to_le32(tcon->ses->server->vals->req_capabilities);
|
cpu_to_le32(server->vals->req_capabilities);
|
||||||
memcpy(pneg_inbuf->Guid, tcon->ses->server->client_guid,
|
memcpy(pneg_inbuf->Guid, server->client_guid,
|
||||||
SMB2_CLIENT_GUID_SIZE);
|
SMB2_CLIENT_GUID_SIZE);
|
||||||
|
|
||||||
if (tcon->ses->sign)
|
if (tcon->ses->sign)
|
||||||
@ -1040,7 +1040,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
|
|||||||
pneg_inbuf->SecurityMode = 0;
|
pneg_inbuf->SecurityMode = 0;
|
||||||
|
|
||||||
|
|
||||||
if (strcmp(tcon->ses->server->vals->version_string,
|
if (strcmp(server->vals->version_string,
|
||||||
SMB3ANY_VERSION_STRING) == 0) {
|
SMB3ANY_VERSION_STRING) == 0) {
|
||||||
pneg_inbuf->Dialects[0] = cpu_to_le16(SMB30_PROT_ID);
|
pneg_inbuf->Dialects[0] = cpu_to_le16(SMB30_PROT_ID);
|
||||||
pneg_inbuf->Dialects[1] = cpu_to_le16(SMB302_PROT_ID);
|
pneg_inbuf->Dialects[1] = cpu_to_le16(SMB302_PROT_ID);
|
||||||
@ -1048,7 +1048,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
|
|||||||
/* structure is big enough for 3 dialects, sending only 2 */
|
/* structure is big enough for 3 dialects, sending only 2 */
|
||||||
inbuflen = sizeof(*pneg_inbuf) -
|
inbuflen = sizeof(*pneg_inbuf) -
|
||||||
(2 * sizeof(pneg_inbuf->Dialects[0]));
|
(2 * sizeof(pneg_inbuf->Dialects[0]));
|
||||||
} else if (strcmp(tcon->ses->server->vals->version_string,
|
} else if (strcmp(server->vals->version_string,
|
||||||
SMBDEFAULT_VERSION_STRING) == 0) {
|
SMBDEFAULT_VERSION_STRING) == 0) {
|
||||||
pneg_inbuf->Dialects[0] = cpu_to_le16(SMB21_PROT_ID);
|
pneg_inbuf->Dialects[0] = cpu_to_le16(SMB21_PROT_ID);
|
||||||
pneg_inbuf->Dialects[1] = cpu_to_le16(SMB30_PROT_ID);
|
pneg_inbuf->Dialects[1] = cpu_to_le16(SMB30_PROT_ID);
|
||||||
@ -1060,7 +1060,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
|
|||||||
} else {
|
} else {
|
||||||
/* otherwise specific dialect was requested */
|
/* otherwise specific dialect was requested */
|
||||||
pneg_inbuf->Dialects[0] =
|
pneg_inbuf->Dialects[0] =
|
||||||
cpu_to_le16(tcon->ses->server->vals->protocol_id);
|
cpu_to_le16(server->vals->protocol_id);
|
||||||
pneg_inbuf->DialectCount = cpu_to_le16(1);
|
pneg_inbuf->DialectCount = cpu_to_le16(1);
|
||||||
/* structure is big enough for 3 dialects, sending only 1 */
|
/* structure is big enough for 3 dialects, sending only 1 */
|
||||||
inbuflen = sizeof(*pneg_inbuf) -
|
inbuflen = sizeof(*pneg_inbuf) -
|
||||||
@ -1076,18 +1076,18 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
|
|||||||
* Old Windows versions or Netapp SMB server can return
|
* Old Windows versions or Netapp SMB server can return
|
||||||
* not supported error. Client should accept it.
|
* not supported error. Client should accept it.
|
||||||
*/
|
*/
|
||||||
cifs_dbg(VFS, "Server does not support validate negotiate\n");
|
cifs_tcon_dbg(VFS, "Server does not support validate negotiate\n");
|
||||||
rc = 0;
|
rc = 0;
|
||||||
goto out_free_inbuf;
|
goto out_free_inbuf;
|
||||||
} else if (rc != 0) {
|
} else if (rc != 0) {
|
||||||
cifs_dbg(VFS, "validate protocol negotiate failed: %d\n", rc);
|
cifs_tcon_dbg(VFS, "validate protocol negotiate failed: %d\n", rc);
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
goto out_free_inbuf;
|
goto out_free_inbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
if (rsplen != sizeof(*pneg_rsp)) {
|
if (rsplen != sizeof(*pneg_rsp)) {
|
||||||
cifs_dbg(VFS, "invalid protocol negotiate response size: %d\n",
|
cifs_tcon_dbg(VFS, "invalid protocol negotiate response size: %d\n",
|
||||||
rsplen);
|
rsplen);
|
||||||
|
|
||||||
/* relax check since Mac returns max bufsize allowed on ioctl */
|
/* relax check since Mac returns max bufsize allowed on ioctl */
|
||||||
@ -1096,16 +1096,16 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check validate negotiate info response matches what we got earlier */
|
/* check validate negotiate info response matches what we got earlier */
|
||||||
if (pneg_rsp->Dialect != cpu_to_le16(tcon->ses->server->dialect))
|
if (pneg_rsp->Dialect != cpu_to_le16(server->dialect))
|
||||||
goto vneg_out;
|
goto vneg_out;
|
||||||
|
|
||||||
if (pneg_rsp->SecurityMode != cpu_to_le16(tcon->ses->server->sec_mode))
|
if (pneg_rsp->SecurityMode != cpu_to_le16(server->sec_mode))
|
||||||
goto vneg_out;
|
goto vneg_out;
|
||||||
|
|
||||||
/* do not validate server guid because not saved at negprot time yet */
|
/* do not validate server guid because not saved at negprot time yet */
|
||||||
|
|
||||||
if ((le32_to_cpu(pneg_rsp->Capabilities) | SMB2_NT_FIND |
|
if ((le32_to_cpu(pneg_rsp->Capabilities) | SMB2_NT_FIND |
|
||||||
SMB2_LARGE_FILES) != tcon->ses->server->capabilities)
|
SMB2_LARGE_FILES) != server->capabilities)
|
||||||
goto vneg_out;
|
goto vneg_out;
|
||||||
|
|
||||||
/* validate negotiate successful */
|
/* validate negotiate successful */
|
||||||
@ -1114,7 +1114,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
|
|||||||
goto out_free_rsp;
|
goto out_free_rsp;
|
||||||
|
|
||||||
vneg_out:
|
vneg_out:
|
||||||
cifs_dbg(VFS, "protocol revalidation - security settings mismatch\n");
|
cifs_tcon_dbg(VFS, "protocol revalidation - security settings mismatch\n");
|
||||||
out_free_rsp:
|
out_free_rsp:
|
||||||
kfree(pneg_rsp);
|
kfree(pneg_rsp);
|
||||||
out_free_inbuf:
|
out_free_inbuf:
|
||||||
@ -1568,7 +1568,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
|
|||||||
sess_data->func(sess_data);
|
sess_data->func(sess_data);
|
||||||
|
|
||||||
if ((ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST) && (ses->sign))
|
if ((ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST) && (ses->sign))
|
||||||
cifs_dbg(VFS, "signing requested but authenticated as guest\n");
|
cifs_server_dbg(VFS, "signing requested but authenticated as guest\n");
|
||||||
rc = sess_data->result;
|
rc = sess_data->result;
|
||||||
out:
|
out:
|
||||||
kfree(sess_data);
|
kfree(sess_data);
|
||||||
@ -1661,10 +1661,11 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
|
|||||||
__le16 *unc_path = NULL;
|
__le16 *unc_path = NULL;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
unsigned int total_len;
|
unsigned int total_len;
|
||||||
|
struct TCP_Server_Info *server = ses->server;
|
||||||
|
|
||||||
cifs_dbg(FYI, "TCON\n");
|
cifs_dbg(FYI, "TCON\n");
|
||||||
|
|
||||||
if (!(ses->server) || !tree)
|
if (!server || !tree)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL);
|
unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL);
|
||||||
@ -1707,7 +1708,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
|
|||||||
* unless it is guest or anonymous user. See MS-SMB2 3.2.5.3.1
|
* unless it is guest or anonymous user. See MS-SMB2 3.2.5.3.1
|
||||||
* (Samba servers don't always set the flag so also check if null user)
|
* (Samba servers don't always set the flag so also check if null user)
|
||||||
*/
|
*/
|
||||||
if ((ses->server->dialect == SMB311_PROT_ID) &&
|
if ((server->dialect == SMB311_PROT_ID) &&
|
||||||
!smb3_encryption_required(tcon) &&
|
!smb3_encryption_required(tcon) &&
|
||||||
!(ses->session_flags &
|
!(ses->session_flags &
|
||||||
(SMB2_SESSION_FLAG_IS_GUEST|SMB2_SESSION_FLAG_IS_NULL)) &&
|
(SMB2_SESSION_FLAG_IS_GUEST|SMB2_SESSION_FLAG_IS_NULL)) &&
|
||||||
@ -1746,7 +1747,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
|
|||||||
cifs_dbg(FYI, "connection to printer\n");
|
cifs_dbg(FYI, "connection to printer\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cifs_dbg(VFS, "unknown share type %d\n", rsp->ShareType);
|
cifs_server_dbg(VFS, "unknown share type %d\n", rsp->ShareType);
|
||||||
rc = -EOPNOTSUPP;
|
rc = -EOPNOTSUPP;
|
||||||
goto tcon_error_exit;
|
goto tcon_error_exit;
|
||||||
}
|
}
|
||||||
@ -1761,15 +1762,15 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
|
|||||||
|
|
||||||
if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) &&
|
if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) &&
|
||||||
((tcon->share_flags & SHI1005_FLAGS_DFS) == 0))
|
((tcon->share_flags & SHI1005_FLAGS_DFS) == 0))
|
||||||
cifs_dbg(VFS, "DFS capability contradicts DFS flag\n");
|
cifs_tcon_dbg(VFS, "DFS capability contradicts DFS flag\n");
|
||||||
|
|
||||||
if (tcon->seal &&
|
if (tcon->seal &&
|
||||||
!(tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION))
|
!(server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION))
|
||||||
cifs_dbg(VFS, "Encryption is requested but not supported\n");
|
cifs_tcon_dbg(VFS, "Encryption is requested but not supported\n");
|
||||||
|
|
||||||
init_copy_chunk_defaults(tcon);
|
init_copy_chunk_defaults(tcon);
|
||||||
if (tcon->ses->server->ops->validate_negotiate)
|
if (server->ops->validate_negotiate)
|
||||||
rc = tcon->ses->server->ops->validate_negotiate(xid, tcon);
|
rc = server->ops->validate_negotiate(xid, tcon);
|
||||||
tcon_exit:
|
tcon_exit:
|
||||||
|
|
||||||
free_rsp_buf(resp_buftype, rsp);
|
free_rsp_buf(resp_buftype, rsp);
|
||||||
@ -1778,7 +1779,7 @@ tcon_exit:
|
|||||||
|
|
||||||
tcon_error_exit:
|
tcon_error_exit:
|
||||||
if (rsp && rsp->sync_hdr.Status == STATUS_BAD_NETWORK_NAME) {
|
if (rsp && rsp->sync_hdr.Status == STATUS_BAD_NETWORK_NAME) {
|
||||||
cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
|
cifs_tcon_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
|
||||||
}
|
}
|
||||||
goto tcon_exit;
|
goto tcon_exit;
|
||||||
}
|
}
|
||||||
@ -2458,7 +2459,7 @@ SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock,
|
|||||||
iov[1].iov_len = uni_path_len;
|
iov[1].iov_len = uni_path_len;
|
||||||
iov[1].iov_base = path;
|
iov[1].iov_base = path;
|
||||||
|
|
||||||
if (!server->oplocks)
|
if ((!server->oplocks) || (tcon->no_lease))
|
||||||
*oplock = SMB2_OPLOCK_LEVEL_NONE;
|
*oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||||
|
|
||||||
if (!(server->capabilities & SMB2_GLOBAL_CAP_LEASING) ||
|
if (!(server->capabilities & SMB2_GLOBAL_CAP_LEASING) ||
|
||||||
@ -2594,6 +2595,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
|||||||
}
|
}
|
||||||
trace_smb3_open_err(xid, tcon->tid, ses->Suid,
|
trace_smb3_open_err(xid, tcon->tid, ses->Suid,
|
||||||
oparms->create_options, oparms->desired_access, rc);
|
oparms->create_options, oparms->desired_access, rc);
|
||||||
|
if (rc == -EREMCHG) {
|
||||||
|
printk_once(KERN_WARNING "server share %s deleted\n",
|
||||||
|
tcon->treeName);
|
||||||
|
tcon->need_reconnect = true;
|
||||||
|
}
|
||||||
goto creat_exit;
|
goto creat_exit;
|
||||||
} else
|
} else
|
||||||
trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid,
|
trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid,
|
||||||
@ -2742,6 +2748,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
|||||||
int resp_buftype = CIFS_NO_BUFFER;
|
int resp_buftype = CIFS_NO_BUFFER;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
struct TCP_Server_Info *server;
|
||||||
|
|
||||||
cifs_dbg(FYI, "SMB2 IOCTL\n");
|
cifs_dbg(FYI, "SMB2 IOCTL\n");
|
||||||
|
|
||||||
@ -2757,7 +2764,10 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
|||||||
else
|
else
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (!ses || !(ses->server))
|
if (!ses)
|
||||||
|
return -EIO;
|
||||||
|
server = ses->server;
|
||||||
|
if (!server)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (smb3_encryption_required(tcon))
|
if (smb3_encryption_required(tcon))
|
||||||
@ -2807,14 +2817,14 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
|||||||
if (*plen == 0)
|
if (*plen == 0)
|
||||||
goto ioctl_exit; /* server returned no data */
|
goto ioctl_exit; /* server returned no data */
|
||||||
else if (*plen > rsp_iov.iov_len || *plen > 0xFF00) {
|
else if (*plen > rsp_iov.iov_len || *plen > 0xFF00) {
|
||||||
cifs_dbg(VFS, "srv returned invalid ioctl length: %d\n", *plen);
|
cifs_tcon_dbg(VFS, "srv returned invalid ioctl length: %d\n", *plen);
|
||||||
*plen = 0;
|
*plen = 0;
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
goto ioctl_exit;
|
goto ioctl_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rsp_iov.iov_len - *plen < le32_to_cpu(rsp->OutputOffset)) {
|
if (rsp_iov.iov_len - *plen < le32_to_cpu(rsp->OutputOffset)) {
|
||||||
cifs_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n", *plen,
|
cifs_tcon_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n", *plen,
|
||||||
le32_to_cpu(rsp->OutputOffset));
|
le32_to_cpu(rsp->OutputOffset));
|
||||||
*plen = 0;
|
*plen = 0;
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
@ -2913,6 +2923,7 @@ SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
rqst.rq_iov = iov;
|
rqst.rq_iov = iov;
|
||||||
rqst.rq_nvec = 1;
|
rqst.rq_nvec = 1;
|
||||||
|
|
||||||
|
trace_smb3_close_enter(xid, persistent_fid, tcon->tid, ses->Suid);
|
||||||
rc = SMB2_close_init(tcon, &rqst, persistent_fid, volatile_fid);
|
rc = SMB2_close_init(tcon, &rqst, persistent_fid, volatile_fid);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto close_exit;
|
goto close_exit;
|
||||||
@ -2925,7 +2936,9 @@ SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
trace_smb3_close_err(xid, persistent_fid, tcon->tid, ses->Suid,
|
trace_smb3_close_err(xid, persistent_fid, tcon->tid, ses->Suid,
|
||||||
rc);
|
rc);
|
||||||
goto close_exit;
|
goto close_exit;
|
||||||
}
|
} else
|
||||||
|
trace_smb3_close_done(xid, persistent_fid, tcon->tid,
|
||||||
|
ses->Suid);
|
||||||
|
|
||||||
atomic_dec(&tcon->num_remote_opens);
|
atomic_dec(&tcon->num_remote_opens);
|
||||||
|
|
||||||
@ -3055,12 +3068,16 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
int rc = 0;
|
int rc = 0;
|
||||||
int resp_buftype = CIFS_NO_BUFFER;
|
int resp_buftype = CIFS_NO_BUFFER;
|
||||||
struct cifs_ses *ses = tcon->ses;
|
struct cifs_ses *ses = tcon->ses;
|
||||||
|
struct TCP_Server_Info *server;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
bool allocated = false;
|
bool allocated = false;
|
||||||
|
|
||||||
cifs_dbg(FYI, "Query Info\n");
|
cifs_dbg(FYI, "Query Info\n");
|
||||||
|
|
||||||
if (!ses || !(ses->server))
|
if (!ses)
|
||||||
|
return -EIO;
|
||||||
|
server = ses->server;
|
||||||
|
if (!server)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (smb3_encryption_required(tcon))
|
if (smb3_encryption_required(tcon))
|
||||||
@ -3098,7 +3115,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
if (!*data) {
|
if (!*data) {
|
||||||
*data = kmalloc(*dlen, GFP_KERNEL);
|
*data = kmalloc(*dlen, GFP_KERNEL);
|
||||||
if (!*data) {
|
if (!*data) {
|
||||||
cifs_dbg(VFS,
|
cifs_tcon_dbg(VFS,
|
||||||
"Error %d allocating memory for acl\n",
|
"Error %d allocating memory for acl\n",
|
||||||
rc);
|
rc);
|
||||||
*dlen = 0;
|
*dlen = 0;
|
||||||
@ -3158,6 +3175,91 @@ SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
(void **)&uniqueid, NULL);
|
(void **)&uniqueid, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CHANGE_NOTIFY Request is sent to get notifications on changes to a directory
|
||||||
|
* See MS-SMB2 2.2.35 and 2.2.36
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
SMB2_notify_init(const unsigned int xid, struct smb_rqst *rqst,
|
||||||
|
struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid,
|
||||||
|
u32 completion_filter, bool watch_tree)
|
||||||
|
{
|
||||||
|
struct smb2_change_notify_req *req;
|
||||||
|
struct kvec *iov = rqst->rq_iov;
|
||||||
|
unsigned int total_len;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = smb2_plain_req_init(SMB2_CHANGE_NOTIFY, tcon, (void **) &req, &total_len);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
req->PersistentFileId = persistent_fid;
|
||||||
|
req->VolatileFileId = volatile_fid;
|
||||||
|
req->OutputBufferLength = SMB2_MAX_BUFFER_SIZE - MAX_SMB2_HDR_SIZE;
|
||||||
|
req->CompletionFilter = cpu_to_le32(completion_filter);
|
||||||
|
if (watch_tree)
|
||||||
|
req->Flags = cpu_to_le16(SMB2_WATCH_TREE);
|
||||||
|
else
|
||||||
|
req->Flags = 0;
|
||||||
|
|
||||||
|
iov[0].iov_base = (char *)req;
|
||||||
|
iov[0].iov_len = total_len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
|
u64 persistent_fid, u64 volatile_fid, bool watch_tree,
|
||||||
|
u32 completion_filter)
|
||||||
|
{
|
||||||
|
struct cifs_ses *ses = tcon->ses;
|
||||||
|
struct smb_rqst rqst;
|
||||||
|
struct kvec iov[1];
|
||||||
|
struct kvec rsp_iov = {NULL, 0};
|
||||||
|
int resp_buftype = CIFS_NO_BUFFER;
|
||||||
|
int flags = 0;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
cifs_dbg(FYI, "change notify\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_notify_init(xid, &rqst, tcon, persistent_fid, volatile_fid,
|
||||||
|
completion_filter, watch_tree);
|
||||||
|
if (rc)
|
||||||
|
goto cnotify_exit;
|
||||||
|
|
||||||
|
trace_smb3_notify_enter(xid, persistent_fid, tcon->tid, ses->Suid,
|
||||||
|
(u8)watch_tree, completion_filter);
|
||||||
|
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
|
||||||
|
|
||||||
|
if (rc != 0) {
|
||||||
|
cifs_stats_fail_inc(tcon, SMB2_CHANGE_NOTIFY_HE);
|
||||||
|
trace_smb3_notify_err(xid, persistent_fid, tcon->tid, ses->Suid,
|
||||||
|
(u8)watch_tree, completion_filter, rc);
|
||||||
|
} else
|
||||||
|
trace_smb3_notify_done(xid, persistent_fid, tcon->tid,
|
||||||
|
ses->Suid, (u8)watch_tree, completion_filter);
|
||||||
|
|
||||||
|
cnotify_exit:
|
||||||
|
if (rqst.rq_iov)
|
||||||
|
cifs_small_buf_release(rqst.rq_iov[0].iov_base); /* request */
|
||||||
|
free_rsp_buf(resp_buftype, rsp_iov.iov_base);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a no-op for now. We're not really interested in the reply, but
|
* This is a no-op for now. We're not really interested in the reply, but
|
||||||
* rather in the fact that the server sent one and that server->lstrp
|
* rather in the fact that the server sent one and that server->lstrp
|
||||||
@ -3287,51 +3389,76 @@ SMB2_echo(struct TCP_Server_Info *server)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
SMB2_flush_free(struct smb_rqst *rqst)
|
||||||
u64 volatile_fid)
|
{
|
||||||
|
if (rqst && rqst->rq_iov)
|
||||||
|
cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
SMB2_flush_init(const unsigned int xid, struct smb_rqst *rqst,
|
||||||
|
struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid)
|
||||||
{
|
{
|
||||||
struct smb_rqst rqst;
|
|
||||||
struct smb2_flush_req *req;
|
struct smb2_flush_req *req;
|
||||||
struct cifs_ses *ses = tcon->ses;
|
struct kvec *iov = rqst->rq_iov;
|
||||||
struct kvec iov[1];
|
|
||||||
struct kvec rsp_iov;
|
|
||||||
int resp_buftype;
|
|
||||||
int rc = 0;
|
|
||||||
int flags = 0;
|
|
||||||
unsigned int total_len;
|
unsigned int total_len;
|
||||||
|
int rc;
|
||||||
cifs_dbg(FYI, "Flush\n");
|
|
||||||
|
|
||||||
if (!ses || !(ses->server))
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
rc = smb2_plain_req_init(SMB2_FLUSH, tcon, (void **) &req, &total_len);
|
rc = smb2_plain_req_init(SMB2_FLUSH, tcon, (void **) &req, &total_len);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if (smb3_encryption_required(tcon))
|
|
||||||
flags |= CIFS_TRANSFORM_REQ;
|
|
||||||
|
|
||||||
req->PersistentFileId = persistent_fid;
|
req->PersistentFileId = persistent_fid;
|
||||||
req->VolatileFileId = volatile_fid;
|
req->VolatileFileId = volatile_fid;
|
||||||
|
|
||||||
iov[0].iov_base = (char *)req;
|
iov[0].iov_base = (char *)req;
|
||||||
iov[0].iov_len = total_len;
|
iov[0].iov_len = total_len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
||||||
|
u64 volatile_fid)
|
||||||
|
{
|
||||||
|
struct cifs_ses *ses = tcon->ses;
|
||||||
|
struct smb_rqst rqst;
|
||||||
|
struct kvec iov[1];
|
||||||
|
struct kvec rsp_iov = {NULL, 0};
|
||||||
|
int resp_buftype = CIFS_NO_BUFFER;
|
||||||
|
int flags = 0;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
cifs_dbg(FYI, "flush\n");
|
||||||
|
if (!ses || !(ses->server))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (smb3_encryption_required(tcon))
|
||||||
|
flags |= CIFS_TRANSFORM_REQ;
|
||||||
|
|
||||||
memset(&rqst, 0, sizeof(struct smb_rqst));
|
memset(&rqst, 0, sizeof(struct smb_rqst));
|
||||||
|
memset(&iov, 0, sizeof(iov));
|
||||||
rqst.rq_iov = iov;
|
rqst.rq_iov = iov;
|
||||||
rqst.rq_nvec = 1;
|
rqst.rq_nvec = 1;
|
||||||
|
|
||||||
|
rc = SMB2_flush_init(xid, &rqst, tcon, persistent_fid, volatile_fid);
|
||||||
|
if (rc)
|
||||||
|
goto flush_exit;
|
||||||
|
|
||||||
|
trace_smb3_flush_enter(xid, persistent_fid, tcon->tid, ses->Suid);
|
||||||
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
|
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
|
||||||
cifs_small_buf_release(req);
|
|
||||||
|
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE);
|
cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE);
|
||||||
trace_smb3_flush_err(xid, persistent_fid, tcon->tid, ses->Suid,
|
trace_smb3_flush_err(xid, persistent_fid, tcon->tid, ses->Suid,
|
||||||
rc);
|
rc);
|
||||||
}
|
} else
|
||||||
|
trace_smb3_flush_done(xid, persistent_fid, tcon->tid,
|
||||||
|
ses->Suid);
|
||||||
|
|
||||||
|
flush_exit:
|
||||||
|
SMB2_flush_free(&rqst);
|
||||||
free_rsp_buf(resp_buftype, rsp_iov.iov_base);
|
free_rsp_buf(resp_buftype, rsp_iov.iov_base);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -3446,8 +3573,8 @@ smb2_readv_callback(struct mid_q_entry *mid)
|
|||||||
struct smb2_sync_hdr *shdr =
|
struct smb2_sync_hdr *shdr =
|
||||||
(struct smb2_sync_hdr *)rdata->iov[0].iov_base;
|
(struct smb2_sync_hdr *)rdata->iov[0].iov_base;
|
||||||
struct cifs_credits credits = { .value = 0, .instance = 0 };
|
struct cifs_credits credits = { .value = 0, .instance = 0 };
|
||||||
struct smb_rqst rqst = { .rq_iov = rdata->iov,
|
struct smb_rqst rqst = { .rq_iov = &rdata->iov[1],
|
||||||
.rq_nvec = 2,
|
.rq_nvec = 1,
|
||||||
.rq_pages = rdata->pages,
|
.rq_pages = rdata->pages,
|
||||||
.rq_offset = rdata->page_offset,
|
.rq_offset = rdata->page_offset,
|
||||||
.rq_npages = rdata->nr_pages,
|
.rq_npages = rdata->nr_pages,
|
||||||
@ -3468,7 +3595,7 @@ smb2_readv_callback(struct mid_q_entry *mid)
|
|||||||
|
|
||||||
rc = smb2_verify_signature(&rqst, server);
|
rc = smb2_verify_signature(&rqst, server);
|
||||||
if (rc)
|
if (rc)
|
||||||
cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
|
cifs_tcon_dbg(VFS, "SMB signature verification returned error = %d\n",
|
||||||
rc);
|
rc);
|
||||||
}
|
}
|
||||||
/* FIXME: should this be counted toward the initiating task? */
|
/* FIXME: should this be counted toward the initiating task? */
|
||||||
@ -3595,7 +3722,7 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|||||||
unsigned int *nbytes, char **buf, int *buf_type)
|
unsigned int *nbytes, char **buf, int *buf_type)
|
||||||
{
|
{
|
||||||
struct smb_rqst rqst;
|
struct smb_rqst rqst;
|
||||||
int resp_buftype, rc = -EACCES;
|
int resp_buftype, rc;
|
||||||
struct smb2_read_plain_req *req = NULL;
|
struct smb2_read_plain_req *req = NULL;
|
||||||
struct smb2_read_rsp *rsp = NULL;
|
struct smb2_read_rsp *rsp = NULL;
|
||||||
struct kvec iov[1];
|
struct kvec iov[1];
|
||||||
@ -4058,7 +4185,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
info_buf_size = sizeof(SEARCH_ID_FULL_DIR_INFO) - 1;
|
info_buf_size = sizeof(SEARCH_ID_FULL_DIR_INFO) - 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cifs_dbg(VFS, "info level %u isn't supported\n",
|
cifs_tcon_dbg(VFS, "info level %u isn't supported\n",
|
||||||
srch_inf->info_level);
|
srch_inf->info_level);
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
goto qdir_exit;
|
goto qdir_exit;
|
||||||
@ -4149,7 +4276,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
else if (resp_buftype == CIFS_SMALL_BUFFER)
|
else if (resp_buftype == CIFS_SMALL_BUFFER)
|
||||||
srch_inf->smallBuf = true;
|
srch_inf->smallBuf = true;
|
||||||
else
|
else
|
||||||
cifs_dbg(VFS, "illegal search buffer type\n");
|
cifs_tcon_dbg(VFS, "illegal search buffer type\n");
|
||||||
|
|
||||||
trace_smb3_query_dir_done(xid, persistent_fid, tcon->tid,
|
trace_smb3_query_dir_done(xid, persistent_fid, tcon->tid,
|
||||||
tcon->ses->Suid, index, srch_inf->entries_in_buffer);
|
tcon->ses->Suid, index, srch_inf->entries_in_buffer);
|
||||||
|
@ -143,7 +143,9 @@ struct smb2_transform_hdr {
|
|||||||
#define SMB2_FLAGS_ASYNC_COMMAND cpu_to_le32(0x00000002)
|
#define SMB2_FLAGS_ASYNC_COMMAND cpu_to_le32(0x00000002)
|
||||||
#define SMB2_FLAGS_RELATED_OPERATIONS cpu_to_le32(0x00000004)
|
#define SMB2_FLAGS_RELATED_OPERATIONS cpu_to_le32(0x00000004)
|
||||||
#define SMB2_FLAGS_SIGNED cpu_to_le32(0x00000008)
|
#define SMB2_FLAGS_SIGNED cpu_to_le32(0x00000008)
|
||||||
|
#define SMB2_FLAGS_PRIORITY_MASK cpu_to_le32(0x00000070) /* SMB3.1.1 */
|
||||||
#define SMB2_FLAGS_DFS_OPERATIONS cpu_to_le32(0x10000000)
|
#define SMB2_FLAGS_DFS_OPERATIONS cpu_to_le32(0x10000000)
|
||||||
|
#define SMB2_FLAGS_REPLAY_OPERATION cpu_to_le32(0x20000000) /* SMB3 & up */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Definitions for SMB2 Protocol Data Units (network frames)
|
* Definitions for SMB2 Protocol Data Units (network frames)
|
||||||
|
@ -158,6 +158,10 @@ extern int SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
|
|||||||
extern void SMB2_close_free(struct smb_rqst *rqst);
|
extern void SMB2_close_free(struct smb_rqst *rqst);
|
||||||
extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
|
extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
u64 persistent_file_id, u64 volatile_file_id);
|
u64 persistent_file_id, u64 volatile_file_id);
|
||||||
|
extern int SMB2_flush_init(const unsigned int xid, struct smb_rqst *rqst,
|
||||||
|
struct cifs_tcon *tcon,
|
||||||
|
u64 persistent_file_id, u64 volatile_file_id);
|
||||||
|
extern void SMB2_flush_free(struct smb_rqst *rqst);
|
||||||
extern int SMB2_query_info(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,
|
u64 persistent_file_id, u64 volatile_file_id,
|
||||||
struct smb2_file_all_info *data);
|
struct smb2_file_all_info *data);
|
||||||
|
@ -176,7 +176,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
|||||||
|
|
||||||
ses = smb2_find_smb_ses(server, shdr->SessionId);
|
ses = smb2_find_smb_ses(server, shdr->SessionId);
|
||||||
if (!ses) {
|
if (!ses) {
|
||||||
cifs_dbg(VFS, "%s: Could not find session\n", __func__);
|
cifs_server_dbg(VFS, "%s: Could not find session\n", __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,21 +185,21 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
|||||||
|
|
||||||
rc = smb2_crypto_shash_allocate(server);
|
rc = smb2_crypto_shash_allocate(server);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: sha256 alloc failed\n", __func__);
|
cifs_server_dbg(VFS, "%s: sha256 alloc failed\n", __func__);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = crypto_shash_setkey(server->secmech.hmacsha256,
|
rc = crypto_shash_setkey(server->secmech.hmacsha256,
|
||||||
ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
|
ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
|
cifs_server_dbg(VFS, "%s: Could not update with response\n", __func__);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
shash = &server->secmech.sdeschmacsha256->shash;
|
shash = &server->secmech.sdeschmacsha256->shash;
|
||||||
rc = crypto_shash_init(shash);
|
rc = crypto_shash_init(shash);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Could not init sha256", __func__);
|
cifs_server_dbg(VFS, "%s: Could not init sha256", __func__);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
|||||||
rc = crypto_shash_update(shash, iov[0].iov_base,
|
rc = crypto_shash_update(shash, iov[0].iov_base,
|
||||||
iov[0].iov_len);
|
iov[0].iov_len);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Could not update with payload\n",
|
cifs_server_dbg(VFS, "%s: Could not update with payload\n",
|
||||||
__func__);
|
__func__);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -239,68 +239,69 @@ static int generate_key(struct cifs_ses *ses, struct kvec label,
|
|||||||
int rc = 0;
|
int rc = 0;
|
||||||
unsigned char prfhash[SMB2_HMACSHA256_SIZE];
|
unsigned char prfhash[SMB2_HMACSHA256_SIZE];
|
||||||
unsigned char *hashptr = prfhash;
|
unsigned char *hashptr = prfhash;
|
||||||
|
struct TCP_Server_Info *server = ses->server;
|
||||||
|
|
||||||
memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
|
memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
|
||||||
memset(key, 0x0, key_size);
|
memset(key, 0x0, key_size);
|
||||||
|
|
||||||
rc = smb3_crypto_shash_allocate(ses->server);
|
rc = smb3_crypto_shash_allocate(server);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
|
cifs_server_dbg(VFS, "%s: crypto alloc failed\n", __func__);
|
||||||
goto smb3signkey_ret;
|
goto smb3signkey_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = crypto_shash_setkey(ses->server->secmech.hmacsha256,
|
rc = crypto_shash_setkey(server->secmech.hmacsha256,
|
||||||
ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
|
ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Could not set with session key\n", __func__);
|
cifs_server_dbg(VFS, "%s: Could not set with session key\n", __func__);
|
||||||
goto smb3signkey_ret;
|
goto smb3signkey_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = crypto_shash_init(&ses->server->secmech.sdeschmacsha256->shash);
|
rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Could not init sign hmac\n", __func__);
|
cifs_server_dbg(VFS, "%s: Could not init sign hmac\n", __func__);
|
||||||
goto smb3signkey_ret;
|
goto smb3signkey_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
|
rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
|
||||||
i, 4);
|
i, 4);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Could not update with n\n", __func__);
|
cifs_server_dbg(VFS, "%s: Could not update with n\n", __func__);
|
||||||
goto smb3signkey_ret;
|
goto smb3signkey_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
|
rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
|
||||||
label.iov_base, label.iov_len);
|
label.iov_base, label.iov_len);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Could not update with label\n", __func__);
|
cifs_server_dbg(VFS, "%s: Could not update with label\n", __func__);
|
||||||
goto smb3signkey_ret;
|
goto smb3signkey_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
|
rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
|
||||||
&zero, 1);
|
&zero, 1);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Could not update with zero\n", __func__);
|
cifs_server_dbg(VFS, "%s: Could not update with zero\n", __func__);
|
||||||
goto smb3signkey_ret;
|
goto smb3signkey_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
|
rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
|
||||||
context.iov_base, context.iov_len);
|
context.iov_base, context.iov_len);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Could not update with context\n", __func__);
|
cifs_server_dbg(VFS, "%s: Could not update with context\n", __func__);
|
||||||
goto smb3signkey_ret;
|
goto smb3signkey_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
|
rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
|
||||||
L, 4);
|
L, 4);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Could not update with L\n", __func__);
|
cifs_server_dbg(VFS, "%s: Could not update with L\n", __func__);
|
||||||
goto smb3signkey_ret;
|
goto smb3signkey_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = crypto_shash_final(&ses->server->secmech.sdeschmacsha256->shash,
|
rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash,
|
||||||
hashptr);
|
hashptr);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__);
|
cifs_server_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__);
|
||||||
goto smb3signkey_ret;
|
goto smb3signkey_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,7 +437,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
|||||||
|
|
||||||
ses = smb2_find_smb_ses(server, shdr->SessionId);
|
ses = smb2_find_smb_ses(server, shdr->SessionId);
|
||||||
if (!ses) {
|
if (!ses) {
|
||||||
cifs_dbg(VFS, "%s: Could not find session\n", __func__);
|
cifs_server_dbg(VFS, "%s: Could not find session\n", __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,7 +447,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
|||||||
rc = crypto_shash_setkey(server->secmech.cmacaes,
|
rc = crypto_shash_setkey(server->secmech.cmacaes,
|
||||||
ses->smb3signingkey, SMB2_CMACAES_SIZE);
|
ses->smb3signingkey, SMB2_CMACAES_SIZE);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__);
|
cifs_server_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,7 +458,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
|||||||
*/
|
*/
|
||||||
rc = crypto_shash_init(shash);
|
rc = crypto_shash_init(shash);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
|
cifs_server_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,7 +474,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
|||||||
rc = crypto_shash_update(shash, iov[0].iov_base,
|
rc = crypto_shash_update(shash, iov[0].iov_base,
|
||||||
iov[0].iov_len);
|
iov[0].iov_len);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(VFS, "%s: Could not update with payload\n",
|
cifs_server_dbg(VFS, "%s: Could not update with payload\n",
|
||||||
__func__);
|
__func__);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -521,6 +522,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
|||||||
if ((shdr->Command == SMB2_NEGOTIATE) ||
|
if ((shdr->Command == SMB2_NEGOTIATE) ||
|
||||||
(shdr->Command == SMB2_SESSION_SETUP) ||
|
(shdr->Command == SMB2_SESSION_SETUP) ||
|
||||||
(shdr->Command == SMB2_OPLOCK_BREAK) ||
|
(shdr->Command == SMB2_OPLOCK_BREAK) ||
|
||||||
|
server->ignore_signature ||
|
||||||
(!server->session_estab))
|
(!server->session_estab))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -665,7 +667,7 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
|
|||||||
|
|
||||||
rc = smb2_verify_signature(&rqst, server);
|
rc = smb2_verify_signature(&rqst, server);
|
||||||
if (rc)
|
if (rc)
|
||||||
cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
|
cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n",
|
||||||
rc);
|
rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -739,7 +741,7 @@ smb3_crypto_aead_allocate(struct TCP_Server_Info *server)
|
|||||||
else
|
else
|
||||||
tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
|
tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
|
||||||
if (IS_ERR(tfm)) {
|
if (IS_ERR(tfm)) {
|
||||||
cifs_dbg(VFS, "%s: Failed to alloc encrypt aead\n",
|
cifs_server_dbg(VFS, "%s: Failed to alloc encrypt aead\n",
|
||||||
__func__);
|
__func__);
|
||||||
return PTR_ERR(tfm);
|
return PTR_ERR(tfm);
|
||||||
}
|
}
|
||||||
@ -754,7 +756,7 @@ smb3_crypto_aead_allocate(struct TCP_Server_Info *server)
|
|||||||
if (IS_ERR(tfm)) {
|
if (IS_ERR(tfm)) {
|
||||||
crypto_free_aead(server->secmech.ccmaesencrypt);
|
crypto_free_aead(server->secmech.ccmaesencrypt);
|
||||||
server->secmech.ccmaesencrypt = NULL;
|
server->secmech.ccmaesencrypt = NULL;
|
||||||
cifs_dbg(VFS, "%s: Failed to alloc decrypt aead\n",
|
cifs_server_dbg(VFS, "%s: Failed to alloc decrypt aead\n",
|
||||||
__func__);
|
__func__);
|
||||||
return PTR_ERR(tfm);
|
return PTR_ERR(tfm);
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,41 @@ DEFINE_SMB3_RW_DONE_EVENT(falloc_done);
|
|||||||
/*
|
/*
|
||||||
* For handle based calls other than read and write, and get/set info
|
* For handle based calls other than read and write, and get/set info
|
||||||
*/
|
*/
|
||||||
|
DECLARE_EVENT_CLASS(smb3_fd_class,
|
||||||
|
TP_PROTO(unsigned int xid,
|
||||||
|
__u64 fid,
|
||||||
|
__u32 tid,
|
||||||
|
__u64 sesid),
|
||||||
|
TP_ARGS(xid, fid, tid, sesid),
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field(unsigned int, xid)
|
||||||
|
__field(__u64, fid)
|
||||||
|
__field(__u32, tid)
|
||||||
|
__field(__u64, sesid)
|
||||||
|
),
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->xid = xid;
|
||||||
|
__entry->fid = fid;
|
||||||
|
__entry->tid = tid;
|
||||||
|
__entry->sesid = sesid;
|
||||||
|
),
|
||||||
|
TP_printk("\txid=%u sid=0x%llx tid=0x%x fid=0x%llx",
|
||||||
|
__entry->xid, __entry->sesid, __entry->tid, __entry->fid)
|
||||||
|
)
|
||||||
|
|
||||||
|
#define DEFINE_SMB3_FD_EVENT(name) \
|
||||||
|
DEFINE_EVENT(smb3_fd_class, smb3_##name, \
|
||||||
|
TP_PROTO(unsigned int xid, \
|
||||||
|
__u64 fid, \
|
||||||
|
__u32 tid, \
|
||||||
|
__u64 sesid), \
|
||||||
|
TP_ARGS(xid, fid, tid, sesid))
|
||||||
|
|
||||||
|
DEFINE_SMB3_FD_EVENT(flush_enter);
|
||||||
|
DEFINE_SMB3_FD_EVENT(flush_done);
|
||||||
|
DEFINE_SMB3_FD_EVENT(close_enter);
|
||||||
|
DEFINE_SMB3_FD_EVENT(close_done);
|
||||||
|
|
||||||
DECLARE_EVENT_CLASS(smb3_fd_err_class,
|
DECLARE_EVENT_CLASS(smb3_fd_err_class,
|
||||||
TP_PROTO(unsigned int xid,
|
TP_PROTO(unsigned int xid,
|
||||||
__u64 fid,
|
__u64 fid,
|
||||||
@ -200,6 +235,8 @@ DEFINE_EVENT(smb3_inf_enter_class, smb3_##name, \
|
|||||||
|
|
||||||
DEFINE_SMB3_INF_ENTER_EVENT(query_info_enter);
|
DEFINE_SMB3_INF_ENTER_EVENT(query_info_enter);
|
||||||
DEFINE_SMB3_INF_ENTER_EVENT(query_info_done);
|
DEFINE_SMB3_INF_ENTER_EVENT(query_info_done);
|
||||||
|
DEFINE_SMB3_INF_ENTER_EVENT(notify_enter);
|
||||||
|
DEFINE_SMB3_INF_ENTER_EVENT(notify_done);
|
||||||
|
|
||||||
DECLARE_EVENT_CLASS(smb3_inf_err_class,
|
DECLARE_EVENT_CLASS(smb3_inf_err_class,
|
||||||
TP_PROTO(unsigned int xid,
|
TP_PROTO(unsigned int xid,
|
||||||
@ -246,6 +283,7 @@ DEFINE_EVENT(smb3_inf_err_class, smb3_##name, \
|
|||||||
|
|
||||||
DEFINE_SMB3_INF_ERR_EVENT(query_info_err);
|
DEFINE_SMB3_INF_ERR_EVENT(query_info_err);
|
||||||
DEFINE_SMB3_INF_ERR_EVENT(set_info_err);
|
DEFINE_SMB3_INF_ERR_EVENT(set_info_err);
|
||||||
|
DEFINE_SMB3_INF_ERR_EVENT(notify_err);
|
||||||
DEFINE_SMB3_INF_ERR_EVENT(fsctl_err);
|
DEFINE_SMB3_INF_ERR_EVENT(fsctl_err);
|
||||||
|
|
||||||
DECLARE_EVENT_CLASS(smb3_inf_compound_enter_class,
|
DECLARE_EVENT_CLASS(smb3_inf_compound_enter_class,
|
||||||
|
@ -118,7 +118,7 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
|
|||||||
#ifdef CONFIG_CIFS_STATS2
|
#ifdef CONFIG_CIFS_STATS2
|
||||||
now = jiffies;
|
now = jiffies;
|
||||||
if (now < midEntry->when_alloc)
|
if (now < midEntry->when_alloc)
|
||||||
cifs_dbg(VFS, "invalid mid allocation time\n");
|
cifs_server_dbg(VFS, "invalid mid allocation time\n");
|
||||||
roundtrip_time = now - midEntry->when_alloc;
|
roundtrip_time = now - midEntry->when_alloc;
|
||||||
|
|
||||||
if (smb_cmd < NUMBER_OF_SMB2_COMMANDS) {
|
if (smb_cmd < NUMBER_OF_SMB2_COMMANDS) {
|
||||||
@ -232,7 +232,7 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
|
|||||||
retries++;
|
retries++;
|
||||||
if (retries >= 14 ||
|
if (retries >= 14 ||
|
||||||
(!server->noblocksnd && (retries > 2))) {
|
(!server->noblocksnd && (retries > 2))) {
|
||||||
cifs_dbg(VFS, "sends on sock %p stuck for 15 seconds\n",
|
cifs_server_dbg(VFS, "sends on sock %p stuck for 15 seconds\n",
|
||||||
ssocket);
|
ssocket);
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
@ -246,7 +246,7 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
|
|||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
/* should never happen, letting socket clear before
|
/* should never happen, letting socket clear before
|
||||||
retrying is our only obvious option here */
|
retrying is our only obvious option here */
|
||||||
cifs_dbg(VFS, "tcp sent no data\n");
|
cifs_server_dbg(VFS, "tcp sent no data\n");
|
||||||
msleep(500);
|
msleep(500);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -440,7 +440,7 @@ unmask:
|
|||||||
}
|
}
|
||||||
smbd_done:
|
smbd_done:
|
||||||
if (rc < 0 && rc != -EINTR)
|
if (rc < 0 && rc != -EINTR)
|
||||||
cifs_dbg(VFS, "Error %d sending data on socket to server\n",
|
cifs_server_dbg(VFS, "Error %d sending data on socket to server\n",
|
||||||
rc);
|
rc);
|
||||||
else if (rc > 0)
|
else if (rc > 0)
|
||||||
rc = 0;
|
rc = 0;
|
||||||
@ -473,8 +473,8 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
|||||||
cur_rqst[0].rq_nvec = 1;
|
cur_rqst[0].rq_nvec = 1;
|
||||||
|
|
||||||
if (!server->ops->init_transform_rq) {
|
if (!server->ops->init_transform_rq) {
|
||||||
cifs_dbg(VFS, "Encryption requested but transform callback "
|
cifs_server_dbg(VFS, "Encryption requested but transform "
|
||||||
"is missing\n");
|
"callback is missing\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,6 +532,8 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
|
|||||||
if ((flags & CIFS_TIMEOUT_MASK) == CIFS_NON_BLOCKING) {
|
if ((flags & CIFS_TIMEOUT_MASK) == CIFS_NON_BLOCKING) {
|
||||||
/* oplock breaks must not be held up */
|
/* oplock breaks must not be held up */
|
||||||
server->in_flight++;
|
server->in_flight++;
|
||||||
|
if (server->in_flight > server->max_in_flight)
|
||||||
|
server->max_in_flight = server->in_flight;
|
||||||
*credits -= 1;
|
*credits -= 1;
|
||||||
*instance = server->reconnect_instance;
|
*instance = server->reconnect_instance;
|
||||||
spin_unlock(&server->req_lock);
|
spin_unlock(&server->req_lock);
|
||||||
@ -548,7 +550,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
|
|||||||
if (!rc) {
|
if (!rc) {
|
||||||
trace_smb3_credit_timeout(server->CurrentMid,
|
trace_smb3_credit_timeout(server->CurrentMid,
|
||||||
server->hostname, num_credits);
|
server->hostname, num_credits);
|
||||||
cifs_dbg(VFS, "wait timed out after %d ms\n",
|
cifs_server_dbg(VFS, "wait timed out after %d ms\n",
|
||||||
timeout);
|
timeout);
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
@ -589,7 +591,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
|
|||||||
trace_smb3_credit_timeout(
|
trace_smb3_credit_timeout(
|
||||||
server->CurrentMid,
|
server->CurrentMid,
|
||||||
server->hostname, num_credits);
|
server->hostname, num_credits);
|
||||||
cifs_dbg(VFS, "wait timed out after %d ms\n",
|
cifs_server_dbg(VFS, "wait timed out after %d ms\n",
|
||||||
timeout);
|
timeout);
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
@ -608,6 +610,8 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
|
|||||||
if ((flags & CIFS_TIMEOUT_MASK) != CIFS_BLOCKING_OP) {
|
if ((flags & CIFS_TIMEOUT_MASK) != CIFS_BLOCKING_OP) {
|
||||||
*credits -= num_credits;
|
*credits -= num_credits;
|
||||||
server->in_flight += num_credits;
|
server->in_flight += num_credits;
|
||||||
|
if (server->in_flight > server->max_in_flight)
|
||||||
|
server->max_in_flight = server->in_flight;
|
||||||
*instance = server->reconnect_instance;
|
*instance = server->reconnect_instance;
|
||||||
}
|
}
|
||||||
spin_unlock(&server->req_lock);
|
spin_unlock(&server->req_lock);
|
||||||
@ -869,7 +873,7 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
list_del_init(&mid->qhead);
|
list_del_init(&mid->qhead);
|
||||||
cifs_dbg(VFS, "%s: invalid mid state mid=%llu state=%d\n",
|
cifs_server_dbg(VFS, "%s: invalid mid state mid=%llu state=%d\n",
|
||||||
__func__, mid->mid, mid->mid_state);
|
__func__, mid->mid, mid->mid_state);
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
}
|
}
|
||||||
@ -910,7 +914,7 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
|
|||||||
rc = cifs_verify_signature(&rqst, server,
|
rc = cifs_verify_signature(&rqst, server,
|
||||||
mid->sequence_number);
|
mid->sequence_number);
|
||||||
if (rc)
|
if (rc)
|
||||||
cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
|
cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n",
|
||||||
rc);
|
rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1107,7 +1111,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
|||||||
}
|
}
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
for (; i < num_rqst; i++) {
|
for (; i < num_rqst; i++) {
|
||||||
cifs_dbg(VFS, "Cancelling wait for mid %llu cmd: %d\n",
|
cifs_server_dbg(VFS, "Cancelling wait for mid %llu cmd: %d\n",
|
||||||
midQ[i]->mid, le16_to_cpu(midQ[i]->command));
|
midQ[i]->mid, le16_to_cpu(midQ[i]->command));
|
||||||
send_cancel(server, &rqst[i], midQ[i]);
|
send_cancel(server, &rqst[i], midQ[i]);
|
||||||
spin_lock(&GlobalMid_Lock);
|
spin_lock(&GlobalMid_Lock);
|
||||||
@ -1242,17 +1246,19 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
|
|||||||
struct kvec iov = { .iov_base = in_buf, .iov_len = len };
|
struct kvec iov = { .iov_base = in_buf, .iov_len = len };
|
||||||
struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
|
struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
|
||||||
struct cifs_credits credits = { .value = 1, .instance = 0 };
|
struct cifs_credits credits = { .value = 1, .instance = 0 };
|
||||||
|
struct TCP_Server_Info *server;
|
||||||
|
|
||||||
if (ses == NULL) {
|
if (ses == NULL) {
|
||||||
cifs_dbg(VFS, "Null smb session\n");
|
cifs_dbg(VFS, "Null smb session\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
if (ses->server == NULL) {
|
server = ses->server;
|
||||||
|
if (server == NULL) {
|
||||||
cifs_dbg(VFS, "Null tcp session\n");
|
cifs_dbg(VFS, "Null tcp session\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ses->server->tcpStatus == CifsExiting)
|
if (server->tcpStatus == CifsExiting)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
/* Ensure that we do not send more than 50 overlapping requests
|
/* Ensure that we do not send more than 50 overlapping requests
|
||||||
@ -1260,12 +1266,12 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
|
|||||||
use ses->maxReq */
|
use ses->maxReq */
|
||||||
|
|
||||||
if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||||
cifs_dbg(VFS, "Illegal length, greater than maximum frame, %d\n",
|
cifs_server_dbg(VFS, "Illegal length, greater than maximum frame, %d\n",
|
||||||
len);
|
len);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = wait_for_free_request(ses->server, flags, &credits.instance);
|
rc = wait_for_free_request(server, flags, &credits.instance);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -1273,70 +1279,70 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
|
|||||||
and avoid races inside tcp sendmsg code that could cause corruption
|
and avoid races inside tcp sendmsg code that could cause corruption
|
||||||
of smb data */
|
of smb data */
|
||||||
|
|
||||||
mutex_lock(&ses->server->srv_mutex);
|
mutex_lock(&server->srv_mutex);
|
||||||
|
|
||||||
rc = allocate_mid(ses, in_buf, &midQ);
|
rc = allocate_mid(ses, in_buf, &midQ);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
mutex_unlock(&ses->server->srv_mutex);
|
mutex_unlock(&ses->server->srv_mutex);
|
||||||
/* Update # of requests on wire to server */
|
/* Update # of requests on wire to server */
|
||||||
add_credits(ses->server, &credits, 0);
|
add_credits(server, &credits, 0);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
|
rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
mutex_unlock(&ses->server->srv_mutex);
|
mutex_unlock(&server->srv_mutex);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
midQ->mid_state = MID_REQUEST_SUBMITTED;
|
midQ->mid_state = MID_REQUEST_SUBMITTED;
|
||||||
|
|
||||||
cifs_in_send_inc(ses->server);
|
cifs_in_send_inc(server);
|
||||||
rc = smb_send(ses->server, in_buf, len);
|
rc = smb_send(server, in_buf, len);
|
||||||
cifs_in_send_dec(ses->server);
|
cifs_in_send_dec(server);
|
||||||
cifs_save_when_sent(midQ);
|
cifs_save_when_sent(midQ);
|
||||||
|
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
ses->server->sequence_number -= 2;
|
server->sequence_number -= 2;
|
||||||
|
|
||||||
mutex_unlock(&ses->server->srv_mutex);
|
mutex_unlock(&server->srv_mutex);
|
||||||
|
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
rc = wait_for_response(ses->server, midQ);
|
rc = wait_for_response(server, midQ);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
send_cancel(ses->server, &rqst, midQ);
|
send_cancel(server, &rqst, midQ);
|
||||||
spin_lock(&GlobalMid_Lock);
|
spin_lock(&GlobalMid_Lock);
|
||||||
if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
|
if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
|
||||||
/* no longer considered to be "in-flight" */
|
/* no longer considered to be "in-flight" */
|
||||||
midQ->callback = DeleteMidQEntry;
|
midQ->callback = DeleteMidQEntry;
|
||||||
spin_unlock(&GlobalMid_Lock);
|
spin_unlock(&GlobalMid_Lock);
|
||||||
add_credits(ses->server, &credits, 0);
|
add_credits(server, &credits, 0);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
spin_unlock(&GlobalMid_Lock);
|
spin_unlock(&GlobalMid_Lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = cifs_sync_mid_result(midQ, ses->server);
|
rc = cifs_sync_mid_result(midQ, server);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
add_credits(ses->server, &credits, 0);
|
add_credits(server, &credits, 0);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!midQ->resp_buf || !out_buf ||
|
if (!midQ->resp_buf || !out_buf ||
|
||||||
midQ->mid_state != MID_RESPONSE_RECEIVED) {
|
midQ->mid_state != MID_RESPONSE_RECEIVED) {
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
cifs_dbg(VFS, "Bad MID state?\n");
|
cifs_server_dbg(VFS, "Bad MID state?\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
|
*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
|
||||||
memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
|
memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
|
||||||
rc = cifs_check_receive(midQ, ses->server, 0);
|
rc = cifs_check_receive(midQ, server, 0);
|
||||||
out:
|
out:
|
||||||
cifs_delete_mid(midQ);
|
cifs_delete_mid(midQ);
|
||||||
add_credits(ses->server, &credits, 0);
|
add_credits(server, &credits, 0);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -1379,19 +1385,21 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
struct kvec iov = { .iov_base = in_buf, .iov_len = len };
|
struct kvec iov = { .iov_base = in_buf, .iov_len = len };
|
||||||
struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
|
struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
|
||||||
unsigned int instance;
|
unsigned int instance;
|
||||||
|
struct TCP_Server_Info *server;
|
||||||
|
|
||||||
if (tcon == NULL || tcon->ses == NULL) {
|
if (tcon == NULL || tcon->ses == NULL) {
|
||||||
cifs_dbg(VFS, "Null smb session\n");
|
cifs_dbg(VFS, "Null smb session\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
ses = tcon->ses;
|
ses = tcon->ses;
|
||||||
|
server = ses->server;
|
||||||
|
|
||||||
if (ses->server == NULL) {
|
if (server == NULL) {
|
||||||
cifs_dbg(VFS, "Null tcp session\n");
|
cifs_dbg(VFS, "Null tcp session\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ses->server->tcpStatus == CifsExiting)
|
if (server->tcpStatus == CifsExiting)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
/* Ensure that we do not send more than 50 overlapping requests
|
/* Ensure that we do not send more than 50 overlapping requests
|
||||||
@ -1399,12 +1407,12 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
use ses->maxReq */
|
use ses->maxReq */
|
||||||
|
|
||||||
if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||||
cifs_dbg(VFS, "Illegal length, greater than maximum frame, %d\n",
|
cifs_tcon_dbg(VFS, "Illegal length, greater than maximum frame, %d\n",
|
||||||
len);
|
len);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP, &instance);
|
rc = wait_for_free_request(server, CIFS_BLOCKING_OP, &instance);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -1412,31 +1420,31 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
and avoid races inside tcp sendmsg code that could cause corruption
|
and avoid races inside tcp sendmsg code that could cause corruption
|
||||||
of smb data */
|
of smb data */
|
||||||
|
|
||||||
mutex_lock(&ses->server->srv_mutex);
|
mutex_lock(&server->srv_mutex);
|
||||||
|
|
||||||
rc = allocate_mid(ses, in_buf, &midQ);
|
rc = allocate_mid(ses, in_buf, &midQ);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
mutex_unlock(&ses->server->srv_mutex);
|
mutex_unlock(&server->srv_mutex);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
|
rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_delete_mid(midQ);
|
cifs_delete_mid(midQ);
|
||||||
mutex_unlock(&ses->server->srv_mutex);
|
mutex_unlock(&server->srv_mutex);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
midQ->mid_state = MID_REQUEST_SUBMITTED;
|
midQ->mid_state = MID_REQUEST_SUBMITTED;
|
||||||
cifs_in_send_inc(ses->server);
|
cifs_in_send_inc(server);
|
||||||
rc = smb_send(ses->server, in_buf, len);
|
rc = smb_send(server, in_buf, len);
|
||||||
cifs_in_send_dec(ses->server);
|
cifs_in_send_dec(server);
|
||||||
cifs_save_when_sent(midQ);
|
cifs_save_when_sent(midQ);
|
||||||
|
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
ses->server->sequence_number -= 2;
|
server->sequence_number -= 2;
|
||||||
|
|
||||||
mutex_unlock(&ses->server->srv_mutex);
|
mutex_unlock(&server->srv_mutex);
|
||||||
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
cifs_delete_mid(midQ);
|
cifs_delete_mid(midQ);
|
||||||
@ -1444,21 +1452,21 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for a reply - allow signals to interrupt. */
|
/* Wait for a reply - allow signals to interrupt. */
|
||||||
rc = wait_event_interruptible(ses->server->response_q,
|
rc = wait_event_interruptible(server->response_q,
|
||||||
(!(midQ->mid_state == MID_REQUEST_SUBMITTED)) ||
|
(!(midQ->mid_state == MID_REQUEST_SUBMITTED)) ||
|
||||||
((ses->server->tcpStatus != CifsGood) &&
|
((server->tcpStatus != CifsGood) &&
|
||||||
(ses->server->tcpStatus != CifsNew)));
|
(server->tcpStatus != CifsNew)));
|
||||||
|
|
||||||
/* Were we interrupted by a signal ? */
|
/* Were we interrupted by a signal ? */
|
||||||
if ((rc == -ERESTARTSYS) &&
|
if ((rc == -ERESTARTSYS) &&
|
||||||
(midQ->mid_state == MID_REQUEST_SUBMITTED) &&
|
(midQ->mid_state == MID_REQUEST_SUBMITTED) &&
|
||||||
((ses->server->tcpStatus == CifsGood) ||
|
((server->tcpStatus == CifsGood) ||
|
||||||
(ses->server->tcpStatus == CifsNew))) {
|
(server->tcpStatus == CifsNew))) {
|
||||||
|
|
||||||
if (in_buf->Command == SMB_COM_TRANSACTION2) {
|
if (in_buf->Command == SMB_COM_TRANSACTION2) {
|
||||||
/* POSIX lock. We send a NT_CANCEL SMB to cause the
|
/* POSIX lock. We send a NT_CANCEL SMB to cause the
|
||||||
blocking lock to return. */
|
blocking lock to return. */
|
||||||
rc = send_cancel(ses->server, &rqst, midQ);
|
rc = send_cancel(server, &rqst, midQ);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_delete_mid(midQ);
|
cifs_delete_mid(midQ);
|
||||||
return rc;
|
return rc;
|
||||||
@ -1477,9 +1485,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = wait_for_response(ses->server, midQ);
|
rc = wait_for_response(server, midQ);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
send_cancel(ses->server, &rqst, midQ);
|
send_cancel(server, &rqst, midQ);
|
||||||
spin_lock(&GlobalMid_Lock);
|
spin_lock(&GlobalMid_Lock);
|
||||||
if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
|
if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
|
||||||
/* no longer considered to be "in-flight" */
|
/* no longer considered to be "in-flight" */
|
||||||
@ -1494,20 +1502,20 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
rstart = 1;
|
rstart = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = cifs_sync_mid_result(midQ, ses->server);
|
rc = cifs_sync_mid_result(midQ, server);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* rcvd frame is ok */
|
/* rcvd frame is ok */
|
||||||
if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_RECEIVED) {
|
if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_RECEIVED) {
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
cifs_dbg(VFS, "Bad MID state?\n");
|
cifs_tcon_dbg(VFS, "Bad MID state?\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
|
*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
|
||||||
memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
|
memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
|
||||||
rc = cifs_check_receive(midQ, ses->server, 0);
|
rc = cifs_check_receive(midQ, server, 0);
|
||||||
out:
|
out:
|
||||||
cifs_delete_mid(midQ);
|
cifs_delete_mid(midQ);
|
||||||
if (rstart && rc == -EACCES)
|
if (rstart && rc == -EACCES)
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
Root_NFS = MKDEV(UNNAMED_MAJOR, 255),
|
Root_NFS = MKDEV(UNNAMED_MAJOR, 255),
|
||||||
|
Root_CIFS = MKDEV(UNNAMED_MAJOR, 254),
|
||||||
Root_RAM0 = MKDEV(RAMDISK_MAJOR, 0),
|
Root_RAM0 = MKDEV(RAMDISK_MAJOR, 0),
|
||||||
Root_RAM1 = MKDEV(RAMDISK_MAJOR, 1),
|
Root_RAM1 = MKDEV(RAMDISK_MAJOR, 1),
|
||||||
Root_FD0 = MKDEV(FLOPPY_MAJOR, 0),
|
Root_FD0 = MKDEV(FLOPPY_MAJOR, 0),
|
||||||
|
Loading…
Reference in New Issue
Block a user