blob: 1da4ab250eae327a5e9a8889b9e498b4bc4946eb [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>
25#include <linux/wait.h>
26#include <linux/net.h>
27#include <linux/delay.h>
28#include <asm/uaccess.h>
29#include <asm/processor.h>
30#include <linux/mempool.h>
31#include "cifspdu.h"
32#include "cifsglob.h"
33#include "cifsproto.h"
34#include "cifs_debug.h"
Steve French50c2f752007-07-13 00:33:32 +000035
Linus Torvalds1da177e2005-04-16 15:20:36 -070036extern mempool_t *cifs_mid_poolp;
Christoph Lametere18b8902006-12-06 20:33:20 -080037extern struct kmem_cache *cifs_oplock_cachep;
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) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 cERROR(1, ("Null TCP session in AllocMidQEntry"));
46 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;
57 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
106struct oplock_q_entry *
Steve French79a58d12007-07-06 22:44:50 +0000107AllocOplockQEntry(struct inode *pinode, __u16 fid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108{
109 struct oplock_q_entry *temp;
Steve French79a58d12007-07-06 22:44:50 +0000110 if ((pinode == NULL) || (tcon == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 cERROR(1, ("Null parms passed to AllocOplockQEntry"));
112 return NULL;
113 }
114 temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
Christoph Lametere94b1762006-12-06 20:33:17 -0800115 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 if (temp == NULL)
117 return temp;
118 else {
119 temp->pinode = pinode;
120 temp->tcon = tcon;
121 temp->netfid = fid;
Jeff Layton1b49c552009-08-28 10:11:11 -0400122 spin_lock(&cifs_oplock_lock);
123 list_add_tail(&temp->qhead, &cifs_oplock_list);
124 spin_unlock(&cifs_oplock_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 }
126 return temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127}
128
Steve French79a58d12007-07-06 22:44:50 +0000129void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130{
Jeff Layton1b49c552009-08-28 10:11:11 -0400131 spin_lock(&cifs_oplock_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 /* should we check if list empty first? */
133 list_del(&oplockEntry->qhead);
Jeff Layton1b49c552009-08-28 10:11:11 -0400134 spin_unlock(&cifs_oplock_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 kmem_cache_free(cifs_oplock_cachep, oplockEntry);
136}
137
Steve French5d941ca2008-04-15 18:40:48 +0000138
139void DeleteTconOplockQEntries(struct cifsTconInfo *tcon)
140{
141 struct oplock_q_entry *temp;
142
143 if (tcon == NULL)
144 return;
145
Jeff Layton1b49c552009-08-28 10:11:11 -0400146 spin_lock(&cifs_oplock_lock);
147 list_for_each_entry(temp, &cifs_oplock_list, qhead) {
Steve French5d941ca2008-04-15 18:40:48 +0000148 if ((temp->tcon) && (temp->tcon == tcon)) {
149 list_del(&temp->qhead);
150 kmem_cache_free(cifs_oplock_cachep, temp);
151 }
152 }
Jeff Layton1b49c552009-08-28 10:11:11 -0400153 spin_unlock(&cifs_oplock_lock);
Steve French5d941ca2008-04-15 18:40:48 +0000154}
155
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500156static int
Jeff Layton0496e022008-12-30 12:39:16 -0500157smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158{
159 int rc = 0;
160 int i = 0;
161 struct msghdr smb_msg;
Steve French3e844692005-10-03 13:37:24 -0700162 struct smb_hdr *smb_buffer = iov[0].iov_base;
163 unsigned int len = iov[0].iov_len;
164 unsigned int total_len;
165 int first_vec = 0;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000166 unsigned int smb_buf_length = smb_buffer->smb_buf_length;
Steve Frenchedf1ae42008-10-29 00:47:57 +0000167 struct socket *ssocket = server->ssocket;
Steve French50c2f752007-07-13 00:33:32 +0000168
Steve French79a58d12007-07-06 22:44:50 +0000169 if (ssocket == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 return -ENOTSOCK; /* BB eventually add reconnect code here */
Steve French3e844692005-10-03 13:37:24 -0700171
Jeff Layton0496e022008-12-30 12:39:16 -0500172 smb_msg.msg_name = (struct sockaddr *) &server->addr.sockAddr;
Steve French26f57362007-08-30 22:09:15 +0000173 smb_msg.msg_namelen = sizeof(struct sockaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 smb_msg.msg_control = NULL;
175 smb_msg.msg_controllen = 0;
Jeff Layton0496e022008-12-30 12:39:16 -0500176 if (server->noblocksnd)
Steve Frenchedf1ae42008-10-29 00:47:57 +0000177 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
178 else
179 smb_msg.msg_flags = MSG_NOSIGNAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
181 /* smb header is converted in header_assemble. bcc and rest of SMB word
Steve French79a58d12007-07-06 22:44:50 +0000182 area, and byte area if necessary, is converted to littleendian in
183 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 Flags2 is converted in SendReceive */
185
Steve French3e844692005-10-03 13:37:24 -0700186
187 total_len = 0;
188 for (i = 0; i < n_vec; i++)
189 total_len += iov[i].iov_len;
190
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Steve French3e844692005-10-03 13:37:24 -0700192 cFYI(1, ("Sending smb: total_len %d", total_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 dump_smb(smb_buffer, len);
194
Shirish Pargaonkar17680352008-07-29 21:26:13 +0000195 i = 0;
Steve French3e844692005-10-03 13:37:24 -0700196 while (total_len) {
197 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
198 n_vec - first_vec, total_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
200 i++;
Steve Frenchda505c32009-01-19 03:49:35 +0000201 /* if blocking send we try 3 times, since each can block
202 for 5 seconds. For nonblocking we have to try more
203 but wait increasing amounts of time allowing time for
204 socket to clear. The overall time we wait in either
205 case to send on the socket is about 15 seconds.
206 Similarly we wait for 15 seconds for
207 a response from the server in SendReceive[2]
208 for the server to send a response back for
209 most types of requests (except SMB Write
210 past end of file which can be slow, and
211 blocking lock operations). NFS waits slightly longer
212 than CIFS, but this can make it take longer for
213 nonresponsive servers to be detected and 15 seconds
214 is more than enough time for modern networks to
215 send a packet. In most cases if we fail to send
216 after the retries we will kill the socket and
217 reconnect which may clear the network problem.
218 */
219 if ((i >= 14) || (!server->noblocksnd && (i > 2))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 cERROR(1,
Steve French68058e72005-10-10 10:34:22 -0700221 ("sends on sock %p stuck for 15 seconds",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 ssocket));
223 rc = -EAGAIN;
224 break;
225 }
Steve French68058e72005-10-10 10:34:22 -0700226 msleep(1 << i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 continue;
228 }
Steve French79a58d12007-07-06 22:44:50 +0000229 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 break;
Steve French3e844692005-10-03 13:37:24 -0700231
Steve French61de8002008-10-30 20:15:22 +0000232 if (rc == total_len) {
233 total_len = 0;
234 break;
235 } else if (rc > total_len) {
236 cERROR(1, ("sent %d requested %d", rc, total_len));
Steve French3e844692005-10-03 13:37:24 -0700237 break;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500238 }
Steve French79a58d12007-07-06 22:44:50 +0000239 if (rc == 0) {
Steve French3e844692005-10-03 13:37:24 -0700240 /* should never happen, letting socket clear before
241 retrying is our only obvious option here */
Steve French79a58d12007-07-06 22:44:50 +0000242 cERROR(1, ("tcp sent no data"));
Steve French3e844692005-10-03 13:37:24 -0700243 msleep(500);
244 continue;
245 }
246 total_len -= rc;
Steve French68058e72005-10-10 10:34:22 -0700247 /* the line below resets i */
Steve French3e844692005-10-03 13:37:24 -0700248 for (i = first_vec; i < n_vec; i++) {
249 if (iov[i].iov_len) {
250 if (rc > iov[i].iov_len) {
251 rc -= iov[i].iov_len;
252 iov[i].iov_len = 0;
253 } else {
254 iov[i].iov_base += rc;
255 iov[i].iov_len -= rc;
256 first_vec = i;
257 break;
258 }
259 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500260 }
Steve French5e1253b2005-10-10 14:06:37 -0700261 i = 0; /* in case we get ENOSPC on the next send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 }
263
Steve Frenchedf1ae42008-10-29 00:47:57 +0000264 if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
265 cFYI(1, ("partial send (%d remaining), terminating session",
266 total_len));
267 /* If we have only sent part of an SMB then the next SMB
268 could be taken as the remainder of this one. We need
269 to kill the socket so the server throws away the partial
270 SMB */
271 server->tcpStatus = CifsNeedReconnect;
272 }
273
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 if (rc < 0) {
Steve French79a58d12007-07-06 22:44:50 +0000275 cERROR(1, ("Error %d sending data on socket to server", rc));
Steve French3e844692005-10-03 13:37:24 -0700276 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000279 /* Don't want to modify the buffer as a
280 side effect of this call. */
281 smb_buffer->smb_buf_length = smb_buf_length;
282
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 return rc;
284}
285
Jeff Layton0496e022008-12-30 12:39:16 -0500286int
287smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
288 unsigned int smb_buf_length)
289{
290 struct kvec iov;
291
292 iov.iov_base = smb_buffer;
293 iov.iov_len = smb_buf_length + 4;
294
295 return smb_sendv(server, &iov, 1);
296}
297
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000298static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
299{
Steve French133672e2007-11-13 22:41:37 +0000300 if (long_op == CIFS_ASYNC_OP) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000301 /* oplock breaks must not be held up */
302 atomic_inc(&ses->server->inFlight);
Volker Lendecke27a97a62008-12-08 20:59:39 +0000303 return 0;
304 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000305
Volker Lendecke27a97a62008-12-08 20:59:39 +0000306 spin_lock(&GlobalMid_Lock);
307 while (1) {
308 if (atomic_read(&ses->server->inFlight) >=
309 cifs_max_pending){
310 spin_unlock(&GlobalMid_Lock);
311#ifdef CONFIG_CIFS_STATS2
312 atomic_inc(&ses->server->num_waiters);
313#endif
314 wait_event(ses->server->request_q,
315 atomic_read(&ses->server->inFlight)
316 < cifs_max_pending);
317#ifdef CONFIG_CIFS_STATS2
318 atomic_dec(&ses->server->num_waiters);
319#endif
320 spin_lock(&GlobalMid_Lock);
321 } else {
322 if (ses->server->tcpStatus == CifsExiting) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000323 spin_unlock(&GlobalMid_Lock);
Volker Lendecke27a97a62008-12-08 20:59:39 +0000324 return -ENOENT;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000325 }
Volker Lendecke27a97a62008-12-08 20:59:39 +0000326
327 /* can not count locking commands against total
328 as they are allowed to block on server */
329
330 /* update # of requests on the wire to server */
331 if (long_op != CIFS_BLOCKING_OP)
332 atomic_inc(&ses->server->inFlight);
333 spin_unlock(&GlobalMid_Lock);
334 break;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000335 }
336 }
337 return 0;
338}
339
340static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
341 struct mid_q_entry **ppmidQ)
342{
343 if (ses->server->tcpStatus == CifsExiting) {
344 return -ENOENT;
Volker Lendecke8fbbd362008-12-06 13:12:34 +0100345 }
346
347 if (ses->server->tcpStatus == CifsNeedReconnect) {
Steve French79a58d12007-07-06 22:44:50 +0000348 cFYI(1, ("tcp session dead - return to caller to retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000349 return -EAGAIN;
Volker Lendecke8fbbd362008-12-06 13:12:34 +0100350 }
351
352 if (ses->status != CifsGood) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000353 /* check if SMB session is bad because we are setting it up */
Steve French79a58d12007-07-06 22:44:50 +0000354 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
Steve Frenchad7a2922008-02-07 23:25:02 +0000355 (in_buf->Command != SMB_COM_NEGOTIATE))
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000356 return -EAGAIN;
Steve Frenchad7a2922008-02-07 23:25:02 +0000357 /* else ok - we are setting up session */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000358 }
Jeff Layton24b9b062008-12-01 07:09:34 -0500359 *ppmidQ = AllocMidQEntry(in_buf, ses->server);
Steve French26f57362007-08-30 22:09:15 +0000360 if (*ppmidQ == NULL)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000361 return -ENOMEM;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000362 return 0;
363}
364
Steve French79a58d12007-07-06 22:44:50 +0000365static int wait_for_response(struct cifsSesInfo *ses,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000366 struct mid_q_entry *midQ,
367 unsigned long timeout,
368 unsigned long time_to_wait)
369{
370 unsigned long curr_timeout;
371
372 for (;;) {
373 curr_timeout = timeout + jiffies;
Jeff Layton85705522008-12-05 20:41:21 -0500374 wait_event_timeout(ses->server->response_q,
375 midQ->midState != MID_REQUEST_SUBMITTED, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000376
377 if (time_after(jiffies, curr_timeout) &&
378 (midQ->midState == MID_REQUEST_SUBMITTED) &&
379 ((ses->server->tcpStatus == CifsGood) ||
380 (ses->server->tcpStatus == CifsNew))) {
381
382 unsigned long lrt;
383
384 /* We timed out. Is the server still
385 sending replies ? */
386 spin_lock(&GlobalMid_Lock);
387 lrt = ses->server->lstrp;
388 spin_unlock(&GlobalMid_Lock);
389
390 /* Calculate time_to_wait past last receive time.
Steve French79a58d12007-07-06 22:44:50 +0000391 Although we prefer not to time out if the
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000392 server is still responding - we will time
Steve French79a58d12007-07-06 22:44:50 +0000393 out if the server takes more than 15 (or 45
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000394 or 180) seconds to respond to this request
Steve French79a58d12007-07-06 22:44:50 +0000395 and has not responded to any request from
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000396 other threads on the client within 10 seconds */
397 lrt += time_to_wait;
398 if (time_after(jiffies, lrt)) {
399 /* No replies for time_to_wait. */
Steve French79a58d12007-07-06 22:44:50 +0000400 cERROR(1, ("server not responding"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000401 return -1;
402 }
403 } else {
404 return 0;
405 }
406 }
407}
408
Steve French133672e2007-11-13 22:41:37 +0000409
410/*
411 *
412 * Send an SMB Request. No response info (other than return code)
413 * needs to be parsed.
414 *
415 * flags indicate the type of request buffer and how long to wait
416 * and whether to log NT STATUS code (error) before mapping it to POSIX error
417 *
418 */
419int
420SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
421 struct smb_hdr *in_buf, int flags)
422{
423 int rc;
424 struct kvec iov[1];
425 int resp_buf_type;
426
427 iov[0].iov_base = (char *)in_buf;
428 iov[0].iov_len = in_buf->smb_buf_length + 4;
429 flags |= CIFS_NO_RESP;
430 rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
Steve French90c81e02008-02-12 20:32:36 +0000431 cFYI(DBG2, ("SendRcvNoRsp flags %d rc %d", flags, rc));
432
Steve French133672e2007-11-13 22:41:37 +0000433 return rc;
434}
435
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436int
Steve French79a58d12007-07-06 22:44:50 +0000437SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
438 struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
Steve French133672e2007-11-13 22:41:37 +0000439 const int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440{
441 int rc = 0;
Steve French133672e2007-11-13 22:41:37 +0000442 int long_op;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500443 unsigned int receive_len;
444 unsigned long timeout;
445 struct mid_q_entry *midQ;
Steve French3e844692005-10-03 13:37:24 -0700446 struct smb_hdr *in_buf = iov[0].iov_base;
Steve French50c2f752007-07-13 00:33:32 +0000447
Steve French133672e2007-11-13 22:41:37 +0000448 long_op = flags & CIFS_TIMEOUT_MASK;
449
Steve Frenchec637e32005-12-12 20:53:18 -0800450 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
Steve French4b8f9302006-02-26 16:41:18 +0000452 if ((ses == NULL) || (ses->server == NULL)) {
453 cifs_small_buf_release(in_buf);
Steve French79a58d12007-07-06 22:44:50 +0000454 cERROR(1, ("Null session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 return -EIO;
456 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
Steve French79a58d12007-07-06 22:44:50 +0000458 if (ses->server->tcpStatus == CifsExiting) {
Steve French4b8f9302006-02-26 16:41:18 +0000459 cifs_small_buf_release(in_buf);
Steve French31ca3bc2005-04-28 22:41:11 -0700460 return -ENOENT;
Steve French4b8f9302006-02-26 16:41:18 +0000461 }
Steve French31ca3bc2005-04-28 22:41:11 -0700462
Steve French79a58d12007-07-06 22:44:50 +0000463 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 to the same server. We may make this configurable later or
465 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000467 rc = wait_for_free_request(ses, long_op);
468 if (rc) {
469 cifs_small_buf_release(in_buf);
470 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000472
Steve French79a58d12007-07-06 22:44:50 +0000473 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 and avoid races inside tcp sendmsg code that could cause corruption
475 of smb data */
476
Jeff Layton72ca5452008-12-01 07:09:36 -0500477 mutex_lock(&ses->server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000479 rc = allocate_mid(ses, in_buf, &midQ);
480 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500481 mutex_unlock(&ses->server->srv_mutex);
Steve French4b8f9302006-02-26 16:41:18 +0000482 cifs_small_buf_release(in_buf);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000483 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000484 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000485 wake_up(&ses->server->request_q);
486 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 }
Steve French79a58d12007-07-06 22:44:50 +0000488 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100489 if (rc) {
490 mutex_unlock(&ses->server->srv_mutex);
491 cifs_small_buf_release(in_buf);
492 goto out;
493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700496#ifdef CONFIG_CIFS_STATS2
497 atomic_inc(&ses->server->inSend);
498#endif
Jeff Layton0496e022008-12-30 12:39:16 -0500499 rc = smb_sendv(ses->server, iov, n_vec);
Steve French131afd0b2005-10-07 09:51:05 -0700500#ifdef CONFIG_CIFS_STATS2
501 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700502 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700503#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000504
Jeff Layton72ca5452008-12-01 07:09:36 -0500505 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000506 cifs_small_buf_release(in_buf);
507
Steve French79a58d12007-07-06 22:44:50 +0000508 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000509 goto out;
Steve French4b8f9302006-02-26 16:41:18 +0000510
Steve French133672e2007-11-13 22:41:37 +0000511 if (long_op == CIFS_STD_OP)
512 timeout = 15 * HZ;
513 else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
Steve French37c0eb42005-10-05 14:50:29 -0700514 timeout = 180 * HZ;
Steve French133672e2007-11-13 22:41:37 +0000515 else if (long_op == CIFS_LONG_OP)
Steve French79a58d12007-07-06 22:44:50 +0000516 timeout = 45 * HZ; /* should be greater than
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500517 servers oplock break timeout (about 43 seconds) */
Steve French133672e2007-11-13 22:41:37 +0000518 else if (long_op == CIFS_ASYNC_OP)
519 goto out;
520 else if (long_op == CIFS_BLOCKING_OP)
521 timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */
522 else {
523 cERROR(1, ("unknown timeout flag %d", long_op));
524 rc = -EIO;
525 goto out;
526 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000527
Steve French79a58d12007-07-06 22:44:50 +0000528 /* wait for 15 seconds or until woken up due to response arriving or
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500529 due to last connection to this server being unmounted */
530 if (signal_pending(current)) {
531 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000532 but we still give response a chance to complete */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500533 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000534 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500535
536 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000537 wait_for_response(ses, midQ, timeout, 10 * HZ);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500538
539 spin_lock(&GlobalMid_Lock);
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100540
541 if (midQ->resp_buf == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000542 cERROR(1, ("No response to cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700543 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000544 if (midQ->midState == MID_REQUEST_SUBMITTED) {
545 if (ses->server->tcpStatus == CifsExiting)
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500546 rc = -EHOSTDOWN;
547 else {
548 ses->server->tcpStatus = CifsNeedReconnect;
549 midQ->midState = MID_RETRY_NEEDED;
550 }
551 }
552
553 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000554 if (midQ->midState == MID_RETRY_NEEDED) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500555 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000556 cFYI(1, ("marking request for retry"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500557 } else {
558 rc = -EIO;
559 }
560 }
561 spin_unlock(&GlobalMid_Lock);
562 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000563 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000564 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000565 wake_up(&ses->server->request_q);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500566 return rc;
567 }
Steve French50c2f752007-07-13 00:33:32 +0000568
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100569 spin_unlock(&GlobalMid_Lock);
570 receive_len = midQ->resp_buf->smb_buf_length;
571
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500572 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
573 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
574 receive_len, xid));
575 rc = -EIO;
Steve French2b2bdfb2008-12-11 17:26:54 +0000576 goto out;
577 }
Steve French84afc292005-12-02 13:32:45 -0800578
Steve French2b2bdfb2008-12-11 17:26:54 +0000579 /* rcvd frame is ok */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500580
Steve French2b2bdfb2008-12-11 17:26:54 +0000581 if (midQ->resp_buf &&
582 (midQ->midState == MID_RESPONSE_RECEIVED)) {
583
584 iov[0].iov_base = (char *)midQ->resp_buf;
585 if (midQ->largeBuf)
586 *pRespBufType = CIFS_LARGE_BUFFER;
587 else
588 *pRespBufType = CIFS_SMALL_BUFFER;
589 iov[0].iov_len = receive_len + 4;
590
591 dump_smb(midQ->resp_buf, 80);
592 /* convert the length into a more usable form */
593 if ((receive_len > 24) &&
594 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
595 SECMODE_SIGN_ENABLED))) {
596 rc = cifs_verify_signature(midQ->resp_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000597 &ses->server->mac_signing_key,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500598 midQ->sequence_number+1);
Steve French2b2bdfb2008-12-11 17:26:54 +0000599 if (rc) {
600 cERROR(1, ("Unexpected SMB signature"));
601 /* BB FIXME add code to kill session */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500602 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500603 }
Steve French2b2bdfb2008-12-11 17:26:54 +0000604
605 /* BB special case reconnect tid and uid here? */
606 rc = map_smb_to_linux_error(midQ->resp_buf,
607 flags & CIFS_LOG_ERROR);
608
609 /* convert ByteCount if necessary */
610 if (receive_len >= sizeof(struct smb_hdr) - 4
611 /* do not count RFC1001 header */ +
612 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
613 BCC(midQ->resp_buf) =
614 le16_to_cpu(BCC_LE(midQ->resp_buf));
615 if ((flags & CIFS_NO_RESP) == 0)
616 midQ->resp_buf = NULL; /* mark it so buf will
617 not be freed by
618 DeleteMidQEntry */
619 } else {
620 rc = -EIO;
621 cFYI(1, ("Bad MID state?"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500622 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000623
624out:
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500625 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000626 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000627 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629 return rc;
630}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
632int
633SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
634 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
635 int *pbytes_returned, const int long_op)
636{
637 int rc = 0;
638 unsigned int receive_len;
639 unsigned long timeout;
640 struct mid_q_entry *midQ;
641
642 if (ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000643 cERROR(1, ("Null smb session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 return -EIO;
645 }
Steve French79a58d12007-07-06 22:44:50 +0000646 if (ses->server == NULL) {
647 cERROR(1, ("Null tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 return -EIO;
649 }
650
Steve French79a58d12007-07-06 22:44:50 +0000651 if (ses->server->tcpStatus == CifsExiting)
Steve French31ca3bc2005-04-28 22:41:11 -0700652 return -ENOENT;
653
Steve French79a58d12007-07-06 22:44:50 +0000654 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 to the same server. We may make this configurable later or
656 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000658 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
659 cERROR(1, ("Illegal length, greater than maximum frame, %d",
660 in_buf->smb_buf_length));
661 return -EIO;
662 }
663
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000664 rc = wait_for_free_request(ses, long_op);
665 if (rc)
666 return rc;
667
Steve French79a58d12007-07-06 22:44:50 +0000668 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 and avoid races inside tcp sendmsg code that could cause corruption
670 of smb data */
671
Jeff Layton72ca5452008-12-01 07:09:36 -0500672 mutex_lock(&ses->server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000674 rc = allocate_mid(ses, in_buf, &midQ);
675 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500676 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000677 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000678 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000679 wake_up(&ses->server->request_q);
680 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 }
682
Steve Frenchad009ac2005-04-28 22:41:05 -0700683 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100684 if (rc) {
685 mutex_unlock(&ses->server->srv_mutex);
686 goto out;
687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
689 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700690#ifdef CONFIG_CIFS_STATS2
691 atomic_inc(&ses->server->inSend);
692#endif
Jeff Layton0496e022008-12-30 12:39:16 -0500693 rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
Steve French131afd0b2005-10-07 09:51:05 -0700694#ifdef CONFIG_CIFS_STATS2
695 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700696 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700697#endif
Jeff Layton72ca5452008-12-01 07:09:36 -0500698 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000699
Steve French79a58d12007-07-06 22:44:50 +0000700 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000701 goto out;
702
Steve French133672e2007-11-13 22:41:37 +0000703 if (long_op == CIFS_STD_OP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 timeout = 15 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000705 /* wait for 15 seconds or until woken up due to response arriving or
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 due to last connection to this server being unmounted */
Steve French133672e2007-11-13 22:41:37 +0000707 else if (long_op == CIFS_ASYNC_OP)
708 goto out;
709 else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
710 timeout = 180 * HZ;
711 else if (long_op == CIFS_LONG_OP)
712 timeout = 45 * HZ; /* should be greater than
713 servers oplock break timeout (about 43 seconds) */
714 else if (long_op == CIFS_BLOCKING_OP)
715 timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
716 else {
717 cERROR(1, ("unknown timeout flag %d", long_op));
718 rc = -EIO;
719 goto out;
720 }
721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 if (signal_pending(current)) {
723 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000724 but we still give response a chance to complete */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000726 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
728 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000729 wait_for_response(ses, midQ, timeout, 10 * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730
731 spin_lock(&GlobalMid_Lock);
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100732 if (midQ->resp_buf == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000733 cERROR(1, ("No response for cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700734 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000735 if (midQ->midState == MID_REQUEST_SUBMITTED) {
736 if (ses->server->tcpStatus == CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 rc = -EHOSTDOWN;
738 else {
739 ses->server->tcpStatus = CifsNeedReconnect;
740 midQ->midState = MID_RETRY_NEEDED;
741 }
742 }
743
744 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000745 if (midQ->midState == MID_RETRY_NEEDED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000747 cFYI(1, ("marking request for retry"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 } else {
749 rc = -EIO;
750 }
751 }
752 spin_unlock(&GlobalMid_Lock);
753 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000754 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000755 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000756 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 return rc;
758 }
Steve French50c2f752007-07-13 00:33:32 +0000759
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100760 spin_unlock(&GlobalMid_Lock);
761 receive_len = midQ->resp_buf->smb_buf_length;
762
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Steve Frenchad009ac2005-04-28 22:41:05 -0700764 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 receive_len, xid));
766 rc = -EIO;
Steve French2b2bdfb2008-12-11 17:26:54 +0000767 goto out;
768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
Steve French2b2bdfb2008-12-11 17:26:54 +0000770 /* rcvd frame is ok */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Steve French2b2bdfb2008-12-11 17:26:54 +0000772 if (midQ->resp_buf && out_buf
773 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
774 out_buf->smb_buf_length = receive_len;
775 memcpy((char *)out_buf + 4,
776 (char *)midQ->resp_buf + 4,
777 receive_len);
778
779 dump_smb(out_buf, 92);
780 /* convert the length into a more usable form */
781 if ((receive_len > 24) &&
782 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
783 SECMODE_SIGN_ENABLED))) {
784 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000785 &ses->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -0700786 midQ->sequence_number+1);
Steve French2b2bdfb2008-12-11 17:26:54 +0000787 if (rc) {
788 cERROR(1, ("Unexpected SMB signature"));
789 /* BB FIXME add code to kill session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 }
Steve French2b2bdfb2008-12-11 17:26:54 +0000792
793 *pbytes_returned = out_buf->smb_buf_length;
794
795 /* BB special case reconnect tid and uid here? */
796 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
797
798 /* convert ByteCount if necessary */
799 if (receive_len >= sizeof(struct smb_hdr) - 4
800 /* do not count RFC1001 header */ +
801 (2 * out_buf->WordCount) + 2 /* bcc */ )
802 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
803 } else {
804 rc = -EIO;
805 cERROR(1, ("Bad MID state?"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000808out:
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000809 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000810 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000811 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813 return rc;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000814}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000816/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
817
818static int
819send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
820 struct mid_q_entry *midQ)
821{
822 int rc = 0;
823 struct cifsSesInfo *ses = tcon->ses;
824 __u16 mid = in_buf->Mid;
825
826 header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
827 in_buf->Mid = mid;
Jeff Layton72ca5452008-12-01 07:09:36 -0500828 mutex_lock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000829 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
830 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500831 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000832 return rc;
833 }
Jeff Layton0496e022008-12-30 12:39:16 -0500834 rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
Jeff Layton72ca5452008-12-01 07:09:36 -0500835 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000836 return rc;
837}
838
839/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
840 blocking lock to return. */
841
842static int
843send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
844 struct smb_hdr *in_buf,
845 struct smb_hdr *out_buf)
846{
847 int bytes_returned;
848 struct cifsSesInfo *ses = tcon->ses;
849 LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
850
851 /* We just modify the current in_buf to change
852 the type of lock from LOCKING_ANDX_SHARED_LOCK
853 or LOCKING_ANDX_EXCLUSIVE_LOCK to
854 LOCKING_ANDX_CANCEL_LOCK. */
855
856 pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
857 pSMB->Timeout = 0;
858 pSMB->hdr.Mid = GetNextMid(ses->server);
859
860 return SendReceive(xid, ses, in_buf, out_buf,
Steve French133672e2007-11-13 22:41:37 +0000861 &bytes_returned, CIFS_STD_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000862}
863
864int
865SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
866 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
867 int *pbytes_returned)
868{
869 int rc = 0;
870 int rstart = 0;
871 unsigned int receive_len;
872 struct mid_q_entry *midQ;
873 struct cifsSesInfo *ses;
874
875 if (tcon == NULL || tcon->ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000876 cERROR(1, ("Null smb session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000877 return -EIO;
878 }
879 ses = tcon->ses;
880
Steve French79a58d12007-07-06 22:44:50 +0000881 if (ses->server == NULL) {
882 cERROR(1, ("Null tcp session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000883 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 }
885
Steve French79a58d12007-07-06 22:44:50 +0000886 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000887 return -ENOENT;
888
Steve French79a58d12007-07-06 22:44:50 +0000889 /* Ensure that we do not send more than 50 overlapping requests
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000890 to the same server. We may make this configurable later or
891 use ses->maxReq */
892
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000893 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
894 cERROR(1, ("Illegal length, greater than maximum frame, %d",
895 in_buf->smb_buf_length));
896 return -EIO;
897 }
898
Steve French133672e2007-11-13 22:41:37 +0000899 rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000900 if (rc)
901 return rc;
902
Steve French79a58d12007-07-06 22:44:50 +0000903 /* make sure that we sign in the same order that we send on this socket
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000904 and avoid races inside tcp sendmsg code that could cause corruption
905 of smb data */
906
Jeff Layton72ca5452008-12-01 07:09:36 -0500907 mutex_lock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000908
909 rc = allocate_mid(ses, in_buf, &midQ);
910 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500911 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000912 return rc;
913 }
914
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000915 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100916 if (rc) {
917 DeleteMidQEntry(midQ);
918 mutex_unlock(&ses->server->srv_mutex);
919 return rc;
920 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000921
922 midQ->midState = MID_REQUEST_SUBMITTED;
923#ifdef CONFIG_CIFS_STATS2
924 atomic_inc(&ses->server->inSend);
925#endif
Jeff Layton0496e022008-12-30 12:39:16 -0500926 rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000927#ifdef CONFIG_CIFS_STATS2
928 atomic_dec(&ses->server->inSend);
929 midQ->when_sent = jiffies;
930#endif
Jeff Layton72ca5452008-12-01 07:09:36 -0500931 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000932
Steve French79a58d12007-07-06 22:44:50 +0000933 if (rc < 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000934 DeleteMidQEntry(midQ);
935 return rc;
936 }
937
938 /* Wait for a reply - allow signals to interrupt. */
939 rc = wait_event_interruptible(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000940 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000941 ((ses->server->tcpStatus != CifsGood) &&
942 (ses->server->tcpStatus != CifsNew)));
943
944 /* Were we interrupted by a signal ? */
945 if ((rc == -ERESTARTSYS) &&
946 (midQ->midState == MID_REQUEST_SUBMITTED) &&
947 ((ses->server->tcpStatus == CifsGood) ||
948 (ses->server->tcpStatus == CifsNew))) {
949
950 if (in_buf->Command == SMB_COM_TRANSACTION2) {
951 /* POSIX lock. We send a NT_CANCEL SMB to cause the
952 blocking lock to return. */
953
954 rc = send_nt_cancel(tcon, in_buf, midQ);
955 if (rc) {
956 DeleteMidQEntry(midQ);
957 return rc;
958 }
959 } else {
960 /* Windows lock. We send a LOCKINGX_CANCEL_LOCK
961 to cause the blocking lock to return. */
962
963 rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
964
965 /* If we get -ENOLCK back the lock may have
966 already been removed. Don't exit in this case. */
967 if (rc && rc != -ENOLCK) {
968 DeleteMidQEntry(midQ);
969 return rc;
970 }
971 }
972
973 /* Wait 5 seconds for the response. */
Steve French79a58d12007-07-06 22:44:50 +0000974 if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000975 /* We got the response - restart system call. */
976 rstart = 1;
977 }
978 }
979
980 spin_lock(&GlobalMid_Lock);
981 if (midQ->resp_buf) {
982 spin_unlock(&GlobalMid_Lock);
983 receive_len = midQ->resp_buf->smb_buf_length;
984 } else {
Steve French79a58d12007-07-06 22:44:50 +0000985 cERROR(1, ("No response for cmd %d mid %d",
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000986 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000987 if (midQ->midState == MID_REQUEST_SUBMITTED) {
988 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000989 rc = -EHOSTDOWN;
990 else {
991 ses->server->tcpStatus = CifsNeedReconnect;
992 midQ->midState = MID_RETRY_NEEDED;
993 }
994 }
995
996 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000997 if (midQ->midState == MID_RETRY_NEEDED) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000998 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000999 cFYI(1, ("marking request for retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001000 } else {
1001 rc = -EIO;
1002 }
1003 }
1004 spin_unlock(&GlobalMid_Lock);
1005 DeleteMidQEntry(midQ);
1006 return rc;
1007 }
Steve French50c2f752007-07-13 00:33:32 +00001008
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001009 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
1010 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
1011 receive_len, xid));
1012 rc = -EIO;
Volker Lendecke17c8bfe2008-12-06 16:38:19 +01001013 goto out;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001014 }
Volker Lendecke17c8bfe2008-12-06 16:38:19 +01001015
1016 /* rcvd frame is ok */
1017
Volker Lendeckeac6a3ef2008-12-06 16:40:40 +01001018 if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) {
Volker Lendecke17c8bfe2008-12-06 16:38:19 +01001019 rc = -EIO;
1020 cERROR(1, ("Bad MID state?"));
Volker Lendecke698e96a2008-12-06 16:39:31 +01001021 goto out;
Volker Lendecke17c8bfe2008-12-06 16:38:19 +01001022 }
1023
Volker Lendecke698e96a2008-12-06 16:39:31 +01001024 out_buf->smb_buf_length = receive_len;
1025 memcpy((char *)out_buf + 4,
1026 (char *)midQ->resp_buf + 4,
1027 receive_len);
1028
1029 dump_smb(out_buf, 92);
1030 /* convert the length into a more usable form */
1031 if ((receive_len > 24) &&
1032 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
1033 SECMODE_SIGN_ENABLED))) {
1034 rc = cifs_verify_signature(out_buf,
1035 &ses->server->mac_signing_key,
1036 midQ->sequence_number+1);
1037 if (rc) {
1038 cERROR(1, ("Unexpected SMB signature"));
1039 /* BB FIXME add code to kill session */
1040 }
1041 }
1042
1043 *pbytes_returned = out_buf->smb_buf_length;
1044
1045 /* BB special case reconnect tid and uid here? */
1046 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
1047
1048 /* convert ByteCount if necessary */
1049 if (receive_len >= sizeof(struct smb_hdr) - 4
1050 /* do not count RFC1001 header */ +
1051 (2 * out_buf->WordCount) + 2 /* bcc */ )
1052 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1053
Volker Lendecke17c8bfe2008-12-06 16:38:19 +01001054out:
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001055 DeleteMidQEntry(midQ);
1056 if (rstart && rc == -EACCES)
1057 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 return rc;
1059}