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);
return NULL;
}
-#if 0
static struct fio_client *find_client_by_name(const char *name)
{
struct fio_client *client;
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;
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++;
}
}
client->fd = fd;
+ client->state = Client_connected;
return 0;
}
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;
}
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.
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;
}
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);
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"
#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;
*/
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);
#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)
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");
f_err = f_out;
break;
case 'm':
+ fio_client_add_cmd_option(cur_client, argv[optind]);
terse_output = 1;
break;
case 'h':
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");
}
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");
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)
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);
break;
}
is_backend = 1;
+ backend = 1;
break;
case 'D':
daemonize_server = 1;
break;
}
fio_client_add(optarg);
+ cur_client = optarg;
break;
default:
do_exit++;
return -1;
}
- if (is_backend)
+ if (is_backend && backend)
return fio_start_server(daemonize_server);
if (td) {
return 0;
}
-#define __stringify_1(x) #x
-#define __stringify(x) __stringify_1(x)
-
/*
* Map of job/command line options
*/
.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",
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();
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));
}
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;
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)
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;
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 {
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, ...);
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);