transport.c 23.1 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

L
Linus Torvalds 已提交
38 39
extern mempool_t *cifs_mid_poolp;

40 41 42 43 44 45
static void
wake_up_task(struct mid_q_entry *mid)
{
	wake_up_process(mid->callback_data);
}

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

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

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

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

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

82
void
L
Linus Torvalds 已提交
83 84
DeleteMidQEntry(struct mid_q_entry *midEntry)
{
S
Steve French 已提交
85 86 87
#ifdef CONFIG_CIFS_STATS2
	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 99
	if ((now - midEntry->when_alloc) > HZ) {
		if ((cifsFYI & CIFS_TIMER) &&
100 101
		    (midEntry->command != cpu_to_le16(SMB_COM_LOCKING_ANDX))) {
			printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %llu",
S
Steve French 已提交
102 103 104 105 106 107 108 109
			       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 已提交
110 111 112
	mempool_free(midEntry, cifs_mid_poolp);
}

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

	DeleteMidQEntry(mid);
}

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

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

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

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

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

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

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

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

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

238 239
	/* Don't want to modify the buffer as a side effect of this call. */
	*buf_len = cpu_to_be32(smb_buf_length);
J
[CIFS]  
Jeremy Allison 已提交
240

L
Linus Torvalds 已提交
241 242 243
	return rc;
}

244 245 246 247 248 249 250 251 252 253 254 255
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 已提交
256
static int
257 258
wait_for_free_credits(struct TCP_Server_Info *server, const int optype,
		      int *credits)
L
Linus Torvalds 已提交
259
{
260 261
	int rc;

P
Pavel Shilovsky 已提交
262
	spin_lock(&server->req_lock);
263
	if (optype == CIFS_ASYNC_OP) {
L
Linus Torvalds 已提交
264
		/* oplock breaks must not be held up */
P
Pavel Shilovsky 已提交
265
		server->in_flight++;
266
		*credits -= 1;
P
Pavel Shilovsky 已提交
267
		spin_unlock(&server->req_lock);
268 269 270 271
		return 0;
	}

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

287 288 289 290
			/*
			 * Can not count locking commands against total
			 * as they are allowed to block on server.
			 */
291 292

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

304 305 306
static int
wait_for_free_request(struct TCP_Server_Info *server, const int optype)
{
307 308
	return wait_for_free_credits(server, optype,
				     server->ops->get_credits_field(server));
309 310
}

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

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

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

339 340
static int
wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
J
[CIFS]  
Jeremy Allison 已提交
341
{
342
	int error;
J
[CIFS]  
Jeremy Allison 已提交
343

344
	error = wait_event_freezekillable(server->response_q,
345
				    midQ->mid_state != MID_REQUEST_SUBMITTED);
346 347
	if (error < 0)
		return -ERESTARTSYS;
J
[CIFS]  
Jeremy Allison 已提交
348

349
	return 0;
J
[CIFS]  
Jeremy Allison 已提交
350 351
}

352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
static int
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;

	/* put it on the pending_mid_q */
	spin_lock(&GlobalMid_Lock);
	list_add_tail(&mid->qhead, &server->pending_mid_q);
	spin_unlock(&GlobalMid_Lock);

	rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number);
	if (rc)
		delete_mid(mid);
	*ret_mid = mid;
	return rc;
}
379

J
Jeff Layton 已提交
380 381 382 383 384
/*
 * Send a SMB request and set the callback function in the mid to handle
 * the result. Caller is responsible for dealing with timeouts.
 */
int
385
cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
386 387
		unsigned int nvec, mid_receive_t *receive,
		mid_callback_t *callback, void *cbdata, bool ignore_pend)
