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.
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"
29 /* The signal we'll use to signify aio done. */
31 #define RT_SIGNAL_AIO (SIGRTMIN+3)
34 #ifndef HAVE_STRUCT_SIGEVENT_SIGEV_VALUE_SIVAL_PTR
35 #ifdef HAVE_STRUCT_SIGEVENT_SIGEV_VALUE_SIGVAL_PTR
36 #define sival_int sigval_int
37 #define sival_ptr sigval_ptr
41 static struct tevent_signal *aio_signal_event = NULL;
43 struct aio_posix_state {
49 static int aio_posix_state_destructor(struct aio_posix_state *s)
54 * We could do better here. This destructor is run when a
55 * request is prematurely cancelled. We wait for the aio to
56 * complete, so that we do not have to maintain aiocb structs
57 * beyond the life of an aio_posix_state. Possible, but not
58 * sure the effort is worth it right now.
62 const struct aiocb *a = &s->acb;
63 ret = aio_suspend(&a, 1, NULL);
64 } while ((ret == -1) && (errno == EINTR));
69 static struct tevent_req *aio_posix_pread_send(
70 struct vfs_handle_struct *handle,
71 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
72 struct files_struct *fsp, void *data, size_t n, off_t offset)
74 struct tevent_req *req;
75 struct aio_posix_state *state;
79 req = tevent_req_create(mem_ctx, &state, struct aio_posix_state);
86 a->aio_fildes = fsp->fh->fd;
89 a->aio_offset = offset;
90 a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
91 a->aio_sigevent.sigev_signo = RT_SIGNAL_AIO;
92 a->aio_sigevent.sigev_value.sival_ptr = req;
96 talloc_set_destructor(state, aio_posix_state_destructor);
100 if (errno == EAGAIN) {
102 * aio overloaded, do the sync fallback
104 state->ret = sys_pread(fsp->fh->fd, data, n, offset);
105 if (state->ret == -1) {
108 tevent_req_done(req);
109 return tevent_req_post(req, ev);
112 tevent_req_error(req, errno);
113 return tevent_req_post(req, ev);
116 static struct tevent_req *aio_posix_pwrite_send(
117 struct vfs_handle_struct *handle,
118 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
119 struct files_struct *fsp, const void *data, size_t n, off_t offset)
121 struct tevent_req *req;
122 struct aio_posix_state *state;
126 req = tevent_req_create(mem_ctx, &state, struct aio_posix_state);
133 a->aio_fildes = fsp->fh->fd;
134 a->aio_buf = discard_const(data);
136 a->aio_offset = offset;
137 a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
138 a->aio_sigevent.sigev_signo = RT_SIGNAL_AIO;
139 a->aio_sigevent.sigev_value.sival_ptr = req;
143 talloc_set_destructor(state, aio_posix_state_destructor);
147 if (errno == EAGAIN) {
149 * aio overloaded, do the sync fallback
151 state->ret = sys_pwrite(fsp->fh->fd, data, n, offset);
152 if (state->ret == -1) {
155 tevent_req_done(req);
156 return tevent_req_post(req, ev);
159 tevent_req_error(req, errno);
160 return tevent_req_post(req, ev);
163 static void aio_posix_signal_handler(struct tevent_context *ev,
164 struct tevent_signal *se,
165 int signum, int count,
166 void *_info, void *private_data)
169 struct tevent_req *req;
170 struct aio_posix_state *state;
173 info = (siginfo_t *)_info;
174 req = talloc_get_type_abort(info->si_value.sival_ptr,
176 state = tevent_req_data(req, struct aio_posix_state);
178 err = aio_error(&state->acb);
179 if (err == EINPROGRESS) {
180 DEBUG(10, ("aio_posix_signal_handler: operation req %p "
181 "still in progress\n", req));
184 if (err == ECANCELED) {
185 DEBUG(10, ("aio_posix_signal_handler: operation req %p "
191 * No need to suspend for this in the destructor anymore
193 talloc_set_destructor(state, NULL);
195 state->ret = aio_return(&state->acb);
197 tevent_req_done(req);
200 static ssize_t aio_posix_recv(struct tevent_req *req, int *err)
202 struct aio_posix_state *state = tevent_req_data(
203 req, struct aio_posix_state);
205 if (tevent_req_is_unix_error(req, err)) {
212 static struct tevent_req *aio_posix_fsync_send(
213 struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
214 struct tevent_context *ev, struct files_struct *fsp)
216 struct tevent_req *req;
217 struct aio_posix_state *state;
221 req = tevent_req_create(mem_ctx, &state, struct aio_posix_state);
228 a->aio_fildes = fsp->fh->fd;
229 a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
230 a->aio_sigevent.sigev_signo = RT_SIGNAL_AIO;
231 a->aio_sigevent.sigev_value.sival_ptr = req;
233 ret = aio_fsync(O_SYNC, a);
235 talloc_set_destructor(state, aio_posix_state_destructor);
239 if (errno == EAGAIN) {
241 * aio overloaded, do the sync fallback
243 state->ret = fsync(fsp->fh->fd);
244 if (state->ret == -1) {
247 tevent_req_done(req);
248 return tevent_req_post(req, ev);
251 tevent_req_error(req, errno);
252 return tevent_req_post(req, ev);
255 static int aio_posix_int_recv(struct tevent_req *req, int *err)
257 struct aio_posix_state *state = tevent_req_data(
258 req, struct aio_posix_state);
260 if (tevent_req_is_unix_error(req, err)) {
267 static int aio_posix_connect(vfs_handle_struct *handle, const char *service,
270 if (aio_signal_event == NULL) {
271 struct tevent_context *ev = handle->conn->sconn->ev_ctx;
273 aio_signal_event = tevent_add_signal(
274 ev, ev, RT_SIGNAL_AIO, SA_SIGINFO,
275 aio_posix_signal_handler, NULL);
277 if (aio_signal_event == NULL) {
278 DEBUG(1, ("tevent_add_signal failed\n"));
282 return SMB_VFS_NEXT_CONNECT(handle, service, user);
285 static struct vfs_fn_pointers vfs_aio_posix_fns = {
286 .connect_fn = aio_posix_connect,
287 .pread_send_fn = aio_posix_pread_send,
288 .pread_recv_fn = aio_posix_recv,
289 .pwrite_send_fn = aio_posix_pwrite_send,
290 .pwrite_recv_fn = aio_posix_recv,
291 .fsync_send_fn = aio_posix_fsync_send,
292 .fsync_recv_fn = aio_posix_int_recv,
295 NTSTATUS vfs_aio_posix_init(void);
296 NTSTATUS vfs_aio_posix_init(void)
298 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
299 "aio_posix", &vfs_aio_posix_fns);