blob: c98f929315f24b1811bc4f928bb1ccbd9f6dee48 [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;
Volker Lendecke8fbbd362008-12-06 13:12:34 +0100388 }
389
390 if (ses->server->tcpStatus == CifsNeedReconnect) {
Steve French79a58d12007-07-06 22:44:50 +0000391 cFYI(1, ("tcp session dead - return to caller to retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000392 return -EAGAIN;
Volker Lendecke8fbbd362008-12-06 13:12:34 +0100393 }
394
395 if (ses->status != CifsGood) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000396 /* check if SMB session is bad because we are setting it up */
Steve French79a58d12007-07-06 22:44:50 +0000397 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
Steve Frenchad7a2922008-02-07 23:25:02 +0000398 (in_buf->Command != SMB_COM_NEGOTIATE))
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000399 return -EAGAIN;
Steve Frenchad7a2922008-02-07 23:25:02 +0000400 /* else ok - we are setting up session */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000401 }
Jeff Layton24b9b062008-12-01 07:09:34 -0500402 *ppmidQ = AllocMidQEntry(in_buf, ses->server);
Steve French26f57362007-08-30 22:09:15 +0000403 if (*ppmidQ == NULL)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000404 return -ENOMEM;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000405 return 0;
406}
407
Steve French79a58d12007-07-06 22:44:50 +0000408static int wait_for_response(struct cifsSesInfo *ses,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000409 struct mid_q_entry *midQ,
410 unsigned long timeout,
411 unsigned long time_to_wait)
412{
413 unsigned long curr_timeout;
414
415 for (;;) {
416 curr_timeout = timeout + jiffies;
Jeff Layton85705522008-12-05 20:41:21 -0500417 wait_event_timeout(ses->server->response_q,
418 midQ->midState != MID_REQUEST_SUBMITTED, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000419
420 if (time_after(jiffies, curr_timeout) &&
421 (midQ->midState == MID_REQUEST_SUBMITTED) &&
422 ((ses->server->tcpStatus == CifsGood) ||
423 (ses->server->tcpStatus == CifsNew))) {
424
425 unsigned long lrt;
426
427 /* We timed out. Is the server still
428 sending replies ? */
429 spin_lock(&GlobalMid_Lock);
430 lrt = ses->server->lstrp;
431 spin_unlock(&GlobalMid_Lock);
432
433 /* Calculate time_to_wait past last receive time.
Steve French79a58d12007-07-06 22:44:50 +0000434 Although we prefer not to time out if the
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000435 server is still responding - we will time
Steve French79a58d12007-07-06 22:44:50 +0000436 out if the server takes more than 15 (or 45
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000437 or 180) seconds to respond to this request
Steve French79a58d12007-07-06 22:44:50 +0000438 and has not responded to any request from
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000439 other threads on the client within 10 seconds */
440 lrt += time_to_wait;
441 if (time_after(jiffies, lrt)) {
442 /* No replies for time_to_wait. */
Steve French79a58d12007-07-06 22:44:50 +0000443 cERROR(1, ("server not responding"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000444 return -1;
445 }
446 } else {
447 return 0;
448 }
449 }
450}
451
Steve French133672e2007-11-13 22:41:37 +0000452
453/*
454 *
455 * Send an SMB Request. No response info (other than return code)
456 * needs to be parsed.
457 *
458 * flags indicate the type of request buffer and how long to wait
459 * and whether to log NT STATUS code (error) before mapping it to POSIX error
460 *
461 */
462int
463SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
464 struct smb_hdr *in_buf, int flags)
465{
466 int rc;
467 struct kvec iov[1];
468 int resp_buf_type;
469
470 iov[0].iov_base = (char *)in_buf;
471 iov[0].iov_len = in_buf->smb_buf_length + 4;
472 flags |= CIFS_NO_RESP;
473 rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
Steve French90c81e02008-02-12 20:32:36 +0000474 cFYI(DBG2, ("SendRcvNoRsp flags %d rc %d", flags, rc));
475
Steve French133672e2007-11-13 22:41:37 +0000476 return rc;
477}
478
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479int
Steve French79a58d12007-07-06 22:44:50 +0000480SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
481 struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
Steve French133672e2007-11-13 22:41:37 +0000482 const int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483{
484 int rc = 0;
Steve French133672e2007-11-13 22:41:37 +0000485 int long_op;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500486 unsigned int receive_len;
487 unsigned long timeout;
488 struct mid_q_entry *midQ;
Steve French3e844692005-10-03 13:37:24 -0700489 struct smb_hdr *in_buf = iov[0].iov_base;
Steve French50c2f752007-07-13 00:33:32 +0000490
Steve French133672e2007-11-13 22:41:37 +0000491 long_op = flags & CIFS_TIMEOUT_MASK;
492
Steve Frenchec637e32005-12-12 20:53:18 -0800493 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
Steve French4b8f9302006-02-26 16:41:18 +0000495 if ((ses == NULL) || (ses->server == NULL)) {
496 cifs_small_buf_release(in_buf);
Steve French79a58d12007-07-06 22:44:50 +0000497 cERROR(1, ("Null session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 return -EIO;
499 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
Steve French79a58d12007-07-06 22:44:50 +0000501 if (ses->server->tcpStatus == CifsExiting) {
Steve French4b8f9302006-02-26 16:41:18 +0000502 cifs_small_buf_release(in_buf);
Steve French31ca3bc2005-04-28 22:41:11 -0700503 return -ENOENT;
Steve French4b8f9302006-02-26 16:41:18 +0000504 }
Steve French31ca3bc2005-04-28 22:41:11 -0700505
Steve French79a58d12007-07-06 22:44:50 +0000506 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 to the same server. We may make this configurable later or
508 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000510 rc = wait_for_free_request(ses, long_op);
511 if (rc) {
512 cifs_small_buf_release(in_buf);
513 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000515
Steve French79a58d12007-07-06 22:44:50 +0000516 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 and avoid races inside tcp sendmsg code that could cause corruption
518 of smb data */
519
Jeff Layton72ca5452008-12-01 07:09:36 -0500520 mutex_lock(&ses->server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000522 rc = allocate_mid(ses, in_buf, &midQ);
523 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500524 mutex_unlock(&ses->server->srv_mutex);
Steve French4b8f9302006-02-26 16:41:18 +0000525 cifs_small_buf_release(in_buf);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000526 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000527 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000528 wake_up(&ses->server->request_q);
529 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 }
Steve French79a58d12007-07-06 22:44:50 +0000531 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
533 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700534#ifdef CONFIG_CIFS_STATS2
535 atomic_inc(&ses->server->inSend);
536#endif
Steve Frenchedf1ae42008-10-29 00:47:57 +0000537 rc = smb_send2(ses->server, iov, n_vec,
538 (struct sockaddr *) &(ses->server->addr.sockAddr),
539 ses->server->noblocksnd);
Steve French131afd0b2005-10-07 09:51:05 -0700540#ifdef CONFIG_CIFS_STATS2
541 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700542 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700543#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000544
Jeff Layton72ca5452008-12-01 07:09:36 -0500545 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000546 cifs_small_buf_release(in_buf);
547
Steve French79a58d12007-07-06 22:44:50 +0000548 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000549 goto out;
Steve French4b8f9302006-02-26 16:41:18 +0000550
Steve French133672e2007-11-13 22:41:37 +0000551 if (long_op == CIFS_STD_OP)
552 timeout = 15 * HZ;
553 else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
Steve French37c0eb42005-10-05 14:50:29 -0700554 timeout = 180 * HZ;
Steve French133672e2007-11-13 22:41:37 +0000555 else if (long_op == CIFS_LONG_OP)
Steve French79a58d12007-07-06 22:44:50 +0000556 timeout = 45 * HZ; /* should be greater than
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500557 servers oplock break timeout (about 43 seconds) */
Steve French133672e2007-11-13 22:41:37 +0000558 else if (long_op == CIFS_ASYNC_OP)
559 goto out;
560 else if (long_op == CIFS_BLOCKING_OP)
561 timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */
562 else {
563 cERROR(1, ("unknown timeout flag %d", long_op));
564 rc = -EIO;
565 goto out;
566 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000567
Steve French79a58d12007-07-06 22:44:50 +0000568 /* wait for 15 seconds or until woken up due to response arriving or
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500569 due to last connection to this server being unmounted */
570 if (signal_pending(current)) {
571 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000572 but we still give response a chance to complete */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500573 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000574 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500575
576 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000577 wait_for_response(ses, midQ, timeout, 10 * HZ);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500578
579 spin_lock(&GlobalMid_Lock);
580 if (midQ->resp_buf) {
581 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700582 receive_len = midQ->resp_buf->smb_buf_length;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500583 } else {
Steve French79a58d12007-07-06 22:44:50 +0000584 cERROR(1, ("No response to cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700585 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000586 if (midQ->midState == MID_REQUEST_SUBMITTED) {
587 if (ses->server->tcpStatus == CifsExiting)
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500588 rc = -EHOSTDOWN;
589 else {
590 ses->server->tcpStatus = CifsNeedReconnect;
591 midQ->midState = MID_RETRY_NEEDED;
592 }
593 }
594
595 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000596 if (midQ->midState == MID_RETRY_NEEDED) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500597 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000598 cFYI(1, ("marking request for retry"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500599 } else {
600 rc = -EIO;
601 }
602 }
603 spin_unlock(&GlobalMid_Lock);
604 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000605 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000606 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000607 wake_up(&ses->server->request_q);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500608 return rc;
609 }
Steve French50c2f752007-07-13 00:33:32 +0000610
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500611 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
612 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
613 receive_len, xid));
614 rc = -EIO;
615 } else { /* rcvd frame is ok */
Steve French79a58d12007-07-06 22:44:50 +0000616 if (midQ->resp_buf &&
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500617 (midQ->midState == MID_RESPONSE_RECEIVED)) {
Steve French84afc292005-12-02 13:32:45 -0800618
Steve Frenchec637e32005-12-12 20:53:18 -0800619 iov[0].iov_base = (char *)midQ->resp_buf;
Steve French79a58d12007-07-06 22:44:50 +0000620 if (midQ->largeBuf)
Steve Frenchec637e32005-12-12 20:53:18 -0800621 *pRespBufType = CIFS_LARGE_BUFFER;
622 else
623 *pRespBufType = CIFS_SMALL_BUFFER;
624 iov[0].iov_len = receive_len + 4;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500625
Steve Frenchec637e32005-12-12 20:53:18 -0800626 dump_smb(midQ->resp_buf, 80);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500627 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +0000628 if ((receive_len > 24) &&
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500629 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
630 SECMODE_SIGN_ENABLED))) {
Steve Frenchec637e32005-12-12 20:53:18 -0800631 rc = cifs_verify_signature(midQ->resp_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000632 &ses->server->mac_signing_key,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500633 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +0000634 if (rc) {
635 cERROR(1, ("Unexpected SMB signature"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500636 /* BB FIXME add code to kill session */
637 }
638 }
639
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500640 /* BB special case reconnect tid and uid here? */
Steve French133672e2007-11-13 22:41:37 +0000641 rc = map_smb_to_linux_error(midQ->resp_buf,
642 flags & CIFS_LOG_ERROR);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500643
644 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +0000645 if (receive_len >= sizeof(struct smb_hdr) - 4
646 /* do not count RFC1001 header */ +
Steve Frenchec637e32005-12-12 20:53:18 -0800647 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
Steve French79a58d12007-07-06 22:44:50 +0000648 BCC(midQ->resp_buf) =
Steve Frenchec637e32005-12-12 20:53:18 -0800649 le16_to_cpu(BCC_LE(midQ->resp_buf));
Steve French133672e2007-11-13 22:41:37 +0000650 if ((flags & CIFS_NO_RESP) == 0)
651 midQ->resp_buf = NULL; /* mark it so buf will
652 not be freed by
653 DeleteMidQEntry */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500654 } else {
655 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +0000656 cFYI(1, ("Bad MID state?"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500657 }
658 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000659
660out:
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500661 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000662 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000663 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
665 return rc;
666}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
668int
669SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
670 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
671 int *pbytes_returned, const int long_op)
672{
673 int rc = 0;
674 unsigned int receive_len;
675 unsigned long timeout;
676 struct mid_q_entry *midQ;
677
678 if (ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000679 cERROR(1, ("Null smb session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 return -EIO;
681 }
Steve French79a58d12007-07-06 22:44:50 +0000682 if (ses->server == NULL) {
683 cERROR(1, ("Null tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 return -EIO;
685 }
686
Steve French79a58d12007-07-06 22:44:50 +0000687 if (ses->server->tcpStatus == CifsExiting)
Steve French31ca3bc2005-04-28 22:41:11 -0700688 return -ENOENT;
689
Steve French79a58d12007-07-06 22:44:50 +0000690 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 to the same server. We may make this configurable later or
692 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000694 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
695 cERROR(1, ("Illegal length, greater than maximum frame, %d",
696 in_buf->smb_buf_length));
697 return -EIO;
698 }
699
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000700 rc = wait_for_free_request(ses, long_op);
701 if (rc)
702 return rc;
703
Steve French79a58d12007-07-06 22:44:50 +0000704 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 and avoid races inside tcp sendmsg code that could cause corruption
706 of smb data */
707
Jeff Layton72ca5452008-12-01 07:09:36 -0500708 mutex_lock(&ses->server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000710 rc = allocate_mid(ses, in_buf, &midQ);
711 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500712 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000713 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000714 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000715 wake_up(&ses->server->request_q);
716 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 }
718
Steve Frenchad009ac2005-04-28 22:41:05 -0700719 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
721 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700722#ifdef CONFIG_CIFS_STATS2
723 atomic_inc(&ses->server->inSend);
724#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000726 (struct sockaddr *) &(ses->server->addr.sockAddr),
727 ses->server->noblocksnd);
Steve French131afd0b2005-10-07 09:51:05 -0700728#ifdef CONFIG_CIFS_STATS2
729 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700730 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700731#endif
Jeff Layton72ca5452008-12-01 07:09:36 -0500732 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000733
Steve French79a58d12007-07-06 22:44:50 +0000734 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000735 goto out;
736
Steve French133672e2007-11-13 22:41:37 +0000737 if (long_op == CIFS_STD_OP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 timeout = 15 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000739 /* wait for 15 seconds or until woken up due to response arriving or
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 due to last connection to this server being unmounted */
Steve French133672e2007-11-13 22:41:37 +0000741 else if (long_op == CIFS_ASYNC_OP)
742 goto out;
743 else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
744 timeout = 180 * HZ;
745 else if (long_op == CIFS_LONG_OP)
746 timeout = 45 * HZ; /* should be greater than
747 servers oplock break timeout (about 43 seconds) */
748 else if (long_op == CIFS_BLOCKING_OP)
749 timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
750 else {
751 cERROR(1, ("unknown timeout flag %d", long_op));
752 rc = -EIO;
753 goto out;
754 }
755
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 if (signal_pending(current)) {
757 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000758 but we still give response a chance to complete */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000760 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
762 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000763 wait_for_response(ses, midQ, timeout, 10 * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
765 spin_lock(&GlobalMid_Lock);
766 if (midQ->resp_buf) {
767 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700768 receive_len = midQ->resp_buf->smb_buf_length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 } else {
Steve French79a58d12007-07-06 22:44:50 +0000770 cERROR(1, ("No response for cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700771 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000772 if (midQ->midState == MID_REQUEST_SUBMITTED) {
773 if (ses->server->tcpStatus == CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 rc = -EHOSTDOWN;
775 else {
776 ses->server->tcpStatus = CifsNeedReconnect;
777 midQ->midState = MID_RETRY_NEEDED;
778 }
779 }
780
781 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000782 if (midQ->midState == MID_RETRY_NEEDED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000784 cFYI(1, ("marking request for retry"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 } else {
786 rc = -EIO;
787 }
788 }
789 spin_unlock(&GlobalMid_Lock);
790 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000791 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000792 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000793 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 return rc;
795 }
Steve French50c2f752007-07-13 00:33:32 +0000796
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Steve Frenchad009ac2005-04-28 22:41:05 -0700798 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 receive_len, xid));
800 rc = -EIO;
801 } else { /* rcvd frame is ok */
802
803 if (midQ->resp_buf && out_buf
804 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
805 out_buf->smb_buf_length = receive_len;
806 memcpy((char *)out_buf + 4,
807 (char *)midQ->resp_buf + 4,
808 receive_len);
809
810 dump_smb(out_buf, 92);
811 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +0000812 if ((receive_len > 24) &&
Steve Frenchad009ac2005-04-28 22:41:05 -0700813 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
814 SECMODE_SIGN_ENABLED))) {
815 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000816 &ses->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -0700817 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +0000818 if (rc) {
819 cERROR(1, ("Unexpected SMB signature"));
Steve French275cde12005-04-28 22:41:10 -0700820 /* BB FIXME add code to kill session */
Steve Frenchad009ac2005-04-28 22:41:05 -0700821 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 }
823
824 *pbytes_returned = out_buf->smb_buf_length;
825
Steve Frenchad009ac2005-04-28 22:41:05 -0700826 /* BB special case reconnect tid and uid here? */
Steve Frencha761ac52007-10-18 21:45:27 +0000827 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
829 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +0000830 if (receive_len >= sizeof(struct smb_hdr) - 4
831 /* do not count RFC1001 header */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 (2 * out_buf->WordCount) + 2 /* bcc */ )
Steve French0f2b27c2005-11-16 14:25:50 -0800833 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 } else {
835 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +0000836 cERROR(1, ("Bad MID state?"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 }
838 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000840out:
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000841 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000842 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000843 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
845 return rc;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000846}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000848/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
849
850static int
851send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
852 struct mid_q_entry *midQ)
853{
854 int rc = 0;
855 struct cifsSesInfo *ses = tcon->ses;
856 __u16 mid = in_buf->Mid;
857
858 header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
859 in_buf->Mid = mid;
Jeff Layton72ca5452008-12-01 07:09:36 -0500860 mutex_lock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000861 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
862 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500863 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000864 return rc;
865 }
866 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000867 (struct sockaddr *) &(ses->server->addr.sockAddr),
868 ses->server->noblocksnd);
Jeff Layton72ca5452008-12-01 07:09:36 -0500869 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000870 return rc;
871}
872
873/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
874 blocking lock to return. */
875
876static int
877send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
878 struct smb_hdr *in_buf,
879 struct smb_hdr *out_buf)
880{
881 int bytes_returned;
882 struct cifsSesInfo *ses = tcon->ses;
883 LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
884
885 /* We just modify the current in_buf to change
886 the type of lock from LOCKING_ANDX_SHARED_LOCK
887 or LOCKING_ANDX_EXCLUSIVE_LOCK to
888 LOCKING_ANDX_CANCEL_LOCK. */
889
890 pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
891 pSMB->Timeout = 0;
892 pSMB->hdr.Mid = GetNextMid(ses->server);
893
894 return SendReceive(xid, ses, in_buf, out_buf,
Steve French133672e2007-11-13 22:41:37 +0000895 &bytes_returned, CIFS_STD_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000896}
897
898int
899SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
900 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
901 int *pbytes_returned)
902{
903 int rc = 0;
904 int rstart = 0;
905 unsigned int receive_len;
906 struct mid_q_entry *midQ;
907 struct cifsSesInfo *ses;
908
909 if (tcon == NULL || tcon->ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000910 cERROR(1, ("Null smb session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000911 return -EIO;
912 }
913 ses = tcon->ses;
914
Steve French79a58d12007-07-06 22:44:50 +0000915 if (ses->server == NULL) {
916 cERROR(1, ("Null tcp session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000917 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 }
919
Steve French79a58d12007-07-06 22:44:50 +0000920 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000921 return -ENOENT;
922
Steve French79a58d12007-07-06 22:44:50 +0000923 /* Ensure that we do not send more than 50 overlapping requests
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000924 to the same server. We may make this configurable later or
925 use ses->maxReq */
926
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000927 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
928 cERROR(1, ("Illegal length, greater than maximum frame, %d",
929 in_buf->smb_buf_length));
930 return -EIO;
931 }
932
Steve French133672e2007-11-13 22:41:37 +0000933 rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000934 if (rc)
935 return rc;
936
Steve French79a58d12007-07-06 22:44:50 +0000937 /* make sure that we sign in the same order that we send on this socket
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000938 and avoid races inside tcp sendmsg code that could cause corruption
939 of smb data */
940
Jeff Layton72ca5452008-12-01 07:09:36 -0500941 mutex_lock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000942
943 rc = allocate_mid(ses, in_buf, &midQ);
944 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500945 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000946 return rc;
947 }
948
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000949 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
950
951 midQ->midState = MID_REQUEST_SUBMITTED;
952#ifdef CONFIG_CIFS_STATS2
953 atomic_inc(&ses->server->inSend);
954#endif
955 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000956 (struct sockaddr *) &(ses->server->addr.sockAddr),
957 ses->server->noblocksnd);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000958#ifdef CONFIG_CIFS_STATS2
959 atomic_dec(&ses->server->inSend);
960 midQ->when_sent = jiffies;
961#endif
Jeff Layton72ca5452008-12-01 07:09:36 -0500962 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000963
Steve French79a58d12007-07-06 22:44:50 +0000964 if (rc < 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000965 DeleteMidQEntry(midQ);
966 return rc;
967 }
968
969 /* Wait for a reply - allow signals to interrupt. */
970 rc = wait_event_interruptible(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000971 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000972 ((ses->server->tcpStatus != CifsGood) &&
973 (ses->server->tcpStatus != CifsNew)));
974
975 /* Were we interrupted by a signal ? */
976 if ((rc == -ERESTARTSYS) &&
977 (midQ->midState == MID_REQUEST_SUBMITTED) &&
978 ((ses->server->tcpStatus == CifsGood) ||
979 (ses->server->tcpStatus == CifsNew))) {
980
981 if (in_buf->Command == SMB_COM_TRANSACTION2) {
982 /* POSIX lock. We send a NT_CANCEL SMB to cause the
983 blocking lock to return. */
984
985 rc = send_nt_cancel(tcon, in_buf, midQ);
986 if (rc) {
987 DeleteMidQEntry(midQ);
988 return rc;
989 }
990 } else {
991 /* Windows lock. We send a LOCKINGX_CANCEL_LOCK
992 to cause the blocking lock to return. */
993
994 rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
995
996 /* If we get -ENOLCK back the lock may have
997 already been removed. Don't exit in this case. */
998 if (rc && rc != -ENOLCK) {
999 DeleteMidQEntry(midQ);
1000 return rc;
1001 }
1002 }
1003
1004 /* Wait 5 seconds for the response. */
Steve French79a58d12007-07-06 22:44:50 +00001005 if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001006 /* We got the response - restart system call. */
1007 rstart = 1;
1008 }
1009 }
1010
1011 spin_lock(&GlobalMid_Lock);
1012 if (midQ->resp_buf) {
1013 spin_unlock(&GlobalMid_Lock);
1014 receive_len = midQ->resp_buf->smb_buf_length;
1015 } else {
Steve French79a58d12007-07-06 22:44:50 +00001016 cERROR(1, ("No response for cmd %d mid %d",
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001017 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +00001018 if (midQ->midState == MID_REQUEST_SUBMITTED) {
1019 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001020 rc = -EHOSTDOWN;
1021 else {
1022 ses->server->tcpStatus = CifsNeedReconnect;
1023 midQ->midState = MID_RETRY_NEEDED;
1024 }
1025 }
1026
1027 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +00001028 if (midQ->midState == MID_RETRY_NEEDED) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001029 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +00001030 cFYI(1, ("marking request for retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001031 } else {
1032 rc = -EIO;
1033 }
1034 }
1035 spin_unlock(&GlobalMid_Lock);
1036 DeleteMidQEntry(midQ);
1037 return rc;
1038 }
Steve French50c2f752007-07-13 00:33:32 +00001039
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001040 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
1041 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
1042 receive_len, xid));
1043 rc = -EIO;
1044 } else { /* rcvd frame is ok */
1045
1046 if (midQ->resp_buf && out_buf
1047 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
1048 out_buf->smb_buf_length = receive_len;
1049 memcpy((char *)out_buf + 4,
1050 (char *)midQ->resp_buf + 4,
1051 receive_len);
1052
1053 dump_smb(out_buf, 92);
1054 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +00001055 if ((receive_len > 24) &&
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001056 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
1057 SECMODE_SIGN_ENABLED))) {
1058 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +00001059 &ses->server->mac_signing_key,
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001060 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +00001061 if (rc) {
1062 cERROR(1, ("Unexpected SMB signature"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001063 /* BB FIXME add code to kill session */
1064 }
1065 }
1066
1067 *pbytes_returned = out_buf->smb_buf_length;
1068
1069 /* BB special case reconnect tid and uid here? */
Steve Frencha761ac52007-10-18 21:45:27 +00001070 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001071
1072 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +00001073 if (receive_len >= sizeof(struct smb_hdr) - 4
1074 /* do not count RFC1001 header */ +
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001075 (2 * out_buf->WordCount) + 2 /* bcc */ )
1076 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1077 } else {
1078 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +00001079 cERROR(1, ("Bad MID state?"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001080 }
1081 }
1082 DeleteMidQEntry(midQ);
1083 if (rstart && rc == -EACCES)
1084 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 return rc;
1086}