transport.c 27.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 *   fs/cifs/transport.c
 *
S
Steve French 已提交
4
 *   Copyright (C) International Business Machines  Corp., 2002,2008
L
Linus Torvalds 已提交
5
 *   Author(s): Steve French (sfrench@us.ibm.com)
6
 *   Jeremy Allison (jra@samba.org) 2006.
S
Steve French 已提交
7
 *
L
Linus Torvalds 已提交
8 9 10 11 12 13 14 15 16 17 18 19
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this library; if not, write to the Free Software
S
Steve French 已提交
20
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
L
Linus Torvalds 已提交
21 22 23 24
 */

#include <linux/fs.h>
#include <linux/list.h>
25
#include <linux/gfp.h>
L
Linus Torvalds 已提交
26 27 28
#include <linux/wait.h>
#include <linux/net.h>
#include <linux/delay.h>
29
#include <linux/freezer.h>
30
#include <linux/tcp.h>
31
#include <linux/bvec.h>
32
#include <linux/highmem.h>
33
#include <linux/uaccess.h>
L
Linus Torvalds 已提交
34 35 36 37 38 39
#include <asm/processor.h>
#include <linux/mempool.h>
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
40

41 42
void
cifs_wake_up_task(struct mid_q_entry *mid)
43 44 45 46
{
	wake_up_process(mid->callback_data);
}

J
Jeff Layton 已提交
47
struct mid_q_entry *
48
AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
L
Linus Torvalds 已提交
49 50 51
{
	struct mid_q_entry *temp;

52
	if (server == NULL) {
53
		cifs_dbg(VFS, "Null TCP session in AllocMidQEntry\n");
L
Linus Torvalds 已提交
54 55
		return NULL;
	}
56

57
	temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
58 59 60 61 62
	memset(temp, 0, sizeof(struct mid_q_entry));
	temp->mid = get_mid(smb_buffer);
	temp->pid = current->pid;
	temp->command = cpu_to_le16(smb_buffer->Command);
	cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command);
S
Steve French 已提交
63
	/*	do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
64 65 66
	/* when mid allocated can be before when sent */
	temp->when_alloc = jiffies;
	temp->server = server;
67

68 69 70 71 72 73
	/*
	 * The default is for the mid to be synchronous, so the
	 * default callback just wakes up the current task.
	 */
	temp->callback = cifs_wake_up_task;
	temp->callback_data = current;
L
Linus Torvalds 已提交
74 75

	atomic_inc(&midCount);
76
	temp->mid_state = MID_REQUEST_ALLOCATED;
L
Linus Torvalds 已提交
77 78 79
	return temp;
}

80
void
L
Linus Torvalds 已提交
81 82
DeleteMidQEntry(struct mid_q_entry *midEntry)
{
S
Steve French 已提交
83
#ifdef CONFIG_CIFS_STATS2
84
	__le16 command = midEntry->server->vals->lock_cmd;
S
Steve French 已提交
85 86
	unsigned long now;
#endif
87
	midEntry->mid_state = MID_FREE;
88
	atomic_dec(&midCount);
89
	if (midEntry->large_buf)
90 91 92
		cifs_buf_release(midEntry->resp_buf);
	else
		cifs_small_buf_release(midEntry->resp_buf);
S
Steve French 已提交
93 94 95 96
#ifdef CONFIG_CIFS_STATS2
	now = jiffies;
	/* commands taking longer than one second are indications that
	   something is wrong, unless it is quite a slow link or server */
97
	if (time_after(now, midEntry->when_alloc + HZ)) {
98
		if ((cifsFYI & CIFS_TIMER) && (midEntry->command != command)) {
99
			pr_debug(" CIFS slow rsp: cmd %d mid %llu",
S
Steve French 已提交
100
			       midEntry->command, midEntry->mid);
101
			pr_info(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
S
Steve French 已提交
102 103 104 105 106 107
			       now - midEntry->when_alloc,
			       now - midEntry->when_sent,
			       now - midEntry->when_received);
		}
	}
#endif
L
Linus Torvalds 已提交
108 109 110
	mempool_free(midEntry, cifs_mid_poolp);
}

P
Pavel Shilovsky 已提交
111 112
void
cifs_delete_mid(struct mid_q_entry *mid)
113 114 115 116 117 118 119 120
{
	spin_lock(&GlobalMid_Lock);
	list_del(&mid->qhead);
	spin_unlock(&GlobalMid_Lock);

	DeleteMidQEntry(mid);
}

121 122 123
/*
 * smb_send_kvec - send an array of kvecs to the server
 * @server:	Server to send the data to
124
 * @smb_msg:	Message to send
125 126 127 128 129
 * @sent:	amount of data sent on socket is stored here
 *
 * Our basic "send data to server" function. Should be called with srv_mutex
 * held. The caller is responsible for handling the results.
 */
130
static int
131 132
smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
	      size_t *sent)
