Catch one more erroneous use of errno.
[ira/wip.git] / source3 / smbd / aio.c
index 8c6eaf1498fa8b33cf3f7fe4c7fb58e4cb02be1c..37278b313ccd48f49470f1e98f33483bb33ee9f0 100644 (file)
 */
 
 #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)
+#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
 
 /****************************************************************************
@@ -35,94 +43,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, int errcode);
 };
 
-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, int errcode);
+static int handle_aio_write_complete(struct aio_extra *aio_ex, int errcode);
 
-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 inbuflen,
-                                            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);
-       if (!aio_ex->outbuf) {
-               SAFE_FREE(aio_ex);
-               return NULL;
-       }
+       /* 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. */
 
-       if (!(aio_ex->inbuf = SMB_MALLOC_ARRAY(char, inbuflen))) {
-               SAFE_FREE(aio_ex->outbuf);
-               SAFE_FREE(aio_ex);
+       aio_ex->outbuf = TALLOC_ARRAY(aio_ex, char, buflen);
+       if (!aio_ex->outbuf) {
+               TALLOC_FREE(aio_ex);
                return NULL;
        }
-
        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_FREE(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)
@@ -130,7 +94,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;
                }
        }
@@ -141,53 +105,6 @@ 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) {
-               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.
 *****************************************************************************/
@@ -201,6 +118,13 @@ 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 (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)) {
@@ -214,12 +138,11 @@ 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(req->inbuf,smb_vwv0) != 0xFF)
-           || (lp_write_cache_size(SNUM(conn)) != 0) ) {
+        if (req_is_in_chain(req) || (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 ));
@@ -231,41 +154,44 @@ bool schedule_aio_read_and_X(connection_struct *conn,
 
        bufsize = smb_size + 12 * 2 + smb_maxcnt;
 
-       if ((aio_ex = create_aio_ex_read(fsp, bufsize, req->mid)) == NULL) {
+       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;
 
-       construct_reply_common((char *)req->inbuf, aio_ex->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) {
+       ret = SMB_VFS_AIO_READ(fsp, a);
+       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;
        }
 
+       outstanding_aio_calls++;
+       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 ));
+                 fsp_str_dbg(fsp), (double)startpos, (unsigned int)smb_maxcnt,
+                 (unsigned int)aio_ex->req->mid ));
 
-       srv_defer_sign_response(aio_ex->mid);
-       outstanding_aio_calls++;
        return True;
 }
 
@@ -281,9 +207,16 @@ bool schedule_aio_write_and_X(connection_struct *conn,
 {
        struct aio_extra *aio_ex;
        SMB_STRUCT_AIOCB *a;
-       size_t inbufsize, outbufsize;
-       bool write_through = BITSETW(req->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 (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)) {
@@ -297,61 +230,61 @@ 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(req->inbuf,smb_vwv0) != 0xFF)
-           || (lp_write_cache_size(SNUM(conn)) != 0) ) {
+        if (req_is_in_chain(req) || (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 ));
                DEBUG(10,("schedule_aio_write_and_X: failed to schedule "
                          "aio_write for file %s, offset %.0f, len = %u "
                          "(mid = %u)\n",
-                         fsp->fsp_name, (double)startpos,
+                         fsp_str_dbg(fsp), (double)startpos,
                          (unsigned int)numtowrite,
                          (unsigned int)req->mid ));
                return False;
        }
 
-       inbufsize =  smb_len(req->inbuf) + 4;
-       reply_outbuf(req, 6, 0);
-       outbufsize = smb_len(req->outbuf) + 4;
-       if (!(aio_ex = create_aio_ex_write(fsp, inbufsize, outbufsize,
-                                          req->mid))) {
+       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;
 
-       /* Copy the SMB header already setup in outbuf. */
-       memcpy(aio_ex->inbuf, req->inbuf, inbufsize);
-
-       /* Copy the SMB header already setup in outbuf. */
-       memcpy(aio_ex->outbuf, req->outbuf, outbufsize);
-       TALLOC_FREE(req->outbuf);
+       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 = aio_ex->inbuf + (PTR_DIFF(data, req->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) {
+       ret = SMB_VFS_AIO_WRITE(fsp, a);
+       if (ret == -1) {
                DEBUG(3,("schedule_aio_wrote_and_X: aio_write failed. "
                         "Error %s\n", strerror(errno) ));
-               delete_aio_ex(aio_ex);
+               TALLOC_FREE(aio_ex);
                return False;
        }
 
-       release_level_2_oplocks_on_change(fsp);
+       outstanding_aio_calls++;
+       aio_ex->req = talloc_move(aio_ex, &req);
+
+       /* This should actually be improved to span the write. */
+       contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
+       contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
 
        if (!write_through && !lp_syncalways(SNUM(fsp->conn))
            && fsp->aio_write_behind) {
@@ -361,22 +294,21 @@ bool schedule_aio_write_and_X(connection_struct *conn,
                 SSVAL(aio_ex->outbuf,smb_vwv4,(numtowrite>>16)&1);
                show_msg(aio_ex->outbuf);
                if (!srv_send_smb(smbd_server_fd(),aio_ex->outbuf,
-                               IS_CONN_ENCRYPTED(fsp->conn))) {
+                               true, aio_ex->req->seqnum+1,
+                               IS_CONN_ENCRYPTED(fsp->conn),
+                               &aio_ex->req->pcd)) {
                        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);
+                         "behind for file %s\n", fsp_str_dbg(fsp)));
        }
-       outstanding_aio_calls++;
 
        DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write for file "
                  "%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 ));
+                 fsp_str_dbg(fsp), (double)startpos, (unsigned int)numtowrite,
+                 (unsigned int)aio_ex->req->mid, outstanding_aio_calls ));
 
        return True;
 }
