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