blob: 01b3aa5f928bb2749a611a85edc5b6425432f4be [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);
Volker Lendecke27a97a62008-12-08 20:59:39 +0000347 return 0;
348 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000349
Volker Lendecke27a97a62008-12-08 20:59:39 +0000350 spin_lock(&GlobalMid_Lock);
351 while (1) {
352 if (atomic_read(&ses->server->inFlight) >=
353 cifs_max_pending){
354 spin_unlock(&GlobalMid_Lock);
355#ifdef CONFIG_CIFS_STATS2
356 atomic_inc(&ses->server->num_waiters);
357#endif
358 wait_event(ses->server->request_q,
359 atomic_read(&ses->server->inFlight)
360 < cifs_max_pending);
361#ifdef CONFIG_CIFS_STATS2
362 atomic_dec(&ses->server->num_waiters);
363#endif
364 spin_lock(&GlobalMid_Lock);
365 } else {
366 if (ses->server->tcpStatus == CifsExiting) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000367 spin_unlock(&GlobalMid_Lock);
Volker Lendecke27a97a62008-12-08 20:59:39 +0000368 return -ENOENT;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000369 }
Volker Lendecke27a97a62008-12-08 20:59:39 +0000370
371 /* can not count locking commands against total
372 as they are allowed to block on server */
373
374 /* update # of requests on the wire to server */
375 if (long_op != CIFS_BLOCKING_OP)
376 atomic_inc(&ses->server->inFlight);
377 spin_unlock(&GlobalMid_Lock);
378 break;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000379 }
380 }
381 return 0;
382}
383
384static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
385 struct mid_q_entry **ppmidQ)
386{
387 if (ses->server->tcpStatus == CifsExiting) {
388 return -ENOENT;
Volker Lendecke8fbbd362008-12-06 13:12:34 +0100389 }
390
391 if (ses->server->tcpStatus == CifsNeedReconnect) {
Steve French79a58d12007-07-06 22:44:50 +0000392 cFYI(1, ("tcp session dead - return to caller to retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000393 return -EAGAIN;
Volker Lendecke8fbbd362008-12-06 13:12:34 +0100394 }
395
396 if (ses->status != CifsGood) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000397 /* check if SMB session is bad because we are setting it up */
Steve French79a58d12007-07-06 22:44:50 +0000398 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
Steve Frenchad7a2922008-02-07 23:25:02 +0000399 (in_buf->Command != SMB_COM_NEGOTIATE))
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000400 return -EAGAIN;
Steve Frenchad7a2922008-02-07 23:25:02 +0000401 /* else ok - we are setting up session */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000402 }
Jeff Layton24b9b062008-12-01 07:09:34 -0500403 *ppmidQ = AllocMidQEntry(in_buf, ses->server);
Steve French26f57362007-08-30 22:09:15 +0000404 if (*ppmidQ == NULL)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000405 return -ENOMEM;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000406 return 0;
407}
408
Steve French79a58d12007-07-06 22:44:50 +0000409static int wait_for_response(struct cifsSesInfo *ses,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000410 struct mid_q_entry *midQ,
411 unsigned long timeout,
412 unsigned long time_to_wait)
413{
414 unsigned long curr_timeout;
415
416 for (;;) {
417 curr_timeout = timeout + jiffies;
Jeff Layton85705522008-12-05 20:41:21 -0500418 wait_event_timeout(ses->server->response_q,
419 midQ->midState != MID_REQUEST_SUBMITTED, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000420
421 if (time_after(jiffies, curr_timeout) &&
422 (midQ->midState == MID_REQUEST_SUBMITTED) &&
423 ((ses->server->tcpStatus == CifsGood) ||
424 (ses->server->tcpStatus == CifsNew))) {
425
426 unsigned long lrt;
427
428 /* We timed out. Is the server still
429 sending replies ? */
430 spin_lock(&GlobalMid_Lock);
431 lrt = ses->server->lstrp;
432 spin_unlock(&GlobalMid_Lock);
433
434 /* Calculate time_to_wait past last receive time.
Steve French79a58d12007-07-06 22:44:50 +0000435 Although we prefer not to time out if the
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000436 server is still responding - we will time
Steve French79a58d12007-07-06 22:44:50 +0000437 out if the server takes more than 15 (or 45
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000438 or 180) seconds to respond to this request
Steve French79a58d12007-07-06 22:44:50 +0000439 and has not responded to any request from
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000440 other threads on the client within 10 seconds */
441 lrt += time_to_wait;
442 if (time_after(jiffies, lrt)) {
443 /* No replies for time_to_wait. */
Steve French79a58d12007-07-06 22:44:50 +0000444 cERROR(1, ("server not responding"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000445 return -1;
446 }
447 } else {
448 return 0;
449 }
450 }
451}
452
Steve French133672e2007-11-13 22:41:37 +0000453
454/*
455 *
456 * Send an SMB Request. No response info (other than return code)
457 * needs to be parsed.
458 *
459 * flags indicate the type of request buffer and how long to wait
460 * and whether to log NT STATUS code (error) before mapping it to POSIX error
461 *
462 */
463int
464SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
465 struct smb_hdr *in_buf, int flags)
466{
467 int rc;
468 struct kvec iov[1];
469 int resp_buf_type;
470
471 iov[0].iov_base = (char *)in_buf;
472 iov[0].iov_len = in_buf->smb_buf_length + 4;
473 flags |= CIFS_NO_RESP;
474 rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
Steve French90c81e02008-02-12 20:32:36 +0000475 cFYI(DBG2, ("SendRcvNoRsp flags %d rc %d", flags, rc));
476
Steve French133672e2007-11-13 22:41:37 +0000477 return rc;
478}
479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480int
Steve French79a58d12007-07-06 22:44:50 +0000481SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
482 struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
Steve French133672e2007-11-13 22:41:37 +0000483 const int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
485 int rc = 0;
Steve French133672e2007-11-13 22:41:37 +0000486 int long_op;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500487 unsigned int receive_len;
488 unsigned long timeout;
489 struct mid_q_entry *midQ;
Steve French3e844692005-10-03 13:37:24 -0700490 struct smb_hdr *in_buf = iov[0].iov_base;
Steve French50c2f752007-07-13 00:33:32 +0000491
Steve French133672e2007-11-13 22:41:37 +0000492 long_op = flags & CIFS_TIMEOUT_MASK;
493
Steve Frenchec637e32005-12-12 20:53:18 -0800494 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
Steve French4b8f9302006-02-26 16:41:18 +0000496 if ((ses == NULL) || (ses->server == NULL)) {
497 cifs_small_buf_release(in_buf);
Steve French79a58d12007-07-06 22:44:50 +0000498 cERROR(1, ("Null session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 return -EIO;
500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
Steve French79a58d12007-07-06 22:44:50 +0000502 if (ses->server->tcpStatus == CifsExiting) {
Steve French4b8f9302006-02-26 16:41:18 +0000503 cifs_small_buf_release(in_buf);
Steve French31ca3bc2005-04-28 22:41:11 -0700504 return -ENOENT;
Steve French4b8f9302006-02-26 16:41:18 +0000505 }
Steve French31ca3bc2005-04-28 22:41:11 -0700506
Steve French79a58d12007-07-06 22:44:50 +0000507 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 to the same server. We may make this configurable later or
509 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000511 rc = wait_for_free_request(ses, long_op);
512 if (rc) {
513 cifs_small_buf_release(in_buf);
514 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000516
Steve French79a58d12007-07-06 22:44:50 +0000517 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 and avoid races inside tcp sendmsg code that could cause corruption
519 of smb data */
520
Jeff Layton72ca5452008-12-01 07:09:36 -0500521 mutex_lock(&ses->server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000523 rc = allocate_mid(ses, in_buf, &midQ);
524 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500525 mutex_unlock(&ses->server->srv_mutex);
Steve French4b8f9302006-02-26 16:41:18 +0000526 cifs_small_buf_release(in_buf);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000527 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000528 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000529 wake_up(&ses->server->request_q);
530 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 }
Steve French79a58d12007-07-06 22:44:50 +0000532 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100533 if (rc) {
534 mutex_unlock(&ses->server->srv_mutex);
535 cifs_small_buf_release(in_buf);
536 goto out;
537 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
539 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700540#ifdef CONFIG_CIFS_STATS2
541 atomic_inc(&ses->server->inSend);
542#endif
Steve Frenchedf1ae42008-10-29 00:47:57 +0000543 rc = smb_send2(ses->server, iov, n_vec,
544 (struct sockaddr *) &(ses->server->addr.sockAddr),
545 ses->server->noblocksnd);
Steve French131afd0b2005-10-07 09:51:05 -0700546#ifdef CONFIG_CIFS_STATS2
547 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700548 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700549#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000550
Jeff Layton72ca5452008-12-01 07:09:36 -0500551 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000552 cifs_small_buf_release(in_buf);
553
Steve French79a58d12007-07-06 22:44:50 +0000554 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000555 goto out;
Steve French4b8f9302006-02-26 16:41:18 +0000556
Steve French133672e2007-11-13 22:41:37 +0000557 if (long_op == CIFS_STD_OP)
558 timeout = 15 * HZ;
559 else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
Steve French37c0eb42005-10-05 14:50:29 -0700560 timeout = 180 * HZ;
Steve French133672e2007-11-13 22:41:37 +0000561 else if (long_op == CIFS_LONG_OP)
Steve French79a58d12007-07-06 22:44:50 +0000562 timeout = 45 * HZ; /* should be greater than
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500563 servers oplock break timeout (about 43 seconds) */
Steve French133672e2007-11-13 22:41:37 +0000564 else if (long_op == CIFS_ASYNC_OP)
565 goto out;
566 else if (long_op == CIFS_BLOCKING_OP)
567 timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */
568 else {
569 cERROR(1, ("unknown timeout flag %d", long_op));
570 rc = -EIO;
571 goto out;
572 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000573
Steve French79a58d12007-07-06 22:44:50 +0000574 /* wait for 15 seconds or until woken up due to response arriving or
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500575 due to last connection to this server being unmounted */
576 if (signal_pending(current)) {
577 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000578 but we still give response a chance to complete */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500579 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000580 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500581
582 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000583 wait_for_response(ses, midQ, timeout, 10 * HZ);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500584
585 spin_lock(&GlobalMid_Lock);
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100586
587 if (midQ->resp_buf == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000588 cERROR(1, ("No response to cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700589 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000590 if (midQ->midState == MID_REQUEST_SUBMITTED) {
591 if (ses->server->tcpStatus == CifsExiting)
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500592 rc = -EHOSTDOWN;
593 else {
594 ses->server->tcpStatus = CifsNeedReconnect;
595 midQ->midState = MID_RETRY_NEEDED;
596 }
597 }
598
599 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000600 if (midQ->midState == MID_RETRY_NEEDED) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500601 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000602 cFYI(1, ("marking request for retry"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500603 } else {
604 rc = -EIO;
605 }
606 }
607 spin_unlock(&GlobalMid_Lock);
608 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000609 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000610 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000611 wake_up(&ses->server->request_q);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500612 return rc;
613 }
Steve French50c2f752007-07-13 00:33:32 +0000614
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100615 spin_unlock(&GlobalMid_Lock);
616 receive_len = midQ->resp_buf->smb_buf_length;
617
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500618 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
619 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
620 receive_len, xid));
621 rc = -EIO;
622 } else { /* rcvd frame is ok */
Steve French79a58d12007-07-06 22:44:50 +0000623 if (midQ->resp_buf &&
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500624 (midQ->midState == MID_RESPONSE_RECEIVED)) {
Steve French84afc292005-12-02 13:32:45 -0800625
Steve Frenchec637e32005-12-12 20:53:18 -0800626 iov[0].iov_base = (char *)midQ->resp_buf;
Steve French79a58d12007-07-06 22:44:50 +0000627 if (midQ->largeBuf)
Steve Frenchec637e32005-12-12 20:53:18 -0800628 *pRespBufType = CIFS_LARGE_BUFFER;
629 else
630 *pRespBufType = CIFS_SMALL_BUFFER;
631 iov[0].iov_len = receive_len + 4;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500632
Steve Frenchec637e32005-12-12 20:53:18 -0800633 dump_smb(midQ->resp_buf, 80);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500634 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +0000635 if ((receive_len > 24) &&
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500636 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
637 SECMODE_SIGN_ENABLED))) {
Steve Frenchec637e32005-12-12 20:53:18 -0800638 rc = cifs_verify_signature(midQ->resp_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000639 &ses->server->mac_signing_key,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500640 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +0000641 if (rc) {
642 cERROR(1, ("Unexpected SMB signature"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500643 /* BB FIXME add code to kill session */
644 }
645 }
646
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500647 /* BB special case reconnect tid and uid here? */
Steve French133672e2007-11-13 22:41:37 +0000648 rc = map_smb_to_linux_error(midQ->resp_buf,
649 flags & CIFS_LOG_ERROR);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500650
651 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +0000652 if (receive_len >= sizeof(struct smb_hdr) - 4
653 /* do not count RFC1001 header */ +
Steve Frenchec637e32005-12-12 20:53:18 -0800654 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
Steve French79a58d12007-07-06 22:44:50 +0000655 BCC(midQ->resp_buf) =
Steve Frenchec637e32005-12-12 20:53:18 -0800656 le16_to_cpu(BCC_LE(midQ->resp_buf));
Steve French133672e2007-11-13 22:41:37 +0000657 if ((flags & CIFS_NO_RESP) == 0)
658 midQ->resp_buf = NULL; /* mark it so buf will
659 not be freed by
660 DeleteMidQEntry */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500661 } else {
662 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +0000663 cFYI(1, ("Bad MID state?"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500664 }
665 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000666
667out:
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500668 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000669 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000670 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
672 return rc;
673}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
675int
676SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
677 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
678 int *pbytes_returned, const int long_op)
679{
680 int rc = 0;
681 unsigned int receive_len;
682 unsigned long timeout;
683 struct mid_q_entry *midQ;
684
685 if (ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000686 cERROR(1, ("Null smb session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 return -EIO;
688 }
Steve French79a58d12007-07-06 22:44:50 +0000689 if (ses->server == NULL) {
690 cERROR(1, ("Null tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 return -EIO;
692 }
693
Steve French79a58d12007-07-06 22:44:50 +0000694 if (ses->server->tcpStatus == CifsExiting)
Steve French31ca3bc2005-04-28 22:41:11 -0700695 return -ENOENT;
696
Steve French79a58d12007-07-06 22:44:50 +0000697 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 to the same server. We may make this configurable later or
699 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000701 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
702 cERROR(1, ("Illegal length, greater than maximum frame, %d",
703 in_buf->smb_buf_length));
704 return -EIO;
705 }
706
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000707 rc = wait_for_free_request(ses, long_op);
708 if (rc)
709 return rc;
710
Steve French79a58d12007-07-06 22:44:50 +0000711 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 and avoid races inside tcp sendmsg code that could cause corruption
713 of smb data */
714
Jeff Layton72ca5452008-12-01 07:09:36 -0500715 mutex_lock(&ses->server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000717 rc = allocate_mid(ses, in_buf, &midQ);
718 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500719 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000720 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000721 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000722 wake_up(&ses->server->request_q);
723 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 }
725
Steve Frenchad009ac2005-04-28 22:41:05 -0700726 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100727 if (rc) {
728 mutex_unlock(&ses->server->srv_mutex);
729 goto out;
730 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
732 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700733#ifdef CONFIG_CIFS_STATS2
734 atomic_inc(&ses->server->inSend);
735#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000737 (struct sockaddr *) &(ses->server->addr.sockAddr),
738 ses->server->noblocksnd);
Steve French131afd0b2005-10-07 09:51:05 -0700739#ifdef CONFIG_CIFS_STATS2
740 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700741 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700742#endif
Jeff Layton72ca5452008-12-01 07:09:36 -0500743 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000744
Steve French79a58d12007-07-06 22:44:50 +0000745 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000746 goto out;
747
Steve French133672e2007-11-13 22:41:37 +0000748 if (long_op == CIFS_STD_OP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 timeout = 15 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000750 /* wait for 15 seconds or until woken up due to response arriving or
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 due to last connection to this server being unmounted */
Steve French133672e2007-11-13 22:41:37 +0000752 else if (long_op == CIFS_ASYNC_OP)
753 goto out;
754 else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
755 timeout = 180 * HZ;
756 else if (long_op == CIFS_LONG_OP)
757 timeout = 45 * HZ; /* should be greater than
758 servers oplock break timeout (about 43 seconds) */
759 else if (long_op == CIFS_BLOCKING_OP)
760 timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
761 else {
762 cERROR(1, ("unknown timeout flag %d", long_op));
763 rc = -EIO;
764 goto out;
765 }
766
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 if (signal_pending(current)) {
768 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000769 but we still give response a chance to complete */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000771 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
773 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000774 wait_for_response(ses, midQ, timeout, 10 * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
776 spin_lock(&GlobalMid_Lock);
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100777 if (midQ->resp_buf == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000778 cERROR(1, ("No response for cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700779 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000780 if (midQ->midState == MID_REQUEST_SUBMITTED) {
781 if (ses->server->tcpStatus == CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 rc = -EHOSTDOWN;
783 else {
784 ses->server->tcpStatus = CifsNeedReconnect;
785 midQ->midState = MID_RETRY_NEEDED;
786 }
787 }
788
789 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000790 if (midQ->midState == MID_RETRY_NEEDED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000792 cFYI(1, ("marking request for retry"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 } else {
794 rc = -EIO;
795 }
796 }
797 spin_unlock(&GlobalMid_Lock);
798 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000799 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000800 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000801 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 return rc;
803 }
Steve French50c2f752007-07-13 00:33:32 +0000804
Volker Lendecke8e4f2e82008-12-06 16:22:15 +0100805 spin_unlock(&GlobalMid_Lock);
806 receive_len = midQ->resp_buf->smb_buf_length;
807
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Steve Frenchad009ac2005-04-28 22:41:05 -0700809 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 receive_len, xid));
811 rc = -EIO;
812 } else { /* rcvd frame is ok */
813
814 if (midQ->resp_buf && out_buf
815 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
816 out_buf->smb_buf_length = receive_len;
817 memcpy((char *)out_buf + 4,
818 (char *)midQ->resp_buf + 4,
819 receive_len);
820
821 dump_smb(out_buf, 92);
822 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +0000823 if ((receive_len > 24) &&
Steve Frenchad009ac2005-04-28 22:41:05 -0700824 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
825 SECMODE_SIGN_ENABLED))) {
826 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000827 &ses->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -0700828 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +0000829 if (rc) {
830 cERROR(1, ("Unexpected SMB signature"));
Steve French275cde12005-04-28 22:41:10 -0700831 /* BB FIXME add code to kill session */
Steve Frenchad009ac2005-04-28 22:41:05 -0700832 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 }
834
835 *pbytes_returned = out_buf->smb_buf_length;
836
Steve Frenchad009ac2005-04-28 22:41:05 -0700837 /* BB special case reconnect tid and uid here? */
Steve Frencha761ac52007-10-18 21:45:27 +0000838 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
840 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +0000841 if (receive_len >= sizeof(struct smb_hdr) - 4
842 /* do not count RFC1001 header */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 (2 * out_buf->WordCount) + 2 /* bcc */ )
Steve French0f2b27c2005-11-16 14:25:50 -0800844 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 } else {
846 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +0000847 cERROR(1, ("Bad MID state?"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 }
849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000851out:
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000852 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000853 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000854 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855
856 return rc;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000857}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000859/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
860
861static int
862send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
863 struct mid_q_entry *midQ)
864{
865 int rc = 0;
866 struct cifsSesInfo *ses = tcon->ses;
867 __u16 mid = in_buf->Mid;
868
869 header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
870 in_buf->Mid = mid;
Jeff Layton72ca5452008-12-01 07:09:36 -0500871 mutex_lock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000872 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
873 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500874 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000875 return rc;
876 }
877 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000878 (struct sockaddr *) &(ses->server->addr.sockAddr),
879 ses->server->noblocksnd);
Jeff Layton72ca5452008-12-01 07:09:36 -0500880 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000881 return rc;
882}
883
884/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
885 blocking lock to return. */
886
887static int
888send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
889 struct smb_hdr *in_buf,
890 struct smb_hdr *out_buf)
891{
892 int bytes_returned;
893 struct cifsSesInfo *ses = tcon->ses;
894 LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
895
896 /* We just modify the current in_buf to change
897 the type of lock from LOCKING_ANDX_SHARED_LOCK
898 or LOCKING_ANDX_EXCLUSIVE_LOCK to
899 LOCKING_ANDX_CANCEL_LOCK. */
900
901 pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
902 pSMB->Timeout = 0;
903 pSMB->hdr.Mid = GetNextMid(ses->server);
904
905 return SendReceive(xid, ses, in_buf, out_buf,
Steve French133672e2007-11-13 22:41:37 +0000906 &bytes_returned, CIFS_STD_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000907}
908
909int
910SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
911 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
912 int *pbytes_returned)
913{
914 int rc = 0;
915 int rstart = 0;
916 unsigned int receive_len;
917 struct mid_q_entry *midQ;
918 struct cifsSesInfo *ses;
919
920 if (tcon == NULL || tcon->ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000921 cERROR(1, ("Null smb session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000922 return -EIO;
923 }
924 ses = tcon->ses;
925
Steve French79a58d12007-07-06 22:44:50 +0000926 if (ses->server == NULL) {
927 cERROR(1, ("Null tcp session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000928 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 }
930
Steve French79a58d12007-07-06 22:44:50 +0000931 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000932 return -ENOENT;
933
Steve French79a58d12007-07-06 22:44:50 +0000934 /* Ensure that we do not send more than 50 overlapping requests
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000935 to the same server. We may make this configurable later or
936 use ses->maxReq */
937
Volker Lendecke6d9c6d52008-12-08 20:50:24 +0000938 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
939 cERROR(1, ("Illegal length, greater than maximum frame, %d",
940 in_buf->smb_buf_length));
941 return -EIO;
942 }
943
Steve French133672e2007-11-13 22:41:37 +0000944 rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000945 if (rc)
946 return rc;
947
Steve French79a58d12007-07-06 22:44:50 +0000948 /* make sure that we sign in the same order that we send on this socket
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000949 and avoid races inside tcp sendmsg code that could cause corruption
950 of smb data */
951
Jeff Layton72ca5452008-12-01 07:09:36 -0500952 mutex_lock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000953
954 rc = allocate_mid(ses, in_buf, &midQ);
955 if (rc) {
Jeff Layton72ca5452008-12-01 07:09:36 -0500956 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000957 return rc;
958 }
959
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000960 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Volker Lendecke829049c2008-12-06 16:00:53 +0100961 if (rc) {
962 DeleteMidQEntry(midQ);
963 mutex_unlock(&ses->server->srv_mutex);
964 return rc;
965 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000966
967 midQ->midState = MID_REQUEST_SUBMITTED;
968#ifdef CONFIG_CIFS_STATS2
969 atomic_inc(&ses->server->inSend);
970#endif
971 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000972 (struct sockaddr *) &(ses->server->addr.sockAddr),
973 ses->server->noblocksnd);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000974#ifdef CONFIG_CIFS_STATS2
975 atomic_dec(&ses->server->inSend);
976 midQ->when_sent = jiffies;
977#endif
Jeff Layton72ca5452008-12-01 07:09:36 -0500978 mutex_unlock(&ses->server->srv_mutex);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000979
Steve French79a58d12007-07-06 22:44:50 +0000980 if (rc < 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000981 DeleteMidQEntry(midQ);
982 return rc;
983 }
984
985 /* Wait for a reply - allow signals to interrupt. */
986 rc = wait_event_interruptible(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000987 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000988 ((ses->server->tcpStatus != CifsGood) &&
989 (ses->server->tcpStatus != CifsNew)));
990
991 /* Were we interrupted by a signal ? */
992 if ((rc == -ERESTARTSYS) &&
993 (midQ->midState == MID_REQUEST_SUBMITTED) &&
994 ((ses->server->tcpStatus == CifsGood) ||
995 (ses->server->tcpStatus == CifsNew))) {
996
997 if (in_buf->Command == SMB_COM_TRANSACTION2) {
998 /* POSIX lock. We send a NT_CANCEL SMB to cause the
999 blocking lock to return. */
1000
1001 rc = send_nt_cancel(tcon, in_buf, midQ);
1002 if (rc) {
1003 DeleteMidQEntry(midQ);
1004 return rc;
1005 }
1006 } else {
1007 /* Windows lock. We send a LOCKINGX_CANCEL_LOCK
1008 to cause the blocking lock to return. */
1009
1010 rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
1011
1012 /* If we get -ENOLCK back the lock may have
1013 already been removed. Don't exit in this case. */
1014 if (rc && rc != -ENOLCK) {
1015 DeleteMidQEntry(midQ);
1016 return rc;
1017 }
1018 }
1019
1020 /* Wait 5 seconds for the response. */
Steve French79a58d12007-07-06 22:44:50 +00001021 if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001022 /* We got the response - restart system call. */
1023 rstart = 1;
1024 }
1025 }
1026
1027 spin_lock(&GlobalMid_Lock);
1028 if (midQ->resp_buf) {
1029 spin_unlock(&GlobalMid_Lock);
1030 receive_len = midQ->resp_buf->smb_buf_length;
1031 } else {
Steve French79a58d12007-07-06 22:44:50 +00001032 cERROR(1, ("No response for cmd %d mid %d",
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001033 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +00001034 if (midQ->midState == MID_REQUEST_SUBMITTED) {
1035 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001036 rc = -EHOSTDOWN;
1037 else {
1038 ses->server->tcpStatus = CifsNeedReconnect;
1039 midQ->midState = MID_RETRY_NEEDED;
1040 }
1041 }
1042
1043 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +00001044 if (midQ->midState == MID_RETRY_NEEDED) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001045 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +00001046 cFYI(1, ("marking request for retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001047 } else {
1048 rc = -EIO;
1049 }
1050 }
1051 spin_unlock(&GlobalMid_Lock);
1052 DeleteMidQEntry(midQ);
1053 return rc;
1054 }
Steve French50c2f752007-07-13 00:33:32 +00001055
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001056 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
1057 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
1058 receive_len, xid));
1059 rc = -EIO;
1060 } else { /* rcvd frame is ok */
1061
1062 if (midQ->resp_buf && out_buf
1063 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
1064 out_buf->smb_buf_length = receive_len;
1065 memcpy((char *)out_buf + 4,
1066 (char *)midQ->resp_buf + 4,
1067 receive_len);
1068
1069 dump_smb(out_buf, 92);
1070 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +00001071 if ((receive_len > 24) &&
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001072 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
1073 SECMODE_SIGN_ENABLED))) {
1074 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +00001075 &ses->server->mac_signing_key,
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001076 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +00001077 if (rc) {
1078 cERROR(1, ("Unexpected SMB signature"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001079 /* BB FIXME add code to kill session */
1080 }
1081 }
1082
1083 *pbytes_returned = out_buf->smb_buf_length;
1084
1085 /* BB special case reconnect tid and uid here? */
Steve Frencha761ac52007-10-18 21:45:27 +00001086 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001087
1088 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +00001089 if (receive_len >= sizeof(struct smb_hdr) - 4
1090 /* do not count RFC1001 header */ +
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001091 (2 * out_buf->WordCount) + 2 /* bcc */ )
1092 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1093 } else {
1094 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +00001095 cERROR(1, ("Bad MID state?"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001096 }
1097 }
1098 DeleteMidQEntry(midQ);
1099 if (rstart && rc == -EACCES)
1100 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 return rc;
1102}