#include "server.h"
#include "flist.h"
#include "hash.h"
+#include "verify.h"
static void handle_du(struct fio_client *client, struct fio_net_cmd *cmd);
static void handle_ts(struct fio_client *client, struct fio_net_cmd *cmd);
static struct json_array *clients_array = NULL;
static struct json_array *du_array = NULL;
+static int error_clients;
+
#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)
INIT_FLIST_HEAD(&client_hash[i]);
}
+static int read_data(int fd, void *data, size_t size)
+{
+ ssize_t ret;
+
+ while (size) {
+ ret = read(fd, data, size);
+ if (ret < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ break;
+ } else if (!ret)
+ break;
+ else {
+ data += ret;
+ size -= ret;
+ }
+ }
+
+ if (size)
+ return EAGAIN;
+
+ return 0;
+}
+
static void fio_client_json_init(void)
{
if (output_format != FIO_OUTPUT_JSON)
if (!client->did_stat)
sum_stat_clients--;
+ if (client->error)
+ error_clients++;
+
free(client);
}
return 0;
}
+static const char *server_name(struct fio_client *client, char *buf,
+ size_t bufsize)
+{
+ const char *from;
+
+ if (client->ipv6)
+ from = inet_ntop(AF_INET6, (struct sockaddr *) &client->addr6.sin6_addr, buf, bufsize);
+ else if (client->is_sock)
+ from = "sock";
+ else
+ from = inet_ntop(AF_INET, (struct sockaddr *) &client->addr.sin_addr, buf, bufsize);
+
+ return from;
+}
+
static void probe_client(struct fio_client *client)
{
struct cmd_client_probe_pdu pdu;
+ const char *sname;
uint64_t tag;
+ char buf[64];
dprint(FD_NET, "client: send probe\n");
pdu.flags = 0;
#endif
+ sname = server_name(client, buf, sizeof(buf));
+ memset(pdu.server, 0, sizeof(pdu.server));
+ strncpy((char *) pdu.server, sname, sizeof(pdu.server) - 1);
+
fio_net_send_cmd(client->fd, FIO_NET_CMD_PROBE, &pdu, sizeof(pdu), &tag, &client->cmd_list);
}
fd = open(filename, O_RDONLY);
if (fd < 0) {
- int ret = -errno;
-
+ ret = -errno;
log_err("fio: job file <%s> open: %s\n", filename, strerror(errno));
return ret;
}
if (fstat(fd, &sb) < 0) {
- int ret = -errno;
-
+ ret = -errno;
log_err("fio: job file stat: %s\n", strerror(errno));
close(fd);
return ret;
len = sb.st_size;
p = buf;
- do {
- ret = read(fd, p, len);
- if (ret > 0) {
- len -= ret;
- if (!len)
- break;
- p += ret;
- continue;
- } else if (!ret)
- break;
- else if (errno == EAGAIN || errno == EINTR)
- continue;
- } while (1);
-
- if (len) {
+ if (read_data(fd, p, len)) {
log_err("fio: failed reading job file %s\n", filename);
close(fd);
free(pdu);
dst->minf = le64_to_cpu(src->minf);
dst->majf = le64_to_cpu(src->majf);
dst->clat_percentiles = le64_to_cpu(src->clat_percentiles);
+ dst->percentile_precision = le64_to_cpu(src->percentile_precision);
for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) {
fio_fp64_t *fps = &src->percentile_list[i];
dst->latency_target = le64_to_cpu(src->latency_target);
dst->latency_window = le64_to_cpu(src->latency_window);
dst->latency_percentile.u.f = fio_uint64_to_double(le64_to_cpu(src->latency_percentile.u.i));
+
+ dst->nr_block_infos = le64_to_cpu(src->nr_block_infos);
+ for (i = 0; i < dst->nr_block_infos; i++)
+ dst->block_infos[i] = le32_to_cpu(src->block_infos[i]);
}
static void convert_gs(struct group_run_stats *dst, struct group_run_stats *src)
int i;
for (i = 0; i < 2; i++) {
- agg->ios[i] = le32_to_cpu(agg->ios[i]);
- agg->merges[i] = le32_to_cpu(agg->merges[i]);
+ agg->ios[i] = le64_to_cpu(agg->ios[i]);
+ agg->merges[i] = le64_to_cpu(agg->merges[i]);
agg->sectors[i] = le64_to_cpu(agg->sectors[i]);
- agg->ticks[i] = le32_to_cpu(agg->ticks[i]);
+ agg->ticks[i] = le64_to_cpu(agg->ticks[i]);
}
- agg->io_ticks = le32_to_cpu(agg->io_ticks);
- agg->time_in_queue = le32_to_cpu(agg->time_in_queue);
+ agg->io_ticks = le64_to_cpu(agg->io_ticks);
+ agg->time_in_queue = le64_to_cpu(agg->time_in_queue);
agg->slavecount = le32_to_cpu(agg->slavecount);
agg->max_util.u.f = fio_uint64_to_double(le64_to_cpu(agg->max_util.u.i));
}
int i;
for (i = 0; i < 2; i++) {
- dus->s.ios[i] = le32_to_cpu(dus->s.ios[i]);
- dus->s.merges[i] = le32_to_cpu(dus->s.merges[i]);
+ dus->s.ios[i] = le64_to_cpu(dus->s.ios[i]);
+ dus->s.merges[i] = le64_to_cpu(dus->s.merges[i]);
dus->s.sectors[i] = le64_to_cpu(dus->s.sectors[i]);
- dus->s.ticks[i] = le32_to_cpu(dus->s.ticks[i]);
+ dus->s.ticks[i] = le64_to_cpu(dus->s.ticks[i]);
}
- dus->s.io_ticks = le32_to_cpu(dus->s.io_ticks);
- dus->s.time_in_queue = le32_to_cpu(dus->s.time_in_queue);
+ dus->s.io_ticks = le64_to_cpu(dus->s.io_ticks);
+ dus->s.time_in_queue = le64_to_cpu(dus->s.time_in_queue);
dus->s.msec = le64_to_cpu(dus->s.msec);
}
return ret;
}
+static void sendfile_reply(int fd, struct cmd_sendfile_reply *rep,
+ size_t size, uint64_t tag)
+{
+ rep->error = cpu_to_le32(rep->error);
+ fio_net_send_cmd(fd, FIO_NET_CMD_SENDFILE, rep, size, &tag, NULL);
+}
+
+static int send_file(struct fio_client *client, struct cmd_sendfile *pdu,
+ uint64_t tag)
+{
+ struct cmd_sendfile_reply *rep;
+ struct stat sb;
+ size_t size;
+ int fd;
+
+ size = sizeof(*rep);
+ rep = malloc(size);
+
+ if (stat((char *)pdu->path, &sb) < 0) {
+fail:
+ rep->error = errno;
+ sendfile_reply(client->fd, rep, size, tag);
+ free(rep);
+ return 1;
+ }
+
+ size += sb.st_size;
+ rep = realloc(rep, size);
+ rep->size = cpu_to_le32((uint32_t) sb.st_size);
+
+ fd = open((char *)pdu->path, O_RDONLY);
+ if (fd == -1 )
+ goto fail;
+
+ rep->error = read_data(fd, &rep->data, sb.st_size);
+ sendfile_reply(client->fd, rep, size, tag);
+ free(rep);
+ close(fd);
+ return 0;
+}
+
int fio_handle_client(struct fio_client *client)
{
struct client_ops *ops = client->ops;
if (ops->quit)
ops->quit(client, cmd);
remove_client(client);
- free(cmd);
break;
case FIO_NET_CMD_TEXT:
convert_text(cmd);
ops->text(client, cmd);
- free(cmd);
break;
case FIO_NET_CMD_DU: {
struct cmd_du_pdu *du = (struct cmd_du_pdu *) cmd->payload;
convert_agg(&du->agg);
ops->disk_util(client, cmd);
- free(cmd);
break;
}
case FIO_NET_CMD_TS: {
convert_gs(&p->rs, &p->rs);
ops->thread_status(client, cmd);
- free(cmd);
break;
}
case FIO_NET_CMD_GS: {
convert_gs(gs, gs);
ops->group_stats(client, cmd);
- free(cmd);
break;
}
case FIO_NET_CMD_ETA: {
remove_reply_cmd(client, cmd);
convert_jobs_eta(je);
handle_eta(client, cmd);
- free(cmd);
break;
}
case FIO_NET_CMD_PROBE:
remove_reply_cmd(client, cmd);
ops->probe(client, cmd);
- free(cmd);
break;
case FIO_NET_CMD_SERVER_START:
client->state = Client_running;
if (ops->job_start)
ops->job_start(client, cmd);
- free(cmd);
break;
case FIO_NET_CMD_START: {
struct cmd_start_pdu *pdu = (struct cmd_start_pdu *) cmd->payload;
pdu->jobs = le32_to_cpu(pdu->jobs);
ops->start(client, cmd);
- free(cmd);
break;
}
case FIO_NET_CMD_STOP: {
client->error = le32_to_cpu(pdu->error);
client->signal = le32_to_cpu(pdu->signal);
ops->stop(client, cmd);
- free(cmd);
break;
}
case FIO_NET_CMD_ADD_JOB: {
if (ops->add_job)
ops->add_job(client, cmd);
- free(cmd);
break;
}
case FIO_NET_CMD_IOLOG:
pdu = convert_iolog(cmd);
ops->iolog(client, pdu);
}
- free(cmd);
break;
case FIO_NET_CMD_UPDATE_JOB:
ops->update_job(client, cmd);
remove_reply_cmd(client, cmd);
- free(cmd);
break;
+ case FIO_NET_CMD_VTRIGGER: {
+ struct all_io_list *pdu = (struct all_io_list *) cmd->payload;
+ char buf[64];
+
+ __verify_save_state(pdu, server_name(client, buf, sizeof(buf)));
+ exec_trigger(trigger_cmd);
+ break;
+ }
+ case FIO_NET_CMD_SENDFILE: {
+ struct cmd_sendfile *pdu = (struct cmd_sendfile *) cmd->payload;
+ send_file(client, pdu, cmd->tag);
+ break;
+ }
default:
log_err("fio: unknown client op: %s\n", fio_server_op(cmd->opcode));
- free(cmd);
break;
}
+ free(cmd);
return 1;
}
+int fio_clients_send_trigger(const char *cmd)
+{
+ struct flist_head *entry;
+ struct fio_client *client;
+ size_t slen;
+
+ dprint(FD_NET, "client: send vtrigger: %s\n", cmd);
+
+ if (!cmd)
+ slen = 0;
+ else
+ slen = strlen(cmd);
+
+ flist_for_each(entry, &client_list) {
+ struct cmd_vtrigger_pdu *pdu;
+
+ client = flist_entry(entry, struct fio_client, list);
+
+ pdu = malloc(sizeof(*pdu) + slen);
+ pdu->len = cpu_to_le16((uint16_t) slen);
+ if (slen)
+ memcpy(pdu->cmd, cmd, slen);
+ fio_net_send_cmd(client->fd, FIO_NET_CMD_VTRIGGER, pdu,
+ sizeof(*pdu) + slen, NULL, NULL);
+ free(pdu);
+ }
+
+ return 0;
+}
+
static void request_client_etas(struct client_ops *ops)
{
struct fio_client *client;
else
log_err("fio: client %s timed out\n", client->hostname);
+ client->error = ETIMEDOUT;
remove_client(client);
ret = 1;
}
do {
struct timeval tv;
+ int timeout;
fio_gettime(&tv, NULL);
if (mtime_since(&eta_tv, &tv) >= 900) {
break;
}
- ret = poll(pfds, nr_clients, ops->eta_msec);
+ check_trigger_file();
+
+ timeout = min(100u, ops->eta_msec);
+
+ ret = poll(pfds, nr_clients, timeout);
if (ret < 0) {
if (errno == EINTR)
continue;
fio_client_json_fini();
free(pfds);
- return retval;
+ return retval || error_clients;
}