s3:smbd: convert aio to use tevent_signal
[metze/samba/wip.git] / source3 / smbd / aio.c
index d19706ff61ad316f0b066e127cb16464745c0e06..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,95 +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);
-               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);
+               TALLOC_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)
@@ -132,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;
                }
        }
@@ -143,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] = *(uint16 *)(info->si_value.sival_ptr);
-               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)
 {
@@ -204,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",
@@ -214,53 +139,66 @@ BOOL schedule_aio_read_and_X(connection_struct *conn,
                return False;
        }
 
-       /* Only do this on non-chained and non-chaining reads not using the write cache. */
-        if (chain_size !=0 || (CVAL(inbuf,smb_vwv0) != 0xFF) || (lp_write_cache_size(SNUM(conn)) != 0) ) {
+       /* Only do this on non-chained and non-chaining reads not using the
+        * write cache. */
+        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) {
-               DEBUG(10,("schedule_aio_read_and_X: Already have %d aio activities outstanding.\n",
+       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 */
+
+       bufsize = smb_size + 12 * 2 + smb_maxcnt;
 
-       if ((aio_ex = create_aio_ex_read(fsp, bufsize, SVAL(inbuf,smb_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;
 
-       /* 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_ptr = (void *)&aio_ex->mid;
+       a->aio_sigevent.sigev_value.sival_int = req->mid;
+
+       become_root();
+       ret = SMB_VFS_AIO_READ(fsp, a);
+       unbecome_root();
 
-       if (SMB_VFS_AIO_READ(fsp,a) == -1) {
-               DEBUG(0,("schedule_aio_read_and_X: aio_read failed. Error %s\n",
-                       strerror(errno) ));
-               delete_aio_ex(aio_ex);
+       if (ret == -1) {
+               DEBUG(0,("schedule_aio_read_and_X: aio_read failed. "
+                        "Error %s\n", strerror(errno) ));
+               TALLOC_FREE(aio_ex);
                return False;
        }
 
-       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 ));
+       aio_ex->req = talloc_move(aio_ex, &req);
 
-       srv_defer_sign_response(aio_ex->mid);
+       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->req->mid ));
+
+       srv_defer_sign_response(aio_ex->req->mid);
        outstanding_aio_calls++;
        return True;
 }
@@ -269,94 +207,118 @@ 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",
+               DEBUG(10,("schedule_aio_write_and_X: write size (%u) too "
+                         "small for minimum aio_write of %u\n",
                          (unsigned int)numtowrite,
                          (unsigned int)min_aio_write_size ));
                return False;
        }
 
-       /* Only do this on non-chained and non-chaining reads not using the write cache. */
-        if (chain_size !=0 || (CVAL(inbuf,smb_vwv0) != 0xFF) || (lp_write_cache_size(SNUM(conn)) != 0) ) {
+       /* Only do this on non-chained and non-chaining reads not using the
+        * write cache. */
+        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) {
-               DEBUG(3,("schedule_aio_write_and_X: Already have %d aio activities outstanding.\n",
+       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, (unsigned int)numtowrite, (unsigned int)SVAL(inbuf,smb_mid) ));
+               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,
+                         (unsigned int)numtowrite,
+                         (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_ptr = (void *)&aio_ex->mid;
-
-       if (SMB_VFS_AIO_WRITE(fsp,a) == -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);
+       a->aio_sigevent.sigev_value.sival_int = req->mid;
+
+       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) ));
+               TALLOC_FREE(aio_ex);
                return False;
        }
 
-       if (!write_through && !lp_syncalways(SNUM(fsp->conn)) && fsp->aio_write_behind) {
-               /* Lie to the client and immediately claim we finished the write. */
+       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
+                * write. */
                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("handle_aio_write: send_smb failed.");
+               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 ));
+               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++;
 
-       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 ));
+       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->req->mid, outstanding_aio_calls ));
 
        return True;
 }
@@ -381,38 +343,49 @@ 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 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;
                }
 
-               DEBUG( 3,( "handle_aio_read_complete: file %s nread == -1. Error = %s\n",
-                       aio_ex->fsp->fsp_name, strerror(errno) ));
+               DEBUG( 3,( "handle_aio_read_complete: file %s nread == -1. "
+                          "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);
 
-               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 ) );
+               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,
+                           (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("handle_aio_read_complete: send_smb failed.");
+       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.");
        }
 
-       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, (unsigned int)nread ));
+       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,
+                 (unsigned int)nread ));
 
        return ret;
 }
