transport.c 26.8 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 29 30 31 32 33 34 35
#include <linux/wait.h>
#include <linux/net.h>
#include <linux/delay.h>
#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"
36

L
Linus Torvalds 已提交
37
extern mempool_t *cifs_mid_poolp;
38
extern struct kmem_cache *cifs_oplock_cachep;
L
Linus Torvalds 已提交
39 40

static struct mid_q_entry *
41
AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
L
Linus Torvalds 已提交
42 43 44
{
	struct mid_q_entry *temp;

45
	if (server == NULL) {
L
Linus Torvalds 已提交
46 47 48
		cERROR(1, ("Null TCP session in AllocMidQEntry"));
		return NULL;
	}
49

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

	spin_lock(&GlobalMid_Lock);
66
	list_add_tail(&temp->qhead, &server->pending_mid_q);
L
Linus Torvalds 已提交
67 68 69 70 71 72 73 74 75
	atomic_inc(&midCount);
	temp->midState = MID_REQUEST_ALLOCATED;
	spin_unlock(&GlobalMid_Lock);
	return temp;
}

static void
DeleteMidQEntry(struct mid_q_entry *midEntry)
{
S
Steve French 已提交
76 77 78
#ifdef CONFIG_CIFS_STATS2
	unsigned long now;
#endif
L
Linus Torvalds 已提交
79 80 81 82 83
	spin_lock(&GlobalMid_Lock);
	midEntry->midState = MID_FREE;
	list_del(&midEntry->qhead);
	atomic_dec(&midCount);
	spin_unlock(&GlobalMid_Lock);
S
Steve French 已提交
84
	if (midEntry->largeBuf)
85 86 87
		cifs_buf_release(midEntry->resp_buf);
	else
		cifs_small_buf_release(midEntry->resp_buf);
S
Steve French 已提交
88 89 90 91
#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 已提交
92 93
	if ((now - midEntry->when_alloc) > HZ) {
		if ((cifsFYI & CIFS_TIMER) &&
S
Steve French 已提交
94 95 96 97 98 99 100 101 102 103
		   (midEntry->command != SMB_COM_LOCKING_ANDX)) {
			printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
			       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 已提交
104 105 106
	mempool_free(midEntry, cifs_mid_poolp);
}

107
static int
108
smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
L
Linus Torvalds 已提交
109 110 111 112
{
	int rc = 0;
	int i = 0;
	struct msghdr smb_msg;
113 114 115 116
	struct smb_hdr *smb_buffer = iov[0].iov_base;
	unsigned int len = iov[0].iov_len;
	unsigned int total_len;
	int first_vec = 0;
J
[CIFS]  
Jeremy Allison 已提交
117
	unsigned int smb_buf_length = smb_buffer->smb_buf_length;
118
	struct socket *ssocket = server->ssocket;
119

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

123
	smb_msg.msg_name = (struct sockaddr *) &server->addr.sockAddr;
124
	smb_msg.msg_namelen = sizeof(struct sockaddr);
L
Linus Torvalds 已提交
125 126
	smb_msg.msg_control = NULL;
	smb_msg.msg_controllen = 0;
127
	if (server->noblocksnd)
128 129 130
		smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
	else
		smb_msg.msg_flags = MSG_NOSIGNAL;
L
Linus Torvalds 已提交
131 132

	/* smb header is converted in header_assemble. bcc and rest of SMB word
S
Steve French 已提交
133 134
	   area, and byte area if necessary, is converted to littleendian in
	   cifssmb.c and RFC1001 len is converted to bigendian in smb_send
L
Linus Torvalds 已提交
135 136
	   Flags2 is converted in SendReceive */

137 138 139 140 141

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

L
Linus Torvalds 已提交
142
	smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
143
	cFYI(1, ("Sending smb:  total_len %d", total_len));
L
Linus Torvalds 已提交
144 145
	dump_smb(smb_buffer, len);

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

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

215 216 217 218 219 220 221 222 223 224
	if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
		cFYI(1, ("partial send (%d remaining), terminating session",
			total_len));
		/* 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;
	}

L
Linus Torvalds 已提交
225
	if (rc < 0) {
S
Steve French 已提交
226
		cERROR(1, ("Error %d sending data on socket to server", rc));
227
	} else
L
Linus Torvalds 已提交
228 229
		rc = 0;

J
[CIFS]  
Jeremy Allison 已提交
230 231 232 233
	/* Don't want to modify the buffer as a
	   side effect of this call. */
	smb_buffer->smb_buf_length = smb_buf_length;

L
Linus Torvalds 已提交
234 235 236
	return rc;
}

237 238 239 240 241 242 243 244 245 246 247 248
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);
}

