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