]> git.ipfire.org Git - people/ms/linux.git/blame - fs/cifs/transport.c
[CIFS] Allow cifsd to suspend if connection is lost
[people/ms/linux.git] / fs / cifs / transport.c
CommitLineData
1da177e4
LT
1/*
2 * fs/cifs/transport.c
3 *
b8643e1b 4 * Copyright (C) International Business Machines Corp., 2002,2005
1da177e4 5 * Author(s): Steve French (sfrench@us.ibm.com)
14a441a2
SF
6 * Jeremy Allison (jra@samba.org) 2006.
7 *
1da177e4
LT
8 * 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) {
275cde1a 45 cERROR(1, ("Null session passed in to AllocMidQEntry"));
1da177e4
LT
46 return NULL;
47 }
48 if (ses->server == NULL) {
49 cERROR(1, ("Null TCP session in AllocMidQEntry"));
50 return NULL;
51 }
52
d6e04ae6
SF
53 temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
54 SLAB_KERNEL | SLAB_NOFS);
1da177e4
LT
55 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));
1047abc1
SF
63 /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
64 /* when mid allocated can be before when sent */
65 temp->when_alloc = jiffies;
1da177e4
LT
66 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{
1047abc1
SF
81#ifdef CONFIG_CIFS_STATS2
82 unsigned long now;
83#endif
1da177e4
LT
84 spin_lock(&GlobalMid_Lock);
85 midEntry->midState = MID_FREE;
86 list_del(&midEntry->qhead);
87 atomic_dec(&midCount);
88 spin_unlock(&GlobalMid_Lock);
b8643e1b
SF
89 if(midEntry->largeBuf)
90 cifs_buf_release(midEntry->resp_buf);
91 else
92 cifs_small_buf_release(midEntry->resp_buf);
1047abc1
SF
93#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
1da177e4
LT
109 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);
3e84469d 172 cFYI(1, ("Sending smb of length %d", smb_buf_length));
1da177e4
LT
173 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++;
3e84469d
SF
179 /* smaller timeout here than send2 since smaller size */
180 /* Although it may not be required, this also is smaller
181 oplock break time */
68058e75 182 if(i > 12) {
1da177e4 183 cERROR(1,
68058e75 184 ("sends on sock %p stuck for 7 seconds",
1da177e4
LT
185 ssocket));
186 rc = -EAGAIN;
187 break;
188 }
68058e75 189 msleep(1 << i);
1da177e4
LT
190 continue;
191 }
192 if (rc < 0)
193 break;
5e1253b5
SF
194 else
195 i = 0; /* reset i after each successful send */
1da177e4
LT
196 iov.iov_base += rc;
197 iov.iov_len -= rc;
198 len -= rc;
199 }
200
201 if (rc < 0) {
3e84469d 202 cERROR(1,("Error %d sending data on socket to server", rc));
1da177e4
LT
203 } else {
204 rc = 0;
205 }
206
207 return rc;
208}
209
d6e04ae6 210static int
3e84469d
SF
211smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
212 struct sockaddr *sin)
1da177e4
LT
213{
214 int rc = 0;
215 int i = 0;
216 struct msghdr smb_msg;
3e84469d
SF
217 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;
d6e04ae6 221
1da177e4
LT
222 if(ssocket == NULL)
223 return -ENOTSOCK; /* BB eventually add reconnect code here */
3e84469d 224
1da177e4
LT
225 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
3e84469d
SF
236
237 total_len = 0;
238 for (i = 0; i < n_vec; i++)
239 total_len += iov[i].iov_len;
240
1da177e4 241 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
3e84469d 242 cFYI(1, ("Sending smb: total_len %d", total_len));
1da177e4
LT
243 dump_smb(smb_buffer, len);
244
3e84469d
SF
245 while (total_len) {
246 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
247 n_vec - first_vec, total_len);
1da177e4
LT
248 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
249 i++;
68058e75 250 if(i >= 14) {
1da177e4 251 cERROR(1,
68058e75 252 ("sends on sock %p stuck for 15 seconds",
1da177e4
LT
253 ssocket));
254 rc = -EAGAIN;
255 break;
256 }
68058e75 257 msleep(1 << i);
1da177e4
LT
258 continue;
259 }
260 if (rc < 0)
261 break;
3e84469d
SF
262
263 if (rc >= total_len) {
264 WARN_ON(rc > total_len);
265 break;
266 }
267 if(rc == 0) {
268 /* should never happen, letting socket clear before
269 retrying is our only obvious option here */
04c08816 270 cERROR(1,("tcp sent no data"));
3e84469d
SF
271 msleep(500);
272 continue;
d6e04ae6 273 }
3e84469d 274 total_len -= rc;
68058e75 275 /* the line below resets i */
3e84469d
SF
276 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 }
d6e04ae6 288 }
5e1253b5 289 i = 0; /* in case we get ENOSPC on the next send */
1da177e4
LT
290 }
291
292 if (rc < 0) {
3e84469d
SF
293 cERROR(1,("Error %d sending data on socket to server", rc));
294 } else
1da177e4 295 rc = 0;
1da177e4
LT
296
297 return rc;
298}
299
1da177e4 300int
d6e04ae6 301SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
ec637e3f 302 struct kvec *iov, int n_vec, int * pRespBufType /* ret */,
3e84469d 303 const int long_op)
1da177e4
LT
304{
305 int rc = 0;
d6e04ae6
SF
306 unsigned int receive_len;
307 unsigned long timeout;
308 struct mid_q_entry *midQ;
3e84469d 309 struct smb_hdr *in_buf = iov[0].iov_base;
ec637e3f
SF
310
311 *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
1da177e4 312
4b8f930f
SF
313 if ((ses == NULL) || (ses->server == NULL)) {
314 cifs_small_buf_release(in_buf);
315 cERROR(1,("Null session"));
1da177e4
LT
316 return -EIO;
317 }
1da177e4 318
4b8f930f
SF
319 if(ses->server->tcpStatus == CifsExiting) {
320 cifs_small_buf_release(in_buf);
31ca3bc3 321 return -ENOENT;
4b8f930f 322 }
31ca3bc3 323
1da177e4
LT
324 /* 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) {
d6e04ae6
SF
333 if(atomic_read(&ses->server->inFlight) >=
334 cifs_max_pending){
1da177e4 335 spin_unlock(&GlobalMid_Lock);
131afd0b
SF
336#ifdef CONFIG_CIFS_STATS2
337 atomic_inc(&ses->server->num_waiters);
338#endif
1da177e4
LT
339 wait_event(ses->server->request_q,
340 atomic_read(&ses->server->inFlight)
341 < cifs_max_pending);
131afd0b
SF
342#ifdef CONFIG_CIFS_STATS2
343 atomic_dec(&ses->server->num_waiters);
344#endif
1da177e4
LT
345 spin_lock(&GlobalMid_Lock);
346 } else {
347 if(ses->server->tcpStatus == CifsExiting) {
348 spin_unlock(&GlobalMid_Lock);
4b8f930f 349 cifs_small_buf_release(in_buf);
1da177e4
LT
350 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;
d6e04ae6 373 goto out_unlock2;
1da177e4
LT
374 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
375 cFYI(1,("tcp session dead - return to caller to retry"));
376 rc = -EAGAIN;
d6e04ae6 377 goto out_unlock2;
1da177e4
LT
378 } 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;
d6e04ae6 383 goto out_unlock2;
1da177e4
LT
384 } /* else ok - we are setting up session */
385 }
386 midQ = AllocMidQEntry(in_buf, ses);
387 if (midQ == NULL) {
388 up(&ses->server->tcpSem);
4b8f930f 389 cifs_small_buf_release(in_buf);
1da177e4
LT
390 /* 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
84afc29b 398 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
1da177e4
LT
399
400 midQ->midState = MID_REQUEST_SUBMITTED;
131afd0b
SF
401#ifdef CONFIG_CIFS_STATS2
402 atomic_inc(&ses->server->inSend);
403#endif
3e84469d 404 rc = smb_send2(ses->server->ssocket, iov, n_vec,
d6e04ae6 405 (struct sockaddr *) &(ses->server->addr.sockAddr));
131afd0b
SF
406#ifdef CONFIG_CIFS_STATS2
407 atomic_dec(&ses->server->inSend);
1047abc1 408 midQ->when_sent = jiffies;
131afd0b 409#endif
1da177e4
LT
410 if(rc < 0) {
411 DeleteMidQEntry(midQ);
412 up(&ses->server->tcpSem);
4b8f930f 413 cifs_small_buf_release(in_buf);
1da177e4
LT
414 /* 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;
4b8f930f 420 } else {
1da177e4 421 up(&ses->server->tcpSem);
4b8f930f
SF
422 cifs_small_buf_release(in_buf);
423 }
424
d6e04ae6
SF
425 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 */
37c0eb46 428 timeout = 180 * HZ;
d6e04ae6
SF
429 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) {
14a441a2
SF
446 unsigned long curr_timeout;
447
448 for (;;) {
449 curr_timeout = timeout + jiffies;
450 wait_event(ses->server->response_q,
5da07b02 451 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
14a441a2
SF
452 time_after(jiffies, curr_timeout) ||
453 ((ses->server->tcpStatus != CifsGood) &&
454 (ses->server->tcpStatus != CifsNew)));
455
456 if (time_after(jiffies, curr_timeout) &&
5da07b02 457 (midQ->midState == MID_REQUEST_SUBMITTED) &&
14a441a2
SF
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 }
d6e04ae6
SF
486 } else {
487 wait_event(ses->server->response_q,
5da07b02 488 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
d6e04ae6
SF
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);
70ca734a 496 receive_len = midQ->resp_buf->smb_buf_length;
d6e04ae6 497 } else {
37c0eb46
SF
498 cERROR(1,("No response to cmd %d mid %d",
499 midQ->command, midQ->mid));
d6e04ae6
SF
500 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 */
d6e04ae6
SF
532 if (midQ->resp_buf &&
533 (midQ->midState == MID_RESPONSE_RECEIVED)) {
84afc29b 534
ec637e3f
SF
535 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;
d6e04ae6 541
ec637e3f 542 dump_smb(midQ->resp_buf, 80);
d6e04ae6
SF
543 /* convert the length into a more usable form */
544 if((receive_len > 24) &&
545 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
546 SECMODE_SIGN_ENABLED))) {
ec637e3f 547 rc = cifs_verify_signature(midQ->resp_buf,
d6e04ae6
SF
548 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
d6e04ae6 556 /* BB special case reconnect tid and uid here? */
6ab16d24 557 /* BB special case Errbadpassword and pwdexpired here */
ec637e3f 558 rc = map_smb_to_linux_error(midQ->resp_buf);
d6e04ae6
SF
559
560 /* convert ByteCount if necessary */
561 if (receive_len >=
562 sizeof (struct smb_hdr) -
563 4 /* do not count RFC1001 header */ +
ec637e3f
SF
564 (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 */
d6e04ae6
SF
569 } else {
570 rc = -EIO;
ab2f218f 571 cFYI(1,("Bad MID state?"));
d6e04ae6
SF
572 }
573 }
574cifs_no_response_exit2:
575 DeleteMidQEntry(midQ);
576
1da177e4 577 if(long_op < 3) {
d6e04ae6 578 atomic_dec(&ses->server->inFlight);
1da177e4
LT
579 wake_up(&ses->server->request_q);
580 }
581
582 return rc;
1da177e4 583
d6e04ae6
SF
584out_unlock2:
585 up(&ses->server->tcpSem);
4b8f930f 586 cifs_small_buf_release(in_buf);
d6e04ae6
SF
587 /* If not lock req, update # of requests on wire to server */
588 if(long_op < 3) {
589 atomic_dec(&ses->server->inFlight);
590 wake_up(&ses->server->request_q);
591 }
1da177e4 592
d6e04ae6
SF
593 return rc;
594}
1da177e4
LT
595
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
31ca3bc3
SF
615 if(ses->server->tcpStatus == CifsExiting)
616 return -ENOENT;
617
1da177e4
LT
618 /* 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) {
275cde1a
SF
627 if(atomic_read(&ses->server->inFlight) >=
628 cifs_max_pending){
1da177e4 629 spin_unlock(&GlobalMid_Lock);
131afd0b
SF
630#ifdef CONFIG_CIFS_STATS2
631 atomic_inc(&ses->server->num_waiters);
632#endif
1da177e4
LT
633 wait_event(ses->server->request_q,
634 atomic_read(&ses->server->inFlight)
635 < cifs_max_pending);
131afd0b
SF
636#ifdef CONFIG_CIFS_STATS2
637 atomic_dec(&ses->server->num_waiters);
638#endif
1da177e4
LT
639 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);
26a21b98 692 cERROR(1, ("Illegal length, greater than maximum frame, %d",
1da177e4
LT
693 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
ad009ac9 703 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
1da177e4
LT
704
705 midQ->midState = MID_REQUEST_SUBMITTED;
131afd0b
SF
706#ifdef CONFIG_CIFS_STATS2
707 atomic_inc(&ses->server->inSend);
708#endif
1da177e4
LT
709 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
710 (struct sockaddr *) &(ses->server->addr.sockAddr));
131afd0b
SF
711#ifdef CONFIG_CIFS_STATS2
712 atomic_dec(&ses->server->inSend);
1047abc1 713 midQ->when_sent = jiffies;
131afd0b 714#endif
1da177e4
LT
715 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;
275cde1a 728 else if (long_op == 2) /* writes past end of file can take loong time */
37c0eb46 729 timeout = 180 * HZ;
1da177e4
LT
730 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) {
14a441a2
SF
747 unsigned long curr_timeout;
748
749 for (;;) {
750 curr_timeout = timeout + jiffies;
751 wait_event(ses->server->response_q,
5da07b02 752 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
14a441a2
SF
753 time_after(jiffies, curr_timeout) ||
754 ((ses->server->tcpStatus != CifsGood) &&
755 (ses->server->tcpStatus != CifsNew)));
756
757 if (time_after(jiffies, curr_timeout) &&
5da07b02 758 (midQ->midState == MID_REQUEST_SUBMITTED) &&
14a441a2
SF
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 }
1da177e4
LT
781 } else {
782 wait_event(ses->server->response_q,
5da07b02 783 (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
1da177e4
LT
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);
70ca734a 791 receive_len = midQ->resp_buf->smb_buf_length;
1da177e4 792 } else {
37c0eb46
SF
793 cERROR(1,("No response for cmd %d mid %d",
794 midQ->command, midQ->mid));
1da177e4
LT
795 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) {
ad009ac9 823 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
1da177e4
LT
824 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) &&
ad009ac9
SF
838 (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) {
275cde1a
SF
844 cERROR(1,("Unexpected SMB signature"));
845 /* BB FIXME add code to kill session */
ad009ac9 846 }
1da177e4
LT
847 }
848
849 *pbytes_returned = out_buf->smb_buf_length;
850
ad009ac9 851 /* BB special case reconnect tid and uid here? */
1da177e4
LT
852 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 */ )
0f2b27c4 859 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1da177e4
LT
860 } else {
861 rc = -EIO;
ec637e3f 862 cERROR(1,("Bad MID state?"));
1da177e4
LT
863 }
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}