L
Linus Torvalds 已提交
133 134
{
	int rc = 0;
135
	int retries = 0;
136
	struct socket *ssocket = server->ssocket;
137

138 139
	*sent = 0;

140 141 142 143
	smb_msg->msg_name = (struct sockaddr *) &server->dstaddr;
	smb_msg->msg_namelen = sizeof(struct sockaddr);
	smb_msg->msg_control = NULL;
	smb_msg->msg_controllen = 0;
144
	if (server->noblocksnd)
145
		smb_msg->msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
146
	else
147
		smb_msg->msg_flags = MSG_NOSIGNAL;
L
Linus Torvalds 已提交
148

149
	while (msg_data_left(smb_msg)) {
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
		/*
		 * If blocking send, we try 3 times, since each can block
		 * for 5 seconds. For nonblocking  we have to try more
		 * but wait increasing amounts of time allowing time for
		 * socket to clear.  The overall time we wait in either
		 * case to send on the socket is about 15 seconds.
		 * Similarly we wait for 15 seconds for a response from
		 * the server in SendReceive[2] for the server to send
		 * a response back for most types of requests (except
		 * SMB Write past end of file which can be slow, and
		 * blocking lock operations). NFS waits slightly longer
		 * than CIFS, but this can make it take longer for
		 * nonresponsive servers to be detected and 15 seconds
		 * is more than enough time for modern networks to
		 * send a packet.  In most cases if we fail to send
		 * after the retries we will kill the socket and
		 * reconnect which may clear the network problem.
		 */
168
		rc = sock_sendmsg(ssocket, smb_msg);
169
		if (rc == -EAGAIN) {
170 171 172
			retries++;
			if (retries >= 14 ||
			    (!server->noblocksnd && (retries > 2))) {
173 174
				cifs_dbg(VFS, "sends on sock %p stuck for 15 seconds\n",
					 ssocket);
175
				return -EAGAIN;
L
Linus Torvalds 已提交
176
			}
177
			msleep(1 << retries);
L
Linus Torvalds 已提交
178 179
			continue;
		}
180

S
Steve French 已提交
181
		if (rc < 0)
182
			return rc;
183

S
Steve French 已提交
184
		if (rc == 0) {
185 186
			/* should never happen, letting socket clear before
			   retrying is our only obvious option here */
187
			cifs_dbg(VFS, "tcp sent no data\n");
188 189
			msleep(500);
			continue;
190
		}
191

192 193 194
		/* send was at least partially successful */
		*sent += rc;
		retries = 0; /* in case we get ENOSPC on the next send */
L
Linus Torvalds 已提交
195
	}
196
	return 0;
197 198
}

199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
static unsigned long
rqst_len(struct smb_rqst *rqst)
{
	unsigned int i;
	struct kvec *iov = rqst->rq_iov;
	unsigned long buflen = 0;

	/* total up iov array first */
	for (i = 0; i < rqst->rq_nvec; i++)
		buflen += iov[i].iov_len;

	/* add in the page array if there is one */
	if (rqst->rq_npages) {
		buflen += rqst->rq_pagesz * (rqst->rq_npages - 1);
		buflen += rqst->rq_tailsz;
	}

	return buflen;
}

219
static int
220
__smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
221 222 223 224 225
{
	int rc;
	struct kvec *iov = rqst->rq_iov;
	int n_vec = rqst->rq_nvec;
	unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
226
	unsigned long send_length;
227
	unsigned int i;
228
	size_t total_len = 0, sent, size;
229
	struct socket *ssocket = server->ssocket;
230
	struct msghdr smb_msg;
231
	int val = 1;
232

233 234 235
	if (ssocket == NULL)
		return -ENOTSOCK;

236 237 238 239 240 241 242 243
	/* sanity check send length */
	send_length = rqst_len(rqst);
	if (send_length != smb_buf_length + 4) {
		WARN(1, "Send length mismatch(send_length=%lu smb_buf_length=%u)\n",
			send_length, smb_buf_length);
		return -EIO;
	}

244 245 246
	if (n_vec < 2)
		return -EIO;

247
	cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length);
248
	dump_smb(iov[0].iov_base, iov[0].iov_len);
249
	dump_smb(iov[1].iov_base, iov[1].iov_len);
250

251 252 253 254
	/* cork the socket */
	kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
				(char *)&val, sizeof(val));

255 256 257 258 259 260 261
	size = 0;
	for (i = 0; i < n_vec; i++)
		size += iov[i].iov_len;

	iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC, iov, n_vec, size);

	rc = smb_send_kvec(server, &smb_msg, &sent);
262 263 264 265 266 267 268
	if (rc < 0)
		goto uncork;

	total_len += sent;

	/* now walk the page array and send each page in it */
	for (i = 0; i < rqst->rq_npages; i++) {
269 270 271 272 273 274 275 276 277 278
		size_t len = i == rqst->rq_npages - 1
				? rqst->rq_tailsz
				: rqst->rq_pagesz;
		struct bio_vec bvec = {
			.bv_page = rqst->rq_pages[i],
			.bv_len = len
		};
		iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC,
			      &bvec, 1, len);
		rc = smb_send_kvec(server, &smb_msg, &sent);
279 280 281 282 283
		if (rc < 0)
			break;

		total_len += sent;
	}
L
Linus Torvalds 已提交
284

285
uncork:
286 287 288 289 290
	/* uncork it */
	val = 0;
	kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
				(char *)&val, sizeof(val));

291
	if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
292 293
		cifs_dbg(FYI, "partial send (wanted=%u sent=%zu): terminating session\n",
			 smb_buf_length + 4, total_len);
294 295 296 297 298
		/*
		 * If we have only sent part of an SMB then the next SMB could
		 * be taken as the remainder of this one. We need to kill the
		 * socket so the server throws away the partial SMB
		 */
299 300 301
		server->tcpStatus = CifsNeedReconnect;
	}

302
	if (rc < 0 && rc != -EINTR)
303 304
		cifs_dbg(VFS, "Error %d sending data on socket to server\n",
			 rc);