J
[CIFS]  
Jeremy Allison 已提交
249
static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
L
Linus Torvalds 已提交
250
{
251
	if (long_op == CIFS_ASYNC_OP) {
L
Linus Torvalds 已提交
252 253
		/* oplock breaks must not be held up */
		atomic_inc(&ses->server->inFlight);
254 255 256 257 258 259 260 261
		return 0;
	}

	spin_lock(&GlobalMid_Lock);
	while (1) {
		if (atomic_read(&ses->server->inFlight) >=
				cifs_max_pending){
			spin_unlock(&GlobalMid_Lock);
262
#ifdef CONFIG_CIFS_STATS2
263
			atomic_inc(&ses->server->num_waiters);
264
#endif
265 266 267
			wait_event(ses->server->request_q,
				   atomic_read(&ses->server->inFlight)
				     < cifs_max_pending);
268
#ifdef CONFIG_CIFS_STATS2
269
			atomic_dec(&ses->server->num_waiters);
270
#endif
271 272 273
			spin_lock(&GlobalMid_Lock);
		} else {
			if (ses->server->tcpStatus == CifsExiting) {
L
Linus Torvalds 已提交
274
				spin_unlock(&GlobalMid_Lock);
275
				return -ENOENT;
L
Linus Torvalds 已提交
276
			}
277 278 279 280 281 282 283 284 285

			/* can not count locking commands against total
			   as they are allowed to block on server */

			/* update # of requests on the wire to server */
			if (long_op != CIFS_BLOCKING_OP)
				atomic_inc(&ses->server->inFlight);
			spin_unlock(&GlobalMid_Lock);
			break;
L
Linus Torvalds 已提交
286 287
		}
	}
J
[CIFS]  
Jeremy Allison 已提交
288 289
	return 0;
}
L
Linus Torvalds 已提交
290

J
[CIFS]  
Jeremy Allison 已提交
291 292 293
static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
			struct mid_q_entry **ppmidQ)
{
L
Linus Torvalds 已提交
294
	if (ses->server->tcpStatus == CifsExiting) {
J
[CIFS]  
Jeremy Allison 已提交
295
		return -ENOENT;
296 297 298
	}

	if (ses->server->tcpStatus == CifsNeedReconnect) {
S
Steve French 已提交
299
		cFYI(1, ("tcp session dead - return to caller to retry"));
J
[CIFS]  
Jeremy Allison 已提交
300
		return -EAGAIN;
301 302 303
	}

	if (ses->status != CifsGood) {
L
Linus Torvalds 已提交
304
		/* check if SMB session is bad because we are setting it up */
S
Steve French 已提交
305
		if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
S
Steve French 已提交
306
			(in_buf->Command != SMB_COM_NEGOTIATE))
J
[CIFS]  
Jeremy Allison 已提交
307
			return -EAGAIN;
S
Steve French 已提交
308
		/* else ok - we are setting up session */
L
Linus Torvalds 已提交
309
	}
310
	*ppmidQ = AllocMidQEntry(in_buf, ses->server);
311
	if (*ppmidQ == NULL)
J
[CIFS]  
Jeremy Allison 已提交
312 313 314 315
		return -ENOMEM;
	return 0;
}

S
Steve French 已提交
316
static int wait_for_response(struct cifsSesInfo *ses,
J
[CIFS]  
Jeremy Allison 已提交
317 318 319 320 321 322 323 324
			struct mid_q_entry *midQ,
			unsigned long timeout,
			unsigned long time_to_wait)
{
	unsigned long curr_timeout;

	for (;;) {
		curr_timeout = timeout + jiffies;
325 326
		wait_event_timeout(ses->server->response_q,
			midQ->midState != MID_REQUEST_SUBMITTED, timeout);
J
[CIFS]  
Jeremy Allison 已提交
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341

		if (time_after(jiffies, curr_timeout) &&
			(midQ->midState == MID_REQUEST_SUBMITTED) &&
			((ses->server->tcpStatus == CifsGood) ||
			 (ses->server->tcpStatus == CifsNew))) {

			unsigned long lrt;

			/* We timed out. Is the server still
			   sending replies ? */
			spin_lock(&GlobalMid_Lock);
			lrt = ses->server->lstrp;
			spin_unlock(&GlobalMid_Lock);

			/* Calculate time_to_wait past last receive time.
S
Steve French 已提交
342
			 Although we prefer not to time out if the
J
[CIFS]  
Jeremy Allison 已提交
343
			 server is still responding - we will time
S
Steve French 已提交
344
			 out if the server takes more than 15 (or 45
J
[CIFS]  
Jeremy Allison 已提交
345
			 or 180) seconds to respond to this request
S
Steve French 已提交
346
			 and has not responded to any request from
J
[CIFS]  
Jeremy Allison 已提交
347 348 349 350
			 other threads on the client within 10 seconds */
			lrt += time_to_wait;
			if (time_after(jiffies, lrt)) {
				/* No replies for time_to_wait. */
S
Steve French 已提交
351
				cERROR(1, ("server not responding"));
J
[CIFS]  
Jeremy Allison 已提交
352 353 354 355 356 357 358 359
				return -1;
			}
		} else {
			return 0;
		}
	}
}

360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381

/*
 *
 * 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
SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
		struct smb_hdr *in_buf, int flags)
{
	int rc;
	struct kvec iov[1];
	int resp_buf_type;

	iov[0].iov_base = (char *)in_buf;
	iov[0].iov_len = in_buf->smb_buf_length + 4;
	flags |= CIFS_NO_RESP;
	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
382 383
	cFYI(DBG2, ("SendRcvNoRsp flags %d rc %d", flags, rc));

384 385 386
	return rc;
}

J
[CIFS]  
Jeremy Allison 已提交
387
int
S
Steve French 已提交
388 389
SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
	     struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
390
	     const int flags)
J
[CIFS]  
Jeremy Allison 已提交
391 392
{
	int rc = 0;
393
	int long_op;
J
[CIFS]  
Jeremy Allison 已提交
394 395 396 397
	unsigned int receive_len;
	unsigned long timeout;
	struct mid_q_entry *midQ;
	struct smb_hdr *in_buf = iov[0].iov_base;
398

399 400
	long_op = flags & CIFS_TIMEOUT_MASK;

J
[CIFS]  
Jeremy Allison 已提交
401 402 403 404
	*pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */

	if ((ses == NULL) || (ses->server == NULL)) {
		cifs_small_buf_release(in_buf);
S
Steve French 已提交
405
		cERROR(1, ("Null session"));
J
[CIFS]  
Jeremy Allison 已提交
406 407 408
		return -EIO;
	}

S
Steve French 已提交
409
	if (ses->server->tcpStatus == CifsExiting) {
J
[CIFS]  
Jeremy Allison 已提交
410 411 412 413
		cifs_small_buf_release(in_buf);
		return -ENOENT;
	}

S
Steve French 已提交
414
	/* Ensure that we do not send more than 50 overlapping requests
J
[CIFS]  
Jeremy Allison 已提交
415 416 417 418 419 420 421 422 423
	   to the same server. We may make this configurable later or
	   use ses->maxReq */

	rc = wait_for_free_request(ses, long_op);
	if (rc) {
		cifs_small_buf_release(in_buf);
		return rc;
	}

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

J
Jeff Layton 已提交
428
	mutex_lock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
429 430 431

	rc = allocate_mid(ses, in_buf, &midQ);
	if (rc) {
J
Jeff Layton 已提交
432
		mutex_unlock(&ses->server->srv_mutex);
433
		cifs_small_buf_release(in_buf);
J
[CIFS]  
Jeremy Allison 已提交
434
		/* Update # of requests on wire to server */
S
Steve French 已提交
435
		atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
436 437
		wake_up(&ses->server->request_q);
		return rc;
L
Linus Torvalds 已提交
438
	}
S
Steve French 已提交
439
	rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
440 441 442 443 444
	if (rc) {
		mutex_unlock(&ses->server->srv_mutex);
		cifs_small_buf_release(in_buf);
		goto out;
	}
L
Linus Torvalds 已提交
445 446

	midQ->midState = MID_REQUEST_SUBMITTED;
447 448 449
#ifdef CONFIG_CIFS_STATS2
	atomic_inc(&ses->server->inSend);
#endif
450
	rc = smb_sendv(ses->server, iov, n_vec);
451 452
#ifdef CONFIG_CIFS_STATS2
	atomic_dec(&ses->server->inSend);
S
Steve French 已提交
453
	midQ->when_sent = jiffies;
454
#endif
J
[CIFS]  
Jeremy Allison 已提交
455

J
Jeff Layton 已提交
456
	mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
457 458
	cifs_small_buf_release(in_buf);

S
Steve French 已提交
459
	if (rc < 0)
J
[CIFS]  
Jeremy Allison 已提交
460
		goto out;
461

462 463 464
	if (long_op == CIFS_STD_OP)
		timeout = 15 * HZ;
	else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
465
		timeout = 180 * HZ;
466
	else if (long_op == CIFS_LONG_OP)
S
Steve French 已提交
467
		timeout = 45 * HZ; /* should be greater than
468
			servers oplock break timeout (about 43 seconds) */
469 470 471 472 473 474 475 476 477
	else if (long_op == CIFS_ASYNC_OP)
		goto out;
	else if (long_op == CIFS_BLOCKING_OP)
		timeout = 0x7FFFFFFF; /*  large, but not so large as to wrap */
	else {
		cERROR(1, ("unknown timeout flag %d", long_op));
		rc = -EIO;
		goto out;
	}
J
[CIFS]  
Jeremy Allison 已提交
478

S
Steve French 已提交
479
	/* wait for 15 seconds or until woken up due to response arriving or
480 481 482
	   due to last connection to this server being unmounted */
	if (signal_pending(current)) {
		/* if signal pending do not hold up user for full smb timeout
483
		but we still give response a chance to complete */
484
		timeout = 2 * HZ;
S
Steve French 已提交
485
	}
486 487

	/* No user interrupts in wait - wreaks havoc with performance */
J
[CIFS]  
Jeremy Allison 已提交
488
	wait_for_response(ses, midQ, timeout, 10 * HZ);
489 490

	spin_lock(&GlobalMid_Lock);
491 492

	if (midQ->resp_buf == NULL) {
S
Steve French 已提交
493
		cERROR(1, ("No response to cmd %d mid %d",
494
			midQ->command, midQ->mid));
S
Steve French 已提交
495 496
		if (midQ->midState == MID_REQUEST_SUBMITTED) {
			if (ses->server->tcpStatus == CifsExiting)
497 498 499 500 501 502 503 504
				rc = -EHOSTDOWN;
			else {
				ses->server->tcpStatus = CifsNeedReconnect;
				midQ->midState = MID_RETRY_NEEDED;
			}
		}

		if (rc != -EHOSTDOWN) {
S
Steve French 已提交
505
			if (midQ->midState == MID_RETRY_NEEDED) {
506
				rc = -EAGAIN;
S
Steve French 已提交
507
				cFYI(1, ("marking request for retry"));
508 509 510 511 512 513
			} else {
				rc = -EIO;
			}
		}
		spin_unlock(&GlobalMid_Lock);
		DeleteMidQEntry(midQ);
J
[CIFS]  
Jeremy Allison 已提交
514
		/* Update # of requests on wire to server */
S
Steve French 已提交
515
		atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
516
		wake_up(&ses->server->request_q);
517 518
		return rc;
	}
519

520 521 522
	spin_unlock(&GlobalMid_Lock);
	receive_len = midQ->resp_buf->smb_buf_length;

