The branch, v3-2-test has been updated
       via  c364d44de2285cabb83a0c105f061b8640a3a431 (commit)
       via  75b5b7b2664e4d55aa97418f42a415fd88d3d4bd (commit)
       via  6bfcf1904ef50b74656d1cfb7f11b730481d2c6c (commit)
       via  2d05db409e11443480c8cdc52e205f57aa512fba (commit)
       via  9f6710abfaafa4b918b0c55547d5cd0823a26a56 (commit)
      from  b995677f9895ba7fa9744b079ebc905713e59d40 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-2-test


- Log -----------------------------------------------------------------
commit c364d44de2285cabb83a0c105f061b8640a3a431
Author: Volker Lendecke <[email protected]>
Date:   Mon Dec 22 22:42:44 2008 +0100

    Add code to test write_data_iov a bit

commit 75b5b7b2664e4d55aa97418f42a415fd88d3d4bd
Author: Volker Lendecke <[email protected]>
Date:   Mon Dec 22 22:32:12 2008 +0100

    Attempt to fix bug 5953: Make cli_send_smb_direct_writeX use writev
    
    It seems there are SMB servers around which can't cope with the write header
    being sent in a packet of its own. With writev we keep the advantage of 
direct
    writes, giving the kernel the chance to coalesce the write calls.

commit 6bfcf1904ef50b74656d1cfb7f11b730481d2c6c
Author: Volker Lendecke <[email protected]>
Date:   Mon Dec 22 22:17:59 2008 +0100

    Make write_data use write_data_iov

commit 2d05db409e11443480c8cdc52e205f57aa512fba
Author: Volker Lendecke <[email protected]>
Date:   Mon Dec 22 22:17:28 2008 +0100

    Add write_data_iov

commit 9f6710abfaafa4b918b0c55547d5cd0823a26a56
Author: Volker Lendecke <[email protected]>
Date:   Sun Dec 21 23:22:30 2008 +0100

    Add sys_writev

-----------------------------------------------------------------------

Summary of changes:
 source/lib/system.c       |   25 ++++++++++
 source/lib/util_sock.c    |  115 ++++++++++++++++++++++++++++++++++++---------
 source/libsmb/clientgen.c |   40 +++++-----------
 3 files changed, 130 insertions(+), 50 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source/lib/system.c b/source/lib/system.c
index eabb6d6..48ecf90 100644
--- a/source/lib/system.c
+++ b/source/lib/system.c
@@ -142,6 +142,31 @@ ssize_t sys_write(int fd, const void *buf, size_t count)
 }
 
 /*******************************************************************
+A writev wrapper that will deal with EINTR.
+********************************************************************/
+
+ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt)
+{
+       ssize_t ret;
+
+#if 0
+       /* Try to confuse write_data_iov a bit */
+       if ((random() % 5) == 0) {
+               return sys_write(fd, iov[0].iov_base, iov[0].iov_len);
+       }
+       if (iov[0].iov_len > 1) {
+               return sys_write(fd, iov[0].iov_base,
+                                (random() % (iov[0].iov_len-1)) + 1);
+       }
+#endif
+
+       do {
+               ret = writev(fd, iov, iovcnt);
+       } while (ret == -1 && errno == EINTR);
+       return ret;
+}
+
+/*******************************************************************
 A pread wrapper that will deal with EINTR and 64-bit file offsets.
 ********************************************************************/
 
diff --git a/source/lib/util_sock.c b/source/lib/util_sock.c
index e64b003..9c37e0c 100644
--- a/source/lib/util_sock.c
+++ b/source/lib/util_sock.c
@@ -1037,40 +1037,109 @@ NTSTATUS read_data(int fd, char *buffer, size_t N)
 }
 
 /****************************************************************************
- Write data to a fd.
+ Write all data from an iov array
 ****************************************************************************/
 