305
	else
L
Linus Torvalds 已提交
306 307 308 309 310
		rc = 0;

	return rc;
}

311
static int
312
smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags)
313
{
314 315 316 317 318 319 320 321 322 323 324
	struct smb_rqst cur_rqst;
	int rc;

	if (!(flags & CIFS_TRANSFORM_REQ))
		return __smb_send_rqst(server, rqst);

	if (!server->ops->init_transform_rq ||
	    !server->ops->free_transform_rq) {
		cifs_dbg(VFS, "Encryption requested but transform callbacks are missed\n");
		return -EIO;
	}
325

326 327 328 329 330 331 332
	rc = server->ops->init_transform_rq(server, &cur_rqst, rqst);
	if (rc)
		return rc;

	rc = __smb_send_rqst(server, &cur_rqst);
	server->ops->free_transform_rq(&cur_rqst);
	return rc;
333 334
}

335 336 337 338
int
smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
	 unsigned int smb_buf_length)
{
339
	struct kvec iov[2];
340 341
	struct smb_rqst rqst = { .rq_iov = iov,
				 .rq_nvec = 2 };
342

343 344 345 346
	iov[0].iov_base = smb_buffer;
	iov[0].iov_len = 4;
	iov[1].iov_base = (char *)smb_buffer + 4;
	iov[1].iov_len = smb_buf_length;
347

348
	return __smb_send_rqst(server, &rqst);
349 350
}

P
Pavel Shilovsky 已提交
351
static int
352
wait_for_free_credits(struct TCP_Server_Info *server, const int timeout,
353
		      int *credits)
L
Linus Torvalds 已提交
354
{
355 356
	int rc;

P
Pavel Shilovsky 已提交
357
	spin_lock(&server->req_lock);
358
	if (timeout == CIFS_ASYNC_OP) {
L
Linus Torvalds 已提交
359
		/* oplock breaks must not be held up */
P
Pavel Shilovsky 已提交
360
		server->in_flight++;
361
		*credits -= 1;
P
Pavel Shilovsky 已提交
362
		spin_unlock(&server->req_lock);
363 364 365 366
		return 0;
	}

	while (1) {
367
		if (*credits <= 0) {
P
Pavel Shilovsky 已提交
368
			spin_unlock(&server->req_lock);
369
			cifs_num_waiters_inc(server);
370
			rc = wait_event_killable(server->request_q,
371
						 has_credits(server, credits));
372
			cifs_num_waiters_dec(server);
373 374
			if (rc)
				return rc;
P
Pavel Shilovsky 已提交
375
			spin_lock(&server->req_lock);
376
		} else {
377
			if (server->tcpStatus == CifsExiting) {
P
Pavel Shilovsky 已提交
378
				spin_unlock(&server->req_lock);
379
				return -ENOENT;
L
Linus Torvalds 已提交
380
			}
381

382 383 384 385
			/*
			 * Can not count locking commands against total
			 * as they are allowed to block on server.
			 */
386 387

			/* update # of requests on the wire to server */
388
			if (timeout != CIFS_BLOCKING_OP) {
389
				*credits -= 1;
P
Pavel Shilovsky 已提交
390
				server->in_flight++;
391
			}
P
Pavel Shilovsky 已提交
392
			spin_unlock(&server->req_lock);
393
			break;
L
Linus Torvalds 已提交
394 395
		}
	}
J
[CIFS]  
Jeremy Allison 已提交
396 397
	return 0;
}
L
Linus Torvalds 已提交
398

399
static int
400 401
wait_for_free_request(struct TCP_Server_Info *server, const int timeout,
		      const int optype)
402
{
403 404 405 406 407 408 409
	int *val;

	val = server->ops->get_credits_field(server, optype);
	/* Since an echo is already inflight, no need to wait to send another */
	if (*val <= 0 && optype == CIFS_ECHO_OP)
		return -EAGAIN;
	return wait_for_free_credits(server, timeout, val);
410 411
}

412 413 414 415 416 417 418 419 420
int
cifs_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
		      unsigned int *num, unsigned int *credits)
{
	*num = size;
	*credits = 0;
	return 0;
}

421
static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
J
[CIFS]  
Jeremy Allison 已提交
422 423
			struct mid_q_entry **ppmidQ)
{
L
Linus Torvalds 已提交
424
	if (ses->server->tcpStatus == CifsExiting) {
J
[CIFS]  
Jeremy Allison 已提交
425
		return -ENOENT;
426 427 428
	}

	if (ses->server->tcpStatus == CifsNeedReconnect) {
429
		cifs_dbg(FYI, "tcp session dead - return to caller to retry\n");
J
[CIFS]  
Jeremy Allison 已提交
430
		return -EAGAIN;
431 432
	}

433
	if (ses->status == CifsNew) {
S
Steve French 已提交
434
		if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
S
Steve French 已提交
435
			(in_buf->Command != SMB_COM_NEGOTIATE))
J
[CIFS]  
Jeremy Allison 已提交
436
			return -EAGAIN;
S
Steve French 已提交
437
		/* else ok - we are setting up session */
L
Linus Torvalds 已提交
438
	}
439 440 441 442 443 444 445 446

	if (ses->status == CifsExiting) {
		/* check if SMB session is bad because we are setting it up */
		if (in_buf->Command != SMB_COM_LOGOFF_ANDX)
			return -EAGAIN;
		/* else ok - we are shutting down session */
	}

