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"
27 #include "lib/sys_rw.h"
30 /* The signal we'll use to signify aio done. */
32 #define RT_SIGNAL_AIO (SIGRTMIN+3)
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
42 static struct tevent_signal
*aio_signal_event
= NULL
;
44 struct aio_posix_state
{
50 static int aio_posix_state_destructor(struct aio_posix_state
*s
)
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.
63 const struct aiocb
*a
= &s
->acb
;
64 ret
= aio_suspend(&a
, 1, NULL
);
65 } while ((ret
== -1) && (errno
== EINTR
));
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
;
80 req
= tevent_req_create(mem_ctx
, &state
, struct aio_posix_state
);
87 a
->aio_fildes
= fsp
->fh
->fd
;
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
;
97 talloc_set_destructor(state
, aio_posix_state_destructor
);
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) {
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
;
127 req
= tevent_req_create(mem_ctx
, &state
, struct aio_posix_state
);
134 a
->aio_fildes
= fsp
->fh
->fd
;
135 a
->aio_buf
= discard_const(data
);
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
;
144 talloc_set_destructor(state
, aio_posix_state_destructor
);
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) {
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
)
170 struct tevent_req
*req
;
171 struct aio_posix_state
*state
;
174 info
= (siginfo_t
*)_info
;
175 req
= talloc_get_type_abort(info
->si_value
.sival_ptr
,
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
));
185 if (err
== ECANCELED
) {
186 DEBUG(10, ("aio_posix_signal_handler: operation req %p "
192 * No need to suspend for this in the destructor anymore
194 talloc_set_destructor(state
, NULL
);
196 state
->ret
= aio_return(&state
->acb
);
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
)) {
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
;
222 req
= tevent_req_create(mem_ctx
, &state
, struct aio_posix_state
);
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
);
236 talloc_set_destructor(state
, aio_posix_state_destructor
);
240 if (errno
== EAGAIN
) {
242 * aio overloaded, do the sync fallback
244 state
->ret
= fsync(fsp
->fh
->fd
);
245 if (state
->ret
== -1) {
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
)) {
268 static int aio_posix_connect(vfs_handle_struct
*handle
, const char *service
,
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"));
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
);