[PATCH] libaio sign error
[fio.git] / engines / fio-engine-splice.c
1 /*
2  * splice io engine
3  *
4  */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <errno.h>
9 #include <assert.h>
10 #include <sys/poll.h>
11 #include "fio.h"
12 #include "os.h"
13
14 struct spliceio_data {
15         struct io_u *last_io_u;
16         int pipe[2];
17 };
18
19 static int fio_spliceio_getevents(struct thread_data *td, int fio_unused min,
20                                   int max, struct timespec fio_unused *t)
21 {
22         assert(max <= 1);
23
24         /*
25          * we can only have one finished io_u for sync io, since the depth
26          * is always 1
27          */
28         if (list_empty(&td->io_u_busylist))
29                 return 0;
30
31         return 1;
32 }
33
34 static struct io_u *fio_spliceio_event(struct thread_data *td, int event)
35 {
36         struct spliceio_data *sd = td->io_ops->data;
37
38         assert(event == 0);
39
40         return sd->last_io_u;
41 }
42
43 /*
44  * For splice reading, we unfortunately cannot (yet) vmsplice the other way.
45  * So just splice the data from the file into the pipe, and use regular
46  * read to fill the buffer. Doesn't make a lot of sense, but...
47  */
48 static int fio_splice_read(struct thread_data *td, struct io_u *io_u)
49 {
50         struct spliceio_data *sd = td->io_ops->data;
51         struct fio_file *f = io_u->file;
52         int ret, ret2, buflen;
53         off_t offset;
54         void *p;
55
56         offset = io_u->offset;
57         buflen = io_u->buflen;
58         p = io_u->buf;
59         while (buflen) {
60                 int this_len = buflen;
61
62                 if (this_len > SPLICE_DEF_SIZE)
63                         this_len = SPLICE_DEF_SIZE;
64
65                 ret = splice(f->fd, &offset, sd->pipe[1], NULL, this_len, SPLICE_F_MORE);
66                 if (ret < 0) {
67                         if (errno == ENODATA || errno == EAGAIN)
68                                 continue;
69
70                         return errno;
71                 }
72
73                 buflen -= ret;
74
75                 while (ret) {
76                         ret2 = read(sd->pipe[0], p, ret);
77                         if (ret2 < 0)
78                                 return errno;
79
80                         ret -= ret2;
81                         p += ret2;
82                 }
83         }
84
85         return io_u->buflen;
86 }
87
88 /*
89  * For splice writing, we can vmsplice our data buffer directly into a
90  * pipe and then splice that to a file.
91  */
92 static int fio_splice_write(struct thread_data *td, struct io_u *io_u)
93 {
94         struct spliceio_data *sd = td->io_ops->data;
95         struct iovec iov[1] = {
96                 {
97                         .iov_base = io_u->buf,
98                         .iov_len = io_u->buflen,
99                 }
100         };
101         struct pollfd pfd = { .fd = sd->pipe[1], .events = POLLOUT, };
102         struct fio_file *f = io_u->file;
103         off_t off = io_u->offset;
104         int ret, ret2;
105
106         while (iov[0].iov_len) {
107                 if (poll(&pfd, 1, -1) < 0)
108                         return errno;
109
110                 ret = vmsplice(sd->pipe[1], iov, 1, SPLICE_F_NONBLOCK);
111                 if (ret < 0)
112                         return errno;
113
114                 iov[0].iov_len -= ret;
115                 iov[0].iov_base += ret;
116
117                 while (ret) {
118                         ret2 = splice(sd->pipe[0], NULL, f->fd, &off, ret, 0);
119                         if (ret2 < 0)
120                                 return errno;
121
122                         ret -= ret2;
123                 }
124         }
125
126         return io_u->buflen;
127 }
128
129 static int fio_spliceio_queue(struct thread_data *td, struct io_u *io_u)
130 {
131         struct spliceio_data *sd = td->io_ops->data;
132         unsigned int ret;
133
134         if (io_u->ddir == DDIR_READ)
135                 ret = fio_splice_read(td, io_u);
136         else if (io_u->ddir == DDIR_WRITE)
137                 ret = fio_splice_write(td, io_u);
138         else
139                 ret = fsync(io_u->file->fd);
140
141         if (ret != io_u->buflen) {
142                 if (ret > 0) {
143                         io_u->resid = io_u->buflen - ret;
144                         io_u->error = ENODATA;
145                 } else
146                         io_u->error = errno;
147         }
148
149         if (!io_u->error)
150                 sd->last_io_u = io_u;
151
152         return io_u->error;
153 }
154
155 static void fio_spliceio_cleanup(struct thread_data *td)
156 {
157         struct spliceio_data *sd = td->io_ops->data;
158
159         if (sd) {
160                 close(sd->pipe[0]);
161                 close(sd->pipe[1]);
162                 free(sd);
163                 td->io_ops->data = NULL;
164         }
165 }
166
167 static int fio_spliceio_init(struct thread_data *td)
168 {
169         struct spliceio_data *sd = malloc(sizeof(*sd));
170
171         sd->last_io_u = NULL;
172         if (pipe(sd->pipe) < 0) {
173                 td_verror(td, errno);
174                 free(sd);
175                 return 1;
176         }
177
178         td->io_ops->data = sd;
179         return 0;
180 }
181
182 struct ioengine_ops ioengine = {
183         .name           = "splice",
184         .version        = FIO_IOOPS_VERSION,
185         .init           = fio_spliceio_init,
186         .queue          = fio_spliceio_queue,
187         .getevents      = fio_spliceio_getevents,
188         .event          = fio_spliceio_event,
189         .cleanup        = fio_spliceio_cleanup,
190         .flags          = FIO_SYNCIO,
191 };