X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=server.c;h=2e8682c999cc395f0af45ab67723d40459735484;hp=4f9c02310563604c08064209af92567a306acbe6;hb=5adc2447a8d52322981da4cd364a560bbd9d8351;hpb=13755d946d034eb7395a818db7ace2c9cb60b4cb diff --git a/server.c b/server.c index 4f9c0231..2e8682c9 100644 --- a/server.c +++ b/server.c @@ -20,11 +20,11 @@ #include "fio.h" #include "server.h" #include "crc/crc16.h" -#include "ieee754.h" +#include "lib/ieee754.h" #include "fio_version.h" -int fio_net_port = 8765; +int fio_net_port = FIO_NET_PORT; int exit_backend = 0; @@ -32,6 +32,38 @@ static int server_fd = -1; static char *fio_server_arg; static char *bind_sock; static struct sockaddr_in saddr_in; +static struct sockaddr_in6 saddr_in6; +static int first_cmd_check; +static int use_ipv6; + +static const char *fio_server_ops[FIO_NET_CMD_NR] = { + "", + "QUIT", + "EXIT", + "JOB", + "JOBLINE", + "TEXT", + "TS", + "GS", + "SEND_ETA", + "ETA", + "PROBE", + "START", + "STOP", + "DISK_UTIL", + "RUN", +}; + +const char *fio_server_op(unsigned int op) +{ + static char buf[32]; + + if (op < FIO_NET_CMD_NR) + return fio_server_ops[op]; + + sprintf(buf, "UNKNOWN/%d", op); + return buf; +} int fio_send_data(int sk, const void *p, unsigned int len) { @@ -50,6 +82,8 @@ int fio_send_data(int sk, const void *p, unsigned int len) break; else if (errno == EAGAIN || errno == EINTR) continue; + else + break; } while (!exit_backend); if (!len) @@ -73,6 +107,8 @@ int fio_recv_data(int sk, void *p, unsigned int len) break; else if (errno == EAGAIN || errno == EINTR) continue; + else + break; } while (!exit_backend); if (!len) @@ -149,8 +185,12 @@ struct fio_net_cmd *fio_net_recv_cmd(int sk) if (first) memcpy(cmdret, &cmd, sizeof(cmd)); - else - assert(cmdret->opcode == cmd.opcode); + else if (cmdret->opcode != cmd.opcode) { + log_err("fio: fragment opcode mismatch (%d != %d)\n", + cmdret->opcode, cmd.opcode); + ret = 1; + break; + } if (!cmd.pdu_len) break; @@ -243,7 +283,7 @@ int fio_net_send_cmd(int fd, uint16_t opcode, const void *buf, off_t size, return ret; } -int fio_net_send_simple_cmd(int sk, uint16_t opcode, uint64_t tag) +static int fio_net_send_simple_stack_cmd(int sk, uint16_t opcode, uint64_t tag) { struct fio_net_cmd cmd; @@ -253,15 +293,49 @@ int fio_net_send_simple_cmd(int sk, uint16_t opcode, uint64_t tag) return fio_send_data(sk, &cmd, sizeof(cmd)); } +/* + * If 'list' is non-NULL, then allocate and store the sent command for + * later verification. + */ +int fio_net_send_simple_cmd(int sk, uint16_t opcode, uint64_t tag, + struct flist_head *list) +{ + struct fio_net_int_cmd *cmd; + int ret; + + if (!list) + return fio_net_send_simple_stack_cmd(sk, opcode, tag); + + cmd = malloc(sizeof(*cmd)); + + fio_init_net_cmd(&cmd->cmd, opcode, NULL, 0, (uintptr_t) cmd); + fio_net_cmd_crc(&cmd->cmd); + + INIT_FLIST_HEAD(&cmd->list); + gettimeofday(&cmd->tv, NULL); + cmd->saved_tag = tag; + + ret = fio_send_data(sk, &cmd->cmd, sizeof(cmd->cmd)); + if (ret) { + free(cmd); + return ret; + } + + flist_add_tail(&cmd->list, list); + return 0; +} + static int fio_server_send_quit_cmd(void) { dprint(FD_NET, "server: sending quit\n"); - return fio_net_send_simple_cmd(server_fd, FIO_NET_CMD_QUIT, 0); + return fio_net_send_simple_cmd(server_fd, FIO_NET_CMD_QUIT, 0, NULL); } static int handle_job_cmd(struct fio_net_cmd *cmd) { char *buf = (char *) cmd->payload; + struct cmd_start_pdu spdu; + struct cmd_end_pdu epdu; int ret; if (parse_jobs_ini(buf, 1, 0)) { @@ -269,9 +343,14 @@ static int handle_job_cmd(struct fio_net_cmd *cmd) return -1; } - fio_net_send_simple_cmd(server_fd, FIO_NET_CMD_START, 0); + spdu.jobs = cpu_to_le32(thread_number); + fio_net_send_cmd(server_fd, FIO_NET_CMD_START, &spdu, sizeof(spdu), 0); + + ret = fio_backend(); + + epdu.error = ret; + fio_net_send_cmd(server_fd, FIO_NET_CMD_STOP, &epdu, sizeof(epdu), 0); - ret = exec_run(); fio_server_send_quit_cmd(); reset_fio_state(); return ret; @@ -309,9 +388,9 @@ static int handle_jobline_cmd(struct fio_net_cmd *cmd) free(argv); - fio_net_send_simple_cmd(server_fd, FIO_NET_CMD_START, 0); + fio_net_send_simple_cmd(server_fd, FIO_NET_CMD_START, 0, NULL); - ret = exec_run(); + ret = fio_backend(); fio_server_send_quit_cmd(); reset_fio_state(); return ret; @@ -321,6 +400,8 @@ static int handle_probe_cmd(struct fio_net_cmd *cmd) { struct cmd_probe_pdu probe; + dprint(FD_NET, "server: sending probe reply\n"); + memset(&probe, 0, sizeof(probe)); gethostname((char *) probe.hostname, sizeof(probe.hostname)); #ifdef FIO_BIG_ENDIAN @@ -333,7 +414,9 @@ static int handle_probe_cmd(struct fio_net_cmd *cmd) probe.os = FIO_OS; probe.arch = FIO_ARCH; - return fio_net_send_cmd(server_fd, FIO_NET_CMD_PROBE, &probe, sizeof(probe), 0); + probe.bpp = sizeof(void *); + + return fio_net_send_cmd(server_fd, FIO_NET_CMD_PROBE, &probe, sizeof(probe), cmd->tag); } static int handle_send_eta_cmd(struct fio_net_cmd *cmd) @@ -342,7 +425,10 @@ static int handle_send_eta_cmd(struct fio_net_cmd *cmd) size_t size; int i; - size = sizeof(*je) + thread_number * sizeof(char); + if (!thread_number) + return 0; + + size = sizeof(*je) + thread_number * sizeof(char) + 1; je = malloc(size); memset(je, 0, size); @@ -379,7 +465,8 @@ static int handle_command(struct fio_net_cmd *cmd) { int ret; - dprint(FD_NET, "server: got opcode %d, pdu=%u\n", cmd->opcode, cmd->pdu_len); + dprint(FD_NET, "server: got op [%s], pdu=%u, tag=%lx\n", + fio_server_op(cmd->opcode), cmd->pdu_len, cmd->tag); switch (cmd->opcode) { case FIO_NET_CMD_QUIT: @@ -401,7 +488,7 @@ static int handle_command(struct fio_net_cmd *cmd) ret = handle_send_eta_cmd(cmd); break; default: - log_err("fio: unknown opcode: %d\n", cmd->opcode); + log_err("fio: unknown opcode: %s\n",fio_server_op(cmd->opcode)); ret = 1; } @@ -467,6 +554,8 @@ static int handle_connection(int sk, int block) void fio_server_idle_loop(void) { + if (!first_cmd_check) + fio_net_send_simple_cmd(server_fd, FIO_NET_CMD_RUN, 0, NULL); if (server_fd != -1) handle_connection(server_fd, 0); } @@ -600,9 +689,10 @@ void fio_server_send_ts(struct thread_stat *ts, struct group_run_stats *rs) p.ts.clat_percentiles = cpu_to_le64(ts->clat_percentiles); for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) { - fio_fp64_t *fp = &p.ts.percentile_list[i]; + fio_fp64_t *src = &ts->percentile_list[i]; + fio_fp64_t *dst = &p.ts.percentile_list[i]; - fp->u.i = __cpu_to_le64(fio_double_to_uint64(fp->u.f)); + dst->u.i = __cpu_to_le64(fio_double_to_uint64(src->u.f)); } for (i = 0; i < FIO_IO_U_MAP_NR; i++) { @@ -654,6 +744,61 @@ void fio_server_send_gs(struct group_run_stats *rs) fio_net_send_cmd(server_fd, FIO_NET_CMD_GS, &gs, sizeof(gs), 0); } +static void convert_agg(struct disk_util_agg *dst, struct disk_util_agg *src) +{ + int i; + + for (i = 0; i < 2; i++) { + dst->ios[i] = cpu_to_le32(src->ios[i]); + dst->merges[i] = cpu_to_le32(src->merges[i]); + dst->sectors[i] = cpu_to_le64(src->sectors[i]); + dst->ticks[i] = cpu_to_le32(src->ticks[i]); + } + + dst->io_ticks = cpu_to_le32(src->io_ticks); + dst->time_in_queue = cpu_to_le32(src->time_in_queue); + dst->slavecount = cpu_to_le32(src->slavecount); + dst->max_util.u.i = __cpu_to_le64(fio_double_to_uint64(src->max_util.u.f)); +} + +static void convert_dus(struct disk_util_stat *dst, struct disk_util_stat *src) +{ + int i; + + strcpy((char *) dst->name, (char *) src->name); + + for (i = 0; i < 2; i++) { + dst->ios[i] = cpu_to_le32(src->ios[i]); + dst->merges[i] = cpu_to_le32(src->merges[i]); + dst->sectors[i] = cpu_to_le64(src->sectors[i]); + dst->ticks[i] = cpu_to_le32(src->ticks[i]); + } + + dst->io_ticks = cpu_to_le32(src->io_ticks); + dst->time_in_queue = cpu_to_le32(src->time_in_queue); + dst->msec = cpu_to_le64(src->msec); +} + +void fio_server_send_du(void) +{ + struct disk_util *du; + struct flist_head *entry; + struct cmd_du_pdu pdu; + + dprint(FD_NET, "server: sending disk_util %d\n", !flist_empty(&disk_list)); + + memset(&pdu, 0, sizeof(pdu)); + + flist_for_each(entry, &disk_list) { + du = flist_entry(entry, struct disk_util, list); + + convert_dus(&pdu.dus, &du->dus); + convert_agg(&pdu.agg, &du->agg); + + fio_net_send_cmd(server_fd, FIO_NET_CMD_DU, &pdu, sizeof(pdu), 0); + } +} + int fio_server_log(const char *format, ...) { char buffer[1024]; @@ -671,9 +816,15 @@ int fio_server_log(const char *format, ...) static int fio_init_server_ip(void) { + struct sockaddr *addr; + fio_socklen_t socklen; int sk, opt; - sk = socket(AF_INET, SOCK_STREAM, 0); + if (use_ipv6) + sk = socket(AF_INET6, SOCK_STREAM, 0); + else + sk = socket(AF_INET, SOCK_STREAM, 0); + if (sk < 0) { log_err("fio: socket: %s\n", strerror(errno)); return -1; @@ -693,9 +844,17 @@ static int fio_init_server_ip(void) } #endif - saddr_in.sin_family = AF_INET; + if (use_ipv6) { + addr = (struct sockaddr *) &saddr_in6; + socklen = sizeof(saddr_in6); + saddr_in6.sin6_family = AF_INET6; + } else { + addr = (struct sockaddr *) &saddr_in; + socklen = sizeof(saddr_in); + saddr_in.sin_family = AF_INET; + } - if (bind(sk, (struct sockaddr *) &saddr_in, sizeof(saddr_in)) < 0) { + if (bind(sk, addr, socklen) < 0) { log_err("fio: bind: %s\n", strerror(errno)); close(sk); return -1; @@ -751,14 +910,32 @@ static int fio_init_server_connection(void) if (sk < 0) return sk; - if (!bind_sock) - sprintf(bind_str, "%s:%u", inet_ntoa(saddr_in.sin_addr), fio_net_port); - else + if (!bind_sock) { + char *p, port[16]; + const void *src; + int af; + + if (use_ipv6) { + af = AF_INET6; + src = &saddr_in6.sin6_addr; + } else { + af = AF_INET; + src = &saddr_in.sin_addr; + } + + p = (char *) inet_ntop(af, src, bind_str, sizeof(bind_str)); + + sprintf(port, ",%u", fio_net_port); + if (p) + strcat(p, port); + else + strcpy(bind_str, port); + } else strcpy(bind_str, bind_sock); log_info("fio: server listening on %s\n", bind_str); - if (listen(sk, 1) < 0) { + if (listen(sk, 0) < 0) { log_err("fio: listen: %s\n", strerror(errno)); return -1; } @@ -766,71 +943,116 @@ static int fio_init_server_connection(void) return sk; } +/* + * Parse a host/ip/port string. Reads from 'str'. + * + * Outputs: + * + * For IPv4: + * *ptr is the host, *port is the port, inp is the destination. + * For IPv6: + * *ptr is the host, *port is the port, inp6 is the dest, and *ipv6 is 1. + * For local domain sockets: + * *ptr is the filename, *is_sock is 1. + */ int fio_server_parse_string(const char *str, char **ptr, int *is_sock, - int *port, struct in_addr *inp) + int *port, struct in_addr *inp, + struct in6_addr *inp6, int *ipv6) { + const char *host = str; + char *portp; + int ret, lport = 0; + *ptr = NULL; *is_sock = 0; *port = fio_net_port; + *ipv6 = 0; if (!strncmp(str, "sock:", 5)) { *ptr = strdup(str + 5); *is_sock = 1; - } else { - const char *host = str; - char *portp; - int lport = 0; - - /* - * Is it ip::port - */ - if (!strncmp(host, "ip:", 3)) - host += 3; - else if (host[0] == ':') { - /* String is :port */ - host++; - lport = atoi(host); + + return 0; + } + + /* + * Is it ip::port + */ + if (!strncmp(host, "ip:", 3)) + host += 3; + else if (!strncmp(host, "ip4:", 4)) + host += 4; + else if (!strncmp(host, "ip6:", 4)) { + host += 4; + *ipv6 = 1; + } else if (host[0] == ':') { + /* String is :port */ + host++; + lport = atoi(host); + if (!lport || lport > 65535) { + log_err("fio: bad server port %u\n", port); + return 1; + } + /* no hostname given, we are done */ + *port = lport; + return 0; + } + + /* + * If no port seen yet, check if there's a last ':' at the end + */ + if (!lport) { + portp = strchr(host, ','); + if (portp) { + *portp = '\0'; + portp++; + lport = atoi(portp); if (!lport || lport > 65535) { log_err("fio: bad server port %u\n", port); return 1; } - /* no hostname given, we are done */ - *port = lport; - return 0; } + } - /* - * If no port seen yet, check if there's a last ':' at the end - */ - if (!lport) { - portp = strchr(host, ':'); - if (portp) { - *portp = '\0'; - portp++; - lport = atoi(portp); - if (!lport || lport > 65535) { - log_err("fio: bad server port %u\n", port); - return 1; - } - } - } + if (lport) + *port = lport; + + if (!strlen(host)) + return 0; + + *ptr = strdup(host); - if (lport) - *port = lport; + if (*ipv6) + ret = inet_pton(AF_INET6, host, inp6); + else + ret = inet_pton(AF_INET, host, inp); - *ptr = strdup(host); + if (ret != 1) { + struct hostent *hent; - if (inet_aton(host, inp) != 1) { - struct hostent *hent; + hent = gethostbyname(host); + if (!hent) { + log_err("fio: failed to resolve <%s>\n", host); + free(*ptr); + *ptr = NULL; + return 1; + } - hent = gethostbyname(host); - if (!hent) { + if (*ipv6) { + if (hent->h_addrtype != AF_INET6) { + log_info("fio: falling back to IPv4\n"); + *ipv6 = 0; + } else + memcpy(inp6, hent->h_addr_list[0], 16); + } + if (!*ipv6) { + if (hent->h_addrtype != AF_INET) { + log_err("fio: lookup type mismatch\n"); free(*ptr); *ptr = NULL; return 1; } - - memcpy(inp, hent->h_addr, 4); + memcpy(inp, hent->h_addr_list[0], 4); } } @@ -863,7 +1085,8 @@ static int fio_handle_server_arg(void) goto out; ret = fio_server_parse_string(fio_server_arg, &bind_sock, &is_sock, - &port, &saddr_in.sin_addr); + &port, &saddr_in.sin_addr, + &saddr_in6.sin6_addr, &use_ipv6); if (!is_sock && bind_sock) { free(bind_sock); @@ -873,6 +1096,7 @@ static int fio_handle_server_arg(void) out: fio_net_port = port; saddr_in.sin_port = htons(port); + saddr_in6.sin6_port = htons(port); return ret; } @@ -903,25 +1127,14 @@ static int fio_server(void) return ret; } -static void sig_int(int sig) -{ - fio_terminate_threads(TERMINATE_ALL); - exit_backend = 1; -} - -static void server_signal_handler(void) +void fio_server_got_signal(int signal) { - struct sigaction act; - - memset(&act, 0, sizeof(act)); - act.sa_handler = sig_int; - act.sa_flags = SA_RESTART; - sigaction(SIGINT, &act, NULL); - - memset(&act, 0, sizeof(act)); - act.sa_handler = sig_int; - act.sa_flags = SA_RESTART; - sigaction(SIGTERM, &act, NULL); + if (signal == SIGPIPE) + server_fd = -1; + else { + log_info("\nfio: terminating on signal %d\n", signal); + exit_backend = 1; + } } static int check_existing_pidfile(const char *pidfile) @@ -938,7 +1151,7 @@ static int check_existing_pidfile(const char *pidfile) if (!f) return 0; - if (fread(buf, sb.st_size, 1, f) < 0) { + if (fread(buf, sb.st_size, 1, f) <= 0) { fclose(f); return 1; } @@ -946,7 +1159,7 @@ static int check_existing_pidfile(const char *pidfile) pid = atoi(buf); if (kill(pid, SIGCONT) < 0) - return 0; + return errno != ESRCH; return 1; } @@ -974,7 +1187,10 @@ int fio_start_server(char *pidfile) pid_t pid; int ret; - server_signal_handler(); +#if defined(WIN32) + WSADATA wsd; + WSAStartup(MAKEWORD(2,2), &wsd); +#endif if (!pidfile) return fio_server();