s3:smbd: convert aio to use tevent_signal
[metze/samba/wip.git] / source3 / smbd / aio.c
index fd886178f606fb2c97d44395307105e2b25767ed..4ce43c95e80f2cd04bf5b84e4be5d90f80d8d530 100644 (file)
@@ -6,7 +6,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
+#include "smbd/globals.h"
 
 #if defined(WITH_AIO)
 
 /* The signal we'll use to signify aio done. */
 #ifndef RT_SIGNAL_AIO
-#define RT_SIGNAL_AIO (SIGRTMIN+3)
+#ifndef SIGRTMIN
+#define SIGRTMIN       NSIG
+#endif
+#define RT_SIGNAL_AIO  (SIGRTMIN+3)
+#endif
+
+#ifndef HAVE_STRUCT_SIGEVENT_SIGEV_VALUE_SIVAL_PTR
+#ifdef HAVE_STRUCT_SIGEVENT_SIGEV_VALUE_SIGVAL_PTR
+#define sival_int      sigval_int
+#define sival_ptr      sigval_ptr
+#endif
 #endif
 
 /****************************************************************************
@@ -36,99 +46,50 @@ struct aio_extra {
        struct aio_extra *next, *prev;
        SMB_STRUCT_AIOCB acb;
        files_struct *fsp;
-       BOOL read_req;
-       uint16 mid;
-       char *inbuf;
+       struct smb_request *req;
        char *outbuf;
+       int (*handle_completion)(struct aio_extra *ex);
 };
 
-static struct aio_extra *aio_list_head;
-
-/****************************************************************************
- Create the extended aio struct we must keep around for the lifetime
- of the aio_read call.
-*****************************************************************************/
+static int handle_aio_read_complete(struct aio_extra *aio_ex);
+static int handle_aio_write_complete(struct aio_extra *aio_ex);
 
-static struct aio_extra *create_aio_ex_read(files_struct *fsp, size_t buflen,
-                                           uint16 mid)
+static int aio_extra_destructor(struct aio_extra *aio_ex)
 {
-       struct aio_extra *aio_ex = SMB_MALLOC_P(struct aio_extra);
-
-       if (!aio_ex) {
-               return NULL;
-       }
-       ZERO_STRUCTP(aio_ex);
-       /* The output buffer stored in the aio_ex is the start of
-          the smb return buffer. The buffer used in the acb
-          is the start of the reply data portion of that buffer. */
-       aio_ex->outbuf = SMB_MALLOC_ARRAY(char, buflen);
-       if (!aio_ex->outbuf) {
-               SAFE_FREE(aio_ex);
-               return NULL;
-       }
-       DLIST_ADD(aio_list_head, aio_ex);
-       aio_ex->fsp = fsp;
-       aio_ex->read_req = True;
-       aio_ex->mid = mid;
-       return aio_ex;
+       DLIST_REMOVE(aio_list_head, aio_ex);
+       return 0;
 }
 
 /****************************************************************************
  Create the extended aio struct we must keep around for the lifetime
- of the aio_write call.
+ of the aio call.
 *****************************************************************************/
 
