transport.c 23.3 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>
L
Linus Torvalds 已提交
30 31 32 33 34 35 36
#include <asm/uaccess.h>
#include <asm/processor.h>
#include <linux/mempool.h>
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
37

38 39
void
cifs_wake_up_task(struct mid_q_entry *mid)
40 41 42 43
{
	wake_up_process(mid->callback_data);
}

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

49
	if (server == NULL) {
50
		cERROR(1, "Null TCP session in AllocMidQEntry");
L
Linus Torvalds 已提交
51 52
		return NULL;
	}
53

54
	temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
L
Linus Torvalds 已提交
55 56 57
	if (temp == NULL)
		return temp;
	else {
58
		memset(temp, 0, sizeof(struct mid_q_entry));
L
Linus Torvalds 已提交
59 60
		temp->mid = smb_buffer->Mid;	/* always LE */
		temp->pid = current->pid;
61 62
		temp->command = cpu_to_le16(smb_buffer->Command);
		cFYI(1, "For smb_command %d", smb_buffer->Command);
S
Steve French 已提交
63 64 65
	/*	do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
		/* when mid allocated can be before when sent */
		temp->when_alloc = jiffies;
66
		temp->server = server;
67 68 69 70 71

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

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

81
void
L
Linus Torvalds 已提交
82 83
DeleteMidQEntry(struct mid_q_entry *midEntry)
{
S
Steve French 已提交
84
#ifdef CONFIG_CIFS_STATS2
85
	__le16 command = midEntry->server->vals->lock_cmd;
S
Steve French 已提交
86 87
	unsigned long now;
#endif
88
	midEntry->mid_state = MID_FREE;
89
	atomic_dec(&midCount);
90
	if (midEntry->large_buf)
91 92 93
		cifs_buf_release(midEntry->resp_buf);
	else
		cifs_small_buf_release(midEntry->resp_buf);
S
Steve French 已提交
94 95 96 97
#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 */
S
Steve French 已提交
98
	if ((now - midEntry->when_alloc) > HZ) {
99
		if ((cifsFYI & CIFS_TIMER) && (midEntry->command != command)) {
100
			printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %llu",
S
Steve French 已提交
101 102 103 104 105 106 107 108
			       midEntry->command, midEntry->mid);
			printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
			       now - midEntry->when_alloc,
			       now - midEntry->when_sent,
			       now - midEntry->when_received);
		}
	}
#endif
L
Linus Torvalds 已提交
109 110 111
	mempool_free(midEntry, cifs_mid_poolp);
}

112 113 114 115 116 117 118 119 120 121
static void
delete_mid(struct mid_q_entry *mid)
{
	spin_lock(&GlobalMid_Lock);
	list_del(&mid->qhead);
	spin_unlock(&GlobalMid_Lock);

	DeleteMidQEntry(mid);
}

122
static int
123
smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
L
Linus Torvalds 已提交
124 125 126 127
{
	int rc = 0;
	int i = 0;
	struct msghdr smb_msg;
128 129 130
	unsigned int len = iov[0].iov_len;
	unsigned int total_len;
	int first_vec = 0;
131
	unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
132
	struct socket *ssocket = server->ssocket;
133

S
Steve French 已提交
134
	if (ssocket == NULL)
L
Linus Torvalds 已提交
135
		return -ENOTSOCK; /* BB eventually add reconnect code here */
136

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

146 147 148 149
	total_len = 0;
	for (i = 0; i < n_vec; i++)
		total_len += iov[i].iov_len;

150
	cFYI(1, "Sending smb:  total_len %d", total_len);
151
	dump_smb(iov[0].iov_base, len);
L
Linus Torvalds 已提交
152

153
	i = 0;
154 155 156
	while (total_len) {
		rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
				    n_vec - first_vec, total_len);
L
Linus Torvalds 已提交
157 158
		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
			i++;
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
			/*
			 * 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.
			 */
177
			if ((i >= 14) || (!server->noblocksnd && (i > 2))) {
178 179
				cERROR(1, "sends on sock %p stuck for 15 seconds",
				    ssocket);
L
Linus Torvalds 已提交
180 181 182
				rc = -EAGAIN;
				break;
			}
183
			msleep(1 << i);
L
Linus Torvalds 已提交
184 185
			continue;
		}
