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