]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/cifs/transport.c
[PATCH] cifs: handle termination of cifs oplockd kernel thread
[net-next-2.6.git] / fs / cifs / transport.c
CommitLineData
1da177e4
LT
1/*
2 * fs/cifs/transport.c
3 *
b8643e1b 4 * Copyright (C) International Business Machines Corp., 2002,2005
1da177e4
LT
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
35extern mempool_t *cifs_mid_poolp;
36extern kmem_cache_t *cifs_oplock_cachep;
37
38static struct mid_q_entry *
39AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
40{
41 struct mid_q_entry *temp;
42
43 if (ses == NULL) {
275cde1a 44 cERROR(1, ("Null session passed in to AllocMidQEntry"));
1da177e4
LT
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
74static void
75DeleteMidQEntry(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);
b8643e1b
SF
82 if(midEntry->largeBuf)
83 cifs_buf_release(midEntry->resp_buf);
84 else
85 cifs_small_buf_release(midEntry->resp_buf);
1da177e4
LT
86 mempool_free(midEntry, cifs_mid_poolp);
87}
88
89struct oplock_q_entry *
90AllocOplockQEntry(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
113void 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
122int
123smb_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
186int
187smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
275cde1a
SF
188 unsigned int smb_buf_length, struct kvec * write_vector
189 /* page list */, struct sockaddr *sin)
1da177e4
LT
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));
1da177e4
LT
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) {
275cde1a
SF
219 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages,
220 len);
1da177e4
LT
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
250int
251CIFSSendRcv(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? */
ad009ac9 353 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
1da177e4
LT
354
355 midQ->midState = MID_REQUEST_SUBMITTED;
275cde1a
SF
356/* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
357 piovec,
358 (struct sockaddr *) &(ses->server->addr.sockAddr));*/
1da177e4
LT
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);
370cifs_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
385int
386SendReceive(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) {
275cde1a
SF
413 if(atomic_read(&ses->server->inFlight) >=
414 cifs_max_pending){
1da177e4
LT
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
ad009ac9 484 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
1da177e4
LT
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;
275cde1a 502 else if (long_op == 2) /* writes past end of file can take loong time */
1da177e4
LT
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) {
ad009ac9 568 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
1da177e4
LT
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) &&
ad009ac9
SF
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) {
275cde1a
SF
589 cERROR(1,("Unexpected SMB signature"));
590 /* BB FIXME add code to kill session */
ad009ac9 591 }
1da177e4
LT
592 }
593
594 *pbytes_returned = out_buf->smb_buf_length;
595
ad009ac9 596 /* BB special case reconnect tid and uid here? */
1da177e4
LT
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 }
610cifs_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
620out_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}