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