]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - fs/cifs/transport.c
Merge with rsync://rsync.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6.git
[mirror_ubuntu-bionic-kernel.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
31ca3bc3
SF
273 if(ses->server->tcpStatus == CIFS_EXITING)
274 return -ENOENT;
275
1da177e4
LT
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;
295 }
296
297 /* can not count locking commands against total since
298 they are allowed to block on server */
299
300 if(long_op < 3) {
301 /* update # of requests on the wire to server */
302 atomic_inc(&ses->server->inFlight);
303 }
304 spin_unlock(&GlobalMid_Lock);
305 break;
306 }
307 }
308 }
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 */
312
313 down(&ses->server->tcpSem);
314
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 */
329 }
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);
337 }
338 return -ENOMEM;
339 }
340
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);
351 }
352 return -EIO;
353 }
354
355 /* BB can we sign efficiently in this path? */
ad009ac9 356 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
1da177e4
LT
357
358 midQ->midState = MID_REQUEST_SUBMITTED;
275cde1a
SF
359/* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
360 piovec,
361 (struct sockaddr *) &(ses->server->addr.sockAddr));*/
1da177e4
LT
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);
369 }
370 return rc;
371 } else
372 up(&ses->server->tcpSem);
373cifs_out_label:
374 if(midQ)
375 DeleteMidQEntry(midQ);
376
377 if(long_op < 3) {
378 atomic_dec(&ses->server->inFlight);
379 wake_up(&ses->server->request_q);
380 }
381
382 return rc;
383}
384
385
386#endif /* CIFS_EXPERIMENTAL */
387
388int
389SendReceive(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)
392{
393 int rc = 0;
394 unsigned int receive_len;
395 unsigned long timeout;
396 struct mid_q_entry *midQ;
397
398 if (ses == NULL) {
399 cERROR(1,("Null smb session"));
400 return -EIO;
401 }
402 if(ses->server == NULL) {
403 cERROR(1,("Null tcp session"));
404 return -EIO;
405 }
406
31ca3bc3
SF
407 if(ses->server->tcpStatus == CifsExiting)
408 return -ENOENT;
409
1da177e4
LT
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) {
275cde1a
SF
419 if(atomic_read(&ses->server->inFlight) >=
420 cifs_max_pending){
1da177e4
LT
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;
430 }
431
432 /* can not count locking commands against total since
433 they are allowed to block on server */
434
435 if(long_op < 3) {
436 /* update # of requests on the wire to server */
437 atomic_inc(&ses->server->inFlight);
438 }
439 spin_unlock(&GlobalMid_Lock);
440 break;
441 }
442 }
443 }
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 */
447
448 down(&ses->server->tcpSem);
449
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 */
464 }
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);
472 }
473 return -ENOMEM;
474 }
475
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);
486 }
487 return -EIO;
488 }
489
ad009ac9 490 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
1da177e4
LT
491
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);
502 }
503 return rc;
504 } else
505 up(&ses->server->tcpSem);
506 if (long_op == -1)
507 goto cifs_no_response_exit;
275cde1a 508 else if (long_op == 2) /* writes past end of file can take loong time */
1da177e4
LT
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;
523 }
524
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)));
538 }
539
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;
552 }
553 }
554
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;
561 }
562 }
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);
569 }
570 return rc;
571 }
572
573 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
ad009ac9 574 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
1da177e4
LT
575 receive_len, xid));
576 rc = -EIO;
577 } else { /* rcvd frame is ok */
578
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);
585
586 dump_smb(out_buf, 92);
587 /* convert the length into a more usable form */
588 if((receive_len > 24) &&
ad009ac9
SF
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) {
275cde1a
SF
595 cERROR(1,("Unexpected SMB signature"));
596 /* BB FIXME add code to kill session */
ad009ac9 597 }
1da177e4
LT
598 }
599
600 *pbytes_returned = out_buf->smb_buf_length;
601
ad009ac9 602 /* BB special case reconnect tid and uid here? */
1da177e4
LT
603 rc = map_smb_to_linux_error(out_buf);
604
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? "));
614 }
615 }
616cifs_no_response_exit:
617 DeleteMidQEntry(midQ);
618
619 if(long_op < 3) {
620 atomic_dec(&ses->server->inFlight);
621 wake_up(&ses->server->request_q);
622 }
623
624 return rc;
625
626out_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);
632 }
633
634 return rc;
635}