From 81179eec4a84ff25c190a8a6a685b0b3b4dd2a37 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 4 Oct 2011 12:42:06 +0200 Subject: [PATCH] server: initial support for command line passing Signed-off-by: Jens Axboe --- client.c | 79 ++++++++++++++++++++++++++---- fio.h | 8 ++++ init.c | 35 ++++++++++++-- options.c | 5 +- server.c | 141 ++++++++++++++++++++++++++++++++---------------------- server.h | 21 ++++++-- 6 files changed, 213 insertions(+), 76 deletions(-) diff --git a/client.c b/client.c index 536ff310..5f0f710a 100644 --- a/client.c +++ b/client.c @@ -23,6 +23,17 @@ struct fio_client { struct sockaddr_in addr; char *hostname; int fd; + + int state; + + uint16_t argc; + char **argv; +}; + +enum { + Client_connected = 1, + Client_started = 2, + Client_stopped = 3, }; static FLIST_HEAD(client_list); @@ -44,7 +55,6 @@ static struct fio_client *find_client_by_fd(int fd) return NULL; } -#if 0 static struct fio_client *find_client_by_name(const char *name) { struct fio_client *client; @@ -59,17 +69,44 @@ static struct fio_client *find_client_by_name(const char *name) return NULL; } -#endif static void remove_client(struct fio_client *client) { dprint(FD_NET, "removed client <%s>\n", client->hostname); flist_del(&client->list); nr_clients--; + free(client->hostname); + if (client->argv) + free(client->argv); + free(client); } +static void __fio_client_add_cmd_option(struct fio_client *client, + const char *opt) +{ + client->argc++; + client->argv = realloc(client->argv, sizeof(char *) * client->argc); + client->argv[client->argc - 1] = strdup(opt); +} + +void fio_client_add_cmd_option(const char *hostname, const char *opt) +{ + struct fio_client *client; + + if (!hostname || !opt) + return; + + client = find_client_by_name(hostname); + if (!client) { + log_err("fio: unknown client %s\n", hostname); + return; + } + + __fio_client_add_cmd_option(client, opt); +} + void fio_client_add(const char *hostname) { struct fio_client *client; @@ -77,8 +114,12 @@ void fio_client_add(const char *hostname) dprint(FD_NET, "added client <%s>\n", hostname); client = malloc(sizeof(*client)); memset(client, 0, sizeof(*client)); + client->hostname = strdup(hostname); client->fd = -1; + + __fio_client_add_cmd_option(client, "fio"); + flist_add(&client->list, &client_list); nr_clients++; } @@ -118,6 +159,7 @@ static int fio_client_connect(struct fio_client *client) } client->fd = fd; + client->state = Client_connected; return 0; } @@ -159,6 +201,21 @@ static void probe_client(struct fio_client *client) handle_client(client, 1); } +static int send_client_cmd_line(struct fio_client *client) +{ + struct cmd_line_pdu *pdu; + int i, ret; + + pdu = malloc(sizeof(*pdu)); + for (i = 0; i < client->argc; i++) + strcpy((char *) pdu->argv[i], client->argv[i]); + + pdu->argc = cpu_to_le16(client->argc); + ret = fio_net_send_cmd(client->fd, FIO_NET_CMD_JOBLINE, pdu, sizeof(*pdu)); + free(pdu); + return ret; +} + int fio_clients_connect(void) { struct fio_client *client; @@ -177,16 +234,14 @@ int fio_clients_connect(void) } probe_client(client); + + if (client->argc > 1) + send_client_cmd_line(client); } return !nr_clients; } -static int send_file_buf(struct fio_client *client, char *buf, off_t size) -{ - return fio_net_send_cmd(client->fd, FIO_NET_CMD_JOB, buf, size); -} - /* * Send file contents to server backend. We could use sendfile(), but to remain * more portable lets just read/write the darn thing. @@ -234,7 +289,7 @@ static int fio_client_send_ini(struct fio_client *client, const char *filename) return 1; } - ret = send_file_buf(client, buf, sb.st_size); + ret = fio_net_send_cmd(client->fd, FIO_NET_CMD_JOB, buf, sb.st_size); free(buf); return ret; } @@ -428,6 +483,14 @@ static int handle_client(struct fio_client *client, int one) handle_probe(cmd); free(cmd); break; + case FIO_NET_CMD_START: + client->state = Client_started; + free(cmd); + break; + case FIO_NET_CMD_STOP: + client->state = Client_stopped; + free(cmd); + break; default: log_err("fio: unknown client op: %d\n", cmd->opcode); free(cmd); diff --git a/fio.h b/fio.h index a74fb108..dce4d8d4 100644 --- a/fio.h +++ b/fio.h @@ -16,6 +16,10 @@ struct thread_data; +#define FIO_MAJOR 1 +#define FIO_MINOR 58 +#define FIO_PATCH 0 + #include "compiler/compiler.h" #include "flist.h" #include "fifo.h" @@ -470,6 +474,9 @@ enum { #define td_vmsg(td, err, msg, func) \ __td_verror((td), (err), (msg), (func)) +#define __fio_stringify_1(x) #x +#define __fio_stringify(x) __fio_stringify_1(x) + extern int exitall_on_terminate; extern int thread_number; extern int nr_process, nr_thread; @@ -532,6 +539,7 @@ static inline int should_fsync(struct thread_data *td) */ extern int __must_check parse_options(int, char **); extern int parse_jobs_ini(char *, int, int); +extern int parse_cmd_line(int, char **); extern int exec_run(void); extern void reset_fio_state(void); extern int fio_options_parse(struct thread_data *, char **, int); diff --git a/init.c b/init.c index d9c78ec5..045131e8 100644 --- a/init.c +++ b/init.c @@ -23,7 +23,14 @@ #include "lib/getopt.h" -static char fio_version_string[] = "fio 1.58"; +#if FIO_PATCH > 0 +static char fio_version_string[] = __fio_stringify(FIO_MAJOR) "." \ + __fio_stringify(FIO_MINOR) "." \ + __fio_stringify(FIO_PATCH); +#else +static char fio_version_string[] = __fio_stringify(FIO_MAJOR) "." \ + __fio_stringify(FIO_MINOR); +#endif #define FIO_RANDSEED (0xb1899bedUL) @@ -1198,28 +1205,35 @@ static void fio_options_fill_optstring(void) ostr[c] = '\0'; } -static int parse_cmd_line(int argc, char *argv[]) +int parse_cmd_line(int argc, char *argv[]) { struct thread_data *td = NULL; int c, ini_idx = 0, lidx, ret = 0, do_exit = 0, exit_val = 0; char *ostr = cmd_optstr; int daemonize_server = 0; + char *cur_client = NULL; + int backend = 0; while ((c = getopt_long_only(argc, argv, ostr, l_opts, &lidx)) != -1) { switch (c) { case 'a': + fio_client_add_cmd_option(cur_client, argv[optind]); smalloc_pool_size = atoi(optarg); break; case 't': + fio_client_add_cmd_option(cur_client, argv[optind]); def_thread.o.timeout = atoi(optarg); break; case 'l': + fio_client_add_cmd_option(cur_client, argv[optind]); write_lat_log = 1; break; case 'b': + fio_client_add_cmd_option(cur_client, argv[optind]); write_bw_log = 1; break; case 'o': + fio_client_add_cmd_option(cur_client, argv[optind]); f_out = fopen(optarg, "w+"); if (!f_out) { perror("fopen output"); @@ -1228,6 +1242,7 @@ static int parse_cmd_line(int argc, char *argv[]) f_err = f_out; break; case 'm': + fio_client_add_cmd_option(cur_client, argv[optind]); terse_output = 1; break; case 'h': @@ -1236,15 +1251,18 @@ static int parse_cmd_line(int argc, char *argv[]) case 'c': exit(fio_show_option_help(optarg)); case 's': + fio_client_add_cmd_option(cur_client, argv[optind]); dump_cmdline = 1; break; case 'r': + fio_client_add_cmd_option(cur_client, argv[optind]); read_only = 1; break; case 'v': log_info("%s\n", fio_version_string); exit(0); case 'V': + fio_client_add_cmd_option(cur_client, argv[optind]); terse_version = atoi(optarg); if (terse_version != 2) { log_err("fio: bad terse version format\n"); @@ -1253,18 +1271,22 @@ static int parse_cmd_line(int argc, char *argv[]) } break; case 'e': + fio_client_add_cmd_option(cur_client, argv[optind]); if (!strcmp("always", optarg)) eta_print = FIO_ETA_ALWAYS; else if (!strcmp("never", optarg)) eta_print = FIO_ETA_NEVER; break; case 'd': + fio_client_add_cmd_option(cur_client, argv[optind]); if (set_debug(optarg)) do_exit++; break; case 'x': { size_t new_size; + fio_client_add_cmd_option(cur_client, argv[optind]); + if (!strcmp(optarg, "global")) { log_err("fio: can't use global as only " "section\n"); @@ -1279,12 +1301,15 @@ static int parse_cmd_line(int argc, char *argv[]) break; } case 'p': + fio_client_add_cmd_option(cur_client, argv[optind]); exec_profile = strdup(optarg); break; case FIO_GETOPT_JOB: { const char *opt = l_opts[lidx].name; char *val = optarg; + fio_client_add_cmd_option(cur_client, argv[optind]); + if (!strncmp(opt, "name", 4) && td) { ret = add_job(td, td->o.name ?: "fio", 0); if (ret) @@ -1310,9 +1335,11 @@ static int parse_cmd_line(int argc, char *argv[]) break; } case 'w': + fio_client_add_cmd_option(cur_client, argv[optind]); warnings_fatal = 1; break; case 'j': + fio_client_add_cmd_option(cur_client, argv[optind]); max_jobs = atoi(optarg); if (!max_jobs || max_jobs > REAL_MAX_JOBS) { log_err("fio: invalid max jobs: %d\n", max_jobs); @@ -1328,6 +1355,7 @@ static int parse_cmd_line(int argc, char *argv[]) break; } is_backend = 1; + backend = 1; break; case 'D': daemonize_server = 1; @@ -1343,6 +1371,7 @@ static int parse_cmd_line(int argc, char *argv[]) break; } fio_client_add(optarg); + cur_client = optarg; break; default: do_exit++; @@ -1362,7 +1391,7 @@ static int parse_cmd_line(int argc, char *argv[]) return -1; } - if (is_backend) + if (is_backend && backend) return fio_start_server(daemonize_server); if (td) { diff --git a/options.c b/options.c index 5252477b..19140375 100644 --- a/options.c +++ b/options.c @@ -829,9 +829,6 @@ static int kb_base_verify(struct fio_option *o, void *data) return 0; } -#define __stringify_1(x) #x -#define __stringify(x) __stringify_1(x) - /* * Map of job/command line options */ @@ -1946,7 +1943,7 @@ static struct fio_option options[FIO_MAX_OPTS] = { .type = FIO_OPT_INT, .off1 = td_var_offset(hugepage_size), .help = "When using hugepages, specify size of each page", - .def = __stringify(FIO_HUGE_PAGE), + .def = __fio_stringify(FIO_HUGE_PAGE), }, { .name = "group_reporting", diff --git a/server.c b/server.c index a8b8258b..d9aff01c 100644 --- a/server.c +++ b/server.c @@ -280,7 +280,33 @@ static int handle_job_cmd(struct fio_net_cmd *cmd) char *buf = (char *) cmd->payload; int ret; - parse_jobs_ini(buf, 1, 0); + if (parse_jobs_ini(buf, 1, 0)) + return -1; + + fio_net_send_simple_cmd(server_fd, FIO_NET_CMD_START, 0); + + ret = exec_run(); + send_quit_command(); + reset_fio_state(); + return ret; +} + +static int handle_jobline_cmd(struct fio_net_cmd *cmd) +{ + struct cmd_line_pdu *pdu = (struct cmd_line_pdu *) cmd->payload; + char *argv[FIO_NET_CMD_JOBLINE_ARGV]; + int ret, i; + + pdu->argc = le16_to_cpu(pdu->argc); + + for (i = 0; i < pdu->argc; i++) + argv[i] = (char *) pdu->argv[i]; + + if (parse_cmd_line(pdu->argc, argv)) + return -1; + + fio_net_send_simple_cmd(server_fd, FIO_NET_CMD_START, 0); + ret = exec_run(); send_quit_command(); reset_fio_state(); @@ -293,9 +319,9 @@ static int handle_probe_cmd(struct fio_net_cmd *cmd) memset(&probe, 0, sizeof(probe)); gethostname((char *) probe.hostname, sizeof(probe.hostname)); - probe.fio_major = 1; - probe.fio_minor = 58; - probe.fio_patch = 0; + probe.fio_major = FIO_MAJOR; + probe.fio_minor = FIO_MINOR; + probe.fio_patch = FIO_PATCH; return fio_net_send_cmd(server_fd, FIO_NET_CMD_PROBE, &probe, sizeof(probe)); } @@ -316,6 +342,9 @@ static int handle_command(struct fio_net_cmd *cmd) case FIO_NET_CMD_JOB: ret = handle_job_cmd(cmd); break; + case FIO_NET_CMD_JOBLINE: + ret = handle_jobline_cmd(cmd); + break; case FIO_NET_CMD_PROBE: ret = handle_probe_cmd(cmd); break; @@ -412,58 +441,6 @@ out: return exitval; } -static int fio_server(void) -{ - struct sockaddr_in saddr_in; - struct sockaddr addr; - unsigned int len; - int sk, opt, ret; - - dprint(FD_NET, "starting server\n"); - - sk = socket(AF_INET, SOCK_STREAM, 0); - if (sk < 0) { - log_err("fio: socket: %s\n", strerror(errno)); - return -1; - } - - opt = 1; - if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { - log_err("fio: setsockopt: %s\n", strerror(errno)); - return -1; - } -#ifdef SO_REUSEPORT - if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)) < 0) { - log_err("fio: setsockopt: %s\n", strerror(errno)); - return -1; - } -#endif - - saddr_in.sin_family = AF_INET; - saddr_in.sin_addr.s_addr = htonl(INADDR_ANY); - saddr_in.sin_port = htons(fio_net_port); - - if (bind(sk, (struct sockaddr *) &saddr_in, sizeof(saddr_in)) < 0) { - log_err("fio: bind: %s\n", strerror(errno)); - return -1; - } - - if (listen(sk, 1) < 0) { - log_err("fio: listen: %s\n", strerror(errno)); - return -1; - } - - len = sizeof(addr); - if (getsockname(sk, &addr, &len) < 0) { - log_err("fio: getsockname: %s\n", strerror(errno)); - return -1; - } - - ret = accept_loop(sk); - close(sk); - return ret; -} - int fio_server_text_output(const char *buf, unsigned int len) { if (server_fd != -1) @@ -632,6 +609,58 @@ int fio_server_log(const char *format, ...) return fio_server_text_output(buffer, len); } +static int fio_server(void) +{ + struct sockaddr_in saddr_in; + struct sockaddr addr; + unsigned int len; + int sk, opt, ret; + + dprint(FD_NET, "starting server\n"); + + sk = socket(AF_INET, SOCK_STREAM, 0); + if (sk < 0) { + log_err("fio: socket: %s\n", strerror(errno)); + return -1; + } + + opt = 1; + if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { + log_err("fio: setsockopt: %s\n", strerror(errno)); + return -1; + } +#ifdef SO_REUSEPORT + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)) < 0) { + log_err("fio: setsockopt: %s\n", strerror(errno)); + return -1; + } +#endif + + saddr_in.sin_family = AF_INET; + saddr_in.sin_addr.s_addr = htonl(INADDR_ANY); + saddr_in.sin_port = htons(fio_net_port); + + if (bind(sk, (struct sockaddr *) &saddr_in, sizeof(saddr_in)) < 0) { + log_err("fio: bind: %s\n", strerror(errno)); + return -1; + } + + if (listen(sk, 1) < 0) { + log_err("fio: listen: %s\n", strerror(errno)); + return -1; + } + + len = sizeof(addr); + if (getsockname(sk, &addr, &len) < 0) { + log_err("fio: getsockname: %s\n", strerror(errno)); + return -1; + } + + ret = accept_loop(sk); + close(sk); + return ret; +} + int fio_start_server(int daemonize) { pid_t pid; diff --git a/server.h b/server.h index 494c326e..98262af8 100644 --- a/server.h +++ b/server.h @@ -34,17 +34,22 @@ enum { FIO_NET_CMD_QUIT = 1, FIO_NET_CMD_EXIT = 2, FIO_NET_CMD_JOB = 3, - FIO_NET_CMD_TEXT = 4, - FIO_NET_CMD_TS = 5, - FIO_NET_CMD_GS = 6, - FIO_NET_CMD_ETA = 7, - FIO_NET_CMD_PROBE = 8, + FIO_NET_CMD_JOBLINE = 4, + FIO_NET_CMD_TEXT = 5, + FIO_NET_CMD_TS = 6, + FIO_NET_CMD_GS = 7, + FIO_NET_CMD_ETA = 8, + FIO_NET_CMD_PROBE = 9, + FIO_NET_CMD_START = 10, + FIO_NET_CMD_STOP = 11, FIO_NET_CMD_F_MORE = 1UL << 0, /* crc does not include the crc fields */ FIO_NET_CMD_CRC_SZ = sizeof(struct fio_net_cmd) - 2 * sizeof(uint16_t), + + FIO_NET_CMD_JOBLINE_ARGV = 128, }; struct cmd_ts_pdu { @@ -59,6 +64,11 @@ struct cmd_probe_pdu { uint8_t fio_patch; }; +struct cmd_line_pdu { + uint16_t argc; + uint8_t argv[FIO_NET_CMD_JOBLINE_ARGV][64]; +}; + extern int fio_start_server(int); extern int fio_server_text_output(const char *, unsigned int len); extern int fio_server_log(const char *format, ...); @@ -76,6 +86,7 @@ extern int fio_clients_connect(void); extern int fio_clients_send_ini(const char *); extern int fio_handle_clients(void); extern void fio_client_add(const char *); +extern void fio_client_add_cmd_option(const char *, const char *); extern int fio_recv_data(int sk, void *p, unsigned int len); extern int fio_send_data(int sk, const void *p, unsigned int len); -- 2.25.1