s3: smbd: Remove aio_pending_size from globals.
[kai/samba-autobuild/.git] / source3 / smbd / aio.c
index 5f9b5c0b1adac2ebe48728e5d61bbff6d2d02d80..a750a1a5982d413ee2271438ce9e87167c56adf5 100644 (file)
 #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.
@@ -106,10 +124,14 @@ static int aio_del_req_from_fsp(struct aio_req_fsp_link *lnk)
        }
        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;
@@ -180,7 +202,7 @@ NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
                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 ));
@@ -190,7 +212,7 @@ NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
        /* 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"));
@@ -200,6 +222,7 @@ NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
        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,
@@ -215,7 +238,8 @@ NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
        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. "
@@ -250,7 +274,7 @@ static void aio_pread_smb1_done(struct tevent_req *req)
        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;
 
@@ -279,7 +303,8 @@ static void aio_pread_smb1_done(struct tevent_req *req)
                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));
@@ -296,7 +321,7 @@ static void aio_pread_smb1_done(struct tevent_req *req)
        }
        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 "
@@ -311,6 +336,99 @@ static void aio_pread_smb1_done(struct tevent_req *req)
        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);
 
 /****************************************************************************
@@ -350,7 +468,7 @@ NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
                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 ));
@@ -388,8 +506,9 @@ NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
        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) ));
@@ -412,14 +531,14 @@ NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
        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),
@@ -450,7 +569,7 @@ static void aio_pwrite_smb1_done(struct tevent_req *req)
        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,
@@ -467,6 +586,8 @@ static void aio_pwrite_smb1_done(struct tevent_req *req)
        /* 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) {
@@ -505,8 +626,6 @@ static void aio_pwrite_smb1_done(struct tevent_req *req)
                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) {
@@ -516,21 +635,12 @@ static void aio_pwrite_smb1_done(struct tevent_req *req)
 
                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)) {
@@ -597,6 +707,11 @@ NTSTATUS schedule_smb2_aio_read(connection_struct *conn,
                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. */
@@ -612,7 +727,7 @@ NTSTATUS schedule_smb2_aio_read(connection_struct *conn,
                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 ));
@@ -629,7 +744,7 @@ NTSTATUS schedule_smb2_aio_read(connection_struct *conn,
                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);
 
@@ -690,10 +805,10 @@ static void aio_pread_smb2_done(struct tevent_req *req)
                   (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;
        }
 
@@ -748,6 +863,11 @@ NTSTATUS schedule_aio_smb2_write(connection_struct *conn,
                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. */
@@ -763,20 +883,25 @@ NTSTATUS schedule_aio_smb2_write(connection_struct *conn,
                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);
 
@@ -789,8 +914,9 @@ NTSTATUS schedule_aio_smb2_write(connection_struct *conn,
        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)));
@@ -845,24 +971,26 @@ static void aio_pwrite_smb2_done(struct tevent_req *req)
        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, "
@@ -879,19 +1007,3 @@ static void aio_pwrite_smb2_done(struct tevent_req *req)
        }
        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;
-       }
-}