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