-static struct aio_extra *create_aio_ex_write(files_struct *fsp,
-                                            size_t outbuflen, uint16 mid)
+static struct aio_extra *create_aio_extra(files_struct *fsp, size_t buflen)
 {
-       struct aio_extra *aio_ex = SMB_MALLOC_P(struct aio_extra);
+       struct aio_extra *aio_ex = TALLOC_ZERO_P(NULL, struct aio_extra);
 
        if (!aio_ex) {
                return NULL;
        }
-       ZERO_STRUCTP(aio_ex);
 
-       /* We need space for an output reply of outbuflen bytes. */
-       aio_ex->outbuf = SMB_MALLOC_ARRAY(char, outbuflen);
+       /* The output buffer stored in the aio_ex is the start of
+          the smb return buffer. The buffer used in the acb
+          is the start of the reply data portion of that buffer. */
+
+       aio_ex->outbuf = TALLOC_ARRAY(aio_ex, char, buflen);
        if (!aio_ex->outbuf) {
-               SAFE_FREE(aio_ex);
+               TALLOC_FREE(aio_ex);
                return NULL;
        }
-       /* Steal the input buffer containing the write data from the main SMB
-        * call. */
-       /* We must re-allocate a new one here. */
-       if (NewInBuffer(&aio_ex->inbuf) == NULL) {
-               SAFE_FREE(aio_ex->outbuf);
-               SAFE_FREE(aio_ex);
-               return NULL;
-       }
-
-       /* aio_ex->inbuf now contains the stolen old InBuf containing the data
-        * to write. */
-
        DLIST_ADD(aio_list_head, aio_ex);
+       talloc_set_destructor(aio_ex, aio_extra_destructor);
        aio_ex->fsp = fsp;
-       aio_ex->read_req = False;
-       aio_ex->mid = mid;
        return aio_ex;
 }
 
 /****************************************************************************
- Delete the extended aio struct.
-*****************************************************************************/
-
-static void delete_aio_ex(struct aio_extra *aio_ex)
-{
-       DLIST_REMOVE(aio_list_head, aio_ex);
-       /* Safe to do as we've removed ourselves from the in use list first. */
-       free_InBuffer(aio_ex->inbuf);
-
-       SAFE_FREE(aio_ex->outbuf);
-       SAFE_FREE(aio_ex);
-}
-
-/****************************************************************************
- Given the aiocb struct find the extended aio struct containing it.
+ Given the mid find the extended aio struct containing it.
 *****************************************************************************/
 
 static struct aio_extra *find_aio_ex(uint16 mid)