@@ -387,7 +319,7 @@ bool schedule_aio_write_and_X(connection_struct *conn,
  Returns errno or zero if all ok.
 *****************************************************************************/
 
-static int handle_aio_read_complete(struct aio_extra *aio_ex)
+static int handle_aio_read_complete(struct aio_extra *aio_ex, int errcode)
 {
        int ret = 0;
        int outsize;
@@ -401,18 +333,11 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex)
                   will return an error. Hopefully this is
                   true.... JRA. */
 
-               /* If errno is ECANCELED then don't return anything to the
-                * client. */
-               if (errno == ECANCELED) {
-                       srv_cancel_sign_response(aio_ex->mid);
-                       return 0;
-               }
-
-               DEBUG( 3,( "handle_aio_read_complete: file %s nread == -1. "
+               DEBUG( 3,( "handle_aio_read_complete: file %s nread == %d. "
                           "Error = %s\n",
-                          aio_ex->fsp->fsp_name, strerror(errno) ));
+                          fsp_str_dbg(aio_ex->fsp), nread, strerror(errcode)));
 
-               ret = errno;
+               ret = errcode;
                ERROR_NT(map_nt_error_from_unix(ret));
                outsize = srv_set_message(outbuf,0,0,true);
        } else {
@@ -428,21 +353,22 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex)
 
                DEBUG( 3, ( "handle_aio_read_complete file %s max=%d "
                            "nread=%d\n",
-                           aio_ex->fsp->fsp_name,
+                           fsp_str_dbg(aio_ex->fsp),
                            (int)aio_ex->acb.aio_nbytes, (int)nread ) );
 
        }
        smb_setlen(outbuf,outsize - 4);
        show_msg(outbuf);
        if (!srv_send_smb(smbd_server_fd(),outbuf,
-                       IS_CONN_ENCRYPTED(aio_ex->fsp->conn))) {
+                       true, aio_ex->req->seqnum+1,
+                       IS_CONN_ENCRYPTED(aio_ex->fsp->conn), NULL)) {
                exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
                                    "failed.");
        }
 
        DEBUG(10,("handle_aio_read_complete: scheduled aio_read completed "
                  "for file %s, offset %.0f, len = %u\n",
-                 aio_ex->fsp->fsp_name, (double)aio_ex->acb.aio_offset,
+                 fsp_str_dbg(aio_ex->fsp), (double)aio_ex->acb.aio_offset,
                  (unsigned int)nread ));
 
        return ret;
@@ -450,10 +376,10 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex)
 
 /****************************************************************************
  Complete the write and return the data or error back to the client.
- Returns errno or zero if all ok.
+ Returns error code or zero if all ok.
 *****************************************************************************/
 
-static int handle_aio_write_complete(struct aio_extra *aio_ex)
+static int handle_aio_write_complete(struct aio_extra *aio_ex, int errcode)
 {
        int ret = 0;
        files_struct *fsp = aio_ex->fsp;
@@ -467,13 +393,13 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex)
                                DEBUG(5,("handle_aio_write_complete: "
                                         "aio_write_behind failed ! File %s "
                                         "is corrupt ! Error %s\n",
-                                        fsp->fsp_name, strerror(errno) ));
-                               ret = errno;
+                                        fsp_str_dbg(fsp), strerror(errcode)));
+                               ret = errcode;
                        } else {
                                DEBUG(0,("handle_aio_write_complete: "
                                         "aio_write_behind failed ! File %s "
                                         "is corrupt ! Wanted %u bytes but "
-                                        "only wrote %d\n", fsp->fsp_name,
+                                        "only wrote %d\n", fsp_str_dbg(fsp),
                                         (unsigned int)numtowrite,
                                         (int)nwritten ));
                                ret = EIO;
@@ -481,8 +407,9 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex)
                } else {
                        DEBUG(10,("handle_aio_write_complete: "
                                  "aio_write_behind completed for file %s\n",
-                                 fsp->fsp_name ));
+                                 fsp_str_dbg(fsp)));
                }
