[CIFS] Reduce CIFS tcp congestion timeout (it was too long) and backoff
[pandora-kernel.git] / fs / cifs / transport.c
1 /*
2  *   fs/cifs/transport.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2005
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  *   This library is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU Lesser General Public License as published
9  *   by the Free Software Foundation; either version 2.1 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This library is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
15  *   the GNU Lesser General Public License for more details.
16  *
17  *   You should have received a copy of the GNU Lesser General Public License
18  *   along with this library; if not, write to the Free Software
19  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
20  */
21
22 #include <linux/fs.h>
23 #include <linux/list.h>
24 #include <linux/wait.h>
25 #include <linux/net.h>
26 #include <linux/delay.h>
27 #include <asm/uaccess.h>
28 #include <asm/processor.h>
29 #include <linux/mempool.h>
30 #include "cifspdu.h"
31 #include "cifsglob.h"
32 #include "cifsproto.h"
33 #include "cifs_debug.h"
34   
35 extern mempool_t *cifs_mid_poolp;
36 extern kmem_cache_t *cifs_oplock_cachep;
37
38 static struct mid_q_entry *
39 AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
40 {
41         struct mid_q_entry *temp;
42
43         if (ses == NULL) {
44                 cERROR(1, ("Null session passed in to AllocMidQEntry"));
45                 return NULL;
46         }
47         if (ses->server == NULL) {
48                 cERROR(1, ("Null TCP session in AllocMidQEntry"));
49                 return NULL;
50         }
51         
52         temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
53                                                     SLAB_KERNEL | SLAB_NOFS);
54         if (temp == NULL)
55                 return temp;
56         else {
57                 memset(temp, 0, sizeof (struct mid_q_entry));
58                 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));
62                 do_gettimeofday(&temp->when_sent);
63                 temp->ses = ses;
64                 temp->tsk = current;
65         }
66
67         spin_lock(&GlobalMid_Lock);
68         list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
69         atomic_inc(&midCount);
70         temp->midState = MID_REQUEST_ALLOCATED;
71         spin_unlock(&GlobalMid_Lock);
72         return temp;
73 }
74
75 static void
76 DeleteMidQEntry(struct mid_q_entry *midEntry)
77 {
78         spin_lock(&GlobalMid_Lock);
79         midEntry->midState = MID_FREE;
80         list_del(&midEntry->qhead);
81         atomic_dec(&midCount);
82         spin_unlock(&GlobalMid_Lock);
83         if(midEntry->largeBuf)
84                 cifs_buf_release(midEntry->resp_buf);
85         else
86                 cifs_small_buf_release(midEntry->resp_buf);
87         mempool_free(midEntry, cifs_mid_poolp);
88 }
89
90 struct oplock_q_entry *
91 AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
92 {
93         struct oplock_q_entry *temp;
94         if ((pinode== NULL) || (tcon == NULL)) {
95                 cERROR(1, ("Null parms passed to AllocOplockQEntry"));
96                 return NULL;
97         }
98         temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
99                                                        SLAB_KERNEL);
100         if (temp == NULL)
101                 return temp;
102         else {
103                 temp->pinode = pinode;
104                 temp->tcon = tcon;
105                 temp->netfid = fid;
106                 spin_lock(&GlobalMid_Lock);
107                 list_add_tail(&temp->qhead, &GlobalOplock_Q);
108                 spin_unlock(&GlobalMid_Lock);
109         }
110         return temp;
111
112 }
113
114 void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry)
115 {
116         spin_lock(&GlobalMid_Lock); 
117     /* should we check if list empty first? */
118         list_del(&oplockEntry->qhead);
119         spin_unlock(&GlobalMid_Lock);
120         kmem_cache_free(cifs_oplock_cachep, oplockEntry);
121 }
122
123 int
124 smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
125          unsigned int smb_buf_length, struct sockaddr *sin)
126 {
127         int rc = 0;
128         int i = 0;
129         struct msghdr smb_msg;
130         struct kvec iov;
131         unsigned len = smb_buf_length + 4;
132
133         if(ssocket == NULL)
134                 return -ENOTSOCK; /* BB eventually add reconnect code here */
135         iov.iov_base = smb_buffer;
136         iov.iov_len = len;
137
138         smb_msg.msg_name = sin;
139         smb_msg.msg_namelen = sizeof (struct sockaddr);
140         smb_msg.msg_control = NULL;
141         smb_msg.msg_controllen = 0;
142         smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
143
144         /* smb header is converted in header_assemble. bcc and rest of SMB word
145            area, and byte area if necessary, is converted to littleendian in 
146            cifssmb.c and RFC1001 len is converted to bigendian in smb_send 
147            Flags2 is converted in SendReceive */
148
149         smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
150         cFYI(1, ("Sending smb of length %d", smb_buf_length));
151         dump_smb(smb_buffer, len);
152
153         while (len > 0) {
154                 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
155                 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
156                         i++;
157                 /* smaller timeout here than send2 since smaller size */
158                 /* Although it may not be required, this also is smaller 
159                    oplock break time */  
160                         if(i > 12) {
161                                 cERROR(1,
162                                    ("sends on sock %p stuck for 7 seconds",
163                                     ssocket));
164                                 rc = -EAGAIN;
165                                 break;
166                         }
167                         msleep(1 << i);
168                         continue;
169                 }
170                 if (rc < 0) 
171                         break;
172                 iov.iov_base += rc;
173                 iov.iov_len -= rc;
174                 len -= rc;
175         }
176
177         if (rc < 0) {
178                 cERROR(1,("Error %d sending data on socket to server", rc));
179         } else {
180                 rc = 0;
181         }
182
183         return rc;
184 }
185
186 #ifdef CONFIG_CIFS_EXPERIMENTAL
187 static int
188 smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
189           struct sockaddr *sin)
190 {
191         int rc = 0;
192         int i = 0;
193         struct msghdr smb_msg;
194         struct smb_hdr *smb_buffer = iov[0].iov_base;
195         unsigned int len = iov[0].iov_len;
196         unsigned int total_len;
197         int first_vec = 0;
198         
199         if(ssocket == NULL)
200                 return -ENOTSOCK; /* BB eventually add reconnect code here */
201
202         smb_msg.msg_name = sin;
203         smb_msg.msg_namelen = sizeof (struct sockaddr);
204         smb_msg.msg_control = NULL;
205         smb_msg.msg_controllen = 0;
206         smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
207
208         /* smb header is converted in header_assemble. bcc and rest of SMB word
209            area, and byte area if necessary, is converted to littleendian in 
210            cifssmb.c and RFC1001 len is converted to bigendian in smb_send 
211            Flags2 is converted in SendReceive */
212
213
214         total_len = 0;
215         for (i = 0; i < n_vec; i++)
216                 total_len += iov[i].iov_len;
217
218         smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
219         cFYI(1, ("Sending smb:  total_len %d", total_len));
220         dump_smb(smb_buffer, len);
221
222         while (total_len) {
223                 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
224                                     n_vec - first_vec, total_len);
225                 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
226                         i++;
227                         if(i >= 14) {
228                                 cERROR(1,
229                                    ("sends on sock %p stuck for 15 seconds",
230                                     ssocket));
231                                 rc = -EAGAIN;
232                                 break;
233                         }
234                         msleep(1 << i);
235                         continue;
236                 }
237                 if (rc < 0) 
238                         break;
239
240                 if (rc >= total_len) {
241                         WARN_ON(rc > total_len);
242                         break;
243                 }
244                 if(rc == 0) {
245                         /* should never happen, letting socket clear before
246                            retrying is our only obvious option here */
247                         cERROR(1,("tcp sent no data"));
248                         msleep(500);
249                         continue;
250                 }
251                 total_len -= rc;
252                 /* the line below resets i */
253                 for (i = first_vec; i < n_vec; i++) {
254                         if (iov[i].iov_len) {
255                                 if (rc > iov[i].iov_len) {
256                                         rc -= iov[i].iov_len;
257                                         iov[i].iov_len = 0;
258                                 } else {
259                                         iov[i].iov_base += rc;
260                                         iov[i].iov_len -= rc;
261                                         first_vec = i;
262                                         break;
263                                 }
264                         }
265                 }
266         }
267
268         if (rc < 0) {
269                 cERROR(1,("Error %d sending data on socket to server", rc));
270         } else
271                 rc = 0;
272
273         return rc;
274 }
275
276 int
277 SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, 
278              struct kvec *iov, int n_vec, int *pbytes_returned,
279              const int long_op)
280 {
281         int rc = 0;
282         unsigned int receive_len;
283         unsigned long timeout;
284         struct mid_q_entry *midQ;
285         struct smb_hdr *in_buf = iov[0].iov_base;
286
287         if (ses == NULL) {
288                 cERROR(1,("Null smb session"));
289                 return -EIO;
290         }
291         if(ses->server == NULL) {
292                 cERROR(1,("Null tcp session"));
293                 return -EIO;
294         }
295
296         if(ses->server->tcpStatus == CifsExiting)
297                 return -ENOENT;
298
299         /* Ensure that we do not send more than 50 overlapping requests 
300            to the same server. We may make this configurable later or
301            use ses->maxReq */
302         if(long_op == -1) {
303                 /* oplock breaks must not be held up */
304                 atomic_inc(&ses->server->inFlight);
305         } else {
306                 spin_lock(&GlobalMid_Lock); 
307                 while(1) {        
308                         if(atomic_read(&ses->server->inFlight) >= 
309                                         cifs_max_pending){
310                                 spin_unlock(&GlobalMid_Lock);
311 #ifdef CONFIG_CIFS_STATS2
312                                 atomic_inc(&ses->server->num_waiters);
313 #endif
314                                 wait_event(ses->server->request_q,
315                                         atomic_read(&ses->server->inFlight)
316                                          < cifs_max_pending);
317 #ifdef CONFIG_CIFS_STATS2
318                                 atomic_dec(&ses->server->num_waiters);
319 #endif
320                                 spin_lock(&GlobalMid_Lock);
321                         } else {
322                                 if(ses->server->tcpStatus == CifsExiting) {
323                                         spin_unlock(&GlobalMid_Lock);
324                                         return -ENOENT;
325                                 }
326
327                         /* can not count locking commands against total since
328                            they are allowed to block on server */
329                                         
330                                 if(long_op < 3) {
331                                 /* update # of requests on the wire to server */
332                                         atomic_inc(&ses->server->inFlight);
333                                 }
334                                 spin_unlock(&GlobalMid_Lock);
335                                 break;
336                         }
337                 }
338         }
339         /* make sure that we sign in the same order that we send on this socket 
340            and avoid races inside tcp sendmsg code that could cause corruption
341            of smb data */
342
343         down(&ses->server->tcpSem); 
344
345         if (ses->server->tcpStatus == CifsExiting) {
346                 rc = -ENOENT;
347                 goto out_unlock2;
348         } else if (ses->server->tcpStatus == CifsNeedReconnect) {
349                 cFYI(1,("tcp session dead - return to caller to retry"));
350                 rc = -EAGAIN;
351                 goto out_unlock2;
352         } else if (ses->status != CifsGood) {
353                 /* check if SMB session is bad because we are setting it up */
354                 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
355                         (in_buf->Command != SMB_COM_NEGOTIATE)) {
356                         rc = -EAGAIN;
357                         goto out_unlock2;
358                 } /* else ok - we are setting up session */
359         }
360         midQ = AllocMidQEntry(in_buf, ses);
361         if (midQ == NULL) {
362                 up(&ses->server->tcpSem);
363                 /* If not lock req, update # of requests on wire to server */
364                 if(long_op < 3) {
365                         atomic_dec(&ses->server->inFlight); 
366                         wake_up(&ses->server->request_q);
367                 }
368                 return -ENOMEM;
369         }
370
371 /* BB FIXME */
372 /*      rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); */
373
374         midQ->midState = MID_REQUEST_SUBMITTED;
375 #ifdef CONFIG_CIFS_STATS2
376         atomic_inc(&ses->server->inSend);
377 #endif
378         rc = smb_send2(ses->server->ssocket, iov, n_vec,
379                       (struct sockaddr *) &(ses->server->addr.sockAddr));
380 #ifdef CONFIG_CIFS_STATS2
381         atomic_dec(&ses->server->inSend);
382 #endif
383         if(rc < 0) {
384                 DeleteMidQEntry(midQ);
385                 up(&ses->server->tcpSem);
386                 /* If not lock req, update # of requests on wire to server */
387                 if(long_op < 3) {
388                         atomic_dec(&ses->server->inFlight); 
389                         wake_up(&ses->server->request_q);
390                 }
391                 return rc;
392         } else
393                 up(&ses->server->tcpSem);
394         if (long_op == -1)
395                 goto cifs_no_response_exit2;
396         else if (long_op == 2) /* writes past end of file can take loong time */
397                 timeout = 180 * HZ;
398         else if (long_op == 1)
399                 timeout = 45 * HZ; /* should be greater than 
400                         servers oplock break timeout (about 43 seconds) */
401         else if (long_op > 2) {
402                 timeout = MAX_SCHEDULE_TIMEOUT;
403         } else
404                 timeout = 15 * HZ;
405         /* wait for 15 seconds or until woken up due to response arriving or 
406            due to last connection to this server being unmounted */
407         if (signal_pending(current)) {
408                 /* if signal pending do not hold up user for full smb timeout
409                 but we still give response a change to complete */
410                 timeout = 2 * HZ;
411         }   
412
413         /* No user interrupts in wait - wreaks havoc with performance */
414         if(timeout != MAX_SCHEDULE_TIMEOUT) {
415                 timeout += jiffies;
416                 wait_event(ses->server->response_q,
417                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
418                         time_after(jiffies, timeout) || 
419                         ((ses->server->tcpStatus != CifsGood) &&
420                          (ses->server->tcpStatus != CifsNew)));
421         } else {
422                 wait_event(ses->server->response_q,
423                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
424                         ((ses->server->tcpStatus != CifsGood) &&
425                          (ses->server->tcpStatus != CifsNew)));
426         }
427
428         spin_lock(&GlobalMid_Lock);
429         if (midQ->resp_buf) {
430                 spin_unlock(&GlobalMid_Lock);
431                 receive_len = midQ->resp_buf->smb_buf_length;
432         } else {
433                 cERROR(1,("No response to cmd %d mid %d",
434                         midQ->command, midQ->mid));
435                 if(midQ->midState == MID_REQUEST_SUBMITTED) {
436                         if(ses->server->tcpStatus == CifsExiting)
437                                 rc = -EHOSTDOWN;
438                         else {
439                                 ses->server->tcpStatus = CifsNeedReconnect;
440                                 midQ->midState = MID_RETRY_NEEDED;
441                         }
442                 }
443
444                 if (rc != -EHOSTDOWN) {
445                         if(midQ->midState == MID_RETRY_NEEDED) {
446                                 rc = -EAGAIN;
447                                 cFYI(1,("marking request for retry"));
448                         } else {
449                                 rc = -EIO;
450                         }
451                 }
452                 spin_unlock(&GlobalMid_Lock);
453                 DeleteMidQEntry(midQ);
454                 /* If not lock req, update # of requests on wire to server */
455                 if(long_op < 3) {
456                         atomic_dec(&ses->server->inFlight); 
457                         wake_up(&ses->server->request_q);
458                 }
459                 return rc;
460         }
461   
462         if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
463                 cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
464                         receive_len, xid));
465                 rc = -EIO;
466         } else {                /* rcvd frame is ok */
467
468                 if (midQ->resp_buf && 
469                         (midQ->midState == MID_RESPONSE_RECEIVED)) {
470                         in_buf->smb_buf_length = receive_len;
471                         /* BB verify that length would not overrun small buf */
472                         memcpy((char *)in_buf + 4,
473                                (char *)midQ->resp_buf + 4,
474                                receive_len);
475
476                         dump_smb(in_buf, 80);
477                         /* convert the length into a more usable form */
478                         if((receive_len > 24) &&
479                            (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
480                                         SECMODE_SIGN_ENABLED))) {
481                                 rc = cifs_verify_signature(in_buf,
482                                                 ses->server->mac_signing_key,
483                                                 midQ->sequence_number+1);
484                                 if(rc) {
485                                         cERROR(1,("Unexpected SMB signature"));
486                                         /* BB FIXME add code to kill session */
487                                 }
488                         }
489
490                         *pbytes_returned = in_buf->smb_buf_length;
491
492                         /* BB special case reconnect tid and uid here? */
493                         rc = map_smb_to_linux_error(in_buf);
494
495                         /* convert ByteCount if necessary */
496                         if (receive_len >=
497                             sizeof (struct smb_hdr) -
498                             4 /* do not count RFC1001 header */  +
499                             (2 * in_buf->WordCount) + 2 /* bcc */ )
500                                 BCC(in_buf) = le16_to_cpu(BCC(in_buf));
501                 } else {
502                         rc = -EIO;
503                         cFYI(1,("Bad MID state?"));
504                 }
505         }
506 cifs_no_response_exit2:
507         DeleteMidQEntry(midQ);
508
509         if(long_op < 3) {
510                 atomic_dec(&ses->server->inFlight); 
511                 wake_up(&ses->server->request_q);
512         }
513
514         return rc;
515
516 out_unlock2:
517         up(&ses->server->tcpSem);
518         /* If not lock req, update # of requests on wire to server */
519         if(long_op < 3) {
520                 atomic_dec(&ses->server->inFlight); 
521                 wake_up(&ses->server->request_q);
522         }
523
524         return rc;
525 }
526 #endif /* CIFS_EXPERIMENTAL */
527
528 int
529 SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
530             struct smb_hdr *in_buf, struct smb_hdr *out_buf,
531             int *pbytes_returned, const int long_op)
532 {
533         int rc = 0;
534         unsigned int receive_len;
535         unsigned long timeout;
536         struct mid_q_entry *midQ;
537
538         if (ses == NULL) {
539                 cERROR(1,("Null smb session"));
540                 return -EIO;
541         }
542         if(ses->server == NULL) {
543                 cERROR(1,("Null tcp session"));
544                 return -EIO;
545         }
546
547         if(ses->server->tcpStatus == CifsExiting)
548                 return -ENOENT;
549
550         /* Ensure that we do not send more than 50 overlapping requests 
551            to the same server. We may make this configurable later or
552            use ses->maxReq */
553         if(long_op == -1) {
554                 /* oplock breaks must not be held up */
555                 atomic_inc(&ses->server->inFlight);
556         } else {
557                 spin_lock(&GlobalMid_Lock); 
558                 while(1) {        
559                         if(atomic_read(&ses->server->inFlight) >= 
560                                         cifs_max_pending){
561                                 spin_unlock(&GlobalMid_Lock);
562 #ifdef CONFIG_CIFS_STATS2
563                                 atomic_inc(&ses->server->num_waiters);
564 #endif
565                                 wait_event(ses->server->request_q,
566                                         atomic_read(&ses->server->inFlight)
567                                          < cifs_max_pending);
568 #ifdef CONFIG_CIFS_STATS2
569                                 atomic_dec(&ses->server->num_waiters);
570 #endif
571                                 spin_lock(&GlobalMid_Lock);
572                         } else {
573                                 if(ses->server->tcpStatus == CifsExiting) {
574                                         spin_unlock(&GlobalMid_Lock);
575                                         return -ENOENT;
576                                 }
577
578                         /* can not count locking commands against total since
579                            they are allowed to block on server */
580                                         
581                                 if(long_op < 3) {
582                                 /* update # of requests on the wire to server */
583                                         atomic_inc(&ses->server->inFlight);
584                                 }
585                                 spin_unlock(&GlobalMid_Lock);
586                                 break;
587                         }
588                 }
589         }
590         /* make sure that we sign in the same order that we send on this socket 
591            and avoid races inside tcp sendmsg code that could cause corruption
592            of smb data */
593
594         down(&ses->server->tcpSem); 
595
596         if (ses->server->tcpStatus == CifsExiting) {
597                 rc = -ENOENT;
598                 goto out_unlock;
599         } else if (ses->server->tcpStatus == CifsNeedReconnect) {
600                 cFYI(1,("tcp session dead - return to caller to retry"));
601                 rc = -EAGAIN;
602                 goto out_unlock;
603         } else if (ses->status != CifsGood) {
604                 /* check if SMB session is bad because we are setting it up */
605                 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
606                         (in_buf->Command != SMB_COM_NEGOTIATE)) {
607                         rc = -EAGAIN;
608                         goto out_unlock;
609                 } /* else ok - we are setting up session */
610         }
611         midQ = AllocMidQEntry(in_buf, ses);
612         if (midQ == NULL) {
613                 up(&ses->server->tcpSem);
614                 /* If not lock req, update # of requests on wire to server */
615                 if(long_op < 3) {
616                         atomic_dec(&ses->server->inFlight); 
617                         wake_up(&ses->server->request_q);
618                 }
619                 return -ENOMEM;
620         }
621
622         if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
623                 up(&ses->server->tcpSem);
624                 cERROR(1,
625                        ("Illegal length, greater than maximum frame, %d ",
626                         in_buf->smb_buf_length));
627                 DeleteMidQEntry(midQ);
628                 /* If not lock req, update # of requests on wire to server */
629                 if(long_op < 3) {
630                         atomic_dec(&ses->server->inFlight); 
631                         wake_up(&ses->server->request_q);
632                 }
633                 return -EIO;
634         }
635
636         rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
637
638         midQ->midState = MID_REQUEST_SUBMITTED;
639 #ifdef CONFIG_CIFS_STATS2
640         atomic_inc(&ses->server->inSend);
641 #endif
642         rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
643                       (struct sockaddr *) &(ses->server->addr.sockAddr));
644 #ifdef CONFIG_CIFS_STATS2
645         atomic_dec(&ses->server->inSend);
646 #endif
647         if(rc < 0) {
648                 DeleteMidQEntry(midQ);
649                 up(&ses->server->tcpSem);
650                 /* If not lock req, update # of requests on wire to server */
651                 if(long_op < 3) {
652                         atomic_dec(&ses->server->inFlight); 
653                         wake_up(&ses->server->request_q);
654                 }
655                 return rc;
656         } else
657                 up(&ses->server->tcpSem);
658         if (long_op == -1)
659                 goto cifs_no_response_exit;
660         else if (long_op == 2) /* writes past end of file can take loong time */
661                 timeout = 180 * HZ;
662         else if (long_op == 1)
663                 timeout = 45 * HZ; /* should be greater than 
664                         servers oplock break timeout (about 43 seconds) */
665         else if (long_op > 2) {
666                 timeout = MAX_SCHEDULE_TIMEOUT;
667         } else
668                 timeout = 15 * HZ;
669         /* wait for 15 seconds or until woken up due to response arriving or 
670            due to last connection to this server being unmounted */
671         if (signal_pending(current)) {
672                 /* if signal pending do not hold up user for full smb timeout
673                 but we still give response a change to complete */
674                 timeout = 2 * HZ;
675         }   
676
677         /* No user interrupts in wait - wreaks havoc with performance */
678         if(timeout != MAX_SCHEDULE_TIMEOUT) {
679                 timeout += jiffies;
680                 wait_event(ses->server->response_q,
681                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
682                         time_after(jiffies, timeout) || 
683                         ((ses->server->tcpStatus != CifsGood) &&
684                          (ses->server->tcpStatus != CifsNew)));
685         } else {
686                 wait_event(ses->server->response_q,
687                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
688                         ((ses->server->tcpStatus != CifsGood) &&
689                          (ses->server->tcpStatus != CifsNew)));
690         }
691
692         spin_lock(&GlobalMid_Lock);
693         if (midQ->resp_buf) {
694                 spin_unlock(&GlobalMid_Lock);
695                 receive_len = midQ->resp_buf->smb_buf_length;
696         } else {
697                 cERROR(1,("No response for cmd %d mid %d",
698                           midQ->command, midQ->mid));
699                 if(midQ->midState == MID_REQUEST_SUBMITTED) {
700                         if(ses->server->tcpStatus == CifsExiting)
701                                 rc = -EHOSTDOWN;
702                         else {
703                                 ses->server->tcpStatus = CifsNeedReconnect;
704                                 midQ->midState = MID_RETRY_NEEDED;
705                         }
706                 }
707
708                 if (rc != -EHOSTDOWN) {
709                         if(midQ->midState == MID_RETRY_NEEDED) {
710                                 rc = -EAGAIN;
711                                 cFYI(1,("marking request for retry"));
712                         } else {
713                                 rc = -EIO;
714                         }
715                 }
716                 spin_unlock(&GlobalMid_Lock);
717                 DeleteMidQEntry(midQ);
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         }
725   
726         if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
727                 cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
728                         receive_len, xid));
729                 rc = -EIO;
730         } else {                /* rcvd frame is ok */
731
732                 if (midQ->resp_buf && out_buf
733                     && (midQ->midState == MID_RESPONSE_RECEIVED)) {
734                         out_buf->smb_buf_length = receive_len;
735                         memcpy((char *)out_buf + 4,
736                                (char *)midQ->resp_buf + 4,
737                                receive_len);
738
739                         dump_smb(out_buf, 92);
740                         /* convert the length into a more usable form */
741                         if((receive_len > 24) &&
742                            (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
743                                         SECMODE_SIGN_ENABLED))) {
744                                 rc = cifs_verify_signature(out_buf,
745                                                 ses->server->mac_signing_key,
746                                                 midQ->sequence_number+1);
747                                 if(rc) {
748                                         cERROR(1,("Unexpected SMB signature"));
749                                         /* BB FIXME add code to kill session */
750                                 }
751                         }
752
753                         *pbytes_returned = out_buf->smb_buf_length;
754
755                         /* BB special case reconnect tid and uid here? */
756                         rc = map_smb_to_linux_error(out_buf);
757
758                         /* convert ByteCount if necessary */
759                         if (receive_len >=
760                             sizeof (struct smb_hdr) -
761                             4 /* do not count RFC1001 header */  +
762                             (2 * out_buf->WordCount) + 2 /* bcc */ )
763                                 BCC(out_buf) = le16_to_cpu(BCC(out_buf));
764                 } else {
765                         rc = -EIO;
766                         cERROR(1,("Bad MID state? "));
767                 }
768         }
769 cifs_no_response_exit:
770         DeleteMidQEntry(midQ);
771
772         if(long_op < 3) {
773                 atomic_dec(&ses->server->inFlight); 
774                 wake_up(&ses->server->request_q);
775         }
776
777         return rc;
778
779 out_unlock:
780         up(&ses->server->tcpSem);
781         /* If not lock req, update # of requests on wire to server */
782         if(long_op < 3) {
783                 atomic_dec(&ses->server->inFlight); 
784                 wake_up(&ses->server->request_q);
785         }
786
787         return rc;
788 }