@@ -136,7 +97,7 @@ static struct aio_extra *find_aio_ex(uint16 mid)
        struct aio_extra *p;
 
        for( p = aio_list_head; p; p = p->next) {
-               if (mid == p->mid) {
+               if (mid == p->req->mid) {
                        return p;
                }
        }
@@ -147,60 +108,12 @@ static struct aio_extra *find_aio_ex(uint16 mid)
  We can have these many aio buffers in flight.
 *****************************************************************************/
 
-#define AIO_PENDING_SIZE 10
-static sig_atomic_t signals_received;
-static int outstanding_aio_calls;
-static uint16 aio_pending_array[AIO_PENDING_SIZE];
-
-/****************************************************************************
- Signal handler when an aio request completes.
-*****************************************************************************/
-
-static void signal_handler(int sig, siginfo_t *info, void *unused)
-{
-       if (signals_received < AIO_PENDING_SIZE - 1) {
-               aio_pending_array[signals_received] = info->si_value.sival_int;
-               signals_received++;
-       } /* Else signal is lost. */
-       sys_select_signal(RT_SIGNAL_AIO);
-}
-
-/****************************************************************************
- Is there a signal waiting ?
-*****************************************************************************/
-
-BOOL aio_finished(void)
-{
-       return (signals_received != 0);
-}
-
-/****************************************************************************
- Initialize the signal handler for aio read/write.
-*****************************************************************************/
-
-void initialize_async_io_handler(void)
-{
-       struct sigaction act;
-
-       ZERO_STRUCT(act);
-       act.sa_sigaction = signal_handler;
-       act.sa_flags = SA_SIGINFO;
-       sigemptyset( &act.sa_mask );
-       if (sigaction(RT_SIGNAL_AIO, &act, NULL) != 0) {
-                DEBUG(0,("Failed to setup RT_SIGNAL_AIO handler\n"));
-        }
-
-       /* the signal can start off blocked due to a bug in bash */
-       BlockSignals(False, RT_SIGNAL_AIO);
-}
-
 /****************************************************************************
  Set up an aio request from a SMBreadX call.
 *****************************************************************************/
 
-BOOL schedule_aio_read_and_X(connection_struct *conn,
-                            char *inbuf, char *outbuf,
-                            int length, int len_outbuf,
+bool schedule_aio_read_and_X(connection_struct *conn,
+                            struct smb_request *req,
                             files_struct *fsp, SMB_OFF_T startpos,
                             size_t smb_maxcnt)
 {
@@ -208,8 +121,16 @@ BOOL schedule_aio_read_and_X(connection_struct *conn,
        SMB_STRUCT_AIOCB *a;
        size_t bufsize;
        size_t min_aio_read_size = lp_aio_read_size(SNUM(conn));
+       int ret;
 
-       if (!min_aio_read_size || (smb_maxcnt < min_aio_read_size)) {
+       if (fsp->base_fsp != NULL) {
+               /* No AIO on streams yet */
+               DEBUG(10, ("AIO on streams not yet supported\n"));
+               return false;
+       }
+
+       if ((!min_aio_read_size || (smb_maxcnt < min_aio_read_size))
+           && !SMB_VFS_AIO_FORCE(fsp)) {
                /* Too small a read for aio request. */
                DEBUG(10,("schedule_aio_read_and_X: read size (%u) too small "
                          "for minimum aio_read of %u\n",
@@ -220,57 +141,64 @@ BOOL schedule_aio_read_and_X(connection_struct *conn,
 
        /* Only do this on non-chained and non-chaining reads not using the
         * write cache. */
-        if (chain_size !=0 || (CVAL(inbuf,smb_vwv0) != 0xFF)
+        if (chain_size !=0 || (CVAL(req->vwv+0, 0) != 0xFF)
            || (lp_write_cache_size(SNUM(conn)) != 0) ) {
                return False;
        }
 
-       if (outstanding_aio_calls >= AIO_PENDING_SIZE) {
+       if (outstanding_aio_calls >= aio_pending_size) {
                DEBUG(10,("schedule_aio_read_and_X: Already have %d aio "
                          "activities outstanding.\n",
                          outstanding_aio_calls ));
                return False;
        }
 
-       /* The following is safe from integer wrap as we've already
-          checked smb_maxcnt is 128k or less. */
-       bufsize = PTR_DIFF(smb_buf(outbuf),outbuf) + smb_maxcnt;
+       /* The following is safe from integer wrap as we've already checked
+          smb_maxcnt is 128k or less. Wct is 12 for read replies */
 
-       if ((aio_ex = create_aio_ex_read(fsp, bufsize,
-                                        SVAL(inbuf,smb_mid))) == NULL) {
+       bufsize = smb_size + 12 * 2 + smb_maxcnt;
+
+       if ((aio_ex = create_aio_extra(fsp, bufsize)) == NULL) {
                DEBUG(10,("schedule_aio_read_and_X: malloc fail.\n"));
                return False;
        }
+       aio_ex->handle_completion = handle_aio_read_complete;
 
-       /* Copy the SMB header already setup in outbuf. */
-       memcpy(aio_ex->outbuf, outbuf, smb_buf(outbuf) - outbuf);
+       construct_reply_common_req(req, aio_ex->outbuf);
+       srv_set_message(aio_ex->outbuf, 12, 0, True);
        SCVAL(aio_ex->outbuf,smb_vwv0,0xFF); /* Never a chained reply. */
 
        a = &aio_ex->acb;
 
        /* Now set up the aio record for the read call. */
-       
+
        a->aio_fildes = fsp->fh->fd;
        a->aio_buf = smb_buf(aio_ex->outbuf);
        a->aio_nbytes = smb_maxcnt;
        a->aio_offset = startpos;
        a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
        a->aio_sigevent.sigev_signo  = RT_SIGNAL_AIO;
-       a->aio_sigevent.sigev_value.sival_int = aio_ex->mid;
+       a->aio_sigevent.sigev_value.sival_int = req->mid;
 
-       if (SMB_VFS_AIO_READ(fsp,a) == -1) {
+       become_root();
+       ret = SMB_VFS_AIO_READ(fsp, a);
+       unbecome_root();
+
+       if (ret == -1) {
                DEBUG(0,("schedule_aio_read_and_X: aio_read failed. "
                         "Error %s\n", strerror(errno) ));
-               delete_aio_ex(aio_ex);
+               TALLOC_FREE(aio_ex);
                return False;
        }
 
+       aio_ex->req = talloc_move(aio_ex, &req);
+
        DEBUG(10,("schedule_aio_read_and_X: scheduled aio_read for file %s, "
                  "offset %.0f, len = %u (mid = %u)\n",
                  fsp->fsp_name, (double)startpos, (unsigned int)smb_maxcnt,
-                 (unsigned int)aio_ex->mid ));
+                 (unsigned int)aio_ex->req->mid ));
 
-       srv_defer_sign_response(aio_ex->mid);
+       srv_defer_sign_response(aio_ex->req->mid);
        outstanding_aio_calls++;
        return True;
 }
@@ -279,20 +207,27 @@ BOOL schedule_aio_read_and_X(connection_struct *conn,
  Set up an aio request from a SMBwriteX call.
 *****************************************************************************/
 
-BOOL schedule_aio_write_and_X(connection_struct *conn,
-                               char *inbuf, char *outbuf,
-                               int length, int len_outbuf,
-                               files_struct *fsp, char *data,
-                               SMB_OFF_T startpos,
-                               size_t numtowrite)
+bool schedule_aio_write_and_X(connection_struct *conn,
+                             struct smb_request *req,
+                             files_struct *fsp, char *data,
+                             SMB_OFF_T startpos,
+                             size_t numtowrite)
 {
        struct aio_extra *aio_ex;
        SMB_STRUCT_AIOCB *a;
-       size_t outbufsize;
-       BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
+       size_t bufsize;
+       bool write_through = BITSETW(req->vwv+7,0);
        size_t min_aio_write_size = lp_aio_write_size(SNUM(conn));
+       int ret;
 
-       if (!min_aio_write_size || (numtowrite < min_aio_write_size)) {
+       if (fsp->base_fsp != NULL) {
+               /* No AIO on streams yet */
+               DEBUG(10, ("AIO on streams not yet supported\n"));
+               return false;
+       }
+
+       if ((!min_aio_write_size || (numtowrite < min_aio_write_size))
+           && !SMB_VFS_AIO_FORCE(fsp)) {
                /* Too small a write for aio request. */
                DEBUG(10,("schedule_aio_write_and_X: write size (%u) too "
                          "small for minimum aio_write of %u\n",
@@ -303,12 +238,12 @@ BOOL schedule_aio_write_and_X(connection_struct *conn,
 
        /* Only do this on non-chained and non-chaining reads not using the
         * write cache. */
-        if (chain_size !=0 || (CVAL(inbuf,smb_vwv0) != 0xFF)
+        if (chain_size !=0 || (CVAL(req->vwv+0, 0) != 0xFF)
            || (lp_write_cache_size(SNUM(conn)) != 0) ) {
                return False;
        }
 
-       if (outstanding_aio_calls >= AIO_PENDING_SIZE) {
+       if (outstanding_aio_calls >= aio_pending_size) {
                DEBUG(3,("schedule_aio_write_and_X: Already have %d aio "
                         "activities outstanding.\n",
                          outstanding_aio_calls ));
@@ -317,47 +252,49 @@ BOOL schedule_aio_write_and_X(connection_struct *conn,
                          "(mid = %u)\n",
                          fsp->fsp_name, (double)startpos,
                          (unsigned int)numtowrite,
-                         (unsigned int)SVAL(inbuf,smb_mid) ));
+                         (unsigned int)req->mid ));
                return False;
        }
 
-       outbufsize = smb_len(outbuf) + 4;
-       if ((aio_ex = create_aio_ex_write(fsp, outbufsize,
-                                         SVAL(inbuf,smb_mid))) == NULL) {
+       bufsize = smb_size + 6*2;
+
+       if (!(aio_ex = create_aio_extra(fsp, bufsize))) {
                DEBUG(0,("schedule_aio_write_and_X: malloc fail.\n"));
                return False;
        }
+       aio_ex->handle_completion = handle_aio_write_complete;
 
-       /* Paranioa.... */
-       SMB_ASSERT(aio_ex->inbuf == inbuf);
-
-       /* Copy the SMB header already setup in outbuf. */
-       memcpy(aio_ex->outbuf, outbuf, outbufsize);
+       construct_reply_common_req(req, aio_ex->outbuf);
+       srv_set_message(aio_ex->outbuf, 6, 0, True);
        SCVAL(aio_ex->outbuf,smb_vwv0,0xFF); /* Never a chained reply. */
 
        a = &aio_ex->acb;
 
        /* Now set up the aio record for the write call. */
-       
+
        a->aio_fildes = fsp->fh->fd;
-       a->aio_buf = data; /* As we've stolen inbuf this points within
-                           * inbuf. */
+       a->aio_buf = data;
        a->aio_nbytes = numtowrite;
        a->aio_offset = startpos;
        a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
        a->aio_sigevent.sigev_signo  = RT_SIGNAL_AIO;
-       a->aio_sigevent.sigev_value.sival_int = aio_ex->mid;
+       a->aio_sigevent.sigev_value.sival_int = req->mid;
 
-       if (SMB_VFS_AIO_WRITE(fsp,a) == -1) {
+       become_root();
+       ret = SMB_VFS_AIO_WRITE(fsp, a);
+       unbecome_root();
+
+       if (ret == -1) {
                DEBUG(3,("schedule_aio_wrote_and_X: aio_write failed. "
                         "Error %s\n", strerror(errno) ));
-               /* Replace global InBuf as we're going to do a normal write. */
-               set_InBuffer(aio_ex->inbuf);
-               aio_ex->inbuf = NULL;
-               delete_aio_ex(aio_ex);
+               TALLOC_FREE(aio_ex);
                return False;
        }
 
+       aio_ex->req = talloc_move(aio_ex, &req);
+
+       release_level_2_oplocks_on_change(fsp);
+
        if (!write_through && !lp_syncalways(SNUM(fsp->conn))
            && fsp->aio_write_behind) {
                /* Lie to the client and immediately claim we finished the
@@ -365,14 +302,15 @@ BOOL schedule_aio_write_and_X(connection_struct *conn,
                SSVAL(aio_ex->outbuf,smb_vwv2,numtowrite);
                 SSVAL(aio_ex->outbuf,smb_vwv4,(numtowrite>>16)&1);
                show_msg(aio_ex->outbuf);
-               if (!send_smb(smbd_server_fd(),aio_ex->outbuf)) {
-                       exit_server_cleanly("handle_aio_write: send_smb "
+               if (!srv_send_smb(smbd_server_fd(),aio_ex->outbuf,
+                               IS_CONN_ENCRYPTED(fsp->conn))) {
+                       exit_server_cleanly("handle_aio_write: srv_send_smb "
                                            "failed.");
                }
                DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write "
                          "behind for file %s\n", fsp->fsp_name ));
        } else {
-               srv_defer_sign_response(aio_ex->mid);
+               srv_defer_sign_response(aio_ex->req->mid);
        }
        outstanding_aio_calls++;
 
@@ -380,7 +318,7 @@ BOOL schedule_aio_write_and_X(connection_struct *conn,
                  "%s, offset %.0f, len = %u (mid = %u) "
                  "outstanding_aio_calls = %d\n",
                  fsp->fsp_name, (double)startpos, (unsigned int)numtowrite,
-                 (unsigned int)aio_ex->mid, outstanding_aio_calls ));
+                 (unsigned int)aio_ex->req->mid, outstanding_aio_calls ));
 
        return True;
 }
@@ -408,7 +346,7 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex)
                /* If errno is ECANCELED then don't return anything to the
                 * client. */
                if (errno == ECANCELED) {
-                       srv_cancel_sign_response(aio_ex->mid);
+                       srv_cancel_sign_response(aio_ex->req->mid);
                        return 0;
                }
 
@@ -416,26 +354,31 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex)
                           "Error = %s\n",
                           aio_ex->fsp->fsp_name, strerror(errno) ));
 
-               outsize = (UNIXERROR(ERRDOS,ERRnoaccess));
                ret = errno;
+               ERROR_NT(map_nt_error_from_unix(ret));
+               outsize = srv_set_message(outbuf,0,0,true);
        } else {
-               outsize = set_message(outbuf,12,nread,False);
+               outsize = srv_set_message(outbuf,12,nread,False);
                SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be * -1. */
                SSVAL(outbuf,smb_vwv5,nread);
                SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
                SSVAL(outbuf,smb_vwv7,((nread >> 16) & 1));
                SSVAL(smb_buf(outbuf),-2,nread);
 
+               aio_ex->fsp->fh->pos = aio_ex->acb.aio_offset + nread;
+               aio_ex->fsp->fh->position_information = aio_ex->fsp->fh->pos;
+
                DEBUG( 3, ( "handle_aio_read_complete file %s max=%d "
                            "nread=%d\n",
                            aio_ex->fsp->fsp_name,
-                           aio_ex->acb.aio_nbytes, (int)nread ) );
+                           (int)aio_ex->acb.aio_nbytes, (int)nread ) );
 
        }
        smb_setlen(outbuf,outsize - 4);
        show_msg(outbuf);
-       if (!send_smb(smbd_server_fd(),outbuf)) {
-               exit_server_cleanly("handle_aio_read_complete: send_smb "
+       if (!srv_send_smb(smbd_server_fd(),outbuf,
+                       IS_CONN_ENCRYPTED(aio_ex->fsp->conn))) {
+               exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
                                    "failed.");
        }
 
@@ -497,14 +440,16 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex)
                /* If errno is ECANCELED then don't return anything to the
                 * client. */
                if (errno == ECANCELED) {
-                       srv_cancel_sign_response(aio_ex->mid);
+                       srv_cancel_sign_response(aio_ex->req->mid);
                        return 0;
                }
 
-               UNIXERROR(ERRHRD,ERRdiskfull);
                ret = errno;
+               ERROR_BOTH(map_nt_error_from_unix(ret), ERRHRD, ERRdiskfull);
+               srv_set_message(outbuf,0,0,true);
         } else {
-               BOOL write_through = BITSETW(aio_ex->inbuf+smb_vwv7,0);
+               bool write_through = BITSETW(aio_ex->req->vwv+7,0);
+               NTSTATUS status;
 
                SSVAL(outbuf,smb_vwv2,nwritten);
                SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1);
@@ -515,12 +460,22 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex)
 
                DEBUG(3,("handle_aio_write: fnum=%d num=%d wrote=%d\n",
                         fsp->fnum, (int)numtowrite, (int)nwritten));
-               sync_file(fsp->conn,fsp, write_through);
+               status = sync_file(fsp->conn,fsp, write_through);
+               if (!NT_STATUS_IS_OK(status)) {
+                       ret = errno;
+                       ERROR_BOTH(map_nt_error_from_unix(ret),
+                                  ERRHRD, ERRdiskfull);
+                       srv_set_message(outbuf,0,0,true);
+                       DEBUG(5,("handle_aio_write: sync_file for %s returned %s\n",
+                               fsp->fsp_name, nt_errstr(status) ));
+               }
+
+               aio_ex->fsp->fh->pos = aio_ex->acb.aio_offset + nwritten;
        }
 
        show_msg(outbuf);
-       if (!send_smb(smbd_server_fd(),outbuf)) {
-               exit_server_cleanly("handle_aio_write: send_smb failed.");
+       if (!srv_send_smb(smbd_server_fd(),outbuf,IS_CONN_ENCRYPTED(fsp->conn))) {
+               exit_server_cleanly("handle_aio_write: srv_send_smb failed.");
        }
 
        DEBUG(10,("handle_aio_write_complete: scheduled aio_write completed "
@@ -536,24 +491,24 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex)
  was non-zero), False if not.
 *****************************************************************************/
 
-static BOOL handle_aio_completed(struct aio_extra *aio_ex, int *perr)
+static bool handle_aio_completed(struct aio_extra *aio_ex, int *perr)
 {
        int err;
 
+       if(!aio_ex) {
+               DEBUG(3, ("handle_aio_completed: Non-existing aio_ex passed\n"));
+               return false;
+       }
+
        /* Ensure the operation has really completed. */
        if (SMB_VFS_AIO_ERROR(aio_ex->fsp, &aio_ex->acb) == EINPROGRESS) {
                DEBUG(10,( "handle_aio_completed: operation mid %u still in "
                           "process for file %s\n",
-                          aio_ex->mid, aio_ex->fsp->fsp_name ));
+                          aio_ex->req->mid, aio_ex->fsp->fsp_name ));
                return False;
        }
 
-       if (aio_ex->read_req) {
-               err = handle_aio_read_complete(aio_ex);
-       } else {
-               err = handle_aio_write_complete(aio_ex);
-       }
-
+       err = aio_ex->handle_completion(aio_ex);
        if (err) {
                *perr = err; /* Only save non-zero errors. */
        }
@@ -566,57 +521,47 @@ static BOOL handle_aio_completed(struct aio_extra *aio_ex, int *perr)
  Returns non-zero errno if fail or zero if all ok.
 *****************************************************************************/
 
-int process_aio_queue(void)
+void smbd_aio_complete_mid(unsigned int mid)
 {
-       int i;
+       files_struct *fsp = NULL;
+       struct aio_extra *aio_ex = find_aio_ex(mid);
        int ret = 0;
 
-       BlockSignals(True, RT_SIGNAL_AIO);
+       DEBUG(10,("smbd_aio_complete_mid: mid[%u]\n", mid));
 
-       DEBUG(10,("process_aio_queue: signals_received = %d\n",
-                 (int)signals_received));
-       DEBUG(10,("process_aio_queue: outstanding_aio_calls = %d\n",
-                 outstanding_aio_calls));
-
-       if (!signals_received) {
-               BlockSignals(False, RT_SIGNAL_AIO);
-               return 0;
+       if (!aio_ex) {
+               DEBUG(3,("smbd_aio_complete_mid: Can't find record to "
+                        "match mid %u.\n", mid));
+               srv_cancel_sign_response(mid);
+               return;
        }
 
-       /* Drain all the complete aio_reads. */
-       for (i = 0; i < signals_received; i++) {
-               uint16 mid = aio_pending_array[i];
-               files_struct *fsp = NULL;
-               struct aio_extra *aio_ex = find_aio_ex(mid);
-
-               if (!aio_ex) {
-                       DEBUG(3,("process_aio_queue: Can't find record to "
-                                "match mid %u.\n", (unsigned int)mid));
-                       srv_cancel_sign_response(mid);
-                       continue;
-               }
+       fsp = aio_ex->fsp;
+       if (fsp == NULL) {
+               /* file was closed whilst I/O was outstanding. Just
+                * ignore. */
+               DEBUG( 3,( "smbd_aio_complete_mid: file closed whilst "
+                          "aio outstanding (mid[%u]).\n", mid));
+               srv_cancel_sign_response(mid);
+               return;
+       }
 
-               fsp = aio_ex->fsp;
-               if (fsp == NULL) {
-                       /* file was closed whilst I/O was outstanding. Just
-                        * ignore. */
-                       DEBUG( 3,( "process_aio_queue: file closed whilst "
-                                  "aio outstanding.\n"));
-                       srv_cancel_sign_response(mid);
-                       continue;
-               }
+       if (!handle_aio_completed(aio_ex, &ret)) {
+               return;
+       }
 
-               if (!handle_aio_completed(aio_ex, &ret)) {
-                       continue;
-               }
+       TALLOC_FREE(aio_ex);
+}
 
-               delete_aio_ex(aio_ex);
-       }
+static void smbd_aio_signal_handler(struct tevent_context *ev_ctx,
+                                   struct tevent_signal *se,
+                                   int signum, int count,
+                                   void *_info, void *private_data)
+{
+       siginfo_t *info = (siginfo_t *)_info;
+       unsigned int mid = (unsigned int)info->si_value.sival_int;
 
-       outstanding_aio_calls -= signals_received;
-       signals_received = 0;
-       BlockSignals(False, RT_SIGNAL_AIO);
-       return ret;
+       smbd_aio_complete_mid(mid);
 }
 
 /****************************************************************************
@@ -682,7 +627,7 @@ int wait_for_aio_completion(files_struct *fsp)
 
                DEBUG(10,("wait_for_aio_completion: returned err = %d, "
                          "errno = %s\n", err, strerror(errno) ));
-               
+
                if (err == -1 && errno == EAGAIN) {
                        DEBUG(0,("wait_for_aio_completion: aio_suspend timed "
                                 "out waiting for %d events after a wait of "
@@ -711,7 +656,7 @@ int wait_for_aio_completion(files_struct *fsp)
                        if (!handle_aio_completed(aio_ex, &err)) {
                                continue;
                        }
-                       delete_aio_ex(aio_ex);
+                       TALLOC_FREE(aio_ex);
                }
 
                SAFE_FREE(aiocb_list);
@@ -741,7 +686,7 @@ void cancel_aio_by_fsp(files_struct *fsp)
                        /* Don't delete the aio_extra record as we may have
                           completed and don't yet know it. Just do the
                           aio_cancel call and return. */
-                       SMB_VFS_AIO_CANCEL(fsp,fsp->fh->fd, &aio_ex->acb);
+                       SMB_VFS_AIO_CANCEL(fsp, &aio_ex->acb);
                        aio_ex->fsp = NULL; /* fsp will be closed when we
                                             * return. */
                }
@@ -749,50 +694,42 @@ void cancel_aio_by_fsp(files_struct *fsp)
 }
 
 /****************************************************************************
Check if a buffer was stolen for aio use.
Initialize the signal handler for aio read/write.
 *****************************************************************************/
 
-BOOL aio_inbuffer_in_use(char *inbuf)
+void initialize_async_io_handler(void)
 {
-       struct aio_extra *aio_ex;
-
-       for( aio_ex = aio_list_head; aio_ex; aio_ex = aio_ex->next) {
-               if (aio_ex->inbuf == inbuf) {
-                       return True;
-               }
+       aio_signal_event = tevent_add_signal(smbd_event_context(),
+                                            smbd_event_context(),
+                                            RT_SIGNAL_AIO, SA_SIGINFO,
+                                            smbd_aio_signal_handler,
+                                            NULL);
+       if (!aio_signal_event) {
+               exit_server("Failed to setup RT_SIGNAL_AIO handler");
        }
-       return False;
-}
-#else
-BOOL aio_finished(void)
-{
-       return False;
-}
 
-void initialize_async_io_handler(void)
-{
+       /* tevent supports 100 signal with SA_SIGINFO */
+       aio_pending_size = 100;
 }
 
-int process_aio_queue(void)
+#else
+void initialize_async_io_handler(void)
 {
-       return False;
 }
 
-BOOL schedule_aio_read_and_X(connection_struct *conn,
-                            char *inbuf, char *outbuf,
-                            int length, int len_outbuf,
+bool schedule_aio_read_and_X(connection_struct *conn,
+                            struct smb_request *req,
                             files_struct *fsp, SMB_OFF_T startpos,
                             size_t smb_maxcnt)
 {
        return False;
 }
 
-BOOL schedule_aio_write_and_X(connection_struct *conn,
-                                char *inbuf, char *outbuf,
-                                int length, int len_outbuf,
-                                files_struct *fsp, char *data,
-                                SMB_OFF_T startpos,
-                                size_t numtowrite)
+bool schedule_aio_write_and_X(connection_struct *conn,
+                             struct smb_request *req,
+                             files_struct *fsp, char *data,
+                             SMB_OFF_T startpos,
+                             size_t numtowrite)
 {
        return False;
 }
@@ -801,13 +738,11 @@ void cancel_aio_by_fsp(files_struct *fsp)
 {
 }
 
-BOOL wait_for_aio_completion(files_struct *fsp)
+int wait_for_aio_completion(files_struct *fsp)
 {
-       return True;
+       return ENOSYS;
 }
 
-BOOL aio_inbuffer_in_use(char *ptr)
-{
-       return False;
-}
+void smbd_aio_complete_mid(unsigned int mid);
+
 #endif