blob: 2c7efd26992de25cc7f1dde83c158d2c28668fa2 [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;
122 spin_lock(&GlobalMid_Lock);
123 list_add_tail(&temp->qhead, &GlobalOplock_Q);
124 spin_unlock(&GlobalMid_Lock);
125 }
126 return temp;
127
128}
129
Steve French79a58d12007-07-06 22:44:50 +0000130void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131{
Steve French79a58d12007-07-06 22:44:50 +0000132 spin_lock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 /* should we check if list empty first? */
134 list_del(&oplockEntry->qhead);
135 spin_unlock(&GlobalMid_Lock);
136 kmem_cache_free(cifs_oplock_cachep, oplockEntry);
137}
138
Steve French5d941ca2008-04-15 18:40:48 +0000139
140void DeleteTconOplockQEntries(struct cifsTconInfo *tcon)
141{
142 struct oplock_q_entry *temp;
143
144 if (tcon == NULL)
145 return;
146
147 spin_lock(&GlobalMid_Lock);
148 list_for_each_entry(temp, &GlobalOplock_Q, qhead) {
149 if ((temp->tcon) && (temp->tcon == tcon)) {
150 list_del(&temp->qhead);
151 kmem_cache_free(cifs_oplock_cachep, temp);
152 }
153 }
154 spin_unlock(&GlobalMid_Lock);
155}
156
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500157static int
Jeff Layton0496e022008-12-30 12:39:16 -0500158smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159{
160 int rc = 0;
161 int i = 0;
162 struct msghdr smb_msg;
Steve French3e844692005-10-03 13:37:24 -0700163 struct smb_hdr *smb_buffer = iov[0].iov_base;
164 unsigned int len = iov[0].iov_len;
165 unsigned int total_len;
166 int first_vec = 0;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000167 unsigned int smb_buf_length = smb_buffer->smb_buf_length;
Steve Frenchedf1ae42008-10-29 00:47:57 +0000168 struct socket *ssocket = server->ssocket;
Steve French50c2f752007-07-13 00:33:32 +0000169
Steve French79a58d12007-07-06 22:44:50 +0000170 if (ssocket == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 return -ENOTSOCK; /* BB eventually add reconnect code here */
Steve French3e844692005-10-03 13:37:24 -0700172
Jeff Layton0496e022008-12-30 12:39:16 -0500173 smb_msg.msg_name = (struct sockaddr *) &server->addr.sockAddr;
Steve French26f57362007-08-30 22:09:15 +0000174 smb_msg.msg_namelen = sizeof(struct sockaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 smb_msg.msg_control = NULL;
176 smb_msg.msg_controllen = 0;
Jeff Layton0496e022008-12-30 12:39:16 -0500177 if (server->noblocksnd)
Steve Frenchedf1ae42008-10-29 00:47:57 +0000178 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
179 else
180 smb_msg.msg_flags = MSG_NOSIGNAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182 /* smb header is converted in header_assemble. bcc and rest of SMB word
Steve French79a58d12007-07-06 22:44:50 +0000183 area, and byte area if necessary, is converted to littleendian in
184 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 Flags2 is converted in SendReceive */
186
Steve French3e844692005-10-03 13:37:24 -0700187
188 total_len = 0;
189 for (i = 0; i < n_vec; i++)
190 total_len += iov[i].iov_len;
191
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Steve French3e844692005-10-03 13:37:24 -0700193 cFYI(1, ("Sending smb: total_len %d", total_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 dump_smb(smb_buffer, len);
195
Shirish Pargaonkar17680352008-07-29 21:26:13 +0000196 i = 0;
Steve French3e844692005-10-03 13:37:24 -0700197 while (total_len) {
198 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
199 n_vec - first_vec, total_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
201 i++;
Steve French79a58d12007-07-06 22:44:50 +0000202 if (i >= 14) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 cERROR(1,
Steve French68058e72005-10-10 10:34:22 -0700204 ("sends on sock %p stuck for 15 seconds",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 ssocket));
206 rc = -EAGAIN;
207 break;
208 }
Steve French68058e72005-10-10 10:34:22 -0700209 msleep(1 << i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 continue;
211 }
Steve French79a58d12007-07-06 22:44:50 +0000212 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 break;
Steve French3e844692005-10-03 13:37:24 -0700214
Steve French61de8002008-10-30 20:15:22 +0000215 if (rc == total_len) {
216 total_len = 0;
217 break;
218 } else if (rc > total_len) {
219 cERROR(1, ("sent %d requested %d", rc, total_len));
Steve French3e844692005-10-03 13:37:24 -0700220 break;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500221 }
Steve French79a58d12007-07-06 22:44:50 +0000222 if (rc == 0) {
Steve French3e844692005-10-03 13:37:24 -0700223 /* should never happen, letting socket clear before
224 retrying is our only obvious option here */
Steve French79a58d12007-07-06 22:44:50 +0000225 cERROR(1, ("tcp sent no data"));
Steve French3e844692005-10-03 13:37:24 -0700226 msleep(500);
227 continue;
228 }
229 total_len -= rc;
Steve French68058e72005-10-10 10:34:22 -0700230 /* the line below resets i */
Steve French3e844692005-10-03 13:37:24 -0700231 for (i = first_vec; i < n_vec; i++) {
232 if (iov[i].iov_len) {
233 if (rc > iov[i].iov_len) {
234 rc -= iov[i].iov_len;
235 iov[i].iov_len = 0;
236 } else {
237 iov[i].iov_base += rc;
238 iov[i].iov_len -= rc;
239 first_vec = i;
240 break;
241 }
242 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500243 }
Steve French5e1253b2005-10-10 14:06:37 -0700244 i = 0; /* in case we get ENOSPC on the next send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 }
246
Steve Frenchedf1ae42008-10-29 00:47:57 +0000247 if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
248 cFYI(1, ("partial send (%d remaining), terminating session",
249 total_len));
250 /* If we have only sent part of an SMB then the next SMB
251 could be taken as the remainder of this one. We need
252 to kill the socket so the server throws away the partial
253 SMB */
254 server->tcpStatus = CifsNeedReconnect;
255 }
256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 if (rc < 0) {
Steve French79a58d12007-07-06 22:44:50 +0000258 cERROR(1, ("Error %d sending data on socket to server", rc));
Steve French3e844692005-10-03 13:37:24 -0700259 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000262 /* Don't want to modify the buffer as a
263 side effect of this call. */
264 smb_buffer->smb_buf_length = smb_buf_length;
265
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 return rc;
267}
268
Jeff Layton0496e022008-12-30 12:39:16 -0500269int
270smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
271 unsigned int smb_buf_length)
272{
273 struct kvec iov;
274
275 iov.iov_base = smb_buffer;
276 iov.iov_len = smb_buf_length + 4;
277
278 return smb_sendv(server, &iov, 1);
279}
280
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000281static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
282{
Steve French133672e2007-11-13 22:41:37 +0000283 if (long_op == CIFS_ASYNC_OP) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000284 /* oplock breaks must not be held up */
285 atomic_inc(&ses->server->inFlight);
Volker Lendecke27a97a62008-12-08 20:59:39 +0000286 return 0;
287 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000288
Volker Lendecke27a97a62008-12-08 20:59:39 +0000289 spin_lock(&GlobalMid_Lock);
290 while (1) {
291 if (atomic_read(&ses->server->inFlight) >=
292 cifs_max_pending){
293 spin_unlock(&GlobalMid_Lock);
294#ifdef CONFIG_CIFS_STATS2
295 atomic_inc(&ses->server->num_waiters);
296#endif
297 wait_event(ses->server->request_q,
298 atomic_read(&ses->server->inFlight)
299 < cifs_max_pending);
300#ifdef CONFIG_CIFS_STATS2
301 atomic_dec(&ses->server->num_waiters);
302#endif
303 spin_lock(&GlobalMid_Lock);
304 } else {
305 if (ses->server->tcpStatus == CifsExiting) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000306 spin_unlock(&GlobalMid_Lock);
Volker Lendecke27a97a62008-12-08 20:59:39 +0000307 return -ENOENT;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000308 }
Volker Lendecke27a97a62008-12-08 20:59:39 +0000309
310 /* can not count locking commands against total
311 as they are allowed to block on server */
312
313 /* update # of requests on the wire to server */
314 if (long_op != CIFS_BLOCKING_OP)
315 atomic_inc(&ses->server->inFlight);
316 spin_unlock(&GlobalMid_Lock);
317 break;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000318 }
319 }
320 return 0;
321}
322
323static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
324 struct mid_q_entry **ppmidQ)
325{
326 if (ses->server->tcpStatus == CifsExiting) {
327 return -ENOENT;
Volker Lendecke8fbbd362008-12-06 13:12:34 +0100328 }
329
330 if (ses->server->tcpStatus == CifsNeedReconnect) {
Steve French79a58d12007-07-06 22:44:50 +0000331 cFYI(1, ("tcp session dead - return to caller to retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000332 return -EAGAIN;
Volker Lendecke8fbbd362008-12-06 13:12:34 +0100333 }
334
335 if (ses->status != CifsGood) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000336 /* check if SMB session is bad because we are setting it up */
Steve French79a58d12007-07-06 22:44:50 +0000337 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
Steve Frenchad7a2922008-02-07 23:25:02 +0000338 (in_buf->Command != SMB_COM_NEGOTIATE))
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000339 return -EAGAIN;
Steve Frenchad7a2922008-02-07 23:25:02 +0000340 /* else ok - we are setting up session */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000341 }
Jeff Layton24b9b062008-12-01 07:09:34 -0500342 *ppmidQ = AllocMidQEntry(in_buf, ses->server);
Steve French26f57362007-08-30 22:09:15 +0000343 if (*ppmidQ == NULL)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000344 return -ENOMEM;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000345 return 0;
346}
347
Steve French79a58d12007-07-06 22:44:50 +0000348static int wait_for_response(struct cifsSesInfo *ses,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000349 struct mid_q_entry *midQ,
350 unsigned long timeout,
351 unsigned long time_to_wait)
352{
353 unsigned long curr_timeout;
354
355 for (;;) {
356 curr_timeout = timeout + jiffies;
Jeff Layton85705522008-12-05 20:41:21 -0500357 wait_event_timeout(ses->server->response_q,
358 midQ->midState != MID_REQUEST_SUBMITTED, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000359
360 if (time_after(jiffies, curr_timeout) &&
361 (midQ->midState == MID_REQUEST_SUBMITTED) &&
362 ((ses->server->tcpStatus == CifsGood) ||
363 (ses->server->tcpStatus == CifsNew))) {
364
365 unsigned long lrt;
366
367 /* We timed out. Is the server still
368 sending replies ? */
369 spin_lock(&GlobalMid_Lock);
370 lrt = ses->server->lstrp;
371 spin_unlock(&GlobalMid_Lock);
372
373 /* Calculate time_to_wait past last receive time.
Steve French79a58d12007-07-06 22:44:50 +0000374 Although we prefer not to time out if the
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000375 server is still responding - we will time
Steve French79a58d12007-07-06 22:44:50 +0000376 out if the server takes more than 15 (or 45
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000377 or 180) seconds to respond to this request
Steve French79a58d12007-07-06 22:44:50 +0000378 and has not responded to any request from
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000379 other threads on the client within 10 seconds */
380 lrt += time_to_wait;
381 if (time_after(jiffies, lrt)) {
382 /* No replies for time_to_wait. */
Steve French79a58d12007-07-06 22:44:50 +0000383 cERROR(1, ("server not responding"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000384 return -1;
385 }
386 } else {
387 return 0;
388 }
389 }
390}
391
Steve French133672e2007-11-13 22:41:37 +0000392
393/*
394 *
395 * Send an SMB Request. No response info (other than return code)
396 * needs to be parsed.
397 *
398 * flags indicate the type of request buffer and how long to wait
399 * and whether to log NT STATUS code (error) before mapping it to POSIX error
400 *
401 */
402int
403SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
404 struct smb_hdr *in_buf, int flags)
405{
406 int rc;
407 struct kvec iov[1];
408 int resp_buf_type;
409
410 iov[0].iov_base = (char *)in_buf;
411 iov[0].iov_len = in_buf->smb_buf_length + 4;
412 flags |= CIFS_NO_RESP;
413 rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
Steve French90c81e02008-02-12 20:32:36 +0000414 cFYI(DBG2, ("SendRcvNoRsp flags %d rc %d", flags, rc));
415
Steve French133672e2007-11-13 22:41:37 +0000416 return rc;
417}
418
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419int
Steve French79a58d12007-07-06 22:44:50 +0000420SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
421 struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
Steve French133672e2007-11-13 22:41:37 +0000422 const int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423{
424 int rc = 0;
Steve French133672e2007-11-13 22:41:37 +0000425 int long_op;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500426 unsigned int receive_len;
427 unsigned long timeout;
428 struct mid_q_entry *midQ;
Steve French3e844692005-10-03 13:37:24 -0700429 struct smb_hdr *in_buf = iov[0].iov_base;
Steve French50c2f752007-07-13 00:33:32 +0000430
Steve French133672e2007-11-13 22:41:37 +0000431 long_op = flags & CIFS_TIMEOUT_MASK;
432
Steve Frenchec637e32005-12-12 20:53:18 -0800433 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
Steve French4b8f9302006-02-26 16:41:18 +0000435 if ((ses == NULL) || (ses->server == NULL)) {
436 cifs_small_buf_release(in_buf);
Steve French79a58d12007-07-06 22:44:50 +0000437 cERROR(1, ("Null session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 return -EIO;
439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
Steve French79a58d12007-07-06 22:44:50 +0000441 if (ses->server->tcpStatus == CifsExiting) {
Steve French4b8f9302006-02-26 16:41:18 +0000442 cifs_small_buf_release(in_buf);
Steve French31ca3bc2005-04-28 22:41:11 -0700443 return -ENOENT;
Steve French4b8f9302006-02-26 16:41:18 +0000444 }
Steve French31ca3bc2005-04-28 22:41:11 -0700445
Steve French79a58d12007-07-06 22:44:50 +0000446 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 to the same server. We may make this configurable later or
448 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000450 rc = wait_for_free_request(ses, long_op);
451 if (rc) {
452 cifs_small_buf_release(in_buf);
453 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000455
Steve French79a58d12007-07-06 22:44:50 +0000456 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 and avoid races inside tcp sendmsg code that could cause corruption
458 of smb data */
459
Jeff Layton72ca5452008-12-01 07:09:36 -0500460 mutex_lock(&ses->server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000462 rc = allocate_mid(ses, in_buf, &midQ);
463 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500464 mutex_unlock(&ses->server->srv_mutex);
Steve French4b8f9302006-02-26 16:41:18 +0000465 cifs_small_buf_release(in_buf);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000466 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000467 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000468 wake_up(&ses->server->request_q);
469 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 }
Steve French79a58d12007-07-06 22:44:50 +0000471 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100472 if (rc) {
473 mutex_unlock(&ses->server->srv_mutex);
474 cifs_small_buf_release(in_buf);
475 goto out;
476 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477
478 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700479#ifdef CONFIG_CIFS_STATS2
480 atomic_inc(&ses->server->inSend);
481#endif
Jeff Layton0496e022008-12-30 12:39:16 -0500482 rc = smb_sendv(ses->server, iov, n_vec);
Steve French131afd0b2005-10-07 09:51:05 -0700483#ifdef CONFIG_CIFS_STATS2
484 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700485 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700486#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000487
Jeff Layton72ca5452008-12-01 07:09:36 -0500488 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000489 cifs_small_buf_release(in_buf);
490
Steve French79a58d12007-07-06 22:44:50 +0000491 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000492 goto out;
Steve French4b8f9302006-02-26 16:41:18 +0000493
Steve French133672e2007-11-13 22:41:37 +0000494 if (long_op == CIFS_STD_OP)
495 timeout = 15 * HZ;
496 else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
Steve French37c0eb42005-10-05 14:50:29 -0700497 timeout = 180 * HZ;
Steve French133672e2007-11-13 22:41:37 +0000498 else if (long_op == CIFS_LONG_OP)
Steve French79a58d12007-07-06 22:44:50 +0000499 timeout = 45 * HZ; /* should be greater than
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500500 servers oplock break timeout (about 43 seconds) */
Steve French133672e2007-11-13 22:41:37 +0000501 else if (long_op == CIFS_ASYNC_OP)
502 goto out;
503 else if (long_op == CIFS_BLOCKING_OP)
504 timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */
505 else {
506 cERROR(1, ("unknown timeout flag %d", long_op));
507 rc = -EIO;
508 goto out;
509 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000510
Steve French79a58d12007-07-06 22:44:50 +0000511 /* wait for 15 seconds or until woken up due to response arriving or
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500512 due to last connection to this server being unmounted */
513 if (signal_pending(current)) {
514 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000515 but we still give response a chance to complete */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500516 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000517 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500518
519 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000520 wait_for_response(ses, midQ, timeout, 10 * HZ);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500521
522 spin_lock(&GlobalMid_Lock);
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100523
524 if (midQ->resp_buf == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000525 cERROR(1, ("No response to cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700526 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000527 if (midQ->midState == MID_REQUEST_SUBMITTED) {
528 if (ses->server->tcpStatus == CifsExiting)
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500529 rc = -EHOSTDOWN;
530 else {
531 ses->server->tcpStatus = CifsNeedReconnect;
532 midQ->midState = MID_RETRY_NEEDED;
533 }
534 }
535
536 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000537 if (midQ->midState == MID_RETRY_NEEDED) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500538 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000539 cFYI(1, ("marking request for retry"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500540 } else {
541 rc = -EIO;
542 }
543 }
544 spin_unlock(&GlobalMid_Lock);
545 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000546 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000547 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000548 wake_up(&ses->server->request_q);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500549 return rc;
550 }
Steve French50c2f752007-07-13 00:33:32 +0000551
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100552 spin_unlock(&GlobalMid_Lock);
553 receive_len = midQ->resp_buf->smb_buf_length;
554
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500555 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
556 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
557 receive_len, xid));
558 rc = -EIO;
Steve French2b2bdfb2008-12-11 17:26:54 +0000559 goto out;
560 }
Steve French84afc292005-12-02 13:32:45 -0800561
Steve French2b2bdfb2008-12-11 17:26:54 +0000562 /* rcvd frame is ok */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500563
Steve French2b2bdfb2008-12-11 17:26:54 +0000564 if (midQ->resp_buf &&
565 (midQ->midState == MID_RESPONSE_RECEIVED)) {
566
567 iov[0].iov_base = (char *)midQ->resp_buf;
568 if (midQ->largeBuf)
569 *pRespBufType = CIFS_LARGE_BUFFER;
570 else
571 *pRespBufType = CIFS_SMALL_BUFFER;
572 iov[0].iov_len = receive_len + 4;
573
574 dump_smb(midQ->resp_buf, 80);
575 /* convert the length into a more usable form */
576 if ((receive_len > 24) &&
577 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
578 SECMODE_SIGN_ENABLED))) {
579 rc = cifs_verify_signature(midQ->resp_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000580 &ses->server->mac_signing_key,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500581 midQ->sequence_number+1);
Steve French2b2bdfb2008-12-11 17:26:54 +0000582 if (rc) {
583 cERROR(1, ("Unexpected SMB signature"));
584 /* BB FIXME add code to kill session */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500585 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500586 }
Steve French2b2bdfb2008-12-11 17:26:54 +0000587
588 /* BB special case reconnect tid and uid here? */
589 rc = map_smb_to_linux_error(midQ->resp_buf,
590 flags & CIFS_LOG_ERROR);
591
592 /* convert ByteCount if necessary */
593 if (receive_len >= sizeof(struct smb_hdr) - 4
594 /* do not count RFC1001 header */ +
595 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
596 BCC(midQ->resp_buf) =
597 le16_to_cpu(BCC_LE(midQ->resp_buf));
598 if ((flags & CIFS_NO_RESP) == 0)
599 midQ->resp_buf = NULL; /* mark it so buf will
600 not be freed by
601 DeleteMidQEntry */
602 } else {
603 rc = -EIO;
604 cFYI(1, ("Bad MID state?"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500605 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000606
607out:
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500608 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000609 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000610 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611
612 return rc;
613}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
615int
616SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
617 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
618 int *pbytes_returned, const int long_op)
619{
620 int rc = 0;
621 unsigned int receive_len;
622 unsigned long timeout;
623 struct mid_q_entry *midQ;
624
625 if (ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000626 cERROR(1, ("Null smb session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 return -EIO;
628 }
Steve French79a58d12007-07-06 22:44:50 +0000629 if (ses->server == NULL) {
630 cERROR(1, ("Null tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 return -EIO;
632 }
633
Steve French79a58d12007-07-06 22:44:50 +0000634 if (ses->server->tcpStatus == CifsExiting)
Steve French31ca3bc2005-04-28 22:41:11 -0700635 return -ENOENT;
636
Steve French79a58d12007-07-06 22:44:50 +0000637 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 to the same server. We may make this configurable later or
639 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000641 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
642 cERROR(1, ("Illegal length, greater than maximum frame, %d",
643 in_buf->smb_buf_length));
644 return -EIO;
645 }
646
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000647 rc = wait_for_free_request(ses, long_op);
648 if (rc)
649 return rc;
650
Steve French79a58d12007-07-06 22:44:50 +0000651 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 and avoid races inside tcp sendmsg code that could cause corruption
653 of smb data */
654
Jeff Layton72ca5452008-12-01 07:09:36 -0500655 mutex_lock(&ses->server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000657 rc = allocate_mid(ses, in_buf, &midQ);
658 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500659 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000660 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000661 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000662 wake_up(&ses->server->request_q);
663 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 }
665
Steve Frenchad009ac2005-04-28 22:41:05 -0700666 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100667 if (rc) {
668 mutex_unlock(&ses->server->srv_mutex);
669 goto out;
670 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
672 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700673#ifdef CONFIG_CIFS_STATS2
674 atomic_inc(&ses->server->inSend);
675#endif
Jeff Layton0496e022008-12-30 12:39:16 -0500676 rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
Steve French131afd0b2005-10-07 09:51:05 -0700677#ifdef CONFIG_CIFS_STATS2
678 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700679 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700680#endif
Jeff Layton72ca5452008-12-01 07:09:36 -0500681 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000682
Steve French79a58d12007-07-06 22:44:50 +0000683 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000684 goto out;
685
Steve French133672e2007-11-13 22:41:37 +0000686 if (long_op == CIFS_STD_OP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 timeout = 15 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000688 /* wait for 15 seconds or until woken up due to response arriving or
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 due to last connection to this server being unmounted */
Steve French133672e2007-11-13 22:41:37 +0000690 else if (long_op == CIFS_ASYNC_OP)
691 goto out;
692 else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
693 timeout = 180 * HZ;
694 else if (long_op == CIFS_LONG_OP)
695 timeout = 45 * HZ; /* should be greater than
696 servers oplock break timeout (about 43 seconds) */
697 else if (long_op == CIFS_BLOCKING_OP)
698 timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
699 else {
700 cERROR(1, ("unknown timeout flag %d", long_op));
701 rc = -EIO;
702 goto out;
703 }
704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 if (signal_pending(current)) {
706 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000707 but we still give response a chance to complete */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000709 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
711 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000712 wait_for_response(ses, midQ, timeout, 10 * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
714 spin_lock(&GlobalMid_Lock);
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100715 if (midQ->resp_buf == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000716 cERROR(1, ("No response for cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700717 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000718 if (midQ->midState == MID_REQUEST_SUBMITTED) {
719 if (ses->server->tcpStatus == CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 rc = -EHOSTDOWN;
721 else {
722 ses->server->tcpStatus = CifsNeedReconnect;
723 midQ->midState = MID_RETRY_NEEDED;
724 }
725 }
726
727 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000728 if (midQ->midState == MID_RETRY_NEEDED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000730 cFYI(1, ("marking request for retry"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 } else {
732 rc = -EIO;
733 }
734 }
735 spin_unlock(&GlobalMid_Lock);
736 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000737 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000738 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000739 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 return rc;
741 }
Steve French50c2f752007-07-13 00:33:32 +0000742
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100743 spin_unlock(&GlobalMid_Lock);
744 receive_len = midQ->resp_buf->smb_buf_length;
745
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Steve Frenchad009ac2005-04-28 22:41:05 -0700747 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 receive_len, xid));
749 rc = -EIO;
Steve French2b2bdfb2008-12-11 17:26:54 +0000750 goto out;
751 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
Steve French2b2bdfb2008-12-11 17:26:54 +0000753 /* rcvd frame is ok */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
Steve French2b2bdfb2008-12-11 17:26:54 +0000755 if (midQ->resp_buf && out_buf
756 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
757 out_buf->smb_buf_length = receive_len;
758 memcpy((char *)out_buf + 4,
759 (char *)midQ->resp_buf + 4,
760 receive_len);
761
762 dump_smb(out_buf, 92);
763 /* convert the length into a more usable form */
764 if ((receive_len > 24) &&
765 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
766 SECMODE_SIGN_ENABLED))) {
767 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000768 &ses->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -0700769 midQ->sequence_number+1);
Steve French2b2bdfb2008-12-11 17:26:54 +0000770 if (rc) {
771 cERROR(1, ("Unexpected SMB signature"));
772 /* BB FIXME add code to kill session */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 }
Steve French2b2bdfb2008-12-11 17:26:54 +0000775
776 *pbytes_returned = out_buf->smb_buf_length;
777
778 /* BB special case reconnect tid and uid here? */
779 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
780
781 /* convert ByteCount if necessary */
782 if (receive_len >= sizeof(struct smb_hdr) - 4
783 /* do not count RFC1001 header */ +
784 (2 * out_buf->WordCount) + 2 /* bcc */ )
785 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
786 } else {
787 rc = -EIO;
788 cERROR(1, ("Bad MID state?"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000791out:
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000792 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000793 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000794 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 return rc;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000797}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000799/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
800
801static int
802send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
803 struct mid_q_entry *midQ)
804{
805 int rc = 0;
806 struct cifsSesInfo *ses = tcon->ses;
807 __u16 mid = in_buf->Mid;
808
809 header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
810 in_buf->Mid = mid;
Jeff Layton72ca5452008-12-01 07:09:36 -0500811 mutex_lock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000812 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
813 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500814 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000815 return rc;
816 }
Jeff Layton0496e022008-12-30 12:39:16 -0500817 rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
Jeff Layton72ca5452008-12-01 07:09:36 -0500818 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000819 return rc;
820}
821
822/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
823 blocking lock to return. */
824
825static int
826send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
827 struct smb_hdr *in_buf,
828 struct smb_hdr *out_buf)
829{
830 int bytes_returned;
831 struct cifsSesInfo *ses = tcon->ses;
832 LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
833
834 /* We just modify the current in_buf to change
835 the type of lock from LOCKING_ANDX_SHARED_LOCK
836 or LOCKING_ANDX_EXCLUSIVE_LOCK to
837 LOCKING_ANDX_CANCEL_LOCK. */
838
839 pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
840 pSMB->Timeout = 0;
841 pSMB->hdr.Mid = GetNextMid(ses->server);
842
843 return SendReceive(xid, ses, in_buf, out_buf,
Steve French133672e2007-11-13 22:41:37 +0000844 &bytes_returned, CIFS_STD_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000845}
846
847int
848SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
849 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
850 int *pbytes_returned)
851{
852 int rc = 0;
853 int rstart = 0;
854 unsigned int receive_len;
855 struct mid_q_entry *midQ;
856 struct cifsSesInfo *ses;
857
858 if (tcon == NULL || tcon->ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000859 cERROR(1, ("Null smb session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000860 return -EIO;
861 }
862 ses = tcon->ses;
863
Steve French79a58d12007-07-06 22:44:50 +0000864 if (ses->server == NULL) {
865 cERROR(1, ("Null tcp session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000866 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 }
868
Steve French79a58d12007-07-06 22:44:50 +0000869 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000870 return -ENOENT;
871
Steve French79a58d12007-07-06 22:44:50 +0000872 /* Ensure that we do not send more than 50 overlapping requests
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000873 to the same server. We may make this configurable later or
874 use ses->maxReq */
875
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000876 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
877 cERROR(1, ("Illegal length, greater than maximum frame, %d",
878 in_buf->smb_buf_length));
879 return -EIO;
880 }
881
Steve French133672e2007-11-13 22:41:37 +0000882 rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000883 if (rc)
884 return rc;
885
Steve French79a58d12007-07-06 22:44:50 +0000886 /* make sure that we sign in the same order that we send on this socket
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000887 and avoid races inside tcp sendmsg code that could cause corruption
888 of smb data */
889
Jeff Layton72ca5452008-12-01 07:09:36 -0500890 mutex_lock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000891
892 rc = allocate_mid(ses, in_buf, &midQ);
893 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500894 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000895 return rc;
896 }
897
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000898 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100899 if (rc) {
900 DeleteMidQEntry(midQ);
901 mutex_unlock(&ses->server->srv_mutex);
902 return rc;
903 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000904
905 midQ->midState = MID_REQUEST_SUBMITTED;
906#ifdef CONFIG_CIFS_STATS2
907 atomic_inc(&ses->server->inSend);
908#endif
Jeff Layton0496e022008-12-30 12:39:16 -0500909 rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000910#ifdef CONFIG_CIFS_STATS2
911 atomic_dec(&ses->server->inSend);
912 midQ->when_sent = jiffies;
913#endif
Jeff Layton72ca5452008-12-01 07:09:36 -0500914 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000915
Steve French79a58d12007-07-06 22:44:50 +0000916 if (rc < 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000917 DeleteMidQEntry(midQ);
918 return rc;
919 }
920
921 /* Wait for a reply - allow signals to interrupt. */
922 rc = wait_event_interruptible(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000923 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000924 ((ses->server->tcpStatus != CifsGood) &&
925 (ses->server->tcpStatus != CifsNew)));
926
927 /* Were we interrupted by a signal ? */
928 if ((rc == -ERESTARTSYS) &&
929 (midQ->midState == MID_REQUEST_SUBMITTED) &&
930 ((ses->server->tcpStatus == CifsGood) ||
931 (ses->server->tcpStatus == CifsNew))) {
932
933 if (in_buf->Command == SMB_COM_TRANSACTION2) {
934 /* POSIX lock. We send a NT_CANCEL SMB to cause the
935 blocking lock to return. */
936
937 rc = send_nt_cancel(tcon, in_buf, midQ);
938 if (rc) {
939 DeleteMidQEntry(midQ);
940 return rc;
941 }
942 } else {
943 /* Windows lock. We send a LOCKINGX_CANCEL_LOCK
944 to cause the blocking lock to return. */
945
946 rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
947
948 /* If we get -ENOLCK back the lock may have
949 already been removed. Don't exit in this case. */
950 if (rc && rc != -ENOLCK) {
951 DeleteMidQEntry(midQ);
952 return rc;
953 }
954 }
955
956 /* Wait 5 seconds for the response. */
Steve French79a58d12007-07-06 22:44:50 +0000957 if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000958 /* We got the response - restart system call. */
959 rstart = 1;
960 }
961 }
962
963 spin_lock(&GlobalMid_Lock);
964 if (midQ->resp_buf) {
965 spin_unlock(&GlobalMid_Lock);
966 receive_len = midQ->resp_buf->smb_buf_length;
967 } else {
Steve French79a58d12007-07-06 22:44:50 +0000968 cERROR(1, ("No response for cmd %d mid %d",
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000969 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000970 if (midQ->midState == MID_REQUEST_SUBMITTED) {
971 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000972 rc = -EHOSTDOWN;
973 else {
974 ses->server->tcpStatus = CifsNeedReconnect;
975 midQ->midState = MID_RETRY_NEEDED;
976 }
977 }
978
979 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000980 if (midQ->midState == MID_RETRY_NEEDED) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000981 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000982 cFYI(1, ("marking request for retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000983 } else {
984 rc = -EIO;
985 }
986 }
987 spin_unlock(&GlobalMid_Lock);
988 DeleteMidQEntry(midQ);
989 return rc;
990 }
Steve French50c2f752007-07-13 00:33:32 +0000991
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000992 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
993 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
994 receive_len, xid));
995 rc = -EIO;
Volker Lendecke17c8bfe2008-12-06 16:38:19 +0100996 goto out;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000997 }
Volker Lendecke17c8bfe2008-12-06 16:38:19 +0100998
999 /* rcvd frame is ok */
1000
Volker Lendeckeac6a3ef2008-12-06 16:40:40 +01001001 if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) {
Volker Lendecke17c8bfe2008-12-06 16:38:19 +01001002 rc = -EIO;
1003 cERROR(1, ("Bad MID state?"));
Volker Lendecke698e96a2008-12-06 16:39:31 +01001004 goto out;
Volker Lendecke17c8bfe2008-12-06 16:38:19 +01001005 }
1006
Volker Lendecke698e96a2008-12-06 16:39:31 +01001007 out_buf->smb_buf_length = receive_len;
1008 memcpy((char *)out_buf + 4,
1009 (char *)midQ->resp_buf + 4,
1010 receive_len);
1011
1012 dump_smb(out_buf, 92);
1013 /* convert the length into a more usable form */
1014 if ((receive_len > 24) &&
1015 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
1016 SECMODE_SIGN_ENABLED))) {
1017 rc = cifs_verify_signature(out_buf,
1018 &ses->server->mac_signing_key,
1019 midQ->sequence_number+1);
1020 if (rc) {
1021 cERROR(1, ("Unexpected SMB signature"));
1022 /* BB FIXME add code to kill session */
1023 }
1024 }
1025
1026 *pbytes_returned = out_buf->smb_buf_length;
1027
1028 /* BB special case reconnect tid and uid here? */
1029 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
1030
1031 /* convert ByteCount if necessary */
1032 if (receive_len >= sizeof(struct smb_hdr) - 4
1033 /* do not count RFC1001 header */ +
1034 (2 * out_buf->WordCount) + 2 /* bcc */ )
1035 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1036
Volker Lendecke17c8bfe2008-12-06 16:38:19 +01001037out:
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001038 DeleteMidQEntry(midQ);
1039 if (rstart && rc == -EACCES)
1040 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 return rc;
1042}