S
Steve French 已提交
186
		if (rc < 0)
L
Linus Torvalds 已提交
187
			break;
188

S
Steve French 已提交
189 190 191 192
		if (rc == total_len) {
			total_len = 0;
			break;
		} else if (rc > total_len) {
193
			cERROR(1, "sent %d requested %d", rc, total_len);
194 195
			break;
		}
S
Steve French 已提交
196
		if (rc == 0) {
197 198
			/* should never happen, letting socket clear before
			   retrying is our only obvious option here */
199
			cERROR(1, "tcp sent no data");
200 201
			msleep(500);
			continue;
202
		}
203
		total_len -= rc;
204
		/* the line below resets i */
205 206 207 208 209 210 211 212 213 214 215 216
		for (i = first_vec; i < n_vec; i++) {
			if (iov[i].iov_len) {
				if (rc > iov[i].iov_len) {
					rc -= iov[i].iov_len;
					iov[i].iov_len = 0;
				} else {
					iov[i].iov_base += rc;
					iov[i].iov_len -= rc;
					first_vec = i;
					break;
				}
			}
217
		}
218
		i = 0; /* in case we get ENOSPC on the next send */
L
Linus Torvalds 已提交
219 220
	}

221
	if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
222 223
		cFYI(1, "partial send (%d remaining), terminating session",
			total_len);
224 225 226 227 228 229 230
		/* 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 */
		server->tcpStatus = CifsNeedReconnect;
	}

231
	if (rc < 0 && rc != -EINTR)
232
		cERROR(1, "Error %d sending data on socket to server", rc);
233
	else
L
Linus Torvalds 已提交
234 235 236 237 238
		rc = 0;

	return rc;
}

239 240 241 242 243 244 245 246 247 248 249 250
int
smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
	 unsigned int smb_buf_length)
{
	struct kvec iov;

	iov.iov_base = smb_buffer;
	iov.iov_len = smb_buf_length + 4;

	return smb_sendv(server, &iov, 1);
}

P
Pavel Shilovsky 已提交
251
static int
252
wait_for_free_credits(struct TCP_Server_Info *server, const int timeout,
253
		      int *credits)
L
Linus Torvalds 已提交
254
{
255 256
	int rc;

P
Pavel Shilovsky 已提交
257
	spin_lock(&server->req_lock);
258
	if (timeout == CIFS_ASYNC_OP) {
L
Linus Torvalds 已提交
259
		/* oplock breaks must not be held up */
P
Pavel Shilovsky 已提交
260
		server->in_flight++;
261
		*credits -= 1;
P
Pavel Shilovsky 已提交
262
		spin_unlock(&server->req_lock);
263 264 265 266
		return 0;
	}

	while (1) {
267
		if (*credits <= 0) {
P
Pavel Shilovsky 已提交
268
			spin_unlock(&server->req_lock);
269
			cifs_num_waiters_inc(server);
270
			rc = wait_event_killable(server->request_q,
271
						 has_credits(server, credits));
272
			cifs_num_waiters_dec(server);
273 274
			if (rc)
				return rc;
P
Pavel Shilovsky 已提交
275
			spin_lock(&server->req_lock);
276
		} else {
277
			if (server->tcpStatus == CifsExiting) {
P
Pavel Shilovsky 已提交
278
				spin_unlock(&server->req_lock);
279
				return -ENOENT;
L
Linus Torvalds 已提交
280
			}
281

282 283 284 285
			/*
			 * Can not count locking commands against total
			 * as they are allowed to block on server.
			 */
286 287

			/* update # of requests on the wire to server */
288
			if (timeout != CIFS_BLOCKING_OP) {
289
				*credits -= 1;
P
Pavel Shilovsky 已提交
290
				server->in_flight++;
291
			}
P
Pavel Shilovsky 已提交
292
			spin_unlock(&server->req_lock);
293
			break;
L
Linus Torvalds 已提交
294 295
		}
	}
J
[CIFS]  
Jeremy Allison 已提交
296 297
	return 0;
}
L
Linus Torvalds 已提交
298

