blob: ff8243a8fe3e955757cf087d53c6dbd5bc6befc1 [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 *
Jeremy Allison7ee1af72006-08-02 21:56:33 +000040AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -070041{
42 struct mid_q_entry *temp;
43
44 if (ses == NULL) {
Steve French275cde12005-04-28 22:41:10 -070045 cERROR(1, ("Null session passed in to AllocMidQEntry"));
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 return NULL;
47 }
48 if (ses->server == NULL) {
49 cERROR(1, ("Null TCP session in AllocMidQEntry"));
50 return NULL;
51 }
Steve French50c2f752007-07-13 00:33:32 +000052
Pekka Enberg232087c2008-09-15 13:22:54 +030053 temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 if (temp == NULL)
55 return temp;
56 else {
Steve French26f57362007-08-30 22:09:15 +000057 memset(temp, 0, sizeof(struct mid_q_entry));
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 temp->mid = smb_buffer->Mid; /* always LE */
59 temp->pid = current->pid;
60 temp->command = smb_buffer->Command;
61 cFYI(1, ("For smb_command %d", temp->command));
Steve French1047abc2005-10-11 19:58:06 -070062 /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
63 /* when mid allocated can be before when sent */
64 temp->when_alloc = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 temp->ses = ses;
66 temp->tsk = current;
67 }
68
69 spin_lock(&GlobalMid_Lock);
70 list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
71 atomic_inc(&midCount);
72 temp->midState = MID_REQUEST_ALLOCATED;
73 spin_unlock(&GlobalMid_Lock);
74 return temp;
75}
76
77static void
78DeleteMidQEntry(struct mid_q_entry *midEntry)
79{
Steve French1047abc2005-10-11 19:58:06 -070080#ifdef CONFIG_CIFS_STATS2
81 unsigned long now;
82#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 spin_lock(&GlobalMid_Lock);
84 midEntry->midState = MID_FREE;
85 list_del(&midEntry->qhead);
86 atomic_dec(&midCount);
87 spin_unlock(&GlobalMid_Lock);
Steve French79a58d12007-07-06 22:44:50 +000088 if (midEntry->largeBuf)
Steve Frenchb8643e12005-04-28 22:41:07 -070089 cifs_buf_release(midEntry->resp_buf);
90 else
91 cifs_small_buf_release(midEntry->resp_buf);
Steve French1047abc2005-10-11 19:58:06 -070092#ifdef CONFIG_CIFS_STATS2
93 now = jiffies;
94 /* commands taking longer than one second are indications that
95 something is wrong, unless it is quite a slow link or server */
Steve French79a58d12007-07-06 22:44:50 +000096 if ((now - midEntry->when_alloc) > HZ) {
97 if ((cifsFYI & CIFS_TIMER) &&
Steve French1047abc2005-10-11 19:58:06 -070098 (midEntry->command != SMB_COM_LOCKING_ANDX)) {
99 printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
100 midEntry->command, midEntry->mid);
101 printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
102 now - midEntry->when_alloc,
103 now - midEntry->when_sent,
104 now - midEntry->when_received);
105 }
106 }
107#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 mempool_free(midEntry, cifs_mid_poolp);
109}
110
111struct oplock_q_entry *
Steve French79a58d12007-07-06 22:44:50 +0000112AllocOplockQEntry(struct inode *pinode, __u16 fid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113{
114 struct oplock_q_entry *temp;
Steve French79a58d12007-07-06 22:44:50 +0000115 if ((pinode == NULL) || (tcon == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 cERROR(1, ("Null parms passed to AllocOplockQEntry"));
117 return NULL;
118 }
119 temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
Christoph Lametere94b1762006-12-06 20:33:17 -0800120 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 if (temp == NULL)
122 return temp;
123 else {
124 temp->pinode = pinode;
125 temp->tcon = tcon;
126 temp->netfid = fid;
127 spin_lock(&GlobalMid_Lock);
128 list_add_tail(&temp->qhead, &GlobalOplock_Q);
129 spin_unlock(&GlobalMid_Lock);
130 }
131 return temp;
132
133}
134
Steve French79a58d12007-07-06 22:44:50 +0000135void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136{
Steve French79a58d12007-07-06 22:44:50 +0000137 spin_lock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 /* should we check if list empty first? */
139 list_del(&oplockEntry->qhead);
140 spin_unlock(&GlobalMid_Lock);
141 kmem_cache_free(cifs_oplock_cachep, oplockEntry);
142}
143
Steve French5d941ca2008-04-15 18:40:48 +0000144
145void DeleteTconOplockQEntries(struct cifsTconInfo *tcon)
146{
147 struct oplock_q_entry *temp;
148
149 if (tcon == NULL)
150 return;
151
152 spin_lock(&GlobalMid_Lock);
153 list_for_each_entry(temp, &GlobalOplock_Q, qhead) {
154 if ((temp->tcon) && (temp->tcon == tcon)) {
155 list_del(&temp->qhead);
156 kmem_cache_free(cifs_oplock_cachep, temp);
157 }
158 }
159 spin_unlock(&GlobalMid_Lock);
160}
161
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162int
163smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000164 unsigned int smb_buf_length, struct sockaddr *sin, bool noblocksnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165{
166 int rc = 0;
167 int i = 0;
168 struct msghdr smb_msg;
169 struct kvec iov;
170 unsigned len = smb_buf_length + 4;
171
Steve French79a58d12007-07-06 22:44:50 +0000172 if (ssocket == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 return -ENOTSOCK; /* BB eventually add reconnect code here */
174 iov.iov_base = smb_buffer;
175 iov.iov_len = len;
176
177 smb_msg.msg_name = sin;
Steve French26f57362007-08-30 22:09:15 +0000178 smb_msg.msg_namelen = sizeof(struct sockaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 smb_msg.msg_control = NULL;
180 smb_msg.msg_controllen = 0;
Steve Frenchedf1ae42008-10-29 00:47:57 +0000181 if (noblocksnd)
182 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
183 else
184 smb_msg.msg_flags = MSG_NOSIGNAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
186 /* smb header is converted in header_assemble. bcc and rest of SMB word
Steve French79a58d12007-07-06 22:44:50 +0000187 area, and byte area if necessary, is converted to littleendian in
188 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 Flags2 is converted in SendReceive */
190
191 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 of length %d", smb_buf_length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 dump_smb(smb_buffer, len);
194
195 while (len > 0) {
196 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
197 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
198 i++;
Steve French3e844692005-10-03 13:37:24 -0700199 /* smaller timeout here than send2 since smaller size */
Steve French79a58d12007-07-06 22:44:50 +0000200 /* Although it may not be required, this also is smaller
201 oplock break time */
202 if (i > 12) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 cERROR(1,
Steve French68058e72005-10-10 10:34:22 -0700204 ("sends on sock %p stuck for 7 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 French5e1253b2005-10-10 14:06:37 -0700214 else
215 i = 0; /* reset i after each successful send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 iov.iov_base += rc;
217 iov.iov_len -= rc;
218 len -= rc;
219 }
220
221 if (rc < 0) {
Steve French79a58d12007-07-06 22:44:50 +0000222 cERROR(1, ("Error %d sending data on socket to server", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 } else {
224 rc = 0;
225 }
226
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000227 /* Don't want to modify the buffer as a
228 side effect of this call. */
229 smb_buffer->smb_buf_length = smb_buf_length;
230
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 return rc;
232}
233
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500234static int
Steve Frenchedf1ae42008-10-29 00:47:57 +0000235smb_send2(struct TCP_Server_Info *server, struct kvec *iov, int n_vec,
236 struct sockaddr *sin, bool noblocksnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
238 int rc = 0;
239 int i = 0;
240 struct msghdr smb_msg;
Steve French3e844692005-10-03 13:37:24 -0700241 struct smb_hdr *smb_buffer = iov[0].iov_base;
242 unsigned int len = iov[0].iov_len;
243 unsigned int total_len;
244 int first_vec = 0;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000245 unsigned int smb_buf_length = smb_buffer->smb_buf_length;
Steve Frenchedf1ae42008-10-29 00:47:57 +0000246 struct socket *ssocket = server->ssocket;
Steve French50c2f752007-07-13 00:33:32 +0000247
Steve French79a58d12007-07-06 22:44:50 +0000248 if (ssocket == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 return -ENOTSOCK; /* BB eventually add reconnect code here */
Steve French3e844692005-10-03 13:37:24 -0700250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 smb_msg.msg_name = sin;
Steve French26f57362007-08-30 22:09:15 +0000252 smb_msg.msg_namelen = sizeof(struct sockaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 smb_msg.msg_control = NULL;
254 smb_msg.msg_controllen = 0;
Steve Frenchedf1ae42008-10-29 00:47:57 +0000255 if (noblocksnd)
256 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
257 else
258 smb_msg.msg_flags = MSG_NOSIGNAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
260 /* smb header is converted in header_assemble. bcc and rest of SMB word
Steve French79a58d12007-07-06 22:44:50 +0000261 area, and byte area if necessary, is converted to littleendian in
262 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 Flags2 is converted in SendReceive */
264
Steve French3e844692005-10-03 13:37:24 -0700265
266 total_len = 0;
267 for (i = 0; i < n_vec; i++)
268 total_len += iov[i].iov_len;
269
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Steve French3e844692005-10-03 13:37:24 -0700271 cFYI(1, ("Sending smb: total_len %d", total_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 dump_smb(smb_buffer, len);
273
Shirish Pargaonkar17680352008-07-29 21:26:13 +0000274 i = 0;
Steve French3e844692005-10-03 13:37:24 -0700275 while (total_len) {
276 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
277 n_vec - first_vec, total_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
279 i++;
Steve French79a58d12007-07-06 22:44:50 +0000280 if (i >= 14) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 cERROR(1,
Steve French68058e72005-10-10 10:34:22 -0700282 ("sends on sock %p stuck for 15 seconds",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 ssocket));
284 rc = -EAGAIN;
285 break;
286 }
Steve French68058e72005-10-10 10:34:22 -0700287 msleep(1 << i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 continue;
289 }
Steve French79a58d12007-07-06 22:44:50 +0000290 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 break;
Steve French3e844692005-10-03 13:37:24 -0700292
Steve French61de8002008-10-30 20:15:22 +0000293 if (rc == total_len) {
294 total_len = 0;
295 break;
296 } else if (rc > total_len) {
297 cERROR(1, ("sent %d requested %d", rc, total_len));
Steve French3e844692005-10-03 13:37:24 -0700298 break;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500299 }
Steve French79a58d12007-07-06 22:44:50 +0000300 if (rc == 0) {
Steve French3e844692005-10-03 13:37:24 -0700301 /* should never happen, letting socket clear before
302 retrying is our only obvious option here */
Steve French79a58d12007-07-06 22:44:50 +0000303 cERROR(1, ("tcp sent no data"));
Steve French3e844692005-10-03 13:37:24 -0700304 msleep(500);
305 continue;
306 }
307 total_len -= rc;
Steve French68058e72005-10-10 10:34:22 -0700308 /* the line below resets i */
Steve French3e844692005-10-03 13:37:24 -0700309 for (i = first_vec; i < n_vec; i++) {
310 if (iov[i].iov_len) {
311 if (rc > iov[i].iov_len) {
312 rc -= iov[i].iov_len;
313 iov[i].iov_len = 0;
314 } else {
315 iov[i].iov_base += rc;
316 iov[i].iov_len -= rc;
317 first_vec = i;
318 break;
319 }
320 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500321 }
Steve French5e1253b2005-10-10 14:06:37 -0700322 i = 0; /* in case we get ENOSPC on the next send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 }
324
Steve Frenchedf1ae42008-10-29 00:47:57 +0000325 if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
326 cFYI(1, ("partial send (%d remaining), terminating session",
327 total_len));
328 /* If we have only sent part of an SMB then the next SMB
329 could be taken as the remainder of this one. We need
330 to kill the socket so the server throws away the partial
331 SMB */
332 server->tcpStatus = CifsNeedReconnect;
333 }
334
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 if (rc < 0) {
Steve French79a58d12007-07-06 22:44:50 +0000336 cERROR(1, ("Error %d sending data on socket to server", rc));
Steve French3e844692005-10-03 13:37:24 -0700337 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000340 /* Don't want to modify the buffer as a
341 side effect of this call. */
342 smb_buffer->smb_buf_length = smb_buf_length;
343
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 return rc;
345}
346
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000347static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
348{
Steve French133672e2007-11-13 22:41:37 +0000349 if (long_op == CIFS_ASYNC_OP) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000350 /* oplock breaks must not be held up */
351 atomic_inc(&ses->server->inFlight);
352 } else {
Steve French79a58d12007-07-06 22:44:50 +0000353 spin_lock(&GlobalMid_Lock);
354 while (1) {
355 if (atomic_read(&ses->server->inFlight) >=
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000356 cifs_max_pending){
357 spin_unlock(&GlobalMid_Lock);
358#ifdef CONFIG_CIFS_STATS2
359 atomic_inc(&ses->server->num_waiters);
360#endif
361 wait_event(ses->server->request_q,
362 atomic_read(&ses->server->inFlight)
363 < cifs_max_pending);
364#ifdef CONFIG_CIFS_STATS2
365 atomic_dec(&ses->server->num_waiters);
366#endif
367 spin_lock(&GlobalMid_Lock);
368 } else {
Steve French79a58d12007-07-06 22:44:50 +0000369 if (ses->server->tcpStatus == CifsExiting) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000370 spin_unlock(&GlobalMid_Lock);
371 return -ENOENT;
372 }
373
Steve French79a58d12007-07-06 22:44:50 +0000374 /* can not count locking commands against total
375 as they are allowed to block on server */
Steve French50c2f752007-07-13 00:33:32 +0000376
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000377 /* update # of requests on the wire to server */
Steve French133672e2007-11-13 22:41:37 +0000378 if (long_op != CIFS_BLOCKING_OP)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000379 atomic_inc(&ses->server->inFlight);
380 spin_unlock(&GlobalMid_Lock);
381 break;
382 }
383 }
384 }
385 return 0;
386}
387
388static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
389 struct mid_q_entry **ppmidQ)
390{
391 if (ses->server->tcpStatus == CifsExiting) {
392 return -ENOENT;
393 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
Steve French79a58d12007-07-06 22:44:50 +0000394 cFYI(1, ("tcp session dead - return to caller to retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000395 return -EAGAIN;
396 } else if (ses->status != CifsGood) {
397 /* check if SMB session is bad because we are setting it up */
Steve French79a58d12007-07-06 22:44:50 +0000398 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
Steve Frenchad7a2922008-02-07 23:25:02 +0000399 (in_buf->Command != SMB_COM_NEGOTIATE))
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000400 return -EAGAIN;
Steve Frenchad7a2922008-02-07 23:25:02 +0000401 /* else ok - we are setting up session */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000402 }
403 *ppmidQ = AllocMidQEntry(in_buf, ses);
Steve French26f57362007-08-30 22:09:15 +0000404 if (*ppmidQ == NULL)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000405 return -ENOMEM;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000406 return 0;
407}
408
Steve French79a58d12007-07-06 22:44:50 +0000409static int wait_for_response(struct cifsSesInfo *ses,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000410 struct mid_q_entry *midQ,
411 unsigned long timeout,
412 unsigned long time_to_wait)
413{
414 unsigned long curr_timeout;
415
416 for (;;) {
417 curr_timeout = timeout + jiffies;
418 wait_event(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000419 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
420 time_after(jiffies, curr_timeout) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000421 ((ses->server->tcpStatus != CifsGood) &&
422 (ses->server->tcpStatus != CifsNew)));
423
424 if (time_after(jiffies, curr_timeout) &&
425 (midQ->midState == MID_REQUEST_SUBMITTED) &&
426 ((ses->server->tcpStatus == CifsGood) ||
427 (ses->server->tcpStatus == CifsNew))) {
428
429 unsigned long lrt;
430
431 /* We timed out. Is the server still
432 sending replies ? */
433 spin_lock(&GlobalMid_Lock);
434 lrt = ses->server->lstrp;
435 spin_unlock(&GlobalMid_Lock);
436
437 /* Calculate time_to_wait past last receive time.
Steve French79a58d12007-07-06 22:44:50 +0000438 Although we prefer not to time out if the
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000439 server is still responding - we will time
Steve French79a58d12007-07-06 22:44:50 +0000440 out if the server takes more than 15 (or 45
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000441 or 180) seconds to respond to this request
Steve French79a58d12007-07-06 22:44:50 +0000442 and has not responded to any request from
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000443 other threads on the client within 10 seconds */
444 lrt += time_to_wait;
445 if (time_after(jiffies, lrt)) {
446 /* No replies for time_to_wait. */
Steve French79a58d12007-07-06 22:44:50 +0000447 cERROR(1, ("server not responding"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000448 return -1;
449 }
450 } else {
451 return 0;
452 }
453 }
454}
455
Steve French133672e2007-11-13 22:41:37 +0000456
457/*
458 *
459 * Send an SMB Request. No response info (other than return code)
460 * needs to be parsed.
461 *
462 * flags indicate the type of request buffer and how long to wait
463 * and whether to log NT STATUS code (error) before mapping it to POSIX error
464 *
465 */
466int
467SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
468 struct smb_hdr *in_buf, int flags)
469{
470 int rc;
471 struct kvec iov[1];
472 int resp_buf_type;
473
474 iov[0].iov_base = (char *)in_buf;
475 iov[0].iov_len = in_buf->smb_buf_length + 4;
476 flags |= CIFS_NO_RESP;
477 rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
Steve French90c81e02008-02-12 20:32:36 +0000478 cFYI(DBG2, ("SendRcvNoRsp flags %d rc %d", flags, rc));
479
Steve French133672e2007-11-13 22:41:37 +0000480 return rc;
481}
482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483int
Steve French79a58d12007-07-06 22:44:50 +0000484SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
485 struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
Steve French133672e2007-11-13 22:41:37 +0000486 const int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
488 int rc = 0;
Steve French133672e2007-11-13 22:41:37 +0000489 int long_op;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500490 unsigned int receive_len;
491 unsigned long timeout;
492 struct mid_q_entry *midQ;
Steve French3e844692005-10-03 13:37:24 -0700493 struct smb_hdr *in_buf = iov[0].iov_base;
Steve French50c2f752007-07-13 00:33:32 +0000494
Steve French133672e2007-11-13 22:41:37 +0000495 long_op = flags & CIFS_TIMEOUT_MASK;
496
Steve Frenchec637e32005-12-12 20:53:18 -0800497 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
Steve French4b8f9302006-02-26 16:41:18 +0000499 if ((ses == NULL) || (ses->server == NULL)) {
500 cifs_small_buf_release(in_buf);
Steve French79a58d12007-07-06 22:44:50 +0000501 cERROR(1, ("Null session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 return -EIO;
503 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
Steve French79a58d12007-07-06 22:44:50 +0000505 if (ses->server->tcpStatus == CifsExiting) {
Steve French4b8f9302006-02-26 16:41:18 +0000506 cifs_small_buf_release(in_buf);
Steve French31ca3bc2005-04-28 22:41:11 -0700507 return -ENOENT;
Steve French4b8f9302006-02-26 16:41:18 +0000508 }
Steve French31ca3bc2005-04-28 22:41:11 -0700509
Steve French79a58d12007-07-06 22:44:50 +0000510 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 to the same server. We may make this configurable later or
512 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000514 rc = wait_for_free_request(ses, long_op);
515 if (rc) {
516 cifs_small_buf_release(in_buf);
517 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000519
Steve French79a58d12007-07-06 22:44:50 +0000520 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 and avoid races inside tcp sendmsg code that could cause corruption
522 of smb data */
523
Steve French79a58d12007-07-06 22:44:50 +0000524 down(&ses->server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000526 rc = allocate_mid(ses, in_buf, &midQ);
527 if (rc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 up(&ses->server->tcpSem);
Steve French4b8f9302006-02-26 16:41:18 +0000529 cifs_small_buf_release(in_buf);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000530 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000531 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000532 wake_up(&ses->server->request_q);
533 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 }
Steve French79a58d12007-07-06 22:44:50 +0000535 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
537 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700538#ifdef CONFIG_CIFS_STATS2
539 atomic_inc(&ses->server->inSend);
540#endif
Steve Frenchedf1ae42008-10-29 00:47:57 +0000541 rc = smb_send2(ses->server, iov, n_vec,
542 (struct sockaddr *) &(ses->server->addr.sockAddr),
543 ses->server->noblocksnd);
Steve French131afd0b2005-10-07 09:51:05 -0700544#ifdef CONFIG_CIFS_STATS2
545 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700546 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700547#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000548
549 up(&ses->server->tcpSem);
550 cifs_small_buf_release(in_buf);
551
Steve French79a58d12007-07-06 22:44:50 +0000552 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000553 goto out;
Steve French4b8f9302006-02-26 16:41:18 +0000554
Steve French133672e2007-11-13 22:41:37 +0000555 if (long_op == CIFS_STD_OP)
556 timeout = 15 * HZ;
557 else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
Steve French37c0eb42005-10-05 14:50:29 -0700558 timeout = 180 * HZ;
Steve French133672e2007-11-13 22:41:37 +0000559 else if (long_op == CIFS_LONG_OP)
Steve French79a58d12007-07-06 22:44:50 +0000560 timeout = 45 * HZ; /* should be greater than
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500561 servers oplock break timeout (about 43 seconds) */
Steve French133672e2007-11-13 22:41:37 +0000562 else if (long_op == CIFS_ASYNC_OP)
563 goto out;
564 else if (long_op == CIFS_BLOCKING_OP)
565 timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */
566 else {
567 cERROR(1, ("unknown timeout flag %d", long_op));
568 rc = -EIO;
569 goto out;
570 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000571
Steve French79a58d12007-07-06 22:44:50 +0000572 /* wait for 15 seconds or until woken up due to response arriving or
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500573 due to last connection to this server being unmounted */
574 if (signal_pending(current)) {
575 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000576 but we still give response a chance to complete */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500577 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000578 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500579
580 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000581 wait_for_response(ses, midQ, timeout, 10 * HZ);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500582
583 spin_lock(&GlobalMid_Lock);
584 if (midQ->resp_buf) {
585 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700586 receive_len = midQ->resp_buf->smb_buf_length;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500587 } else {
Steve French79a58d12007-07-06 22:44:50 +0000588 cERROR(1, ("No response to cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700589 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000590 if (midQ->midState == MID_REQUEST_SUBMITTED) {
591 if (ses->server->tcpStatus == CifsExiting)
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500592 rc = -EHOSTDOWN;
593 else {
594 ses->server->tcpStatus = CifsNeedReconnect;
595 midQ->midState = MID_RETRY_NEEDED;
596 }
597 }
598
599 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000600 if (midQ->midState == MID_RETRY_NEEDED) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500601 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000602 cFYI(1, ("marking request for retry"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500603 } else {
604 rc = -EIO;
605 }
606 }
607 spin_unlock(&GlobalMid_Lock);
608 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000609 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000610 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000611 wake_up(&ses->server->request_q);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500612 return rc;
613 }
Steve French50c2f752007-07-13 00:33:32 +0000614
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500615 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
616 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
617 receive_len, xid));
618 rc = -EIO;
619 } else { /* rcvd frame is ok */
Steve French79a58d12007-07-06 22:44:50 +0000620 if (midQ->resp_buf &&
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500621 (midQ->midState == MID_RESPONSE_RECEIVED)) {
Steve French84afc292005-12-02 13:32:45 -0800622
Steve Frenchec637e32005-12-12 20:53:18 -0800623 iov[0].iov_base = (char *)midQ->resp_buf;
Steve French79a58d12007-07-06 22:44:50 +0000624 if (midQ->largeBuf)
Steve Frenchec637e32005-12-12 20:53:18 -0800625 *pRespBufType = CIFS_LARGE_BUFFER;
626 else
627 *pRespBufType = CIFS_SMALL_BUFFER;
628 iov[0].iov_len = receive_len + 4;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500629
Steve Frenchec637e32005-12-12 20:53:18 -0800630 dump_smb(midQ->resp_buf, 80);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500631 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +0000632 if ((receive_len > 24) &&
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500633 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
634 SECMODE_SIGN_ENABLED))) {
Steve Frenchec637e32005-12-12 20:53:18 -0800635 rc = cifs_verify_signature(midQ->resp_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000636 &ses->server->mac_signing_key,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500637 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +0000638 if (rc) {
639 cERROR(1, ("Unexpected SMB signature"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500640 /* BB FIXME add code to kill session */
641 }
642 }
643
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500644 /* BB special case reconnect tid and uid here? */
Steve French133672e2007-11-13 22:41:37 +0000645 rc = map_smb_to_linux_error(midQ->resp_buf,
646 flags & CIFS_LOG_ERROR);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500647
648 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +0000649 if (receive_len >= sizeof(struct smb_hdr) - 4
650 /* do not count RFC1001 header */ +
Steve Frenchec637e32005-12-12 20:53:18 -0800651 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
Steve French79a58d12007-07-06 22:44:50 +0000652 BCC(midQ->resp_buf) =
Steve Frenchec637e32005-12-12 20:53:18 -0800653 le16_to_cpu(BCC_LE(midQ->resp_buf));
Steve French133672e2007-11-13 22:41:37 +0000654 if ((flags & CIFS_NO_RESP) == 0)
655 midQ->resp_buf = NULL; /* mark it so buf will
656 not be freed by
657 DeleteMidQEntry */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500658 } else {
659 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +0000660 cFYI(1, ("Bad MID state?"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500661 }
662 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000663
664out:
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500665 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000666 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000667 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
669 return rc;
670}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
672int
673SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
674 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
675 int *pbytes_returned, const int long_op)
676{
677 int rc = 0;
678 unsigned int receive_len;
679 unsigned long timeout;
680 struct mid_q_entry *midQ;
681
682 if (ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000683 cERROR(1, ("Null smb session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 return -EIO;
685 }
Steve French79a58d12007-07-06 22:44:50 +0000686 if (ses->server == NULL) {
687 cERROR(1, ("Null tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 return -EIO;
689 }
690
Steve French79a58d12007-07-06 22:44:50 +0000691 if (ses->server->tcpStatus == CifsExiting)
Steve French31ca3bc2005-04-28 22:41:11 -0700692 return -ENOENT;
693
Steve French79a58d12007-07-06 22:44:50 +0000694 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 to the same server. We may make this configurable later or
696 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000698 rc = wait_for_free_request(ses, long_op);
699 if (rc)
700 return rc;
701
Steve French79a58d12007-07-06 22:44:50 +0000702 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 and avoid races inside tcp sendmsg code that could cause corruption
704 of smb data */
705
Steve French79a58d12007-07-06 22:44:50 +0000706 down(&ses->server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000708 rc = allocate_mid(ses, in_buf, &midQ);
709 if (rc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 up(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000711 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000712 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000713 wake_up(&ses->server->request_q);
714 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 }
716
717 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
Steve French26a21b92006-05-31 18:05:34 +0000718 cERROR(1, ("Illegal length, greater than maximum frame, %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 in_buf->smb_buf_length));
720 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000721 up(&ses->server->tcpSem);
722 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000723 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000724 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 return -EIO;
726 }
727
Steve Frenchad009ac2005-04-28 22:41:05 -0700728 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
730 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700731#ifdef CONFIG_CIFS_STATS2
732 atomic_inc(&ses->server->inSend);
733#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000735 (struct sockaddr *) &(ses->server->addr.sockAddr),
736 ses->server->noblocksnd);
Steve French131afd0b2005-10-07 09:51:05 -0700737#ifdef CONFIG_CIFS_STATS2
738 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700739 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700740#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000741 up(&ses->server->tcpSem);
742
Steve French79a58d12007-07-06 22:44:50 +0000743 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000744 goto out;
745
Steve French133672e2007-11-13 22:41:37 +0000746 if (long_op == CIFS_STD_OP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 timeout = 15 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000748 /* wait for 15 seconds or until woken up due to response arriving or
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 due to last connection to this server being unmounted */
Steve French133672e2007-11-13 22:41:37 +0000750 else if (long_op == CIFS_ASYNC_OP)
751 goto out;
752 else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
753 timeout = 180 * HZ;
754 else if (long_op == CIFS_LONG_OP)
755 timeout = 45 * HZ; /* should be greater than
756 servers oplock break timeout (about 43 seconds) */
757 else if (long_op == CIFS_BLOCKING_OP)
758 timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
759 else {
760 cERROR(1, ("unknown timeout flag %d", long_op));
761 rc = -EIO;
762 goto out;
763 }
764
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 if (signal_pending(current)) {
766 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000767 but we still give response a chance to complete */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
771 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000772 wait_for_response(ses, midQ, timeout, 10 * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
774 spin_lock(&GlobalMid_Lock);
775 if (midQ->resp_buf) {
776 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700777 receive_len = midQ->resp_buf->smb_buf_length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 } else {
Steve French79a58d12007-07-06 22:44:50 +0000779 cERROR(1, ("No response for cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700780 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000781 if (midQ->midState == MID_REQUEST_SUBMITTED) {
782 if (ses->server->tcpStatus == CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 rc = -EHOSTDOWN;
784 else {
785 ses->server->tcpStatus = CifsNeedReconnect;
786 midQ->midState = MID_RETRY_NEEDED;
787 }
788 }
789
790 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000791 if (midQ->midState == MID_RETRY_NEEDED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000793 cFYI(1, ("marking request for retry"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 } else {
795 rc = -EIO;
796 }
797 }
798 spin_unlock(&GlobalMid_Lock);
799 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000800 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000801 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000802 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 return rc;
804 }
Steve French50c2f752007-07-13 00:33:32 +0000805
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Steve Frenchad009ac2005-04-28 22:41:05 -0700807 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 receive_len, xid));
809 rc = -EIO;
810 } else { /* rcvd frame is ok */
811
812 if (midQ->resp_buf && out_buf
813 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
814 out_buf->smb_buf_length = receive_len;
815 memcpy((char *)out_buf + 4,
816 (char *)midQ->resp_buf + 4,
817 receive_len);
818
819 dump_smb(out_buf, 92);
820 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +0000821 if ((receive_len > 24) &&
Steve Frenchad009ac2005-04-28 22:41:05 -0700822 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
823 SECMODE_SIGN_ENABLED))) {
824 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000825 &ses->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -0700826 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +0000827 if (rc) {
828 cERROR(1, ("Unexpected SMB signature"));
Steve French275cde12005-04-28 22:41:10 -0700829 /* BB FIXME add code to kill session */
Steve Frenchad009ac2005-04-28 22:41:05 -0700830 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 }
832
833 *pbytes_returned = out_buf->smb_buf_length;
834
Steve Frenchad009ac2005-04-28 22:41:05 -0700835 /* BB special case reconnect tid and uid here? */
Steve Frencha761ac52007-10-18 21:45:27 +0000836 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
838 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +0000839 if (receive_len >= sizeof(struct smb_hdr) - 4
840 /* do not count RFC1001 header */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 (2 * out_buf->WordCount) + 2 /* bcc */ )
Steve French0f2b27c2005-11-16 14:25:50 -0800842 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 } else {
844 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +0000845 cERROR(1, ("Bad MID state?"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 }
847 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000849out:
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000850 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000851 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000852 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
854 return rc;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000855}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000857/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
858
859static int
860send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
861 struct mid_q_entry *midQ)
862{
863 int rc = 0;
864 struct cifsSesInfo *ses = tcon->ses;
865 __u16 mid = in_buf->Mid;
866
867 header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
868 in_buf->Mid = mid;
Steve French79a58d12007-07-06 22:44:50 +0000869 down(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000870 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
871 if (rc) {
872 up(&ses->server->tcpSem);
873 return rc;
874 }
875 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000876 (struct sockaddr *) &(ses->server->addr.sockAddr),
877 ses->server->noblocksnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 up(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000879 return rc;
880}
881
882/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
883 blocking lock to return. */
884
885static int
886send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
887 struct smb_hdr *in_buf,
888 struct smb_hdr *out_buf)
889{
890 int bytes_returned;
891 struct cifsSesInfo *ses = tcon->ses;
892 LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
893
894 /* We just modify the current in_buf to change
895 the type of lock from LOCKING_ANDX_SHARED_LOCK
896 or LOCKING_ANDX_EXCLUSIVE_LOCK to
897 LOCKING_ANDX_CANCEL_LOCK. */
898
899 pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
900 pSMB->Timeout = 0;
901 pSMB->hdr.Mid = GetNextMid(ses->server);
902
903 return SendReceive(xid, ses, in_buf, out_buf,
Steve French133672e2007-11-13 22:41:37 +0000904 &bytes_returned, CIFS_STD_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000905}
906
907int
908SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
909 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
910 int *pbytes_returned)
911{
912 int rc = 0;
913 int rstart = 0;
914 unsigned int receive_len;
915 struct mid_q_entry *midQ;
916 struct cifsSesInfo *ses;
917
918 if (tcon == NULL || tcon->ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000919 cERROR(1, ("Null smb session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000920 return -EIO;
921 }
922 ses = tcon->ses;
923
Steve French79a58d12007-07-06 22:44:50 +0000924 if (ses->server == NULL) {
925 cERROR(1, ("Null tcp session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000926 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 }
928
Steve French79a58d12007-07-06 22:44:50 +0000929 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000930 return -ENOENT;
931
Steve French79a58d12007-07-06 22:44:50 +0000932 /* Ensure that we do not send more than 50 overlapping requests
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000933 to the same server. We may make this configurable later or
934 use ses->maxReq */
935
Steve French133672e2007-11-13 22:41:37 +0000936 rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000937 if (rc)
938 return rc;
939
Steve French79a58d12007-07-06 22:44:50 +0000940 /* make sure that we sign in the same order that we send on this socket
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000941 and avoid races inside tcp sendmsg code that could cause corruption
942 of smb data */
943
Steve French79a58d12007-07-06 22:44:50 +0000944 down(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000945
946 rc = allocate_mid(ses, in_buf, &midQ);
947 if (rc) {
948 up(&ses->server->tcpSem);
949 return rc;
950 }
951
952 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
953 up(&ses->server->tcpSem);
954 cERROR(1, ("Illegal length, greater than maximum frame, %d",
955 in_buf->smb_buf_length));
956 DeleteMidQEntry(midQ);
957 return -EIO;
958 }
959
960 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
961
962 midQ->midState = MID_REQUEST_SUBMITTED;
963#ifdef CONFIG_CIFS_STATS2
964 atomic_inc(&ses->server->inSend);
965#endif
966 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000967 (struct sockaddr *) &(ses->server->addr.sockAddr),
968 ses->server->noblocksnd);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000969#ifdef CONFIG_CIFS_STATS2
970 atomic_dec(&ses->server->inSend);
971 midQ->when_sent = jiffies;
972#endif
973 up(&ses->server->tcpSem);
974
Steve French79a58d12007-07-06 22:44:50 +0000975 if (rc < 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000976 DeleteMidQEntry(midQ);
977 return rc;
978 }
979
980 /* Wait for a reply - allow signals to interrupt. */
981 rc = wait_event_interruptible(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000982 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000983 ((ses->server->tcpStatus != CifsGood) &&
984 (ses->server->tcpStatus != CifsNew)));
985
986 /* Were we interrupted by a signal ? */
987 if ((rc == -ERESTARTSYS) &&
988 (midQ->midState == MID_REQUEST_SUBMITTED) &&
989 ((ses->server->tcpStatus == CifsGood) ||
990 (ses->server->tcpStatus == CifsNew))) {
991
992 if (in_buf->Command == SMB_COM_TRANSACTION2) {
993 /* POSIX lock. We send a NT_CANCEL SMB to cause the
994 blocking lock to return. */
995
996 rc = send_nt_cancel(tcon, in_buf, midQ);
997 if (rc) {
998 DeleteMidQEntry(midQ);
999 return rc;
1000 }
1001 } else {
1002 /* Windows lock. We send a LOCKINGX_CANCEL_LOCK
1003 to cause the blocking lock to return. */
1004
1005 rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
1006
1007 /* If we get -ENOLCK back the lock may have
1008 already been removed. Don't exit in this case. */
1009 if (rc && rc != -ENOLCK) {
1010 DeleteMidQEntry(midQ);
1011 return rc;
1012 }
1013 }
1014
1015 /* Wait 5 seconds for the response. */
Steve French79a58d12007-07-06 22:44:50 +00001016 if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001017 /* We got the response - restart system call. */
1018 rstart = 1;
1019 }
1020 }
1021
1022 spin_lock(&GlobalMid_Lock);
1023 if (midQ->resp_buf) {
1024 spin_unlock(&GlobalMid_Lock);
1025 receive_len = midQ->resp_buf->smb_buf_length;
1026 } else {
Steve French79a58d12007-07-06 22:44:50 +00001027 cERROR(1, ("No response for cmd %d mid %d",
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001028 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +00001029 if (midQ->midState == MID_REQUEST_SUBMITTED) {
1030 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001031 rc = -EHOSTDOWN;
1032 else {
1033 ses->server->tcpStatus = CifsNeedReconnect;
1034 midQ->midState = MID_RETRY_NEEDED;
1035 }
1036 }
1037
1038 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +00001039 if (midQ->midState == MID_RETRY_NEEDED) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001040 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +00001041 cFYI(1, ("marking request for retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001042 } else {
1043 rc = -EIO;
1044 }
1045 }
1046 spin_unlock(&GlobalMid_Lock);
1047 DeleteMidQEntry(midQ);
1048 return rc;
1049 }
Steve French50c2f752007-07-13 00:33:32 +00001050
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001051 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
1052 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
1053 receive_len, xid));
1054 rc = -EIO;
1055 } else { /* rcvd frame is ok */
1056
1057 if (midQ->resp_buf && out_buf
1058 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
1059 out_buf->smb_buf_length = receive_len;
1060 memcpy((char *)out_buf + 4,
1061 (char *)midQ->resp_buf + 4,
1062 receive_len);
1063
1064 dump_smb(out_buf, 92);
1065 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +00001066 if ((receive_len > 24) &&
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001067 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
1068 SECMODE_SIGN_ENABLED))) {
1069 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +00001070 &ses->server->mac_signing_key,
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001071 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +00001072 if (rc) {
1073 cERROR(1, ("Unexpected SMB signature"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001074 /* BB FIXME add code to kill session */
1075 }
1076 }
1077
1078 *pbytes_returned = out_buf->smb_buf_length;
1079
1080 /* BB special case reconnect tid and uid here? */
Steve Frencha761ac52007-10-18 21:45:27 +00001081 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001082
1083 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +00001084 if (receive_len >= sizeof(struct smb_hdr) - 4
1085 /* do not count RFC1001 header */ +
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001086 (2 * out_buf->WordCount) + 2 /* bcc */ )
1087 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1088 } else {
1089 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +00001090 cERROR(1, ("Bad MID state?"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001091 }
1092 }
1093 DeleteMidQEntry(midQ);
1094 if (rstart && rc == -EACCES)
1095 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 return rc;
1097}