From: Jens Axboe Date: Fri, 7 Oct 2011 08:00:51 +0000 (+0200) Subject: Unify client/server argument X-Git-Tag: fio-1.99.2~6 X-Git-Url: https://git.kernel.dk/?a=commitdiff_plain;h=bebe639808147d587bbe776566d390b9ff98773f;p=fio.git Unify client/server argument Add documentation as well for client/server. Get rid of name hash for clients, just pass a cookie back and forth. Signed-off-by: Jens Axboe --- diff --git a/README b/README index 0eac41fe..26b59099 100644 --- a/README +++ b/README @@ -133,23 +133,25 @@ $ fio --debug Enable some debugging options (see below) --output Write output to file --timeout Runtime in seconds - --latency-log Generate per-job latency logs - --bandwidth-log Generate per-job bandwidth logs + --latency-log Generate per-job latency logs + --bandwidth-log Generate per-job bandwidth logs --minimal Minimal (terse) output --version Print version info and exit --terse-version=type Terse version output format --help Print this page - --cmdhelp=cmd Print command help, "all" for all of them + --cmdhelp=cmd Print command help, "all" for all of them --showcmd Turn a job file into command line options --readonly Turn on safety read-only checks, preventing - writes + writes --eta=when When ETA estimate should be printed - May be "always", "never" or "auto" - --section=name Only run specified section in job file. Multiple - sections can be specified. + May be "always", "never" or "auto" + --section=name Only run specified section in job file. + Multiple sections can be specified. --alloc-size=kb Set smalloc pool to this size in kb (def 1024) --warnings-fatal Fio parser warnings are fatal --max-jobs Maximum number of threads/processes to support + --server=args Start backend server. See Client/Server section. + --client=host Connect to specified backend. Any parameters following the options will be assumed to be job files, @@ -315,6 +317,59 @@ The job file parameters are: +Client/server +------------ + +Normally you would run fio as a stand-alone application on the machine +where the IO workload should be generated. However, it is also possible to +run the frontend and backend of fio separately. This makes it possible to +have a fio server running on the machine(s) where the IO workload should +be running, while controlling it from another machine. + +To start the server, you would do: + +fio --server=args + +on that machine, where args defines what fio listens to. The arguments +are of the form 'type:hostname or IP:port'. 'type' is either 'ip' for +TCP/IP, or 'sock' for a local unix domain socket. 'hostname' is either +a hostname or IP address, and 'port' is the port to listen to (only valid +for TCP/IP, not a local socket). Some examples: + +1) fio --server + + Start a fio server, listening on all interfaces on the default port (8765). + +2) fio --server=ip:hostname:4444 + + Start a fio server, listening on IP belonging to hostname and on port 4444. + +3) fio --server=:4444 + + Start a fio server, listening on all interfaces on port 4444. + +4) fio --server=1.2.3.4 + + Start a fio server, listening on IP 1.2.3.4 on the default port. + +5) fio --server=sock:/tmp/fio.sock + + Start a fio server, listening on the local socket /tmp/fio.sock. + +When a server is running, you can connect to it from a client. The client +is run with: + +fio --local-args --client=server --remote-args + +where --local-args are arguments that are local to the client where it is +running, 'server' is the connect string, and --remote-args and +are sent to the server. The 'server' string follows the same format as it +does on the server side, to allow IP/hostname/socket and port strings. +You can connect to multiple clients as well, to do that you could run: + +fio --client=server2 --client=server2 + + Platforms --------- diff --git a/client.c b/client.c index 10d41e5b..ef23c3e9 100644 --- a/client.c +++ b/client.c @@ -22,11 +22,11 @@ struct fio_client { struct flist_head list; - struct flist_head fd_hash_list; - struct flist_head name_hash_list; + struct flist_head hash_list; struct sockaddr_in addr; struct sockaddr_un addr_un; char *hostname; + int port; int fd; int state; @@ -50,47 +50,30 @@ static FLIST_HEAD(client_list); #define FIO_CLIENT_HASH_BITS 7 #define FIO_CLIENT_HASH_SZ (1 << FIO_CLIENT_HASH_BITS) #define FIO_CLIENT_HASH_MASK (FIO_CLIENT_HASH_SZ - 1) -static struct flist_head client_fd_hash[FIO_CLIENT_HASH_SZ]; -static struct flist_head client_name_hash[FIO_CLIENT_HASH_SZ]; +static struct flist_head client_hash[FIO_CLIENT_HASH_SZ]; static int handle_client(struct fio_client *client); -static void fio_client_add_fd_hash(struct fio_client *client) +static void fio_client_add_hash(struct fio_client *client) { int bucket = hash_long(client->fd, FIO_CLIENT_HASH_BITS); bucket &= FIO_CLIENT_HASH_MASK; - flist_add(&client->fd_hash_list, &client_fd_hash[bucket]); + flist_add(&client->hash_list, &client_hash[bucket]); } -static void fio_client_remove_fd_hash(struct fio_client *client) +static void fio_client_remove_hash(struct fio_client *client) { - if (!flist_empty(&client->fd_hash_list)) - flist_del_init(&client->fd_hash_list); -} - -static void fio_client_add_name_hash(struct fio_client *client) -{ - int bucket = jhash(client->hostname, strlen(client->hostname), 0); - - bucket &= FIO_CLIENT_HASH_MASK; - flist_add(&client->name_hash_list, &client_name_hash[bucket]); -} - -static void fio_client_remove_name_hash(struct fio_client *client) -{ - if (!flist_empty(&client->name_hash_list)) - flist_del_init(&client->name_hash_list); + if (!flist_empty(&client->hash_list)) + flist_del_init(&client->hash_list); } static void fio_init fio_client_hash_init(void) { int i; - for (i = 0; i < FIO_CLIENT_HASH_SZ; i++) { - INIT_FLIST_HEAD(&client_fd_hash[i]); - INIT_FLIST_HEAD(&client_name_hash[i]); - } + for (i = 0; i < FIO_CLIENT_HASH_SZ; i++) + INIT_FLIST_HEAD(&client_hash[i]); } static struct fio_client *find_client_by_fd(int fd) @@ -99,8 +82,8 @@ static struct fio_client *find_client_by_fd(int fd) struct fio_client *client; struct flist_head *entry; - flist_for_each(entry, &client_fd_hash[bucket]) { - client = flist_entry(entry, struct fio_client, fd_hash_list); + flist_for_each(entry, &client_hash[bucket]) { + client = flist_entry(entry, struct fio_client, hash_list); if (client->fd == fd) return client; @@ -109,29 +92,12 @@ static struct fio_client *find_client_by_fd(int fd) return NULL; } -static struct fio_client *find_client_by_name(const char *name) -{ - int bucket = jhash(name, strlen(name), 0) & FIO_CLIENT_HASH_BITS; - struct fio_client *client; - struct flist_head *entry; - - flist_for_each(entry, &client_name_hash[bucket]) { - client = flist_entry(entry, struct fio_client, name_hash_list); - - if (!strcmp(name, client->hostname)) - return client; - } - - return NULL; -} - static void remove_client(struct fio_client *client) { dprint(FD_NET, "client: removed <%s>\n", client->hostname); flist_del(&client->list); - fio_client_remove_fd_hash(client); - fio_client_remove_name_hash(client); + fio_client_remove_hash(client); free(client->hostname); if (client->argv) @@ -159,48 +125,42 @@ static int __fio_client_add_cmd_option(struct fio_client *client, return 0; } -int fio_client_add_cmd_option(const char *hostname, const char *opt) +int fio_client_add_cmd_option(void *cookie, const char *opt) { - struct fio_client *client; + struct fio_client *client = cookie; - if (!hostname || !opt) + if (!client || !opt) return 0; - client = find_client_by_name(hostname); - if (!client) { - log_err("fio: unknown client %s\n", hostname); - return 1; - } - return __fio_client_add_cmd_option(client, opt); } -void fio_client_add(const char *hostname) +int fio_client_add(const char *hostname, void **cookie) { struct fio_client *client; - dprint(FD_NET, "client: added <%s>\n", hostname); client = malloc(sizeof(*client)); memset(client, 0, sizeof(*client)); INIT_FLIST_HEAD(&client->list); - INIT_FLIST_HEAD(&client->fd_hash_list); - INIT_FLIST_HEAD(&client->name_hash_list); + INIT_FLIST_HEAD(&client->hash_list); + + if (fio_server_parse_string(hostname, &client->hostname, + &client->is_sock, &client->port, + &client->addr.sin_addr)) + return -1; - if (!strncmp(hostname, "sock:", 5)) { - client->hostname = strdup(hostname + 5); - client->is_sock = 1; - } else - client->hostname = strdup(hostname); + printf("%s %d %d\n", client->hostname, client->is_sock, client->port); client->fd = -1; - fio_client_add_name_hash(client); - __fio_client_add_cmd_option(client, "fio"); flist_add(&client->list, &client_list); nr_clients++; + dprint(FD_NET, "client: added <%s>\n", client->hostname); + *cookie = client; + return 0; } static int fio_client_connect_ip(struct fio_client *client) @@ -208,21 +168,7 @@ static int fio_client_connect_ip(struct fio_client *client) int fd; client->addr.sin_family = AF_INET; - client->addr.sin_port = htons(fio_net_port); - - if (inet_aton(client->hostname, &client->addr.sin_addr) != 1) { - struct hostent *hent; - - hent = gethostbyname(client->hostname); - if (!hent) { - log_err("fio: gethostbyname: %s\n", strerror(errno)); - log_err("fio: failed looking up hostname %s\n", - client->hostname); - return -1; - } - - memcpy(&client->addr.sin_addr, hent->h_addr, 4); - } + client->addr.sin_port = htons(client->port); fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { @@ -283,7 +229,7 @@ static int fio_client_connect(struct fio_client *client) return 1; client->fd = fd; - fio_client_add_fd_hash(client); + fio_client_add_hash(client); client->state = Client_connected; return 0; } @@ -304,7 +250,7 @@ void fio_clients_terminate(void) static void sig_int(int sig) { - dprint(FD_NET, "client: got sign %d\n", sig); + dprint(FD_NET, "client: got signal %d\n", sig); fio_clients_terminate(); } diff --git a/init.c b/init.c index 486b7435..849bcf9f 100644 --- a/init.c +++ b/init.c @@ -195,11 +195,6 @@ static struct option l_opts[FIO_NR_OPTIONS] = { .has_arg = no_argument, .val = 'D', }, - { - .name = (char *) "net-port", - .has_arg = required_argument, - .val = 'P', - }, { .name = (char *) "client", .has_arg = required_argument, @@ -1123,9 +1118,8 @@ static void usage(const char *name) " (def 1024)\n"); printf("\t--warnings-fatal Fio parser warnings are fatal\n"); printf("\t--max-jobs\tMaximum number of threads/processes to support\n"); - printf("\t--server\tStart a backend fio server\n"); + printf("\t--server=args\tStart a backend fio server\n"); printf("\t--client=hostname Talk to remove backend fio server at hostname\n"); - printf("\t--net-port=port\tUse specified port for client/server connection\n"); printf("\nFio was written by Jens Axboe "); printf("\n Jens Axboe \n"); } @@ -1247,7 +1241,7 @@ static int client_flag_set(char c) return 0; } -int parse_cmd_client(char *client, char *opt) +int parse_cmd_client(void *client, char *opt) { return fio_client_add_cmd_option(client, opt); } @@ -1258,7 +1252,7 @@ int parse_cmd_line(int argc, char *argv[]) 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; + void *cur_client; int backend = 0; /* @@ -1411,16 +1405,13 @@ int parse_cmd_line(int argc, char *argv[]) break; } if (optarg) - fio_server_add_arg(optarg); + fio_server_set_arg(optarg); is_backend = 1; backend = 1; break; case 'D': daemonize_server = 1; break; - case 'P': - fio_net_port = atoi(optarg); - break; case 'C': if (is_backend) { log_err("fio: can't be both client and server\n"); @@ -1428,8 +1419,12 @@ int parse_cmd_line(int argc, char *argv[]) exit_val = 1; break; } - fio_client_add(optarg); - cur_client = optarg; + if (fio_client_add(optarg, &cur_client)) { + log_err("fio: failed adding client %s\n", optarg); + do_exit++; + exit_val = 1; + break; + } break; default: do_exit++; diff --git a/server.c b/server.c index 553eb82c..524c8146 100644 --- a/server.c +++ b/server.c @@ -666,7 +666,6 @@ static int fio_init_server_ip(void) #endif saddr_in.sin_family = AF_INET; - 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)); @@ -711,6 +710,7 @@ static int fio_init_server_sock(void) static int fio_init_server_connection(void) { + char bind_str[128]; int sk; dprint(FD_NET, "starting server\n"); @@ -723,6 +723,13 @@ 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 + strcpy(bind_str, bind_sock); + + log_info("fio: server listening on %s\n", bind_str); + if (listen(sk, 1) < 0) { log_err("fio: listen: %s\n", strerror(errno)); return -1; @@ -731,6 +738,81 @@ static int fio_init_server_connection(void) return sk; } +int fio_server_parse_string(const char *str, char **ptr, int *is_sock, + int *port, struct in_addr *inp) +{ + *ptr = NULL; + *is_sock = 0; + *port = 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); + 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; + + *ptr = strdup(host); + + if (inet_aton(host, inp) != 1) { + struct hostent *hent; + + hent = gethostbyname(host); + if (!hent) { + printf("FAIL\n"); + free(*ptr); + *ptr = NULL; + return 1; + } + + memcpy(inp, hent->h_addr, 4); + } + } + + if (*port == 0) + *port = fio_net_port; + + return 0; +} + /* * Server arg should be one of: * @@ -745,28 +827,16 @@ static int fio_init_server_connection(void) */ static int fio_handle_server_arg(void) { + int unused; + saddr_in.sin_addr.s_addr = htonl(INADDR_ANY); + saddr_in.sin_port = htons(fio_net_port); if (!fio_server_arg) return 0; - if (!strncmp(fio_server_arg, "sock:", 5)) { - bind_sock = fio_server_arg + 5; - return 0; - } else { - char *host = fio_server_arg; - - if (!strncmp(host, "ip:", 3)) - host += 3; - if (inet_aton(host, &saddr_in.sin_addr) != 1) { - struct hostent *hent; - - hent = gethostbyname(host); - if (hent) - memcpy(&saddr_in.sin_addr, hent->h_addr, 4); - } - return 0; - } + return fio_server_parse_string(fio_server_arg, &bind_sock, &unused, + &fio_net_port, &saddr_in.sin_addr); } static int fio_server(void) @@ -790,6 +860,8 @@ static int fio_server(void) free(fio_server_arg); fio_server_arg = NULL; } + if (bind_sock) + free(bind_sock); return ret; } @@ -842,7 +914,7 @@ int fio_start_server(int daemonize) return fio_server(); } -void fio_server_add_arg(const char *arg) +void fio_server_set_arg(const char *arg) { fio_server_arg = strdup(arg); } diff --git a/server.h b/server.h index 0e35fde1..6a6ac338 100644 --- a/server.h +++ b/server.h @@ -76,7 +76,8 @@ extern int fio_server_text_output(const char *, unsigned int len); extern int fio_server_log(const char *format, ...); extern int fio_net_send_cmd(int, uint16_t, const void *, off_t); extern int fio_net_send_simple_cmd(int sk, uint16_t opcode, uint64_t serial); -extern void fio_server_add_arg(const char *); +extern void fio_server_set_arg(const char *); +extern int fio_server_parse_string(const char *, char **, int *, int *, struct in_addr *); struct thread_stat; struct group_run_stats; @@ -88,8 +89,8 @@ extern void fio_server_idle_loop(void); 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 int fio_client_add_cmd_option(const char *, const char *); +extern int fio_client_add(const char *, void **); +extern int fio_client_add_cmd_option(void *, 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);