some smb3 fixes for stable, as well as addition of ftrace hooks for cifs.ko, and improvements in compounding and smbdirect (RDMA)
-----BEGIN PGP SIGNATURE-----
iQHHBAABCgAxFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAlsUs3QTHHNtZnJlbmNo
QGdtYWlsLmNvbQAKCRCKLL1wB3JPUWFIDACpB/nxQT0l+SMfXe+7W5Txy6x1hasi
fFtcQd03dSzTwGN6ANPmsszktu5LVU1htifwSDIMj9x6MLE+VRCFhuWEszs6N/WD
kQO3DQmuyB3w+s8rkN2V+mjamDuf0jTiq2uLsTvicUsyEmJtJgKJdcmB+bDxXTcE
AQbh5qjMtQIl4IyI6cqxIRm/6laeVyGurJKYGp2G8UcyLg6ddv/vp5mXDIdoCnrv
/gvzi/A7a7UwTEZolFa2vNT/KTLofG8fstdtfqlSa9qTWZwjhoFPKVd3eQPJV3Fj
SjTpwbnM4q0MSY7XijPMkSpnBniaF3e5bf3Cp6QmtQeU+FmfkoYOy7EUlZJ1ar15
xNjLEl/EEfy1C3hIwsdoVB8iLFPhFlAMONUWGjs2cyiTRMZx2OP4VgbyN8pcZUcJ
mGNbBx2SQDJo8iR579dRh2gl6Gy/i5DNOClyIPfEpzGTURrzoV0C9EAnoweyK1qh
wxvdA7SfPRi2rw9a4Kg+PJxWnd8oNRyhzUw=
=EXH7
-----END PGP SIGNATURE-----
Merge tag '4.18-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs updates from Steve French:
- smb3 fixes for stable
- addition of ftrace hooks for cifs.ko
- improvements in compounding and smbdirect (rdma)
* tag '4.18-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6: (38 commits)
CIFS: Add support for direct pages in wdata
CIFS: Use offset when reading pages
CIFS: Add support for direct pages in rdata
cifs: update multiplex loop to handle compounded responses
cifs: remove header_preamble_size where it is always 0
cifs: remove struct smb2_hdr
CIFS: 511c54a2f6
adds a check for session expiry, status STATUS_NETWORK_SESSION_EXPIRED, however the server can also respond with STATUS_USER_SESSION_DELETED in cases where the session has been idle for some time and the server reaps the session to recover resources.
cifs: change smb2_get_data_area_len to take a smb2_sync_hdr as argument
cifs: update smb2_calc_size to use smb2_sync_hdr instead of smb2_hdr
cifs: remove struct smb2_oplock_break_rsp
cifs: remove rfc1002 header from all SMB2 response structures
smb3: on reconnect set PreviousSessionId field
smb3: Add posix create context for smb3.11 posix mounts
smb3: add tracepoints for smb2/smb3 open
cifs: add debug output to show nocase mount option
smb3: add define for id for posix create context and corresponding struct
cifs: update smb2_check_message to handle PDUs without a 4 byte length header
smb3: allow "posix" mount option to enable new SMB311 protocol extensions
smb3: add support for posix negotiate context
cifs: allow disabling less secure legacy dialects
...
This commit is contained in:
commit
325520142b
|
@ -1,11 +1,12 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for Linux CIFS VFS client
|
||||
# Makefile for Linux CIFS/SMB2/SMB3 VFS client
|
||||
#
|
||||
ccflags-y += -I$(src) # needed for trace events
|
||||
obj-$(CONFIG_CIFS) += cifs.o
|
||||
|
||||
cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
|
||||
link.o misc.o netmisc.o smbencrypt.o transport.o asn1.o \
|
||||
cifs-y := trace.o cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o \
|
||||
inode.o link.o misc.o netmisc.o smbencrypt.o transport.o asn1.o \
|
||||
cifs_unicode.o nterr.o cifsencrypt.o \
|
||||
readdir.o ioctl.o sess.o export.o smb1ops.o winucase.o \
|
||||
smb2ops.o smb2maperror.o smb2transport.o \
|
||||
|
|
|
@ -42,7 +42,7 @@ cifs_dump_mem(char *label, void *data, int length)
|
|||
data, length, true);
|
||||
}
|
||||
|
||||
void cifs_dump_detail(void *buf)
|
||||
void cifs_dump_detail(void *buf, struct TCP_Server_Info *server)
|
||||
{
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
struct smb_hdr *smb = (struct smb_hdr *)buf;
|
||||
|
@ -50,7 +50,8 @@ void cifs_dump_detail(void *buf)
|
|||
cifs_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d\n",
|
||||
smb->Command, smb->Status.CifsError,
|
||||
smb->Flags, smb->Flags2, smb->Mid, smb->Pid);
|
||||
cifs_dbg(VFS, "smb buf %p len %u\n", smb, smbCalcSize(smb));
|
||||
cifs_dbg(VFS, "smb buf %p len %u\n", smb,
|
||||
server->ops->calc_smb_size(smb, server));
|
||||
#endif /* CONFIG_CIFS_DEBUG2 */
|
||||
}
|
||||
|
||||
|
@ -83,7 +84,7 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
|
|||
cifs_dbg(VFS, "IsMult: %d IsEnd: %d\n",
|
||||
mid_entry->multiRsp, mid_entry->multiEnd);
|
||||
if (mid_entry->resp_buf) {
|
||||
cifs_dump_detail(mid_entry->resp_buf);
|
||||
cifs_dump_detail(mid_entry->resp_buf, server);
|
||||
cifs_dump_mem("existing buf: ",
|
||||
mid_entry->resp_buf, 62);
|
||||
}
|
||||
|
@ -113,6 +114,8 @@ static void cifs_debug_tcon(struct seq_file *m, struct cifs_tcon *tcon)
|
|||
seq_printf(m, " type: %d ", dev_type);
|
||||
if (tcon->seal)
|
||||
seq_printf(m, " Encrypted");
|
||||
if (tcon->nocase)
|
||||
seq_printf(m, " nocase");
|
||||
if (tcon->unix_ext)
|
||||
seq_printf(m, " POSIX Extensions");
|
||||
if (tcon->ses->server->ops->dump_share_caps)
|
||||
|
@ -237,6 +240,10 @@ skip_rdma:
|
|||
server->credits, server->dialect);
|
||||
if (server->sign)
|
||||
seq_printf(m, " signed");
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if (server->posix_ext_supported)
|
||||
seq_printf(m, " posix");
|
||||
#endif /* 3.1.1 */
|
||||
i++;
|
||||
list_for_each(tmp2, &server->smb_ses_list) {
|
||||
ses = list_entry(tmp2, struct cifs_ses,
|
||||
|
@ -489,32 +496,32 @@ cifs_proc_init(void)
|
|||
cifs_debug_data_proc_show);
|
||||
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
proc_create("Stats", 0, proc_fs_cifs, &cifs_stats_proc_fops);
|
||||
proc_create("Stats", 0644, proc_fs_cifs, &cifs_stats_proc_fops);
|
||||
#endif /* STATS */
|
||||
proc_create("cifsFYI", 0, proc_fs_cifs, &cifsFYI_proc_fops);
|
||||
proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops);
|
||||
proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs,
|
||||
proc_create("cifsFYI", 0644, proc_fs_cifs, &cifsFYI_proc_fops);
|
||||
proc_create("traceSMB", 0644, proc_fs_cifs, &traceSMB_proc_fops);
|
||||
proc_create("LinuxExtensionsEnabled", 0644, proc_fs_cifs,
|
||||
&cifs_linux_ext_proc_fops);
|
||||
proc_create("SecurityFlags", 0, proc_fs_cifs,
|
||||
proc_create("SecurityFlags", 0644, proc_fs_cifs,
|
||||
&cifs_security_flags_proc_fops);
|
||||
proc_create("LookupCacheEnabled", 0, proc_fs_cifs,
|
||||
proc_create("LookupCacheEnabled", 0644, proc_fs_cifs,
|
||||
&cifs_lookup_cache_proc_fops);
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
proc_create("rdma_readwrite_threshold", 0, proc_fs_cifs,
|
||||
proc_create("rdma_readwrite_threshold", 0644, proc_fs_cifs,
|
||||
&cifs_rdma_readwrite_threshold_proc_fops);
|
||||
proc_create("smbd_max_frmr_depth", 0, proc_fs_cifs,
|
||||
proc_create("smbd_max_frmr_depth", 0644, proc_fs_cifs,
|
||||
&cifs_smbd_max_frmr_depth_proc_fops);
|
||||
proc_create("smbd_keep_alive_interval", 0, proc_fs_cifs,
|
||||
proc_create("smbd_keep_alive_interval", 0644, proc_fs_cifs,
|
||||
&cifs_smbd_keep_alive_interval_proc_fops);
|
||||
proc_create("smbd_max_receive_size", 0, proc_fs_cifs,
|
||||
proc_create("smbd_max_receive_size", 0644, proc_fs_cifs,
|
||||
&cifs_smbd_max_receive_size_proc_fops);
|
||||
proc_create("smbd_max_fragmented_recv_size", 0, proc_fs_cifs,
|
||||
proc_create("smbd_max_fragmented_recv_size", 0644, proc_fs_cifs,
|
||||
&cifs_smbd_max_fragmented_recv_size_proc_fops);
|
||||
proc_create("smbd_max_send_size", 0, proc_fs_cifs,
|
||||
proc_create("smbd_max_send_size", 0644, proc_fs_cifs,
|
||||
&cifs_smbd_max_send_size_proc_fops);
|
||||
proc_create("smbd_send_credit_target", 0, proc_fs_cifs,
|
||||
proc_create("smbd_send_credit_target", 0644, proc_fs_cifs,
|
||||
&cifs_smbd_send_credit_target_proc_fops);
|
||||
proc_create("smbd_receive_credit_max", 0, proc_fs_cifs,
|
||||
proc_create("smbd_receive_credit_max", 0644, proc_fs_cifs,
|
||||
&cifs_smbd_receive_credit_max_proc_fops);
|
||||
#endif
|
||||
}
|
||||
|
@ -572,6 +579,8 @@ static ssize_t cifsFYI_proc_write(struct file *file, const char __user *buffer,
|
|||
cifsFYI = bv;
|
||||
else if ((c[0] > '1') && (c[0] <= '9'))
|
||||
cifsFYI = (int) (c[0] - '0'); /* see cifs_debug.h for meanings */
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#define _H_CIFS_DEBUG
|
||||
|
||||
void cifs_dump_mem(char *label, void *data, int length);
|
||||
void cifs_dump_detail(void *);
|
||||
void cifs_dump_detail(void *buf, struct TCP_Server_Info *ptcp_info);
|
||||
void cifs_dump_mids(struct TCP_Server_Info *);
|
||||
extern bool traceSMB; /* flag which enables the function below */
|
||||
void dump_smb(void *, int);
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
* root mountable
|
||||
*/
|
||||
#define CIFS_MOUNT_UID_FROM_ACL 0x2000000 /* try to get UID via special SID */
|
||||
#define CIFS_MOUNT_NO_HANDLE_CACHE 0x4000000 /* disable caching dir handles */
|
||||
|
||||
struct cifs_sb_info {
|
||||
struct rb_root tlink_tree;
|
||||
|
|
|
@ -58,13 +58,15 @@ bool traceSMB;
|
|||
bool enable_oplocks = true;
|
||||
bool linuxExtEnabled = true;
|
||||
bool lookupCacheEnabled = true;
|
||||
bool disable_legacy_dialects; /* false by default */
|
||||
unsigned int global_secflags = CIFSSEC_DEF;
|
||||
/* unsigned int ntlmv2_support = 0; */
|
||||
unsigned int sign_CIFS_PDUs = 1;
|
||||
static const struct super_operations cifs_super_ops;
|
||||
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
|
||||
module_param(CIFSMaxBufSize, uint, 0444);
|
||||
MODULE_PARM_DESC(CIFSMaxBufSize, "Network buffer size (not including header). "
|
||||
MODULE_PARM_DESC(CIFSMaxBufSize, "Network buffer size (not including header) "
|
||||
"for CIFS requests. "
|
||||
"Default: 16384 Range: 8192 to 130048");
|
||||
unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL;
|
||||
module_param(cifs_min_rcv, uint, 0444);
|
||||
|
@ -76,11 +78,21 @@ MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 "
|
|||
"Range: 2 to 256");
|
||||
unsigned int cifs_max_pending = CIFS_MAX_REQ;
|
||||
module_param(cifs_max_pending, uint, 0444);
|
||||
MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
|
||||
MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server for "
|
||||
"CIFS/SMB1 dialect (N/A for SMB3) "
|
||||
"Default: 32767 Range: 2 to 32767.");
|
||||
module_param(enable_oplocks, bool, 0644);
|
||||
MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks. Default: y/Y/1");
|
||||
|
||||
module_param(disable_legacy_dialects, bool, 0644);
|
||||
MODULE_PARM_DESC(disable_legacy_dialects, "To improve security it may be "
|
||||
"helpful to restrict the ability to "
|
||||
"override the default dialects (SMB2.1, "
|
||||
"SMB3 and SMB3.02) on mount with old "
|
||||
"dialects (CIFS/SMB1 and SMB2) since "
|
||||
"vers=1.0 (CIFS/SMB1) and vers=2.0 are weaker"
|
||||
" and less secure. Default: n/N/0");
|
||||
|
||||
extern mempool_t *cifs_sm_req_poolp;
|
||||
extern mempool_t *cifs_req_poolp;
|
||||
extern mempool_t *cifs_mid_poolp;
|
||||
|
@ -469,10 +481,20 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
|
|||
seq_puts(s, ",persistenthandles");
|
||||
else if (tcon->use_resilient)
|
||||
seq_puts(s, ",resilienthandles");
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if (tcon->posix_extensions)
|
||||
seq_puts(s, ",posix");
|
||||
else if (tcon->unix_ext)
|
||||
seq_puts(s, ",unix");
|
||||
else
|
||||
seq_puts(s, ",nounix");
|
||||
#else
|
||||
if (tcon->unix_ext)
|
||||
seq_puts(s, ",unix");
|
||||
else
|
||||
seq_puts(s, ",nounix");
|
||||
#endif /* SMB311 */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
|
||||
seq_puts(s, ",posixpaths");
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
|
||||
|
@ -495,6 +517,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
|
|||
seq_puts(s, ",sfu");
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
||||
seq_puts(s, ",nobrl");
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_HANDLE_CACHE)
|
||||
seq_puts(s, ",nohandlecache");
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
|
||||
seq_puts(s, ",cifsacl");
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
|
||||
|
@ -897,6 +921,17 @@ struct file_system_type cifs_fs_type = {
|
|||
/* .fs_flags */
|
||||
};
|
||||
MODULE_ALIAS_FS("cifs");
|
||||
|
||||
static struct file_system_type smb3_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "smb3",
|
||||
.mount = cifs_do_mount,
|
||||
.kill_sb = cifs_kill_sb,
|
||||
/* .fs_flags */
|
||||
};
|
||||
MODULE_ALIAS_FS("smb3");
|
||||
MODULE_ALIAS("smb3");
|
||||
|
||||
const struct inode_operations cifs_dir_inode_ops = {
|
||||
.create = cifs_create,
|
||||
.atomic_open = cifs_atomic_open,
|
||||
|
@ -1435,6 +1470,12 @@ init_cifs(void)
|
|||
if (rc)
|
||||
goto out_init_cifs_idmap;
|
||||
|
||||
rc = register_filesystem(&smb3_fs_type);
|
||||
if (rc) {
|
||||
unregister_filesystem(&cifs_fs_type);
|
||||
goto out_init_cifs_idmap;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_init_cifs_idmap:
|
||||
|
@ -1465,8 +1506,9 @@ out_clean_proc:
|
|||
static void __exit
|
||||
exit_cifs(void)
|
||||
{
|
||||
cifs_dbg(NOISY, "exit_cifs\n");
|
||||
cifs_dbg(NOISY, "exit_smb3\n");
|
||||
unregister_filesystem(&cifs_fs_type);
|
||||
unregister_filesystem(&smb3_fs_type);
|
||||
cifs_dfs_release_automount_timer();
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
exit_cifs_idmap();
|
||||
|
|
|
@ -149,5 +149,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
|||
extern const struct export_operations cifs_export_ops;
|
||||
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
||||
|
||||
#define CIFS_VERSION "2.11"
|
||||
#define CIFS_VERSION "2.12"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
|
|
@ -176,6 +176,7 @@ struct smb_rqst {
|
|||
struct kvec *rq_iov; /* array of kvecs */
|
||||
unsigned int rq_nvec; /* number of kvecs in array */
|
||||
struct page **rq_pages; /* pointer to array of page ptrs */
|
||||
unsigned int rq_offset; /* the offset to the 1st page */
|
||||
unsigned int rq_npages; /* number pages in array */
|
||||
unsigned int rq_pagesz; /* page size to use */
|
||||
unsigned int rq_tailsz; /* length of last page */
|
||||
|
@ -244,7 +245,7 @@ struct smb_version_operations {
|
|||
int (*map_error)(char *, bool);
|
||||
/* find mid corresponding to the response message */
|
||||
struct mid_q_entry * (*find_mid)(struct TCP_Server_Info *, char *);
|
||||
void (*dump_detail)(void *);
|
||||
void (*dump_detail)(void *buf, struct TCP_Server_Info *ptcp_info);
|
||||
void (*clear_stats)(struct cifs_tcon *);
|
||||
void (*print_stats)(struct seq_file *m, struct cifs_tcon *);
|
||||
void (*dump_share_caps)(struct seq_file *, struct cifs_tcon *);
|
||||
|
@ -372,7 +373,7 @@ struct smb_version_operations {
|
|||
int (*close_dir)(const unsigned int, struct cifs_tcon *,
|
||||
struct cifs_fid *);
|
||||
/* calculate a size of SMB message */
|
||||
unsigned int (*calc_smb_size)(void *);
|
||||
unsigned int (*calc_smb_size)(void *buf, struct TCP_Server_Info *ptcpi);
|
||||
/* check for STATUS_PENDING and process it in a positive case */
|
||||
bool (*is_status_pending)(char *, struct TCP_Server_Info *, int);
|
||||
/* check for STATUS_NETWORK_SESSION_EXPIRED */
|
||||
|
@ -417,7 +418,7 @@ struct smb_version_operations {
|
|||
/* create lease context buffer for CREATE request */
|
||||
char * (*create_lease_buf)(u8 *, u8);
|
||||
/* parse lease context buffer and return oplock/epoch info */
|
||||
__u8 (*parse_lease_buf)(void *, unsigned int *);
|
||||
__u8 (*parse_lease_buf)(void *buf, unsigned int *epoch, char *lkey);
|
||||
ssize_t (*copychunk_range)(const unsigned int,
|
||||
struct cifsFileInfo *src_file,
|
||||
struct cifsFileInfo *target_file,
|
||||
|
@ -457,7 +458,7 @@ struct smb_version_operations {
|
|||
struct mid_q_entry **);
|
||||
enum securityEnum (*select_sectype)(struct TCP_Server_Info *,
|
||||
enum securityEnum);
|
||||
|
||||
int (*next_header)(char *);
|
||||
};
|
||||
|
||||
struct smb_version_values {
|
||||
|
@ -521,10 +522,12 @@ struct smb_vol {
|
|||
bool sfu_remap:1; /* remap seven reserved chars ala SFU */
|
||||
bool posix_paths:1; /* unset to not ask for posix pathnames. */
|
||||
bool no_linux_ext:1;
|
||||
bool linux_ext:1;
|
||||
bool sfu_emul:1;
|
||||
bool nullauth:1; /* attempt to authenticate with null user */
|
||||
bool nocase:1; /* request case insensitive filenames */
|
||||
bool nobrl:1; /* disable sending byte range locks to srv */
|
||||
bool nohandlecache:1; /* disable caching dir handles if srvr probs */
|
||||
bool mand_lock:1; /* send mandatory not posix byte range lock reqs */
|
||||
bool seal:1; /* request transport encryption on share */
|
||||
bool nodfs:1; /* Do not request DFS, even if available */
|
||||
|
@ -630,7 +633,7 @@ struct TCP_Server_Info {
|
|||
bool oplocks:1; /* enable oplocks */
|
||||
unsigned int maxReq; /* Clients should submit no more */
|
||||
/* than maxReq distinct unanswered SMBs to the server when using */
|
||||
/* multiplexed reads or writes */
|
||||
/* multiplexed reads or writes (for SMB1/CIFS only, not SMB2/SMB3) */
|
||||
unsigned int maxBuf; /* maxBuf specifies the maximum */
|
||||
/* message size the server can send or receive for non-raw SMBs */
|
||||
/* maxBuf is returned by SMB NegotiateProtocol so maxBuf is only 0 */
|
||||
|
@ -681,6 +684,7 @@ struct TCP_Server_Info {
|
|||
__le16 cipher_type;
|
||||
/* save initital negprot hash */
|
||||
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
|
||||
bool posix_ext_supported;
|
||||
#endif /* 3.1.1 */
|
||||
struct delayed_work reconnect; /* reconnect workqueue job */
|
||||
struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
|
||||
|
@ -953,9 +957,13 @@ struct cifs_tcon {
|
|||
bool print:1; /* set if connection to printer share */
|
||||
bool retry:1;
|
||||
bool nocase:1;
|
||||
bool nohandlecache:1; /* if strange server resource prob can turn off */
|
||||
bool seal:1; /* transport encryption for this mounted share */
|
||||
bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol
|
||||
for this mount even if server would support */
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
bool posix_extensions; /* if true SMB3.11 posix extensions enabled */
|
||||
#endif /* CIFS_311 */
|
||||
bool local_lease:1; /* check leases (only) on local system not remote */
|
||||
bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
|
||||
bool broken_sparse_sup; /* if server or share does not support sparse */
|
||||
|
@ -979,6 +987,9 @@ struct cifs_tcon {
|
|||
struct fscache_cookie *fscache; /* cookie for share */
|
||||
#endif
|
||||
struct list_head pending_opens; /* list of incomplete opens */
|
||||
bool valid_root_fid:1; /* Do we have a useable root fid */
|
||||
struct mutex prfid_mutex; /* prevents reopen race after dead ses*/
|
||||
struct cifs_fid *prfid; /* handle to the directory at top of share */
|
||||
/* BB add field for back pointer to sb struct(s)? */
|
||||
};
|
||||
|
||||
|
@ -1071,6 +1082,7 @@ struct cifs_open_parms {
|
|||
int create_options;
|
||||
const char *path;
|
||||
struct cifs_fid *fid;
|
||||
umode_t mode;
|
||||
bool reconnect:1;
|
||||
};
|
||||
|
||||
|
@ -1169,10 +1181,11 @@ struct cifs_readdata {
|
|||
struct smbd_mr *mr;
|
||||
#endif
|
||||
unsigned int pagesz;
|
||||
unsigned int page_offset;
|
||||
unsigned int tailsz;
|
||||
unsigned int credits;
|
||||
unsigned int nr_pages;
|
||||
struct page *pages[];
|
||||
struct page **pages;
|
||||
};
|
||||
|
||||
struct cifs_writedata;
|
||||
|
@ -1194,10 +1207,11 @@ struct cifs_writedata {
|
|||
struct smbd_mr *mr;
|
||||
#endif
|
||||
unsigned int pagesz;
|
||||
unsigned int page_offset;
|
||||
unsigned int tailsz;
|
||||
unsigned int credits;
|
||||
unsigned int nr_pages;
|
||||
struct page *pages[];
|
||||
struct page **pages;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1692,16 +1706,17 @@ GLOBAL_EXTERN atomic_t smBufAllocCount;
|
|||
GLOBAL_EXTERN atomic_t midCount;
|
||||
|
||||
/* Misc globals */
|
||||
GLOBAL_EXTERN bool enable_oplocks; /* enable or disable oplocks */
|
||||
GLOBAL_EXTERN bool lookupCacheEnabled;
|
||||
GLOBAL_EXTERN unsigned int global_secflags; /* if on, session setup sent
|
||||
extern bool enable_oplocks; /* enable or disable oplocks */
|
||||
extern bool lookupCacheEnabled;
|
||||
extern unsigned int global_secflags; /* if on, session setup sent
|
||||
with more secure ntlmssp2 challenge/resp */
|
||||
GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */
|
||||
GLOBAL_EXTERN bool linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
|
||||
GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */
|
||||
GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */
|
||||
GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */
|
||||
GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
|
||||
extern unsigned int sign_CIFS_PDUs; /* enable smb packet signing */
|
||||
extern bool linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
|
||||
extern unsigned int CIFSMaxBufSize; /* max size not including hdr */
|
||||
extern unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */
|
||||
extern unsigned int cifs_min_small; /* min size of small buf pool */
|
||||
extern unsigned int cifs_max_pending; /* MAX requests at once to server*/
|
||||
extern bool disable_legacy_dialects; /* forbid vers=1.0 and vers=2.0 mounts */
|
||||
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
GLOBAL_EXTERN struct rb_root uidtree;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#ifndef _CIFSPROTO_H
|
||||
#define _CIFSPROTO_H
|
||||
#include <linux/nls.h>
|
||||
#include "trace.h"
|
||||
|
||||
struct statfs;
|
||||
struct smb_vol;
|
||||
|
@ -47,6 +48,7 @@ extern void _free_xid(unsigned int);
|
|||
cifs_dbg(FYI, "CIFS VFS: in %s as Xid: %u with uid: %d\n", \
|
||||
__func__, __xid, \
|
||||
from_kuid(&init_user_ns, current_fsuid())); \
|
||||
trace_smb3_enter(__xid, __func__); \
|
||||
__xid; \
|
||||
})
|
||||
|
||||
|
@ -54,7 +56,11 @@ extern void _free_xid(unsigned int);
|
|||
do { \
|
||||
_free_xid(curr_xid); \
|
||||
cifs_dbg(FYI, "CIFS VFS: leaving %s (xid = %u) rc = %d\n", \
|
||||
__func__, curr_xid, (int)rc); \
|
||||
__func__, curr_xid, (int)rc); \
|
||||
if (rc) \
|
||||
trace_smb3_exit_err(curr_xid, __func__, (int)rc); \
|
||||
else \
|
||||
trace_smb3_exit_done(curr_xid, __func__); \
|
||||
} while (0)
|
||||
extern int init_cifs_idmap(void);
|
||||
extern void exit_cifs_idmap(void);
|
||||
|
@ -124,7 +130,7 @@ extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
|
|||
unsigned int bytes_written);
|
||||
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
|
||||
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
|
||||
extern unsigned int smbCalcSize(void *buf);
|
||||
extern unsigned int smbCalcSize(void *buf, struct TCP_Server_Info *server);
|
||||
extern int decode_negTokenInit(unsigned char *security_blob, int length,
|
||||
struct TCP_Server_Info *server);
|
||||
extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
|
||||
|
@ -197,7 +203,9 @@ extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
|
|||
extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
|
||||
unsigned int to_read);
|
||||
extern int cifs_read_page_from_socket(struct TCP_Server_Info *server,
|
||||
struct page *page, unsigned int to_read);
|
||||
struct page *page,
|
||||
unsigned int page_offset,
|
||||
unsigned int to_read);
|
||||
extern int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
|
||||
struct cifs_sb_info *cifs_sb);
|
||||
extern int cifs_match_super(struct super_block *, void *);
|
||||
|
@ -525,6 +533,8 @@ int cifs_async_writev(struct cifs_writedata *wdata,
|
|||
void cifs_writev_complete(struct work_struct *work);
|
||||
struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
|
||||
work_func_t complete);
|
||||
struct cifs_writedata *cifs_writedata_direct_alloc(struct page **pages,
|
||||
work_func_t complete);
|
||||
void cifs_writedata_release(struct kref *refcount);
|
||||
int cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
|
|
|
@ -106,6 +106,12 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
|
|||
open_file->oplock_break_cancelled = true;
|
||||
}
|
||||
spin_unlock(&tcon->open_file_lock);
|
||||
|
||||
mutex_lock(&tcon->prfid_mutex);
|
||||
tcon->valid_root_fid = false;
|
||||
memset(tcon->prfid, 0, sizeof(struct cifs_fid));
|
||||
mutex_unlock(&tcon->prfid_mutex);
|
||||
|
||||
/*
|
||||
* BB Add call to invalidate_inodes(sb) for all superblocks mounted
|
||||
* to this tcon.
|
||||
|
@ -1946,6 +1952,7 @@ cifs_writedata_release(struct kref *refcount)
|
|||
if (wdata->cfile)
|
||||
cifsFileInfo_put(wdata->cfile);
|
||||
|
||||
kvfree(wdata->pages);
|
||||
kfree(wdata);
|
||||
}
|
||||
|
||||
|
@ -2068,13 +2075,23 @@ cifs_writev_complete(struct work_struct *work)
|
|||
|
||||
struct cifs_writedata *
|
||||
cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
|
||||
{
|
||||
struct page **pages =
|
||||
kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS);
|
||||
if (pages)
|
||||
return cifs_writedata_direct_alloc(pages, complete);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct cifs_writedata *
|
||||
cifs_writedata_direct_alloc(struct page **pages, work_func_t complete)
|
||||
{
|
||||
struct cifs_writedata *wdata;
|
||||
|
||||
/* writedata + number of page pointers */
|
||||
wdata = kzalloc(sizeof(*wdata) +
|
||||
sizeof(struct page *) * nr_pages, GFP_NOFS);
|
||||
wdata = kzalloc(sizeof(*wdata), GFP_NOFS);
|
||||
if (wdata != NULL) {
|
||||
wdata->pages = pages;
|
||||
kref_init(&wdata->refcount);
|
||||
INIT_LIST_HEAD(&wdata->list);
|
||||
init_completion(&wdata->done);
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#define RFC1001_PORT 139
|
||||
|
||||
extern mempool_t *cifs_req_poolp;
|
||||
extern bool disable_legacy_dialects;
|
||||
|
||||
/* FIXME: should these be tunable? */
|
||||
#define TLINK_ERROR_EXPIRE (1 * HZ)
|
||||
|
@ -76,9 +77,10 @@ enum {
|
|||
Opt_mapposix, Opt_nomapposix,
|
||||
Opt_mapchars, Opt_nomapchars, Opt_sfu,
|
||||
Opt_nosfu, Opt_nodfs, Opt_posixpaths,
|
||||
Opt_noposixpaths, Opt_nounix,
|
||||
Opt_noposixpaths, Opt_nounix, Opt_unix,
|
||||
Opt_nocase,
|
||||
Opt_brl, Opt_nobrl,
|
||||
Opt_handlecache, Opt_nohandlecache,
|
||||
Opt_forcemandatorylock, Opt_setuidfromacl, Opt_setuids,
|
||||
Opt_nosetuids, Opt_dynperm, Opt_nodynperm,
|
||||
Opt_nohard, Opt_nosoft,
|
||||
|
@ -144,10 +146,16 @@ static const match_table_t cifs_mount_option_tokens = {
|
|||
{ Opt_noposixpaths, "noposixpaths" },
|
||||
{ Opt_nounix, "nounix" },
|
||||
{ Opt_nounix, "nolinux" },
|
||||
{ Opt_nounix, "noposix" },
|
||||
{ Opt_unix, "unix" },
|
||||
{ Opt_unix, "linux" },
|
||||
{ Opt_unix, "posix" },
|
||||
{ Opt_nocase, "nocase" },
|
||||
{ Opt_nocase, "ignorecase" },
|
||||
{ Opt_brl, "brl" },
|
||||
{ Opt_nobrl, "nobrl" },
|
||||
{ Opt_handlecache, "handlecache" },
|
||||
{ Opt_nohandlecache, "nohandlecache" },
|
||||
{ Opt_nobrl, "nolock" },
|
||||
{ Opt_forcemandatorylock, "forcemandatorylock" },
|
||||
{ Opt_forcemandatorylock, "forcemand" },
|
||||
|
@ -591,10 +599,11 @@ cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
|
|||
|
||||
int
|
||||
cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page,
|
||||
unsigned int to_read)
|
||||
unsigned int page_offset, unsigned int to_read)
|
||||
{
|
||||
struct msghdr smb_msg;
|
||||
struct bio_vec bv = {.bv_page = page, .bv_len = to_read};
|
||||
struct bio_vec bv = {
|
||||
.bv_page = page, .bv_len = to_read, .bv_offset = page_offset};
|
||||
iov_iter_bvec(&smb_msg.msg_iter, READ | ITER_BVEC, &bv, 1, to_read);
|
||||
return cifs_readv_from_socket(server, &smb_msg);
|
||||
}
|
||||
|
@ -848,6 +857,7 @@ cifs_demultiplex_thread(void *p)
|
|||
int length;
|
||||
struct TCP_Server_Info *server = p;
|
||||
unsigned int pdu_length;
|
||||
unsigned int next_offset;
|
||||
char *buf = NULL;
|
||||
struct task_struct *task_to_wake = NULL;
|
||||
struct mid_q_entry *mid_entry;
|
||||
|
@ -874,24 +884,29 @@ cifs_demultiplex_thread(void *p)
|
|||
length = cifs_read_from_socket(server, buf, pdu_length);
|
||||
if (length < 0)
|
||||
continue;
|
||||
server->total_read = length;
|
||||
|
||||
if (server->vals->header_preamble_size == 0)
|
||||
server->total_read = 0;
|
||||
else
|
||||
server->total_read = length;
|
||||
|
||||
/*
|
||||
* The right amount was read from socket - 4 bytes,
|
||||
* so we can now interpret the length field.
|
||||
*/
|
||||
pdu_length = get_rfc1002_length(buf);
|
||||
server->pdu_size = pdu_length;
|
||||
|
||||
cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length);
|
||||
if (!is_smb_response(server, buf[0]))
|
||||
continue;
|
||||
next_pdu:
|
||||
server->pdu_size = pdu_length;
|
||||
|
||||
/* make sure we have enough to get to the MID */
|
||||
if (pdu_length < HEADER_SIZE(server) - 1 -
|
||||
if (server->pdu_size < HEADER_SIZE(server) - 1 -
|
||||
server->vals->header_preamble_size) {
|
||||
cifs_dbg(VFS, "SMB response too short (%u bytes)\n",
|
||||
pdu_length);
|
||||
server->pdu_size);
|
||||
cifs_reconnect(server);
|
||||
wake_up(&server->response_q);
|
||||
continue;
|
||||
|
@ -906,6 +921,12 @@ cifs_demultiplex_thread(void *p)
|
|||
continue;
|
||||
server->total_read += length;
|
||||
|
||||
if (server->ops->next_header) {
|
||||
next_offset = server->ops->next_header(buf);
|
||||
if (next_offset)
|
||||
server->pdu_size = next_offset;
|
||||
}
|
||||
|
||||
if (server->ops->is_transform_hdr &&
|
||||
server->ops->receive_transform &&
|
||||
server->ops->is_transform_hdr(buf)) {
|
||||
|
@ -948,10 +969,18 @@ cifs_demultiplex_thread(void *p)
|
|||
HEADER_SIZE(server));
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
if (server->ops->dump_detail)
|
||||
server->ops->dump_detail(buf);
|
||||
server->ops->dump_detail(buf, server);
|
||||
cifs_dump_mids(server);
|
||||
#endif /* CIFS_DEBUG2 */
|
||||
|
||||
}
|
||||
if (pdu_length > server->pdu_size) {
|
||||
if (!allocate_buffers(server))
|
||||
continue;
|
||||
pdu_length -= server->pdu_size;
|
||||
server->total_read = 0;
|
||||
server->large_buf = false;
|
||||
buf = server->smallbuf;
|
||||
goto next_pdu;
|
||||
}
|
||||
} /* end while !EXITING */
|
||||
|
||||
|
@ -1143,10 +1172,18 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol)
|
|||
|
||||
switch (match_token(value, cifs_smb_version_tokens, args)) {
|
||||
case Smb_1:
|
||||
if (disable_legacy_dialects) {
|
||||
cifs_dbg(VFS, "mount with legacy dialect disabled\n");
|
||||
return 1;
|
||||
}
|
||||
vol->ops = &smb1_operations;
|
||||
vol->vals = &smb1_values;
|
||||
break;
|
||||
case Smb_20:
|
||||
if (disable_legacy_dialects) {
|
||||
cifs_dbg(VFS, "mount with legacy dialect disabled\n");
|
||||
return 1;
|
||||
}
|
||||
vol->ops = &smb20_operations;
|
||||
vol->vals = &smb20_values;
|
||||
break;
|
||||
|
@ -1426,8 +1463,17 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
|
|||
vol->posix_paths = 0;
|
||||
break;
|
||||
case Opt_nounix:
|
||||
if (vol->linux_ext)
|
||||
cifs_dbg(VFS,
|
||||
"conflicting unix mount options\n");
|
||||
vol->no_linux_ext = 1;
|
||||
break;
|
||||
case Opt_unix:
|
||||
if (vol->no_linux_ext)
|
||||
cifs_dbg(VFS,
|
||||
"conflicting unix mount options\n");
|
||||
vol->linux_ext = 1;
|
||||
break;
|
||||
case Opt_nocase:
|
||||
vol->nocase = 1;
|
||||
break;
|
||||
|
@ -1445,6 +1491,12 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
|
|||
(S_IALLUGO & ~(S_ISUID | S_IXGRP)))
|
||||
vol->file_mode = S_IALLUGO;
|
||||
break;
|
||||
case Opt_nohandlecache:
|
||||
vol->nohandlecache = 1;
|
||||
break;
|
||||
case Opt_handlecache:
|
||||
vol->nohandlecache = 0;
|
||||
break;
|
||||
case Opt_forcemandatorylock:
|
||||
vol->mand_lock = 1;
|
||||
break;
|
||||
|
@ -2967,6 +3019,13 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if ((volume_info->linux_ext) && (ses->server->posix_ext_supported)) {
|
||||
if (ses->server->vals->protocol_id == SMB311_PROT_ID)
|
||||
tcon->posix_extensions = true;
|
||||
}
|
||||
#endif /* 311 */
|
||||
|
||||
/*
|
||||
* BB Do we need to wrap session_mutex around this TCon call and Unix
|
||||
* SetFS as we do on SessSetup and reconnect?
|
||||
|
@ -3022,6 +3081,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
|
|||
*/
|
||||
tcon->retry = volume_info->retry;
|
||||
tcon->nocase = volume_info->nocase;
|
||||
tcon->nohandlecache = volume_info->nohandlecache;
|
||||
tcon->local_lease = volume_info->local_lease;
|
||||
INIT_LIST_HEAD(&tcon->pending_opens);
|
||||
|
||||
|
@ -3580,6 +3640,8 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
|
|||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
|
||||
if (pvolume_info->nobrl)
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
|
||||
if (pvolume_info->nohandlecache)
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_HANDLE_CACHE;
|
||||
if (pvolume_info->nostrictsync)
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC;
|
||||
if (pvolume_info->mand_lock)
|
||||
|
@ -3922,6 +3984,12 @@ try_mount_again:
|
|||
goto remote_path_check;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
/* if new SMB3.11 POSIX extensions are supported do not remap / and \ */
|
||||
if (tcon->posix_extensions)
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
|
||||
#endif /* SMB3.11 */
|
||||
|
||||
/* tell server which Unix caps we support */
|
||||
if (cap_unix(tcon->ses)) {
|
||||
/* reset of caps checks mount to see if unix extensions
|
||||
|
@ -4353,6 +4421,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
|
|||
vol_info->UNC = master_tcon->treeName;
|
||||
vol_info->retry = master_tcon->retry;
|
||||
vol_info->nocase = master_tcon->nocase;
|
||||
vol_info->nohandlecache = master_tcon->nohandlecache;
|
||||
vol_info->local_lease = master_tcon->local_lease;
|
||||
vol_info->no_linux_ext = !master_tcon->unix_ext;
|
||||
vol_info->sectype = master_tcon->ses->sectype;
|
||||
|
@ -4382,8 +4451,14 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
|
|||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
/* if new SMB3.11 POSIX extensions are supported do not remap / and \ */
|
||||
if (tcon->posix_extensions)
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
|
||||
#endif /* SMB3.11 */
|
||||
if (cap_unix(ses))
|
||||
reset_cifs_unix_caps(0, tcon, NULL, vol_info);
|
||||
|
||||
out:
|
||||
kfree(vol_info->username);
|
||||
kzfree(vol_info->password);
|
||||
|
|
|
@ -369,7 +369,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
|
|||
oparms.path = full_path;
|
||||
oparms.fid = fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
oparms.mode = mode;
|
||||
rc = server->ops->open(xid, &oparms, oplock, buf);
|
||||
if (rc) {
|
||||
cifs_dbg(FYI, "cifs_create returned 0x%x\n", rc);
|
||||
|
|
|
@ -2880,13 +2880,13 @@ out:
|
|||
}
|
||||
|
||||
static struct cifs_readdata *
|
||||
cifs_readdata_alloc(unsigned int nr_pages, work_func_t complete)
|
||||
cifs_readdata_direct_alloc(struct page **pages, work_func_t complete)
|
||||
{
|
||||
struct cifs_readdata *rdata;
|
||||
|
||||
rdata = kzalloc(sizeof(*rdata) + (sizeof(struct page *) * nr_pages),
|
||||
GFP_KERNEL);
|
||||
rdata = kzalloc(sizeof(*rdata), GFP_KERNEL);
|
||||
if (rdata != NULL) {
|
||||
rdata->pages = pages;
|
||||
kref_init(&rdata->refcount);
|
||||
INIT_LIST_HEAD(&rdata->list);
|
||||
init_completion(&rdata->done);
|
||||
|
@ -2896,6 +2896,22 @@ cifs_readdata_alloc(unsigned int nr_pages, work_func_t complete)
|
|||
return rdata;
|
||||
}
|
||||
|
||||
static struct cifs_readdata *
|
||||
cifs_readdata_alloc(unsigned int nr_pages, work_func_t complete)
|
||||
{
|
||||
struct page **pages =
|
||||
kzalloc(sizeof(struct page *) * nr_pages, GFP_KERNEL);
|
||||
struct cifs_readdata *ret = NULL;
|
||||
|
||||
if (pages) {
|
||||
ret = cifs_readdata_direct_alloc(pages, complete);
|
||||
if (!ret)
|
||||
kfree(pages);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
cifs_readdata_release(struct kref *refcount)
|
||||
{
|
||||
|
@ -2910,6 +2926,7 @@ cifs_readdata_release(struct kref *refcount)
|
|||
if (rdata->cfile)
|
||||
cifsFileInfo_put(rdata->cfile);
|
||||
|
||||
kvfree(rdata->pages);
|
||||
kfree(rdata);
|
||||
}
|
||||
|
||||
|
@ -3009,12 +3026,20 @@ uncached_fill_pages(struct TCP_Server_Info *server,
|
|||
int result = 0;
|
||||
unsigned int i;
|
||||
unsigned int nr_pages = rdata->nr_pages;
|
||||
unsigned int page_offset = rdata->page_offset;
|
||||
|
||||
rdata->got_bytes = 0;
|
||||
rdata->tailsz = PAGE_SIZE;
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
struct page *page = rdata->pages[i];
|
||||
size_t n;
|
||||
unsigned int segment_size = rdata->pagesz;
|
||||
|
||||
if (i == 0)
|
||||
segment_size -= page_offset;
|
||||
else
|
||||
page_offset = 0;
|
||||
|
||||
|
||||
if (len <= 0) {
|
||||
/* no need to hold page hostage */
|
||||
|
@ -3023,24 +3048,25 @@ uncached_fill_pages(struct TCP_Server_Info *server,
|
|||
put_page(page);
|
||||
continue;
|
||||
}
|
||||
|
||||
n = len;
|
||||
if (len >= PAGE_SIZE) {
|
||||
if (len >= segment_size)
|
||||
/* enough data to fill the page */
|
||||
n = PAGE_SIZE;
|
||||
len -= n;
|
||||
} else {
|
||||
zero_user(page, len, PAGE_SIZE - len);
|
||||
n = segment_size;
|
||||
else
|
||||
rdata->tailsz = len;
|
||||
len = 0;
|
||||
}
|
||||
len -= n;
|
||||
|
||||
if (iter)
|
||||
result = copy_page_from_iter(page, 0, n, iter);
|
||||
result = copy_page_from_iter(
|
||||
page, page_offset, n, iter);
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
else if (rdata->mr)
|
||||
result = n;
|
||||
#endif
|
||||
else
|
||||
result = cifs_read_page_from_socket(server, page, n);
|
||||
result = cifs_read_page_from_socket(
|
||||
server, page, page_offset, n);
|
||||
if (result < 0)
|
||||
break;
|
||||
|
||||
|
@ -3113,6 +3139,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
|
|||
rdata->bytes = cur_len;
|
||||
rdata->pid = pid;
|
||||
rdata->pagesz = PAGE_SIZE;
|
||||
rdata->tailsz = PAGE_SIZE;
|
||||
rdata->read_into_pages = cifs_uncached_read_into_pages;
|
||||
rdata->copy_into_pages = cifs_uncached_copy_into_pages;
|
||||
rdata->credits = credits;
|
||||
|
@ -3557,6 +3584,7 @@ readpages_fill_pages(struct TCP_Server_Info *server,
|
|||
u64 eof;
|
||||
pgoff_t eof_index;
|
||||
unsigned int nr_pages = rdata->nr_pages;
|
||||
unsigned int page_offset = rdata->page_offset;
|
||||
|
||||
/* determine the eof that the server (probably) has */
|
||||
eof = CIFS_I(rdata->mapping->host)->server_eof;
|
||||
|
@ -3567,13 +3595,21 @@ readpages_fill_pages(struct TCP_Server_Info *server,
|
|||
rdata->tailsz = PAGE_SIZE;
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
struct page *page = rdata->pages[i];
|
||||
size_t n = PAGE_SIZE;
|
||||
unsigned int to_read = rdata->pagesz;
|
||||
size_t n;
|
||||
|
||||
if (len >= PAGE_SIZE) {
|
||||
len -= PAGE_SIZE;
|
||||
if (i == 0)
|
||||
to_read -= page_offset;
|
||||
else
|
||||
page_offset = 0;
|
||||
|
||||
n = to_read;
|
||||
|
||||
if (len >= to_read) {
|
||||
len -= to_read;
|
||||
} else if (len > 0) {
|
||||
/* enough for partial page, fill and zero the rest */
|
||||
zero_user(page, len, PAGE_SIZE - len);
|
||||
zero_user(page, len + page_offset, to_read - len);
|
||||
n = rdata->tailsz = len;
|
||||
len = 0;
|
||||
} else if (page->index > eof_index) {
|
||||
|
@ -3605,13 +3641,15 @@ readpages_fill_pages(struct TCP_Server_Info *server,
|
|||
}
|
||||
|
||||
if (iter)
|
||||
result = copy_page_from_iter(page, 0, n, iter);
|
||||
result = copy_page_from_iter(
|
||||
page, page_offset, n, iter);
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
else if (rdata->mr)
|
||||
result = n;
|
||||
#endif
|
||||
else
|
||||
result = cifs_read_page_from_socket(server, page, n);
|
||||
result = cifs_read_page_from_socket(
|
||||
server, page, page_offset, n);
|
||||
if (result < 0)
|
||||
break;
|
||||
|
||||
|
@ -3790,6 +3828,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
|
|||
rdata->bytes = bytes;
|
||||
rdata->pid = pid;
|
||||
rdata->pagesz = PAGE_SIZE;
|
||||
rdata->tailsz = PAGE_SIZE;
|
||||
rdata->read_into_pages = cifs_readpages_read_into_pages;
|
||||
rdata->copy_into_pages = cifs_readpages_copy_into_pages;
|
||||
rdata->credits = credits;
|
||||
|
|
|
@ -746,7 +746,8 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
|
|||
cifs_dbg(FYI, "Getting info on %s\n", full_path);
|
||||
|
||||
if ((data == NULL) && (*inode != NULL)) {
|
||||
if (CIFS_CACHE_READ(CIFS_I(*inode))) {
|
||||
if (CIFS_CACHE_READ(CIFS_I(*inode)) &&
|
||||
CIFS_I(*inode)->time != 0) {
|
||||
cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
|
||||
goto cgii_exit;
|
||||
}
|
||||
|
@ -1857,15 +1858,15 @@ cifs_inode_needs_reval(struct inode *inode)
|
|||
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
|
||||
if (cifs_i->time == 0)
|
||||
return true;
|
||||
|
||||
if (CIFS_CACHE_READ(cifs_i))
|
||||
return false;
|
||||
|
||||
if (!lookupCacheEnabled)
|
||||
return true;
|
||||
|
||||
if (cifs_i->time == 0)
|
||||
return true;
|
||||
|
||||
if (!cifs_sb->actimeo)
|
||||
return true;
|
||||
|
||||
|
@ -2104,10 +2105,14 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from)
|
|||
|
||||
static void cifs_setsize(struct inode *inode, loff_t offset)
|
||||
{
|
||||
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
i_size_write(inode, offset);
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
/* Cached inode must be refreshed on truncate */
|
||||
cifs_i->time = 0;
|
||||
truncate_pagecache(inode, offset);
|
||||
}
|
||||
|
||||
|
|
|
@ -117,6 +117,8 @@ tconInfoAlloc(void)
|
|||
INIT_LIST_HEAD(&ret_buf->openFileList);
|
||||
INIT_LIST_HEAD(&ret_buf->tcon_list);
|
||||
spin_lock_init(&ret_buf->open_file_lock);
|
||||
mutex_init(&ret_buf->prfid_mutex);
|
||||
ret_buf->prfid = kzalloc(sizeof(struct cifs_fid), GFP_KERNEL);
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
spin_lock_init(&ret_buf->stat_lock);
|
||||
#endif
|
||||
|
@ -134,6 +136,7 @@ tconInfoFree(struct cifs_tcon *buf_to_free)
|
|||
atomic_dec(&tconInfoAllocCount);
|
||||
kfree(buf_to_free->nativeFileSystem);
|
||||
kzfree(buf_to_free->password);
|
||||
kfree(buf_to_free->prfid);
|
||||
kfree(buf_to_free);
|
||||
}
|
||||
|
||||
|
@ -145,7 +148,7 @@ cifs_buf_get(void)
|
|||
* SMB2 header is bigger than CIFS one - no problems to clean some
|
||||
* more bytes for CIFS.
|
||||
*/
|
||||
size_t buf_size = sizeof(struct smb2_hdr);
|
||||
size_t buf_size = sizeof(struct smb2_sync_hdr);
|
||||
|
||||
/*
|
||||
* We could use negotiated size instead of max_msgsize -
|
||||
|
@ -339,7 +342,7 @@ checkSMB(char *buf, unsigned int total_read, struct TCP_Server_Info *server)
|
|||
/* otherwise, there is enough to get to the BCC */
|
||||
if (check_smb_hdr(smb))
|
||||
return -EIO;
|
||||
clc_len = smbCalcSize(smb);
|
||||
clc_len = smbCalcSize(smb, server);
|
||||
|
||||
if (4 + rfclen != total_read) {
|
||||
cifs_dbg(VFS, "Length read does not match RFC1001 length %d\n",
|
||||
|
|
|
@ -903,7 +903,7 @@ map_smb_to_linux_error(char *buf, bool logErr)
|
|||
* portion, the number of word parameters and the data portion of the message
|
||||
*/
|
||||
unsigned int
|
||||
smbCalcSize(void *buf)
|
||||
smbCalcSize(void *buf, struct TCP_Server_Info *server)
|
||||
{
|
||||
struct smb_hdr *ptr = (struct smb_hdr *)buf;
|
||||
return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
|
||||
|
|
|
@ -650,7 +650,8 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
|
|||
char *cur_ent;
|
||||
char *end_of_smb = cfile->srch_inf.ntwrk_buf_start +
|
||||
server->ops->calc_smb_size(
|
||||
cfile->srch_inf.ntwrk_buf_start);
|
||||
cfile->srch_inf.ntwrk_buf_start,
|
||||
server);
|
||||
|
||||
cur_ent = cfile->srch_inf.srch_entries_start;
|
||||
first_entry_in_buffer = cfile->srch_inf.index_of_last_entry
|
||||
|
@ -831,7 +832,8 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
|
|||
cifs_dbg(FYI, "loop through %d times filling dir for net buf %p\n",
|
||||
num_to_fill, cifsFile->srch_inf.ntwrk_buf_start);
|
||||
max_len = tcon->ses->server->ops->calc_smb_size(
|
||||
cifsFile->srch_inf.ntwrk_buf_start);
|
||||
cifsFile->srch_inf.ntwrk_buf_start,
|
||||
tcon->ses->server);
|
||||
end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
|
||||
|
||||
tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
|
||||
|
|
|
@ -61,9 +61,4 @@
|
|||
/* Maximum buffer size value we can send with 1 credit */
|
||||
#define SMB2_MAX_BUFFER_SIZE 65536
|
||||
|
||||
static inline struct smb2_sync_hdr *get_sync_hdr(void *buf)
|
||||
{
|
||||
return &(((struct smb2_hdr *)buf)->sync_hdr);
|
||||
}
|
||||
|
||||
#endif /* _SMB2_GLOB_H */
|
||||
|
|
|
@ -44,26 +44,38 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
__u32 create_options, void *data, int command)
|
||||
{
|
||||
int rc, tmprc = 0;
|
||||
__le16 *utf16_path;
|
||||
__le16 *utf16_path = NULL;
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_fid fid;
|
||||
bool use_cached_root_handle = false;
|
||||
|
||||
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
||||
if (!utf16_path)
|
||||
return -ENOMEM;
|
||||
if ((strcmp(full_path, "") == 0) && (create_options == 0) &&
|
||||
(desired_access == FILE_READ_ATTRIBUTES) &&
|
||||
(create_disposition == FILE_OPEN) &&
|
||||
(tcon->nohandlecache == false)) {
|
||||
rc = open_shroot(xid, tcon, &fid);
|
||||
if (rc == 0)
|
||||
use_cached_root_handle = true;
|
||||
}
|
||||
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = desired_access;
|
||||
oparms.disposition = create_disposition;
|
||||
oparms.create_options = create_options;
|
||||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
if (use_cached_root_handle == false) {
|
||||
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
||||
if (!utf16_path)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
|
||||
if (rc) {
|
||||
kfree(utf16_path);
|
||||
return rc;
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = desired_access;
|
||||
oparms.disposition = create_disposition;
|
||||
oparms.create_options = create_options;
|
||||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
|
||||
if (rc) {
|
||||
kfree(utf16_path);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
switch (command) {
|
||||
|
@ -107,7 +119,8 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
break;
|
||||
}
|
||||
|
||||
rc = SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
if (use_cached_root_handle == false)
|
||||
rc = SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
if (tmprc)
|
||||
rc = tmprc;
|
||||
kfree(utf16_path);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "smb2proto.h"
|
||||
#include "smb2status.h"
|
||||
#include "smb2glob.h"
|
||||
#include "trace.h"
|
||||
|
||||
struct status_to_posix_error {
|
||||
__le32 smb2_status;
|
||||
|
@ -2450,13 +2451,16 @@ smb2_print_status(__le32 status)
|
|||
int
|
||||
map_smb2_to_linux_error(char *buf, bool log_err)
|
||||
{
|
||||
struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
|
||||
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
|
||||
unsigned int i;
|
||||
int rc = -EIO;
|
||||
__le32 smb2err = shdr->Status;
|
||||
|
||||
if (smb2err == 0)
|
||||
if (smb2err == 0) {
|
||||
trace_smb3_cmd_done(shdr->TreeId, shdr->SessionId,
|
||||
le16_to_cpu(shdr->Command), le64_to_cpu(shdr->MessageId));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* mask facility */
|
||||
if (log_err && (smb2err != STATUS_MORE_PROCESSING_REQUIRED) &&
|
||||
|
@ -2478,5 +2482,8 @@ map_smb2_to_linux_error(char *buf, bool log_err)
|
|||
cifs_dbg(FYI, "Mapping SMB2 status code 0x%08x to POSIX err %d\n",
|
||||
__le32_to_cpu(smb2err), rc);
|
||||
|
||||
trace_smb3_cmd_err(shdr->TreeId, shdr->SessionId,
|
||||
le16_to_cpu(shdr->Command),
|
||||
le64_to_cpu(shdr->MessageId), le32_to_cpu(smb2err), rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -94,8 +94,8 @@ static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
static __u32 get_neg_ctxt_len(struct smb2_hdr *hdr, __u32 len, __u32 non_ctxlen,
|
||||
size_t hdr_preamble_size)
|
||||
static __u32 get_neg_ctxt_len(struct smb2_sync_hdr *hdr, __u32 len,
|
||||
__u32 non_ctxlen)
|
||||
{
|
||||
__u16 neg_count;
|
||||
__u32 nc_offset, size_of_pad_before_neg_ctxts;
|
||||
|
@ -109,12 +109,11 @@ static __u32 get_neg_ctxt_len(struct smb2_hdr *hdr, __u32 len, __u32 non_ctxlen,
|
|||
|
||||
/* Make sure that negotiate contexts start after gss security blob */
|
||||
nc_offset = le32_to_cpu(pneg_rsp->NegotiateContextOffset);
|
||||
if (nc_offset < non_ctxlen - hdr_preamble_size /* RFC1001 len */) {
|
||||
if (nc_offset < non_ctxlen) {
|
||||
printk_once(KERN_WARNING "invalid negotiate context offset\n");
|
||||
return 0;
|
||||
}
|
||||
size_of_pad_before_neg_ctxts = nc_offset -
|
||||
(non_ctxlen - hdr_preamble_size);
|
||||
size_of_pad_before_neg_ctxts = nc_offset - non_ctxlen;
|
||||
|
||||
/* Verify that at least minimal negotiate contexts fit within frame */
|
||||
if (len < nc_offset + (neg_count * sizeof(struct smb2_neg_context))) {
|
||||
|
@ -131,25 +130,20 @@ static __u32 get_neg_ctxt_len(struct smb2_hdr *hdr, __u32 len, __u32 non_ctxlen,
|
|||
#endif /* CIFS_SMB311 */
|
||||
|
||||
int
|
||||
smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
|
||||
smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *srvr)
|
||||
{
|
||||
struct smb2_pdu *pdu = (struct smb2_pdu *)buf;
|
||||
struct smb2_hdr *hdr = &pdu->hdr;
|
||||
struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
|
||||
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
|
||||
struct smb2_sync_pdu *pdu = (struct smb2_sync_pdu *)shdr;
|
||||
__u64 mid;
|
||||
__u32 len = get_rfc1002_length(buf);
|
||||
__u32 clc_len; /* calculated length */
|
||||
int command;
|
||||
|
||||
/* BB disable following printk later */
|
||||
cifs_dbg(FYI, "%s length: 0x%x, smb_buf_length: 0x%x\n",
|
||||
__func__, length, len);
|
||||
int pdu_size = sizeof(struct smb2_sync_pdu);
|
||||
int hdr_size = sizeof(struct smb2_sync_hdr);
|
||||
|
||||
/*
|
||||
* Add function to do table lookup of StructureSize by command
|
||||
* ie Validate the wct via smb2_struct_sizes table above
|
||||
*/
|
||||
|
||||
if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
|
||||
struct smb2_transform_hdr *thdr =
|
||||
(struct smb2_transform_hdr *)buf;
|
||||
|
@ -173,8 +167,8 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
|
|||
}
|
||||
|
||||
mid = le64_to_cpu(shdr->MessageId);
|
||||
if (length < sizeof(struct smb2_pdu)) {
|
||||
if ((length >= sizeof(struct smb2_hdr))
|
||||
if (len < pdu_size) {
|
||||
if ((len >= hdr_size)
|
||||
&& (shdr->Status != 0)) {
|
||||
pdu->StructureSize2 = 0;
|
||||
/*
|
||||
|
@ -187,8 +181,7 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
|
|||
}
|
||||
return 1;
|
||||
}
|
||||
if (len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE -
|
||||
srvr->vals->header_preamble_size) {
|
||||
if (len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE) {
|
||||
cifs_dbg(VFS, "SMB length greater than maximum, mid=%llu\n",
|
||||
mid);
|
||||
return 1;
|
||||
|
@ -227,44 +220,38 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
|
|||
}
|
||||
}
|
||||
|
||||
if (srvr->vals->header_preamble_size + len != length) {
|
||||
cifs_dbg(VFS, "Total length %u RFC1002 length %zu mismatch mid %llu\n",
|
||||
length, srvr->vals->header_preamble_size + len, mid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
clc_len = smb2_calc_size(hdr);
|
||||
clc_len = smb2_calc_size(buf, srvr);
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if (shdr->Command == SMB2_NEGOTIATE)
|
||||
clc_len += get_neg_ctxt_len(hdr, len, clc_len,
|
||||
srvr->vals->header_preamble_size);
|
||||
clc_len += get_neg_ctxt_len(shdr, len, clc_len);
|
||||
#endif /* SMB311 */
|
||||
if (srvr->vals->header_preamble_size + len != clc_len) {
|
||||
cifs_dbg(FYI, "Calculated size %u length %zu mismatch mid %llu\n",
|
||||
clc_len, srvr->vals->header_preamble_size + len, mid);
|
||||
if (len != clc_len) {
|
||||
cifs_dbg(FYI, "Calculated size %u length %u mismatch mid %llu\n",
|
||||
clc_len, len, mid);
|
||||
/* create failed on symlink */
|
||||
if (command == SMB2_CREATE_HE &&
|
||||
shdr->Status == STATUS_STOPPED_ON_SYMLINK)
|
||||
return 0;
|
||||
/* Windows 7 server returns 24 bytes more */
|
||||
if (clc_len + 24 - srvr->vals->header_preamble_size == len && command == SMB2_OPLOCK_BREAK_HE)
|
||||
if (clc_len + 24 == len && command == SMB2_OPLOCK_BREAK_HE)
|
||||
return 0;
|
||||
/* server can return one byte more due to implied bcc[0] */
|
||||
if (clc_len == srvr->vals->header_preamble_size + len + 1)
|
||||
if (clc_len == len + 1)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* MacOS server pads after SMB2.1 write response with 3 bytes
|
||||
* of junk. Other servers match RFC1001 len to actual
|
||||
* SMB2/SMB3 frame length (header + smb2 response specific data)
|
||||
* Some windows servers do too when compounding is used.
|
||||
* Log the server error (once), but allow it and continue
|
||||
* since the frame is parseable.
|
||||
*/
|
||||
if (clc_len < srvr->vals->header_preamble_size /* RFC1001 header size */ + len) {
|
||||
if (clc_len < len) {
|
||||
printk_once(KERN_WARNING
|
||||
"SMB2 server sent bad RFC1001 len %d not %zu\n",
|
||||
len, clc_len - srvr->vals->header_preamble_size);
|
||||
"SMB2 server sent bad RFC1001 len %d not %d\n",
|
||||
len, clc_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -305,15 +292,14 @@ static const bool has_smb2_data_area[NUMBER_OF_SMB2_COMMANDS] = {
|
|||
* area and the offset to it (from the beginning of the smb are also returned.
|
||||
*/
|
||||
char *
|
||||
smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
|
||||
smb2_get_data_area_len(int *off, int *len, struct smb2_sync_hdr *shdr)
|
||||
{
|
||||
struct smb2_sync_hdr *shdr = get_sync_hdr(hdr);
|
||||
*off = 0;
|
||||
*len = 0;
|
||||
|
||||
/* error responses do not have data area */
|
||||
if (shdr->Status && shdr->Status != STATUS_MORE_PROCESSING_REQUIRED &&
|
||||
(((struct smb2_err_rsp *)hdr)->StructureSize) ==
|
||||
(((struct smb2_err_rsp *)shdr)->StructureSize) ==
|
||||
SMB2_ERROR_STRUCTURE_SIZE2)
|
||||
return NULL;
|
||||
|
||||
|
@ -325,42 +311,44 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
|
|||
switch (shdr->Command) {
|
||||
case SMB2_NEGOTIATE:
|
||||
*off = le16_to_cpu(
|
||||
((struct smb2_negotiate_rsp *)hdr)->SecurityBufferOffset);
|
||||
((struct smb2_negotiate_rsp *)shdr)->SecurityBufferOffset);
|
||||
*len = le16_to_cpu(
|
||||
((struct smb2_negotiate_rsp *)hdr)->SecurityBufferLength);
|
||||
((struct smb2_negotiate_rsp *)shdr)->SecurityBufferLength);
|
||||
break;
|
||||
case SMB2_SESSION_SETUP:
|
||||
*off = le16_to_cpu(
|
||||
((struct smb2_sess_setup_rsp *)hdr)->SecurityBufferOffset);
|
||||
((struct smb2_sess_setup_rsp *)shdr)->SecurityBufferOffset);
|
||||
*len = le16_to_cpu(
|
||||
((struct smb2_sess_setup_rsp *)hdr)->SecurityBufferLength);
|
||||
((struct smb2_sess_setup_rsp *)shdr)->SecurityBufferLength);
|
||||
break;
|
||||
case SMB2_CREATE:
|
||||
*off = le32_to_cpu(
|
||||
((struct smb2_create_rsp *)hdr)->CreateContextsOffset);
|
||||
((struct smb2_create_rsp *)shdr)->CreateContextsOffset);
|
||||
*len = le32_to_cpu(
|
||||
((struct smb2_create_rsp *)hdr)->CreateContextsLength);
|
||||
((struct smb2_create_rsp *)shdr)->CreateContextsLength);
|
||||
break;
|
||||
case SMB2_QUERY_INFO:
|
||||
*off = le16_to_cpu(
|
||||
((struct smb2_query_info_rsp *)hdr)->OutputBufferOffset);
|
||||
((struct smb2_query_info_rsp *)shdr)->OutputBufferOffset);
|
||||
*len = le32_to_cpu(
|
||||
((struct smb2_query_info_rsp *)hdr)->OutputBufferLength);
|
||||
((struct smb2_query_info_rsp *)shdr)->OutputBufferLength);
|
||||
break;
|
||||
case SMB2_READ:
|
||||
*off = ((struct smb2_read_rsp *)hdr)->DataOffset;
|
||||
*len = le32_to_cpu(((struct smb2_read_rsp *)hdr)->DataLength);
|
||||
/* TODO: is this a bug ? */
|
||||
*off = ((struct smb2_read_rsp *)shdr)->DataOffset;
|
||||
*len = le32_to_cpu(((struct smb2_read_rsp *)shdr)->DataLength);
|
||||
break;
|
||||
case SMB2_QUERY_DIRECTORY:
|
||||
*off = le16_to_cpu(
|
||||
((struct smb2_query_directory_rsp *)hdr)->OutputBufferOffset);
|
||||
((struct smb2_query_directory_rsp *)shdr)->OutputBufferOffset);
|
||||
*len = le32_to_cpu(
|
||||
((struct smb2_query_directory_rsp *)hdr)->OutputBufferLength);
|
||||
((struct smb2_query_directory_rsp *)shdr)->OutputBufferLength);
|
||||
break;
|
||||
case SMB2_IOCTL:
|
||||
*off = le32_to_cpu(
|
||||
((struct smb2_ioctl_rsp *)hdr)->OutputOffset);
|
||||
*len = le32_to_cpu(((struct smb2_ioctl_rsp *)hdr)->OutputCount);
|
||||
((struct smb2_ioctl_rsp *)shdr)->OutputOffset);
|
||||
*len = le32_to_cpu(
|
||||
((struct smb2_ioctl_rsp *)shdr)->OutputCount);
|
||||
break;
|
||||
case SMB2_CHANGE_NOTIFY:
|
||||
default:
|
||||
|
@ -403,15 +391,14 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
|
|||
* portion, the number of word parameters and the data portion of the message.
|
||||
*/
|
||||
unsigned int
|
||||
smb2_calc_size(void *buf)
|
||||
smb2_calc_size(void *buf, struct TCP_Server_Info *srvr)
|
||||
{
|
||||
struct smb2_pdu *pdu = (struct smb2_pdu *)buf;
|
||||
struct smb2_hdr *hdr = &pdu->hdr;
|
||||
struct smb2_sync_hdr *shdr = get_sync_hdr(hdr);
|
||||
struct smb2_sync_pdu *pdu = (struct smb2_sync_pdu *)buf;
|
||||
struct smb2_sync_hdr *shdr = &pdu->sync_hdr;
|
||||
int offset; /* the offset from the beginning of SMB to data area */
|
||||
int data_length; /* the length of the variable length data area */
|
||||
/* Structure Size has already been checked to make sure it is 64 */
|
||||
int len = 4 + le16_to_cpu(shdr->StructureSize);
|
||||
int len = le16_to_cpu(shdr->StructureSize);
|
||||
|
||||
/*
|
||||
* StructureSize2, ie length of fixed parameter area has already
|
||||
|
@ -422,7 +409,7 @@ smb2_calc_size(void *buf)
|
|||
if (has_smb2_data_area[le16_to_cpu(shdr->Command)] == false)
|
||||
goto calc_size_exit;
|
||||
|
||||
smb2_get_data_area_len(&offset, &data_length, hdr);
|
||||
smb2_get_data_area_len(&offset, &data_length, shdr);
|
||||
cifs_dbg(FYI, "SMB2 data length %d offset %d\n", data_length, offset);
|
||||
|
||||
if (data_length > 0) {
|
||||
|
@ -430,15 +417,14 @@ smb2_calc_size(void *buf)
|
|||
* Check to make sure that data area begins after fixed area,
|
||||
* Note that last byte of the fixed area is part of data area
|
||||
* for some commands, typically those with odd StructureSize,
|
||||
* so we must add one to the calculation (and 4 to account for
|
||||
* the size of the RFC1001 hdr.
|
||||
* so we must add one to the calculation.
|
||||
*/
|
||||
if (offset + 4 + 1 < len) {
|
||||
if (offset + 1 < len) {
|
||||
cifs_dbg(VFS, "data area offset %d overlaps SMB2 header %d\n",
|
||||
offset + 4 + 1, len);
|
||||
offset + 1, len);
|
||||
data_length = 0;
|
||||
} else {
|
||||
len = 4 + offset + data_length;
|
||||
len = offset + data_length;
|
||||
}
|
||||
}
|
||||
calc_size_exit:
|
||||
|
@ -465,8 +451,14 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
|
|||
/* Windows doesn't allow paths beginning with \ */
|
||||
if (from[0] == '\\')
|
||||
start_of_path = from + 1;
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
/* SMB311 POSIX extensions paths do not include leading slash */
|
||||
else if (cifs_sb_master_tcon(cifs_sb)->posix_extensions)
|
||||
start_of_path = from + 1;
|
||||
#endif /* 311 */
|
||||
else
|
||||
start_of_path = from;
|
||||
|
||||
to = cifs_strndup_to_utf16(start_of_path, PATH_MAX, &len,
|
||||
cifs_sb->local_nls, map_type);
|
||||
return to;
|
||||
|
@ -621,7 +613,7 @@ smb2_is_valid_lease_break(char *buffer)
|
|||
bool
|
||||
smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
|
||||
{
|
||||
struct smb2_oplock_break_rsp *rsp = (struct smb2_oplock_break_rsp *)buffer;
|
||||
struct smb2_oplock_break *rsp = (struct smb2_oplock_break *)buffer;
|
||||
struct list_head *tmp, *tmp1, *tmp2;
|
||||
struct cifs_ses *ses;
|
||||
struct cifs_tcon *tcon;
|
||||
|
@ -630,7 +622,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
|
|||
|
||||
cifs_dbg(FYI, "Checking for oplock break\n");
|
||||
|
||||
if (rsp->hdr.sync_hdr.Command != SMB2_OPLOCK_BREAK)
|
||||
if (rsp->sync_hdr.Command != SMB2_OPLOCK_BREAK)
|
||||
return false;
|
||||
|
||||
if (rsp->StructureSize !=
|
||||
|
@ -721,7 +713,7 @@ smb2_cancelled_close_fid(struct work_struct *work)
|
|||
int
|
||||
smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server)
|
||||
{
|
||||
struct smb2_sync_hdr *sync_hdr = get_sync_hdr(buffer);
|
||||
struct smb2_sync_hdr *sync_hdr = (struct smb2_sync_hdr *)buffer;
|
||||
struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)buffer;
|
||||
struct cifs_tcon *tcon;
|
||||
struct close_cancelled_open *cancelled;
|
||||
|
|
|
@ -123,7 +123,7 @@ smb2_get_credits_field(struct TCP_Server_Info *server, const int optype)
|
|||
static unsigned int
|
||||
smb2_get_credits(struct mid_q_entry *mid)
|
||||
{
|
||||
struct smb2_sync_hdr *shdr = get_sync_hdr(mid->resp_buf);
|
||||
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)mid->resp_buf;
|
||||
|
||||
return le16_to_cpu(shdr->CreditRequest);
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ static struct mid_q_entry *
|
|||
smb2_find_mid(struct TCP_Server_Info *server, char *buf)
|
||||
{
|
||||
struct mid_q_entry *mid;
|
||||
struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
|
||||
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
|
||||
__u64 wire_mid = le64_to_cpu(shdr->MessageId);
|
||||
|
||||
if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
|
||||
|
@ -212,15 +212,16 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
|
|||
}
|
||||
|
||||
static void
|
||||
smb2_dump_detail(void *buf)
|
||||
smb2_dump_detail(void *buf, struct TCP_Server_Info *server)
|
||||
{
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
struct smb2_sync_hdr *shdr = get_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",
|
||||
shdr->Command, shdr->Status, shdr->Flags, shdr->MessageId,
|
||||
shdr->ProcessId);
|
||||
cifs_dbg(VFS, "smb buf %p len %u\n", buf, smb2_calc_size(buf));
|
||||
cifs_dbg(VFS, "smb buf %p len %u\n", buf,
|
||||
server->ops->calc_smb_size(buf, server));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -322,6 +323,40 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
|
|||
}
|
||||
#endif /* STATS2 */
|
||||
|
||||
/*
|
||||
* Open the directory at the root of a share
|
||||
*/
|
||||
int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
||||
{
|
||||
struct cifs_open_parms oparams;
|
||||
int rc;
|
||||
__le16 srch_path = 0; /* Null - since an open of top of share */
|
||||
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
|
||||
mutex_lock(&tcon->prfid_mutex);
|
||||
if (tcon->valid_root_fid) {
|
||||
cifs_dbg(FYI, "found a cached root file handle\n");
|
||||
memcpy(pfid, tcon->prfid, sizeof(struct cifs_fid));
|
||||
mutex_unlock(&tcon->prfid_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
oparams.tcon = tcon;
|
||||
oparams.create_options = 0;
|
||||
oparams.desired_access = FILE_READ_ATTRIBUTES;
|
||||
oparams.disposition = FILE_OPEN;
|
||||
oparams.fid = pfid;
|
||||
oparams.reconnect = false;
|
||||
|
||||
rc = SMB2_open(xid, &oparams, &srch_path, &oplock, NULL, NULL);
|
||||
if (rc == 0) {
|
||||
memcpy(tcon->prfid, pfid, sizeof(struct cifs_fid));
|
||||
tcon->valid_root_fid = true;
|
||||
}
|
||||
mutex_unlock(&tcon->prfid_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
|
||||
{
|
||||
|
@ -330,6 +365,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
|
|||
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_fid fid;
|
||||
bool no_cached_open = tcon->nohandlecache;
|
||||
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = FILE_READ_ATTRIBUTES;
|
||||
|
@ -338,7 +374,11 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
|
|||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL);
|
||||
if (no_cached_open)
|
||||
rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL);
|
||||
else
|
||||
rc = open_shroot(xid, tcon, &fid);
|
||||
|
||||
if (rc)
|
||||
return;
|
||||
|
||||
|
@ -352,7 +392,8 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
|
|||
FS_DEVICE_INFORMATION);
|
||||
SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
|
||||
FS_SECTOR_SIZE_INFORMATION); /* SMB3 specific */
|
||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
if (no_cached_open)
|
||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -394,6 +435,9 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
struct cifs_open_parms oparms;
|
||||
struct cifs_fid fid;
|
||||
|
||||
if ((*full_path == 0) && tcon->valid_root_fid)
|
||||
return 0;
|
||||
|
||||
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
||||
if (!utf16_path)
|
||||
return -ENOMEM;
|
||||
|
@ -704,9 +748,11 @@ smb2_dump_share_caps(struct seq_file *m, struct cifs_tcon *tcon)
|
|||
seq_puts(m, " TRIM-support,");
|
||||
|
||||
seq_printf(m, "\tShare Flags: 0x%x", tcon->share_flags);
|
||||
seq_printf(m, "\n\ttid: 0x%x", tcon->tid);
|
||||
if (tcon->perf_sector_size)
|
||||
seq_printf(m, "\tOptimal sector size: 0x%x",
|
||||
tcon->perf_sector_size);
|
||||
seq_printf(m, "\tMaximal Access: 0x%x", tcon->maximal_access);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1257,7 +1303,7 @@ smb2_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
static bool
|
||||
smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
|
||||
{
|
||||
struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
|
||||
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
|
||||
|
||||
if (shdr->Status != STATUS_PENDING)
|
||||
return false;
|
||||
|
@ -1275,12 +1321,13 @@ smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
|
|||
static bool
|
||||
smb2_is_session_expired(char *buf)
|
||||
{
|
||||
struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
|
||||
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
|
||||
|
||||
if (shdr->Status != STATUS_NETWORK_SESSION_EXPIRED)
|
||||
if (shdr->Status != STATUS_NETWORK_SESSION_EXPIRED &&
|
||||
shdr->Status != STATUS_USER_SESSION_DELETED)
|
||||
return false;
|
||||
|
||||
cifs_dbg(FYI, "Session expired\n");
|
||||
cifs_dbg(FYI, "Session expired or deleted\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1474,8 +1521,6 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
unsigned int sub_offset;
|
||||
unsigned int print_len;
|
||||
unsigned int print_offset;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
|
||||
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
|
||||
|
||||
|
@ -1499,7 +1544,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
err_buf = err_iov.iov_base;
|
||||
if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) ||
|
||||
err_iov.iov_len + server->vals->header_preamble_size < SMB2_SYMLINK_STRUCT_SIZE) {
|
||||
err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE) {
|
||||
kfree(utf16_path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
@ -1512,14 +1557,13 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
print_len = le16_to_cpu(symlink->PrintNameLength);
|
||||
print_offset = le16_to_cpu(symlink->PrintNameOffset);
|
||||
|
||||
if (err_iov.iov_len + server->vals->header_preamble_size <
|
||||
SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) {
|
||||
if (err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) {
|
||||
kfree(utf16_path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (err_iov.iov_len + server->vals->header_preamble_size <
|
||||
SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) {
|
||||
if (err_iov.iov_len <
|
||||
SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) {
|
||||
kfree(utf16_path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
@ -1593,8 +1637,11 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb,
|
|||
oparms.create_options = 0;
|
||||
|
||||
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
||||
if (!utf16_path)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (!utf16_path) {
|
||||
rc = -ENOMEM;
|
||||
free_xid(xid);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = READ_CONTROL;
|
||||
|
@ -1652,8 +1699,11 @@ set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
|||
access_flags = WRITE_DAC;
|
||||
|
||||
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
||||
if (!utf16_path)
|
||||
return -ENOMEM;
|
||||
if (!utf16_path) {
|
||||
rc = -ENOMEM;
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = access_flags;
|
||||
|
@ -1713,15 +1763,21 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
|
|||
|
||||
/* if file not oplocked can't be sure whether asking to extend size */
|
||||
if (!CIFS_CACHE_READ(cifsi))
|
||||
if (keep_size == false)
|
||||
return -EOPNOTSUPP;
|
||||
if (keep_size == false) {
|
||||
rc = -EOPNOTSUPP;
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Must check if file sparse since fallocate -z (zero range) assumes
|
||||
* non-sparse allocation
|
||||
*/
|
||||
if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE))
|
||||
return -EOPNOTSUPP;
|
||||
if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)) {
|
||||
rc = -EOPNOTSUPP;
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* need to make sure we are not asked to extend the file since the SMB3
|
||||
|
@ -1730,8 +1786,11 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
|
|||
* which for a non sparse file would zero the newly extended range
|
||||
*/
|
||||
if (keep_size == false)
|
||||
if (i_size_read(inode) < offset + len)
|
||||
return -EOPNOTSUPP;
|
||||
if (i_size_read(inode) < offset + len) {
|
||||
rc = -EOPNOTSUPP;
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
cifs_dbg(FYI, "offset %lld len %lld", offset, len);
|
||||
|
||||
|
@ -1764,8 +1823,11 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
|
|||
|
||||
/* Need to make file sparse, if not already, before freeing range. */
|
||||
/* Consider adding equivalent for compressed since it could also work */
|
||||
if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse))
|
||||
return -EOPNOTSUPP;
|
||||
if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse)) {
|
||||
rc = -EOPNOTSUPP;
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
cifs_dbg(FYI, "offset %lld len %lld", offset, len);
|
||||
|
||||
|
@ -1796,8 +1858,10 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
|
|||
|
||||
/* if file not oplocked can't be sure whether asking to extend size */
|
||||
if (!CIFS_CACHE_READ(cifsi))
|
||||
if (keep_size == false)
|
||||
return -EOPNOTSUPP;
|
||||
if (keep_size == false) {
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Files are non-sparse by default so falloc may be a no-op
|
||||
|
@ -1806,14 +1870,16 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
|
|||
*/
|
||||
if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) == 0) {
|
||||
if (keep_size == true)
|
||||
return 0;
|
||||
rc = 0;
|
||||
/* check if extending file */
|
||||
else if (i_size_read(inode) >= off + len)
|
||||
/* not extending file and already not sparse */
|
||||
return 0;
|
||||
rc = 0;
|
||||
/* BB: in future add else clause to extend file */
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
rc = -EOPNOTSUPP;
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if ((keep_size == true) || (i_size_read(inode) >= off + len)) {
|
||||
|
@ -1825,8 +1891,11 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
|
|||
* ie potentially making a few extra pages at the beginning
|
||||
* or end of the file non-sparse via set_sparse is harmless.
|
||||
*/
|
||||
if ((off > 8192) || (off + len + 8192 < i_size_read(inode)))
|
||||
return -EOPNOTSUPP;
|
||||
if ((off > 8192) || (off + len + 8192 < i_size_read(inode))) {
|
||||
rc = -EOPNOTSUPP;
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = smb2_set_sparse(xid, tcon, cfile, inode, false);
|
||||
}
|
||||
|
@ -2035,7 +2104,7 @@ smb3_create_lease_buf(u8 *lease_key, u8 oplock)
|
|||
}
|
||||
|
||||
static __u8
|
||||
smb2_parse_lease_buf(void *buf, unsigned int *epoch)
|
||||
smb2_parse_lease_buf(void *buf, unsigned int *epoch, char *lease_key)
|
||||
{
|
||||
struct create_lease *lc = (struct create_lease *)buf;
|
||||
|
||||
|
@ -2046,13 +2115,16 @@ smb2_parse_lease_buf(void *buf, unsigned int *epoch)
|
|||
}
|
||||
|
||||
static __u8
|
||||
smb3_parse_lease_buf(void *buf, unsigned int *epoch)
|
||||
smb3_parse_lease_buf(void *buf, unsigned int *epoch, char *lease_key)
|
||||
{
|
||||
struct create_lease_v2 *lc = (struct create_lease_v2 *)buf;
|
||||
|
||||
*epoch = le16_to_cpu(lc->lcontext.Epoch);
|
||||
if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS)
|
||||
return SMB2_OPLOCK_LEVEL_NOCHANGE;
|
||||
if (lease_key)
|
||||
memcpy(lease_key, &lc->lcontext.LeaseKeyLow,
|
||||
SMB2_LEASE_KEY_SIZE);
|
||||
return le32_to_cpu(lc->lcontext.LeaseState);
|
||||
}
|
||||
|
||||
|
@ -2070,12 +2142,11 @@ smb2_dir_needs_close(struct cifsFileInfo *cfile)
|
|||
}
|
||||
|
||||
static void
|
||||
fill_transform_hdr(struct TCP_Server_Info *server,
|
||||
struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq)
|
||||
fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len,
|
||||
struct smb_rqst *old_rq)
|
||||
{
|
||||
struct smb2_sync_hdr *shdr =
|
||||
(struct smb2_sync_hdr *)old_rq->rq_iov[1].iov_base;
|
||||
unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base);
|
||||
|
||||
memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr));
|
||||
tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM;
|
||||
|
@ -2083,8 +2154,6 @@ fill_transform_hdr(struct TCP_Server_Info *server,
|
|||
tr_hdr->Flags = cpu_to_le16(0x01);
|
||||
get_random_bytes(&tr_hdr->Nonce, SMB3_AES128CMM_NONCE);
|
||||
memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8);
|
||||
inc_rfc1001_len(tr_hdr, sizeof(struct smb2_transform_hdr) - server->vals->header_preamble_size);
|
||||
inc_rfc1001_len(tr_hdr, orig_len);
|
||||
}
|
||||
|
||||
/* We can not use the normal sg_set_buf() as we will sometimes pass a
|
||||
|
@ -2096,11 +2165,16 @@ static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf,
|
|||
sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf));
|
||||
}
|
||||
|
||||
/* Assumes:
|
||||
* rqst->rq_iov[0] is rfc1002 length
|
||||
* rqst->rq_iov[1] is tranform header
|
||||
* rqst->rq_iov[2+] data to be encrypted/decrypted
|
||||
*/
|
||||
static struct scatterlist *
|
||||
init_sg(struct smb_rqst *rqst, u8 *sign)
|
||||
{
|
||||
unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages + 1;
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24;
|
||||
unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages;
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
|
||||
struct scatterlist *sg;
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
|
@ -2110,10 +2184,10 @@ init_sg(struct smb_rqst *rqst, u8 *sign)
|
|||
return NULL;
|
||||
|
||||
sg_init_table(sg, sg_len);
|
||||
smb2_sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len);
|
||||
for (i = 1; i < rqst->rq_nvec; i++)
|
||||
smb2_sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base,
|
||||
rqst->rq_iov[i].iov_len);
|
||||
smb2_sg_set_buf(&sg[0], rqst->rq_iov[1].iov_base + 20, assoc_data_len);
|
||||
for (i = 1; i < rqst->rq_nvec - 1; i++)
|
||||
smb2_sg_set_buf(&sg[i], rqst->rq_iov[i+1].iov_base,
|
||||
rqst->rq_iov[i+1].iov_len);
|
||||
for (j = 0; i < sg_len - 1; i++, j++) {
|
||||
unsigned int len = (j < rqst->rq_npages - 1) ? rqst->rq_pagesz
|
||||
: rqst->rq_tailsz;
|
||||
|
@ -2145,9 +2219,10 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
|
|||
}
|
||||
/*
|
||||
* Encrypt or decrypt @rqst message. @rqst has the following format:
|
||||
* iov[0] - transform header (associate data),
|
||||
* iov[1-N] and pages - data to encrypt.
|
||||
* On success return encrypted data in iov[1-N] and pages, leave iov[0]
|
||||
* iov[0] - rfc1002 length
|
||||
* iov[1] - transform header (associate data),
|
||||
* iov[2-N] and pages - data to encrypt.
|
||||
* On success return encrypted data in iov[2-N] and pages, leave iov[0-1]
|
||||
* untouched.
|
||||
*/
|
||||
static int
|
||||
|
@ -2155,7 +2230,7 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc)
|
|||
{
|
||||
struct smb2_transform_hdr *tr_hdr =
|
||||
(struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base;
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20 - server->vals->header_preamble_size;
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
|
||||
int rc = 0;
|
||||
struct scatterlist *sg;
|
||||
u8 sign[SMB2_SIGNATURE_SIZE] = {};
|
||||
|
@ -2242,6 +2317,10 @@ free_req:
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called from smb_send_rqst. At this point we have the rfc1002
|
||||
* header as the first element in the vector.
|
||||
*/
|
||||
static int
|
||||
smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
|
||||
struct smb_rqst *old_rq)
|
||||
|
@ -2250,6 +2329,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
|
|||
struct page **pages;
|
||||
struct smb2_transform_hdr *tr_hdr;
|
||||
unsigned int npages = old_rq->rq_npages;
|
||||
unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base);
|
||||
int i;
|
||||
int rc = -ENOMEM;
|
||||
|
||||
|
@ -2268,24 +2348,34 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
|
|||
goto err_free_pages;
|
||||
}
|
||||
|
||||
iov = kmalloc_array(old_rq->rq_nvec, sizeof(struct kvec), GFP_KERNEL);
|
||||
/* Make space for one extra iov to hold the transform header */
|
||||
iov = kmalloc_array(old_rq->rq_nvec + 1, sizeof(struct kvec),
|
||||
GFP_KERNEL);
|
||||
if (!iov)
|
||||
goto err_free_pages;
|
||||
|
||||
/* copy all iovs from the old except the 1st one (rfc1002 length) */
|
||||
memcpy(&iov[1], &old_rq->rq_iov[1],
|
||||
memcpy(&iov[2], &old_rq->rq_iov[1],
|
||||
sizeof(struct kvec) * (old_rq->rq_nvec - 1));
|
||||
/* copy the rfc1002 iov */
|
||||
iov[0].iov_base = old_rq->rq_iov[0].iov_base;
|
||||
iov[0].iov_len = old_rq->rq_iov[0].iov_len;
|
||||
|
||||
new_rq->rq_iov = iov;
|
||||
new_rq->rq_nvec = old_rq->rq_nvec;
|
||||
new_rq->rq_nvec = old_rq->rq_nvec + 1;
|
||||
|
||||
tr_hdr = kmalloc(sizeof(struct smb2_transform_hdr), GFP_KERNEL);
|
||||
if (!tr_hdr)
|
||||
goto err_free_iov;
|
||||
|
||||
/* fill the 1st iov with a transform header */
|
||||
fill_transform_hdr(server, tr_hdr, old_rq);
|
||||
new_rq->rq_iov[0].iov_base = tr_hdr;
|
||||
new_rq->rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr);
|
||||
/* fill the 2nd iov with a transform header */
|
||||
fill_transform_hdr(tr_hdr, orig_len, old_rq);
|
||||
new_rq->rq_iov[1].iov_base = tr_hdr;
|
||||
new_rq->rq_iov[1].iov_len = sizeof(struct smb2_transform_hdr);
|
||||
|
||||
/* Update rfc1002 header */
|
||||
inc_rfc1001_len(new_rq->rq_iov[0].iov_base,
|
||||
sizeof(struct smb2_transform_hdr));
|
||||
|
||||
/* copy pages form the old */
|
||||
for (i = 0; i < npages; i++) {
|
||||
|
@ -2325,7 +2415,7 @@ smb3_free_transform_rq(struct smb_rqst *rqst)
|
|||
put_page(rqst->rq_pages[i]);
|
||||
kfree(rqst->rq_pages);
|
||||
/* free transform header */
|
||||
kfree(rqst->rq_iov[0].iov_base);
|
||||
kfree(rqst->rq_iov[1].iov_base);
|
||||
kfree(rqst->rq_iov);
|
||||
}
|
||||
|
||||
|
@ -2342,18 +2432,19 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
|
|||
unsigned int buf_data_size, struct page **pages,
|
||||
unsigned int npages, unsigned int page_data_size)
|
||||
{
|
||||
struct kvec iov[2];
|
||||
struct kvec iov[3];
|
||||
struct smb_rqst rqst = {NULL};
|
||||
struct smb2_hdr *hdr;
|
||||
int rc;
|
||||
|
||||
iov[0].iov_base = buf;
|
||||
iov[0].iov_len = sizeof(struct smb2_transform_hdr);
|
||||
iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr);
|
||||
iov[1].iov_len = buf_data_size;
|
||||
iov[0].iov_base = NULL;
|
||||
iov[0].iov_len = 0;
|
||||
iov[1].iov_base = buf;
|
||||
iov[1].iov_len = sizeof(struct smb2_transform_hdr);
|
||||
iov[2].iov_base = buf + sizeof(struct smb2_transform_hdr);
|
||||
iov[2].iov_len = buf_data_size;
|
||||
|
||||
rqst.rq_iov = iov;
|
||||
rqst.rq_nvec = 2;
|
||||
rqst.rq_nvec = 3;
|
||||
rqst.rq_pages = pages;
|
||||
rqst.rq_npages = npages;
|
||||
rqst.rq_pagesz = PAGE_SIZE;
|
||||
|
@ -2365,10 +2456,9 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
memmove(buf + server->vals->header_preamble_size, iov[1].iov_base, buf_data_size);
|
||||
hdr = (struct smb2_hdr *)buf;
|
||||
hdr->smb2_buf_length = cpu_to_be32(buf_data_size + page_data_size);
|
||||
server->total_read = buf_data_size + page_data_size + server->vals->header_preamble_size;
|
||||
memmove(buf, iov[2].iov_base, buf_data_size);
|
||||
|
||||
server->total_read = buf_data_size + page_data_size;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -2393,7 +2483,7 @@ read_data_into_pages(struct TCP_Server_Info *server, struct page **pages,
|
|||
zero_user(page, len, PAGE_SIZE - len);
|
||||
len = 0;
|
||||
}
|
||||
length = cifs_read_page_from_socket(server, page, n);
|
||||
length = cifs_read_page_from_socket(server, page, 0, n);
|
||||
if (length < 0)
|
||||
return length;
|
||||
server->total_read += length;
|
||||
|
@ -2441,7 +2531,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
|||
unsigned int cur_page_idx;
|
||||
unsigned int pad_len;
|
||||
struct cifs_readdata *rdata = mid->callback_data;
|
||||
struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
|
||||
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
|
||||
struct bio_vec *bvec = NULL;
|
||||
struct iov_iter iter;
|
||||
struct kvec iov;
|
||||
|
@ -2472,7 +2562,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
|||
return 0;
|
||||
}
|
||||
|
||||
data_offset = server->ops->read_data_offset(buf) + server->vals->header_preamble_size;
|
||||
data_offset = server->ops->read_data_offset(buf);
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
use_rdma_mr = rdata->mr;
|
||||
#endif
|
||||
|
@ -2568,12 +2658,11 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
|
|||
unsigned int npages;
|
||||
struct page **pages;
|
||||
unsigned int len;
|
||||
unsigned int buflen = server->pdu_size + server->vals->header_preamble_size;
|
||||
unsigned int buflen = server->pdu_size;
|
||||
int rc;
|
||||
int i = 0;
|
||||
|
||||
len = min_t(unsigned int, buflen, server->vals->read_rsp_size -
|
||||
server->vals->header_preamble_size +
|
||||
len = min_t(unsigned int, buflen, server->vals->read_rsp_size +
|
||||
sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1;
|
||||
|
||||
rc = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, len);
|
||||
|
@ -2581,8 +2670,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
|
|||
return rc;
|
||||
server->total_read += rc;
|
||||
|
||||
len = le32_to_cpu(tr_hdr->OriginalMessageSize) +
|
||||
server->vals->header_preamble_size -
|
||||
len = le32_to_cpu(tr_hdr->OriginalMessageSize) -
|
||||
server->vals->read_rsp_size;
|
||||
npages = DIV_ROUND_UP(len, PAGE_SIZE);
|
||||
|
||||
|
@ -2609,8 +2697,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
|
|||
if (rc)
|
||||
goto free_pages;
|
||||
|
||||
rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size -
|
||||
server->vals->header_preamble_size,
|
||||
rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size,
|
||||
pages, npages, len);
|
||||
if (rc)
|
||||
goto free_pages;
|
||||
|
@ -2647,7 +2734,7 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
|
|||
struct mid_q_entry *mid_entry;
|
||||
|
||||
/* switch to large buffer if too big for a small one */
|
||||
if (pdu_length + server->vals->header_preamble_size > MAX_CIFS_SMALL_BUFFER_SIZE) {
|
||||
if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE) {
|
||||
server->large_buf = true;
|
||||
memcpy(server->bigbuf, buf, server->total_read);
|
||||
buf = server->bigbuf;
|
||||
|
@ -2655,13 +2742,12 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
|
|||
|
||||
/* now read the rest */
|
||||
length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
|
||||
pdu_length - HEADER_SIZE(server) + 1 +
|
||||
server->vals->header_preamble_size);
|
||||
pdu_length - HEADER_SIZE(server) + 1);
|
||||
if (length < 0)
|
||||
return length;
|
||||
server->total_read += length;
|
||||
|
||||
buf_size = pdu_length + server->vals->header_preamble_size - sizeof(struct smb2_transform_hdr);
|
||||
buf_size = pdu_length - sizeof(struct smb2_transform_hdr);
|
||||
length = decrypt_raw_data(server, buf, buf_size, NULL, 0, 0);
|
||||
if (length)
|
||||
return length;
|
||||
|
@ -2690,7 +2776,7 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid)
|
|||
struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
|
||||
unsigned int orig_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
|
||||
|
||||
if (pdu_length + server->vals->header_preamble_size < sizeof(struct smb2_transform_hdr) +
|
||||
if (pdu_length < sizeof(struct smb2_transform_hdr) +
|
||||
sizeof(struct smb2_sync_hdr)) {
|
||||
cifs_dbg(VFS, "Transform message is too small (%u)\n",
|
||||
pdu_length);
|
||||
|
@ -2699,14 +2785,14 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid)
|
|||
return -ECONNABORTED;
|
||||
}
|
||||
|
||||
if (pdu_length + server->vals->header_preamble_size < 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_reconnect(server);
|
||||
wake_up(&server->response_q);
|
||||
return -ECONNABORTED;
|
||||
}
|
||||
|
||||
if (pdu_length + server->vals->header_preamble_size > CIFSMaxBufSize + MAX_HEADER_SIZE(server))
|
||||
if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server))
|
||||
return receive_encrypted_read(server, mid);
|
||||
|
||||
return receive_encrypted_standard(server, mid);
|
||||
|
@ -2717,11 +2803,23 @@ smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
{
|
||||
char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
|
||||
|
||||
return handle_read_data(server, mid, buf, server->pdu_size +
|
||||
server->vals->header_preamble_size,
|
||||
return handle_read_data(server, mid, buf, server->pdu_size,
|
||||
NULL, 0, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
smb2_next_header(char *buf)
|
||||
{
|
||||
struct smb2_sync_hdr *hdr = (struct smb2_sync_hdr *)buf;
|
||||
struct smb2_transform_hdr *t_hdr = (struct smb2_transform_hdr *)buf;
|
||||
|
||||
if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM)
|
||||
return sizeof(struct smb2_transform_hdr) +
|
||||
le32_to_cpu(t_hdr->OriginalMessageSize);
|
||||
|
||||
return le32_to_cpu(hdr->NextCommand);
|
||||
}
|
||||
|
||||
struct smb_version_operations smb20_operations = {
|
||||
.compare_fids = smb2_compare_fids,
|
||||
.setup_request = smb2_setup_request,
|
||||
|
@ -2813,6 +2911,7 @@ struct smb_version_operations smb20_operations = {
|
|||
.get_acl_by_fid = get_smb2_acl_by_fid,
|
||||
.set_acl = set_smb2_acl,
|
||||
#endif /* CIFS_ACL */
|
||||
.next_header = smb2_next_header,
|
||||
};
|
||||
|
||||
struct smb_version_operations smb21_operations = {
|
||||
|
@ -2907,6 +3006,7 @@ struct smb_version_operations smb21_operations = {
|
|||
.get_acl_by_fid = get_smb2_acl_by_fid,
|
||||
.set_acl = set_smb2_acl,
|
||||
#endif /* CIFS_ACL */
|
||||
.next_header = smb2_next_header,
|
||||
};
|
||||
|
||||
struct smb_version_operations smb30_operations = {
|
||||
|
@ -3011,6 +3111,7 @@ struct smb_version_operations smb30_operations = {
|
|||
.get_acl_by_fid = get_smb2_acl_by_fid,
|
||||
.set_acl = set_smb2_acl,
|
||||
#endif /* CIFS_ACL */
|
||||
.next_header = smb2_next_header,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
|
@ -3111,6 +3212,7 @@ struct smb_version_operations smb311_operations = {
|
|||
.query_all_EAs = smb2_query_eas,
|
||||
.set_EA = smb2_set_ea,
|
||||
#endif /* CIFS_XATTR */
|
||||
.next_header = smb2_next_header,
|
||||
};
|
||||
#endif /* CIFS_SMB311 */
|
||||
|
||||
|
@ -3122,8 +3224,8 @@ struct smb_version_values smb20_values = {
|
|||
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
|
||||
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 4,
|
||||
.header_size = sizeof(struct smb2_sync_hdr),
|
||||
.header_preamble_size = 0,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
@ -3143,8 +3245,8 @@ struct smb_version_values smb21_values = {
|
|||
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
|
||||
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 4,
|
||||
.header_size = sizeof(struct smb2_sync_hdr),
|
||||
.header_preamble_size = 0,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
@ -3164,8 +3266,8 @@ struct smb_version_values smb3any_values = {
|
|||
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
|
||||
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 4,
|
||||
.header_size = sizeof(struct smb2_sync_hdr),
|
||||
.header_preamble_size = 0,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
@ -3185,8 +3287,8 @@ struct smb_version_values smbdefault_values = {
|
|||
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
|
||||
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 4,
|
||||
.header_size = sizeof(struct smb2_sync_hdr),
|
||||
.header_preamble_size = 0,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
@ -3206,8 +3308,8 @@ struct smb_version_values smb30_values = {
|
|||
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
|
||||
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 4,
|
||||
.header_size = sizeof(struct smb2_sync_hdr),
|
||||
.header_preamble_size = 0,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
@ -3227,8 +3329,8 @@ struct smb_version_values smb302_values = {
|
|||
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
|
||||
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 4,
|
||||
.header_size = sizeof(struct smb2_sync_hdr),
|
||||
.header_preamble_size = 0,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
@ -3249,8 +3351,8 @@ struct smb_version_values smb311_values = {
|
|||
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
|
||||
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 4,
|
||||
.header_size = sizeof(struct smb2_sync_hdr),
|
||||
.header_preamble_size = 0,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "cifspdu.h"
|
||||
#include "cifs_spnego.h"
|
||||
#include "smbdirect.h"
|
||||
#include "trace.h"
|
||||
|
||||
/*
|
||||
* The following table defines the expected "StructureSize" of SMB2 requests
|
||||
|
@ -79,7 +80,7 @@ static const int smb2_req_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {
|
|||
/* SMB2_OPLOCK_BREAK */ 24 /* BB this is 36 for LEASE_BREAK variant */
|
||||
};
|
||||
|
||||
static int encryption_required(const struct cifs_tcon *tcon)
|
||||
static int smb3_encryption_required(const struct cifs_tcon *tcon)
|
||||
{
|
||||
if (!tcon)
|
||||
return 0;
|
||||
|
@ -145,7 +146,7 @@ smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd,
|
|||
shdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */
|
||||
|
||||
if (tcon->ses && tcon->ses->server && tcon->ses->server->sign &&
|
||||
!encryption_required(tcon))
|
||||
!smb3_encryption_required(tcon))
|
||||
shdr->Flags |= SMB2_FLAGS_SIGNED;
|
||||
out:
|
||||
return;
|
||||
|
@ -367,6 +368,7 @@ smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
|
|||
|
||||
#define SMB2_PREAUTH_INTEGRITY_CAPABILITIES cpu_to_le16(1)
|
||||
#define SMB2_ENCRYPTION_CAPABILITIES cpu_to_le16(2)
|
||||
#define SMB2_POSIX_EXTENSIONS_AVAILABLE cpu_to_le16(0x100)
|
||||
|
||||
static void
|
||||
build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt)
|
||||
|
@ -389,22 +391,36 @@ build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt)
|
|||
pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_CCM;
|
||||
}
|
||||
|
||||
static void
|
||||
build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt)
|
||||
{
|
||||
pneg_ctxt->ContextType = SMB2_POSIX_EXTENSIONS_AVAILABLE;
|
||||
pneg_ctxt->DataLength = cpu_to_le16(POSIX_CTXT_DATA_LEN);
|
||||
}
|
||||
|
||||
static void
|
||||
assemble_neg_contexts(struct smb2_negotiate_req *req,
|
||||
unsigned int *total_len)
|
||||
{
|
||||
char *pneg_ctxt = (char *)req + OFFSET_OF_NEG_CONTEXT;
|
||||
unsigned int ctxt_len;
|
||||
|
||||
*total_len += 2; /* Add 2 due to round to 8 byte boundary for 1st ctxt */
|
||||
build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt);
|
||||
/* Add 2 to size to round to 8 byte boundary */
|
||||
ctxt_len = DIV_ROUND_UP(sizeof(struct smb2_preauth_neg_context), 8) * 8;
|
||||
*total_len += ctxt_len;
|
||||
pneg_ctxt += ctxt_len;
|
||||
|
||||
pneg_ctxt += 2 + sizeof(struct smb2_preauth_neg_context);
|
||||
build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt);
|
||||
req->NegotiateContextOffset = cpu_to_le32(OFFSET_OF_NEG_CONTEXT);
|
||||
req->NegotiateContextCount = cpu_to_le16(2);
|
||||
ctxt_len = DIV_ROUND_UP(sizeof(struct smb2_encryption_neg_context), 8) * 8;
|
||||
*total_len += ctxt_len;
|
||||
pneg_ctxt += ctxt_len;
|
||||
|
||||
*total_len += 4 + sizeof(struct smb2_preauth_neg_context)
|
||||
+ sizeof(struct smb2_encryption_neg_context);
|
||||
build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
|
||||
*total_len += sizeof(struct smb2_posix_neg_context);
|
||||
|
||||
req->NegotiateContextOffset = cpu_to_le32(OFFSET_OF_NEG_CONTEXT);
|
||||
req->NegotiateContextCount = cpu_to_le16(3);
|
||||
}
|
||||
|
||||
static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
|
||||
|
@ -449,12 +465,12 @@ static int decode_encrypt_ctx(struct TCP_Server_Info *server,
|
|||
}
|
||||
|
||||
static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
|
||||
struct TCP_Server_Info *server)
|
||||
struct TCP_Server_Info *server,
|
||||
unsigned int len_of_smb)
|
||||
{
|
||||
struct smb2_neg_context *pctx;
|
||||
unsigned int offset = le32_to_cpu(rsp->NegotiateContextOffset);
|
||||
unsigned int ctxt_cnt = le16_to_cpu(rsp->NegotiateContextCount);
|
||||
unsigned int len_of_smb = be32_to_cpu(rsp->hdr.smb2_buf_length);
|
||||
unsigned int len_of_ctxts, i;
|
||||
int rc = 0;
|
||||
|
||||
|
@ -475,8 +491,7 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
|
|||
if (len_of_ctxts < sizeof(struct smb2_neg_context))
|
||||
break;
|
||||
|
||||
pctx = (struct smb2_neg_context *)(offset +
|
||||
server->vals->header_preamble_size + (char *)rsp);
|
||||
pctx = (struct smb2_neg_context *)(offset + (char *)rsp);
|
||||
clen = le16_to_cpu(pctx->DataLength);
|
||||
if (clen > len_of_ctxts)
|
||||
break;
|
||||
|
@ -487,6 +502,8 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
|
|||
else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES)
|
||||
rc = decode_encrypt_ctx(server,
|
||||
(struct smb2_encryption_neg_context *)pctx);
|
||||
else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE)
|
||||
server->posix_ext_supported = true;
|
||||
else
|
||||
cifs_dbg(VFS, "unknown negcontext of type %d ignored\n",
|
||||
le16_to_cpu(pctx->ContextType));
|
||||
|
@ -501,6 +518,64 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static struct create_posix *
|
||||
create_posix_buf(umode_t mode)
|
||||
{
|
||||
struct create_posix *buf;
|
||||
|
||||
buf = kzalloc(sizeof(struct create_posix),
|
||||
GFP_KERNEL);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
buf->ccontext.DataOffset =
|
||||
cpu_to_le16(offsetof(struct create_posix, Mode));
|
||||
buf->ccontext.DataLength = cpu_to_le32(4);
|
||||
buf->ccontext.NameOffset =
|
||||
cpu_to_le16(offsetof(struct create_posix, Name));
|
||||
buf->ccontext.NameLength = cpu_to_le16(16);
|
||||
|
||||
/* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */
|
||||
buf->Name[0] = 0x93;
|
||||
buf->Name[1] = 0xAD;
|
||||
buf->Name[2] = 0x25;
|
||||
buf->Name[3] = 0x50;
|
||||
buf->Name[4] = 0x9C;
|
||||
buf->Name[5] = 0xB4;
|
||||
buf->Name[6] = 0x11;
|
||||
buf->Name[7] = 0xE7;
|
||||
buf->Name[8] = 0xB4;
|
||||
buf->Name[9] = 0x23;
|
||||
buf->Name[10] = 0x83;
|
||||
buf->Name[11] = 0xDE;
|
||||
buf->Name[12] = 0x96;
|
||||
buf->Name[13] = 0x8B;
|
||||
buf->Name[14] = 0xCD;
|
||||
buf->Name[15] = 0x7C;
|
||||
buf->Mode = cpu_to_le32(mode);
|
||||
cifs_dbg(FYI, "mode on posix create 0%o", mode);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int
|
||||
add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
|
||||
{
|
||||
struct smb2_create_req *req = iov[0].iov_base;
|
||||
unsigned int num = *num_iovec;
|
||||
|
||||
iov[num].iov_base = create_posix_buf(mode);
|
||||
if (iov[num].iov_base == NULL)
|
||||
return -ENOMEM;
|
||||
iov[num].iov_len = sizeof(struct create_posix);
|
||||
if (!req->CreateContextsOffset)
|
||||
req->CreateContextsOffset = cpu_to_le32(
|
||||
sizeof(struct smb2_create_req) +
|
||||
iov[num - 1].iov_len);
|
||||
le32_add_cpu(&req->CreateContextsLength, sizeof(struct create_posix));
|
||||
*num_iovec = num + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
static void assemble_neg_contexts(struct smb2_negotiate_req *req,
|
||||
unsigned int *total_len)
|
||||
|
@ -691,7 +766,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||
server->capabilities |= SMB2_NT_FIND | SMB2_LARGE_FILES;
|
||||
|
||||
security_blob = smb2_get_data_area_len(&blob_offset, &blob_length,
|
||||
&rsp->hdr);
|
||||
(struct smb2_sync_hdr *)rsp);
|
||||
/*
|
||||
* See MS-SMB2 section 2.2.4: if no blob, client picks default which
|
||||
* for us will be
|
||||
|
@ -718,7 +793,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||
#ifdef CONFIG_CIFS_SMB311
|
||||
if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
|
||||
if (rsp->NegotiateContextCount)
|
||||
rc = smb311_decode_neg_context(rsp, server);
|
||||
rc = smb311_decode_neg_context(rsp, server,
|
||||
rsp_iov.iov_len);
|
||||
else
|
||||
cifs_dbg(VFS, "Missing expected negotiate contexts\n");
|
||||
}
|
||||
|
@ -1054,7 +1130,7 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
|
|||
goto out_put_spnego_key;
|
||||
|
||||
rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
|
||||
ses->Suid = rsp->hdr.sync_hdr.SessionId;
|
||||
ses->Suid = rsp->sync_hdr.SessionId;
|
||||
|
||||
ses->session_flags = le16_to_cpu(rsp->SessionFlags);
|
||||
|
||||
|
@ -1130,13 +1206,13 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
|
|||
|
||||
/* If true, rc here is expected and not an error */
|
||||
if (sess_data->buf0_type != CIFS_NO_BUFFER &&
|
||||
rsp->hdr.sync_hdr.Status == STATUS_MORE_PROCESSING_REQUIRED)
|
||||
rsp->sync_hdr.Status == STATUS_MORE_PROCESSING_REQUIRED)
|
||||
rc = 0;
|
||||
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (offsetof(struct smb2_sess_setup_rsp, Buffer) - ses->server->vals->header_preamble_size !=
|
||||
if (offsetof(struct smb2_sess_setup_rsp, Buffer) !=
|
||||
le16_to_cpu(rsp->SecurityBufferOffset)) {
|
||||
cifs_dbg(VFS, "Invalid security buffer offset %d\n",
|
||||
le16_to_cpu(rsp->SecurityBufferOffset));
|
||||
|
@ -1151,7 +1227,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
|
|||
cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n");
|
||||
|
||||
|
||||
ses->Suid = rsp->hdr.sync_hdr.SessionId;
|
||||
ses->Suid = rsp->sync_hdr.SessionId;
|
||||
ses->session_flags = le16_to_cpu(rsp->SessionFlags);
|
||||
|
||||
out:
|
||||
|
@ -1209,7 +1285,7 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
|
|||
|
||||
rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
|
||||
|
||||
ses->Suid = rsp->hdr.sync_hdr.SessionId;
|
||||
ses->Suid = rsp->sync_hdr.SessionId;
|
||||
ses->session_flags = le16_to_cpu(rsp->SessionFlags);
|
||||
|
||||
rc = SMB2_sess_establish_session(sess_data);
|
||||
|
@ -1276,6 +1352,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
|
|||
sess_data->ses = ses;
|
||||
sess_data->buf0_type = CIFS_NO_BUFFER;
|
||||
sess_data->nls_cp = (struct nls_table *) nls_cp;
|
||||
sess_data->previous_session = ses->Suid;
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
/*
|
||||
|
@ -1403,7 +1480,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
|
|||
return rc;
|
||||
}
|
||||
|
||||
if (encryption_required(tcon))
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
iov[0].iov_base = (char *)req;
|
||||
|
@ -1419,7 +1496,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
|
|||
|
||||
/* 3.11 tcon req must be signed if not encrypted. See MS-SMB2 3.2.4.1.1 */
|
||||
if ((ses->server->dialect == SMB311_PROT_ID) &&
|
||||
!encryption_required(tcon))
|
||||
!smb3_encryption_required(tcon))
|
||||
req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED;
|
||||
|
||||
rc = smb2_send_recv(xid, ses, iov, 2, &resp_buftype, flags, &rsp_iov);
|
||||
|
@ -1457,7 +1534,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
|
|||
tcon->maximal_access = le32_to_cpu(rsp->MaximalAccess);
|
||||
tcon->tidStatus = CifsGood;
|
||||
tcon->need_reconnect = false;
|
||||
tcon->tid = rsp->hdr.sync_hdr.TreeId;
|
||||
tcon->tid = rsp->sync_hdr.TreeId;
|
||||
strlcpy(tcon->treeName, tree, sizeof(tcon->treeName));
|
||||
|
||||
if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) &&
|
||||
|
@ -1477,7 +1554,7 @@ tcon_exit:
|
|||
return rc;
|
||||
|
||||
tcon_error_exit:
|
||||
if (rsp && rsp->hdr.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);
|
||||
}
|
||||
goto tcon_exit;
|
||||
|
@ -1508,7 +1585,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (encryption_required(tcon))
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
flags |= CIFS_NO_RESP;
|
||||
|
@ -1575,7 +1652,7 @@ create_reconnect_durable_buf(struct cifs_fid *fid)
|
|||
|
||||
static __u8
|
||||
parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp,
|
||||
unsigned int *epoch)
|
||||
unsigned int *epoch, char *lease_key)
|
||||
{
|
||||
char *data_offset;
|
||||
struct create_context *cc;
|
||||
|
@ -1583,14 +1660,15 @@ parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp,
|
|||
unsigned int remaining;
|
||||
char *name;
|
||||
|
||||
data_offset = (char *)rsp + server->vals->header_preamble_size + le32_to_cpu(rsp->CreateContextsOffset);
|
||||
data_offset = (char *)rsp + le32_to_cpu(rsp->CreateContextsOffset);
|
||||
remaining = le32_to_cpu(rsp->CreateContextsLength);
|
||||
cc = (struct create_context *)data_offset;
|
||||
while (remaining >= sizeof(struct create_context)) {
|
||||
name = le16_to_cpu(cc->NameOffset) + (char *)cc;
|
||||
if (le16_to_cpu(cc->NameLength) == 4 &&
|
||||
strncmp(name, "RqLs", 4) == 0)
|
||||
return server->ops->parse_lease_buf(cc, epoch);
|
||||
return server->ops->parse_lease_buf(cc, epoch,
|
||||
lease_key);
|
||||
|
||||
next = le32_to_cpu(cc->Next);
|
||||
if (!next)
|
||||
|
@ -1818,7 +1896,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
|||
struct TCP_Server_Info *server;
|
||||
struct cifs_tcon *tcon = oparms->tcon;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct kvec iov[4];
|
||||
struct kvec iov[5]; /* make sure at least one for each open context */
|
||||
struct kvec rsp_iov = {NULL, 0};
|
||||
int resp_buftype;
|
||||
int uni_path_len;
|
||||
|
@ -1827,7 +1905,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
|||
int rc = 0;
|
||||
unsigned int n_iov = 2;
|
||||
__u32 file_attributes = 0;
|
||||
char *dhc_buf = NULL, *lc_buf = NULL;
|
||||
char *dhc_buf = NULL, *lc_buf = NULL, *pc_buf = NULL;
|
||||
int flags = 0;
|
||||
unsigned int total_len;
|
||||
|
||||
|
@ -1843,7 +1921,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (encryption_required(tcon))
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
if (oparms->create_options & CREATE_OPTION_READONLY)
|
||||
|
@ -1944,6 +2022,27 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
|||
dhc_buf = iov[n_iov-1].iov_base;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
if (tcon->posix_extensions) {
|
||||
if (n_iov > 2) {
|
||||
struct create_context *ccontext =
|
||||
(struct create_context *)iov[n_iov-1].iov_base;
|
||||
ccontext->Next =
|
||||
cpu_to_le32(iov[n_iov-1].iov_len);
|
||||
}
|
||||
|
||||
rc = add_posix_context(iov, &n_iov, oparms->mode);
|
||||
if (rc) {
|
||||
cifs_small_buf_release(req);
|
||||
kfree(copy_path);
|
||||
kfree(lc_buf);
|
||||
kfree(dhc_buf);
|
||||
return rc;
|
||||
}
|
||||
pc_buf = iov[n_iov-1].iov_base;
|
||||
}
|
||||
#endif /* SMB311 */
|
||||
|
||||
rc = smb2_send_recv(xid, ses, iov, n_iov, &resp_buftype, flags,
|
||||
&rsp_iov);
|
||||
cifs_small_buf_release(req);
|
||||
|
@ -1956,8 +2055,13 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
|||
resp_buftype = CIFS_NO_BUFFER;
|
||||
rsp = NULL;
|
||||
}
|
||||
trace_smb3_open_err(xid, tcon->tid, ses->Suid,
|
||||
oparms->create_options, oparms->desired_access, rc);
|
||||
goto creat_exit;
|
||||
}
|
||||
} else
|
||||
trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid,
|
||||
ses->Suid, oparms->create_options,
|
||||
oparms->desired_access);
|
||||
|
||||
oparms->fid->persistent_fid = rsp->PersistentFileId;
|
||||
oparms->fid->volatile_fid = rsp->VolatileFileId;
|
||||
|
@ -1972,13 +2076,15 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
|||
}
|
||||
|
||||
if (rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE)
|
||||
*oplock = parse_lease_state(server, rsp, &oparms->fid->epoch);
|
||||
*oplock = parse_lease_state(server, rsp, &oparms->fid->epoch,
|
||||
oparms->fid->lease_key);
|
||||
else
|
||||
*oplock = rsp->OplockLevel;
|
||||
creat_exit:
|
||||
kfree(copy_path);
|
||||
kfree(lc_buf);
|
||||
kfree(dhc_buf);
|
||||
kfree(pc_buf);
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
return rc;
|
||||
}
|
||||
|
@ -1994,7 +2100,6 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
|||
{
|
||||
struct smb2_ioctl_req *req;
|
||||
struct smb2_ioctl_rsp *rsp;
|
||||
struct smb2_sync_hdr *shdr;
|
||||
struct cifs_ses *ses;
|
||||
struct kvec iov[2];
|
||||
struct kvec rsp_iov;
|
||||
|
@ -2025,7 +2130,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (encryption_required(tcon))
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
req->CtlCode = cpu_to_le32(opcode);
|
||||
|
@ -2088,6 +2193,10 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
|||
cifs_small_buf_release(req);
|
||||
rsp = (struct smb2_ioctl_rsp *)rsp_iov.iov_base;
|
||||
|
||||
if (rc != 0)
|
||||
trace_smb3_fsctl_err(xid, persistent_fid, tcon->tid,
|
||||
ses->Suid, 0, opcode, rc);
|
||||
|
||||
if ((rc != 0) && (rc != -EINVAL)) {
|
||||
cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
|
||||
goto ioctl_exit;
|
||||
|
@ -2115,7 +2224,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
|||
goto ioctl_exit;
|
||||
}
|
||||
|
||||
if (get_rfc1002_length(rsp) < le32_to_cpu(rsp->OutputOffset) + *plen) {
|
||||
if (rsp_iov.iov_len < le32_to_cpu(rsp->OutputOffset) + *plen) {
|
||||
cifs_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n", *plen,
|
||||
le32_to_cpu(rsp->OutputOffset));
|
||||
*plen = 0;
|
||||
|
@ -2129,8 +2238,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
|||
goto ioctl_exit;
|
||||
}
|
||||
|
||||
shdr = get_sync_hdr(rsp);
|
||||
memcpy(*out_data, (char *)shdr + le32_to_cpu(rsp->OutputOffset), *plen);
|
||||
memcpy(*out_data, (char *)rsp + le32_to_cpu(rsp->OutputOffset), *plen);
|
||||
ioctl_exit:
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
return rc;
|
||||
|
@ -2162,8 +2270,8 @@ SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
}
|
||||
|
||||
int
|
||||
SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid)
|
||||
SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, int flags)
|
||||
{
|
||||
struct smb2_close_req *req;
|
||||
struct smb2_close_rsp *rsp;
|
||||
|
@ -2172,7 +2280,6 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
struct kvec rsp_iov;
|
||||
int resp_buftype;
|
||||
int rc = 0;
|
||||
int flags = 0;
|
||||
unsigned int total_len;
|
||||
|
||||
cifs_dbg(FYI, "Close\n");
|
||||
|
@ -2184,7 +2291,7 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (encryption_required(tcon))
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
req->PersistentFileId = persistent_fid;
|
||||
|
@ -2199,6 +2306,8 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
if (rc != 0) {
|
||||
cifs_stats_fail_inc(tcon, SMB2_CLOSE_HE);
|
||||
trace_smb3_close_err(xid, persistent_fid, tcon->tid, ses->Suid,
|
||||
rc);
|
||||
goto close_exit;
|
||||
}
|
||||
|
||||
|
@ -2209,14 +2318,20 @@ close_exit:
|
|||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid)
|
||||
{
|
||||
return SMB2_close_flags(xid, tcon, persistent_fid, volatile_fid, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
validate_iov(struct TCP_Server_Info *server,
|
||||
unsigned int offset, unsigned int buffer_length,
|
||||
validate_iov(unsigned int offset, unsigned int buffer_length,
|
||||
struct kvec *iov, unsigned int min_buf_size)
|
||||
{
|
||||
unsigned int smb_len = iov->iov_len;
|
||||
char *end_of_smb = smb_len + server->vals->header_preamble_size + (char *)iov->iov_base;
|
||||
char *begin_of_buf = server->vals->header_preamble_size + offset + (char *)iov->iov_base;
|
||||
char *end_of_smb = smb_len + (char *)iov->iov_base;
|
||||
char *begin_of_buf = offset + (char *)iov->iov_base;
|
||||
char *end_of_buf = begin_of_buf + buffer_length;
|
||||
|
||||
|
||||
|
@ -2246,18 +2361,17 @@ validate_iov(struct TCP_Server_Info *server,
|
|||
* Caller must free buffer.
|
||||
*/
|
||||
static int
|
||||
validate_and_copy_iov(struct TCP_Server_Info *server,
|
||||
unsigned int offset, unsigned int buffer_length,
|
||||
validate_and_copy_iov(unsigned int offset, unsigned int buffer_length,
|
||||
struct kvec *iov, unsigned int minbufsize,
|
||||
char *data)
|
||||
{
|
||||
char *begin_of_buf = server->vals->header_preamble_size + offset + (char *)(iov->iov_base);
|
||||
char *begin_of_buf = offset + (char *)iov->iov_base;
|
||||
int rc;
|
||||
|
||||
if (!data)
|
||||
return -EINVAL;
|
||||
|
||||
rc = validate_iov(server, offset, buffer_length, iov, minbufsize);
|
||||
rc = validate_iov(offset, buffer_length, iov, minbufsize);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -2292,7 +2406,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (encryption_required(tcon))
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
req->InfoType = info_type;
|
||||
|
@ -2318,6 +2432,8 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
if (rc) {
|
||||
cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
|
||||
trace_smb3_query_info_err(xid, persistent_fid, tcon->tid,
|
||||
ses->Suid, info_class, (__u32)info_type, rc);
|
||||
goto qinf_exit;
|
||||
}
|
||||
|
||||
|
@ -2335,8 +2451,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
}
|
||||
}
|
||||
|
||||
rc = validate_and_copy_iov(ses->server,
|
||||
le16_to_cpu(rsp->OutputBufferOffset),
|
||||
rc = validate_and_copy_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength),
|
||||
&rsp_iov, min_len, *data);
|
||||
|
||||
|
@ -2407,7 +2522,7 @@ smb2_echo_callback(struct mid_q_entry *mid)
|
|||
unsigned int credits_received = 1;
|
||||
|
||||
if (mid->mid_state == MID_RESPONSE_RECEIVED)
|
||||
credits_received = le16_to_cpu(rsp->hdr.sync_hdr.CreditRequest);
|
||||
credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest);
|
||||
|
||||
DeleteMidQEntry(mid);
|
||||
add_credits(server, credits_received, CIFS_ECHO_OP);
|
||||
|
@ -2536,7 +2651,7 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (encryption_required(tcon))
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
req->PersistentFileId = persistent_fid;
|
||||
|
@ -2548,8 +2663,11 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
|||
rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
|
||||
cifs_small_buf_release(req);
|
||||
|
||||
if (rc != 0)
|
||||
if (rc != 0) {
|
||||
cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE);
|
||||
trace_smb3_flush_err(xid, persistent_fid, tcon->tid, ses->Suid,
|
||||
rc);
|
||||
}
|
||||
|
||||
free_rsp_buf(resp_buftype, rsp_iov.iov_base);
|
||||
return rc;
|
||||
|
@ -2658,11 +2776,12 @@ smb2_readv_callback(struct mid_q_entry *mid)
|
|||
struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
struct smb2_sync_hdr *shdr =
|
||||
(struct smb2_sync_hdr *)rdata->iov[1].iov_base;
|
||||
(struct smb2_sync_hdr *)rdata->iov[0].iov_base;
|
||||
unsigned int credits_received = 1;
|
||||
struct smb_rqst rqst = { .rq_iov = rdata->iov,
|
||||
.rq_nvec = 2,
|
||||
.rq_pages = rdata->pages,
|
||||
.rq_offset = rdata->page_offset,
|
||||
.rq_npages = rdata->nr_pages,
|
||||
.rq_pagesz = rdata->pagesz,
|
||||
.rq_tailsz = rdata->tailsz };
|
||||
|
@ -2760,7 +2879,7 @@ smb2_async_readv(struct cifs_readdata *rdata)
|
|||
return rc;
|
||||
}
|
||||
|
||||
if (encryption_required(io_parms.tcon))
|
||||
if (smb3_encryption_required(io_parms.tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
req_len = cpu_to_be32(total_len);
|
||||
|
@ -2791,7 +2910,13 @@ smb2_async_readv(struct cifs_readdata *rdata)
|
|||
if (rc) {
|
||||
kref_put(&rdata->refcount, cifs_readdata_release);
|
||||
cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE);
|
||||
}
|
||||
trace_smb3_read_err(rc, 0 /* xid */, io_parms.persistent_fid,
|
||||
io_parms.tcon->tid, io_parms.tcon->ses->Suid,
|
||||
io_parms.offset, io_parms.length);
|
||||
} else
|
||||
trace_smb3_read_done(0 /* xid */, io_parms.persistent_fid,
|
||||
io_parms.tcon->tid, io_parms.tcon->ses->Suid,
|
||||
io_parms.offset, io_parms.length);
|
||||
|
||||
cifs_small_buf_release(buf);
|
||||
return rc;
|
||||
|
@ -2804,7 +2929,6 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|||
int resp_buftype, rc = -EACCES;
|
||||
struct smb2_read_plain_req *req = NULL;
|
||||
struct smb2_read_rsp *rsp = NULL;
|
||||
struct smb2_sync_hdr *shdr;
|
||||
struct kvec iov[1];
|
||||
struct kvec rsp_iov;
|
||||
unsigned int total_len;
|
||||
|
@ -2816,7 +2940,7 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (encryption_required(io_parms->tcon))
|
||||
if (smb3_encryption_required(io_parms->tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
iov[0].iov_base = (char *)req;
|
||||
|
@ -2832,9 +2956,15 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|||
cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE);
|
||||
cifs_dbg(VFS, "Send error in read = %d\n", rc);
|
||||
}
|
||||
trace_smb3_read_err(rc, xid, req->PersistentFileId,
|
||||
io_parms->tcon->tid, ses->Suid,
|
||||
io_parms->offset, io_parms->length);
|
||||
free_rsp_buf(resp_buftype, rsp_iov.iov_base);
|
||||
return rc == -ENODATA ? 0 : rc;
|
||||
}
|
||||
} else
|
||||
trace_smb3_read_done(xid, req->PersistentFileId,
|
||||
io_parms->tcon->tid, ses->Suid,
|
||||
io_parms->offset, io_parms->length);
|
||||
|
||||
*nbytes = le32_to_cpu(rsp->DataLength);
|
||||
if ((*nbytes > CIFS_MAX_MSGSIZE) ||
|
||||
|
@ -2845,10 +2975,8 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|||
*nbytes = 0;
|
||||
}
|
||||
|
||||
shdr = get_sync_hdr(rsp);
|
||||
|
||||
if (*buf) {
|
||||
memcpy(*buf, (char *)shdr + rsp->DataOffset, *nbytes);
|
||||
memcpy(*buf, (char *)rsp + rsp->DataOffset, *nbytes);
|
||||
free_rsp_buf(resp_buftype, rsp_iov.iov_base);
|
||||
} else if (resp_buftype != CIFS_NO_BUFFER) {
|
||||
*buf = rsp_iov.iov_base;
|
||||
|
@ -2875,7 +3003,7 @@ smb2_writev_callback(struct mid_q_entry *mid)
|
|||
|
||||
switch (mid->mid_state) {
|
||||
case MID_RESPONSE_RECEIVED:
|
||||
credits_received = le16_to_cpu(rsp->hdr.sync_hdr.CreditRequest);
|
||||
credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest);
|
||||
wdata->result = smb2_check_receive(mid, tcon->ses->server, 0);
|
||||
if (wdata->result != 0)
|
||||
break;
|
||||
|
@ -2952,7 +3080,7 @@ smb2_async_writev(struct cifs_writedata *wdata,
|
|||
goto async_writev_out;
|
||||
}
|
||||
|
||||
if (encryption_required(tcon))
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
shdr = (struct smb2_sync_hdr *)req;
|
||||
|
@ -3013,6 +3141,7 @@ smb2_async_writev(struct cifs_writedata *wdata,
|
|||
rqst.rq_iov = iov;
|
||||
rqst.rq_nvec = 2;
|
||||
rqst.rq_pages = wdata->pages;
|
||||
rqst.rq_offset = wdata->page_offset;
|
||||
rqst.rq_npages = wdata->nr_pages;
|
||||
rqst.rq_pagesz = wdata->pagesz;
|
||||
rqst.rq_tailsz = wdata->tailsz;
|
||||
|
@ -3050,9 +3179,15 @@ smb2_async_writev(struct cifs_writedata *wdata,
|
|||
wdata, flags);
|
||||
|
||||
if (rc) {
|
||||
trace_smb3_write_err(0 /* no xid */, req->PersistentFileId,
|
||||
tcon->tid, tcon->ses->Suid, wdata->offset,
|
||||
wdata->bytes, rc);
|
||||
kref_put(&wdata->refcount, release);
|
||||
cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
|
||||
}
|
||||
} else
|
||||
trace_smb3_write_done(0 /* no xid */, req->PersistentFileId,
|
||||
tcon->tid, tcon->ses->Suid, wdata->offset,
|
||||
wdata->bytes);
|
||||
|
||||
async_writev_out:
|
||||
cifs_small_buf_release(req);
|
||||
|
@ -3090,7 +3225,7 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|||
if (io_parms->tcon->ses->server == NULL)
|
||||
return -ECONNABORTED;
|
||||
|
||||
if (encryption_required(io_parms->tcon))
|
||||
if (smb3_encryption_required(io_parms->tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
req->sync_hdr.ProcessId = cpu_to_le32(io_parms->pid);
|
||||
|
@ -3116,10 +3251,19 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|||
rsp = (struct smb2_write_rsp *)rsp_iov.iov_base;
|
||||
|
||||
if (rc) {
|
||||
trace_smb3_write_err(xid, req->PersistentFileId,
|
||||
io_parms->tcon->tid,
|
||||
io_parms->tcon->ses->Suid,
|
||||
io_parms->offset, io_parms->length, rc);
|
||||
cifs_stats_fail_inc(io_parms->tcon, SMB2_WRITE_HE);
|
||||
cifs_dbg(VFS, "Send error in write = %d\n", rc);
|
||||
} else
|
||||
} else {
|
||||
*nbytes = le32_to_cpu(rsp->DataLength);
|
||||
trace_smb3_write_done(xid, req->PersistentFileId,
|
||||
io_parms->tcon->tid,
|
||||
io_parms->tcon->ses->Suid,
|
||||
io_parms->offset, *nbytes);
|
||||
}
|
||||
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
return rc;
|
||||
|
@ -3200,7 +3344,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (encryption_required(tcon))
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
switch (srch_inf->info_level) {
|
||||
|
@ -3251,7 +3395,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
if (rc) {
|
||||
if (rc == -ENODATA &&
|
||||
rsp->hdr.sync_hdr.Status == STATUS_NO_MORE_FILES) {
|
||||
rsp->sync_hdr.Status == STATUS_NO_MORE_FILES) {
|
||||
srch_inf->endOfSearch = true;
|
||||
rc = 0;
|
||||
}
|
||||
|
@ -3259,8 +3403,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
goto qdir_exit;
|
||||
}
|
||||
|
||||
rc = validate_iov(server,
|
||||
le16_to_cpu(rsp->OutputBufferOffset),
|
||||
rc = validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength), &rsp_iov,
|
||||
info_buf_size);
|
||||
if (rc)
|
||||
|
@ -3275,10 +3418,9 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
cifs_buf_release(srch_inf->ntwrk_buf_start);
|
||||
}
|
||||
srch_inf->ntwrk_buf_start = (char *)rsp;
|
||||
srch_inf->srch_entries_start = srch_inf->last_entry = 4 /* rfclen */ +
|
||||
(char *)&rsp->hdr + le16_to_cpu(rsp->OutputBufferOffset);
|
||||
/* 4 for rfc1002 length field */
|
||||
end_of_smb = get_rfc1002_length(rsp) + 4 + (char *)&rsp->hdr;
|
||||
srch_inf->srch_entries_start = srch_inf->last_entry =
|
||||
(char *)rsp + le16_to_cpu(rsp->OutputBufferOffset);
|
||||
end_of_smb = rsp_iov.iov_len + (char *)rsp;
|
||||
srch_inf->entries_in_buffer =
|
||||
num_entries(srch_inf->srch_entries_start, end_of_smb,
|
||||
&srch_inf->last_entry, info_buf_size);
|
||||
|
@ -3333,7 +3475,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
return rc;
|
||||
}
|
||||
|
||||
if (encryption_required(tcon))
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
req->sync_hdr.ProcessId = cpu_to_le32(pid);
|
||||
|
@ -3366,8 +3508,11 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
cifs_small_buf_release(req);
|
||||
rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base;
|
||||
|
||||
if (rc != 0)
|
||||
if (rc != 0) {
|
||||
cifs_stats_fail_inc(tcon, SMB2_SET_INFO_HE);
|
||||
trace_smb3_set_info_err(xid, persistent_fid, tcon->tid,
|
||||
ses->Suid, info_class, (__u32)info_type, rc);
|
||||
}
|
||||
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
kfree(iov);
|
||||
|
@ -3514,7 +3659,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
__u8 oplock_level)
|
||||
{
|
||||
int rc;
|
||||
struct smb2_oplock_break_req *req = NULL;
|
||||
struct smb2_oplock_break *req = NULL;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
int flags = CIFS_OBREAK_OP;
|
||||
unsigned int total_len;
|
||||
|
@ -3528,7 +3673,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (encryption_required(tcon))
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
req->VolatileFid = volatile_fid;
|
||||
|
@ -3593,7 +3738,7 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
|
|||
req->InputBufferOffset =
|
||||
cpu_to_le16(sizeof(struct smb2_query_info_req) - 1);
|
||||
req->OutputBufferLength = cpu_to_le32(
|
||||
outbuf_len + sizeof(struct smb2_query_info_rsp) - 1 - server->vals->header_preamble_size);
|
||||
outbuf_len + sizeof(struct smb2_query_info_rsp) - 1);
|
||||
|
||||
iov->iov_base = (char *)req;
|
||||
iov->iov_len = total_len;
|
||||
|
@ -3610,7 +3755,6 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
int rc = 0;
|
||||
int resp_buftype;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
struct smb2_fs_full_size_info *info = NULL;
|
||||
int flags = 0;
|
||||
|
||||
|
@ -3620,7 +3764,7 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (encryption_required(tcon))
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
rc = smb2_send_recv(xid, ses, &iov, 1, &resp_buftype, flags, &rsp_iov);
|
||||
|
@ -3631,10 +3775,9 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
}
|
||||
rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
|
||||
|
||||
info = (struct smb2_fs_full_size_info *)(server->vals->header_preamble_size +
|
||||
le16_to_cpu(rsp->OutputBufferOffset) + (char *)&rsp->hdr);
|
||||
rc = validate_iov(server,
|
||||
le16_to_cpu(rsp->OutputBufferOffset),
|
||||
info = (struct smb2_fs_full_size_info *)(
|
||||
le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
|
||||
rc = validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength), &rsp_iov,
|
||||
sizeof(struct smb2_fs_full_size_info));
|
||||
if (!rc)
|
||||
|
@ -3655,7 +3798,6 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
int rc = 0;
|
||||
int resp_buftype, max_len, min_len;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
unsigned int rsp_len, offset;
|
||||
int flags = 0;
|
||||
|
||||
|
@ -3678,7 +3820,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (encryption_required(tcon))
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
rc = smb2_send_recv(xid, ses, &iov, 1, &resp_buftype, flags, &rsp_iov);
|
||||
|
@ -3691,20 +3833,20 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
rsp_len = le32_to_cpu(rsp->OutputBufferLength);
|
||||
offset = le16_to_cpu(rsp->OutputBufferOffset);
|
||||
rc = validate_iov(server, offset, rsp_len, &rsp_iov, min_len);
|
||||
rc = validate_iov(offset, rsp_len, &rsp_iov, min_len);
|
||||
if (rc)
|
||||
goto qfsattr_exit;
|
||||
|
||||
if (level == FS_ATTRIBUTE_INFORMATION)
|
||||
memcpy(&tcon->fsAttrInfo, server->vals->header_preamble_size + offset
|
||||
+ (char *)&rsp->hdr, min_t(unsigned int,
|
||||
memcpy(&tcon->fsAttrInfo, offset
|
||||
+ (char *)rsp, min_t(unsigned int,
|
||||
rsp_len, max_len));
|
||||
else if (level == FS_DEVICE_INFORMATION)
|
||||
memcpy(&tcon->fsDevInfo, server->vals->header_preamble_size + offset
|
||||
+ (char *)&rsp->hdr, sizeof(FILE_SYSTEM_DEVICE_INFO));
|
||||
memcpy(&tcon->fsDevInfo, offset
|
||||
+ (char *)rsp, sizeof(FILE_SYSTEM_DEVICE_INFO));
|
||||
else if (level == FS_SECTOR_SIZE_INFORMATION) {
|
||||
struct smb3_fs_ss_info *ss_info = (struct smb3_fs_ss_info *)
|
||||
(server->vals->header_preamble_size + offset + (char *)&rsp->hdr);
|
||||
(offset + (char *)rsp);
|
||||
tcon->ss_flags = le32_to_cpu(ss_info->Flags);
|
||||
tcon->perf_sector_size =
|
||||
le32_to_cpu(ss_info->PhysicalBytesPerSectorForPerf);
|
||||
|
@ -3735,7 +3877,7 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (encryption_required(tcon))
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
req->sync_hdr.ProcessId = cpu_to_le32(pid);
|
||||
|
@ -3758,6 +3900,8 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
if (rc) {
|
||||
cifs_dbg(FYI, "Send error in smb2_lockv = %d\n", rc);
|
||||
cifs_stats_fail_inc(tcon, SMB2_LOCK_HE);
|
||||
trace_smb3_lock_err(xid, persist_fid, tcon->tid,
|
||||
tcon->ses->Suid, rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@ -3799,7 +3943,7 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (encryption_required(tcon))
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
req->sync_hdr.CreditRequest = cpu_to_le16(1);
|
||||
|
|
|
@ -122,25 +122,10 @@ struct smb2_sync_pdu {
|
|||
__le16 StructureSize2; /* size of wct area (varies, request specific) */
|
||||
} __packed;
|
||||
|
||||
struct smb2_hdr {
|
||||
__be32 smb2_buf_length; /* big endian on wire */
|
||||
/* length is only two or three bytes - with */
|
||||
/* one or two byte type preceding it that MBZ */
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
} __packed;
|
||||
|
||||
struct smb2_pdu {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize2; /* size of wct area (varies, request specific) */
|
||||
} __packed;
|
||||
|
||||
#define SMB3_AES128CMM_NONCE 11
|
||||
#define SMB3_AES128GCM_NONCE 12
|
||||
|
||||
struct smb2_transform_hdr {
|
||||
__be32 smb2_buf_length; /* big endian on wire */
|
||||
/* length is only two or three bytes - with
|
||||
one or two byte type preceding it that MBZ */
|
||||
__le32 ProtocolId; /* 0xFD 'S' 'M' 'B' */
|
||||
__u8 Signature[16];
|
||||
__u8 Nonce[16];
|
||||
|
@ -171,7 +156,7 @@ struct smb2_transform_hdr {
|
|||
#define SMB2_ERROR_STRUCTURE_SIZE2 cpu_to_le16(9)
|
||||
|
||||
struct smb2_err_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize;
|
||||
__le16 Reserved; /* MBZ */
|
||||
__le32 ByteCount; /* even if zero, at least one byte follows */
|
||||
|
@ -300,8 +285,16 @@ struct smb2_encryption_neg_context {
|
|||
__le16 Ciphers[1]; /* Ciphers[0] since only one used now */
|
||||
} __packed;
|
||||
|
||||
#define POSIX_CTXT_DATA_LEN 8
|
||||
struct smb2_posix_neg_context {
|
||||
__le16 ContextType; /* 0x100 */
|
||||
__le16 DataLength;
|
||||
__le32 Reserved;
|
||||
__le64 Reserved1; /* In case needed for future (eg version or caps) */
|
||||
} __packed;
|
||||
|
||||
struct smb2_negotiate_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 65 */
|
||||
__le16 SecurityMode;
|
||||
__le16 DialectRevision;
|
||||
|
@ -341,7 +334,7 @@ struct smb2_sess_setup_req {
|
|||
#define SMB2_SESSION_FLAG_IS_NULL 0x0002
|
||||
#define SMB2_SESSION_FLAG_ENCRYPT_DATA 0x0004
|
||||
struct smb2_sess_setup_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 9 */
|
||||
__le16 SessionFlags;
|
||||
__le16 SecurityBufferOffset;
|
||||
|
@ -356,7 +349,7 @@ struct smb2_logoff_req {
|
|||
} __packed;
|
||||
|
||||
struct smb2_logoff_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 4 */
|
||||
__le16 Reserved;
|
||||
} __packed;
|
||||
|
@ -452,7 +445,7 @@ struct smb2_tree_connect_req_extension {
|
|||
} __packed;
|
||||
|
||||
struct smb2_tree_connect_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 16 */
|
||||
__u8 ShareType; /* see below */
|
||||
__u8 Reserved;
|
||||
|
@ -503,7 +496,7 @@ struct smb2_tree_disconnect_req {
|
|||
} __packed;
|
||||
|
||||
struct smb2_tree_disconnect_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 4 */
|
||||
__le16 Reserved;
|
||||
} __packed;
|
||||
|
@ -615,7 +608,9 @@ struct smb2_tree_disconnect_rsp {
|
|||
#define SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 "DH2Q"
|
||||
#define SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 "DH2C"
|
||||
#define SMB2_CREATE_APP_INSTANCE_ID 0x45BCA66AEFA7F74A9008FA462E144D74
|
||||
#define SVHDX_OPEN_DEVICE_CONTEXT 0x83CE6F1AD851E0986E34401CC9BCFCE9
|
||||
#define SVHDX_OPEN_DEVICE_CONTEX 0x9CCBCF9E04C1E643980E158DA1F6EC83
|
||||
#define SMB2_CREATE_TAG_POSIX 0x93AD25509CB411E7B42383DE968BCD7C
|
||||
|
||||
|
||||
struct smb2_create_req {
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
|
@ -638,7 +633,7 @@ struct smb2_create_req {
|
|||
} __packed;
|
||||
|
||||
struct smb2_create_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 89 */
|
||||
__u8 OplockLevel;
|
||||
__u8 Reserved;
|
||||
|
@ -727,6 +722,13 @@ struct create_durable {
|
|||
} Data;
|
||||
} __packed;
|
||||
|
||||
struct create_posix {
|
||||
struct create_context ccontext;
|
||||
__u8 Name[16];
|
||||
__le32 Mode;
|
||||
__u32 Reserved;
|
||||
} __packed;
|
||||
|
||||
/* See MS-SMB2 2.2.13.2.11 */
|
||||
/* Flags */
|
||||
#define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002
|
||||
|
@ -894,7 +896,7 @@ struct smb2_ioctl_req {
|
|||
} __packed;
|
||||
|
||||
struct smb2_ioctl_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 57 */
|
||||
__u16 Reserved;
|
||||
__le32 CtlCode;
|
||||
|
@ -921,7 +923,7 @@ struct smb2_close_req {
|
|||
} __packed;
|
||||
|
||||
struct smb2_close_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* 60 */
|
||||
__le16 Flags;
|
||||
__le32 Reserved;
|
||||
|
@ -944,7 +946,7 @@ struct smb2_flush_req {
|
|||
} __packed;
|
||||
|
||||
struct smb2_flush_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize;
|
||||
__le16 Reserved;
|
||||
} __packed;
|
||||
|
@ -976,7 +978,7 @@ struct smb2_read_plain_req {
|
|||
} __packed;
|
||||
|
||||
struct smb2_read_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 17 */
|
||||
__u8 DataOffset;
|
||||
__u8 Reserved;
|
||||
|
@ -1007,7 +1009,7 @@ struct smb2_write_req {
|
|||
} __packed;
|
||||
|
||||
struct smb2_write_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 17 */
|
||||
__u8 DataOffset;
|
||||
__u8 Reserved;
|
||||
|
@ -1041,7 +1043,7 @@ struct smb2_lock_req {
|
|||
} __packed;
|
||||
|
||||
struct smb2_lock_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 4 */
|
||||
__le16 Reserved;
|
||||
} __packed;
|
||||
|
@ -1053,7 +1055,7 @@ struct smb2_echo_req {
|
|||
} __packed;
|
||||
|
||||
struct smb2_echo_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 4 */
|
||||
__u16 Reserved;
|
||||
} __packed;
|
||||
|
@ -1079,7 +1081,7 @@ struct smb2_query_directory_req {
|
|||
} __packed;
|
||||
|
||||
struct smb2_query_directory_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 9 */
|
||||
__le16 OutputBufferOffset;
|
||||
__le32 OutputBufferLength;
|
||||
|
@ -1128,7 +1130,7 @@ struct smb2_query_info_req {
|
|||
} __packed;
|
||||
|
||||
struct smb2_query_info_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 9 */
|
||||
__le16 OutputBufferOffset;
|
||||
__le32 OutputBufferLength;
|
||||
|
@ -1150,12 +1152,11 @@ struct smb2_set_info_req {
|
|||
} __packed;
|
||||
|
||||
struct smb2_set_info_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 2 */
|
||||
} __packed;
|
||||
|
||||
/* oplock break without an rfc1002 header */
|
||||
struct smb2_oplock_break_req {
|
||||
struct smb2_oplock_break {
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 24 */
|
||||
__u8 OplockLevel;
|
||||
|
@ -1165,21 +1166,10 @@ struct smb2_oplock_break_req {
|
|||
__u64 VolatileFid;
|
||||
} __packed;
|
||||
|
||||
/* oplock break with an rfc1002 header */
|
||||
struct smb2_oplock_break_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 24 */
|
||||
__u8 OplockLevel;
|
||||
__u8 Reserved;
|
||||
__le32 Reserved2;
|
||||
__u64 PersistentFid;
|
||||
__u64 VolatileFid;
|
||||
} __packed;
|
||||
|
||||
#define SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED cpu_to_le32(0x01)
|
||||
|
||||
struct smb2_lease_break {
|
||||
struct smb2_hdr hdr;
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 44 */
|
||||
__le16 Reserved;
|
||||
__le32 Flags;
|
||||
|
|
|
@ -36,8 +36,9 @@ struct smb_rqst;
|
|||
extern int map_smb2_to_linux_error(char *buf, bool log_err);
|
||||
extern int smb2_check_message(char *buf, unsigned int length,
|
||||
struct TCP_Server_Info *server);
|
||||
extern unsigned int smb2_calc_size(void *buf);
|
||||
extern char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr);
|
||||
extern unsigned int smb2_calc_size(void *buf, struct TCP_Server_Info *server);
|
||||
extern char *smb2_get_data_area_len(int *off, int *len,
|
||||
struct smb2_sync_hdr *shdr);
|
||||
extern __le16 *cifs_convert_path_to_utf16(const char *from,
|
||||
struct cifs_sb_info *cifs_sb);
|
||||
|
||||
|
@ -65,6 +66,8 @@ extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server,
|
|||
extern int smb3_handle_read_data(struct TCP_Server_Info *server,
|
||||
struct mid_q_entry *mid);
|
||||
|
||||
extern int open_shroot(unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_fid *pfid);
|
||||
extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
|
||||
struct smb2_file_all_info *src);
|
||||
extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
@ -129,6 +132,8 @@ extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
char **out_data, u32 *plen /* returned data len */);
|
||||
extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_file_id, u64 volatile_file_id);
|
||||
extern int SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, int flags);
|
||||
extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_file_id, u64 volatile_file_id);
|
||||
extern int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
|
|
@ -480,7 +480,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
|||
unsigned int rc;
|
||||
char server_response_sig[16];
|
||||
struct smb2_sync_hdr *shdr =
|
||||
(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
|
||||
(struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base;
|
||||
|
||||
if ((shdr->Command == SMB2_NEGOTIATE) ||
|
||||
(shdr->Command == SMB2_SESSION_SETUP) ||
|
||||
|
@ -605,14 +605,12 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
|
|||
bool log_error)
|
||||
{
|
||||
unsigned int len = mid->resp_buf_size;
|
||||
struct kvec iov[2];
|
||||
struct kvec iov[1];
|
||||
struct smb_rqst rqst = { .rq_iov = iov,
|
||||
.rq_nvec = 2 };
|
||||
.rq_nvec = 1 };
|
||||
|
||||
iov[0].iov_base = (char *)mid->resp_buf;
|
||||
iov[0].iov_len = 4;
|
||||
iov[1].iov_base = (char *)mid->resp_buf + 4;
|
||||
iov[1].iov_len = len;
|
||||
iov[0].iov_len = len;
|
||||
|
||||
dump_smb(mid->resp_buf, min_t(u32, 80, len));
|
||||
/* convert the length into a more usable form */
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2018, Microsoft Corporation.
|
||||
*
|
||||
* Author(s): Steve French <stfrench@microsoft.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU General Public License for more details.
|
||||
*/
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "trace.h"
|
|
@ -0,0 +1,429 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2018, Microsoft Corporation.
|
||||
*
|
||||
* Author(s): Steve French <stfrench@microsoft.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU General Public License for more details.
|
||||
*/
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM cifs
|
||||
|
||||
#if !defined(_CIFS_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _CIFS_TRACE_H
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
/* For logging errors in read or write */
|
||||
DECLARE_EVENT_CLASS(smb3_rw_err_class,
|
||||
TP_PROTO(unsigned int xid,
|
||||
__u64 fid,
|
||||
__u32 tid,
|
||||
__u64 sesid,
|
||||
__u64 offset,
|
||||
__u32 len,
|
||||
int rc),
|
||||
TP_ARGS(xid, fid, tid, sesid, offset, len, rc),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, xid)
|
||||
__field(__u64, fid)
|
||||
__field(__u32, tid)
|
||||
__field(__u64, sesid)
|
||||
__field(__u64, offset)
|
||||
__field(__u32, len)
|
||||
__field(int, rc)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->xid = xid;
|
||||
__entry->fid = fid;
|
||||
__entry->tid = tid;
|
||||
__entry->sesid = sesid;
|
||||
__entry->offset = offset;
|
||||
__entry->len = len;
|
||||
__entry->rc = rc;
|
||||
),
|
||||
TP_printk("\txid=%u sid=0x%llx tid=0x%x fid=0x%llx offset=0x%llx len=0x%x rc=%d",
|
||||
__entry->xid, __entry->sesid, __entry->tid, __entry->fid,
|
||||
__entry->offset, __entry->len, __entry->rc)
|
||||
)
|
||||
|
||||
#define DEFINE_SMB3_RW_ERR_EVENT(name) \
|
||||
DEFINE_EVENT(smb3_rw_err_class, smb3_##name, \
|
||||
TP_PROTO(unsigned int xid, \
|
||||
__u64 fid, \
|
||||
__u32 tid, \
|
||||
__u64 sesid, \
|
||||
__u64 offset, \
|
||||
__u32 len, \
|
||||
int rc), \
|
||||
TP_ARGS(xid, fid, tid, sesid, offset, len, rc))
|
||||
|
||||
DEFINE_SMB3_RW_ERR_EVENT(write_err);
|
||||
DEFINE_SMB3_RW_ERR_EVENT(read_err);
|
||||
|
||||
|
||||
/* For logging successful read or write */
|
||||
DECLARE_EVENT_CLASS(smb3_rw_done_class,
|
||||
TP_PROTO(unsigned int xid,
|
||||
__u64 fid,
|
||||
__u32 tid,
|
||||
__u64 sesid,
|
||||
__u64 offset,
|
||||
__u32 len),
|
||||
TP_ARGS(xid, fid, tid, sesid, offset, len),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, xid)
|
||||
__field(__u64, fid)
|
||||
__field(__u32, tid)
|
||||
__field(__u64, sesid)
|
||||
__field(__u64, offset)
|
||||
__field(__u32, len)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->xid = xid;
|
||||
__entry->fid = fid;
|
||||
__entry->tid = tid;
|
||||
__entry->sesid = sesid;
|
||||
__entry->offset = offset;
|
||||
__entry->len = len;
|
||||
),
|
||||
TP_printk("xid=%u sid=0x%llx tid=0x%x fid=0x%llx offset=0x%llx len=0x%x",
|
||||
__entry->xid, __entry->sesid, __entry->tid, __entry->fid,
|
||||
__entry->offset, __entry->len)
|
||||
)
|
||||
|
||||
#define DEFINE_SMB3_RW_DONE_EVENT(name) \
|
||||
DEFINE_EVENT(smb3_rw_done_class, smb3_##name, \
|
||||
TP_PROTO(unsigned int xid, \
|
||||
__u64 fid, \
|
||||
__u32 tid, \
|
||||
__u64 sesid, \
|
||||
__u64 offset, \
|
||||
__u32 len), \
|
||||
TP_ARGS(xid, fid, tid, sesid, offset, len))
|
||||
|
||||
DEFINE_SMB3_RW_DONE_EVENT(write_done);
|
||||
DEFINE_SMB3_RW_DONE_EVENT(read_done);
|
||||
|
||||
/*
|
||||
* For handle based calls other than read and write, and get/set info
|
||||
*/
|
||||
DECLARE_EVENT_CLASS(smb3_fd_err_class,
|
||||
TP_PROTO(unsigned int xid,
|
||||
__u64 fid,
|
||||
__u32 tid,
|
||||
__u64 sesid,
|
||||
int rc),
|
||||
TP_ARGS(xid, fid, tid, sesid, rc),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, xid)
|
||||
__field(__u64, fid)
|
||||
__field(__u32, tid)
|
||||
__field(__u64, sesid)
|
||||
__field(int, rc)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->xid = xid;
|
||||
__entry->fid = fid;
|
||||
__entry->tid = tid;
|
||||
__entry->sesid = sesid;
|
||||
__entry->rc = rc;
|
||||
),
|
||||
TP_printk("\txid=%u sid=0x%llx tid=0x%x fid=0x%llx rc=%d",
|
||||
__entry->xid, __entry->sesid, __entry->tid, __entry->fid,
|
||||
__entry->rc)
|
||||
)
|
||||
|
||||
#define DEFINE_SMB3_FD_ERR_EVENT(name) \
|
||||
DEFINE_EVENT(smb3_fd_err_class, smb3_##name, \
|
||||
TP_PROTO(unsigned int xid, \
|
||||
__u64 fid, \
|
||||
__u32 tid, \
|
||||
__u64 sesid, \
|
||||
int rc), \
|
||||
TP_ARGS(xid, fid, tid, sesid, rc))
|
||||
|
||||
DEFINE_SMB3_FD_ERR_EVENT(flush_err);
|
||||
DEFINE_SMB3_FD_ERR_EVENT(lock_err);
|
||||
DEFINE_SMB3_FD_ERR_EVENT(close_err);
|
||||
|
||||
/*
|
||||
* For handle based query/set info calls
|
||||
*/
|
||||
DECLARE_EVENT_CLASS(smb3_inf_err_class,
|
||||
TP_PROTO(unsigned int xid,
|
||||
__u64 fid,
|
||||
__u32 tid,
|
||||
__u64 sesid,
|
||||
__u8 infclass,
|
||||
__u32 type,
|
||||
int rc),
|
||||
TP_ARGS(xid, fid, tid, sesid, infclass, type, rc),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, xid)
|
||||
__field(__u64, fid)
|
||||
__field(__u32, tid)
|
||||
__field(__u64, sesid)
|
||||
__field(__u8, infclass)
|
||||
__field(__u32, type)
|
||||
__field(int, rc)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->xid = xid;
|
||||
__entry->fid = fid;
|
||||
__entry->tid = tid;
|
||||
__entry->sesid = sesid;
|
||||
__entry->infclass = infclass;
|
||||
__entry->type = type;
|
||||
__entry->rc = rc;
|
||||
),
|
||||
TP_printk("xid=%u sid=0x%llx tid=0x%x fid=0x%llx class=%u type=0x%x rc=%d",
|
||||
__entry->xid, __entry->sesid, __entry->tid, __entry->fid,
|
||||
__entry->infclass, __entry->type, __entry->rc)
|
||||
)
|
||||
|
||||
#define DEFINE_SMB3_INF_ERR_EVENT(name) \
|
||||
DEFINE_EVENT(smb3_inf_err_class, smb3_##name, \
|
||||
TP_PROTO(unsigned int xid, \
|
||||
__u64 fid, \
|
||||
__u32 tid, \
|
||||
__u64 sesid, \
|
||||
__u8 infclass, \
|
||||
__u32 type, \
|
||||
int rc), \
|
||||
TP_ARGS(xid, fid, tid, sesid, infclass, type, rc))
|
||||
|
||||
DEFINE_SMB3_INF_ERR_EVENT(query_info_err);
|
||||
DEFINE_SMB3_INF_ERR_EVENT(set_info_err);
|
||||
DEFINE_SMB3_INF_ERR_EVENT(fsctl_err);
|
||||
|
||||
/*
|
||||
* For logging SMB3 Status code and Command for responses which return errors
|
||||
*/
|
||||
DECLARE_EVENT_CLASS(smb3_cmd_err_class,
|
||||
TP_PROTO(__u32 tid,
|
||||
__u64 sesid,
|
||||
__u16 cmd,
|
||||
__u64 mid,
|
||||
__u32 status,
|
||||
int rc),
|
||||
TP_ARGS(tid, sesid, cmd, mid, status, rc),
|
||||
TP_STRUCT__entry(
|
||||
__field(__u32, tid)
|
||||
__field(__u64, sesid)
|
||||
__field(__u16, cmd)
|
||||
__field(__u64, mid)
|
||||
__field(__u32, status)
|
||||
__field(int, rc)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->tid = tid;
|
||||
__entry->sesid = sesid;
|
||||
__entry->cmd = cmd;
|
||||
__entry->mid = mid;
|
||||
__entry->status = status;
|
||||
__entry->rc = rc;
|
||||
),
|
||||
TP_printk("\tsid=0x%llx tid=0x%x cmd=%u mid=%llu status=0x%x rc=%d",
|
||||
__entry->sesid, __entry->tid, __entry->cmd, __entry->mid,
|
||||
__entry->status, __entry->rc)
|
||||
)
|
||||
|
||||
#define DEFINE_SMB3_CMD_ERR_EVENT(name) \
|
||||
DEFINE_EVENT(smb3_cmd_err_class, smb3_##name, \
|
||||
TP_PROTO(__u32 tid, \
|
||||
__u64 sesid, \
|
||||
__u16 cmd, \
|
||||
__u64 mid, \
|
||||
__u32 status, \
|
||||
int rc), \
|
||||
TP_ARGS(tid, sesid, cmd, mid, status, rc))
|
||||
|
||||
DEFINE_SMB3_CMD_ERR_EVENT(cmd_err);
|
||||
|
||||
DECLARE_EVENT_CLASS(smb3_cmd_done_class,
|
||||
TP_PROTO(__u32 tid,
|
||||
__u64 sesid,
|
||||
__u16 cmd,
|
||||
__u64 mid),
|
||||
TP_ARGS(tid, sesid, cmd, mid),
|
||||
TP_STRUCT__entry(
|
||||
__field(__u32, tid)
|
||||
__field(__u64, sesid)
|
||||
__field(__u16, cmd)
|
||||
__field(__u64, mid)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->tid = tid;
|
||||
__entry->sesid = sesid;
|
||||
__entry->cmd = cmd;
|
||||
__entry->mid = mid;
|
||||
),
|
||||
TP_printk("\tsid=0x%llx tid=0x%x cmd=%u mid=%llu",
|
||||
__entry->sesid, __entry->tid,
|
||||
__entry->cmd, __entry->mid)
|
||||
)
|
||||
|
||||
#define DEFINE_SMB3_CMD_DONE_EVENT(name) \
|
||||
DEFINE_EVENT(smb3_cmd_done_class, smb3_##name, \
|
||||
TP_PROTO(__u32 tid, \
|
||||
__u64 sesid, \
|
||||
__u16 cmd, \
|
||||
__u64 mid), \
|
||||
TP_ARGS(tid, sesid, cmd, mid))
|
||||
|
||||
DEFINE_SMB3_CMD_DONE_EVENT(cmd_done);
|
||||
|
||||
DECLARE_EVENT_CLASS(smb3_exit_err_class,
|
||||
TP_PROTO(unsigned int xid,
|
||||
const char *func_name,
|
||||
int rc),
|
||||
TP_ARGS(xid, func_name, rc),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, xid)
|
||||
__field(const char *, func_name)
|
||||
__field(int, rc)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->xid = xid;
|
||||
__entry->func_name = func_name;
|
||||
__entry->rc = rc;
|
||||
),
|
||||
TP_printk("\t%s: xid=%u rc=%d",
|
||||
__entry->func_name, __entry->xid, __entry->rc)
|
||||
)
|
||||
|
||||
#define DEFINE_SMB3_EXIT_ERR_EVENT(name) \
|
||||
DEFINE_EVENT(smb3_exit_err_class, smb3_##name, \
|
||||
TP_PROTO(unsigned int xid, \
|
||||
const char *func_name, \
|
||||
int rc), \
|
||||
TP_ARGS(xid, func_name, rc))
|
||||
|
||||
DEFINE_SMB3_EXIT_ERR_EVENT(exit_err);
|
||||
|
||||
DECLARE_EVENT_CLASS(smb3_enter_exit_class,
|
||||
TP_PROTO(unsigned int xid,
|
||||
const char *func_name),
|
||||
TP_ARGS(xid, func_name),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, xid)
|
||||
__field(const char *, func_name)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->xid = xid;
|
||||
__entry->func_name = func_name;
|
||||
),
|
||||
TP_printk("\t%s: xid=%u",
|
||||
__entry->func_name, __entry->xid)
|
||||
)
|
||||
|
||||
#define DEFINE_SMB3_ENTER_EXIT_EVENT(name) \
|
||||
DEFINE_EVENT(smb3_enter_exit_class, smb3_##name, \
|
||||
TP_PROTO(unsigned int xid, \
|
||||
const char *func_name), \
|
||||
TP_ARGS(xid, func_name))
|
||||
|
||||
DEFINE_SMB3_ENTER_EXIT_EVENT(enter);
|
||||
DEFINE_SMB3_ENTER_EXIT_EVENT(exit_done);
|
||||
|
||||
/*
|
||||
* For smb2/smb3 open call
|
||||
*/
|
||||
DECLARE_EVENT_CLASS(smb3_open_err_class,
|
||||
TP_PROTO(unsigned int xid,
|
||||
__u32 tid,
|
||||
__u64 sesid,
|
||||
int create_options,
|
||||
int desired_access,
|
||||
int rc),
|
||||
TP_ARGS(xid, tid, sesid, create_options, desired_access, rc),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, xid)
|
||||
__field(__u32, tid)
|
||||
__field(__u64, sesid)
|
||||
__field(int, create_options)
|
||||
__field(int, desired_access)
|
||||
__field(int, rc)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->xid = xid;
|
||||
__entry->tid = tid;
|
||||
__entry->sesid = sesid;
|
||||
__entry->create_options = create_options;
|
||||
__entry->desired_access = desired_access;
|
||||
__entry->rc = rc;
|
||||
),
|
||||
TP_printk("xid=%u sid=0x%llx tid=0x%x cr_opts=0x%x des_access=0x%x rc=%d",
|
||||
__entry->xid, __entry->sesid, __entry->tid,
|
||||
__entry->create_options, __entry->desired_access, __entry->rc)
|
||||
)
|
||||
|
||||
#define DEFINE_SMB3_OPEN_ERR_EVENT(name) \
|
||||
DEFINE_EVENT(smb3_open_err_class, smb3_##name, \
|
||||
TP_PROTO(unsigned int xid, \
|
||||
__u32 tid, \
|
||||
__u64 sesid, \
|
||||
int create_options, \
|
||||
int desired_access, \
|
||||
int rc), \
|
||||
TP_ARGS(xid, tid, sesid, create_options, desired_access, rc))
|
||||
|
||||
DEFINE_SMB3_OPEN_ERR_EVENT(open_err);
|
||||
|
||||
|
||||
DECLARE_EVENT_CLASS(smb3_open_done_class,
|
||||
TP_PROTO(unsigned int xid,
|
||||
__u64 fid,
|
||||
__u32 tid,
|
||||
__u64 sesid,
|
||||
int create_options,
|
||||
int desired_access),
|
||||
TP_ARGS(xid, fid, tid, sesid, create_options, desired_access),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, xid)
|
||||
__field(__u64, fid)
|
||||
__field(__u32, tid)
|
||||
__field(__u64, sesid)
|
||||
__field(int, create_options)
|
||||
__field(int, desired_access)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->xid = xid;
|
||||
__entry->fid = fid;
|
||||
__entry->tid = tid;
|
||||
__entry->sesid = sesid;
|
||||
__entry->create_options = create_options;
|
||||
__entry->desired_access = desired_access;
|
||||
),
|
||||
TP_printk("xid=%u sid=0x%llx tid=0x%x fid=0x%llx cr_opts=0x%x des_access=0x%x",
|
||||
__entry->xid, __entry->sesid, __entry->tid, __entry->fid,
|
||||
__entry->create_options, __entry->desired_access)
|
||||
)
|
||||
|
||||
#define DEFINE_SMB3_OPEN_DONE_EVENT(name) \
|
||||
DEFINE_EVENT(smb3_open_done_class, smb3_##name, \
|
||||
TP_PROTO(unsigned int xid, \
|
||||
__u64 fid, \
|
||||
__u32 tid, \
|
||||
__u64 sesid, \
|
||||
int create_options, \
|
||||
int desired_access), \
|
||||
TP_ARGS(xid, fid, tid, sesid, create_options, desired_access))
|
||||
|
||||
DEFINE_SMB3_OPEN_DONE_EVENT(open_done);
|
||||
|
||||
#endif /* _CIFS_TRACE_H */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH .
|
||||
#define TRACE_INCLUDE_FILE trace
|
||||
#include <trace/define_trace.h>
|
|
@ -800,8 +800,8 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
|||
#ifdef CONFIG_CIFS_SMB311
|
||||
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) {
|
||||
struct kvec iov = {
|
||||
.iov_base = buf + 4,
|
||||
.iov_len = get_rfc1002_length(buf)
|
||||
.iov_base = buf,
|
||||
.iov_len = midQ->resp_buf_size
|
||||
};
|
||||
smb311_update_preauth_hash(ses, &iov, 1);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue