blob: 28f563cef5d77c65c4684d74c23acc324a92aeae [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/transport.c
3 *
Steve Frenchad7a2922008-02-07 23:25:02 +00004 * Copyright (C) International Business Machines Corp., 2002,2008
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
Steve French14a441a2b2006-07-16 04:32:51 +00006 * Jeremy Allison (jra@samba.org) 2006.
Steve French79a58d12007-07-06 22:44:50 +00007 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * This library is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published
10 * by the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
16 * the GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, write to the Free Software
Steve French79a58d12007-07-06 22:44:50 +000020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 */
22
23#include <linux/fs.h>
24#include <linux/list.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/gfp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/wait.h>
27#include <linux/net.h>
28#include <linux/delay.h>
29#include <asm/uaccess.h>
30#include <asm/processor.h>
31#include <linux/mempool.h>
32#include "cifspdu.h"
33#include "cifsglob.h"
34#include "cifsproto.h"
35#include "cifs_debug.h"
Steve French50c2f752007-07-13 00:33:32 +000036
Linus Torvalds1da177e2005-04-16 15:20:36 -070037extern mempool_t *cifs_mid_poolp;
Christoph Lametere18b8902006-12-06 20:33:20 -080038extern struct kmem_cache *cifs_oplock_cachep;
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40static struct mid_q_entry *
Jeff Layton24b9b062008-12-01 07:09:34 -050041AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -070042{
43 struct mid_q_entry *temp;
44
Jeff Layton24b9b062008-12-01 07:09:34 -050045 if (server == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +000046 cERROR(1, "Null TCP session in AllocMidQEntry");
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 return NULL;
48 }
Steve French50c2f752007-07-13 00:33:32 +000049
Pekka Enberg232087c2008-09-15 13:22:54 +030050 temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 if (temp == NULL)
52 return temp;
53 else {
Steve French26f57362007-08-30 22:09:15 +000054 memset(temp, 0, sizeof(struct mid_q_entry));
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 temp->mid = smb_buffer->Mid; /* always LE */
56 temp->pid = current->pid;
57 temp->command = smb_buffer->Command;
Joe Perchesb6b38f72010-04-21 03:50:45 +000058 cFYI(1, "For smb_command %d", temp->command);
Steve French1047abc2005-10-11 19:58:06 -070059 /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
60 /* when mid allocated can be before when sent */
61 temp->when_alloc = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 temp->tsk = current;
63 }
64
65 spin_lock(&GlobalMid_Lock);
Jeff Layton24b9b062008-12-01 07:09:34 -050066 list_add_tail(&temp->qhead, &server->pending_mid_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 atomic_inc(&midCount);
68 temp->midState = MID_REQUEST_ALLOCATED;
69 spin_unlock(&GlobalMid_Lock);
70 return temp;
71}
72
73static void
74DeleteMidQEntry(struct mid_q_entry *midEntry)
75{
Steve French1047abc2005-10-11 19:58:06 -070076#ifdef CONFIG_CIFS_STATS2
77 unsigned long now;
78#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 spin_lock(&GlobalMid_Lock);
80 midEntry->midState = MID_FREE;
81 list_del(&midEntry->qhead);
82 atomic_dec(&midCount);
83 spin_unlock(&GlobalMid_Lock);
Steve French79a58d12007-07-06 22:44:50 +000084 if (midEntry->largeBuf)
Steve Frenchb8643e12005-04-28 22:41:07 -070085 cifs_buf_release(midEntry->resp_buf);
86 else
87 cifs_small_buf_release(midEntry->resp_buf);
Steve French1047abc2005-10-11 19:58:06 -070088#ifdef CONFIG_CIFS_STATS2
89 now = jiffies;
90 /* commands taking longer than one second are indications that
91 something is wrong, unless it is quite a slow link or server */
Steve French79a58d12007-07-06 22:44:50 +000092 if ((now - midEntry->when_alloc) > HZ) {
93 if ((cifsFYI & CIFS_TIMER) &&
Steve French1047abc2005-10-11 19:58:06 -070094 (midEntry->command != SMB_COM_LOCKING_ANDX)) {
95 printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
96 midEntry->command, midEntry->mid);
97 printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
98 now - midEntry->when_alloc,
99 now - midEntry->when_sent,
100 now - midEntry->when_received);
101 }
102 }
103#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 mempool_free(midEntry, cifs_mid_poolp);
105}
106
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500107static int
Jeff Layton0496e022008-12-30 12:39:16 -0500108smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109{
110 int rc = 0;
111 int i = 0;
112 struct msghdr smb_msg;
Steve French3e844692005-10-03 13:37:24 -0700113 struct smb_hdr *smb_buffer = iov[0].iov_base;
114 unsigned int len = iov[0].iov_len;
115 unsigned int total_len;
116 int first_vec = 0;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000117 unsigned int smb_buf_length = smb_buffer->smb_buf_length;
Steve Frenchedf1ae42008-10-29 00:47:57 +0000118 struct socket *ssocket = server->ssocket;
Steve French50c2f752007-07-13 00:33:32 +0000119
Steve French79a58d12007-07-06 22:44:50 +0000120 if (ssocket == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 return -ENOTSOCK; /* BB eventually add reconnect code here */
Steve French3e844692005-10-03 13:37:24 -0700122
Jeff Layton0496e022008-12-30 12:39:16 -0500123 smb_msg.msg_name = (struct sockaddr *) &server->addr.sockAddr;
Steve French26f57362007-08-30 22:09:15 +0000124 smb_msg.msg_namelen = sizeof(struct sockaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 smb_msg.msg_control = NULL;
126 smb_msg.msg_controllen = 0;
Jeff Layton0496e022008-12-30 12:39:16 -0500127 if (server->noblocksnd)
Steve Frenchedf1ae42008-10-29 00:47:57 +0000128 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
129 else
130 smb_msg.msg_flags = MSG_NOSIGNAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
132 /* smb header is converted in header_assemble. bcc and rest of SMB word
Steve French79a58d12007-07-06 22:44:50 +0000133 area, and byte area if necessary, is converted to littleendian in
134 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 Flags2 is converted in SendReceive */
136
Steve French3e844692005-10-03 13:37:24 -0700137
138 total_len = 0;
139 for (i = 0; i < n_vec; i++)
140 total_len += iov[i].iov_len;
141
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000143 cFYI(1, "Sending smb: total_len %d", total_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 dump_smb(smb_buffer, len);
145
Shirish Pargaonkar17680352008-07-29 21:26:13 +0000146 i = 0;
Steve French3e844692005-10-03 13:37:24 -0700147 while (total_len) {
148 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
149 n_vec - first_vec, total_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
151 i++;
Steve Frenchda505c32009-01-19 03:49:35 +0000152 /* if blocking send we try 3 times, since each can block
153 for 5 seconds. For nonblocking we have to try more
154 but wait increasing amounts of time allowing time for
155 socket to clear. The overall time we wait in either
156 case to send on the socket is about 15 seconds.
157 Similarly we wait for 15 seconds for
158 a response from the server in SendReceive[2]
159 for the server to send a response back for
160 most types of requests (except SMB Write
161 past end of file which can be slow, and
162 blocking lock operations). NFS waits slightly longer
163 than CIFS, but this can make it take longer for
164 nonresponsive servers to be detected and 15 seconds
165 is more than enough time for modern networks to
166 send a packet. In most cases if we fail to send
167 after the retries we will kill the socket and
168 reconnect which may clear the network problem.
169 */
170 if ((i >= 14) || (!server->noblocksnd && (i > 2))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000171 cERROR(1, "sends on sock %p stuck for 15 seconds",
172 ssocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 rc = -EAGAIN;
174 break;
175 }
Steve French68058e72005-10-10 10:34:22 -0700176 msleep(1 << i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 continue;
178 }
Steve French79a58d12007-07-06 22:44:50 +0000179 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 break;
Steve French3e844692005-10-03 13:37:24 -0700181
Steve French61de8002008-10-30 20:15:22 +0000182 if (rc == total_len) {
183 total_len = 0;
184 break;
185 } else if (rc > total_len) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000186 cERROR(1, "sent %d requested %d", rc, total_len);
Steve French3e844692005-10-03 13:37:24 -0700187 break;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500188 }
Steve French79a58d12007-07-06 22:44:50 +0000189 if (rc == 0) {
Steve French3e844692005-10-03 13:37:24 -0700190 /* should never happen, letting socket clear before
191 retrying is our only obvious option here */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000192 cERROR(1, "tcp sent no data");
Steve French3e844692005-10-03 13:37:24 -0700193 msleep(500);
194 continue;
195 }
196 total_len -= rc;
Steve French68058e72005-10-10 10:34:22 -0700197 /* the line below resets i */
Steve French3e844692005-10-03 13:37:24 -0700198 for (i = first_vec; i < n_vec; i++) {
199 if (iov[i].iov_len) {
200 if (rc > iov[i].iov_len) {
201 rc -= iov[i].iov_len;
202 iov[i].iov_len = 0;
203 } else {
204 iov[i].iov_base += rc;
205 iov[i].iov_len -= rc;
206 first_vec = i;
207 break;
208 }
209 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500210 }
Steve French5e1253b2005-10-10 14:06:37 -0700211 i = 0; /* in case we get ENOSPC on the next send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 }
213
Steve Frenchedf1ae42008-10-29 00:47:57 +0000214 if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000215 cFYI(1, "partial send (%d remaining), terminating session",
216 total_len);
Steve Frenchedf1ae42008-10-29 00:47:57 +0000217 /* If we have only sent part of an SMB then the next SMB
218 could be taken as the remainder of this one. We need
219 to kill the socket so the server throws away the partial
220 SMB */
221 server->tcpStatus = CifsNeedReconnect;
222 }
223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 if (rc < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000225 cERROR(1, "Error %d sending data on socket to server", rc);
Steve French3e844692005-10-03 13:37:24 -0700226 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000229 /* Don't want to modify the buffer as a
230 side effect of this call. */
231 smb_buffer->smb_buf_length = smb_buf_length;
232
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 return rc;
234}
235
Jeff Layton0496e022008-12-30 12:39:16 -0500236int
237smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
238 unsigned int smb_buf_length)
239{
240 struct kvec iov;
241
242 iov.iov_base = smb_buffer;
243 iov.iov_len = smb_buf_length + 4;
244
245 return smb_sendv(server, &iov, 1);
246}
247
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000248static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
249{
Steve French133672e2007-11-13 22:41:37 +0000250 if (long_op == CIFS_ASYNC_OP) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000251 /* oplock breaks must not be held up */
252 atomic_inc(&ses->server->inFlight);
Volker Lendecke27a97a62008-12-08 20:59:39 +0000253 return 0;
254 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000255
Volker Lendecke27a97a62008-12-08 20:59:39 +0000256 spin_lock(&GlobalMid_Lock);
257 while (1) {
258 if (atomic_read(&ses->server->inFlight) >=
259 cifs_max_pending){
260 spin_unlock(&GlobalMid_Lock);
261#ifdef CONFIG_CIFS_STATS2
262 atomic_inc(&ses->server->num_waiters);
263#endif
264 wait_event(ses->server->request_q,
265 atomic_read(&ses->server->inFlight)
266 < cifs_max_pending);
267#ifdef CONFIG_CIFS_STATS2
268 atomic_dec(&ses->server->num_waiters);
269#endif
270 spin_lock(&GlobalMid_Lock);
271 } else {
272 if (ses->server->tcpStatus == CifsExiting) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000273 spin_unlock(&GlobalMid_Lock);
Volker Lendecke27a97a62008-12-08 20:59:39 +0000274 return -ENOENT;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000275 }
Volker Lendecke27a97a62008-12-08 20:59:39 +0000276
277 /* can not count locking commands against total
278 as they are allowed to block on server */
279
280 /* update # of requests on the wire to server */
281 if (long_op != CIFS_BLOCKING_OP)
282 atomic_inc(&ses->server->inFlight);
283 spin_unlock(&GlobalMid_Lock);
284 break;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000285 }
286 }
287 return 0;
288}
289
290static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
291 struct mid_q_entry **ppmidQ)
292{
293 if (ses->server->tcpStatus == CifsExiting) {
294 return -ENOENT;
Volker Lendecke8fbbd362008-12-06 13:12:34 +0100295 }
296
297 if (ses->server->tcpStatus == CifsNeedReconnect) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000298 cFYI(1, "tcp session dead - return to caller to retry");
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000299 return -EAGAIN;
Volker Lendecke8fbbd362008-12-06 13:12:34 +0100300 }
301
302 if (ses->status != CifsGood) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000303 /* check if SMB session is bad because we are setting it up */
Steve French79a58d12007-07-06 22:44:50 +0000304 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
Steve Frenchad7a2922008-02-07 23:25:02 +0000305 (in_buf->Command != SMB_COM_NEGOTIATE))
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000306 return -EAGAIN;
Steve Frenchad7a2922008-02-07 23:25:02 +0000307 /* else ok - we are setting up session */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000308 }
Jeff Layton24b9b062008-12-01 07:09:34 -0500309 *ppmidQ = AllocMidQEntry(in_buf, ses->server);
Steve French26f57362007-08-30 22:09:15 +0000310 if (*ppmidQ == NULL)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000311 return -ENOMEM;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000312 return 0;
313}
314
Steve French79a58d12007-07-06 22:44:50 +0000315static int wait_for_response(struct cifsSesInfo *ses,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000316 struct mid_q_entry *midQ,
317 unsigned long timeout,
318 unsigned long time_to_wait)
319{
320 unsigned long curr_timeout;
321
322 for (;;) {
323 curr_timeout = timeout + jiffies;
Jeff Layton85705522008-12-05 20:41:21 -0500324 wait_event_timeout(ses->server->response_q,
325 midQ->midState != MID_REQUEST_SUBMITTED, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000326
327 if (time_after(jiffies, curr_timeout) &&
328 (midQ->midState == MID_REQUEST_SUBMITTED) &&
329 ((ses->server->tcpStatus == CifsGood) ||
330 (ses->server->tcpStatus == CifsNew))) {
331
332 unsigned long lrt;
333
334 /* We timed out. Is the server still
335 sending replies ? */
336 spin_lock(&GlobalMid_Lock);
337 lrt = ses->server->lstrp;
338 spin_unlock(&GlobalMid_Lock);
339
340 /* Calculate time_to_wait past last receive time.
Steve French79a58d12007-07-06 22:44:50 +0000341 Although we prefer not to time out if the
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000342 server is still responding - we will time
Steve French79a58d12007-07-06 22:44:50 +0000343 out if the server takes more than 15 (or 45
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000344 or 180) seconds to respond to this request
Steve French79a58d12007-07-06 22:44:50 +0000345 and has not responded to any request from
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000346 other threads on the client within 10 seconds */
347 lrt += time_to_wait;
348 if (time_after(jiffies, lrt)) {
349 /* No replies for time_to_wait. */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000350 cERROR(1, "server not responding");
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000351 return -1;
352 }
353 } else {
354 return 0;
355 }
356 }
357}
358
Steve French133672e2007-11-13 22:41:37 +0000359
360/*
361 *
362 * Send an SMB Request. No response info (other than return code)
363 * needs to be parsed.
364 *
365 * flags indicate the type of request buffer and how long to wait
366 * and whether to log NT STATUS code (error) before mapping it to POSIX error
367 *
368 */
369int
370SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
371 struct smb_hdr *in_buf, int flags)
372{
373 int rc;
374 struct kvec iov[1];
375 int resp_buf_type;
376
377 iov[0].iov_base = (char *)in_buf;
378 iov[0].iov_len = in_buf->smb_buf_length + 4;
379 flags |= CIFS_NO_RESP;
380 rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000381 cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc);
Steve French90c81e02008-02-12 20:32:36 +0000382
Steve French133672e2007-11-13 22:41:37 +0000383 return rc;
384}
385
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386int
Steve French79a58d12007-07-06 22:44:50 +0000387SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
388 struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
Steve French133672e2007-11-13 22:41:37 +0000389 const int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390{
391 int rc = 0;
Steve French133672e2007-11-13 22:41:37 +0000392 int long_op;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500393 unsigned int receive_len;
394 unsigned long timeout;
395 struct mid_q_entry *midQ;
Steve French3e844692005-10-03 13:37:24 -0700396 struct smb_hdr *in_buf = iov[0].iov_base;
Steve French50c2f752007-07-13 00:33:32 +0000397
Steve French133672e2007-11-13 22:41:37 +0000398 long_op = flags & CIFS_TIMEOUT_MASK;
399
Steve Frenchec637e32005-12-12 20:53:18 -0800400 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
Steve French4b8f9302006-02-26 16:41:18 +0000402 if ((ses == NULL) || (ses->server == NULL)) {
403 cifs_small_buf_release(in_buf);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000404 cERROR(1, "Null session");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 return -EIO;
406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407
Steve French79a58d12007-07-06 22:44:50 +0000408 if (ses->server->tcpStatus == CifsExiting) {
Steve French4b8f9302006-02-26 16:41:18 +0000409 cifs_small_buf_release(in_buf);
Steve French31ca3bc2005-04-28 22:41:11 -0700410 return -ENOENT;
Steve French4b8f9302006-02-26 16:41:18 +0000411 }
Steve French31ca3bc2005-04-28 22:41:11 -0700412
Steve French79a58d12007-07-06 22:44:50 +0000413 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 to the same server. We may make this configurable later or
415 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000417 rc = wait_for_free_request(ses, long_op);
418 if (rc) {
419 cifs_small_buf_release(in_buf);
420 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000422
Steve French79a58d12007-07-06 22:44:50 +0000423 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 and avoid races inside tcp sendmsg code that could cause corruption
425 of smb data */
426
Jeff Layton72ca5452008-12-01 07:09:36 -0500427 mutex_lock(&ses->server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000429 rc = allocate_mid(ses, in_buf, &midQ);
430 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500431 mutex_unlock(&ses->server->srv_mutex);
Steve French4b8f9302006-02-26 16:41:18 +0000432 cifs_small_buf_release(in_buf);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000433 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000434 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000435 wake_up(&ses->server->request_q);
436 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 }
Steve French79a58d12007-07-06 22:44:50 +0000438 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100439 if (rc) {
440 mutex_unlock(&ses->server->srv_mutex);
441 cifs_small_buf_release(in_buf);
442 goto out;
443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444
445 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700446#ifdef CONFIG_CIFS_STATS2
447 atomic_inc(&ses->server->inSend);
448#endif
Jeff Layton0496e022008-12-30 12:39:16 -0500449 rc = smb_sendv(ses->server, iov, n_vec);
Steve French131afd0b2005-10-07 09:51:05 -0700450#ifdef CONFIG_CIFS_STATS2
451 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700452 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700453#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000454
Jeff Layton72ca5452008-12-01 07:09:36 -0500455 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000456 cifs_small_buf_release(in_buf);
457
Steve French79a58d12007-07-06 22:44:50 +0000458 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000459 goto out;
Steve French4b8f9302006-02-26 16:41:18 +0000460
Steve French133672e2007-11-13 22:41:37 +0000461 if (long_op == CIFS_STD_OP)
462 timeout = 15 * HZ;
463 else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
Steve French37c0eb42005-10-05 14:50:29 -0700464 timeout = 180 * HZ;
Steve French133672e2007-11-13 22:41:37 +0000465 else if (long_op == CIFS_LONG_OP)
Steve French79a58d12007-07-06 22:44:50 +0000466 timeout = 45 * HZ; /* should be greater than
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500467 servers oplock break timeout (about 43 seconds) */
Steve French133672e2007-11-13 22:41:37 +0000468 else if (long_op == CIFS_ASYNC_OP)
469 goto out;
470 else if (long_op == CIFS_BLOCKING_OP)
471 timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */
472 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000473 cERROR(1, "unknown timeout flag %d", long_op);
Steve French133672e2007-11-13 22:41:37 +0000474 rc = -EIO;
475 goto out;
476 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000477
Steve French79a58d12007-07-06 22:44:50 +0000478 /* wait for 15 seconds or until woken up due to response arriving or
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500479 due to last connection to this server being unmounted */
480 if (signal_pending(current)) {
481 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000482 but we still give response a chance to complete */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500483 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000484 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500485
486 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000487 wait_for_response(ses, midQ, timeout, 10 * HZ);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500488
489 spin_lock(&GlobalMid_Lock);
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100490
491 if (midQ->resp_buf == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000492 cERROR(1, "No response to cmd %d mid %d",
493 midQ->command, midQ->mid);
Steve French79a58d12007-07-06 22:44:50 +0000494 if (midQ->midState == MID_REQUEST_SUBMITTED) {
495 if (ses->server->tcpStatus == CifsExiting)
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500496 rc = -EHOSTDOWN;
497 else {
498 ses->server->tcpStatus = CifsNeedReconnect;
499 midQ->midState = MID_RETRY_NEEDED;
500 }
501 }
502
503 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000504 if (midQ->midState == MID_RETRY_NEEDED) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500505 rc = -EAGAIN;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000506 cFYI(1, "marking request for retry");
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500507 } else {
508 rc = -EIO;
509 }
510 }
511 spin_unlock(&GlobalMid_Lock);
512 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000513 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000514 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000515 wake_up(&ses->server->request_q);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500516 return rc;
517 }
Steve French50c2f752007-07-13 00:33:32 +0000518
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100519 spin_unlock(&GlobalMid_Lock);
520 receive_len = midQ->resp_buf->smb_buf_length;
521
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500522 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000523 cERROR(1, "Frame too large received. Length: %d Xid: %d",
524 receive_len, xid);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500525 rc = -EIO;
Steve French2b2bdfb2008-12-11 17:26:54 +0000526 goto out;
527 }
Steve French84afc292005-12-02 13:32:45 -0800528
Steve French2b2bdfb2008-12-11 17:26:54 +0000529 /* rcvd frame is ok */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500530
Steve French2b2bdfb2008-12-11 17:26:54 +0000531 if (midQ->resp_buf &&
532 (midQ->midState == MID_RESPONSE_RECEIVED)) {
533
534 iov[0].iov_base = (char *)midQ->resp_buf;
535 if (midQ->largeBuf)
536 *pRespBufType = CIFS_LARGE_BUFFER;
537 else
538 *pRespBufType = CIFS_SMALL_BUFFER;
539 iov[0].iov_len = receive_len + 4;
540
541 dump_smb(midQ->resp_buf, 80);
542 /* convert the length into a more usable form */
543 if ((receive_len > 24) &&
544 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
545 SECMODE_SIGN_ENABLED))) {
546 rc = cifs_verify_signature(midQ->resp_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000547 &ses->server->mac_signing_key,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500548 midQ->sequence_number+1);
Steve French2b2bdfb2008-12-11 17:26:54 +0000549 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000550 cERROR(1, "Unexpected SMB signature");
Steve French2b2bdfb2008-12-11 17:26:54 +0000551 /* BB FIXME add code to kill session */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500552 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500553 }
Steve French2b2bdfb2008-12-11 17:26:54 +0000554
555 /* BB special case reconnect tid and uid here? */
556 rc = map_smb_to_linux_error(midQ->resp_buf,
557 flags & CIFS_LOG_ERROR);
558
559 /* convert ByteCount if necessary */
560 if (receive_len >= sizeof(struct smb_hdr) - 4
561 /* do not count RFC1001 header */ +
562 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
563 BCC(midQ->resp_buf) =
564 le16_to_cpu(BCC_LE(midQ->resp_buf));
565 if ((flags & CIFS_NO_RESP) == 0)
566 midQ->resp_buf = NULL; /* mark it so buf will
567 not be freed by
568 DeleteMidQEntry */
569 } else {
570 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000571 cFYI(1, "Bad MID state?");
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500572 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000573
574out:
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500575 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000576 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000577 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
579 return rc;
580}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
582int
583SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
584 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
585 int *pbytes_returned, const int long_op)
586{
587 int rc = 0;
588 unsigned int receive_len;
589 unsigned long timeout;
590 struct mid_q_entry *midQ;
591
592 if (ses == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000593 cERROR(1, "Null smb session");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 return -EIO;
595 }
Steve French79a58d12007-07-06 22:44:50 +0000596 if (ses->server == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000597 cERROR(1, "Null tcp session");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 return -EIO;
599 }
600
Steve French79a58d12007-07-06 22:44:50 +0000601 if (ses->server->tcpStatus == CifsExiting)
Steve French31ca3bc2005-04-28 22:41:11 -0700602 return -ENOENT;
603
Steve French79a58d12007-07-06 22:44:50 +0000604 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 to the same server. We may make this configurable later or
606 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000608 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000609 cERROR(1, "Illegal length, greater than maximum frame, %d",
610 in_buf->smb_buf_length);
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000611 return -EIO;
612 }
613
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000614 rc = wait_for_free_request(ses, long_op);
615 if (rc)
616 return rc;
617
Steve French79a58d12007-07-06 22:44:50 +0000618 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 and avoid races inside tcp sendmsg code that could cause corruption
620 of smb data */
621
Jeff Layton72ca5452008-12-01 07:09:36 -0500622 mutex_lock(&ses->server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000624 rc = allocate_mid(ses, in_buf, &midQ);
625 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500626 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000627 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000628 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000629 wake_up(&ses->server->request_q);
630 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 }
632
Steve Frenchad009ac2005-04-28 22:41:05 -0700633 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100634 if (rc) {
635 mutex_unlock(&ses->server->srv_mutex);
636 goto out;
637 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
639 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700640#ifdef CONFIG_CIFS_STATS2
641 atomic_inc(&ses->server->inSend);
642#endif
Jeff Layton0496e022008-12-30 12:39:16 -0500643 rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
Steve French131afd0b2005-10-07 09:51:05 -0700644#ifdef CONFIG_CIFS_STATS2
645 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700646 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700647#endif
Jeff Layton72ca5452008-12-01 07:09:36 -0500648 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000649
Steve French79a58d12007-07-06 22:44:50 +0000650 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000651 goto out;
652
Steve French133672e2007-11-13 22:41:37 +0000653 if (long_op == CIFS_STD_OP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 timeout = 15 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000655 /* wait for 15 seconds or until woken up due to response arriving or
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 due to last connection to this server being unmounted */
Steve French133672e2007-11-13 22:41:37 +0000657 else if (long_op == CIFS_ASYNC_OP)
658 goto out;
659 else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
660 timeout = 180 * HZ;
661 else if (long_op == CIFS_LONG_OP)
662 timeout = 45 * HZ; /* should be greater than
663 servers oplock break timeout (about 43 seconds) */
664 else if (long_op == CIFS_BLOCKING_OP)
665 timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
666 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000667 cERROR(1, "unknown timeout flag %d", long_op);
Steve French133672e2007-11-13 22:41:37 +0000668 rc = -EIO;
669 goto out;
670 }
671
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 if (signal_pending(current)) {
673 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000674 but we still give response a chance to complete */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000676 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
678 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000679 wait_for_response(ses, midQ, timeout, 10 * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681 spin_lock(&GlobalMid_Lock);
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100682 if (midQ->resp_buf == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000683 cERROR(1, "No response for cmd %d mid %d",
684 midQ->command, midQ->mid);
Steve French79a58d12007-07-06 22:44:50 +0000685 if (midQ->midState == MID_REQUEST_SUBMITTED) {
686 if (ses->server->tcpStatus == CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 rc = -EHOSTDOWN;
688 else {
689 ses->server->tcpStatus = CifsNeedReconnect;
690 midQ->midState = MID_RETRY_NEEDED;
691 }
692 }
693
694 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000695 if (midQ->midState == MID_RETRY_NEEDED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 rc = -EAGAIN;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000697 cFYI(1, "marking request for retry");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 } else {
699 rc = -EIO;
700 }
701 }
702 spin_unlock(&GlobalMid_Lock);
703 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000704 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000705 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000706 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 return rc;
708 }
Steve French50c2f752007-07-13 00:33:32 +0000709
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100710 spin_unlock(&GlobalMid_Lock);
711 receive_len = midQ->resp_buf->smb_buf_length;
712
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000714 cERROR(1, "Frame too large received. Length: %d Xid: %d",
715 receive_len, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 rc = -EIO;
Steve French2b2bdfb2008-12-11 17:26:54 +0000717 goto out;
718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
Steve French2b2bdfb2008-12-11 17:26:54 +0000720 /* rcvd frame is ok */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
Steve French2b2bdfb2008-12-11 17:26:54 +0000722 if (midQ->resp_buf && out_buf
723 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
724 out_buf->smb_buf_length = receive_len;
725 memcpy((char *)out_buf + 4,
726 (char *)midQ->resp_buf + 4,
727 receive_len);
728
729 dump_smb(out_buf, 92);
730 /* convert the length into a more usable form */
731 if ((receive_len > 24) &&
732 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
733 SECMODE_SIGN_ENABLED))) {
734 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000735 &ses->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -0700736 midQ->sequence_number+1);
Steve French2b2bdfb2008-12-11 17:26:54 +0000737 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000738 cERROR(1, "Unexpected SMB signature");
Steve French2b2bdfb2008-12-11 17:26:54 +0000739 /* BB FIXME add code to kill session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 }
Steve French2b2bdfb2008-12-11 17:26:54 +0000742
743 *pbytes_returned = out_buf->smb_buf_length;
744
745 /* BB special case reconnect tid and uid here? */
746 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
747
748 /* convert ByteCount if necessary */
749 if (receive_len >= sizeof(struct smb_hdr) - 4
750 /* do not count RFC1001 header */ +
751 (2 * out_buf->WordCount) + 2 /* bcc */ )
752 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
753 } else {
754 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000755 cERROR(1, "Bad MID state?");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000758out:
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000759 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000760 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000761 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
763 return rc;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000764}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000766/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
767
768static int
769send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
770 struct mid_q_entry *midQ)
771{
772 int rc = 0;
773 struct cifsSesInfo *ses = tcon->ses;
774 __u16 mid = in_buf->Mid;
775
776 header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
777 in_buf->Mid = mid;
Jeff Layton72ca5452008-12-01 07:09:36 -0500778 mutex_lock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000779 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
780 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500781 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000782 return rc;
783 }
Jeff Layton0496e022008-12-30 12:39:16 -0500784 rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
Jeff Layton72ca5452008-12-01 07:09:36 -0500785 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000786 return rc;
787}
788
789/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
790 blocking lock to return. */
791
792static int
793send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
794 struct smb_hdr *in_buf,
795 struct smb_hdr *out_buf)
796{
797 int bytes_returned;
798 struct cifsSesInfo *ses = tcon->ses;
799 LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
800
801 /* We just modify the current in_buf to change
802 the type of lock from LOCKING_ANDX_SHARED_LOCK
803 or LOCKING_ANDX_EXCLUSIVE_LOCK to
804 LOCKING_ANDX_CANCEL_LOCK. */
805
806 pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
807 pSMB->Timeout = 0;
808 pSMB->hdr.Mid = GetNextMid(ses->server);
809
810 return SendReceive(xid, ses, in_buf, out_buf,
Steve French133672e2007-11-13 22:41:37 +0000811 &bytes_returned, CIFS_STD_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000812}
813
814int
815SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
816 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
817 int *pbytes_returned)
818{
819 int rc = 0;
820 int rstart = 0;
821 unsigned int receive_len;
822 struct mid_q_entry *midQ;
823 struct cifsSesInfo *ses;
824
825 if (tcon == NULL || tcon->ses == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000826 cERROR(1, "Null smb session");
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000827 return -EIO;
828 }
829 ses = tcon->ses;
830
Steve French79a58d12007-07-06 22:44:50 +0000831 if (ses->server == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000832 cERROR(1, "Null tcp session");
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000833 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 }
835
Steve French79a58d12007-07-06 22:44:50 +0000836 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000837 return -ENOENT;
838
Steve French79a58d12007-07-06 22:44:50 +0000839 /* Ensure that we do not send more than 50 overlapping requests
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000840 to the same server. We may make this configurable later or
841 use ses->maxReq */
842
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000843 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000844 cERROR(1, "Illegal length, greater than maximum frame, %d",
845 in_buf->smb_buf_length);
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000846 return -EIO;
847 }
848
Steve French133672e2007-11-13 22:41:37 +0000849 rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000850 if (rc)
851 return rc;
852
Steve French79a58d12007-07-06 22:44:50 +0000853 /* make sure that we sign in the same order that we send on this socket
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000854 and avoid races inside tcp sendmsg code that could cause corruption
855 of smb data */
856
Jeff Layton72ca5452008-12-01 07:09:36 -0500857 mutex_lock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000858
859 rc = allocate_mid(ses, in_buf, &midQ);
860 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500861 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000862 return rc;
863 }
864
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000865 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100866 if (rc) {
867 DeleteMidQEntry(midQ);
868 mutex_unlock(&ses->server->srv_mutex);
869 return rc;
870 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000871
872 midQ->midState = MID_REQUEST_SUBMITTED;
873#ifdef CONFIG_CIFS_STATS2
874 atomic_inc(&ses->server->inSend);
875#endif
Jeff Layton0496e022008-12-30 12:39:16 -0500876 rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000877#ifdef CONFIG_CIFS_STATS2
878 atomic_dec(&ses->server->inSend);
879 midQ->when_sent = jiffies;
880#endif
Jeff Layton72ca5452008-12-01 07:09:36 -0500881 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000882
Steve French79a58d12007-07-06 22:44:50 +0000883 if (rc < 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000884 DeleteMidQEntry(midQ);
885 return rc;
886 }
887
888 /* Wait for a reply - allow signals to interrupt. */
889 rc = wait_event_interruptible(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000890 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000891 ((ses->server->tcpStatus != CifsGood) &&
892 (ses->server->tcpStatus != CifsNew)));
893
894 /* Were we interrupted by a signal ? */
895 if ((rc == -ERESTARTSYS) &&
896 (midQ->midState == MID_REQUEST_SUBMITTED) &&
897 ((ses->server->tcpStatus == CifsGood) ||
898 (ses->server->tcpStatus == CifsNew))) {
899
900 if (in_buf->Command == SMB_COM_TRANSACTION2) {
901 /* POSIX lock. We send a NT_CANCEL SMB to cause the
902 blocking lock to return. */
903
904 rc = send_nt_cancel(tcon, in_buf, midQ);
905 if (rc) {
906 DeleteMidQEntry(midQ);
907 return rc;
908 }
909 } else {
910 /* Windows lock. We send a LOCKINGX_CANCEL_LOCK
911 to cause the blocking lock to return. */
912
913 rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
914
915 /* If we get -ENOLCK back the lock may have
916 already been removed. Don't exit in this case. */
917 if (rc && rc != -ENOLCK) {
918 DeleteMidQEntry(midQ);
919 return rc;
920 }
921 }
922
923 /* Wait 5 seconds for the response. */
Steve French79a58d12007-07-06 22:44:50 +0000924 if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000925 /* We got the response - restart system call. */
926 rstart = 1;
927 }
928 }
929
930 spin_lock(&GlobalMid_Lock);
931 if (midQ->resp_buf) {
932 spin_unlock(&GlobalMid_Lock);
933 receive_len = midQ->resp_buf->smb_buf_length;
934 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000935 cERROR(1, "No response for cmd %d mid %d",
936 midQ->command, midQ->mid);
Steve French79a58d12007-07-06 22:44:50 +0000937 if (midQ->midState == MID_REQUEST_SUBMITTED) {
938 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000939 rc = -EHOSTDOWN;
940 else {
941 ses->server->tcpStatus = CifsNeedReconnect;
942 midQ->midState = MID_RETRY_NEEDED;
943 }
944 }
945
946 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000947 if (midQ->midState == MID_RETRY_NEEDED) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000948 rc = -EAGAIN;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000949 cFYI(1, "marking request for retry");
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000950 } else {
951 rc = -EIO;
952 }
953 }
954 spin_unlock(&GlobalMid_Lock);
955 DeleteMidQEntry(midQ);
956 return rc;
957 }
Steve French50c2f752007-07-13 00:33:32 +0000958
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000959 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000960 cERROR(1, "Frame too large received. Length: %d Xid: %d",
961 receive_len, xid);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000962 rc = -EIO;
Volker Lendecke17c8bfe2008-12-06 16:38:19 +0100963 goto out;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000964 }
Volker Lendecke17c8bfe2008-12-06 16:38:19 +0100965
966 /* rcvd frame is ok */
967
Volker Lendeckeac6a3ef2008-12-06 16:40:40 +0100968 if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) {
Volker Lendecke17c8bfe2008-12-06 16:38:19 +0100969 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000970 cERROR(1, "Bad MID state?");
Volker Lendecke698e96a2008-12-06 16:39:31 +0100971 goto out;
Volker Lendecke17c8bfe2008-12-06 16:38:19 +0100972 }
973
Volker Lendecke698e96a2008-12-06 16:39:31 +0100974 out_buf->smb_buf_length = receive_len;
975 memcpy((char *)out_buf + 4,
976 (char *)midQ->resp_buf + 4,
977 receive_len);
978
979 dump_smb(out_buf, 92);
980 /* convert the length into a more usable form */
981 if ((receive_len > 24) &&
982 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
983 SECMODE_SIGN_ENABLED))) {
984 rc = cifs_verify_signature(out_buf,
985 &ses->server->mac_signing_key,
986 midQ->sequence_number+1);
987 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000988 cERROR(1, "Unexpected SMB signature");
Volker Lendecke698e96a2008-12-06 16:39:31 +0100989 /* BB FIXME add code to kill session */
990 }
991 }
992
993 *pbytes_returned = out_buf->smb_buf_length;
994
995 /* BB special case reconnect tid and uid here? */
996 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
997
998 /* convert ByteCount if necessary */
999 if (receive_len >= sizeof(struct smb_hdr) - 4
1000 /* do not count RFC1001 header */ +
1001 (2 * out_buf->WordCount) + 2 /* bcc */ )
1002 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1003
Volker Lendecke17c8bfe2008-12-06 16:38:19 +01001004out:
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001005 DeleteMidQEntry(midQ);
1006 if (rstart && rc == -EACCES)
1007 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 return rc;
1009}