+               /* TODO: should no return 0 in case of an error !!! */
                return 0;
        }
 
@@ -492,21 +419,14 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex)
        if(nwritten == -1) {
                DEBUG( 3,( "handle_aio_write: file %s wanted %u bytes. "
                           "nwritten == %d. Error = %s\n",
-                          fsp->fsp_name, (unsigned int)numtowrite,
-                          (int)nwritten, strerror(errno) ));
+                          fsp_str_dbg(fsp), (unsigned int)numtowrite,
+                          (int)nwritten, strerror(errcode) ));
 
-               /* If errno is ECANCELED then don't return anything to the
-                * client. */
-               if (errno == ECANCELED) {
-                       srv_cancel_sign_response(aio_ex->mid);
-                       return 0;
-               }
-
-               ret = errno;
-               ERROR_BOTH(map_nt_error_from_unix(ret), ERRHRD, ERRdiskfull);
+               ret = errcode;
+               ERROR_NT(map_nt_error_from_unix(ret));
                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);
@@ -525,20 +445,23 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex)
                                   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) ));
+                                fsp_str_dbg(fsp), nt_errstr(status)));
                }
 
                aio_ex->fsp->fh->pos = aio_ex->acb.aio_offset + nwritten;
        }
 
        show_msg(outbuf);
-       if (!srv_send_smb(smbd_server_fd(),outbuf,IS_CONN_ENCRYPTED(fsp->conn))) {
+       if (!srv_send_smb(smbd_server_fd(),outbuf,
+                         true, aio_ex->req->seqnum+1,
+                         IS_CONN_ENCRYPTED(fsp->conn),
+                         NULL)) {
                exit_server_cleanly("handle_aio_write: srv_send_smb failed.");
        }
 
        DEBUG(10,("handle_aio_write_complete: scheduled aio_write completed "
                  "for file %s, offset %.0f, requested %u, written = %u\n",
-                 fsp->fsp_name, (double)aio_ex->acb.aio_offset,
+                 fsp_str_dbg(fsp), (double)aio_ex->acb.aio_offset,
                  (unsigned int)numtowrite, (unsigned int)nwritten ));
 
        return ret;
@@ -553,20 +476,27 @@ 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) {
+       err = SMB_VFS_AIO_ERROR(aio_ex->fsp, &aio_ex->acb);
+       if (err == 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, fsp_str_dbg(aio_ex->fsp)));
                return False;
-       }
-
-       if (aio_ex->read_req) {
-               err = handle_aio_read_complete(aio_ex);
-       } else {
-               err = handle_aio_write_complete(aio_ex);
-       }
+       } else if (err == ECANCELED) {
+               /* If error is ECANCELED then don't return anything to the
+                * client. */
+               DEBUG(10,( "handle_aio_completed: operation mid %u"
+                           " canceled\n", aio_ex->req->mid));
+               return True;
+        }
 
+       err = aio_ex->handle_completion(aio_ex, err);
        if (err) {
                *perr = err; /* Only save non-zero errors. */
        }
@@ -576,60 +506,49 @@ static bool handle_aio_completed(struct aio_extra *aio_ex, int *perr)
 
 /****************************************************************************
  Handle any aio completion inline.
- 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);
+       outstanding_aio_calls--;
 
-       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));
+       DEBUG(10,("smbd_aio_complete_mid: mid[%u]\n", mid));
 
-       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));
+               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));
+               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);
 }
 
 /****************************************************************************
@@ -695,7 +614,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 "
@@ -724,7 +643,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);
@@ -761,19 +680,28 @@ void cancel_aio_by_fsp(files_struct *fsp)
        }
 }
 
-#else
-bool aio_finished(void)
-{
-       return False;
-}
+/****************************************************************************
+ Initialize the signal handler for aio read/write.
+*****************************************************************************/
 
 void initialize_async_io_handler(void)
 {
+       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");
+       }
+
+       /* 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,
@@ -801,4 +729,7 @@ int wait_for_aio_completion(files_struct *fsp)
 {
        return ENOSYS;
 }
+
+void smbd_aio_complete_mid(unsigned int mid);
+
 #endif