22 smb3 client fixes
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmk3lJoACgkQiiy9cAdy T1HZhAv+IreQpPeRVeq8hd8JYfsys75bo6Dc4eElyO4mLBirMS2wcfM54kCm1Uxr 9dOt/q+nD6YI6L0IYRMwGSawWFqs76qpz5ZxZzg9xQ2AS3jWCPXK1cdtIOZFahJ0 v14Pvo0tF8QmSxqKtTQ10FojWIS9Y9feqWvXW+BbVd2w1zk7iQ//9vnygfzu27o2 DTWqkmEOirt08AUDuROr5vvhl6Ew4J6Dej6jd3C7GuZ5vB0o425vxk3gFE7dI2d1 1h+YeyiLLmgAKyZ9QZAqLVXqgsBz1SflycR6UpW4gvNeTkDxI1MbXsIUz+f/xReJ SUM6t7gp3hO3XCtW+wYkDq4spIjspJVUNeM1YK0Ip4x5TRy5Jcoe0ikeh/DbET+N W7mijp+LLTrWG9B1hIXH+0fATuH5dolGmhADOrVqvHL4A8oIp16HyGEjg3dRpMZ+ AsDyjICmv1qXQNX/lvEJtXAQOSyOoO6ouCuavNBXwJVTsSqDrcW5pmifSkF+ZAV8 5PGQNI+2 =PmvL -----END PGP SIGNATURE----- Merge tag 'v6.19-rc-part1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull smb client updates from Steve French: - multichannel fixes, including enabling ability to change multichannel settings with remount - debugging improvements: adding additional tracepoints, improving log messages - cleanup, including restructuring some of the transport layer for the client to make it clearer, and cleanup of status code table to be more consistent with protocol documentation - fixes for reads that start beyond end of file use cases - fix to backoff reconnects to reduce reconnect storms - locking improvement for getting mid entries - fixes for missing status code error mappings - performance improvement for status code to error mappings * tag 'v6.19-rc-part1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: (22 commits) smb/client: update some SMB2 status strings cifs: Remove dead function prototypes smb/client: add two elements to smb2_error_map_table array smb: rename to STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP smb/client: remove unused elements from smb2_error_map_table array smb/client: reduce loop count in map_smb2_to_linux_error() by half smb: client: Add tracepoint for krb5 auth smb: client: improve error message when creating SMB session smb: client: relax session and tcon reconnect attempts cifs: Fix handling of a beyond-EOF DIO/unbuffered read over SMB2 cifs: client: allow changing multichannel mount options on remount cifs: Do some preparation prior to organising the function declarations cifs: Add a tracepoint to log EIO errors cifs: Don't need state locking in smb2_get_mid_entry() cifs: Remove the server pointer from smb_message cifs: Fix specification of function pointers cifs: Replace SendReceiveBlockingLock() with SendReceive() plus flags cifs: Clean up some places where an extra kvec[] was required for rfc1002 cifs: Make smb1's SendReceive() wrap cifs_send_recv() cifs: Remove the RFC1002 header from smb_hdr ...pull/1354/merge
commit
3d99347a2e
|
|
@ -176,7 +176,7 @@ replay_again:
|
|||
server = cifs_pick_channel(ses);
|
||||
|
||||
if (!server->ops->new_lease_key)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_no_lease_key);
|
||||
|
||||
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
||||
if (!utf16_path)
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ cifs_dump_mem(char *label, void *data, int length)
|
|||
data, length, true);
|
||||
}
|
||||
|
||||
void cifs_dump_detail(void *buf, struct TCP_Server_Info *server)
|
||||
void cifs_dump_detail(void *buf, size_t buf_len, struct TCP_Server_Info *server)
|
||||
{
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
struct smb_hdr *smb = buf;
|
||||
|
|
@ -45,7 +45,7 @@ void cifs_dump_detail(void *buf, struct TCP_Server_Info *server)
|
|||
cifs_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d Wct: %d\n",
|
||||
smb->Command, smb->Status.CifsError, smb->Flags,
|
||||
smb->Flags2, smb->Mid, smb->Pid, smb->WordCount);
|
||||
if (!server->ops->check_message(buf, server->total_read, server)) {
|
||||
if (!server->ops->check_message(buf, buf_len, server->total_read, server)) {
|
||||
cifs_dbg(VFS, "smb buf %p len %u\n", smb,
|
||||
server->ops->calc_smb_size(smb));
|
||||
}
|
||||
|
|
@ -79,9 +79,9 @@ 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, server);
|
||||
cifs_dump_mem("existing buf: ",
|
||||
mid_entry->resp_buf, 62);
|
||||
cifs_dump_detail(mid_entry->resp_buf,
|
||||
mid_entry->response_pdu_len, server);
|
||||
cifs_dump_mem("existing buf: ", mid_entry->resp_buf, 62);
|
||||
}
|
||||
}
|
||||
spin_unlock(&server->mid_queue_lock);
|
||||
|
|
@ -1318,11 +1318,11 @@ static const struct proc_ops cifs_mount_params_proc_ops = {
|
|||
};
|
||||
|
||||
#else
|
||||
inline void cifs_proc_init(void)
|
||||
void cifs_proc_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
inline void cifs_proc_clean(void)
|
||||
void cifs_proc_clean(void)
|
||||
{
|
||||
}
|
||||
#endif /* PROC_FS */
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@
|
|||
#define pr_fmt(fmt) "CIFS: " fmt
|
||||
|
||||
void cifs_dump_mem(char *label, void *data, int length);
|
||||
void cifs_dump_detail(void *buf, struct TCP_Server_Info *ptcp_info);
|
||||
void cifs_dump_mids(struct TCP_Server_Info *);
|
||||
void cifs_dump_detail(void *buf, size_t buf_len, struct TCP_Server_Info *server);
|
||||
void cifs_dump_mids(struct TCP_Server_Info *server);
|
||||
extern bool traceSMB; /* flag which enables the function below */
|
||||
void dump_smb(void *, int);
|
||||
void dump_smb(void *buf, int smb_buf_length);
|
||||
#define CIFS_INFO 0x01
|
||||
#define CIFS_RC 0x02
|
||||
#define CIFS_TIMER 0x04
|
||||
|
|
|
|||
|
|
@ -159,6 +159,7 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo,
|
|||
cifs_dbg(FYI, "key description = %s\n", description);
|
||||
scoped_with_creds(spnego_cred)
|
||||
spnego_key = request_key(&cifs_spnego_key_type, description, "");
|
||||
trace_smb3_kerberos_auth(server, sesInfo, PTR_ERR_OR_ZERO(spnego_key));
|
||||
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
if (cifsFYI && !IS_ERR(spnego_key)) {
|
||||
|
|
|
|||
|
|
@ -27,10 +27,8 @@ struct cifs_spnego_msg {
|
|||
uint8_t data[];
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
extern struct key_type cifs_spnego_key_type;
|
||||
extern struct key *cifs_get_spnego_key(struct cifs_ses *sesInfo,
|
||||
struct TCP_Server_Info *server);
|
||||
#endif /* KERNEL */
|
||||
|
||||
#endif /* _CIFS_SPNEGO_H */
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@
|
|||
#define SFM_MAP_UNI_RSVD 1
|
||||
#define SFU_MAP_UNI_RSVD 2
|
||||
|
||||
#ifdef __KERNEL__
|
||||
int cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
|
||||
const struct nls_table *cp, int map_type);
|
||||
int cifs_utf16_bytes(const __le16 *from, int maxbytes,
|
||||
|
|
@ -69,8 +68,6 @@ extern int cifs_remap(struct cifs_sb_info *cifs_sb);
|
|||
extern __le16 *cifs_strndup_to_utf16(const char *src, const int maxlen,
|
||||
int *utf16_len, const struct nls_table *cp,
|
||||
int remap);
|
||||
#endif
|
||||
|
||||
wchar_t cifs_toupper(wchar_t in);
|
||||
|
||||
#endif /* _CIFS_UNICODE_H */
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid)
|
|||
__func__, sidtype == SIDOWNER ? 'u' : 'g', cid);
|
||||
goto out_revert_creds;
|
||||
} else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
|
||||
rc = -EIO;
|
||||
rc = smb_EIO1(smb_eio_trace_malformed_sid_key, sidkey->datalen);
|
||||
cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
|
||||
__func__, sidkey->datalen);
|
||||
goto invalidate_key;
|
||||
|
|
@ -317,7 +317,8 @@ id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid)
|
|||
|
||||
ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
|
||||
if (ksid_size > sidkey->datalen) {
|
||||
rc = -EIO;
|
||||
rc = smb_EIO2(smb_eio_trace_malformed_ksid_key,
|
||||
ksid_size, sidkey->datalen);
|
||||
cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n",
|
||||
__func__, sidkey->datalen, ksid_size);
|
||||
goto invalidate_key;
|
||||
|
|
@ -352,7 +353,8 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct smb_sid *psid,
|
|||
if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
|
||||
cifs_dbg(FYI, "%s: %u subauthorities is too many!\n",
|
||||
__func__, psid->num_subauth);
|
||||
return -EIO;
|
||||
return smb_EIO2(smb_eio_trace_sid_too_many_auth,
|
||||
psid->num_subauth, SID_MAX_SUB_AUTHORITIES);
|
||||
}
|
||||
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) ||
|
||||
|
|
@ -1227,7 +1229,7 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
|
|||
__u32 dacloffset;
|
||||
|
||||
if (pntsd == NULL)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
owner_sid_ptr = (struct smb_sid *)((char *)pntsd +
|
||||
le32_to_cpu(pntsd->osidoffset));
|
||||
|
|
|
|||
|
|
@ -75,48 +75,35 @@ static int cifs_sig_iter(const struct iov_iter *iter, size_t maxsize,
|
|||
struct cifs_calc_sig_ctx *ctx)
|
||||
{
|
||||
struct iov_iter tmp_iter = *iter;
|
||||
int err = -EIO;
|
||||
size_t did;
|
||||
int err;
|
||||
|
||||
if (iterate_and_advance_kernel(&tmp_iter, maxsize, ctx, &err,
|
||||
cifs_sig_step) != maxsize)
|
||||
return err;
|
||||
did = iterate_and_advance_kernel(&tmp_iter, maxsize, ctx, &err,
|
||||
cifs_sig_step);
|
||||
if (did != maxsize)
|
||||
return smb_EIO2(smb_eio_trace_sig_iter, did, maxsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
|
||||
char *signature, struct cifs_calc_sig_ctx *ctx)
|
||||
{
|
||||
int i;
|
||||
struct iov_iter iter;
|
||||
ssize_t rc;
|
||||
struct kvec *iov = rqst->rq_iov;
|
||||
int n_vec = rqst->rq_nvec;
|
||||
size_t size = 0;
|
||||
|
||||
/* iov[0] is actual data and not the rfc1002 length for SMB2+ */
|
||||
if (!is_smb1(server)) {
|
||||
if (iov[0].iov_len <= 4)
|
||||
return -EIO;
|
||||
i = 0;
|
||||
} else {
|
||||
if (n_vec < 2 || iov[0].iov_len != 4)
|
||||
return -EIO;
|
||||
i = 1; /* skip rfc1002 length */
|
||||
}
|
||||
for (int i = 0; i < rqst->rq_nvec; i++)
|
||||
size += rqst->rq_iov[i].iov_len;
|
||||
|
||||
for (; i < n_vec; i++) {
|
||||
if (iov[i].iov_len == 0)
|
||||
continue;
|
||||
if (iov[i].iov_base == NULL) {
|
||||
cifs_dbg(VFS, "null iovec entry\n");
|
||||
return -EIO;
|
||||
}
|
||||
iov_iter_kvec(&iter, ITER_SOURCE, rqst->rq_iov, rqst->rq_nvec, size);
|
||||
|
||||
rc = cifs_sig_update(ctx, iov[i].iov_base, iov[i].iov_len);
|
||||
if (rc) {
|
||||
cifs_dbg(VFS, "%s: Could not update with payload\n",
|
||||
__func__);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
if (iov_iter_count(&iter) <= 4)
|
||||
return smb_EIO2(smb_eio_trace_sig_data_too_small,
|
||||
iov_iter_count(&iter), 4);
|
||||
|
||||
rc = cifs_sig_iter(&iter, iov_iter_count(&iter), ctx);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = cifs_sig_iter(&rqst->rq_iter, iov_iter_count(&rqst->rq_iter), ctx);
|
||||
if (rc < 0)
|
||||
|
|
@ -165,10 +152,6 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
|
|||
char smb_signature[20];
|
||||
struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
|
||||
|
||||
if (rqst->rq_iov[0].iov_len != 4 ||
|
||||
rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
|
||||
return -EIO;
|
||||
|
||||
if ((cifs_pdu == NULL) || (server == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -201,30 +184,6 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
|
|||
return rc;
|
||||
}
|
||||
|
||||
int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
|
||||
__u32 *pexpected_response_sequence)
|
||||
{
|
||||
struct smb_rqst rqst = { .rq_iov = iov,
|
||||
.rq_nvec = n_vec };
|
||||
|
||||
return cifs_sign_rqst(&rqst, server, pexpected_response_sequence);
|
||||
}
|
||||
|
||||
/* must be called with server->srv_mutex held */
|
||||
int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
|
||||
__u32 *pexpected_response_sequence_number)
|
||||
{
|
||||
struct kvec iov[2];
|
||||
|
||||
iov[0].iov_base = cifs_pdu;
|
||||
iov[0].iov_len = 4;
|
||||
iov[1].iov_base = (char *)cifs_pdu + 4;
|
||||
iov[1].iov_len = be32_to_cpu(cifs_pdu->smb_buf_length);
|
||||
|
||||
return cifs_sign_smbv(iov, 2, server,
|
||||
pexpected_response_sequence_number);
|
||||
}
|
||||
|
||||
int cifs_verify_signature(struct smb_rqst *rqst,
|
||||
struct TCP_Server_Info *server,
|
||||
__u32 expected_sequence_number)
|
||||
|
|
@ -234,10 +193,6 @@ int cifs_verify_signature(struct smb_rqst *rqst,
|
|||
char what_we_think_sig_should_be[20];
|
||||
struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
|
||||
|
||||
if (rqst->rq_iov[0].iov_len != 4 ||
|
||||
rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
|
||||
return -EIO;
|
||||
|
||||
if (cifs_pdu == NULL || server == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
#include <linux/splice.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/key-type.h>
|
||||
#include <uapi/linux/magic.h>
|
||||
#include <net/ipv6.h>
|
||||
#include "cifsfs.h"
|
||||
|
|
@ -35,10 +37,9 @@
|
|||
#define DECLARE_GLOBALS_HERE
|
||||
#include "cifsglob.h"
|
||||
#include "cifsproto.h"
|
||||
#include "smb2proto.h"
|
||||
#include "cifs_debug.h"
|
||||
#include "cifs_fs_sb.h"
|
||||
#include <linux/mm.h>
|
||||
#include <linux/key-type.h>
|
||||
#include "cifs_spnego.h"
|
||||
#include "fscache.h"
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
|
|
@ -442,7 +443,7 @@ static struct kmem_cache *cifs_io_request_cachep;
|
|||
static struct kmem_cache *cifs_io_subrequest_cachep;
|
||||
mempool_t *cifs_sm_req_poolp;
|
||||
mempool_t *cifs_req_poolp;
|
||||
mempool_t *cifs_mid_poolp;
|
||||
mempool_t cifs_mid_pool;
|
||||
mempool_t cifs_io_request_pool;
|
||||
mempool_t cifs_io_subrequest_pool;
|
||||
|
||||
|
|
@ -1016,7 +1017,6 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
|
|||
} else {
|
||||
cifs_info("Attempting to mount %s\n", old_ctx->source);
|
||||
}
|
||||
|
||||
cifs_sb = kzalloc(sizeof(*cifs_sb), GFP_KERNEL);
|
||||
if (!cifs_sb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
|
@ -1847,8 +1847,7 @@ static int init_mids(void)
|
|||
return -ENOMEM;
|
||||
|
||||
/* 3 is a reasonable minimum number of simultaneous operations */
|
||||
cifs_mid_poolp = mempool_create_slab_pool(3, cifs_mid_cachep);
|
||||
if (cifs_mid_poolp == NULL) {
|
||||
if (mempool_init_slab_pool(&cifs_mid_pool, 3, cifs_mid_cachep) < 0) {
|
||||
kmem_cache_destroy(cifs_mid_cachep);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
@ -1858,7 +1857,7 @@ static int init_mids(void)
|
|||
|
||||
static void destroy_mids(void)
|
||||
{
|
||||
mempool_destroy(cifs_mid_poolp);
|
||||
mempool_exit(&cifs_mid_pool);
|
||||
kmem_cache_destroy(cifs_mid_cachep);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -311,8 +311,9 @@ struct cifs_open_parms;
|
|||
struct cifs_credits;
|
||||
|
||||
struct smb_version_operations {
|
||||
int (*send_cancel)(struct TCP_Server_Info *, struct smb_rqst *,
|
||||
struct mid_q_entry *);
|
||||
int (*send_cancel)(struct cifs_ses *ses, struct TCP_Server_Info *server,
|
||||
struct smb_rqst *rqst, struct mid_q_entry *mid,
|
||||
unsigned int xid);
|
||||
bool (*compare_fids)(struct cifsFileInfo *, struct cifsFileInfo *);
|
||||
/* setup request: allocate mid, sign message */
|
||||
struct mid_q_entry *(*setup_request)(struct cifs_ses *,
|
||||
|
|
@ -346,13 +347,14 @@ struct smb_version_operations {
|
|||
/* map smb to linux error */
|
||||
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 *buf, struct TCP_Server_Info *ptcp_info);
|
||||
struct mid_q_entry *(*find_mid)(struct TCP_Server_Info *server, char *buf);
|
||||
void (*dump_detail)(void *buf, size_t buf_len, 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 *);
|
||||
/* verify the message */
|
||||
int (*check_message)(char *, unsigned int, struct TCP_Server_Info *);
|
||||
int (*check_message)(char *buf, unsigned int pdu_len, unsigned int len,
|
||||
struct TCP_Server_Info *server);
|
||||
bool (*is_oplock_break)(char *, struct TCP_Server_Info *);
|
||||
int (*handle_cancelled_mid)(struct mid_q_entry *, struct TCP_Server_Info *);
|
||||
void (*downgrade_oplock)(struct TCP_Server_Info *server,
|
||||
|
|
@ -636,8 +638,7 @@ struct smb_version_operations {
|
|||
|
||||
#define HEADER_SIZE(server) (server->vals->header_size)
|
||||
#define MAX_HEADER_SIZE(server) (server->vals->max_header_size)
|
||||
#define HEADER_PREAMBLE_SIZE(server) (server->vals->header_preamble_size)
|
||||
#define MID_HEADER_SIZE(server) (HEADER_SIZE(server) - 1 - HEADER_PREAMBLE_SIZE(server))
|
||||
#define MID_HEADER_SIZE(server) (HEADER_SIZE(server) - 1)
|
||||
|
||||
/**
|
||||
* CIFS superblock mount flags (mnt_cifs_flags) to consider when
|
||||
|
|
@ -744,6 +745,7 @@ struct TCP_Server_Info {
|
|||
struct session_key session_key;
|
||||
unsigned long lstrp; /* when we got last response from this server */
|
||||
unsigned long neg_start; /* when negotiate started (jiffies) */
|
||||
unsigned long reconn_delay; /* when resched session and tcon reconnect */
|
||||
struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */
|
||||
#define CIFS_NEGFLAVOR_UNENCAP 1 /* wct == 17, but no ext_sec */
|
||||
#define CIFS_NEGFLAVOR_EXTENDED 2 /* wct == 17, ext_sec bit set */
|
||||
|
|
@ -832,9 +834,9 @@ struct TCP_Server_Info {
|
|||
char dns_dom[CIFS_MAX_DOMAINNAME_LEN + 1];
|
||||
};
|
||||
|
||||
static inline bool is_smb1(struct TCP_Server_Info *server)
|
||||
static inline bool is_smb1(const struct TCP_Server_Info *server)
|
||||
{
|
||||
return HEADER_PREAMBLE_SIZE(server) != 0;
|
||||
return server->vals->protocol_id == SMB10_PROT_ID;
|
||||
}
|
||||
|
||||
static inline void cifs_server_lock(struct TCP_Server_Info *server)
|
||||
|
|
@ -973,16 +975,16 @@ compare_mid(__u16 mid, const struct smb_hdr *smb)
|
|||
* of kvecs to handle the receive, though that should only need to be done
|
||||
* once.
|
||||
*/
|
||||
#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4)
|
||||
#define CIFS_MAX_RSIZE ((1<<24) - sizeof(READ_RSP) + 4)
|
||||
#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ))
|
||||
#define CIFS_MAX_RSIZE ((1<<24) - sizeof(READ_RSP))
|
||||
|
||||
/*
|
||||
* When the server doesn't allow large posix writes, only allow a rsize/wsize
|
||||
* of 2^17-1 minus the size of the call header. That allows for a read or
|
||||
* write up to the maximum size described by RFC1002.
|
||||
*/
|
||||
#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4)
|
||||
#define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP) + 4)
|
||||
#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ))
|
||||
#define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP))
|
||||
|
||||
/*
|
||||
* Windows only supports a max of 60kb reads and 65535 byte writes. Default to
|
||||
|
|
@ -1659,7 +1661,7 @@ static inline void cifs_stats_bytes_read(struct cifs_tcon *tcon,
|
|||
* Returns zero on a successful receive, or an error. The receive state in
|
||||
* the TCP_Server_Info will also be updated.
|
||||
*/
|
||||
typedef int (mid_receive_t)(struct TCP_Server_Info *server,
|
||||
typedef int (*mid_receive_t)(struct TCP_Server_Info *server,
|
||||
struct mid_q_entry *mid);
|
||||
|
||||
/*
|
||||
|
|
@ -1670,37 +1672,38 @@ typedef int (mid_receive_t)(struct TCP_Server_Info *server,
|
|||
* - it will be called by cifsd, with no locks held
|
||||
* - the mid will be removed from any lists
|
||||
*/
|
||||
typedef void (mid_callback_t)(struct mid_q_entry *mid);
|
||||
typedef void (*mid_callback_t)(struct TCP_Server_Info *srv, struct mid_q_entry *mid);
|
||||
|
||||
/*
|
||||
* This is the protopyte for mid handle function. This is called once the mid
|
||||
* has been recognized after decryption of the message.
|
||||
*/
|
||||
typedef int (mid_handle_t)(struct TCP_Server_Info *server,
|
||||
typedef int (*mid_handle_t)(struct TCP_Server_Info *server,
|
||||
struct mid_q_entry *mid);
|
||||
|
||||
/* one of these for every pending CIFS request to the server */
|
||||
struct mid_q_entry {
|
||||
struct list_head qhead; /* mids waiting on reply from this server */
|
||||
struct kref refcount;
|
||||
struct TCP_Server_Info *server; /* server corresponding to this mid */
|
||||
refcount_t refcount;
|
||||
__u64 mid; /* multiplex id */
|
||||
__u16 credits; /* number of credits consumed by this mid */
|
||||
__u16 credits_received; /* number of credits from the response */
|
||||
__u32 pid; /* process id */
|
||||
__u32 sequence_number; /* for CIFS signing */
|
||||
unsigned int sr_flags; /* Flags passed to send_recv() */
|
||||
unsigned long when_alloc; /* when mid was created */
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
unsigned long when_sent; /* time when smb send finished */
|
||||
unsigned long when_received; /* when demux complete (taken off wire) */
|
||||
#endif
|
||||
mid_receive_t *receive; /* call receive callback */
|
||||
mid_callback_t *callback; /* call completion callback */
|
||||
mid_handle_t *handle; /* call handle mid callback */
|
||||
mid_receive_t receive; /* call receive callback */
|
||||
mid_callback_t callback; /* call completion callback */
|
||||
mid_handle_t handle; /* call handle mid callback */
|
||||
void *callback_data; /* general purpose pointer for callback */
|
||||
struct task_struct *creator;
|
||||
void *resp_buf; /* pointer to received SMB header */
|
||||
unsigned int resp_buf_size;
|
||||
u32 response_pdu_len;
|
||||
int mid_state; /* wish this were enum but can not pass to wait_event */
|
||||
int mid_rc; /* rc for MID_RC */
|
||||
__le16 command; /* smb command code */
|
||||
|
|
@ -1899,6 +1902,8 @@ enum cifs_writable_file_flags {
|
|||
#define CIFS_TRANSFORM_REQ 0x0800 /* transform request before sending */
|
||||
#define CIFS_NO_SRV_RSP 0x1000 /* there is no server response */
|
||||
#define CIFS_COMPRESS_REQ 0x4000 /* compress request before sending */
|
||||
#define CIFS_INTERRUPTIBLE_WAIT 0x8000 /* Interruptible wait (e.g. lock request) */
|
||||
#define CIFS_WINDOWS_LOCK 0x10000 /* We're trying to get a Windows lock */
|
||||
|
||||
/* Security Flags: indicate type of session setup needed */
|
||||
#define CIFSSEC_MAY_SIGN 0x00001
|
||||
|
|
@ -2104,7 +2109,7 @@ extern __u32 cifs_lock_secret;
|
|||
|
||||
extern mempool_t *cifs_sm_req_poolp;
|
||||
extern mempool_t *cifs_req_poolp;
|
||||
extern mempool_t *cifs_mid_poolp;
|
||||
extern mempool_t cifs_mid_pool;
|
||||
extern mempool_t cifs_io_request_pool;
|
||||
extern mempool_t cifs_io_subrequest_pool;
|
||||
|
||||
|
|
@ -2114,7 +2119,7 @@ extern struct smb_version_operations smb1_operations;
|
|||
extern struct smb_version_values smb1_values;
|
||||
extern struct smb_version_operations smb20_operations;
|
||||
extern struct smb_version_values smb20_values;
|
||||
#endif /* CIFS_ALLOW_INSECURE_LEGACY */
|
||||
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
|
||||
extern struct smb_version_operations smb21_operations;
|
||||
extern struct smb_version_values smb21_values;
|
||||
extern struct smb_version_values smbdefault_values;
|
||||
|
|
@ -2202,94 +2207,6 @@ static inline void move_cifs_info_to_smb2(struct smb2_file_all_info *dst, const
|
|||
dst->FileNameLength = src->FileNameLength;
|
||||
}
|
||||
|
||||
static inline int cifs_get_num_sgs(const struct smb_rqst *rqst,
|
||||
int num_rqst,
|
||||
const u8 *sig)
|
||||
{
|
||||
unsigned int len, skip;
|
||||
unsigned int nents = 0;
|
||||
unsigned long addr;
|
||||
size_t data_size;
|
||||
int i, j;
|
||||
|
||||
/*
|
||||
* The first rqst has a transform header where the first 20 bytes are
|
||||
* not part of the encrypted blob.
|
||||
*/
|
||||
skip = 20;
|
||||
|
||||
/* Assumes the first rqst has a transform header as the first iov.
|
||||
* I.e.
|
||||
* rqst[0].rq_iov[0] is transform header
|
||||
* rqst[0].rq_iov[1+] data to be encrypted/decrypted
|
||||
* rqst[1+].rq_iov[0+] data to be encrypted/decrypted
|
||||
*/
|
||||
for (i = 0; i < num_rqst; i++) {
|
||||
data_size = iov_iter_count(&rqst[i].rq_iter);
|
||||
|
||||
/* We really don't want a mixture of pinned and unpinned pages
|
||||
* in the sglist. It's hard to keep track of which is what.
|
||||
* Instead, we convert to a BVEC-type iterator higher up.
|
||||
*/
|
||||
if (data_size &&
|
||||
WARN_ON_ONCE(user_backed_iter(&rqst[i].rq_iter)))
|
||||
return -EIO;
|
||||
|
||||
/* We also don't want to have any extra refs or pins to clean
|
||||
* up in the sglist.
|
||||
*/
|
||||
if (data_size &&
|
||||
WARN_ON_ONCE(iov_iter_extract_will_pin(&rqst[i].rq_iter)))
|
||||
return -EIO;
|
||||
|
||||
for (j = 0; j < rqst[i].rq_nvec; j++) {
|
||||
struct kvec *iov = &rqst[i].rq_iov[j];
|
||||
|
||||
addr = (unsigned long)iov->iov_base + skip;
|
||||
if (is_vmalloc_or_module_addr((void *)addr)) {
|
||||
len = iov->iov_len - skip;
|
||||
nents += DIV_ROUND_UP(offset_in_page(addr) + len,
|
||||
PAGE_SIZE);
|
||||
} else {
|
||||
nents++;
|
||||
}
|
||||
skip = 0;
|
||||
}
|
||||
if (data_size)
|
||||
nents += iov_iter_npages(&rqst[i].rq_iter, INT_MAX);
|
||||
}
|
||||
nents += DIV_ROUND_UP(offset_in_page(sig) + SMB2_SIGNATURE_SIZE, PAGE_SIZE);
|
||||
return nents;
|
||||
}
|
||||
|
||||
/* We can not use the normal sg_set_buf() as we will sometimes pass a
|
||||
* stack object as buf.
|
||||
*/
|
||||
static inline void cifs_sg_set_buf(struct sg_table *sgtable,
|
||||
const void *buf,
|
||||
unsigned int buflen)
|
||||
{
|
||||
unsigned long addr = (unsigned long)buf;
|
||||
unsigned int off = offset_in_page(addr);
|
||||
|
||||
addr &= PAGE_MASK;
|
||||
if (is_vmalloc_or_module_addr((void *)addr)) {
|
||||
do {
|
||||
unsigned int len = min_t(unsigned int, buflen, PAGE_SIZE - off);
|
||||
|
||||
sg_set_page(&sgtable->sgl[sgtable->nents++],
|
||||
vmalloc_to_page((void *)addr), len, off);
|
||||
|
||||
off = 0;
|
||||
addr += PAGE_SIZE;
|
||||
buflen -= len;
|
||||
} while (buflen);
|
||||
} else {
|
||||
sg_set_page(&sgtable->sgl[sgtable->nents++],
|
||||
virt_to_page((void *)addr), buflen, off);
|
||||
}
|
||||
}
|
||||
|
||||
#define CIFS_OPARMS(_cifs_sb, _tcon, _path, _da, _cd, _co, _mode) \
|
||||
((struct cifs_open_parms) { \
|
||||
.tcon = _tcon, \
|
||||
|
|
@ -2351,9 +2268,10 @@ static inline bool cifs_netbios_name(const char *name, size_t namelen)
|
|||
* Execute mid callback atomically - ensures callback runs exactly once
|
||||
* and prevents sleeping in atomic context.
|
||||
*/
|
||||
static inline void mid_execute_callback(struct mid_q_entry *mid)
|
||||
static inline void mid_execute_callback(struct TCP_Server_Info *server,
|
||||
struct mid_q_entry *mid)
|
||||
{
|
||||
void (*callback)(struct mid_q_entry *mid);
|
||||
mid_callback_t callback;
|
||||
|
||||
spin_lock(&mid->mid_lock);
|
||||
callback = mid->callback;
|
||||
|
|
@ -2361,7 +2279,7 @@ static inline void mid_execute_callback(struct mid_q_entry *mid)
|
|||
spin_unlock(&mid->mid_lock);
|
||||
|
||||
if (callback)
|
||||
callback(mid);
|
||||
callback(server, mid);
|
||||
}
|
||||
|
||||
#define CIFS_REPARSE_SUPPORT(tcon) \
|
||||
|
|
@ -2369,4 +2287,30 @@ static inline void mid_execute_callback(struct mid_q_entry *mid)
|
|||
(le32_to_cpu((tcon)->fsAttrInfo.Attributes) & \
|
||||
FILE_SUPPORTS_REPARSE_POINTS))
|
||||
|
||||
struct cifs_calc_sig_ctx {
|
||||
struct md5_ctx *md5;
|
||||
struct hmac_sha256_ctx *hmac;
|
||||
struct shash_desc *shash;
|
||||
};
|
||||
|
||||
#define CIFS_RECONN_DELAY_SECS 30
|
||||
#define CIFS_MAX_RECONN_DELAY (4 * CIFS_RECONN_DELAY_SECS)
|
||||
|
||||
static inline void cifs_queue_server_reconn(struct TCP_Server_Info *server)
|
||||
{
|
||||
if (!delayed_work_pending(&server->reconnect)) {
|
||||
WRITE_ONCE(server->reconn_delay, 0);
|
||||
mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cifs_requeue_server_reconn(struct TCP_Server_Info *server)
|
||||
{
|
||||
unsigned long delay = READ_ONCE(server->reconn_delay);
|
||||
|
||||
delay = umin(delay + CIFS_RECONN_DELAY_SECS, CIFS_MAX_RECONN_DELAY);
|
||||
WRITE_ONCE(server->reconn_delay, delay);
|
||||
queue_delayed_work(cifsiod_wq, &server->reconnect, delay * HZ);
|
||||
}
|
||||
|
||||
#endif /* _CIFS_GLOB_H */
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@
|
|||
|
||||
/* future chained NTCreateXReadX bigger, but for time being NTCreateX biggest */
|
||||
/* among the requests (NTCreateX response is bigger with wct of 34) */
|
||||
#define MAX_CIFS_HDR_SIZE 0x58 /* 4 len + 32 hdr + (2*24 wct) + 2 bct + 2 pad */
|
||||
#define MAX_CIFS_HDR_SIZE 0x54 /* 32 hdr + (2*24 wct) + 2 bct + 2 pad */
|
||||
#define CIFS_SMALL_PATH 120 /* allows for (448-88)/3 */
|
||||
|
||||
/* internal cifs vfs structures */
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@ extern void cifs_buf_release(void *);
|
|||
extern struct smb_hdr *cifs_small_buf_get(void);
|
||||
extern void cifs_small_buf_release(void *);
|
||||
extern void free_rsp_buf(int, void *);
|
||||
extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *,
|
||||
unsigned int /* length */);
|
||||
extern int smb_send_kvec(struct TCP_Server_Info *server,
|
||||
struct msghdr *msg,
|
||||
size_t *sent);
|
||||
|
|
@ -82,11 +80,10 @@ extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
|
|||
struct cifs_sb_info *cifs_sb,
|
||||
struct cifs_tcon *tcon,
|
||||
int add_treename);
|
||||
extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
|
||||
char *cifs_build_devname(char *nodename, const char *prepath);
|
||||
extern void delete_mid(struct mid_q_entry *mid);
|
||||
void __release_mid(struct kref *refcount);
|
||||
extern void cifs_wake_up_task(struct mid_q_entry *mid);
|
||||
void delete_mid(struct TCP_Server_Info *server, struct mid_q_entry *mid);
|
||||
void __release_mid(struct TCP_Server_Info *server, struct mid_q_entry *mid);
|
||||
void cifs_wake_up_task(struct TCP_Server_Info *server, struct mid_q_entry *mid);
|
||||
extern int cifs_handle_standard(struct TCP_Server_Info *server,
|
||||
struct mid_q_entry *mid);
|
||||
extern char *smb3_fs_context_fullpath(const struct smb3_fs_context *ctx,
|
||||
|
|
@ -97,10 +94,10 @@ extern int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs);
|
|||
extern bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs);
|
||||
extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
|
||||
extern int cifs_call_async(struct TCP_Server_Info *server,
|
||||
struct smb_rqst *rqst,
|
||||
mid_receive_t *receive, mid_callback_t *callback,
|
||||
mid_handle_t *handle, void *cbdata, const int flags,
|
||||
const struct cifs_credits *exist_credits);
|
||||
struct smb_rqst *rqst,
|
||||
mid_receive_t receive, mid_callback_t callback,
|
||||
mid_handle_t handle, void *cbdata, const int flags,
|
||||
const struct cifs_credits *exist_credits);
|
||||
extern struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses);
|
||||
extern int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
struct TCP_Server_Info *server,
|
||||
|
|
@ -111,18 +108,16 @@ extern int compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
|||
const int flags, const int num_rqst,
|
||||
struct smb_rqst *rqst, int *resp_buf_type,
|
||||
struct kvec *resp_iov);
|
||||
extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
|
||||
struct smb_hdr * /* input */ ,
|
||||
struct smb_hdr * /* out */ ,
|
||||
int * /* bytes returned */ , const int);
|
||||
extern int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
|
||||
char *in_buf, int flags);
|
||||
int SendReceive(const unsigned int xid, struct cifs_ses *ses,
|
||||
struct smb_hdr *in_buf, unsigned int in_len,
|
||||
struct smb_hdr *out_buf, int *pbytes_returned, const int flags);
|
||||
int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
|
||||
char *in_buf, unsigned int in_len, int flags);
|
||||
int cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server);
|
||||
extern struct mid_q_entry *cifs_setup_request(struct cifs_ses *,
|
||||
struct TCP_Server_Info *,
|
||||
struct smb_rqst *);
|
||||
extern struct mid_q_entry *cifs_setup_async_request(struct TCP_Server_Info *,
|
||||
struct smb_rqst *);
|
||||
struct mid_q_entry *cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *ignored,
|
||||
struct smb_rqst *rqst);
|
||||
struct mid_q_entry *cifs_setup_async_request(struct TCP_Server_Info *server,
|
||||
struct smb_rqst *rqst);
|
||||
int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
||||
struct smb_rqst *rqst);
|
||||
extern int cifs_check_receive(struct mid_q_entry *mid,
|
||||
|
|
@ -134,11 +129,12 @@ extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server,
|
|||
struct cifs_credits *credits);
|
||||
|
||||
static inline int
|
||||
send_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
|
||||
struct mid_q_entry *mid)
|
||||
send_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
|
||||
struct smb_rqst *rqst, struct mid_q_entry *mid,
|
||||
unsigned int xid)
|
||||
{
|
||||
return server->ops->send_cancel ?
|
||||
server->ops->send_cancel(server, rqst, mid) : 0;
|
||||
server->ops->send_cancel(ses, server, rqst, mid, xid) : 0;
|
||||
}
|
||||
|
||||
int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ);
|
||||
|
|
@ -146,11 +142,6 @@ extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
|
|||
struct kvec *, int /* nvec to send */,
|
||||
int * /* type of buf returned */, const int flags,
|
||||
struct kvec * /* resp vec */);
|
||||
extern int SendReceiveBlockingLock(const unsigned int xid,
|
||||
struct cifs_tcon *ptcon,
|
||||
struct smb_hdr *in_buf,
|
||||
struct smb_hdr *out_buf,
|
||||
int *bytes_returned);
|
||||
|
||||
void smb2_query_server_interfaces(struct work_struct *work);
|
||||
void
|
||||
|
|
@ -161,13 +152,12 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
|
|||
bool mark_smb_session);
|
||||
extern int cifs_reconnect(struct TCP_Server_Info *server,
|
||||
bool mark_smb_session);
|
||||
extern int checkSMB(char *buf, unsigned int len, struct TCP_Server_Info *srvr);
|
||||
int checkSMB(char *buf, unsigned int pdu_len, unsigned int len,
|
||||
struct TCP_Server_Info *srvr);
|
||||
extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *);
|
||||
extern bool backup_cred(struct cifs_sb_info *);
|
||||
extern bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 eof,
|
||||
bool from_readdir);
|
||||
extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
|
||||
unsigned int bytes_written);
|
||||
void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t result);
|
||||
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, int);
|
||||
extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
|
||||
|
|
@ -187,15 +177,14 @@ extern int decode_negTokenInit(unsigned char *security_blob, int length,
|
|||
extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
|
||||
extern void cifs_set_port(struct sockaddr *addr, const unsigned short int port);
|
||||
extern int map_smb_to_linux_error(char *buf, bool logErr);
|
||||
extern int map_and_check_smb_error(struct mid_q_entry *mid, bool logErr);
|
||||
extern void header_assemble(struct smb_hdr *, char /* command */ ,
|
||||
const struct cifs_tcon *, int /* length of
|
||||
fixed section (word count) in two byte units */);
|
||||
extern int map_and_check_smb_error(struct TCP_Server_Info *server,
|
||||
struct mid_q_entry *mid, bool logErr);
|
||||
unsigned int header_assemble(struct smb_hdr *buffer, char smb_command,
|
||||
const struct cifs_tcon *treeCon, int word_count
|
||||
/* length of fixed section word count in two byte units */);
|
||||
extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
|
||||
struct cifs_ses *ses,
|
||||
void **request_buf);
|
||||
extern enum securityEnum select_sectype(struct TCP_Server_Info *server,
|
||||
enum securityEnum requested);
|
||||
extern int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
|
||||
struct TCP_Server_Info *server,
|
||||
const struct nls_table *nls_cp);
|
||||
|
|
@ -270,7 +259,7 @@ extern unsigned int setup_special_mode_ACE(struct smb_ace *pace,
|
|||
__u64 nmode);
|
||||
extern unsigned int setup_special_user_owner_ACE(struct smb_ace *pace);
|
||||
|
||||
extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
|
||||
void dequeue_mid(struct TCP_Server_Info *server, struct mid_q_entry *mid, bool malformed);
|
||||
extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
|
||||
unsigned int to_read);
|
||||
extern ssize_t cifs_discard_from_socket(struct TCP_Server_Info *server,
|
||||
|
|
@ -565,12 +554,9 @@ extern void tconInfoFree(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace)
|
|||
|
||||
extern int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
|
||||
__u32 *pexpected_response_sequence_number);
|
||||
extern int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
|
||||
__u32 *);
|
||||
extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *);
|
||||
extern int cifs_verify_signature(struct smb_rqst *rqst,
|
||||
struct TCP_Server_Info *server,
|
||||
__u32 expected_sequence_number);
|
||||
int cifs_verify_signature(struct smb_rqst *rqst,
|
||||
struct TCP_Server_Info *server,
|
||||
__u32 expected_sequence_number);
|
||||
extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
|
||||
extern void cifs_crypto_secmech_release(struct TCP_Server_Info *server);
|
||||
extern int calc_seckey(struct cifs_ses *);
|
||||
|
|
@ -603,7 +589,7 @@ extern int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
const struct nls_table *nls_codepage, int remap);
|
||||
extern int CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
|
||||
#endif /* CIFS_ALLOW_INSECURE_LEGACY */
|
||||
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
|
||||
extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb);
|
||||
extern bool couldbe_mf_symlink(const struct cifs_fattr *fattr);
|
||||
extern int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
|
@ -635,11 +621,6 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
|
|||
struct cifs_sb_info *cifs_sb,
|
||||
const unsigned char *path, char *pbuf,
|
||||
unsigned int *pbytes_written);
|
||||
struct cifs_calc_sig_ctx {
|
||||
struct md5_ctx *md5;
|
||||
struct hmac_sha256_ctx *hmac;
|
||||
struct shash_desc *shash;
|
||||
};
|
||||
int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
|
||||
char *signature, struct cifs_calc_sig_ctx *ctx);
|
||||
enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
|
||||
|
|
@ -649,8 +630,9 @@ int cifs_alloc_hash(const char *name, struct shash_desc **sdesc);
|
|||
void cifs_free_hash(struct shash_desc **sdesc);
|
||||
|
||||
int cifs_try_adding_channels(struct cifs_ses *ses);
|
||||
int smb3_update_ses_channels(struct cifs_ses *ses, struct TCP_Server_Info *server,
|
||||
bool from_reconnect, bool disable_mchan);
|
||||
bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface);
|
||||
void cifs_ses_mark_for_reconnect(struct cifs_ses *ses);
|
||||
|
||||
int
|
||||
cifs_ses_get_chan_index(struct cifs_ses *ses,
|
||||
|
|
@ -674,7 +656,7 @@ bool
|
|||
cifs_chan_is_iface_active(struct cifs_ses *ses,
|
||||
struct TCP_Server_Info *server);
|
||||
void
|
||||
cifs_disable_secondary_channels(struct cifs_ses *ses);
|
||||
cifs_decrease_secondary_channels(struct cifs_ses *ses, bool disable_mchan);
|
||||
void
|
||||
cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server);
|
||||
int
|
||||
|
|
@ -777,9 +759,15 @@ static inline bool dfs_src_pathname_equal(const char *s1, const char *s2)
|
|||
return true;
|
||||
}
|
||||
|
||||
static inline void release_mid(struct mid_q_entry *mid)
|
||||
static inline void smb_get_mid(struct mid_q_entry *mid)
|
||||
{
|
||||
kref_put(&mid->refcount, __release_mid);
|
||||
refcount_inc(&mid->refcount);
|
||||
}
|
||||
|
||||
static inline void release_mid(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
{
|
||||
if (refcount_dec_and_test(&mid->refcount))
|
||||
__release_mid(server, mid);
|
||||
}
|
||||
|
||||
static inline void cifs_free_open_info(struct cifs_open_info_data *data)
|
||||
|
|
@ -789,4 +777,110 @@ static inline void cifs_free_open_info(struct cifs_open_info_data *data)
|
|||
memset(data, 0, sizeof(*data));
|
||||
}
|
||||
|
||||
static inline int smb_EIO(enum smb_eio_trace trace)
|
||||
{
|
||||
trace_smb3_eio(trace, 0, 0);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static inline int smb_EIO1(enum smb_eio_trace trace, unsigned long info)
|
||||
{
|
||||
trace_smb3_eio(trace, info, 0);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static inline int smb_EIO2(enum smb_eio_trace trace, unsigned long info, unsigned long info2)
|
||||
{
|
||||
trace_smb3_eio(trace, info, info2);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static inline int cifs_get_num_sgs(const struct smb_rqst *rqst,
|
||||
int num_rqst,
|
||||
const u8 *sig)
|
||||
{
|
||||
unsigned int len, skip;
|
||||
unsigned int nents = 0;
|
||||
unsigned long addr;
|
||||
size_t data_size;
|
||||
int i, j;
|
||||
|
||||
/*
|
||||
* The first rqst has a transform header where the first 20 bytes are
|
||||
* not part of the encrypted blob.
|
||||
*/
|
||||
skip = 20;
|
||||
|
||||
/* Assumes the first rqst has a transform header as the first iov.
|
||||
* I.e.
|
||||
* rqst[0].rq_iov[0] is transform header
|
||||
* rqst[0].rq_iov[1+] data to be encrypted/decrypted
|
||||
* rqst[1+].rq_iov[0+] data to be encrypted/decrypted
|
||||
*/
|
||||
for (i = 0; i < num_rqst; i++) {
|
||||
data_size = iov_iter_count(&rqst[i].rq_iter);
|
||||
|
||||
/* We really don't want a mixture of pinned and unpinned pages
|
||||
* in the sglist. It's hard to keep track of which is what.
|
||||
* Instead, we convert to a BVEC-type iterator higher up.
|
||||
*/
|
||||
if (data_size &&
|
||||
WARN_ON_ONCE(user_backed_iter(&rqst[i].rq_iter)))
|
||||
return smb_EIO(smb_eio_trace_user_iter);
|
||||
|
||||
/* We also don't want to have any extra refs or pins to clean
|
||||
* up in the sglist.
|
||||
*/
|
||||
if (data_size &&
|
||||
WARN_ON_ONCE(iov_iter_extract_will_pin(&rqst[i].rq_iter)))
|
||||
return smb_EIO(smb_eio_trace_extract_will_pin);
|
||||
|
||||
for (j = 0; j < rqst[i].rq_nvec; j++) {
|
||||
struct kvec *iov = &rqst[i].rq_iov[j];
|
||||
|
||||
addr = (unsigned long)iov->iov_base + skip;
|
||||
if (is_vmalloc_or_module_addr((void *)addr)) {
|
||||
len = iov->iov_len - skip;
|
||||
nents += DIV_ROUND_UP(offset_in_page(addr) + len,
|
||||
PAGE_SIZE);
|
||||
} else {
|
||||
nents++;
|
||||
}
|
||||
skip = 0;
|
||||
}
|
||||
if (data_size)
|
||||
nents += iov_iter_npages(&rqst[i].rq_iter, INT_MAX);
|
||||
}
|
||||
nents += DIV_ROUND_UP(offset_in_page(sig) + SMB2_SIGNATURE_SIZE, PAGE_SIZE);
|
||||
return nents;
|
||||
}
|
||||
|
||||
/* We can not use the normal sg_set_buf() as we will sometimes pass a
|
||||
* stack object as buf.
|
||||
*/
|
||||
static inline void cifs_sg_set_buf(struct sg_table *sgtable,
|
||||
const void *buf,
|
||||
unsigned int buflen)
|
||||
{
|
||||
unsigned long addr = (unsigned long)buf;
|
||||
unsigned int off = offset_in_page(addr);
|
||||
|
||||
addr &= PAGE_MASK;
|
||||
if (is_vmalloc_or_module_addr((void *)addr)) {
|
||||
do {
|
||||
unsigned int len = min_t(unsigned int, buflen, PAGE_SIZE - off);
|
||||
|
||||
sg_set_page(&sgtable->sgl[sgtable->nents++],
|
||||
vmalloc_to_page((void *)addr), len, off);
|
||||
|
||||
off = 0;
|
||||
addr += PAGE_SIZE;
|
||||
buflen -= len;
|
||||
} while (buflen);
|
||||
} else {
|
||||
sg_set_page(&sgtable->sgl[sgtable->nents++],
|
||||
virt_to_page((void *)addr), buflen, off);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _CIFSPROTO_H */
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -43,9 +43,9 @@ alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
|
||||
temp = mempool_alloc(&cifs_mid_pool, GFP_NOFS);
|
||||
memset(temp, 0, sizeof(struct mid_q_entry));
|
||||
kref_init(&temp->refcount);
|
||||
refcount_set(&temp->refcount, 1);
|
||||
spin_lock_init(&temp->mid_lock);
|
||||
temp->mid = get_mid(smb_buffer);
|
||||
temp->pid = current->pid;
|
||||
|
|
@ -54,7 +54,6 @@ alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
|
|||
/* easier to use jiffies */
|
||||
/* when mid allocated can be before when sent */
|
||||
temp->when_alloc = jiffies;
|
||||
temp->server = server;
|
||||
|
||||
/*
|
||||
* The default is for the mid to be synchronous, so the
|
||||
|
|
@ -70,22 +69,6 @@ alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
|
|||
return temp;
|
||||
}
|
||||
|
||||
int
|
||||
smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
|
||||
unsigned int smb_buf_length)
|
||||
{
|
||||
struct kvec iov[2];
|
||||
struct smb_rqst rqst = { .rq_iov = iov,
|
||||
.rq_nvec = 2 };
|
||||
|
||||
iov[0].iov_base = smb_buffer;
|
||||
iov[0].iov_len = 4;
|
||||
iov[1].iov_base = (char *)smb_buffer + 4;
|
||||
iov[1].iov_len = smb_buf_length;
|
||||
|
||||
return __smb_send_rqst(server, 1, &rqst);
|
||||
}
|
||||
|
||||
static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
|
||||
struct mid_q_entry **ppmidQ)
|
||||
{
|
||||
|
|
@ -125,10 +108,6 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
|
|||
struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
|
||||
struct mid_q_entry *mid;
|
||||
|
||||
if (rqst->rq_iov[0].iov_len != 4 ||
|
||||
rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
|
||||
return ERR_PTR(-EIO);
|
||||
|
||||
/* enable signing if server requires it */
|
||||
if (server->sign)
|
||||
hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
|
||||
|
|
@ -139,7 +118,7 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
|
|||
|
||||
rc = cifs_sign_rqst(rqst, server, &mid->sequence_number);
|
||||
if (rc) {
|
||||
release_mid(mid);
|
||||
release_mid(server, mid);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
|
|
@ -157,7 +136,7 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
|
|||
*/
|
||||
int
|
||||
SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
|
||||
char *in_buf, int flags)
|
||||
char *in_buf, unsigned int in_len, int flags)
|
||||
{
|
||||
int rc;
|
||||
struct kvec iov[1];
|
||||
|
|
@ -165,7 +144,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
|
|||
int resp_buf_type;
|
||||
|
||||
iov[0].iov_base = in_buf;
|
||||
iov[0].iov_len = get_rfc1002_len(in_buf) + 4;
|
||||
iov[0].iov_len = in_len;
|
||||
flags |= CIFS_NO_RSP_BUF;
|
||||
rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
|
||||
cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc);
|
||||
|
|
@ -177,21 +156,19 @@ int
|
|||
cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
|
||||
bool log_error)
|
||||
{
|
||||
unsigned int len = get_rfc1002_len(mid->resp_buf) + 4;
|
||||
unsigned int len = mid->response_pdu_len;
|
||||
|
||||
dump_smb(mid->resp_buf, min_t(u32, 92, len));
|
||||
|
||||
/* convert the length into a more usable form */
|
||||
if (server->sign) {
|
||||
struct kvec iov[2];
|
||||
struct kvec iov[1];
|
||||
int rc = 0;
|
||||
struct smb_rqst rqst = { .rq_iov = iov,
|
||||
.rq_nvec = 2 };
|
||||
.rq_nvec = ARRAY_SIZE(iov) };
|
||||
|
||||
iov[0].iov_base = mid->resp_buf;
|
||||
iov[0].iov_len = 4;
|
||||
iov[1].iov_base = (char *)mid->resp_buf + 4;
|
||||
iov[1].iov_len = len - 4;
|
||||
iov[0].iov_len = len;
|
||||
/* FIXME: add code to kill session */
|
||||
rc = cifs_verify_signature(&rqst, server,
|
||||
mid->sequence_number);
|
||||
|
|
@ -201,27 +178,23 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
|
|||
}
|
||||
|
||||
/* BB special case reconnect tid and uid here? */
|
||||
return map_and_check_smb_error(mid, log_error);
|
||||
return map_and_check_smb_error(server, mid, log_error);
|
||||
}
|
||||
|
||||
struct mid_q_entry *
|
||||
cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *ignored,
|
||||
cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server,
|
||||
struct smb_rqst *rqst)
|
||||
{
|
||||
int rc;
|
||||
struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
|
||||
struct mid_q_entry *mid;
|
||||
|
||||
if (rqst->rq_iov[0].iov_len != 4 ||
|
||||
rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
|
||||
return ERR_PTR(-EIO);
|
||||
|
||||
rc = allocate_mid(ses, hdr, &mid);
|
||||
if (rc)
|
||||
return ERR_PTR(rc);
|
||||
rc = cifs_sign_rqst(rqst, ses->server, &mid->sequence_number);
|
||||
rc = cifs_sign_rqst(rqst, server, &mid->sequence_number);
|
||||
if (rc) {
|
||||
delete_mid(mid);
|
||||
delete_mid(server, mid);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
return mid;
|
||||
|
|
@ -232,334 +205,59 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
|
|||
struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
|
||||
const int flags, struct kvec *resp_iov)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
struct kvec s_iov[CIFS_MAX_IOV_SIZE], *new_iov;
|
||||
int rc;
|
||||
struct smb_rqst rqst = {
|
||||
.rq_iov = iov,
|
||||
.rq_nvec = n_vec,
|
||||
};
|
||||
|
||||
if (n_vec + 1 > CIFS_MAX_IOV_SIZE) {
|
||||
new_iov = kmalloc_array(n_vec + 1, sizeof(struct kvec),
|
||||
GFP_KERNEL);
|
||||
if (!new_iov) {
|
||||
/* otherwise cifs_send_recv below sets resp_buf_type */
|
||||
*resp_buf_type = CIFS_NO_BUFFER;
|
||||
return -ENOMEM;
|
||||
}
|
||||
} else
|
||||
new_iov = s_iov;
|
||||
|
||||
/* 1st iov is a RFC1001 length followed by the rest of the packet */
|
||||
memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec));
|
||||
|
||||
new_iov[0].iov_base = new_iov[1].iov_base;
|
||||
new_iov[0].iov_len = 4;
|
||||
new_iov[1].iov_base += 4;
|
||||
new_iov[1].iov_len -= 4;
|
||||
|
||||
memset(&rqst, 0, sizeof(struct smb_rqst));
|
||||
rqst.rq_iov = new_iov;
|
||||
rqst.rq_nvec = n_vec + 1;
|
||||
|
||||
rc = cifs_send_recv(xid, ses, ses->server,
|
||||
&rqst, resp_buf_type, flags, resp_iov);
|
||||
if (n_vec + 1 > CIFS_MAX_IOV_SIZE)
|
||||
kfree(new_iov);
|
||||
return rc;
|
||||
return cifs_send_recv(xid, ses, ses->server,
|
||||
&rqst, resp_buf_type, flags, resp_iov);
|
||||
}
|
||||
|
||||
int
|
||||
SendReceive(const unsigned int xid, struct cifs_ses *ses,
|
||||
struct smb_hdr *in_buf, struct smb_hdr *out_buf,
|
||||
int *pbytes_returned, const int flags)
|
||||
struct smb_hdr *in_buf, unsigned int in_len,
|
||||
struct smb_hdr *out_buf, int *pbytes_returned, const int flags)
|
||||
{
|
||||
int rc = 0;
|
||||
struct mid_q_entry *midQ;
|
||||
unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
|
||||
struct kvec iov = { .iov_base = in_buf, .iov_len = len };
|
||||
struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
|
||||
struct cifs_credits credits = { .value = 1, .instance = 0 };
|
||||
struct TCP_Server_Info *server;
|
||||
struct kvec resp_iov = {};
|
||||
struct kvec iov = { .iov_base = in_buf, .iov_len = in_len };
|
||||
struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
|
||||
int resp_buf_type;
|
||||
int rc = 0;
|
||||
|
||||
if (WARN_ON_ONCE(in_len > 0xffffff))
|
||||
return smb_EIO1(smb_eio_trace_tx_too_long, in_len);
|
||||
if (ses == NULL) {
|
||||
cifs_dbg(VFS, "Null smb session\n");
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
}
|
||||
server = ses->server;
|
||||
if (server == NULL) {
|
||||
cifs_dbg(VFS, "Null tcp session\n");
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
}
|
||||
|
||||
spin_lock(&server->srv_lock);
|
||||
if (server->tcpStatus == CifsExiting) {
|
||||
spin_unlock(&server->srv_lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
spin_unlock(&server->srv_lock);
|
||||
|
||||
/* Ensure that we do not send more than 50 overlapping requests
|
||||
to the same server. We may make this configurable later or
|
||||
use ses->maxReq */
|
||||
|
||||
if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||
if (in_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
|
||||
cifs_server_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
|
||||
len);
|
||||
return -EIO;
|
||||
in_len);
|
||||
return smb_EIO1(smb_eio_trace_tx_too_long, in_len);
|
||||
}
|
||||
|
||||
rc = wait_for_free_request(server, flags, &credits.instance);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* make sure that we sign in the same order that we send on this socket
|
||||
and avoid races inside tcp sendmsg code that could cause corruption
|
||||
of smb data */
|
||||
|
||||
cifs_server_lock(server);
|
||||
|
||||
rc = allocate_mid(ses, in_buf, &midQ);
|
||||
if (rc) {
|
||||
cifs_server_unlock(server);
|
||||
/* Update # of requests on wire to server */
|
||||
add_credits(server, &credits, 0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
|
||||
if (rc) {
|
||||
cifs_server_unlock(server);
|
||||
goto out;
|
||||
}
|
||||
|
||||
midQ->mid_state = MID_REQUEST_SUBMITTED;
|
||||
|
||||
rc = smb_send(server, in_buf, len);
|
||||
cifs_save_when_sent(midQ);
|
||||
|
||||
rc = cifs_send_recv(xid, ses, ses->server,
|
||||
&rqst, &resp_buf_type, flags, &resp_iov);
|
||||
if (rc < 0)
|
||||
server->sequence_number -= 2;
|
||||
|
||||
cifs_server_unlock(server);
|
||||
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
rc = wait_for_response(server, midQ);
|
||||
if (rc != 0) {
|
||||
send_cancel(server, &rqst, midQ);
|
||||
spin_lock(&midQ->mid_lock);
|
||||
if (midQ->callback) {
|
||||
/* no longer considered to be "in-flight" */
|
||||
midQ->callback = release_mid;
|
||||
spin_unlock(&midQ->mid_lock);
|
||||
add_credits(server, &credits, 0);
|
||||
return rc;
|
||||
}
|
||||
spin_unlock(&midQ->mid_lock);
|
||||
}
|
||||
|
||||
rc = cifs_sync_mid_result(midQ, server);
|
||||
if (rc != 0) {
|
||||
add_credits(server, &credits, 0);
|
||||
return rc;
|
||||
|
||||
if (out_buf) {
|
||||
*pbytes_returned = resp_iov.iov_len;
|
||||
if (resp_iov.iov_len)
|
||||
memcpy(out_buf, resp_iov.iov_base, resp_iov.iov_len);
|
||||
}
|
||||
|
||||
if (!midQ->resp_buf || !out_buf ||
|
||||
midQ->mid_state != MID_RESPONSE_READY) {
|
||||
rc = -EIO;
|
||||
cifs_server_dbg(VFS, "Bad MID state?\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
*pbytes_returned = get_rfc1002_len(midQ->resp_buf);
|
||||
memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
|
||||
rc = cifs_check_receive(midQ, server, 0);
|
||||
out:
|
||||
delete_mid(midQ);
|
||||
add_credits(server, &credits, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
|
||||
blocking lock to return. */
|
||||
|
||||
static int
|
||||
send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct smb_hdr *in_buf,
|
||||
struct smb_hdr *out_buf)
|
||||
{
|
||||
int bytes_returned;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
|
||||
|
||||
/* We just modify the current in_buf to change
|
||||
the type of lock from LOCKING_ANDX_SHARED_LOCK
|
||||
or LOCKING_ANDX_EXCLUSIVE_LOCK to
|
||||
LOCKING_ANDX_CANCEL_LOCK. */
|
||||
|
||||
pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
|
||||
pSMB->Timeout = 0;
|
||||
pSMB->hdr.Mid = get_next_mid(ses->server);
|
||||
|
||||
return SendReceive(xid, ses, in_buf, out_buf,
|
||||
&bytes_returned, 0);
|
||||
}
|
||||
|
||||
int
|
||||
SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct smb_hdr *in_buf, struct smb_hdr *out_buf,
|
||||
int *pbytes_returned)
|
||||
{
|
||||
int rc = 0;
|
||||
int rstart = 0;
|
||||
struct mid_q_entry *midQ;
|
||||
struct cifs_ses *ses;
|
||||
unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
|
||||
struct kvec iov = { .iov_base = in_buf, .iov_len = len };
|
||||
struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
|
||||
unsigned int instance;
|
||||
struct TCP_Server_Info *server;
|
||||
|
||||
if (tcon == NULL || tcon->ses == NULL) {
|
||||
cifs_dbg(VFS, "Null smb session\n");
|
||||
return -EIO;
|
||||
}
|
||||
ses = tcon->ses;
|
||||
server = ses->server;
|
||||
|
||||
if (server == NULL) {
|
||||
cifs_dbg(VFS, "Null tcp session\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
spin_lock(&server->srv_lock);
|
||||
if (server->tcpStatus == CifsExiting) {
|
||||
spin_unlock(&server->srv_lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
spin_unlock(&server->srv_lock);
|
||||
|
||||
/* Ensure that we do not send more than 50 overlapping requests
|
||||
to the same server. We may make this configurable later or
|
||||
use ses->maxReq */
|
||||
|
||||
if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||
cifs_tcon_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
|
||||
len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
rc = wait_for_free_request(server, CIFS_BLOCKING_OP, &instance);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* make sure that we sign in the same order that we send on this socket
|
||||
and avoid races inside tcp sendmsg code that could cause corruption
|
||||
of smb data */
|
||||
|
||||
cifs_server_lock(server);
|
||||
|
||||
rc = allocate_mid(ses, in_buf, &midQ);
|
||||
if (rc) {
|
||||
cifs_server_unlock(server);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
|
||||
if (rc) {
|
||||
delete_mid(midQ);
|
||||
cifs_server_unlock(server);
|
||||
return rc;
|
||||
}
|
||||
|
||||
midQ->mid_state = MID_REQUEST_SUBMITTED;
|
||||
rc = smb_send(server, in_buf, len);
|
||||
cifs_save_when_sent(midQ);
|
||||
|
||||
if (rc < 0)
|
||||
server->sequence_number -= 2;
|
||||
|
||||
cifs_server_unlock(server);
|
||||
|
||||
if (rc < 0) {
|
||||
delete_mid(midQ);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Wait for a reply - allow signals to interrupt. */
|
||||
rc = wait_event_interruptible(server->response_q,
|
||||
(!(midQ->mid_state == MID_REQUEST_SUBMITTED ||
|
||||
midQ->mid_state == MID_RESPONSE_RECEIVED)) ||
|
||||
((server->tcpStatus != CifsGood) &&
|
||||
(server->tcpStatus != CifsNew)));
|
||||
|
||||
/* Were we interrupted by a signal ? */
|
||||
spin_lock(&server->srv_lock);
|
||||
if ((rc == -ERESTARTSYS) &&
|
||||
(midQ->mid_state == MID_REQUEST_SUBMITTED ||
|
||||
midQ->mid_state == MID_RESPONSE_RECEIVED) &&
|
||||
((server->tcpStatus == CifsGood) ||
|
||||
(server->tcpStatus == CifsNew))) {
|
||||
spin_unlock(&server->srv_lock);
|
||||
|
||||
if (in_buf->Command == SMB_COM_TRANSACTION2) {
|
||||
/* POSIX lock. We send a NT_CANCEL SMB to cause the
|
||||
blocking lock to return. */
|
||||
rc = send_cancel(server, &rqst, midQ);
|
||||
if (rc) {
|
||||
delete_mid(midQ);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
/* Windows lock. We send a LOCKINGX_CANCEL_LOCK
|
||||
to cause the blocking lock to return. */
|
||||
|
||||
rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
|
||||
|
||||
/* If we get -ENOLCK back the lock may have
|
||||
already been removed. Don't exit in this case. */
|
||||
if (rc && rc != -ENOLCK) {
|
||||
delete_mid(midQ);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
rc = wait_for_response(server, midQ);
|
||||
if (rc) {
|
||||
send_cancel(server, &rqst, midQ);
|
||||
spin_lock(&midQ->mid_lock);
|
||||
if (midQ->callback) {
|
||||
/* no longer considered to be "in-flight" */
|
||||
midQ->callback = release_mid;
|
||||
spin_unlock(&midQ->mid_lock);
|
||||
return rc;
|
||||
}
|
||||
spin_unlock(&midQ->mid_lock);
|
||||
}
|
||||
|
||||
/* We got the response - restart system call. */
|
||||
rstart = 1;
|
||||
spin_lock(&server->srv_lock);
|
||||
}
|
||||
spin_unlock(&server->srv_lock);
|
||||
|
||||
rc = cifs_sync_mid_result(midQ, server);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
/* rcvd frame is ok */
|
||||
if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_READY) {
|
||||
rc = -EIO;
|
||||
cifs_tcon_dbg(VFS, "Bad MID state?\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
*pbytes_returned = get_rfc1002_len(midQ->resp_buf);
|
||||
memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
|
||||
rc = cifs_check_receive(midQ, server, 0);
|
||||
out:
|
||||
delete_mid(midQ);
|
||||
if (rstart && rc == -EACCES)
|
||||
return -ERESTARTSYS;
|
||||
free_rsp_buf(resp_buf_type, resp_iov.iov_base);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ struct bucket {
|
|||
unsigned int count;
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* has_low_entropy() - Compute Shannon entropy of the sampled data.
|
||||
* @bkt: Bytes counts of the sample.
|
||||
* @slen: Size of the sample.
|
||||
|
|
@ -82,7 +82,7 @@ static bool has_low_entropy(struct bucket *bkt, size_t slen)
|
|||
#define BYTE_DIST_BAD 0
|
||||
#define BYTE_DIST_GOOD 1
|
||||
#define BYTE_DIST_MAYBE 2
|
||||
/**
|
||||
/*
|
||||
* calc_byte_distribution() - Compute byte distribution on the sampled data.
|
||||
* @bkt: Byte counts of the sample.
|
||||
* @slen: Size of the sample.
|
||||
|
|
@ -182,7 +182,7 @@ static int collect_sample(const struct iov_iter *source, ssize_t max, u8 *sample
|
|||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* is_compressible() - Determines if a chunk of data is compressible.
|
||||
* @data: Iterator containing uncompressed data.
|
||||
*
|
||||
|
|
@ -261,6 +261,21 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* should_compress() - Determines if a request (write) or the response to a
|
||||
* request (read) should be compressed.
|
||||
* @tcon: tcon of the request is being sent to
|
||||
* @rqst: request to evaluate
|
||||
*
|
||||
* Return: true iff:
|
||||
* - compression was successfully negotiated with server
|
||||
* - server has enabled compression for the share
|
||||
* - it's a read or write request
|
||||
* - (write only) request length is >= SMB_COMPRESS_MIN_LEN
|
||||
* - (write only) is_compressible() returns 1
|
||||
*
|
||||
* Return false otherwise.
|
||||
*/
|
||||
bool should_compress(const struct cifs_tcon *tcon, const struct smb_rqst *rq)
|
||||
{
|
||||
const struct smb2_hdr *shdr = rq->rq_iov->iov_base;
|
||||
|
|
@ -310,7 +325,7 @@ int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, compress_s
|
|||
iter = rq->rq_iter;
|
||||
|
||||
if (!copy_from_iter_full(src, slen, &iter)) {
|
||||
ret = -EIO;
|
||||
ret = smb_EIO(smb_eio_trace_compress_copy);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,26 +29,11 @@
|
|||
#ifdef CONFIG_CIFS_COMPRESSION
|
||||
typedef int (*compress_send_fn)(struct TCP_Server_Info *, int, struct smb_rqst *);
|
||||
|
||||
int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, compress_send_fn send_fn);
|
||||
|
||||
/**
|
||||
* should_compress() - Determines if a request (write) or the response to a
|
||||
* request (read) should be compressed.
|
||||
* @tcon: tcon of the request is being sent to
|
||||
* @rqst: request to evaluate
|
||||
*
|
||||
* Return: true iff:
|
||||
* - compression was successfully negotiated with server
|
||||
* - server has enabled compression for the share
|
||||
* - it's a read or write request
|
||||
* - (write only) request length is >= SMB_COMPRESS_MIN_LEN
|
||||
* - (write only) is_compressible() returns 1
|
||||
*
|
||||
* Return false otherwise.
|
||||
*/
|
||||
int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, compress_send_fn send_fn);
|
||||
bool should_compress(const struct cifs_tcon *tcon, const struct smb_rqst *rq);
|
||||
|
||||
/**
|
||||
/*
|
||||
* smb_compress_alg_valid() - Validate a compression algorithm.
|
||||
* @alg: Compression algorithm to check.
|
||||
* @valid_none: Conditional check whether NONE algorithm should be
|
||||
|
|
|
|||
|
|
@ -325,7 +325,7 @@ cifs_abort_connection(struct TCP_Server_Info *server)
|
|||
cifs_dbg(FYI, "%s: moving mids to private list\n", __func__);
|
||||
spin_lock(&server->mid_queue_lock);
|
||||
list_for_each_entry_safe(mid, nmid, &server->pending_mid_q, qhead) {
|
||||
kref_get(&mid->refcount);
|
||||
smb_get_mid(mid);
|
||||
if (mid->mid_state == MID_REQUEST_SUBMITTED)
|
||||
mid->mid_state = MID_RETRY_NEEDED;
|
||||
list_move(&mid->qhead, &retry_list);
|
||||
|
|
@ -337,8 +337,8 @@ cifs_abort_connection(struct TCP_Server_Info *server)
|
|||
cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
|
||||
list_for_each_entry_safe(mid, nmid, &retry_list, qhead) {
|
||||
list_del_init(&mid->qhead);
|
||||
mid_execute_callback(mid);
|
||||
release_mid(mid);
|
||||
mid_execute_callback(server, mid);
|
||||
release_mid(server, mid);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -425,7 +425,7 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
|
|||
spin_unlock(&server->srv_lock);
|
||||
cifs_swn_reset_server_dstaddr(server);
|
||||
cifs_server_unlock(server);
|
||||
mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
|
||||
cifs_queue_server_reconn(server);
|
||||
}
|
||||
} while (server->tcpStatus == CifsNeedReconnect);
|
||||
|
||||
|
|
@ -564,7 +564,7 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server)
|
|||
spin_unlock(&server->srv_lock);
|
||||
cifs_swn_reset_server_dstaddr(server);
|
||||
cifs_server_unlock(server);
|
||||
mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
|
||||
cifs_queue_server_reconn(server);
|
||||
} while (server->tcpStatus == CifsNeedReconnect);
|
||||
|
||||
dfs_cache_noreq_update_tgthint(ref_path, target_hint);
|
||||
|
|
@ -882,7 +882,7 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
|
|||
*/
|
||||
spin_lock(&server->mid_queue_lock);
|
||||
list_for_each_entry_safe(mid, nmid, &server->pending_mid_q, qhead) {
|
||||
kref_get(&mid->refcount);
|
||||
smb_get_mid(mid);
|
||||
list_move(&mid->qhead, &dispose_list);
|
||||
mid->deleted_from_q = true;
|
||||
}
|
||||
|
|
@ -915,8 +915,8 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
|
|||
list_del_init(&mid->qhead);
|
||||
mid->mid_rc = mid_rc;
|
||||
mid->mid_state = MID_RC;
|
||||
mid_execute_callback(mid);
|
||||
release_mid(mid);
|
||||
mid_execute_callback(server, mid);
|
||||
release_mid(server, mid);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -948,12 +948,12 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
|
|||
}
|
||||
|
||||
void
|
||||
dequeue_mid(struct mid_q_entry *mid, bool malformed)
|
||||
dequeue_mid(struct TCP_Server_Info *server, struct mid_q_entry *mid, bool malformed)
|
||||
{
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
mid->when_received = jiffies;
|
||||
#endif
|
||||
spin_lock(&mid->server->mid_queue_lock);
|
||||
spin_lock(&server->mid_queue_lock);
|
||||
if (!malformed)
|
||||
mid->mid_state = MID_RESPONSE_RECEIVED;
|
||||
else
|
||||
|
|
@ -963,12 +963,12 @@ dequeue_mid(struct mid_q_entry *mid, bool malformed)
|
|||
* function has finished processing it is a bug.
|
||||
*/
|
||||
if (mid->deleted_from_q == true) {
|
||||
spin_unlock(&mid->server->mid_queue_lock);
|
||||
spin_unlock(&server->mid_queue_lock);
|
||||
pr_warn_once("trying to dequeue a deleted mid\n");
|
||||
} else {
|
||||
list_del_init(&mid->qhead);
|
||||
mid->deleted_from_q = true;
|
||||
spin_unlock(&mid->server->mid_queue_lock);
|
||||
spin_unlock(&server->mid_queue_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1004,7 +1004,7 @@ handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
|
|||
else
|
||||
server->smallbuf = NULL;
|
||||
}
|
||||
dequeue_mid(mid, malformed);
|
||||
dequeue_mid(server, mid, malformed);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -1101,7 +1101,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
|
|||
list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
|
||||
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
|
||||
cifs_dbg(FYI, "Clearing mid %llu\n", mid_entry->mid);
|
||||
kref_get(&mid_entry->refcount);
|
||||
smb_get_mid(mid_entry);
|
||||
mid_entry->mid_state = MID_SHUTDOWN;
|
||||
list_move(&mid_entry->qhead, &dispose_list);
|
||||
mid_entry->deleted_from_q = true;
|
||||
|
|
@ -1113,8 +1113,8 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
|
|||
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
|
||||
cifs_dbg(FYI, "Callback mid %llu\n", mid_entry->mid);
|
||||
list_del_init(&mid_entry->qhead);
|
||||
mid_execute_callback(mid_entry);
|
||||
release_mid(mid_entry);
|
||||
mid_execute_callback(server, mid_entry);
|
||||
release_mid(server, mid_entry);
|
||||
}
|
||||
/* 1/8th of sec is more than enough time for them to exit */
|
||||
msleep(125);
|
||||
|
|
@ -1155,15 +1155,14 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
unsigned int pdu_length = server->pdu_size;
|
||||
|
||||
/* make sure this will fit in a large buffer */
|
||||
if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
|
||||
HEADER_PREAMBLE_SIZE(server)) {
|
||||
if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) {
|
||||
cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
|
||||
cifs_reconnect(server, true);
|
||||
return -ECONNABORTED;
|
||||
}
|
||||
|
||||
/* switch to large buffer if too big for a small one */
|
||||
if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
|
||||
if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE) {
|
||||
server->large_buf = true;
|
||||
memcpy(server->bigbuf, buf, server->total_read);
|
||||
buf = server->bigbuf;
|
||||
|
|
@ -1196,7 +1195,8 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
* 48 bytes is enough to display the header and a little bit
|
||||
* into the payload for debugging purposes.
|
||||
*/
|
||||
rc = server->ops->check_message(buf, server->total_read, server);
|
||||
rc = server->ops->check_message(buf, server->pdu_size,
|
||||
server->total_read, server);
|
||||
if (rc)
|
||||
cifs_dump_mem("Bad SMB: ", buf,
|
||||
min_t(unsigned int, server->total_read, 48));
|
||||
|
|
@ -1286,16 +1286,13 @@ cifs_demultiplex_thread(void *p)
|
|||
if (length < 0)
|
||||
continue;
|
||||
|
||||
if (is_smb1(server))
|
||||
server->total_read = length;
|
||||
else
|
||||
server->total_read = 0;
|
||||
server->total_read = 0;
|
||||
|
||||
/*
|
||||
* The right amount was read from socket - 4 bytes,
|
||||
* so we can now interpret the length field.
|
||||
*/
|
||||
pdu_length = get_rfc1002_len(buf);
|
||||
pdu_length = be32_to_cpup(((__be32 *)buf)) & 0xffffff;
|
||||
|
||||
cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length);
|
||||
if (!is_smb_response(server, buf[0]))
|
||||
|
|
@ -1314,9 +1311,8 @@ next_pdu:
|
|||
}
|
||||
|
||||
/* read down to the MID */
|
||||
length = cifs_read_from_socket(server,
|
||||
buf + HEADER_PREAMBLE_SIZE(server),
|
||||
MID_HEADER_SIZE(server));
|
||||
length = cifs_read_from_socket(server, buf,
|
||||
MID_HEADER_SIZE(server));
|
||||
if (length < 0)
|
||||
continue;
|
||||
server->total_read += length;
|
||||
|
|
@ -1348,6 +1344,8 @@ next_pdu:
|
|||
bufs[0] = buf;
|
||||
num_mids = 1;
|
||||
|
||||
if (mids[0])
|
||||
mids[0]->response_pdu_len = pdu_length;
|
||||
if (!mids[0] || !mids[0]->receive)
|
||||
length = standard_receive3(server, mids[0]);
|
||||
else
|
||||
|
|
@ -1357,7 +1355,7 @@ next_pdu:
|
|||
if (length < 0) {
|
||||
for (i = 0; i < num_mids; i++)
|
||||
if (mids[i])
|
||||
release_mid(mids[i]);
|
||||
release_mid(server, mids[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1390,9 +1388,9 @@ next_pdu:
|
|||
}
|
||||
|
||||
if (!mids[i]->multiRsp || mids[i]->multiEnd)
|
||||
mid_execute_callback(mids[i]);
|
||||
mid_execute_callback(server, mids[i]);
|
||||
|
||||
release_mid(mids[i]);
|
||||
release_mid(server, mids[i]);
|
||||
} else if (server->ops->is_oplock_break &&
|
||||
server->ops->is_oplock_break(bufs[i],
|
||||
server)) {
|
||||
|
|
@ -1406,7 +1404,7 @@ next_pdu:
|
|||
smb2_add_credits_from_hdr(bufs[i], server);
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
if (server->ops->dump_detail)
|
||||
server->ops->dump_detail(bufs[i],
|
||||
server->ops->dump_detail(bufs[i], pdu_length,
|
||||
server);
|
||||
cifs_dump_mids(server);
|
||||
#endif /* CIFS_DEBUG2 */
|
||||
|
|
@ -3242,7 +3240,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
|
|||
if (be16_to_cpu(resp.length) != 0) {
|
||||
cifs_dbg(VFS, "RFC 1002 positive session response but with invalid non-zero length %u\n",
|
||||
be16_to_cpu(resp.length));
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_rx_pos_sess_resp);
|
||||
}
|
||||
cifs_dbg(FYI, "RFC 1002 positive session response");
|
||||
break;
|
||||
|
|
@ -3281,17 +3279,18 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
|
|||
break;
|
||||
case RFC1002_INSUFFICIENT_RESOURCE:
|
||||
/* remote server resource error */
|
||||
smb_EIO(smb_eio_trace_rx_insuff_res);
|
||||
rc = -EREMOTEIO;
|
||||
break;
|
||||
case RFC1002_UNSPECIFIED_ERROR:
|
||||
default:
|
||||
/* other/unknown error */
|
||||
rc = -EIO;
|
||||
rc = smb_EIO(smb_eio_trace_rx_unspec_error);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
cifs_dbg(VFS, "RFC 1002 negative session response\n");
|
||||
rc = -EIO;
|
||||
rc = smb_EIO(smb_eio_trace_rx_neg_sess_resp);
|
||||
}
|
||||
return rc;
|
||||
case RFC1002_RETARGET_SESSION_RESPONSE:
|
||||
|
|
@ -3313,7 +3312,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
|
|||
return -EMULTIHOP;
|
||||
default:
|
||||
cifs_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", resp.type);
|
||||
return -EIO;
|
||||
return smb_EIO1(smb_eio_trace_rx_unknown_resp, resp.type);
|
||||
}
|
||||
|
||||
server->with_rfc1001 = true;
|
||||
|
|
@ -3927,7 +3926,9 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
|
|||
ctx->prepath = NULL;
|
||||
|
||||
out:
|
||||
cifs_try_adding_channels(mnt_ctx.ses);
|
||||
smb3_update_ses_channels(mnt_ctx.ses, mnt_ctx.server,
|
||||
false /* from_reconnect */,
|
||||
false /* disable_mchan */);
|
||||
rc = mount_setup_tlink(cifs_sb, mnt_ctx.ses, mnt_ctx.tcon);
|
||||
if (rc)
|
||||
goto error;
|
||||
|
|
@ -3999,11 +4000,11 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
|
|||
TCONX_RSP *pSMBr;
|
||||
unsigned char *bcc_ptr;
|
||||
int rc = 0;
|
||||
int length;
|
||||
int length, in_len;
|
||||
__u16 bytes_left, count;
|
||||
|
||||
if (ses == NULL)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
smb_buffer = cifs_buf_get();
|
||||
if (smb_buffer == NULL)
|
||||
|
|
@ -4011,8 +4012,8 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
|
|||
|
||||
smb_buffer_response = smb_buffer;
|
||||
|
||||
header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
|
||||
NULL /*no tid */, 4 /*wct */);
|
||||
in_len = header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
|
||||
NULL /*no tid */, 4 /*wct */);
|
||||
|
||||
smb_buffer->Mid = get_next_mid(ses->server);
|
||||
smb_buffer->Uid = ses->Suid;
|
||||
|
|
@ -4053,11 +4054,11 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
|
|||
bcc_ptr += strlen("?????");
|
||||
bcc_ptr += 1;
|
||||
count = bcc_ptr - &pSMB->Password[0];
|
||||
be32_add_cpu(&pSMB->hdr.smb_buf_length, count);
|
||||
in_len += count;
|
||||
pSMB->ByteCount = cpu_to_le16(count);
|
||||
|
||||
rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
|
||||
0);
|
||||
rc = SendReceive(xid, ses, smb_buffer, in_len, smb_buffer_response,
|
||||
&length, 0);
|
||||
|
||||
/* above now done in SendReceive */
|
||||
if (rc == 0) {
|
||||
|
|
@ -4237,8 +4238,10 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
|
|||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&pserver->dstaddr;
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)&pserver->dstaddr;
|
||||
bool is_binding = false;
|
||||
bool new_ses;
|
||||
|
||||
spin_lock(&ses->ses_lock);
|
||||
new_ses = ses->ses_status == SES_NEW;
|
||||
cifs_dbg(FYI, "%s: channel connect bitmap: 0x%lx\n",
|
||||
__func__, ses->chans_need_reconnect);
|
||||
|
||||
|
|
@ -4324,7 +4327,10 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
|
|||
}
|
||||
|
||||
if (rc) {
|
||||
cifs_server_dbg(VFS, "Send error in SessSetup = %d\n", rc);
|
||||
if (new_ses) {
|
||||
cifs_server_dbg(VFS, "failed to create a new SMB session with %s: %d\n",
|
||||
get_security_type_str(ses->sectype), rc);
|
||||
}
|
||||
spin_lock(&ses->ses_lock);
|
||||
if (ses->ses_status == SES_IN_SETUP)
|
||||
ses->ses_status = SES_NEED_RECON;
|
||||
|
|
|
|||
|
|
@ -457,7 +457,7 @@ out_err:
|
|||
|
||||
int
|
||||
cifs_atomic_open(struct inode *inode, struct dentry *direntry,
|
||||
struct file *file, unsigned oflags, umode_t mode)
|
||||
struct file *file, unsigned int oflags, umode_t mode)
|
||||
{
|
||||
int rc;
|
||||
unsigned int xid;
|
||||
|
|
@ -471,7 +471,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
|
|||
struct cifs_open_info_data buf = {};
|
||||
|
||||
if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb))))
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_forced_shutdown);
|
||||
|
||||
/*
|
||||
* Posix open is only called (at lookup time) for file create now. For
|
||||
|
|
@ -589,7 +589,7 @@ int cifs_create(struct mnt_idmap *idmap, struct inode *inode,
|
|||
inode, direntry, direntry);
|
||||
|
||||
if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb)))) {
|
||||
rc = -EIO;
|
||||
rc = smb_EIO(smb_eio_trace_forced_shutdown);
|
||||
goto out_free_xid;
|
||||
}
|
||||
|
||||
|
|
@ -631,7 +631,7 @@ int cifs_mknod(struct mnt_idmap *idmap, struct inode *inode,
|
|||
|
||||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_forced_shutdown);
|
||||
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink))
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@
|
|||
#include "cifsglob.h"
|
||||
#include "cifsproto.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
int dns_resolve_name(const char *dom, const char *name,
|
||||
size_t namelen, struct sockaddr *ip_addr);
|
||||
|
||||
|
|
@ -36,6 +34,4 @@ static inline int dns_resolve_unc(const char *dom, const char *unc,
|
|||
return dns_resolve_name(dom, name, namelen, ip_addr);
|
||||
}
|
||||
|
||||
#endif /* KERNEL */
|
||||
|
||||
#endif /* _DNS_RESOLVE_H */
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ static void cifs_issue_write(struct netfs_io_subrequest *subreq)
|
|||
int rc;
|
||||
|
||||
if (cifs_forced_shutdown(sbi)) {
|
||||
rc = -EIO;
|
||||
rc = smb_EIO(smb_eio_trace_forced_shutdown);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
@ -286,7 +286,7 @@ static int cifs_init_request(struct netfs_io_request *rreq, struct file *file)
|
|||
req->pid = req->cfile->pid;
|
||||
} else if (rreq->origin != NETFS_WRITEBACK) {
|
||||
WARN_ON_ONCE(1);
|
||||
return -EIO;
|
||||
return smb_EIO1(smb_eio_trace_not_netfs_writeback, rreq->origin);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1036,7 +1036,7 @@ int cifs_open(struct inode *inode, struct file *file)
|
|||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
if (unlikely(cifs_forced_shutdown(cifs_sb))) {
|
||||
free_xid(xid);
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_forced_shutdown);
|
||||
}
|
||||
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
|
|
|
|||
|
|
@ -505,7 +505,7 @@ cifs_parse_smb_version(struct fs_context *fc, char *value, struct smb3_fs_contex
|
|||
case Smb_20:
|
||||
cifs_errorf(fc, "vers=2.0 mount not permitted when legacy dialects disabled\n");
|
||||
return 1;
|
||||
#endif /* CIFS_ALLOW_INSECURE_LEGACY */
|
||||
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
|
||||
case Smb_21:
|
||||
ctx->ops = &smb21_operations;
|
||||
ctx->vals = &smb21_values;
|
||||
|
|
@ -711,12 +711,54 @@ smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int smb3_handle_conflicting_options(struct fs_context *fc)
|
||||
{
|
||||
struct smb3_fs_context *ctx = smb3_fc2context(fc);
|
||||
|
||||
if (ctx->multichannel_specified) {
|
||||
if (ctx->multichannel) {
|
||||
if (!ctx->max_channels_specified) {
|
||||
ctx->max_channels = 2;
|
||||
} else if (ctx->max_channels == 1) {
|
||||
cifs_errorf(fc,
|
||||
"max_channels must be greater than 1 when multichannel is enabled\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
if (!ctx->max_channels_specified) {
|
||||
ctx->max_channels = 1;
|
||||
} else if (ctx->max_channels > 1) {
|
||||
cifs_errorf(fc,
|
||||
"max_channels must be equal to 1 when multichannel is disabled\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ctx->max_channels_specified) {
|
||||
if (ctx->max_channels > 1)
|
||||
ctx->multichannel = true;
|
||||
else
|
||||
ctx->multichannel = false;
|
||||
} else {
|
||||
ctx->multichannel = false;
|
||||
ctx->max_channels = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//resetting default values as remount doesn't initialize fs_context again
|
||||
ctx->multichannel_specified = false;
|
||||
ctx->max_channels_specified = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void smb3_fs_context_free(struct fs_context *fc);
|
||||
static int smb3_fs_context_parse_param(struct fs_context *fc,
|
||||
struct fs_parameter *param);
|
||||
static int smb3_fs_context_parse_monolithic(struct fs_context *fc,
|
||||
void *data);
|
||||
static int smb3_get_tree(struct fs_context *fc);
|
||||
static void smb3_sync_ses_chan_max(struct cifs_ses *ses, unsigned int max_channels);
|
||||
static int smb3_reconfigure(struct fs_context *fc);
|
||||
|
||||
static const struct fs_context_operations smb3_fs_context_ops = {
|
||||
|
|
@ -784,6 +826,7 @@ static int smb3_fs_context_parse_monolithic(struct fs_context *fc,
|
|||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
ret = smb3_handle_conflicting_options(fc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1013,6 +1056,22 @@ int smb3_sync_session_ctx_passwords(struct cifs_sb_info *cifs_sb, struct cifs_se
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* smb3_sync_ses_chan_max - Synchronize the session's maximum channel count
|
||||
* @ses: pointer to the old CIFS session structure
|
||||
* @max_channels: new maximum number of channels to allow
|
||||
*
|
||||
* Updates the session's chan_max field to the new value, protecting the update
|
||||
* with the session's channel lock. This should be called whenever the maximum
|
||||
* allowed channels for a session changes (e.g., after a remount or reconfigure).
|
||||
*/
|
||||
static void smb3_sync_ses_chan_max(struct cifs_ses *ses, unsigned int max_channels)
|
||||
{
|
||||
spin_lock(&ses->chan_lock);
|
||||
ses->chan_max = max_channels;
|
||||
spin_unlock(&ses->chan_lock);
|
||||
}
|
||||
|
||||
static int smb3_reconfigure(struct fs_context *fc)
|
||||
{
|
||||
struct smb3_fs_context *ctx = smb3_fc2context(fc);
|
||||
|
|
@ -1095,7 +1154,39 @@ static int smb3_reconfigure(struct fs_context *fc)
|
|||
ses->password2 = new_password2;
|
||||
}
|
||||
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
/*
|
||||
* If multichannel or max_channels has changed, update the session's channels accordingly.
|
||||
* This may add or remove channels to match the new configuration.
|
||||
*/
|
||||
if ((ctx->multichannel != cifs_sb->ctx->multichannel) ||
|
||||
(ctx->max_channels != cifs_sb->ctx->max_channels)) {
|
||||
|
||||
/* Synchronize ses->chan_max with the new mount context */
|
||||
smb3_sync_ses_chan_max(ses, ctx->max_channels);
|
||||
/* Now update the session's channels to match the new configuration */
|
||||
/* Prevent concurrent scaling operations */
|
||||
spin_lock(&ses->ses_lock);
|
||||
if (ses->flags & CIFS_SES_FLAG_SCALE_CHANNELS) {
|
||||
spin_unlock(&ses->ses_lock);
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
ses->flags |= CIFS_SES_FLAG_SCALE_CHANNELS;
|
||||
spin_unlock(&ses->ses_lock);
|
||||
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
|
||||
rc = smb3_update_ses_channels(ses, ses->server,
|
||||
false /* from_reconnect */,
|
||||
false /* disable_mchan */);
|
||||
|
||||
/* Clear scaling flag after operation */
|
||||
spin_lock(&ses->ses_lock);
|
||||
ses->flags &= ~CIFS_SES_FLAG_SCALE_CHANNELS;
|
||||
spin_unlock(&ses->ses_lock);
|
||||
} else {
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
}
|
||||
|
||||
STEAL_STRING(cifs_sb, ctx, domainname);
|
||||
STEAL_STRING(cifs_sb, ctx, nodename);
|
||||
|
|
@ -1250,15 +1341,11 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
|
|||
ctx->nodelete = 1;
|
||||
break;
|
||||
case Opt_multichannel:
|
||||
if (result.negated) {
|
||||
ctx->multichannel_specified = true;
|
||||
if (result.negated)
|
||||
ctx->multichannel = false;
|
||||
ctx->max_channels = 1;
|
||||
} else {
|
||||
else
|
||||
ctx->multichannel = true;
|
||||
/* if number of channels not specified, default to 2 */
|
||||
if (ctx->max_channels < 2)
|
||||
ctx->max_channels = 2;
|
||||
}
|
||||
break;
|
||||
case Opt_uid:
|
||||
ctx->linux_uid = result.uid;
|
||||
|
|
@ -1394,15 +1481,13 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
|
|||
ctx->max_credits = result.uint_32;
|
||||
break;
|
||||
case Opt_max_channels:
|
||||
ctx->max_channels_specified = true;
|
||||
if (result.uint_32 < 1 || result.uint_32 > CIFS_MAX_CHANNELS) {
|
||||
cifs_errorf(fc, "%s: Invalid max_channels value, needs to be 1-%d\n",
|
||||
__func__, CIFS_MAX_CHANNELS);
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
ctx->max_channels = result.uint_32;
|
||||
/* If more than one channel requested ... they want multichan */
|
||||
if (result.uint_32 > 1)
|
||||
ctx->multichannel = true;
|
||||
break;
|
||||
case Opt_max_cached_dirs:
|
||||
if (result.uint_32 < 1) {
|
||||
|
|
@ -1820,13 +1905,6 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
|
|||
goto cifs_parse_mount_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Multichannel is not meaningful if max_channels is 1.
|
||||
* Force multichannel to false to ensure consistent configuration.
|
||||
*/
|
||||
if (ctx->multichannel && ctx->max_channels == 1)
|
||||
ctx->multichannel = false;
|
||||
|
||||
return 0;
|
||||
|
||||
cifs_parse_mount_err:
|
||||
|
|
@ -1913,6 +1991,8 @@ int smb3_init_fs_context(struct fs_context *fc)
|
|||
|
||||
/* default to no multichannel (single server connection) */
|
||||
ctx->multichannel = false;
|
||||
ctx->multichannel_specified = false;
|
||||
ctx->max_channels_specified = false;
|
||||
ctx->max_channels = 1;
|
||||
|
||||
ctx->backupuid_specified = false; /* no backup intent for a user */
|
||||
|
|
|
|||
|
|
@ -294,6 +294,8 @@ struct smb3_fs_context {
|
|||
bool domainauto:1;
|
||||
bool rdma:1;
|
||||
bool multichannel:1;
|
||||
bool multichannel_specified:1; /* true if user specified multichannel or nomultichannel */
|
||||
bool max_channels_specified:1; /* true if user specified max_channels */
|
||||
bool use_client_guid:1;
|
||||
/* reuse existing guid for multichannel */
|
||||
u8 client_guid[SMB2_CLIENT_GUID_SIZE];
|
||||
|
|
|
|||
|
|
@ -1952,7 +1952,7 @@ static int __cifs_unlink(struct inode *dir, struct dentry *dentry, bool sillyren
|
|||
cifs_dbg(FYI, "cifs_unlink, dir=0x%p, dentry=0x%p\n", dir, dentry);
|
||||
|
||||
if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_forced_shutdown);
|
||||
|
||||
/* Unhash dentry in advance to prevent any concurrent opens */
|
||||
spin_lock(&dentry->d_lock);
|
||||
|
|
@ -2268,7 +2268,7 @@ struct dentry *cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode,
|
|||
|
||||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
||||
return ERR_PTR(-EIO);
|
||||
return ERR_PTR(smb_EIO(smb_eio_trace_forced_shutdown));
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink))
|
||||
return ERR_CAST(tlink);
|
||||
|
|
@ -2354,7 +2354,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
|
|||
|
||||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
if (unlikely(cifs_forced_shutdown(cifs_sb))) {
|
||||
rc = -EIO;
|
||||
rc = smb_EIO(smb_eio_trace_forced_shutdown);
|
||||
goto rmdir_exit;
|
||||
}
|
||||
|
||||
|
|
@ -2516,7 +2516,7 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
|
|||
|
||||
cifs_sb = CIFS_SB(source_dir->i_sb);
|
||||
if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_forced_shutdown);
|
||||
|
||||
/*
|
||||
* Prevent any concurrent opens on the target by unhashing the dentry.
|
||||
|
|
@ -2901,7 +2901,7 @@ int cifs_getattr(struct mnt_idmap *idmap, const struct path *path,
|
|||
int rc;
|
||||
|
||||
if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb))))
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_forced_shutdown);
|
||||
|
||||
/*
|
||||
* We need to be sure that all dirty pages are written and the server
|
||||
|
|
@ -2976,7 +2976,7 @@ int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start,
|
|||
int rc;
|
||||
|
||||
if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_forced_shutdown);
|
||||
|
||||
/*
|
||||
* We need to be sure that all dirty pages are written as they
|
||||
|
|
@ -3468,7 +3468,7 @@ cifs_setattr(struct mnt_idmap *idmap, struct dentry *direntry,
|
|||
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
|
||||
|
||||
if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_forced_shutdown);
|
||||
/*
|
||||
* Avoid setting [cm]time with O_TRUNC to prevent the server from
|
||||
* disabling automatic timestamp updates as specified in
|
||||
|
|
|
|||
|
|
@ -160,7 +160,8 @@ create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
goto out;
|
||||
|
||||
if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
|
||||
rc = -EIO;
|
||||
rc = smb_EIO2(smb_eio_trace_symlink_file_size,
|
||||
bytes_written, CIFS_MF_SYMLINK_FILE_SIZE);
|
||||
out:
|
||||
kfree(buf);
|
||||
return rc;
|
||||
|
|
@ -424,7 +425,8 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
/* Make sure we wrote all of the symlink data */
|
||||
if ((rc == 0) && (*pbytes_written != CIFS_MF_SYMLINK_FILE_SIZE))
|
||||
rc = -EIO;
|
||||
rc = smb_EIO2(smb_eio_trace_short_symlink_write,
|
||||
*pbytes_written, CIFS_MF_SYMLINK_FILE_SIZE);
|
||||
|
||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
|
||||
|
|
@ -451,7 +453,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
|
|||
struct cifsInodeInfo *cifsInode;
|
||||
|
||||
if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_forced_shutdown);
|
||||
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink))
|
||||
|
|
@ -553,7 +555,7 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
|
|||
struct inode *newinode = NULL;
|
||||
|
||||
if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_forced_shutdown);
|
||||
|
||||
page = alloc_dentry_path();
|
||||
if (!page)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "nterr.h"
|
||||
#include "cifs_unicode.h"
|
||||
#include "smb2pdu.h"
|
||||
#include "smb2proto.h"
|
||||
#include "cifsfs.h"
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
#include "dns_resolve.h"
|
||||
|
|
@ -264,19 +265,18 @@ free_rsp_buf(int resp_buftype, void *rsp)
|
|||
|
||||
/* NB: MID can not be set if treeCon not passed in, in that
|
||||
case it is responsibility of caller to set the mid */
|
||||
void
|
||||
header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
|
||||
unsigned int
|
||||
header_assemble(struct smb_hdr *buffer, char smb_command,
|
||||
const struct cifs_tcon *treeCon, int word_count
|
||||
/* length of fixed section (word count) in two byte units */)
|
||||
{
|
||||
unsigned int in_len;
|
||||
char *temp = (char *) buffer;
|
||||
|
||||
memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */
|
||||
|
||||
buffer->smb_buf_length = cpu_to_be32(
|
||||
(2 * word_count) + sizeof(struct smb_hdr) -
|
||||
4 /* RFC 1001 length field does not count */ +
|
||||
2 /* for bcc field itself */) ;
|
||||
in_len = (2 * word_count) + sizeof(struct smb_hdr) +
|
||||
2 /* for bcc field itself */;
|
||||
|
||||
buffer->Protocol[0] = 0xFF;
|
||||
buffer->Protocol[1] = 'S';
|
||||
|
|
@ -311,7 +311,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
|
|||
|
||||
/* endian conversion of flags is now done just before sending */
|
||||
buffer->WordCount = (char) word_count;
|
||||
return;
|
||||
return in_len;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -346,10 +346,11 @@ check_smb_hdr(struct smb_hdr *smb)
|
|||
}
|
||||
|
||||
int
|
||||
checkSMB(char *buf, unsigned int total_read, struct TCP_Server_Info *server)
|
||||
checkSMB(char *buf, unsigned int pdu_len, unsigned int total_read,
|
||||
struct TCP_Server_Info *server)
|
||||
{
|
||||
struct smb_hdr *smb = (struct smb_hdr *)buf;
|
||||
__u32 rfclen = be32_to_cpu(smb->smb_buf_length);
|
||||
__u32 rfclen = pdu_len;
|
||||
__u32 clc_len; /* calculated length */
|
||||
cifs_dbg(FYI, "checkSMB Length: 0x%x, smb_buf_length: 0x%x\n",
|
||||
total_read, rfclen);
|
||||
|
|
@ -379,42 +380,47 @@ checkSMB(char *buf, unsigned int total_read, struct TCP_Server_Info *server)
|
|||
return 0;
|
||||
}
|
||||
cifs_dbg(VFS, "rcvd invalid byte count (bcc)\n");
|
||||
return smb_EIO1(smb_eio_trace_rx_inv_bcc, tmp[sizeof(struct smb_hdr)]);
|
||||
} else {
|
||||
cifs_dbg(VFS, "Length less than smb header size\n");
|
||||
return smb_EIO2(smb_eio_trace_rx_too_short,
|
||||
total_read, smb->WordCount);
|
||||
}
|
||||
return -EIO;
|
||||
} else if (total_read < sizeof(*smb) + 2 * smb->WordCount) {
|
||||
cifs_dbg(VFS, "%s: can't read BCC due to invalid WordCount(%u)\n",
|
||||
__func__, smb->WordCount);
|
||||
return -EIO;
|
||||
return smb_EIO2(smb_eio_trace_rx_check_rsp,
|
||||
total_read, 2 + sizeof(struct smb_hdr));
|
||||
}
|
||||
|
||||
/* otherwise, there is enough to get to the BCC */
|
||||
if (check_smb_hdr(smb))
|
||||
return -EIO;
|
||||
return smb_EIO1(smb_eio_trace_rx_rfc1002_magic, *(u32 *)smb->Protocol);
|
||||
clc_len = smbCalcSize(smb);
|
||||
|
||||
if (4 + rfclen != total_read) {
|
||||
cifs_dbg(VFS, "Length read does not match RFC1001 length %d\n",
|
||||
rfclen);
|
||||
return -EIO;
|
||||
if (rfclen != total_read) {
|
||||
cifs_dbg(VFS, "Length read does not match RFC1001 length %d/%d\n",
|
||||
rfclen, total_read);
|
||||
return smb_EIO2(smb_eio_trace_rx_check_rsp,
|
||||
total_read, rfclen);
|
||||
}
|
||||
|
||||
if (4 + rfclen != clc_len) {
|
||||
if (rfclen != clc_len) {
|
||||
__u16 mid = get_mid(smb);
|
||||
/* check if bcc wrapped around for large read responses */
|
||||
if ((rfclen > 64 * 1024) && (rfclen > clc_len)) {
|
||||
/* check if lengths match mod 64K */
|
||||
if (((4 + rfclen) & 0xFFFF) == (clc_len & 0xFFFF))
|
||||
if (((rfclen) & 0xFFFF) == (clc_len & 0xFFFF))
|
||||
return 0; /* bcc wrapped */
|
||||
}
|
||||
cifs_dbg(FYI, "Calculated size %u vs length %u mismatch for mid=%u\n",
|
||||
clc_len, 4 + rfclen, mid);
|
||||
clc_len, rfclen, mid);
|
||||
|
||||
if (4 + rfclen < clc_len) {
|
||||
if (rfclen < clc_len) {
|
||||
cifs_dbg(VFS, "RFC1001 size %u smaller than SMB for mid=%u\n",
|
||||
rfclen, mid);
|
||||
return -EIO;
|
||||
return smb_EIO2(smb_eio_trace_rx_calc_len_too_big,
|
||||
rfclen, clc_len);
|
||||
} else if (rfclen > clc_len + 512) {
|
||||
/*
|
||||
* Some servers (Windows XP in particular) send more
|
||||
|
|
@ -427,7 +433,8 @@ checkSMB(char *buf, unsigned int total_read, struct TCP_Server_Info *server)
|
|||
*/
|
||||
cifs_dbg(VFS, "RFC1001 size %u more than 512 bytes larger than SMB for mid=%u\n",
|
||||
rfclen, mid);
|
||||
return -EIO;
|
||||
return smb_EIO2(smb_eio_trace_rx_overlong,
|
||||
rfclen, clc_len + 512);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -451,7 +458,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
|
|||
(struct smb_com_transaction_change_notify_rsp *)buf;
|
||||
struct file_notify_information *pnotify;
|
||||
__u32 data_offset = 0;
|
||||
size_t len = srv->total_read - sizeof(pSMBr->hdr.smb_buf_length);
|
||||
size_t len = srv->total_read - srv->pdu_size;
|
||||
|
||||
if (get_bcc(buf) > sizeof(struct file_notify_information)) {
|
||||
data_offset = le32_to_cpu(pSMBr->DataOffset);
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ cifs_set_port(struct sockaddr *addr, const unsigned short int port)
|
|||
}
|
||||
|
||||
/*****************************************************************************
|
||||
convert a NT status code to a dos class/code
|
||||
*convert a NT status code to a dos class/code
|
||||
*****************************************************************************/
|
||||
/* NT status -> dos error map */
|
||||
static const struct {
|
||||
|
|
@ -885,11 +885,16 @@ map_smb_to_linux_error(char *buf, bool logErr)
|
|||
/* generic corrective action e.g. reconnect SMB session on
|
||||
* ERRbaduid could be added */
|
||||
|
||||
if (rc == -EIO)
|
||||
smb_EIO2(smb_eio_trace_smb1_received_error,
|
||||
le32_to_cpu(smb->Status.CifsError),
|
||||
le16_to_cpu(smb->Flags2));
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
map_and_check_smb_error(struct mid_q_entry *mid, bool logErr)
|
||||
map_and_check_smb_error(struct TCP_Server_Info *server,
|
||||
struct mid_q_entry *mid, bool logErr)
|
||||
{
|
||||
int rc;
|
||||
struct smb_hdr *smb = (struct smb_hdr *)mid->resp_buf;
|
||||
|
|
@ -904,7 +909,7 @@ map_and_check_smb_error(struct mid_q_entry *mid, bool logErr)
|
|||
if (class == ERRSRV && code == ERRbaduid) {
|
||||
cifs_dbg(FYI, "Server returned 0x%x, reconnecting session...\n",
|
||||
code);
|
||||
cifs_signal_cifsd_for_reconnect(mid->server, false);
|
||||
cifs_signal_cifsd_for_reconnect(server, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -775,7 +775,7 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
|
|||
|
||||
if (cfile->srch_inf.ntwrk_buf_start == NULL) {
|
||||
cifs_dbg(VFS, "ntwrk_buf_start is NULL during readdir\n");
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
}
|
||||
|
||||
end_of_smb = cfile->srch_inf.ntwrk_buf_start +
|
||||
|
|
|
|||
|
|
@ -732,7 +732,8 @@ static int parse_reparse_nfs(struct reparse_nfs_data_buffer *buf,
|
|||
len = le16_to_cpu(buf->ReparseDataLength);
|
||||
if (len < sizeof(buf->InodeType)) {
|
||||
cifs_dbg(VFS, "srv returned malformed nfs buffer\n");
|
||||
return -EIO;
|
||||
return smb_EIO2(smb_eio_trace_reparse_nfs_too_short,
|
||||
len, sizeof(buf->InodeType));
|
||||
}
|
||||
|
||||
len -= sizeof(buf->InodeType);
|
||||
|
|
@ -741,7 +742,7 @@ static int parse_reparse_nfs(struct reparse_nfs_data_buffer *buf,
|
|||
case NFS_SPECFILE_LNK:
|
||||
if (len == 0 || (len % 2)) {
|
||||
cifs_dbg(VFS, "srv returned malformed nfs symlink buffer\n");
|
||||
return -EIO;
|
||||
return smb_EIO1(smb_eio_trace_reparse_nfs_symbuf, len);
|
||||
}
|
||||
/*
|
||||
* Check that buffer does not contain UTF-16 null codepoint
|
||||
|
|
@ -749,7 +750,7 @@ static int parse_reparse_nfs(struct reparse_nfs_data_buffer *buf,
|
|||
*/
|
||||
if (UniStrnlen((wchar_t *)buf->DataBuffer, len/2) != len/2) {
|
||||
cifs_dbg(VFS, "srv returned null byte in nfs symlink target location\n");
|
||||
return -EIO;
|
||||
return smb_EIO1(smb_eio_trace_reparse_nfs_nul, len);
|
||||
}
|
||||
data->symlink_target = cifs_strndup_from_utf16(buf->DataBuffer,
|
||||
len, true,
|
||||
|
|
@ -764,7 +765,7 @@ static int parse_reparse_nfs(struct reparse_nfs_data_buffer *buf,
|
|||
/* DataBuffer for block and char devices contains two 32-bit numbers */
|
||||
if (len != 8) {
|
||||
cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type);
|
||||
return -EIO;
|
||||
return smb_EIO1(smb_eio_trace_reparse_nfs_dev, len);
|
||||
}
|
||||
break;
|
||||
case NFS_SPECFILE_FIFO:
|
||||
|
|
@ -772,7 +773,7 @@ static int parse_reparse_nfs(struct reparse_nfs_data_buffer *buf,
|
|||
/* DataBuffer for fifos and sockets is empty */
|
||||
if (len != 0) {
|
||||
cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type);
|
||||
return -EIO;
|
||||
return smb_EIO1(smb_eio_trace_reparse_nfs_sockfifo, len);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
@ -796,13 +797,13 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
|
|||
int abs_path_len;
|
||||
char *abs_path;
|
||||
int levels;
|
||||
int rc;
|
||||
int rc, ulen;
|
||||
int i;
|
||||
|
||||
/* Check that length it valid */
|
||||
if (!len || (len % 2)) {
|
||||
cifs_dbg(VFS, "srv returned malformed symlink buffer\n");
|
||||
rc = -EIO;
|
||||
rc = smb_EIO1(smb_eio_trace_reparse_native_nul, len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -810,9 +811,10 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
|
|||
* Check that buffer does not contain UTF-16 null codepoint
|
||||
* because Linux cannot process symlink with null byte.
|
||||
*/
|
||||
if (UniStrnlen((wchar_t *)buf, len/2) != len/2) {
|
||||
ulen = UniStrnlen((wchar_t *)buf, len/2);
|
||||
if (ulen != len/2) {
|
||||
cifs_dbg(VFS, "srv returned null byte in native symlink target location\n");
|
||||
rc = -EIO;
|
||||
rc = smb_EIO2(smb_eio_trace_reparse_native_nul, ulen, len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -996,7 +998,8 @@ static int parse_reparse_native_symlink(struct reparse_symlink_data_buffer *sym,
|
|||
len = le16_to_cpu(sym->SubstituteNameLength);
|
||||
if (offs + 20 > plen || offs + len + 20 > plen) {
|
||||
cifs_dbg(VFS, "srv returned malformed symlink buffer\n");
|
||||
return -EIO;
|
||||
return smb_EIO2(smb_eio_trace_reparse_native_sym_len,
|
||||
offs << 16 | len, plen);
|
||||
}
|
||||
|
||||
return smb2_parse_native_symlink(&data->symlink_target,
|
||||
|
|
@ -1019,13 +1022,16 @@ static int parse_reparse_wsl_symlink(struct reparse_wsl_symlink_data_buffer *buf
|
|||
|
||||
if (len <= data_offset) {
|
||||
cifs_dbg(VFS, "srv returned malformed wsl symlink buffer\n");
|
||||
return -EIO;
|
||||
return smb_EIO2(smb_eio_trace_reparse_wsl_symbuf,
|
||||
len, data_offset);
|
||||
}
|
||||
|
||||
/* MS-FSCC 2.1.2.7 defines layout of the Target field only for Version 2. */
|
||||
if (le32_to_cpu(buf->Version) != 2) {
|
||||
cifs_dbg(VFS, "srv returned unsupported wsl symlink version %u\n", le32_to_cpu(buf->Version));
|
||||
return -EIO;
|
||||
u32 version = le32_to_cpu(buf->Version);
|
||||
|
||||
if (version != 2) {
|
||||
cifs_dbg(VFS, "srv returned unsupported wsl symlink version %u\n", version);
|
||||
return smb_EIO1(smb_eio_trace_reparse_wsl_ver, version);
|
||||
}
|
||||
|
||||
/* Target for Version 2 is in UTF-8 but without trailing null-term byte */
|
||||
|
|
@ -1034,9 +1040,12 @@ static int parse_reparse_wsl_symlink(struct reparse_wsl_symlink_data_buffer *buf
|
|||
* Check that buffer does not contain null byte
|
||||
* because Linux cannot process symlink with null byte.
|
||||
*/
|
||||
if (strnlen(buf->Target, symname_utf8_len) != symname_utf8_len) {
|
||||
size_t ulen = strnlen(buf->Target, symname_utf8_len);
|
||||
|
||||
if (ulen != symname_utf8_len) {
|
||||
cifs_dbg(VFS, "srv returned null byte in wsl symlink target location\n");
|
||||
return -EIO;
|
||||
return smb_EIO2(smb_eio_trace_reparse_wsl_ver,
|
||||
ulen, symname_utf8_len);
|
||||
}
|
||||
symname_utf16 = kzalloc(symname_utf8_len * 2, GFP_KERNEL);
|
||||
if (!symname_utf16)
|
||||
|
|
@ -1083,13 +1092,17 @@ int parse_reparse_point(struct reparse_data_buffer *buf,
|
|||
case IO_REPARSE_TAG_AF_UNIX:
|
||||
case IO_REPARSE_TAG_LX_FIFO:
|
||||
case IO_REPARSE_TAG_LX_CHR:
|
||||
case IO_REPARSE_TAG_LX_BLK:
|
||||
if (le16_to_cpu(buf->ReparseDataLength) != 0) {
|
||||
case IO_REPARSE_TAG_LX_BLK: {
|
||||
u16 dlen = le16_to_cpu(buf->ReparseDataLength);
|
||||
|
||||
if (dlen != 0) {
|
||||
u32 rtag = le32_to_cpu(buf->ReparseTag);
|
||||
cifs_dbg(VFS, "srv returned malformed buffer for reparse point: 0x%08x\n",
|
||||
le32_to_cpu(buf->ReparseTag));
|
||||
return -EIO;
|
||||
rtag);
|
||||
return smb_EIO2(smb_eio_trace_reparse_data_len, dlen, rtag);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -265,12 +265,16 @@ int cifs_try_adding_channels(struct cifs_ses *ses)
|
|||
}
|
||||
|
||||
/*
|
||||
* called when multichannel is disabled by the server.
|
||||
* this always gets called from smb2_reconnect
|
||||
* and cannot get called in parallel threads.
|
||||
* cifs_decrease_secondary_channels - Reduce the number of active secondary channels
|
||||
* @ses: pointer to the CIFS session structure
|
||||
* @disable_mchan: if true, reduce to a single channel; if false, reduce to chan_max
|
||||
*
|
||||
* This function disables and cleans up extra secondary channels for a CIFS session.
|
||||
* If called during reconfiguration, it reduces the channel count to the new maximum (chan_max).
|
||||
* Otherwise, it disables all but the primary channel.
|
||||
*/
|
||||
void
|
||||
cifs_disable_secondary_channels(struct cifs_ses *ses)
|
||||
cifs_decrease_secondary_channels(struct cifs_ses *ses, bool disable_mchan)
|
||||
{
|
||||
int i, chan_count;
|
||||
struct TCP_Server_Info *server;
|
||||
|
|
@ -281,12 +285,16 @@ cifs_disable_secondary_channels(struct cifs_ses *ses)
|
|||
if (chan_count == 1)
|
||||
goto done;
|
||||
|
||||
ses->chan_count = 1;
|
||||
/* Update the chan_count to the new maximum */
|
||||
if (disable_mchan) {
|
||||
cifs_dbg(FYI, "server does not support multichannel anymore.\n");
|
||||
ses->chan_count = 1;
|
||||
} else {
|
||||
ses->chan_count = ses->chan_max;
|
||||
}
|
||||
|
||||
/* for all secondary channels reset the need reconnect bit */
|
||||
ses->chans_need_reconnect &= 1;
|
||||
|
||||
for (i = 1; i < chan_count; i++) {
|
||||
/* Disable all secondary channels beyond the new chan_count */
|
||||
for (i = ses->chan_count ; i < chan_count; i++) {
|
||||
iface = ses->chans[i].iface;
|
||||
server = ses->chans[i].server;
|
||||
|
||||
|
|
@ -318,6 +326,15 @@ cifs_disable_secondary_channels(struct cifs_ses *ses)
|
|||
spin_lock(&ses->chan_lock);
|
||||
}
|
||||
|
||||
/* For extra secondary channels, reset the need reconnect bit */
|
||||
if (ses->chan_count == 1) {
|
||||
cifs_dbg(VFS, "Disable all secondary channels\n");
|
||||
ses->chans_need_reconnect &= 1;
|
||||
} else {
|
||||
cifs_dbg(VFS, "Disable extra secondary channels\n");
|
||||
ses->chans_need_reconnect &= ((1UL << ses->chan_max) - 1);
|
||||
}
|
||||
|
||||
done:
|
||||
spin_unlock(&ses->chan_lock);
|
||||
}
|
||||
|
|
@ -1313,6 +1330,7 @@ struct sess_data {
|
|||
struct nls_table *nls_cp;
|
||||
void (*func)(struct sess_data *);
|
||||
int result;
|
||||
unsigned int in_len;
|
||||
|
||||
/* we will send the SMB in three pieces:
|
||||
* a fixed length beginning part, an optional
|
||||
|
|
@ -1336,11 +1354,12 @@ sess_alloc_buffer(struct sess_data *sess_data, int wct)
|
|||
rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
|
||||
(void **)&smb_buf);
|
||||
|
||||
if (rc)
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
sess_data->in_len = rc;
|
||||
sess_data->iov[0].iov_base = (char *)smb_buf;
|
||||
sess_data->iov[0].iov_len = be32_to_cpu(smb_buf->smb_buf_length) + 4;
|
||||
sess_data->iov[0].iov_len = sess_data->in_len;
|
||||
/*
|
||||
* This variable will be used to clear the buffer
|
||||
* allocated above in case of any error in the calling function.
|
||||
|
|
@ -1418,7 +1437,7 @@ sess_sendreceive(struct sess_data *sess_data)
|
|||
struct kvec rsp_iov = { NULL, 0 };
|
||||
|
||||
count = sess_data->iov[1].iov_len + sess_data->iov[2].iov_len;
|
||||
be32_add_cpu(&smb_buf->smb_buf_length, count);
|
||||
sess_data->in_len += count;
|
||||
put_bcc(count, smb_buf);
|
||||
|
||||
rc = SendReceive2(sess_data->xid, sess_data->ses,
|
||||
|
|
@ -1501,7 +1520,7 @@ sess_auth_ntlmv2(struct sess_data *sess_data)
|
|||
smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
|
||||
|
||||
if (smb_buf->WordCount != 3) {
|
||||
rc = -EIO;
|
||||
rc = smb_EIO1(smb_eio_trace_sess_nl2_wcc, smb_buf->WordCount);
|
||||
cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1627,7 +1646,7 @@ sess_auth_kerberos(struct sess_data *sess_data)
|
|||
smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
|
||||
|
||||
if (smb_buf->WordCount != 4) {
|
||||
rc = -EIO;
|
||||
rc = smb_EIO1(smb_eio_trace_sess_krb_wcc, smb_buf->WordCount);
|
||||
cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
|
||||
goto out_put_spnego_key;
|
||||
}
|
||||
|
|
@ -1788,7 +1807,7 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data)
|
|||
cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n");
|
||||
|
||||
if (smb_buf->WordCount != 4) {
|
||||
rc = -EIO;
|
||||
rc = smb_EIO1(smb_eio_trace_sess_rawnl_neg_wcc, smb_buf->WordCount);
|
||||
cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
|
||||
goto out_free_ntlmsspblob;
|
||||
}
|
||||
|
|
@ -1878,7 +1897,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
|
|||
pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
|
||||
smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
|
||||
if (smb_buf->WordCount != 4) {
|
||||
rc = -EIO;
|
||||
rc = smb_EIO1(smb_eio_trace_sess_rawnl_auth_wcc, smb_buf->WordCount);
|
||||
cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
|
||||
goto out_free_ntlmsspblob;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,20 +30,25 @@
|
|||
* SMB_COM_NT_CANCEL request and then sends it.
|
||||
*/
|
||||
static int
|
||||
send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
|
||||
struct mid_q_entry *mid)
|
||||
send_nt_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
|
||||
struct smb_rqst *rqst, struct mid_q_entry *mid,
|
||||
unsigned int xid)
|
||||
{
|
||||
int rc = 0;
|
||||
struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
|
||||
struct kvec iov[1];
|
||||
struct smb_rqst crqst = { .rq_iov = iov, .rq_nvec = 1 };
|
||||
int rc = 0;
|
||||
|
||||
/* -4 for RFC1001 length and +2 for BCC field */
|
||||
in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2);
|
||||
/* +2 for BCC field */
|
||||
in_buf->Command = SMB_COM_NT_CANCEL;
|
||||
in_buf->WordCount = 0;
|
||||
put_bcc(0, in_buf);
|
||||
|
||||
iov[0].iov_base = in_buf;
|
||||
iov[0].iov_len = sizeof(struct smb_hdr) + 2;
|
||||
|
||||
cifs_server_lock(server);
|
||||
rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
|
||||
rc = cifs_sign_rqst(&crqst, server, &mid->sequence_number);
|
||||
if (rc) {
|
||||
cifs_server_unlock(server);
|
||||
return rc;
|
||||
|
|
@ -55,7 +60,7 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
|
|||
* after signing here.
|
||||
*/
|
||||
--server->sequence_number;
|
||||
rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
|
||||
rc = __smb_send_rqst(server, 1, &crqst);
|
||||
if (rc < 0)
|
||||
server->sequence_number--;
|
||||
|
||||
|
|
@ -67,6 +72,46 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a LOCKINGX_CANCEL_LOCK to cause the Windows blocking lock to
|
||||
* return.
|
||||
*/
|
||||
static int
|
||||
send_lock_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
|
||||
struct smb_rqst *rqst, struct mid_q_entry *mid,
|
||||
unsigned int xid)
|
||||
{
|
||||
struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
|
||||
unsigned int in_len = rqst->rq_iov[0].iov_len;
|
||||
LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
|
||||
int rc;
|
||||
|
||||
/* We just modify the current in_buf to change
|
||||
* the type of lock from LOCKING_ANDX_SHARED_LOCK
|
||||
* or LOCKING_ANDX_EXCLUSIVE_LOCK to
|
||||
* LOCKING_ANDX_CANCEL_LOCK.
|
||||
*/
|
||||
pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
|
||||
pSMB->Timeout = 0;
|
||||
pSMB->hdr.Mid = get_next_mid(ses->server);
|
||||
|
||||
rc = SendReceive(xid, ses, in_buf, in_len, NULL, NULL, 0);
|
||||
if (rc == -ENOLCK)
|
||||
rc = 0; /* If we get back -ENOLCK, it probably means we managed
|
||||
* to cancel the lock command before it took effect.
|
||||
*/
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cifs_send_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
|
||||
struct smb_rqst *rqst, struct mid_q_entry *mid,
|
||||
unsigned int xid)
|
||||
{
|
||||
if (mid->sr_flags & CIFS_WINDOWS_LOCK)
|
||||
return send_lock_cancel(ses, server, rqst, mid, xid);
|
||||
return send_nt_cancel(ses, server, rqst, mid, xid);
|
||||
}
|
||||
|
||||
static bool
|
||||
cifs_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2)
|
||||
{
|
||||
|
|
@ -101,7 +146,7 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
|
|||
if (compare_mid(mid->mid, buf) &&
|
||||
mid->mid_state == MID_REQUEST_SUBMITTED &&
|
||||
le16_to_cpu(mid->command) == buf->Command) {
|
||||
kref_get(&mid->refcount);
|
||||
smb_get_mid(mid);
|
||||
spin_unlock(&server->mid_queue_lock);
|
||||
return mid;
|
||||
}
|
||||
|
|
@ -289,7 +334,7 @@ check2ndT2(char *buf)
|
|||
}
|
||||
|
||||
static int
|
||||
coalesce_t2(char *second_buf, struct smb_hdr *target_hdr)
|
||||
coalesce_t2(char *second_buf, struct smb_hdr *target_hdr, unsigned int *pdu_len)
|
||||
{
|
||||
struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)second_buf;
|
||||
struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)target_hdr;
|
||||
|
|
@ -355,15 +400,15 @@ coalesce_t2(char *second_buf, struct smb_hdr *target_hdr)
|
|||
}
|
||||
put_bcc(byte_count, target_hdr);
|
||||
|
||||
byte_count = be32_to_cpu(target_hdr->smb_buf_length);
|
||||
byte_count = *pdu_len;
|
||||
byte_count += total_in_src;
|
||||
/* don't allow buffer to overflow */
|
||||
if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||
if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
|
||||
cifs_dbg(FYI, "coalesced BCC exceeds buffer size (%u)\n",
|
||||
byte_count);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
target_hdr->smb_buf_length = cpu_to_be32(byte_count);
|
||||
*pdu_len = byte_count;
|
||||
|
||||
/* copy second buffer into end of first buffer */
|
||||
memcpy(data_area_of_tgt, data_area_of_src, total_in_src);
|
||||
|
|
@ -398,12 +443,12 @@ cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
|
|||
mid->multiRsp = true;
|
||||
if (mid->resp_buf) {
|
||||
/* merge response - fix up 1st*/
|
||||
malformed = coalesce_t2(buf, mid->resp_buf);
|
||||
malformed = coalesce_t2(buf, mid->resp_buf, &mid->response_pdu_len);
|
||||
if (malformed > 0)
|
||||
return true;
|
||||
/* All parts received or packet is malformed. */
|
||||
mid->multiEnd = true;
|
||||
dequeue_mid(mid, malformed);
|
||||
dequeue_mid(server, mid, malformed);
|
||||
return true;
|
||||
}
|
||||
if (!server->large_buf) {
|
||||
|
|
@ -461,7 +506,7 @@ smb1_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
|
|||
if (!(server->capabilities & CAP_LARGE_WRITE_X) ||
|
||||
(!(server->capabilities & CAP_UNIX) && server->sign))
|
||||
wsize = min_t(unsigned int, wsize,
|
||||
server->maxBuf - sizeof(WRITE_REQ) + 4);
|
||||
server->maxBuf - sizeof(WRITE_REQ));
|
||||
|
||||
/* hard limit of CIFS_MAX_WSIZE */
|
||||
wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
|
||||
|
|
@ -1393,7 +1438,7 @@ cifs_is_network_name_deleted(char *buf, struct TCP_Server_Info *server)
|
|||
}
|
||||
|
||||
struct smb_version_operations smb1_operations = {
|
||||
.send_cancel = send_nt_cancel,
|
||||
.send_cancel = cifs_send_cancel,
|
||||
.compare_fids = cifs_compare_fids,
|
||||
.setup_request = cifs_setup_request,
|
||||
.setup_async_request = cifs_setup_async_request,
|
||||
|
|
@ -1487,7 +1532,6 @@ struct smb_version_values smb1_values = {
|
|||
.exclusive_lock_type = 0,
|
||||
.shared_lock_type = LOCKING_ANDX_SHARED_LOCK,
|
||||
.unlock_lock_type = 0,
|
||||
.header_preamble_size = 4,
|
||||
.header_size = sizeof(struct smb_hdr),
|
||||
.max_header_size = MAX_CIFS_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(READ_RSP),
|
||||
|
|
|
|||
|
|
@ -76,11 +76,11 @@ int smb2_fix_symlink_target_type(char **target, bool directory, struct cifs_sb_i
|
|||
return 0;
|
||||
|
||||
if (!*target)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
len = strlen(*target);
|
||||
if (!len)
|
||||
return -EIO;
|
||||
return smb_EIO1(smb_eio_trace_sym_target_len, len);
|
||||
|
||||
/*
|
||||
* If this is directory symlink and it does not have trailing slash then
|
||||
|
|
@ -104,7 +104,7 @@ int smb2_fix_symlink_target_type(char **target, bool directory, struct cifs_sb_i
|
|||
* both Windows and Linux systems. So return an error for such symlink.
|
||||
*/
|
||||
if (!directory && (*target)[len-1] == '/')
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_sym_slash);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -140,7 +140,8 @@ int smb2_parse_symlink_response(struct cifs_sb_info *cifs_sb, const struct kvec
|
|||
cifs_sb);
|
||||
}
|
||||
|
||||
int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock, void *buf)
|
||||
int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
|
||||
__u32 *oplock, void *buf)
|
||||
{
|
||||
int rc;
|
||||
__le16 *smb2_path;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
#include "cifs_unicode.h"
|
||||
#include "fscache.h"
|
||||
#include "smb2glob.h"
|
||||
#include "smb2pdu.h"
|
||||
#include "smb2proto.h"
|
||||
#include "cached_dir.h"
|
||||
#include "../common/smb2status.h"
|
||||
|
|
@ -31,16 +30,20 @@ static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
|
|||
struct reparse_data_buffer *buf;
|
||||
struct smb2_ioctl_rsp *io = iov->iov_base;
|
||||
u32 off, count, len;
|
||||
u16 rdlen;
|
||||
|
||||
count = le32_to_cpu(io->OutputCount);
|
||||
off = le32_to_cpu(io->OutputOffset);
|
||||
if (check_add_overflow(off, count, &len) || len > iov->iov_len)
|
||||
return ERR_PTR(-EIO);
|
||||
return ERR_PTR(smb_EIO2(smb_eio_trace_reparse_overlong,
|
||||
off, count));
|
||||
|
||||
buf = (struct reparse_data_buffer *)((u8 *)io + off);
|
||||
len = sizeof(*buf);
|
||||
if (count < len || count < le16_to_cpu(buf->ReparseDataLength) + len)
|
||||
return ERR_PTR(-EIO);
|
||||
rdlen = le16_to_cpu(buf->ReparseDataLength);
|
||||
|
||||
if (count < len || count < rdlen + len)
|
||||
return ERR_PTR(smb_EIO2(smb_eio_trace_reparse_rdlen, count, rdlen));
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
|
@ -1635,7 +1638,7 @@ int smb2_rename_pending_delete(const char *full_path,
|
|||
} else {
|
||||
cifs_tcon_dbg(FYI, "%s: failed to rename '%s' to '%s': %d\n",
|
||||
__func__, full_path, to_name, rc);
|
||||
rc = -EIO;
|
||||
rc = smb_EIO1(smb_eio_trace_pend_del_fail, rc);
|
||||
}
|
||||
out:
|
||||
cifs_put_tlink(tlink);
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@
|
|||
*/
|
||||
#include <linux/errno.h>
|
||||
#include "cifsglob.h"
|
||||
#include "cifsproto.h"
|
||||
#include "cifs_debug.h"
|
||||
#include "smb2pdu.h"
|
||||
#include "smb2proto.h"
|
||||
#include "../common/smb2status.h"
|
||||
#include "smb2glob.h"
|
||||
#include "../common/smb2status.h"
|
||||
#include "trace.h"
|
||||
|
||||
struct status_to_posix_error {
|
||||
|
|
@ -23,14 +23,13 @@ struct status_to_posix_error {
|
|||
};
|
||||
|
||||
static const struct status_to_posix_error smb2_error_map_table[] = {
|
||||
{STATUS_SUCCESS, 0, "STATUS_SUCCESS"},
|
||||
{STATUS_WAIT_0, 0, "STATUS_WAIT_0"},
|
||||
{STATUS_WAIT_1, -EIO, "STATUS_WAIT_1"},
|
||||
{STATUS_WAIT_2, -EIO, "STATUS_WAIT_2"},
|
||||
{STATUS_WAIT_3, -EIO, "STATUS_WAIT_3"},
|
||||
{STATUS_WAIT_63, -EIO, "STATUS_WAIT_63"},
|
||||
{STATUS_ABANDONED, -EIO, "STATUS_ABANDONED"},
|
||||
{STATUS_ABANDONED_WAIT_0, -EIO, "STATUS_ABANDONED_WAIT_0"},
|
||||
{STATUS_ABANDONED, -EIO, "STATUS_ABANDONED or STATUS_ABANDONED_WAIT_0"},
|
||||
{STATUS_ABANDONED_WAIT_0, -EIO,
|
||||
"STATUS_ABANDONED or STATUS_ABANDONED_WAIT_0"},
|
||||
{STATUS_ABANDONED_WAIT_63, -EIO, "STATUS_ABANDONED_WAIT_63"},
|
||||
{STATUS_USER_APC, -EIO, "STATUS_USER_APC"},
|
||||
{STATUS_KERNEL_APC, -EIO, "STATUS_KERNEL_APC"},
|
||||
|
|
@ -736,6 +735,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
|
|||
{STATUS_FS_DRIVER_REQUIRED, -EOPNOTSUPP, "STATUS_FS_DRIVER_REQUIRED"},
|
||||
{STATUS_IMAGE_ALREADY_LOADED_AS_DLL, -EIO,
|
||||
"STATUS_IMAGE_ALREADY_LOADED_AS_DLL"},
|
||||
{STATUS_INVALID_LOCK_RANGE, -EIO, "STATUS_INVALID_LOCK_RANGE"},
|
||||
{STATUS_NETWORK_OPEN_RESTRICTION, -EIO,
|
||||
"STATUS_NETWORK_OPEN_RESTRICTION"},
|
||||
{STATUS_NO_USER_SESSION_KEY, -EIO, "STATUS_NO_USER_SESSION_KEY"},
|
||||
|
|
@ -2298,8 +2298,9 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
|
|||
{STATUS_FWP_LIFETIME_MISMATCH, -EIO, "STATUS_FWP_LIFETIME_MISMATCH"},
|
||||
{STATUS_FWP_BUILTIN_OBJECT, -EIO, "STATUS_FWP_BUILTIN_OBJECT"},
|
||||
{STATUS_FWP_TOO_MANY_BOOTTIME_FILTERS, -EIO,
|
||||
"STATUS_FWP_TOO_MANY_BOOTTIME_FILTERS"},
|
||||
{STATUS_FWP_TOO_MANY_CALLOUTS, -EIO, "STATUS_FWP_TOO_MANY_CALLOUTS"},
|
||||
"STATUS_FWP_TOO_MANY_BOOTTIME_FILTERS or STATUS_FWP_TOO_MANY_CALLOUTS"},
|
||||
{STATUS_FWP_TOO_MANY_CALLOUTS, -EIO,
|
||||
"STATUS_FWP_TOO_MANY_BOOTTIME_FILTERS or STATUS_FWP_TOO_MANY_CALLOUTS"},
|
||||
{STATUS_FWP_NOTIFICATION_DROPPED, -EIO,
|
||||
"STATUS_FWP_NOTIFICATION_DROPPED"},
|
||||
{STATUS_FWP_TRAFFIC_MISMATCH, -EIO, "STATUS_FWP_TRAFFIC_MISMATCH"},
|
||||
|
|
@ -2415,27 +2416,10 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
|
|||
{STATUS_IPSEC_INTEGRITY_CHECK_FAILED, -EIO,
|
||||
"STATUS_IPSEC_INTEGRITY_CHECK_FAILED"},
|
||||
{STATUS_IPSEC_CLEAR_TEXT_DROP, -EIO, "STATUS_IPSEC_CLEAR_TEXT_DROP"},
|
||||
{0, 0, NULL}
|
||||
{STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP, -EIO,
|
||||
"STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP"},
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
Print an error message from the status code
|
||||
*****************************************************************************/
|
||||
static void
|
||||
smb2_print_status(__le32 status)
|
||||
{
|
||||
int idx = 0;
|
||||
|
||||
while (smb2_error_map_table[idx].status_string != NULL) {
|
||||
if ((smb2_error_map_table[idx].smb2_status) == status) {
|
||||
pr_notice("Status code returned 0x%08x %s\n", status,
|
||||
smb2_error_map_table[idx].status_string);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
map_smb2_to_linux_error(char *buf, bool log_err)
|
||||
{
|
||||
|
|
@ -2452,16 +2436,16 @@ map_smb2_to_linux_error(char *buf, bool log_err)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* mask facility */
|
||||
if (log_err && (smb2err != STATUS_MORE_PROCESSING_REQUIRED) &&
|
||||
(smb2err != STATUS_END_OF_FILE))
|
||||
smb2_print_status(smb2err);
|
||||
else if (cifsFYI & CIFS_RC)
|
||||
smb2_print_status(smb2err);
|
||||
log_err = (log_err && (smb2err != STATUS_MORE_PROCESSING_REQUIRED) &&
|
||||
(smb2err != STATUS_END_OF_FILE)) ||
|
||||
(cifsFYI & CIFS_RC);
|
||||
|
||||
for (i = 0; i < sizeof(smb2_error_map_table) /
|
||||
sizeof(struct status_to_posix_error); i++) {
|
||||
if (smb2_error_map_table[i].smb2_status == smb2err) {
|
||||
if (log_err)
|
||||
pr_notice("Status code returned 0x%08x %s\n", smb2err,
|
||||
smb2_error_map_table[i].status_string);
|
||||
rc = smb2_error_map_table[i].posix_error;
|
||||
break;
|
||||
}
|
||||
|
|
@ -2477,5 +2461,7 @@ map_smb2_to_linux_error(char *buf, bool log_err)
|
|||
le16_to_cpu(shdr->Command),
|
||||
le64_to_cpu(shdr->MessageId),
|
||||
le32_to_cpu(smb2err), rc);
|
||||
if (rc == -EIO)
|
||||
smb_EIO1(smb_eio_trace_smb2_received_error, le32_to_cpu(smb2err));
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,7 +134,8 @@ static __u32 get_neg_ctxt_len(struct smb2_hdr *hdr, __u32 len,
|
|||
}
|
||||
|
||||
int
|
||||
smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
|
||||
smb2_check_message(char *buf, unsigned int pdu_len, unsigned int len,
|
||||
struct TCP_Server_Info *server)
|
||||
{
|
||||
struct TCP_Server_Info *pserver;
|
||||
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@
|
|||
#include <uapi/linux/magic.h>
|
||||
#include "cifsfs.h"
|
||||
#include "cifsglob.h"
|
||||
#include "smb2pdu.h"
|
||||
#include "smb2proto.h"
|
||||
#include "cifsproto.h"
|
||||
#include "smb2proto.h"
|
||||
#include "smb2pdu.h"
|
||||
#include "cifs_debug.h"
|
||||
#include "cifs_unicode.h"
|
||||
#include "../common/smb2status.h"
|
||||
|
|
@ -406,7 +406,7 @@ __smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
|
|||
if ((mid->mid == wire_mid) &&
|
||||
(mid->mid_state == MID_REQUEST_SUBMITTED) &&
|
||||
(mid->command == shdr->Command)) {
|
||||
kref_get(&mid->refcount);
|
||||
smb_get_mid(mid);
|
||||
if (dequeue) {
|
||||
list_del_init(&mid->qhead);
|
||||
mid->deleted_from_q = true;
|
||||
|
|
@ -432,7 +432,7 @@ smb2_find_dequeue_mid(struct TCP_Server_Info *server, char *buf)
|
|||
}
|
||||
|
||||
static void
|
||||
smb2_dump_detail(void *buf, struct TCP_Server_Info *server)
|
||||
smb2_dump_detail(void *buf, size_t buf_len, struct TCP_Server_Info *server)
|
||||
{
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
|
||||
|
|
@ -440,7 +440,7 @@ smb2_dump_detail(void *buf, struct TCP_Server_Info *server)
|
|||
cifs_server_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d\n",
|
||||
shdr->Command, shdr->Status, shdr->Flags, shdr->MessageId,
|
||||
shdr->Id.SyncId.ProcessId);
|
||||
if (!server->ops->check_message(buf, server->total_read, server)) {
|
||||
if (!server->ops->check_message(buf, buf_len, server->total_read, server)) {
|
||||
cifs_server_dbg(VFS, "smb buf %p len %u\n", buf,
|
||||
server->ops->calc_smb_size(buf));
|
||||
}
|
||||
|
|
@ -1046,7 +1046,8 @@ move_smb2_ea_to_cifs(char *dst, size_t dst_size,
|
|||
|
||||
if (src_size < 8 + name_len + 1 + value_len) {
|
||||
cifs_dbg(FYI, "EA entry goes beyond length of list\n");
|
||||
rc = -EIO;
|
||||
rc = smb_EIO2(smb_eio_trace_ea_overrun,
|
||||
src_size, 8 + name_len + 1 + value_len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -1607,7 +1608,7 @@ replay_again:
|
|||
}
|
||||
|
||||
if (!ses || !server) {
|
||||
rc = -EIO;
|
||||
rc = smb_EIO(smb_eio_trace_null_pointers);
|
||||
goto free_vars;
|
||||
}
|
||||
|
||||
|
|
@ -1942,7 +1943,7 @@ retry:
|
|||
if (unlikely(ret_data_len != sizeof(*cc_rsp))) {
|
||||
cifs_tcon_dbg(VFS, "Copychunk invalid response: size %u/%zu\n",
|
||||
ret_data_len, sizeof(*cc_rsp));
|
||||
rc = -EIO;
|
||||
rc = smb_EIO1(smb_eio_trace_copychunk_inv_rsp, ret_data_len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -1952,11 +1953,18 @@ retry:
|
|||
|
||||
if (rc == 0) {
|
||||
/* Check if server claimed to write more than we asked */
|
||||
if (unlikely(!bytes_written || bytes_written > copy_bytes ||
|
||||
!chunks_written || chunks_written > chunks)) {
|
||||
cifs_tcon_dbg(VFS, "Copychunk invalid response: bytes written %u/%u, chunks written %u/%u\n",
|
||||
bytes_written, copy_bytes, chunks_written, chunks);
|
||||
rc = -EIO;
|
||||
if (unlikely(!bytes_written || bytes_written > copy_bytes)) {
|
||||
cifs_tcon_dbg(VFS, "Copychunk invalid response: bytes written %u/%u\n",
|
||||
bytes_written, copy_bytes);
|
||||
rc = smb_EIO2(smb_eio_trace_copychunk_overcopy_b,
|
||||
bytes_written, copy_bytes);
|
||||
goto out;
|
||||
}
|
||||
if (unlikely(!chunks_written || chunks_written > chunks)) {
|
||||
cifs_tcon_dbg(VFS, "Copychunk invalid response: chunks written %u/%u\n",
|
||||
chunks_written, chunks);
|
||||
rc = smb_EIO2(smb_eio_trace_copychunk_overcopy_c,
|
||||
chunks_written, chunks);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -3127,7 +3135,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
|
|||
}
|
||||
|
||||
if (!rc && !dfs_rsp)
|
||||
rc = -EIO;
|
||||
rc = smb_EIO(smb_eio_trace_dfsref_no_rsp);
|
||||
if (rc) {
|
||||
if (!is_retryable_error(rc) && rc != -ENOENT && rc != -EOPNOTSUPP)
|
||||
cifs_tcon_dbg(FYI, "%s: ioctl error: rc=%d\n", __func__, rc);
|
||||
|
|
@ -4555,7 +4563,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
|
|||
buffer, 0, 0, size);
|
||||
|
||||
if (!cifs_copy_iter_to_folioq(&old->rq_iter, size, buffer)) {
|
||||
rc = -EIO;
|
||||
rc = smb_EIO1(smb_eio_trace_tx_copy_iter_to_buf, size);
|
||||
goto err_free;
|
||||
}
|
||||
}
|
||||
|
|
@ -4656,7 +4664,8 @@ cifs_copy_folioq_to_iter(struct folio_queue *folioq, size_t data_size,
|
|||
n = copy_folio_to_iter(folio, skip, len, iter);
|
||||
if (n != len) {
|
||||
cifs_dbg(VFS, "%s: something went wrong\n", __func__);
|
||||
return -EIO;
|
||||
return smb_EIO2(smb_eio_trace_rx_copy_to_iter,
|
||||
n, len);
|
||||
}
|
||||
data_size -= n;
|
||||
skip = 0;
|
||||
|
|
@ -4716,7 +4725,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
|||
if (is_offloaded)
|
||||
mid->mid_state = MID_RESPONSE_RECEIVED;
|
||||
else
|
||||
dequeue_mid(mid, false);
|
||||
dequeue_mid(server, mid, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -4739,11 +4748,11 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
|||
/* data_offset is beyond the end of smallbuf */
|
||||
cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
|
||||
__func__, data_offset);
|
||||
rdata->result = -EIO;
|
||||
rdata->result = smb_EIO1(smb_eio_trace_rx_overlong, data_offset);
|
||||
if (is_offloaded)
|
||||
mid->mid_state = MID_RESPONSE_MALFORMED;
|
||||
else
|
||||
dequeue_mid(mid, rdata->result);
|
||||
dequeue_mid(server, mid, rdata->result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -4758,21 +4767,21 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
|||
/* data offset is beyond the 1st page of response */
|
||||
cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n",
|
||||
__func__, data_offset);
|
||||
rdata->result = -EIO;
|
||||
rdata->result = smb_EIO1(smb_eio_trace_rx_overpage, data_offset);
|
||||
if (is_offloaded)
|
||||
mid->mid_state = MID_RESPONSE_MALFORMED;
|
||||
else
|
||||
dequeue_mid(mid, rdata->result);
|
||||
dequeue_mid(server, mid, rdata->result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data_len > buffer_len - pad_len) {
|
||||
/* data_len is corrupt -- discard frame */
|
||||
rdata->result = -EIO;
|
||||
rdata->result = smb_EIO1(smb_eio_trace_rx_bad_datalen, data_len);
|
||||
if (is_offloaded)
|
||||
mid->mid_state = MID_RESPONSE_MALFORMED;
|
||||
else
|
||||
dequeue_mid(mid, rdata->result);
|
||||
dequeue_mid(server, mid, rdata->result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -4783,7 +4792,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
|||
if (is_offloaded)
|
||||
mid->mid_state = MID_RESPONSE_MALFORMED;
|
||||
else
|
||||
dequeue_mid(mid, rdata->result);
|
||||
dequeue_mid(server, mid, rdata->result);
|
||||
return 0;
|
||||
}
|
||||
rdata->got_bytes = buffer_len;
|
||||
|
|
@ -4793,23 +4802,23 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
|||
WARN_ONCE(buffer, "read data can be either in buf or in buffer");
|
||||
copied = copy_to_iter(buf + data_offset, data_len, &rdata->subreq.io_iter);
|
||||
if (copied == 0)
|
||||
return -EIO;
|
||||
return smb_EIO2(smb_eio_trace_rx_copy_to_iter, copied, data_len);
|
||||
rdata->got_bytes = copied;
|
||||
} else {
|
||||
/* read response payload cannot be in both buf and pages */
|
||||
WARN_ONCE(1, "buf can not contain only a part of read data");
|
||||
rdata->result = -EIO;
|
||||
rdata->result = smb_EIO(smb_eio_trace_rx_both_buf);
|
||||
if (is_offloaded)
|
||||
mid->mid_state = MID_RESPONSE_MALFORMED;
|
||||
else
|
||||
dequeue_mid(mid, rdata->result);
|
||||
dequeue_mid(server, mid, rdata->result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_offloaded)
|
||||
mid->mid_state = MID_RESPONSE_RECEIVED;
|
||||
else
|
||||
dequeue_mid(mid, false);
|
||||
dequeue_mid(server, mid, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -4856,7 +4865,7 @@ static void smb2_decrypt_offload(struct work_struct *work)
|
|||
dw->server->ops->is_network_name_deleted(dw->buf,
|
||||
dw->server);
|
||||
|
||||
mid_execute_callback(mid);
|
||||
mid_execute_callback(dw->server, mid);
|
||||
} else {
|
||||
spin_lock(&dw->server->srv_lock);
|
||||
if (dw->server->tcpStatus == CifsNeedReconnect) {
|
||||
|
|
@ -4864,7 +4873,7 @@ static void smb2_decrypt_offload(struct work_struct *work)
|
|||
mid->mid_state = MID_RETRY_NEEDED;
|
||||
spin_unlock(&dw->server->mid_queue_lock);
|
||||
spin_unlock(&dw->server->srv_lock);
|
||||
mid_execute_callback(mid);
|
||||
mid_execute_callback(dw->server, mid);
|
||||
} else {
|
||||
spin_lock(&dw->server->mid_queue_lock);
|
||||
mid->mid_state = MID_REQUEST_SUBMITTED;
|
||||
|
|
@ -4875,7 +4884,7 @@ static void smb2_decrypt_offload(struct work_struct *work)
|
|||
spin_unlock(&dw->server->srv_lock);
|
||||
}
|
||||
}
|
||||
release_mid(mid);
|
||||
release_mid(dw->server, mid);
|
||||
}
|
||||
|
||||
free_pages:
|
||||
|
|
@ -5767,7 +5776,6 @@ struct smb_version_values smb20_values = {
|
|||
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 0,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp),
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
|
@ -5789,7 +5797,6 @@ struct smb_version_values smb21_values = {
|
|||
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 0,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp),
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
|
@ -5810,7 +5817,6 @@ struct smb_version_values smb3any_values = {
|
|||
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 0,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp),
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
|
@ -5831,7 +5837,6 @@ struct smb_version_values smbdefault_values = {
|
|||
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 0,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp),
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
|
@ -5852,7 +5857,6 @@ struct smb_version_values smb30_values = {
|
|||
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 0,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp),
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
|
@ -5873,7 +5877,6 @@ struct smb_version_values smb302_values = {
|
|||
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 0,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp),
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
|
@ -5894,7 +5897,6 @@ struct smb_version_values smb311_values = {
|
|||
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
|
||||
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
||||
.header_size = sizeof(struct smb2_hdr),
|
||||
.header_preamble_size = 0,
|
||||
.max_header_size = MAX_SMB2_HDR_SIZE,
|
||||
.read_rsp_size = sizeof(struct smb2_read_rsp),
|
||||
.lock_cmd = SMB2_LOCK,
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@
|
|||
#include <linux/netfs.h>
|
||||
#include <trace/events/netfs.h>
|
||||
#include "cifsglob.h"
|
||||
#include "cifsacl.h"
|
||||
#include "cifsproto.h"
|
||||
#include "cifsacl.h"
|
||||
#include "smb2proto.h"
|
||||
#include "cifs_unicode.h"
|
||||
#include "cifs_debug.h"
|
||||
|
|
@ -168,7 +168,7 @@ out:
|
|||
static int
|
||||
cifs_chan_skip_or_disable(struct cifs_ses *ses,
|
||||
struct TCP_Server_Info *server,
|
||||
bool from_reconnect)
|
||||
bool from_reconnect, bool disable_mchan)
|
||||
{
|
||||
struct TCP_Server_Info *pserver;
|
||||
unsigned int chan_index;
|
||||
|
|
@ -206,14 +206,46 @@ skip_terminate:
|
|||
return -EHOSTDOWN;
|
||||
}
|
||||
|
||||
cifs_server_dbg(VFS,
|
||||
"server does not support multichannel anymore. Disable all other channels\n");
|
||||
cifs_disable_secondary_channels(ses);
|
||||
|
||||
cifs_decrease_secondary_channels(ses, disable_mchan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* smb3_update_ses_channels - Synchronize session channels with new configuration
|
||||
* @ses: pointer to the CIFS session structure
|
||||
* @server: pointer to the TCP server info structure
|
||||
* @from_reconnect: indicates if called from reconnect context
|
||||
* @disable_mchan: indicates if called from reconnect to disable multichannel
|
||||
*
|
||||
* Returns 0 on success or error code on failure.
|
||||
*
|
||||
* Outside of reconfigure, this function is called from cifs_mount() during mount
|
||||
* and from reconnect scenarios to adjust channel count when the
|
||||
* server's multichannel support changes.
|
||||
*/
|
||||
int smb3_update_ses_channels(struct cifs_ses *ses, struct TCP_Server_Info *server,
|
||||
bool from_reconnect, bool disable_mchan)
|
||||
{
|
||||
int rc = 0;
|
||||
/*
|
||||
* Manage session channels based on current count vs max:
|
||||
* - If disable requested, skip or disable the channel
|
||||
* - If below max channels, attempt to add more
|
||||
* - If above max channels, skip or disable excess channels
|
||||
*/
|
||||
if (disable_mchan)
|
||||
rc = cifs_chan_skip_or_disable(ses, server, from_reconnect, disable_mchan);
|
||||
else {
|
||||
if (ses->chan_count < ses->chan_max)
|
||||
rc = cifs_try_adding_channels(ses);
|
||||
else if (ses->chan_count > ses->chan_max)
|
||||
rc = cifs_chan_skip_or_disable(ses, server, from_reconnect, disable_mchan);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
||||
struct TCP_Server_Info *server, bool from_reconnect)
|
||||
|
|
@ -249,15 +281,15 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
|||
|
||||
ses = tcon->ses;
|
||||
if (!ses)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
spin_lock(&ses->ses_lock);
|
||||
if (ses->ses_status == SES_EXITING) {
|
||||
spin_unlock(&ses->ses_lock);
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_sess_exiting);
|
||||
}
|
||||
spin_unlock(&ses->ses_lock);
|
||||
if (!ses->server || !server)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
spin_lock(&server->srv_lock);
|
||||
if (server->tcpStatus == CifsNeedReconnect) {
|
||||
|
|
@ -355,8 +387,8 @@ again:
|
|||
*/
|
||||
if (ses->chan_count > 1 &&
|
||||
!(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
|
||||
rc = cifs_chan_skip_or_disable(ses, server,
|
||||
from_reconnect);
|
||||
rc = smb3_update_ses_channels(ses, server,
|
||||
from_reconnect, true /* disable_mchan */);
|
||||
if (rc) {
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
goto out;
|
||||
|
|
@ -438,8 +470,9 @@ skip_sess_setup:
|
|||
* treat this as server not supporting multichannel
|
||||
*/
|
||||
|
||||
rc = cifs_chan_skip_or_disable(ses, server,
|
||||
from_reconnect);
|
||||
rc = smb3_update_ses_channels(ses, server,
|
||||
from_reconnect,
|
||||
true /* disable_mchan */);
|
||||
goto skip_add_channels;
|
||||
} else if (rc)
|
||||
cifs_tcon_dbg(FYI, "%s: failed to query server interfaces: %d\n",
|
||||
|
|
@ -451,7 +484,8 @@ skip_sess_setup:
|
|||
if (ses->chan_count == 1)
|
||||
cifs_server_dbg(VFS, "supports multichannel now\n");
|
||||
|
||||
cifs_try_adding_channels(ses);
|
||||
smb3_update_ses_channels(ses, server, from_reconnect,
|
||||
false /* disable_mchan */);
|
||||
}
|
||||
} else {
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
|
|
@ -463,7 +497,7 @@ skip_add_channels:
|
|||
spin_unlock(&ses->ses_lock);
|
||||
|
||||
if (smb2_command != SMB2_INTERNAL_CMD)
|
||||
mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
|
||||
cifs_queue_server_reconn(server);
|
||||
|
||||
atomic_inc(&tconInfoReconnectCount);
|
||||
out:
|
||||
|
|
@ -1061,7 +1095,7 @@ SMB2_negotiate(const unsigned int xid,
|
|||
|
||||
if (!server) {
|
||||
WARN(1, "%s: server is NULL!\n", __func__);
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
}
|
||||
|
||||
rc = smb2_plain_req_init(SMB2_NEGOTIATE, NULL, server,
|
||||
|
|
@ -1105,8 +1139,7 @@ SMB2_negotiate(const unsigned int xid,
|
|||
req->SecurityMode = 0;
|
||||
|
||||
req->Capabilities = cpu_to_le32(server->vals->req_capabilities);
|
||||
if (ses->chan_max > 1)
|
||||
req->Capabilities |= cpu_to_le32(SMB2_GLOBAL_CAP_MULTI_CHANNEL);
|
||||
req->Capabilities |= cpu_to_le32(SMB2_GLOBAL_CAP_MULTI_CHANNEL);
|
||||
|
||||
/* ClientGUID must be zero for SMB2.02 dialect */
|
||||
if (server->vals->protocol_id == SMB20_PROT_ID)
|
||||
|
|
@ -1142,64 +1175,84 @@ SMB2_negotiate(const unsigned int xid,
|
|||
} else if (rc != 0)
|
||||
goto neg_exit;
|
||||
|
||||
rc = -EIO;
|
||||
u16 dialect = le16_to_cpu(rsp->DialectRevision);
|
||||
if (strcmp(server->vals->version_string,
|
||||
SMB3ANY_VERSION_STRING) == 0) {
|
||||
if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) {
|
||||
switch (dialect) {
|
||||
case SMB20_PROT_ID:
|
||||
cifs_server_dbg(VFS,
|
||||
"SMB2 dialect returned but not requested\n");
|
||||
rc = smb_EIO2(smb_eio_trace_neg_unreq_dialect, dialect, 3);
|
||||
goto neg_exit;
|
||||
} else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) {
|
||||
case SMB21_PROT_ID:
|
||||
cifs_server_dbg(VFS,
|
||||
"SMB2.1 dialect returned but not requested\n");
|
||||
rc = smb_EIO2(smb_eio_trace_neg_unreq_dialect, dialect, 3);
|
||||
goto neg_exit;
|
||||
} else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
|
||||
case SMB311_PROT_ID:
|
||||
/* ops set to 3.0 by default for default so update */
|
||||
server->ops = &smb311_operations;
|
||||
server->vals = &smb311_values;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (strcmp(server->vals->version_string,
|
||||
SMBDEFAULT_VERSION_STRING) == 0) {
|
||||
if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) {
|
||||
SMBDEFAULT_VERSION_STRING) == 0) {
|
||||
switch (dialect) {
|
||||
case SMB20_PROT_ID:
|
||||
cifs_server_dbg(VFS,
|
||||
"SMB2 dialect returned but not requested\n");
|
||||
rc = smb_EIO2(smb_eio_trace_neg_unreq_dialect, dialect, 0);
|
||||
goto neg_exit;
|
||||
} else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) {
|
||||
case SMB21_PROT_ID:
|
||||
/* ops set to 3.0 by default for default so update */
|
||||
server->ops = &smb21_operations;
|
||||
server->vals = &smb21_values;
|
||||
} else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
|
||||
break;
|
||||
case SMB311_PROT_ID:
|
||||
server->ops = &smb311_operations;
|
||||
server->vals = &smb311_values;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (le16_to_cpu(rsp->DialectRevision) !=
|
||||
server->vals->protocol_id) {
|
||||
} else if (dialect != server->vals->protocol_id) {
|
||||
/* if requested single dialect ensure returned dialect matched */
|
||||
cifs_server_dbg(VFS, "Invalid 0x%x dialect returned: not requested\n",
|
||||
le16_to_cpu(rsp->DialectRevision));
|
||||
dialect);
|
||||
rc = smb_EIO2(smb_eio_trace_neg_unreq_dialect,
|
||||
dialect, server->vals->protocol_id);
|
||||
goto neg_exit;
|
||||
}
|
||||
|
||||
cifs_dbg(FYI, "mode 0x%x\n", rsp->SecurityMode);
|
||||
|
||||
if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID))
|
||||
switch (dialect) {
|
||||
case SMB20_PROT_ID:
|
||||
cifs_dbg(FYI, "negotiated smb2.0 dialect\n");
|
||||
else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID))
|
||||
break;
|
||||
case SMB21_PROT_ID:
|
||||
cifs_dbg(FYI, "negotiated smb2.1 dialect\n");
|
||||
else if (rsp->DialectRevision == cpu_to_le16(SMB30_PROT_ID))
|
||||
break;
|
||||
case SMB30_PROT_ID:
|
||||
cifs_dbg(FYI, "negotiated smb3.0 dialect\n");
|
||||
else if (rsp->DialectRevision == cpu_to_le16(SMB302_PROT_ID))
|
||||
break;
|
||||
case SMB302_PROT_ID:
|
||||
cifs_dbg(FYI, "negotiated smb3.02 dialect\n");
|
||||
else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID))
|
||||
break;
|
||||
case SMB311_PROT_ID:
|
||||
cifs_dbg(FYI, "negotiated smb3.1.1 dialect\n");
|
||||
else {
|
||||
break;
|
||||
default:
|
||||
cifs_server_dbg(VFS, "Invalid dialect returned by server 0x%x\n",
|
||||
le16_to_cpu(rsp->DialectRevision));
|
||||
dialect);
|
||||
rc = smb_EIO1(smb_eio_trace_neg_inval_dialect, dialect);
|
||||
goto neg_exit;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
server->dialect = le16_to_cpu(rsp->DialectRevision);
|
||||
server->dialect = dialect;
|
||||
|
||||
/*
|
||||
* Keep a copy of the hash after negprot. This hash will be
|
||||
|
|
@ -1255,10 +1308,10 @@ SMB2_negotiate(const unsigned int xid,
|
|||
if (rc == 1)
|
||||
rc = 0;
|
||||
else if (rc == 0)
|
||||
rc = -EIO;
|
||||
rc = smb_EIO1(smb_eio_trace_neg_decode_token, rc);
|
||||
}
|
||||
|
||||
if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
|
||||
if (server->dialect == SMB311_PROT_ID) {
|
||||
if (rsp->NegotiateContextCount)
|
||||
rc = smb311_decode_neg_context(rsp, server,
|
||||
rsp_iov.iov_len);
|
||||
|
|
@ -1312,8 +1365,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
|
|||
|
||||
pneg_inbuf->Capabilities =
|
||||
cpu_to_le32(server->vals->req_capabilities);
|
||||
if (tcon->ses->chan_max > 1)
|
||||
pneg_inbuf->Capabilities |= cpu_to_le32(SMB2_GLOBAL_CAP_MULTI_CHANNEL);
|
||||
pneg_inbuf->Capabilities |= cpu_to_le32(SMB2_GLOBAL_CAP_MULTI_CHANNEL);
|
||||
|
||||
memcpy(pneg_inbuf->Guid, server->client_guid,
|
||||
SMB2_CLIENT_GUID_SIZE);
|
||||
|
|
@ -1371,32 +1423,47 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
|
|||
} else if (rc != 0) {
|
||||
cifs_tcon_dbg(VFS, "validate protocol negotiate failed: %d\n",
|
||||
rc);
|
||||
rc = -EIO;
|
||||
rc = smb_EIO1(smb_eio_trace_neg_info_fail, rc);
|
||||
goto out_free_inbuf;
|
||||
}
|
||||
|
||||
rc = -EIO;
|
||||
if (rsplen != sizeof(*pneg_rsp)) {
|
||||
cifs_tcon_dbg(VFS, "Invalid protocol negotiate response size: %d\n",
|
||||
rsplen);
|
||||
|
||||
/* relax check since Mac returns max bufsize allowed on ioctl */
|
||||
if (rsplen > CIFSMaxBufSize || rsplen < sizeof(*pneg_rsp))
|
||||
if (rsplen > CIFSMaxBufSize || rsplen < sizeof(*pneg_rsp)) {
|
||||
rc = smb_EIO1(smb_eio_trace_neg_bad_rsplen, rsplen);
|
||||
goto out_free_rsp;
|
||||
}
|
||||
}
|
||||
|
||||
/* check validate negotiate info response matches what we got earlier */
|
||||
if (pneg_rsp->Dialect != cpu_to_le16(server->dialect))
|
||||
goto vneg_out;
|
||||
u16 dialect = le16_to_cpu(pneg_rsp->Dialect);
|
||||
|
||||
if (pneg_rsp->SecurityMode != cpu_to_le16(server->sec_mode))
|
||||
if (dialect != server->dialect) {
|
||||
rc = smb_EIO2(smb_eio_trace_neg_info_dialect,
|
||||
dialect, server->dialect);
|
||||
goto vneg_out;
|
||||
}
|
||||
|
||||
u16 sec_mode = le16_to_cpu(pneg_rsp->SecurityMode);
|
||||
|
||||
if (sec_mode != server->sec_mode) {
|
||||
rc = smb_EIO2(smb_eio_trace_neg_info_sec_mode,
|
||||
sec_mode, server->sec_mode);
|
||||
goto vneg_out;
|
||||
}
|
||||
|
||||
/* do not validate server guid because not saved at negprot time yet */
|
||||
u32 caps = le32_to_cpu(pneg_rsp->Capabilities);
|
||||
|
||||
if ((le32_to_cpu(pneg_rsp->Capabilities) | SMB2_NT_FIND |
|
||||
SMB2_LARGE_FILES) != server->capabilities)
|
||||
if ((caps | SMB2_NT_FIND |
|
||||
SMB2_LARGE_FILES) != server->capabilities) {
|
||||
rc = smb_EIO2(smb_eio_trace_neg_info_caps,
|
||||
caps, server->capabilities);
|
||||
goto vneg_out;
|
||||
}
|
||||
|
||||
/* validate negotiate successful */
|
||||
rc = 0;
|
||||
|
|
@ -1628,8 +1695,6 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
|
|||
spnego_key = cifs_get_spnego_key(ses, server);
|
||||
if (IS_ERR(spnego_key)) {
|
||||
rc = PTR_ERR(spnego_key);
|
||||
if (rc == -ENOKEY)
|
||||
cifs_dbg(VFS, "Verify user has a krb5 ticket and keyutils is installed\n");
|
||||
spnego_key = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1758,11 +1823,11 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
|
|||
if (rc)
|
||||
goto out;
|
||||
|
||||
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));
|
||||
rc = -EIO;
|
||||
u16 boff = le16_to_cpu(rsp->SecurityBufferOffset);
|
||||
|
||||
if (offsetof(struct smb2_sess_setup_rsp, Buffer) != boff) {
|
||||
cifs_dbg(VFS, "Invalid security buffer offset %d\n", boff);
|
||||
rc = smb_EIO1(smb_eio_trace_sess_buf_off, boff);
|
||||
goto out;
|
||||
}
|
||||
rc = decode_ntlmssp_challenge(rsp->Buffer,
|
||||
|
|
@ -1916,7 +1981,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
|
|||
|
||||
if (!server) {
|
||||
WARN(1, "%s: server is NULL!\n", __func__);
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
}
|
||||
|
||||
sess_data = kzalloc(sizeof(struct SMB2_sess_data), GFP_KERNEL);
|
||||
|
|
@ -1966,10 +2031,9 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
|
|||
|
||||
cifs_dbg(FYI, "disconnect session %p\n", ses);
|
||||
|
||||
if (ses && (ses->server))
|
||||
server = ses->server;
|
||||
else
|
||||
return -EIO;
|
||||
if (!ses || !ses->server)
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
server = ses->server;
|
||||
|
||||
/* no need to send SMB logoff if uid already closed due to reconnect */
|
||||
spin_lock(&ses->chan_lock);
|
||||
|
|
@ -2048,7 +2112,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
|
|||
cifs_dbg(FYI, "TCON\n");
|
||||
|
||||
if (!server || !tree)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL);
|
||||
if (unc_path == NULL)
|
||||
|
|
@ -2186,7 +2250,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
|
|||
cifs_dbg(FYI, "Tree Disconnect\n");
|
||||
|
||||
if (!ses || !(ses->server))
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
trace_smb3_tdis_enter(xid, tcon->tid, ses->Suid, tcon->tree_name);
|
||||
spin_lock(&ses->chan_lock);
|
||||
|
|
@ -2856,7 +2920,7 @@ replay_again:
|
|||
return -ENOMEM;
|
||||
|
||||
if (!ses || !server) {
|
||||
rc = -EIO;
|
||||
rc = smb_EIO(smb_eio_trace_null_pointers);
|
||||
goto err_free_path;
|
||||
}
|
||||
|
||||
|
|
@ -2973,7 +3037,7 @@ replay_again:
|
|||
*/
|
||||
rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
|
||||
if (rsp == NULL) {
|
||||
rc = -EIO;
|
||||
rc = smb_EIO(smb_eio_trace_mkdir_no_rsp);
|
||||
kfree(pc_buf);
|
||||
goto err_free_req;
|
||||
}
|
||||
|
|
@ -3211,7 +3275,7 @@ replay_again:
|
|||
|
||||
cifs_dbg(FYI, "create/open\n");
|
||||
if (!ses || !server)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
|
@ -3417,11 +3481,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
|||
int retries = 0, cur_sleep = 1;
|
||||
|
||||
if (!tcon)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
ses = tcon->ses;
|
||||
if (!ses)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
replay_again:
|
||||
/* reinitialize for possible replay */
|
||||
|
|
@ -3429,7 +3493,7 @@ replay_again:
|
|||
server = cifs_pick_channel(ses);
|
||||
|
||||
if (!server)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
cifs_dbg(FYI, "SMB2 IOCTL\n");
|
||||
|
||||
|
|
@ -3492,7 +3556,7 @@ replay_again:
|
|||
* warning)
|
||||
*/
|
||||
if (rsp == NULL) {
|
||||
rc = -EIO;
|
||||
rc = smb_EIO(smb_eio_trace_ioctl_no_rsp);
|
||||
goto ioctl_exit;
|
||||
}
|
||||
|
||||
|
|
@ -3503,16 +3567,18 @@ replay_again:
|
|||
goto ioctl_exit; /* server returned no data */
|
||||
else if (*plen > rsp_iov.iov_len || *plen > 0xFF00) {
|
||||
cifs_tcon_dbg(VFS, "srv returned invalid ioctl length: %d\n", *plen);
|
||||
rc = smb_EIO2(smb_eio_trace_ioctl_data_len, *plen, rsp_iov.iov_len);
|
||||
*plen = 0;
|
||||
rc = -EIO;
|
||||
goto ioctl_exit;
|
||||
}
|
||||
|
||||
if (rsp_iov.iov_len - *plen < le32_to_cpu(rsp->OutputOffset)) {
|
||||
cifs_tcon_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n", *plen,
|
||||
le32_to_cpu(rsp->OutputOffset));
|
||||
u32 outoff = le32_to_cpu(rsp->OutputOffset);
|
||||
|
||||
if (rsp_iov.iov_len - *plen < outoff) {
|
||||
cifs_tcon_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n",
|
||||
*plen, outoff);
|
||||
rc = smb_EIO2(smb_eio_trace_ioctl_out_off, rsp_iov.iov_len - *plen, outoff);
|
||||
*plen = 0;
|
||||
rc = -EIO;
|
||||
goto ioctl_exit;
|
||||
}
|
||||
|
||||
|
|
@ -3620,7 +3686,7 @@ replay_again:
|
|||
cifs_dbg(FYI, "Close\n");
|
||||
|
||||
if (!ses || !server)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
|
@ -3817,7 +3883,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
cifs_dbg(FYI, "Query Info\n");
|
||||
|
||||
if (!ses)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
replay_again:
|
||||
/* reinitialize for possible replay */
|
||||
|
|
@ -3826,7 +3892,7 @@ replay_again:
|
|||
server = cifs_pick_channel(ses);
|
||||
|
||||
if (!server)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
|
@ -3913,7 +3979,8 @@ int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
/* currently unused, as now we are doing compounding instead (see smb311_posix_query_path_info) */
|
||||
int
|
||||
SMB311_posix_query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, struct smb311_posix_qinfo *data, u32 *plen)
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
struct smb311_posix_qinfo *data, u32 *plen)
|
||||
{
|
||||
size_t output_len = sizeof(struct smb311_posix_qinfo *) +
|
||||
(sizeof(struct smb_sid) * 2) + (PATH_MAX * 2);
|
||||
|
|
@ -4011,7 +4078,7 @@ replay_again:
|
|||
|
||||
cifs_dbg(FYI, "change notify\n");
|
||||
if (!ses || !server)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
|
@ -4091,9 +4158,8 @@ replay_again:
|
|||
* FIXME: maybe we should consider checking that the reply matches request?
|
||||
*/
|
||||
static void
|
||||
smb2_echo_callback(struct mid_q_entry *mid)
|
||||
smb2_echo_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
{
|
||||
struct TCP_Server_Info *server = mid->callback_data;
|
||||
struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)mid->resp_buf;
|
||||
struct cifs_credits credits = { .value = 0, .instance = 0 };
|
||||
|
||||
|
|
@ -4103,7 +4169,7 @@ smb2_echo_callback(struct mid_q_entry *mid)
|
|||
credits.instance = server->reconnect_instance;
|
||||
}
|
||||
|
||||
release_mid(mid);
|
||||
release_mid(server, mid);
|
||||
add_credits(server, &credits, CIFS_ECHO_OP);
|
||||
}
|
||||
|
||||
|
|
@ -4248,7 +4314,7 @@ void smb2_reconnect_server(struct work_struct *work)
|
|||
done:
|
||||
cifs_dbg(FYI, "Reconnecting tcons and channels finished\n");
|
||||
if (resched)
|
||||
queue_delayed_work(cifsiod_wq, &server->reconnect, 2 * HZ);
|
||||
cifs_requeue_server_reconn(server);
|
||||
mutex_unlock(&pserver->reconnect_mutex);
|
||||
|
||||
/* now we can safely release srv struct */
|
||||
|
|
@ -4272,7 +4338,7 @@ SMB2_echo(struct TCP_Server_Info *server)
|
|||
server->ops->need_neg(server)) {
|
||||
spin_unlock(&server->srv_lock);
|
||||
/* No need to send echo on newly established connections */
|
||||
mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
|
||||
cifs_queue_server_reconn(server);
|
||||
return rc;
|
||||
}
|
||||
spin_unlock(&server->srv_lock);
|
||||
|
|
@ -4348,7 +4414,7 @@ replay_again:
|
|||
|
||||
cifs_dbg(FYI, "flush\n");
|
||||
if (!ses || !(ses->server))
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
|
@ -4518,21 +4584,19 @@ smb2_new_read_req(void **buf, unsigned int *total_len,
|
|||
}
|
||||
|
||||
static void
|
||||
smb2_readv_callback(struct mid_q_entry *mid)
|
||||
smb2_readv_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
{
|
||||
struct cifs_io_subrequest *rdata = mid->callback_data;
|
||||
struct netfs_inode *ictx = netfs_inode(rdata->rreq->inode);
|
||||
struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink);
|
||||
struct TCP_Server_Info *server = rdata->server;
|
||||
struct smb2_hdr *shdr =
|
||||
(struct smb2_hdr *)rdata->iov[0].iov_base;
|
||||
struct smb2_hdr *shdr = (struct smb2_hdr *)rdata->iov[0].iov_base;
|
||||
struct cifs_credits credits = {
|
||||
.value = 0,
|
||||
.instance = 0,
|
||||
.rreq_debug_id = rdata->rreq->debug_id,
|
||||
.rreq_debug_index = rdata->subreq.debug_index,
|
||||
};
|
||||
struct smb_rqst rqst = { .rq_iov = &rdata->iov[1], .rq_nvec = 1 };
|
||||
struct smb_rqst rqst = { .rq_iov = &rdata->iov[0], .rq_nvec = 1 };
|
||||
unsigned int rreq_debug_id = rdata->rreq->debug_id;
|
||||
unsigned int subreq_debug_index = rdata->subreq.debug_index;
|
||||
|
||||
|
|
@ -4540,9 +4604,9 @@ smb2_readv_callback(struct mid_q_entry *mid)
|
|||
rqst.rq_iter = rdata->subreq.io_iter;
|
||||
}
|
||||
|
||||
WARN_ONCE(rdata->server != mid->server,
|
||||
WARN_ONCE(rdata->server != server,
|
||||
"rdata server %p != mid server %p",
|
||||
rdata->server, mid->server);
|
||||
rdata->server, server);
|
||||
|
||||
cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu/%zu\n",
|
||||
__func__, mid->mid, mid->mid_state, rdata->result,
|
||||
|
|
@ -4585,11 +4649,12 @@ do_retry:
|
|||
trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_malformed);
|
||||
credits.value = le16_to_cpu(shdr->CreditRequest);
|
||||
credits.instance = server->reconnect_instance;
|
||||
rdata->result = -EIO;
|
||||
rdata->result = smb_EIO(smb_eio_trace_read_rsp_malformed);
|
||||
break;
|
||||
default:
|
||||
trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_unknown);
|
||||
rdata->result = -EIO;
|
||||
rdata->result = smb_EIO1(smb_eio_trace_read_mid_state_unknown,
|
||||
mid->mid_state);
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
|
|
@ -4628,7 +4693,7 @@ do_retry:
|
|||
} else {
|
||||
size_t trans = rdata->subreq.transferred + rdata->got_bytes;
|
||||
if (trans < rdata->subreq.len &&
|
||||
rdata->subreq.start + trans == ictx->remote_i_size) {
|
||||
rdata->subreq.start + trans >= ictx->remote_i_size) {
|
||||
__set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags);
|
||||
rdata->result = 0;
|
||||
}
|
||||
|
|
@ -4643,7 +4708,7 @@ do_retry:
|
|||
rdata->subreq.transferred += rdata->got_bytes;
|
||||
trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress);
|
||||
netfs_read_subreq_terminated(&rdata->subreq);
|
||||
release_mid(mid);
|
||||
release_mid(server, mid);
|
||||
trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0,
|
||||
server->credits, server->in_flight,
|
||||
credits.value, cifs_trace_rw_credits_read_response_add);
|
||||
|
|
@ -4798,7 +4863,8 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|||
(*nbytes > io_parms->length)) {
|
||||
cifs_dbg(FYI, "bad length %d for count %d\n",
|
||||
*nbytes, io_parms->length);
|
||||
rc = -EIO;
|
||||
rc = smb_EIO2(smb_eio_trace_read_overlarge,
|
||||
*nbytes, io_parms->length);
|
||||
*nbytes = 0;
|
||||
}
|
||||
|
||||
|
|
@ -4820,11 +4886,10 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|||
* workqueue completion task.
|
||||
*/
|
||||
static void
|
||||
smb2_writev_callback(struct mid_q_entry *mid)
|
||||
smb2_writev_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
{
|
||||
struct cifs_io_subrequest *wdata = mid->callback_data;
|
||||
struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink);
|
||||
struct TCP_Server_Info *server = wdata->server;
|
||||
struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf;
|
||||
struct cifs_credits credits = {
|
||||
.value = 0,
|
||||
|
|
@ -4837,9 +4902,9 @@ smb2_writev_callback(struct mid_q_entry *mid)
|
|||
ssize_t result = 0;
|
||||
size_t written;
|
||||
|
||||
WARN_ONCE(wdata->server != mid->server,
|
||||
WARN_ONCE(wdata->server != server,
|
||||
"wdata server %p != mid server %p",
|
||||
wdata->server, mid->server);
|
||||
wdata->server, server);
|
||||
|
||||
switch (mid->mid_state) {
|
||||
case MID_RESPONSE_RECEIVED:
|
||||
|
|
@ -4885,11 +4950,12 @@ smb2_writev_callback(struct mid_q_entry *mid)
|
|||
trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_malformed);
|
||||
credits.value = le16_to_cpu(rsp->hdr.CreditRequest);
|
||||
credits.instance = server->reconnect_instance;
|
||||
result = -EIO;
|
||||
result = smb_EIO(smb_eio_trace_write_rsp_malformed);
|
||||
break;
|
||||
default:
|
||||
trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_unknown);
|
||||
result = -EIO;
|
||||
result = smb_EIO1(smb_eio_trace_write_mid_state_unknown,
|
||||
mid->mid_state);
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
|
|
@ -4929,7 +4995,7 @@ smb2_writev_callback(struct mid_q_entry *mid)
|
|||
0, cifs_trace_rw_credits_write_response_clear);
|
||||
wdata->credits.value = 0;
|
||||
cifs_write_subrequest_terminated(wdata, result ?: written);
|
||||
release_mid(mid);
|
||||
release_mid(server, mid);
|
||||
trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0,
|
||||
server->credits, server->in_flight,
|
||||
credits.value, cifs_trace_rw_credits_write_response_add);
|
||||
|
|
@ -5532,7 +5598,7 @@ replay_again:
|
|||
server = cifs_pick_channel(ses);
|
||||
|
||||
if (!ses || !(ses->server))
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
|
@ -5667,7 +5733,7 @@ replay_again:
|
|||
server = cifs_pick_channel(ses);
|
||||
|
||||
if (!ses || !server)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
if (!num)
|
||||
return -EINVAL;
|
||||
|
|
@ -5864,7 +5930,7 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon,
|
|||
cifs_dbg(FYI, "Query FSInfo level %d\n", level);
|
||||
|
||||
if ((tcon->ses == NULL) || server == NULL)
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
|
||||
rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, server,
|
||||
(void **) &req, &total_len);
|
||||
|
|
|
|||
|
|
@ -9,8 +9,10 @@
|
|||
*/
|
||||
#ifndef _SMB2PROTO_H
|
||||
#define _SMB2PROTO_H
|
||||
|
||||
#include <linux/nls.h>
|
||||
#include <linux/key-type.h>
|
||||
#include "cached_dir.h"
|
||||
|
||||
struct statfs;
|
||||
struct smb_rqst;
|
||||
|
|
@ -21,7 +23,7 @@ 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,
|
||||
extern int smb2_check_message(char *buf, unsigned int pdu_len, 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,
|
||||
|
|
@ -39,15 +41,11 @@ extern struct mid_q_entry *smb2_setup_async_request(
|
|||
struct TCP_Server_Info *server, struct smb_rqst *rqst);
|
||||
extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server,
|
||||
__u64 ses_id, __u32 tid);
|
||||
extern void smb2_echo_request(struct work_struct *work);
|
||||
extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
|
||||
extern bool smb2_is_valid_oplock_break(char *buffer,
|
||||
struct TCP_Server_Info *srv);
|
||||
extern int smb3_handle_read_data(struct TCP_Server_Info *server,
|
||||
struct mid_q_entry *mid);
|
||||
extern int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *path,
|
||||
__u32 *reparse_tag);
|
||||
struct inode *smb2_create_reparse_inode(struct cifs_open_info_data *data,
|
||||
struct super_block *sb,
|
||||
const unsigned int xid,
|
||||
|
|
@ -300,17 +298,9 @@ extern int smb2_query_info_compound(const unsigned int xid,
|
|||
struct kvec *rsp, int *buftype,
|
||||
struct cifs_sb_info *cifs_sb);
|
||||
/* query path info from the server using SMB311 POSIX extensions*/
|
||||
int smb311_posix_query_path_info(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
struct cifs_open_info_data *data);
|
||||
int posix_info_parse(const void *beg, const void *end,
|
||||
struct smb2_posix_info_parsed *out);
|
||||
int posix_info_sid_size(const void *beg, const void *end);
|
||||
int smb2_make_nfs_node(unsigned int xid, struct inode *inode,
|
||||
struct dentry *dentry, struct cifs_tcon *tcon,
|
||||
const char *full_path, umode_t mode, dev_t dev);
|
||||
int smb2_rename_pending_delete(const char *full_path,
|
||||
struct dentry *dentry,
|
||||
const unsigned int xid);
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ static int smb2_get_sign_key(struct TCP_Server_Info *server,
|
|||
memcpy(key, ses->auth_key.response,
|
||||
SMB2_NTLMV2_SESSKEY_SIZE);
|
||||
} else {
|
||||
rc = -EIO;
|
||||
rc = smb_EIO(smb_eio_trace_no_auth_key);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
@ -653,16 +653,15 @@ smb2_mid_entry_alloc(const struct smb2_hdr *shdr,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
|
||||
temp = mempool_alloc(&cifs_mid_pool, GFP_NOFS);
|
||||
memset(temp, 0, sizeof(struct mid_q_entry));
|
||||
kref_init(&temp->refcount);
|
||||
refcount_set(&temp->refcount, 1);
|
||||
spin_lock_init(&temp->mid_lock);
|
||||
temp->mid = le64_to_cpu(shdr->MessageId);
|
||||
temp->credits = credits > 0 ? credits : 1;
|
||||
temp->pid = current->pid;
|
||||
temp->command = shdr->Command; /* Always LE */
|
||||
temp->when_alloc = jiffies;
|
||||
temp->server = server;
|
||||
|
||||
/*
|
||||
* The default is for the mid to be synchronous, so the
|
||||
|
|
@ -685,43 +684,35 @@ static int
|
|||
smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
|
||||
struct smb2_hdr *shdr, struct mid_q_entry **mid)
|
||||
{
|
||||
spin_lock(&server->srv_lock);
|
||||
if (server->tcpStatus == CifsExiting) {
|
||||
spin_unlock(&server->srv_lock);
|
||||
switch (READ_ONCE(server->tcpStatus)) {
|
||||
case CifsExiting:
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (server->tcpStatus == CifsNeedReconnect) {
|
||||
spin_unlock(&server->srv_lock);
|
||||
case CifsNeedReconnect:
|
||||
cifs_dbg(FYI, "tcp session dead - return to caller to retry\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (server->tcpStatus == CifsNeedNegotiate &&
|
||||
shdr->Command != SMB2_NEGOTIATE) {
|
||||
spin_unlock(&server->srv_lock);
|
||||
return -EAGAIN;
|
||||
}
|
||||
spin_unlock(&server->srv_lock);
|
||||
|
||||
spin_lock(&ses->ses_lock);
|
||||
if (ses->ses_status == SES_NEW) {
|
||||
if ((shdr->Command != SMB2_SESSION_SETUP) &&
|
||||
(shdr->Command != SMB2_NEGOTIATE)) {
|
||||
spin_unlock(&ses->ses_lock);
|
||||
case CifsNeedNegotiate:
|
||||
if (shdr->Command != SMB2_NEGOTIATE)
|
||||
return -EAGAIN;
|
||||
}
|
||||
/* else ok - we are setting up session */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (ses->ses_status == SES_EXITING) {
|
||||
if (shdr->Command != SMB2_LOGOFF) {
|
||||
spin_unlock(&ses->ses_lock);
|
||||
switch (READ_ONCE(ses->ses_status)) {
|
||||
case SES_NEW:
|
||||
if (shdr->Command != SMB2_SESSION_SETUP &&
|
||||
shdr->Command != SMB2_NEGOTIATE)
|
||||
return -EAGAIN;
|
||||
/* else ok - we are setting up session */
|
||||
break;
|
||||
case SES_EXITING:
|
||||
if (shdr->Command != SMB2_LOGOFF)
|
||||
return -EAGAIN;
|
||||
}
|
||||
/* else ok - we are shutting down the session */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
spin_unlock(&ses->ses_lock);
|
||||
|
||||
*mid = smb2_mid_entry_alloc(shdr, server);
|
||||
if (*mid == NULL)
|
||||
|
|
@ -779,7 +770,7 @@ smb2_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server,
|
|||
rc = smb2_sign_rqst(rqst, server);
|
||||
if (rc) {
|
||||
revert_current_mid_from_hdr(server, shdr);
|
||||
delete_mid(mid);
|
||||
delete_mid(server, mid);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
|
|
@ -813,7 +804,7 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
|
|||
rc = smb2_sign_rqst(rqst, server);
|
||||
if (rc) {
|
||||
revert_current_mid_from_hdr(server, shdr);
|
||||
release_mid(mid);
|
||||
release_mid(server, mid);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,5 +5,6 @@
|
|||
* Author(s): Steve French <stfrench@microsoft.com>
|
||||
*/
|
||||
#include "cifsglob.h"
|
||||
#include "cifs_spnego.h"
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "trace.h"
|
||||
|
|
|
|||
|
|
@ -20,6 +20,136 @@
|
|||
/*
|
||||
* Specify enums for tracing information.
|
||||
*/
|
||||
#define smb_eio_traces \
|
||||
EM(smb_eio_trace_compress_copy, "compress_copy") \
|
||||
EM(smb_eio_trace_copychunk_inv_rsp, "copychunk_inv_rsp") \
|
||||
EM(smb_eio_trace_copychunk_overcopy_b, "copychunk_overcopy_b") \
|
||||
EM(smb_eio_trace_copychunk_overcopy_c, "copychunk_overcopy_c") \
|
||||
EM(smb_eio_trace_create_rsp_too_small, "create_rsp_too_small") \
|
||||
EM(smb_eio_trace_dfsref_no_rsp, "dfsref_no_rsp") \
|
||||
EM(smb_eio_trace_ea_overrun, "ea_overrun") \
|
||||
EM(smb_eio_trace_extract_will_pin, "extract_will_pin") \
|
||||
EM(smb_eio_trace_forced_shutdown, "forced_shutdown") \
|
||||
EM(smb_eio_trace_getacl_bcc_too_small, "getacl_bcc_too_small") \
|
||||
EM(smb_eio_trace_getcifsacl_param_count, "getcifsacl_param_count") \
|
||||
EM(smb_eio_trace_getdfsrefer_bcc_too_small, "getdfsrefer_bcc_too_small") \
|
||||
EM(smb_eio_trace_getextattr_bcc_too_small, "getextattr_bcc_too_small") \
|
||||
EM(smb_eio_trace_getextattr_inv_size, "getextattr_inv_size") \
|
||||
EM(smb_eio_trace_getsrvinonum_bcc_too_small, "getsrvinonum_bcc_too_small") \
|
||||
EM(smb_eio_trace_getsrvinonum_size, "getsrvinonum_size") \
|
||||
EM(smb_eio_trace_ioctl_data_len, "ioctl_data_len") \
|
||||
EM(smb_eio_trace_ioctl_no_rsp, "ioctl_no_rsp") \
|
||||
EM(smb_eio_trace_ioctl_out_off, "ioctl_out_off") \
|
||||
EM(smb_eio_trace_lock_bcc_too_small, "lock_bcc_too_small") \
|
||||
EM(smb_eio_trace_lock_data_too_small, "lock_data_too_small") \
|
||||
EM(smb_eio_trace_malformed_ksid_key, "malformed_ksid_key") \
|
||||
EM(smb_eio_trace_malformed_sid_key, "malformed_sid_key") \
|
||||
EM(smb_eio_trace_mkdir_no_rsp, "mkdir_no_rsp") \
|
||||
EM(smb_eio_trace_neg_bad_rsplen, "neg_bad_rsplen") \
|
||||
EM(smb_eio_trace_neg_decode_token, "neg_decode_token") \
|
||||
EM(smb_eio_trace_neg_info_caps, "neg_info_caps") \
|
||||
EM(smb_eio_trace_neg_info_dialect, "neg_info_dialect") \
|
||||
EM(smb_eio_trace_neg_info_fail, "neg_info_fail") \
|
||||
EM(smb_eio_trace_neg_info_sec_mode, "neg_info_sec_mode") \
|
||||
EM(smb_eio_trace_neg_inval_dialect, "neg_inval_dialect") \
|
||||
EM(smb_eio_trace_neg_no_crypt_key, "neg_no_crypt_key") \
|
||||
EM(smb_eio_trace_neg_sec_blob_too_small, "neg_sec_blob_too_small") \
|
||||
EM(smb_eio_trace_neg_unreq_dialect, "neg_unreq_dialect") \
|
||||
EM(smb_eio_trace_no_auth_key, "no_auth_key") \
|
||||
EM(smb_eio_trace_no_lease_key, "no_lease_key") \
|
||||
EM(smb_eio_trace_not_netfs_writeback, "not_netfs_writeback") \
|
||||
EM(smb_eio_trace_null_pointers, "null_pointers") \
|
||||
EM(smb_eio_trace_oldqfsinfo_bcc_too_small, "oldqfsinfo_bcc_too_small") \
|
||||
EM(smb_eio_trace_pend_del_fail, "pend_del_fail") \
|
||||
EM(smb_eio_trace_qalleas_bcc_too_small, "qalleas_bcc_too_small") \
|
||||
EM(smb_eio_trace_qalleas_ea_overlong, "qalleas_ea_overlong") \
|
||||
EM(smb_eio_trace_qalleas_overlong, "qalleas_overlong") \
|
||||
EM(smb_eio_trace_qfileinfo_bcc_too_small, "qfileinfo_bcc_too_small") \
|
||||
EM(smb_eio_trace_qfileinfo_invalid, "qfileinfo_invalid") \
|
||||
EM(smb_eio_trace_qfsattrinfo_bcc_too_small, "qfsattrinfo_bcc_too_small") \
|
||||
EM(smb_eio_trace_qfsdevinfo_bcc_too_small, "qfsdevinfo_bcc_too_small") \
|
||||
EM(smb_eio_trace_qfsinfo_bcc_too_small, "qfsinfo_bcc_too_small") \
|
||||
EM(smb_eio_trace_qfsposixinfo_bcc_too_small, "qfsposixinfo_bcc_too_small") \
|
||||
EM(smb_eio_trace_qfsunixinfo_bcc_too_small, "qfsunixinfo_bcc_too_small") \
|
||||
EM(smb_eio_trace_qpathinfo_bcc_too_small, "qpathinfo_bcc_too_small") \
|
||||
EM(smb_eio_trace_qpathinfo_invalid, "qpathinfo_invalid") \
|
||||
EM(smb_eio_trace_qreparse_data_area, "qreparse_data_area") \
|
||||
EM(smb_eio_trace_qreparse_rep_datalen, "qreparse_rep_datalen") \
|
||||
EM(smb_eio_trace_qreparse_ret_datalen, "qreparse_ret_datalen") \
|
||||
EM(smb_eio_trace_qreparse_setup_count, "qreparse_setup_count") \
|
||||
EM(smb_eio_trace_qreparse_sizes_wrong, "qreparse_sizes_wrong") \
|
||||
EM(smb_eio_trace_qsym_bcc_too_small, "qsym_bcc_too_small") \
|
||||
EM(smb_eio_trace_read_mid_state_unknown, "read_mid_state_unknown") \
|
||||
EM(smb_eio_trace_read_overlarge, "read_overlarge") \
|
||||
EM(smb_eio_trace_read_rsp_malformed, "read_rsp_malformed") \
|
||||
EM(smb_eio_trace_read_rsp_short, "read_rsp_short") \
|
||||
EM(smb_eio_trace_read_too_far, "read_too_far") \
|
||||
EM(smb_eio_trace_reparse_data_len, "reparse_data_len") \
|
||||
EM(smb_eio_trace_reparse_native_len, "reparse_native_len") \
|
||||
EM(smb_eio_trace_reparse_native_nul, "reparse_native_nul") \
|
||||
EM(smb_eio_trace_reparse_native_sym_len, "reparse_native_sym_len") \
|
||||
EM(smb_eio_trace_reparse_nfs_dev, "reparse_nfs_dev") \
|
||||
EM(smb_eio_trace_reparse_nfs_nul, "reparse_nfs_nul") \
|
||||
EM(smb_eio_trace_reparse_nfs_sockfifo, "reparse_nfs_sockfifo") \
|
||||
EM(smb_eio_trace_reparse_nfs_symbuf, "reparse_nfs_symbuf") \
|
||||
EM(smb_eio_trace_reparse_nfs_too_short, "reparse_nfs_too_short") \
|
||||
EM(smb_eio_trace_reparse_overlong, "reparse_overlong") \
|
||||
EM(smb_eio_trace_reparse_rdlen, "reparse_rdlen") \
|
||||
EM(smb_eio_trace_reparse_wsl_nul, "reparse_wsl_nul") \
|
||||
EM(smb_eio_trace_reparse_wsl_symbuf, "reparse_wsl_symbuf") \
|
||||
EM(smb_eio_trace_reparse_wsl_ver, "reparse_wsl_ver") \
|
||||
EM(smb_eio_trace_rx_b_read_short, "rx_b_read_short") \
|
||||
EM(smb_eio_trace_rx_bad_datalen, "rx_bad_datalen") \
|
||||
EM(smb_eio_trace_rx_both_buf, "rx_both_buf") \
|
||||
EM(smb_eio_trace_rx_calc_len_too_big, "rx_calc_len_too_big") \
|
||||
EM(smb_eio_trace_rx_check_rsp, "rx_check_rsp") \
|
||||
EM(smb_eio_trace_rx_copy_to_iter, "rx_copy_to_iter") \
|
||||
EM(smb_eio_trace_rx_insuff_res, "rx_insuff_res") \
|
||||
EM(smb_eio_trace_rx_inv_bcc, "rx_inv_bcc") \
|
||||
EM(smb_eio_trace_rx_mid_unready, "rx_mid_unready") \
|
||||
EM(smb_eio_trace_rx_neg_sess_resp, "rx_neg_sess_resp") \
|
||||
EM(smb_eio_trace_rx_overlong, "rx_overlong") \
|
||||
EM(smb_eio_trace_rx_overpage, "rx_overpage") \
|
||||
EM(smb_eio_trace_rx_pos_sess_resp, "rx_pos_sess_resp") \
|
||||
EM(smb_eio_trace_rx_rfc1002_magic, "rx_rfc1002_magic") \
|
||||
EM(smb_eio_trace_rx_sync_mid_invalid, "rx_sync_mid_invalid") \
|
||||
EM(smb_eio_trace_rx_sync_mid_malformed, "rx_sync_mid_malformed") \
|
||||
EM(smb_eio_trace_rx_too_short, "rx_too_short") \
|
||||
EM(smb_eio_trace_rx_trans2_extract, "rx_trans2_extract") \
|
||||
EM(smb_eio_trace_rx_unknown_resp, "rx_unknown_resp") \
|
||||
EM(smb_eio_trace_rx_unspec_error, "rx_unspec_error") \
|
||||
EM(smb_eio_trace_sess_buf_off, "sess_buf_off") \
|
||||
EM(smb_eio_trace_sess_exiting, "sess_exiting") \
|
||||
EM(smb_eio_trace_sess_krb_wcc, "sess_krb_wcc") \
|
||||
EM(smb_eio_trace_sess_nl2_wcc, "sess_nl2_wcc") \
|
||||
EM(smb_eio_trace_sess_rawnl_auth_wcc, "sess_rawnl_auth_wcc") \
|
||||
EM(smb_eio_trace_sess_rawnl_neg_wcc, "sess_rawnl_neg_wcc") \
|
||||
EM(smb_eio_trace_short_symlink_write, "short_symlink_write") \
|
||||
EM(smb_eio_trace_sid_too_many_auth, "sid_too_many_auth") \
|
||||
EM(smb_eio_trace_sig_data_too_small, "sig_data_too_small") \
|
||||
EM(smb_eio_trace_sig_iter, "sig_iter") \
|
||||
EM(smb_eio_trace_smb1_received_error, "smb1_received_error") \
|
||||
EM(smb_eio_trace_smb2_received_error, "smb2_received_error") \
|
||||
EM(smb_eio_trace_sym_slash, "sym_slash") \
|
||||
EM(smb_eio_trace_sym_target_len, "sym_target_len") \
|
||||
EM(smb_eio_trace_symlink_file_size, "symlink_file_size") \
|
||||
EM(smb_eio_trace_tdis_in_reconnect, "tdis_in_reconnect") \
|
||||
EM(smb_eio_trace_tx_chained_async, "tx_chained_async") \
|
||||
EM(smb_eio_trace_tx_compress_failed, "tx_compress_failed") \
|
||||
EM(smb_eio_trace_tx_copy_iter_to_buf, "tx_copy_iter_to_buf") \
|
||||
EM(smb_eio_trace_tx_copy_to_buf, "tx_copy_to_buf") \
|
||||
EM(smb_eio_trace_tx_max_compound, "tx_max_compound") \
|
||||
EM(smb_eio_trace_tx_miscopy_to_buf, "tx_miscopy_to_buf") \
|
||||
EM(smb_eio_trace_tx_need_transform, "tx_need_transform") \
|
||||
EM(smb_eio_trace_tx_too_long, "sr_too_long") \
|
||||
EM(smb_eio_trace_unixqfileinfo_bcc_too_small, "unixqfileinfo_bcc_too_small") \
|
||||
EM(smb_eio_trace_unixqpathinfo_bcc_too_small, "unixqpathinfo_bcc_too_small") \
|
||||
EM(smb_eio_trace_user_iter, "user_iter") \
|
||||
EM(smb_eio_trace_write_bad_buf_type, "write_bad_buf_type") \
|
||||
EM(smb_eio_trace_write_mid_state_unknown, "write_mid_state_unknown") \
|
||||
EM(smb_eio_trace_write_rsp_malformed, "write_rsp_malformed") \
|
||||
E_(smb_eio_trace_write_too_far, "write_too_far")
|
||||
|
||||
#define smb3_rw_credits_traces \
|
||||
EM(cifs_trace_rw_credits_call_readv_adjust, "rd-call-adj") \
|
||||
EM(cifs_trace_rw_credits_call_writev_adjust, "wr-call-adj") \
|
||||
|
|
@ -79,6 +209,7 @@
|
|||
#define EM(a, b) a,
|
||||
#define E_(a, b) a
|
||||
|
||||
enum smb_eio_trace { smb_eio_traces } __mode(byte);
|
||||
enum smb3_rw_credits_trace { smb3_rw_credits_traces } __mode(byte);
|
||||
enum smb3_tcon_ref_trace { smb3_tcon_ref_traces } __mode(byte);
|
||||
|
||||
|
|
@ -92,6 +223,7 @@ enum smb3_tcon_ref_trace { smb3_tcon_ref_traces } __mode(byte);
|
|||
#define EM(a, b) TRACE_DEFINE_ENUM(a);
|
||||
#define E_(a, b) TRACE_DEFINE_ENUM(a);
|
||||
|
||||
smb_eio_traces;
|
||||
smb3_rw_credits_traces;
|
||||
smb3_tcon_ref_traces;
|
||||
|
||||
|
|
@ -1560,6 +1692,49 @@ DEFINE_SMB3_CREDIT_EVENT(waitff_credits);
|
|||
DEFINE_SMB3_CREDIT_EVENT(overflow_credits);
|
||||
DEFINE_SMB3_CREDIT_EVENT(set_credits);
|
||||
|
||||
TRACE_EVENT(smb3_kerberos_auth,
|
||||
TP_PROTO(struct TCP_Server_Info *server,
|
||||
struct cifs_ses *ses,
|
||||
int rc),
|
||||
TP_ARGS(server, ses, rc),
|
||||
TP_STRUCT__entry(
|
||||
__field(pid_t, pid)
|
||||
__field(uid_t, uid)
|
||||
__field(uid_t, cruid)
|
||||
__string(host, server->hostname)
|
||||
__string(user, ses->user_name)
|
||||
__array(__u8, addr, sizeof(struct sockaddr_storage))
|
||||
__array(char, sec, sizeof("ntlmsspi"))
|
||||
__array(char, upcall_target, sizeof("mount"))
|
||||
__field(int, rc)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->pid = current->pid;
|
||||
__entry->uid = from_kuid_munged(&init_user_ns, ses->linux_uid);
|
||||
__entry->cruid = from_kuid_munged(&init_user_ns, ses->cred_uid);
|
||||
__assign_str(host);
|
||||
__assign_str(user);
|
||||
memcpy(__entry->addr, &server->dstaddr, sizeof(__entry->addr));
|
||||
|
||||
if (server->sec_kerberos)
|
||||
memcpy(__entry->sec, "krb5", sizeof("krb5"));
|
||||
else if (server->sec_mskerberos)
|
||||
memcpy(__entry->sec, "mskrb5", sizeof("mskrb5"));
|
||||
else if (server->sec_iakerb)
|
||||
memcpy(__entry->sec, "iakerb", sizeof("iakerb"));
|
||||
else
|
||||
memcpy(__entry->sec, "krb5", sizeof("krb5"));
|
||||
|
||||
if (ses->upcall_target == UPTARGET_MOUNT)
|
||||
memcpy(__entry->upcall_target, "mount", sizeof("mount"));
|
||||
else
|
||||
memcpy(__entry->upcall_target, "app", sizeof("app"));
|
||||
__entry->rc = rc;
|
||||
),
|
||||
TP_printk("vers=%d host=%s ip=%pISpsfc sec=%s uid=%d cruid=%d user=%s pid=%d upcall_target=%s err=%d",
|
||||
CIFS_SPNEGO_UPCALL_VERSION, __get_str(host), __entry->addr,
|
||||
__entry->sec, __entry->uid, __entry->cruid, __get_str(user),
|
||||
__entry->pid, __entry->upcall_target, __entry->rc))
|
||||
|
||||
TRACE_EVENT(smb3_tcon_ref,
|
||||
TP_PROTO(unsigned int tcon_debug_id, int ref,
|
||||
|
|
@ -1616,6 +1791,23 @@ TRACE_EVENT(smb3_rw_credits,
|
|||
__entry->server_credits, __entry->in_flight)
|
||||
);
|
||||
|
||||
TRACE_EVENT(smb3_eio,
|
||||
TP_PROTO(enum smb_eio_trace trace, unsigned long info, unsigned long info2),
|
||||
TP_ARGS(trace, info, info2),
|
||||
TP_STRUCT__entry(
|
||||
__field(enum smb_eio_trace, trace)
|
||||
__field(unsigned long, info)
|
||||
__field(unsigned long, info2)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->trace = trace;
|
||||
__entry->info = info;
|
||||
__entry->info2 = info2;
|
||||
),
|
||||
TP_printk("%s info=%lx,%lx",
|
||||
__print_symbolic(__entry->trace, smb_eio_traces),
|
||||
__entry->info, __entry->info2)
|
||||
);
|
||||
|
||||
#undef EM
|
||||
#undef E_
|
||||
|
|
|
|||
|
|
@ -32,24 +32,21 @@
|
|||
#include "compress.h"
|
||||
|
||||
void
|
||||
cifs_wake_up_task(struct mid_q_entry *mid)
|
||||
cifs_wake_up_task(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
{
|
||||
if (mid->mid_state == MID_RESPONSE_RECEIVED)
|
||||
mid->mid_state = MID_RESPONSE_READY;
|
||||
wake_up_process(mid->callback_data);
|
||||
}
|
||||
|
||||
void __release_mid(struct kref *refcount)
|
||||
void __release_mid(struct TCP_Server_Info *server, struct mid_q_entry *midEntry)
|
||||
{
|
||||
struct mid_q_entry *midEntry =
|
||||
container_of(refcount, struct mid_q_entry, refcount);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
__le16 command = midEntry->server->vals->lock_cmd;
|
||||
__le16 command = server->vals->lock_cmd;
|
||||
__u16 smb_cmd = le16_to_cpu(midEntry->command);
|
||||
unsigned long now;
|
||||
unsigned long roundtrip_time;
|
||||
#endif
|
||||
struct TCP_Server_Info *server = midEntry->server;
|
||||
|
||||
if (midEntry->resp_buf && (midEntry->wait_cancelled) &&
|
||||
(midEntry->mid_state == MID_RESPONSE_RECEIVED ||
|
||||
|
|
@ -116,20 +113,21 @@ void __release_mid(struct kref *refcount)
|
|||
#endif
|
||||
put_task_struct(midEntry->creator);
|
||||
|
||||
mempool_free(midEntry, cifs_mid_poolp);
|
||||
mempool_free(midEntry, &cifs_mid_pool);
|
||||
}
|
||||
|
||||
void
|
||||
delete_mid(struct mid_q_entry *mid)
|
||||
delete_mid(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
{
|
||||
spin_lock(&mid->server->mid_queue_lock);
|
||||
if (mid->deleted_from_q == false) {
|
||||
spin_lock(&server->mid_queue_lock);
|
||||
|
||||
if (!mid->deleted_from_q) {
|
||||
list_del_init(&mid->qhead);
|
||||
mid->deleted_from_q = true;
|
||||
}
|
||||
spin_unlock(&mid->server->mid_queue_lock);
|
||||
spin_unlock(&server->mid_queue_lock);
|
||||
|
||||
release_mid(mid);
|
||||
release_mid(server, mid);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -289,8 +287,8 @@ int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
|||
sigfillset(&mask);
|
||||
sigprocmask(SIG_BLOCK, &mask, &oldmask);
|
||||
|
||||
/* Generate a rfc1002 marker for SMB2+ */
|
||||
if (!is_smb1(server)) {
|
||||
/* Generate a rfc1002 marker */
|
||||
{
|
||||
struct kvec hiov = {
|
||||
.iov_base = &rfc1002_marker,
|
||||
.iov_len = 4
|
||||
|
|
@ -404,11 +402,11 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
|||
return __smb_send_rqst(server, num_rqst, rqst);
|
||||
|
||||
if (WARN_ON_ONCE(num_rqst > MAX_COMPOUND - 1))
|
||||
return -EIO;
|
||||
return smb_EIO1(smb_eio_trace_tx_max_compound, num_rqst);
|
||||
|
||||
if (!server->ops->init_transform_rq) {
|
||||
cifs_server_dbg(VFS, "Encryption requested but transform callback is missing\n");
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_tx_need_transform);
|
||||
}
|
||||
|
||||
new_rqst[0].rq_iov = &iov;
|
||||
|
|
@ -640,14 +638,18 @@ cifs_wait_mtu_credits(struct TCP_Server_Info *server, size_t size,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
|
||||
int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
{
|
||||
unsigned int sleep_state = TASK_KILLABLE;
|
||||
int error;
|
||||
|
||||
if (mid->sr_flags & CIFS_INTERRUPTIBLE_WAIT)
|
||||
sleep_state = TASK_INTERRUPTIBLE;
|
||||
|
||||
error = wait_event_state(server->response_q,
|
||||
midQ->mid_state != MID_REQUEST_SUBMITTED &&
|
||||
midQ->mid_state != MID_RESPONSE_RECEIVED,
|
||||
(TASK_KILLABLE|TASK_FREEZABLE_UNSAFE));
|
||||
mid->mid_state != MID_REQUEST_SUBMITTED &&
|
||||
mid->mid_state != MID_RESPONSE_RECEIVED,
|
||||
(sleep_state | TASK_FREEZABLE_UNSAFE));
|
||||
if (error < 0)
|
||||
return -ERESTARTSYS;
|
||||
|
||||
|
|
@ -660,8 +662,8 @@ int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
|
|||
*/
|
||||
int
|
||||
cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
|
||||
mid_receive_t *receive, mid_callback_t *callback,
|
||||
mid_handle_t *handle, void *cbdata, const int flags,
|
||||
mid_receive_t receive, mid_callback_t callback,
|
||||
mid_handle_t handle, void *cbdata, const int flags,
|
||||
const struct cifs_credits *exist_credits)
|
||||
{
|
||||
int rc;
|
||||
|
|
@ -701,6 +703,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
|
|||
return PTR_ERR(mid);
|
||||
}
|
||||
|
||||
mid->sr_flags = flags;
|
||||
mid->receive = receive;
|
||||
mid->callback = callback;
|
||||
mid->callback_data = cbdata;
|
||||
|
|
@ -722,7 +725,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
|
|||
if (rc < 0) {
|
||||
revert_current_mid(server, mid->credits);
|
||||
server->sequence_number -= 2;
|
||||
delete_mid(mid);
|
||||
delete_mid(server, mid);
|
||||
}
|
||||
|
||||
cifs_server_unlock(server);
|
||||
|
|
@ -750,7 +753,7 @@ int cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server
|
|||
rc = -EAGAIN;
|
||||
break;
|
||||
case MID_RESPONSE_MALFORMED:
|
||||
rc = -EIO;
|
||||
rc = smb_EIO(smb_eio_trace_rx_sync_mid_malformed);
|
||||
break;
|
||||
case MID_SHUTDOWN:
|
||||
rc = -EHOSTDOWN;
|
||||
|
|
@ -766,20 +769,19 @@ int cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server
|
|||
spin_unlock(&server->mid_queue_lock);
|
||||
cifs_server_dbg(VFS, "%s: invalid mid state mid=%llu state=%d\n",
|
||||
__func__, mid->mid, mid->mid_state);
|
||||
rc = -EIO;
|
||||
rc = smb_EIO1(smb_eio_trace_rx_sync_mid_invalid, mid->mid_state);
|
||||
goto sync_mid_done;
|
||||
}
|
||||
spin_unlock(&server->mid_queue_lock);
|
||||
|
||||
sync_mid_done:
|
||||
release_mid(mid);
|
||||
release_mid(server, mid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
cifs_compound_callback(struct mid_q_entry *mid)
|
||||
cifs_compound_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
{
|
||||
struct TCP_Server_Info *server = mid->server;
|
||||
struct cifs_credits credits = {
|
||||
.value = server->ops->get_credits(mid),
|
||||
.instance = server->reconnect_instance,
|
||||
|
|
@ -792,17 +794,17 @@ cifs_compound_callback(struct mid_q_entry *mid)
|
|||
}
|
||||
|
||||
static void
|
||||
cifs_compound_last_callback(struct mid_q_entry *mid)
|
||||
cifs_compound_last_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
{
|
||||
cifs_compound_callback(mid);
|
||||
cifs_wake_up_task(mid);
|
||||
cifs_compound_callback(server, mid);
|
||||
cifs_wake_up_task(server, mid);
|
||||
}
|
||||
|
||||
static void
|
||||
cifs_cancelled_callback(struct mid_q_entry *mid)
|
||||
cifs_cancelled_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
{
|
||||
cifs_compound_callback(mid);
|
||||
release_mid(mid);
|
||||
cifs_compound_callback(server, mid);
|
||||
release_mid(server, mid);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -866,7 +868,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
|||
int *resp_buf_type, struct kvec *resp_iov)
|
||||
{
|
||||
int i, j, optype, rc = 0;
|
||||
struct mid_q_entry *midQ[MAX_COMPOUND];
|
||||
struct mid_q_entry *mid[MAX_COMPOUND];
|
||||
bool cancelled_mid[MAX_COMPOUND] = {false};
|
||||
struct cifs_credits credits[MAX_COMPOUND] = {
|
||||
{ .value = 0, .instance = 0 }
|
||||
|
|
@ -881,7 +883,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
|||
|
||||
if (!ses || !ses->server || !server) {
|
||||
cifs_dbg(VFS, "Null session\n");
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_null_pointers);
|
||||
}
|
||||
|
||||
spin_lock(&server->srv_lock);
|
||||
|
|
@ -932,35 +934,36 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
|||
}
|
||||
|
||||
for (i = 0; i < num_rqst; i++) {
|
||||
midQ[i] = server->ops->setup_request(ses, server, &rqst[i]);
|
||||
if (IS_ERR(midQ[i])) {
|
||||
mid[i] = server->ops->setup_request(ses, server, &rqst[i]);
|
||||
if (IS_ERR(mid[i])) {
|
||||
revert_current_mid(server, i);
|
||||
for (j = 0; j < i; j++)
|
||||
delete_mid(midQ[j]);
|
||||
delete_mid(server, mid[j]);
|
||||
cifs_server_unlock(server);
|
||||
|
||||
/* Update # of requests on wire to server */
|
||||
for (j = 0; j < num_rqst; j++)
|
||||
add_credits(server, &credits[j], optype);
|
||||
return PTR_ERR(midQ[i]);
|
||||
return PTR_ERR(mid[i]);
|
||||
}
|
||||
|
||||
midQ[i]->mid_state = MID_REQUEST_SUBMITTED;
|
||||
midQ[i]->optype = optype;
|
||||
mid[i]->sr_flags = flags;
|
||||
mid[i]->mid_state = MID_REQUEST_SUBMITTED;
|
||||
mid[i]->optype = optype;
|
||||
/*
|
||||
* Invoke callback for every part of the compound chain
|
||||
* to calculate credits properly. Wake up this thread only when
|
||||
* the last element is received.
|
||||
*/
|
||||
if (i < num_rqst - 1)
|
||||
midQ[i]->callback = cifs_compound_callback;
|
||||
mid[i]->callback = cifs_compound_callback;
|
||||
else
|
||||
midQ[i]->callback = cifs_compound_last_callback;
|
||||
mid[i]->callback = cifs_compound_last_callback;
|
||||
}
|
||||
rc = smb_send_rqst(server, num_rqst, rqst, flags);
|
||||
|
||||
for (i = 0; i < num_rqst; i++)
|
||||
cifs_save_when_sent(midQ[i]);
|
||||
cifs_save_when_sent(mid[i]);
|
||||
|
||||
if (rc < 0) {
|
||||
revert_current_mid(server, num_rqst);
|
||||
|
|
@ -994,6 +997,9 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
|||
if ((ses->ses_status == SES_NEW) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) {
|
||||
spin_unlock(&ses->ses_lock);
|
||||
|
||||
if (WARN_ON_ONCE(num_rqst != 1 || !resp_iov))
|
||||
return -EINVAL;
|
||||
|
||||
cifs_server_lock(server);
|
||||
smb311_update_preauth_hash(ses, server, rqst[0].rq_iov, rqst[0].rq_nvec);
|
||||
cifs_server_unlock(server);
|
||||
|
|
@ -1003,23 +1009,24 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
|||
spin_unlock(&ses->ses_lock);
|
||||
|
||||
for (i = 0; i < num_rqst; i++) {
|
||||
rc = wait_for_response(server, midQ[i]);
|
||||
rc = wait_for_response(server, mid[i]);
|
||||
if (rc != 0)
|
||||
break;
|
||||
}
|
||||
if (rc != 0) {
|
||||
for (; i < num_rqst; i++) {
|
||||
cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n",
|
||||
midQ[i]->mid, le16_to_cpu(midQ[i]->command));
|
||||
send_cancel(server, &rqst[i], midQ[i]);
|
||||
spin_lock(&midQ[i]->mid_lock);
|
||||
midQ[i]->wait_cancelled = true;
|
||||
if (midQ[i]->callback) {
|
||||
midQ[i]->callback = cifs_cancelled_callback;
|
||||
mid[i]->mid, le16_to_cpu(mid[i]->command));
|
||||
send_cancel(ses, server, &rqst[i], mid[i], xid);
|
||||
spin_lock(&mid[i]->mid_lock);
|
||||
mid[i]->wait_cancelled = true;
|
||||
if (mid[i]->mid_state == MID_REQUEST_SUBMITTED ||
|
||||
mid[i]->mid_state == MID_RESPONSE_RECEIVED) {
|
||||
mid[i]->callback = cifs_cancelled_callback;
|
||||
cancelled_mid[i] = true;
|
||||
credits[i].value = 0;
|
||||
}
|
||||
spin_unlock(&midQ[i]->mid_lock);
|
||||
spin_unlock(&mid[i]->mid_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1027,37 +1034,37 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
|||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
rc = cifs_sync_mid_result(midQ[i], server);
|
||||
rc = cifs_sync_mid_result(mid[i], server);
|
||||
if (rc != 0) {
|
||||
/* mark this mid as cancelled to not free it below */
|
||||
cancelled_mid[i] = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!midQ[i]->resp_buf ||
|
||||
midQ[i]->mid_state != MID_RESPONSE_READY) {
|
||||
rc = -EIO;
|
||||
if (!mid[i]->resp_buf ||
|
||||
mid[i]->mid_state != MID_RESPONSE_READY) {
|
||||
rc = smb_EIO1(smb_eio_trace_rx_mid_unready, mid[i]->mid_state);
|
||||
cifs_dbg(FYI, "Bad MID state?\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf = (char *)midQ[i]->resp_buf;
|
||||
resp_iov[i].iov_base = buf;
|
||||
resp_iov[i].iov_len = midQ[i]->resp_buf_size +
|
||||
HEADER_PREAMBLE_SIZE(server);
|
||||
rc = server->ops->check_receive(mid[i], server,
|
||||
flags & CIFS_LOG_ERROR);
|
||||
|
||||
if (midQ[i]->large_buf)
|
||||
resp_buf_type[i] = CIFS_LARGE_BUFFER;
|
||||
else
|
||||
resp_buf_type[i] = CIFS_SMALL_BUFFER;
|
||||
if (resp_iov) {
|
||||
buf = (char *)mid[i]->resp_buf;
|
||||
resp_iov[i].iov_base = buf;
|
||||
resp_iov[i].iov_len = mid[i]->resp_buf_size;
|
||||
|
||||
rc = server->ops->check_receive(midQ[i], server,
|
||||
flags & CIFS_LOG_ERROR);
|
||||
|
||||
/* mark it so buf will not be freed by delete_mid */
|
||||
if ((flags & CIFS_NO_RSP_BUF) == 0)
|
||||
midQ[i]->resp_buf = NULL;
|
||||
if (mid[i]->large_buf)
|
||||
resp_buf_type[i] = CIFS_LARGE_BUFFER;
|
||||
else
|
||||
resp_buf_type[i] = CIFS_SMALL_BUFFER;
|
||||
|
||||
/* mark it so buf will not be freed by delete_mid */
|
||||
if ((flags & CIFS_NO_RSP_BUF) == 0)
|
||||
mid[i]->resp_buf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1086,7 +1093,7 @@ out:
|
|||
*/
|
||||
for (i = 0; i < num_rqst; i++) {
|
||||
if (!cancelled_mid[i])
|
||||
delete_mid(midQ[i]);
|
||||
delete_mid(server, mid[i]);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
|
@ -1111,8 +1118,7 @@ int
|
|||
cifs_discard_remaining_data(struct TCP_Server_Info *server)
|
||||
{
|
||||
unsigned int rfclen = server->pdu_size;
|
||||
size_t remaining = rfclen + HEADER_PREAMBLE_SIZE(server) -
|
||||
server->total_read;
|
||||
size_t remaining = rfclen - server->total_read;
|
||||
|
||||
while (remaining > 0) {
|
||||
ssize_t length;
|
||||
|
|
@ -1136,7 +1142,7 @@ __cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
|||
int length;
|
||||
|
||||
length = cifs_discard_remaining_data(server);
|
||||
dequeue_mid(mid, malformed);
|
||||
dequeue_mid(server, mid, malformed);
|
||||
mid->resp_buf = server->smallbuf;
|
||||
server->smallbuf = NULL;
|
||||
return length;
|
||||
|
|
@ -1157,7 +1163,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
unsigned int data_offset, data_len;
|
||||
struct cifs_io_subrequest *rdata = mid->callback_data;
|
||||
char *buf = server->smallbuf;
|
||||
unsigned int buflen = server->pdu_size + HEADER_PREAMBLE_SIZE(server);
|
||||
unsigned int buflen = server->pdu_size;
|
||||
bool use_rdma_mr = false;
|
||||
|
||||
cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%zu\n",
|
||||
|
|
@ -1191,14 +1197,9 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
|
||||
/* set up first two iov for signature check and to get credits */
|
||||
rdata->iov[0].iov_base = buf;
|
||||
rdata->iov[0].iov_len = HEADER_PREAMBLE_SIZE(server);
|
||||
rdata->iov[1].iov_base = buf + HEADER_PREAMBLE_SIZE(server);
|
||||
rdata->iov[1].iov_len =
|
||||
server->total_read - HEADER_PREAMBLE_SIZE(server);
|
||||
rdata->iov[0].iov_len = server->total_read;
|
||||
cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
|
||||
rdata->iov[0].iov_base, rdata->iov[0].iov_len);
|
||||
cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
|
||||
rdata->iov[1].iov_base, rdata->iov[1].iov_len);
|
||||
|
||||
/* Was the SMB read successful? */
|
||||
rdata->result = server->ops->map_error(buf, false);
|
||||
|
|
@ -1214,12 +1215,12 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
|
||||
__func__, server->total_read,
|
||||
server->vals->read_rsp_size);
|
||||
rdata->result = -EIO;
|
||||
rdata->result = smb_EIO2(smb_eio_trace_read_rsp_short,
|
||||
server->total_read, server->vals->read_rsp_size);
|
||||
return cifs_readv_discard(server, mid);
|
||||
}
|
||||
|
||||
data_offset = server->ops->read_data_offset(buf) +
|
||||
HEADER_PREAMBLE_SIZE(server);
|
||||
data_offset = server->ops->read_data_offset(buf);
|
||||
if (data_offset < server->total_read) {
|
||||
/*
|
||||
* win2k8 sometimes sends an offset of 0 when the read
|
||||
|
|
@ -1233,7 +1234,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
/* data_offset is beyond the end of smallbuf */
|
||||
cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
|
||||
__func__, data_offset);
|
||||
rdata->result = -EIO;
|
||||
rdata->result = smb_EIO1(smb_eio_trace_read_overlarge,
|
||||
data_offset);
|
||||
return cifs_readv_discard(server, mid);
|
||||
}
|
||||
|
||||
|
|
@ -1248,6 +1250,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
if (length < 0)
|
||||
return length;
|
||||
server->total_read += length;
|
||||
rdata->iov[0].iov_len = server->total_read;
|
||||
}
|
||||
|
||||
/* how much data is in the response? */
|
||||
|
|
@ -1257,7 +1260,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
data_len = server->ops->read_data_length(buf, use_rdma_mr);
|
||||
if (!use_rdma_mr && (data_offset + data_len > buflen)) {
|
||||
/* data_len is corrupt -- discard frame */
|
||||
rdata->result = -EIO;
|
||||
rdata->result = smb_EIO2(smb_eio_trace_read_rsp_malformed,
|
||||
data_offset + data_len, buflen);
|
||||
return cifs_readv_discard(server, mid);
|
||||
}
|
||||
|
||||
|
|
@ -1279,7 +1283,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
if (server->total_read < buflen)
|
||||
return cifs_readv_discard(server, mid);
|
||||
|
||||
dequeue_mid(mid, false);
|
||||
dequeue_mid(server, mid, false);
|
||||
mid->resp_buf = server->smallbuf;
|
||||
server->smallbuf = NULL;
|
||||
return length;
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
|
|||
void *page;
|
||||
|
||||
if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
||||
return -EIO;
|
||||
return smb_EIO(smb_eio_trace_forced_shutdown);
|
||||
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
|
||||
return -EOPNOTSUPP;
|
||||
|
|
|
|||
|
|
@ -2016,9 +2016,6 @@ struct smb2_lease_ack {
|
|||
* MS-SMB 2.2.3.1
|
||||
*/
|
||||
struct smb_hdr {
|
||||
__be32 smb_buf_length; /* BB length is only two (rarely three) bytes,
|
||||
with one or two byte "type" preceding it that will be
|
||||
zero - we could mask the type byte off */
|
||||
__u8 Protocol[4];
|
||||
__u8 Command;
|
||||
union {
|
||||
|
|
|
|||
|
|
@ -631,6 +631,7 @@ struct ntstatus {
|
|||
#define STATUS_DOMAIN_TRUST_INCONSISTENT cpu_to_le32(0xC000019B)
|
||||
#define STATUS_FS_DRIVER_REQUIRED cpu_to_le32(0xC000019C)
|
||||
#define STATUS_IMAGE_ALREADY_LOADED_AS_DLL cpu_to_le32(0xC000019D)
|
||||
#define STATUS_INVALID_LOCK_RANGE cpu_to_le32(0xC00001A1)
|
||||
#define STATUS_NETWORK_OPEN_RESTRICTION cpu_to_le32(0xC0000201)
|
||||
#define STATUS_NO_USER_SESSION_KEY cpu_to_le32(0xC0000202)
|
||||
#define STATUS_USER_SESSION_DELETED cpu_to_le32(0xC0000203)
|
||||
|
|
@ -1773,5 +1774,5 @@ struct ntstatus {
|
|||
#define STATUS_IPSEC_INVALID_PACKET cpu_to_le32(0xC0360005)
|
||||
#define STATUS_IPSEC_INTEGRITY_CHECK_FAILED cpu_to_le32(0xC0360006)
|
||||
#define STATUS_IPSEC_CLEAR_TEXT_DROP cpu_to_le32(0xC0360007)
|
||||
#define STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP cpu_to_le32(0xC05D0000)
|
||||
#define STATUS_INVALID_LOCK_RANGE cpu_to_le32(0xC00001a1)
|
||||
/* See MS-SMB2 3.3.5.4 */
|
||||
#define STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP cpu_to_le32(0xC05D0000)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ struct smb_version_values {
|
|||
__u32 exclusive_lock_type;
|
||||
__u32 shared_lock_type;
|
||||
__u32 unlock_lock_type;
|
||||
size_t header_preamble_size;
|
||||
size_t header_size;
|
||||
size_t max_header_size;
|
||||
size_t read_rsp_size;
|
||||
|
|
|
|||
|
|
@ -896,7 +896,7 @@ static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn,
|
|||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
if (pneg_ctxt->HashAlgorithms != SMB2_PREAUTH_INTEGRITY_SHA512)
|
||||
return STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP;
|
||||
return STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP;
|
||||
|
||||
conn->preauth_info->Preauth_HashId = SMB2_PREAUTH_INTEGRITY_SHA512;
|
||||
return STATUS_SUCCESS;
|
||||
|
|
|
|||
Loading…
Reference in New Issue