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
Linus Torvalds 2025-12-09 16:09:32 +09:00
commit 3d99347a2e
46 changed files with 1741 additions and 1512 deletions

View File

@ -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)

View File

@ -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 */

View File

@ -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

View File

@ -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)) {

View File

@ -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 */

View File

@ -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 */

View File

@ -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));

View File

@ -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;

View File

@ -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);
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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))

View File

@ -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 */

View File

@ -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);

View File

@ -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 */

View File

@ -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];

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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 +

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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),

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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"

View File

@ -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_

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -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)

View File

@ -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;

View File

@ -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;