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
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>
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
;
44 cERROR(1, ("Null session passed in to AllocMidQEntry"));
47 if (ses
->server
== NULL
) {
48 cERROR(1, ("Null TCP session in AllocMidQEntry"));
52 temp
= (struct mid_q_entry
*) mempool_alloc(cifs_mid_poolp
,SLAB_KERNEL
| SLAB_NOFS
);
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
);
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
);
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
);
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"));
97 temp
= (struct oplock_q_entry
*) kmem_cache_alloc(cifs_oplock_cachep
,
102 temp
->pinode
= pinode
;
105 spin_lock(&GlobalMid_Lock
);
106 list_add_tail(&temp
->qhead
, &GlobalOplock_Q
);
107 spin_unlock(&GlobalMid_Lock
);
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
)
128 struct msghdr smb_msg
;
130 unsigned len
= smb_buf_length
+ 4;
133 return -ENOTSOCK
; /* BB eventually add reconnect code here */
134 iov
.iov_base
= smb_buffer
;
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
);
153 rc
= kernel_sendmsg(ssocket
, &smb_msg
, &iov
, 1, len
);
154 if ((rc
== -ENOSPC
) || (rc
== -EAGAIN
)) {
158 ("sends on sock %p stuck for 30 seconds",
174 cERROR(1,("Error %d sending data on socket to server.", 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
)
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;
199 return -ENOTSOCK
; /* BB eventually add reconnect code here */
200 iov
.iov_base
= smb_buffer
;
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
);
219 rc
= kernel_sendmsg(ssocket
, &smb_msg
, &iov
, number_of_pages
,
221 if ((rc
== -ENOSPC
) || (rc
== -EAGAIN
)) {
225 ("sends on sock %p stuck for 30 seconds",
241 cERROR(1,("Error %d sending data on socket to server.", 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
)
255 unsigned long timeout
= 15 * HZ
;
256 struct mid_q_entry
*midQ
= NULL
;
259 cERROR(1,("Null smb session"));
262 if(ses
->server
== NULL
) {
263 cERROR(1,("Null tcp session"));
266 if(pbytes_returned
== NULL
)
269 *pbytes_returned
= 0;
273 if(ses
->server
->tcpStatus
== CIFS_EXITING
)
276 /* Ensure that we do not send more than 50 overlapping requests
277 to the same server. We may make this configurable later or
280 /* oplock breaks must not be held up */
281 atomic_inc(&ses
->server
->inFlight
);
283 spin_lock(&GlobalMid_Lock
);
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
)
290 spin_lock(&GlobalMid_Lock
);
292 if(ses
->server
->tcpStatus
== CifsExiting
) {
293 spin_unlock(&GlobalMid_Lock
);
297 /* can not count locking commands against total since
298 they are allowed to block on server */
301 /* update # of requests on the wire to server */
302 atomic_inc(&ses
->server
->inFlight
);
304 spin_unlock(&GlobalMid_Lock
);
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
313 down(&ses
->server
->tcpSem
);
315 if (ses
->server
->tcpStatus
== CifsExiting
) {
318 } else if (ses
->server
->tcpStatus
== CifsNeedReconnect
) {
319 cFYI(1,("tcp session dead - return to caller to retry"));
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
)) {
328 } /* else ok - we are setting up session */
330 midQ
= AllocMidQEntry(in_buf
, ses
);
332 up(&ses
->server
->tcpSem
);
333 /* If not lock req, update # of requests on wire to server */
335 atomic_dec(&ses
->server
->inFlight
);
336 wake_up(&ses
->server
->request_q
);
341 if (in_buf
->smb_buf_length
> CIFSMaxBufSize
+ MAX_CIFS_HDR_SIZE
- 4) {
342 up(&ses
->server
->tcpSem
);
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 */
349 atomic_dec(&ses
->server
->inFlight
);
350 wake_up(&ses
->server
->request_q
);
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,
361 (struct sockaddr *) &(ses->server->addr.sockAddr));*/
363 DeleteMidQEntry(midQ
);
364 up(&ses
->server
->tcpSem
);
365 /* If not lock req, update # of requests on wire to server */
367 atomic_dec(&ses
->server
->inFlight
);
368 wake_up(&ses
->server
->request_q
);
372 up(&ses
->server
->tcpSem
);
375 DeleteMidQEntry(midQ
);
378 atomic_dec(&ses
->server
->inFlight
);
379 wake_up(&ses
->server
->request_q
);
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
)
394 unsigned int receive_len
;
395 unsigned long timeout
;
396 struct mid_q_entry
*midQ
;
399 cERROR(1,("Null smb session"));
402 if(ses
->server
== NULL
) {
403 cERROR(1,("Null tcp session"));
407 if(ses
->server
->tcpStatus
== CifsExiting
)
410 /* Ensure that we do not send more than 50 overlapping requests
411 to the same server. We may make this configurable later or
414 /* oplock breaks must not be held up */
415 atomic_inc(&ses
->server
->inFlight
);
417 spin_lock(&GlobalMid_Lock
);
419 if(atomic_read(&ses
->server
->inFlight
) >=
421 spin_unlock(&GlobalMid_Lock
);
422 wait_event(ses
->server
->request_q
,
423 atomic_read(&ses
->server
->inFlight
)
425 spin_lock(&GlobalMid_Lock
);
427 if(ses
->server
->tcpStatus
== CifsExiting
) {
428 spin_unlock(&GlobalMid_Lock
);
432 /* can not count locking commands against total since
433 they are allowed to block on server */
436 /* update # of requests on the wire to server */
437 atomic_inc(&ses
->server
->inFlight
);
439 spin_unlock(&GlobalMid_Lock
);
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
448 down(&ses
->server
->tcpSem
);
450 if (ses
->server
->tcpStatus
== CifsExiting
) {
453 } else if (ses
->server
->tcpStatus
== CifsNeedReconnect
) {
454 cFYI(1,("tcp session dead - return to caller to retry"));
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
)) {
463 } /* else ok - we are setting up session */
465 midQ
= AllocMidQEntry(in_buf
, ses
);
467 up(&ses
->server
->tcpSem
);
468 /* If not lock req, update # of requests on wire to server */
470 atomic_dec(&ses
->server
->inFlight
);
471 wake_up(&ses
->server
->request_q
);
476 if (in_buf
->smb_buf_length
> CIFSMaxBufSize
+ MAX_CIFS_HDR_SIZE
- 4) {
477 up(&ses
->server
->tcpSem
);
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 */
484 atomic_dec(&ses
->server
->inFlight
);
485 wake_up(&ses
->server
->request_q
);
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
));
496 DeleteMidQEntry(midQ
);
497 up(&ses
->server
->tcpSem
);
498 /* If not lock req, update # of requests on wire to server */
500 atomic_dec(&ses
->server
->inFlight
);
501 wake_up(&ses
->server
->request_q
);
505 up(&ses
->server
->tcpSem
);
507 goto cifs_no_response_exit
;
508 else if (long_op
== 2) /* writes past end of file can take loong time */
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
;
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 */
525 /* No user interrupts in wait - wreaks havoc with performance */
526 if(timeout
!= MAX_SCHEDULE_TIMEOUT
) {
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
)));
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
);
545 cERROR(1,("No response buffer"));
546 if(midQ
->midState
== MID_REQUEST_SUBMITTED
) {
547 if(ses
->server
->tcpStatus
== CifsExiting
)
550 ses
->server
->tcpStatus
= CifsNeedReconnect
;
551 midQ
->midState
= MID_RETRY_NEEDED
;
555 if (rc
!= -EHOSTDOWN
) {
556 if(midQ
->midState
== MID_RETRY_NEEDED
) {
558 cFYI(1,("marking request for retry"));
563 spin_unlock(&GlobalMid_Lock
);
564 DeleteMidQEntry(midQ
);
565 /* If not lock req, update # of requests on wire to server */
567 atomic_dec(&ses
->server
->inFlight
);
568 wake_up(&ses
->server
->request_q
);
573 if (receive_len
> CIFSMaxBufSize
+ MAX_CIFS_HDR_SIZE
) {
574 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
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,
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);
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 */
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
));
613 cFYI(1,("Bad MID state? "));
616 cifs_no_response_exit
:
617 DeleteMidQEntry(midQ
);
620 atomic_dec(&ses
->server
->inFlight
);
621 wake_up(&ses
->server
->request_q
);
627 up(&ses
->server
->tcpSem
);
628 /* If not lock req, update # of requests on wire to server */
630 atomic_dec(&ses
->server
->inFlight
);
631 wake_up(&ses
->server
->request_q
);