299
static int
300 301
wait_for_free_request(struct TCP_Server_Info *server, const int timeout,
		      const int optype)
302
{
303 304
	return wait_for_free_credits(server, timeout,
				server->ops->get_credits_field(server, optype));
305 306
}

307
static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
J
[CIFS]  
Jeremy Allison 已提交
308 309
			struct mid_q_entry **ppmidQ)
{
L
Linus Torvalds 已提交
310
	if (ses->server->tcpStatus == CifsExiting) {
J
[CIFS]  
Jeremy Allison 已提交
311
		return -ENOENT;
312 313 314
	}

	if (ses->server->tcpStatus == CifsNeedReconnect) {
315
		cFYI(1, "tcp session dead - return to caller to retry");
J
[CIFS]  
Jeremy Allison 已提交
316
		return -EAGAIN;
317 318 319
	}

	if (ses->status != CifsGood) {
L
Linus Torvalds 已提交
320
		/* check if SMB session is bad because we are setting it up */
S
Steve French 已提交
321
		if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
S
Steve French 已提交
322
			(in_buf->Command != SMB_COM_NEGOTIATE))
J
[CIFS]  
Jeremy Allison 已提交
323
			return -EAGAIN;
S
Steve French 已提交
324
		/* else ok - we are setting up session */
L
Linus Torvalds 已提交
325
	}
326
	*ppmidQ = AllocMidQEntry(in_buf, ses->server);
327
	if (*ppmidQ == NULL)
J
[CIFS]  
Jeremy Allison 已提交
328
		return -ENOMEM;
329 330 331
	spin_lock(&GlobalMid_Lock);
	list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q);
	spin_unlock(&GlobalMid_Lock);
J
[CIFS]  
Jeremy Allison 已提交
332 333 334
	return 0;
}

335 336
static int
wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
J
[CIFS]  
Jeremy Allison 已提交
337
{
338
	int error;
J
[CIFS]  
Jeremy Allison 已提交
339

340
	error = wait_event_freezekillable(server->response_q,
341
				    midQ->mid_state != MID_REQUEST_SUBMITTED);
342 343
	if (error < 0)
		return -ERESTARTSYS;
J
[CIFS]  
Jeremy Allison 已提交
344

345
	return 0;
J
[CIFS]  
Jeremy Allison 已提交
346 347
}

348
int
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
cifs_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov,
			 unsigned int nvec, struct mid_q_entry **ret_mid)
{
	int rc;
	struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
	struct mid_q_entry *mid;

	/* enable signing if server requires it */
	if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
		hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;

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

364
	rc = cifs_sign_smbv(iov, nvec, server, &mid->sequence_number);
365 366 367 368 369
	if (rc) {
		DeleteMidQEntry(mid);
		return rc;
	}

370
	*ret_mid = mid;
371
	return 0;
372
}
373

J
Jeff Layton 已提交
374 375 376 377 378
/*
 * Send a SMB request and set the callback function in the mid to handle
 * the result. Caller is responsible for dealing with timeouts.
 */
int
379
cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
380
		unsigned int nvec, mid_receive_t *receive,
381
		mid_callback_t *callback, void *cbdata, const int flags)