447
	*ppmidQ = AllocMidQEntry(in_buf, ses->server);
448
	if (*ppmidQ == NULL)
J
[CIFS]  
Jeremy Allison 已提交
449
		return -ENOMEM;
450 451 452
	spin_lock(&GlobalMid_Lock);
	list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q);
	spin_unlock(&GlobalMid_Lock);
J
[CIFS]  
Jeremy Allison 已提交
453 454 455
	return 0;
}

456 457
static int
wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
J
[CIFS]  
Jeremy Allison 已提交
458
{
459
	int error;
J
[CIFS]  
Jeremy Allison 已提交
460

461
	error = wait_event_freezekillable_unsafe(server->response_q,
462
				    midQ->mid_state != MID_REQUEST_SUBMITTED);
463 464
	if (error < 0)
		return -ERESTARTSYS;
J
[CIFS]  
Jeremy Allison 已提交
465

466
	return 0;
J
[CIFS]  
Jeremy Allison 已提交
467 468
}

469 470
struct mid_q_entry *
cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
471 472
{
	int rc;
473
	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
474 475
	struct mid_q_entry *mid;

476 477 478 479
	if (rqst->rq_iov[0].iov_len != 4 ||
	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
		return ERR_PTR(-EIO);

480
	/* enable signing if server requires it */
481
	if (server->sign)
482 483 484 485
		hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;

	mid = AllocMidQEntry(hdr, server);
	if (mid == NULL)
486
		return ERR_PTR(-ENOMEM);
487

488
	rc = cifs_sign_rqst(rqst, server, &mid->sequence_number);
489 490
	if (rc) {
		DeleteMidQEntry(mid);
491
		return ERR_PTR(rc);
492 493
	}

494
	return mid;
495
}
496

J
Jeff Layton 已提交
497 498 499 500 501
/*
 * Send a SMB request and set the callback function in the mid to handle
 * the result. Caller is responsible for dealing with timeouts.
 */
int
502
cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
P
Pavel Shilovsky 已提交
503 504
		mid_receive_t *receive, mid_callback_t *callback,
		mid_handle_t *handle, void *cbdata, const int flags)
J
Jeff Layton 已提交
505
{
506
	int rc, timeout, optype;
J
Jeff Layton 已提交
507
	struct mid_q_entry *mid;
508
	unsigned int credits = 0;
J
Jeff Layton 已提交
509

510 511 512
	timeout = flags & CIFS_TIMEOUT_MASK;
	optype = flags & CIFS_OP_MASK;

513 514 515 516 517 518
	if ((flags & CIFS_HAS_CREDITS) == 0) {
		rc = wait_for_free_request(server, timeout, optype);
		if (rc)
			return rc;
		credits = 1;
	}
J
Jeff Layton 已提交
519 520

	mutex_lock(&server->srv_mutex);
521 522
	mid = server->ops->setup_async_request(server, rqst);
	if (IS_ERR(mid)) {
J
Jeff Layton 已提交
523
		mutex_unlock(&server->srv_mutex);
524
		add_credits_and_wake_if(server, credits, optype);
525
		return PTR_ERR(mid);
J
Jeff Layton 已提交
526 527
	}

528
	mid->receive = receive;
J
Jeff Layton 已提交
529 530
	mid->callback = callback;
	mid->callback_data = cbdata;
P
Pavel Shilovsky 已提交
531
	mid->handle = handle;
532
	mid->mid_state = MID_REQUEST_SUBMITTED;
533

534 535 536 537 538 539
	/* put it on the pending_mid_q */
	spin_lock(&GlobalMid_Lock);
	list_add_tail(&mid->qhead, &server->pending_mid_q);
	spin_unlock(&GlobalMid_Lock);


540
	cifs_in_send_inc(server);
541
	rc = smb_send_rqst(server, rqst, flags);
542 543
	cifs_in_send_dec(server);
	cifs_save_when_sent(mid);
544

545
	if (rc < 0) {
546
		server->sequence_number -= 2;
547 548 549
		cifs_delete_mid(mid);
	}

J
Jeff Layton 已提交
550
	mutex_unlock(&server->srv_mutex);
551

552 553
	if (rc == 0)
		return 0;
J
Jeff Layton 已提交
554

555
	add_credits_and_wake_if(server, credits, optype);
J
Jeff Layton 已提交
556 557 558
	return rc;
}

559 560 561 562 563 564 565 566 567 568
/*
 *
 * Send an SMB Request.  No response info (other than return code)
 * needs to be parsed.
 *
 * flags indicate the type of request buffer and how long to wait
 * and whether to log NT STATUS code (error) before mapping it to POSIX error
 *
 */
int
569
SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
570
		 char *in_buf, int flags)
571 572 573
{
	int rc;
	struct kvec iov[1];
574
	struct kvec rsp_iov;
575 576
	int resp_buf_type;

577 578
	iov[0].iov_base = in_buf;
	iov[0].iov_len = get_rfc1002_length(in_buf) + 4;
579
	flags |= CIFS_NO_RESP;
580
	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
581
	cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc);
582

583 584 585
	return rc;
}

