xref: /openbmc/linux/fs/smb/client/transport.c (revision c1e01cdbe0312d95b8c1542abd67fe786b534f57)
138c8a9a5SSteve French // SPDX-License-Identifier: LGPL-2.1
238c8a9a5SSteve French /*
338c8a9a5SSteve French  *
438c8a9a5SSteve French  *   Copyright (C) International Business Machines  Corp., 2002,2008
538c8a9a5SSteve French  *   Author(s): Steve French (sfrench@us.ibm.com)
638c8a9a5SSteve French  *   Jeremy Allison (jra@samba.org) 2006.
738c8a9a5SSteve French  *
838c8a9a5SSteve French  */
938c8a9a5SSteve French 
1038c8a9a5SSteve French #include <linux/fs.h>
1138c8a9a5SSteve French #include <linux/list.h>
1238c8a9a5SSteve French #include <linux/gfp.h>
1338c8a9a5SSteve French #include <linux/wait.h>
1438c8a9a5SSteve French #include <linux/net.h>
1538c8a9a5SSteve French #include <linux/delay.h>
1638c8a9a5SSteve French #include <linux/freezer.h>
1738c8a9a5SSteve French #include <linux/tcp.h>
1838c8a9a5SSteve French #include <linux/bvec.h>
1938c8a9a5SSteve French #include <linux/highmem.h>
2038c8a9a5SSteve French #include <linux/uaccess.h>
212c75426cSSteve French #include <linux/processor.h>
2238c8a9a5SSteve French #include <linux/mempool.h>
2338c8a9a5SSteve French #include <linux/sched/signal.h>
2438c8a9a5SSteve French #include <linux/task_io_accounting_ops.h>
2538c8a9a5SSteve French #include "cifspdu.h"
2638c8a9a5SSteve French #include "cifsglob.h"
2738c8a9a5SSteve French #include "cifsproto.h"
2838c8a9a5SSteve French #include "cifs_debug.h"
2938c8a9a5SSteve French #include "smb2proto.h"
3038c8a9a5SSteve French #include "smbdirect.h"
3138c8a9a5SSteve French 
3238c8a9a5SSteve French /* Max number of iovectors we can use off the stack when sending requests. */
3338c8a9a5SSteve French #define CIFS_MAX_IOV_SIZE 8
3438c8a9a5SSteve French 
3538c8a9a5SSteve French void
cifs_wake_up_task(struct mid_q_entry * mid)3638c8a9a5SSteve French cifs_wake_up_task(struct mid_q_entry *mid)
3738c8a9a5SSteve French {
38d527f513SZhang Xiaoxu 	if (mid->mid_state == MID_RESPONSE_RECEIVED)
39d527f513SZhang Xiaoxu 		mid->mid_state = MID_RESPONSE_READY;
4038c8a9a5SSteve French 	wake_up_process(mid->callback_data);
4138c8a9a5SSteve French }
4238c8a9a5SSteve French 
4338c8a9a5SSteve French static struct mid_q_entry *
alloc_mid(const struct smb_hdr * smb_buffer,struct TCP_Server_Info * server)4438c8a9a5SSteve French alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
4538c8a9a5SSteve French {
4638c8a9a5SSteve French 	struct mid_q_entry *temp;
4738c8a9a5SSteve French 
4838c8a9a5SSteve French 	if (server == NULL) {
4938c8a9a5SSteve French 		cifs_dbg(VFS, "%s: null TCP session\n", __func__);
5038c8a9a5SSteve French 		return NULL;
5138c8a9a5SSteve French 	}
5238c8a9a5SSteve French 
5338c8a9a5SSteve French 	temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
5438c8a9a5SSteve French 	memset(temp, 0, sizeof(struct mid_q_entry));
5538c8a9a5SSteve French 	kref_init(&temp->refcount);
5638c8a9a5SSteve French 	temp->mid = get_mid(smb_buffer);
5738c8a9a5SSteve French 	temp->pid = current->pid;
5838c8a9a5SSteve French 	temp->command = cpu_to_le16(smb_buffer->Command);
5938c8a9a5SSteve French 	cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command);
60a5998a9eS鑫华 	/* easier to use jiffies */
6138c8a9a5SSteve French 	/* when mid allocated can be before when sent */
6238c8a9a5SSteve French 	temp->when_alloc = jiffies;
6338c8a9a5SSteve French 	temp->server = server;
6438c8a9a5SSteve French 
6538c8a9a5SSteve French 	/*
6638c8a9a5SSteve French 	 * The default is for the mid to be synchronous, so the
6738c8a9a5SSteve French 	 * default callback just wakes up the current task.
6838c8a9a5SSteve French 	 */
6938c8a9a5SSteve French 	get_task_struct(current);
7038c8a9a5SSteve French 	temp->creator = current;
7138c8a9a5SSteve French 	temp->callback = cifs_wake_up_task;
7238c8a9a5SSteve French 	temp->callback_data = current;
7338c8a9a5SSteve French 
7438c8a9a5SSteve French 	atomic_inc(&mid_count);
7538c8a9a5SSteve French 	temp->mid_state = MID_REQUEST_ALLOCATED;
7638c8a9a5SSteve French 	return temp;
7738c8a9a5SSteve French }
7838c8a9a5SSteve French 
__release_mid(struct kref * refcount)79c1a5962fSPaulo Alcantara void __release_mid(struct kref *refcount)
8038c8a9a5SSteve French {
8138c8a9a5SSteve French 	struct mid_q_entry *midEntry =
8238c8a9a5SSteve French 			container_of(refcount, struct mid_q_entry, refcount);
8338c8a9a5SSteve French #ifdef CONFIG_CIFS_STATS2
8438c8a9a5SSteve French 	__le16 command = midEntry->server->vals->lock_cmd;
8538c8a9a5SSteve French 	__u16 smb_cmd = le16_to_cpu(midEntry->command);
8638c8a9a5SSteve French 	unsigned long now;
8738c8a9a5SSteve French 	unsigned long roundtrip_time;
8838c8a9a5SSteve French #endif
8938c8a9a5SSteve French 	struct TCP_Server_Info *server = midEntry->server;
9038c8a9a5SSteve French 
9138c8a9a5SSteve French 	if (midEntry->resp_buf && (midEntry->mid_flags & MID_WAIT_CANCELLED) &&
92d527f513SZhang Xiaoxu 	    (midEntry->mid_state == MID_RESPONSE_RECEIVED ||
93d527f513SZhang Xiaoxu 	     midEntry->mid_state == MID_RESPONSE_READY) &&
9438c8a9a5SSteve French 	    server->ops->handle_cancelled_mid)
9538c8a9a5SSteve French 		server->ops->handle_cancelled_mid(midEntry, server);
9638c8a9a5SSteve French 
9738c8a9a5SSteve French 	midEntry->mid_state = MID_FREE;
9838c8a9a5SSteve French 	atomic_dec(&mid_count);
9938c8a9a5SSteve French 	if (midEntry->large_buf)
10038c8a9a5SSteve French 		cifs_buf_release(midEntry->resp_buf);
10138c8a9a5SSteve French 	else
10238c8a9a5SSteve French 		cifs_small_buf_release(midEntry->resp_buf);
10338c8a9a5SSteve French #ifdef CONFIG_CIFS_STATS2
10438c8a9a5SSteve French 	now = jiffies;
10538c8a9a5SSteve French 	if (now < midEntry->when_alloc)
10638c8a9a5SSteve French 		cifs_server_dbg(VFS, "Invalid mid allocation time\n");
10738c8a9a5SSteve French 	roundtrip_time = now - midEntry->when_alloc;
10838c8a9a5SSteve French 
10938c8a9a5SSteve French 	if (smb_cmd < NUMBER_OF_SMB2_COMMANDS) {
11038c8a9a5SSteve French 		if (atomic_read(&server->num_cmds[smb_cmd]) == 0) {
11138c8a9a5SSteve French 			server->slowest_cmd[smb_cmd] = roundtrip_time;
11238c8a9a5SSteve French 			server->fastest_cmd[smb_cmd] = roundtrip_time;
11338c8a9a5SSteve French 		} else {
11438c8a9a5SSteve French 			if (server->slowest_cmd[smb_cmd] < roundtrip_time)
11538c8a9a5SSteve French 				server->slowest_cmd[smb_cmd] = roundtrip_time;
11638c8a9a5SSteve French 			else if (server->fastest_cmd[smb_cmd] > roundtrip_time)
11738c8a9a5SSteve French 				server->fastest_cmd[smb_cmd] = roundtrip_time;
11838c8a9a5SSteve French 		}
11938c8a9a5SSteve French 		cifs_stats_inc(&server->num_cmds[smb_cmd]);
12038c8a9a5SSteve French 		server->time_per_cmd[smb_cmd] += roundtrip_time;
12138c8a9a5SSteve French 	}
12238c8a9a5SSteve French 	/*
12338c8a9a5SSteve French 	 * commands taking longer than one second (default) can be indications
12438c8a9a5SSteve French 	 * that something is wrong, unless it is quite a slow link or a very
12538c8a9a5SSteve French 	 * busy server. Note that this calc is unlikely or impossible to wrap
12638c8a9a5SSteve French 	 * as long as slow_rsp_threshold is not set way above recommended max
12738c8a9a5SSteve French 	 * value (32767 ie 9 hours) and is generally harmless even if wrong
12838c8a9a5SSteve French 	 * since only affects debug counters - so leaving the calc as simple
12938c8a9a5SSteve French 	 * comparison rather than doing multiple conversions and overflow
13038c8a9a5SSteve French 	 * checks
13138c8a9a5SSteve French 	 */
13238c8a9a5SSteve French 	if ((slow_rsp_threshold != 0) &&
13338c8a9a5SSteve French 	    time_after(now, midEntry->when_alloc + (slow_rsp_threshold * HZ)) &&
13438c8a9a5SSteve French 	    (midEntry->command != command)) {
13538c8a9a5SSteve French 		/*
13638c8a9a5SSteve French 		 * smb2slowcmd[NUMBER_OF_SMB2_COMMANDS] counts by command
13738c8a9a5SSteve French 		 * NB: le16_to_cpu returns unsigned so can not be negative below
13838c8a9a5SSteve French 		 */
13938c8a9a5SSteve French 		if (smb_cmd < NUMBER_OF_SMB2_COMMANDS)
14038c8a9a5SSteve French 			cifs_stats_inc(&server->smb2slowcmd[smb_cmd]);
14138c8a9a5SSteve French 
14238c8a9a5SSteve French 		trace_smb3_slow_rsp(smb_cmd, midEntry->mid, midEntry->pid,
14338c8a9a5SSteve French 			       midEntry->when_sent, midEntry->when_received);
14438c8a9a5SSteve French 		if (cifsFYI & CIFS_TIMER) {
14538c8a9a5SSteve French 			pr_debug("slow rsp: cmd %d mid %llu",
14638c8a9a5SSteve French 				 midEntry->command, midEntry->mid);
14738c8a9a5SSteve French 			cifs_info("A: 0x%lx S: 0x%lx R: 0x%lx\n",
14838c8a9a5SSteve French 				  now - midEntry->when_alloc,
14938c8a9a5SSteve French 				  now - midEntry->when_sent,
15038c8a9a5SSteve French 				  now - midEntry->when_received);
15138c8a9a5SSteve French 		}
15238c8a9a5SSteve French 	}
15338c8a9a5SSteve French #endif
15438c8a9a5SSteve French 	put_task_struct(midEntry->creator);
15538c8a9a5SSteve French 
15638c8a9a5SSteve French 	mempool_free(midEntry, cifs_mid_poolp);
15738c8a9a5SSteve French }
15838c8a9a5SSteve French 
15938c8a9a5SSteve French void
delete_mid(struct mid_q_entry * mid)16038c8a9a5SSteve French delete_mid(struct mid_q_entry *mid)
16138c8a9a5SSteve French {
16238c8a9a5SSteve French 	spin_lock(&mid->server->mid_lock);
16338c8a9a5SSteve French 	if (!(mid->mid_flags & MID_DELETED)) {
16438c8a9a5SSteve French 		list_del_init(&mid->qhead);
16538c8a9a5SSteve French 		mid->mid_flags |= MID_DELETED;
16638c8a9a5SSteve French 	}
16738c8a9a5SSteve French 	spin_unlock(&mid->server->mid_lock);
16838c8a9a5SSteve French 
16938c8a9a5SSteve French 	release_mid(mid);
17038c8a9a5SSteve French }
17138c8a9a5SSteve French 
17238c8a9a5SSteve French /*
17338c8a9a5SSteve French  * smb_send_kvec - send an array of kvecs to the server
17438c8a9a5SSteve French  * @server:	Server to send the data to
17538c8a9a5SSteve French  * @smb_msg:	Message to send
17638c8a9a5SSteve French  * @sent:	amount of data sent on socket is stored here
17738c8a9a5SSteve French  *
17838c8a9a5SSteve French  * Our basic "send data to server" function. Should be called with srv_mutex
17938c8a9a5SSteve French  * held. The caller is responsible for handling the results.
18038c8a9a5SSteve French  */
18138c8a9a5SSteve French static int
smb_send_kvec(struct TCP_Server_Info * server,struct msghdr * smb_msg,size_t * sent)18238c8a9a5SSteve French smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
18338c8a9a5SSteve French 	      size_t *sent)
18438c8a9a5SSteve French {
18538c8a9a5SSteve French 	int rc = 0;
18638c8a9a5SSteve French 	int retries = 0;
18738c8a9a5SSteve French 	struct socket *ssocket = server->ssocket;
18838c8a9a5SSteve French 
18938c8a9a5SSteve French 	*sent = 0;
19038c8a9a5SSteve French 
19138c8a9a5SSteve French 	if (server->noblocksnd)
19238c8a9a5SSteve French 		smb_msg->msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
19338c8a9a5SSteve French 	else
19438c8a9a5SSteve French 		smb_msg->msg_flags = MSG_NOSIGNAL;
19538c8a9a5SSteve French 
19638c8a9a5SSteve French 	while (msg_data_left(smb_msg)) {
19738c8a9a5SSteve French 		/*
19838c8a9a5SSteve French 		 * If blocking send, we try 3 times, since each can block
19938c8a9a5SSteve French 		 * for 5 seconds. For nonblocking  we have to try more
20038c8a9a5SSteve French 		 * but wait increasing amounts of time allowing time for
20138c8a9a5SSteve French 		 * socket to clear.  The overall time we wait in either
20238c8a9a5SSteve French 		 * case to send on the socket is about 15 seconds.
20338c8a9a5SSteve French 		 * Similarly we wait for 15 seconds for a response from
20438c8a9a5SSteve French 		 * the server in SendReceive[2] for the server to send
20538c8a9a5SSteve French 		 * a response back for most types of requests (except
20638c8a9a5SSteve French 		 * SMB Write past end of file which can be slow, and
20738c8a9a5SSteve French 		 * blocking lock operations). NFS waits slightly longer
20838c8a9a5SSteve French 		 * than CIFS, but this can make it take longer for
20938c8a9a5SSteve French 		 * nonresponsive servers to be detected and 15 seconds
21038c8a9a5SSteve French 		 * is more than enough time for modern networks to
21138c8a9a5SSteve French 		 * send a packet.  In most cases if we fail to send
21238c8a9a5SSteve French 		 * after the retries we will kill the socket and
21338c8a9a5SSteve French 		 * reconnect which may clear the network problem.
21438c8a9a5SSteve French 		 */
21538c8a9a5SSteve French 		rc = sock_sendmsg(ssocket, smb_msg);
21638c8a9a5SSteve French 		if (rc == -EAGAIN) {
21738c8a9a5SSteve French 			retries++;
21838c8a9a5SSteve French 			if (retries >= 14 ||
21938c8a9a5SSteve French 			    (!server->noblocksnd && (retries > 2))) {
22038c8a9a5SSteve French 				cifs_server_dbg(VFS, "sends on sock %p stuck for 15 seconds\n",
22138c8a9a5SSteve French 					 ssocket);
22238c8a9a5SSteve French 				return -EAGAIN;
22338c8a9a5SSteve French 			}
22438c8a9a5SSteve French 			msleep(1 << retries);
22538c8a9a5SSteve French 			continue;
22638c8a9a5SSteve French 		}
22738c8a9a5SSteve French 
22838c8a9a5SSteve French 		if (rc < 0)
22938c8a9a5SSteve French 			return rc;
23038c8a9a5SSteve French 
23138c8a9a5SSteve French 		if (rc == 0) {
23238c8a9a5SSteve French 			/* should never happen, letting socket clear before
23338c8a9a5SSteve French 			   retrying is our only obvious option here */
23438c8a9a5SSteve French 			cifs_server_dbg(VFS, "tcp sent no data\n");
23538c8a9a5SSteve French 			msleep(500);
23638c8a9a5SSteve French 			continue;
23738c8a9a5SSteve French 		}
23838c8a9a5SSteve French 
23938c8a9a5SSteve French 		/* send was at least partially successful */
24038c8a9a5SSteve French 		*sent += rc;
24138c8a9a5SSteve French 		retries = 0; /* in case we get ENOSPC on the next send */
24238c8a9a5SSteve French 	}
24338c8a9a5SSteve French 	return 0;
24438c8a9a5SSteve French }
24538c8a9a5SSteve French 
24638c8a9a5SSteve French unsigned long
smb_rqst_len(struct TCP_Server_Info * server,struct smb_rqst * rqst)24738c8a9a5SSteve French smb_rqst_len(struct TCP_Server_Info *server, struct smb_rqst *rqst)
24838c8a9a5SSteve French {
24938c8a9a5SSteve French 	unsigned int i;
25038c8a9a5SSteve French 	struct kvec *iov;
25138c8a9a5SSteve French 	int nvec;
25238c8a9a5SSteve French 	unsigned long buflen = 0;
25338c8a9a5SSteve French 
25438c8a9a5SSteve French 	if (!is_smb1(server) && rqst->rq_nvec >= 2 &&
25538c8a9a5SSteve French 	    rqst->rq_iov[0].iov_len == 4) {
25638c8a9a5SSteve French 		iov = &rqst->rq_iov[1];
25738c8a9a5SSteve French 		nvec = rqst->rq_nvec - 1;
25838c8a9a5SSteve French 	} else {
25938c8a9a5SSteve French 		iov = rqst->rq_iov;
26038c8a9a5SSteve French 		nvec = rqst->rq_nvec;
26138c8a9a5SSteve French 	}
26238c8a9a5SSteve French 
26338c8a9a5SSteve French 	/* total up iov array first */
26438c8a9a5SSteve French 	for (i = 0; i < nvec; i++)
26538c8a9a5SSteve French 		buflen += iov[i].iov_len;
26638c8a9a5SSteve French 
26738c8a9a5SSteve French 	buflen += iov_iter_count(&rqst->rq_iter);
26838c8a9a5SSteve French 	return buflen;
26938c8a9a5SSteve French }
27038c8a9a5SSteve French 
27138c8a9a5SSteve French static int
__smb_send_rqst(struct TCP_Server_Info * server,int num_rqst,struct smb_rqst * rqst)27238c8a9a5SSteve French __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
27338c8a9a5SSteve French 		struct smb_rqst *rqst)
27438c8a9a5SSteve French {
27538c8a9a5SSteve French 	int rc;
27638c8a9a5SSteve French 	struct kvec *iov;
27738c8a9a5SSteve French 	int n_vec;
27838c8a9a5SSteve French 	unsigned int send_length = 0;
27938c8a9a5SSteve French 	unsigned int i, j;
28038c8a9a5SSteve French 	sigset_t mask, oldmask;
28138c8a9a5SSteve French 	size_t total_len = 0, sent, size;
28238c8a9a5SSteve French 	struct socket *ssocket = server->ssocket;
28338c8a9a5SSteve French 	struct msghdr smb_msg = {};
28438c8a9a5SSteve French 	__be32 rfc1002_marker;
28538c8a9a5SSteve French 
28638c8a9a5SSteve French 	cifs_in_send_inc(server);
28738c8a9a5SSteve French 	if (cifs_rdma_enabled(server)) {
28838c8a9a5SSteve French 		/* return -EAGAIN when connecting or reconnecting */
28938c8a9a5SSteve French 		rc = -EAGAIN;
29038c8a9a5SSteve French 		if (server->smbd_conn)
29138c8a9a5SSteve French 			rc = smbd_send(server, num_rqst, rqst);
29238c8a9a5SSteve French 		goto smbd_done;
29338c8a9a5SSteve French 	}
29438c8a9a5SSteve French 
29538c8a9a5SSteve French 	rc = -EAGAIN;
29638c8a9a5SSteve French 	if (ssocket == NULL)
29738c8a9a5SSteve French 		goto out;
29838c8a9a5SSteve French 
29938c8a9a5SSteve French 	rc = -ERESTARTSYS;
30038c8a9a5SSteve French 	if (fatal_signal_pending(current)) {
30138c8a9a5SSteve French 		cifs_dbg(FYI, "signal pending before send request\n");
30238c8a9a5SSteve French 		goto out;
30338c8a9a5SSteve French 	}
30438c8a9a5SSteve French 
30538c8a9a5SSteve French 	rc = 0;
30638c8a9a5SSteve French 	/* cork the socket */
30738c8a9a5SSteve French 	tcp_sock_set_cork(ssocket->sk, true);
30838c8a9a5SSteve French 
30938c8a9a5SSteve French 	for (j = 0; j < num_rqst; j++)
31038c8a9a5SSteve French 		send_length += smb_rqst_len(server, &rqst[j]);
31138c8a9a5SSteve French 	rfc1002_marker = cpu_to_be32(send_length);
31238c8a9a5SSteve French 
31338c8a9a5SSteve French 	/*
31438c8a9a5SSteve French 	 * We should not allow signals to interrupt the network send because
31538c8a9a5SSteve French 	 * any partial send will cause session reconnects thus increasing
31638c8a9a5SSteve French 	 * latency of system calls and overload a server with unnecessary
31738c8a9a5SSteve French 	 * requests.
31838c8a9a5SSteve French 	 */
31938c8a9a5SSteve French 
32038c8a9a5SSteve French 	sigfillset(&mask);
32138c8a9a5SSteve French 	sigprocmask(SIG_BLOCK, &mask, &oldmask);
32238c8a9a5SSteve French 
32338c8a9a5SSteve French 	/* Generate a rfc1002 marker for SMB2+ */
32438c8a9a5SSteve French 	if (!is_smb1(server)) {
32538c8a9a5SSteve French 		struct kvec hiov = {
32638c8a9a5SSteve French 			.iov_base = &rfc1002_marker,
32738c8a9a5SSteve French 			.iov_len  = 4
32838c8a9a5SSteve French 		};
32938c8a9a5SSteve French 		iov_iter_kvec(&smb_msg.msg_iter, ITER_SOURCE, &hiov, 1, 4);
33038c8a9a5SSteve French 		rc = smb_send_kvec(server, &smb_msg, &sent);
33138c8a9a5SSteve French 		if (rc < 0)
33238c8a9a5SSteve French 			goto unmask;
33338c8a9a5SSteve French 
33438c8a9a5SSteve French 		total_len += sent;
33538c8a9a5SSteve French 		send_length += 4;
33638c8a9a5SSteve French 	}
33738c8a9a5SSteve French 
33838c8a9a5SSteve French 	cifs_dbg(FYI, "Sending smb: smb_len=%u\n", send_length);
33938c8a9a5SSteve French 
34038c8a9a5SSteve French 	for (j = 0; j < num_rqst; j++) {
34138c8a9a5SSteve French 		iov = rqst[j].rq_iov;
34238c8a9a5SSteve French 		n_vec = rqst[j].rq_nvec;
34338c8a9a5SSteve French 
34438c8a9a5SSteve French 		size = 0;
34538c8a9a5SSteve French 		for (i = 0; i < n_vec; i++) {
34638c8a9a5SSteve French 			dump_smb(iov[i].iov_base, iov[i].iov_len);
34738c8a9a5SSteve French 			size += iov[i].iov_len;
34838c8a9a5SSteve French 		}
34938c8a9a5SSteve French 
35038c8a9a5SSteve French 		iov_iter_kvec(&smb_msg.msg_iter, ITER_SOURCE, iov, n_vec, size);
35138c8a9a5SSteve French 
35238c8a9a5SSteve French 		rc = smb_send_kvec(server, &smb_msg, &sent);
35338c8a9a5SSteve French 		if (rc < 0)
35438c8a9a5SSteve French 			goto unmask;
35538c8a9a5SSteve French 
35638c8a9a5SSteve French 		total_len += sent;
35738c8a9a5SSteve French 
35838c8a9a5SSteve French 		if (iov_iter_count(&rqst[j].rq_iter) > 0) {
35938c8a9a5SSteve French 			smb_msg.msg_iter = rqst[j].rq_iter;
36038c8a9a5SSteve French 			rc = smb_send_kvec(server, &smb_msg, &sent);
36138c8a9a5SSteve French 			if (rc < 0)
36238c8a9a5SSteve French 				break;
36338c8a9a5SSteve French 			total_len += sent;
36438c8a9a5SSteve French 		}
36538c8a9a5SSteve French 
36638c8a9a5SSteve French }
36738c8a9a5SSteve French 
36838c8a9a5SSteve French unmask:
36938c8a9a5SSteve French 	sigprocmask(SIG_SETMASK, &oldmask, NULL);
37038c8a9a5SSteve French 
37138c8a9a5SSteve French 	/*
37238c8a9a5SSteve French 	 * If signal is pending but we have already sent the whole packet to
37338c8a9a5SSteve French 	 * the server we need to return success status to allow a corresponding
37438c8a9a5SSteve French 	 * mid entry to be kept in the pending requests queue thus allowing
37538c8a9a5SSteve French 	 * to handle responses from the server by the client.
37638c8a9a5SSteve French 	 *
37738c8a9a5SSteve French 	 * If only part of the packet has been sent there is no need to hide
37838c8a9a5SSteve French 	 * interrupt because the session will be reconnected anyway, so there
37938c8a9a5SSteve French 	 * won't be any response from the server to handle.
38038c8a9a5SSteve French 	 */
38138c8a9a5SSteve French 
38238c8a9a5SSteve French 	if (signal_pending(current) && (total_len != send_length)) {
38338c8a9a5SSteve French 		cifs_dbg(FYI, "signal is pending after attempt to send\n");
38438c8a9a5SSteve French 		rc = -ERESTARTSYS;
38538c8a9a5SSteve French 	}
38638c8a9a5SSteve French 
38738c8a9a5SSteve French 	/* uncork it */
38838c8a9a5SSteve French 	tcp_sock_set_cork(ssocket->sk, false);
38938c8a9a5SSteve French 
39038c8a9a5SSteve French 	if ((total_len > 0) && (total_len != send_length)) {
39138c8a9a5SSteve French 		cifs_dbg(FYI, "partial send (wanted=%u sent=%zu): terminating session\n",
39238c8a9a5SSteve French 			 send_length, total_len);
39338c8a9a5SSteve French 		/*
39438c8a9a5SSteve French 		 * If we have only sent part of an SMB then the next SMB could
39538c8a9a5SSteve French 		 * be taken as the remainder of this one. We need to kill the
39638c8a9a5SSteve French 		 * socket so the server throws away the partial SMB
39738c8a9a5SSteve French 		 */
39838c8a9a5SSteve French 		cifs_signal_cifsd_for_reconnect(server, false);
39938c8a9a5SSteve French 		trace_smb3_partial_send_reconnect(server->CurrentMid,
40038c8a9a5SSteve French 						  server->conn_id, server->hostname);
40138c8a9a5SSteve French 	}
40238c8a9a5SSteve French smbd_done:
403c09de6bbSShyam Prasad N 	/*
404c09de6bbSShyam Prasad N 	 * there's hardly any use for the layers above to know the
405c09de6bbSShyam Prasad N 	 * actual error code here. All they should do at this point is
406c09de6bbSShyam Prasad N 	 * to retry the connection and hope it goes away.
407c09de6bbSShyam Prasad N 	 */
408c09de6bbSShyam Prasad N 	if (rc < 0 && rc != -EINTR && rc != -EAGAIN) {
40938c8a9a5SSteve French 		cifs_server_dbg(VFS, "Error %d sending data on socket to server\n",
41038c8a9a5SSteve French 			 rc);
411c09de6bbSShyam Prasad N 		rc = -ECONNABORTED;
412c09de6bbSShyam Prasad N 		cifs_signal_cifsd_for_reconnect(server, false);
413c09de6bbSShyam Prasad N 	} else if (rc > 0)
41438c8a9a5SSteve French 		rc = 0;
41538c8a9a5SSteve French out:
41638c8a9a5SSteve French 	cifs_in_send_dec(server);
41738c8a9a5SSteve French 	return rc;
41838c8a9a5SSteve French }
41938c8a9a5SSteve French 
420933148a4SPaulo Alcantara struct send_req_vars {
421933148a4SPaulo Alcantara 	struct smb2_transform_hdr tr_hdr;
422933148a4SPaulo Alcantara 	struct smb_rqst rqst[MAX_COMPOUND];
423933148a4SPaulo Alcantara 	struct kvec iov;
424933148a4SPaulo Alcantara };
425933148a4SPaulo Alcantara 
42638c8a9a5SSteve French static int
smb_send_rqst(struct TCP_Server_Info * server,int num_rqst,struct smb_rqst * rqst,int flags)42738c8a9a5SSteve French smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
42838c8a9a5SSteve French 	      struct smb_rqst *rqst, int flags)
42938c8a9a5SSteve French {
430933148a4SPaulo Alcantara 	struct send_req_vars *vars;
431933148a4SPaulo Alcantara 	struct smb_rqst *cur_rqst;
432933148a4SPaulo Alcantara 	struct kvec *iov;
43338c8a9a5SSteve French 	int rc;
43438c8a9a5SSteve French 
43538c8a9a5SSteve French 	if (!(flags & CIFS_TRANSFORM_REQ))
43638c8a9a5SSteve French 		return __smb_send_rqst(server, num_rqst, rqst);
43738c8a9a5SSteve French 
4382fdb5551SPaulo Alcantara 	if (WARN_ON_ONCE(num_rqst > MAX_COMPOUND - 1))
4392fdb5551SPaulo Alcantara 		return -EIO;
44038c8a9a5SSteve French 
44138c8a9a5SSteve French 	if (!server->ops->init_transform_rq) {
44238c8a9a5SSteve French 		cifs_server_dbg(VFS, "Encryption requested but transform callback is missing\n");
44338c8a9a5SSteve French 		return -EIO;
44438c8a9a5SSteve French 	}
44538c8a9a5SSteve French 
446933148a4SPaulo Alcantara 	vars = kzalloc(sizeof(*vars), GFP_NOFS);
447933148a4SPaulo Alcantara 	if (!vars)
44838c8a9a5SSteve French 		return -ENOMEM;
449933148a4SPaulo Alcantara 	cur_rqst = vars->rqst;
450933148a4SPaulo Alcantara 	iov = &vars->iov;
45138c8a9a5SSteve French 
452933148a4SPaulo Alcantara 	iov->iov_base = &vars->tr_hdr;
453933148a4SPaulo Alcantara 	iov->iov_len = sizeof(vars->tr_hdr);
454933148a4SPaulo Alcantara 	cur_rqst[0].rq_iov = iov;
45538c8a9a5SSteve French 	cur_rqst[0].rq_nvec = 1;
45638c8a9a5SSteve French 
45738c8a9a5SSteve French 	rc = server->ops->init_transform_rq(server, num_rqst + 1,
45838c8a9a5SSteve French 					    &cur_rqst[0], rqst);
45938c8a9a5SSteve French 	if (rc)
46038c8a9a5SSteve French 		goto out;
46138c8a9a5SSteve French 
46238c8a9a5SSteve French 	rc = __smb_send_rqst(server, num_rqst + 1, &cur_rqst[0]);
46338c8a9a5SSteve French 	smb3_free_compound_rqst(num_rqst, &cur_rqst[1]);
46438c8a9a5SSteve French out:
465933148a4SPaulo Alcantara 	kfree(vars);
46638c8a9a5SSteve French 	return rc;
46738c8a9a5SSteve French }
46838c8a9a5SSteve French 
46938c8a9a5SSteve French int
smb_send(struct TCP_Server_Info * server,struct smb_hdr * smb_buffer,unsigned int smb_buf_length)47038c8a9a5SSteve French smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
47138c8a9a5SSteve French 	 unsigned int smb_buf_length)
47238c8a9a5SSteve French {
47338c8a9a5SSteve French 	struct kvec iov[2];
47438c8a9a5SSteve French 	struct smb_rqst rqst = { .rq_iov = iov,
47538c8a9a5SSteve French 				 .rq_nvec = 2 };
47638c8a9a5SSteve French 
47738c8a9a5SSteve French 	iov[0].iov_base = smb_buffer;
47838c8a9a5SSteve French 	iov[0].iov_len = 4;
47938c8a9a5SSteve French 	iov[1].iov_base = (char *)smb_buffer + 4;
48038c8a9a5SSteve French 	iov[1].iov_len = smb_buf_length;
48138c8a9a5SSteve French 
48238c8a9a5SSteve French 	return __smb_send_rqst(server, 1, &rqst);
48338c8a9a5SSteve French }
48438c8a9a5SSteve French 
48538c8a9a5SSteve French static int
wait_for_free_credits(struct TCP_Server_Info * server,const int num_credits,const int timeout,const int flags,unsigned int * instance)48638c8a9a5SSteve French wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
48738c8a9a5SSteve French 		      const int timeout, const int flags,
48838c8a9a5SSteve French 		      unsigned int *instance)
48938c8a9a5SSteve French {
49038c8a9a5SSteve French 	long rc;
49138c8a9a5SSteve French 	int *credits;
49238c8a9a5SSteve French 	int optype;
49338c8a9a5SSteve French 	long int t;
49438c8a9a5SSteve French 	int scredits, in_flight;
49538c8a9a5SSteve French 
49638c8a9a5SSteve French 	if (timeout < 0)
49738c8a9a5SSteve French 		t = MAX_JIFFY_OFFSET;
49838c8a9a5SSteve French 	else
49938c8a9a5SSteve French 		t = msecs_to_jiffies(timeout);
50038c8a9a5SSteve French 
50138c8a9a5SSteve French 	optype = flags & CIFS_OP_MASK;
50238c8a9a5SSteve French 
50338c8a9a5SSteve French 	*instance = 0;
50438c8a9a5SSteve French 
50538c8a9a5SSteve French 	credits = server->ops->get_credits_field(server, optype);
50638c8a9a5SSteve French 	/* Since an echo is already inflight, no need to wait to send another */
50738c8a9a5SSteve French 	if (*credits <= 0 && optype == CIFS_ECHO_OP)
50838c8a9a5SSteve French 		return -EAGAIN;
50938c8a9a5SSteve French 
51038c8a9a5SSteve French 	spin_lock(&server->req_lock);
51138c8a9a5SSteve French 	if ((flags & CIFS_TIMEOUT_MASK) == CIFS_NON_BLOCKING) {
51238c8a9a5SSteve French 		/* oplock breaks must not be held up */
51338c8a9a5SSteve French 		server->in_flight++;
51438c8a9a5SSteve French 		if (server->in_flight > server->max_in_flight)
51538c8a9a5SSteve French 			server->max_in_flight = server->in_flight;
51638c8a9a5SSteve French 		*credits -= 1;
51738c8a9a5SSteve French 		*instance = server->reconnect_instance;
51838c8a9a5SSteve French 		scredits = *credits;
51938c8a9a5SSteve French 		in_flight = server->in_flight;
52038c8a9a5SSteve French 		spin_unlock(&server->req_lock);
52138c8a9a5SSteve French 
52238c8a9a5SSteve French 		trace_smb3_nblk_credits(server->CurrentMid,
52338c8a9a5SSteve French 				server->conn_id, server->hostname, scredits, -1, in_flight);
52438c8a9a5SSteve French 		cifs_dbg(FYI, "%s: remove %u credits total=%d\n",
52538c8a9a5SSteve French 				__func__, 1, scredits);
52638c8a9a5SSteve French 
52738c8a9a5SSteve French 		return 0;
52838c8a9a5SSteve French 	}
52938c8a9a5SSteve French 
53038c8a9a5SSteve French 	while (1) {
531326a8d04SShyam Prasad N 		spin_unlock(&server->req_lock);
532326a8d04SShyam Prasad N 
533326a8d04SShyam Prasad N 		spin_lock(&server->srv_lock);
534326a8d04SShyam Prasad N 		if (server->tcpStatus == CifsExiting) {
535326a8d04SShyam Prasad N 			spin_unlock(&server->srv_lock);
536326a8d04SShyam Prasad N 			return -ENOENT;
537326a8d04SShyam Prasad N 		}
538326a8d04SShyam Prasad N 		spin_unlock(&server->srv_lock);
539326a8d04SShyam Prasad N 
540326a8d04SShyam Prasad N 		spin_lock(&server->req_lock);
54138c8a9a5SSteve French 		if (*credits < num_credits) {
54238c8a9a5SSteve French 			scredits = *credits;
54338c8a9a5SSteve French 			spin_unlock(&server->req_lock);
54438c8a9a5SSteve French 
54538c8a9a5SSteve French 			cifs_num_waiters_inc(server);
54638c8a9a5SSteve French 			rc = wait_event_killable_timeout(server->request_q,
54738c8a9a5SSteve French 				has_credits(server, credits, num_credits), t);
54838c8a9a5SSteve French 			cifs_num_waiters_dec(server);
54938c8a9a5SSteve French 			if (!rc) {
55038c8a9a5SSteve French 				spin_lock(&server->req_lock);
55138c8a9a5SSteve French 				scredits = *credits;
55238c8a9a5SSteve French 				in_flight = server->in_flight;
55338c8a9a5SSteve French 				spin_unlock(&server->req_lock);
55438c8a9a5SSteve French 
55538c8a9a5SSteve French 				trace_smb3_credit_timeout(server->CurrentMid,
55638c8a9a5SSteve French 						server->conn_id, server->hostname, scredits,
55738c8a9a5SSteve French 						num_credits, in_flight);
55838c8a9a5SSteve French 				cifs_server_dbg(VFS, "wait timed out after %d ms\n",
55938c8a9a5SSteve French 						timeout);
56038c8a9a5SSteve French 				return -EBUSY;
56138c8a9a5SSteve French 			}
56238c8a9a5SSteve French 			if (rc == -ERESTARTSYS)
56338c8a9a5SSteve French 				return -ERESTARTSYS;
56438c8a9a5SSteve French 			spin_lock(&server->req_lock);
56538c8a9a5SSteve French 		} else {
56638c8a9a5SSteve French 			/*
56738c8a9a5SSteve French 			 * For normal commands, reserve the last MAX_COMPOUND
56838c8a9a5SSteve French 			 * credits to compound requests.
56938c8a9a5SSteve French 			 * Otherwise these compounds could be permanently
57038c8a9a5SSteve French 			 * starved for credits by single-credit requests.
57138c8a9a5SSteve French 			 *
57238c8a9a5SSteve French 			 * To prevent spinning CPU, block this thread until
57338c8a9a5SSteve French 			 * there are >MAX_COMPOUND credits available.
57438c8a9a5SSteve French 			 * But only do this is we already have a lot of
57538c8a9a5SSteve French 			 * credits in flight to avoid triggering this check
57638c8a9a5SSteve French 			 * for servers that are slow to hand out credits on
57738c8a9a5SSteve French 			 * new sessions.
57838c8a9a5SSteve French 			 */
57938c8a9a5SSteve French 			if (!optype && num_credits == 1 &&
58038c8a9a5SSteve French 			    server->in_flight > 2 * MAX_COMPOUND &&
58138c8a9a5SSteve French 			    *credits <= MAX_COMPOUND) {
58238c8a9a5SSteve French 				spin_unlock(&server->req_lock);
58338c8a9a5SSteve French 
58438c8a9a5SSteve French 				cifs_num_waiters_inc(server);
58538c8a9a5SSteve French 				rc = wait_event_killable_timeout(
58638c8a9a5SSteve French 					server->request_q,
58738c8a9a5SSteve French 					has_credits(server, credits,
58838c8a9a5SSteve French 						    MAX_COMPOUND + 1),
58938c8a9a5SSteve French 					t);
59038c8a9a5SSteve French 				cifs_num_waiters_dec(server);
59138c8a9a5SSteve French 				if (!rc) {
59238c8a9a5SSteve French 					spin_lock(&server->req_lock);
59338c8a9a5SSteve French 					scredits = *credits;
59438c8a9a5SSteve French 					in_flight = server->in_flight;
59538c8a9a5SSteve French 					spin_unlock(&server->req_lock);
59638c8a9a5SSteve French 
59738c8a9a5SSteve French 					trace_smb3_credit_timeout(
59838c8a9a5SSteve French 							server->CurrentMid,
59938c8a9a5SSteve French 							server->conn_id, server->hostname,
60038c8a9a5SSteve French 							scredits, num_credits, in_flight);
60138c8a9a5SSteve French 					cifs_server_dbg(VFS, "wait timed out after %d ms\n",
60238c8a9a5SSteve French 							timeout);
60338c8a9a5SSteve French 					return -EBUSY;
60438c8a9a5SSteve French 				}
60538c8a9a5SSteve French 				if (rc == -ERESTARTSYS)
60638c8a9a5SSteve French 					return -ERESTARTSYS;
60738c8a9a5SSteve French 				spin_lock(&server->req_lock);
60838c8a9a5SSteve French 				continue;
60938c8a9a5SSteve French 			}
61038c8a9a5SSteve French 
61138c8a9a5SSteve French 			/*
61238c8a9a5SSteve French 			 * Can not count locking commands against total
61338c8a9a5SSteve French 			 * as they are allowed to block on server.
61438c8a9a5SSteve French 			 */
61538c8a9a5SSteve French 
61638c8a9a5SSteve French 			/* update # of requests on the wire to server */
61738c8a9a5SSteve French 			if ((flags & CIFS_TIMEOUT_MASK) != CIFS_BLOCKING_OP) {
61838c8a9a5SSteve French 				*credits -= num_credits;
61938c8a9a5SSteve French 				server->in_flight += num_credits;
62038c8a9a5SSteve French 				if (server->in_flight > server->max_in_flight)
62138c8a9a5SSteve French 					server->max_in_flight = server->in_flight;
62238c8a9a5SSteve French 				*instance = server->reconnect_instance;
62338c8a9a5SSteve French 			}
62438c8a9a5SSteve French 			scredits = *credits;
62538c8a9a5SSteve French 			in_flight = server->in_flight;
62638c8a9a5SSteve French 			spin_unlock(&server->req_lock);
62738c8a9a5SSteve French 
62838c8a9a5SSteve French 			trace_smb3_waitff_credits(server->CurrentMid,
62938c8a9a5SSteve French 					server->conn_id, server->hostname, scredits,
63038c8a9a5SSteve French 					-(num_credits), in_flight);
63138c8a9a5SSteve French 			cifs_dbg(FYI, "%s: remove %u credits total=%d\n",
63238c8a9a5SSteve French 					__func__, num_credits, scredits);
63338c8a9a5SSteve French 			break;
63438c8a9a5SSteve French 		}
63538c8a9a5SSteve French 	}
63638c8a9a5SSteve French 	return 0;
63738c8a9a5SSteve French }
63838c8a9a5SSteve French 
63938c8a9a5SSteve French static int
wait_for_free_request(struct TCP_Server_Info * server,const int flags,unsigned int * instance)64038c8a9a5SSteve French wait_for_free_request(struct TCP_Server_Info *server, const int flags,
64138c8a9a5SSteve French 		      unsigned int *instance)
64238c8a9a5SSteve French {
64338c8a9a5SSteve French 	return wait_for_free_credits(server, 1, -1, flags,
64438c8a9a5SSteve French 				     instance);
64538c8a9a5SSteve French }
64638c8a9a5SSteve French 
64738c8a9a5SSteve French static int
wait_for_compound_request(struct TCP_Server_Info * server,int num,const int flags,unsigned int * instance)64838c8a9a5SSteve French wait_for_compound_request(struct TCP_Server_Info *server, int num,
64938c8a9a5SSteve French 			  const int flags, unsigned int *instance)
65038c8a9a5SSteve French {
65138c8a9a5SSteve French 	int *credits;
65238c8a9a5SSteve French 	int scredits, in_flight;
65338c8a9a5SSteve French 
65438c8a9a5SSteve French 	credits = server->ops->get_credits_field(server, flags & CIFS_OP_MASK);
65538c8a9a5SSteve French 
65638c8a9a5SSteve French 	spin_lock(&server->req_lock);
65738c8a9a5SSteve French 	scredits = *credits;
65838c8a9a5SSteve French 	in_flight = server->in_flight;
65938c8a9a5SSteve French 
66038c8a9a5SSteve French 	if (*credits < num) {
66138c8a9a5SSteve French 		/*
66238c8a9a5SSteve French 		 * If the server is tight on resources or just gives us less
66338c8a9a5SSteve French 		 * credits for other reasons (e.g. requests are coming out of
66438c8a9a5SSteve French 		 * order and the server delays granting more credits until it
66538c8a9a5SSteve French 		 * processes a missing mid) and we exhausted most available
66638c8a9a5SSteve French 		 * credits there may be situations when we try to send
66738c8a9a5SSteve French 		 * a compound request but we don't have enough credits. At this
66838c8a9a5SSteve French 		 * point the client needs to decide if it should wait for
66938c8a9a5SSteve French 		 * additional credits or fail the request. If at least one
67038c8a9a5SSteve French 		 * request is in flight there is a high probability that the
67138c8a9a5SSteve French 		 * server will return enough credits to satisfy this compound
67238c8a9a5SSteve French 		 * request.
67338c8a9a5SSteve French 		 *
67438c8a9a5SSteve French 		 * Return immediately if no requests in flight since we will be
67538c8a9a5SSteve French 		 * stuck on waiting for credits.
67638c8a9a5SSteve French 		 */
67738c8a9a5SSteve French 		if (server->in_flight == 0) {
67838c8a9a5SSteve French 			spin_unlock(&server->req_lock);
67938c8a9a5SSteve French 			trace_smb3_insufficient_credits(server->CurrentMid,
68038c8a9a5SSteve French 					server->conn_id, server->hostname, scredits,
68138c8a9a5SSteve French 					num, in_flight);
68238c8a9a5SSteve French 			cifs_dbg(FYI, "%s: %d requests in flight, needed %d total=%d\n",
68338c8a9a5SSteve French 					__func__, in_flight, num, scredits);
68438c8a9a5SSteve French 			return -EDEADLK;
68538c8a9a5SSteve French 		}
68638c8a9a5SSteve French 	}
68738c8a9a5SSteve French 	spin_unlock(&server->req_lock);
68838c8a9a5SSteve French 
68938c8a9a5SSteve French 	return wait_for_free_credits(server, num, 60000, flags,
69038c8a9a5SSteve French 				     instance);
69138c8a9a5SSteve French }
69238c8a9a5SSteve French 
69338c8a9a5SSteve French int
cifs_wait_mtu_credits(struct TCP_Server_Info * server,unsigned int size,unsigned int * num,struct cifs_credits * credits)69438c8a9a5SSteve French cifs_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
69538c8a9a5SSteve French 		      unsigned int *num, struct cifs_credits *credits)
69638c8a9a5SSteve French {
69738c8a9a5SSteve French 	*num = size;
69838c8a9a5SSteve French 	credits->value = 0;
69938c8a9a5SSteve French 	credits->instance = server->reconnect_instance;
70038c8a9a5SSteve French 	return 0;
70138c8a9a5SSteve French }
70238c8a9a5SSteve French 
allocate_mid(struct cifs_ses * ses,struct smb_hdr * in_buf,struct mid_q_entry ** ppmidQ)70338c8a9a5SSteve French static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
70438c8a9a5SSteve French 			struct mid_q_entry **ppmidQ)
70538c8a9a5SSteve French {
70638c8a9a5SSteve French 	spin_lock(&ses->ses_lock);
70738c8a9a5SSteve French 	if (ses->ses_status == SES_NEW) {
70838c8a9a5SSteve French 		if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
70938c8a9a5SSteve French 			(in_buf->Command != SMB_COM_NEGOTIATE)) {
71038c8a9a5SSteve French 			spin_unlock(&ses->ses_lock);
71138c8a9a5SSteve French 			return -EAGAIN;
71238c8a9a5SSteve French 		}
71338c8a9a5SSteve French 		/* else ok - we are setting up session */
71438c8a9a5SSteve French 	}
71538c8a9a5SSteve French 
71638c8a9a5SSteve French 	if (ses->ses_status == SES_EXITING) {
71738c8a9a5SSteve French 		/* check if SMB session is bad because we are setting it up */
71838c8a9a5SSteve French 		if (in_buf->Command != SMB_COM_LOGOFF_ANDX) {
71938c8a9a5SSteve French 			spin_unlock(&ses->ses_lock);
72038c8a9a5SSteve French 			return -EAGAIN;
72138c8a9a5SSteve French 		}
72238c8a9a5SSteve French 		/* else ok - we are shutting down session */
72338c8a9a5SSteve French 	}
72438c8a9a5SSteve French 	spin_unlock(&ses->ses_lock);
72538c8a9a5SSteve French 
72638c8a9a5SSteve French 	*ppmidQ = alloc_mid(in_buf, ses->server);
72738c8a9a5SSteve French 	if (*ppmidQ == NULL)
72838c8a9a5SSteve French 		return -ENOMEM;
72938c8a9a5SSteve French 	spin_lock(&ses->server->mid_lock);
73038c8a9a5SSteve French 	list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q);
73138c8a9a5SSteve French 	spin_unlock(&ses->server->mid_lock);
73238c8a9a5SSteve French 	return 0;
73338c8a9a5SSteve French }
73438c8a9a5SSteve French 
73538c8a9a5SSteve French static int
wait_for_response(struct TCP_Server_Info * server,struct mid_q_entry * midQ)73638c8a9a5SSteve French wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
73738c8a9a5SSteve French {
73838c8a9a5SSteve French 	int error;
73938c8a9a5SSteve French 
74038c8a9a5SSteve French 	error = wait_event_state(server->response_q,
741d527f513SZhang Xiaoxu 				 midQ->mid_state != MID_REQUEST_SUBMITTED &&
742d527f513SZhang Xiaoxu 				 midQ->mid_state != MID_RESPONSE_RECEIVED,
74338c8a9a5SSteve French 				 (TASK_KILLABLE|TASK_FREEZABLE_UNSAFE));
74438c8a9a5SSteve French 	if (error < 0)
74538c8a9a5SSteve French 		return -ERESTARTSYS;
74638c8a9a5SSteve French 
74738c8a9a5SSteve French 	return 0;
74838c8a9a5SSteve French }
74938c8a9a5SSteve French 
75038c8a9a5SSteve French struct mid_q_entry *
cifs_setup_async_request(struct TCP_Server_Info * server,struct smb_rqst * rqst)75138c8a9a5SSteve French cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
75238c8a9a5SSteve French {
75338c8a9a5SSteve French 	int rc;
75438c8a9a5SSteve French 	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
75538c8a9a5SSteve French 	struct mid_q_entry *mid;
75638c8a9a5SSteve French 
75738c8a9a5SSteve French 	if (rqst->rq_iov[0].iov_len != 4 ||
75838c8a9a5SSteve French 	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
75938c8a9a5SSteve French 		return ERR_PTR(-EIO);
76038c8a9a5SSteve French 
76138c8a9a5SSteve French 	/* enable signing if server requires it */
76238c8a9a5SSteve French 	if (server->sign)
76338c8a9a5SSteve French 		hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
76438c8a9a5SSteve French 
76538c8a9a5SSteve French 	mid = alloc_mid(hdr, server);
76638c8a9a5SSteve French 	if (mid == NULL)
76738c8a9a5SSteve French 		return ERR_PTR(-ENOMEM);
76838c8a9a5SSteve French 
76938c8a9a5SSteve French 	rc = cifs_sign_rqst(rqst, server, &mid->sequence_number);
77038c8a9a5SSteve French 	if (rc) {
77138c8a9a5SSteve French 		release_mid(mid);
77238c8a9a5SSteve French 		return ERR_PTR(rc);
77338c8a9a5SSteve French 	}
77438c8a9a5SSteve French 
77538c8a9a5SSteve French 	return mid;
77638c8a9a5SSteve French }
77738c8a9a5SSteve French 
77838c8a9a5SSteve French /*
77938c8a9a5SSteve French  * Send a SMB request and set the callback function in the mid to handle
78038c8a9a5SSteve French  * the result. Caller is responsible for dealing with timeouts.
78138c8a9a5SSteve French  */
78238c8a9a5SSteve French 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)78338c8a9a5SSteve French cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
78438c8a9a5SSteve French 		mid_receive_t *receive, mid_callback_t *callback,
78538c8a9a5SSteve French 		mid_handle_t *handle, void *cbdata, const int flags,
78638c8a9a5SSteve French 		const struct cifs_credits *exist_credits)
78738c8a9a5SSteve French {
78838c8a9a5SSteve French 	int rc;
78938c8a9a5SSteve French 	struct mid_q_entry *mid;
79038c8a9a5SSteve French 	struct cifs_credits credits = { .value = 0, .instance = 0 };
79138c8a9a5SSteve French 	unsigned int instance;
79238c8a9a5SSteve French 	int optype;
79338c8a9a5SSteve French 
79438c8a9a5SSteve French 	optype = flags & CIFS_OP_MASK;
79538c8a9a5SSteve French 
79638c8a9a5SSteve French 	if ((flags & CIFS_HAS_CREDITS) == 0) {
79738c8a9a5SSteve French 		rc = wait_for_free_request(server, flags, &instance);
79838c8a9a5SSteve French 		if (rc)
79938c8a9a5SSteve French 			return rc;
80038c8a9a5SSteve French 		credits.value = 1;
80138c8a9a5SSteve French 		credits.instance = instance;
80238c8a9a5SSteve French 	} else
80338c8a9a5SSteve French 		instance = exist_credits->instance;
80438c8a9a5SSteve French 
80538c8a9a5SSteve French 	cifs_server_lock(server);
80638c8a9a5SSteve French 
80738c8a9a5SSteve French 	/*
80838c8a9a5SSteve French 	 * We can't use credits obtained from the previous session to send this
80938c8a9a5SSteve French 	 * request. Check if there were reconnects after we obtained credits and
81038c8a9a5SSteve French 	 * return -EAGAIN in such cases to let callers handle it.
81138c8a9a5SSteve French 	 */
81238c8a9a5SSteve French 	if (instance != server->reconnect_instance) {
81338c8a9a5SSteve French 		cifs_server_unlock(server);
81438c8a9a5SSteve French 		add_credits_and_wake_if(server, &credits, optype);
81538c8a9a5SSteve French 		return -EAGAIN;
81638c8a9a5SSteve French 	}
81738c8a9a5SSteve French 
81838c8a9a5SSteve French 	mid = server->ops->setup_async_request(server, rqst);
81938c8a9a5SSteve French 	if (IS_ERR(mid)) {
82038c8a9a5SSteve French 		cifs_server_unlock(server);
82138c8a9a5SSteve French 		add_credits_and_wake_if(server, &credits, optype);
82238c8a9a5SSteve French 		return PTR_ERR(mid);
82338c8a9a5SSteve French 	}
82438c8a9a5SSteve French 
82538c8a9a5SSteve French 	mid->receive = receive;
82638c8a9a5SSteve French 	mid->callback = callback;
82738c8a9a5SSteve French 	mid->callback_data = cbdata;
82838c8a9a5SSteve French 	mid->handle = handle;
82938c8a9a5SSteve French 	mid->mid_state = MID_REQUEST_SUBMITTED;
83038c8a9a5SSteve French 
83138c8a9a5SSteve French 	/* put it on the pending_mid_q */
83238c8a9a5SSteve French 	spin_lock(&server->mid_lock);
83338c8a9a5SSteve French 	list_add_tail(&mid->qhead, &server->pending_mid_q);
83438c8a9a5SSteve French 	spin_unlock(&server->mid_lock);
83538c8a9a5SSteve French 
83638c8a9a5SSteve French 	/*
83738c8a9a5SSteve French 	 * Need to store the time in mid before calling I/O. For call_async,
83838c8a9a5SSteve French 	 * I/O response may come back and free the mid entry on another thread.
83938c8a9a5SSteve French 	 */
84038c8a9a5SSteve French 	cifs_save_when_sent(mid);
84138c8a9a5SSteve French 	rc = smb_send_rqst(server, 1, rqst, flags);
84238c8a9a5SSteve French 
84338c8a9a5SSteve French 	if (rc < 0) {
84438c8a9a5SSteve French 		revert_current_mid(server, mid->credits);
84538c8a9a5SSteve French 		server->sequence_number -= 2;
84638c8a9a5SSteve French 		delete_mid(mid);
84738c8a9a5SSteve French 	}
84838c8a9a5SSteve French 
84938c8a9a5SSteve French 	cifs_server_unlock(server);
85038c8a9a5SSteve French 
85138c8a9a5SSteve French 	if (rc == 0)
85238c8a9a5SSteve French 		return 0;
85338c8a9a5SSteve French 
85438c8a9a5SSteve French 	add_credits_and_wake_if(server, &credits, optype);
85538c8a9a5SSteve French 	return rc;
85638c8a9a5SSteve French }
85738c8a9a5SSteve French 
85838c8a9a5SSteve French /*
85938c8a9a5SSteve French  *
86038c8a9a5SSteve French  * Send an SMB Request.  No response info (other than return code)
86138c8a9a5SSteve French  * needs to be parsed.
86238c8a9a5SSteve French  *
86338c8a9a5SSteve French  * flags indicate the type of request buffer and how long to wait
86438c8a9a5SSteve French  * and whether to log NT STATUS code (error) before mapping it to POSIX error
86538c8a9a5SSteve French  *
86638c8a9a5SSteve French  */
86738c8a9a5SSteve French int
SendReceiveNoRsp(const unsigned int xid,struct cifs_ses * ses,char * in_buf,int flags)86838c8a9a5SSteve French SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
86938c8a9a5SSteve French 		 char *in_buf, int flags)
87038c8a9a5SSteve French {
87138c8a9a5SSteve French 	int rc;
87238c8a9a5SSteve French 	struct kvec iov[1];
87338c8a9a5SSteve French 	struct kvec rsp_iov;
87438c8a9a5SSteve French 	int resp_buf_type;
87538c8a9a5SSteve French 
87638c8a9a5SSteve French 	iov[0].iov_base = in_buf;
87738c8a9a5SSteve French 	iov[0].iov_len = get_rfc1002_length(in_buf) + 4;
87838c8a9a5SSteve French 	flags |= CIFS_NO_RSP_BUF;
87938c8a9a5SSteve French 	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
88038c8a9a5SSteve French 	cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc);
88138c8a9a5SSteve French 
88238c8a9a5SSteve French 	return rc;
88338c8a9a5SSteve French }
88438c8a9a5SSteve French 
88538c8a9a5SSteve French static int
cifs_sync_mid_result(struct mid_q_entry * mid,struct TCP_Server_Info * server)88638c8a9a5SSteve French cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
88738c8a9a5SSteve French {
88838c8a9a5SSteve French 	int rc = 0;
88938c8a9a5SSteve French 
89038c8a9a5SSteve French 	cifs_dbg(FYI, "%s: cmd=%d mid=%llu state=%d\n",
89138c8a9a5SSteve French 		 __func__, le16_to_cpu(mid->command), mid->mid, mid->mid_state);
89238c8a9a5SSteve French 
89338c8a9a5SSteve French 	spin_lock(&server->mid_lock);
89438c8a9a5SSteve French 	switch (mid->mid_state) {
895d527f513SZhang Xiaoxu 	case MID_RESPONSE_READY:
89638c8a9a5SSteve French 		spin_unlock(&server->mid_lock);
89738c8a9a5SSteve French 		return rc;
89838c8a9a5SSteve French 	case MID_RETRY_NEEDED:
89938c8a9a5SSteve French 		rc = -EAGAIN;
90038c8a9a5SSteve French 		break;
90138c8a9a5SSteve French 	case MID_RESPONSE_MALFORMED:
90238c8a9a5SSteve French 		rc = -EIO;
90338c8a9a5SSteve French 		break;
90438c8a9a5SSteve French 	case MID_SHUTDOWN:
90538c8a9a5SSteve French 		rc = -EHOSTDOWN;
90638c8a9a5SSteve French 		break;
90738c8a9a5SSteve French 	default:
90838c8a9a5SSteve French 		if (!(mid->mid_flags & MID_DELETED)) {
90938c8a9a5SSteve French 			list_del_init(&mid->qhead);
91038c8a9a5SSteve French 			mid->mid_flags |= MID_DELETED;
91138c8a9a5SSteve French 		}
912*699f8958SSteve French 		spin_unlock(&server->mid_lock);
91338c8a9a5SSteve French 		cifs_server_dbg(VFS, "%s: invalid mid state mid=%llu state=%d\n",
91438c8a9a5SSteve French 			 __func__, mid->mid, mid->mid_state);
91538c8a9a5SSteve French 		rc = -EIO;
916*699f8958SSteve French 		goto sync_mid_done;
91738c8a9a5SSteve French 	}
91838c8a9a5SSteve French 	spin_unlock(&server->mid_lock);
91938c8a9a5SSteve French 
920*699f8958SSteve French sync_mid_done:
92138c8a9a5SSteve French 	release_mid(mid);
92238c8a9a5SSteve French 	return rc;
92338c8a9a5SSteve French }
92438c8a9a5SSteve French 
92538c8a9a5SSteve French static inline int
send_cancel(struct TCP_Server_Info * server,struct smb_rqst * rqst,struct mid_q_entry * mid)92638c8a9a5SSteve French send_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
92738c8a9a5SSteve French 	    struct mid_q_entry *mid)
92838c8a9a5SSteve French {
92938c8a9a5SSteve French 	return server->ops->send_cancel ?
93038c8a9a5SSteve French 				server->ops->send_cancel(server, rqst, mid) : 0;
93138c8a9a5SSteve French }
93238c8a9a5SSteve French 
93338c8a9a5SSteve French int
cifs_check_receive(struct mid_q_entry * mid,struct TCP_Server_Info * server,bool log_error)93438c8a9a5SSteve French cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
93538c8a9a5SSteve French 		   bool log_error)
93638c8a9a5SSteve French {
93738c8a9a5SSteve French 	unsigned int len = get_rfc1002_length(mid->resp_buf) + 4;
93838c8a9a5SSteve French 
93938c8a9a5SSteve French 	dump_smb(mid->resp_buf, min_t(u32, 92, len));
94038c8a9a5SSteve French 
94138c8a9a5SSteve French 	/* convert the length into a more usable form */
94238c8a9a5SSteve French 	if (server->sign) {
94338c8a9a5SSteve French 		struct kvec iov[2];
94438c8a9a5SSteve French 		int rc = 0;
94538c8a9a5SSteve French 		struct smb_rqst rqst = { .rq_iov = iov,
94638c8a9a5SSteve French 					 .rq_nvec = 2 };
94738c8a9a5SSteve French 
94838c8a9a5SSteve French 		iov[0].iov_base = mid->resp_buf;
94938c8a9a5SSteve French 		iov[0].iov_len = 4;
95038c8a9a5SSteve French 		iov[1].iov_base = (char *)mid->resp_buf + 4;
95138c8a9a5SSteve French 		iov[1].iov_len = len - 4;
95238c8a9a5SSteve French 		/* FIXME: add code to kill session */
95338c8a9a5SSteve French 		rc = cifs_verify_signature(&rqst, server,
95438c8a9a5SSteve French 					   mid->sequence_number);
95538c8a9a5SSteve French 		if (rc)
95638c8a9a5SSteve French 			cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n",
95738c8a9a5SSteve French 				 rc);
95838c8a9a5SSteve French 	}
95938c8a9a5SSteve French 
96038c8a9a5SSteve French 	/* BB special case reconnect tid and uid here? */
96138c8a9a5SSteve French 	return map_and_check_smb_error(mid, log_error);
96238c8a9a5SSteve French }
96338c8a9a5SSteve French 
96438c8a9a5SSteve French struct mid_q_entry *
cifs_setup_request(struct cifs_ses * ses,struct TCP_Server_Info * ignored,struct smb_rqst * rqst)96538c8a9a5SSteve French cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *ignored,
96638c8a9a5SSteve French 		   struct smb_rqst *rqst)
96738c8a9a5SSteve French {
96838c8a9a5SSteve French 	int rc;
96938c8a9a5SSteve French 	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
97038c8a9a5SSteve French 	struct mid_q_entry *mid;
97138c8a9a5SSteve French 
97238c8a9a5SSteve French 	if (rqst->rq_iov[0].iov_len != 4 ||
97338c8a9a5SSteve French 	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
97438c8a9a5SSteve French 		return ERR_PTR(-EIO);
97538c8a9a5SSteve French 
97638c8a9a5SSteve French 	rc = allocate_mid(ses, hdr, &mid);
97738c8a9a5SSteve French 	if (rc)
97838c8a9a5SSteve French 		return ERR_PTR(rc);
97938c8a9a5SSteve French 	rc = cifs_sign_rqst(rqst, ses->server, &mid->sequence_number);
98038c8a9a5SSteve French 	if (rc) {
98138c8a9a5SSteve French 		delete_mid(mid);
98238c8a9a5SSteve French 		return ERR_PTR(rc);
98338c8a9a5SSteve French 	}
98438c8a9a5SSteve French 	return mid;
98538c8a9a5SSteve French }
98638c8a9a5SSteve French 
98738c8a9a5SSteve French static void
cifs_compound_callback(struct mid_q_entry * mid)98838c8a9a5SSteve French cifs_compound_callback(struct mid_q_entry *mid)
98938c8a9a5SSteve French {
99038c8a9a5SSteve French 	struct TCP_Server_Info *server = mid->server;
99138c8a9a5SSteve French 	struct cifs_credits credits;
99238c8a9a5SSteve French 
99338c8a9a5SSteve French 	credits.value = server->ops->get_credits(mid);
99438c8a9a5SSteve French 	credits.instance = server->reconnect_instance;
99538c8a9a5SSteve French 
99638c8a9a5SSteve French 	add_credits(server, &credits, mid->optype);
997d527f513SZhang Xiaoxu 
998d527f513SZhang Xiaoxu 	if (mid->mid_state == MID_RESPONSE_RECEIVED)
999d527f513SZhang Xiaoxu 		mid->mid_state = MID_RESPONSE_READY;
100038c8a9a5SSteve French }
100138c8a9a5SSteve French 
100238c8a9a5SSteve French static void
cifs_compound_last_callback(struct mid_q_entry * mid)100338c8a9a5SSteve French cifs_compound_last_callback(struct mid_q_entry *mid)
100438c8a9a5SSteve French {
100538c8a9a5SSteve French 	cifs_compound_callback(mid);
100638c8a9a5SSteve French 	cifs_wake_up_task(mid);
100738c8a9a5SSteve French }
100838c8a9a5SSteve French 
100938c8a9a5SSteve French static void
cifs_cancelled_callback(struct mid_q_entry * mid)101038c8a9a5SSteve French cifs_cancelled_callback(struct mid_q_entry *mid)
101138c8a9a5SSteve French {
101238c8a9a5SSteve French 	cifs_compound_callback(mid);
101338c8a9a5SSteve French 	release_mid(mid);
101438c8a9a5SSteve French }
101538c8a9a5SSteve French 
101638c8a9a5SSteve French /*
101738c8a9a5SSteve French  * Return a channel (master if none) of @ses that can be used to send
101838c8a9a5SSteve French  * regular requests.
101938c8a9a5SSteve French  *
102038c8a9a5SSteve French  * If we are currently binding a new channel (negprot/sess.setup),
102138c8a9a5SSteve French  * return the new incomplete channel.
102238c8a9a5SSteve French  */
cifs_pick_channel(struct cifs_ses * ses)102338c8a9a5SSteve French struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses)
102438c8a9a5SSteve French {
102538c8a9a5SSteve French 	uint index = 0;
102638c8a9a5SSteve French 	unsigned int min_in_flight = UINT_MAX, max_in_flight = 0;
102738c8a9a5SSteve French 	struct TCP_Server_Info *server = NULL;
102838c8a9a5SSteve French 	int i;
102938c8a9a5SSteve French 
103038c8a9a5SSteve French 	if (!ses)
103138c8a9a5SSteve French 		return NULL;
103238c8a9a5SSteve French 
103338c8a9a5SSteve French 	spin_lock(&ses->chan_lock);
103438c8a9a5SSteve French 	for (i = 0; i < ses->chan_count; i++) {
103538c8a9a5SSteve French 		server = ses->chans[i].server;
10363e161536SShyam Prasad N 		if (!server || server->terminate)
103738c8a9a5SSteve French 			continue;
103838c8a9a5SSteve French 
103959e04d39SShyam Prasad N 		if (CIFS_CHAN_NEEDS_RECONNECT(ses, i))
104059e04d39SShyam Prasad N 			continue;
104159e04d39SShyam Prasad N 
104238c8a9a5SSteve French 		/*
104338c8a9a5SSteve French 		 * strictly speaking, we should pick up req_lock to read
104438c8a9a5SSteve French 		 * server->in_flight. But it shouldn't matter much here if we
104538c8a9a5SSteve French 		 * race while reading this data. The worst that can happen is
104638c8a9a5SSteve French 		 * that we could use a channel that's not least loaded. Avoiding
104738c8a9a5SSteve French 		 * taking the lock could help reduce wait time, which is
104838c8a9a5SSteve French 		 * important for this function
104938c8a9a5SSteve French 		 */
105038c8a9a5SSteve French 		if (server->in_flight < min_in_flight) {
105138c8a9a5SSteve French 			min_in_flight = server->in_flight;
105238c8a9a5SSteve French 			index = i;
105338c8a9a5SSteve French 		}
105438c8a9a5SSteve French 		if (server->in_flight > max_in_flight)
105538c8a9a5SSteve French 			max_in_flight = server->in_flight;
105638c8a9a5SSteve French 	}
105738c8a9a5SSteve French 
105838c8a9a5SSteve French 	/* if all channels are equally loaded, fall back to round-robin */
105938c8a9a5SSteve French 	if (min_in_flight == max_in_flight) {
106038c8a9a5SSteve French 		index = (uint)atomic_inc_return(&ses->chan_seq);
106138c8a9a5SSteve French 		index %= ses->chan_count;
106238c8a9a5SSteve French 	}
10630fcf7e21SSteve French 
10640fcf7e21SSteve French 	server = ses->chans[index].server;
106538c8a9a5SSteve French 	spin_unlock(&ses->chan_lock);
106638c8a9a5SSteve French 
10670fcf7e21SSteve French 	return server;
106838c8a9a5SSteve French }
106938c8a9a5SSteve French 
107038c8a9a5SSteve French int
compound_send_recv(const unsigned int xid,struct cifs_ses * ses,struct TCP_Server_Info * server,const int flags,const int num_rqst,struct smb_rqst * rqst,int * resp_buf_type,struct kvec * resp_iov)107138c8a9a5SSteve French compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
107238c8a9a5SSteve French 		   struct TCP_Server_Info *server,
107338c8a9a5SSteve French 		   const int flags, const int num_rqst, struct smb_rqst *rqst,
107438c8a9a5SSteve French 		   int *resp_buf_type, struct kvec *resp_iov)
107538c8a9a5SSteve French {
107638c8a9a5SSteve French 	int i, j, optype, rc = 0;
107738c8a9a5SSteve French 	struct mid_q_entry *midQ[MAX_COMPOUND];
107838c8a9a5SSteve French 	bool cancelled_mid[MAX_COMPOUND] = {false};
107938c8a9a5SSteve French 	struct cifs_credits credits[MAX_COMPOUND] = {
108038c8a9a5SSteve French 		{ .value = 0, .instance = 0 }
108138c8a9a5SSteve French 	};
108238c8a9a5SSteve French 	unsigned int instance;
108338c8a9a5SSteve French 	char *buf;
108438c8a9a5SSteve French 
108538c8a9a5SSteve French 	optype = flags & CIFS_OP_MASK;
108638c8a9a5SSteve French 
108738c8a9a5SSteve French 	for (i = 0; i < num_rqst; i++)
108838c8a9a5SSteve French 		resp_buf_type[i] = CIFS_NO_BUFFER;  /* no response buf yet */
108938c8a9a5SSteve French 
109038c8a9a5SSteve French 	if (!ses || !ses->server || !server) {
109138c8a9a5SSteve French 		cifs_dbg(VFS, "Null session\n");
109238c8a9a5SSteve French 		return -EIO;
109338c8a9a5SSteve French 	}
109438c8a9a5SSteve French 
109538c8a9a5SSteve French 	spin_lock(&server->srv_lock);
109638c8a9a5SSteve French 	if (server->tcpStatus == CifsExiting) {
109738c8a9a5SSteve French 		spin_unlock(&server->srv_lock);
109838c8a9a5SSteve French 		return -ENOENT;
109938c8a9a5SSteve French 	}
110038c8a9a5SSteve French 	spin_unlock(&server->srv_lock);
110138c8a9a5SSteve French 
110238c8a9a5SSteve French 	/*
110338c8a9a5SSteve French 	 * Wait for all the requests to become available.
110438c8a9a5SSteve French 	 * This approach still leaves the possibility to be stuck waiting for
110538c8a9a5SSteve French 	 * credits if the server doesn't grant credits to the outstanding
110638c8a9a5SSteve French 	 * requests and if the client is completely idle, not generating any
110738c8a9a5SSteve French 	 * other requests.
110838c8a9a5SSteve French 	 * This can be handled by the eventual session reconnect.
110938c8a9a5SSteve French 	 */
111038c8a9a5SSteve French 	rc = wait_for_compound_request(server, num_rqst, flags,
111138c8a9a5SSteve French 				       &instance);
111238c8a9a5SSteve French 	if (rc)
111338c8a9a5SSteve French 		return rc;
111438c8a9a5SSteve French 
111538c8a9a5SSteve French 	for (i = 0; i < num_rqst; i++) {
111638c8a9a5SSteve French 		credits[i].value = 1;
111738c8a9a5SSteve French 		credits[i].instance = instance;
111838c8a9a5SSteve French 	}
111938c8a9a5SSteve French 
112038c8a9a5SSteve French 	/*
112138c8a9a5SSteve French 	 * Make sure that we sign in the same order that we send on this socket
112238c8a9a5SSteve French 	 * and avoid races inside tcp sendmsg code that could cause corruption
112338c8a9a5SSteve French 	 * of smb data.
112438c8a9a5SSteve French 	 */
112538c8a9a5SSteve French 
112638c8a9a5SSteve French 	cifs_server_lock(server);
112738c8a9a5SSteve French 
112838c8a9a5SSteve French 	/*
112938c8a9a5SSteve French 	 * All the parts of the compound chain belong obtained credits from the
113038c8a9a5SSteve French 	 * same session. We can not use credits obtained from the previous
113138c8a9a5SSteve French 	 * session to send this request. Check if there were reconnects after
113238c8a9a5SSteve French 	 * we obtained credits and return -EAGAIN in such cases to let callers
113338c8a9a5SSteve French 	 * handle it.
113438c8a9a5SSteve French 	 */
113538c8a9a5SSteve French 	if (instance != server->reconnect_instance) {
113638c8a9a5SSteve French 		cifs_server_unlock(server);
113738c8a9a5SSteve French 		for (j = 0; j < num_rqst; j++)
113838c8a9a5SSteve French 			add_credits(server, &credits[j], optype);
113938c8a9a5SSteve French 		return -EAGAIN;
114038c8a9a5SSteve French 	}
114138c8a9a5SSteve French 
114238c8a9a5SSteve French 	for (i = 0; i < num_rqst; i++) {
114338c8a9a5SSteve French 		midQ[i] = server->ops->setup_request(ses, server, &rqst[i]);
114438c8a9a5SSteve French 		if (IS_ERR(midQ[i])) {
114538c8a9a5SSteve French 			revert_current_mid(server, i);
114638c8a9a5SSteve French 			for (j = 0; j < i; j++)
114738c8a9a5SSteve French 				delete_mid(midQ[j]);
114838c8a9a5SSteve French 			cifs_server_unlock(server);
114938c8a9a5SSteve French 
115038c8a9a5SSteve French 			/* Update # of requests on wire to server */
115138c8a9a5SSteve French 			for (j = 0; j < num_rqst; j++)
115238c8a9a5SSteve French 				add_credits(server, &credits[j], optype);
115338c8a9a5SSteve French 			return PTR_ERR(midQ[i]);
115438c8a9a5SSteve French 		}
115538c8a9a5SSteve French 
115638c8a9a5SSteve French 		midQ[i]->mid_state = MID_REQUEST_SUBMITTED;
115738c8a9a5SSteve French 		midQ[i]->optype = optype;
115838c8a9a5SSteve French 		/*
115938c8a9a5SSteve French 		 * Invoke callback for every part of the compound chain
116038c8a9a5SSteve French 		 * to calculate credits properly. Wake up this thread only when
116138c8a9a5SSteve French 		 * the last element is received.
116238c8a9a5SSteve French 		 */
116338c8a9a5SSteve French 		if (i < num_rqst - 1)
116438c8a9a5SSteve French 			midQ[i]->callback = cifs_compound_callback;
116538c8a9a5SSteve French 		else
116638c8a9a5SSteve French 			midQ[i]->callback = cifs_compound_last_callback;
116738c8a9a5SSteve French 	}
116838c8a9a5SSteve French 	rc = smb_send_rqst(server, num_rqst, rqst, flags);
116938c8a9a5SSteve French 
117038c8a9a5SSteve French 	for (i = 0; i < num_rqst; i++)
117138c8a9a5SSteve French 		cifs_save_when_sent(midQ[i]);
117238c8a9a5SSteve French 
117338c8a9a5SSteve French 	if (rc < 0) {
117438c8a9a5SSteve French 		revert_current_mid(server, num_rqst);
117538c8a9a5SSteve French 		server->sequence_number -= 2;
117638c8a9a5SSteve French 	}
117738c8a9a5SSteve French 
117838c8a9a5SSteve French 	cifs_server_unlock(server);
117938c8a9a5SSteve French 
118038c8a9a5SSteve French 	/*
118138c8a9a5SSteve French 	 * If sending failed for some reason or it is an oplock break that we
118238c8a9a5SSteve French 	 * will not receive a response to - return credits back
118338c8a9a5SSteve French 	 */
118438c8a9a5SSteve French 	if (rc < 0 || (flags & CIFS_NO_SRV_RSP)) {
118538c8a9a5SSteve French 		for (i = 0; i < num_rqst; i++)
118638c8a9a5SSteve French 			add_credits(server, &credits[i], optype);
118738c8a9a5SSteve French 		goto out;
118838c8a9a5SSteve French 	}
118938c8a9a5SSteve French 
119038c8a9a5SSteve French 	/*
119138c8a9a5SSteve French 	 * At this point the request is passed to the network stack - we assume
119238c8a9a5SSteve French 	 * that any credits taken from the server structure on the client have
119338c8a9a5SSteve French 	 * been spent and we can't return them back. Once we receive responses
119438c8a9a5SSteve French 	 * we will collect credits granted by the server in the mid callbacks
119538c8a9a5SSteve French 	 * and add those credits to the server structure.
119638c8a9a5SSteve French 	 */
119738c8a9a5SSteve French 
119838c8a9a5SSteve French 	/*
119938c8a9a5SSteve French 	 * Compounding is never used during session establish.
120038c8a9a5SSteve French 	 */
120138c8a9a5SSteve French 	spin_lock(&ses->ses_lock);
120238c8a9a5SSteve French 	if ((ses->ses_status == SES_NEW) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) {
120338c8a9a5SSteve French 		spin_unlock(&ses->ses_lock);
120438c8a9a5SSteve French 
120538c8a9a5SSteve French 		cifs_server_lock(server);
120638c8a9a5SSteve French 		smb311_update_preauth_hash(ses, server, rqst[0].rq_iov, rqst[0].rq_nvec);
120738c8a9a5SSteve French 		cifs_server_unlock(server);
120838c8a9a5SSteve French 
120938c8a9a5SSteve French 		spin_lock(&ses->ses_lock);
121038c8a9a5SSteve French 	}
121138c8a9a5SSteve French 	spin_unlock(&ses->ses_lock);
121238c8a9a5SSteve French 
121338c8a9a5SSteve French 	for (i = 0; i < num_rqst; i++) {
121438c8a9a5SSteve French 		rc = wait_for_response(server, midQ[i]);
121538c8a9a5SSteve French 		if (rc != 0)
121638c8a9a5SSteve French 			break;
121738c8a9a5SSteve French 	}
121838c8a9a5SSteve French 	if (rc != 0) {
121938c8a9a5SSteve French 		for (; i < num_rqst; i++) {
122038c8a9a5SSteve French 			cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n",
122138c8a9a5SSteve French 				 midQ[i]->mid, le16_to_cpu(midQ[i]->command));
122238c8a9a5SSteve French 			send_cancel(server, &rqst[i], midQ[i]);
122338c8a9a5SSteve French 			spin_lock(&server->mid_lock);
122438c8a9a5SSteve French 			midQ[i]->mid_flags |= MID_WAIT_CANCELLED;
1225d527f513SZhang Xiaoxu 			if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED ||
1226d527f513SZhang Xiaoxu 			    midQ[i]->mid_state == MID_RESPONSE_RECEIVED) {
122738c8a9a5SSteve French 				midQ[i]->callback = cifs_cancelled_callback;
122838c8a9a5SSteve French 				cancelled_mid[i] = true;
122938c8a9a5SSteve French 				credits[i].value = 0;
123038c8a9a5SSteve French 			}
123138c8a9a5SSteve French 			spin_unlock(&server->mid_lock);
123238c8a9a5SSteve French 		}
123338c8a9a5SSteve French 	}
123438c8a9a5SSteve French 
123538c8a9a5SSteve French 	for (i = 0; i < num_rqst; i++) {
123638c8a9a5SSteve French 		if (rc < 0)
123738c8a9a5SSteve French 			goto out;
123838c8a9a5SSteve French 
123938c8a9a5SSteve French 		rc = cifs_sync_mid_result(midQ[i], server);
124038c8a9a5SSteve French 		if (rc != 0) {
124138c8a9a5SSteve French 			/* mark this mid as cancelled to not free it below */
124238c8a9a5SSteve French 			cancelled_mid[i] = true;
124338c8a9a5SSteve French 			goto out;
124438c8a9a5SSteve French 		}
124538c8a9a5SSteve French 
124638c8a9a5SSteve French 		if (!midQ[i]->resp_buf ||
1247d527f513SZhang Xiaoxu 		    midQ[i]->mid_state != MID_RESPONSE_READY) {
124838c8a9a5SSteve French 			rc = -EIO;
124938c8a9a5SSteve French 			cifs_dbg(FYI, "Bad MID state?\n");
125038c8a9a5SSteve French 			goto out;
125138c8a9a5SSteve French 		}
125238c8a9a5SSteve French 
125338c8a9a5SSteve French 		buf = (char *)midQ[i]->resp_buf;
125438c8a9a5SSteve French 		resp_iov[i].iov_base = buf;
125538c8a9a5SSteve French 		resp_iov[i].iov_len = midQ[i]->resp_buf_size +
125638c8a9a5SSteve French 			HEADER_PREAMBLE_SIZE(server);
125738c8a9a5SSteve French 
125838c8a9a5SSteve French 		if (midQ[i]->large_buf)
125938c8a9a5SSteve French 			resp_buf_type[i] = CIFS_LARGE_BUFFER;
126038c8a9a5SSteve French 		else
126138c8a9a5SSteve French 			resp_buf_type[i] = CIFS_SMALL_BUFFER;
126238c8a9a5SSteve French 
126338c8a9a5SSteve French 		rc = server->ops->check_receive(midQ[i], server,
126438c8a9a5SSteve French 						     flags & CIFS_LOG_ERROR);
126538c8a9a5SSteve French 
126638c8a9a5SSteve French 		/* mark it so buf will not be freed by delete_mid */
126738c8a9a5SSteve French 		if ((flags & CIFS_NO_RSP_BUF) == 0)
126838c8a9a5SSteve French 			midQ[i]->resp_buf = NULL;
126938c8a9a5SSteve French 
127038c8a9a5SSteve French 	}
127138c8a9a5SSteve French 
127238c8a9a5SSteve French 	/*
127338c8a9a5SSteve French 	 * Compounding is never used during session establish.
127438c8a9a5SSteve French 	 */
127538c8a9a5SSteve French 	spin_lock(&ses->ses_lock);
127638c8a9a5SSteve French 	if ((ses->ses_status == SES_NEW) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) {
127738c8a9a5SSteve French 		struct kvec iov = {
127838c8a9a5SSteve French 			.iov_base = resp_iov[0].iov_base,
127938c8a9a5SSteve French 			.iov_len = resp_iov[0].iov_len
128038c8a9a5SSteve French 		};
128138c8a9a5SSteve French 		spin_unlock(&ses->ses_lock);
128238c8a9a5SSteve French 		cifs_server_lock(server);
128338c8a9a5SSteve French 		smb311_update_preauth_hash(ses, server, &iov, 1);
128438c8a9a5SSteve French 		cifs_server_unlock(server);
128538c8a9a5SSteve French 		spin_lock(&ses->ses_lock);
128638c8a9a5SSteve French 	}
128738c8a9a5SSteve French 	spin_unlock(&ses->ses_lock);
128838c8a9a5SSteve French 
128938c8a9a5SSteve French out:
129038c8a9a5SSteve French 	/*
129138c8a9a5SSteve French 	 * This will dequeue all mids. After this it is important that the
129238c8a9a5SSteve French 	 * demultiplex_thread will not process any of these mids any futher.
129338c8a9a5SSteve French 	 * This is prevented above by using a noop callback that will not
129438c8a9a5SSteve French 	 * wake this thread except for the very last PDU.
129538c8a9a5SSteve French 	 */
129638c8a9a5SSteve French 	for (i = 0; i < num_rqst; i++) {
129738c8a9a5SSteve French 		if (!cancelled_mid[i])
129838c8a9a5SSteve French 			delete_mid(midQ[i]);
129938c8a9a5SSteve French 	}
130038c8a9a5SSteve French 
130138c8a9a5SSteve French 	return rc;
130238c8a9a5SSteve French }
130338c8a9a5SSteve French 
130438c8a9a5SSteve French int
cifs_send_recv(const unsigned int xid,struct cifs_ses * ses,struct TCP_Server_Info * server,struct smb_rqst * rqst,int * resp_buf_type,const int flags,struct kvec * resp_iov)130538c8a9a5SSteve French cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
130638c8a9a5SSteve French 	       struct TCP_Server_Info *server,
130738c8a9a5SSteve French 	       struct smb_rqst *rqst, int *resp_buf_type, const int flags,
130838c8a9a5SSteve French 	       struct kvec *resp_iov)
130938c8a9a5SSteve French {
131038c8a9a5SSteve French 	return compound_send_recv(xid, ses, server, flags, 1,
131138c8a9a5SSteve French 				  rqst, resp_buf_type, resp_iov);
131238c8a9a5SSteve French }
131338c8a9a5SSteve French 
131438c8a9a5SSteve French int
SendReceive2(const unsigned int xid,struct cifs_ses * ses,struct kvec * iov,int n_vec,int * resp_buf_type,const int flags,struct kvec * resp_iov)131538c8a9a5SSteve French SendReceive2(const unsigned int xid, struct cifs_ses *ses,
131638c8a9a5SSteve French 	     struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
131738c8a9a5SSteve French 	     const int flags, struct kvec *resp_iov)
131838c8a9a5SSteve French {
131938c8a9a5SSteve French 	struct smb_rqst rqst;
132038c8a9a5SSteve French 	struct kvec s_iov[CIFS_MAX_IOV_SIZE], *new_iov;
132138c8a9a5SSteve French 	int rc;
132238c8a9a5SSteve French 
132338c8a9a5SSteve French 	if (n_vec + 1 > CIFS_MAX_IOV_SIZE) {
132438c8a9a5SSteve French 		new_iov = kmalloc_array(n_vec + 1, sizeof(struct kvec),
132538c8a9a5SSteve French 					GFP_KERNEL);
132638c8a9a5SSteve French 		if (!new_iov) {
132738c8a9a5SSteve French 			/* otherwise cifs_send_recv below sets resp_buf_type */
132838c8a9a5SSteve French 			*resp_buf_type = CIFS_NO_BUFFER;
132938c8a9a5SSteve French 			return -ENOMEM;
133038c8a9a5SSteve French 		}
133138c8a9a5SSteve French 	} else
133238c8a9a5SSteve French 		new_iov = s_iov;
133338c8a9a5SSteve French 
133438c8a9a5SSteve French 	/* 1st iov is a RFC1001 length followed by the rest of the packet */
133538c8a9a5SSteve French 	memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec));
133638c8a9a5SSteve French 
133738c8a9a5SSteve French 	new_iov[0].iov_base = new_iov[1].iov_base;
133838c8a9a5SSteve French 	new_iov[0].iov_len = 4;
133938c8a9a5SSteve French 	new_iov[1].iov_base += 4;
134038c8a9a5SSteve French 	new_iov[1].iov_len -= 4;
134138c8a9a5SSteve French 
134238c8a9a5SSteve French 	memset(&rqst, 0, sizeof(struct smb_rqst));
134338c8a9a5SSteve French 	rqst.rq_iov = new_iov;
134438c8a9a5SSteve French 	rqst.rq_nvec = n_vec + 1;
134538c8a9a5SSteve French 
134638c8a9a5SSteve French 	rc = cifs_send_recv(xid, ses, ses->server,
134738c8a9a5SSteve French 			    &rqst, resp_buf_type, flags, resp_iov);
134838c8a9a5SSteve French 	if (n_vec + 1 > CIFS_MAX_IOV_SIZE)
134938c8a9a5SSteve French 		kfree(new_iov);
135038c8a9a5SSteve French 	return rc;
135138c8a9a5SSteve French }
135238c8a9a5SSteve French 
135338c8a9a5SSteve French 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)135438c8a9a5SSteve French SendReceive(const unsigned int xid, struct cifs_ses *ses,
135538c8a9a5SSteve French 	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
135638c8a9a5SSteve French 	    int *pbytes_returned, const int flags)
135738c8a9a5SSteve French {
135838c8a9a5SSteve French 	int rc = 0;
135938c8a9a5SSteve French 	struct mid_q_entry *midQ;
136038c8a9a5SSteve French 	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
136138c8a9a5SSteve French 	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
136238c8a9a5SSteve French 	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
136338c8a9a5SSteve French 	struct cifs_credits credits = { .value = 1, .instance = 0 };
136438c8a9a5SSteve French 	struct TCP_Server_Info *server;
136538c8a9a5SSteve French 
136638c8a9a5SSteve French 	if (ses == NULL) {
136738c8a9a5SSteve French 		cifs_dbg(VFS, "Null smb session\n");
136838c8a9a5SSteve French 		return -EIO;
136938c8a9a5SSteve French 	}
137038c8a9a5SSteve French 	server = ses->server;
137138c8a9a5SSteve French 	if (server == NULL) {
137238c8a9a5SSteve French 		cifs_dbg(VFS, "Null tcp session\n");
137338c8a9a5SSteve French 		return -EIO;
137438c8a9a5SSteve French 	}
137538c8a9a5SSteve French 
137638c8a9a5SSteve French 	spin_lock(&server->srv_lock);
137738c8a9a5SSteve French 	if (server->tcpStatus == CifsExiting) {
137838c8a9a5SSteve French 		spin_unlock(&server->srv_lock);
137938c8a9a5SSteve French 		return -ENOENT;
138038c8a9a5SSteve French 	}
138138c8a9a5SSteve French 	spin_unlock(&server->srv_lock);
138238c8a9a5SSteve French 
138338c8a9a5SSteve French 	/* Ensure that we do not send more than 50 overlapping requests
138438c8a9a5SSteve French 	   to the same server. We may make this configurable later or
138538c8a9a5SSteve French 	   use ses->maxReq */
138638c8a9a5SSteve French 
138738c8a9a5SSteve French 	if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
138838c8a9a5SSteve French 		cifs_server_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
138938c8a9a5SSteve French 				len);
139038c8a9a5SSteve French 		return -EIO;
139138c8a9a5SSteve French 	}
139238c8a9a5SSteve French 
139338c8a9a5SSteve French 	rc = wait_for_free_request(server, flags, &credits.instance);
139438c8a9a5SSteve French 	if (rc)
139538c8a9a5SSteve French 		return rc;
139638c8a9a5SSteve French 
139738c8a9a5SSteve French 	/* make sure that we sign in the same order that we send on this socket
139838c8a9a5SSteve French 	   and avoid races inside tcp sendmsg code that could cause corruption
139938c8a9a5SSteve French 	   of smb data */
140038c8a9a5SSteve French 
140138c8a9a5SSteve French 	cifs_server_lock(server);
140238c8a9a5SSteve French 
140338c8a9a5SSteve French 	rc = allocate_mid(ses, in_buf, &midQ);
140438c8a9a5SSteve French 	if (rc) {
140538c8a9a5SSteve French 		cifs_server_unlock(server);
140638c8a9a5SSteve French 		/* Update # of requests on wire to server */
140738c8a9a5SSteve French 		add_credits(server, &credits, 0);
140838c8a9a5SSteve French 		return rc;
140938c8a9a5SSteve French 	}
141038c8a9a5SSteve French 
141138c8a9a5SSteve French 	rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
141238c8a9a5SSteve French 	if (rc) {
141338c8a9a5SSteve French 		cifs_server_unlock(server);
141438c8a9a5SSteve French 		goto out;
141538c8a9a5SSteve French 	}
141638c8a9a5SSteve French 
141738c8a9a5SSteve French 	midQ->mid_state = MID_REQUEST_SUBMITTED;
141838c8a9a5SSteve French 
141938c8a9a5SSteve French 	rc = smb_send(server, in_buf, len);
142038c8a9a5SSteve French 	cifs_save_when_sent(midQ);
142138c8a9a5SSteve French 
142238c8a9a5SSteve French 	if (rc < 0)
142338c8a9a5SSteve French 		server->sequence_number -= 2;
142438c8a9a5SSteve French 
142538c8a9a5SSteve French 	cifs_server_unlock(server);
142638c8a9a5SSteve French 
142738c8a9a5SSteve French 	if (rc < 0)
142838c8a9a5SSteve French 		goto out;
142938c8a9a5SSteve French 
143038c8a9a5SSteve French 	rc = wait_for_response(server, midQ);
143138c8a9a5SSteve French 	if (rc != 0) {
143238c8a9a5SSteve French 		send_cancel(server, &rqst, midQ);
143338c8a9a5SSteve French 		spin_lock(&server->mid_lock);
1434d527f513SZhang Xiaoxu 		if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
1435d527f513SZhang Xiaoxu 		    midQ->mid_state == MID_RESPONSE_RECEIVED) {
143638c8a9a5SSteve French 			/* no longer considered to be "in-flight" */
143738c8a9a5SSteve French 			midQ->callback = release_mid;
143838c8a9a5SSteve French 			spin_unlock(&server->mid_lock);
143938c8a9a5SSteve French 			add_credits(server, &credits, 0);
144038c8a9a5SSteve French 			return rc;
144138c8a9a5SSteve French 		}
144238c8a9a5SSteve French 		spin_unlock(&server->mid_lock);
144338c8a9a5SSteve French 	}
144438c8a9a5SSteve French 
144538c8a9a5SSteve French 	rc = cifs_sync_mid_result(midQ, server);
144638c8a9a5SSteve French 	if (rc != 0) {
144738c8a9a5SSteve French 		add_credits(server, &credits, 0);
144838c8a9a5SSteve French 		return rc;
144938c8a9a5SSteve French 	}
145038c8a9a5SSteve French 
145138c8a9a5SSteve French 	if (!midQ->resp_buf || !out_buf ||
1452d527f513SZhang Xiaoxu 	    midQ->mid_state != MID_RESPONSE_READY) {
145338c8a9a5SSteve French 		rc = -EIO;
145438c8a9a5SSteve French 		cifs_server_dbg(VFS, "Bad MID state?\n");
145538c8a9a5SSteve French 		goto out;
145638c8a9a5SSteve French 	}
145738c8a9a5SSteve French 
145838c8a9a5SSteve French 	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
145938c8a9a5SSteve French 	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
146038c8a9a5SSteve French 	rc = cifs_check_receive(midQ, server, 0);
146138c8a9a5SSteve French out:
146238c8a9a5SSteve French 	delete_mid(midQ);
146338c8a9a5SSteve French 	add_credits(server, &credits, 0);
146438c8a9a5SSteve French 
146538c8a9a5SSteve French 	return rc;
146638c8a9a5SSteve French }
146738c8a9a5SSteve French 
146838c8a9a5SSteve French /* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
146938c8a9a5SSteve French    blocking lock to return. */
147038c8a9a5SSteve French 
147138c8a9a5SSteve French static int
send_lock_cancel(const unsigned int xid,struct cifs_tcon * tcon,struct smb_hdr * in_buf,struct smb_hdr * out_buf)147238c8a9a5SSteve French send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon,
147338c8a9a5SSteve French 			struct smb_hdr *in_buf,
147438c8a9a5SSteve French 			struct smb_hdr *out_buf)
147538c8a9a5SSteve French {
147638c8a9a5SSteve French 	int bytes_returned;
147738c8a9a5SSteve French 	struct cifs_ses *ses = tcon->ses;
147838c8a9a5SSteve French 	LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
147938c8a9a5SSteve French 
148038c8a9a5SSteve French 	/* We just modify the current in_buf to change
148138c8a9a5SSteve French 	   the type of lock from LOCKING_ANDX_SHARED_LOCK
148238c8a9a5SSteve French 	   or LOCKING_ANDX_EXCLUSIVE_LOCK to
148338c8a9a5SSteve French 	   LOCKING_ANDX_CANCEL_LOCK. */
148438c8a9a5SSteve French 
148538c8a9a5SSteve French 	pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
148638c8a9a5SSteve French 	pSMB->Timeout = 0;
148738c8a9a5SSteve French 	pSMB->hdr.Mid = get_next_mid(ses->server);
148838c8a9a5SSteve French 
148938c8a9a5SSteve French 	return SendReceive(xid, ses, in_buf, out_buf,
149038c8a9a5SSteve French 			&bytes_returned, 0);
149138c8a9a5SSteve French }
149238c8a9a5SSteve French 
149338c8a9a5SSteve French int
SendReceiveBlockingLock(const unsigned int xid,struct cifs_tcon * tcon,struct smb_hdr * in_buf,struct smb_hdr * out_buf,int * pbytes_returned)149438c8a9a5SSteve French SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
149538c8a9a5SSteve French 	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
149638c8a9a5SSteve French 	    int *pbytes_returned)
149738c8a9a5SSteve French {
149838c8a9a5SSteve French 	int rc = 0;
149938c8a9a5SSteve French 	int rstart = 0;
150038c8a9a5SSteve French 	struct mid_q_entry *midQ;
150138c8a9a5SSteve French 	struct cifs_ses *ses;
150238c8a9a5SSteve French 	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
150338c8a9a5SSteve French 	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
150438c8a9a5SSteve French 	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
150538c8a9a5SSteve French 	unsigned int instance;
150638c8a9a5SSteve French 	struct TCP_Server_Info *server;
150738c8a9a5SSteve French 
150838c8a9a5SSteve French 	if (tcon == NULL || tcon->ses == NULL) {
150938c8a9a5SSteve French 		cifs_dbg(VFS, "Null smb session\n");
151038c8a9a5SSteve French 		return -EIO;
151138c8a9a5SSteve French 	}
151238c8a9a5SSteve French 	ses = tcon->ses;
151338c8a9a5SSteve French 	server = ses->server;
151438c8a9a5SSteve French 
151538c8a9a5SSteve French 	if (server == NULL) {
151638c8a9a5SSteve French 		cifs_dbg(VFS, "Null tcp session\n");
151738c8a9a5SSteve French 		return -EIO;
151838c8a9a5SSteve French 	}
151938c8a9a5SSteve French 
152038c8a9a5SSteve French 	spin_lock(&server->srv_lock);
152138c8a9a5SSteve French 	if (server->tcpStatus == CifsExiting) {
152238c8a9a5SSteve French 		spin_unlock(&server->srv_lock);
152338c8a9a5SSteve French 		return -ENOENT;
152438c8a9a5SSteve French 	}
152538c8a9a5SSteve French 	spin_unlock(&server->srv_lock);
152638c8a9a5SSteve French 
152738c8a9a5SSteve French 	/* Ensure that we do not send more than 50 overlapping requests
152838c8a9a5SSteve French 	   to the same server. We may make this configurable later or
152938c8a9a5SSteve French 	   use ses->maxReq */
153038c8a9a5SSteve French 
153138c8a9a5SSteve French 	if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
153238c8a9a5SSteve French 		cifs_tcon_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
153338c8a9a5SSteve French 			      len);
153438c8a9a5SSteve French 		return -EIO;
153538c8a9a5SSteve French 	}
153638c8a9a5SSteve French 
153738c8a9a5SSteve French 	rc = wait_for_free_request(server, CIFS_BLOCKING_OP, &instance);
153838c8a9a5SSteve French 	if (rc)
153938c8a9a5SSteve French 		return rc;
154038c8a9a5SSteve French 
154138c8a9a5SSteve French 	/* make sure that we sign in the same order that we send on this socket
154238c8a9a5SSteve French 	   and avoid races inside tcp sendmsg code that could cause corruption
154338c8a9a5SSteve French 	   of smb data */
154438c8a9a5SSteve French 
154538c8a9a5SSteve French 	cifs_server_lock(server);
154638c8a9a5SSteve French 
154738c8a9a5SSteve French 	rc = allocate_mid(ses, in_buf, &midQ);
154838c8a9a5SSteve French 	if (rc) {
154938c8a9a5SSteve French 		cifs_server_unlock(server);
155038c8a9a5SSteve French 		return rc;
155138c8a9a5SSteve French 	}
155238c8a9a5SSteve French 
155338c8a9a5SSteve French 	rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
155438c8a9a5SSteve French 	if (rc) {
155538c8a9a5SSteve French 		delete_mid(midQ);
155638c8a9a5SSteve French 		cifs_server_unlock(server);
155738c8a9a5SSteve French 		return rc;
155838c8a9a5SSteve French 	}
155938c8a9a5SSteve French 
156038c8a9a5SSteve French 	midQ->mid_state = MID_REQUEST_SUBMITTED;
156138c8a9a5SSteve French 	rc = smb_send(server, in_buf, len);
156238c8a9a5SSteve French 	cifs_save_when_sent(midQ);
156338c8a9a5SSteve French 
156438c8a9a5SSteve French 	if (rc < 0)
156538c8a9a5SSteve French 		server->sequence_number -= 2;
156638c8a9a5SSteve French 
156738c8a9a5SSteve French 	cifs_server_unlock(server);
156838c8a9a5SSteve French 
156938c8a9a5SSteve French 	if (rc < 0) {
157038c8a9a5SSteve French 		delete_mid(midQ);
157138c8a9a5SSteve French 		return rc;
157238c8a9a5SSteve French 	}
157338c8a9a5SSteve French 
157438c8a9a5SSteve French 	/* Wait for a reply - allow signals to interrupt. */
157538c8a9a5SSteve French 	rc = wait_event_interruptible(server->response_q,
1576d527f513SZhang Xiaoxu 		(!(midQ->mid_state == MID_REQUEST_SUBMITTED ||
1577d527f513SZhang Xiaoxu 		   midQ->mid_state == MID_RESPONSE_RECEIVED)) ||
157838c8a9a5SSteve French 		((server->tcpStatus != CifsGood) &&
157938c8a9a5SSteve French 		 (server->tcpStatus != CifsNew)));
158038c8a9a5SSteve French 
158138c8a9a5SSteve French 	/* Were we interrupted by a signal ? */
158238c8a9a5SSteve French 	spin_lock(&server->srv_lock);
158338c8a9a5SSteve French 	if ((rc == -ERESTARTSYS) &&
1584d527f513SZhang Xiaoxu 		(midQ->mid_state == MID_REQUEST_SUBMITTED ||
1585d527f513SZhang Xiaoxu 		 midQ->mid_state == MID_RESPONSE_RECEIVED) &&
158638c8a9a5SSteve French 		((server->tcpStatus == CifsGood) ||
158738c8a9a5SSteve French 		 (server->tcpStatus == CifsNew))) {
158838c8a9a5SSteve French 		spin_unlock(&server->srv_lock);
158938c8a9a5SSteve French 
159038c8a9a5SSteve French 		if (in_buf->Command == SMB_COM_TRANSACTION2) {
159138c8a9a5SSteve French 			/* POSIX lock. We send a NT_CANCEL SMB to cause the
159238c8a9a5SSteve French 			   blocking lock to return. */
159338c8a9a5SSteve French 			rc = send_cancel(server, &rqst, midQ);
159438c8a9a5SSteve French 			if (rc) {
159538c8a9a5SSteve French 				delete_mid(midQ);
159638c8a9a5SSteve French 				return rc;
159738c8a9a5SSteve French 			}
159838c8a9a5SSteve French 		} else {
159938c8a9a5SSteve French 			/* Windows lock. We send a LOCKINGX_CANCEL_LOCK
160038c8a9a5SSteve French 			   to cause the blocking lock to return. */
160138c8a9a5SSteve French 
160238c8a9a5SSteve French 			rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
160338c8a9a5SSteve French 
160438c8a9a5SSteve French 			/* If we get -ENOLCK back the lock may have
160538c8a9a5SSteve French 			   already been removed. Don't exit in this case. */
160638c8a9a5SSteve French 			if (rc && rc != -ENOLCK) {
160738c8a9a5SSteve French 				delete_mid(midQ);
160838c8a9a5SSteve French 				return rc;
160938c8a9a5SSteve French 			}
161038c8a9a5SSteve French 		}
161138c8a9a5SSteve French 
161238c8a9a5SSteve French 		rc = wait_for_response(server, midQ);
161338c8a9a5SSteve French 		if (rc) {
161438c8a9a5SSteve French 			send_cancel(server, &rqst, midQ);
161538c8a9a5SSteve French 			spin_lock(&server->mid_lock);
1616d527f513SZhang Xiaoxu 			if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
1617d527f513SZhang Xiaoxu 			    midQ->mid_state == MID_RESPONSE_RECEIVED) {
161838c8a9a5SSteve French 				/* no longer considered to be "in-flight" */
161938c8a9a5SSteve French 				midQ->callback = release_mid;
162038c8a9a5SSteve French 				spin_unlock(&server->mid_lock);
162138c8a9a5SSteve French 				return rc;
162238c8a9a5SSteve French 			}
162338c8a9a5SSteve French 			spin_unlock(&server->mid_lock);
162438c8a9a5SSteve French 		}
162538c8a9a5SSteve French 
162638c8a9a5SSteve French 		/* We got the response - restart system call. */
162738c8a9a5SSteve French 		rstart = 1;
162838c8a9a5SSteve French 		spin_lock(&server->srv_lock);
162938c8a9a5SSteve French 	}
163038c8a9a5SSteve French 	spin_unlock(&server->srv_lock);
163138c8a9a5SSteve French 
163238c8a9a5SSteve French 	rc = cifs_sync_mid_result(midQ, server);
163338c8a9a5SSteve French 	if (rc != 0)
163438c8a9a5SSteve French 		return rc;
163538c8a9a5SSteve French 
163638c8a9a5SSteve French 	/* rcvd frame is ok */
1637d527f513SZhang Xiaoxu 	if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_READY) {
163838c8a9a5SSteve French 		rc = -EIO;
163938c8a9a5SSteve French 		cifs_tcon_dbg(VFS, "Bad MID state?\n");
164038c8a9a5SSteve French 		goto out;
164138c8a9a5SSteve French 	}
164238c8a9a5SSteve French 
164338c8a9a5SSteve French 	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
164438c8a9a5SSteve French 	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
164538c8a9a5SSteve French 	rc = cifs_check_receive(midQ, server, 0);
164638c8a9a5SSteve French out:
164738c8a9a5SSteve French 	delete_mid(midQ);
164838c8a9a5SSteve French 	if (rstart && rc == -EACCES)
164938c8a9a5SSteve French 		return -ERESTARTSYS;
165038c8a9a5SSteve French 	return rc;
165138c8a9a5SSteve French }
165238c8a9a5SSteve French 
165338c8a9a5SSteve French /*
165438c8a9a5SSteve French  * Discard any remaining data in the current SMB. To do this, we borrow the
165538c8a9a5SSteve French  * current bigbuf.
165638c8a9a5SSteve French  */
165738c8a9a5SSteve French int
cifs_discard_remaining_data(struct TCP_Server_Info * server)165838c8a9a5SSteve French cifs_discard_remaining_data(struct TCP_Server_Info *server)
165938c8a9a5SSteve French {
166038c8a9a5SSteve French 	unsigned int rfclen = server->pdu_size;
166138c8a9a5SSteve French 	size_t remaining = rfclen + HEADER_PREAMBLE_SIZE(server) -
166238c8a9a5SSteve French 		server->total_read;
166338c8a9a5SSteve French 
166438c8a9a5SSteve French 	while (remaining > 0) {
166538c8a9a5SSteve French 		ssize_t length;
166638c8a9a5SSteve French 
166738c8a9a5SSteve French 		length = cifs_discard_from_socket(server,
166838c8a9a5SSteve French 				min_t(size_t, remaining,
166938c8a9a5SSteve French 				      CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
167038c8a9a5SSteve French 		if (length < 0)
167138c8a9a5SSteve French 			return length;
167238c8a9a5SSteve French 		server->total_read += length;
167338c8a9a5SSteve French 		remaining -= length;
167438c8a9a5SSteve French 	}
167538c8a9a5SSteve French 
167638c8a9a5SSteve French 	return 0;
167738c8a9a5SSteve French }
167838c8a9a5SSteve French 
167938c8a9a5SSteve French static int
__cifs_readv_discard(struct TCP_Server_Info * server,struct mid_q_entry * mid,bool malformed)168038c8a9a5SSteve French __cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
168138c8a9a5SSteve French 		     bool malformed)
168238c8a9a5SSteve French {
168338c8a9a5SSteve French 	int length;
168438c8a9a5SSteve French 
168538c8a9a5SSteve French 	length = cifs_discard_remaining_data(server);
168638c8a9a5SSteve French 	dequeue_mid(mid, malformed);
168738c8a9a5SSteve French 	mid->resp_buf = server->smallbuf;
168838c8a9a5SSteve French 	server->smallbuf = NULL;
168938c8a9a5SSteve French 	return length;
169038c8a9a5SSteve French }
169138c8a9a5SSteve French 
169238c8a9a5SSteve French static int
cifs_readv_discard(struct TCP_Server_Info * server,struct mid_q_entry * mid)169338c8a9a5SSteve French cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
169438c8a9a5SSteve French {
169538c8a9a5SSteve French 	struct cifs_readdata *rdata = mid->callback_data;
169638c8a9a5SSteve French 
169738c8a9a5SSteve French 	return  __cifs_readv_discard(server, mid, rdata->result);
169838c8a9a5SSteve French }
169938c8a9a5SSteve French 
170038c8a9a5SSteve French int
cifs_readv_receive(struct TCP_Server_Info * server,struct mid_q_entry * mid)170138c8a9a5SSteve French cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
170238c8a9a5SSteve French {
170338c8a9a5SSteve French 	int length, len;
170438c8a9a5SSteve French 	unsigned int data_offset, data_len;
170538c8a9a5SSteve French 	struct cifs_readdata *rdata = mid->callback_data;
170638c8a9a5SSteve French 	char *buf = server->smallbuf;
170738c8a9a5SSteve French 	unsigned int buflen = server->pdu_size + HEADER_PREAMBLE_SIZE(server);
170838c8a9a5SSteve French 	bool use_rdma_mr = false;
170938c8a9a5SSteve French 
171038c8a9a5SSteve French 	cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
171138c8a9a5SSteve French 		 __func__, mid->mid, rdata->offset, rdata->bytes);
171238c8a9a5SSteve French 
171338c8a9a5SSteve French 	/*
171438c8a9a5SSteve French 	 * read the rest of READ_RSP header (sans Data array), or whatever we
171538c8a9a5SSteve French 	 * can if there's not enough data. At this point, we've read down to
171638c8a9a5SSteve French 	 * the Mid.
171738c8a9a5SSteve French 	 */
171838c8a9a5SSteve French 	len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
171938c8a9a5SSteve French 							HEADER_SIZE(server) + 1;
172038c8a9a5SSteve French 
172138c8a9a5SSteve French 	length = cifs_read_from_socket(server,
172238c8a9a5SSteve French 				       buf + HEADER_SIZE(server) - 1, len);
172338c8a9a5SSteve French 	if (length < 0)
172438c8a9a5SSteve French 		return length;
172538c8a9a5SSteve French 	server->total_read += length;
172638c8a9a5SSteve French 
172738c8a9a5SSteve French 	if (server->ops->is_session_expired &&
172838c8a9a5SSteve French 	    server->ops->is_session_expired(buf)) {
172938c8a9a5SSteve French 		cifs_reconnect(server, true);
173038c8a9a5SSteve French 		return -1;
173138c8a9a5SSteve French 	}
173238c8a9a5SSteve French 
173338c8a9a5SSteve French 	if (server->ops->is_status_pending &&
173438c8a9a5SSteve French 	    server->ops->is_status_pending(buf, server)) {
173538c8a9a5SSteve French 		cifs_discard_remaining_data(server);
173638c8a9a5SSteve French 		return -1;
173738c8a9a5SSteve French 	}
173838c8a9a5SSteve French 
173938c8a9a5SSteve French 	/* set up first two iov for signature check and to get credits */
174038c8a9a5SSteve French 	rdata->iov[0].iov_base = buf;
174138c8a9a5SSteve French 	rdata->iov[0].iov_len = HEADER_PREAMBLE_SIZE(server);
174238c8a9a5SSteve French 	rdata->iov[1].iov_base = buf + HEADER_PREAMBLE_SIZE(server);
174338c8a9a5SSteve French 	rdata->iov[1].iov_len =
174438c8a9a5SSteve French 		server->total_read - HEADER_PREAMBLE_SIZE(server);
174538c8a9a5SSteve French 	cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
174638c8a9a5SSteve French 		 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
174738c8a9a5SSteve French 	cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
174838c8a9a5SSteve French 		 rdata->iov[1].iov_base, rdata->iov[1].iov_len);
174938c8a9a5SSteve French 
175038c8a9a5SSteve French 	/* Was the SMB read successful? */
175138c8a9a5SSteve French 	rdata->result = server->ops->map_error(buf, false);
175238c8a9a5SSteve French 	if (rdata->result != 0) {
175338c8a9a5SSteve French 		cifs_dbg(FYI, "%s: server returned error %d\n",
175438c8a9a5SSteve French 			 __func__, rdata->result);
175538c8a9a5SSteve French 		/* normal error on read response */
175638c8a9a5SSteve French 		return __cifs_readv_discard(server, mid, false);
175738c8a9a5SSteve French 	}
175838c8a9a5SSteve French 
175938c8a9a5SSteve French 	/* Is there enough to get to the rest of the READ_RSP header? */
176038c8a9a5SSteve French 	if (server->total_read < server->vals->read_rsp_size) {
176138c8a9a5SSteve French 		cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
176238c8a9a5SSteve French 			 __func__, server->total_read,
176338c8a9a5SSteve French 			 server->vals->read_rsp_size);
176438c8a9a5SSteve French 		rdata->result = -EIO;
176538c8a9a5SSteve French 		return cifs_readv_discard(server, mid);
176638c8a9a5SSteve French 	}
176738c8a9a5SSteve French 
176838c8a9a5SSteve French 	data_offset = server->ops->read_data_offset(buf) +
176938c8a9a5SSteve French 		HEADER_PREAMBLE_SIZE(server);
177038c8a9a5SSteve French 	if (data_offset < server->total_read) {
177138c8a9a5SSteve French 		/*
177238c8a9a5SSteve French 		 * win2k8 sometimes sends an offset of 0 when the read
177338c8a9a5SSteve French 		 * is beyond the EOF. Treat it as if the data starts just after
177438c8a9a5SSteve French 		 * the header.
177538c8a9a5SSteve French 		 */
177638c8a9a5SSteve French 		cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
177738c8a9a5SSteve French 			 __func__, data_offset);
177838c8a9a5SSteve French 		data_offset = server->total_read;
177938c8a9a5SSteve French 	} else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
178038c8a9a5SSteve French 		/* data_offset is beyond the end of smallbuf */
178138c8a9a5SSteve French 		cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
178238c8a9a5SSteve French 			 __func__, data_offset);
178338c8a9a5SSteve French 		rdata->result = -EIO;
178438c8a9a5SSteve French 		return cifs_readv_discard(server, mid);
178538c8a9a5SSteve French 	}
178638c8a9a5SSteve French 
178738c8a9a5SSteve French 	cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
178838c8a9a5SSteve French 		 __func__, server->total_read, data_offset);
178938c8a9a5SSteve French 
179038c8a9a5SSteve French 	len = data_offset - server->total_read;
179138c8a9a5SSteve French 	if (len > 0) {
179238c8a9a5SSteve French 		/* read any junk before data into the rest of smallbuf */
179338c8a9a5SSteve French 		length = cifs_read_from_socket(server,
179438c8a9a5SSteve French 					       buf + server->total_read, len);
179538c8a9a5SSteve French 		if (length < 0)
179638c8a9a5SSteve French 			return length;
179738c8a9a5SSteve French 		server->total_read += length;
179838c8a9a5SSteve French 	}
179938c8a9a5SSteve French 
180038c8a9a5SSteve French 	/* how much data is in the response? */
180138c8a9a5SSteve French #ifdef CONFIG_CIFS_SMB_DIRECT
180238c8a9a5SSteve French 	use_rdma_mr = rdata->mr;
180338c8a9a5SSteve French #endif
180438c8a9a5SSteve French 	data_len = server->ops->read_data_length(buf, use_rdma_mr);
180538c8a9a5SSteve French 	if (!use_rdma_mr && (data_offset + data_len > buflen)) {
180638c8a9a5SSteve French 		/* data_len is corrupt -- discard frame */
180738c8a9a5SSteve French 		rdata->result = -EIO;
180838c8a9a5SSteve French 		return cifs_readv_discard(server, mid);
180938c8a9a5SSteve French 	}
181038c8a9a5SSteve French 
181138c8a9a5SSteve French #ifdef CONFIG_CIFS_SMB_DIRECT
181238c8a9a5SSteve French 	if (rdata->mr)
181338c8a9a5SSteve French 		length = data_len; /* An RDMA read is already done. */
181438c8a9a5SSteve French 	else
181538c8a9a5SSteve French #endif
181638c8a9a5SSteve French 		length = cifs_read_iter_from_socket(server, &rdata->iter,
181738c8a9a5SSteve French 						    data_len);
181838c8a9a5SSteve French 	if (length > 0)
181938c8a9a5SSteve French 		rdata->got_bytes += length;
182038c8a9a5SSteve French 	server->total_read += length;
182138c8a9a5SSteve French 
182238c8a9a5SSteve French 	cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
182338c8a9a5SSteve French 		 server->total_read, buflen, data_len);
182438c8a9a5SSteve French 
182538c8a9a5SSteve French 	/* discard anything left over */
182638c8a9a5SSteve French 	if (server->total_read < buflen)
182738c8a9a5SSteve French 		return cifs_readv_discard(server, mid);
182838c8a9a5SSteve French 
182938c8a9a5SSteve French 	dequeue_mid(mid, false);
183038c8a9a5SSteve French 	mid->resp_buf = server->smallbuf;
183138c8a9a5SSteve French 	server->smallbuf = NULL;
183238c8a9a5SSteve French 	return length;
183338c8a9a5SSteve French }
1834