@@ -433,17 +406,24 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex)
        if (fsp->aio_write_behind) {
                if (nwritten != numtowrite) {
                        if (nwritten == -1) {
-                               DEBUG(5,("handle_aio_write_complete: aio_write_behind failed ! File %s is corrupt ! Error %s\n",
-                                       fsp->fsp_name, strerror(errno) ));
+                               DEBUG(5,("handle_aio_write_complete: "
+                                        "aio_write_behind failed ! File %s "
+                                        "is corrupt ! Error %s\n",
+                                        fsp->fsp_name, strerror(errno) ));
                                ret = errno;
                        } 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, (unsigned int)numtowrite, (int)nwritten ));
+                               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,
+                                        (unsigned int)numtowrite,
+                                        (int)nwritten ));
                                ret = EIO;
                        }
                } else {
-                       DEBUG(10,("handle_aio_write_complete: aio_write_behind completed for file %s\n",
-                               fsp->fsp_name ));
+                       DEBUG(10,("handle_aio_write_complete: "
+                                 "aio_write_behind completed for file %s\n",
+                                 fsp->fsp_name ));
                }
                return 0;
        }
@@ -452,20 +432,24 @@ Wanted %u bytes but only wrote %d\n", fsp->fsp_name, (unsigned int)numtowrite, (
           fixed size length when we set up the aio call. */
 
        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) ));
+               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) ));
 
-               /* If errno is ECANCELED then don't return anything to the client. */
+               /* 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);
@@ -473,46 +457,58 @@ Wanted %u bytes but only wrote %d\n", fsp->fsp_name, (unsigned int)numtowrite, (
                        SCVAL(outbuf,smb_rcls,ERRHRD);
                        SSVAL(outbuf,smb_err,ERRdiskfull);
                }
-                                                                                                                                  
-               DEBUG(3,("handle_aio_write: fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
-               if (lp_syncalways(SNUM(fsp->conn)) || write_through) {
-                       sync_file(fsp->conn,fsp);
+
+               DEBUG(3,("handle_aio_write: fnum=%d num=%d wrote=%d\n",
+                        fsp->fnum, (int)numtowrite, (int)nwritten));
+               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("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 for file %s, offset %.0f, requested %u, written = %u\n",
-               fsp->fsp_name, (double)aio_ex->acb.aio_offset, (unsigned int)numtowrite, (unsigned int)nwritten ));
+       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,
+                 (unsigned int)numtowrite, (unsigned int)nwritten ));
 
        return ret;
 }
 
 /****************************************************************************
- Handle any aio completion. Returns True if finished (and sets *perr if err was non-zero),
- False if not.
+ Handle any aio completion. Returns True if finished (and sets *perr if err
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 ));
+               DEBUG(10,( "handle_aio_completed: operation mid %u still in "
+                          "process for file %s\n",
+                          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. */
        }
@@ -525,73 +521,67 @@ 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);
 }
 
 /****************************************************************************
- We're doing write behind and the client closed the file. Wait up to 30 seconds
- (my arbitrary choice) for the aio to complete. Return 0 if all writes completed,
- errno to return if not.
+ We're doing write behind and the client closed the file. Wait up to 30
+ seconds (my arbitrary choice) for the aio to complete. Return 0 if all writes
completed, errno to return if not.
 *****************************************************************************/
 
 #define SMB_TIME_FOR_AIO_COMPLETE_WAIT 29
 