586
static int
587
cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
588 589 590
{
	int rc = 0;

591 592
	cifs_dbg(FYI, "%s: cmd=%d mid=%llu state=%d\n",
		 __func__, le16_to_cpu(mid->command), mid->mid, mid->mid_state);
593

J
Jeff Layton 已提交
594
	spin_lock(&GlobalMid_Lock);
595
	switch (mid->mid_state) {
J
Jeff Layton 已提交
596
	case MID_RESPONSE_RECEIVED:
597 598
		spin_unlock(&GlobalMid_Lock);
		return rc;
J
Jeff Layton 已提交
599 600 601
	case MID_RETRY_NEEDED:
		rc = -EAGAIN;
		break;
602 603 604
	case MID_RESPONSE_MALFORMED:
		rc = -EIO;
		break;
605 606 607
	case MID_SHUTDOWN:
		rc = -EHOSTDOWN;
		break;
J
Jeff Layton 已提交
608
	default:
609
		list_del_init(&mid->qhead);
610 611
		cifs_dbg(VFS, "%s: invalid mid state mid=%llu state=%d\n",
			 __func__, mid->mid, mid->mid_state);
J
Jeff Layton 已提交
612
		rc = -EIO;
613 614 615
	}
	spin_unlock(&GlobalMid_Lock);

616
	DeleteMidQEntry(mid);
617 618 619
	return rc;
}

620
static inline int
621 622
send_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
	    struct mid_q_entry *mid)
623
{
624
	return server->ops->send_cancel ?
625
				server->ops->send_cancel(server, rqst, mid) : 0;
626 627
}

628 629 630 631
int
cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
		   bool log_error)
{
632
	unsigned int len = get_rfc1002_length(mid->resp_buf) + 4;
633 634

	dump_smb(mid->resp_buf, min_t(u32, 92, len));
635 636

	/* convert the length into a more usable form */
637
	if (server->sign) {
638
		struct kvec iov[2];
639
		int rc = 0;
640 641
		struct smb_rqst rqst = { .rq_iov = iov,
					 .rq_nvec = 2 };
642

643 644 645 646
		iov[0].iov_base = mid->resp_buf;
		iov[0].iov_len = 4;
		iov[1].iov_base = (char *)mid->resp_buf + 4;
		iov[1].iov_len = len - 4;
647
		/* FIXME: add code to kill session */
648
		rc = cifs_verify_signature(&rqst, server,
649
					   mid->sequence_number);
650
		if (rc)
651 652
			cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
				 rc);
653 654 655 656 657 658
	}

	/* BB special case reconnect tid and uid here? */
	return map_smb_to_linux_error(mid->resp_buf, log_error);
}

659 660
struct mid_q_entry *
cifs_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
661 662
{
	int rc;
663
	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
664 665
	struct mid_q_entry *mid;

666 667 668 669
	if (rqst->rq_iov[0].iov_len != 4 ||
	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
		return ERR_PTR(-EIO);

670 671
	rc = allocate_mid(ses, hdr, &mid);
	if (rc)
672 673 674
		return ERR_PTR(rc);
	rc = cifs_sign_rqst(rqst, ses->server, &mid->sequence_number);
	if (rc) {
P
Pavel Shilovsky 已提交
675
		cifs_delete_mid(mid);
676 677 678
		return ERR_PTR(rc);
	}
	return mid;
679 680
}

681
int
682 683 684
cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
	       struct smb_rqst *rqst, int *resp_buf_type, const int flags,
	       struct kvec *resp_iov)
J
[CIFS]  
Jeremy Allison 已提交
685 686
{
	int rc = 0;
687
	int timeout, optype;
J
[CIFS]  
Jeremy Allison 已提交
688
	struct mid_q_entry *midQ;
689
	unsigned int credits = 1;
690
	char *buf;
691

692 693
	timeout = flags & CIFS_TIMEOUT_MASK;
	optype = flags & CIFS_OP_MASK;
694

695
	*resp_buf_type = CIFS_NO_BUFFER;  /* no response buf yet */
J
[CIFS]  
Jeremy Allison 已提交
696 697

	if ((ses == NULL) || (ses->server == NULL)) {
698
		cifs_dbg(VFS, "Null session\n");
J
[CIFS]  
Jeremy Allison 已提交
699 700 701
		return -EIO;
	}

702
	if (ses->server->tcpStatus == CifsExiting)
J
[CIFS]  
Jeremy Allison 已提交
703 704
		return -ENOENT;

705 706 707 708 709
	/*
	 * Ensure that we do not send more than 50 overlapping requests
	 * to the same server. We may make this configurable later or
	 * use ses->maxReq.
	 */
J
[CIFS]  
Jeremy Allison 已提交
710

711
	rc = wait_for_free_request(ses->server, timeout, optype);
712
	if (rc)
J
[CIFS]  
Jeremy Allison 已提交
713 714
		return rc;

715 716 717 718 719
	/*
	 * Make sure that we sign in the same order that we send on this socket
	 * and avoid races inside tcp sendmsg code that could cause corruption
	 * of smb data.
	 */
J
[CIFS]  
Jeremy Allison 已提交
720

J
Jeff Layton 已提交
721
	mutex_lock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
722

723
	midQ = ses->server->ops->setup_request(ses, rqst);
724
	if (IS_ERR(midQ)) {
J
Jeff Layton 已提交
725
		mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
726
		/* Update # of requests on wire to server */
727
		add_credits(ses->server, 1, optype);
728
		return PTR_ERR(midQ);
L
Linus Torvalds 已提交
729 730
	}

731
	midQ->mid_state = MID_REQUEST_SUBMITTED;
732
	cifs_in_send_inc(ses->server);
733
	rc = smb_send_rqst(ses->server, rqst, flags);
734 735
	cifs_in_send_dec(ses->server);
	cifs_save_when_sent(midQ);
J
[CIFS]  
Jeremy Allison 已提交
736

737 738
	if (rc < 0)
		ses->server->sequence_number -= 2;
J
Jeff Layton 已提交
739
	mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
740

741
	if (rc < 0)
J
[CIFS]  
Jeremy Allison 已提交
742
		goto out;
743

744
	if (timeout == CIFS_ASYNC_OP)
745
		goto out;
746

747
	rc = wait_for_response(ses->server, midQ);
748
	if (rc != 0) {
S
Sachin Prabhu 已提交
749
		cifs_dbg(FYI, "Cancelling wait for mid %llu\n",	midQ->mid);
750
		send_cancel(ses->server, rqst, midQ);
751
		spin_lock(&GlobalMid_Lock);
752
		if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
S
Sachin Prabhu 已提交
753
			midQ->mid_flags |= MID_WAIT_CANCELLED;
754 755
			midQ->callback = DeleteMidQEntry;
			spin_unlock(&GlobalMid_Lock);
756
			add_credits(ses->server, 1, optype);
757 758 759 760
			return rc;
		}
		spin_unlock(&GlobalMid_Lock);
	}
