[PATCH] Fix JBD race in t_forget list handling
[linux-2.6/openmoko-kernel/knife-kernel.git] / fs / cifs / transport.c
blob0046c219833d6cfbef77e85addc663e1be71e290
1 /*
2 * fs/cifs/transport.c
4 * Copyright (C) International Business Machines Corp., 2002,2005
5 * Author(s): Steve French (sfrench@us.ibm.com)
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.
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.
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
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"
35 extern mempool_t *cifs_mid_poolp;
36 extern kmem_cache_t *cifs_oplock_cachep;
38 static struct mid_q_entry *
39 AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
41 struct mid_q_entry *temp;
43 if (ses == NULL) {
44 cERROR(1, ("Null session passed in to AllocMidQEntry"));
45 return NULL;
47 if (ses->server == NULL) {
48 cERROR(1, ("Null TCP session in AllocMidQEntry"));
49 return NULL;
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;
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;
74 static void
75 DeleteMidQEntry(struct mid_q_entry *midEntry)
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);
89 struct oplock_q_entry *
90 AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
92 struct oplock_q_entry *temp;
93 if ((pinode== NULL) || (tcon == NULL)) {
94 cERROR(1, ("Null parms passed to AllocOplockQEntry"));
95 return NULL;
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);
109 return temp;
113 void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry)
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);
123 smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
124 unsigned int smb_buf_length, struct sockaddr *sin)
126 int rc = 0;
127 int i = 0;
128 struct msghdr smb_msg;
129 struct kvec iov;
130 unsigned len = smb_buf_length + 4;
132 if(ssocket == NULL)
133 return -ENOTSOCK; /* BB eventually add reconnect code here */
134 iov.iov_base = smb_buffer;
135 iov.iov_len = len;
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?*/
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 */
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);
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;
163 msleep(500);
164 continue;
166 if (rc < 0)
167 break;
168 iov.iov_base += rc;
169 iov.iov_len -= rc;
170 len -= rc;
173 if (rc < 0) {
174 cERROR(1,("Error %d sending data on socket to server.", rc));
175 } else {
176 rc = 0;
179 return rc;
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 */
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)
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;
198 if(ssocket == NULL)
199 return -ENOTSOCK; /* BB eventually add reconnect code here */
200 iov.iov_base = smb_buffer;
201 iov.iov_len = len;
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?*/
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 */
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);
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;
230 msleep(500);
231 continue;
233 if (rc < 0)
234 break;
235 iov.iov_base += rc;
236 iov.iov_len -= rc;
237 len -= rc;
240 if (rc < 0) {
241 cERROR(1,("Error %d sending data on socket to server.", rc));
242 } else {
243 rc = 0;
246 return rc;
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)
254 int rc = 0;
255 unsigned long timeout = 15 * HZ;
256 struct mid_q_entry *midQ = NULL;
258 if (ses == NULL) {
259 cERROR(1,("Null smb session"));
260 return -EIO;
262 if(ses->server == NULL) {
263 cERROR(1,("Null tcp session"));
264 return -EIO;
266 if(pbytes_returned == NULL)
267 return -EIO;
268 else
269 *pbytes_returned = 0;
273 if(ses->server->tcpStatus == CIFS_EXITING)
274 return -ENOENT;
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;
297 /* can not count locking commands against total since
298 they are allowed to block on server */
300 if(long_op < 3) {
301 /* update # of requests on the wire to server */
302 atomic_inc(&ses->server->inFlight);
304 spin_unlock(&GlobalMid_Lock);
305 break;
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 */
313 down(&ses->server->tcpSem);
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 */
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);
338 return -ENOMEM;
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);
352 return -EIO;
355 /* BB can we sign efficiently in this path? */
356 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
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);
370 return rc;
371 } else
372 up(&ses->server->tcpSem);
373 cifs_out_label:
374 if(midQ)
375 DeleteMidQEntry(midQ);
377 if(long_op < 3) {
378 atomic_dec(&ses->server->inFlight);
379 wake_up(&ses->server->request_q);
382 return rc;
386 #endif /* CIFS_EXPERIMENTAL */
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)
393 int rc = 0;
394 unsigned int receive_len;
395 unsigned long timeout;
396 struct mid_q_entry *midQ;
398 if (ses == NULL) {
399 cERROR(1,("Null smb session"));
400 return -EIO;
402 if(ses->server == NULL) {
403 cERROR(1,("Null tcp session"));
404 return -EIO;
407 if(ses->server->tcpStatus == CifsExiting)
408 return -ENOENT;
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;
432 /* can not count locking commands against total since
433 they are allowed to block on server */
435 if(long_op < 3) {
436 /* update # of requests on the wire to server */
437 atomic_inc(&ses->server->inFlight);
439 spin_unlock(&GlobalMid_Lock);
440 break;
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 */
448 down(&ses->server->tcpSem);
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 */
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);
473 return -ENOMEM;
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);
487 return -EIO;
490 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
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);
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;
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)));
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;
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;
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);
570 return rc;
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 */
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);
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 */
600 *pbytes_returned = out_buf->smb_buf_length;
602 /* BB special case reconnect tid and uid here? */
603 rc = map_smb_to_linux_error(out_buf);
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? "));
616 cifs_no_response_exit:
617 DeleteMidQEntry(midQ);
619 if(long_op < 3) {
620 atomic_dec(&ses->server->inFlight);
621 wake_up(&ses->server->request_q);
624 return rc;
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);
634 return rc;