523 524 525 526
	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
			receive_len, xid));
		rc = -EIO;
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
		goto out;
	}

	/* rcvd frame is ok */

	if (midQ->resp_buf &&
	    (midQ->midState == MID_RESPONSE_RECEIVED)) {

		iov[0].iov_base = (char *)midQ->resp_buf;
		if (midQ->largeBuf)
			*pRespBufType = CIFS_LARGE_BUFFER;
		else
			*pRespBufType = CIFS_SMALL_BUFFER;
		iov[0].iov_len = receive_len + 4;

		dump_smb(midQ->resp_buf, 80);
		/* convert the length into a more usable form */
		if ((receive_len > 24) &&
		    (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
					     SECMODE_SIGN_ENABLED))) {
			rc = cifs_verify_signature(midQ->resp_buf,
548
						&ses->server->mac_signing_key,
549
						midQ->sequence_number+1);
550 551 552
			if (rc) {
				cERROR(1, ("Unexpected SMB signature"));
				/* BB FIXME add code to kill session */
553 554
			}
		}
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572

		/* BB special case reconnect tid and uid here? */
		rc = map_smb_to_linux_error(midQ->resp_buf,
					    flags & CIFS_LOG_ERROR);

		/* convert ByteCount if necessary */
		if (receive_len >= sizeof(struct smb_hdr) - 4
		    /* do not count RFC1001 header */  +
		    (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
			BCC(midQ->resp_buf) =
				le16_to_cpu(BCC_LE(midQ->resp_buf));
		if ((flags & CIFS_NO_RESP) == 0)
			midQ->resp_buf = NULL;  /* mark it so buf will
						   not be freed by
						   DeleteMidQEntry */
	} else {
		rc = -EIO;
		cFYI(1, ("Bad MID state?"));
573
	}
L
Linus Torvalds 已提交
574

J
[CIFS]  
Jeremy Allison 已提交
575 576
out:
	DeleteMidQEntry(midQ);
S
Steve French 已提交
577
	atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
578
	wake_up(&ses->server->request_q);
L
Linus Torvalds 已提交
579

580 581
	return rc;
}
L
Linus Torvalds 已提交
582 583 584 585 586 587 588 589 590 591 592 593

int
SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
	    int *pbytes_returned, const int long_op)
{
	int rc = 0;
	unsigned int receive_len;
	unsigned long timeout;
	struct mid_q_entry *midQ;

	if (ses == NULL) {
S
Steve French 已提交
594
		cERROR(1, ("Null smb session"));
L
Linus Torvalds 已提交
595 596
		return -EIO;
	}
S
Steve French 已提交
597 598
	if (ses->server == NULL) {
		cERROR(1, ("Null tcp session"));
L
Linus Torvalds 已提交
599 600 601
		return -EIO;
	}

S
Steve French 已提交
602
	if (ses->server->tcpStatus == CifsExiting)
603 604
		return -ENOENT;

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

609 610 611 612 613 614
	if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
		cERROR(1, ("Illegal length, greater than maximum frame, %d",
			   in_buf->smb_buf_length));
		return -EIO;
	}

J
[CIFS]  
Jeremy Allison 已提交
615 616 617 618
	rc = wait_for_free_request(ses, long_op);
	if (rc)
		return rc;

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

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

J
[CIFS]  
Jeremy Allison 已提交
625 626
	rc = allocate_mid(ses, in_buf, &midQ);
	if (rc) {
J
Jeff Layton 已提交
627
		mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
628
		/* Update # of requests on wire to server */
S
Steve French 已提交
629
		atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
630 631
		wake_up(&ses->server->request_q);
		return rc;
L
Linus Torvalds 已提交
632 633
	}

634
	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
635 636 637 638
	if (rc) {
		mutex_unlock(&ses->server->srv_mutex);
		goto out;
	}
L
Linus Torvalds 已提交
639 640

	midQ->midState = MID_REQUEST_SUBMITTED;
641 642 643
#ifdef CONFIG_CIFS_STATS2
	atomic_inc(&ses->server->inSend);
#endif
644
	rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
645 646
#ifdef CONFIG_CIFS_STATS2
	atomic_dec(&ses->server->inSend);
S
Steve French 已提交
647
	midQ->when_sent = jiffies;
648
#endif
J
Jeff Layton 已提交
649
	mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
650

S
Steve French 已提交
651
	if (rc < 0)
J
[CIFS]  
Jeremy Allison 已提交
652 653
		goto out;

654 655 656 657 658
	if (long_op == CIFS_STD_OP)
		timeout = 15 * HZ;
	/* wait for 15 seconds or until woken up due to response arriving or
	   due to last connection to this server being unmounted */
	else if (long_op == CIFS_ASYNC_OP)
J
[CIFS]  
Jeremy Allison 已提交
659
		goto out;
660
	else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
661
		timeout = 180 * HZ;
662
	else if (long_op == CIFS_LONG_OP)
S
Steve French 已提交
663
		timeout = 45 * HZ; /* should be greater than
L
Linus Torvalds 已提交
664
			servers oplock break timeout (about 43 seconds) */