761

762
	rc = cifs_sync_mid_result(midQ, ses->server);
763
	if (rc != 0) {
764
		add_credits(ses->server, 1, optype);
765 766
		return rc;
	}
767

768
	if (!midQ->resp_buf || midQ->mid_state != MID_RESPONSE_RECEIVED) {
769
		rc = -EIO;
770
		cifs_dbg(FYI, "Bad MID state?\n");
771 772 773
		goto out;
	}

774
	buf = (char *)midQ->resp_buf;
775 776
	resp_iov->iov_base = buf;
	resp_iov->iov_len = get_rfc1002_length(buf) + 4;
777
	if (midQ->large_buf)
778
		*resp_buf_type = CIFS_LARGE_BUFFER;
779
	else
780 781 782
		*resp_buf_type = CIFS_SMALL_BUFFER;

	credits = ses->server->ops->get_credits(midQ);
783

784 785
	rc = ses->server->ops->check_receive(midQ, ses->server,
					     flags & CIFS_LOG_ERROR);
L
Linus Torvalds 已提交
786

P
Pavel Shilovsky 已提交
787
	/* mark it so buf will not be freed by cifs_delete_mid */
788 789
	if ((flags & CIFS_NO_RESP) == 0)
		midQ->resp_buf = NULL;
J
[CIFS]  
Jeremy Allison 已提交
790
out:
P
Pavel Shilovsky 已提交
791
	cifs_delete_mid(midQ);
792
	add_credits(ses->server, credits, optype);
L
Linus Torvalds 已提交
793

794 795
	return rc;
}
L
Linus Torvalds 已提交
796

797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
int
SendReceive2(const unsigned int xid, struct cifs_ses *ses,
	     struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
	     const int flags, struct kvec *resp_iov)
{
	struct smb_rqst rqst;
	struct kvec *new_iov;
	int rc;

	new_iov = kmalloc(sizeof(struct kvec) * (n_vec + 1), GFP_KERNEL);
	if (!new_iov)
		return -ENOMEM;

	/* 1st iov is a RFC1001 length followed by the rest of the packet */
	memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec));

	new_iov[0].iov_base = new_iov[1].iov_base;
	new_iov[0].iov_len = 4;
	new_iov[1].iov_base += 4;
	new_iov[1].iov_len -= 4;

	memset(&rqst, 0, sizeof(struct smb_rqst));
	rqst.rq_iov = new_iov;
	rqst.rq_nvec = n_vec + 1;

	rc = cifs_send_recv(xid, ses, &rqst, resp_buf_type, flags, resp_iov);
	kfree(new_iov);
	return rc;
}

L
Linus Torvalds 已提交
827
int
828
SendReceive(const unsigned int xid, struct cifs_ses *ses,
L
Linus Torvalds 已提交
829
	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
830
	    int *pbytes_returned, const int timeout)
L
Linus Torvalds 已提交
831 832 833
{
	int rc = 0;
	struct mid_q_entry *midQ;
834 835 836
	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
L
Linus Torvalds 已提交
837 838

	if (ses == NULL) {
839
		cifs_dbg(VFS, "Null smb session\n");
L
Linus Torvalds 已提交
840 841
		return -EIO;
	}
S
Steve French 已提交
842
	if (ses->server == NULL) {
843
		cifs_dbg(VFS, "Null tcp session\n");
L
Linus Torvalds 已提交
844 845 846
		return -EIO;
	}

S
Steve French 已提交
847
	if (ses->server->tcpStatus == CifsExiting)
848 849
		return -ENOENT;

S
Steve French 已提交
850
	/* Ensure that we do not send more than 50 overlapping requests
L
Linus Torvalds 已提交
851 852 853
	   to the same server. We may make this configurable later or
	   use ses->maxReq */

854
	if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
855
		cifs_dbg(VFS, "Illegal length, greater than maximum frame, %d\n",
856
			 len);
857 858 859
		return -EIO;
	}

860
	rc = wait_for_free_request(ses->server, timeout, 0);
J
[CIFS]  
Jeremy Allison 已提交
861 862 863
	if (rc)
		return rc;

S
Steve French 已提交
864
	/* make sure that we sign in the same order that we send on this socket
L
Linus Torvalds 已提交
865 866 867
	   and avoid races inside tcp sendmsg code that could cause corruption
	   of smb data */

