]> git.karo-electronics.de Git - karo-tx-linux.git/blob - fs/cifs/transport.c
[CIFS] Correct cifs tcp retry when some data sent before getting EAGAIN.
[karo-tx-linux.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                 else
173                         i = 0; /* reset i after each successful send */
174                 iov.iov_base += rc;
175                 iov.iov_len -= rc;
176                 len -= rc;
177         }
178
179         if (rc < 0) {
180                 cERROR(1,("Error %d sending data on socket to server", rc));
181         } else {
182                 rc = 0;
183         }
184
185         return rc;
186 }
187
188 #ifdef CONFIG_CIFS_EXPERIMENTAL
189 static int
190 smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
191           struct sockaddr *sin)
192 {
193         int rc = 0;
194         int i = 0;
195         struct msghdr smb_msg;
196         struct smb_hdr *smb_buffer = iov[0].iov_base;
197         unsigned int len = iov[0].iov_len;
198         unsigned int total_len;
199         int first_vec = 0;
200         
201         if(ssocket == NULL)
202                 return -ENOTSOCK; /* BB eventually add reconnect code here */
203
204         smb_msg.msg_name = sin;
205         smb_msg.msg_namelen = sizeof (struct sockaddr);
206         smb_msg.msg_control = NULL;
207         smb_msg.msg_controllen = 0;
208         smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
209
210         /* smb header is converted in header_assemble. bcc and rest of SMB word
211            area, and byte area if necessary, is converted to littleendian in 
212            cifssmb.c and RFC1001 len is converted to bigendian in smb_send 
213            Flags2 is converted in SendReceive */
214
215
216         total_len = 0;
217         for (i = 0; i < n_vec; i++)
218                 total_len += iov[i].iov_len;
219
220         smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
221         cFYI(1, ("Sending smb:  total_len %d", total_len));
222         dump_smb(smb_buffer, len);
223
224         while (total_len) {
225                 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
226                                     n_vec - first_vec, total_len);
227                 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
228                         i++;
229                         if(i >= 14) {
230                                 cERROR(1,
231                                    ("sends on sock %p stuck for 15 seconds",
232                                     ssocket));
233                                 rc = -EAGAIN;
234                                 break;
235                         }
236                         msleep(1 << i);
237                         continue;
238                 }
239                 if (rc < 0) 
240                         break;
241
242                 if (rc >= total_len) {
243                         WARN_ON(rc > total_len);
244                         break;
245                 }
246                 if(rc == 0) {
247                         /* should never happen, letting socket clear before
248                            retrying is our only obvious option here */
249                         cERROR(1,("tcp sent no data"));
250                         msleep(500);
251                         continue;
252                 }
253                 total_len -= rc;
254                 /* the line below resets i */
255                 for (i = first_vec; i < n_vec; i++) {
256                         if (iov[i].iov_len) {
257                                 if (rc > iov[i].iov_len) {
258                                         rc -= iov[i].iov_len;
259                                         iov[i].iov_len = 0;
260                                 } else {
261                                         iov[i].iov_base += rc;
262                                         iov[i].iov_len -= rc;
263                                         first_vec = i;
264                                         break;
265                                 }
266                         }
267                 }
268                 i = 0; /* in case we get ENOSPC on the next send */
269         }
270
271         if (rc < 0) {
272                 cERROR(1,("Error %d sending data on socket to server", rc));
273         } else
274                 rc = 0;
275
276         return rc;
277 }
278
279 int
280 SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, 
281              struct kvec *iov, int n_vec, int *pbytes_returned,
282              const int long_op)
283 {
284         int rc = 0;
285         unsigned int receive_len;
286         unsigned long timeout;
287         struct mid_q_entry *midQ;
288         struct smb_hdr *in_buf = iov[0].iov_base;
289
290         if (ses == NULL) {
291                 cERROR(1,("Null smb session"));
292                 return -EIO;
293         }
294         if(ses->server == NULL) {
295                 cERROR(1,("Null tcp session"));
296                 return -EIO;
297         }
298
299         if(ses->server->tcpStatus == CifsExiting)
300                 return -ENOENT;
301
302         /* Ensure that we do not send more than 50 overlapping requests 
303            to the same server. We may make this configurable later or
304            use ses->maxReq */
305         if(long_op == -1) {
306                 /* oplock breaks must not be held up */
307                 atomic_inc(&ses->server->inFlight);
308         } else {
309                 spin_lock(&GlobalMid_Lock); 
310                 while(1) {        
311                         if(atomic_read(&ses->server->inFlight) >= 
312                                         cifs_max_pending){
313                                 spin_unlock(&GlobalMid_Lock);
314 #ifdef CONFIG_CIFS_STATS2
315                                 atomic_inc(&ses->server->num_waiters);
316 #endif
317                                 wait_event(ses->server->request_q,
318                                         atomic_read(&ses->server->inFlight)
319                                          < cifs_max_pending);
320 #ifdef CONFIG_CIFS_STATS2
321                                 atomic_dec(&ses->server->num_waiters);
322 #endif
323                                 spin_lock(&GlobalMid_Lock);
324                         } else {
325                                 if(ses->server->tcpStatus == CifsExiting) {
326                                         spin_unlock(&GlobalMid_Lock);
327                                         return -ENOENT;
328                                 }
329
330                         /* can not count locking commands against total since
331                            they are allowed to block on server */
332                                         
333                                 if(long_op < 3) {
334                                 /* update # of requests on the wire to server */
335                                         atomic_inc(&ses->server->inFlight);
336                                 }
337                                 spin_unlock(&GlobalMid_Lock);
338                                 break;
339                         }
340                 }
341         }
342         /* make sure that we sign in the same order that we send on this socket 
343            and avoid races inside tcp sendmsg code that could cause corruption
344            of smb data */
345
346         down(&ses->server->tcpSem); 
347
348         if (ses->server->tcpStatus == CifsExiting) {
349                 rc = -ENOENT;
350                 goto out_unlock2;
351         } else if (ses->server->tcpStatus == CifsNeedReconnect) {
352                 cFYI(1,("tcp session dead - return to caller to retry"));
353                 rc = -EAGAIN;
354                 goto out_unlock2;
355         } else if (ses->status != CifsGood) {
356                 /* check if SMB session is bad because we are setting it up */
357                 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
358                         (in_buf->Command != SMB_COM_NEGOTIATE)) {
359                         rc = -EAGAIN;
360                         goto out_unlock2;
361                 } /* else ok - we are setting up session */
362         }
363         midQ = AllocMidQEntry(in_buf, ses);
364         if (midQ == NULL) {
365                 up(&ses->server->tcpSem);
366                 /* If not lock req, update # of requests on wire to server */
367                 if(long_op < 3) {
368                         atomic_dec(&ses->server->inFlight); 
369                         wake_up(&ses->server->request_q);
370                 }
371                 return -ENOMEM;
372         }
373
374 /* BB FIXME */
375 /*      rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); */
376
377         midQ->midState = MID_REQUEST_SUBMITTED;
378 #ifdef CONFIG_CIFS_STATS2
379         atomic_inc(&ses->server->inSend);
380 #endif
381         rc = smb_send2(ses->server->ssocket, iov, n_vec,
382                       (struct sockaddr *) &(ses->server->addr.sockAddr));
383 #ifdef CONFIG_CIFS_STATS2
384         atomic_dec(&ses->server->inSend);
385 #endif
386         if(rc < 0) {
387                 DeleteMidQEntry(midQ);
388                 up(&ses->server->tcpSem);
389                 /* If not lock req, update # of requests on wire to server */
390                 if(long_op < 3) {
391                         atomic_dec(&ses->server->inFlight); 
392                         wake_up(&ses->server->request_q);
393                 }
394                 return rc;
395         } else
396                 up(&ses->server->tcpSem);
397         if (long_op == -1)
398                 goto cifs_no_response_exit2;
399         else if (long_op == 2) /* writes past end of file can take loong time */
400                 timeout = 180 * HZ;
401         else if (long_op == 1)
402                 timeout = 45 * HZ; /* should be greater than 
403                         servers oplock break timeout (about 43 seconds) */
404         else if (long_op > 2) {
405                 timeout = MAX_SCHEDULE_TIMEOUT;
406         } else
407                 timeout = 15 * HZ;
408         /* wait for 15 seconds or until woken up due to response arriving or 
409            due to last connection to this server being unmounted */
410         if (signal_pending(current)) {
411                 /* if signal pending do not hold up user for full smb timeout
412                 but we still give response a change to complete */
413                 timeout = 2 * HZ;
414         }   
415
416         /* No user interrupts in wait - wreaks havoc with performance */
417         if(timeout != MAX_SCHEDULE_TIMEOUT) {
418                 timeout += jiffies;
419                 wait_event(ses->server->response_q,
420                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
421                         time_after(jiffies, timeout) || 
422                         ((ses->server->tcpStatus != CifsGood) &&
423                          (ses->server->tcpStatus != CifsNew)));
424         } else {
425                 wait_event(ses->server->response_q,
426                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
427                         ((ses->server->tcpStatus != CifsGood) &&
428                          (ses->server->tcpStatus != CifsNew)));
429         }
430
431         spin_lock(&GlobalMid_Lock);
432         if (midQ->resp_buf) {
433                 spin_unlock(&GlobalMid_Lock);
434                 receive_len = midQ->resp_buf->smb_buf_length;
435         } else {
436                 cERROR(1,("No response to cmd %d mid %d",
437                         midQ->command, midQ->mid));
438                 if(midQ->midState == MID_REQUEST_SUBMITTED) {
439                         if(ses->server->tcpStatus == CifsExiting)
440                                 rc = -EHOSTDOWN;
441                         else {
442                                 ses->server->tcpStatus = CifsNeedReconnect;
443                                 midQ->midState = MID_RETRY_NEEDED;
444                         }
445                 }
446
447                 if (rc != -EHOSTDOWN) {
448                         if(midQ->midState == MID_RETRY_NEEDED) {
449                                 rc = -EAGAIN;
450                                 cFYI(1,("marking request for retry"));
451                         } else {
452                                 rc = -EIO;
453                         }
454                 }
455                 spin_unlock(&GlobalMid_Lock);
456                 DeleteMidQEntry(midQ);
457                 /* If not lock req, update # of requests on wire to server */
458                 if(long_op < 3) {
459                         atomic_dec(&ses->server->inFlight); 
460                         wake_up(&ses->server->request_q);
461                 }
462                 return rc;
463         }
464   
465         if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
466                 cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
467                         receive_len, xid));
468                 rc = -EIO;
469         } else {                /* rcvd frame is ok */
470
471                 if (midQ->resp_buf && 
472                         (midQ->midState == MID_RESPONSE_RECEIVED)) {
473                         in_buf->smb_buf_length = receive_len;
474                         /* BB verify that length would not overrun small buf */
475                         memcpy((char *)in_buf + 4,
476                                (char *)midQ->resp_buf + 4,
477                                receive_len);
478
479                         dump_smb(in_buf, 80);
480                         /* convert the length into a more usable form */
481                         if((receive_len > 24) &&
482                            (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
483                                         SECMODE_SIGN_ENABLED))) {
484                                 rc = cifs_verify_signature(in_buf,
485                                                 ses->server->mac_signing_key,
486                                                 midQ->sequence_number+1);
487                                 if(rc) {
488                                         cERROR(1,("Unexpected SMB signature"));
489                                         /* BB FIXME add code to kill session */
490                                 }
491                         }
492
493                         *pbytes_returned = in_buf->smb_buf_length;
494
495                         /* BB special case reconnect tid and uid here? */
496                         rc = map_smb_to_linux_error(in_buf);
497
498                         /* convert ByteCount if necessary */
499                         if (receive_len >=
500                             sizeof (struct smb_hdr) -
501                             4 /* do not count RFC1001 header */  +
502                             (2 * in_buf->WordCount) + 2 /* bcc */ )
503                                 BCC(in_buf) = le16_to_cpu(BCC(in_buf));
504                 } else {
505                         rc = -EIO;
506                         cFYI(1,("Bad MID state?"));
507                 }
508         }
509 cifs_no_response_exit2:
510         DeleteMidQEntry(midQ);
511
512         if(long_op < 3) {
513                 atomic_dec(&ses->server->inFlight); 
514                 wake_up(&ses->server->request_q);
515         }
516
517         return rc;
518
519 out_unlock2:
520         up(&ses->server->tcpSem);
521         /* If not lock req, update # of requests on wire to server */
522         if(long_op < 3) {
523                 atomic_dec(&ses->server->inFlight); 
524                 wake_up(&ses->server->request_q);
525         }
526
527         return rc;
528 }
529 #endif /* CIFS_EXPERIMENTAL */
530
531 int
532 SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
533             struct smb_hdr *in_buf, struct smb_hdr *out_buf,
534             int *pbytes_returned, const int long_op)
535 {
536         int rc = 0;
537         unsigned int receive_len;
538         unsigned long timeout;
539         struct mid_q_entry *midQ;
540
541         if (ses == NULL) {
542                 cERROR(1,("Null smb session"));
543                 return -EIO;
544         }
545         if(ses->server == NULL) {
546                 cERROR(1,("Null tcp session"));
547                 return -EIO;
548         }
549
550         if(ses->server->tcpStatus == CifsExiting)
551                 return -ENOENT;
552
553         /* Ensure that we do not send more than 50 overlapping requests 
554            to the same server. We may make this configurable later or
555            use ses->maxReq */
556         if(long_op == -1) {
557                 /* oplock breaks must not be held up */
558                 atomic_inc(&ses->server->inFlight);
559         } else {
560                 spin_lock(&GlobalMid_Lock); 
561                 while(1) {        
562                         if(atomic_read(&ses->server->inFlight) >= 
563                                         cifs_max_pending){
564                                 spin_unlock(&GlobalMid_Lock);
565 #ifdef CONFIG_CIFS_STATS2
566                                 atomic_inc(&ses->server->num_waiters);
567 #endif
568                                 wait_event(ses->server->request_q,
569                                         atomic_read(&ses->server->inFlight)
570                                          < cifs_max_pending);
571 #ifdef CONFIG_CIFS_STATS2
572                                 atomic_dec(&ses->server->num_waiters);
573 #endif
574                                 spin_lock(&GlobalMid_Lock);
575                         } else {
576                                 if(ses->server->tcpStatus == CifsExiting) {
577                                         spin_unlock(&GlobalMid_Lock);
578                                         return -ENOENT;
579                                 }
580
581                         /* can not count locking commands against total since
582                            they are allowed to block on server */
583                                         
584                                 if(long_op < 3) {
585                                 /* update # of requests on the wire to server */
586                                         atomic_inc(&ses->server->inFlight);
587                                 }
588                                 spin_unlock(&GlobalMid_Lock);
589                                 break;
590                         }
591                 }
592         }
593         /* make sure that we sign in the same order that we send on this socket 
594            and avoid races inside tcp sendmsg code that could cause corruption
595            of smb data */
596
597         down(&ses->server->tcpSem); 
598
599         if (ses->server->tcpStatus == CifsExiting) {
600                 rc = -ENOENT;
601                 goto out_unlock;
602         } else if (ses->server->tcpStatus == CifsNeedReconnect) {
603                 cFYI(1,("tcp session dead - return to caller to retry"));
604                 rc = -EAGAIN;
605                 goto out_unlock;
606         } else if (ses->status != CifsGood) {
607                 /* check if SMB session is bad because we are setting it up */
608                 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
609                         (in_buf->Command != SMB_COM_NEGOTIATE)) {
610                         rc = -EAGAIN;
611                         goto out_unlock;
612                 } /* else ok - we are setting up session */
613         }
614         midQ = AllocMidQEntry(in_buf, ses);
615         if (midQ == NULL) {
616                 up(&ses->server->tcpSem);
617                 /* If not lock req, update # of requests on wire to server */
618                 if(long_op < 3) {
619                         atomic_dec(&ses->server->inFlight); 
620                         wake_up(&ses->server->request_q);
621                 }
622                 return -ENOMEM;
623         }
624
625         if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
626                 up(&ses->server->tcpSem);
627                 cERROR(1,
628                        ("Illegal length, greater than maximum frame, %d ",
629                         in_buf->smb_buf_length));
630                 DeleteMidQEntry(midQ);
631                 /* If not lock req, update # of requests on wire to server */
632                 if(long_op < 3) {
633                         atomic_dec(&ses->server->inFlight); 
634                         wake_up(&ses->server->request_q);
635                 }
636                 return -EIO;
637         }
638
639         rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
640
641         midQ->midState = MID_REQUEST_SUBMITTED;
642 #ifdef CONFIG_CIFS_STATS2
643         atomic_inc(&ses->server->inSend);
644 #endif
645         rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
646                       (struct sockaddr *) &(ses->server->addr.sockAddr));
647 #ifdef CONFIG_CIFS_STATS2
648         atomic_dec(&ses->server->inSend);
649 #endif
650         if(rc < 0) {
651                 DeleteMidQEntry(midQ);
652                 up(&ses->server->tcpSem);
653                 /* If not lock req, update # of requests on wire to server */
654                 if(long_op < 3) {
655                         atomic_dec(&ses->server->inFlight); 
656                         wake_up(&ses->server->request_q);
657                 }
658                 return rc;
659         } else
660                 up(&ses->server->tcpSem);
661         if (long_op == -1)
662                 goto cifs_no_response_exit;
663         else if (long_op == 2) /* writes past end of file can take loong time */
664                 timeout = 180 * HZ;
665         else if (long_op == 1)
666                 timeout = 45 * HZ; /* should be greater than 
667                         servers oplock break timeout (about 43 seconds) */
668         else if (long_op > 2) {
669                 timeout = MAX_SCHEDULE_TIMEOUT;
670         } else
671                 timeout = 15 * HZ;
672         /* wait for 15 seconds or until woken up due to response arriving or 
673            due to last connection to this server being unmounted */
674         if (signal_pending(current)) {
675                 /* if signal pending do not hold up user for full smb timeout
676                 but we still give response a change to complete */
677                 timeout = 2 * HZ;
678         }   
679
680         /* No user interrupts in wait - wreaks havoc with performance */
681         if(timeout != MAX_SCHEDULE_TIMEOUT) {
682                 timeout += jiffies;
683                 wait_event(ses->server->response_q,
684                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
685                         time_after(jiffies, timeout) || 
686                         ((ses->server->tcpStatus != CifsGood) &&
687                          (ses->server->tcpStatus != CifsNew)));
688         } else {
689                 wait_event(ses->server->response_q,
690                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
691                         ((ses->server->tcpStatus != CifsGood) &&
692                          (ses->server->tcpStatus != CifsNew)));
693         }
694
695         spin_lock(&GlobalMid_Lock);
696         if (midQ->resp_buf) {
697                 spin_unlock(&GlobalMid_Lock);
698                 receive_len = midQ->resp_buf->smb_buf_length;
699         } else {
700                 cERROR(1,("No response for cmd %d mid %d",
701                           midQ->command, midQ->mid));
702                 if(midQ->midState == MID_REQUEST_SUBMITTED) {
703                         if(ses->server->tcpStatus == CifsExiting)
704                                 rc = -EHOSTDOWN;
705                         else {
706                                 ses->server->tcpStatus = CifsNeedReconnect;
707                                 midQ->midState = MID_RETRY_NEEDED;
708                         }
709                 }
710
711                 if (rc != -EHOSTDOWN) {
712                         if(midQ->midState == MID_RETRY_NEEDED) {
713                                 rc = -EAGAIN;
714                                 cFYI(1,("marking request for retry"));
715                         } else {
716                                 rc = -EIO;
717                         }
718                 }
719                 spin_unlock(&GlobalMid_Lock);
720                 DeleteMidQEntry(midQ);
721                 /* If not lock req, update # of requests on wire to server */
722                 if(long_op < 3) {
723                         atomic_dec(&ses->server->inFlight); 
724                         wake_up(&ses->server->request_q);
725                 }
726                 return rc;
727         }
728   
729         if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
730                 cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
731                         receive_len, xid));
732                 rc = -EIO;
733         } else {                /* rcvd frame is ok */
734
735                 if (midQ->resp_buf && out_buf
736                     && (midQ->midState == MID_RESPONSE_RECEIVED)) {
737                         out_buf->smb_buf_length = receive_len;
738                         memcpy((char *)out_buf + 4,
739                                (char *)midQ->resp_buf + 4,
740                                receive_len);
741
742                         dump_smb(out_buf, 92);
743                         /* convert the length into a more usable form */
744                         if((receive_len > 24) &&
745                            (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
746                                         SECMODE_SIGN_ENABLED))) {
747                                 rc = cifs_verify_signature(out_buf,
748                                                 ses->server->mac_signing_key,
749                                                 midQ->sequence_number+1);
750                                 if(rc) {
751                                         cERROR(1,("Unexpected SMB signature"));
752                                         /* BB FIXME add code to kill session */
753                                 }
754                         }
755
756                         *pbytes_returned = out_buf->smb_buf_length;
757
758                         /* BB special case reconnect tid and uid here? */
759                         rc = map_smb_to_linux_error(out_buf);
760
761                         /* convert ByteCount if necessary */
762                         if (receive_len >=
763                             sizeof (struct smb_hdr) -
764                             4 /* do not count RFC1001 header */  +
765                             (2 * out_buf->WordCount) + 2 /* bcc */ )
766                                 BCC(out_buf) = le16_to_cpu(BCC(out_buf));
767                 } else {
768                         rc = -EIO;
769                         cERROR(1,("Bad MID state? "));
770                 }
771         }
772 cifs_no_response_exit:
773         DeleteMidQEntry(midQ);
774
775         if(long_op < 3) {
776                 atomic_dec(&ses->server->inFlight); 
777                 wake_up(&ses->server->request_q);
778         }
779
780         return rc;
781
782 out_unlock:
783         up(&ses->server->tcpSem);
784         /* If not lock req, update # of requests on wire to server */
785         if(long_op < 3) {
786                 atomic_dec(&ses->server->inFlight); 
787                 wake_up(&ses->server->request_q);
788         }
789
790         return rc;
791 }