blob: 59ca81b16919ea2a9d978ced67df60315499711c [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;
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39static struct mid_q_entry *
Jeff Layton24b9b062008-12-01 07:09:34 -050040AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -070041{
42 struct mid_q_entry *temp;
43
Jeff Layton24b9b062008-12-01 07:09:34 -050044 if (server == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +000045 cERROR(1, "Null TCP session in AllocMidQEntry");
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 return NULL;
47 }
Steve French50c2f752007-07-13 00:33:32 +000048
Pekka Enberg232087c2008-09-15 13:22:54 +030049 temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 if (temp == NULL)
51 return temp;
52 else {
Steve French26f57362007-08-30 22:09:15 +000053 memset(temp, 0, sizeof(struct mid_q_entry));
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 temp->mid = smb_buffer->Mid; /* always LE */
55 temp->pid = current->pid;
56 temp->command = smb_buffer->Command;
Joe Perchesb6b38f72010-04-21 03:50:45 +000057 cFYI(1, "For smb_command %d", temp->command);
Steve French1047abc2005-10-11 19:58:06 -070058 /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
59 /* when mid allocated can be before when sent */
60 temp->when_alloc = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 temp->tsk = current;
62 }
63
64 spin_lock(&GlobalMid_Lock);
Jeff Layton24b9b062008-12-01 07:09:34 -050065 list_add_tail(&temp->qhead, &server->pending_mid_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 atomic_inc(&midCount);
67 temp->midState = MID_REQUEST_ALLOCATED;
68 spin_unlock(&GlobalMid_Lock);
69 return temp;
70}
71
72static void
73DeleteMidQEntry(struct mid_q_entry *midEntry)
74{
Steve French1047abc2005-10-11 19:58:06 -070075#ifdef CONFIG_CIFS_STATS2
76 unsigned long now;
77#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 spin_lock(&GlobalMid_Lock);
79 midEntry->midState = MID_FREE;
80 list_del(&midEntry->qhead);
81 atomic_dec(&midCount);
82 spin_unlock(&GlobalMid_Lock);
Steve French79a58d12007-07-06 22:44:50 +000083 if (midEntry->largeBuf)
Steve Frenchb8643e12005-04-28 22:41:07 -070084 cifs_buf_release(midEntry->resp_buf);
85 else
86 cifs_small_buf_release(midEntry->resp_buf);
Steve French1047abc2005-10-11 19:58:06 -070087#ifdef CONFIG_CIFS_STATS2
88 now = jiffies;
89 /* commands taking longer than one second are indications that
90 something is wrong, unless it is quite a slow link or server */
Steve French79a58d12007-07-06 22:44:50 +000091 if ((now - midEntry->when_alloc) > HZ) {
92 if ((cifsFYI & CIFS_TIMER) &&
Steve French1047abc2005-10-11 19:58:06 -070093 (midEntry->command != SMB_COM_LOCKING_ANDX)) {
94 printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
95 midEntry->command, midEntry->mid);
96 printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
97 now - midEntry->when_alloc,
98 now - midEntry->when_sent,
99 now - midEntry->when_received);
100 }
101 }
102#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 mempool_free(midEntry, cifs_mid_poolp);
104}
105
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500106static int
Jeff Layton0496e022008-12-30 12:39:16 -0500107smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108{
109 int rc = 0;
110 int i = 0;
111 struct msghdr smb_msg;
Steve French3e844692005-10-03 13:37:24 -0700112 struct smb_hdr *smb_buffer = iov[0].iov_base;
113 unsigned int len = iov[0].iov_len;
114 unsigned int total_len;
115 int first_vec = 0;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000116 unsigned int smb_buf_length = smb_buffer->smb_buf_length;
Steve Frenchedf1ae42008-10-29 00:47:57 +0000117 struct socket *ssocket = server->ssocket;
Steve French50c2f752007-07-13 00:33:32 +0000118
Steve French79a58d12007-07-06 22:44:50 +0000119 if (ssocket == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 return -ENOTSOCK; /* BB eventually add reconnect code here */
Steve French3e844692005-10-03 13:37:24 -0700121
Pavel Shilovskya9f1b852010-12-13 19:08:35 +0300122 smb_msg.msg_name = (struct sockaddr *) &server->dstaddr;
Steve French26f57362007-08-30 22:09:15 +0000123 smb_msg.msg_namelen = sizeof(struct sockaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 smb_msg.msg_control = NULL;
125 smb_msg.msg_controllen = 0;
Jeff Layton0496e022008-12-30 12:39:16 -0500126 if (server->noblocksnd)
Steve Frenchedf1ae42008-10-29 00:47:57 +0000127 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
128 else
129 smb_msg.msg_flags = MSG_NOSIGNAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131 /* smb header is converted in header_assemble. bcc and rest of SMB word
Steve French79a58d12007-07-06 22:44:50 +0000132 area, and byte area if necessary, is converted to littleendian in
133 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 Flags2 is converted in SendReceive */
135
Steve French3e844692005-10-03 13:37:24 -0700136
137 total_len = 0;
138 for (i = 0; i < n_vec; i++)
139 total_len += iov[i].iov_len;
140
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000142 cFYI(1, "Sending smb: total_len %d", total_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 dump_smb(smb_buffer, len);
144
Shirish Pargaonkar17680352008-07-29 21:26:13 +0000145 i = 0;
Steve French3e844692005-10-03 13:37:24 -0700146 while (total_len) {
147 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
148 n_vec - first_vec, total_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
150 i++;
Steve Frenchda505c32009-01-19 03:49:35 +0000151 /* if blocking send we try 3 times, since each can block
152 for 5 seconds. For nonblocking we have to try more
153 but wait increasing amounts of time allowing time for
154 socket to clear. The overall time we wait in either
155 case to send on the socket is about 15 seconds.
156 Similarly we wait for 15 seconds for
157 a response from the server in SendReceive[2]
158 for the server to send a response back for
159 most types of requests (except SMB Write
160 past end of file which can be slow, and
161 blocking lock operations). NFS waits slightly longer
162 than CIFS, but this can make it take longer for
163 nonresponsive servers to be detected and 15 seconds
164 is more than enough time for modern networks to
165 send a packet. In most cases if we fail to send
166 after the retries we will kill the socket and
167 reconnect which may clear the network problem.
168 */
169 if ((i >= 14) || (!server->noblocksnd && (i > 2))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000170 cERROR(1, "sends on sock %p stuck for 15 seconds",
171 ssocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 rc = -EAGAIN;
173 break;
174 }
Steve French68058e72005-10-10 10:34:22 -0700175 msleep(1 << i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 continue;
177 }
Steve French79a58d12007-07-06 22:44:50 +0000178 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 break;
Steve French3e844692005-10-03 13:37:24 -0700180
Steve French61de8002008-10-30 20:15:22 +0000181 if (rc == total_len) {
182 total_len = 0;
183 break;
184 } else if (rc > total_len) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000185 cERROR(1, "sent %d requested %d", rc, total_len);
Steve French3e844692005-10-03 13:37:24 -0700186 break;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500187 }
Steve French79a58d12007-07-06 22:44:50 +0000188 if (rc == 0) {
Steve French3e844692005-10-03 13:37:24 -0700189 /* should never happen, letting socket clear before
190 retrying is our only obvious option here */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000191 cERROR(1, "tcp sent no data");
Steve French3e844692005-10-03 13:37:24 -0700192 msleep(500);
193 continue;
194 }
195 total_len -= rc;
Steve French68058e72005-10-10 10:34:22 -0700196 /* the line below resets i */
Steve French3e844692005-10-03 13:37:24 -0700197 for (i = first_vec; i < n_vec; i++) {
198 if (iov[i].iov_len) {
199 if (rc > iov[i].iov_len) {
200 rc -= iov[i].iov_len;
201 iov[i].iov_len = 0;
202 } else {
203 iov[i].iov_base += rc;
204 iov[i].iov_len -= rc;
205 first_vec = i;
206 break;
207 }
208 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500209 }
Steve French5e1253b2005-10-10 14:06:37 -0700210 i = 0; /* in case we get ENOSPC on the next send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 }
212
Steve Frenchedf1ae42008-10-29 00:47:57 +0000213 if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000214 cFYI(1, "partial send (%d remaining), terminating session",
215 total_len);
Steve Frenchedf1ae42008-10-29 00:47:57 +0000216 /* If we have only sent part of an SMB then the next SMB
217 could be taken as the remainder of this one. We need
218 to kill the socket so the server throws away the partial
219 SMB */
220 server->tcpStatus = CifsNeedReconnect;
221 }
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 if (rc < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000224 cERROR(1, "Error %d sending data on socket to server", rc);
Steve French3e844692005-10-03 13:37:24 -0700225 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000228 /* Don't want to modify the buffer as a
229 side effect of this call. */
230 smb_buffer->smb_buf_length = smb_buf_length;
231
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 return rc;
233}
234
Jeff Layton0496e022008-12-30 12:39:16 -0500235int
236smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
237 unsigned int smb_buf_length)
238{
239 struct kvec iov;
240
241 iov.iov_base = smb_buffer;
242 iov.iov_len = smb_buf_length + 4;
243
244 return smb_sendv(server, &iov, 1);
245}
246
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000247static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
248{
Steve French133672e2007-11-13 22:41:37 +0000249 if (long_op == CIFS_ASYNC_OP) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000250 /* oplock breaks must not be held up */
251 atomic_inc(&ses->server->inFlight);
Volker Lendecke27a97a62008-12-08 20:59:39 +0000252 return 0;
253 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000254
Volker Lendecke27a97a62008-12-08 20:59:39 +0000255 spin_lock(&GlobalMid_Lock);
256 while (1) {
257 if (atomic_read(&ses->server->inFlight) >=
258 cifs_max_pending){
259 spin_unlock(&GlobalMid_Lock);
260#ifdef CONFIG_CIFS_STATS2
261 atomic_inc(&ses->server->num_waiters);
262#endif
263 wait_event(ses->server->request_q,
264 atomic_read(&ses->server->inFlight)
265 < cifs_max_pending);
266#ifdef CONFIG_CIFS_STATS2
267 atomic_dec(&ses->server->num_waiters);
268#endif
269 spin_lock(&GlobalMid_Lock);
270 } else {
271 if (ses->server->tcpStatus == CifsExiting) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000272 spin_unlock(&GlobalMid_Lock);
Volker Lendecke27a97a62008-12-08 20:59:39 +0000273 return -ENOENT;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000274 }
Volker Lendecke27a97a62008-12-08 20:59:39 +0000275
276 /* can not count locking commands against total
277 as they are allowed to block on server */
278
279 /* update # of requests on the wire to server */
280 if (long_op != CIFS_BLOCKING_OP)
281 atomic_inc(&ses->server->inFlight);
282 spin_unlock(&GlobalMid_Lock);
283 break;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000284 }
285 }
286 return 0;
287}
288
289static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
290 struct mid_q_entry **ppmidQ)
291{
292 if (ses->server->tcpStatus == CifsExiting) {
293 return -ENOENT;
Volker Lendecke8fbbd362008-12-06 13:12:34 +0100294 }
295
296 if (ses->server->tcpStatus == CifsNeedReconnect) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000297 cFYI(1, "tcp session dead - return to caller to retry");
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000298 return -EAGAIN;
Volker Lendecke8fbbd362008-12-06 13:12:34 +0100299 }
300
301 if (ses->status != CifsGood) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000302 /* check if SMB session is bad because we are setting it up */
Steve French79a58d12007-07-06 22:44:50 +0000303 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
Steve Frenchad7a2922008-02-07 23:25:02 +0000304 (in_buf->Command != SMB_COM_NEGOTIATE))
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000305 return -EAGAIN;
Steve Frenchad7a2922008-02-07 23:25:02 +0000306 /* else ok - we are setting up session */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000307 }
Jeff Layton24b9b062008-12-01 07:09:34 -0500308 *ppmidQ = AllocMidQEntry(in_buf, ses->server);
Steve French26f57362007-08-30 22:09:15 +0000309 if (*ppmidQ == NULL)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000310 return -ENOMEM;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000311 return 0;
312}
313
Steve French79a58d12007-07-06 22:44:50 +0000314static int wait_for_response(struct cifsSesInfo *ses,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000315 struct mid_q_entry *midQ,
316 unsigned long timeout,
317 unsigned long time_to_wait)
318{
319 unsigned long curr_timeout;
320
321 for (;;) {
322 curr_timeout = timeout + jiffies;
Jeff Layton85705522008-12-05 20:41:21 -0500323 wait_event_timeout(ses->server->response_q,
324 midQ->midState != MID_REQUEST_SUBMITTED, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000325
326 if (time_after(jiffies, curr_timeout) &&
327 (midQ->midState == MID_REQUEST_SUBMITTED) &&
328 ((ses->server->tcpStatus == CifsGood) ||
329 (ses->server->tcpStatus == CifsNew))) {
330
331 unsigned long lrt;
332
333 /* We timed out. Is the server still
334 sending replies ? */
335 spin_lock(&GlobalMid_Lock);
336 lrt = ses->server->lstrp;
337 spin_unlock(&GlobalMid_Lock);
338
339 /* Calculate time_to_wait past last receive time.
Steve French79a58d12007-07-06 22:44:50 +0000340 Although we prefer not to time out if the
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000341 server is still responding - we will time
Steve French79a58d12007-07-06 22:44:50 +0000342 out if the server takes more than 15 (or 45
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000343 or 180) seconds to respond to this request
Steve French79a58d12007-07-06 22:44:50 +0000344 and has not responded to any request from
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000345 other threads on the client within 10 seconds */
346 lrt += time_to_wait;
347 if (time_after(jiffies, lrt)) {
348 /* No replies for time_to_wait. */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000349 cERROR(1, "server not responding");
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000350 return -1;
351 }
352 } else {
353 return 0;
354 }
355 }
356}
357
Steve French133672e2007-11-13 22:41:37 +0000358
359/*
360 *
361 * Send an SMB Request. No response info (other than return code)
362 * needs to be parsed.
363 *
364 * flags indicate the type of request buffer and how long to wait
365 * and whether to log NT STATUS code (error) before mapping it to POSIX error
366 *
367 */
368int
369SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
370 struct smb_hdr *in_buf, int flags)
371{
372 int rc;
373 struct kvec iov[1];
374 int resp_buf_type;
375
376 iov[0].iov_base = (char *)in_buf;
377 iov[0].iov_len = in_buf->smb_buf_length + 4;
378 flags |= CIFS_NO_RESP;
379 rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000380 cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc);
Steve French90c81e02008-02-12 20:32:36 +0000381
Steve French133672e2007-11-13 22:41:37 +0000382 return rc;
383}
384
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385int
Steve French79a58d12007-07-06 22:44:50 +0000386SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
387 struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
Steve French133672e2007-11-13 22:41:37 +0000388 const int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389{
390 int rc = 0;
Steve French133672e2007-11-13 22:41:37 +0000391 int long_op;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500392 unsigned int receive_len;
393 unsigned long timeout;
394 struct mid_q_entry *midQ;
Steve French3e844692005-10-03 13:37:24 -0700395 struct smb_hdr *in_buf = iov[0].iov_base;
Steve French50c2f752007-07-13 00:33:32 +0000396
Steve French133672e2007-11-13 22:41:37 +0000397 long_op = flags & CIFS_TIMEOUT_MASK;
398
Steve Frenchec637e32005-12-12 20:53:18 -0800399 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
Steve French4b8f9302006-02-26 16:41:18 +0000401 if ((ses == NULL) || (ses->server == NULL)) {
402 cifs_small_buf_release(in_buf);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000403 cERROR(1, "Null session");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 return -EIO;
405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Steve French79a58d12007-07-06 22:44:50 +0000407 if (ses->server->tcpStatus == CifsExiting) {
Steve French4b8f9302006-02-26 16:41:18 +0000408 cifs_small_buf_release(in_buf);
Steve French31ca3bc2005-04-28 22:41:11 -0700409 return -ENOENT;
Steve French4b8f9302006-02-26 16:41:18 +0000410 }
Steve French31ca3bc2005-04-28 22:41:11 -0700411
Steve French79a58d12007-07-06 22:44:50 +0000412 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 to the same server. We may make this configurable later or
414 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000416 rc = wait_for_free_request(ses, long_op);
417 if (rc) {
418 cifs_small_buf_release(in_buf);
419 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000421
Steve French79a58d12007-07-06 22:44:50 +0000422 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 and avoid races inside tcp sendmsg code that could cause corruption
424 of smb data */
425
Jeff Layton72ca5452008-12-01 07:09:36 -0500426 mutex_lock(&ses->server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000428 rc = allocate_mid(ses, in_buf, &midQ);
429 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500430 mutex_unlock(&ses->server->srv_mutex);
Steve French4b8f9302006-02-26 16:41:18 +0000431 cifs_small_buf_release(in_buf);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000432 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000433 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000434 wake_up(&ses->server->request_q);
435 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 }
Steve French79a58d12007-07-06 22:44:50 +0000437 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100438 if (rc) {
439 mutex_unlock(&ses->server->srv_mutex);
440 cifs_small_buf_release(in_buf);
441 goto out;
442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
444 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700445#ifdef CONFIG_CIFS_STATS2
446 atomic_inc(&ses->server->inSend);
447#endif
Jeff Layton0496e022008-12-30 12:39:16 -0500448 rc = smb_sendv(ses->server, iov, n_vec);
Steve French131afd0b2005-10-07 09:51:05 -0700449#ifdef CONFIG_CIFS_STATS2
450 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700451 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700452#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000453
Jeff Layton72ca5452008-12-01 07:09:36 -0500454 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000455 cifs_small_buf_release(in_buf);
456
Steve French79a58d12007-07-06 22:44:50 +0000457 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000458 goto out;
Steve French4b8f9302006-02-26 16:41:18 +0000459
Steve French133672e2007-11-13 22:41:37 +0000460 if (long_op == CIFS_STD_OP)
461 timeout = 15 * HZ;
462 else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
Steve French37c0eb42005-10-05 14:50:29 -0700463 timeout = 180 * HZ;
Steve French133672e2007-11-13 22:41:37 +0000464 else if (long_op == CIFS_LONG_OP)
Steve French79a58d12007-07-06 22:44:50 +0000465 timeout = 45 * HZ; /* should be greater than
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500466 servers oplock break timeout (about 43 seconds) */
Steve French133672e2007-11-13 22:41:37 +0000467 else if (long_op == CIFS_ASYNC_OP)
468 goto out;
469 else if (long_op == CIFS_BLOCKING_OP)
470 timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */
471 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000472 cERROR(1, "unknown timeout flag %d", long_op);
Steve French133672e2007-11-13 22:41:37 +0000473 rc = -EIO;
474 goto out;
475 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000476
Steve French79a58d12007-07-06 22:44:50 +0000477 /* wait for 15 seconds or until woken up due to response arriving or
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500478 due to last connection to this server being unmounted */
479 if (signal_pending(current)) {
480 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000481 but we still give response a chance to complete */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500482 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000483 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500484
485 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000486 wait_for_response(ses, midQ, timeout, 10 * HZ);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500487
488 spin_lock(&GlobalMid_Lock);
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100489
490 if (midQ->resp_buf == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000491 cERROR(1, "No response to cmd %d mid %d",
492 midQ->command, midQ->mid);
Steve French79a58d12007-07-06 22:44:50 +0000493 if (midQ->midState == MID_REQUEST_SUBMITTED) {
494 if (ses->server->tcpStatus == CifsExiting)
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500495 rc = -EHOSTDOWN;
496 else {
497 ses->server->tcpStatus = CifsNeedReconnect;
498 midQ->midState = MID_RETRY_NEEDED;
499 }
500 }
501
502 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000503 if (midQ->midState == MID_RETRY_NEEDED) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500504 rc = -EAGAIN;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000505 cFYI(1, "marking request for retry");
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500506 } else {
507 rc = -EIO;
508 }
509 }
510 spin_unlock(&GlobalMid_Lock);
511 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000512 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000513 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000514 wake_up(&ses->server->request_q);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500515 return rc;
516 }
Steve French50c2f752007-07-13 00:33:32 +0000517
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100518 spin_unlock(&GlobalMid_Lock);
519 receive_len = midQ->resp_buf->smb_buf_length;
520
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500521 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000522 cERROR(1, "Frame too large received. Length: %d Xid: %d",
523 receive_len, xid);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500524 rc = -EIO;
Steve French2b2bdfb2008-12-11 17:26:54 +0000525 goto out;
526 }
Steve French84afc292005-12-02 13:32:45 -0800527
Steve French2b2bdfb2008-12-11 17:26:54 +0000528 /* rcvd frame is ok */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500529
Steve French2b2bdfb2008-12-11 17:26:54 +0000530 if (midQ->resp_buf &&
531 (midQ->midState == MID_RESPONSE_RECEIVED)) {
532
533 iov[0].iov_base = (char *)midQ->resp_buf;
534 if (midQ->largeBuf)
535 *pRespBufType = CIFS_LARGE_BUFFER;
536 else
537 *pRespBufType = CIFS_SMALL_BUFFER;
538 iov[0].iov_len = receive_len + 4;
539
540 dump_smb(midQ->resp_buf, 80);
541 /* convert the length into a more usable form */
542 if ((receive_len > 24) &&
543 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
544 SECMODE_SIGN_ENABLED))) {
545 rc = cifs_verify_signature(midQ->resp_buf,
Shirish Pargaonkar21e73392010-10-21 06:42:55 -0500546 ses->server,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500547 midQ->sequence_number+1);
Steve French2b2bdfb2008-12-11 17:26:54 +0000548 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000549 cERROR(1, "Unexpected SMB signature");
Steve French2b2bdfb2008-12-11 17:26:54 +0000550 /* BB FIXME add code to kill session */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500551 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500552 }
Steve French2b2bdfb2008-12-11 17:26:54 +0000553
554 /* BB special case reconnect tid and uid here? */
555 rc = map_smb_to_linux_error(midQ->resp_buf,
556 flags & CIFS_LOG_ERROR);
557
558 /* convert ByteCount if necessary */
559 if (receive_len >= sizeof(struct smb_hdr) - 4
560 /* do not count RFC1001 header */ +
561 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
562 BCC(midQ->resp_buf) =
563 le16_to_cpu(BCC_LE(midQ->resp_buf));
564 if ((flags & CIFS_NO_RESP) == 0)
565 midQ->resp_buf = NULL; /* mark it so buf will
566 not be freed by
567 DeleteMidQEntry */
568 } else {
569 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000570 cFYI(1, "Bad MID state?");
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500571 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000572
573out:
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500574 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000575 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000576 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
578 return rc;
579}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
581int
582SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
583 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
584 int *pbytes_returned, const int long_op)
585{
586 int rc = 0;
587 unsigned int receive_len;
588 unsigned long timeout;
589 struct mid_q_entry *midQ;
590
591 if (ses == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000592 cERROR(1, "Null smb session");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 return -EIO;
594 }
Steve French79a58d12007-07-06 22:44:50 +0000595 if (ses->server == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000596 cERROR(1, "Null tcp session");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 return -EIO;
598 }
599
Steve French79a58d12007-07-06 22:44:50 +0000600 if (ses->server->tcpStatus == CifsExiting)
Steve French31ca3bc2005-04-28 22:41:11 -0700601 return -ENOENT;
602
Steve French79a58d12007-07-06 22:44:50 +0000603 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 to the same server. We may make this configurable later or
605 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000607 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000608 cERROR(1, "Illegal length, greater than maximum frame, %d",
609 in_buf->smb_buf_length);
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000610 return -EIO;
611 }
612
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000613 rc = wait_for_free_request(ses, long_op);
614 if (rc)
615 return rc;
616
Steve French79a58d12007-07-06 22:44:50 +0000617 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 and avoid races inside tcp sendmsg code that could cause corruption
619 of smb data */
620
Jeff Layton72ca5452008-12-01 07:09:36 -0500621 mutex_lock(&ses->server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000623 rc = allocate_mid(ses, in_buf, &midQ);
624 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500625 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000626 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000627 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000628 wake_up(&ses->server->request_q);
629 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 }
631
Steve Frenchad009ac2005-04-28 22:41:05 -0700632 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100633 if (rc) {
634 mutex_unlock(&ses->server->srv_mutex);
635 goto out;
636 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
638 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700639#ifdef CONFIG_CIFS_STATS2
640 atomic_inc(&ses->server->inSend);
641#endif
Jeff Layton0496e022008-12-30 12:39:16 -0500642 rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
Steve French131afd0b2005-10-07 09:51:05 -0700643#ifdef CONFIG_CIFS_STATS2
644 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700645 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700646#endif
Jeff Layton72ca5452008-12-01 07:09:36 -0500647 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000648
Steve French79a58d12007-07-06 22:44:50 +0000649 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000650 goto out;
651
Steve French133672e2007-11-13 22:41:37 +0000652 if (long_op == CIFS_STD_OP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 timeout = 15 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000654 /* wait for 15 seconds or until woken up due to response arriving or
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 due to last connection to this server being unmounted */
Steve French133672e2007-11-13 22:41:37 +0000656 else if (long_op == CIFS_ASYNC_OP)
657 goto out;
658 else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
659 timeout = 180 * HZ;
660 else if (long_op == CIFS_LONG_OP)
661 timeout = 45 * HZ; /* should be greater than
662 servers oplock break timeout (about 43 seconds) */
663 else if (long_op == CIFS_BLOCKING_OP)
664 timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
665 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000666 cERROR(1, "unknown timeout flag %d", long_op);
Steve French133672e2007-11-13 22:41:37 +0000667 rc = -EIO;
668 goto out;
669 }
670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 if (signal_pending(current)) {
672 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000673 but we still give response a chance to complete */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000675 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
677 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000678 wait_for_response(ses, midQ, timeout, 10 * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
680 spin_lock(&GlobalMid_Lock);
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100681 if (midQ->resp_buf == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000682 cERROR(1, "No response for cmd %d mid %d",
683 midQ->command, midQ->mid);
Steve French79a58d12007-07-06 22:44:50 +0000684 if (midQ->midState == MID_REQUEST_SUBMITTED) {
685 if (ses->server->tcpStatus == CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 rc = -EHOSTDOWN;
687 else {
688 ses->server->tcpStatus = CifsNeedReconnect;
689 midQ->midState = MID_RETRY_NEEDED;
690 }
691 }
692
693 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000694 if (midQ->midState == MID_RETRY_NEEDED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 rc = -EAGAIN;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000696 cFYI(1, "marking request for retry");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 } else {
698 rc = -EIO;
699 }
700 }
701 spin_unlock(&GlobalMid_Lock);
702 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000703 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000704 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000705 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 return rc;
707 }
Steve French50c2f752007-07-13 00:33:32 +0000708
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100709 spin_unlock(&GlobalMid_Lock);
710 receive_len = midQ->resp_buf->smb_buf_length;
711
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000713 cERROR(1, "Frame too large received. Length: %d Xid: %d",
714 receive_len, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 rc = -EIO;
Steve French2b2bdfb2008-12-11 17:26:54 +0000716 goto out;
717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
Steve French2b2bdfb2008-12-11 17:26:54 +0000719 /* rcvd frame is ok */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
Steve French2b2bdfb2008-12-11 17:26:54 +0000721 if (midQ->resp_buf && out_buf
722 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
723 out_buf->smb_buf_length = receive_len;
724 memcpy((char *)out_buf + 4,
725 (char *)midQ->resp_buf + 4,
726 receive_len);
727
728 dump_smb(out_buf, 92);
729 /* convert the length into a more usable form */
730 if ((receive_len > 24) &&
731 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
732 SECMODE_SIGN_ENABLED))) {
733 rc = cifs_verify_signature(out_buf,
Shirish Pargaonkar21e73392010-10-21 06:42:55 -0500734 ses->server,
Steve Frenchad009ac2005-04-28 22:41:05 -0700735 midQ->sequence_number+1);
Steve French2b2bdfb2008-12-11 17:26:54 +0000736 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000737 cERROR(1, "Unexpected SMB signature");
Steve French2b2bdfb2008-12-11 17:26:54 +0000738 /* BB FIXME add code to kill session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 }
Steve French2b2bdfb2008-12-11 17:26:54 +0000741
742 *pbytes_returned = out_buf->smb_buf_length;
743
744 /* BB special case reconnect tid and uid here? */
745 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
746
747 /* convert ByteCount if necessary */
748 if (receive_len >= sizeof(struct smb_hdr) - 4
749 /* do not count RFC1001 header */ +
750 (2 * out_buf->WordCount) + 2 /* bcc */ )
751 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
752 } else {
753 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000754 cERROR(1, "Bad MID state?");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000757out:
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000758 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000759 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000760 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
762 return rc;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000763}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000765/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
766
767static int
768send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
769 struct mid_q_entry *midQ)
770{
771 int rc = 0;
772 struct cifsSesInfo *ses = tcon->ses;
773 __u16 mid = in_buf->Mid;
774
775 header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
776 in_buf->Mid = mid;
Jeff Layton72ca5452008-12-01 07:09:36 -0500777 mutex_lock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000778 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
779 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500780 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000781 return rc;
782 }
Jeff Layton0496e022008-12-30 12:39:16 -0500783 rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
Jeff Layton72ca5452008-12-01 07:09:36 -0500784 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000785 return rc;
786}
787
788/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
789 blocking lock to return. */
790
791static int
792send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
793 struct smb_hdr *in_buf,
794 struct smb_hdr *out_buf)
795{
796 int bytes_returned;
797 struct cifsSesInfo *ses = tcon->ses;
798 LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
799
800 /* We just modify the current in_buf to change
801 the type of lock from LOCKING_ANDX_SHARED_LOCK
802 or LOCKING_ANDX_EXCLUSIVE_LOCK to
803 LOCKING_ANDX_CANCEL_LOCK. */
804
805 pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
806 pSMB->Timeout = 0;
807 pSMB->hdr.Mid = GetNextMid(ses->server);
808
809 return SendReceive(xid, ses, in_buf, out_buf,
Steve French133672e2007-11-13 22:41:37 +0000810 &bytes_returned, CIFS_STD_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000811}
812
813int
814SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
815 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
816 int *pbytes_returned)
817{
818 int rc = 0;
819 int rstart = 0;
820 unsigned int receive_len;
821 struct mid_q_entry *midQ;
822 struct cifsSesInfo *ses;
823
824 if (tcon == NULL || tcon->ses == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000825 cERROR(1, "Null smb session");
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000826 return -EIO;
827 }
828 ses = tcon->ses;
829
Steve French79a58d12007-07-06 22:44:50 +0000830 if (ses->server == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000831 cERROR(1, "Null tcp session");
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000832 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 }
834
Steve French79a58d12007-07-06 22:44:50 +0000835 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000836 return -ENOENT;
837
Steve French79a58d12007-07-06 22:44:50 +0000838 /* Ensure that we do not send more than 50 overlapping requests
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000839 to the same server. We may make this configurable later or
840 use ses->maxReq */
841
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000842 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000843 cERROR(1, "Illegal length, greater than maximum frame, %d",
844 in_buf->smb_buf_length);
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000845 return -EIO;
846 }
847
Steve French133672e2007-11-13 22:41:37 +0000848 rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000849 if (rc)
850 return rc;
851
Steve French79a58d12007-07-06 22:44:50 +0000852 /* make sure that we sign in the same order that we send on this socket
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000853 and avoid races inside tcp sendmsg code that could cause corruption
854 of smb data */
855
Jeff Layton72ca5452008-12-01 07:09:36 -0500856 mutex_lock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000857
858 rc = allocate_mid(ses, in_buf, &midQ);
859 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500860 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000861 return rc;
862 }
863
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000864 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100865 if (rc) {
866 DeleteMidQEntry(midQ);
867 mutex_unlock(&ses->server->srv_mutex);
868 return rc;
869 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000870
871 midQ->midState = MID_REQUEST_SUBMITTED;
872#ifdef CONFIG_CIFS_STATS2
873 atomic_inc(&ses->server->inSend);
874#endif
Jeff Layton0496e022008-12-30 12:39:16 -0500875 rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000876#ifdef CONFIG_CIFS_STATS2
877 atomic_dec(&ses->server->inSend);
878 midQ->when_sent = jiffies;
879#endif
Jeff Layton72ca5452008-12-01 07:09:36 -0500880 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000881
Steve French79a58d12007-07-06 22:44:50 +0000882 if (rc < 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000883 DeleteMidQEntry(midQ);
884 return rc;
885 }
886
887 /* Wait for a reply - allow signals to interrupt. */
888 rc = wait_event_interruptible(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000889 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000890 ((ses->server->tcpStatus != CifsGood) &&
891 (ses->server->tcpStatus != CifsNew)));
892
893 /* Were we interrupted by a signal ? */
894 if ((rc == -ERESTARTSYS) &&
895 (midQ->midState == MID_REQUEST_SUBMITTED) &&
896 ((ses->server->tcpStatus == CifsGood) ||
897 (ses->server->tcpStatus == CifsNew))) {
898
899 if (in_buf->Command == SMB_COM_TRANSACTION2) {
900 /* POSIX lock. We send a NT_CANCEL SMB to cause the
901 blocking lock to return. */
902
903 rc = send_nt_cancel(tcon, in_buf, midQ);
904 if (rc) {
905 DeleteMidQEntry(midQ);
906 return rc;
907 }
908 } else {
909 /* Windows lock. We send a LOCKINGX_CANCEL_LOCK
910 to cause the blocking lock to return. */
911
912 rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
913
914 /* If we get -ENOLCK back the lock may have
915 already been removed. Don't exit in this case. */
916 if (rc && rc != -ENOLCK) {
917 DeleteMidQEntry(midQ);
918 return rc;
919 }
920 }
921
922 /* Wait 5 seconds for the response. */
Steve French79a58d12007-07-06 22:44:50 +0000923 if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000924 /* We got the response - restart system call. */
925 rstart = 1;
926 }
927 }
928
929 spin_lock(&GlobalMid_Lock);
930 if (midQ->resp_buf) {
931 spin_unlock(&GlobalMid_Lock);
932 receive_len = midQ->resp_buf->smb_buf_length;
933 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000934 cERROR(1, "No response for cmd %d mid %d",
935 midQ->command, midQ->mid);
Steve French79a58d12007-07-06 22:44:50 +0000936 if (midQ->midState == MID_REQUEST_SUBMITTED) {
937 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000938 rc = -EHOSTDOWN;
939 else {
940 ses->server->tcpStatus = CifsNeedReconnect;
941 midQ->midState = MID_RETRY_NEEDED;
942 }
943 }
944
945 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000946 if (midQ->midState == MID_RETRY_NEEDED) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000947 rc = -EAGAIN;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000948 cFYI(1, "marking request for retry");
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000949 } else {
950 rc = -EIO;
951 }
952 }
953 spin_unlock(&GlobalMid_Lock);
954 DeleteMidQEntry(midQ);
955 return rc;
956 }
Steve French50c2f752007-07-13 00:33:32 +0000957
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000958 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000959 cERROR(1, "Frame too large received. Length: %d Xid: %d",
960 receive_len, xid);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000961 rc = -EIO;
Volker Lendecke17c8bfe2008-12-06 16:38:19 +0100962 goto out;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000963 }
Volker Lendecke17c8bfe2008-12-06 16:38:19 +0100964
965 /* rcvd frame is ok */
966
Volker Lendeckeac6a3ef2008-12-06 16:40:40 +0100967 if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) {
Volker Lendecke17c8bfe2008-12-06 16:38:19 +0100968 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000969 cERROR(1, "Bad MID state?");
Volker Lendecke698e96a2008-12-06 16:39:31 +0100970 goto out;
Volker Lendecke17c8bfe2008-12-06 16:38:19 +0100971 }
972
Volker Lendecke698e96a2008-12-06 16:39:31 +0100973 out_buf->smb_buf_length = receive_len;
974 memcpy((char *)out_buf + 4,
975 (char *)midQ->resp_buf + 4,
976 receive_len);
977
978 dump_smb(out_buf, 92);
979 /* convert the length into a more usable form */
980 if ((receive_len > 24) &&
981 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
982 SECMODE_SIGN_ENABLED))) {
983 rc = cifs_verify_signature(out_buf,
Shirish Pargaonkar21e73392010-10-21 06:42:55 -0500984 ses->server,
Volker Lendecke698e96a2008-12-06 16:39:31 +0100985 midQ->sequence_number+1);
986 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000987 cERROR(1, "Unexpected SMB signature");
Volker Lendecke698e96a2008-12-06 16:39:31 +0100988 /* BB FIXME add code to kill session */
989 }
990 }
991
992 *pbytes_returned = out_buf->smb_buf_length;
993
994 /* BB special case reconnect tid and uid here? */
995 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
996
997 /* convert ByteCount if necessary */
998 if (receive_len >= sizeof(struct smb_hdr) - 4
999 /* do not count RFC1001 header */ +
1000 (2 * out_buf->WordCount) + 2 /* bcc */ )
1001 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1002
Volker Lendecke17c8bfe2008-12-06 16:38:19 +01001003out:
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001004 DeleteMidQEntry(midQ);
1005 if (rstart && rc == -EACCES)
1006 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 return rc;
1008}