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