665 666 667 668 669 670 671 672
	else if (long_op == CIFS_BLOCKING_OP)
		timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
	else {
		cERROR(1, ("unknown timeout flag %d", long_op));
		rc = -EIO;
		goto out;
	}

L
Linus Torvalds 已提交
673 674
	if (signal_pending(current)) {
		/* if signal pending do not hold up user for full smb timeout
675
		but we still give response a chance to complete */
L
Linus Torvalds 已提交
676
		timeout = 2 * HZ;
S
Steve French 已提交
677
	}
L
Linus Torvalds 已提交
678 679

	/* No user interrupts in wait - wreaks havoc with performance */
J
[CIFS]  
Jeremy Allison 已提交
680
	wait_for_response(ses, midQ, timeout, 10 * HZ);
L
Linus Torvalds 已提交
681 682

	spin_lock(&GlobalMid_Lock);
683
	if (midQ->resp_buf == NULL) {
S
Steve French 已提交
684
		cERROR(1, ("No response for cmd %d mid %d",
685
			  midQ->command, midQ->mid));
S
Steve French 已提交
686 687
		if (midQ->midState == MID_REQUEST_SUBMITTED) {
			if (ses->server->tcpStatus == CifsExiting)
L
Linus Torvalds 已提交
688 689 690 691 692 693 694 695
				rc = -EHOSTDOWN;
			else {
				ses->server->tcpStatus = CifsNeedReconnect;
				midQ->midState = MID_RETRY_NEEDED;
			}
		}

		if (rc != -EHOSTDOWN) {
S
Steve French 已提交
696
			if (midQ->midState == MID_RETRY_NEEDED) {
L
Linus Torvalds 已提交
697
				rc = -EAGAIN;
S
Steve French 已提交
698
				cFYI(1, ("marking request for retry"));
L
Linus Torvalds 已提交
699 700 701 702 703 704
			} else {
				rc = -EIO;
			}
		}
		spin_unlock(&GlobalMid_Lock);
		DeleteMidQEntry(midQ);
J
[CIFS]  
Jeremy Allison 已提交
705
		/* Update # of requests on wire to server */
S
Steve French 已提交
706
		atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
707
		wake_up(&ses->server->request_q);
L
Linus Torvalds 已提交
708 709
		return rc;
	}
710

711 712 713
	spin_unlock(&GlobalMid_Lock);
	receive_len = midQ->resp_buf->smb_buf_length;

L
Linus Torvalds 已提交
714
	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
715
		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
L
Linus Torvalds 已提交
716 717
			receive_len, xid));
		rc = -EIO;
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735
		goto out;
	}

	/* rcvd frame is ok */

	if (midQ->resp_buf && out_buf
	    && (midQ->midState == MID_RESPONSE_RECEIVED)) {
		out_buf->smb_buf_length = receive_len;
		memcpy((char *)out_buf + 4,
		       (char *)midQ->resp_buf + 4,
		       receive_len);

		dump_smb(out_buf, 92);
		/* convert the length into a more usable form */
		if ((receive_len > 24) &&
		    (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
					     SECMODE_SIGN_ENABLED))) {
			rc = cifs_verify_signature(out_buf,
736
						&ses->server->mac_signing_key,
737
						midQ->sequence_number+1);
738 739 740
			if (rc) {
				cERROR(1, ("Unexpected SMB signature"));
				/* BB FIXME add code to kill session */
L
Linus Torvalds 已提交
741
			}
742
		}
L
Linus Torvalds 已提交
743

744
		*pbytes_returned = out_buf->smb_buf_length;
L
Linus Torvalds 已提交
745

746 747
		/* BB special case reconnect tid and uid here? */
		rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
L
Linus Torvalds 已提交
748

749 750 751 752 753 754 755 756
		/* convert ByteCount if necessary */
		if (receive_len >= sizeof(struct smb_hdr) - 4
		    /* do not count RFC1001 header */  +
		    (2 * out_buf->WordCount) + 2 /* bcc */ )
			BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
	} else {
		rc = -EIO;
		cERROR(1, ("Bad MID state?"));
L
Linus Torvalds 已提交
757
	}
J
[CIFS]  
Jeremy Allison 已提交
758 759

out:
L
Linus Torvalds 已提交
760
	DeleteMidQEntry(midQ);
