[CIFS] Avoid extra large buffer allocation (and memcpy) in cifs_readpages
[sfrench/cifs-2.6.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) {
313                 cERROR(1,("Null smb session"));
314                 return -EIO;
315         }
316         if(ses->server == NULL) {
317                 cERROR(1,("Null tcp session"));
318                 return -EIO;
319         }
320
321         if(ses->server->tcpStatus == CifsExiting)
322                 return -ENOENT;
323
324         /* Ensure that we do not send more than 50 overlapping requests 
325            to the same server. We may make this configurable later or
326            use ses->maxReq */
327         if(long_op == -1) {
328                 /* oplock breaks must not be held up */
329                 atomic_inc(&ses->server->inFlight);
330         } else {
331                 spin_lock(&GlobalMid_Lock); 
332                 while(1) {        
333                         if(atomic_read(&ses->server->inFlight) >= 
334                                         cifs_max_pending){
335                                 spin_unlock(&GlobalMid_Lock);
336 #ifdef CONFIG_CIFS_STATS2
337                                 atomic_inc(&ses->server->num_waiters);
338 #endif
339                                 wait_event(ses->server->request_q,
340                                         atomic_read(&ses->server->inFlight)
341                                          < cifs_max_pending);
342 #ifdef CONFIG_CIFS_STATS2
343                                 atomic_dec(&ses->server->num_waiters);
344 #endif
345                                 spin_lock(&GlobalMid_Lock);
346                         } else {
347                                 if(ses->server->tcpStatus == CifsExiting) {
348                                         spin_unlock(&GlobalMid_Lock);
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                 /* If not lock req, update # of requests on wire to server */
389                 if(long_op < 3) {
390                         atomic_dec(&ses->server->inFlight); 
391                         wake_up(&ses->server->request_q);
392                 }
393                 return -ENOMEM;
394         }
395
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
496                         iov[0].iov_base = (char *)midQ->resp_buf;
497                         if(midQ->largeBuf)
498                                 *pRespBufType = CIFS_LARGE_BUFFER;
499                         else
500                                 *pRespBufType = CIFS_SMALL_BUFFER;
501                         iov[0].iov_len = receive_len + 4;
502                         iov[1].iov_len = 0;
503
504                         dump_smb(midQ->resp_buf, 80);
505                         /* convert the length into a more usable form */
506                         if((receive_len > 24) &&
507                            (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
508                                         SECMODE_SIGN_ENABLED))) {
509                                 rc = cifs_verify_signature(midQ->resp_buf,
510                                                 ses->server->mac_signing_key,
511                                                 midQ->sequence_number+1);
512                                 if(rc) {
513                                         cERROR(1,("Unexpected SMB signature"));
514                                         /* BB FIXME add code to kill session */
515                                 }
516                         }
517
518                         /* BB special case reconnect tid and uid here? */
519                         /* BB special case Errbadpassword and pwdexpired here */
520                         rc = map_smb_to_linux_error(midQ->resp_buf);
521
522                         /* convert ByteCount if necessary */
523                         if (receive_len >=
524                             sizeof (struct smb_hdr) -
525                             4 /* do not count RFC1001 header */  +
526                             (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
527                                 BCC(midQ->resp_buf) = 
528                                         le16_to_cpu(BCC_LE(midQ->resp_buf));
529                         midQ->resp_buf = NULL;  /* mark it so will not be freed
530                                                 by DeleteMidQEntry */
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 }