blob: d16e6032d4cfceae507e8920efa7686b020170bc [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/transport.c
3 *
Steve Frenchb8643e12005-04-28 22:41:07 -07004 * Copyright (C) International Business Machines Corp., 2002,2005
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.
7 *
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
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
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"
35
36extern mempool_t *cifs_mid_poolp;
37extern kmem_cache_t *cifs_oplock_cachep;
38
39static struct mid_q_entry *
40AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
41{
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 }
52
Steve Frenchd6e04ae2005-06-13 13:24:43 -050053 temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
54 SLAB_KERNEL | SLAB_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 if (temp == NULL)
56 return temp;
57 else {
58 memset(temp, 0, sizeof (struct mid_q_entry));
59 temp->mid = smb_buffer->Mid; /* always LE */
60 temp->pid = current->pid;
61 temp->command = smb_buffer->Command;
62 cFYI(1, ("For smb_command %d", temp->command));
Steve French1047abc2005-10-11 19:58:06 -070063 /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
64 /* when mid allocated can be before when sent */
65 temp->when_alloc = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 temp->ses = ses;
67 temp->tsk = current;
68 }
69
70 spin_lock(&GlobalMid_Lock);
71 list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
72 atomic_inc(&midCount);
73 temp->midState = MID_REQUEST_ALLOCATED;
74 spin_unlock(&GlobalMid_Lock);
75 return temp;
76}
77
78static void
79DeleteMidQEntry(struct mid_q_entry *midEntry)
80{
Steve French1047abc2005-10-11 19:58:06 -070081#ifdef CONFIG_CIFS_STATS2
82 unsigned long now;
83#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 spin_lock(&GlobalMid_Lock);
85 midEntry->midState = MID_FREE;
86 list_del(&midEntry->qhead);
87 atomic_dec(&midCount);
88 spin_unlock(&GlobalMid_Lock);
Steve Frenchb8643e12005-04-28 22:41:07 -070089 if(midEntry->largeBuf)
90 cifs_buf_release(midEntry->resp_buf);
91 else
92 cifs_small_buf_release(midEntry->resp_buf);
Steve French1047abc2005-10-11 19:58:06 -070093#ifdef CONFIG_CIFS_STATS2
94 now = jiffies;
95 /* commands taking longer than one second are indications that
96 something is wrong, unless it is quite a slow link or server */
97 if((now - midEntry->when_alloc) > HZ) {
98 if((cifsFYI & CIFS_TIMER) &&
99 (midEntry->command != SMB_COM_LOCKING_ANDX)) {
100 printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
101 midEntry->command, midEntry->mid);
102 printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
103 now - midEntry->when_alloc,
104 now - midEntry->when_sent,
105 now - midEntry->when_received);
106 }
107 }
108#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 mempool_free(midEntry, cifs_mid_poolp);
110}
111
112struct oplock_q_entry *
113AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
114{
115 struct oplock_q_entry *temp;
116 if ((pinode== NULL) || (tcon == NULL)) {
117 cERROR(1, ("Null parms passed to AllocOplockQEntry"));
118 return NULL;
119 }
120 temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
121 SLAB_KERNEL);
122 if (temp == NULL)
123 return temp;
124 else {
125 temp->pinode = pinode;
126 temp->tcon = tcon;
127 temp->netfid = fid;
128 spin_lock(&GlobalMid_Lock);
129 list_add_tail(&temp->qhead, &GlobalOplock_Q);
130 spin_unlock(&GlobalMid_Lock);
131 }
132 return temp;
133
134}
135
136void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry)
137{
138 spin_lock(&GlobalMid_Lock);
139 /* should we check if list empty first? */
140 list_del(&oplockEntry->qhead);
141 spin_unlock(&GlobalMid_Lock);
142 kmem_cache_free(cifs_oplock_cachep, oplockEntry);
143}
144
145int
146smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
147 unsigned int smb_buf_length, struct sockaddr *sin)
148{
149 int rc = 0;
150 int i = 0;
151 struct msghdr smb_msg;
152 struct kvec iov;
153 unsigned len = smb_buf_length + 4;
154
155 if(ssocket == NULL)
156 return -ENOTSOCK; /* BB eventually add reconnect code here */
157 iov.iov_base = smb_buffer;
158 iov.iov_len = len;
159
160 smb_msg.msg_name = sin;
161 smb_msg.msg_namelen = sizeof (struct sockaddr);
162 smb_msg.msg_control = NULL;
163 smb_msg.msg_controllen = 0;
164 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
165
166 /* smb header is converted in header_assemble. bcc and rest of SMB word
167 area, and byte area if necessary, is converted to littleendian in
168 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
169 Flags2 is converted in SendReceive */
170
171 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Steve French3e844692005-10-03 13:37:24 -0700172 cFYI(1, ("Sending smb of length %d", smb_buf_length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 dump_smb(smb_buffer, len);
174
175 while (len > 0) {
176 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
177 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
178 i++;
Steve French3e844692005-10-03 13:37:24 -0700179 /* smaller timeout here than send2 since smaller size */
180 /* Although it may not be required, this also is smaller
181 oplock break time */
Steve French68058e72005-10-10 10:34:22 -0700182 if(i > 12) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 cERROR(1,
Steve French68058e72005-10-10 10:34:22 -0700184 ("sends on sock %p stuck for 7 seconds",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 ssocket));
186 rc = -EAGAIN;
187 break;
188 }
Steve French68058e72005-10-10 10:34:22 -0700189 msleep(1 << i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 continue;
191 }
192 if (rc < 0)
193 break;
Steve French5e1253b2005-10-10 14:06:37 -0700194 else
195 i = 0; /* reset i after each successful send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 iov.iov_base += rc;
197 iov.iov_len -= rc;
198 len -= rc;
199 }
200
201 if (rc < 0) {
Steve French3e844692005-10-03 13:37:24 -0700202 cERROR(1,("Error %d sending data on socket to server", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 } else {
204 rc = 0;
205 }
206
207 return rc;
208}
209
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500210static int
Steve French3e844692005-10-03 13:37:24 -0700211smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
212 struct sockaddr *sin)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213{
214 int rc = 0;
215 int i = 0;
216 struct msghdr smb_msg;
Steve French3e844692005-10-03 13:37:24 -0700217 struct smb_hdr *smb_buffer = iov[0].iov_base;
218 unsigned int len = iov[0].iov_len;
219 unsigned int total_len;
220 int first_vec = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500221
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 if(ssocket == NULL)
223 return -ENOTSOCK; /* BB eventually add reconnect code here */
Steve French3e844692005-10-03 13:37:24 -0700224
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 smb_msg.msg_name = sin;
226 smb_msg.msg_namelen = sizeof (struct sockaddr);
227 smb_msg.msg_control = NULL;
228 smb_msg.msg_controllen = 0;
229 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
230
231 /* smb header is converted in header_assemble. bcc and rest of SMB word
232 area, and byte area if necessary, is converted to littleendian in
233 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
234 Flags2 is converted in SendReceive */
235
Steve French3e844692005-10-03 13:37:24 -0700236
237 total_len = 0;
238 for (i = 0; i < n_vec; i++)
239 total_len += iov[i].iov_len;
240
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
Steve French3e844692005-10-03 13:37:24 -0700242 cFYI(1, ("Sending smb: total_len %d", total_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 dump_smb(smb_buffer, len);
244
Steve French3e844692005-10-03 13:37:24 -0700245 while (total_len) {
246 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
247 n_vec - first_vec, total_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
249 i++;
Steve French68058e72005-10-10 10:34:22 -0700250 if(i >= 14) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 cERROR(1,
Steve French68058e72005-10-10 10:34:22 -0700252 ("sends on sock %p stuck for 15 seconds",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 ssocket));
254 rc = -EAGAIN;
255 break;
256 }
Steve French68058e72005-10-10 10:34:22 -0700257 msleep(1 << i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 continue;
259 }
260 if (rc < 0)
261 break;
Steve French3e844692005-10-03 13:37:24 -0700262
263 if (rc >= total_len) {
264 WARN_ON(rc > total_len);
265 break;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500266 }
Steve French3e844692005-10-03 13:37:24 -0700267 if(rc == 0) {
268 /* should never happen, letting socket clear before
269 retrying is our only obvious option here */
Steve French04c08812005-10-03 19:33:15 -0700270 cERROR(1,("tcp sent no data"));
Steve French3e844692005-10-03 13:37:24 -0700271 msleep(500);
272 continue;
273 }
274 total_len -= rc;
Steve French68058e72005-10-10 10:34:22 -0700275 /* the line below resets i */
Steve French3e844692005-10-03 13:37:24 -0700276 for (i = first_vec; i < n_vec; i++) {
277 if (iov[i].iov_len) {
278 if (rc > iov[i].iov_len) {
279 rc -= iov[i].iov_len;
280 iov[i].iov_len = 0;
281 } else {
282 iov[i].iov_base += rc;
283 iov[i].iov_len -= rc;
284 first_vec = i;
285 break;
286 }
287 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500288 }
Steve French5e1253b2005-10-10 14:06:37 -0700289 i = 0; /* in case we get ENOSPC on the next send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 }
291
292 if (rc < 0) {
Steve French3e844692005-10-03 13:37:24 -0700293 cERROR(1,("Error %d sending data on socket to server", rc));
294 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
297 return rc;
298}
299
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300int
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500301SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
Steve Frenchec637e32005-12-12 20:53:18 -0800302 struct kvec *iov, int n_vec, int * pRespBufType /* ret */,
Steve French3e844692005-10-03 13:37:24 -0700303 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304{
305 int rc = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500306 unsigned int receive_len;
307 unsigned long timeout;
308 struct mid_q_entry *midQ;
Steve French3e844692005-10-03 13:37:24 -0700309 struct smb_hdr *in_buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -0800310
311 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Steve French4b8f9302006-02-26 16:41:18 +0000313 if ((ses == NULL) || (ses->server == NULL)) {
314 cifs_small_buf_release(in_buf);
315 cERROR(1,("Null session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 return -EIO;
317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Steve French4b8f9302006-02-26 16:41:18 +0000319 if(ses->server->tcpStatus == CifsExiting) {
320 cifs_small_buf_release(in_buf);
Steve French31ca3bc2005-04-28 22:41:11 -0700321 return -ENOENT;
Steve French4b8f9302006-02-26 16:41:18 +0000322 }
Steve French31ca3bc2005-04-28 22:41:11 -0700323
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 /* Ensure that we do not send more than 50 overlapping requests
325 to the same server. We may make this configurable later or
326 use ses->maxReq */
327 if(long_op == -1) {
328 /* oplock breaks must not be held up */
329 atomic_inc(&ses->server->inFlight);
330 } else {
331 spin_lock(&GlobalMid_Lock);
332 while(1) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500333 if(atomic_read(&ses->server->inFlight) >=
334 cifs_max_pending){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 spin_unlock(&GlobalMid_Lock);
Steve French131afd0b2005-10-07 09:51:05 -0700336#ifdef CONFIG_CIFS_STATS2
337 atomic_inc(&ses->server->num_waiters);
338#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 wait_event(ses->server->request_q,
340 atomic_read(&ses->server->inFlight)
341 < cifs_max_pending);
Steve French131afd0b2005-10-07 09:51:05 -0700342#ifdef CONFIG_CIFS_STATS2
343 atomic_dec(&ses->server->num_waiters);
344#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 spin_lock(&GlobalMid_Lock);
346 } else {
347 if(ses->server->tcpStatus == CifsExiting) {
348 spin_unlock(&GlobalMid_Lock);
Steve French4b8f9302006-02-26 16:41:18 +0000349 cifs_small_buf_release(in_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 return -ENOENT;
351 }
352
353 /* can not count locking commands against total since
354 they are allowed to block on server */
355
356 if(long_op < 3) {
357 /* update # of requests on the wire to server */
358 atomic_inc(&ses->server->inFlight);
359 }
360 spin_unlock(&GlobalMid_Lock);
361 break;
362 }
363 }
364 }
365 /* make sure that we sign in the same order that we send on this socket
366 and avoid races inside tcp sendmsg code that could cause corruption
367 of smb data */
368
369 down(&ses->server->tcpSem);
370
371 if (ses->server->tcpStatus == CifsExiting) {
372 rc = -ENOENT;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500373 goto out_unlock2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
375 cFYI(1,("tcp session dead - return to caller to retry"));
376 rc = -EAGAIN;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500377 goto out_unlock2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 } else if (ses->status != CifsGood) {
379 /* check if SMB session is bad because we are setting it up */
380 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
381 (in_buf->Command != SMB_COM_NEGOTIATE)) {
382 rc = -EAGAIN;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500383 goto out_unlock2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 } /* else ok - we are setting up session */
385 }
386 midQ = AllocMidQEntry(in_buf, ses);
387 if (midQ == NULL) {
388 up(&ses->server->tcpSem);
Steve French4b8f9302006-02-26 16:41:18 +0000389 cifs_small_buf_release(in_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 /* If not lock req, update # of requests on wire to server */
391 if(long_op < 3) {
392 atomic_dec(&ses->server->inFlight);
393 wake_up(&ses->server->request_q);
394 }
395 return -ENOMEM;
396 }
397
Steve French84afc292005-12-02 13:32:45 -0800398 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
400 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700401#ifdef CONFIG_CIFS_STATS2
402 atomic_inc(&ses->server->inSend);
403#endif
Steve French3e844692005-10-03 13:37:24 -0700404 rc = smb_send2(ses->server->ssocket, iov, n_vec,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500405 (struct sockaddr *) &(ses->server->addr.sockAddr));
Steve French131afd0b2005-10-07 09:51:05 -0700406#ifdef CONFIG_CIFS_STATS2
407 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700408 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700409#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 if(rc < 0) {
411 DeleteMidQEntry(midQ);
412 up(&ses->server->tcpSem);
Steve French4b8f9302006-02-26 16:41:18 +0000413 cifs_small_buf_release(in_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 /* If not lock req, update # of requests on wire to server */
415 if(long_op < 3) {
416 atomic_dec(&ses->server->inFlight);
417 wake_up(&ses->server->request_q);
418 }
419 return rc;
Steve French4b8f9302006-02-26 16:41:18 +0000420 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 up(&ses->server->tcpSem);
Steve French4b8f9302006-02-26 16:41:18 +0000422 cifs_small_buf_release(in_buf);
423 }
424
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500425 if (long_op == -1)
426 goto cifs_no_response_exit2;
427 else if (long_op == 2) /* writes past end of file can take loong time */
Steve French37c0eb42005-10-05 14:50:29 -0700428 timeout = 180 * HZ;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500429 else if (long_op == 1)
430 timeout = 45 * HZ; /* should be greater than
431 servers oplock break timeout (about 43 seconds) */
432 else if (long_op > 2) {
433 timeout = MAX_SCHEDULE_TIMEOUT;
434 } else
435 timeout = 15 * HZ;
436 /* wait for 15 seconds or until woken up due to response arriving or
437 due to last connection to this server being unmounted */
438 if (signal_pending(current)) {
439 /* if signal pending do not hold up user for full smb timeout
440 but we still give response a change to complete */
441 timeout = 2 * HZ;
442 }
443
444 /* No user interrupts in wait - wreaks havoc with performance */
445 if(timeout != MAX_SCHEDULE_TIMEOUT) {
Steve French14a441a2b2006-07-16 04:32:51 +0000446 unsigned long curr_timeout;
447
448 for (;;) {
449 curr_timeout = timeout + jiffies;
450 wait_event(ses->server->response_q,
451 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
452 time_after(jiffies, curr_timeout) ||
453 ((ses->server->tcpStatus != CifsGood) &&
454 (ses->server->tcpStatus != CifsNew)));
455
456 if (time_after(jiffies, curr_timeout) &&
457 (midQ->midState & MID_REQUEST_SUBMITTED) &&
458 ((ses->server->tcpStatus == CifsGood) ||
459 (ses->server->tcpStatus == CifsNew))) {
460
461 unsigned long lrt;
462
463 /* We timed out. Is the server still
464 sending replies ? */
465 spin_lock(&GlobalMid_Lock);
466 lrt = ses->server->lstrp;
467 spin_unlock(&GlobalMid_Lock);
468
469 /* Calculate 10 seconds past last receive time.
470 Although we prefer not to time out if the
471 server is still responding - we will time
472 out if the server takes more than 15 (or 45
473 or 180) seconds to respond to this request
474 and has not responded to any request from
475 other threads on the client within 10 seconds */
476 lrt += (10 * HZ);
477 if (time_after(jiffies, lrt)) {
478 /* No replies for 10 seconds. */
479 cERROR(1,("server not responding"));
480 break;
481 }
482 } else {
483 break;
484 }
485 }
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500486 } else {
487 wait_event(ses->server->response_q,
488 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
489 ((ses->server->tcpStatus != CifsGood) &&
490 (ses->server->tcpStatus != CifsNew)));
491 }
492
493 spin_lock(&GlobalMid_Lock);
494 if (midQ->resp_buf) {
495 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700496 receive_len = midQ->resp_buf->smb_buf_length;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500497 } else {
Steve French37c0eb42005-10-05 14:50:29 -0700498 cERROR(1,("No response to cmd %d mid %d",
499 midQ->command, midQ->mid));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500500 if(midQ->midState == MID_REQUEST_SUBMITTED) {
501 if(ses->server->tcpStatus == CifsExiting)
502 rc = -EHOSTDOWN;
503 else {
504 ses->server->tcpStatus = CifsNeedReconnect;
505 midQ->midState = MID_RETRY_NEEDED;
506 }
507 }
508
509 if (rc != -EHOSTDOWN) {
510 if(midQ->midState == MID_RETRY_NEEDED) {
511 rc = -EAGAIN;
512 cFYI(1,("marking request for retry"));
513 } else {
514 rc = -EIO;
515 }
516 }
517 spin_unlock(&GlobalMid_Lock);
518 DeleteMidQEntry(midQ);
519 /* If not lock req, update # of requests on wire to server */
520 if(long_op < 3) {
521 atomic_dec(&ses->server->inFlight);
522 wake_up(&ses->server->request_q);
523 }
524 return rc;
525 }
526
527 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
528 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
529 receive_len, xid));
530 rc = -EIO;
531 } else { /* rcvd frame is ok */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500532 if (midQ->resp_buf &&
533 (midQ->midState == MID_RESPONSE_RECEIVED)) {
Steve French84afc292005-12-02 13:32:45 -0800534
Steve Frenchec637e32005-12-12 20:53:18 -0800535 iov[0].iov_base = (char *)midQ->resp_buf;
536 if(midQ->largeBuf)
537 *pRespBufType = CIFS_LARGE_BUFFER;
538 else
539 *pRespBufType = CIFS_SMALL_BUFFER;
540 iov[0].iov_len = receive_len + 4;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500541
Steve Frenchec637e32005-12-12 20:53:18 -0800542 dump_smb(midQ->resp_buf, 80);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500543 /* convert the length into a more usable form */
544 if((receive_len > 24) &&
545 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
546 SECMODE_SIGN_ENABLED))) {
Steve Frenchec637e32005-12-12 20:53:18 -0800547 rc = cifs_verify_signature(midQ->resp_buf,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500548 ses->server->mac_signing_key,
549 midQ->sequence_number+1);
550 if(rc) {
551 cERROR(1,("Unexpected SMB signature"));
552 /* BB FIXME add code to kill session */
553 }
554 }
555
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500556 /* BB special case reconnect tid and uid here? */
Steve French6ab16d22005-11-29 20:55:11 -0800557 /* BB special case Errbadpassword and pwdexpired here */
Steve Frenchec637e32005-12-12 20:53:18 -0800558 rc = map_smb_to_linux_error(midQ->resp_buf);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500559
560 /* convert ByteCount if necessary */
561 if (receive_len >=
562 sizeof (struct smb_hdr) -
563 4 /* do not count RFC1001 header */ +
Steve Frenchec637e32005-12-12 20:53:18 -0800564 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
565 BCC(midQ->resp_buf) =
566 le16_to_cpu(BCC_LE(midQ->resp_buf));
567 midQ->resp_buf = NULL; /* mark it so will not be freed
568 by DeleteMidQEntry */
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500569 } else {
570 rc = -EIO;
Steve Frenchab2f2182005-09-15 20:44:50 -0700571 cFYI(1,("Bad MID state?"));
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500572 }
573 }
574cifs_no_response_exit2:
575 DeleteMidQEntry(midQ);
576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 if(long_op < 3) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500578 atomic_dec(&ses->server->inFlight);
579 wake_up(&ses->server->request_q);
580 }
581
582 return rc;
583
584out_unlock2:
585 up(&ses->server->tcpSem);
Steve French4b8f9302006-02-26 16:41:18 +0000586 cifs_small_buf_release(in_buf);
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500587 /* If not lock req, update # of requests on wire to server */
588 if(long_op < 3) {
589 atomic_dec(&ses->server->inFlight);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 wake_up(&ses->server->request_q);
591 }
592
593 return rc;
594}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596int
597SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
598 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
599 int *pbytes_returned, const int long_op)
600{
601 int rc = 0;
602 unsigned int receive_len;
603 unsigned long timeout;
604 struct mid_q_entry *midQ;
605
606 if (ses == NULL) {
607 cERROR(1,("Null smb session"));
608 return -EIO;
609 }
610 if(ses->server == NULL) {
611 cERROR(1,("Null tcp session"));
612 return -EIO;
613 }
614
Steve French31ca3bc2005-04-28 22:41:11 -0700615 if(ses->server->tcpStatus == CifsExiting)
616 return -ENOENT;
617
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 /* Ensure that we do not send more than 50 overlapping requests
619 to the same server. We may make this configurable later or
620 use ses->maxReq */
621 if(long_op == -1) {
622 /* oplock breaks must not be held up */
623 atomic_inc(&ses->server->inFlight);
624 } else {
625 spin_lock(&GlobalMid_Lock);
626 while(1) {
Steve French275cde12005-04-28 22:41:10 -0700627 if(atomic_read(&ses->server->inFlight) >=
628 cifs_max_pending){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 spin_unlock(&GlobalMid_Lock);
Steve French131afd0b2005-10-07 09:51:05 -0700630#ifdef CONFIG_CIFS_STATS2
631 atomic_inc(&ses->server->num_waiters);
632#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 wait_event(ses->server->request_q,
634 atomic_read(&ses->server->inFlight)
635 < cifs_max_pending);
Steve French131afd0b2005-10-07 09:51:05 -0700636#ifdef CONFIG_CIFS_STATS2
637 atomic_dec(&ses->server->num_waiters);
638#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 spin_lock(&GlobalMid_Lock);
640 } else {
641 if(ses->server->tcpStatus == CifsExiting) {
642 spin_unlock(&GlobalMid_Lock);
643 return -ENOENT;
644 }
645
646 /* can not count locking commands against total since
647 they are allowed to block on server */
648
649 if(long_op < 3) {
650 /* update # of requests on the wire to server */
651 atomic_inc(&ses->server->inFlight);
652 }
653 spin_unlock(&GlobalMid_Lock);
654 break;
655 }
656 }
657 }
658 /* make sure that we sign in the same order that we send on this socket
659 and avoid races inside tcp sendmsg code that could cause corruption
660 of smb data */
661
662 down(&ses->server->tcpSem);
663
664 if (ses->server->tcpStatus == CifsExiting) {
665 rc = -ENOENT;
666 goto out_unlock;
667 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
668 cFYI(1,("tcp session dead - return to caller to retry"));
669 rc = -EAGAIN;
670 goto out_unlock;
671 } else if (ses->status != CifsGood) {
672 /* check if SMB session is bad because we are setting it up */
673 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
674 (in_buf->Command != SMB_COM_NEGOTIATE)) {
675 rc = -EAGAIN;
676 goto out_unlock;
677 } /* else ok - we are setting up session */
678 }
679 midQ = AllocMidQEntry(in_buf, ses);
680 if (midQ == NULL) {
681 up(&ses->server->tcpSem);
682 /* If not lock req, update # of requests on wire to server */
683 if(long_op < 3) {
684 atomic_dec(&ses->server->inFlight);
685 wake_up(&ses->server->request_q);
686 }
687 return -ENOMEM;
688 }
689
690 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
691 up(&ses->server->tcpSem);
Steve French26a21b92006-05-31 18:05:34 +0000692 cERROR(1, ("Illegal length, greater than maximum frame, %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 in_buf->smb_buf_length));
694 DeleteMidQEntry(midQ);
695 /* If not lock req, update # of requests on wire to server */
696 if(long_op < 3) {
697 atomic_dec(&ses->server->inFlight);
698 wake_up(&ses->server->request_q);
699 }
700 return -EIO;
701 }
702
Steve Frenchad009ac2005-04-28 22:41:05 -0700703 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
705 midQ->midState = MID_REQUEST_SUBMITTED;
Steve French131afd0b2005-10-07 09:51:05 -0700706#ifdef CONFIG_CIFS_STATS2
707 atomic_inc(&ses->server->inSend);
708#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
710 (struct sockaddr *) &(ses->server->addr.sockAddr));
Steve French131afd0b2005-10-07 09:51:05 -0700711#ifdef CONFIG_CIFS_STATS2
712 atomic_dec(&ses->server->inSend);
Steve French1047abc2005-10-11 19:58:06 -0700713 midQ->when_sent = jiffies;
Steve French131afd0b2005-10-07 09:51:05 -0700714#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 if(rc < 0) {
716 DeleteMidQEntry(midQ);
717 up(&ses->server->tcpSem);
718 /* If not lock req, update # of requests on wire to server */
719 if(long_op < 3) {
720 atomic_dec(&ses->server->inFlight);
721 wake_up(&ses->server->request_q);
722 }
723 return rc;
724 } else
725 up(&ses->server->tcpSem);
726 if (long_op == -1)
727 goto cifs_no_response_exit;
Steve French275cde12005-04-28 22:41:10 -0700728 else if (long_op == 2) /* writes past end of file can take loong time */
Steve French37c0eb42005-10-05 14:50:29 -0700729 timeout = 180 * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 else if (long_op == 1)
731 timeout = 45 * HZ; /* should be greater than
732 servers oplock break timeout (about 43 seconds) */
733 else if (long_op > 2) {
734 timeout = MAX_SCHEDULE_TIMEOUT;
735 } else
736 timeout = 15 * HZ;
737 /* wait for 15 seconds or until woken up due to response arriving or
738 due to last connection to this server being unmounted */
739 if (signal_pending(current)) {
740 /* if signal pending do not hold up user for full smb timeout
741 but we still give response a change to complete */
742 timeout = 2 * HZ;
743 }
744
745 /* No user interrupts in wait - wreaks havoc with performance */
746 if(timeout != MAX_SCHEDULE_TIMEOUT) {
Steve French14a441a2b2006-07-16 04:32:51 +0000747 unsigned long curr_timeout;
748
749 for (;;) {
750 curr_timeout = timeout + jiffies;
751 wait_event(ses->server->response_q,
752 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
753 time_after(jiffies, curr_timeout) ||
754 ((ses->server->tcpStatus != CifsGood) &&
755 (ses->server->tcpStatus != CifsNew)));
756
757 if (time_after(jiffies, curr_timeout) &&
758 (midQ->midState & MID_REQUEST_SUBMITTED) &&
759 ((ses->server->tcpStatus == CifsGood) ||
760 (ses->server->tcpStatus == CifsNew))) {
761
762 unsigned long lrt;
763
764 /* We timed out. Is the server still
765 sending replies ? */
766 spin_lock(&GlobalMid_Lock);
767 lrt = ses->server->lstrp;
768 spin_unlock(&GlobalMid_Lock);
769
770 /* Calculate 10 seconds past last receive time*/
771 lrt += (10 * HZ);
772 if (time_after(jiffies, lrt)) {
773 /* Server sent no reply in 10 seconds */
774 cERROR(1,("Server not responding"));
775 break;
776 }
777 } else {
778 break;
779 }
780 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 } else {
782 wait_event(ses->server->response_q,
783 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
784 ((ses->server->tcpStatus != CifsGood) &&
785 (ses->server->tcpStatus != CifsNew)));
786 }
787
788 spin_lock(&GlobalMid_Lock);
789 if (midQ->resp_buf) {
790 spin_unlock(&GlobalMid_Lock);
Steve French70ca7342005-09-22 16:32:06 -0700791 receive_len = midQ->resp_buf->smb_buf_length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 } else {
Steve French37c0eb42005-10-05 14:50:29 -0700793 cERROR(1,("No response for cmd %d mid %d",
794 midQ->command, midQ->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 if(midQ->midState == MID_REQUEST_SUBMITTED) {
796 if(ses->server->tcpStatus == CifsExiting)
797 rc = -EHOSTDOWN;
798 else {
799 ses->server->tcpStatus = CifsNeedReconnect;
800 midQ->midState = MID_RETRY_NEEDED;
801 }
802 }
803
804 if (rc != -EHOSTDOWN) {
805 if(midQ->midState == MID_RETRY_NEEDED) {
806 rc = -EAGAIN;
807 cFYI(1,("marking request for retry"));
808 } else {
809 rc = -EIO;
810 }
811 }
812 spin_unlock(&GlobalMid_Lock);
813 DeleteMidQEntry(midQ);
814 /* If not lock req, update # of requests on wire to server */
815 if(long_op < 3) {
816 atomic_dec(&ses->server->inFlight);
817 wake_up(&ses->server->request_q);
818 }
819 return rc;
820 }
821
822 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Steve Frenchad009ac2005-04-28 22:41:05 -0700823 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 receive_len, xid));
825 rc = -EIO;
826 } else { /* rcvd frame is ok */
827
828 if (midQ->resp_buf && out_buf
829 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
830 out_buf->smb_buf_length = receive_len;
831 memcpy((char *)out_buf + 4,
832 (char *)midQ->resp_buf + 4,
833 receive_len);
834
835 dump_smb(out_buf, 92);
836 /* convert the length into a more usable form */
837 if((receive_len > 24) &&
Steve Frenchad009ac2005-04-28 22:41:05 -0700838 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
839 SECMODE_SIGN_ENABLED))) {
840 rc = cifs_verify_signature(out_buf,
841 ses->server->mac_signing_key,
842 midQ->sequence_number+1);
843 if(rc) {
Steve French275cde12005-04-28 22:41:10 -0700844 cERROR(1,("Unexpected SMB signature"));
845 /* BB FIXME add code to kill session */
Steve Frenchad009ac2005-04-28 22:41:05 -0700846 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 }
848
849 *pbytes_returned = out_buf->smb_buf_length;
850
Steve Frenchad009ac2005-04-28 22:41:05 -0700851 /* BB special case reconnect tid and uid here? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 rc = map_smb_to_linux_error(out_buf);
853
854 /* convert ByteCount if necessary */
855 if (receive_len >=
856 sizeof (struct smb_hdr) -
857 4 /* do not count RFC1001 header */ +
858 (2 * out_buf->WordCount) + 2 /* bcc */ )
Steve French0f2b27c2005-11-16 14:25:50 -0800859 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 } else {
861 rc = -EIO;
Steve Frenchec637e32005-12-12 20:53:18 -0800862 cERROR(1,("Bad MID state?"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 }
864 }
865cifs_no_response_exit:
866 DeleteMidQEntry(midQ);
867
868 if(long_op < 3) {
869 atomic_dec(&ses->server->inFlight);
870 wake_up(&ses->server->request_q);
871 }
872
873 return rc;
874
875out_unlock:
876 up(&ses->server->tcpSem);
877 /* If not lock req, update # of requests on wire to server */
878 if(long_op < 3) {
879 atomic_dec(&ses->server->inFlight);
880 wake_up(&ses->server->request_q);
881 }
882
883 return rc;
884}