79bf686a2a190875dcb37a239811659c2e2c95df
[pandora-kernel.git] / fs / cifs / transport.c
1 /*
2  *   fs/cifs/transport.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2005
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  *   This library is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU Lesser General Public License as published
9  *   by the Free Software Foundation; either version 2.1 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This library is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
15  *   the GNU Lesser General Public License for more details.
16  *
17  *   You should have received a copy of the GNU Lesser General Public License
18  *   along with this library; if not, write to the Free Software
19  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
20  */
21
22 #include <linux/fs.h>
23 #include <linux/list.h>
24 #include <linux/wait.h>
25 #include <linux/net.h>
26 #include <linux/delay.h>
27 #include <asm/uaccess.h>
28 #include <asm/processor.h>
29 #include <linux/mempool.h>
30 #include "cifspdu.h"
31 #include "cifsglob.h"
32 #include "cifsproto.h"
33 #include "cifs_debug.h"
34   
35 extern mempool_t *cifs_mid_poolp;
36 extern kmem_cache_t *cifs_oplock_cachep;
37
38 static struct mid_q_entry *
39 AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
40 {
41         struct mid_q_entry *temp;
42
43         if (ses == NULL) {
44                 cERROR(1, ("Null session passed in to AllocMidQEntry"));
45                 return NULL;
46         }
47         if (ses->server == NULL) {
48                 cERROR(1, ("Null TCP session in AllocMidQEntry"));
49                 return NULL;
50         }
51         
52         temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,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         /* Ensure that we do not send more than 50 overlapping requests 
274            to the same server. We may make this configurable later or
275            use ses->maxReq */
276         if(long_op == -1) {
277                 /* oplock breaks must not be held up */
278                 atomic_inc(&ses->server->inFlight);
279         } else {
280                 spin_lock(&GlobalMid_Lock); 
281                 while(1) {        
282                         if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){
283                                 spin_unlock(&GlobalMid_Lock);
284                                 wait_event(ses->server->request_q,
285                                         atomic_read(&ses->server->inFlight)
286                                          < cifs_max_pending);
287                                 spin_lock(&GlobalMid_Lock);
288                         } else {
289                                 if(ses->server->tcpStatus == CifsExiting) {
290                                         spin_unlock(&GlobalMid_Lock);
291                                         return -ENOENT;
292                                 }
293
294                         /* can not count locking commands against total since
295                            they are allowed to block on server */
296                                         
297                                 if(long_op < 3) {
298                                 /* update # of requests on the wire to server */
299                                         atomic_inc(&ses->server->inFlight);
300                                 }
301                                 spin_unlock(&GlobalMid_Lock);
302                                 break;
303                         }
304                 }
305         }
306         /* make sure that we sign in the same order that we send on this socket 
307            and avoid races inside tcp sendmsg code that could cause corruption
308            of smb data */
309
310         down(&ses->server->tcpSem); 
311
312         if (ses->server->tcpStatus == CifsExiting) {
313                 rc = -ENOENT;
314                 goto cifs_out_label;
315         } else if (ses->server->tcpStatus == CifsNeedReconnect) {
316                 cFYI(1,("tcp session dead - return to caller to retry"));
317                 rc = -EAGAIN;
318                 goto cifs_out_label;
319         } else if (ses->status != CifsGood) {
320                 /* check if SMB session is bad because we are setting it up */
321                 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
322                         (in_buf->Command != SMB_COM_NEGOTIATE)) {
323                         rc = -EAGAIN;
324                         goto cifs_out_label;
325                 } /* else ok - we are setting up session */
326         }
327         midQ = AllocMidQEntry(in_buf, ses);
328         if (midQ == NULL) {
329                 up(&ses->server->tcpSem);
330                 /* If not lock req, update # of requests on wire to server */
331                 if(long_op < 3) {
332                         atomic_dec(&ses->server->inFlight); 
333                         wake_up(&ses->server->request_q);
334                 }
335                 return -ENOMEM;
336         }
337
338         if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
339                 up(&ses->server->tcpSem);
340                 cERROR(1,
341                        ("Illegal length, greater than maximum frame, %d ",
342                         in_buf->smb_buf_length));
343                 DeleteMidQEntry(midQ);
344                 /* If not lock req, update # of requests on wire to server */
345                 if(long_op < 3) {
346                         atomic_dec(&ses->server->inFlight); 
347                         wake_up(&ses->server->request_q);
348                 }
349                 return -EIO;
350         }
351
352         /* BB can we sign efficiently in this path? */
353         rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
354
355         midQ->midState = MID_REQUEST_SUBMITTED;
356 /*      rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
357                        piovec, 
358                        (struct sockaddr *) &(ses->server->addr.sockAddr));*/
359         if(rc < 0) {
360                 DeleteMidQEntry(midQ);
361                 up(&ses->server->tcpSem);
362                 /* If not lock req, update # of requests on wire to server */
363                 if(long_op < 3) {
364                         atomic_dec(&ses->server->inFlight); 
365                         wake_up(&ses->server->request_q);
366                 }
367                 return rc;
368         } else
369                 up(&ses->server->tcpSem);
370 cifs_out_label:
371         if(midQ)
372                 DeleteMidQEntry(midQ);
373                                                                                                                            
374         if(long_op < 3) {
375                 atomic_dec(&ses->server->inFlight);
376                 wake_up(&ses->server->request_q);
377         }
378
379         return rc;
380 }
381
382
383 #endif /* CIFS_EXPERIMENTAL */
384
385 int
386 SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
387             struct smb_hdr *in_buf, struct smb_hdr *out_buf,
388             int *pbytes_returned, const int long_op)
389 {
390         int rc = 0;
391         unsigned int receive_len;
392         unsigned long timeout;
393         struct mid_q_entry *midQ;
394
395         if (ses == NULL) {
396                 cERROR(1,("Null smb session"));
397                 return -EIO;
398         }
399         if(ses->server == NULL) {
400                 cERROR(1,("Null tcp session"));
401                 return -EIO;
402         }
403
404         /* Ensure that we do not send more than 50 overlapping requests 
405            to the same server. We may make this configurable later or
406            use ses->maxReq */
407         if(long_op == -1) {
408                 /* oplock breaks must not be held up */
409                 atomic_inc(&ses->server->inFlight);
410         } else {
411                 spin_lock(&GlobalMid_Lock); 
412                 while(1) {        
413                         if(atomic_read(&ses->server->inFlight) >= 
414                                         cifs_max_pending){
415                                 spin_unlock(&GlobalMid_Lock);
416                                 wait_event(ses->server->request_q,
417                                         atomic_read(&ses->server->inFlight)
418                                          < cifs_max_pending);
419                                 spin_lock(&GlobalMid_Lock);
420                         } else {
421                                 if(ses->server->tcpStatus == CifsExiting) {
422                                         spin_unlock(&GlobalMid_Lock);
423                                         return -ENOENT;
424                                 }
425
426                         /* can not count locking commands against total since
427                            they are allowed to block on server */
428                                         
429                                 if(long_op < 3) {
430                                 /* update # of requests on the wire to server */
431                                         atomic_inc(&ses->server->inFlight);
432                                 }
433                                 spin_unlock(&GlobalMid_Lock);
434                                 break;
435                         }
436                 }
437         }
438         /* make sure that we sign in the same order that we send on this socket 
439            and avoid races inside tcp sendmsg code that could cause corruption
440            of smb data */
441
442         down(&ses->server->tcpSem); 
443
444         if (ses->server->tcpStatus == CifsExiting) {
445                 rc = -ENOENT;
446                 goto out_unlock;
447         } else if (ses->server->tcpStatus == CifsNeedReconnect) {
448                 cFYI(1,("tcp session dead - return to caller to retry"));
449                 rc = -EAGAIN;
450                 goto out_unlock;
451         } else if (ses->status != CifsGood) {
452                 /* check if SMB session is bad because we are setting it up */
453                 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
454                         (in_buf->Command != SMB_COM_NEGOTIATE)) {
455                         rc = -EAGAIN;
456                         goto out_unlock;
457                 } /* else ok - we are setting up session */
458         }
459         midQ = AllocMidQEntry(in_buf, ses);
460         if (midQ == NULL) {
461                 up(&ses->server->tcpSem);
462                 /* If not lock req, update # of requests on wire to server */
463                 if(long_op < 3) {
464                         atomic_dec(&ses->server->inFlight); 
465                         wake_up(&ses->server->request_q);
466                 }
467                 return -ENOMEM;
468         }
469
470         if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
471                 up(&ses->server->tcpSem);
472                 cERROR(1,
473                        ("Illegal length, greater than maximum frame, %d ",
474                         in_buf->smb_buf_length));
475                 DeleteMidQEntry(midQ);
476                 /* If not lock req, update # of requests on wire to server */
477                 if(long_op < 3) {
478                         atomic_dec(&ses->server->inFlight); 
479                         wake_up(&ses->server->request_q);
480                 }
481                 return -EIO;
482         }
483
484         rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
485
486         midQ->midState = MID_REQUEST_SUBMITTED;
487         rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
488                       (struct sockaddr *) &(ses->server->addr.sockAddr));
489         if(rc < 0) {
490                 DeleteMidQEntry(midQ);
491                 up(&ses->server->tcpSem);
492                 /* If not lock req, update # of requests on wire to server */
493                 if(long_op < 3) {
494                         atomic_dec(&ses->server->inFlight); 
495                         wake_up(&ses->server->request_q);
496                 }
497                 return rc;
498         } else
499                 up(&ses->server->tcpSem);
500         if (long_op == -1)
501                 goto cifs_no_response_exit;
502         else if (long_op == 2) /* writes past end of file can take loong time */
503                 timeout = 300 * HZ;
504         else if (long_op == 1)
505                 timeout = 45 * HZ; /* should be greater than 
506                         servers oplock break timeout (about 43 seconds) */
507         else if (long_op > 2) {
508                 timeout = MAX_SCHEDULE_TIMEOUT;
509         } else
510                 timeout = 15 * HZ;
511         /* wait for 15 seconds or until woken up due to response arriving or 
512            due to last connection to this server being unmounted */
513         if (signal_pending(current)) {
514                 /* if signal pending do not hold up user for full smb timeout
515                 but we still give response a change to complete */
516                 timeout = 2 * HZ;
517         }   
518
519         /* No user interrupts in wait - wreaks havoc with performance */
520         if(timeout != MAX_SCHEDULE_TIMEOUT) {
521                 timeout += jiffies;
522                 wait_event(ses->server->response_q,
523                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
524                         time_after(jiffies, timeout) || 
525                         ((ses->server->tcpStatus != CifsGood) &&
526                          (ses->server->tcpStatus != CifsNew)));
527         } else {
528                 wait_event(ses->server->response_q,
529                         (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
530                         ((ses->server->tcpStatus != CifsGood) &&
531                          (ses->server->tcpStatus != CifsNew)));
532         }
533
534         spin_lock(&GlobalMid_Lock);
535         if (midQ->resp_buf) {
536                 spin_unlock(&GlobalMid_Lock);
537                 receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf);
538         } else {
539                 cERROR(1,("No response buffer"));
540                 if(midQ->midState == MID_REQUEST_SUBMITTED) {
541                         if(ses->server->tcpStatus == CifsExiting)
542                                 rc = -EHOSTDOWN;
543                         else {
544                                 ses->server->tcpStatus = CifsNeedReconnect;
545                                 midQ->midState = MID_RETRY_NEEDED;
546                         }
547                 }
548
549                 if (rc != -EHOSTDOWN) {
550                         if(midQ->midState == MID_RETRY_NEEDED) {
551                                 rc = -EAGAIN;
552                                 cFYI(1,("marking request for retry"));
553                         } else {
554                                 rc = -EIO;
555                         }
556                 }
557                 spin_unlock(&GlobalMid_Lock);
558                 DeleteMidQEntry(midQ);
559                 /* If not lock req, update # of requests on wire to server */
560                 if(long_op < 3) {
561                         atomic_dec(&ses->server->inFlight); 
562                         wake_up(&ses->server->request_q);
563                 }
564                 return rc;
565         }
566   
567         if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
568                 cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
569                         receive_len, xid));
570                 rc = -EIO;
571         } else {                /* rcvd frame is ok */
572
573                 if (midQ->resp_buf && out_buf
574                     && (midQ->midState == MID_RESPONSE_RECEIVED)) {
575                         out_buf->smb_buf_length = receive_len;
576                         memcpy((char *)out_buf + 4,
577                                (char *)midQ->resp_buf + 4,
578                                receive_len);
579
580                         dump_smb(out_buf, 92);
581                         /* convert the length into a more usable form */
582                         if((receive_len > 24) &&
583                            (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
584                                         SECMODE_SIGN_ENABLED))) {
585                                 rc = cifs_verify_signature(out_buf,
586                                                 ses->server->mac_signing_key,
587                                                 midQ->sequence_number+1);
588                                 if(rc) {
589                                         cERROR(1,("Unexpected SMB signature"));
590                                         /* BB FIXME add code to kill session */
591                                 }
592                         }
593
594                         *pbytes_returned = out_buf->smb_buf_length;
595
596                         /* BB special case reconnect tid and uid here? */
597                         rc = map_smb_to_linux_error(out_buf);
598
599                         /* convert ByteCount if necessary */
600                         if (receive_len >=
601                             sizeof (struct smb_hdr) -
602                             4 /* do not count RFC1001 header */  +
603                             (2 * out_buf->WordCount) + 2 /* bcc */ )
604                                 BCC(out_buf) = le16_to_cpu(BCC(out_buf));
605                 } else {
606                         rc = -EIO;
607                         cFYI(1,("Bad MID state? "));
608                 }
609         }
610 cifs_no_response_exit:
611         DeleteMidQEntry(midQ);
612
613         if(long_op < 3) {
614                 atomic_dec(&ses->server->inFlight); 
615                 wake_up(&ses->server->request_q);
616         }
617
618         return rc;
619
620 out_unlock:
621         up(&ses->server->tcpSem);
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
628         return rc;
629 }