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