blob: ba4d66644ebf165baf0008108183f48bdb54d462 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/transport.c
3 *
Steve Frenchad7a2922008-02-07 23:25:02 +00004 * Copyright (C) International Business Machines Corp., 2002,2008
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
Steve French14a441a2b2006-07-16 04:32:51 +00006 * Jeremy Allison (jra@samba.org) 2006.
Steve French79a58d12007-07-06 22:44:50 +00007 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * This library is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published
10 * by the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
16 * the GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, write to the Free Software
Steve French79a58d12007-07-06 22:44:50 +000020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 */
22
23#include <linux/fs.h>
24#include <linux/list.h>
25#include <linux/wait.h>
26#include <linux/net.h>
27#include <linux/delay.h>
28#include <asm/uaccess.h>
29#include <asm/processor.h>
30#include <linux/mempool.h>
31#include "cifspdu.h"
32#include "cifsglob.h"
33#include "cifsproto.h"
34#include "cifs_debug.h"
Steve French50c2f752007-07-13 00:33:32 +000035
Linus Torvalds1da177e2005-04-16 15:20:36 -070036extern mempool_t *cifs_mid_poolp;
Christoph Lametere18b8902006-12-06 20:33:20 -080037extern struct kmem_cache *cifs_oplock_cachep;
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39static struct mid_q_entry *
Jeremy Allison7ee1af72006-08-02 21:56:33 +000040AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -070041{
42 struct mid_q_entry *temp;
43
44 if (ses == NULL) {
Steve French275cde12005-04-28 22:41:10 -070045 cERROR(1, ("Null session passed in to AllocMidQEntry"));
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 return NULL;
47 }
48 if (ses->server == NULL) {
49 cERROR(1, ("Null TCP session in AllocMidQEntry"));
50 return NULL;
51 }
Steve French50c2f752007-07-13 00:33:32 +000052
Pekka Enberg232087c2008-09-15 13:22:54 +030053 temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 if (temp == NULL)
55 return temp;
56 else {
Steve French26f57362007-08-30 22:09:15 +000057 memset(temp, 0, sizeof(struct mid_q_entry));
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 temp->mid = smb_buffer->Mid; /* always LE */
59 temp->pid = current->pid;
60 temp->command = smb_buffer->Command;
61 cFYI(1, ("For smb_command %d", temp->command));
Steve French1047abc2005-10-11 19:58:06 -070062 /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
63 /* when mid allocated can be before when sent */
64 temp->when_alloc = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 temp->ses = ses;
66 temp->tsk = current;
67 }
68
69 spin_lock(&GlobalMid_Lock);
70 list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
71 atomic_inc(&midCount);
72 temp->midState = MID_REQUEST_ALLOCATED;
73 spin_unlock(&GlobalMid_Lock);
74 return temp;
75}
76
77static void
78DeleteMidQEntry(struct mid_q_entry *midEntry)
79{
Steve French1047abc2005-10-11 19:58:06 -070080#ifdef CONFIG_CIFS_STATS2
81 unsigned long now;
82#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 spin_lock(&GlobalMid_Lock);
84 midEntry->midState = MID_FREE;
85 list_del(&midEntry->qhead);
86 atomic_dec(&midCount);
87 spin_unlock(&GlobalMid_Lock);
Steve French79a58d12007-07-06 22:44:50 +000088 if (midEntry->largeBuf)
Steve Frenchb8643e12005-04-28 22:41:07 -070089 cifs_buf_release(midEntry->resp_buf);
90 else
91 cifs_small_buf_release(midEntry->resp_buf);
Steve French1047abc2005-10-11 19:58:06 -070092#ifdef CONFIG_CIFS_STATS2
93 now = jiffies;
94 /* commands taking longer than one second are indications that
95 something is wrong, unless it is quite a slow link or server */
Steve French79a58d12007-07-06 22:44:50 +000096 if ((now - midEntry->when_alloc) > HZ) {
97 if ((cifsFYI & CIFS_TIMER) &&
Steve French1047abc2005-10-11 19:58:06 -070098 (midEntry->command != SMB_COM_LOCKING_ANDX)) {
99 printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
100 midEntry->command, midEntry->mid);
101 printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
102 now - midEntry->when_alloc,
103 now - midEntry->when_sent,
104 now - midEntry->when_received);
105 }
106 }
107#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 mempool_free(midEntry, cifs_mid_poolp);
109}
110
111struct oplock_q_entry *
Steve French79a58d12007-07-06 22:44:50 +0000112AllocOplockQEntry(struct inode *pinode, __u16 fid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113{
114 struct oplock_q_entry *temp;
Steve French79a58d12007-07-06 22:44:50 +0000115 if ((pinode == NULL) || (tcon == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 cERROR(1, ("Null parms passed to AllocOplockQEntry"));
117 return NULL;
118 }
119 temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
Christoph Lametere94b1762006-12-06 20:33:17 -0800120 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 if (temp == NULL)
122 return temp;
123 else {
124 temp->pinode = pinode;
125 temp->tcon = tcon;
126 temp->netfid = fid;
127 spin_lock(&GlobalMid_Lock);
128 list_add_tail(&temp->qhead, &GlobalOplock_Q);
129 spin_unlock(&GlobalMid_Lock);
130 }
131 return temp;
132
133}
134
Steve French79a58d12007-07-06 22:44:50 +0000135void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136{
Steve French79a58d12007-07-06 22:44:50 +0000137 spin_lock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 /* should we check if list empty first? */
139 list_del(&oplockEntry->qhead);
140 spin_unlock(&GlobalMid_Lock);
141 kmem_cache_free(cifs_oplock_cachep, oplockEntry);
142}
143
Steve French5d941ca2008-04-15 18:40:48 +0000144
145void DeleteTconOplockQEntries(struct cifsTconInfo *tcon)
146{
147 struct oplock_q_entry *temp;
148
149 if (tcon == NULL)
150 return;
151
152 spin_lock(&GlobalMid_Lock);
153 list_for_each_entry(temp, &GlobalOplock_Q, qhead) {
154 if ((temp->tcon) && (temp->tcon == tcon)) {
155 list_del(&temp->qhead);
156 kmem_cache_free(cifs_oplock_cachep, temp);
157 }
158 }
159 spin_unlock(&GlobalMid_Lock);
160}
161
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162int
163smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000164 unsigned int smb_buf_length, struct sockaddr *sin, bool noblocksnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165{
166 int rc = 0;
167 int i = 0;
168 struct msghdr smb_msg;
169 struct kvec iov;
170 unsigned len = smb_buf_length + 4;
171
Steve French79a58d12007-07-06 22:44:50 +0000172 if (ssocket == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 return -ENOTSOCK; /* BB eventually add reconnect code here */
174 iov.iov_base = smb_buffer;
175 iov.iov_len = len;
176
177 smb_msg.msg_name = sin;
Steve French26f57362007-08-30 22:09:15 +0000178 smb_msg.msg_namelen = sizeof(struct sockaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 smb_msg.msg_control = NULL;
180 smb_msg.msg_controllen = 0;
Steve Frenchedf1ae42008-10-29 00:47:57 +0000181 if (noblocksnd)
182 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
183 else
184 smb_msg.msg_flags = MSG_NOSIGNAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
186 /* smb header is converted in header_assemble. bcc and rest of SMB word
Steve French79a58d12007-07-06 22:44:50 +0000187 area, and byte area if necessary, is converted to littleendian in
188 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 Flags2 is converted in SendReceive */
190
191 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Steve French3e844692005-10-03 13:37:24 -0700192 cFYI(1, ("Sending smb of length %d", smb_buf_length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 dump_smb(smb_buffer, len);
194
195 while (len > 0) {
196 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
197 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
198 i++;
Steve French3e844692005-10-03 13:37:24 -0700199 /* smaller timeout here than send2 since smaller size */
Steve French79a58d12007-07-06 22:44:50 +0000200 /* Although it may not be required, this also is smaller
201 oplock break time */
202 if (i > 12) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 cERROR(1,
Steve French68058e72005-10-10 10:34:22 -0700204 ("sends on sock %p stuck for 7 seconds",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 ssocket));
206 rc = -EAGAIN;
207 break;
208 }
Steve French68058e72005-10-10 10:34:22 -0700209 msleep(1 << i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 continue;
211 }
Steve French79a58d12007-07-06 22:44:50 +0000212 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 break;
Steve French5e1253b2005-10-10 14:06:37 -0700214 else
215 i = 0; /* reset i after each successful send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 iov.iov_base += rc;
217 iov.iov_len -= rc;
218 len -= rc;
219 }
220
221 if (rc < 0) {
Steve French79a58d12007-07-06 22:44:50 +0000222 cERROR(1, ("Error %d sending data on socket to server", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 } else {
224 rc = 0;
225 }
226
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000227 /* Don't want to modify the buffer as a
228 side effect of this call. */
229 smb_buffer->smb_buf_length = smb_buf_length;
230
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 return rc;
232}
233
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500234static int
Steve Frenchedf1ae42008-10-29 00:47:57 +0000235smb_send2(struct TCP_Server_Info *server, struct kvec *iov, int n_vec,
236 struct sockaddr *sin, bool noblocksnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
238 int rc = 0;
239 int i = 0;
240 struct msghdr smb_msg;
Steve French3e844692005-10-03 13:37:24 -0700241 struct smb_hdr *smb_buffer = iov[0].iov_base;
242 unsigned int len = iov[0].iov_len;
243 unsigned int total_len;
244 int first_vec = 0;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000245 unsigned int smb_buf_length = smb_buffer->smb_buf_length;
Steve Frenchedf1ae42008-10-29 00:47:57 +0000246 struct socket *ssocket = server->ssocket;
Steve French50c2f752007-07-13 00:33:32 +0000247
Steve French79a58d12007-07-06 22:44:50 +0000248 if (ssocket == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 return -ENOTSOCK; /* BB eventually add reconnect code here */
Steve French3e844692005-10-03 13:37:24 -0700250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 smb_msg.msg_name = sin;
Steve French26f57362007-08-30 22:09:15 +0000252 smb_msg.msg_namelen = sizeof(struct sockaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 smb_msg.msg_control = NULL;
254 smb_msg.msg_controllen = 0;
Steve Frenchedf1ae42008-10-29 00:47:57 +0000255 if (noblocksnd)
256 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
257 else
258 smb_msg.msg_flags = MSG_NOSIGNAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
260 /* smb header is converted in header_assemble. bcc and rest of SMB word
Steve French79a58d12007-07-06 22:44:50 +0000261 area, and byte area if necessary, is converted to littleendian in
262 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 Flags2 is converted in SendReceive */
264
Steve French3e844692005-10-03 13:37:24 -0700265
266 total_len = 0;
267 for (i = 0; i < n_vec; i++)
268 total_len += iov[i].iov_len;
269
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Steve French3e844692005-10-03 13:37:24 -0700271 cFYI(1, ("Sending smb: total_len %d", total_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 dump_smb(smb_buffer, len);
273
Shirish Pargaonkar17680352008-07-29 21:26:13 +0000274 i = 0;
Steve French3e844692005-10-03 13:37:24 -0700275 while (total_len) {
276 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
277 n_vec - first_vec, total_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
279 i++;
Steve French79a58d12007-07-06 22:44:50 +0000280 if (i >= 14) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 cERROR(1,
Steve French68058e72005-10-10 10:34:22 -0700282 ("sends on sock %p stuck for 15 seconds",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 ssocket));
284 rc = -EAGAIN;
285 break;
286 }
Steve French68058e72005-10-10 10:34:22 -0700287 msleep(1 << i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 continue;
289 }
Steve French79a58d12007-07-06 22:44:50 +0000290 if (rc < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 break;
Steve French3e844692005-10-03 13:37:24 -0700292
293 if (rc >= total_len) {
294 WARN_ON(rc > total_len);
295 break;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500296 }
Steve French79a58d12007-07-06 22:44:50 +0000297 if (rc == 0) {
Steve French3e844692005-10-03 13:37:24 -0700298 /* should never happen, letting socket clear before
299 retrying is our only obvious option here */
Steve French79a58d12007-07-06 22:44:50 +0000300 cERROR(1, ("tcp sent no data"));
Steve French3e844692005-10-03 13:37:24 -0700301 msleep(500);
302 continue;
303 }
304 total_len -= rc;
Steve French68058e72005-10-10 10:34:22 -0700305 /* the line below resets i */
Steve French3e844692005-10-03 13:37:24 -0700306 for (i = first_vec; i < n_vec; i++) {
307 if (iov[i].iov_len) {
308 if (rc > iov[i].iov_len) {
309 rc -= iov[i].iov_len;
310 iov[i].iov_len = 0;
311 } else {
312 iov[i].iov_base += rc;
313 iov[i].iov_len -= rc;
314 first_vec = i;
315 break;
316 }
317 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500318 }
Steve French5e1253b2005-10-10 14:06:37 -0700319 i = 0; /* in case we get ENOSPC on the next send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 }
321
Steve Frenchedf1ae42008-10-29 00:47:57 +0000322 if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
323 cFYI(1, ("partial send (%d remaining), terminating session",
324 total_len));
325 /* If we have only sent part of an SMB then the next SMB
326 could be taken as the remainder of this one. We need
327 to kill the socket so the server throws away the partial
328 SMB */
329 server->tcpStatus = CifsNeedReconnect;
330 }
331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 if (rc < 0) {
Steve French79a58d12007-07-06 22:44:50 +0000333 cERROR(1, ("Error %d sending data on socket to server", rc));
Steve French3e844692005-10-03 13:37:24 -0700334 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000337 /* Don't want to modify the buffer as a
338 side effect of this call. */
339 smb_buffer->smb_buf_length = smb_buf_length;
340
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 return rc;
342}
343
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000344static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
345{
Steve French133672e2007-11-13 22:41:37 +0000346 if (long_op == CIFS_ASYNC_OP) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000347 /* oplock breaks must not be held up */
348 atomic_inc(&ses->server->inFlight);
349 } else {
Steve French79a58d12007-07-06 22:44:50 +0000350 spin_lock(&GlobalMid_Lock);
351 while (1) {
352 if (atomic_read(&ses->server->inFlight) >=
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000353 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 {
Steve French79a58d12007-07-06 22:44:50 +0000366 if (ses->server->tcpStatus == CifsExiting) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000367 spin_unlock(&GlobalMid_Lock);
368 return -ENOENT;
369 }
370
Steve French79a58d12007-07-06 22:44:50 +0000371 /* can not count locking commands against total
372 as they are allowed to block on server */
Steve French50c2f752007-07-13 00:33:32 +0000373
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000374 /* update # of requests on the wire to server */
Steve French133672e2007-11-13 22:41:37 +0000375 if (long_op != CIFS_BLOCKING_OP)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000376 atomic_inc(&ses->server->inFlight);
377 spin_unlock(&GlobalMid_Lock);
378 break;
379 }
380 }
381 }
382 return 0;
383}
384
385static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
386 struct mid_q_entry **ppmidQ)
387{
388 if (ses->server->tcpStatus == CifsExiting) {
389 return -ENOENT;
390 } else 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;
393 } else if (ses->status != CifsGood) {
394 /* check if SMB session is bad because we are setting it up */
Steve French79a58d12007-07-06 22:44:50 +0000395 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
Steve Frenchad7a2922008-02-07 23:25:02 +0000396 (in_buf->Command != SMB_COM_NEGOTIATE))
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000397 return -EAGAIN;
Steve Frenchad7a2922008-02-07 23:25:02 +0000398 /* else ok - we are setting up session */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000399 }
400 *ppmidQ = AllocMidQEntry(in_buf, ses);
Steve French26f57362007-08-30 22:09:15 +0000401 if (*ppmidQ == NULL)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000402 return -ENOMEM;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000403 return 0;
404}
405
Steve French79a58d12007-07-06 22:44:50 +0000406static int wait_for_response(struct cifsSesInfo *ses,
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000407 struct mid_q_entry *midQ,
408 unsigned long timeout,
409 unsigned long time_to_wait)
410{
411 unsigned long curr_timeout;
412
413 for (;;) {
414 curr_timeout = timeout + jiffies;
415 wait_event(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000416 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
417 time_after(jiffies, curr_timeout) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000418 ((ses->server->tcpStatus != CifsGood) &&
419 (ses->server->tcpStatus != CifsNew)));
420
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
Steve French79a58d12007-07-06 22:44:50 +0000521 down(&ses->server->tcpSem);
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) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 up(&ses->server->tcpSem);
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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
534 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700535#ifdef CONFIG_CIFS_STATS2
536 atomic_inc(&ses->server->inSend);
537#endif
Steve Frenchedf1ae42008-10-29 00:47:57 +0000538 rc = smb_send2(ses->server, iov, n_vec,
539 (struct sockaddr *) &(ses->server->addr.sockAddr),
540 ses->server->noblocksnd);
Steve French131afd0b2005-10-07 09:51:05 -0700541#ifdef CONFIG_CIFS_STATS2
542 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700543 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700544#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000545
546 up(&ses->server->tcpSem);
547 cifs_small_buf_release(in_buf);
548
Steve French79a58d12007-07-06 22:44:50 +0000549 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000550 goto out;
Steve French4b8f9302006-02-26 16:41:18 +0000551
Steve French133672e2007-11-13 22:41:37 +0000552 if (long_op == CIFS_STD_OP)
553 timeout = 15 * HZ;
554 else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
Steve French37c0eb42005-10-05 14:50:29 -0700555 timeout = 180 * HZ;
Steve French133672e2007-11-13 22:41:37 +0000556 else if (long_op == CIFS_LONG_OP)
Steve French79a58d12007-07-06 22:44:50 +0000557 timeout = 45 * HZ; /* should be greater than
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500558 servers oplock break timeout (about 43 seconds) */
Steve French133672e2007-11-13 22:41:37 +0000559 else if (long_op == CIFS_ASYNC_OP)
560 goto out;
561 else if (long_op == CIFS_BLOCKING_OP)
562 timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */
563 else {
564 cERROR(1, ("unknown timeout flag %d", long_op));
565 rc = -EIO;
566 goto out;
567 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000568
Steve French79a58d12007-07-06 22:44:50 +0000569 /* wait for 15 seconds or until woken up due to response arriving or
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500570 due to last connection to this server being unmounted */
571 if (signal_pending(current)) {
572 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000573 but we still give response a chance to complete */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500574 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000575 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500576
577 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000578 wait_for_response(ses, midQ, timeout, 10 * HZ);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500579
580 spin_lock(&GlobalMid_Lock);
581 if (midQ->resp_buf) {
582 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700583 receive_len = midQ->resp_buf->smb_buf_length;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500584 } else {
Steve French79a58d12007-07-06 22:44:50 +0000585 cERROR(1, ("No response to cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700586 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000587 if (midQ->midState == MID_REQUEST_SUBMITTED) {
588 if (ses->server->tcpStatus == CifsExiting)
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500589 rc = -EHOSTDOWN;
590 else {
591 ses->server->tcpStatus = CifsNeedReconnect;
592 midQ->midState = MID_RETRY_NEEDED;
593 }
594 }
595
596 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000597 if (midQ->midState == MID_RETRY_NEEDED) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500598 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000599 cFYI(1, ("marking request for retry"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500600 } else {
601 rc = -EIO;
602 }
603 }
604 spin_unlock(&GlobalMid_Lock);
605 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000606 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000607 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000608 wake_up(&ses->server->request_q);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500609 return rc;
610 }
Steve French50c2f752007-07-13 00:33:32 +0000611
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500612 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
613 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
614 receive_len, xid));
615 rc = -EIO;
616 } else { /* rcvd frame is ok */
Steve French79a58d12007-07-06 22:44:50 +0000617 if (midQ->resp_buf &&
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500618 (midQ->midState == MID_RESPONSE_RECEIVED)) {
Steve French84afc292005-12-02 13:32:45 -0800619
Steve Frenchec637e32005-12-12 20:53:18 -0800620 iov[0].iov_base = (char *)midQ->resp_buf;
Steve French79a58d12007-07-06 22:44:50 +0000621 if (midQ->largeBuf)
Steve Frenchec637e32005-12-12 20:53:18 -0800622 *pRespBufType = CIFS_LARGE_BUFFER;
623 else
624 *pRespBufType = CIFS_SMALL_BUFFER;
625 iov[0].iov_len = receive_len + 4;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500626
Steve Frenchec637e32005-12-12 20:53:18 -0800627 dump_smb(midQ->resp_buf, 80);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500628 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +0000629 if ((receive_len > 24) &&
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500630 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
631 SECMODE_SIGN_ENABLED))) {
Steve Frenchec637e32005-12-12 20:53:18 -0800632 rc = cifs_verify_signature(midQ->resp_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000633 &ses->server->mac_signing_key,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500634 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +0000635 if (rc) {
636 cERROR(1, ("Unexpected SMB signature"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500637 /* BB FIXME add code to kill session */
638 }
639 }
640
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500641 /* BB special case reconnect tid and uid here? */
Steve French133672e2007-11-13 22:41:37 +0000642 rc = map_smb_to_linux_error(midQ->resp_buf,
643 flags & CIFS_LOG_ERROR);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500644
645 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +0000646 if (receive_len >= sizeof(struct smb_hdr) - 4
647 /* do not count RFC1001 header */ +
Steve Frenchec637e32005-12-12 20:53:18 -0800648 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
Steve French79a58d12007-07-06 22:44:50 +0000649 BCC(midQ->resp_buf) =
Steve Frenchec637e32005-12-12 20:53:18 -0800650 le16_to_cpu(BCC_LE(midQ->resp_buf));
Steve French133672e2007-11-13 22:41:37 +0000651 if ((flags & CIFS_NO_RESP) == 0)
652 midQ->resp_buf = NULL; /* mark it so buf will
653 not be freed by
654 DeleteMidQEntry */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500655 } else {
656 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +0000657 cFYI(1, ("Bad MID state?"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500658 }
659 }
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000660
661out:
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500662 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000663 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000664 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
666 return rc;
667}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
669int
670SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
671 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
672 int *pbytes_returned, const int long_op)
673{
674 int rc = 0;
675 unsigned int receive_len;
676 unsigned long timeout;
677 struct mid_q_entry *midQ;
678
679 if (ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000680 cERROR(1, ("Null smb session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 return -EIO;
682 }
Steve French79a58d12007-07-06 22:44:50 +0000683 if (ses->server == NULL) {
684 cERROR(1, ("Null tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 return -EIO;
686 }
687
Steve French79a58d12007-07-06 22:44:50 +0000688 if (ses->server->tcpStatus == CifsExiting)
Steve French31ca3bc2005-04-28 22:41:11 -0700689 return -ENOENT;
690
Steve French79a58d12007-07-06 22:44:50 +0000691 /* Ensure that we do not send more than 50 overlapping requests
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 to the same server. We may make this configurable later or
693 use ses->maxReq */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000695 rc = wait_for_free_request(ses, long_op);
696 if (rc)
697 return rc;
698
Steve French79a58d12007-07-06 22:44:50 +0000699 /* make sure that we sign in the same order that we send on this socket
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 and avoid races inside tcp sendmsg code that could cause corruption
701 of smb data */
702
Steve French79a58d12007-07-06 22:44:50 +0000703 down(&ses->server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000705 rc = allocate_mid(ses, in_buf, &midQ);
706 if (rc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 up(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000708 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000709 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000710 wake_up(&ses->server->request_q);
711 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 }
713
714 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
Steve French26a21b92006-05-31 18:05:34 +0000715 cERROR(1, ("Illegal length, greater than maximum frame, %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 in_buf->smb_buf_length));
717 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000718 up(&ses->server->tcpSem);
719 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000720 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000721 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 return -EIO;
723 }
724
Steve Frenchad009ac2005-04-28 22:41:05 -0700725 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
727 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700728#ifdef CONFIG_CIFS_STATS2
729 atomic_inc(&ses->server->inSend);
730#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000732 (struct sockaddr *) &(ses->server->addr.sockAddr),
733 ses->server->noblocksnd);
Steve French131afd0b2005-10-07 09:51:05 -0700734#ifdef CONFIG_CIFS_STATS2
735 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700736 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700737#endif
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000738 up(&ses->server->tcpSem);
739
Steve French79a58d12007-07-06 22:44:50 +0000740 if (rc < 0)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000741 goto out;
742
Steve French133672e2007-11-13 22:41:37 +0000743 if (long_op == CIFS_STD_OP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 timeout = 15 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000745 /* wait for 15 seconds or until woken up due to response arriving or
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 due to last connection to this server being unmounted */
Steve French133672e2007-11-13 22:41:37 +0000747 else if (long_op == CIFS_ASYNC_OP)
748 goto out;
749 else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
750 timeout = 180 * HZ;
751 else if (long_op == CIFS_LONG_OP)
752 timeout = 45 * HZ; /* should be greater than
753 servers oplock break timeout (about 43 seconds) */
754 else if (long_op == CIFS_BLOCKING_OP)
755 timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
756 else {
757 cERROR(1, ("unknown timeout flag %d", long_op));
758 rc = -EIO;
759 goto out;
760 }
761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 if (signal_pending(current)) {
763 /* if signal pending do not hold up user for full smb timeout
Steve French8a236262007-03-06 00:31:00 +0000764 but we still give response a chance to complete */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 timeout = 2 * HZ;
Steve French79a58d12007-07-06 22:44:50 +0000766 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
768 /* No user interrupts in wait - wreaks havoc with performance */
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000769 wait_for_response(ses, midQ, timeout, 10 * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
771 spin_lock(&GlobalMid_Lock);
772 if (midQ->resp_buf) {
773 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700774 receive_len = midQ->resp_buf->smb_buf_length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 } else {
Steve French79a58d12007-07-06 22:44:50 +0000776 cERROR(1, ("No response for cmd %d mid %d",
Steve French37c0eb42005-10-05 14:50:29 -0700777 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +0000778 if (midQ->midState == MID_REQUEST_SUBMITTED) {
779 if (ses->server->tcpStatus == CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 rc = -EHOSTDOWN;
781 else {
782 ses->server->tcpStatus = CifsNeedReconnect;
783 midQ->midState = MID_RETRY_NEEDED;
784 }
785 }
786
787 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +0000788 if (midQ->midState == MID_RETRY_NEEDED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +0000790 cFYI(1, ("marking request for retry"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 } else {
792 rc = -EIO;
793 }
794 }
795 spin_unlock(&GlobalMid_Lock);
796 DeleteMidQEntry(midQ);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000797 /* Update # of requests on wire to server */
Steve French79a58d12007-07-06 22:44:50 +0000798 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000799 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 return rc;
801 }
Steve French50c2f752007-07-13 00:33:32 +0000802
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Steve Frenchad009ac2005-04-28 22:41:05 -0700804 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 receive_len, xid));
806 rc = -EIO;
807 } else { /* rcvd frame is ok */
808
809 if (midQ->resp_buf && out_buf
810 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
811 out_buf->smb_buf_length = receive_len;
812 memcpy((char *)out_buf + 4,
813 (char *)midQ->resp_buf + 4,
814 receive_len);
815
816 dump_smb(out_buf, 92);
817 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +0000818 if ((receive_len > 24) &&
Steve Frenchad009ac2005-04-28 22:41:05 -0700819 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
820 SECMODE_SIGN_ENABLED))) {
821 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +0000822 &ses->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -0700823 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +0000824 if (rc) {
825 cERROR(1, ("Unexpected SMB signature"));
Steve French275cde12005-04-28 22:41:10 -0700826 /* BB FIXME add code to kill session */
Steve Frenchad009ac2005-04-28 22:41:05 -0700827 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 }
829
830 *pbytes_returned = out_buf->smb_buf_length;
831
Steve Frenchad009ac2005-04-28 22:41:05 -0700832 /* BB special case reconnect tid and uid here? */
Steve Frencha761ac52007-10-18 21:45:27 +0000833 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
835 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +0000836 if (receive_len >= sizeof(struct smb_hdr) - 4
837 /* do not count RFC1001 header */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 (2 * out_buf->WordCount) + 2 /* bcc */ )
Steve French0f2b27c2005-11-16 14:25:50 -0800839 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 } else {
841 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +0000842 cERROR(1, ("Bad MID state?"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 }
844 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000846out:
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000847 DeleteMidQEntry(midQ);
Steve French79a58d12007-07-06 22:44:50 +0000848 atomic_dec(&ses->server->inFlight);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000849 wake_up(&ses->server->request_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
851 return rc;
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000852}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000854/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
855
856static int
857send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
858 struct mid_q_entry *midQ)
859{
860 int rc = 0;
861 struct cifsSesInfo *ses = tcon->ses;
862 __u16 mid = in_buf->Mid;
863
864 header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
865 in_buf->Mid = mid;
Steve French79a58d12007-07-06 22:44:50 +0000866 down(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000867 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
868 if (rc) {
869 up(&ses->server->tcpSem);
870 return rc;
871 }
872 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000873 (struct sockaddr *) &(ses->server->addr.sockAddr),
874 ses->server->noblocksnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 up(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000876 return rc;
877}
878
879/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
880 blocking lock to return. */
881
882static int
883send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
884 struct smb_hdr *in_buf,
885 struct smb_hdr *out_buf)
886{
887 int bytes_returned;
888 struct cifsSesInfo *ses = tcon->ses;
889 LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
890
891 /* We just modify the current in_buf to change
892 the type of lock from LOCKING_ANDX_SHARED_LOCK
893 or LOCKING_ANDX_EXCLUSIVE_LOCK to
894 LOCKING_ANDX_CANCEL_LOCK. */
895
896 pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
897 pSMB->Timeout = 0;
898 pSMB->hdr.Mid = GetNextMid(ses->server);
899
900 return SendReceive(xid, ses, in_buf, out_buf,
Steve French133672e2007-11-13 22:41:37 +0000901 &bytes_returned, CIFS_STD_OP);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000902}
903
904int
905SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
906 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
907 int *pbytes_returned)
908{
909 int rc = 0;
910 int rstart = 0;
911 unsigned int receive_len;
912 struct mid_q_entry *midQ;
913 struct cifsSesInfo *ses;
914
915 if (tcon == NULL || tcon->ses == NULL) {
Steve French79a58d12007-07-06 22:44:50 +0000916 cERROR(1, ("Null smb session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000917 return -EIO;
918 }
919 ses = tcon->ses;
920
Steve French79a58d12007-07-06 22:44:50 +0000921 if (ses->server == NULL) {
922 cERROR(1, ("Null tcp session"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000923 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 }
925
Steve French79a58d12007-07-06 22:44:50 +0000926 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000927 return -ENOENT;
928
Steve French79a58d12007-07-06 22:44:50 +0000929 /* Ensure that we do not send more than 50 overlapping requests
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000930 to the same server. We may make this configurable later or
931 use ses->maxReq */
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
Steve French79a58d12007-07-06 22:44:50 +0000941 down(&ses->server->tcpSem);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000942
943 rc = allocate_mid(ses, in_buf, &midQ);
944 if (rc) {
945 up(&ses->server->tcpSem);
946 return rc;
947 }
948
949 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
950 up(&ses->server->tcpSem);
951 cERROR(1, ("Illegal length, greater than maximum frame, %d",
952 in_buf->smb_buf_length));
953 DeleteMidQEntry(midQ);
954 return -EIO;
955 }
956
957 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
958
959 midQ->midState = MID_REQUEST_SUBMITTED;
960#ifdef CONFIG_CIFS_STATS2
961 atomic_inc(&ses->server->inSend);
962#endif
963 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000964 (struct sockaddr *) &(ses->server->addr.sockAddr),
965 ses->server->noblocksnd);
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000966#ifdef CONFIG_CIFS_STATS2
967 atomic_dec(&ses->server->inSend);
968 midQ->when_sent = jiffies;
969#endif
970 up(&ses->server->tcpSem);
971
Steve French79a58d12007-07-06 22:44:50 +0000972 if (rc < 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000973 DeleteMidQEntry(midQ);
974 return rc;
975 }
976
977 /* Wait for a reply - allow signals to interrupt. */
978 rc = wait_event_interruptible(ses->server->response_q,
Steve French79a58d12007-07-06 22:44:50 +0000979 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
Jeremy Allison7ee1af72006-08-02 21:56:33 +0000980 ((ses->server->tcpStatus != CifsGood) &&
981 (ses->server->tcpStatus != CifsNew)));
982
983 /* Were we interrupted by a signal ? */
984 if ((rc == -ERESTARTSYS) &&
985 (midQ->midState == MID_REQUEST_SUBMITTED) &&
986 ((ses->server->tcpStatus == CifsGood) ||
987 (ses->server->tcpStatus == CifsNew))) {
988
989 if (in_buf->Command == SMB_COM_TRANSACTION2) {
990 /* POSIX lock. We send a NT_CANCEL SMB to cause the
991 blocking lock to return. */
992
993 rc = send_nt_cancel(tcon, in_buf, midQ);
994 if (rc) {
995 DeleteMidQEntry(midQ);
996 return rc;
997 }
998 } else {
999 /* Windows lock. We send a LOCKINGX_CANCEL_LOCK
1000 to cause the blocking lock to return. */
1001
1002 rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
1003
1004 /* If we get -ENOLCK back the lock may have
1005 already been removed. Don't exit in this case. */
1006 if (rc && rc != -ENOLCK) {
1007 DeleteMidQEntry(midQ);
1008 return rc;
1009 }
1010 }
1011
1012 /* Wait 5 seconds for the response. */
Steve French79a58d12007-07-06 22:44:50 +00001013 if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001014 /* We got the response - restart system call. */
1015 rstart = 1;
1016 }
1017 }
1018
1019 spin_lock(&GlobalMid_Lock);
1020 if (midQ->resp_buf) {
1021 spin_unlock(&GlobalMid_Lock);
1022 receive_len = midQ->resp_buf->smb_buf_length;
1023 } else {
Steve French79a58d12007-07-06 22:44:50 +00001024 cERROR(1, ("No response for cmd %d mid %d",
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001025 midQ->command, midQ->mid));
Steve French79a58d12007-07-06 22:44:50 +00001026 if (midQ->midState == MID_REQUEST_SUBMITTED) {
1027 if (ses->server->tcpStatus == CifsExiting)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001028 rc = -EHOSTDOWN;
1029 else {
1030 ses->server->tcpStatus = CifsNeedReconnect;
1031 midQ->midState = MID_RETRY_NEEDED;
1032 }
1033 }
1034
1035 if (rc != -EHOSTDOWN) {
Steve French79a58d12007-07-06 22:44:50 +00001036 if (midQ->midState == MID_RETRY_NEEDED) {
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001037 rc = -EAGAIN;
Steve French79a58d12007-07-06 22:44:50 +00001038 cFYI(1, ("marking request for retry"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001039 } else {
1040 rc = -EIO;
1041 }
1042 }
1043 spin_unlock(&GlobalMid_Lock);
1044 DeleteMidQEntry(midQ);
1045 return rc;
1046 }
Steve French50c2f752007-07-13 00:33:32 +00001047
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001048 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
1049 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
1050 receive_len, xid));
1051 rc = -EIO;
1052 } else { /* rcvd frame is ok */
1053
1054 if (midQ->resp_buf && out_buf
1055 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
1056 out_buf->smb_buf_length = receive_len;
1057 memcpy((char *)out_buf + 4,
1058 (char *)midQ->resp_buf + 4,
1059 receive_len);
1060
1061 dump_smb(out_buf, 92);
1062 /* convert the length into a more usable form */
Steve French79a58d12007-07-06 22:44:50 +00001063 if ((receive_len > 24) &&
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001064 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
1065 SECMODE_SIGN_ENABLED))) {
1066 rc = cifs_verify_signature(out_buf,
Steve Frenchb609f062007-07-09 07:55:14 +00001067 &ses->server->mac_signing_key,
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001068 midQ->sequence_number+1);
Steve French79a58d12007-07-06 22:44:50 +00001069 if (rc) {
1070 cERROR(1, ("Unexpected SMB signature"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001071 /* BB FIXME add code to kill session */
1072 }
1073 }
1074
1075 *pbytes_returned = out_buf->smb_buf_length;
1076
1077 /* BB special case reconnect tid and uid here? */
Steve Frencha761ac52007-10-18 21:45:27 +00001078 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001079
1080 /* convert ByteCount if necessary */
Steve French26f57362007-08-30 22:09:15 +00001081 if (receive_len >= sizeof(struct smb_hdr) - 4
1082 /* do not count RFC1001 header */ +
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001083 (2 * out_buf->WordCount) + 2 /* bcc */ )
1084 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1085 } else {
1086 rc = -EIO;
Steve French79a58d12007-07-06 22:44:50 +00001087 cERROR(1, ("Bad MID state?"));
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001088 }
1089 }
1090 DeleteMidQEntry(midQ);
1091 if (rstart && rc == -EACCES)
1092 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 return rc;
1094}