-BOOL wait_for_aio_completion(files_struct *fsp)
+int wait_for_aio_completion(files_struct *fsp)
 {
        struct aio_extra *aio_ex;
        const SMB_STRUCT_AIOCB **aiocb_list;
        int aio_completion_count = 0;
        time_t start_time = time(NULL);
        int seconds_left;
-       int ret = 0;
 
-       for (seconds_left = SMB_TIME_FOR_AIO_COMPLETE_WAIT; seconds_left >= 0;) {
+       for (seconds_left = SMB_TIME_FOR_AIO_COMPLETE_WAIT;
+            seconds_left >= 0;) {
                int err = 0;
                int i;
                struct timespec ts;
@@ -604,18 +594,21 @@ BOOL wait_for_aio_completion(files_struct *fsp)
                }
 
                if (!aio_completion_count) {
-                       return ret;
+                       return 0;
                }
 
-               DEBUG(3,("wait_for_aio_completion: waiting for %d aio events to complete.\n",
-                       aio_completion_count ));
+               DEBUG(3,("wait_for_aio_completion: waiting for %d aio events "
+                        "to complete.\n", aio_completion_count ));
 
-               aiocb_list = SMB_MALLOC_ARRAY(const SMB_STRUCT_AIOCB *, aio_completion_count);
+               aiocb_list = SMB_MALLOC_ARRAY(const SMB_STRUCT_AIOCB *,
+                                             aio_completion_count);
                if (!aiocb_list) {
-                       return False;
+                       return ENOMEM;
                }
 
-               for( i = 0, aio_ex = aio_list_head; aio_ex; aio_ex = aio_ex->next) {
+               for( i = 0, aio_ex = aio_list_head;
+                    aio_ex;
+                    aio_ex = aio_ex->next) {
                        if (aio_ex->fsp == fsp) {
                                aiocb_list[i++] = &aio_ex->acb;
                        }
@@ -625,44 +618,59 @@ BOOL wait_for_aio_completion(files_struct *fsp)
                ts.tv_sec = seconds_left;
                ts.tv_nsec = 0;
 
-               DEBUG(10,("wait_for_aio_completion: %d events, doing a wait of %d seconds.\n",
-                       aio_completion_count, seconds_left ));
+               DEBUG(10,("wait_for_aio_completion: %d events, doing a wait "
+                         "of %d seconds.\n",
+                         aio_completion_count, seconds_left ));
+
+               err = SMB_VFS_AIO_SUSPEND(fsp, aiocb_list,
+                                         aio_completion_count, &ts);
 
-               err = SMB_VFS_AIO_SUSPEND(fsp, aiocb_list, aio_completion_count, &ts);
+               DEBUG(10,("wait_for_aio_completion: returned err = %d, "
+                         "errno = %s\n", err, strerror(errno) ));
 
-               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 %d seconds\n",
-                                       aio_completion_count, seconds_left));
+                       DEBUG(0,("wait_for_aio_completion: aio_suspend timed "
+                                "out waiting for %d events after a wait of "
+                                "%d seconds\n", aio_completion_count,
+                                seconds_left));
                        /* Timeout. */
                        cancel_aio_by_fsp(fsp);
                        SAFE_FREE(aiocb_list);
-                       return ret ? ret : EIO;
+                       return EIO;
                }
 
-               /* One or more events might have completed - process them if so. */
+               /* One or more events might have completed - process them if
+                * so. */
                for( i = 0; i < aio_completion_count; i++) {
-                       uint16 mid = *(uint16 *)aiocb_list[i]->aio_sigevent.sigev_value.sival_ptr;
+                       uint16 mid = aiocb_list[i]->aio_sigevent.sigev_value.sival_int;
 
                        aio_ex = find_aio_ex(mid);
 
+                       if (!aio_ex) {
+                               DEBUG(0, ("wait_for_aio_completion: mid %u "
+                                         "doesn't match an aio record\n",
+                                         (unsigned int)mid ));
+                               continue;
+                       }
+
                        if (!handle_aio_completed(aio_ex, &err)) {
                                continue;
                        }
-                       delete_aio_ex(aio_ex);
+                       TALLOC_FREE(aio_ex);
                }
 
                SAFE_FREE(aiocb_list);
-               seconds_left = SMB_TIME_FOR_AIO_COMPLETE_WAIT - (time(NULL) - start_time);
+               seconds_left = SMB_TIME_FOR_AIO_COMPLETE_WAIT
+                       - (time(NULL) - start_time);
        }
 
-       /* We timed out - we don't know why. Return ret if already an error, else EIO. */
-       DEBUG(10,("wait_for_aio_completion: aio_suspend timed out waiting for %d events\n",
-                       aio_completion_count));
+       /* We timed out - we don't know why. Return ret if already an error,
+        * else EIO. */
+       DEBUG(10,("wait_for_aio_completion: aio_suspend timed out waiting "
+                 "for %d events\n",
+                 aio_completion_count));
 
-       return ret ? ret : EIO;
+       return EIO;
 }
 
 /****************************************************************************
@@ -675,59 +683,53 @@ void cancel_aio_by_fsp(files_struct *fsp)
 
        for( aio_ex = aio_list_head; aio_ex; aio_ex = aio_ex->next) {
                if (aio_ex->fsp == 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);
-                       aio_ex->fsp = NULL; /* fsp will be closed when we return. */
+                       /* 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, &aio_ex->acb);
+                       aio_ex->fsp = NULL; /* fsp will be closed when we
+                                            * return. */
                }
        }
 }
 
 /****************************************************************************
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;
 }
@@ -736,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