client: check and error out on exceeding number of command line args to pass
[fio.git] / client.c
CommitLineData
132159a5
JA
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <limits.h>
5#include <errno.h>
6#include <fcntl.h>
7#include <sys/poll.h>
8#include <sys/types.h>
9#include <sys/stat.h>
10#include <sys/wait.h>
d05c4a03 11#include <sys/socket.h>
132159a5
JA
12#include <netinet/in.h>
13#include <arpa/inet.h>
14#include <netdb.h>
9e22ecb0 15#include <signal.h>
132159a5
JA
16
17#include "fio.h"
18#include "server.h"
19#include "crc/crc32.h"
b66570dc 20#include "flist.h"
132159a5 21
b66570dc
JA
22struct fio_client {
23 struct flist_head list;
24 struct sockaddr_in addr;
25 char *hostname;
26 int fd;
81179eec
JA
27
28 int state;
17dd1764 29 int skip_newline;
81179eec
JA
30
31 uint16_t argc;
32 char **argv;
33};
34
35enum {
5c2857f9 36 Client_created = 0,
81179eec
JA
37 Client_connected = 1,
38 Client_started = 2,
39 Client_stopped = 3,
5c2857f9 40 Client_exited = 4,
b66570dc
JA
41};
42
43static FLIST_HEAD(client_list);
b66570dc 44
0b8f30a5
JA
45static int handle_client(struct fio_client *client, int one);
46
b66570dc
JA
47static struct fio_client *find_client_by_fd(int fd)
48{
49 struct fio_client *client;
50 struct flist_head *entry;
51
52 flist_for_each(entry, &client_list) {
53 client = flist_entry(entry, struct fio_client, list);
54
55 if (client->fd == fd)
56 return client;
57 }
58
59 return NULL;
60}
61
62static struct fio_client *find_client_by_name(const char *name)
63{
64 struct fio_client *client;
65 struct flist_head *entry;
66
67 flist_for_each(entry, &client_list) {
68 client = flist_entry(entry, struct fio_client, list);
69
70 if (!strcmp(name, client->hostname))
71 return client;
72 }
73
74 return NULL;
75}
76
77static void remove_client(struct fio_client *client)
78{
39e8e016 79 dprint(FD_NET, "client: removed <%s>\n", client->hostname);
b66570dc
JA
80 flist_del(&client->list);
81 nr_clients--;
81179eec 82
b66570dc 83 free(client->hostname);
81179eec
JA
84 if (client->argv)
85 free(client->argv);
86
b66570dc
JA
87 free(client);
88}
132159a5 89
7a4b8240
JA
90static int __fio_client_add_cmd_option(struct fio_client *client,
91 const char *opt)
81179eec 92{
39e8e016
JA
93 int index;
94
7a4b8240
JA
95 if (client->argc == FIO_NET_CMD_JOBLINE_ARGV) {
96 log_err("fio: max cmd line number reached.\n");
97 log_err("fio: cmd line <%s> has been ignored.\n", opt);
98 return 1;
99 }
100
39e8e016 101 index = client->argc++;
81179eec 102 client->argv = realloc(client->argv, sizeof(char *) * client->argc);
39e8e016
JA
103 client->argv[index] = strdup(opt);
104 dprint(FD_NET, "client: add cmd %d: %s\n", index, opt);
7a4b8240 105 return 0;
81179eec
JA
106}
107
7a4b8240 108int fio_client_add_cmd_option(const char *hostname, const char *opt)
81179eec
JA
109{
110 struct fio_client *client;
111
112 if (!hostname || !opt)
7a4b8240 113 return 0;
81179eec
JA
114
115 client = find_client_by_name(hostname);
116 if (!client) {
117 log_err("fio: unknown client %s\n", hostname);
7a4b8240 118 return 1;
81179eec
JA
119 }
120
7a4b8240 121 return __fio_client_add_cmd_option(client, opt);
81179eec
JA
122}
123
a37f69b7 124void fio_client_add(const char *hostname)
132159a5 125{
b66570dc 126 struct fio_client *client;
132159a5 127
39e8e016 128 dprint(FD_NET, "client: added <%s>\n", hostname);
b66570dc 129 client = malloc(sizeof(*client));
a37f69b7 130 memset(client, 0, sizeof(*client));
81179eec 131
a37f69b7
JA
132 client->hostname = strdup(hostname);
133 client->fd = -1;
81179eec
JA
134
135 __fio_client_add_cmd_option(client, "fio");
136
a37f69b7
JA
137 flist_add(&client->list, &client_list);
138 nr_clients++;
139}
140
141static int fio_client_connect(struct fio_client *client)
142{
143 int fd;
132159a5 144
39e8e016 145 dprint(FD_NET, "client: connect to host %s\n", client->hostname);
46c48f1f 146
b66570dc
JA
147 memset(&client->addr, 0, sizeof(client->addr));
148 client->addr.sin_family = AF_INET;
149 client->addr.sin_port = htons(fio_net_port);
150
a37f69b7 151 if (inet_aton(client->hostname, &client->addr.sin_addr) != 1) {
132159a5
JA
152 struct hostent *hent;
153
a37f69b7 154 hent = gethostbyname(client->hostname);
132159a5
JA
155 if (!hent) {
156 log_err("fio: gethostbyname: %s\n", strerror(errno));
157 return 1;
158 }
159
b66570dc 160 memcpy(&client->addr.sin_addr, hent->h_addr, 4);
132159a5
JA
161 }
162
163 fd = socket(AF_INET, SOCK_STREAM, 0);
164 if (fd < 0) {
165 log_err("fio: socket: %s\n", strerror(errno));
166 return 1;
167 }
168
b66570dc 169 if (connect(fd, (struct sockaddr *) &client->addr, sizeof(client->addr)) < 0) {
132159a5 170 log_err("fio: connect: %s\n", strerror(errno));
cdf54d85 171 log_err("fio: failed to connect to %s\n", client->hostname);
132159a5
JA
172 return 1;
173 }
174
b66570dc 175 client->fd = fd;
81179eec 176 client->state = Client_connected;
132159a5
JA
177 return 0;
178}
179
cc0df00a
JA
180void fio_clients_terminate(void)
181{
182 struct flist_head *entry;
183 struct fio_client *client;
184
60efd14e
JA
185 dprint(FD_NET, "client: terminate clients\n");
186
cc0df00a
JA
187 flist_for_each(entry, &client_list) {
188 client = flist_entry(entry, struct fio_client, list);
189
190 fio_net_send_simple_cmd(client->fd, FIO_NET_CMD_QUIT, 0);
191 }
192}
193
194static void sig_int(int sig)
195{
60efd14e 196 dprint(FD_NET, "client: got sign %d\n", sig);
cc0df00a
JA
197 fio_clients_terminate();
198}
199
200static void client_signal_handler(void)
201{
202 struct sigaction act;
203
204 memset(&act, 0, sizeof(act));
205 act.sa_handler = sig_int;
206 act.sa_flags = SA_RESTART;
207 sigaction(SIGINT, &act, NULL);
208
209 memset(&act, 0, sizeof(act));
210 act.sa_handler = sig_int;
211 act.sa_flags = SA_RESTART;
212 sigaction(SIGTERM, &act, NULL);
213}
214
0b8f30a5
JA
215static void probe_client(struct fio_client *client)
216{
60efd14e
JA
217 dprint(FD_NET, "client: send probe\n");
218
0b8f30a5
JA
219 fio_net_send_simple_cmd(client->fd, FIO_NET_CMD_PROBE, 0);
220 handle_client(client, 1);
221}
222
81179eec
JA
223static int send_client_cmd_line(struct fio_client *client)
224{
225 struct cmd_line_pdu *pdu;
226 int i, ret;
227
39e8e016 228 dprint(FD_NET, "client: send cmdline %d\n", client->argc);
60efd14e 229
81179eec
JA
230 pdu = malloc(sizeof(*pdu));
231 for (i = 0; i < client->argc; i++)
232 strcpy((char *) pdu->argv[i], client->argv[i]);
233
234 pdu->argc = cpu_to_le16(client->argc);
235 ret = fio_net_send_cmd(client->fd, FIO_NET_CMD_JOBLINE, pdu, sizeof(*pdu));
236 free(pdu);
237 return ret;
238}
239
a37f69b7
JA
240int fio_clients_connect(void)
241{
242 struct fio_client *client;
243 struct flist_head *entry, *tmp;
244 int ret;
245
60efd14e
JA
246 dprint(FD_NET, "client: connect all\n");
247
cc0df00a
JA
248 client_signal_handler();
249
a37f69b7
JA
250 flist_for_each_safe(entry, tmp, &client_list) {
251 client = flist_entry(entry, struct fio_client, list);
252
253 ret = fio_client_connect(client);
0b8f30a5 254 if (ret) {
a37f69b7 255 remove_client(client);
0b8f30a5
JA
256 continue;
257 }
258
259 probe_client(client);
81179eec
JA
260
261 if (client->argc > 1)
262 send_client_cmd_line(client);
a37f69b7
JA
263 }
264
265 return !nr_clients;
266}
267
132159a5
JA
268/*
269 * Send file contents to server backend. We could use sendfile(), but to remain
270 * more portable lets just read/write the darn thing.
271 */
a37f69b7 272static int fio_client_send_ini(struct fio_client *client, const char *filename)
132159a5
JA
273{
274 struct stat sb;
275 char *p, *buf;
276 off_t len;
277 int fd, ret;
278
46c48f1f
JA
279 dprint(FD_NET, "send ini %s to %s\n", filename, client->hostname);
280
132159a5
JA
281 fd = open(filename, O_RDONLY);
282 if (fd < 0) {
283 log_err("fio: job file open: %s\n", strerror(errno));
284 return 1;
285 }
286
287 if (fstat(fd, &sb) < 0) {
288 log_err("fio: job file stat: %s\n", strerror(errno));
289 return 1;
290 }
291
292 buf = malloc(sb.st_size);
293
294 len = sb.st_size;
295 p = buf;
296 do {
297 ret = read(fd, p, len);
298 if (ret > 0) {
299 len -= ret;
300 if (!len)
301 break;
302 p += ret;
303 continue;
304 } else if (!ret)
305 break;
306 else if (errno == EAGAIN || errno == EINTR)
307 continue;
308 } while (1);
309
0b8f30a5
JA
310 if (len) {
311 log_err("fio: failed reading job file %s\n", filename);
312 return 1;
313 }
314
81179eec 315 ret = fio_net_send_cmd(client->fd, FIO_NET_CMD_JOB, buf, sb.st_size);
132159a5
JA
316 free(buf);
317 return ret;
318}
37db14fe 319
a37f69b7
JA
320int fio_clients_send_ini(const char *filename)
321{
322 struct fio_client *client;
323 struct flist_head *entry, *tmp;
324
325 flist_for_each_safe(entry, tmp, &client_list) {
326 client = flist_entry(entry, struct fio_client, list);
327
328 if (fio_client_send_ini(client, filename))
329 remove_client(client);
330 }
331
332 return !nr_clients;
333}
334
a64e88da
JA
335static void convert_io_stat(struct io_stat *dst, struct io_stat *src)
336{
337 dst->max_val = le64_to_cpu(src->max_val);
338 dst->min_val = le64_to_cpu(src->min_val);
339 dst->samples = le64_to_cpu(src->samples);
802ad4a8
JA
340
341 /*
342 * Floats arrive as IEEE 754 encoded uint64_t, convert back to double
343 */
344 dst->mean.u.f = fio_uint64_to_double(le64_to_cpu(dst->mean.u.i));
345 dst->S.u.f = fio_uint64_to_double(le64_to_cpu(dst->S.u.i));
a64e88da
JA
346}
347
348static void convert_ts(struct thread_stat *dst, struct thread_stat *src)
349{
350 int i, j;
351
352 dst->error = le32_to_cpu(src->error);
353 dst->groupid = le32_to_cpu(src->groupid);
354 dst->pid = le32_to_cpu(src->pid);
355 dst->members = le32_to_cpu(src->members);
356
357 for (i = 0; i < 2; i++) {
358 convert_io_stat(&dst->clat_stat[i], &src->clat_stat[i]);
359 convert_io_stat(&dst->slat_stat[i], &src->slat_stat[i]);
360 convert_io_stat(&dst->lat_stat[i], &src->lat_stat[i]);
361 convert_io_stat(&dst->bw_stat[i], &src->bw_stat[i]);
362 }
363
364 dst->usr_time = le64_to_cpu(src->usr_time);
365 dst->sys_time = le64_to_cpu(src->sys_time);
366 dst->ctx = le64_to_cpu(src->ctx);
367 dst->minf = le64_to_cpu(src->minf);
368 dst->majf = le64_to_cpu(src->majf);
369 dst->clat_percentiles = le64_to_cpu(src->clat_percentiles);
802ad4a8
JA
370
371 for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) {
372 fio_fp64_t *fps = &src->percentile_list[i];
373 fio_fp64_t *fpd = &dst->percentile_list[i];
374
375 fpd->u.f = fio_uint64_to_double(le64_to_cpu(fps->u.i));
376 }
a64e88da
JA
377
378 for (i = 0; i < FIO_IO_U_MAP_NR; i++) {
379 dst->io_u_map[i] = le32_to_cpu(src->io_u_map[i]);
380 dst->io_u_submit[i] = le32_to_cpu(src->io_u_submit[i]);
381 dst->io_u_complete[i] = le32_to_cpu(src->io_u_complete[i]);
382 }
383
384 for (i = 0; i < FIO_IO_U_LAT_U_NR; i++) {
385 dst->io_u_lat_u[i] = le32_to_cpu(src->io_u_lat_u[i]);
386 dst->io_u_lat_m[i] = le32_to_cpu(src->io_u_lat_m[i]);
387 }
388
389 for (i = 0; i < 2; i++)
390 for (j = 0; j < FIO_IO_U_PLAT_NR; j++)
391 dst->io_u_plat[i][j] = le32_to_cpu(src->io_u_plat[i][j]);
392
393 for (i = 0; i < 3; i++) {
394 dst->total_io_u[i] = le64_to_cpu(src->total_io_u[i]);
93eee04a 395 dst->short_io_u[i] = le64_to_cpu(src->short_io_u[i]);
a64e88da
JA
396 }
397
398 dst->total_submit = le64_to_cpu(src->total_submit);
399 dst->total_complete = le64_to_cpu(src->total_complete);
400
401 for (i = 0; i < 2; i++) {
402 dst->io_bytes[i] = le64_to_cpu(src->io_bytes[i]);
403 dst->runtime[i] = le64_to_cpu(src->runtime[i]);
404 }
405
406 dst->total_run_time = le64_to_cpu(src->total_run_time);
407 dst->continue_on_error = le16_to_cpu(src->continue_on_error);
408 dst->total_err_count = le64_to_cpu(src->total_err_count);
ddcc0b69
JA
409 dst->first_error = le32_to_cpu(src->first_error);
410 dst->kb_base = le32_to_cpu(src->kb_base);
a64e88da
JA
411}
412
413static void convert_gs(struct group_run_stats *dst, struct group_run_stats *src)
414{
415 int i;
416
417 for (i = 0; i < 2; i++) {
418 dst->max_run[i] = le64_to_cpu(src->max_run[i]);
419 dst->min_run[i] = le64_to_cpu(src->min_run[i]);
420 dst->max_bw[i] = le64_to_cpu(src->max_bw[i]);
421 dst->min_bw[i] = le64_to_cpu(src->min_bw[i]);
422 dst->io_kb[i] = le64_to_cpu(src->io_kb[i]);
423 dst->agg[i] = le64_to_cpu(src->agg[i]);
424 }
425
426 dst->kb_base = le32_to_cpu(src->kb_base);
427 dst->groupid = le32_to_cpu(src->groupid);
428}
429
430static void handle_ts(struct fio_net_cmd *cmd)
431{
432 struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
433
434 convert_ts(&p->ts, &p->ts);
435 convert_gs(&p->rs, &p->rs);
436
437 show_thread_status(&p->ts, &p->rs);
438}
439
440static void handle_gs(struct fio_net_cmd *cmd)
441{
442 struct group_run_stats *gs = (struct group_run_stats *) cmd->payload;
443
444 convert_gs(gs, gs);
445 show_group_stats(gs);
446}
447
cf451d1e
JA
448static void handle_eta(struct fio_net_cmd *cmd)
449{
450 struct jobs_eta *je = (struct jobs_eta *) cmd->payload;
451 int i;
452
453 je->nr_running = le32_to_cpu(je->nr_running);
454 je->nr_ramp = le32_to_cpu(je->nr_ramp);
455 je->nr_pending = le32_to_cpu(je->nr_pending);
456 je->files_open = le32_to_cpu(je->files_open);
457 je->m_rate = le32_to_cpu(je->m_rate);
458 je->t_rate = le32_to_cpu(je->t_rate);
459 je->m_iops = le32_to_cpu(je->m_iops);
460 je->t_iops = le32_to_cpu(je->t_iops);
461
462 for (i = 0; i < 2; i++) {
463 je->rate[i] = le32_to_cpu(je->rate[i]);
464 je->iops[i] = le32_to_cpu(je->iops[i]);
465 }
466
467 je->elapsed_sec = le32_to_cpu(je->nr_running);
468 je->eta_sec = le64_to_cpu(je->eta_sec);
469
470 display_thread_status(je);
471}
472
2e03b4b2
JA
473static void handle_probe(struct fio_net_cmd *cmd)
474{
475 struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
476
6eb24791
JA
477 log_info("Probe: hostname=%s, be=%u, fio ver %u.%u.%u\n",
478 probe->hostname, probe->bigendian, probe->fio_major,
479 probe->fio_minor, probe->fio_patch);
2e03b4b2
JA
480}
481
0b8f30a5 482static int handle_client(struct fio_client *client, int one)
37db14fe
JA
483{
484 struct fio_net_cmd *cmd;
a450e492 485 int done = 0;
37db14fe 486
60efd14e
JA
487 dprint(FD_NET, "client: handle %s\n", client->hostname);
488
70e0c316 489 while ((cmd = fio_net_recv_cmd(client->fd, 1)) != NULL) {
46c48f1f
JA
490 dprint(FD_NET, "%s: got cmd op %d\n", client->hostname,
491 cmd->opcode);
492
a64e88da 493 switch (cmd->opcode) {
a64e88da 494 case FIO_NET_CMD_QUIT:
b66570dc 495 remove_client(client);
437377e1 496 free(cmd);
a450e492 497 done = 1;
437377e1 498 break;
17dd1764
JA
499 case FIO_NET_CMD_TEXT: {
500 const char *buf = (const char *) cmd->payload;
1f39e555 501 int fio_unused ret;
17dd1764
JA
502
503 if (!client->skip_newline)
9a7e10b9 504 fprintf(f_out, "<%s> ", client->hostname);
1f39e555 505 ret = fwrite(buf, cmd->pdu_len, 1, f_out);
0b8f30a5 506 fflush(f_out);
17dd1764 507 client->skip_newline = strchr(buf, '\n') == NULL;
37db14fe 508 free(cmd);
a64e88da 509 break;
17dd1764 510 }
a64e88da
JA
511 case FIO_NET_CMD_TS:
512 handle_ts(cmd);
513 free(cmd);
514 break;
515 case FIO_NET_CMD_GS:
516 handle_gs(cmd);
517 free(cmd);
518 break;
cf451d1e
JA
519 case FIO_NET_CMD_ETA:
520 handle_eta(cmd);
521 free(cmd);
522 break;
2e03b4b2
JA
523 case FIO_NET_CMD_PROBE:
524 handle_probe(cmd);
525 free(cmd);
526 break;
81179eec
JA
527 case FIO_NET_CMD_START:
528 client->state = Client_started;
529 free(cmd);
530 break;
531 case FIO_NET_CMD_STOP:
532 client->state = Client_stopped;
533 free(cmd);
534 break;
a64e88da
JA
535 default:
536 log_err("fio: unknown client op: %d\n", cmd->opcode);
537 free(cmd);
538 break;
37db14fe 539 }
a450e492 540
0b8f30a5 541 if (done || one)
a450e492 542 break;
37db14fe
JA
543 }
544
545 return 0;
546}
b66570dc
JA
547
548int fio_handle_clients(void)
549{
550 struct fio_client *client;
551 struct flist_head *entry;
552 struct pollfd *pfds;
82a4be1b 553 int i, ret = 0;
b66570dc
JA
554
555 pfds = malloc(nr_clients * sizeof(struct pollfd));
556
82a4be1b
JA
557 while (!exit_backend && nr_clients) {
558 i = 0;
559 flist_for_each(entry, &client_list) {
560 client = flist_entry(entry, struct fio_client, list);
b66570dc 561
82a4be1b
JA
562 pfds[i].fd = client->fd;
563 pfds[i].events = POLLIN;
564 i++;
565 }
566
567 assert(i == nr_clients);
b66570dc 568
5c2857f9
JA
569 do {
570 ret = poll(pfds, nr_clients, 100);
571 if (ret < 0) {
572 if (errno == EINTR)
573 continue;
574 log_err("fio: poll clients: %s\n", strerror(errno));
575 break;
576 } else if (!ret)
b66570dc 577 continue;
5c2857f9 578 } while (ret <= 0);
b66570dc
JA
579
580 for (i = 0; i < nr_clients; i++) {
581 if (!(pfds[i].revents & POLLIN))
582 continue;
583
584 client = find_client_by_fd(pfds[i].fd);
585 if (!client) {
586 log_err("fio: unknown client\n");
587 continue;
588 }
0b8f30a5 589 handle_client(client, 0);
b66570dc
JA
590 }
591 }
592
593 free(pfds);
b66570dc
JA
594 return 0;
595}