diff options
Diffstat (limited to 'fs/cifs/smb1ops.c')
-rw-r--r-- | fs/cifs/smb1ops.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index df20dd9e64ca..7e8a2bdd69c8 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c | |||
@@ -17,6 +17,7 @@ | |||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/pagemap.h> | ||
20 | #include "cifsglob.h" | 21 | #include "cifsglob.h" |
21 | #include "cifsproto.h" | 22 | #include "cifsproto.h" |
22 | #include "cifs_debug.h" | 23 | #include "cifs_debug.h" |
@@ -410,6 +411,89 @@ cifs_negotiate(const unsigned int xid, struct cifs_ses *ses) | |||
410 | return rc; | 411 | return rc; |
411 | } | 412 | } |
412 | 413 | ||
414 | static unsigned int | ||
415 | cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) | ||
416 | { | ||
417 | __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); | ||
418 | struct TCP_Server_Info *server = tcon->ses->server; | ||
419 | unsigned int wsize; | ||
420 | |||
421 | /* start with specified wsize, or default */ | ||
422 | if (volume_info->wsize) | ||
423 | wsize = volume_info->wsize; | ||
424 | else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP)) | ||
425 | wsize = CIFS_DEFAULT_IOSIZE; | ||
426 | else | ||
427 | wsize = CIFS_DEFAULT_NON_POSIX_WSIZE; | ||
428 | |||
429 | /* can server support 24-bit write sizes? (via UNIX extensions) */ | ||
430 | if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP)) | ||
431 | wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1002_WSIZE); | ||
432 | |||
433 | /* | ||
434 | * no CAP_LARGE_WRITE_X or is signing enabled without CAP_UNIX set? | ||
435 | * Limit it to max buffer offered by the server, minus the size of the | ||
436 | * WRITEX header, not including the 4 byte RFC1001 length. | ||
437 | */ | ||
438 | if (!(server->capabilities & CAP_LARGE_WRITE_X) || | ||
439 | (!(server->capabilities & CAP_UNIX) && | ||
440 | (server->sec_mode & (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)))) | ||
441 | wsize = min_t(unsigned int, wsize, | ||
442 | server->maxBuf - sizeof(WRITE_REQ) + 4); | ||
443 | |||
444 | /* limit to the amount that we can kmap at once */ | ||
445 | wsize = min_t(unsigned int, wsize, CIFS_KMAP_SIZE_LIMIT); | ||
446 | |||
447 | /* hard limit of CIFS_MAX_WSIZE */ | ||
448 | wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE); | ||
449 | |||
450 | return wsize; | ||
451 | } | ||
452 | |||
453 | static unsigned int | ||
454 | cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) | ||
455 | { | ||
456 | __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); | ||
457 | struct TCP_Server_Info *server = tcon->ses->server; | ||
458 | unsigned int rsize, defsize; | ||
459 | |||
460 | /* | ||
461 | * Set default value... | ||
462 | * | ||
463 | * HACK alert! Ancient servers have very small buffers. Even though | ||
464 | * MS-CIFS indicates that servers are only limited by the client's | ||
465 | * bufsize for reads, testing against win98se shows that it throws | ||
466 | * INVALID_PARAMETER errors if you try to request too large a read. | ||
467 | * OS/2 just sends back short reads. | ||
468 | * | ||
469 | * If the server doesn't advertise CAP_LARGE_READ_X, then assume that | ||
470 | * it can't handle a read request larger than its MaxBufferSize either. | ||
471 | */ | ||
472 | if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP)) | ||
473 | defsize = CIFS_DEFAULT_IOSIZE; | ||
474 | else if (server->capabilities & CAP_LARGE_READ_X) | ||
475 | defsize = CIFS_DEFAULT_NON_POSIX_RSIZE; | ||
476 | else | ||
477 | defsize = server->maxBuf - sizeof(READ_RSP); | ||
478 | |||
479 | rsize = volume_info->rsize ? volume_info->rsize : defsize; | ||
480 | |||
481 | /* | ||
482 | * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to | ||
483 | * the client's MaxBufferSize. | ||
484 | */ | ||
485 | if (!(server->capabilities & CAP_LARGE_READ_X)) | ||
486 | rsize = min_t(unsigned int, CIFSMaxBufSize, rsize); | ||
487 | |||
488 | /* limit to the amount that we can kmap at once */ | ||
489 | rsize = min_t(unsigned int, rsize, CIFS_KMAP_SIZE_LIMIT); | ||
490 | |||
491 | /* hard limit of CIFS_MAX_RSIZE */ | ||
492 | rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE); | ||
493 | |||
494 | return rsize; | ||
495 | } | ||
496 | |||
413 | static void | 497 | static void |
414 | cifs_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) | 498 | cifs_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) |
415 | { | 499 | { |
@@ -678,6 +762,8 @@ struct smb_version_operations smb1_operations = { | |||
678 | .check_trans2 = cifs_check_trans2, | 762 | .check_trans2 = cifs_check_trans2, |
679 | .need_neg = cifs_need_neg, | 763 | .need_neg = cifs_need_neg, |
680 | .negotiate = cifs_negotiate, | 764 | .negotiate = cifs_negotiate, |
765 | .negotiate_wsize = cifs_negotiate_wsize, | ||
766 | .negotiate_rsize = cifs_negotiate_rsize, | ||
681 | .sess_setup = CIFS_SessSetup, | 767 | .sess_setup = CIFS_SessSetup, |
682 | .logoff = CIFSSMBLogoff, | 768 | .logoff = CIFSSMBLogoff, |
683 | .tree_connect = CIFSTCon, | 769 | .tree_connect = CIFSTCon, |