diff options
-rw-r--r-- | source3/Makefile.in | 5 | ||||
-rw-r--r-- | source3/configure.in | 5 | ||||
-rw-r--r-- | source3/modules/vfs_aio_posix.c | 243 | ||||
-rw-r--r-- | source3/modules/wscript_build | 10 | ||||
-rw-r--r-- | source3/smbd/globals.c | 2 | ||||
-rw-r--r-- | source3/smbd/globals.h | 3 | ||||
-rw-r--r-- | source3/smbd/smbd.h | 1 | ||||
-rwxr-xr-x | source3/wscript | 1 |
8 files changed, 264 insertions, 6 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 06090446c3..7538077a54 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -888,6 +888,7 @@ VFS_TSMSM_OBJ = modules/vfs_tsmsm.o VFS_FILEID_OBJ = modules/vfs_fileid.o VFS_AIO_FORK_OBJ = modules/vfs_aio_fork.o VFS_AIO_PTHREAD_OBJ = modules/vfs_aio_pthread.o +VFS_AIO_POSIX_OBJ = modules/vfs_aio_posix.o VFS_AIO_LINUX_OBJ = modules/vfs_aio_linux.o VFS_PREOPEN_OBJ = modules/vfs_preopen.o VFS_SYNCOPS_OBJ = modules/vfs_syncops.o @@ -2901,6 +2902,10 @@ bin/aio_pthread.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_AIO_PTHREAD_OBJ) @echo "Building plugin $@" @$(SHLD_MODULE) $(VFS_AIO_PTHREAD_OBJ) +bin/aio_posix.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_AIO_POSIX_OBJ) + @echo "Building plugin $@" + @$(SHLD_MODULE) $(VFS_AIO_POSIX_OBJ) + bin/aio_linux.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_AIO_LINUX_OBJ) @echo "Building plugin $@" @$(SHLD_MODULE) $(VFS_AIO_LINUX_OBJ) diff --git a/source3/configure.in b/source3/configure.in index 150f1896da..b5fd8c253e 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -5585,6 +5585,10 @@ samba_cv_HAVE_LINUX_KERNEL_AIO=yes,samba_cv_HAVE_LINUX_KERNEL_AIO=no) esac fi +if test x"$samba_cv_HAVE_AIO" = x"yes"; then + default_shared_modules="$default_shared_modules vfs_aio_posix" +fi + ################################################# # check for sendfile support @@ -6530,6 +6534,7 @@ SMB_MODULE(vfs_tsmsm, \$(VFS_TSMSM_OBJ), "bin/tsmsm.$SHLIBEXT", VFS) SMB_MODULE(vfs_fileid, \$(VFS_FILEID_OBJ), "bin/fileid.$SHLIBEXT", VFS) SMB_MODULE(vfs_aio_fork, \$(VFS_AIO_FORK_OBJ), "bin/aio_fork.$SHLIBEXT", VFS) SMB_MODULE(vfs_aio_pthread, \$(VFS_AIO_PTHREAD_OBJ), "bin/aio_pthread.$SHLIBEXT", VFS) +SMB_MODULE(vfs_aio_posix, \$(VFS_AIO_POSIX_OBJ), "bin/aio_posix.$SHLIBEXT", VFS) SMB_MODULE(vfs_aio_linux, \$(VFS_AIO_LINUX_OBJ), "bin/aio_linux.$SHLIBEXT", VFS) SMB_MODULE(vfs_preopen, \$(VFS_PREOPEN_OBJ), "bin/preopen.$SHLIBEXT", VFS) SMB_MODULE(vfs_syncops, \$(VFS_SYNCOPS_OBJ), "bin/syncops.$SHLIBEXT", VFS) diff --git a/source3/modules/vfs_aio_posix.c b/source3/modules/vfs_aio_posix.c new file mode 100644 index 0000000000..97b102b5e4 --- /dev/null +++ b/source3/modules/vfs_aio_posix.c @@ -0,0 +1,243 @@ +/* + * Simulate pread_send/recv and pwrite_send/recv using posix aio + * + * Copyright (C) Volker Lendecke 2012 + * + * 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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. + */ + +#include "includes.h" +#include "system/filesys.h" +#include "system/shmem.h" +#include "smbd/smbd.h" +#include "smbd/globals.h" +#include "lib/util/tevent_unix.h" +#include <aio.h> + +/* The signal we'll use to signify aio done. */ +#ifndef RT_SIGNAL_AIO +#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 + +static struct tevent_signal *aio_signal_event = NULL; + +struct aio_posix_state { + struct aiocb acb; + ssize_t ret; + int err; +}; + +static int aio_posix_state_destructor(struct aio_posix_state *s) +{ + int ret; + + /* + * We could do better here. This destructor is run when a + * request is prematurely cancelled. We wait for the aio to + * complete, so that we do not have to maintain aiocb structs + * beyond the life of an aio_posix_state. Possible, but not + * sure the effort is worth it right now. + */ + + do { + const struct aiocb *a = &s->acb; + ret = aio_suspend(&a, 1, NULL); + } while ((ret == -1) && (errno == EINTR)); + + return 0; +} + +static struct tevent_req *aio_posix_pread_send( + struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct files_struct *fsp, void *data, size_t n, off_t offset) +{ + struct tevent_req *req; + struct aio_posix_state *state; + struct aiocb *a; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct aio_posix_state); + if (req == NULL) { + return NULL; + } + + a = &state->acb; + + a->aio_fildes = fsp->fh->fd; + a->aio_buf = data; + a->aio_nbytes = n; + a->aio_offset = offset; + a->aio_sigevent.sigev_notify = SIGEV_SIGNAL; + a->aio_sigevent.sigev_signo = RT_SIGNAL_AIO; + a->aio_sigevent.sigev_value.sival_ptr = req; + + ret = aio_read(a); + if (ret == 0) { + talloc_set_destructor(state, aio_posix_state_destructor); + return req; + } + + if (errno == EAGAIN) { + /* + * aio overloaded, do the sync fallback + */ + state->ret = sys_pread(fsp->fh->fd, data, n, offset); + if (state->ret == -1) { + state->err = errno; + } + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + tevent_req_error(req, errno); + return tevent_req_post(req, ev); +} + +static struct tevent_req *aio_posix_pwrite_send( + struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct files_struct *fsp, const void *data, size_t n, off_t offset) +{ + struct tevent_req *req; + struct aio_posix_state *state; + struct aiocb *a; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct aio_posix_state); + if (req == NULL) { + return NULL; + } + + a = &state->acb; + + a->aio_fildes = fsp->fh->fd; + a->aio_buf = discard_const(data); + a->aio_nbytes = n; + a->aio_offset = offset; + a->aio_sigevent.sigev_notify = SIGEV_SIGNAL; + a->aio_sigevent.sigev_signo = RT_SIGNAL_AIO; + a->aio_sigevent.sigev_value.sival_ptr = req; + + ret = aio_write(a); + if (ret == 0) { + talloc_set_destructor(state, aio_posix_state_destructor); + return req; + } + + if (errno == EAGAIN) { + /* + * aio overloaded, do the sync fallback + */ + state->ret = sys_pwrite(fsp->fh->fd, data, n, offset); + if (state->ret == -1) { + state->err = errno; + } + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + tevent_req_error(req, errno); + return tevent_req_post(req, ev); +} + +static void aio_posix_signal_handler(struct tevent_context *ev, + struct tevent_signal *se, + int signum, int count, + void *_info, void *private_data) +{ + siginfo_t *info; + struct tevent_req *req; + struct aio_posix_state *state; + int err; + + info = (siginfo_t *)_info; + req = talloc_get_type_abort(info->si_value.sival_ptr, + struct tevent_req); + state = tevent_req_data(req, struct aio_posix_state); + + err = aio_error(&state->acb); + if (err == EINPROGRESS) { + DEBUG(10, ("aio_posix_signal_handler: operation req %p " + "still in progress\n", req)); + return; + } + if (err == ECANCELED) { + DEBUG(10, ("aio_posix_signal_handler: operation req %p " + "canceled\n", req)); + return; + } + + /* + * No need to suspend for this in the destructor anymore + */ + talloc_set_destructor(state, NULL); + + state->ret = aio_return(&state->acb); + state->err = err; + tevent_req_done(req); +} + +static ssize_t aio_posix_recv(struct tevent_req *req, int *err) +{ + struct aio_posix_state *state = tevent_req_data( + req, struct aio_posix_state); + + if (tevent_req_is_unix_error(req, err)) { + return -1; + } + *err = state->err; + return state->ret; +} + +static int aio_posix_connect(vfs_handle_struct *handle, const char *service, + const char *user) +{ + if (aio_signal_event == NULL) { + struct tevent_context *ev = handle->conn->sconn->ev_ctx; + + aio_signal_event = tevent_add_signal( + ev, ev, RT_SIGNAL_AIO, SA_SIGINFO, + aio_posix_signal_handler, NULL); + + if (aio_signal_event == NULL) { + DEBUG(1, ("tevent_add_signal failed\n")); + return -1; + } + } + return SMB_VFS_NEXT_CONNECT(handle, service, user); +} + +static struct vfs_fn_pointers vfs_aio_posix_fns = { + .connect_fn = aio_posix_connect, + .pread_send_fn = aio_posix_pread_send, + .pread_recv_fn = aio_posix_recv, + .pwrite_send_fn = aio_posix_pwrite_send, + .pwrite_recv_fn = aio_posix_recv, +}; + +NTSTATUS vfs_aio_posix_init(void); +NTSTATUS vfs_aio_posix_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, + "aio_posix", &vfs_aio_posix_fns); +} diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build index 1f3189affb..2f5088ad24 100644 --- a/source3/modules/wscript_build +++ b/source3/modules/wscript_build @@ -37,6 +37,7 @@ VFS_TSMSM_SRC = 'vfs_tsmsm.c' VFS_FILEID_SRC = 'vfs_fileid.c' VFS_AIO_FORK_SRC = 'vfs_aio_fork.c' VFS_AIO_PTHREAD_SRC = 'vfs_aio_pthread.c' +VFS_AIO_POSIX_SRC = 'vfs_aio_posix.c' VFS_AIO_LINUX_SRC = 'vfs_aio_linux.c' VFS_PREOPEN_SRC = 'vfs_preopen.c' VFS_SYNCOPS_SRC = 'vfs_syncops.c' @@ -363,6 +364,15 @@ bld.SAMBA3_MODULE('vfs_aio_pthread', enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_aio_pthread'), allow_undefined_symbols=True) +bld.SAMBA3_MODULE('vfs_aio_posix', + subsystem='vfs', + source=VFS_AIO_POSIX_SRC, + deps='samba-util tevent', + init_function='', + internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_aio_posix'), + enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_aio_posix'), + allow_undefined_symbols=True) + bld.SAMBA3_MODULE('vfs_aio_linux', subsystem='vfs', source=VFS_AIO_LINUX_SRC, diff --git a/source3/smbd/globals.c b/source3/smbd/globals.c index cc6b87102f..80f6a66427 100644 --- a/source3/smbd/globals.c +++ b/source3/smbd/globals.c @@ -25,10 +25,8 @@ #include "messages.h" #include "tdb_compat.h" -#if defined(HAVE_AIO) int aio_pending_size = 100; /* tevent supports 100 signals SA_SIGINFO */ int outstanding_aio_calls = 0; -#endif #ifdef USE_DMAPI struct smbd_dmapi_context *dmapi_ctx = NULL; diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 764496c648..80612eb716 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -21,11 +21,8 @@ #include "system/select.h" #include "librpc/gen_ndr/smbXsrv.h" -#if defined(HAVE_AIO) -struct aio_extra; extern int aio_pending_size; extern int outstanding_aio_calls; -#endif #ifdef USE_DMAPI struct smbd_dmapi_context; diff --git a/source3/smbd/smbd.h b/source3/smbd/smbd.h index 9233fd743c..009b183c64 100644 --- a/source3/smbd/smbd.h +++ b/source3/smbd/smbd.h @@ -20,7 +20,6 @@ #define _SMBD_SMBD_H struct dptr_struct; -struct aio_extra; #include "smb_acls.h" #include "librpc/gen_ndr/smbXsrv.h" diff --git a/source3/wscript b/source3/wscript index bd6ddcf421..be39a6f845 100755 --- a/source3/wscript +++ b/source3/wscript @@ -1468,6 +1468,7 @@ main() { if conf.CONFIG_SET('HAVE_AIO') and Options.options.with_pthreadpool: default_shared_modules.extend(TO_LIST('vfs_aio_pthread')) + default_shared_modules.extend(TO_LIST('vfs_aio_posix')) if conf.CONFIG_SET('HAVE_AIO') and conf.CONFIG_SET('HAVE_LINUX_KERNEL_AIO'): default_shared_modules.extend(TO_LIST('vfs_aio_linux')) |