J
Jeff Layton 已提交
382
{
383
	int rc, timeout, optype;
J
Jeff Layton 已提交
384 385
	struct mid_q_entry *mid;

386 387 388 389
	timeout = flags & CIFS_TIMEOUT_MASK;
	optype = flags & CIFS_OP_MASK;

	rc = wait_for_free_request(server, timeout, optype);
J
Jeff Layton 已提交
390 391 392 393
	if (rc)
		return rc;

	mutex_lock(&server->srv_mutex);
394
	rc = server->ops->setup_async_request(server, iov, nvec, &mid);
395
	if (rc) {
J
Jeff Layton 已提交
396
		mutex_unlock(&server->srv_mutex);
397
		add_credits(server, 1, optype);
398
		wake_up(&server->request_q);
399
		return rc;
J
Jeff Layton 已提交
400 401
	}

402
	mid->receive = receive;
J
Jeff Layton 已提交
403 404
	mid->callback = callback;
	mid->callback_data = cbdata;
405
	mid->mid_state = MID_REQUEST_SUBMITTED;
406

407 408 409 410 411 412
	/* put it on the pending_mid_q */
	spin_lock(&GlobalMid_Lock);
	list_add_tail(&mid->qhead, &server->pending_mid_q);
	spin_unlock(&GlobalMid_Lock);


413
	cifs_in_send_inc(server);
414
	rc = smb_sendv(server, iov, nvec);
415 416
	cifs_in_send_dec(server);
	cifs_save_when_sent(mid);
J
Jeff Layton 已提交
417
	mutex_unlock(&server->srv_mutex);
418

419 420
	if (rc == 0)
		return 0;
J
Jeff Layton 已提交
421 422

	delete_mid(mid);
423
	add_credits(server, 1, optype);
J
Jeff Layton 已提交
424 425 426 427
	wake_up(&server->request_q);
	return rc;
}

428 429 430 431 432 433 434 435 436 437
/*
 *
 * 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
438
SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
439
		 char *in_buf, int flags)
440 441 442 443 444
{
	int rc;
	struct kvec iov[1];
	int resp_buf_type;

445 446
	iov[0].iov_base = in_buf;
	iov[0].iov_len = get_rfc1002_length(in_buf) + 4;
447 448
	flags |= CIFS_NO_RESP;
	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
449
	cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc);
450

451 452 453
	return rc;
}

454
static int
455
cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
456 457 458
{
	int rc = 0;

459 460
	cFYI(1, "%s: cmd=%d mid=%llu state=%d", __func__,
	     le16_to_cpu(mid->command), mid->mid, mid->mid_state);
461

J
Jeff Layton 已提交
462
	spin_lock(&GlobalMid_Lock);
463
	switch (mid->mid_state) {
J
Jeff Layton 已提交
464
	case MID_RESPONSE_RECEIVED:
465 466
		spin_unlock(&GlobalMid_Lock);
		return rc;
J
Jeff Layton 已提交
467 468 469
	case MID_RETRY_NEEDED:
		rc = -EAGAIN;
		break;
470 471 472
	case MID_RESPONSE_MALFORMED:
		rc = -EIO;
		break;
473 474 475
	case MID_SHUTDOWN:
		rc = -EHOSTDOWN;
		break;
J
Jeff Layton 已提交
476
	default:
477
		list_del_init(&mid->qhead);
478 479
		cERROR(1, "%s: invalid mid state mid=%llu state=%d", __func__,
		       mid->mid, mid->mid_state);
J
Jeff Layton 已提交
480
		rc = -EIO;
481 482 483
	}
	spin_unlock(&GlobalMid_Lock);

484
	DeleteMidQEntry(mid);
485 486 487
	return rc;
}

488 489
static inline int
send_cancel(struct TCP_Server_Info *server, void *buf, struct mid_q_entry *mid)
490
{
491 492
	return server->ops->send_cancel ?
				server->ops->send_cancel(server, buf, mid) : 0;
493 494
}

495 496 497 498
int
cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
		   bool log_error)
{
499
	unsigned int len = get_rfc1002_length(mid->resp_buf) + 4;
500 501

	dump_smb(mid->resp_buf, min_t(u32, 92, len));
502 503

	/* convert the length into a more usable form */