J
Jeff Layton 已提交
388 389 390 391
{
	int rc;
	struct mid_q_entry *mid;

392
	rc = wait_for_free_request(server, ignore_pend ? CIFS_ASYNC_OP : 0);
J
Jeff Layton 已提交
393 394 395 396
	if (rc)
		return rc;

	mutex_lock(&server->srv_mutex);
397 398
	rc = cifs_setup_async_request(server, iov, nvec, &mid);
	if (rc) {
J
Jeff Layton 已提交
399
		mutex_unlock(&server->srv_mutex);
400
		add_credits(server, 1);
401
		wake_up(&server->request_q);
402
		return rc;
J
Jeff Layton 已提交
403 404
	}

405
	mid->receive = receive;
J
Jeff Layton 已提交
406 407
	mid->callback = callback;
	mid->callback_data = cbdata;
408
	mid->mid_state = MID_REQUEST_SUBMITTED;
409 410

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

J
Jeff Layton 已提交
416 417 418 419 420 421
	if (rc)
		goto out_err;

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

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

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

450 451 452
	return rc;
}

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

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

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

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

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

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

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

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

		iov.iov_base = mid->resp_buf;
		iov.iov_len = len;
508
		/* FIXME: add code to kill session */
509
		if (cifs_verify_signature(&iov, 1, server,
510 511 512 513 514 515 516 517
					  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);
}

518
int
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
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;
	rc = cifs_sign_smb2(iov, nvec, ses->server, &mid->sequence_number);
	if (rc)
		delete_mid(mid);
	*ret_mid = mid;
	return rc;
}

J
[CIFS]  
Jeremy Allison 已提交
536
int
537
SendReceive2(const unsigned int xid, struct cifs_ses *ses,
S
Steve French 已提交
538
	     struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
539
	     const int flags)
J
[CIFS]  
Jeremy Allison 已提交
540 541
{
	int rc = 0;
542
	int long_op;
J
[CIFS]  
Jeremy Allison 已提交
543
	struct mid_q_entry *midQ;
544
	char *buf = iov[0].iov_base;
545

546 547
	long_op = flags & CIFS_TIMEOUT_MASK;

J
[CIFS]  
Jeremy Allison 已提交
548 549 550
	*pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */

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

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

561 562 563 564 565
	/*
	 * 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 已提交
566

567
	rc = wait_for_free_request(ses->server, long_op);
J
[CIFS]  
Jeremy Allison 已提交
568
	if (rc) {
569
		cifs_small_buf_release(buf);
J
[CIFS]  
Jeremy Allison 已提交
570 571 572
		return rc;
	}

573 574 575 576 577
	/*
	 * 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 已提交
578

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

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

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

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

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

603
	if (long_op == CIFS_ASYNC_OP) {
604
		cifs_small_buf_release(buf);
605
		goto out;
606
	}
607

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

622
	cifs_small_buf_release(buf);
623

624
	rc = cifs_sync_mid_result(midQ, ses->server);
625
	if (rc != 0) {
626
		add_credits(ses->server, 1);
627 628
		return rc;
	}
629

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

636 637 638
	buf = (char *)midQ->resp_buf;
	iov[0].iov_base = buf;
	iov[0].iov_len = get_rfc1002_length(buf) + 4;
639
	if (midQ->large_buf)
640 641 642
		*pRespBufType = CIFS_LARGE_BUFFER;
	else
		*pRespBufType = CIFS_SMALL_BUFFER;
643

644 645
	rc = ses->server->ops->check_receive(midQ, ses->server,
					     flags & CIFS_LOG_ERROR);
L
Linus Torvalds 已提交
646

647 648 649
	/* 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 已提交
650
out:
651
	delete_mid(midQ);
652
	add_credits(ses->server, 1);
L
Linus Torvalds 已提交
653

654 655
	return rc;
}
L
Linus Torvalds 已提交
656 657

int
658
SendReceive(const unsigned int xid, struct cifs_ses *ses,
L
Linus Torvalds 已提交
659 660 661 662 663 664 665
	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
	    int *pbytes_returned, const int long_op)
{
	int rc = 0;
	struct mid_q_entry *midQ;

	if (ses == NULL) {
666
		cERROR(1, "Null smb session");
L
Linus Torvalds 已提交
667 668
		return -EIO;
	}
S
Steve French 已提交
669
	if (ses->server == NULL) {
670
		cERROR(1, "Null tcp session");
L
Linus Torvalds 已提交
671 672 673
		return -EIO;
	}

S
Steve French 已提交
674
	if (ses->server->tcpStatus == CifsExiting)
675 676
		return -ENOENT;

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

681 682
	if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize +
			MAX_CIFS_HDR_SIZE - 4) {
683
		cERROR(1, "Illegal length, greater than maximum frame, %d",
684
			   be32_to_cpu(in_buf->smb_buf_length));
685 686 687
		return -EIO;
	}

688
	rc = wait_for_free_request(ses->server, long_op);
J
[CIFS]  
Jeremy Allison 已提交
689 690 691
	if (rc)
		return rc;

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

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

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

706
	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
707 708 709 710
	if (rc) {
		mutex_unlock(&ses->server->srv_mutex);
		goto out;
	}
L
Linus Torvalds 已提交
711

712
	midQ->mid_state = MID_REQUEST_SUBMITTED;
713 714

	cifs_in_send_inc(ses->server);
715
	rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
716 717
	cifs_in_send_dec(ses->server);
	cifs_save_when_sent(midQ);
J
Jeff Layton 已提交
718
	mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
719

S
Steve French 已提交
720
	if (rc < 0)
J
[CIFS]  
Jeremy Allison 已提交
721 722
		goto out;

723
	if (long_op == CIFS_ASYNC_OP)
J
[CIFS]  
Jeremy Allison 已提交
724
		goto out;
L
Linus Torvalds 已提交
725

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

740
	rc = cifs_sync_mid_result(midQ, ses->server);
741
	if (rc != 0) {
742
		add_credits(ses->server, 1);
L
Linus Torvalds 已提交
743 744
		return rc;
	}
745

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

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

J
[CIFS]  
Jeremy Allison 已提交
760 761
	return rc;
}
L
Linus Torvalds 已提交
762

J
[CIFS]  
Jeremy Allison 已提交
763 764 765 766
/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
   blocking lock to return. */

static int
767
send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon,
J
[CIFS]  
Jeremy Allison 已提交
768 769 770 771
			struct smb_hdr *in_buf,
			struct smb_hdr *out_buf)
{
	int bytes_returned;
772
	struct cifs_ses *ses = tcon->ses;
J
[CIFS]  
Jeremy Allison 已提交
773 774 775 776 777 778 779 780 781 782 783 784
	LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;

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

	pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
	pSMB->Timeout = 0;
	pSMB->hdr.Mid = GetNextMid(ses->server);

	return SendReceive(xid, ses, in_buf, out_buf,
785
			&bytes_returned, 0);
J
[CIFS]  
Jeremy Allison 已提交
786 787 788
}

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

	if (tcon == NULL || tcon->ses == NULL) {
799
		cERROR(1, "Null smb session");
J
[CIFS]  
Jeremy Allison 已提交
800 801 802 803
		return -EIO;
	}
	ses = tcon->ses;

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

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

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

816 817
	if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize +
			MAX_CIFS_HDR_SIZE - 4) {
818
		cERROR(1, "Illegal length, greater than maximum frame, %d",
819
			   be32_to_cpu(in_buf->smb_buf_length));
820 821 822
		return -EIO;
	}

823
	rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP);
J
[CIFS]  
Jeremy Allison 已提交
824 825 826
	if (rc)
		return rc;

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

J
Jeff Layton 已提交
831
	mutex_lock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
832 833 834

	rc = allocate_mid(ses, in_buf, &midQ);
	if (rc) {
J
Jeff Layton 已提交
835
		mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
836 837 838 839
		return rc;
	}

	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
840
	if (rc) {
841
		delete_mid(midQ);
842 843 844
		mutex_unlock(&ses->server->srv_mutex);
		return rc;
	}
L
Linus Torvalds 已提交
845

846
	midQ->mid_state = MID_REQUEST_SUBMITTED;
847
	cifs_in_send_inc(ses->server);
848
	rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
849 850
	cifs_in_send_dec(ses->server);
	cifs_save_when_sent(midQ);
J
Jeff Layton 已提交
851
	mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
852

S
Steve French 已提交
853
	if (rc < 0) {
854
		delete_mid(midQ);
J
[CIFS]  
Jeremy Allison 已提交
855 856 857 858 859
		return rc;
	}

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

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

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

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

909
	rc = cifs_sync_mid_result(midQ, ses->server);
910
	if (rc != 0)
J
[CIFS]  
Jeremy Allison 已提交
911
		return rc;
912

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

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