#include "smbd/smbd.h"
#include "smbd/globals.h"
#include "../lib/util/tevent_ntstatus.h"
+#include "../lib/util/tevent_unix.h"
+#include "lib/tevent_wait.h"
+
+/****************************************************************************
+ Statics plus accessor functions.
+*****************************************************************************/
+
+static int aio_pending_size = 100; /* tevent supports 100 signals SA_SIGINFO */
+
+int get_aio_pending_size(void)
+{
+ return aio_pending_size;
+}
+
+void set_aio_pending_size(int newsize)
+{
+ aio_pending_size = newsize;
+}
/****************************************************************************
The buffer we keep around whilst an aio request is in process.
}
fsp->num_aio_requests -= 1;
fsp->aio_requests[i] = fsp->aio_requests[fsp->num_aio_requests];
+
+ if (fsp->num_aio_requests == 0) {
+ tevent_wait_done(fsp->deferred_close);
+ }
return 0;
}
-static bool aio_add_req_to_fsp(files_struct *fsp, struct tevent_req *req)
+bool aio_add_req_to_fsp(files_struct *fsp, struct tevent_req *req)
{
size_t array_len;
struct aio_req_fsp_link *lnk;
return NT_STATUS_RETRY;
}
- if (outstanding_aio_calls >= aio_pending_size) {
+ if (outstanding_aio_calls >= get_aio_pending_size()) {
DEBUG(10,("schedule_aio_read_and_X: Already have %d aio "
"activities outstanding.\n",
outstanding_aio_calls ));
/* The following is safe from integer wrap as we've already checked
smb_maxcnt is 128k or less. Wct is 12 for read replies */
- bufsize = smb_size + 12 * 2 + smb_maxcnt;
+ bufsize = smb_size + 12 * 2 + smb_maxcnt + 1 /* padding byte */;
if ((aio_ex = create_aio_extra(NULL, fsp, bufsize)) == NULL) {
DEBUG(10,("schedule_aio_read_and_X: malloc fail.\n"));
construct_reply_common_req(smbreq, (char *)aio_ex->outbuf.data);
srv_set_message((char *)aio_ex->outbuf.data, 12, 0, True);
SCVAL(aio_ex->outbuf.data,smb_vwv0,0xFF); /* Never a chained reply. */
+ SCVAL(smb_buf(aio_ex->outbuf.data), 0, 0); /* padding byte */
init_strict_lock_struct(fsp, (uint64_t)smbreq->smbpid,
(uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
aio_ex->offset = startpos;
req = SMB_VFS_PREAD_SEND(aio_ex, fsp->conn->sconn->ev_ctx,
- fsp, smb_buf(aio_ex->outbuf.data),
+ fsp,
+ smb_buf(aio_ex->outbuf.data) + 1 /* pad */,
smb_maxcnt, startpos);
if (req == NULL) {
DEBUG(0,("schedule_aio_read_and_X: aio_read failed. "
files_struct *fsp = aio_ex->fsp;
int outsize;
char *outbuf = (char *)aio_ex->outbuf.data;
- char *data = smb_buf(outbuf);
+ char *data = smb_buf(outbuf) + 1 /* padding byte */;
ssize_t nread;
int err;
ERROR_NT(map_nt_error_from_unix(err));
outsize = srv_set_message(outbuf,0,0,true);
} else {
- outsize = srv_set_message(outbuf, 12, nread, False);
+ outsize = srv_set_message(outbuf, 12,
+ nread + 1 /* padding byte */, false);
SSVAL(outbuf,smb_vwv2, 0xFFFF); /* Remaining - must be * -1. */
SSVAL(outbuf,smb_vwv5, nread);
SSVAL(outbuf,smb_vwv6, smb_offset(data,outbuf));
}
smb_setlen(outbuf, outsize - 4);
show_msg(outbuf);
- if (!srv_send_smb(aio_ex->smbreq->sconn, outbuf,
+ if (!srv_send_smb(aio_ex->smbreq->xconn, outbuf,
true, aio_ex->smbreq->seqnum+1,
IS_CONN_ENCRYPTED(fsp->conn), NULL)) {
exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
TALLOC_FREE(aio_ex);
}
+struct pwrite_fsync_state {
+ struct tevent_context *ev;
+ files_struct *fsp;
+ bool write_through;
+ ssize_t nwritten;
+};
+
+static void pwrite_fsync_write_done(struct tevent_req *subreq);
+static void pwrite_fsync_sync_done(struct tevent_req *subreq);
+
+static struct tevent_req *pwrite_fsync_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *fsp,
+ const void *data,
+ size_t n, off_t offset,
+ bool write_through)
+{
+ struct tevent_req *req, *subreq;
+ struct pwrite_fsync_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct pwrite_fsync_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->fsp = fsp;
+ state->write_through = write_through;
+
+ subreq = SMB_VFS_PWRITE_SEND(state, ev, fsp, data, n, offset);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, pwrite_fsync_write_done, req);
+ return req;
+}
+
+static void pwrite_fsync_write_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct pwrite_fsync_state *state = tevent_req_data(
+ req, struct pwrite_fsync_state);
+ connection_struct *conn = state->fsp->conn;
+ int err;
+ bool do_sync;
+
+ state->nwritten = SMB_VFS_PWRITE_RECV(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (state->nwritten == -1) {
+ tevent_req_error(req, err);
+ return;
+ }
+
+ do_sync = (lp_strict_sync(SNUM(conn)) &&
+ (lp_sync_always(SNUM(conn)) || state->write_through));
+ if (!do_sync) {
+ tevent_req_done(req);
+ return;
+ }
+
+ subreq = SMB_VFS_FSYNC_SEND(state, state->ev, state->fsp);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, pwrite_fsync_sync_done, req);
+}
+
+static void pwrite_fsync_sync_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ int ret, err;
+
+ ret = SMB_VFS_FSYNC_RECV(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, err);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static ssize_t pwrite_fsync_recv(struct tevent_req *req, int *perr)
+{
+ struct pwrite_fsync_state *state = tevent_req_data(
+ req, struct pwrite_fsync_state);
+
+ if (tevent_req_is_unix_error(req, perr)) {
+ return -1;
+ }
+ return state->nwritten;
+}
+
static void aio_pwrite_smb1_done(struct tevent_req *req);
/****************************************************************************
return NT_STATUS_RETRY;
}
- if (outstanding_aio_calls >= aio_pending_size) {
+ if (outstanding_aio_calls >= get_aio_pending_size()) {
DEBUG(3,("schedule_aio_write_and_X: Already have %d aio "
"activities outstanding.\n",
outstanding_aio_calls ));
aio_ex->nbyte = numtowrite;
aio_ex->offset = startpos;
- req = SMB_VFS_PWRITE_SEND(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
- data, numtowrite, startpos);
+ req = pwrite_fsync_send(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
+ data, numtowrite, startpos,
+ aio_ex->write_through);
if (req == NULL) {
DEBUG(3,("schedule_aio_wrote_and_X: aio_write failed. "
"Error %s\n", strerror(errno) ));
contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
- if (!aio_ex->write_through && !lp_syncalways(SNUM(fsp->conn))
+ if (!aio_ex->write_through && !lp_sync_always(SNUM(fsp->conn))
&& fsp->aio_write_behind) {
/* Lie to the client and immediately claim we finished the
* write. */
SSVAL(aio_ex->outbuf.data,smb_vwv2,numtowrite);
SSVAL(aio_ex->outbuf.data,smb_vwv4,(numtowrite>>16)&1);
show_msg((char *)aio_ex->outbuf.data);
- if (!srv_send_smb(aio_ex->smbreq->sconn,
+ if (!srv_send_smb(aio_ex->smbreq->xconn,
(char *)aio_ex->outbuf.data,
true, aio_ex->smbreq->seqnum+1,
IS_CONN_ENCRYPTED(fsp->conn),
ssize_t nwritten;
int err;
- nwritten = SMB_VFS_PWRITE_RECV(req, &err);
+ nwritten = pwrite_fsync_recv(req, &err);
TALLOC_FREE(req);
DEBUG(10, ("pwrite_recv returned %d, err = %s\n", (int)nwritten,
/* Unlock now we're done. */
SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &aio_ex->lock);
+ mark_file_modified(fsp);
+
if (fsp->aio_write_behind) {
if (nwritten != numtowrite) {
ERROR_NT(map_nt_error_from_unix(err));
srv_set_message(outbuf,0,0,true);
} else {
- NTSTATUS status;
-
SSVAL(outbuf,smb_vwv2,nwritten);
SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1);
if (nwritten < (ssize_t)numtowrite) {
DEBUG(3,("handle_aio_write: %s, num=%d wrote=%d\n",
fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
- status = sync_file(fsp->conn,fsp, aio_ex->write_through);
- if (!NT_STATUS_IS_OK(status)) {
- ERROR_BOTH(map_nt_error_from_unix(errno),
- ERRHRD, ERRdiskfull);
- srv_set_message(outbuf,0,0,true);
- DEBUG(5, ("handle_aio_write: sync_file for %s "
- "returned %s\n",
- fsp_str_dbg(fsp), nt_errstr(status)));
- }
aio_ex->fsp->fh->pos = aio_ex->offset + nwritten;
}
show_msg(outbuf);
- if (!srv_send_smb(aio_ex->smbreq->sconn, outbuf,
+ if (!srv_send_smb(aio_ex->smbreq->xconn, outbuf,
true, aio_ex->smbreq->seqnum+1,
IS_CONN_ENCRYPTED(fsp->conn),
NULL)) {
return NT_STATUS_RETRY;
}
+ if (fsp->op == NULL) {
+ /* No AIO on internal opens. */
+ return NT_STATUS_RETRY;
+ }
+
if ((!min_aio_read_size || (smb_maxcnt < min_aio_read_size))
&& !SMB_VFS_AIO_FORCE(fsp)) {
/* Too small a read for aio request. */
return NT_STATUS_RETRY;
}
- if (outstanding_aio_calls >= aio_pending_size) {
+ if (outstanding_aio_calls >= get_aio_pending_size()) {
DEBUG(10,("smb2: Already have %d aio "
"activities outstanding.\n",
outstanding_aio_calls ));
return NT_STATUS_NO_MEMORY;
}
- init_strict_lock_struct(fsp, (uint64_t)smbreq->smbpid,
+ init_strict_lock_struct(fsp, fsp->op->global->open_persistent_id,
(uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
&aio_ex->lock);
(nread == -1) ? strerror(err) : "no error"));
if (fsp == NULL) {
- DEBUG( 3, ("aio_pread_smb2_done: file closed whilst "
- "aio outstanding (mid[%llu]).\n",
- (unsigned long long)aio_ex->smbreq->mid));
+ DEBUG(3, ("%s: request cancelled (mid[%ju])\n",
+ __func__, (uintmax_t)aio_ex->smbreq->mid));
TALLOC_FREE(aio_ex);
+ tevent_req_nterror(subreq, NT_STATUS_INTERNAL_ERROR);
return;
}
return NT_STATUS_RETRY;
}
+ if (fsp->op == NULL) {
+ /* No AIO on internal opens. */
+ return NT_STATUS_RETRY;
+ }
+
if ((!min_aio_write_size || (in_data.length < min_aio_write_size))
&& !SMB_VFS_AIO_FORCE(fsp)) {
/* Too small a write for aio request. */
return NT_STATUS_RETRY;
}
- if (outstanding_aio_calls >= aio_pending_size) {
+ if (outstanding_aio_calls >= get_aio_pending_size()) {
DEBUG(3,("smb2: Already have %d aio "
"activities outstanding.\n",
outstanding_aio_calls ));
return NT_STATUS_RETRY;
}
+ if (smbreq->unread_bytes) {
+ /* Can't do async with recvfile. */
+ return NT_STATUS_RETRY;
+ }
+
if (!(aio_ex = create_aio_extra(smbreq->smb2req, fsp, 0))) {
return NT_STATUS_NO_MEMORY;
}
aio_ex->write_through = write_through;
- init_strict_lock_struct(fsp, (uint64_t)smbreq->smbpid,
+ init_strict_lock_struct(fsp, fsp->op->global->open_persistent_id,
in_offset, (uint64_t)in_data.length, WRITE_LOCK,
&aio_ex->lock);
aio_ex->nbyte = in_data.length;
aio_ex->offset = in_offset;
- req = SMB_VFS_PWRITE_SEND(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
- in_data.data, in_data.length, in_offset);
+ req = pwrite_fsync_send(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
+ in_data.data, in_data.length, in_offset,
+ write_through);
if (req == NULL) {
DEBUG(3, ("smb2: SMB_VFS_PWRITE_SEND failed. "
"Error %s\n", strerror(errno)));
ssize_t nwritten;
int err = 0;
- nwritten = SMB_VFS_PWRITE_RECV(req, &err);
+ nwritten = pwrite_fsync_recv(req, &err);
TALLOC_FREE(req);
DEBUG(10, ("pwrite_recv returned %d, err = %s\n", (int)nwritten,
(nwritten == -1) ? strerror(err) : "no error"));
if (fsp == NULL) {
- DEBUG( 3, ("aio_pwrite_smb2_done: file closed whilst "
- "aio outstanding (mid[%llu]).\n",
- (unsigned long long)aio_ex->smbreq->mid));
+ DEBUG(3, ("%s: request cancelled (mid[%ju])\n",
+ __func__, (uintmax_t)aio_ex->smbreq->mid));
TALLOC_FREE(aio_ex);
+ tevent_req_nterror(subreq, NT_STATUS_INTERNAL_ERROR);
return;
}
/* Unlock now we're done. */
SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &aio_ex->lock);
- status = smb2_write_complete(subreq, nwritten, err);
+ mark_file_modified(fsp);
+
+ status = smb2_write_complete_nosync(subreq, nwritten, err);
DEBUG(10, ("smb2: scheduled aio_write completed "
"for file %s, offset %.0f, requested %u, "
}
tevent_req_done(subreq);
}
-
-/****************************************************************************
- Handle any aio completion inline.
-*****************************************************************************/
-
-void aio_fsp_close(files_struct *fsp)
-{
- unsigned i;
-
- for (i=0; i<fsp->num_aio_requests; i++) {
- struct tevent_req *req = fsp->aio_requests[i];
- struct aio_extra *aio_ex = tevent_req_callback_data(
- req, struct aio_extra);
- aio_ex->fsp = NULL;
- }
-}