-ssize_t write_data(int fd, const char *buffer, size_t N)
+ssize_t write_data_iov(int fd, const struct iovec *orig_iov, int iovcnt)
 {
-       size_t total=0;
-       ssize_t ret;
-       char addr[INET6_ADDRSTRLEN];
+       int i;
+       size_t to_send;
+       ssize_t thistime;
+       size_t sent;
+       struct iovec *iov_copy, *iov;
 
-       while (total < N) {
-               ret = sys_write(fd,buffer + total,N - total);
+       to_send = 0;
+       for (i=0; i<iovcnt; i++) {
+               to_send += orig_iov[i].iov_len;
+       }
 
-               if (ret == -1) {
-                       if (fd == get_client_fd()) {
-                               /* Try and give an error message saying
-                                * what client failed. */
-                               DEBUG(0,("write_data: write failure in "
-                                       "writing to client %s. Error %s\n",
-                                       get_peer_addr(fd,addr,sizeof(addr)),
-                                       strerror(errno) ));
-                       } else {
-                               DEBUG(0,("write_data: write failure. "
-                                       "Error = %s\n", strerror(errno) ));
+       thistime = sys_writev(fd, orig_iov, iovcnt);
+       if ((thistime <= 0) || (thistime == to_send)) {
+               return thistime;
+       }
+       sent = thistime;
+
+       /*
+        * We could not send everything in one call. Make a copy of iov that
+        * we can mess with. We keep a copy of the array start in iov_copy for
+        * the TALLOC_FREE, because we're going to modify iov later on,
+        * discarding elements.
+        */
+
+       iov_copy = (struct iovec *)TALLOC_MEMDUP(
+               talloc_tos(), orig_iov, sizeof(struct iovec) * iovcnt);
+
+       if (iov_copy == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+       iov = iov_copy;
+
+       while (sent < to_send) {
+               /*
+                * We have to discard "thistime" bytes from the beginning
+                * iov array, "thistime" contains the number of bytes sent
+                * via writev last.
+                */
+               while (thistime > 0) {
+                       if (thistime < iov[0].iov_len) {
+                               char *new_base =
+                                       (char *)iov[0].iov_base + thistime;
+                               iov[0].iov_base = new_base;
+                               iov[0].iov_len -= thistime;
+                               break;
                        }
-                       return -1;
+                       thistime -= iov[0].iov_len;
+                       iov += 1;
+                       iovcnt -= 1;
                }
 
-               if (ret == 0) {
-                       return total;
+               thistime = sys_writev(fd, iov, iovcnt);
+               if (thistime <= 0) {
+                       break;
                }
+               sent += thistime;
+       }
+
+       TALLOC_FREE(iov_copy);
+       return sent;
+}
+
+/****************************************************************************
+ Write data to a fd.
+****************************************************************************/
+
+/****************************************************************************
+ Write data to a fd.
+****************************************************************************/
+
+ssize_t write_data(int fd, const char *buffer, size_t N)
+{
+       ssize_t ret;
+       struct iovec iov;
+
+       iov.iov_base = CONST_DISCARD(char *, buffer);
+       iov.iov_len = N;
+
+       ret = write_data_iov(fd, &iov, 1);
+       if (ret >= 0) {
+               return ret;
+       }
 
-               total += ret;
+       if (fd == get_client_fd()) {
+               char addr[INET6_ADDRSTRLEN];
+               /*
+                * Try and give an error message saying what client failed.
+                */
+               DEBUG(0, ("write_data: write failure in writing to client %s. "
+                         "Error %s\n", get_peer_addr(fd,addr,sizeof(addr)),
+                         strerror(errno)));
+       } else {
+               DEBUG(0,("write_data: write failure. Error = %s\n",
+                        strerror(errno) ));
        }
-       return (ssize_t)total;
+
+       return -1;
 }
 
 /****************************************************************************
diff --git a/source/libsmb/clientgen.c b/source/libsmb/clientgen.c
index d6d26e4..aeb1c28 100644
--- a/source/libsmb/clientgen.c
+++ b/source/libsmb/clientgen.c
@@ -315,7 +315,7 @@ bool cli_send_smb_direct_writeX(struct cli_state *cli,
        /* First length to send is the offset to the data. */
        size_t len = SVAL(cli->outbuf,smb_vwv11) + 4;
        size_t nwritten=0;
-       ssize_t ret;
+       struct iovec iov[2];
 
        /* fd == -1 causes segfaults -- Tom ([email protected]) */
        if (cli->fd == -1) {
@@ -327,33 +327,19 @@ bool cli_send_smb_direct_writeX(struct cli_state *cli,
                return false;
        }
 
-       while (nwritten < len) {
-               ret = write_socket(cli->fd,cli->outbuf+nwritten,len - nwritten);
-               if (ret <= 0) {
-                       close(cli->fd);
-                       cli->fd = -1;
-                       cli->smb_rw_error = SMB_WRITE_ERROR;
-                       DEBUG(0,("Error writing %d bytes to client. %d (%s)\n",
-                               (int)len,(int)ret, strerror(errno) ));
-                       return false;
-               }
-               nwritten += ret;
-       }
+       iov[0].iov_base = cli->outbuf;
+       iov[0].iov_len = len;
+       iov[1].iov_base = CONST_DISCARD(char *, p);
+       iov[1].iov_len = extradata;
 
-       /* Now write the extra data. */
-       nwritten=0;
-       while (nwritten < extradata) {
-               ret = write_socket(cli->fd,p+nwritten,extradata - nwritten);
-               if (ret <= 0) {
-                       close(cli->fd);
-                       cli->fd = -1;
-                       cli->smb_rw_error = SMB_WRITE_ERROR;
-                       DEBUG(0,("Error writing %d extradata "
-                               "bytes to client. %d (%s)\n",
-                               (int)extradata,(int)ret, strerror(errno) ));
-                       return false;
-               }
-               nwritten += ret;
+       nwritten = write_data_iov(cli->fd, iov, 2);
+       if (nwritten < (len + extradata)) {
+               close(cli->fd);
+               cli->fd = -1;
+               cli->smb_rw_error = SMB_WRITE_ERROR;
+               DEBUG(0,("Error writing %d bytes to client. (%s)\n",
+                        (int)(len+extradata), strerror(errno)));
+               return false;
        }
 
        /* Increment the mid so we can tell between responses. */


-- 
Samba Shared Repository

Reply via email to