blob: ff8e9e4a1cd4ab4552ee39620910e26d1d11c1ce [file] [log] [blame]
Jens Axboeed92ac02007-02-06 14:43:52 +01001/*
Jens Axboeda751ca2007-03-14 10:59:33 +01002 * net engine
3 *
4 * IO engine that reads/writes to/from sockets.
5 *
Jens Axboeed92ac02007-02-06 14:43:52 +01006 */
7#include <stdio.h>
8#include <stdlib.h>
9#include <unistd.h>
10#include <errno.h>
11#include <assert.h>
12#include <netinet/in.h>
13#include <arpa/inet.h>
14#include <netdb.h>
Jens Axboe5fdd1242007-02-11 04:00:37 +010015#include <sys/poll.h>
Jens Axboe72920562008-06-02 12:30:06 +020016#include <sys/types.h>
Jens Axboe0fd666b2011-10-06 20:08:53 +020017#include <sys/stat.h>
Jens Axboe72920562008-06-02 12:30:06 +020018#include <sys/socket.h>
Jens Axboe0fd666b2011-10-06 20:08:53 +020019#include <sys/un.h>
Jens Axboeed92ac02007-02-06 14:43:52 +010020
21#include "../fio.h"
Jens Axboeed92ac02007-02-06 14:43:52 +010022
Jens Axboeb5af8292007-03-08 12:43:13 +010023struct netio_data {
24 int listenfd;
Jens Axboe9cce02e2007-06-22 15:42:21 +020025 int use_splice;
26 int pipes[2];
Jens Axboeb5af8292007-03-08 12:43:13 +010027 struct sockaddr_in addr;
Jens Axboe0fd666b2011-10-06 20:08:53 +020028 struct sockaddr_un addr_un;
Jens Axboeb5af8292007-03-08 12:43:13 +010029};
Jens Axboeed92ac02007-02-06 14:43:52 +010030
Steven Langde890a12011-11-09 14:03:34 +010031struct netio_options {
32 struct thread_data *td;
33 unsigned int port;
34 unsigned int proto;
35 unsigned int listen;
Jens Axboe6f73a7f2012-11-30 09:59:20 +010036 unsigned int pingpong;
Steven Langde890a12011-11-09 14:03:34 +010037};
38
Jens Axboe664fb3b2009-01-19 13:26:36 +010039struct udp_close_msg {
40 uint32_t magic;
41 uint32_t cmd;
42};
43
44enum {
45 FIO_LINK_CLOSE = 0x89,
Jens Axboeb96d2432012-11-30 08:27:46 +010046 FIO_LINK_OPEN_CLOSE_MAGIC = 0x6c696e6b,
47 FIO_LINK_OPEN = 0x98,
Jens Axboe0fd666b2011-10-06 20:08:53 +020048
49 FIO_TYPE_TCP = 1,
50 FIO_TYPE_UDP = 2,
51 FIO_TYPE_UNIX = 3,
Jens Axboe664fb3b2009-01-19 13:26:36 +010052};
53
Steven Langde890a12011-11-09 14:03:34 +010054static int str_hostname_cb(void *data, const char *input);
55static struct fio_option options[] = {
56 {
57 .name = "hostname",
58 .type = FIO_OPT_STR_STORE,
59 .cb = str_hostname_cb,
60 .help = "Hostname for net IO engine",
61 },
62 {
63 .name = "port",
64 .type = FIO_OPT_INT,
65 .off1 = offsetof(struct netio_options, port),
66 .minval = 1,
67 .maxval = 65535,
68 .help = "Port to use for TCP or UDP net connections",
69 },
70 {
71 .name = "protocol",
72 .alias = "proto",
73 .type = FIO_OPT_STR,
74 .off1 = offsetof(struct netio_options, proto),
75 .help = "Network protocol to use",
76 .def = "tcp",
77 .posval = {
78 { .ival = "tcp",
79 .oval = FIO_TYPE_TCP,
80 .help = "Transmission Control Protocol",
81 },
82 { .ival = "udp",
83 .oval = FIO_TYPE_UDP,
Bruce Cranf5cc3d02012-10-10 08:17:44 -060084 .help = "User Datagram Protocol",
Steven Langde890a12011-11-09 14:03:34 +010085 },
86 { .ival = "unix",
87 .oval = FIO_TYPE_UNIX,
88 .help = "UNIX domain socket",
89 },
90 },
91 },
92 {
93 .name = "listen",
94 .type = FIO_OPT_STR_SET,
95 .off1 = offsetof(struct netio_options, listen),
96 .help = "Listen for incoming TCP connections",
97 },
98 {
Jens Axboe6f73a7f2012-11-30 09:59:20 +010099 .name = "pingpong",
100 .type = FIO_OPT_STR_SET,
101 .off1 = offsetof(struct netio_options, pingpong),
102 .help = "Ping-pong IO requests",
103 },
104 {
Steven Langde890a12011-11-09 14:03:34 +0100105 .name = NULL,
106 },
107};
108
Jens Axboe371d4562009-01-19 10:17:06 +0100109/*
110 * Return -1 for error and 'nr events' for a positive number
111 * of events
112 */
113static int poll_wait(struct thread_data *td, int fd, short events)
114{
115 struct pollfd pfd;
116 int ret;
117
118 while (!td->terminate) {
119 pfd.fd = fd;
120 pfd.events = events;
121 ret = poll(&pfd, 1, -1);
122 if (ret < 0) {
123 if (errno == EINTR)
Jens Axboed5b388a2009-01-19 12:38:27 +0100124 break;
Jens Axboe371d4562009-01-19 10:17:06 +0100125
126 td_verror(td, errno, "poll");
127 return -1;
128 } else if (!ret)
129 continue;
130
131 break;
132 }
133
134 if (pfd.revents & events)
135 return 1;
Jens Axboe371d4562009-01-19 10:17:06 +0100136
137 return -1;
138}
139
Jens Axboeed92ac02007-02-06 14:43:52 +0100140static int fio_netio_prep(struct thread_data *td, struct io_u *io_u)
141{
Steven Langde890a12011-11-09 14:03:34 +0100142 struct netio_options *o = td->eo;
Jens Axboeed92ac02007-02-06 14:43:52 +0100143
Jens Axboe7a6499d2007-02-07 09:35:29 +0100144 /*
145 * Make sure we don't see spurious reads to a receiver, and vice versa
146 */
Steven Langde890a12011-11-09 14:03:34 +0100147 if (o->proto == FIO_TYPE_TCP)
148 return 0;
149
150 if ((o->listen && io_u->ddir == DDIR_WRITE) ||
151 (!o->listen && io_u->ddir == DDIR_READ)) {
Jens Axboee1161c32007-02-22 19:36:48 +0100152 td_verror(td, EINVAL, "bad direction");
Jens Axboe7a6499d2007-02-07 09:35:29 +0100153 return 1;
Jens Axboeed92ac02007-02-06 14:43:52 +0100154 }
Bruce Cran3f457be2012-10-10 13:37:41 +0100155
Jens Axboef85ac252008-03-01 18:09:49 +0100156 return 0;
Jens Axboeed92ac02007-02-06 14:43:52 +0100157}
158
Jens Axboe5921e802008-05-30 15:02:38 +0200159#ifdef FIO_HAVE_SPLICE
Jens Axboecd963e12007-06-24 21:41:46 +0200160static int splice_io_u(int fdin, int fdout, unsigned int len)
Jens Axboe9cce02e2007-06-22 15:42:21 +0200161{
Jens Axboe9cce02e2007-06-22 15:42:21 +0200162 int bytes = 0;
163
164 while (len) {
Jens Axboecd963e12007-06-24 21:41:46 +0200165 int ret = splice(fdin, NULL, fdout, NULL, len, 0);
Jens Axboe9cce02e2007-06-22 15:42:21 +0200166
167 if (ret < 0) {
168 if (!bytes)
169 bytes = ret;
170
171 break;
172 } else if (!ret)
173 break;
174
175 bytes += ret;
Jens Axboef657a2f2007-06-22 20:40:10 +0200176 len -= ret;
Jens Axboe9cce02e2007-06-22 15:42:21 +0200177 }
178
179 return bytes;
180}
181
182/*
Jens Axboecd963e12007-06-24 21:41:46 +0200183 * Receive bytes from a socket and fill them into the internal pipe
184 */
185static int splice_in(struct thread_data *td, struct io_u *io_u)
186{
187 struct netio_data *nd = td->io_ops->data;
188
189 return splice_io_u(io_u->file->fd, nd->pipes[1], io_u->xfer_buflen);
190}
191
192/*
Jens Axboe9cce02e2007-06-22 15:42:21 +0200193 * Transmit 'len' bytes from the internal pipe
194 */
195static int splice_out(struct thread_data *td, struct io_u *io_u,
196 unsigned int len)
197{
198 struct netio_data *nd = td->io_ops->data;
Jens Axboecd963e12007-06-24 21:41:46 +0200199
200 return splice_io_u(nd->pipes[0], io_u->file->fd, len);
201}
202
203static int vmsplice_io_u(struct io_u *io_u, int fd, unsigned int len)
204{
205 struct iovec iov = {
206 .iov_base = io_u->xfer_buf,
207 .iov_len = len,
208 };
Jens Axboe9cce02e2007-06-22 15:42:21 +0200209 int bytes = 0;
210
Jens Axboecd963e12007-06-24 21:41:46 +0200211 while (iov.iov_len) {
212 int ret = vmsplice(fd, &iov, 1, SPLICE_F_MOVE);
Jens Axboe9cce02e2007-06-22 15:42:21 +0200213
214 if (ret < 0) {
215 if (!bytes)
216 bytes = ret;
Jens Axboe9cce02e2007-06-22 15:42:21 +0200217 break;
218 } else if (!ret)
219 break;
220
Jens Axboecd963e12007-06-24 21:41:46 +0200221 iov.iov_len -= ret;
222 iov.iov_base += ret;
Jens Axboe9cce02e2007-06-22 15:42:21 +0200223 bytes += ret;
Jens Axboe9cce02e2007-06-22 15:42:21 +0200224 }
225
226 return bytes;
Jens Axboecd963e12007-06-24 21:41:46 +0200227
Jens Axboe9cce02e2007-06-22 15:42:21 +0200228}
229
230/*
231 * vmsplice() pipe to io_u buffer
232 */
233static int vmsplice_io_u_out(struct thread_data *td, struct io_u *io_u,
234 unsigned int len)
235{
236 struct netio_data *nd = td->io_ops->data;
Jens Axboe9cce02e2007-06-22 15:42:21 +0200237
Jens Axboecd963e12007-06-24 21:41:46 +0200238 return vmsplice_io_u(io_u, nd->pipes[0], len);
Jens Axboe9cce02e2007-06-22 15:42:21 +0200239}
240
241/*
242 * vmsplice() io_u to pipe
243 */
244static int vmsplice_io_u_in(struct thread_data *td, struct io_u *io_u)
245{
246 struct netio_data *nd = td->io_ops->data;
Jens Axboe9cce02e2007-06-22 15:42:21 +0200247
Jens Axboecd963e12007-06-24 21:41:46 +0200248 return vmsplice_io_u(io_u, nd->pipes[1], io_u->xfer_buflen);
Jens Axboe9cce02e2007-06-22 15:42:21 +0200249}
250
Jens Axboecd963e12007-06-24 21:41:46 +0200251/*
252 * splice receive - transfer socket data into a pipe using splice, then map
253 * that pipe data into the io_u using vmsplice.
254 */
Jens Axboe9cce02e2007-06-22 15:42:21 +0200255static int fio_netio_splice_in(struct thread_data *td, struct io_u *io_u)
256{
257 int ret;
258
259 ret = splice_in(td, io_u);
Jens Axboecd963e12007-06-24 21:41:46 +0200260 if (ret > 0)
261 return vmsplice_io_u_out(td, io_u, ret);
Jens Axboe9cce02e2007-06-22 15:42:21 +0200262
Jens Axboecd963e12007-06-24 21:41:46 +0200263 return ret;
Jens Axboe9cce02e2007-06-22 15:42:21 +0200264}
265
Jens Axboecd963e12007-06-24 21:41:46 +0200266/*
267 * splice transmit - map data from the io_u into a pipe by using vmsplice,
268 * then transfer that pipe to a socket using splice.
269 */
Jens Axboe9cce02e2007-06-22 15:42:21 +0200270static int fio_netio_splice_out(struct thread_data *td, struct io_u *io_u)
271{
272 int ret;
273
274 ret = vmsplice_io_u_in(td, io_u);
Jens Axboecd963e12007-06-24 21:41:46 +0200275 if (ret > 0)
276 return splice_out(td, io_u, ret);
Jens Axboe9cce02e2007-06-22 15:42:21 +0200277
Jens Axboecd963e12007-06-24 21:41:46 +0200278 return ret;
Jens Axboe9cce02e2007-06-22 15:42:21 +0200279}
Jens Axboe5921e802008-05-30 15:02:38 +0200280#else
281static int fio_netio_splice_in(struct thread_data *td, struct io_u *io_u)
282{
Jens Axboeaf8771b2008-05-30 22:58:28 +0200283 errno = EOPNOTSUPP;
Jens Axboe5921e802008-05-30 15:02:38 +0200284 return -1;
285}
286
287static int fio_netio_splice_out(struct thread_data *td, struct io_u *io_u)
288{
Jens Axboeaf8771b2008-05-30 22:58:28 +0200289 errno = EOPNOTSUPP;
Jens Axboe5921e802008-05-30 15:02:38 +0200290 return -1;
291}
292#endif
Jens Axboe9cce02e2007-06-22 15:42:21 +0200293
294static int fio_netio_send(struct thread_data *td, struct io_u *io_u)
295{
Jens Axboe414c2a32009-01-16 13:21:15 +0100296 struct netio_data *nd = td->io_ops->data;
Steven Langde890a12011-11-09 14:03:34 +0100297 struct netio_options *o = td->eo;
Jens Axboe6f73a7f2012-11-30 09:59:20 +0100298 int ret, flags = 0;
Jens Axboe371d4562009-01-19 10:17:06 +0100299
Jens Axboe664fb3b2009-01-19 13:26:36 +0100300 do {
Steven Langde890a12011-11-09 14:03:34 +0100301 if (o->proto == FIO_TYPE_UDP) {
Jens Axboe62b38922009-05-11 10:37:33 +0200302 struct sockaddr *to = (struct sockaddr *) &nd->addr;
303
Jens Axboe664fb3b2009-01-19 13:26:36 +0100304 ret = sendto(io_u->file->fd, io_u->xfer_buf,
Jens Axboe62b38922009-05-11 10:37:33 +0200305 io_u->xfer_buflen, flags, to,
306 sizeof(*to));
Jens Axboe664fb3b2009-01-19 13:26:36 +0100307 } else {
308 /*
309 * if we are going to write more, set MSG_MORE
310 */
Jens Axboe5921e802008-05-30 15:02:38 +0200311#ifdef MSG_MORE
Jens Axboe6f73a7f2012-11-30 09:59:20 +0100312 if ((td->this_io_bytes[DDIR_WRITE] + io_u->xfer_buflen <
313 td->o.size) && !o->pingpong)
Jens Axboe664fb3b2009-01-19 13:26:36 +0100314 flags |= MSG_MORE;
Jens Axboe5921e802008-05-30 15:02:38 +0200315#endif
Jens Axboe664fb3b2009-01-19 13:26:36 +0100316 ret = send(io_u->file->fd, io_u->xfer_buf,
317 io_u->xfer_buflen, flags);
318 }
319 if (ret > 0)
320 break;
Jens Axboe9cce02e2007-06-22 15:42:21 +0200321
Jens Axboe664fb3b2009-01-19 13:26:36 +0100322 ret = poll_wait(td, io_u->file->fd, POLLOUT);
323 if (ret <= 0)
324 break;
Jens Axboe664fb3b2009-01-19 13:26:36 +0100325 } while (1);
326
327 return ret;
328}
329
330static int is_udp_close(struct io_u *io_u, int len)
331{
332 struct udp_close_msg *msg;
333
334 if (len != sizeof(struct udp_close_msg))
335 return 0;
336
337 msg = io_u->xfer_buf;
Jens Axboeb96d2432012-11-30 08:27:46 +0100338 if (ntohl(msg->magic) != FIO_LINK_OPEN_CLOSE_MAGIC)
Jens Axboe664fb3b2009-01-19 13:26:36 +0100339 return 0;
340 if (ntohl(msg->cmd) != FIO_LINK_CLOSE)
341 return 0;
342
343 return 1;
Jens Axboe9cce02e2007-06-22 15:42:21 +0200344}
345
Jens Axboe414c2a32009-01-16 13:21:15 +0100346static int fio_netio_recv(struct thread_data *td, struct io_u *io_u)
Jens Axboe9cce02e2007-06-22 15:42:21 +0200347{
Jens Axboe414c2a32009-01-16 13:21:15 +0100348 struct netio_data *nd = td->io_ops->data;
Steven Langde890a12011-11-09 14:03:34 +0100349 struct netio_options *o = td->eo;
Jens Axboe6f73a7f2012-11-30 09:59:20 +0100350 int ret, flags = 0;
Jens Axboe371d4562009-01-19 10:17:06 +0100351
Jens Axboe664fb3b2009-01-19 13:26:36 +0100352 do {
Steven Langde890a12011-11-09 14:03:34 +0100353 if (o->proto == FIO_TYPE_UDP) {
Jens Axboe5ba13ea2011-10-04 23:50:28 +0200354 fio_socklen_t len = sizeof(nd->addr);
Jens Axboe62b38922009-05-11 10:37:33 +0200355 struct sockaddr *from = (struct sockaddr *) &nd->addr;
Jens Axboe9cce02e2007-06-22 15:42:21 +0200356
Jens Axboe664fb3b2009-01-19 13:26:36 +0100357 ret = recvfrom(io_u->file->fd, io_u->xfer_buf,
Jens Axboe62b38922009-05-11 10:37:33 +0200358 io_u->xfer_buflen, flags, from, &len);
Jens Axboe664fb3b2009-01-19 13:26:36 +0100359 if (is_udp_close(io_u, ret)) {
360 td->done = 1;
361 return 0;
362 }
363 } else {
364 ret = recv(io_u->file->fd, io_u->xfer_buf,
365 io_u->xfer_buflen, flags);
366 }
367 if (ret > 0)
368 break;
Jens Axboe7d988f62012-11-29 19:57:35 +0100369 else if (!ret && (flags & MSG_WAITALL))
370 break;
Jens Axboe414c2a32009-01-16 13:21:15 +0100371
Jens Axboe664fb3b2009-01-19 13:26:36 +0100372 ret = poll_wait(td, io_u->file->fd, POLLIN);
373 if (ret <= 0)
374 break;
Jens Axboe664fb3b2009-01-19 13:26:36 +0100375 flags |= MSG_WAITALL;
376 } while (1);
377
378 return ret;
Jens Axboe9cce02e2007-06-22 15:42:21 +0200379}
380
Jens Axboe6f73a7f2012-11-30 09:59:20 +0100381static int __fio_netio_queue(struct thread_data *td, struct io_u *io_u,
382 enum fio_ddir ddir)
Jens Axboeed92ac02007-02-06 14:43:52 +0100383{
Jens Axboe9cce02e2007-06-22 15:42:21 +0200384 struct netio_data *nd = td->io_ops->data;
Steven Langde890a12011-11-09 14:03:34 +0100385 struct netio_options *o = td->eo;
Jens Axboe9cce02e2007-06-22 15:42:21 +0200386 int ret;
Jens Axboeed92ac02007-02-06 14:43:52 +0100387
Jens Axboe6f73a7f2012-11-30 09:59:20 +0100388 if (ddir == DDIR_WRITE) {
Steven Langde890a12011-11-09 14:03:34 +0100389 if (!nd->use_splice || o->proto == FIO_TYPE_UDP ||
390 o->proto == FIO_TYPE_UNIX)
Jens Axboe9cce02e2007-06-22 15:42:21 +0200391 ret = fio_netio_send(td, io_u);
Jens Axboe9cce02e2007-06-22 15:42:21 +0200392 else
Jens Axboe414c2a32009-01-16 13:21:15 +0100393 ret = fio_netio_splice_out(td, io_u);
Jens Axboe6f73a7f2012-11-30 09:59:20 +0100394 } else if (ddir == DDIR_READ) {
Steven Langde890a12011-11-09 14:03:34 +0100395 if (!nd->use_splice || o->proto == FIO_TYPE_UDP ||
396 o->proto == FIO_TYPE_UNIX)
Jens Axboe414c2a32009-01-16 13:21:15 +0100397 ret = fio_netio_recv(td, io_u);
398 else
399 ret = fio_netio_splice_in(td, io_u);
Jens Axboed4f12dd2007-02-08 12:59:02 +0100400 } else
Jens Axboe7a6499d2007-02-07 09:35:29 +0100401 ret = 0; /* must be a SYNC */
Jens Axboeed92ac02007-02-06 14:43:52 +0100402
Jens Axboecec6b552007-02-06 20:15:38 +0100403 if (ret != (int) io_u->xfer_buflen) {
Jens Axboe22819ec2007-02-18 07:47:14 +0100404 if (ret >= 0) {
Jens Axboecec6b552007-02-06 20:15:38 +0100405 io_u->resid = io_u->xfer_buflen - ret;
406 io_u->error = 0;
Jens Axboe36167d82007-02-18 05:41:31 +0100407 return FIO_Q_COMPLETED;
Jens Axboe414c2a32009-01-16 13:21:15 +0100408 } else {
409 int err = errno;
410
Jens Axboe6f73a7f2012-11-30 09:59:20 +0100411 if (ddir == DDIR_WRITE && err == EMSGSIZE)
Jens Axboe414c2a32009-01-16 13:21:15 +0100412 return FIO_Q_BUSY;
413
414 io_u->error = err;
415 }
Jens Axboeed92ac02007-02-06 14:43:52 +0100416 }
417
Jens Axboe36167d82007-02-18 05:41:31 +0100418 if (io_u->error)
Jens Axboee1161c32007-02-22 19:36:48 +0100419 td_verror(td, io_u->error, "xfer");
Jens Axboeed92ac02007-02-06 14:43:52 +0100420
Jens Axboe36167d82007-02-18 05:41:31 +0100421 return FIO_Q_COMPLETED;
Jens Axboeed92ac02007-02-06 14:43:52 +0100422}
423
Jens Axboe6f73a7f2012-11-30 09:59:20 +0100424static int fio_netio_queue(struct thread_data *td, struct io_u *io_u)
425{
426 struct netio_options *o = td->eo;
427 int ret;
428
429 fio_ro_check(td, io_u);
430
431 ret = __fio_netio_queue(td, io_u, io_u->ddir);
432 if (!o->pingpong || ret != FIO_Q_COMPLETED)
433 return ret;
434
435 /*
436 * For ping-pong mode, receive or send reply as needed
437 */
438 if (td_read(td) && io_u->ddir == DDIR_READ)
439 ret = __fio_netio_queue(td, io_u, DDIR_WRITE);
440 else if (td_write(td) && io_u->ddir == DDIR_WRITE)
441 ret = __fio_netio_queue(td, io_u, DDIR_READ);
442
443 return ret;
444}
445
Jens Axboeb5af8292007-03-08 12:43:13 +0100446static int fio_netio_connect(struct thread_data *td, struct fio_file *f)
Jens Axboeed92ac02007-02-06 14:43:52 +0100447{
Jens Axboeb5af8292007-03-08 12:43:13 +0100448 struct netio_data *nd = td->io_ops->data;
Steven Langde890a12011-11-09 14:03:34 +0100449 struct netio_options *o = td->eo;
Jens Axboe0fd666b2011-10-06 20:08:53 +0200450 int type, domain;
Jens Axboeed92ac02007-02-06 14:43:52 +0100451
Steven Langde890a12011-11-09 14:03:34 +0100452 if (o->proto == FIO_TYPE_TCP) {
Jens Axboe0fd666b2011-10-06 20:08:53 +0200453 domain = AF_INET;
Jens Axboe414c2a32009-01-16 13:21:15 +0100454 type = SOCK_STREAM;
Steven Langde890a12011-11-09 14:03:34 +0100455 } else if (o->proto == FIO_TYPE_UDP) {
Jens Axboe0fd666b2011-10-06 20:08:53 +0200456 domain = AF_INET;
Jens Axboe414c2a32009-01-16 13:21:15 +0100457 type = SOCK_DGRAM;
Steven Langde890a12011-11-09 14:03:34 +0100458 } else if (o->proto == FIO_TYPE_UNIX) {
Jens Axboe0fd666b2011-10-06 20:08:53 +0200459 domain = AF_UNIX;
460 type = SOCK_STREAM;
461 } else {
Steven Langde890a12011-11-09 14:03:34 +0100462 log_err("fio: bad network type %d\n", o->proto);
Jens Axboe0fd666b2011-10-06 20:08:53 +0200463 f->fd = -1;
464 return 1;
465 }
Jens Axboe414c2a32009-01-16 13:21:15 +0100466
Jens Axboe0fd666b2011-10-06 20:08:53 +0200467 f->fd = socket(domain, type, 0);
Jens Axboeb5af8292007-03-08 12:43:13 +0100468 if (f->fd < 0) {
469 td_verror(td, errno, "socket");
470 return 1;
Jens Axboeed92ac02007-02-06 14:43:52 +0100471 }
472
Steven Langde890a12011-11-09 14:03:34 +0100473 if (o->proto == FIO_TYPE_UDP)
Jens Axboe414c2a32009-01-16 13:21:15 +0100474 return 0;
Steven Langde890a12011-11-09 14:03:34 +0100475 else if (o->proto == FIO_TYPE_TCP) {
Jens Axboe0fd666b2011-10-06 20:08:53 +0200476 fio_socklen_t len = sizeof(nd->addr);
Jens Axboe414c2a32009-01-16 13:21:15 +0100477
Jens Axboe0fd666b2011-10-06 20:08:53 +0200478 if (connect(f->fd, (struct sockaddr *) &nd->addr, len) < 0) {
479 td_verror(td, errno, "connect");
Jens Axboeb94cba42011-10-06 21:27:10 +0200480 close(f->fd);
Jens Axboe0fd666b2011-10-06 20:08:53 +0200481 return 1;
482 }
483 } else {
484 struct sockaddr_un *addr = &nd->addr_un;
485 fio_socklen_t len;
486
487 len = sizeof(addr->sun_family) + strlen(addr->sun_path) + 1;
488
489 if (connect(f->fd, (struct sockaddr *) addr, len) < 0) {
490 td_verror(td, errno, "connect");
Jens Axboeb94cba42011-10-06 21:27:10 +0200491 close(f->fd);
Jens Axboe0fd666b2011-10-06 20:08:53 +0200492 return 1;
493 }
Jens Axboeed92ac02007-02-06 14:43:52 +0100494 }
495
496 return 0;
Jens Axboeed92ac02007-02-06 14:43:52 +0100497}
498
Jens Axboeb5af8292007-03-08 12:43:13 +0100499static int fio_netio_accept(struct thread_data *td, struct fio_file *f)
Jens Axboe5fdd1242007-02-11 04:00:37 +0100500{
Jens Axboeb5af8292007-03-08 12:43:13 +0100501 struct netio_data *nd = td->io_ops->data;
Steven Langde890a12011-11-09 14:03:34 +0100502 struct netio_options *o = td->eo;
Jens Axboe5ba13ea2011-10-04 23:50:28 +0200503 fio_socklen_t socklen = sizeof(nd->addr);
Jens Axboe859088d2012-11-29 20:02:50 +0100504 int state;
Jens Axboe5fdd1242007-02-11 04:00:37 +0100505
Steven Langde890a12011-11-09 14:03:34 +0100506 if (o->proto == FIO_TYPE_UDP) {
Jens Axboe414c2a32009-01-16 13:21:15 +0100507 f->fd = nd->listenfd;
508 return 0;
509 }
510
Jens Axboe859088d2012-11-29 20:02:50 +0100511 state = td->runstate;
512 td_set_runstate(td, TD_SETTING_UP);
513
Jens Axboe6d861442007-03-15 09:22:23 +0100514 log_info("fio: waiting for connection\n");
Jens Axboe5fdd1242007-02-11 04:00:37 +0100515
Jens Axboe371d4562009-01-19 10:17:06 +0100516 if (poll_wait(td, nd->listenfd, POLLIN) < 0)
Jens Axboe859088d2012-11-29 20:02:50 +0100517 goto err;
Jens Axboe5fdd1242007-02-11 04:00:37 +0100518
Jens Axboe371d4562009-01-19 10:17:06 +0100519 f->fd = accept(nd->listenfd, (struct sockaddr *) &nd->addr, &socklen);
520 if (f->fd < 0) {
521 td_verror(td, errno, "accept");
Jens Axboe859088d2012-11-29 20:02:50 +0100522 goto err;
Jens Axboe5fdd1242007-02-11 04:00:37 +0100523 }
524
Jens Axboe859088d2012-11-29 20:02:50 +0100525 td_set_runstate(td, state);
Jens Axboe5fdd1242007-02-11 04:00:37 +0100526 return 0;
Jens Axboe859088d2012-11-29 20:02:50 +0100527err:
528 td_set_runstate(td, state);
529 return 1;
Jens Axboe5fdd1242007-02-11 04:00:37 +0100530}
531
Jens Axboe664fb3b2009-01-19 13:26:36 +0100532static void fio_netio_udp_close(struct thread_data *td, struct fio_file *f)
533{
534 struct netio_data *nd = td->io_ops->data;
535 struct udp_close_msg msg;
Jens Axboe62b38922009-05-11 10:37:33 +0200536 struct sockaddr *to = (struct sockaddr *) &nd->addr;
Jens Axboe664fb3b2009-01-19 13:26:36 +0100537 int ret;
538
Jens Axboeb96d2432012-11-30 08:27:46 +0100539 msg.magic = htonl(FIO_LINK_OPEN_CLOSE_MAGIC);
Jens Axboe664fb3b2009-01-19 13:26:36 +0100540 msg.cmd = htonl(FIO_LINK_CLOSE);
541
Jens Axboe62b38922009-05-11 10:37:33 +0200542 ret = sendto(f->fd, &msg, sizeof(msg), MSG_WAITALL, to,
Jens Axboe664fb3b2009-01-19 13:26:36 +0100543 sizeof(nd->addr));
544 if (ret < 0)
545 td_verror(td, errno, "sendto udp link close");
546}
547
548static int fio_netio_close_file(struct thread_data *td, struct fio_file *f)
549{
Steven Langde890a12011-11-09 14:03:34 +0100550 struct netio_options *o = td->eo;
Jens Axboe664fb3b2009-01-19 13:26:36 +0100551
552 /*
553 * If this is an UDP connection, notify the receiver that we are
554 * closing down the link
555 */
Steven Langde890a12011-11-09 14:03:34 +0100556 if (o->proto == FIO_TYPE_UDP)
Jens Axboe664fb3b2009-01-19 13:26:36 +0100557 fio_netio_udp_close(td, f);
558
559 return generic_close_file(td, f);
560}
561
Jens Axboeb96d2432012-11-30 08:27:46 +0100562static int fio_netio_udp_recv_open(struct thread_data *td, struct fio_file *f)
563{
564 struct netio_data *nd = td->io_ops->data;
565 struct udp_close_msg msg;
566 struct sockaddr *to = (struct sockaddr *) &nd->addr;
567 fio_socklen_t len = sizeof(nd->addr);
568 int ret;
569
570 ret = recvfrom(f->fd, &msg, sizeof(msg), MSG_WAITALL, to, &len);
571 if (ret < 0) {
572 td_verror(td, errno, "sendto udp link open");
573 return ret;
574 }
575
576 if (ntohl(msg.magic) != FIO_LINK_OPEN_CLOSE_MAGIC ||
577 ntohl(msg.cmd) != FIO_LINK_OPEN) {
578 log_err("fio: bad udp open magic %x/%x\n", ntohl(msg.magic),
579 ntohl(msg.cmd));
580 return -1;
581 }
582
583 return 0;
584}
585
586static int fio_netio_udp_send_open(struct thread_data *td, struct fio_file *f)
587{
588 struct netio_data *nd = td->io_ops->data;
589 struct udp_close_msg msg;
590 struct sockaddr *to = (struct sockaddr *) &nd->addr;
591 int ret;
592
593 msg.magic = htonl(FIO_LINK_OPEN_CLOSE_MAGIC);
594 msg.cmd = htonl(FIO_LINK_OPEN);
595
596 ret = sendto(f->fd, &msg, sizeof(msg), MSG_WAITALL, to,
597 sizeof(nd->addr));
598 if (ret < 0) {
599 td_verror(td, errno, "sendto udp link open");
600 return ret;
601 }
602
603 return 0;
604}
605
606static int fio_netio_open_file(struct thread_data *td, struct fio_file *f)
607{
608 int ret;
609 struct netio_options *o = td->eo;
610
611 if (o->listen)
612 ret = fio_netio_accept(td, f);
613 else
614 ret = fio_netio_connect(td, f);
615
616 if (ret) {
617 f->fd = -1;
618 return ret;
619 }
620
621 if (o->proto == FIO_TYPE_UDP) {
622 if (td_write(td))
623 ret = fio_netio_udp_send_open(td, f);
624 else {
625 int state;
626
627 state = td->runstate;
628 td_set_runstate(td, TD_SETTING_UP);
629 ret = fio_netio_udp_recv_open(td, f);
630 td_set_runstate(td, state);
631 }
632 }
633
634 if (ret)
635 fio_netio_close_file(td, f);
636
637 return ret;
638}
639
Jens Axboe0fd666b2011-10-06 20:08:53 +0200640static int fio_netio_setup_connect_inet(struct thread_data *td,
641 const char *host, unsigned short port)
Jens Axboeb5af8292007-03-08 12:43:13 +0100642{
643 struct netio_data *nd = td->io_ops->data;
644
Jens Axboe166dce42012-11-29 14:35:33 +0100645 if (!host) {
646 log_err("fio: connect with no host to connect to.\n");
647 if (td_read(td))
648 log_err("fio: did you forget to set 'listen'?\n");
649
650 td_verror(td, EINVAL, "no hostname= set");
651 return 1;
652 }
653
Jens Axboeb5af8292007-03-08 12:43:13 +0100654 nd->addr.sin_family = AF_INET;
655 nd->addr.sin_port = htons(port);
656
657 if (inet_aton(host, &nd->addr.sin_addr) != 1) {
658 struct hostent *hent;
659
660 hent = gethostbyname(host);
661 if (!hent) {
662 td_verror(td, errno, "gethostbyname");
663 return 1;
664 }
665
666 memcpy(&nd->addr.sin_addr, hent->h_addr, 4);
667 }
668
669 return 0;
670}
671
Jens Axboe0fd666b2011-10-06 20:08:53 +0200672static int fio_netio_setup_connect_unix(struct thread_data *td,
673 const char *path)
674{
675 struct netio_data *nd = td->io_ops->data;
676 struct sockaddr_un *soun = &nd->addr_un;
677
678 soun->sun_family = AF_UNIX;
679 strcpy(soun->sun_path, path);
680 return 0;
681}
682
Steven Langde890a12011-11-09 14:03:34 +0100683static int fio_netio_setup_connect(struct thread_data *td)
Jens Axboe0fd666b2011-10-06 20:08:53 +0200684{
Steven Langde890a12011-11-09 14:03:34 +0100685 struct netio_options *o = td->eo;
Jens Axboe0fd666b2011-10-06 20:08:53 +0200686
Steven Langde890a12011-11-09 14:03:34 +0100687 if (o->proto == FIO_TYPE_UDP || o->proto == FIO_TYPE_TCP)
688 return fio_netio_setup_connect_inet(td, td->o.filename,o->port);
Jens Axboe0fd666b2011-10-06 20:08:53 +0200689 else
Steven Langde890a12011-11-09 14:03:34 +0100690 return fio_netio_setup_connect_unix(td, td->o.filename);
Jens Axboe0fd666b2011-10-06 20:08:53 +0200691}
692
693static int fio_netio_setup_listen_unix(struct thread_data *td, const char *path)
694{
695 struct netio_data *nd = td->io_ops->data;
696 struct sockaddr_un *addr = &nd->addr_un;
697 mode_t mode;
698 int len, fd;
699
700 fd = socket(AF_UNIX, SOCK_STREAM, 0);
701 if (fd < 0) {
702 log_err("fio: socket: %s\n", strerror(errno));
703 return -1;
704 }
705
706 mode = umask(000);
707
708 memset(addr, 0, sizeof(*addr));
709 addr->sun_family = AF_UNIX;
710 strcpy(addr->sun_path, path);
711 unlink(path);
712
713 len = sizeof(addr->sun_family) + strlen(path) + 1;
714
715 if (bind(fd, (struct sockaddr *) addr, len) < 0) {
716 log_err("fio: bind: %s\n", strerror(errno));
Jens Axboeb94cba42011-10-06 21:27:10 +0200717 close(fd);
Jens Axboe0fd666b2011-10-06 20:08:53 +0200718 return -1;
719 }
720
721 umask(mode);
722 nd->listenfd = fd;
723 return 0;
724}
725
726static int fio_netio_setup_listen_inet(struct thread_data *td, short port)
Jens Axboeb5af8292007-03-08 12:43:13 +0100727{
728 struct netio_data *nd = td->io_ops->data;
Steven Langde890a12011-11-09 14:03:34 +0100729 struct netio_options *o = td->eo;
Jens Axboe414c2a32009-01-16 13:21:15 +0100730 int fd, opt, type;
Jens Axboeed92ac02007-02-06 14:43:52 +0100731
Steven Langde890a12011-11-09 14:03:34 +0100732 if (o->proto == FIO_TYPE_TCP)
Jens Axboe414c2a32009-01-16 13:21:15 +0100733 type = SOCK_STREAM;
734 else
735 type = SOCK_DGRAM;
736
Jens Axboe0fd666b2011-10-06 20:08:53 +0200737 fd = socket(AF_INET, type, 0);
Jens Axboeed92ac02007-02-06 14:43:52 +0100738 if (fd < 0) {
Jens Axboee1161c32007-02-22 19:36:48 +0100739 td_verror(td, errno, "socket");
Jens Axboeed92ac02007-02-06 14:43:52 +0100740 return 1;
741 }
742
743 opt = 1;
744 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
Jens Axboee1161c32007-02-22 19:36:48 +0100745 td_verror(td, errno, "setsockopt");
Jens Axboeed92ac02007-02-06 14:43:52 +0100746 return 1;
747 }
Jens Axboe6bedbfa2007-02-07 09:54:40 +0100748#ifdef SO_REUSEPORT
749 if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)) < 0) {
Jens Axboee1161c32007-02-22 19:36:48 +0100750 td_verror(td, errno, "setsockopt");
Jens Axboe6bedbfa2007-02-07 09:54:40 +0100751 return 1;
752 }
753#endif
Jens Axboeed92ac02007-02-06 14:43:52 +0100754
Jens Axboeb5af8292007-03-08 12:43:13 +0100755 nd->addr.sin_family = AF_INET;
756 nd->addr.sin_addr.s_addr = htonl(INADDR_ANY);
757 nd->addr.sin_port = htons(port);
Jens Axboeed92ac02007-02-06 14:43:52 +0100758
Jens Axboeb5af8292007-03-08 12:43:13 +0100759 if (bind(fd, (struct sockaddr *) &nd->addr, sizeof(nd->addr)) < 0) {
Jens Axboee1161c32007-02-22 19:36:48 +0100760 td_verror(td, errno, "bind");
Jens Axboeed92ac02007-02-06 14:43:52 +0100761 return 1;
762 }
Jens Axboe0fd666b2011-10-06 20:08:53 +0200763
764 nd->listenfd = fd;
765 return 0;
766}
767
Steven Langde890a12011-11-09 14:03:34 +0100768static int fio_netio_setup_listen(struct thread_data *td)
Jens Axboe0fd666b2011-10-06 20:08:53 +0200769{
770 struct netio_data *nd = td->io_ops->data;
Steven Langde890a12011-11-09 14:03:34 +0100771 struct netio_options *o = td->eo;
Jens Axboe0fd666b2011-10-06 20:08:53 +0200772 int ret;
773
Steven Langde890a12011-11-09 14:03:34 +0100774 if (o->proto == FIO_TYPE_UDP || o->proto == FIO_TYPE_TCP)
775 ret = fio_netio_setup_listen_inet(td, o->port);
Jens Axboe0fd666b2011-10-06 20:08:53 +0200776 else
Steven Langde890a12011-11-09 14:03:34 +0100777 ret = fio_netio_setup_listen_unix(td, td->o.filename);
Jens Axboe0fd666b2011-10-06 20:08:53 +0200778
779 if (ret)
780 return ret;
Steven Langde890a12011-11-09 14:03:34 +0100781 if (o->proto == FIO_TYPE_UDP)
Jens Axboe0fd666b2011-10-06 20:08:53 +0200782 return 0;
783
784 if (listen(nd->listenfd, 10) < 0) {
Jens Axboee1161c32007-02-22 19:36:48 +0100785 td_verror(td, errno, "listen");
Jens Axboe0fd666b2011-10-06 20:08:53 +0200786 nd->listenfd = -1;
Jens Axboeed92ac02007-02-06 14:43:52 +0100787 return 1;
788 }
789
Jens Axboeb5af8292007-03-08 12:43:13 +0100790 return 0;
Jens Axboeed92ac02007-02-06 14:43:52 +0100791}
792
Jens Axboe9bec88e2007-03-02 08:55:48 +0100793static int fio_netio_init(struct thread_data *td)
Jens Axboeed92ac02007-02-06 14:43:52 +0100794{
Steven Langde890a12011-11-09 14:03:34 +0100795 struct netio_options *o = td->eo;
Jens Axboeaf52b342007-03-13 10:07:47 +0100796 int ret;
Jens Axboeed92ac02007-02-06 14:43:52 +0100797
Bruce Cran3f457be2012-10-10 13:37:41 +0100798#ifdef WIN32
799 WSADATA wsd;
800 WSAStartup(MAKEWORD(2,2), &wsd);
801#endif
802
Jens Axboe16d55aa2007-05-22 09:21:37 +0200803 if (td_random(td)) {
804 log_err("fio: network IO can't be random\n");
805 return 1;
806 }
Jens Axboeed92ac02007-02-06 14:43:52 +0100807
Steven Langde890a12011-11-09 14:03:34 +0100808 if (o->proto == FIO_TYPE_UNIX && o->port) {
809 log_err("fio: network IO port not valid with unix socket\n");
810 return 1;
811 } else if (o->proto != FIO_TYPE_UNIX && !o->port) {
812 log_err("fio: network IO requires port for tcp or udp\n");
813 return 1;
Jens Axboe414c2a32009-01-16 13:21:15 +0100814 }
Jens Axboe0fd666b2011-10-06 20:08:53 +0200815
Steven Langde890a12011-11-09 14:03:34 +0100816 if (o->proto != FIO_TYPE_TCP) {
817 if (o->listen) {
Jens Axboe9b986062011-12-19 08:57:18 +0100818 log_err("fio: listen only valid for TCP proto IO\n");
819 return 1;
Steven Langde890a12011-11-09 14:03:34 +0100820 }
821 if (td_rw(td)) {
Jens Axboe9b986062011-12-19 08:57:18 +0100822 log_err("fio: datagram network connections must be"
Steven Langde890a12011-11-09 14:03:34 +0100823 " read OR write\n");
Jens Axboe9b986062011-12-19 08:57:18 +0100824 return 1;
825 }
826 if (o->proto == FIO_TYPE_UNIX && !td->o.filename) {
827 log_err("fio: UNIX sockets need host/filename\n");
828 return 1;
Steven Langde890a12011-11-09 14:03:34 +0100829 }
830 o->listen = td_read(td);
831 }
832
833 if (o->proto != FIO_TYPE_UNIX && o->listen && td->o.filename) {
834 log_err("fio: hostname not valid for inbound network IO\n");
835 return 1;
836 }
837
838 if (o->listen)
839 ret = fio_netio_setup_listen(td);
Jens Axboe0fd666b2011-10-06 20:08:53 +0200840 else
Steven Langde890a12011-11-09 14:03:34 +0100841 ret = fio_netio_setup_connect(td);
Jens Axboeed92ac02007-02-06 14:43:52 +0100842
Jens Axboe7bb48f82007-03-27 15:30:28 +0200843 return ret;
Jens Axboeed92ac02007-02-06 14:43:52 +0100844}
845
Jens Axboeb5af8292007-03-08 12:43:13 +0100846static void fio_netio_cleanup(struct thread_data *td)
Jens Axboe9bec88e2007-03-02 08:55:48 +0100847{
Jens Axboeb5af8292007-03-08 12:43:13 +0100848 struct netio_data *nd = td->io_ops->data;
849
850 if (nd) {
Jens Axboe64b24cd2007-06-24 21:28:39 +0200851 if (nd->listenfd != -1)
852 close(nd->listenfd);
853 if (nd->pipes[0] != -1)
854 close(nd->pipes[0]);
855 if (nd->pipes[1] != -1)
856 close(nd->pipes[1]);
857
Jens Axboeb5af8292007-03-08 12:43:13 +0100858 free(nd);
Jens Axboeb5af8292007-03-08 12:43:13 +0100859 }
860}
861
862static int fio_netio_setup(struct thread_data *td)
863{
Jens Axboe7bb48f82007-03-27 15:30:28 +0200864 struct netio_data *nd;
Jens Axboeb5af8292007-03-08 12:43:13 +0100865
Steven Langde890a12011-11-09 14:03:34 +0100866 if (!td->files_index) {
867 add_file(td, td->o.filename ?: "net");
868 td->o.nr_files = td->o.nr_files ?: 1;
869 }
870
Jens Axboe7bb48f82007-03-27 15:30:28 +0200871 if (!td->io_ops->data) {
872 nd = malloc(sizeof(*nd));;
873
874 memset(nd, 0, sizeof(*nd));
875 nd->listenfd = -1;
Jens Axboe64b24cd2007-06-24 21:28:39 +0200876 nd->pipes[0] = nd->pipes[1] = -1;
Jens Axboe7bb48f82007-03-27 15:30:28 +0200877 td->io_ops->data = nd;
Jens Axboe7bb48f82007-03-27 15:30:28 +0200878 }
879
Jens Axboe9bec88e2007-03-02 08:55:48 +0100880 return 0;
881}
882
Jens Axboe5921e802008-05-30 15:02:38 +0200883#ifdef FIO_HAVE_SPLICE
Jens Axboe9cce02e2007-06-22 15:42:21 +0200884static int fio_netio_setup_splice(struct thread_data *td)
885{
886 struct netio_data *nd;
887
888 fio_netio_setup(td);
889
890 nd = td->io_ops->data;
891 if (nd) {
892 if (pipe(nd->pipes) < 0)
893 return 1;
894
895 nd->use_splice = 1;
896 return 0;
897 }
898
899 return 1;
900}
901
Jens Axboe5921e802008-05-30 15:02:38 +0200902static struct ioengine_ops ioengine_splice = {
Steven Langde890a12011-11-09 14:03:34 +0100903 .name = "netsplice",
904 .version = FIO_IOOPS_VERSION,
905 .prep = fio_netio_prep,
906 .queue = fio_netio_queue,
907 .setup = fio_netio_setup_splice,
908 .init = fio_netio_init,
909 .cleanup = fio_netio_cleanup,
910 .open_file = fio_netio_open_file,
911 .close_file = generic_close_file,
912 .options = options,
913 .option_struct_size = sizeof(struct netio_options),
914 .flags = FIO_SYNCIO | FIO_DISKLESSIO | FIO_UNIDIR |
915 FIO_SIGTERM | FIO_PIPEIO,
Jens Axboe5921e802008-05-30 15:02:38 +0200916};
917#endif
918
Jens Axboe9cce02e2007-06-22 15:42:21 +0200919static struct ioengine_ops ioengine_rw = {
Steven Langde890a12011-11-09 14:03:34 +0100920 .name = "net",
921 .version = FIO_IOOPS_VERSION,
922 .prep = fio_netio_prep,
923 .queue = fio_netio_queue,
924 .setup = fio_netio_setup,
925 .init = fio_netio_init,
926 .cleanup = fio_netio_cleanup,
927 .open_file = fio_netio_open_file,
928 .close_file = fio_netio_close_file,
929 .options = options,
930 .option_struct_size = sizeof(struct netio_options),
931 .flags = FIO_SYNCIO | FIO_DISKLESSIO | FIO_UNIDIR |
932 FIO_SIGTERM | FIO_PIPEIO,
Jens Axboeed92ac02007-02-06 14:43:52 +0100933};
934
Steven Langde890a12011-11-09 14:03:34 +0100935static int str_hostname_cb(void *data, const char *input)
936{
937 struct netio_options *o = data;
938
939 if (o->td->o.filename)
940 free(o->td->o.filename);
941 o->td->o.filename = strdup(input);
942 return 0;
943}
944
Jens Axboeed92ac02007-02-06 14:43:52 +0100945static void fio_init fio_netio_register(void)
946{
Jens Axboe9cce02e2007-06-22 15:42:21 +0200947 register_ioengine(&ioengine_rw);
Jens Axboe5921e802008-05-30 15:02:38 +0200948#ifdef FIO_HAVE_SPLICE
Jens Axboe9cce02e2007-06-22 15:42:21 +0200949 register_ioengine(&ioengine_splice);
Jens Axboe5921e802008-05-30 15:02:38 +0200950#endif
Jens Axboeed92ac02007-02-06 14:43:52 +0100951}
952
953static void fio_exit fio_netio_unregister(void)
954{
Jens Axboe9cce02e2007-06-22 15:42:21 +0200955 unregister_ioengine(&ioengine_rw);
Jens Axboe5921e802008-05-30 15:02:38 +0200956#ifdef FIO_HAVE_SPLICE
Jens Axboe9cce02e2007-06-22 15:42:21 +0200957 unregister_ioengine(&ioengine_splice);
Jens Axboe5921e802008-05-30 15:02:38 +0200958#endif
Jens Axboeed92ac02007-02-06 14:43:52 +0100959}