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
);