s3:smb2_read: let smb2_sendfile_send_data() behave like send_file_readX()
authorStefan Metzmacher <metze@samba.org>
Thu, 10 Jul 2014 19:08:06 +0000 (21:08 +0200)
committerJeremy Allison <jra@samba.org>
Fri, 11 Jul 2014 20:57:17 +0000 (22:57 +0200)
We now pass the header to SMB_VFS_SENDFILE(), so we have to handle that also
in the fallback code.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10706

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Fri Jul 11 22:57:17 CEST 2014 on sn-devel-104

source3/smbd/smb2_read.c

index 05563b2900c6f5c58f00c922075f15bfa12da041..603c4a0c2784e6b1748d70f2758fbb9e1b1259b6 100644 (file)
@@ -184,11 +184,13 @@ static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state)
        uint32_t in_length = state->in_length;
        uint64_t in_offset = state->in_offset;
        files_struct *fsp = state->fsp;
+       const DATA_BLOB *hdr = state->smb2req->queue_entry.sendfile_header;
        ssize_t nread;
+       ssize_t ret;
 
        nread = SMB_VFS_SENDFILE(fsp->conn->sconn->sock,
                                 fsp,
-                                state->smb2req->queue_entry.sendfile_header,
+                                hdr,
                                 in_offset,
                                 in_length);
        DEBUG(10,("smb2_sendfile_send_data: SMB_VFS_SENDFILE returned %d on file %s\n",
@@ -196,11 +198,19 @@ static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state)
                fsp_str_dbg(fsp) ));
 
        if (nread == -1) {
-               if (errno == ENOSYS || errno == EINTR) {
+               /*
+                * Returning ENOSYS means no data at all was sent.
+                  Do this as a normal read. */
+               if (errno == ENOSYS) {
+                       goto normal_read;
+               }
+
+               if (errno == EINTR) {
                        /*
-                        * Special hack for broken systems with no working
-                        * sendfile. Fake this up by doing read/write calls.
-                       */
+                        * Special hack for broken Linux with no working sendfile. If we
+                        * return EINTR we sent the header but not the rest of the data.
+                        * Fake this up by doing read/write calls.
+                        */
                        set_use_sendfile(SNUM(fsp->conn), false);
                        nread = fake_sendfile(fsp, in_offset, in_length);
                        if (nread == -1) {
@@ -231,23 +241,50 @@ static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state)
                DEBUG(3, ("send_file_readX: sendfile sent zero bytes "
                        "falling back to the normal read: %s\n",
                        fsp_str_dbg(fsp)));
+               goto normal_read;
+       }
 
-               nread = fake_sendfile(fsp, in_offset, in_length);
-               if (nread == -1) {
-                       DEBUG(0,("smb2_sendfile_send_data: "
-                               "fake_sendfile failed for file "
-                               "%s (%s). Terminating\n",
-                               fsp_str_dbg(fsp),
-                               strerror(errno)));
-                       exit_server_cleanly("smb2_sendfile_send_data: "
-                               "fake_sendfile failed");
-               }
+       /*
+        * We got a short read
+        */
+       goto out;
+
+normal_read:
+       /* Send out the header. */
+       ret = write_data(fsp->conn->sconn->sock,
+                        (const char *)hdr->data, hdr->length);
+       if (ret != hdr->length) {
+               char addr[INET6_ADDRSTRLEN];
+               /*
+                * Try and give an error message saying what
+                * client failed.
+                */
+               DEBUG(0, ("smb2_sendfile_send_data: write_data failed "
+                         "for client %s. Error %s\n",
+                         get_peer_addr(fsp->conn->sconn->sock, addr,
+                                       sizeof(addr)),
+                         strerror(errno)));
+
+               DEBUG(0,("smb2_sendfile_send_data: write_data failed for file "
+                        "%s (%s). Terminating\n", fsp_str_dbg(fsp),
+                        strerror(errno)));
+               exit_server_cleanly("smb2_sendfile_send_data: write_data failed");
+       }
+       nread = fake_sendfile(fsp, in_offset, in_length);
+       if (nread == -1) {
+               DEBUG(0,("smb2_sendfile_send_data: "
+                       "fake_sendfile failed for file "
+                       "%s (%s). Terminating\n",
+                       fsp_str_dbg(fsp),
+                       strerror(errno)));
+               exit_server_cleanly("smb2_sendfile_send_data: "
+                       "fake_sendfile failed");
        }
 
   out:
 
        if (nread < in_length) {
-               sendfile_short_send(fsp, nread, 0, in_length);
+               sendfile_short_send(fsp, nread, hdr->length, in_length);
        }
 
        init_strict_lock_struct(fsp,