S
Steve French 已提交
761
	atomic_dec(&ses->server->inFlight);
J
[CIFS]  
Jeremy Allison 已提交
762
	wake_up(&ses->server->request_q);
L
Linus Torvalds 已提交
763

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

J
[CIFS]  
Jeremy Allison 已提交
767 768 769 770 771 772 773 774 775 776 777 778
/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */

static int
send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
		struct mid_q_entry *midQ)
{
	int rc = 0;
	struct cifsSesInfo *ses = tcon->ses;
	__u16 mid = in_buf->Mid;

	header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
	in_buf->Mid = mid;
J
Jeff Layton 已提交
779
	mutex_lock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
780 781
	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
	if (rc) {
J
Jeff Layton 已提交
782
		mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
783 784
		return rc;
	}
785
	rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
J
Jeff Layton 已提交
786
	mutex_unlock(&ses->server->srv_mutex);
L
Linus Torvalds 已提交
787
	return rc;
J
[CIFS]  
Jeremy Allison 已提交
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
}

/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
   blocking lock to return. */

static int
send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
			struct smb_hdr *in_buf,
			struct smb_hdr *out_buf)
{
	int bytes_returned;
	struct cifsSesInfo *ses = tcon->ses;
	LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;

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

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

	return SendReceive(xid, ses, in_buf, out_buf,
812
			&bytes_returned, CIFS_STD_OP);
J
[CIFS]  
Jeremy Allison 已提交
813 814 815 816 817 818 819 820 821 822 823 824 825 826
}

int
SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
	    int *pbytes_returned)
{
	int rc = 0;
	int rstart = 0;
	unsigned int receive_len;
	struct mid_q_entry *midQ;
	struct cifsSesInfo *ses;

	if (tcon == NULL || tcon->ses == NULL) {
S
Steve French 已提交
827
		cERROR(1, ("Null smb session"));
J
[CIFS]  
Jeremy Allison 已提交
828 829 830 831
		return -EIO;
	}
	ses = tcon->ses;

S
Steve French 已提交
832 833
	if (ses->server == NULL) {
		cERROR(1, ("Null tcp session"));
J
[CIFS]  
Jeremy Allison 已提交
834 835 836
		return -EIO;
	}

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

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

844 845 846 847 848 849
	if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
		cERROR(1, ("Illegal length, greater than maximum frame, %d",
			   in_buf->smb_buf_length));
		return -EIO;
	}

850
	rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
J
[CIFS]  
Jeremy Allison 已提交
851 852 853
	if (rc)
		return rc;

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

J
Jeff Layton 已提交
858
	mutex_lock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
859 860 861

	rc = allocate_mid(ses, in_buf, &midQ);
	if (rc) {
J
Jeff Layton 已提交
862
		mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
863 864 865 866
		return rc;
	}

	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
867 868 869 870 871
	if (rc) {
		DeleteMidQEntry(midQ);
		mutex_unlock(&ses->server->srv_mutex);
		return rc;
	}
L
Linus Torvalds 已提交
872

J
[CIFS]  
Jeremy Allison 已提交
873 874 875 876
	midQ->midState = MID_REQUEST_SUBMITTED;
#ifdef CONFIG_CIFS_STATS2
	atomic_inc(&ses->server->inSend);
#endif
877
	rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
J
[CIFS]  
Jeremy Allison 已提交
878 879 880 881
#ifdef CONFIG_CIFS_STATS2
	atomic_dec(&ses->server->inSend);
	midQ->when_sent = jiffies;
#endif
J
Jeff Layton 已提交
882
	mutex_unlock(&ses->server->srv_mutex);
J
[CIFS]  
Jeremy Allison 已提交
883