504
	if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
505 506 507 508
		struct kvec iov;

		iov.iov_base = mid->resp_buf;
		iov.iov_len = len;
509
		/* FIXME: add code to kill session */
510
		if (cifs_verify_signature(&iov, 1, server,
511 512 513 514 515 516 517 518
					  mid->sequence_number + 1) != 0)
			cERROR(1, "Unexpected SMB signature");
	}

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

519
int
520 521 522 523 524 525 526 527 528 529
cifs_setup_request(struct cifs_ses *ses, struct kvec *iov,
		   unsigned int nvec, struct mid_q_entry **ret_mid)
{
	int rc;
	struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
	struct mid_q_entry *mid;

	rc = allocate_mid(ses, hdr, &mid);
	if (rc)
		return rc;
530
	rc = cifs_sign_smbv(iov, nvec, ses->server, &mid->sequence_number);
531 532 533 534 535 536
	if (rc)
		delete_mid(mid);
	*ret_mid = mid;
	return rc;
}

J
[CIFS]  
Jeremy Allison 已提交
537
int
538
SendReceive2(const unsigned int xid, struct cifs_ses *ses,
539
	     struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
540
	     const int flags)
J
[CIFS]  
Jeremy Allison 已提交
541 542
{
	int rc = 0;
543
	int timeout, optype;
J
[CIFS]  
Jeremy Allison 已提交
544
	struct mid_q_entry *midQ;
545
	char *buf = iov[0].iov_base;
546
	unsigned int credits = 1;
547

548 549
	timeout = flags & CIFS_TIMEOUT_MASK;
	optype = flags & CIFS_OP_MASK;
550

551
	*resp_buf_type = CIFS_NO_BUFFER;  /* no response buf yet */
J
[CIFS]  
Jeremy Allison 已提交
552 553

	if ((ses == NULL) || (ses->server == NULL)) {
554
		cifs_small_buf_release(buf);
555
		cERROR(1, "Null session");
J
[CIFS]  
Jeremy Allison 已提交
556 557 558
		return -EIO;
	}

S
Steve French 已提交
559
	if (ses->server->tcpStatus == CifsExiting) {
560
		cifs_small_buf_release(buf);
J
[CIFS]  
Jeremy Allison 已提交
561 562 563
		return -ENOENT;
	}

564 565 566 567 568
	/*
	 * 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 已提交
569

570
	rc = wait_for_free_request(ses->server, timeout, optype);
J
[CIFS]  
Jeremy Allison 已提交
571
	if (rc) {
572
		cifs_small_buf_release(buf);
J
[CIFS]  
Jeremy Allison 已提交
573 574 575
		return rc;
	}

576 577 578 579 580
	/*
	 * 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 已提交
581

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

584
	rc = ses->server->ops->setup_request(ses, iov, n_vec, &midQ);
J
[CIFS]  
Jeremy Allison 已提交
585
	if (rc) {
J
Jeff Layton 已提交
586
		mutex_unlock(&ses->server->srv_mutex);
587
		cifs_small_buf_release(buf);
J
[CIFS]  
Jeremy Allison 已提交
588
		/* Update # of requests on wire to server */
589
		add_credits(ses->server, 1, optype);
J
[CIFS]  
Jeremy Allison 已提交
590
		return rc;
L
Linus Torvalds 已提交
591 592
	}

593
	midQ->mid_state = MID_REQUEST_SUBMITTED;
594
	cifs_in_send_inc(ses->server);
595
	rc = smb_sendv(ses->server, iov, n_vec);
596 597
	cifs_in_send_dec(ses->server);
	cifs_save_when_sent(midQ);
J
[CIFS]  
Jeremy Allison 已提交
598

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

601
	if (rc < 0) {
602
		cifs_small_buf_release(buf);
J
[CIFS]  
Jeremy Allison 已提交
603
		goto out;
604
	}
