s3:smbd: move all globals and static variables in globals.[ch]
[samba.git] / source3 / smbd / aio.c
index 8c6eaf1498fa8b33cf3f7fe4c7fb58e4cb02be1c..54ae45a7892bc150282c28af80cd78ac1458d234 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)
+#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
 
 /****************************************************************************
@@ -35,94 +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 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 +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;
                }
        }
@@ -141,21 +108,22 @@ 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.
 *****************************************************************************/
 
+void aio_request_done(uint16_t mid)
+{
+       if (aio_signals_received < aio_pending_size) {
+               aio_pending_array[aio_signals_received] = mid;
+               aio_signals_received++;
+       }
+       /* Else signal is lost. */
+}
+
 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. */
+       aio_request_done(info->si_value.sival_int);
        sys_select_signal(RT_SIGNAL_AIO);
 }
 
@@ -165,7 +133,7 @@ static void signal_handler(int sig, siginfo_t *info, void *unused)
 
 bool aio_finished(void)
 {
-       return (signals_received != 0);
+       return (aio_signals_received != 0);
 }
 
 /****************************************************************************
@@ -176,6 +144,10 @@ void initialize_async_io_handler(void)
 {
        struct sigaction act;
 
+       aio_pending_size = lp_maxmux();
+       aio_pending_array = SMB_MALLOC_ARRAY(uint16, aio_pending_size);
+       SMB_ASSERT(aio_pending_array != NULL);
+
        ZERO_STRUCT(act);
        act.sa_sigaction = signal_handler;
        act.sa_flags = SA_SIGINFO;
@@ -201,6 +173,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 +193,12 @@ 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)
+        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 ));
@@ -231,40 +210,47 @@ 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;
+
+       become_root();
+       ret = SMB_VFS_AIO_READ(fsp, a);
+       unbecome_root();
 
-       if (SMB_VFS_AIO_READ(fsp,a) == -1) {
+       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;
 }
@@ -281,9 +267,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,12 +290,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(req->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 ));
@@ -315,42 +308,43 @@ bool schedule_aio_write_and_X(connection_struct *conn,
                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;
+
+       become_root();
+       ret = SMB_VFS_AIO_WRITE(fsp, a);
+       unbecome_root();
 
-       if (SMB_VFS_AIO_WRITE(fsp,a) == -1) {
+       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;
        }
 
+       aio_ex->req = talloc_move(aio_ex, &req);
+
        release_level_2_oplocks_on_change(fsp);
 
        if (!write_through && !lp_syncalways(SNUM(fsp->conn))
@@ -368,7 +362,7 @@ bool schedule_aio_write_and_X(connection_struct *conn,
                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++;
 
@@ -376,7 +370,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;
 }
@@ -404,7 +398,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;
                }
 
@@ -498,7 +492,7 @@ 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;
                }
 
@@ -506,7 +500,7 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex)
                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);
@@ -553,20 +547,20 @@ 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. */
        }
@@ -587,17 +581,17 @@ int process_aio_queue(void)
        BlockSignals(True, RT_SIGNAL_AIO);
 
        DEBUG(10,("process_aio_queue: signals_received = %d\n",
-                 (int)signals_received));
+                 (int)aio_signals_received));
        DEBUG(10,("process_aio_queue: outstanding_aio_calls = %d\n",
                  outstanding_aio_calls));
 
-       if (!signals_received) {
+       if (!aio_signals_received) {
                BlockSignals(False, RT_SIGNAL_AIO);
                return 0;
        }
 
        /* Drain all the complete aio_reads. */
-       for (i = 0; i < signals_received; i++) {
+       for (i = 0; i < aio_signals_received; i++) {
                uint16 mid = aio_pending_array[i];
                files_struct *fsp = NULL;
                struct aio_extra *aio_ex = find_aio_ex(mid);
@@ -623,11 +617,11 @@ int process_aio_queue(void)
                        continue;
                }
 
-               delete_aio_ex(aio_ex);
+               TALLOC_FREE(aio_ex);
        }
 
-       outstanding_aio_calls -= signals_received;
-       signals_received = 0;
+       outstanding_aio_calls -= aio_signals_received;
+       aio_signals_received = 0;
        BlockSignals(False, RT_SIGNAL_AIO);
        return ret;
 }
@@ -695,7 +689,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 +718,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);