+
+ icmd = NULL;
+ }
+
+ if (!icmd) {
+ log_err("fio: client: unable to find matching tag\n");
+ return;
+ }
+
+ flist_del(&icmd->list);
+ cmd->tag = icmd->saved_tag;
+ free(icmd);
+}
+
+static void handle_eta(struct fio_client *client, struct fio_net_cmd *cmd)
+{
+ struct jobs_eta *je = (struct jobs_eta *) cmd->payload;
+ struct client_eta *eta = (struct client_eta *) (uintptr_t) cmd->tag;
+
+ dprint(FD_NET, "client: got eta tag %p, %d\n", eta, eta->pending);
+
+ assert(client->eta_in_flight == eta);
+
+ client->eta_in_flight = NULL;
+ flist_del_init(&client->eta_list);
+
+ if (client->ops->jobs_eta)
+ client->ops->jobs_eta(client, je);
+
+ fio_client_sum_jobs_eta(&eta->eta, je);
+ fio_client_dec_jobs_eta(eta, client->ops->eta);
+}
+
+static void handle_probe(struct fio_client *client, struct fio_net_cmd *cmd)
+{
+ struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
+ const char *os, *arch;
+ char bit[16];
+
+ os = fio_get_os_string(probe->os);
+ if (!os)
+ os = "unknown";
+
+ arch = fio_get_arch_string(probe->arch);
+ if (!arch)
+ os = "unknown";
+
+ sprintf(bit, "%d-bit", probe->bpp * 8);
+
+ log_info("hostname=%s, be=%u, %s, os=%s, arch=%s, fio=%u.%u.%u\n",
+ probe->hostname, probe->bigendian, bit, os, arch,
+ probe->fio_major, probe->fio_minor, probe->fio_patch);
+
+ if (!client->name)
+ client->name = strdup((char *) probe->hostname);
+}
+
+static void handle_start(struct fio_client *client, struct fio_net_cmd *cmd)
+{
+ struct cmd_start_pdu *pdu = (struct cmd_start_pdu *) cmd->payload;
+
+ client->state = Client_started;
+ client->jobs = le32_to_cpu(pdu->jobs);
+}
+
+static void handle_stop(struct fio_client *client, struct fio_net_cmd *cmd)
+{
+ if (client->error)
+ log_info("client <%s>: exited with error %d\n", client->hostname, client->error);
+}
+
+static void convert_stop(struct fio_net_cmd *cmd)
+{
+ struct cmd_end_pdu *pdu = (struct cmd_end_pdu *) cmd->payload;
+
+ pdu->error = le32_to_cpu(pdu->error);
+}
+
+static void convert_text(struct fio_net_cmd *cmd)
+{
+ struct cmd_text_pdu *pdu = (struct cmd_text_pdu *) cmd->payload;
+
+ pdu->level = le32_to_cpu(pdu->level);
+ pdu->buf_len = le32_to_cpu(pdu->buf_len);
+ pdu->log_sec = le64_to_cpu(pdu->log_sec);
+ pdu->log_usec = le64_to_cpu(pdu->log_usec);
+}
+
+int fio_handle_client(struct fio_client *client)
+{
+ struct client_ops *ops = client->ops;
+ struct fio_net_cmd *cmd;
+
+ dprint(FD_NET, "client: handle %s\n", client->hostname);
+
+ cmd = fio_net_recv_cmd(client->fd);
+ if (!cmd)
+ return 0;
+
+ dprint(FD_NET, "client: got cmd op %s from %s (pdu=%u)\n",
+ fio_server_op(cmd->opcode), client->hostname, cmd->pdu_len);
+
+ switch (cmd->opcode) {
+ case FIO_NET_CMD_QUIT:
+ if (ops->quit)
+ ops->quit(client);
+ remove_client(client);
+ free(cmd);
+ break;
+ case FIO_NET_CMD_TEXT:
+ convert_text(cmd);
+ ops->text_op(client, cmd);
+ free(cmd);
+ break;
+ case FIO_NET_CMD_DU: {
+ struct cmd_du_pdu *du = (struct cmd_du_pdu *) cmd->payload;
+
+ convert_dus(&du->dus);
+ convert_agg(&du->agg);
+
+ ops->disk_util(client, cmd);
+ free(cmd);
+ break;
+ }
+ case FIO_NET_CMD_TS: {
+ struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
+
+ convert_ts(&p->ts, &p->ts);
+ convert_gs(&p->rs, &p->rs);
+
+ ops->thread_status(client, cmd);
+ free(cmd);
+ break;
+ }
+ case FIO_NET_CMD_GS: {
+ struct group_run_stats *gs = (struct group_run_stats *) cmd->payload;
+
+ convert_gs(gs, gs);
+
+ ops->group_stats(client, cmd);
+ free(cmd);
+ break;