CIFS: Allow wsize to exceed CIFSMaxBufSize
[firefly-linux-kernel-4.4.55.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 > 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 /* BB FIXME */
365 /*      rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); */
366
367         midQ->midState = MID_REQUEST_SUBMITTED;
368         rc = smb_send2(ses->server->ssocket, iov, n_vec,
369                       (struct sockaddr *) &(ses->server->addr.sockAddr));
370         if(rc < 0) {
371                 DeleteMidQEntry(midQ);
372                 up(&ses->server->tcpSem);
373                 /* If not lock req, update # of requests on wire to server */
374                 if(long_op < 3) {
375                         atomic_dec(&ses->server->inFlight); 
376                         wake_up(&ses->server->request_q);
377                 }
378                 return rc;
379         } else
380                 up(&ses->server->tcpSem);
381         if (long_op == -1)
382                 goto cifs_no_response_exit2;
383         else if (long_op == 2) /* writes past end of file can take loong time */
384                 timeout = 180 * HZ;
385         else if (long_op == 1)
386                 timeout = 45 * HZ; /* should be greater than 
387                         servers oplock break timeout (about 43 seconds) */
388         else if (long_op > 2) {
389                 timeout = MAX_SCHEDULE_TIMEOUT;
390         } else
391                 timeout = 15 * HZ;
392         /* wait for 15 seconds or until woken up due to response arriving or 
393            due to last connection to this server being unmounted */
394         if (signal_pending(current)) {
395                 /* if signal pending do not hold up user for full smb timeout
396                 but we still give response a change to complete */
397                 timeout = 2 * HZ;
398         }   
399
400         /* No user interrupts in wait - wreaks havoc with performance */
401         if(timeout != MAX_SCHEDULE_TIMEOUT) {
402                 timeout += jiffies;
403                 wait_event(ses->server->response_q,
404                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
405                         time_after(jiffies, timeout) || 
406                         ((ses->server->tcpStatus != CifsGood) &&
407                          (ses->server->tcpStatus != CifsNew)));
408         } else {
409                 wait_event(ses->server->response_q,
410                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
411                         ((ses->server->tcpStatus != CifsGood) &&
412                          (ses->server->tcpStatus != CifsNew)));
413         }
414
415         spin_lock(&GlobalMid_Lock);
416         if (midQ->resp_buf) {
417                 spin_unlock(&GlobalMid_Lock);
418                 receive_len = midQ->resp_buf->smb_buf_length;
419         } else {
420                 cERROR(1,("No response to cmd %d mid %d",
421                         midQ->command, midQ->mid));
422                 if(midQ->midState == MID_REQUEST_SUBMITTED) {
423                         if(ses->server->tcpStatus == CifsExiting)
424                                 rc = -EHOSTDOWN;
425                         else {
426                                 ses->server->tcpStatus = CifsNeedReconnect;
427                                 midQ->midState = MID_RETRY_NEEDED;
428                         }
429                 }
430
431                 if (rc != -EHOSTDOWN) {
432                         if(midQ->midState == MID_RETRY_NEEDED) {
433                                 rc = -EAGAIN;
434                                 cFYI(1,("marking request for retry"));
435                         } else {
436                                 rc = -EIO;
437                         }
438                 }
439                 spin_unlock(&GlobalMid_Lock);
440                 DeleteMidQEntry(midQ);
441                 /* If not lock req, update # of requests on wire to server */
442                 if(long_op < 3) {
443                         atomic_dec(&ses->server->inFlight); 
444                         wake_up(&ses->server->request_q);
445                 }
446                 return rc;
447         }
448   
449         if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
450                 cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
451                         receive_len, xid));
452                 rc = -EIO;
453         } else {                /* rcvd frame is ok */
454
455                 if (midQ->resp_buf && 
456                         (midQ->midState == MID_RESPONSE_RECEIVED)) {
457                         in_buf->smb_buf_length = receive_len;
458                         /* BB verify that length would not overrun small buf */
459                         memcpy((char *)in_buf + 4,
460                                (char *)midQ->resp_buf + 4,
461                                receive_len);
462
463                         dump_smb(in_buf, 80);
464                         /* convert the length into a more usable form */
465                         if((receive_len > 24) &&
466                            (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
467                                         SECMODE_SIGN_ENABLED))) {
468                                 rc = cifs_verify_signature(in_buf,
469                                                 ses->server->mac_signing_key,
470                                                 midQ->sequence_number+1);
471                                 if(rc) {
472                                         cERROR(1,("Unexpected SMB signature"));
473                                         /* BB FIXME add code to kill session */
474                                 }
475                         }
476
477                         *pbytes_returned = in_buf->smb_buf_length;
478
479                         /* BB special case reconnect tid and uid here? */
480                         rc = map_smb_to_linux_error(in_buf);
481
482                         /* convert ByteCount if necessary */
483                         if (receive_len >=
484                             sizeof (struct smb_hdr) -
485                             4 /* do not count RFC1001 header */  +
486                             (2 * in_buf->WordCount) + 2 /* bcc */ )
487                                 BCC(in_buf) = le16_to_cpu(BCC(in_buf));
488                 } else {
489                         rc = -EIO;
490                         cFYI(1,("Bad MID state?"));
491                 }
492         }
493 cifs_no_response_exit2:
494         DeleteMidQEntry(midQ);
495
496         if(long_op < 3) {
497                 atomic_dec(&ses->server->inFlight); 
498                 wake_up(&ses->server->request_q);
499         }
500
501         return rc;
502
503 out_unlock2:
504         up(&ses->server->tcpSem);
505         /* If not lock req, update # of requests on wire to server */
506         if(long_op < 3) {
507                 atomic_dec(&ses->server->inFlight); 
508                 wake_up(&ses->server->request_q);
509         }
510
511         return rc;
512 }
513 #endif /* CIFS_EXPERIMENTAL */
514
515 int
516 SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
517             struct smb_hdr *in_buf, struct smb_hdr *out_buf,
518             int *pbytes_returned, const int long_op)
519 {
520         int rc = 0;
521         unsigned int receive_len;
522         unsigned long timeout;
523         struct mid_q_entry *midQ;
524
525         if (ses == NULL) {
526                 cERROR(1,("Null smb session"));
527                 return -EIO;
528         }
529         if(ses->server == NULL) {
530                 cERROR(1,("Null tcp session"));
531                 return -EIO;
532         }
533
534         if(ses->server->tcpStatus == CifsExiting)
535                 return -ENOENT;
536
537         /* Ensure that we do not send more than 50 overlapping requests 
538            to the same server. We may make this configurable later or
539            use ses->maxReq */
540         if(long_op == -1) {
541                 /* oplock breaks must not be held up */
542                 atomic_inc(&ses->server->inFlight);
543         } else {
544                 spin_lock(&GlobalMid_Lock); 
545                 while(1) {        
546                         if(atomic_read(&ses->server->inFlight) >= 
547                                         cifs_max_pending){
548                                 spin_unlock(&GlobalMid_Lock);
549                                 wait_event(ses->server->request_q,
550                                         atomic_read(&ses->server->inFlight)
551                                          < cifs_max_pending);
552                                 spin_lock(&GlobalMid_Lock);
553                         } else {
554                                 if(ses->server->tcpStatus == CifsExiting) {
555                                         spin_unlock(&GlobalMid_Lock);
556                                         return -ENOENT;
557                                 }
558
559                         /* can not count locking commands against total since
560                            they are allowed to block on server */
561                                         
562                                 if(long_op < 3) {
563                                 /* update # of requests on the wire to server */
564                                         atomic_inc(&ses->server->inFlight);
565                                 }
566                                 spin_unlock(&GlobalMid_Lock);
567                                 break;
568                         }
569                 }
570         }
571         /* make sure that we sign in the same order that we send on this socket 
572            and avoid races inside tcp sendmsg code that could cause corruption
573            of smb data */
574
575         down(&ses->server->tcpSem); 
576
577         if (ses->server->tcpStatus == CifsExiting) {
578                 rc = -ENOENT;
579                 goto out_unlock;
580         } else if (ses->server->tcpStatus == CifsNeedReconnect) {
581                 cFYI(1,("tcp session dead - return to caller to retry"));
582                 rc = -EAGAIN;
583                 goto out_unlock;
584         } else if (ses->status != CifsGood) {
585                 /* check if SMB session is bad because we are setting it up */
586                 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
587                         (in_buf->Command != SMB_COM_NEGOTIATE)) {
588                         rc = -EAGAIN;
589                         goto out_unlock;
590                 } /* else ok - we are setting up session */
591         }
592         midQ = AllocMidQEntry(in_buf, ses);
593         if (midQ == NULL) {
594                 up(&ses->server->tcpSem);
595                 /* If not lock req, update # of requests on wire to server */
596                 if(long_op < 3) {
597                         atomic_dec(&ses->server->inFlight); 
598                         wake_up(&ses->server->request_q);
599                 }
600                 return -ENOMEM;
601         }
602
603         if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
604                 up(&ses->server->tcpSem);
605                 cERROR(1,
606                        ("Illegal length, greater than maximum frame, %d ",
607                         in_buf->smb_buf_length));
608                 DeleteMidQEntry(midQ);
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 -EIO;
615         }
616
617         rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
618
619         midQ->midState = MID_REQUEST_SUBMITTED;
620         rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
621                       (struct sockaddr *) &(ses->server->addr.sockAddr));
622         if(rc < 0) {
623                 DeleteMidQEntry(midQ);
624                 up(&ses->server->tcpSem);
625                 /* If not lock req, update # of requests on wire to server */
626                 if(long_op < 3) {
627                         atomic_dec(&ses->server->inFlight); 
628                         wake_up(&ses->server->request_q);
629                 }
630                 return rc;
631         } else
632                 up(&ses->server->tcpSem);
633         if (long_op == -1)
634                 goto cifs_no_response_exit;
635         else if (long_op == 2) /* writes past end of file can take loong time */
636                 timeout = 180 * HZ;
637         else if (long_op == 1)
638                 timeout = 45 * HZ; /* should be greater than 
639                         servers oplock break timeout (about 43 seconds) */
640         else if (long_op > 2) {
641                 timeout = MAX_SCHEDULE_TIMEOUT;
642         } else
643                 timeout = 15 * HZ;
644         /* wait for 15 seconds or until woken up due to response arriving or 
645            due to last connection to this server being unmounted */
646         if (signal_pending(current)) {
647                 /* if signal pending do not hold up user for full smb timeout
648                 but we still give response a change to complete */
649                 timeout = 2 * HZ;
650         }   
651
652         /* No user interrupts in wait - wreaks havoc with performance */
653         if(timeout != MAX_SCHEDULE_TIMEOUT) {
654                 timeout += jiffies;
655                 wait_event(ses->server->response_q,
656                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
657                         time_after(jiffies, timeout) || 
658                         ((ses->server->tcpStatus != CifsGood) &&
659                          (ses->server->tcpStatus != CifsNew)));
660         } else {
661                 wait_event(ses->server->response_q,
662                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
663                         ((ses->server->tcpStatus != CifsGood) &&
664                          (ses->server->tcpStatus != CifsNew)));
665         }
666
667         spin_lock(&GlobalMid_Lock);
668         if (midQ->resp_buf) {
669                 spin_unlock(&GlobalMid_Lock);
670                 receive_len = midQ->resp_buf->smb_buf_length;
671         } else {
672                 cERROR(1,("No response for cmd %d mid %d",
673                           midQ->command, midQ->mid));
674                 if(midQ->midState == MID_REQUEST_SUBMITTED) {
675                         if(ses->server->tcpStatus == CifsExiting)
676                                 rc = -EHOSTDOWN;
677                         else {
678                                 ses->server->tcpStatus = CifsNeedReconnect;
679                                 midQ->midState = MID_RETRY_NEEDED;
680                         }
681                 }
682
683                 if (rc != -EHOSTDOWN) {
684                         if(midQ->midState == MID_RETRY_NEEDED) {
685                                 rc = -EAGAIN;
686                                 cFYI(1,("marking request for retry"));
687                         } else {
688                                 rc = -EIO;
689                         }
690                 }
691                 spin_unlock(&GlobalMid_Lock);
692                 DeleteMidQEntry(midQ);
693                 /* If not lock req, update # of requests on wire to server */
694                 if(long_op < 3) {
695                         atomic_dec(&ses->server->inFlight); 
696                         wake_up(&ses->server->request_q);
697                 }
698                 return rc;
699         }
700   
701         if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
702                 cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
703                         receive_len, xid));
704                 rc = -EIO;
705         } else {                /* rcvd frame is ok */
706
707                 if (midQ->resp_buf && out_buf
708                     && (midQ->midState == MID_RESPONSE_RECEIVED)) {
709                         out_buf->smb_buf_length = receive_len;
710                         memcpy((char *)out_buf + 4,
711                                (char *)midQ->resp_buf + 4,
712                                receive_len);
713
714                         dump_smb(out_buf, 92);
715                         /* convert the length into a more usable form */
716                         if((receive_len > 24) &&
717                            (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
718                                         SECMODE_SIGN_ENABLED))) {
719                                 rc = cifs_verify_signature(out_buf,
720                                                 ses->server->mac_signing_key,
721                                                 midQ->sequence_number+1);
722                                 if(rc) {
723                                         cERROR(1,("Unexpected SMB signature"));
724                                         /* BB FIXME add code to kill session */
725                                 }
726                         }
727
728                         *pbytes_returned = out_buf->smb_buf_length;
729
730                         /* BB special case reconnect tid and uid here? */
731                         rc = map_smb_to_linux_error(out_buf);
732
733                         /* convert ByteCount if necessary */
734                         if (receive_len >=
735                             sizeof (struct smb_hdr) -
736                             4 /* do not count RFC1001 header */  +
737                             (2 * out_buf->WordCount) + 2 /* bcc */ )
738                                 BCC(out_buf) = le16_to_cpu(BCC(out_buf));
739                 } else {
740                         rc = -EIO;
741                         cERROR(1,("Bad MID state? "));
742                 }
743         }
744 cifs_no_response_exit:
745         DeleteMidQEntry(midQ);
746
747         if(long_op < 3) {
748                 atomic_dec(&ses->server->inFlight); 
749                 wake_up(&ses->server->request_q);
750         }
751
752         return rc;
753
754 out_unlock:
755         up(&ses->server->tcpSem);
756         /* If not lock req, update # of requests on wire to server */
757         if(long_op < 3) {
758                 atomic_dec(&ses->server->inFlight); 
759                 wake_up(&ses->server->request_q);
760         }
761
762         return rc;
763 }