[PATCH] Network engine updates
[fio.git] / engines / net.c
CommitLineData
ed92ac0c
JA
1/*
2 * Transfer data over the net. Pretty basic setup, will only support
3 * 1 file per thread/job.
4 */
5#include <stdio.h>
6#include <stdlib.h>
7#include <unistd.h>
8#include <errno.h>
9#include <assert.h>
10#include <netinet/in.h>
11#include <arpa/inet.h>
12#include <netdb.h>
13
14#include "../fio.h"
15#include "../os.h"
16
17struct net_data {
18 int send_to_net;
19 struct io_u *last_io_u;
20};
21
22static int fio_netio_getevents(struct thread_data *td, int fio_unused min,
23 int max, struct timespec fio_unused *t)
24{
25 assert(max <= 1);
26
27 /*
28 * we can only have one finished io_u for sync io, since the depth
29 * is always 1
30 */
31 if (list_empty(&td->io_u_busylist))
32 return 0;
33
34 return 1;
35}
36
37static struct io_u *fio_netio_event(struct thread_data *td, int event)
38{
39 struct net_data *nd = td->io_ops->data;
40
41 assert(event == 0);
42
43 return nd->last_io_u;
44}
45
46static int fio_netio_prep(struct thread_data *td, struct io_u *io_u)
47{
48 struct net_data *nd = td->io_ops->data;
49 struct fio_file *f = io_u->file;
50
51 if (nd->send_to_net) {
52 if (io_u->ddir == DDIR_READ) {
53 td_verror(td, EINVAL);
54 return 1;
55 }
56 } else {
57 if (io_u->ddir == DDIR_WRITE) {
58 td_verror(td, EINVAL);
59 return 1;
60 }
61 }
62
63 if (io_u->ddir == DDIR_SYNC)
64 return 0;
65 if (io_u->offset == f->last_completed_pos)
66 return 0;
67
e01547d2
JA
68 /*
69 * If offset is different from last end position, it's a seek.
70 * As network io is purely sequential, we don't allow seeks.
71 */
ed92ac0c
JA
72 td_verror(td, EINVAL);
73 return 1;
74}
75
76static int fio_netio_queue(struct thread_data *td, struct io_u *io_u)
77{
78 struct net_data *nd = td->io_ops->data;
79 struct fio_file *f = io_u->file;
80 unsigned int ret = 0;
81
82 if (io_u->ddir == DDIR_WRITE)
83 ret = write(f->fd, io_u->buf, io_u->buflen);
84 else if (io_u->ddir == DDIR_READ)
85 ret = read(f->fd, io_u->buf, io_u->buflen);
86
87 if (ret != io_u->buflen) {
88 if (ret > 0) {
89 io_u->resid = io_u->buflen - ret;
90 io_u->error = EIO;
91 } else
92 io_u->error = errno;
93 }
94
95 if (!io_u->error)
96 nd->last_io_u = io_u;
97
98 return io_u->error;
99}
100
101static int fio_netio_setup_connect(struct thread_data *td, const char *host,
e01547d2 102 unsigned short port)
ed92ac0c
JA
103{
104 struct sockaddr_in addr;
105 struct fio_file *f;
106
107 memset(&addr, 0, sizeof(addr));
108 addr.sin_family = AF_INET;
e01547d2 109 addr.sin_port = htons(port);
ed92ac0c
JA
110
111 if (inet_aton(host, &addr.sin_addr) != 1) {
112 struct hostent *hent = gethostbyname(host);
113
114 if (!hent) {
115 td_vmsg(td, errno, "gethostbyname");
116 return 1;
117 }
118
119 memcpy(&addr.sin_addr, hent->h_addr, 4);
120 }
121
122 f = &td->files[0];
123
124 f->fd = socket(AF_INET, SOCK_STREAM, 0);
125 if (f->fd < 0) {
126 td_vmsg(td, errno, "socket");
127 return 1;
128 }
129
130 if (connect(f->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
131 td_vmsg(td, errno, "connect");
132 return 1;
133 }
134
135 return 0;
136
137}
138
e01547d2 139static int fio_netio_setup_listen(struct thread_data *td, unsigned short port)
ed92ac0c
JA
140{
141 struct sockaddr_in addr;
142 socklen_t socklen;
143 int fd, opt;
144
145 fd = socket(AF_INET, SOCK_STREAM, 0);
146 if (fd < 0) {
147 td_vmsg(td, errno, "socket");
148 return 1;
149 }
150
151 opt = 1;
152 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
153 td_vmsg(td, errno, "setsockopt");
154 return 1;
155 }
156
157 memset(&addr, 0, sizeof(addr));
158 addr.sin_family = AF_INET;
159 addr.sin_addr.s_addr = htonl(INADDR_ANY);
e01547d2 160 addr.sin_port = htons(port);
ed92ac0c
JA
161
162 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
163 td_vmsg(td, errno, "bind");
164 return 1;
165 }
166 if (listen(fd, 1) < 0) {
167 td_vmsg(td, errno, "listen");
168 return 1;
169 }
170
171 socklen = sizeof(addr);
172 td->files[0].fd = accept(fd, (struct sockaddr *) &addr, &socklen);
173 if (td->files[0].fd < 0) {
174 td_vmsg(td, errno, "accept");
175 return 1;
176 }
177
178 return 0;
179}
180
181static int fio_netio_setup(struct thread_data *td)
182{
e01547d2 183 char host[64], buf[128];
ed92ac0c 184 struct net_data *nd;
e01547d2 185 unsigned short port;
ed92ac0c
JA
186 char *sep;
187 int ret;
188
189 /*
190 * work around for late init call
191 */
192 if (td->io_ops->init(td))
193 return 1;
194
195 nd = td->io_ops->data;
196
197 if (td->iomix) {
198 log_err("fio: network connections must be read OR write\n");
199 return 1;
200 }
201 if (td->nr_files > 1) {
202 log_err("fio: only one file supported for network\n");
203 return 1;
204 }
205
206 strcpy(buf, td->filename);
207
208 sep = strchr(buf, ':');
209 if (!sep) {
210 log_err("fio: bad network host:port <<%s>>\n", td->filename);
211 return 1;
212 }
213
214 *sep = '\0';
215 sep++;
216 strcpy(host, buf);
e01547d2 217 port = atoi(sep);
ed92ac0c
JA
218
219 if (td->ddir == READ) {
220 nd->send_to_net = 0;
221 ret = fio_netio_setup_listen(td, port);
222 } else {
223 nd->send_to_net = 1;
224 ret = fio_netio_setup_connect(td, host, port);
225 }
226
227 if (!ret) {
228 td->io_size = td->total_file_size;
229 td->total_io_size = td->io_size;
230 td->files[0].real_file_size = td->io_size;
231 }
232
233 return ret;
234}
235
236static void fio_netio_cleanup(struct thread_data *td)
237{
238 if (td->io_ops->data) {
239 free(td->io_ops->data);
240 td->io_ops->data = NULL;
241 }
242}
243
244static int fio_netio_init(struct thread_data *td)
245{
246 struct net_data *nd;
247
e01547d2
JA
248 /*
249 * Hack to work-around the ->setup() function calling init on its
250 * own, since it needs ->io_ops->data to be set up.
251 */
ed92ac0c
JA
252 if (td->io_ops->data)
253 return 0;
254
255 nd = malloc(sizeof(*nd));
256 nd->last_io_u = NULL;
257 td->io_ops->data = nd;
258 return 0;
259}
260
261static struct ioengine_ops ioengine = {
262 .name = "net",
263 .version = FIO_IOOPS_VERSION,
264 .init = fio_netio_init,
265 .prep = fio_netio_prep,
266 .queue = fio_netio_queue,
267 .getevents = fio_netio_getevents,
268 .event = fio_netio_event,
269 .cleanup = fio_netio_cleanup,
270 .setup = fio_netio_setup,
271 .flags = FIO_SYNCIO | FIO_NETIO,
272};
273
274static void fio_init fio_netio_register(void)
275{
276 register_ioengine(&ioengine);
277}
278
279static void fio_exit fio_netio_unregister(void)
280{
281 unregister_ioengine(&ioengine);
282}