blob: 8e0d1c397c73c2cdac65b5e90aa33a22987a896f [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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157int
158smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000159 unsigned int smb_buf_length, struct sockaddr *sin, bool noblocksnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160{
161 int rc = 0;
162 int i = 0;
163 struct msghdr smb_msg;
164 struct kvec iov;
165 unsigned len = smb_buf_length + 4;
166
Steve French79a58d12007-07-06 22:44:50 +0000167 if (ssocket == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 return -ENOTSOCK; /* BB eventually add reconnect code here */
169 iov.iov_base = smb_buffer;
170 iov.iov_len = len;
171
172 smb_msg.msg_name = sin;
Steve French26f57362007-08-30 22:09:15 +0000173 smb_msg.msg_namelen = sizeof(struct sockaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 smb_msg.msg_control = NULL;
175 smb_msg.msg_controllen = 0;
Steve Frenchedf1ae42008-10-29 00:47:57 +0000176 if (noblocksnd)
177 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
178 else
179 smb_msg.msg_flags = MSG_NOSIGNAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
181 /* smb header is converted in header_assemble. bcc and rest of SMB word
Steve French79a58d12007-07-06 22:44:50 +0000182 area, and byte area if necessary, is converted to littleendian in
183 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 Flags2 is converted in SendReceive */
185
186 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Steve French3e844692005-10-03 13:37:24 -0700187 cFYI(1, ("Sending smb of length %d", smb_buf_length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 dump_smb(smb_buffer, len);
189
190 while (len > 0) {
191 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
192 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
193 i++;
Steve French3e844692005-10-03 13:37:24 -0700194 /* smaller timeout here than send2 since smaller size */
Steve French79a58d12007-07-06 22:44:50 +0000195 /* Although it may not be required, this also is smaller
196 oplock break time */
197 if (i > 12) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 cERROR(1,
Steve French68058e72005-10-10 10:34:22 -0700199 ("sends on sock %p stuck for 7 seconds",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 ssocket));
201 rc = -EAGAIN;
202 break;
203 }
Steve French68058e72005-10-10 10:34:22 -0700204 msleep(1 << i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 continue;
206 }
Steve French79a58d12007-07-06 22:44:50 +0000207 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 break;
Steve French5e1253b2005-10-10 14:06:37 -0700209 else
210 i = 0; /* reset i after each successful send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 iov.iov_base += rc;
212 iov.iov_len -= rc;
213 len -= rc;
214 }
215
216 if (rc < 0) {
Steve French79a58d12007-07-06 22:44:50 +0000217 cERROR(1, ("Error %d sending data on socket to server", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 } else {
219 rc = 0;
220 }
221
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000222 /* Don't want to modify the buffer as a
223 side effect of this call. */
224 smb_buffer->smb_buf_length = smb_buf_length;
225
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 return rc;
227}
228
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500229static int
Steve Frenchedf1ae42008-10-29 00:47:57 +0000230smb_send2(struct TCP_Server_Info *server, struct kvec *iov, int n_vec,
231 struct sockaddr *sin, bool noblocksnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232{
233 int rc = 0;
234 int i = 0;
235 struct msghdr smb_msg;
Steve French3e844692005-10-03 13:37:24 -0700236 struct smb_hdr *smb_buffer = iov[0].iov_base;
237 unsigned int len = iov[0].iov_len;
238 unsigned int total_len;
239 int first_vec = 0;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000240 unsigned int smb_buf_length = smb_buffer->smb_buf_length;
Steve Frenchedf1ae42008-10-29 00:47:57 +0000241 struct socket *ssocket = server->ssocket;
Steve French50c2f752007-07-13 00:33:32 +0000242
Steve French79a58d12007-07-06 22:44:50 +0000243 if (ssocket == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 return -ENOTSOCK; /* BB eventually add reconnect code here */
Steve French3e844692005-10-03 13:37:24 -0700245
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 smb_msg.msg_name = sin;
Steve French26f57362007-08-30 22:09:15 +0000247 smb_msg.msg_namelen = sizeof(struct sockaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 smb_msg.msg_control = NULL;
249 smb_msg.msg_controllen = 0;
Steve Frenchedf1ae42008-10-29 00:47:57 +0000250 if (noblocksnd)
251 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
252 else
253 smb_msg.msg_flags = MSG_NOSIGNAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
255 /* smb header is converted in header_assemble. bcc and rest of SMB word
Steve French79a58d12007-07-06 22:44:50 +0000256 area, and byte area if necessary, is converted to littleendian in
257 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 Flags2 is converted in SendReceive */
259
Steve French3e844692005-10-03 13:37:24 -0700260
261 total_len = 0;
262 for (i = 0; i < n_vec; i++)
263 total_len += iov[i].iov_len;
264
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Steve French3e844692005-10-03 13:37:24 -0700266 cFYI(1, ("Sending smb: total_len %d", total_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 dump_smb(smb_buffer, len);
268
Shirish Pargaonkar17680352008-07-29 21:26:13 +0000269 i = 0;
Steve French3e844692005-10-03 13:37:24 -0700270 while (total_len) {
271 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
272 n_vec - first_vec, total_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
274 i++;
Steve French79a58d12007-07-06 22:44:50 +0000275 if (i >= 14) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 cERROR(1,
Steve French68058e72005-10-10 10:34:22 -0700277 ("sends on sock %p stuck for 15 seconds",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 ssocket));
279 rc = -EAGAIN;
280 break;
281 }
Steve French68058e72005-10-10 10:34:22 -0700282 msleep(1 << i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 continue;
284 }
Steve French79a58d12007-07-06 22:44:50 +0000285 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 break;
Steve French3e844692005-10-03 13:37:24 -0700287
Steve French61de8002008-10-30 20:15:22 +0000288 if (rc == total_len) {
289 total_len = 0;
290 break;
291 } else if (rc > total_len) {
292 cERROR(1, ("sent %d requested %d", rc, total_len));
Steve French3e844692005-10-03 13:37:24 -0700293 break;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500294 }
Steve French79a58d12007-07-06 22:44:50 +0000295 if (rc == 0) {
Steve French3e844692005-10-03 13:37:24 -0700296 /* should never happen, letting socket clear before
297 retrying is our only obvious option here */
Steve French79a58d12007-07-06 22:44:50 +0000298 cERROR(1, ("tcp sent no data"));
Steve French3e844692005-10-03 13:37:24 -0700299 msleep(500);
300 continue;
301 }
302 total_len -= rc;
Steve French68058e72005-10-10 10:34:22 -0700303 /* the line below resets i */
Steve French3e844692005-10-03 13:37:24 -0700304 for (i = first_vec; i < n_vec; i++) {
305 if (iov[i].iov_len) {
306 if (rc > iov[i].iov_len) {
307 rc -= iov[i].iov_len;
308 iov[i].iov_len = 0;
309 } else {
310 iov[i].iov_base += rc;
311 iov[i].iov_len -= rc;
312 first_vec = i;
313 break;
314 }
315 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500316 }
Steve French5e1253b2005-10-10 14:06:37 -0700317 i = 0; /* in case we get ENOSPC on the next send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 }
319
Steve Frenchedf1ae42008-10-29 00:47:57 +0000320 if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
321 cFYI(1, ("partial send (%d remaining), terminating session",
322 total_len));
323 /* If we have only sent part of an SMB then the next SMB
324 could be taken as the remainder of this one. We need
325 to kill the socket so the server throws away the partial
326 SMB */
327 server->tcpStatus = CifsNeedReconnect;
328 }
329
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 if (rc < 0) {
Steve French79a58d12007-07-06 22:44:50 +0000331 cERROR(1, ("Error %d sending data on socket to server", rc));
Steve French3e844692005-10-03 13:37:24 -0700332 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000335 /* Don't want to modify the buffer as a
336 side effect of this call. */
337 smb_buffer->smb_buf_length = smb_buf_length;
338
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 return rc;
340}
341
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000342static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
343{
Steve French133672e2007-11-13 22:41:37 +0000344 if (long_op == CIFS_ASYNC_OP) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000345 /* oplock breaks must not be held up */
346 atomic_inc(&ses->server->inFlight);
347 } else {
Steve French79a58d12007-07-06 22:44:50 +0000348 spin_lock(&GlobalMid_Lock);
349 while (1) {
350 if (atomic_read(&ses->server->inFlight) >=
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000351 cifs_max_pending){
352 spin_unlock(&GlobalMid_Lock);
353#ifdef CONFIG_CIFS_STATS2
354 atomic_inc(&ses->server->num_waiters);
355#endif
356 wait_event(ses->server->request_q,
357 atomic_read(&ses->server->inFlight)
358 < cifs_max_pending);
359#ifdef CONFIG_CIFS_STATS2
360 atomic_dec(&ses->server->num_waiters);
361#endif
362 spin_lock(&GlobalMid_Lock);
363 } else {
Steve French79a58d12007-07-06 22:44:50 +0000364 if (ses->server->tcpStatus == CifsExiting) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000365 spin_unlock(&GlobalMid_Lock);
366 return -ENOENT;
367 }
368
Steve French79a58d12007-07-06 22:44:50 +0000369 /* can not count locking commands against total
370 as they are allowed to block on server */
Steve French50c2f752007-07-13 00:33:32 +0000371
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000372 /* update # of requests on the wire to server */
Steve French133672e2007-11-13 22:41:37 +0000373 if (long_op != CIFS_BLOCKING_OP)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000374 atomic_inc(&ses->server->inFlight);
375 spin_unlock(&GlobalMid_Lock);
376 break;
377 }
378 }
379 }
380 return 0;
381}
382
383static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
384 struct mid_q_entry **ppmidQ)
385{
386 if (ses->server->tcpStatus == CifsExiting) {
387 return -ENOENT;
388 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
Steve French79a58d12007-07-06 22:44:50 +0000389 cFYI(1, ("tcp session dead - return to caller to retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000390 return -EAGAIN;
391 } else if (ses->status != CifsGood) {
392 /* check if SMB session is bad because we are setting it up */
Steve French79a58d12007-07-06 22:44:50 +0000393 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
Steve Frenchad7a2922008-02-07 23:25:02 +0000394 (in_buf->Command != SMB_COM_NEGOTIATE))
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000395 return -EAGAIN;
Steve Frenchad7a2922008-02-07 23:25:02 +0000396 /* else ok - we are setting up session */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000397 }
Jeff Layton24b9b062008-12-01 07:09:34 -0500398 *ppmidQ = AllocMidQEntry(in_buf, ses->server);
Steve French26f57362007-08-30 22:09:15 +0000399 if (*ppmidQ == NULL)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000400 return -ENOMEM;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000401 return 0;
402}
403
Steve French79a58d12007-07-06 22:44:50 +0000404static int wait_for_response(struct cifsSesInfo *ses,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000405 struct mid_q_entry *midQ,
406 unsigned long timeout,
407 unsigned long time_to_wait)
408{
409 unsigned long curr_timeout;
410
411 for (;;) {
412 curr_timeout = timeout + jiffies;
413 wait_event(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000414 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
415 time_after(jiffies, curr_timeout) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000416 ((ses->server->tcpStatus != CifsGood) &&
417 (ses->server->tcpStatus != CifsNew)));
418
419 if (time_after(jiffies, curr_timeout) &&
420 (midQ->midState == MID_REQUEST_SUBMITTED) &&
421 ((ses->server->tcpStatus == CifsGood) ||
422 (ses->server->tcpStatus == CifsNew))) {
423
424 unsigned long lrt;
425
426 /* We timed out. Is the server still
427 sending replies ? */
428 spin_lock(&GlobalMid_Lock);
429 lrt = ses->server->lstrp;
430 spin_unlock(&GlobalMid_Lock);
431
432 /* Calculate time_to_wait past last receive time.
Steve French79a58d12007-07-06 22:44:50 +0000433 Although we prefer not to time out if the
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000434 server is still responding - we will time
Steve French79a58d12007-07-06 22:44:50 +0000435 out if the server takes more than 15 (or 45
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000436 or 180) seconds to respond to this request
Steve French79a58d12007-07-06 22:44:50 +0000437 and has not responded to any request from
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000438 other threads on the client within 10 seconds */
439 lrt += time_to_wait;
440 if (time_after(jiffies, lrt)) {
441 /* No replies for time_to_wait. */
Steve French79a58d12007-07-06 22:44:50 +0000442 cERROR(1, ("server not responding"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000443 return -1;
444 }
445 } else {
446 return 0;
447 }
448 }
449}
450
Steve French133672e2007-11-13 22:41:37 +0000451
452/*
453 *
454 * Send an SMB Request. No response info (other than return code)
455 * needs to be parsed.
456 *
457 * flags indicate the type of request buffer and how long to wait
458 * and whether to log NT STATUS code (error) before mapping it to POSIX error
459 *
460 */
461int
462SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
463 struct smb_hdr *in_buf, int flags)
464{
465 int rc;
466 struct kvec iov[1];
467 int resp_buf_type;
468
469 iov[0].iov_base = (char *)in_buf;
470 iov[0].iov_len = in_buf->smb_buf_length + 4;
471 flags |= CIFS_NO_RESP;
472 rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
Steve French90c81e02008-02-12 20:32:36 +0000473 cFYI(DBG2, ("SendRcvNoRsp flags %d rc %d", flags, rc));
474
Steve French133672e2007-11-13 22:41:37 +0000475 return rc;
476}
477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478int
Steve French79a58d12007-07-06 22:44:50 +0000479SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
480 struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
Steve French133672e2007-11-13 22:41:37 +0000481 const int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
483 int rc = 0;
Steve French133672e2007-11-13 22:41:37 +0000484 int long_op;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500485 unsigned int receive_len;
486 unsigned long timeout;
487 struct mid_q_entry *midQ;
Steve French3e844692005-10-03 13:37:24 -0700488 struct smb_hdr *in_buf = iov[0].iov_base;
Steve French50c2f752007-07-13 00:33:32 +0000489
Steve French133672e2007-11-13 22:41:37 +0000490 long_op = flags & CIFS_TIMEOUT_MASK;
491
Steve Frenchec637e32005-12-12 20:53:18 -0800492 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493
Steve French4b8f9302006-02-26 16:41:18 +0000494 if ((ses == NULL) || (ses->server == NULL)) {
495 cifs_small_buf_release(in_buf);
Steve French79a58d12007-07-06 22:44:50 +0000496 cERROR(1, ("Null session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 return -EIO;
498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
Steve French79a58d12007-07-06 22:44:50 +0000500 if (ses->server->tcpStatus == CifsExiting) {
Steve French4b8f9302006-02-26 16:41:18 +0000501 cifs_small_buf_release(in_buf);
Steve French31ca3bc2005-04-28 22:41:11 -0700502 return -ENOENT;
Steve French4b8f9302006-02-26 16:41:18 +0000503 }
Steve French31ca3bc2005-04-28 22:41:11 -0700504
Steve French79a58d12007-07-06 22:44:50 +0000505 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 to the same server. We may make this configurable later or
507 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000509 rc = wait_for_free_request(ses, long_op);
510 if (rc) {
511 cifs_small_buf_release(in_buf);
512 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000514
Steve French79a58d12007-07-06 22:44:50 +0000515 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 and avoid races inside tcp sendmsg code that could cause corruption
517 of smb data */
518
Steve French79a58d12007-07-06 22:44:50 +0000519 down(&ses->server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000521 rc = allocate_mid(ses, in_buf, &midQ);
522 if (rc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 up(&ses->server->tcpSem);
Steve French4b8f9302006-02-26 16:41:18 +0000524 cifs_small_buf_release(in_buf);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000525 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000526 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000527 wake_up(&ses->server->request_q);
528 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 }
Steve French79a58d12007-07-06 22:44:50 +0000530 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
532 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700533#ifdef CONFIG_CIFS_STATS2
534 atomic_inc(&ses->server->inSend);
535#endif
Steve Frenchedf1ae42008-10-29 00:47:57 +0000536 rc = smb_send2(ses->server, iov, n_vec,
537 (struct sockaddr *) &(ses->server->addr.sockAddr),
538 ses->server->noblocksnd);
Steve French131afd0b2005-10-07 09:51:05 -0700539#ifdef CONFIG_CIFS_STATS2
540 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700541 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700542#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000543
544 up(&ses->server->tcpSem);
545 cifs_small_buf_release(in_buf);
546
Steve French79a58d12007-07-06 22:44:50 +0000547 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000548 goto out;
Steve French4b8f9302006-02-26 16:41:18 +0000549
Steve French133672e2007-11-13 22:41:37 +0000550 if (long_op == CIFS_STD_OP)
551 timeout = 15 * HZ;
552 else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
Steve French37c0eb42005-10-05 14:50:29 -0700553 timeout = 180 * HZ;
Steve French133672e2007-11-13 22:41:37 +0000554 else if (long_op == CIFS_LONG_OP)
Steve French79a58d12007-07-06 22:44:50 +0000555 timeout = 45 * HZ; /* should be greater than
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500556 servers oplock break timeout (about 43 seconds) */
Steve French133672e2007-11-13 22:41:37 +0000557 else if (long_op == CIFS_ASYNC_OP)
558 goto out;
559 else if (long_op == CIFS_BLOCKING_OP)
560 timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */
561 else {
562 cERROR(1, ("unknown timeout flag %d", long_op));
563 rc = -EIO;
564 goto out;
565 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000566
Steve French79a58d12007-07-06 22:44:50 +0000567 /* wait for 15 seconds or until woken up due to response arriving or
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500568 due to last connection to this server being unmounted */
569 if (signal_pending(current)) {
570 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000571 but we still give response a chance to complete */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500572 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000573 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500574
575 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000576 wait_for_response(ses, midQ, timeout, 10 * HZ);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500577
578 spin_lock(&GlobalMid_Lock);
579 if (midQ->resp_buf) {
580 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700581 receive_len = midQ->resp_buf->smb_buf_length;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500582 } else {
Steve French79a58d12007-07-06 22:44:50 +0000583 cERROR(1, ("No response to cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700584 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000585 if (midQ->midState == MID_REQUEST_SUBMITTED) {
586 if (ses->server->tcpStatus == CifsExiting)
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500587 rc = -EHOSTDOWN;
588 else {
589 ses->server->tcpStatus = CifsNeedReconnect;
590 midQ->midState = MID_RETRY_NEEDED;
591 }
592 }
593
594 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000595 if (midQ->midState == MID_RETRY_NEEDED) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500596 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000597 cFYI(1, ("marking request for retry"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500598 } else {
599 rc = -EIO;
600 }
601 }
602 spin_unlock(&GlobalMid_Lock);
603 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000604 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000605 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000606 wake_up(&ses->server->request_q);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500607 return rc;
608 }
Steve French50c2f752007-07-13 00:33:32 +0000609
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500610 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
611 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
612 receive_len, xid));
613 rc = -EIO;
614 } else { /* rcvd frame is ok */
Steve French79a58d12007-07-06 22:44:50 +0000615 if (midQ->resp_buf &&
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500616 (midQ->midState == MID_RESPONSE_RECEIVED)) {
Steve French84afc292005-12-02 13:32:45 -0800617
Steve Frenchec637e32005-12-12 20:53:18 -0800618 iov[0].iov_base = (char *)midQ->resp_buf;
Steve French79a58d12007-07-06 22:44:50 +0000619 if (midQ->largeBuf)
Steve Frenchec637e32005-12-12 20:53:18 -0800620 *pRespBufType = CIFS_LARGE_BUFFER;
621 else
622 *pRespBufType = CIFS_SMALL_BUFFER;
623 iov[0].iov_len = receive_len + 4;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500624
Steve Frenchec637e32005-12-12 20:53:18 -0800625 dump_smb(midQ->resp_buf, 80);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500626 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +0000627 if ((receive_len > 24) &&
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500628 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
629 SECMODE_SIGN_ENABLED))) {
Steve Frenchec637e32005-12-12 20:53:18 -0800630 rc = cifs_verify_signature(midQ->resp_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000631 &ses->server->mac_signing_key,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500632 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +0000633 if (rc) {
634 cERROR(1, ("Unexpected SMB signature"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500635 /* BB FIXME add code to kill session */
636 }
637 }
638
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500639 /* BB special case reconnect tid and uid here? */
Steve French133672e2007-11-13 22:41:37 +0000640 rc = map_smb_to_linux_error(midQ->resp_buf,
641 flags & CIFS_LOG_ERROR);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500642
643 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +0000644 if (receive_len >= sizeof(struct smb_hdr) - 4
645 /* do not count RFC1001 header */ +
Steve Frenchec637e32005-12-12 20:53:18 -0800646 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
Steve French79a58d12007-07-06 22:44:50 +0000647 BCC(midQ->resp_buf) =
Steve Frenchec637e32005-12-12 20:53:18 -0800648 le16_to_cpu(BCC_LE(midQ->resp_buf));
Steve French133672e2007-11-13 22:41:37 +0000649 if ((flags & CIFS_NO_RESP) == 0)
650 midQ->resp_buf = NULL; /* mark it so buf will
651 not be freed by
652 DeleteMidQEntry */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500653 } else {
654 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +0000655 cFYI(1, ("Bad MID state?"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500656 }
657 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000658
659out:
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500660 DeleteMidQEntry(midQ);
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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
664 return rc;
665}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
667int
668SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
669 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
670 int *pbytes_returned, const int long_op)
671{
672 int rc = 0;
673 unsigned int receive_len;
674 unsigned long timeout;
675 struct mid_q_entry *midQ;
676
677 if (ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000678 cERROR(1, ("Null smb session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 return -EIO;
680 }
Steve French79a58d12007-07-06 22:44:50 +0000681 if (ses->server == NULL) {
682 cERROR(1, ("Null tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 return -EIO;
684 }
685
Steve French79a58d12007-07-06 22:44:50 +0000686 if (ses->server->tcpStatus == CifsExiting)
Steve French31ca3bc2005-04-28 22:41:11 -0700687 return -ENOENT;
688
Steve French79a58d12007-07-06 22:44:50 +0000689 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 to the same server. We may make this configurable later or
691 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000693 rc = wait_for_free_request(ses, long_op);
694 if (rc)
695 return rc;
696
Steve French79a58d12007-07-06 22:44:50 +0000697 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 and avoid races inside tcp sendmsg code that could cause corruption
699 of smb data */
700
Steve French79a58d12007-07-06 22:44:50 +0000701 down(&ses->server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000703 rc = allocate_mid(ses, in_buf, &midQ);
704 if (rc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 up(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000706 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000707 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000708 wake_up(&ses->server->request_q);
709 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 }
711
712 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
Steve French26a21b92006-05-31 18:05:34 +0000713 cERROR(1, ("Illegal length, greater than maximum frame, %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 in_buf->smb_buf_length));
715 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000716 up(&ses->server->tcpSem);
717 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000718 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000719 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 return -EIO;
721 }
722
Steve Frenchad009ac2005-04-28 22:41:05 -0700723 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
725 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700726#ifdef CONFIG_CIFS_STATS2
727 atomic_inc(&ses->server->inSend);
728#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000730 (struct sockaddr *) &(ses->server->addr.sockAddr),
731 ses->server->noblocksnd);
Steve French131afd0b2005-10-07 09:51:05 -0700732#ifdef CONFIG_CIFS_STATS2
733 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700734 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700735#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000736 up(&ses->server->tcpSem);
737
Steve French79a58d12007-07-06 22:44:50 +0000738 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000739 goto out;
740
Steve French133672e2007-11-13 22:41:37 +0000741 if (long_op == CIFS_STD_OP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 timeout = 15 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000743 /* wait for 15 seconds or until woken up due to response arriving or
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 due to last connection to this server being unmounted */
Steve French133672e2007-11-13 22:41:37 +0000745 else if (long_op == CIFS_ASYNC_OP)
746 goto out;
747 else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
748 timeout = 180 * HZ;
749 else if (long_op == CIFS_LONG_OP)
750 timeout = 45 * HZ; /* should be greater than
751 servers oplock break timeout (about 43 seconds) */
752 else if (long_op == CIFS_BLOCKING_OP)
753 timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
754 else {
755 cERROR(1, ("unknown timeout flag %d", long_op));
756 rc = -EIO;
757 goto out;
758 }
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 if (signal_pending(current)) {
761 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000762 but we still give response a chance to complete */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000764 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
766 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000767 wait_for_response(ses, midQ, timeout, 10 * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
769 spin_lock(&GlobalMid_Lock);
770 if (midQ->resp_buf) {
771 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700772 receive_len = midQ->resp_buf->smb_buf_length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 } else {
Steve French79a58d12007-07-06 22:44:50 +0000774 cERROR(1, ("No response for cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700775 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000776 if (midQ->midState == MID_REQUEST_SUBMITTED) {
777 if (ses->server->tcpStatus == CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 rc = -EHOSTDOWN;
779 else {
780 ses->server->tcpStatus = CifsNeedReconnect;
781 midQ->midState = MID_RETRY_NEEDED;
782 }
783 }
784
785 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000786 if (midQ->midState == MID_RETRY_NEEDED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000788 cFYI(1, ("marking request for retry"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 } else {
790 rc = -EIO;
791 }
792 }
793 spin_unlock(&GlobalMid_Lock);
794 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000795 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000796 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000797 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 return rc;
799 }
Steve French50c2f752007-07-13 00:33:32 +0000800
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Steve Frenchad009ac2005-04-28 22:41:05 -0700802 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 receive_len, xid));
804 rc = -EIO;
805 } else { /* rcvd frame is ok */
806
807 if (midQ->resp_buf && out_buf
808 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
809 out_buf->smb_buf_length = receive_len;
810 memcpy((char *)out_buf + 4,
811 (char *)midQ->resp_buf + 4,
812 receive_len);
813
814 dump_smb(out_buf, 92);
815 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +0000816 if ((receive_len > 24) &&
Steve Frenchad009ac2005-04-28 22:41:05 -0700817 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
818 SECMODE_SIGN_ENABLED))) {
819 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000820 &ses->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -0700821 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +0000822 if (rc) {
823 cERROR(1, ("Unexpected SMB signature"));
Steve French275cde12005-04-28 22:41:10 -0700824 /* BB FIXME add code to kill session */
Steve Frenchad009ac2005-04-28 22:41:05 -0700825 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 }
827
828 *pbytes_returned = out_buf->smb_buf_length;
829
Steve Frenchad009ac2005-04-28 22:41:05 -0700830 /* BB special case reconnect tid and uid here? */
Steve Frencha761ac52007-10-18 21:45:27 +0000831 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +0000834 if (receive_len >= sizeof(struct smb_hdr) - 4
835 /* do not count RFC1001 header */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 (2 * out_buf->WordCount) + 2 /* bcc */ )
Steve French0f2b27c2005-11-16 14:25:50 -0800837 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 } else {
839 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +0000840 cERROR(1, ("Bad MID state?"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 }
842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000844out:
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000845 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000846 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000847 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848
849 return rc;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000850}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000852/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
853
854static int
855send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
856 struct mid_q_entry *midQ)
857{
858 int rc = 0;
859 struct cifsSesInfo *ses = tcon->ses;
860 __u16 mid = in_buf->Mid;
861
862 header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
863 in_buf->Mid = mid;
Steve French79a58d12007-07-06 22:44:50 +0000864 down(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000865 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
866 if (rc) {
867 up(&ses->server->tcpSem);
868 return rc;
869 }
870 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000871 (struct sockaddr *) &(ses->server->addr.sockAddr),
872 ses->server->noblocksnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 up(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000874 return rc;
875}
876
877/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
878 blocking lock to return. */
879
880static int
881send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
882 struct smb_hdr *in_buf,
883 struct smb_hdr *out_buf)
884{
885 int bytes_returned;
886 struct cifsSesInfo *ses = tcon->ses;
887 LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
888
889 /* We just modify the current in_buf to change
890 the type of lock from LOCKING_ANDX_SHARED_LOCK
891 or LOCKING_ANDX_EXCLUSIVE_LOCK to
892 LOCKING_ANDX_CANCEL_LOCK. */
893
894 pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
895 pSMB->Timeout = 0;
896 pSMB->hdr.Mid = GetNextMid(ses->server);
897
898 return SendReceive(xid, ses, in_buf, out_buf,
Steve French133672e2007-11-13 22:41:37 +0000899 &bytes_returned, CIFS_STD_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000900}
901
902int
903SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
904 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
905 int *pbytes_returned)
906{
907 int rc = 0;
908 int rstart = 0;
909 unsigned int receive_len;
910 struct mid_q_entry *midQ;
911 struct cifsSesInfo *ses;
912
913 if (tcon == NULL || tcon->ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000914 cERROR(1, ("Null smb session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000915 return -EIO;
916 }
917 ses = tcon->ses;
918
Steve French79a58d12007-07-06 22:44:50 +0000919 if (ses->server == NULL) {
920 cERROR(1, ("Null tcp session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000921 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 }
923
Steve French79a58d12007-07-06 22:44:50 +0000924 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000925 return -ENOENT;
926
Steve French79a58d12007-07-06 22:44:50 +0000927 /* Ensure that we do not send more than 50 overlapping requests
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000928 to the same server. We may make this configurable later or
929 use ses->maxReq */
930
Steve French133672e2007-11-13 22:41:37 +0000931 rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000932 if (rc)
933 return rc;
934
Steve French79a58d12007-07-06 22:44:50 +0000935 /* make sure that we sign in the same order that we send on this socket
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000936 and avoid races inside tcp sendmsg code that could cause corruption
937 of smb data */
938
Steve French79a58d12007-07-06 22:44:50 +0000939 down(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000940
941 rc = allocate_mid(ses, in_buf, &midQ);
942 if (rc) {
943 up(&ses->server->tcpSem);
944 return rc;
945 }
946
947 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
948 up(&ses->server->tcpSem);
949 cERROR(1, ("Illegal length, greater than maximum frame, %d",
950 in_buf->smb_buf_length));
951 DeleteMidQEntry(midQ);
952 return -EIO;
953 }
954
955 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
956
957 midQ->midState = MID_REQUEST_SUBMITTED;
958#ifdef CONFIG_CIFS_STATS2
959 atomic_inc(&ses->server->inSend);
960#endif
961 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000962 (struct sockaddr *) &(ses->server->addr.sockAddr),
963 ses->server->noblocksnd);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000964#ifdef CONFIG_CIFS_STATS2
965 atomic_dec(&ses->server->inSend);
966 midQ->when_sent = jiffies;
967#endif
968 up(&ses->server->tcpSem);
969
Steve French79a58d12007-07-06 22:44:50 +0000970 if (rc < 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000971 DeleteMidQEntry(midQ);
972 return rc;
973 }
974
975 /* Wait for a reply - allow signals to interrupt. */
976 rc = wait_event_interruptible(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000977 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000978 ((ses->server->tcpStatus != CifsGood) &&
979 (ses->server->tcpStatus != CifsNew)));
980
981 /* Were we interrupted by a signal ? */
982 if ((rc == -ERESTARTSYS) &&
983 (midQ->midState == MID_REQUEST_SUBMITTED) &&
984 ((ses->server->tcpStatus == CifsGood) ||
985 (ses->server->tcpStatus == CifsNew))) {
986
987 if (in_buf->Command == SMB_COM_TRANSACTION2) {
988 /* POSIX lock. We send a NT_CANCEL SMB to cause the
989 blocking lock to return. */
990
991 rc = send_nt_cancel(tcon, in_buf, midQ);
992 if (rc) {
993 DeleteMidQEntry(midQ);
994 return rc;
995 }
996 } else {
997 /* Windows lock. We send a LOCKINGX_CANCEL_LOCK
998 to cause the blocking lock to return. */
999
1000 rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
1001
1002 /* If we get -ENOLCK back the lock may have
1003 already been removed. Don't exit in this case. */
1004 if (rc && rc != -ENOLCK) {
1005 DeleteMidQEntry(midQ);
1006 return rc;
1007 }
1008 }
1009
1010 /* Wait 5 seconds for the response. */
Steve French79a58d12007-07-06 22:44:50 +00001011 if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001012 /* We got the response - restart system call. */
1013 rstart = 1;
1014 }
1015 }
1016
1017 spin_lock(&GlobalMid_Lock);
1018 if (midQ->resp_buf) {
1019 spin_unlock(&GlobalMid_Lock);
1020 receive_len = midQ->resp_buf->smb_buf_length;
1021 } else {
Steve French79a58d12007-07-06 22:44:50 +00001022 cERROR(1, ("No response for cmd %d mid %d",
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001023 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +00001024 if (midQ->midState == MID_REQUEST_SUBMITTED) {
1025 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001026 rc = -EHOSTDOWN;
1027 else {
1028 ses->server->tcpStatus = CifsNeedReconnect;
1029 midQ->midState = MID_RETRY_NEEDED;
1030 }
1031 }
1032
1033 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +00001034 if (midQ->midState == MID_RETRY_NEEDED) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001035 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +00001036 cFYI(1, ("marking request for retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001037 } else {
1038 rc = -EIO;
1039 }
1040 }
1041 spin_unlock(&GlobalMid_Lock);
1042 DeleteMidQEntry(midQ);
1043 return rc;
1044 }
Steve French50c2f752007-07-13 00:33:32 +00001045
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001046 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
1047 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
1048 receive_len, xid));
1049 rc = -EIO;
1050 } else { /* rcvd frame is ok */
1051
1052 if (midQ->resp_buf && out_buf
1053 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
1054 out_buf->smb_buf_length = receive_len;
1055 memcpy((char *)out_buf + 4,
1056 (char *)midQ->resp_buf + 4,
1057 receive_len);
1058
1059 dump_smb(out_buf, 92);
1060 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +00001061 if ((receive_len > 24) &&
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001062 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
1063 SECMODE_SIGN_ENABLED))) {
1064 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +00001065 &ses->server->mac_signing_key,
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001066 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +00001067 if (rc) {
1068 cERROR(1, ("Unexpected SMB signature"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001069 /* BB FIXME add code to kill session */
1070 }
1071 }
1072
1073 *pbytes_returned = out_buf->smb_buf_length;
1074
1075 /* BB special case reconnect tid and uid here? */
Steve Frencha761ac52007-10-18 21:45:27 +00001076 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001077
1078 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +00001079 if (receive_len >= sizeof(struct smb_hdr) - 4
1080 /* do not count RFC1001 header */ +
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001081 (2 * out_buf->WordCount) + 2 /* bcc */ )
1082 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1083 } else {
1084 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +00001085 cERROR(1, ("Bad MID state?"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001086 }
1087 }
1088 DeleteMidQEntry(midQ);
1089 if (rstart && rc == -EACCES)
1090 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 return rc;
1092}