605

606
	if (timeout == CIFS_ASYNC_OP) {
607
		cifs_small_buf_release(buf);
608
		goto out;
609
	}
610

611
	rc = wait_for_response(ses->server, midQ);
612
	if (rc != 0) {
613
		send_cancel(ses->server, buf, midQ);
614
		spin_lock(&GlobalMid_Lock);
615
		if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
616 617
			midQ->callback = DeleteMidQEntry;
			spin_unlock(&GlobalMid_Lock);
618
			cifs_small_buf_release(buf);
619
			add_credits(ses->server, 1, optype);
620 621 622 623
			return rc;
		}
		spin_unlock(&GlobalMid_Lock);
	}
624

625
	cifs_small_buf_release(buf);
626

627
	rc = cifs_sync_mid_result(midQ, ses->server);
628
	if (rc != 0) {
629
		add_credits(ses->server, 1, optype);
630 631
		return rc;
	}
632

633
	if (!midQ->resp_buf || midQ->mid_state != MID_RESPONSE_RECEIVED) {
634
		rc = -EIO;
635
		cFYI(1, "Bad MID state?");
636 637 638
		goto out;
	}

639 640 641
	buf = (char *)midQ->resp_buf;
	iov[0].iov_base = buf;
	iov[0].iov_len = get_rfc1002_length(buf) + 4;
642
	if (midQ->large_buf)
643
		*resp_buf_type = CIFS_LARGE_BUFFER;
644
	else
645 646 647
		*resp_buf_type = CIFS_SMALL_BUFFER;

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

649 650
	rc = ses->server->ops->check_receive(midQ, ses->server,
					     flags & CIFS_LOG_ERROR);
L
Linus Torvalds 已提交
651

652 653 654
	/* mark it so buf will not be freed by delete_mid */
	if ((flags & CIFS_NO_RESP) == 0)
		midQ->resp_buf = NULL;
J
[CIFS]  
Jeremy Allison 已提交
655
out:
656
	delete_mid(midQ);
657
	add_credits(ses->server, credits, optype);
L
Linus Torvalds 已提交
658

659 660
	return rc;
}
L
Linus Torvalds 已提交
661 662

int
663
SendReceive(const unsigned int xid, struct cifs_ses *ses,
L
Linus Torvalds 已提交
664
	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
665
	    int *pbytes_returned, const int timeout)
L
Linus Torvalds 已提交
666 667 668 669 670
{
	int rc = 0;
	struct mid_q_entry *midQ;

	if (ses == NULL) {
671
		cERROR(1, "Null smb session");
L
Linus Torvalds 已提交
672 673
		return -EIO;
	}
S
Steve French 已提交
674
	if (ses->server == NULL) {
675
		cERROR(1, "Null tcp session");
L
Linus Torvalds 已提交
676 677 678
		return -EIO;
	}

S
Steve French 已提交
679
	if (ses->server->tcpStatus == CifsExiting)
680 681
		return -ENOENT;

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

686 687
	if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize +
			MAX_CIFS_HDR_SIZE - 4) {
688
		cERROR(1, "Illegal length, greater than maximum frame, %d",
689
			   be32_to_cpu(in_buf->smb_buf_length));
690 691 692
		return -EIO;
	}

693
	rc = wait_for_free_request(ses->server, timeout, 0);
J
[CIFS]  
Jeremy Allison 已提交
694 695 696
	if (rc)
		return rc;

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

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

J
[CIFS]  
Jeremy Allison 已提交
703 704
	rc = allocate_mid(ses, in_buf, &midQ);
	if (rc) {
J
Jeff Layton 已提交
705
		mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
706
		/* Update # of requests on wire to server */
707
		add_credits(ses->server, 1, 0);
J
[CIFS]  
Jeremy Allison 已提交
708
		return rc;
L
Linus Torvalds 已提交
709 710
	}

711
	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
