smbd: Convert open_np_file to synthetic_smb_fname
[Samba/bjacke.git] / source3 / modules / vfs_aio_posix.c
blob3629541e6158dac761381c98e0c4d4bb3618b5dc
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 <aio.h>
29 /* The signal we'll use to signify aio done. */
30 #ifndef RT_SIGNAL_AIO
31 #define RT_SIGNAL_AIO (SIGRTMIN+3)
32 #endif
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
38 #endif
39 #endif
41 static struct tevent_signal *aio_signal_event = NULL;
43 struct aio_posix_state {
44 struct aiocb acb;
45 ssize_t ret;
46 int err;
49 static int aio_posix_state_destructor(struct aio_posix_state *s)
51 int ret;
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.
61 do {
62 const struct aiocb *a = &s->acb;
63 ret = aio_suspend(&a, 1, NULL);
64 } while ((ret == -1) && (errno == EINTR));
66 return 0;
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;
76 struct aiocb *a;
77 int ret;
79 req = tevent_req_create(mem_ctx, &state, struct aio_posix_state);
80 if (req == NULL) {
81 return NULL;
84 a = &state->acb;
86 a->aio_fildes = fsp->fh->fd;
87 a->aio_buf = data;
88 a->aio_nbytes = n;
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;
94 ret = aio_read(a);
95 if (ret == 0) {
96 talloc_set_destructor(state, aio_posix_state_destructor);
97 return req;
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) {
106 state->err = errno;
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;
123 struct aiocb *a;
124 int ret;
126 req = tevent_req_create(mem_ctx, &state, struct aio_posix_state);
127 if (req == NULL) {
128 return NULL;
131 a = &state->acb;
133 a->aio_fildes = fsp->fh->fd;
134 a->aio_buf = discard_const(data);
135 a->aio_nbytes = n;
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;
141 ret = aio_write(a);
142 if (ret == 0) {
143 talloc_set_destructor(state, aio_posix_state_destructor);
144 return req;
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) {
153 state->err = errno;
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)
168 siginfo_t *info;
169 struct tevent_req *req;
170 struct aio_posix_state *state;
171 int err;
173 info = (siginfo_t *)_info;
174 req = talloc_get_type_abort(info->si_value.sival_ptr,
175 struct tevent_req);
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));
182 return;
184 if (err == ECANCELED) {
185 DEBUG(10, ("aio_posix_signal_handler: operation req %p "
186 "canceled\n", req));
187 return;
191 * No need to suspend for this in the destructor anymore
193 talloc_set_destructor(state, NULL);
195 state->ret = aio_return(&state->acb);
196 state->err = err;
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)) {
206 return -1;
208 *err = state->err;
209 return state->ret;
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;
218 struct aiocb *a;
219 int ret;
221 req = tevent_req_create(mem_ctx, &state, struct aio_posix_state);
222 if (req == NULL) {
223 return NULL;
226 a = &state->acb;
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);
234 if (ret == 0) {
235 talloc_set_destructor(state, aio_posix_state_destructor);
236 return req;
239 if (errno == EAGAIN) {
241 * aio overloaded, do the sync fallback
243 state->ret = fsync(fsp->fh->fd);
244 if (state->ret == -1) {
245 state->err = errno;
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)) {
261 return -1;
263 *err = state->err;
264 return state->ret;
267 static int aio_posix_connect(vfs_handle_struct *handle, const char *service,
268 const char *user)
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"));
279 return -1;
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);