From 7c5ea400ad1f280f5c338c31a0a893154340fdb3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 10 Jul 2014 21:08:06 +0200 Subject: [PATCH] s3:smb2_read: let smb2_sendfile_send_data() behave like send_file_readX() 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 Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Fri Jul 11 22:57:17 CEST 2014 on sn-devel-104 --- source3/smbd/smb2_read.c | 69 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/source3/smbd/smb2_read.c b/source3/smbd/smb2_read.c index 05563b2..603c4a0 100644 --- a/source3/smbd/smb2_read.c +++ b/source3/smbd/smb2_read.c @@ -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, -- 2.0.0.526.g5318336