S
Steve French 已提交
884
	if (rc < 0) {
J
[CIFS]  
Jeremy Allison 已提交
885 886 887 888 889 890
		DeleteMidQEntry(midQ);
		return rc;
	}

	/* Wait for a reply - allow signals to interrupt. */
	rc = wait_event_interruptible(ses->server->response_q,
S
Steve French 已提交
891
		(!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
J
[CIFS]  
Jeremy Allison 已提交
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924
		((ses->server->tcpStatus != CifsGood) &&
		 (ses->server->tcpStatus != CifsNew)));

	/* Were we interrupted by a signal ? */
	if ((rc == -ERESTARTSYS) &&
		(midQ->midState == MID_REQUEST_SUBMITTED) &&
		((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. */

			rc = send_nt_cancel(tcon, in_buf, midQ);
			if (rc) {
				DeleteMidQEntry(midQ);
				return rc;
			}
		} else {
			/* Windows lock. We send a LOCKINGX_CANCEL_LOCK
			   to cause the blocking lock to return. */

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

			/* If we get -ENOLCK back the lock may have
			   already been removed. Don't exit in this case. */
			if (rc && rc != -ENOLCK) {
				DeleteMidQEntry(midQ);
				return rc;
			}
		}

		/* Wait 5 seconds for the response. */
S
Steve French 已提交
925
		if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
J
[CIFS]  
Jeremy Allison 已提交
926 927 928 929 930 931 932 933 934 935
			/* We got the response - restart system call. */
			rstart = 1;
		}
	}

	spin_lock(&GlobalMid_Lock);
	if (midQ->resp_buf) {
		spin_unlock(&GlobalMid_Lock);
		receive_len = midQ->resp_buf->smb_buf_length;
	} else {
S
Steve French 已提交
936
		cERROR(1, ("No response for cmd %d mid %d",
J
[CIFS]  
Jeremy Allison 已提交
937
			  midQ->command, midQ->mid));
S
Steve French 已提交
938 939
		if (midQ->midState == MID_REQUEST_SUBMITTED) {
			if (ses->server->tcpStatus == CifsExiting)
J
[CIFS]  
Jeremy Allison 已提交
940 941 942 943 944 945 946 947
				rc = -EHOSTDOWN;
			else {
				ses->server->tcpStatus = CifsNeedReconnect;
				midQ->midState = MID_RETRY_NEEDED;
			}
		}

		if (rc != -EHOSTDOWN) {
S
Steve French 已提交
948
			if (midQ->midState == MID_RETRY_NEEDED) {
J
[CIFS]  
Jeremy Allison 已提交
949
				rc = -EAGAIN;
S
Steve French 已提交
950
				cFYI(1, ("marking request for retry"));
J
[CIFS]  
Jeremy Allison 已提交
951 952 953 954 955 956 957
			} else {
				rc = -EIO;
			}
		}
		spin_unlock(&GlobalMid_Lock);
		DeleteMidQEntry(midQ);
		return rc;
L
Linus Torvalds 已提交
958
	}
959

J
[CIFS]  
Jeremy Allison 已提交
960 961 962 963
	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
			receive_len, xid));
		rc = -EIO;
964 965
		goto out;
	}
J
[CIFS]  
Jeremy Allison 已提交
966

967
	/* rcvd frame is ok */
J
[CIFS]  
Jeremy Allison 已提交
968

969
	if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) {
970 971 972 973
		rc = -EIO;
		cERROR(1, ("Bad MID state?"));
		goto out;
	}
L
Linus Torvalds 已提交
974

975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990
	out_buf->smb_buf_length = receive_len;
	memcpy((char *)out_buf + 4,
	       (char *)midQ->resp_buf + 4,
	       receive_len);

	dump_smb(out_buf, 92);
	/* convert the length into a more usable form */
	if ((receive_len > 24) &&
	    (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
				     SECMODE_SIGN_ENABLED))) {
		rc = cifs_verify_signature(out_buf,
					   &ses->server->mac_signing_key,
					   midQ->sequence_number+1);
		if (rc) {
			cERROR(1, ("Unexpected SMB signature"));
			/* BB FIXME add code to kill session */
J
[CIFS]  
Jeremy Allison 已提交
991
		}
992
	}
993

994
	*pbytes_returned = out_buf->smb_buf_length;
995

996 997
	/* BB special case reconnect tid and uid here? */
	rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
998

999 1000 1001 1002 1003
	/* convert ByteCount if necessary */
	if (receive_len >= sizeof(struct smb_hdr) - 4
	    /* do not count RFC1001 header */  +
	    (2 * out_buf->WordCount) + 2 /* bcc */ )
		BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1004 1005

out:
J
[CIFS]  
Jeremy Allison 已提交
1006 1007 1008
	DeleteMidQEntry(midQ);
	if (rstart && rc == -EACCES)
		return -ERESTARTSYS;
L
Linus Torvalds 已提交
1009 1010
	return rc;
}