4b3e5ef4ab18c2ca5b0610bbe125f497b7a7ba82
[fio.git] / engines / syslet-rw.c
1 /*
2  * syslet engine
3  *
4  * IO engine that does regular pread(2)/pwrite(2) to transfer data, but
5  * with syslets to make the execution async.
6  *
7  */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <errno.h>
12 #include <assert.h>
13 #include <malloc.h>
14 #include <asm/unistd.h>
15
16 #include "../fio.h"
17 #include "../fls.h"
18
19 #ifdef FIO_HAVE_SYSLET
20
21 #ifdef __NR_pread64
22 #define __NR_fio_pread  __NR_pread64
23 #define __NR_fio_pwrite __NR_pwrite64
24 #else
25 #define __NR_fio_pread  __NR_pread
26 #define __NR_fio_pwrite __NR_pwrite
27 #endif
28
29 struct syslet_data {
30         struct io_u **events;
31         unsigned int nr_events;
32         
33         struct syslet_ring *ring;
34         unsigned int ring_mask;
35         void *stack;
36 };
37
38 static void fio_syslet_add_event(struct thread_data *td, struct io_u *io_u)
39 {
40         struct syslet_data *sd = td->io_ops->data;
41
42         assert(sd->nr_events < td->o.iodepth);
43         sd->events[sd->nr_events++] = io_u;
44 }
45
46 static void fio_syslet_add_events(struct thread_data *td, unsigned int nr)
47 {
48         struct syslet_data *sd = td->io_ops->data;
49         unsigned int i, uidx;
50
51         uidx = sd->ring->user_tail;
52         read_barrier();
53
54         for (i = 0; i < nr; i++) {
55                 unsigned int idx = (i + uidx) & sd->ring_mask;
56                 struct syslet_completion *comp = &sd->ring->comp[idx];
57                 struct io_u *io_u = (struct io_u *) (long) comp->caller_data;
58                 long ret;
59
60                 ret = comp->status;
61                 if (ret <= 0) {
62                         io_u->resid = io_u->xfer_buflen;
63                         io_u->error = -ret;
64                 } else {
65                         io_u->resid = io_u->xfer_buflen - ret;
66                         io_u->error = 0;
67                 }
68
69                 fio_syslet_add_event(td, io_u);
70         }
71 }
72
73 static void fio_syslet_wait_for_events(struct thread_data *td)
74 {
75         struct syslet_data *sd = td->io_ops->data;
76         struct syslet_ring *ring = sd->ring;
77
78         do {
79                 unsigned int kh = ring->kernel_head;
80                 int ret;
81
82                 /*
83                  * first reap events that are already completed
84                  */
85                 if (ring->user_tail != kh) {
86                         unsigned int nr = kh - ring->user_tail;
87
88                         fio_syslet_add_events(td, nr);
89                         ring->user_tail = kh;
90                         break;
91                 }
92
93                 /*
94                  * block waiting for at least one event
95                  */
96                 ret = syscall(__NR_syslet_ring_wait, ring, ring->user_tail);
97                 assert(!ret);
98         } while (1);
99 }
100
101 static int fio_syslet_getevents(struct thread_data *td, unsigned int min,
102                                 unsigned int fio_unused max,
103                                 struct timespec fio_unused *t)
104 {
105         struct syslet_data *sd = td->io_ops->data;
106         long ret;
107
108         /*
109          * While we have less events than requested, block waiting for them
110          * (if we have to, there may already be more completed events ready
111          * for us - see fio_syslet_wait_for_events()
112          */
113         while (sd->nr_events < min)
114                 fio_syslet_wait_for_events(td);
115
116         ret = sd->nr_events;
117         sd->nr_events = 0;
118         return ret;
119 }
120
121 static struct io_u *fio_syslet_event(struct thread_data *td, int event)
122 {
123         struct syslet_data *sd = td->io_ops->data;
124
125         return sd->events[event];
126 }
127
128 static void fio_syslet_prep_sync(struct fio_file *f,
129                                  struct indirect_registers *regs)
130 {
131         FILL_IN(*regs, __NR_fsync, (long) f->fd);
132 }
133
134 static void fio_syslet_prep_rw(struct io_u *io_u, struct fio_file *f,
135                                struct indirect_registers *regs)
136 {
137         long nr;
138
139         /*
140          * prepare rw
141          */
142         if (io_u->ddir == DDIR_READ)
143                 nr = __NR_fio_pread;
144         else
145                 nr = __NR_fio_pwrite;
146
147         FILL_IN(*regs, nr, (long) f->fd, (long) io_u->xfer_buf,
148                 (long) io_u->xfer_buflen, (long) io_u->offset);
149 }
150
151 static void fio_syslet_prep(struct io_u *io_u, struct indirect_registers *regs)
152 {
153         struct fio_file *f = io_u->file;
154
155         if (io_u->ddir == DDIR_SYNC)
156                 fio_syslet_prep_sync(f, regs);
157         else
158                 fio_syslet_prep_rw(io_u, f, regs);
159 }
160
161 static void ret_func(void)
162 {
163         syscall(__NR_exit);
164 }
165
166 static int fio_syslet_queue(struct thread_data *td, struct io_u *io_u)
167 {
168         struct syslet_data *sd = td->io_ops->data;
169         union indirect_params params;
170         struct indirect_registers regs;
171         int ret;
172
173         fio_ro_check(td, io_u);
174
175         memset(&params, 0, sizeof(params));
176         fill_syslet_args(&params.syslet, sd->ring, (long)io_u, ret_func, sd->stack);
177
178         fio_syslet_prep(io_u, &regs);
179
180         ret = syscall(__NR_indirect, &regs, &params, sizeof(params), 0);
181         if (ret == (int) io_u->xfer_buflen) {
182                 /*
183                  * completed sync, account. this also catches fsync().
184                  */
185                 return FIO_Q_COMPLETED;
186         } else if (ret < 0) {
187                 /*
188                  * queued for async execution
189                  */
190                 if (errno == ESYSLETPENDING)
191                         return FIO_Q_QUEUED;
192         }
193
194         io_u->error = errno;
195         td_verror(td, io_u->error, "xfer");
196         return FIO_Q_COMPLETED;
197 }
198
199 static int check_syslet_support(struct syslet_data *sd)
200 {
201         union indirect_params params;
202         struct indirect_registers regs;
203         pid_t pid, my_pid = getpid();
204
205         memset(&params, 0, sizeof(params));
206         fill_syslet_args(&params.syslet, sd->ring, 0, ret_func, sd->stack);
207
208         FILL_IN(regs, __NR_getpid);
209
210         pid = syscall(__NR_indirect, &regs, &params, sizeof(params), 0);
211         if (pid == my_pid)
212                 return 0;
213
214         return 1;
215 }
216
217 static void fio_syslet_cleanup(struct thread_data *td)
218 {
219         struct syslet_data *sd = td->io_ops->data;
220
221         if (sd) {
222                 free(sd->events);
223                 free(sd->ring);
224                 free(sd);
225         }
226 }
227
228 static int fio_syslet_init(struct thread_data *td)
229 {
230         struct syslet_data *sd;
231         void *ring = NULL, *stack = NULL;
232         unsigned int ring_size, ring_nr;
233
234         sd = malloc(sizeof(*sd));
235         memset(sd, 0, sizeof(*sd));
236
237         sd->events = malloc(sizeof(struct io_u *) * td->o.iodepth);
238         memset(sd->events, 0, sizeof(struct io_u *) * td->o.iodepth);
239
240         /*
241          * The ring needs to be a power-of-2, so round it up if we have to
242          */
243         ring_nr = td->o.iodepth;
244         if (ring_nr & (ring_nr - 1))
245                 ring_nr = 1 << __fls(ring_nr);
246
247         ring_size = sizeof(struct syslet_ring) +
248                         ring_nr * sizeof(struct syslet_completion);
249         if (posix_memalign(&ring, sizeof(uint64_t), ring_size))
250                 goto err_mem;
251         if (posix_memalign(&stack, page_size, page_size))
252                 goto err_mem;
253
254         sd->ring = ring;
255         sd->ring_mask = ring_nr - 1;
256         sd->stack = stack;
257
258         memset(sd->ring, 0, ring_size);
259         sd->ring->elements = ring_nr;
260
261         if (!check_syslet_support(sd)) {
262                 td->io_ops->data = sd;
263                 return 0;
264         }
265
266         log_err("fio: syslets do not appear to work\n");
267 err_mem:
268         free(sd->events);
269         if (ring)
270                 free(ring);
271         if (stack)
272                 free(stack);
273         free(sd);
274         return 1;
275 }
276
277 static struct ioengine_ops ioengine = {
278         .name           = "syslet-rw",
279         .version        = FIO_IOOPS_VERSION,
280         .init           = fio_syslet_init,
281         .queue          = fio_syslet_queue,
282         .getevents      = fio_syslet_getevents,
283         .event          = fio_syslet_event,
284         .cleanup        = fio_syslet_cleanup,
285         .open_file      = generic_open_file,
286         .close_file     = generic_close_file,
287 };
288
289 #else /* FIO_HAVE_SYSLET */
290
291 /*
292  * When we have a proper configure system in place, we simply wont build
293  * and install this io engine. For now install a crippled version that
294  * just complains and fails to load.
295  */
296 static int fio_syslet_init(struct thread_data fio_unused *td)
297 {
298         fprintf(stderr, "fio: syslet not available\n");
299         return 1;
300 }
301
302 static struct ioengine_ops ioengine = {
303         .name           = "syslet-rw",
304         .version        = FIO_IOOPS_VERSION,
305         .init           = fio_syslet_init,
306 };
307
308 #endif /* FIO_HAVE_SYSLET */
309
310 static void fio_init fio_syslet_register(void)
311 {
312         register_ioengine(&ioengine);
313 }
314
315 static void fio_exit fio_syslet_unregister(void)
316 {
317         unregister_ioengine(&ioengine);
318 }