J
Jeff Layton 已提交
868
	mutex_lock(&ses->server->srv_mutex);
L
Linus Torvalds 已提交
869

J
[CIFS]  
Jeremy Allison 已提交
870 871
	rc = allocate_mid(ses, in_buf, &midQ);
	if (rc) {
J
Jeff Layton 已提交
872
		mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
873
		/* Update # of requests on wire to server */
874
		add_credits(ses->server, 1, 0);
J
[CIFS]  
Jeremy Allison 已提交
875
		return rc;
L
Linus Torvalds 已提交
876 877
	}

878
	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
879 880 881 882
	if (rc) {
		mutex_unlock(&ses->server->srv_mutex);
		goto out;
	}
L
Linus Torvalds 已提交
883

884
	midQ->mid_state = MID_REQUEST_SUBMITTED;
885 886

	cifs_in_send_inc(ses->server);
887
	rc = smb_send(ses->server, in_buf, len);
888 889
	cifs_in_send_dec(ses->server);
	cifs_save_when_sent(midQ);
890 891 892 893

	if (rc < 0)
		ses->server->sequence_number -= 2;

J
Jeff Layton 已提交
894
	mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
895

S
Steve French 已提交
896
	if (rc < 0)
J
[CIFS]  
Jeremy Allison 已提交
897 898
		goto out;

899
	if (timeout == CIFS_ASYNC_OP)
J
[CIFS]  
Jeremy Allison 已提交
900
		goto out;
L
Linus Torvalds 已提交
901

902
	rc = wait_for_response(ses->server, midQ);
903
	if (rc != 0) {
904
		send_cancel(ses->server, &rqst, midQ);
905
		spin_lock(&GlobalMid_Lock);
906
		if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
907 908 909
			/* no longer considered to be "in-flight" */
			midQ->callback = DeleteMidQEntry;
			spin_unlock(&GlobalMid_Lock);
910
			add_credits(ses->server, 1, 0);
911 912 913 914
			return rc;
		}
		spin_unlock(&GlobalMid_Lock);
	}
L
Linus Torvalds 已提交
915

916
	rc = cifs_sync_mid_result(midQ, ses->server);
917
	if (rc != 0) {
918
		add_credits(ses->server, 1, 0);
L
Linus Torvalds 已提交
919 920
		return rc;
	}
921

922
	if (!midQ->resp_buf || !out_buf ||
923
	    midQ->mid_state != MID_RESPONSE_RECEIVED) {
924
		rc = -EIO;
925
		cifs_dbg(VFS, "Bad MID state?\n");
926
		goto out;
L
Linus Torvalds 已提交
927
	}
J
[CIFS]  
Jeremy Allison 已提交
928

929
	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
930 931
	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
	rc = cifs_check_receive(midQ, ses->server, 0);
J
[CIFS]  
Jeremy Allison 已提交
932
out:
P
Pavel Shilovsky 已提交
933
	cifs_delete_mid(midQ);
934
	add_credits(ses->server, 1, 0);
L
Linus Torvalds 已提交
935

J
[CIFS]  
Jeremy Allison 已提交
936 937
	return rc;
}
L
Linus Torvalds 已提交
938

J
[CIFS]  
Jeremy Allison 已提交
939 940 941 942
/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
   blocking lock to return. */

static int
943
send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon,
J
[CIFS]  
Jeremy Allison 已提交
944 945 946 947
			struct smb_hdr *in_buf,
			struct smb_hdr *out_buf)
{
	int bytes_returned;
948
	struct cifs_ses *ses = tcon->ses;
J
[CIFS]  
Jeremy Allison 已提交
949 950 951 952 953 954 955 956 957
	LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;

	/* We just modify the current in_buf to change
	   the type of lock from LOCKING_ANDX_SHARED_LOCK
	   or LOCKING_ANDX_EXCLUSIVE_LOCK to
	   LOCKING_ANDX_CANCEL_LOCK. */

	pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
	pSMB->Timeout = 0;
958
	pSMB->hdr.Mid = get_next_mid(ses->server);
J
[CIFS]  
Jeremy Allison 已提交
959 960

	return SendReceive(xid, ses, in_buf, out_buf,
961
			&bytes_returned, 0);
J
[CIFS]  
Jeremy Allison 已提交
962 963 964
}

int
965
SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
J
[CIFS]  
Jeremy Allison 已提交
966 967 968 969 970 971
	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
	    int *pbytes_returned)
{
	int rc = 0;
	int rstart = 0;
	struct mid_q_entry *midQ;
972
	struct cifs_ses *ses;
973 974 975
	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
J
[CIFS]  
Jeremy Allison 已提交
976 977

	if (tcon == NULL || tcon->ses == NULL) {
978
		cifs_dbg(VFS, "Null smb session\n");
J
[CIFS]  
Jeremy Allison 已提交
979 980 981 982
		return -EIO;
	}
	ses = tcon->ses;

S
Steve French 已提交
983
	if (ses->server == NULL) {
984
		cifs_dbg(VFS, "Null tcp session\n");
J
[CIFS]  
Jeremy Allison 已提交
985 986 987
		return -EIO;
	}

S
Steve French 已提交
988
	if (ses->server->tcpStatus == CifsExiting)
J
[CIFS]  
Jeremy Allison 已提交
989 990
		return -ENOENT;

S
Steve French 已提交
991
	/* Ensure that we do not send more than 50 overlapping requests
J
[CIFS]  
Jeremy Allison 已提交
992 993 994
	   to the same server. We may make this configurable later or
	   use ses->maxReq */

995
	if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
996
		cifs_dbg(VFS, "Illegal length, greater than maximum frame, %d\n",
997
			 len);
998 999 1000
		return -EIO;
	}

