diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-28 13:43:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-28 13:43:32 -0400 |
commit | dabcbb1bae0f55378060b285062b20f6ec648c6a (patch) | |
tree | 027cdd35ce43cce95a78afab22e1e809b436b636 /fs/cifs/connect.c | |
parent | 5619a693965b291315685bdfe01a0246ebd7e41e (diff) | |
parent | e0c8ea1a69410ef44043646938a6a4175f5307e4 (diff) |
Merge branch '3.2-without-smb2' of git://git.samba.org/sfrench/cifs-2.6
* '3.2-without-smb2' of git://git.samba.org/sfrench/cifs-2.6: (52 commits)
Fix build break when freezer not configured
Add definition for share encryption
CIFS: Make cifs_push_locks send as many locks at once as possible
CIFS: Send as many mandatory unlock ranges at once as possible
CIFS: Implement caching mechanism for posix brlocks
CIFS: Implement caching mechanism for mandatory brlocks
CIFS: Fix DFS handling in cifs_get_file_info
CIFS: Fix error handling in cifs_readv_complete
[CIFS] Fixup trivial checkpatch warning
[CIFS] Show nostrictsync and noperm mount options in /proc/mounts
cifs, freezer: add wait_event_freezekillable and have cifs use it
cifs: allow cifs_max_pending to be readable under /sys/module/cifs/parameters
cifs: tune bdi.ra_pages in accordance with the rsize
cifs: allow for larger rsize= options and change defaults
cifs: convert cifs_readpages to use async reads
cifs: add cifs_async_readv
cifs: fix protocol definition for READ_RSP
cifs: add a callback function to receive the rest of the frame
cifs: break out 3rd receive phase into separate function
cifs: find mid earlier in receive codepath
...
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r-- | fs/cifs/connect.c | 697 |
1 files changed, 424 insertions, 273 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 62abf9fd6ff0..d545a95c30ed 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -181,7 +181,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
181 | -EINVAL = invalid transact2 | 181 | -EINVAL = invalid transact2 |
182 | 182 | ||
183 | */ | 183 | */ |
184 | static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize) | 184 | static int check2ndT2(struct smb_hdr *pSMB) |
185 | { | 185 | { |
186 | struct smb_t2_rsp *pSMBt; | 186 | struct smb_t2_rsp *pSMBt; |
187 | int remaining; | 187 | int remaining; |
@@ -214,9 +214,9 @@ static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize) | |||
214 | 214 | ||
215 | cFYI(1, "missing %d bytes from transact2, check next response", | 215 | cFYI(1, "missing %d bytes from transact2, check next response", |
216 | remaining); | 216 | remaining); |
217 | if (total_data_size > maxBufSize) { | 217 | if (total_data_size > CIFSMaxBufSize) { |
218 | cERROR(1, "TotalDataSize %d is over maximum buffer %d", | 218 | cERROR(1, "TotalDataSize %d is over maximum buffer %d", |
219 | total_data_size, maxBufSize); | 219 | total_data_size, CIFSMaxBufSize); |
220 | return -EINVAL; | 220 | return -EINVAL; |
221 | } | 221 | } |
222 | return remaining; | 222 | return remaining; |
@@ -320,27 +320,24 @@ requeue_echo: | |||
320 | } | 320 | } |
321 | 321 | ||
322 | static bool | 322 | static bool |
323 | allocate_buffers(char **bigbuf, char **smallbuf, unsigned int size, | 323 | allocate_buffers(struct TCP_Server_Info *server) |
324 | bool is_large_buf) | ||
325 | { | 324 | { |
326 | char *bbuf = *bigbuf, *sbuf = *smallbuf; | 325 | if (!server->bigbuf) { |
327 | 326 | server->bigbuf = (char *)cifs_buf_get(); | |
328 | if (bbuf == NULL) { | 327 | if (!server->bigbuf) { |
329 | bbuf = (char *)cifs_buf_get(); | ||
330 | if (!bbuf) { | ||
331 | cERROR(1, "No memory for large SMB response"); | 328 | cERROR(1, "No memory for large SMB response"); |
332 | msleep(3000); | 329 | msleep(3000); |
333 | /* retry will check if exiting */ | 330 | /* retry will check if exiting */ |
334 | return false; | 331 | return false; |
335 | } | 332 | } |
336 | } else if (is_large_buf) { | 333 | } else if (server->large_buf) { |
337 | /* we are reusing a dirty large buf, clear its start */ | 334 | /* we are reusing a dirty large buf, clear its start */ |
338 | memset(bbuf, 0, size); | 335 | memset(server->bigbuf, 0, sizeof(struct smb_hdr)); |
339 | } | 336 | } |
340 | 337 | ||
341 | if (sbuf == NULL) { | 338 | if (!server->smallbuf) { |
342 | sbuf = (char *)cifs_small_buf_get(); | 339 | server->smallbuf = (char *)cifs_small_buf_get(); |
343 | if (!sbuf) { | 340 | if (!server->smallbuf) { |
344 | cERROR(1, "No memory for SMB response"); | 341 | cERROR(1, "No memory for SMB response"); |
345 | msleep(1000); | 342 | msleep(1000); |
346 | /* retry will check if exiting */ | 343 | /* retry will check if exiting */ |
@@ -349,36 +346,116 @@ allocate_buffers(char **bigbuf, char **smallbuf, unsigned int size, | |||
349 | /* beginning of smb buffer is cleared in our buf_get */ | 346 | /* beginning of smb buffer is cleared in our buf_get */ |
350 | } else { | 347 | } else { |
351 | /* if existing small buf clear beginning */ | 348 | /* if existing small buf clear beginning */ |
352 | memset(sbuf, 0, size); | 349 | memset(server->smallbuf, 0, sizeof(struct smb_hdr)); |
353 | } | 350 | } |
354 | 351 | ||
355 | *bigbuf = bbuf; | ||
356 | *smallbuf = sbuf; | ||
357 | |||
358 | return true; | 352 | return true; |
359 | } | 353 | } |
360 | 354 | ||
361 | static int | 355 | static bool |
362 | read_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg, | 356 | server_unresponsive(struct TCP_Server_Info *server) |
363 | struct kvec *iov, unsigned int to_read, | 357 | { |
364 | unsigned int *ptotal_read, bool is_header_read) | 358 | if (echo_retries > 0 && server->tcpStatus == CifsGood && |
359 | time_after(jiffies, server->lstrp + | ||
360 | (echo_retries * SMB_ECHO_INTERVAL))) { | ||
361 | cERROR(1, "Server %s has not responded in %d seconds. " | ||
362 | "Reconnecting...", server->hostname, | ||
363 | (echo_retries * SMB_ECHO_INTERVAL / HZ)); | ||
364 | cifs_reconnect(server); | ||
365 | wake_up(&server->response_q); | ||
366 | return true; | ||
367 | } | ||
368 | |||
369 | return false; | ||
370 | } | ||
371 | |||
372 | /* | ||
373 | * kvec_array_init - clone a kvec array, and advance into it | ||
374 | * @new: pointer to memory for cloned array | ||
375 | * @iov: pointer to original array | ||
376 | * @nr_segs: number of members in original array | ||
377 | * @bytes: number of bytes to advance into the cloned array | ||
378 | * | ||
379 | * This function will copy the array provided in iov to a section of memory | ||
380 | * and advance the specified number of bytes into the new array. It returns | ||
381 | * the number of segments in the new array. "new" must be at least as big as | ||
382 | * the original iov array. | ||
383 | */ | ||
384 | static unsigned int | ||
385 | kvec_array_init(struct kvec *new, struct kvec *iov, unsigned int nr_segs, | ||
386 | size_t bytes) | ||
387 | { | ||
388 | size_t base = 0; | ||
389 | |||
390 | while (bytes || !iov->iov_len) { | ||
391 | int copy = min(bytes, iov->iov_len); | ||
392 | |||
393 | bytes -= copy; | ||
394 | base += copy; | ||
395 | if (iov->iov_len == base) { | ||
396 | iov++; | ||
397 | nr_segs--; | ||
398 | base = 0; | ||
399 | } | ||
400 | } | ||
401 | memcpy(new, iov, sizeof(*iov) * nr_segs); | ||
402 | new->iov_base += base; | ||
403 | new->iov_len -= base; | ||
404 | return nr_segs; | ||
405 | } | ||
406 | |||
407 | static struct kvec * | ||
408 | get_server_iovec(struct TCP_Server_Info *server, unsigned int nr_segs) | ||
409 | { | ||
410 | struct kvec *new_iov; | ||
411 | |||
412 | if (server->iov && nr_segs <= server->nr_iov) | ||
413 | return server->iov; | ||
414 | |||
415 | /* not big enough -- allocate a new one and release the old */ | ||
416 | new_iov = kmalloc(sizeof(*new_iov) * nr_segs, GFP_NOFS); | ||
417 | if (new_iov) { | ||
418 | kfree(server->iov); | ||
419 | server->iov = new_iov; | ||
420 | server->nr_iov = nr_segs; | ||
421 | } | ||
422 | return new_iov; | ||
423 | } | ||
424 | |||
425 | int | ||
426 | cifs_readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig, | ||
427 | unsigned int nr_segs, unsigned int to_read) | ||
365 | { | 428 | { |
366 | int length, rc = 0; | 429 | int length = 0; |
367 | unsigned int total_read; | 430 | int total_read; |
368 | char *buf = iov->iov_base; | 431 | unsigned int segs; |
432 | struct msghdr smb_msg; | ||
433 | struct kvec *iov; | ||
434 | |||
435 | iov = get_server_iovec(server, nr_segs); | ||
436 | if (!iov) | ||
437 | return -ENOMEM; | ||
438 | |||
439 | smb_msg.msg_control = NULL; | ||
440 | smb_msg.msg_controllen = 0; | ||
441 | |||
442 | for (total_read = 0; to_read; total_read += length, to_read -= length) { | ||
443 | if (server_unresponsive(server)) { | ||
444 | total_read = -EAGAIN; | ||
445 | break; | ||
446 | } | ||
447 | |||
448 | segs = kvec_array_init(iov, iov_orig, nr_segs, total_read); | ||
449 | |||
450 | length = kernel_recvmsg(server->ssocket, &smb_msg, | ||
451 | iov, segs, to_read, 0); | ||
369 | 452 | ||
370 | for (total_read = 0; total_read < to_read; total_read += length) { | ||
371 | length = kernel_recvmsg(server->ssocket, smb_msg, iov, 1, | ||
372 | to_read - total_read, 0); | ||
373 | if (server->tcpStatus == CifsExiting) { | 453 | if (server->tcpStatus == CifsExiting) { |
374 | /* then will exit */ | 454 | total_read = -ESHUTDOWN; |
375 | rc = 2; | ||
376 | break; | 455 | break; |
377 | } else if (server->tcpStatus == CifsNeedReconnect) { | 456 | } else if (server->tcpStatus == CifsNeedReconnect) { |
378 | cifs_reconnect(server); | 457 | cifs_reconnect(server); |
379 | /* Reconnect wakes up rspns q */ | 458 | total_read = -EAGAIN; |
380 | /* Now we will reread sock */ | ||
381 | rc = 1; | ||
382 | break; | 459 | break; |
383 | } else if (length == -ERESTARTSYS || | 460 | } else if (length == -ERESTARTSYS || |
384 | length == -EAGAIN || | 461 | length == -EAGAIN || |
@@ -390,56 +467,54 @@ read_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg, | |||
390 | */ | 467 | */ |
391 | usleep_range(1000, 2000); | 468 | usleep_range(1000, 2000); |
392 | length = 0; | 469 | length = 0; |
393 | if (!is_header_read) | 470 | continue; |
394 | continue; | ||
395 | /* Special handling for header read */ | ||
396 | if (total_read) { | ||
397 | iov->iov_base = (to_read - total_read) + | ||
398 | buf; | ||
399 | iov->iov_len = to_read - total_read; | ||
400 | smb_msg->msg_control = NULL; | ||
401 | smb_msg->msg_controllen = 0; | ||
402 | rc = 3; | ||
403 | } else | ||
404 | rc = 1; | ||
405 | break; | ||
406 | } else if (length <= 0) { | 471 | } else if (length <= 0) { |
407 | cERROR(1, "Received no data, expecting %d", | 472 | cFYI(1, "Received no data or error: expecting %d " |
408 | to_read - total_read); | 473 | "got %d", to_read, length); |
409 | cifs_reconnect(server); | 474 | cifs_reconnect(server); |
410 | rc = 1; | 475 | total_read = -EAGAIN; |
411 | break; | 476 | break; |
412 | } | 477 | } |
413 | } | 478 | } |
479 | return total_read; | ||
480 | } | ||
414 | 481 | ||
415 | *ptotal_read = total_read; | 482 | int |
416 | return rc; | 483 | cifs_read_from_socket(struct TCP_Server_Info *server, char *buf, |
484 | unsigned int to_read) | ||
485 | { | ||
486 | struct kvec iov; | ||
487 | |||
488 | iov.iov_base = buf; | ||
489 | iov.iov_len = to_read; | ||
490 | |||
491 | return cifs_readv_from_socket(server, &iov, 1, to_read); | ||
417 | } | 492 | } |
418 | 493 | ||
419 | static bool | 494 | static bool |
420 | check_rfc1002_header(struct TCP_Server_Info *server, char *buf) | 495 | is_smb_response(struct TCP_Server_Info *server, unsigned char type) |
421 | { | 496 | { |
422 | char temp = *buf; | ||
423 | unsigned int pdu_length = be32_to_cpu( | ||
424 | ((struct smb_hdr *)buf)->smb_buf_length); | ||
425 | |||
426 | /* | 497 | /* |
427 | * The first byte big endian of the length field, | 498 | * The first byte big endian of the length field, |
428 | * is actually not part of the length but the type | 499 | * is actually not part of the length but the type |
429 | * with the most common, zero, as regular data. | 500 | * with the most common, zero, as regular data. |
430 | */ | 501 | */ |
431 | if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) { | 502 | switch (type) { |
432 | return false; | 503 | case RFC1002_SESSION_MESSAGE: |
433 | } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { | 504 | /* Regular SMB response */ |
434 | cFYI(1, "Good RFC 1002 session rsp"); | 505 | return true; |
435 | return false; | 506 | case RFC1002_SESSION_KEEP_ALIVE: |
436 | } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { | 507 | cFYI(1, "RFC 1002 session keep alive"); |
508 | break; | ||
509 | case RFC1002_POSITIVE_SESSION_RESPONSE: | ||
510 | cFYI(1, "RFC 1002 positive session response"); | ||
511 | break; | ||
512 | case RFC1002_NEGATIVE_SESSION_RESPONSE: | ||
437 | /* | 513 | /* |
438 | * We get this from Windows 98 instead of an error on | 514 | * We get this from Windows 98 instead of an error on |
439 | * SMB negprot response. | 515 | * SMB negprot response. |
440 | */ | 516 | */ |
441 | cFYI(1, "Negative RFC1002 Session Response Error 0x%x)", | 517 | cFYI(1, "RFC 1002 negative session response"); |
442 | pdu_length); | ||
443 | /* give server a second to clean up */ | 518 | /* give server a second to clean up */ |
444 | msleep(1000); | 519 | msleep(1000); |
445 | /* | 520 | /* |
@@ -448,87 +523,89 @@ check_rfc1002_header(struct TCP_Server_Info *server, char *buf) | |||
448 | * is since we do not begin with RFC1001 session | 523 | * is since we do not begin with RFC1001 session |
449 | * initialize frame). | 524 | * initialize frame). |
450 | */ | 525 | */ |
451 | cifs_set_port((struct sockaddr *) | 526 | cifs_set_port((struct sockaddr *)&server->dstaddr, CIFS_PORT); |
452 | &server->dstaddr, CIFS_PORT); | ||
453 | cifs_reconnect(server); | 527 | cifs_reconnect(server); |
454 | wake_up(&server->response_q); | 528 | wake_up(&server->response_q); |
455 | return false; | 529 | break; |
456 | } else if (temp != (char) 0) { | 530 | default: |
457 | cERROR(1, "Unknown RFC 1002 frame"); | 531 | cERROR(1, "RFC 1002 unknown response type 0x%x", type); |
458 | cifs_dump_mem(" Received Data: ", buf, 4); | ||
459 | cifs_reconnect(server); | ||
460 | return false; | ||
461 | } | ||
462 | |||
463 | /* else we have an SMB response */ | ||
464 | if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) || | ||
465 | (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) { | ||
466 | cERROR(1, "Invalid size SMB length %d pdu_length %d", | ||
467 | 4, pdu_length+4); | ||
468 | cifs_reconnect(server); | 532 | cifs_reconnect(server); |
469 | wake_up(&server->response_q); | ||
470 | return false; | ||
471 | } | 533 | } |
472 | 534 | ||
473 | return true; | 535 | return false; |
474 | } | 536 | } |
475 | 537 | ||
476 | static struct mid_q_entry * | 538 | static struct mid_q_entry * |
477 | find_cifs_mid(struct TCP_Server_Info *server, struct smb_hdr *buf, | 539 | find_mid(struct TCP_Server_Info *server, struct smb_hdr *buf) |
478 | int *length, bool is_large_buf, bool *is_multi_rsp, char **bigbuf) | ||
479 | { | 540 | { |
480 | struct mid_q_entry *mid = NULL, *tmp_mid, *ret = NULL; | 541 | struct mid_q_entry *mid; |
481 | 542 | ||
482 | spin_lock(&GlobalMid_Lock); | 543 | spin_lock(&GlobalMid_Lock); |
483 | list_for_each_entry_safe(mid, tmp_mid, &server->pending_mid_q, qhead) { | 544 | list_for_each_entry(mid, &server->pending_mid_q, qhead) { |
484 | if (mid->mid != buf->Mid || | 545 | if (mid->mid == buf->Mid && |
485 | mid->midState != MID_REQUEST_SUBMITTED || | 546 | mid->midState == MID_REQUEST_SUBMITTED && |
486 | mid->command != buf->Command) | 547 | mid->command == buf->Command) { |
487 | continue; | 548 | spin_unlock(&GlobalMid_Lock); |
488 | 549 | return mid; | |
489 | if (*length == 0 && check2ndT2(buf, server->maxBuf) > 0) { | ||
490 | /* We have a multipart transact2 resp */ | ||
491 | *is_multi_rsp = true; | ||
492 | if (mid->resp_buf) { | ||
493 | /* merge response - fix up 1st*/ | ||
494 | *length = coalesce_t2(buf, mid->resp_buf); | ||
495 | if (*length > 0) { | ||
496 | *length = 0; | ||
497 | mid->multiRsp = true; | ||
498 | break; | ||
499 | } | ||
500 | /* All parts received or packet is malformed. */ | ||
501 | mid->multiEnd = true; | ||
502 | goto multi_t2_fnd; | ||
503 | } | ||
504 | if (!is_large_buf) { | ||
505 | /*FIXME: switch to already allocated largebuf?*/ | ||
506 | cERROR(1, "1st trans2 resp needs bigbuf"); | ||
507 | } else { | ||
508 | /* Have first buffer */ | ||
509 | mid->resp_buf = buf; | ||
510 | mid->largeBuf = true; | ||
511 | *bigbuf = NULL; | ||
512 | } | ||
513 | break; | ||
514 | } | 550 | } |
515 | mid->resp_buf = buf; | 551 | } |
516 | mid->largeBuf = is_large_buf; | 552 | spin_unlock(&GlobalMid_Lock); |
517 | multi_t2_fnd: | 553 | return NULL; |
518 | if (*length == 0) | 554 | } |
519 | mid->midState = MID_RESPONSE_RECEIVED; | 555 | |
520 | else | 556 | void |
521 | mid->midState = MID_RESPONSE_MALFORMED; | 557 | dequeue_mid(struct mid_q_entry *mid, bool malformed) |
558 | { | ||
522 | #ifdef CONFIG_CIFS_STATS2 | 559 | #ifdef CONFIG_CIFS_STATS2 |
523 | mid->when_received = jiffies; | 560 | mid->when_received = jiffies; |
524 | #endif | 561 | #endif |
525 | list_del_init(&mid->qhead); | 562 | spin_lock(&GlobalMid_Lock); |
526 | ret = mid; | 563 | if (!malformed) |
527 | break; | 564 | mid->midState = MID_RESPONSE_RECEIVED; |
528 | } | 565 | else |
566 | mid->midState = MID_RESPONSE_MALFORMED; | ||
567 | list_del_init(&mid->qhead); | ||
529 | spin_unlock(&GlobalMid_Lock); | 568 | spin_unlock(&GlobalMid_Lock); |
569 | } | ||
530 | 570 | ||
531 | return ret; | 571 | static void |
572 | handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server, | ||
573 | struct smb_hdr *buf, int malformed) | ||
574 | { | ||
575 | if (malformed == 0 && check2ndT2(buf) > 0) { | ||
576 | mid->multiRsp = true; | ||
577 | if (mid->resp_buf) { | ||
578 | /* merge response - fix up 1st*/ | ||
579 | malformed = coalesce_t2(buf, mid->resp_buf); | ||
580 | if (malformed > 0) | ||
581 | return; | ||
582 | |||
583 | /* All parts received or packet is malformed. */ | ||
584 | mid->multiEnd = true; | ||
585 | return dequeue_mid(mid, malformed); | ||
586 | } | ||
587 | if (!server->large_buf) { | ||
588 | /*FIXME: switch to already allocated largebuf?*/ | ||
589 | cERROR(1, "1st trans2 resp needs bigbuf"); | ||
590 | } else { | ||
591 | /* Have first buffer */ | ||
592 | mid->resp_buf = buf; | ||
593 | mid->largeBuf = true; | ||
594 | server->bigbuf = NULL; | ||
595 | } | ||
596 | return; | ||
597 | } | ||
598 | mid->resp_buf = buf; | ||
599 | mid->largeBuf = server->large_buf; | ||
600 | /* Was previous buf put in mpx struct for multi-rsp? */ | ||
601 | if (!mid->multiRsp) { | ||
602 | /* smb buffer will be freed by user thread */ | ||
603 | if (server->large_buf) | ||
604 | server->bigbuf = NULL; | ||
605 | else | ||
606 | server->smallbuf = NULL; | ||
607 | } | ||
608 | dequeue_mid(mid, malformed); | ||
532 | } | 609 | } |
533 | 610 | ||
534 | static void clean_demultiplex_info(struct TCP_Server_Info *server) | 611 | static void clean_demultiplex_info(struct TCP_Server_Info *server) |
@@ -618,6 +695,7 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server) | |||
618 | } | 695 | } |
619 | 696 | ||
620 | kfree(server->hostname); | 697 | kfree(server->hostname); |
698 | kfree(server->iov); | ||
621 | kfree(server); | 699 | kfree(server); |
622 | 700 | ||
623 | length = atomic_dec_return(&tcpSesAllocCount); | 701 | length = atomic_dec_return(&tcpSesAllocCount); |
@@ -627,20 +705,70 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server) | |||
627 | } | 705 | } |
628 | 706 | ||
629 | static int | 707 | static int |
708 | standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) | ||
709 | { | ||
710 | int length; | ||
711 | char *buf = server->smallbuf; | ||
712 | struct smb_hdr *smb_buffer = (struct smb_hdr *)buf; | ||
713 | unsigned int pdu_length = be32_to_cpu(smb_buffer->smb_buf_length); | ||
714 | |||
715 | /* make sure this will fit in a large buffer */ | ||
716 | if (pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { | ||
717 | cERROR(1, "SMB response too long (%u bytes)", | ||
718 | pdu_length); | ||
719 | cifs_reconnect(server); | ||
720 | wake_up(&server->response_q); | ||
721 | return -EAGAIN; | ||
722 | } | ||
723 | |||
724 | /* switch to large buffer if too big for a small one */ | ||
725 | if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) { | ||
726 | server->large_buf = true; | ||
727 | memcpy(server->bigbuf, server->smallbuf, server->total_read); | ||
728 | buf = server->bigbuf; | ||
729 | smb_buffer = (struct smb_hdr *)buf; | ||
730 | } | ||
731 | |||
732 | /* now read the rest */ | ||
733 | length = cifs_read_from_socket(server, | ||
734 | buf + sizeof(struct smb_hdr) - 1, | ||
735 | pdu_length - sizeof(struct smb_hdr) + 1 + 4); | ||
736 | if (length < 0) | ||
737 | return length; | ||
738 | server->total_read += length; | ||
739 | |||
740 | dump_smb(smb_buffer, server->total_read); | ||
741 | |||
742 | /* | ||
743 | * We know that we received enough to get to the MID as we | ||
744 | * checked the pdu_length earlier. Now check to see | ||
745 | * if the rest of the header is OK. We borrow the length | ||
746 | * var for the rest of the loop to avoid a new stack var. | ||
747 | * | ||
748 | * 48 bytes is enough to display the header and a little bit | ||
749 | * into the payload for debugging purposes. | ||
750 | */ | ||
751 | length = checkSMB(smb_buffer, smb_buffer->Mid, server->total_read); | ||
752 | if (length != 0) | ||
753 | cifs_dump_mem("Bad SMB: ", buf, | ||
754 | min_t(unsigned int, server->total_read, 48)); | ||
755 | |||
756 | if (mid) | ||
757 | handle_mid(mid, server, smb_buffer, length); | ||
758 | |||
759 | return length; | ||
760 | } | ||
761 | |||
762 | static int | ||
630 | cifs_demultiplex_thread(void *p) | 763 | cifs_demultiplex_thread(void *p) |
631 | { | 764 | { |
632 | int length; | 765 | int length; |
633 | struct TCP_Server_Info *server = p; | 766 | struct TCP_Server_Info *server = p; |
634 | unsigned int pdu_length, total_read; | 767 | unsigned int pdu_length; |
635 | char *buf = NULL, *bigbuf = NULL, *smallbuf = NULL; | 768 | char *buf = NULL; |
636 | struct smb_hdr *smb_buffer = NULL; | 769 | struct smb_hdr *smb_buffer = NULL; |
637 | struct msghdr smb_msg; | ||
638 | struct kvec iov; | ||
639 | struct task_struct *task_to_wake = NULL; | 770 | struct task_struct *task_to_wake = NULL; |
640 | struct mid_q_entry *mid_entry; | 771 | struct mid_q_entry *mid_entry; |
641 | bool isLargeBuf = false; | ||
642 | bool isMultiRsp = false; | ||
643 | int rc; | ||
644 | 772 | ||
645 | current->flags |= PF_MEMALLOC; | 773 | current->flags |= PF_MEMALLOC; |
646 | cFYI(1, "Demultiplex PID: %d", task_pid_nr(current)); | 774 | cFYI(1, "Demultiplex PID: %d", task_pid_nr(current)); |
@@ -655,111 +783,65 @@ cifs_demultiplex_thread(void *p) | |||
655 | if (try_to_freeze()) | 783 | if (try_to_freeze()) |
656 | continue; | 784 | continue; |
657 | 785 | ||
658 | if (!allocate_buffers(&bigbuf, &smallbuf, | 786 | if (!allocate_buffers(server)) |
659 | sizeof(struct smb_hdr), isLargeBuf)) | ||
660 | continue; | 787 | continue; |
661 | 788 | ||
662 | isLargeBuf = false; | 789 | server->large_buf = false; |
663 | isMultiRsp = false; | 790 | smb_buffer = (struct smb_hdr *)server->smallbuf; |
664 | smb_buffer = (struct smb_hdr *)smallbuf; | 791 | buf = server->smallbuf; |
665 | buf = smallbuf; | ||
666 | iov.iov_base = buf; | ||
667 | iov.iov_len = 4; | ||
668 | smb_msg.msg_control = NULL; | ||
669 | smb_msg.msg_controllen = 0; | ||
670 | pdu_length = 4; /* enough to get RFC1001 header */ | 792 | pdu_length = 4; /* enough to get RFC1001 header */ |
671 | 793 | ||
672 | incomplete_rcv: | 794 | length = cifs_read_from_socket(server, buf, pdu_length); |
673 | if (echo_retries > 0 && server->tcpStatus == CifsGood && | 795 | if (length < 0) |
674 | time_after(jiffies, server->lstrp + | ||
675 | (echo_retries * SMB_ECHO_INTERVAL))) { | ||
676 | cERROR(1, "Server %s has not responded in %d seconds. " | ||
677 | "Reconnecting...", server->hostname, | ||
678 | (echo_retries * SMB_ECHO_INTERVAL / HZ)); | ||
679 | cifs_reconnect(server); | ||
680 | wake_up(&server->response_q); | ||
681 | continue; | ||
682 | } | ||
683 | |||
684 | rc = read_from_socket(server, &smb_msg, &iov, pdu_length, | ||
685 | &total_read, true /* header read */); | ||
686 | if (rc == 3) | ||
687 | goto incomplete_rcv; | ||
688 | else if (rc == 2) | ||
689 | break; | ||
690 | else if (rc == 1) | ||
691 | continue; | 796 | continue; |
797 | server->total_read = length; | ||
692 | 798 | ||
693 | /* | 799 | /* |
694 | * The right amount was read from socket - 4 bytes, | 800 | * The right amount was read from socket - 4 bytes, |
695 | * so we can now interpret the length field. | 801 | * so we can now interpret the length field. |
696 | */ | 802 | */ |
697 | |||
698 | /* | ||
699 | * Note that RFC 1001 length is big endian on the wire, | ||
700 | * but we convert it here so it is always manipulated | ||
701 | * as host byte order. | ||
702 | */ | ||
703 | pdu_length = be32_to_cpu(smb_buffer->smb_buf_length); | 803 | pdu_length = be32_to_cpu(smb_buffer->smb_buf_length); |
704 | 804 | ||
705 | cFYI(1, "rfc1002 length 0x%x", pdu_length+4); | 805 | cFYI(1, "RFC1002 header 0x%x", pdu_length); |
706 | if (!check_rfc1002_header(server, buf)) | 806 | if (!is_smb_response(server, buf[0])) |
707 | continue; | 807 | continue; |
708 | 808 | ||
709 | /* else length ok */ | 809 | /* make sure we have enough to get to the MID */ |
710 | if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) { | 810 | if (pdu_length < sizeof(struct smb_hdr) - 1 - 4) { |
711 | isLargeBuf = true; | 811 | cERROR(1, "SMB response too short (%u bytes)", |
712 | memcpy(bigbuf, smallbuf, 4); | 812 | pdu_length); |
713 | smb_buffer = (struct smb_hdr *)bigbuf; | 813 | cifs_reconnect(server); |
714 | buf = bigbuf; | 814 | wake_up(&server->response_q); |
815 | continue; | ||
715 | } | 816 | } |
716 | 817 | ||
717 | iov.iov_base = 4 + buf; | 818 | /* read down to the MID */ |
718 | iov.iov_len = pdu_length; | 819 | length = cifs_read_from_socket(server, buf + 4, |
719 | rc = read_from_socket(server, &smb_msg, &iov, pdu_length, | 820 | sizeof(struct smb_hdr) - 1 - 4); |
720 | &total_read, false); | 821 | if (length < 0) |
721 | if (rc == 2) | ||
722 | break; | ||
723 | else if (rc == 1) | ||
724 | continue; | 822 | continue; |
823 | server->total_read += length; | ||
725 | 824 | ||
726 | total_read += 4; /* account for rfc1002 hdr */ | 825 | mid_entry = find_mid(server, smb_buffer); |
727 | 826 | ||
728 | dump_smb(smb_buffer, total_read); | 827 | if (!mid_entry || !mid_entry->receive) |
828 | length = standard_receive3(server, mid_entry); | ||
829 | else | ||
830 | length = mid_entry->receive(server, mid_entry); | ||
729 | 831 | ||
730 | /* | 832 | if (length < 0) |
731 | * We know that we received enough to get to the MID as we | 833 | continue; |
732 | * checked the pdu_length earlier. Now check to see | ||
733 | * if the rest of the header is OK. We borrow the length | ||
734 | * var for the rest of the loop to avoid a new stack var. | ||
735 | * | ||
736 | * 48 bytes is enough to display the header and a little bit | ||
737 | * into the payload for debugging purposes. | ||
738 | */ | ||
739 | length = checkSMB(smb_buffer, smb_buffer->Mid, total_read); | ||
740 | if (length != 0) | ||
741 | cifs_dump_mem("Bad SMB: ", buf, | ||
742 | min_t(unsigned int, total_read, 48)); | ||
743 | 834 | ||
744 | server->lstrp = jiffies; | 835 | if (server->large_buf) { |
836 | buf = server->bigbuf; | ||
837 | smb_buffer = (struct smb_hdr *)buf; | ||
838 | } | ||
745 | 839 | ||
746 | mid_entry = find_cifs_mid(server, smb_buffer, &length, | 840 | server->lstrp = jiffies; |
747 | isLargeBuf, &isMultiRsp, &bigbuf); | ||
748 | if (mid_entry != NULL) { | 841 | if (mid_entry != NULL) { |
749 | mid_entry->callback(mid_entry); | 842 | if (!mid_entry->multiRsp || mid_entry->multiEnd) |
750 | /* Was previous buf put in mpx struct for multi-rsp? */ | 843 | mid_entry->callback(mid_entry); |
751 | if (!isMultiRsp) { | 844 | } else if (!is_valid_oplock_break(smb_buffer, server)) { |
752 | /* smb buffer will be freed by user thread */ | ||
753 | if (isLargeBuf) | ||
754 | bigbuf = NULL; | ||
755 | else | ||
756 | smallbuf = NULL; | ||
757 | } | ||
758 | } else if (length != 0) { | ||
759 | /* response sanity checks failed */ | ||
760 | continue; | ||
761 | } else if (!is_valid_oplock_break(smb_buffer, server) && | ||
762 | !isMultiRsp) { | ||
763 | cERROR(1, "No task to wake, unknown frame received! " | 845 | cERROR(1, "No task to wake, unknown frame received! " |
764 | "NumMids %d", atomic_read(&midCount)); | 846 | "NumMids %d", atomic_read(&midCount)); |
765 | cifs_dump_mem("Received Data is: ", buf, | 847 | cifs_dump_mem("Received Data is: ", buf, |
@@ -773,9 +855,9 @@ incomplete_rcv: | |||
773 | } /* end while !EXITING */ | 855 | } /* end while !EXITING */ |
774 | 856 | ||
775 | /* buffer usually freed in free_mid - need to free it here on exit */ | 857 | /* buffer usually freed in free_mid - need to free it here on exit */ |
776 | cifs_buf_release(bigbuf); | 858 | cifs_buf_release(server->bigbuf); |
777 | if (smallbuf) /* no sense logging a debug message if NULL */ | 859 | if (server->smallbuf) /* no sense logging a debug message if NULL */ |
778 | cifs_small_buf_release(smallbuf); | 860 | cifs_small_buf_release(server->smallbuf); |
779 | 861 | ||
780 | task_to_wake = xchg(&server->tsk, NULL); | 862 | task_to_wake = xchg(&server->tsk, NULL); |
781 | clean_demultiplex_info(server); | 863 | clean_demultiplex_info(server); |
@@ -827,6 +909,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
827 | { | 909 | { |
828 | char *value, *data, *end; | 910 | char *value, *data, *end; |
829 | char *mountdata_copy = NULL, *options; | 911 | char *mountdata_copy = NULL, *options; |
912 | int err; | ||
830 | unsigned int temp_len, i, j; | 913 | unsigned int temp_len, i, j; |
831 | char separator[2]; | 914 | char separator[2]; |
832 | short int override_uid = -1; | 915 | short int override_uid = -1; |
@@ -883,6 +966,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
883 | cFYI(1, "Null separator not allowed"); | 966 | cFYI(1, "Null separator not allowed"); |
884 | } | 967 | } |
885 | } | 968 | } |
969 | vol->backupuid_specified = false; /* no backup intent for a user */ | ||
970 | vol->backupgid_specified = false; /* no backup intent for a group */ | ||
886 | 971 | ||
887 | while ((data = strsep(&options, separator)) != NULL) { | 972 | while ((data = strsep(&options, separator)) != NULL) { |
888 | if (!*data) | 973 | if (!*data) |
@@ -1442,6 +1527,22 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1442 | vol->mfsymlinks = true; | 1527 | vol->mfsymlinks = true; |
1443 | } else if (strnicmp(data, "multiuser", 8) == 0) { | 1528 | } else if (strnicmp(data, "multiuser", 8) == 0) { |
1444 | vol->multiuser = true; | 1529 | vol->multiuser = true; |
1530 | } else if (!strnicmp(data, "backupuid", 9) && value && *value) { | ||
1531 | err = kstrtouint(value, 0, &vol->backupuid); | ||
1532 | if (err < 0) { | ||
1533 | cERROR(1, "%s: Invalid backupuid value", | ||
1534 | __func__); | ||
1535 | goto cifs_parse_mount_err; | ||
1536 | } | ||
1537 | vol->backupuid_specified = true; | ||
1538 | } else if (!strnicmp(data, "backupgid", 9) && value && *value) { | ||
1539 | err = kstrtouint(value, 0, &vol->backupgid); | ||
1540 | if (err < 0) { | ||
1541 | cERROR(1, "%s: Invalid backupgid value", | ||
1542 | __func__); | ||
1543 | goto cifs_parse_mount_err; | ||
1544 | } | ||
1545 | vol->backupgid_specified = true; | ||
1445 | } else | 1546 | } else |
1446 | printk(KERN_WARNING "CIFS: Unknown mount option %s\n", | 1547 | printk(KERN_WARNING "CIFS: Unknown mount option %s\n", |
1447 | data); | 1548 | data); |
@@ -2209,16 +2310,16 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data) | |||
2209 | (new->mnt_cifs_flags & CIFS_MOUNT_MASK)) | 2310 | (new->mnt_cifs_flags & CIFS_MOUNT_MASK)) |
2210 | return 0; | 2311 | return 0; |
2211 | 2312 | ||
2212 | if (old->rsize != new->rsize) | ||
2213 | return 0; | ||
2214 | |||
2215 | /* | 2313 | /* |
2216 | * We want to share sb only if we don't specify wsize or specified wsize | 2314 | * We want to share sb only if we don't specify an r/wsize or |
2217 | * is greater or equal than existing one. | 2315 | * specified r/wsize is greater than or equal to existing one. |
2218 | */ | 2316 | */ |
2219 | if (new->wsize && new->wsize < old->wsize) | 2317 | if (new->wsize && new->wsize < old->wsize) |
2220 | return 0; | 2318 | return 0; |
2221 | 2319 | ||
2320 | if (new->rsize && new->rsize < old->rsize) | ||
2321 | return 0; | ||
2322 | |||
2222 | if (old->mnt_uid != new->mnt_uid || old->mnt_gid != new->mnt_gid) | 2323 | if (old->mnt_uid != new->mnt_uid || old->mnt_gid != new->mnt_gid) |
2223 | return 0; | 2324 | return 0; |
2224 | 2325 | ||
@@ -2656,14 +2757,6 @@ void reset_cifs_unix_caps(int xid, struct cifs_tcon *tcon, | |||
2656 | CIFS_MOUNT_POSIX_PATHS; | 2757 | CIFS_MOUNT_POSIX_PATHS; |
2657 | } | 2758 | } |
2658 | 2759 | ||
2659 | if (cifs_sb && (cifs_sb->rsize > 127 * 1024)) { | ||
2660 | if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) { | ||
2661 | cifs_sb->rsize = 127 * 1024; | ||
2662 | cFYI(DBG2, "larger reads not supported by srv"); | ||
2663 | } | ||
2664 | } | ||
2665 | |||
2666 | |||
2667 | cFYI(1, "Negotiate caps 0x%x", (int)cap); | 2760 | cFYI(1, "Negotiate caps 0x%x", (int)cap); |
2668 | #ifdef CONFIG_CIFS_DEBUG2 | 2761 | #ifdef CONFIG_CIFS_DEBUG2 |
2669 | if (cap & CIFS_UNIX_FCNTL_CAP) | 2762 | if (cap & CIFS_UNIX_FCNTL_CAP) |
@@ -2708,31 +2801,19 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2708 | spin_lock_init(&cifs_sb->tlink_tree_lock); | 2801 | spin_lock_init(&cifs_sb->tlink_tree_lock); |
2709 | cifs_sb->tlink_tree = RB_ROOT; | 2802 | cifs_sb->tlink_tree = RB_ROOT; |
2710 | 2803 | ||
2711 | if (pvolume_info->rsize > CIFSMaxBufSize) { | ||
2712 | cERROR(1, "rsize %d too large, using MaxBufSize", | ||
2713 | pvolume_info->rsize); | ||
2714 | cifs_sb->rsize = CIFSMaxBufSize; | ||
2715 | } else if ((pvolume_info->rsize) && | ||
2716 | (pvolume_info->rsize <= CIFSMaxBufSize)) | ||
2717 | cifs_sb->rsize = pvolume_info->rsize; | ||
2718 | else /* default */ | ||
2719 | cifs_sb->rsize = CIFSMaxBufSize; | ||
2720 | |||
2721 | if (cifs_sb->rsize < 2048) { | ||
2722 | cifs_sb->rsize = 2048; | ||
2723 | /* Windows ME may prefer this */ | ||
2724 | cFYI(1, "readsize set to minimum: 2048"); | ||
2725 | } | ||
2726 | |||
2727 | /* | 2804 | /* |
2728 | * Temporarily set wsize for matching superblock. If we end up using | 2805 | * Temporarily set r/wsize for matching superblock. If we end up using |
2729 | * new sb then cifs_negotiate_wsize will later negotiate it downward | 2806 | * new sb then client will later negotiate it downward if needed. |
2730 | * if needed. | ||
2731 | */ | 2807 | */ |
2808 | cifs_sb->rsize = pvolume_info->rsize; | ||
2732 | cifs_sb->wsize = pvolume_info->wsize; | 2809 | cifs_sb->wsize = pvolume_info->wsize; |
2733 | 2810 | ||
2734 | cifs_sb->mnt_uid = pvolume_info->linux_uid; | 2811 | cifs_sb->mnt_uid = pvolume_info->linux_uid; |
2735 | cifs_sb->mnt_gid = pvolume_info->linux_gid; | 2812 | cifs_sb->mnt_gid = pvolume_info->linux_gid; |
2813 | if (pvolume_info->backupuid_specified) | ||
2814 | cifs_sb->mnt_backupuid = pvolume_info->backupuid; | ||
2815 | if (pvolume_info->backupgid_specified) | ||
2816 | cifs_sb->mnt_backupgid = pvolume_info->backupgid; | ||
2736 | cifs_sb->mnt_file_mode = pvolume_info->file_mode; | 2817 | cifs_sb->mnt_file_mode = pvolume_info->file_mode; |
2737 | cifs_sb->mnt_dir_mode = pvolume_info->dir_mode; | 2818 | cifs_sb->mnt_dir_mode = pvolume_info->dir_mode; |
2738 | cFYI(1, "file mode: 0x%x dir mode: 0x%x", | 2819 | cFYI(1, "file mode: 0x%x dir mode: 0x%x", |
@@ -2763,6 +2844,10 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2763 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD; | 2844 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD; |
2764 | if (pvolume_info->cifs_acl) | 2845 | if (pvolume_info->cifs_acl) |
2765 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; | 2846 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; |
2847 | if (pvolume_info->backupuid_specified) | ||
2848 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPUID; | ||
2849 | if (pvolume_info->backupgid_specified) | ||
2850 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPGID; | ||
2766 | if (pvolume_info->override_uid) | 2851 | if (pvolume_info->override_uid) |
2767 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; | 2852 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; |
2768 | if (pvolume_info->override_gid) | 2853 | if (pvolume_info->override_gid) |
@@ -2795,29 +2880,41 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2795 | } | 2880 | } |
2796 | 2881 | ||
2797 | /* | 2882 | /* |
2798 | * When the server supports very large writes via POSIX extensions, we can | 2883 | * When the server supports very large reads and writes via POSIX extensions, |
2799 | * allow up to 2^24-1, minus the size of a WRITE_AND_X header, not including | 2884 | * we can allow up to 2^24-1, minus the size of a READ/WRITE_AND_X header, not |
2800 | * the RFC1001 length. | 2885 | * including the RFC1001 length. |
2801 | * | 2886 | * |
2802 | * Note that this might make for "interesting" allocation problems during | 2887 | * Note that this might make for "interesting" allocation problems during |
2803 | * writeback however as we have to allocate an array of pointers for the | 2888 | * writeback however as we have to allocate an array of pointers for the |
2804 | * pages. A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096. | 2889 | * pages. A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096. |
2890 | * | ||
2891 | * For reads, there is a similar problem as we need to allocate an array | ||
2892 | * of kvecs to handle the receive, though that should only need to be done | ||
2893 | * once. | ||
2805 | */ | 2894 | */ |
2806 | #define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4) | 2895 | #define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4) |
2896 | #define CIFS_MAX_RSIZE ((1<<24) - sizeof(READ_RSP) + 4) | ||
2807 | 2897 | ||
2808 | /* | 2898 | /* |
2809 | * When the server doesn't allow large posix writes, only allow a wsize of | 2899 | * When the server doesn't allow large posix writes, only allow a rsize/wsize |
2810 | * 128k minus the size of the WRITE_AND_X header. That allows for a write up | 2900 | * of 2^17-1 minus the size of the call header. That allows for a read or |
2811 | * to the maximum size described by RFC1002. | 2901 | * write up to the maximum size described by RFC1002. |
2812 | */ | 2902 | */ |
2813 | #define CIFS_MAX_RFC1002_WSIZE (128 * 1024 - sizeof(WRITE_REQ) + 4) | 2903 | #define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4) |
2904 | #define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP) + 4) | ||
2814 | 2905 | ||
2815 | /* | 2906 | /* |
2816 | * The default wsize is 1M. find_get_pages seems to return a maximum of 256 | 2907 | * The default wsize is 1M. find_get_pages seems to return a maximum of 256 |
2817 | * pages in a single call. With PAGE_CACHE_SIZE == 4k, this means we can fill | 2908 | * pages in a single call. With PAGE_CACHE_SIZE == 4k, this means we can fill |
2818 | * a single wsize request with a single call. | 2909 | * a single wsize request with a single call. |
2819 | */ | 2910 | */ |
2820 | #define CIFS_DEFAULT_WSIZE (1024 * 1024) | 2911 | #define CIFS_DEFAULT_IOSIZE (1024 * 1024) |
2912 | |||
2913 | /* | ||
2914 | * Windows only supports a max of 60k reads. Default to that when posix | ||
2915 | * extensions aren't in force. | ||
2916 | */ | ||
2917 | #define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024) | ||
2821 | 2918 | ||
2822 | static unsigned int | 2919 | static unsigned int |
2823 | cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) | 2920 | cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) |
@@ -2825,7 +2922,7 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) | |||
2825 | __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); | 2922 | __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); |
2826 | struct TCP_Server_Info *server = tcon->ses->server; | 2923 | struct TCP_Server_Info *server = tcon->ses->server; |
2827 | unsigned int wsize = pvolume_info->wsize ? pvolume_info->wsize : | 2924 | unsigned int wsize = pvolume_info->wsize ? pvolume_info->wsize : |
2828 | CIFS_DEFAULT_WSIZE; | 2925 | CIFS_DEFAULT_IOSIZE; |
2829 | 2926 | ||
2830 | /* can server support 24-bit write sizes? (via UNIX extensions) */ | 2927 | /* can server support 24-bit write sizes? (via UNIX extensions) */ |
2831 | if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP)) | 2928 | if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP)) |
@@ -2848,6 +2945,50 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) | |||
2848 | return wsize; | 2945 | return wsize; |
2849 | } | 2946 | } |
2850 | 2947 | ||
2948 | static unsigned int | ||
2949 | cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) | ||
2950 | { | ||
2951 | __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); | ||
2952 | struct TCP_Server_Info *server = tcon->ses->server; | ||
2953 | unsigned int rsize, defsize; | ||
2954 | |||
2955 | /* | ||
2956 | * Set default value... | ||
2957 | * | ||
2958 | * HACK alert! Ancient servers have very small buffers. Even though | ||
2959 | * MS-CIFS indicates that servers are only limited by the client's | ||
2960 | * bufsize for reads, testing against win98se shows that it throws | ||
2961 | * INVALID_PARAMETER errors if you try to request too large a read. | ||
2962 | * | ||
2963 | * If the server advertises a MaxBufferSize of less than one page, | ||
2964 | * assume that it also can't satisfy reads larger than that either. | ||
2965 | * | ||
2966 | * FIXME: Is there a better heuristic for this? | ||
2967 | */ | ||
2968 | if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP)) | ||
2969 | defsize = CIFS_DEFAULT_IOSIZE; | ||
2970 | else if (server->capabilities & CAP_LARGE_READ_X) | ||
2971 | defsize = CIFS_DEFAULT_NON_POSIX_RSIZE; | ||
2972 | else if (server->maxBuf >= PAGE_CACHE_SIZE) | ||
2973 | defsize = CIFSMaxBufSize; | ||
2974 | else | ||
2975 | defsize = server->maxBuf - sizeof(READ_RSP); | ||
2976 | |||
2977 | rsize = pvolume_info->rsize ? pvolume_info->rsize : defsize; | ||
2978 | |||
2979 | /* | ||
2980 | * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to | ||
2981 | * the client's MaxBufferSize. | ||
2982 | */ | ||
2983 | if (!(server->capabilities & CAP_LARGE_READ_X)) | ||
2984 | rsize = min_t(unsigned int, CIFSMaxBufSize, rsize); | ||
2985 | |||
2986 | /* hard limit of CIFS_MAX_RSIZE */ | ||
2987 | rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE); | ||
2988 | |||
2989 | return rsize; | ||
2990 | } | ||
2991 | |||
2851 | static int | 2992 | static int |
2852 | is_path_accessible(int xid, struct cifs_tcon *tcon, | 2993 | is_path_accessible(int xid, struct cifs_tcon *tcon, |
2853 | struct cifs_sb_info *cifs_sb, const char *full_path) | 2994 | struct cifs_sb_info *cifs_sb, const char *full_path) |
@@ -3041,6 +3182,22 @@ cifs_get_volume_info(char *mount_data, const char *devname) | |||
3041 | return volume_info; | 3182 | return volume_info; |
3042 | } | 3183 | } |
3043 | 3184 | ||
3185 | /* make sure ra_pages is a multiple of rsize */ | ||
3186 | static inline unsigned int | ||
3187 | cifs_ra_pages(struct cifs_sb_info *cifs_sb) | ||
3188 | { | ||
3189 | unsigned int reads; | ||
3190 | unsigned int rsize_pages = cifs_sb->rsize / PAGE_CACHE_SIZE; | ||
3191 | |||
3192 | if (rsize_pages >= default_backing_dev_info.ra_pages) | ||
3193 | return default_backing_dev_info.ra_pages; | ||
3194 | else if (rsize_pages == 0) | ||
3195 | return rsize_pages; | ||
3196 | |||
3197 | reads = default_backing_dev_info.ra_pages / rsize_pages; | ||
3198 | return reads * rsize_pages; | ||
3199 | } | ||
3200 | |||
3044 | int | 3201 | int |
3045 | cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) | 3202 | cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) |
3046 | { | 3203 | { |
@@ -3059,8 +3216,6 @@ cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) | |||
3059 | if (rc) | 3216 | if (rc) |
3060 | return rc; | 3217 | return rc; |
3061 | 3218 | ||
3062 | cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages; | ||
3063 | |||
3064 | #ifdef CONFIG_CIFS_DFS_UPCALL | 3219 | #ifdef CONFIG_CIFS_DFS_UPCALL |
3065 | try_mount_again: | 3220 | try_mount_again: |
3066 | /* cleanup activities if we're chasing a referral */ | 3221 | /* cleanup activities if we're chasing a referral */ |
@@ -3125,15 +3280,11 @@ try_mount_again: | |||
3125 | CIFSSMBQFSAttributeInfo(xid, tcon); | 3280 | CIFSSMBQFSAttributeInfo(xid, tcon); |
3126 | } | 3281 | } |
3127 | 3282 | ||
3128 | if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) { | ||
3129 | cifs_sb->rsize = 1024 * 127; | ||
3130 | cFYI(DBG2, "no very large read support, rsize now 127K"); | ||
3131 | } | ||
3132 | if (!(tcon->ses->capabilities & CAP_LARGE_READ_X)) | ||
3133 | cifs_sb->rsize = min(cifs_sb->rsize, | ||
3134 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); | ||
3135 | |||
3136 | cifs_sb->wsize = cifs_negotiate_wsize(tcon, volume_info); | 3283 | cifs_sb->wsize = cifs_negotiate_wsize(tcon, volume_info); |
3284 | cifs_sb->rsize = cifs_negotiate_rsize(tcon, volume_info); | ||
3285 | |||
3286 | /* tune readahead according to rsize */ | ||
3287 | cifs_sb->bdi.ra_pages = cifs_ra_pages(cifs_sb); | ||
3137 | 3288 | ||
3138 | remote_path_check: | 3289 | remote_path_check: |
3139 | #ifdef CONFIG_CIFS_DFS_UPCALL | 3290 | #ifdef CONFIG_CIFS_DFS_UPCALL |