712 713 714 715
	if (rc) {
		mutex_unlock(&ses->server->srv_mutex);
		goto out;
	}
L
Linus Torvalds 已提交
716

717
	midQ->mid_state = MID_REQUEST_SUBMITTED;
718 719

	cifs_in_send_inc(ses->server);
720
	rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
721 722
	cifs_in_send_dec(ses->server);
	cifs_save_when_sent(midQ);
J
Jeff Layton 已提交
723
	mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
724

S
Steve French 已提交
725
	if (rc < 0)
J
[CIFS]  
Jeremy Allison 已提交
726 727
		goto out;

728
	if (timeout == CIFS_ASYNC_OP)
J
[CIFS]  
Jeremy Allison 已提交
729
		goto out;
L
Linus Torvalds 已提交
730

731
	rc = wait_for_response(ses->server, midQ);
732
	if (rc != 0) {
733
		send_cancel(ses->server, in_buf, midQ);
734
		spin_lock(&GlobalMid_Lock);
735
		if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
736 737 738
			/* no longer considered to be "in-flight" */
			midQ->callback = DeleteMidQEntry;
			spin_unlock(&GlobalMid_Lock);
739
			add_credits(ses->server, 1, 0);
740 741 742 743
			return rc;
		}
		spin_unlock(&GlobalMid_Lock);
	}
L
Linus Torvalds 已提交
744

745
	rc = cifs_sync_mid_result(midQ, ses->server);
746
	if (rc != 0) {
747
		add_credits(ses->server, 1, 0);
L
Linus Torvalds 已提交
748 749
		return rc;
	}
750

751
	if (!midQ->resp_buf || !out_buf ||
752
	    midQ->mid_state != MID_RESPONSE_RECEIVED) {
753
		rc = -EIO;
754
		cERROR(1, "Bad MID state?");
755
		goto out;
L
Linus Torvalds 已提交
756
	}
J
[CIFS]  
Jeremy Allison 已提交
757

758
	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
759 760
	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
	rc = cifs_check_receive(midQ, ses->server, 0);
J
[CIFS]  
Jeremy Allison 已提交
761
out:
762
	delete_mid(midQ);
763
	add_credits(ses->server, 1, 0);
L
Linus Torvalds 已提交
764

J
[CIFS]  
Jeremy Allison 已提交
765 766
	return rc;
}
L
Linus Torvalds 已提交
767

J
[CIFS]  
Jeremy Allison 已提交
768 769 770 771
/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
   blocking lock to return. */

static int
772
send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon,
J
[CIFS]  
Jeremy Allison 已提交
773 774 775 776
			struct smb_hdr *in_buf,
			struct smb_hdr *out_buf)
{
	int bytes_returned;
777
	struct cifs_ses *ses = tcon->ses;
J
[CIFS]  
Jeremy Allison 已提交
778 779 780 781 782 783 784 785 786
	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;
787
	pSMB->hdr.Mid = get_next_mid(ses->server);
J
[CIFS]  
Jeremy Allison 已提交
788 789

	return SendReceive(xid, ses, in_buf, out_buf,
790
			&bytes_returned, 0);
J
[CIFS]  
Jeremy Allison 已提交
791 792 793
}

int
794
SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
J
[CIFS]  
Jeremy Allison 已提交
795 796 797 798 799 800
	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
	    int *pbytes_returned)
{
	int rc = 0;
	int rstart = 0;
	struct mid_q_entry *midQ;
801
	struct cifs_ses *ses;
J
[CIFS]  
Jeremy Allison 已提交
802 803

	if (tcon == NULL || tcon->ses == NULL) {
804
		cERROR(1, "Null smb session");
J
[CIFS]  
Jeremy Allison 已提交
805 806 807 808
		return -EIO;
	}
	ses = tcon->ses;

S
Steve French 已提交
809
	if (ses->server == NULL) {
810
		cERROR(1, "Null tcp session");
J
[CIFS]  
Jeremy Allison 已提交
811 812 813
		return -EIO;
	}

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

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

821 822
	if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize +
			MAX_CIFS_HDR_SIZE - 4) {
823
		cERROR(1, "Illegal length, greater than maximum frame, %d",
824
			   be32_to_cpu(in_buf->smb_buf_length));
825 826 827
		return -EIO;
	}

