From 5ade894f32377ffaed3fc085810892509a6e8c66 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 4 Oct 1998 06:22:08 +0000 Subject: modified cli_read() and cli_write() to issue multiple outstanding read/write requests for large reads. up to max_mux requests may be outstanding. This gives _much_ better throughput and should allow smbsh to saturate just about any network. this is an implementation of the "fast SMB" method I described on the CIFS list a couple of months back. (This used to be commit c728d1c5d6e4626d2f8e318eab4df32acc8cb505) --- source3/include/client.h | 1 + source3/libsmb/clientgen.c | 188 ++++++++++++++++++++++++++++++------------ source3/smbwrapper/smbw.c | 5 +- source3/smbwrapper/smbw.h | 1 + source3/smbwrapper/smbw_dir.c | 2 +- 5 files changed, 139 insertions(+), 58 deletions(-) (limited to 'source3') diff --git a/source3/include/client.h b/source3/include/client.h index 628834925b..c312d29bf7 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -88,6 +88,7 @@ struct cli_state { int writebraw_supported; int timeout; int max_xmit; + int max_mux; char *outbuf; char *inbuf; int bufsize; diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 1d2ea199c0..cd6d295094 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -1129,108 +1129,185 @@ BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int } + +/**************************************************************************** +issue a single SMBread and don't wait for a reply +****************************************************************************/ +static void cli_issue_read(struct cli_state *cli, int fnum, off_t offset, + size_t size, int i) +{ + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); + + set_message(cli->outbuf,10,0,True); + + CVAL(cli->outbuf,smb_com) = SMBreadX; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + CVAL(cli->outbuf,smb_vwv0) = 0xFF; + SSVAL(cli->outbuf,smb_vwv2,fnum); + SIVAL(cli->outbuf,smb_vwv3,offset); + SSVAL(cli->outbuf,smb_vwv5,size); + SSVAL(cli->outbuf,smb_vwv6,size); + SSVAL(cli->outbuf,smb_mid,cli->mid + i); + + send_smb(cli->fd,cli->outbuf); +} + /**************************************************************************** read from a file ****************************************************************************/ size_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size) { char *p; - int total=0; - - while (total < size) { - int size1 = MIN(size-total, cli->max_xmit - (smb_size+32)); + int total = -1; + int issued=0; + int received=0; + int mpx = MAX(cli->max_mux-1, 1); + int block = (cli->max_xmit - (smb_size+32)) & ~1023; + int mid; + int blocks = (size + (block-1)) / block; + + while (received < blocks) { int size2; - bzero(cli->outbuf,smb_size); - bzero(cli->inbuf,smb_size); - - set_message(cli->outbuf,10,0,True); - - CVAL(cli->outbuf,smb_com) = SMBreadX; - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); - - CVAL(cli->outbuf,smb_vwv0) = 0xFF; - SSVAL(cli->outbuf,smb_vwv2,fnum); - SIVAL(cli->outbuf,smb_vwv3,offset+total); - SSVAL(cli->outbuf,smb_vwv5,size1); - SSVAL(cli->outbuf,smb_vwv6,size1); + while (issued - received < mpx && issued < blocks) { + int size1 = MIN(block, size-issued*block); + cli_issue_read(cli, fnum, offset+issued*block, size1, issued); + issued++; + } - send_smb(cli->fd,cli->outbuf); if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { - return total?total:-1; + return total; } + received++; + mid = SVAL(cli->inbuf, smb_mid) - cli->mid; + size2 = SVAL(cli->inbuf, smb_vwv5); + if (CVAL(cli->inbuf,smb_rcls) != 0) { - return total?total:-1; + blocks = MIN(blocks, mid-1); + continue; } - size2 = SVAL(cli->inbuf, smb_vwv5); - if (size2 > size1) { + if (size2 <= 0) { + blocks = MIN(blocks, mid-1); + /* this distinguishes EOF from an error */ + total = MAX(total, 0); + continue; + } + + if (size2 > block) { DEBUG(0,("server returned more than we wanted!\n")); exit(1); } + if (mid >= issued) { + DEBUG(0,("invalid mid from server!\n")); + exit(1); + } p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6); - if (size2 <= 0) break; + memcpy(buf+mid*block, p, size2); - memcpy(buf+total, p, size2); - - total += size2; + total = MAX(total, mid*block + size2); } + while (received < issued) { + client_receive_smb(cli->fd,cli->inbuf,cli->timeout); + received++; + } + return total; } /**************************************************************************** - write to a file +issue a single SMBwrite and don't wait for a reply ****************************************************************************/ -size_t cli_write(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size) +static void cli_issue_write(struct cli_state *cli, int fnum, off_t offset, char *buf, + size_t size, int i) { char *p; - int total=0; - - while (total < size) { - int size1 = MIN(size-total, cli->max_xmit - (smb_size+32)); - int size2; - - bzero(cli->outbuf,smb_size); - bzero(cli->inbuf,smb_size); - set_message(cli->outbuf,12,size1,True); + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); - CVAL(cli->outbuf,smb_com) = SMBwriteX; - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); + set_message(cli->outbuf,12,size,True); + + CVAL(cli->outbuf,smb_com) = SMBwriteX; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + CVAL(cli->outbuf,smb_vwv0) = 0xFF; + SSVAL(cli->outbuf,smb_vwv2,fnum); + SIVAL(cli->outbuf,smb_vwv3,offset); + + SSVAL(cli->outbuf,smb_vwv10,size); + SSVAL(cli->outbuf,smb_vwv11, + smb_buf(cli->outbuf) - smb_base(cli->outbuf)); + + p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11); + memcpy(p, buf, size); - CVAL(cli->outbuf,smb_vwv0) = 0xFF; - SSVAL(cli->outbuf,smb_vwv2,fnum); - SIVAL(cli->outbuf,smb_vwv3,offset+total); + SSVAL(cli->outbuf,smb_mid,cli->mid + i); + + send_smb(cli->fd,cli->outbuf); +} - SSVAL(cli->outbuf,smb_vwv10,size1); - SSVAL(cli->outbuf,smb_vwv11, - smb_buf(cli->outbuf) - smb_base(cli->outbuf)); +/**************************************************************************** + write to a file +****************************************************************************/ +size_t cli_write(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size) +{ + int total = -1; + int issued=0; + int received=0; + int mpx = MAX(cli->max_mux-1, 1); + int block = (cli->max_xmit - (smb_size+32)) & ~1023; + int mid; + int blocks = (size + (block-1)) / block; + + while (received < blocks) { + int size2; - p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11); - memcpy(p, buf+total, size1); + while (issued - received < mpx && issued < blocks) { + int size1 = MIN(block, size-issued*block); + cli_issue_write(cli, fnum, offset+issued*block, buf + issued*block, + size1, issued); + issued++; + } - send_smb(cli->fd,cli->outbuf); if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { - return -1; + return total; } + received++; + mid = SVAL(cli->inbuf, smb_mid) - cli->mid; + size2 = SVAL(cli->inbuf, smb_vwv2); + if (CVAL(cli->inbuf,smb_rcls) != 0) { - return -1; + blocks = MIN(blocks, mid-1); + continue; } - size2 = SVAL(cli->inbuf, smb_vwv2); - - if (size2 <= 0) break; + if (size2 <= 0) { + blocks = MIN(blocks, mid-1); + /* this distinguishes EOF from an error */ + total = MAX(total, 0); + continue; + } total += size2; + + total = MAX(total, mid*block + size2); } + while (received < issued) { + client_receive_smb(cli->fd,cli->inbuf,cli->timeout); + received++; + } + return total; } @@ -1992,6 +2069,7 @@ BOOL cli_negprot(struct cli_state *cli) if (cli->protocol >= PROTOCOL_NT1) { /* NT protocol */ cli->sec_mode = CVAL(cli->inbuf,smb_vwv1); + cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1); cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1); cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1); cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1)*60; diff --git a/source3/smbwrapper/smbw.c b/source3/smbwrapper/smbw.c index 11192bedd7..e933fc3636 100644 --- a/source3/smbwrapper/smbw.c +++ b/source3/smbwrapper/smbw.c @@ -523,7 +523,7 @@ int smbw_open(const char *fname, int flags, mode_t mode) goto failed; } file->srv = srv; - file->fd = open("/dev/null", O_WRONLY); + file->fd = open(SMBW_DUMMY, O_WRONLY); if (file->fd == -1) { errno = EMFILE; goto failed; @@ -567,7 +567,8 @@ ssize_t smbw_read(int fd, void *buf, size_t count) struct smbw_file *file; int ret; - DEBUG(4,("%s %d\n", __FUNCTION__, (int)count)); + DEBUG(4,("%s %d\n", + __FUNCTION__, (int)count)); smbw_busy++; diff --git a/source3/smbwrapper/smbw.h b/source3/smbwrapper/smbw.h index 5fc864456e..af48061ff0 100644 --- a/source3/smbwrapper/smbw.h +++ b/source3/smbwrapper/smbw.h @@ -20,6 +20,7 @@ */ #define SMBW_PREFIX "/smb/" +#define SMBW_DUMMY "/dev/null" #define SMBW_CLI_FD 512 #define SMBW_MAX_OPEN 8192 diff --git a/source3/smbwrapper/smbw_dir.c b/source3/smbwrapper/smbw_dir.c index c437a53e1f..a127048793 100644 --- a/source3/smbwrapper/smbw_dir.c +++ b/source3/smbwrapper/smbw_dir.c @@ -175,7 +175,7 @@ int smbw_dir_open(const char *fname) cur_dir = NULL; - fd = open("/dev/null", O_WRONLY); + fd = open(SMBW_DUMMY, O_WRONLY); if (fd == -1) { errno = EMFILE; goto failed; -- cgit