s4-dsdb-tests: Make unique object names to test with in deletetest
[Samba.git] / source3 / modules / vfs_aio_posix.c
blobef5f706727228300be18990654e8a998609daa4c
1 /*
2 * Simulate pread_send/recv and pwrite_send/recv using posix aio
4 * Copyright (C) Volker Lendecke 2012
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "system/shmem.h"
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "lib/util/tevent_unix.h"
27 #include "lib/sys_rw.h"
28 #include <aio.h>
30 /* The signal we'll use to signify aio done. */
31 #ifndef RT_SIGNAL_AIO
32 #define RT_SIGNAL_AIO (SIGRTMIN+3)
33 #endif
35 #ifndef HAVE_STRUCT_SIGEVENT_SIGEV_VALUE_SIVAL_PTR
36 #ifdef HAVE_STRUCT_SIGEVENT_SIGEV_VALUE_SIGVAL_PTR
37 #define sival_int sigval_int
38 #define sival_ptr sigval_ptr
39 #endif
40 #endif
42 static struct tevent_signal *aio_signal_event = NULL;
44 struct aio_posix_state {
45 struct aiocb acb;
46 ssize_t ret;
47 int err;
50 static int aio_posix_state_destructor(struct aio_posix_state *s)
52 int ret;
55 * We could do better here. This destructor is run when a
56 * request is prematurely cancelled. We wait for the aio to
57 * complete, so that we do not have to maintain aiocb structs
58 * beyond the life of an aio_posix_state. Possible, but not
59 * sure the effort is worth it right now.
62 do {
63 const struct aiocb *a = &s->acb;
64 ret = aio_suspend(&a, 1, NULL);
65 } while ((ret == -1) && (errno == EINTR));
67 return 0;
70 static struct tevent_req *aio_posix_pread_send(
71 struct vfs_handle_struct *handle,
72 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
73 struct files_struct *fsp, void *data, size_t n, off_t offset)
75 struct tevent_req *req;
76 struct aio_posix_state *state;
77 struct aiocb *a;
78 int ret;
80 req = tevent_req_create(mem_ctx, &state, struct aio_posix_state);
81 if (req == NULL) {
82 return NULL;
85 a = &state->acb;
87 a->aio_fildes = fsp->fh->fd;
88 a->aio_buf = data;
89 a->aio_nbytes = n;
90 a->aio_offset = offset;
91 a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
92 a->aio_sigevent.sigev_signo = RT_SIGNAL_AIO;
93 a->aio_sigevent.sigev_value.sival_ptr = req;
95 ret = aio_read(a);
96 if (ret == 0) {
97 talloc_set_destructor(state, aio_posix_state_destructor);
98 return req;
101 if (errno == EAGAIN) {
103 * aio overloaded, do the sync fallback
105 state->ret = sys_pread(fsp->fh->fd, data, n, offset);
106 if (state->ret == -1) {
107 state->err = errno;
109 tevent_req_done(req);
110 return tevent_req_post(req, ev);
113 tevent_req_error(req, errno);
114 return tevent_req_post(req, ev);
117 static struct tevent_req *aio_posix_pwrite_send(
118 struct vfs_handle_struct *handle,
119 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
120 struct files_struct *fsp, const void *data, size_t n, off_t offset)
122 struct tevent_req *req;
123 struct aio_posix_state *state;
124 struct aiocb *a;
125 int ret;
127 req = tevent_req_create(mem_ctx, &state, struct aio_posix_state);
128 if (req == NULL) {
129 return NULL;
132 a = &state->acb;
134 a->aio_fildes = fsp->fh->fd;
135 a->aio_buf = discard_const(data);
136 a->aio_nbytes = n;
137 a->aio_offset = offset;
138 a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
139 a->aio_sigevent.sigev_signo = RT_SIGNAL_AIO;
140 a->aio_sigevent.sigev_value.sival_ptr = req;
142 ret = aio_write(a);
143 if (ret == 0) {
144 talloc_set_destructor(state, aio_posix_state_destructor);
145 return req;
148 if (errno == EAGAIN) {
150 * aio overloaded, do the sync fallback
152 state->ret = sys_pwrite(fsp->fh->fd, data, n, offset);
153 if (state->ret == -1) {
154 state->err = errno;
156 tevent_req_done(req);
157 return tevent_req_post(req, ev);
160 tevent_req_error(req, errno);
161 return tevent_req_post(req, ev);
164 static void aio_posix_signal_handler(struct tevent_context *ev,
165 struct tevent_signal *se,
166 int signum, int count,
167 void *_info, void *private_data)
169 siginfo_t *info;
170 struct tevent_req *req;
171 struct aio_posix_state *state;
172 int err;
174 info = (siginfo_t *)_info;
175 req = talloc_get_type_abort(info->si_value.sival_ptr,
176 struct tevent_req);
177 state = tevent_req_data(req, struct aio_posix_state);
179 err = aio_error(&state->acb);
180 if (err == EINPROGRESS) {
181 DEBUG(10, ("aio_posix_signal_handler: operation req %p "
182 "still in progress\n", req));
183 return;
185 if (err == ECANCELED) {
186 DEBUG(10, ("aio_posix_signal_handler: operation req %p "
187 "canceled\n", req));
188 return;
192 * No need to suspend for this in the destructor anymore
194 talloc_set_destructor(state, NULL);
196 state->ret = aio_return(&state->acb);
197 state->err = err;
198 tevent_req_done(req);
201 static ssize_t aio_posix_recv(struct tevent_req *req, int *err)
203 struct aio_posix_state *state = tevent_req_data(
204 req, struct aio_posix_state);
206 if (tevent_req_is_unix_error(req, err)) {
207 return -1;
209 *err = state->err;
210 return state->ret;
213 static struct tevent_req *aio_posix_fsync_send(
214 struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
215 struct tevent_context *ev, struct files_struct *fsp)
217 struct tevent_req *req;
218 struct aio_posix_state *state;
219 struct aiocb *a;
220 int ret;
222 req = tevent_req_create(mem_ctx, &state, struct aio_posix_state);
223 if (req == NULL) {
224 return NULL;
227 a = &state->acb;
229 a->aio_fildes = fsp->fh->fd;
230 a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
231 a->aio_sigevent.sigev_signo = RT_SIGNAL_AIO;
232 a->aio_sigevent.sigev_value.sival_ptr = req;
234 ret = aio_fsync(O_SYNC, a);
235 if (ret == 0) {
236 talloc_set_destructor(state, aio_posix_state_destructor);
237 return req;
240 if (errno == EAGAIN) {
242 * aio overloaded, do the sync fallback
244 state->ret = fsync(fsp->fh->fd);
245 if (state->ret == -1) {
246 state->err = errno;
248 tevent_req_done(req);
249 return tevent_req_post(req, ev);
252 tevent_req_error(req, errno);
253 return tevent_req_post(req, ev);
256 static int aio_posix_int_recv(struct tevent_req *req, int *err)
258 struct aio_posix_state *state = tevent_req_data(
259 req, struct aio_posix_state);
261 if (tevent_req_is_unix_error(req, err)) {
262 return -1;
264 *err = state->err;
265 return state->ret;
268 static int aio_posix_connect(vfs_handle_struct *handle, const char *service,
269 const char *user)
271 if (aio_signal_event == NULL) {
272 struct tevent_context *ev = handle->conn->sconn->ev_ctx;
274 aio_signal_event = tevent_add_signal(
275 ev, ev, RT_SIGNAL_AIO, SA_SIGINFO,
276 aio_posix_signal_handler, NULL);
278 if (aio_signal_event == NULL) {
279 DEBUG(1, ("tevent_add_signal failed\n"));
280 return -1;
283 return SMB_VFS_NEXT_CONNECT(handle, service, user);
286 static struct vfs_fn_pointers vfs_aio_posix_fns = {
287 .connect_fn = aio_posix_connect,
288 .pread_send_fn = aio_posix_pread_send,
289 .pread_recv_fn = aio_posix_recv,
290 .pwrite_send_fn = aio_posix_pwrite_send,
291 .pwrite_recv_fn = aio_posix_recv,
292 .fsync_send_fn = aio_posix_fsync_send,
293 .fsync_recv_fn = aio_posix_int_recv,
296 NTSTATUS vfs_aio_posix_init(void);
297 NTSTATUS vfs_aio_posix_init(void)
299 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
300 "aio_posix", &vfs_aio_posix_fns);