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