1001
	rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP, 0);
J
[CIFS]  
Jeremy Allison 已提交
1002 1003 1004
	if (rc)
		return rc;

S
Steve French 已提交
1005
	/* make sure that we sign in the same order that we send on this socket
J
[CIFS]  
Jeremy Allison 已提交
1006 1007 1008
	   and avoid races inside tcp sendmsg code that could cause corruption
	   of smb data */

J
Jeff Layton 已提交
1009
	mutex_lock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
1010 1011 1012

	rc = allocate_mid(ses, in_buf, &midQ);
	if (rc) {
J
Jeff Layton 已提交
1013
		mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
1014 1015 1016 1017
		return rc;
	}

	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
1018
	if (rc) {
P
Pavel Shilovsky 已提交
1019
		cifs_delete_mid(midQ);
1020 1021 1022
		mutex_unlock(&ses->server->srv_mutex);
		return rc;
	}
L
Linus Torvalds 已提交
1023

1024
	midQ->mid_state = MID_REQUEST_SUBMITTED;
1025
	cifs_in_send_inc(ses->server);
1026
	rc = smb_send(ses->server, in_buf, len);
1027 1028
	cifs_in_send_dec(ses->server);
	cifs_save_when_sent(midQ);
1029 1030 1031 1032

	if (rc < 0)
		ses->server->sequence_number -= 2;

J
Jeff Layton 已提交
1033
	mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
1034

S
Steve French 已提交
1035
	if (rc < 0) {
P
Pavel Shilovsky 已提交
1036
		cifs_delete_mid(midQ);
J
[CIFS]  
Jeremy Allison 已提交
1037 1038 1039 1040 1041
		return rc;
	}

	/* Wait for a reply - allow signals to interrupt. */
	rc = wait_event_interruptible(ses->server->response_q,
1042
		(!(midQ->mid_state == MID_REQUEST_SUBMITTED)) ||
J
[CIFS]  
Jeremy Allison 已提交
1043 1044 1045 1046 1047
		((ses->server->tcpStatus != CifsGood) &&
		 (ses->server->tcpStatus != CifsNew)));

	/* Were we interrupted by a signal ? */
	if ((rc == -ERESTARTSYS) &&
1048
		(midQ->mid_state == MID_REQUEST_SUBMITTED) &&
J
[CIFS]  
Jeremy Allison 已提交
1049 1050 1051 1052 1053 1054
		((ses->server->tcpStatus == CifsGood) ||
		 (ses->server->tcpStatus == CifsNew))) {

		if (in_buf->Command == SMB_COM_TRANSACTION2) {
			/* POSIX lock. We send a NT_CANCEL SMB to cause the
			   blocking lock to return. */
1055
			rc = send_cancel(ses->server, &rqst, midQ);
J
[CIFS]  
Jeremy Allison 已提交
1056
			if (rc) {
P
Pavel Shilovsky 已提交
1057
				cifs_delete_mid(midQ);
J
[CIFS]  
Jeremy Allison 已提交
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
				return rc;
			}
		} else {
			/* Windows lock. We send a LOCKINGX_CANCEL_LOCK
			   to cause the blocking lock to return. */

			rc = send_lock_cancel(xid, tcon, in_buf, out_buf);

			/* If we get -ENOLCK back the lock may have
			   already been removed. Don't exit in this case. */
			if (rc && rc != -ENOLCK) {
P
Pavel Shilovsky 已提交
1069
				cifs_delete_mid(midQ);
J
[CIFS]  
Jeremy Allison 已提交
1070 1071 1072 1073
				return rc;
			}
		}

1074 1075
		rc = wait_for_response(ses->server, midQ);
		if (rc) {
1076
			send_cancel(ses->server, &rqst, midQ);
1077
			spin_lock(&GlobalMid_Lock);
1078
			if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
1079 1080 1081 1082 1083 1084
				/* no longer considered to be "in-flight" */
				midQ->callback = DeleteMidQEntry;
				spin_unlock(&GlobalMid_Lock);
				return rc;
			}
			spin_unlock(&GlobalMid_Lock);
J
[CIFS]  
Jeremy Allison 已提交
1085
		}
1086 1087 1088

		/* We got the response - restart system call. */
		rstart = 1;
J
[CIFS]  
Jeremy Allison 已提交
1089 1090
	}

1091
	rc = cifs_sync_mid_result(midQ, ses->server);
1092
	if (rc != 0)
J
[CIFS]  
Jeremy Allison 已提交
1093
		return rc;
1094

1095
	/* rcvd frame is ok */
1096
	if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_RECEIVED) {
1097
		rc = -EIO;
1098
		cifs_dbg(VFS, "Bad MID state?\n");
1099 1100
		goto out;
	}
L
Linus Torvalds 已提交
1101

1102
	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
1103 1104
	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
	rc = cifs_check_receive(midQ, ses->server, 0);
1105
out:
P
Pavel Shilovsky 已提交
1106
	cifs_delete_mid(midQ);
J
[CIFS]  
Jeremy Allison 已提交
1107 1108
	if (rstart && rc == -EACCES)
		return -ERESTARTSYS;
L
Linus Torvalds 已提交
1109 1110
	return rc;
}