828
	rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP, 0);
J
[CIFS]  
Jeremy Allison 已提交
829 830 831
	if (rc)
		return rc;

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

J
Jeff Layton 已提交
836
	mutex_lock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
837 838 839

	rc = allocate_mid(ses, in_buf, &midQ);
	if (rc) {
J
Jeff Layton 已提交
840
		mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
841 842 843 844
		return rc;
	}

	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
845
	if (rc) {
846
		delete_mid(midQ);
847 848 849
		mutex_unlock(&ses->server->srv_mutex);
		return rc;
	}
L
Linus Torvalds 已提交
850

851
	midQ->mid_state = MID_REQUEST_SUBMITTED;
852
	cifs_in_send_inc(ses->server);
853
	rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
854 855
	cifs_in_send_dec(ses->server);
	cifs_save_when_sent(midQ);
J
Jeff Layton 已提交
856
	mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
857

S
Steve French 已提交
858
	if (rc < 0) {
859
		delete_mid(midQ);
J
[CIFS]  
Jeremy Allison 已提交
860 861 862 863 864
		return rc;
	}

	/* Wait for a reply - allow signals to interrupt. */
	rc = wait_event_interruptible(ses->server->response_q,
865
		(!(midQ->mid_state == MID_REQUEST_SUBMITTED)) ||
J
[CIFS]  
Jeremy Allison 已提交
866 867 868 869 870
		((ses->server->tcpStatus != CifsGood) &&
		 (ses->server->tcpStatus != CifsNew)));

	/* Were we interrupted by a signal ? */
	if ((rc == -ERESTARTSYS) &&
871
		(midQ->mid_state == MID_REQUEST_SUBMITTED) &&
J
[CIFS]  
Jeremy Allison 已提交
872 873 874 875 876 877
		((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. */
878
			rc = send_cancel(ses->server, in_buf, midQ);
J
[CIFS]  
Jeremy Allison 已提交
879
			if (rc) {
880
				delete_mid(midQ);
J
[CIFS]  
Jeremy Allison 已提交
881 882 883 884 885 886 887 888 889 890 891
				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) {
892
				delete_mid(midQ);
J
[CIFS]  
Jeremy Allison 已提交
893 894 895 896
				return rc;
			}
		}

897 898
		rc = wait_for_response(ses->server, midQ);
		if (rc) {
899
			send_cancel(ses->server, in_buf, midQ);
900
			spin_lock(&GlobalMid_Lock);
901
			if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
902 903 904 905 906 907
				/* no longer considered to be "in-flight" */
				midQ->callback = DeleteMidQEntry;
				spin_unlock(&GlobalMid_Lock);
				return rc;
			}
			spin_unlock(&GlobalMid_Lock);
J
[CIFS]  
Jeremy Allison 已提交
908
		}
909 910 911

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

914
	rc = cifs_sync_mid_result(midQ, ses->server);
915
	if (rc != 0)
J
[CIFS]  
Jeremy Allison 已提交
916
		return rc;
917

918
	/* rcvd frame is ok */
919
	if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_RECEIVED) {
920
		rc = -EIO;
921
		cERROR(1, "Bad MID state?");
922 923
		goto out;
	}
L
Linus Torvalds 已提交
924

925
	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
926 927
	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
	rc = cifs_check_receive(midQ, ses->server, 0);
928
out:
929
	delete_mid(midQ);
J
[CIFS]  
Jeremy Allison 已提交
930 931
	if (rstart && rc == -EACCES)
		return -ERESTARTSYS;
L
Linus Torvalds 已提交
932 933
	return rc;
}