Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[GitHub/mt8127/android_kernel_alcatel_ttab.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
d6e04ae6
SF
52 temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
53 SLAB_KERNEL | SLAB_NOFS);
1da177e4
LT
54 if (temp == NULL)
55 return temp;
56 else {
57 memset(temp, 0, sizeof (struct mid_q_entry));
58 temp->mid = smb_buffer->Mid; /* always LE */
59 temp->pid = current->pid;
60 temp->command = smb_buffer->Command;
61 cFYI(1, ("For smb_command %d", temp->command));
1047abc1
SF
62 /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
63 /* when mid allocated can be before when sent */
64 temp->when_alloc = jiffies;
1da177e4
LT
65 temp->ses = ses;
66 temp->tsk = current;
67 }
68
69 spin_lock(&GlobalMid_Lock);
70 list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
71 atomic_inc(&midCount);
72 temp->midState = MID_REQUEST_ALLOCATED;
73 spin_unlock(&GlobalMid_Lock);
74 return temp;
75}
76
77static void
78DeleteMidQEntry(struct mid_q_entry *midEntry)
79{
1047abc1
SF
80#ifdef CONFIG_CIFS_STATS2
81 unsigned long now;
82#endif
1da177e4
LT
83 spin_lock(&GlobalMid_Lock);
84 midEntry->midState = MID_FREE;
85 list_del(&midEntry->qhead);
86 atomic_dec(&midCount);
87 spin_unlock(&GlobalMid_Lock);
b8643e1b
SF
88 if(midEntry->largeBuf)
89 cifs_buf_release(midEntry->resp_buf);
90 else
91 cifs_small_buf_release(midEntry->resp_buf);
1047abc1
SF
92#ifdef CONFIG_CIFS_STATS2
93 now = jiffies;
94 /* commands taking longer than one second are indications that
95 something is wrong, unless it is quite a slow link or server */
96 if((now - midEntry->when_alloc) > HZ) {
97 if((cifsFYI & CIFS_TIMER) &&
98 (midEntry->command != SMB_COM_LOCKING_ANDX)) {
99 printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
100 midEntry->command, midEntry->mid);
101 printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
102 now - midEntry->when_alloc,
103 now - midEntry->when_sent,
104 now - midEntry->when_received);
105 }
106 }
107#endif
1da177e4
LT
108 mempool_free(midEntry, cifs_mid_poolp);
109}
110
111struct oplock_q_entry *
112AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
113{
114 struct oplock_q_entry *temp;
115 if ((pinode== NULL) || (tcon == NULL)) {
116 cERROR(1, ("Null parms passed to AllocOplockQEntry"));
117 return NULL;
118 }
119 temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
120 SLAB_KERNEL);
121 if (temp == NULL)
122 return temp;
123 else {
124 temp->pinode = pinode;
125 temp->tcon = tcon;
126 temp->netfid = fid;
127 spin_lock(&GlobalMid_Lock);
128 list_add_tail(&temp->qhead, &GlobalOplock_Q);
129 spin_unlock(&GlobalMid_Lock);
130 }
131 return temp;
132
133}
134
135void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry)
136{
137 spin_lock(&GlobalMid_Lock);
138 /* should we check if list empty first? */
139 list_del(&oplockEntry->qhead);
140 spin_unlock(&GlobalMid_Lock);
141 kmem_cache_free(cifs_oplock_cachep, oplockEntry);
142}
143
144int
145smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
146 unsigned int smb_buf_length, struct sockaddr *sin)
147{
148 int rc = 0;
149 int i = 0;
150 struct msghdr smb_msg;
151 struct kvec iov;
152 unsigned len = smb_buf_length + 4;
153
154 if(ssocket == NULL)
155 return -ENOTSOCK; /* BB eventually add reconnect code here */
156 iov.iov_base = smb_buffer;
157 iov.iov_len = len;
158
159 smb_msg.msg_name = sin;
160 smb_msg.msg_namelen = sizeof (struct sockaddr);
161 smb_msg.msg_control = NULL;
162 smb_msg.msg_controllen = 0;
163 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
164
165 /* smb header is converted in header_assemble. bcc and rest of SMB word
166 area, and byte area if necessary, is converted to littleendian in
167 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
168 Flags2 is converted in SendReceive */
169
170 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
3e84469d 171 cFYI(1, ("Sending smb of length %d", smb_buf_length));
1da177e4
LT
172 dump_smb(smb_buffer, len);
173
174 while (len > 0) {
175 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
176 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
177 i++;
3e84469d
SF
178 /* smaller timeout here than send2 since smaller size */
179 /* Although it may not be required, this also is smaller
180 oplock break time */
68058e75 181 if(i > 12) {
1da177e4 182 cERROR(1,
68058e75 183 ("sends on sock %p stuck for 7 seconds",
1da177e4
LT
184 ssocket));
185 rc = -EAGAIN;
186 break;
187 }
68058e75 188 msleep(1 << i);
1da177e4
LT
189 continue;
190 }
191 if (rc < 0)
192 break;
5e1253b5
SF
193 else
194 i = 0; /* reset i after each successful send */
1da177e4
LT
195 iov.iov_base += rc;
196 iov.iov_len -= rc;
197 len -= rc;
198 }
199
200 if (rc < 0) {
3e84469d 201 cERROR(1,("Error %d sending data on socket to server", rc));
1da177e4
LT
202 } else {
203 rc = 0;
204 }
205
206 return rc;
207}
208
d6e04ae6 209static int
3e84469d
SF
210smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
211 struct sockaddr *sin)
1da177e4
LT
212{
213 int rc = 0;
214 int i = 0;
215 struct msghdr smb_msg;
3e84469d
SF
216 struct smb_hdr *smb_buffer = iov[0].iov_base;
217 unsigned int len = iov[0].iov_len;
218 unsigned int total_len;
219 int first_vec = 0;
d6e04ae6 220
1da177e4
LT
221 if(ssocket == NULL)
222 return -ENOTSOCK; /* BB eventually add reconnect code here */
3e84469d 223
1da177e4
LT
224 smb_msg.msg_name = sin;
225 smb_msg.msg_namelen = sizeof (struct sockaddr);
226 smb_msg.msg_control = NULL;
227 smb_msg.msg_controllen = 0;
228 smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
229
230 /* smb header is converted in header_assemble. bcc and rest of SMB word
231 area, and byte area if necessary, is converted to littleendian in
232 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
233 Flags2 is converted in SendReceive */
234
3e84469d
SF
235
236 total_len = 0;
237 for (i = 0; i < n_vec; i++)
238 total_len += iov[i].iov_len;
239
1da177e4 240 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
3e84469d 241 cFYI(1, ("Sending smb: total_len %d", total_len));
1da177e4
LT
242 dump_smb(smb_buffer, len);
243
3e84469d
SF
244 while (total_len) {
245 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
246 n_vec - first_vec, total_len);
1da177e4
LT
247 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
248 i++;
68058e75 249 if(i >= 14) {
1da177e4 250 cERROR(1,
68058e75 251 ("sends on sock %p stuck for 15 seconds",
1da177e4
LT
252 ssocket));
253 rc = -EAGAIN;
254 break;
255 }
68058e75 256 msleep(1 << i);
1da177e4
LT
257 continue;
258 }
259 if (rc < 0)
260 break;
3e84469d
SF
261
262 if (rc >= total_len) {
263 WARN_ON(rc > total_len);
264 break;
265 }
266 if(rc == 0) {
267 /* should never happen, letting socket clear before
268 retrying is our only obvious option here */
04c08816 269 cERROR(1,("tcp sent no data"));
3e84469d
SF
270 msleep(500);
271 continue;
d6e04ae6 272 }
3e84469d 273 total_len -= rc;
68058e75 274 /* the line below resets i */
3e84469d
SF
275 for (i = first_vec; i < n_vec; i++) {
276 if (iov[i].iov_len) {
277 if (rc > iov[i].iov_len) {
278 rc -= iov[i].iov_len;
279 iov[i].iov_len = 0;
280 } else {
281 iov[i].iov_base += rc;
282 iov[i].iov_len -= rc;
283 first_vec = i;
284 break;
285 }
286 }
d6e04ae6 287 }
5e1253b5 288 i = 0; /* in case we get ENOSPC on the next send */
1da177e4
LT
289 }
290
291 if (rc < 0) {
3e84469d
SF
292 cERROR(1,("Error %d sending data on socket to server", rc));
293 } else
1da177e4 294 rc = 0;
1da177e4
LT
295
296 return rc;
297}
298
1da177e4 299int
d6e04ae6 300SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
3e84469d
SF
301 struct kvec *iov, int n_vec, int *pbytes_returned,
302 const int long_op)
1da177e4
LT
303{
304 int rc = 0;
d6e04ae6
SF
305 unsigned int receive_len;
306 unsigned long timeout;
307 struct mid_q_entry *midQ;
3e84469d 308 struct smb_hdr *in_buf = iov[0].iov_base;
1da177e4
LT
309
310 if (ses == NULL) {
311 cERROR(1,("Null smb session"));
312 return -EIO;
313 }
314 if(ses->server == NULL) {
315 cERROR(1,("Null tcp session"));
316 return -EIO;
317 }
1da177e4 318
d6e04ae6 319 if(ses->server->tcpStatus == CifsExiting)
31ca3bc3
SF
320 return -ENOENT;
321
1da177e4
LT
322 /* Ensure that we do not send more than 50 overlapping requests
323 to the same server. We may make this configurable later or
324 use ses->maxReq */
325 if(long_op == -1) {
326 /* oplock breaks must not be held up */
327 atomic_inc(&ses->server->inFlight);
328 } else {
329 spin_lock(&GlobalMid_Lock);
330 while(1) {
d6e04ae6
SF
331 if(atomic_read(&ses->server->inFlight) >=
332 cifs_max_pending){
1da177e4 333 spin_unlock(&GlobalMid_Lock);
131afd0b
SF
334#ifdef CONFIG_CIFS_STATS2
335 atomic_inc(&ses->server->num_waiters);
336#endif
1da177e4
LT
337 wait_event(ses->server->request_q,
338 atomic_read(&ses->server->inFlight)
339 < cifs_max_pending);
131afd0b
SF
340#ifdef CONFIG_CIFS_STATS2
341 atomic_dec(&ses->server->num_waiters);
342#endif
1da177e4
LT
343 spin_lock(&GlobalMid_Lock);
344 } else {
345 if(ses->server->tcpStatus == CifsExiting) {
346 spin_unlock(&GlobalMid_Lock);
347 return -ENOENT;
348 }
349
350 /* can not count locking commands against total since
351 they are allowed to block on server */
352
353 if(long_op < 3) {
354 /* update # of requests on the wire to server */
355 atomic_inc(&ses->server->inFlight);
356 }
357 spin_unlock(&GlobalMid_Lock);
358 break;
359 }
360 }
361 }
362 /* make sure that we sign in the same order that we send on this socket
363 and avoid races inside tcp sendmsg code that could cause corruption
364 of smb data */
365
366 down(&ses->server->tcpSem);
367
368 if (ses->server->tcpStatus == CifsExiting) {
369 rc = -ENOENT;
d6e04ae6 370 goto out_unlock2;
1da177e4
LT
371 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
372 cFYI(1,("tcp session dead - return to caller to retry"));
373 rc = -EAGAIN;
d6e04ae6 374 goto out_unlock2;
1da177e4
LT
375 } else if (ses->status != CifsGood) {
376 /* check if SMB session is bad because we are setting it up */
377 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
378 (in_buf->Command != SMB_COM_NEGOTIATE)) {
379 rc = -EAGAIN;
d6e04ae6 380 goto out_unlock2;
1da177e4
LT
381 } /* else ok - we are setting up session */
382 }
383 midQ = AllocMidQEntry(in_buf, ses);
384 if (midQ == NULL) {
385 up(&ses->server->tcpSem);
386 /* If not lock req, update # of requests on wire to server */
387 if(long_op < 3) {
388 atomic_dec(&ses->server->inFlight);
389 wake_up(&ses->server->request_q);
390 }
391 return -ENOMEM;
392 }
393
84afc29b 394 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
1da177e4
LT
395
396 midQ->midState = MID_REQUEST_SUBMITTED;
131afd0b
SF
397#ifdef CONFIG_CIFS_STATS2
398 atomic_inc(&ses->server->inSend);
399#endif
3e84469d 400 rc = smb_send2(ses->server->ssocket, iov, n_vec,
d6e04ae6 401 (struct sockaddr *) &(ses->server->addr.sockAddr));
131afd0b
SF
402#ifdef CONFIG_CIFS_STATS2
403 atomic_dec(&ses->server->inSend);
1047abc1 404 midQ->when_sent = jiffies;
131afd0b 405#endif
1da177e4
LT
406 if(rc < 0) {
407 DeleteMidQEntry(midQ);
408 up(&ses->server->tcpSem);
409 /* If not lock req, update # of requests on wire to server */
410 if(long_op < 3) {
411 atomic_dec(&ses->server->inFlight);
412 wake_up(&ses->server->request_q);
413 }
414 return rc;
415 } else
416 up(&ses->server->tcpSem);
d6e04ae6
SF
417 if (long_op == -1)
418 goto cifs_no_response_exit2;
419 else if (long_op == 2) /* writes past end of file can take loong time */
37c0eb46 420 timeout = 180 * HZ;
d6e04ae6
SF
421 else if (long_op == 1)
422 timeout = 45 * HZ; /* should be greater than
423 servers oplock break timeout (about 43 seconds) */
424 else if (long_op > 2) {
425 timeout = MAX_SCHEDULE_TIMEOUT;
426 } else
427 timeout = 15 * HZ;
428 /* wait for 15 seconds or until woken up due to response arriving or
429 due to last connection to this server being unmounted */
430 if (signal_pending(current)) {
431 /* if signal pending do not hold up user for full smb timeout
432 but we still give response a change to complete */
433 timeout = 2 * HZ;
434 }
435
436 /* No user interrupts in wait - wreaks havoc with performance */
437 if(timeout != MAX_SCHEDULE_TIMEOUT) {
438 timeout += jiffies;
439 wait_event(ses->server->response_q,
440 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
441 time_after(jiffies, timeout) ||
442 ((ses->server->tcpStatus != CifsGood) &&
443 (ses->server->tcpStatus != CifsNew)));
444 } else {
445 wait_event(ses->server->response_q,
446 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
447 ((ses->server->tcpStatus != CifsGood) &&
448 (ses->server->tcpStatus != CifsNew)));
449 }
450
451 spin_lock(&GlobalMid_Lock);
452 if (midQ->resp_buf) {
453 spin_unlock(&GlobalMid_Lock);
70ca734a 454 receive_len = midQ->resp_buf->smb_buf_length;
d6e04ae6 455 } else {
37c0eb46
SF
456 cERROR(1,("No response to cmd %d mid %d",
457 midQ->command, midQ->mid));
d6e04ae6
SF
458 if(midQ->midState == MID_REQUEST_SUBMITTED) {
459 if(ses->server->tcpStatus == CifsExiting)
460 rc = -EHOSTDOWN;
461 else {
462 ses->server->tcpStatus = CifsNeedReconnect;
463 midQ->midState = MID_RETRY_NEEDED;
464 }
465 }
466
467 if (rc != -EHOSTDOWN) {
468 if(midQ->midState == MID_RETRY_NEEDED) {
469 rc = -EAGAIN;
470 cFYI(1,("marking request for retry"));
471 } else {
472 rc = -EIO;
473 }
474 }
475 spin_unlock(&GlobalMid_Lock);
476 DeleteMidQEntry(midQ);
477 /* If not lock req, update # of requests on wire to server */
478 if(long_op < 3) {
479 atomic_dec(&ses->server->inFlight);
480 wake_up(&ses->server->request_q);
481 }
482 return rc;
483 }
484
485 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
486 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
487 receive_len, xid));
488 rc = -EIO;
489 } else { /* rcvd frame is ok */
490
491 if (midQ->resp_buf &&
492 (midQ->midState == MID_RESPONSE_RECEIVED)) {
84afc29b 493
d6e04ae6 494 in_buf->smb_buf_length = receive_len;
84afc29b
SF
495 if(receive_len > 500) {
496 /* use multiple buffers on way out */
497 } else {
498 memcpy((char *)in_buf + 4,
499 (char *)midQ->resp_buf + 4,
500 receive_len);
501 iov[0].iov_len = receive_len + 4;
502 iov[1].iov_len = 0;
503 }
d6e04ae6
SF
504
505 dump_smb(in_buf, 80);
506 /* convert the length into a more usable form */
507 if((receive_len > 24) &&
508 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
509 SECMODE_SIGN_ENABLED))) {
510 rc = cifs_verify_signature(in_buf,
511 ses->server->mac_signing_key,
512 midQ->sequence_number+1);
513 if(rc) {
514 cERROR(1,("Unexpected SMB signature"));
515 /* BB FIXME add code to kill session */
516 }
517 }
518
519 *pbytes_returned = in_buf->smb_buf_length;
520
521 /* BB special case reconnect tid and uid here? */
6ab16d24 522 /* BB special case Errbadpassword and pwdexpired here */
d6e04ae6
SF
523 rc = map_smb_to_linux_error(in_buf);
524
525 /* convert ByteCount if necessary */
526 if (receive_len >=
527 sizeof (struct smb_hdr) -
528 4 /* do not count RFC1001 header */ +
529 (2 * in_buf->WordCount) + 2 /* bcc */ )
0f2b27c4 530 BCC(in_buf) = le16_to_cpu(BCC_LE(in_buf));
d6e04ae6
SF
531 } else {
532 rc = -EIO;
ab2f218f 533 cFYI(1,("Bad MID state?"));
d6e04ae6
SF
534 }
535 }
536cifs_no_response_exit2:
537 DeleteMidQEntry(midQ);
538
1da177e4 539 if(long_op < 3) {
d6e04ae6 540 atomic_dec(&ses->server->inFlight);
1da177e4
LT
541 wake_up(&ses->server->request_q);
542 }
543
544 return rc;
1da177e4 545
d6e04ae6
SF
546out_unlock2:
547 up(&ses->server->tcpSem);
548 /* If not lock req, update # of requests on wire to server */
549 if(long_op < 3) {
550 atomic_dec(&ses->server->inFlight);
551 wake_up(&ses->server->request_q);
552 }
1da177e4 553
d6e04ae6
SF
554 return rc;
555}
1da177e4
LT
556
557int
558SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
559 struct smb_hdr *in_buf, struct smb_hdr *out_buf,
560 int *pbytes_returned, const int long_op)
561{
562 int rc = 0;
563 unsigned int receive_len;
564 unsigned long timeout;
565 struct mid_q_entry *midQ;
566
567 if (ses == NULL) {
568 cERROR(1,("Null smb session"));
569 return -EIO;
570 }
571 if(ses->server == NULL) {
572 cERROR(1,("Null tcp session"));
573 return -EIO;
574 }
575
31ca3bc3
SF
576 if(ses->server->tcpStatus == CifsExiting)
577 return -ENOENT;
578
1da177e4
LT
579 /* Ensure that we do not send more than 50 overlapping requests
580 to the same server. We may make this configurable later or
581 use ses->maxReq */
582 if(long_op == -1) {
583 /* oplock breaks must not be held up */
584 atomic_inc(&ses->server->inFlight);
585 } else {
586 spin_lock(&GlobalMid_Lock);
587 while(1) {
275cde1a
SF
588 if(atomic_read(&ses->server->inFlight) >=
589 cifs_max_pending){
1da177e4 590 spin_unlock(&GlobalMid_Lock);
131afd0b
SF
591#ifdef CONFIG_CIFS_STATS2
592 atomic_inc(&ses->server->num_waiters);
593#endif
1da177e4
LT
594 wait_event(ses->server->request_q,
595 atomic_read(&ses->server->inFlight)
596 < cifs_max_pending);
131afd0b
SF
597#ifdef CONFIG_CIFS_STATS2
598 atomic_dec(&ses->server->num_waiters);
599#endif
1da177e4
LT
600 spin_lock(&GlobalMid_Lock);
601 } else {
602 if(ses->server->tcpStatus == CifsExiting) {
603 spin_unlock(&GlobalMid_Lock);
604 return -ENOENT;
605 }
606
607 /* can not count locking commands against total since
608 they are allowed to block on server */
609
610 if(long_op < 3) {
611 /* update # of requests on the wire to server */
612 atomic_inc(&ses->server->inFlight);
613 }
614 spin_unlock(&GlobalMid_Lock);
615 break;
616 }
617 }
618 }
619 /* make sure that we sign in the same order that we send on this socket
620 and avoid races inside tcp sendmsg code that could cause corruption
621 of smb data */
622
623 down(&ses->server->tcpSem);
624
625 if (ses->server->tcpStatus == CifsExiting) {
626 rc = -ENOENT;
627 goto out_unlock;
628 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
629 cFYI(1,("tcp session dead - return to caller to retry"));
630 rc = -EAGAIN;
631 goto out_unlock;
632 } else if (ses->status != CifsGood) {
633 /* check if SMB session is bad because we are setting it up */
634 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
635 (in_buf->Command != SMB_COM_NEGOTIATE)) {
636 rc = -EAGAIN;
637 goto out_unlock;
638 } /* else ok - we are setting up session */
639 }
640 midQ = AllocMidQEntry(in_buf, ses);
641 if (midQ == NULL) {
642 up(&ses->server->tcpSem);
643 /* If not lock req, update # of requests on wire to server */
644 if(long_op < 3) {
645 atomic_dec(&ses->server->inFlight);
646 wake_up(&ses->server->request_q);
647 }
648 return -ENOMEM;
649 }
650
651 if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
652 up(&ses->server->tcpSem);
653 cERROR(1,
654 ("Illegal length, greater than maximum frame, %d ",
655 in_buf->smb_buf_length));
656 DeleteMidQEntry(midQ);
657 /* If not lock req, update # of requests on wire to server */
658 if(long_op < 3) {
659 atomic_dec(&ses->server->inFlight);
660 wake_up(&ses->server->request_q);
661 }
662 return -EIO;
663 }
664
ad009ac9 665 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
1da177e4
LT
666
667 midQ->midState = MID_REQUEST_SUBMITTED;
131afd0b
SF
668#ifdef CONFIG_CIFS_STATS2
669 atomic_inc(&ses->server->inSend);
670#endif
1da177e4
LT
671 rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
672 (struct sockaddr *) &(ses->server->addr.sockAddr));
131afd0b
SF
673#ifdef CONFIG_CIFS_STATS2
674 atomic_dec(&ses->server->inSend);
1047abc1 675 midQ->when_sent = jiffies;
131afd0b 676#endif
1da177e4
LT
677 if(rc < 0) {
678 DeleteMidQEntry(midQ);
679 up(&ses->server->tcpSem);
680 /* If not lock req, update # of requests on wire to server */
681 if(long_op < 3) {
682 atomic_dec(&ses->server->inFlight);
683 wake_up(&ses->server->request_q);
684 }
685 return rc;
686 } else
687 up(&ses->server->tcpSem);
688 if (long_op == -1)
689 goto cifs_no_response_exit;
275cde1a 690 else if (long_op == 2) /* writes past end of file can take loong time */
37c0eb46 691 timeout = 180 * HZ;
1da177e4
LT
692 else if (long_op == 1)
693 timeout = 45 * HZ; /* should be greater than
694 servers oplock break timeout (about 43 seconds) */
695 else if (long_op > 2) {
696 timeout = MAX_SCHEDULE_TIMEOUT;
697 } else
698 timeout = 15 * HZ;
699 /* wait for 15 seconds or until woken up due to response arriving or
700 due to last connection to this server being unmounted */
701 if (signal_pending(current)) {
702 /* if signal pending do not hold up user for full smb timeout
703 but we still give response a change to complete */
704 timeout = 2 * HZ;
705 }
706
707 /* No user interrupts in wait - wreaks havoc with performance */
708 if(timeout != MAX_SCHEDULE_TIMEOUT) {
709 timeout += jiffies;
710 wait_event(ses->server->response_q,
711 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
712 time_after(jiffies, timeout) ||
713 ((ses->server->tcpStatus != CifsGood) &&
714 (ses->server->tcpStatus != CifsNew)));
715 } else {
716 wait_event(ses->server->response_q,
717 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
718 ((ses->server->tcpStatus != CifsGood) &&
719 (ses->server->tcpStatus != CifsNew)));
720 }
721
722 spin_lock(&GlobalMid_Lock);
723 if (midQ->resp_buf) {
724 spin_unlock(&GlobalMid_Lock);
70ca734a 725 receive_len = midQ->resp_buf->smb_buf_length;
1da177e4 726 } else {
37c0eb46
SF
727 cERROR(1,("No response for cmd %d mid %d",
728 midQ->command, midQ->mid));
1da177e4
LT
729 if(midQ->midState == MID_REQUEST_SUBMITTED) {
730 if(ses->server->tcpStatus == CifsExiting)
731 rc = -EHOSTDOWN;
732 else {
733 ses->server->tcpStatus = CifsNeedReconnect;
734 midQ->midState = MID_RETRY_NEEDED;
735 }
736 }
737
738 if (rc != -EHOSTDOWN) {
739 if(midQ->midState == MID_RETRY_NEEDED) {
740 rc = -EAGAIN;
741 cFYI(1,("marking request for retry"));
742 } else {
743 rc = -EIO;
744 }
745 }
746 spin_unlock(&GlobalMid_Lock);
747 DeleteMidQEntry(midQ);
748 /* If not lock req, update # of requests on wire to server */
749 if(long_op < 3) {
750 atomic_dec(&ses->server->inFlight);
751 wake_up(&ses->server->request_q);
752 }
753 return rc;
754 }
755
756 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
ad009ac9 757 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
1da177e4
LT
758 receive_len, xid));
759 rc = -EIO;
760 } else { /* rcvd frame is ok */
761
762 if (midQ->resp_buf && out_buf
763 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
764 out_buf->smb_buf_length = receive_len;
765 memcpy((char *)out_buf + 4,
766 (char *)midQ->resp_buf + 4,
767 receive_len);
768
769 dump_smb(out_buf, 92);
770 /* convert the length into a more usable form */
771 if((receive_len > 24) &&
ad009ac9
SF
772 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
773 SECMODE_SIGN_ENABLED))) {
774 rc = cifs_verify_signature(out_buf,
775 ses->server->mac_signing_key,
776 midQ->sequence_number+1);
777 if(rc) {
275cde1a
SF
778 cERROR(1,("Unexpected SMB signature"));
779 /* BB FIXME add code to kill session */
ad009ac9 780 }
1da177e4
LT
781 }
782
783 *pbytes_returned = out_buf->smb_buf_length;
784
ad009ac9 785 /* BB special case reconnect tid and uid here? */
1da177e4
LT
786 rc = map_smb_to_linux_error(out_buf);
787
788 /* convert ByteCount if necessary */
789 if (receive_len >=
790 sizeof (struct smb_hdr) -
791 4 /* do not count RFC1001 header */ +
792 (2 * out_buf->WordCount) + 2 /* bcc */ )
0f2b27c4 793 BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1da177e4
LT
794 } else {
795 rc = -EIO;
a5a2b489 796 cERROR(1,("Bad MID state? "));
1da177e4
LT
797 }
798 }
799cifs_no_response_exit:
800 DeleteMidQEntry(midQ);
801
802 if(long_op < 3) {
803 atomic_dec(&ses->server->inFlight);
804 wake_up(&ses->server->request_q);
805 }
806
807 return rc;
808
809out_unlock:
810 up(&ses->server->tcpSem);
811 /* If not lock req, update # of requests on wire to server */
812 if(long_op < 3) {
813 atomic_dec(&ses->server->inFlight);
814 wake_up(&ses->server->request_q);
815 }
816
817 return rc;
818}