+ while (!flist_empty(&log->io_logs)) {
+ struct io_logs *cur_log;
+ size_t size;
+
+ cur_log = flist_first_entry(&log->io_logs, struct io_logs, list);
+ flist_del_init(&cur_log->list);
+
+ size = cur_log->nr_samples * log_entry_sz(log);
+
+ entry = fio_net_prep_cmd(FIO_NET_CMD_IOLOG, cur_log->log, size,
+ NULL, SK_F_VEC | SK_F_INLINE);
+ if (!entry) {
+ ret = 1;
+ break;
+ }
+ flist_add_tail(&entry->list, &first->next);
+ }
+
+ return ret;
+}
+
+int fio_send_iolog(struct thread_data *td, struct io_log *log, const char *name)
+{
+ struct cmd_iolog_pdu pdu = {
+ .nr_samples = cpu_to_le64(iolog_nr_samples(log)),
+ .thread_number = cpu_to_le32(td->thread_number),
+ .log_type = cpu_to_le32(log->log_type),
+ .log_hist_coarseness = cpu_to_le32(log->hist_coarseness),
+ };
+ struct sk_entry *first;
+ struct flist_head *entry;
+ int ret = 0;
+
+ if (!flist_empty(&log->chunk_list))
+ pdu.compressed = __cpu_to_le32(STORE_COMPRESSED);
+ else if (use_zlib)
+ pdu.compressed = __cpu_to_le32(XMIT_COMPRESSED);
+ else
+ pdu.compressed = 0;
+
+ strncpy((char *) pdu.name, name, FIO_NET_NAME_MAX);
+ pdu.name[FIO_NET_NAME_MAX - 1] = '\0';
+
+ /*
+ * We can't do this for a pre-compressed log, but for that case,
+ * log->nr_samples is zero anyway.
+ */
+ flist_for_each(entry, &log->io_logs) {
+ struct io_logs *cur_log;
+ int i;
+
+ cur_log = flist_entry(entry, struct io_logs, list);
+
+ for (i = 0; i < cur_log->nr_samples; i++) {
+ struct io_sample *s = get_sample(log, cur_log, i);
+
+ s->time = cpu_to_le64(s->time);
+ s->data.val = cpu_to_le64(s->data.val);
+ s->__ddir = cpu_to_le32(s->__ddir);
+ s->bs = cpu_to_le64(s->bs);
+
+ if (log->log_offset) {
+ struct io_sample_offset *so = (void *) s;
+
+ so->offset = cpu_to_le64(so->offset);
+ }
+ }
+ }
+
+ /*
+ * Assemble header entry first
+ */
+ first = fio_net_prep_cmd(FIO_NET_CMD_IOLOG, &pdu, sizeof(pdu), NULL, SK_F_VEC | SK_F_INLINE | SK_F_COPY);
+ if (!first)
+ return 1;
+
+ /*
+ * Now append actual log entries. If log compression was enabled on
+ * the job, just send out the compressed chunks directly. If we
+ * have a plain log, compress if we can, then send. Otherwise, send
+ * the plain text output.
+ */
+ if (!flist_empty(&log->chunk_list))
+ ret = fio_append_gz_chunks(first, log);
+ else if (use_zlib)
+ ret = fio_append_iolog_gz(first, log);
+ else
+ ret = fio_append_text_log(first, log);
+
+ fio_net_queue_entry(first);
+ return ret;
+}
+
+void fio_server_send_add_job(struct thread_data *td)
+{
+ struct cmd_add_job_pdu pdu = {
+ .thread_number = cpu_to_le32(td->thread_number),
+ .groupid = cpu_to_le32(td->groupid),
+ };
+
+ convert_thread_options_to_net(&pdu.top, &td->o);
+
+ fio_net_queue_cmd(FIO_NET_CMD_ADD_JOB, &pdu, sizeof(pdu), NULL,
+ SK_F_COPY);
+}
+
+void fio_server_send_start(struct thread_data *td)
+{
+ struct sk_out *sk_out = pthread_getspecific(sk_out_key);
+
+ assert(sk_out->sk != -1);
+
+ fio_net_queue_cmd(FIO_NET_CMD_SERVER_START, NULL, 0, NULL, SK_F_SIMPLE);
+}
+
+int fio_server_get_verify_state(const char *name, int threadnumber,
+ void **datap)
+{
+ struct thread_io_list *s;
+ struct cmd_sendfile out;
+ struct cmd_reply *rep;
+ uint64_t tag;
+ void *data;
+ int ret;
+
+ dprint(FD_NET, "server: request verify state\n");
+
+ rep = smalloc(sizeof(*rep));
+ if (!rep)
+ return ENOMEM;
+
+ __fio_sem_init(&rep->lock, FIO_SEM_LOCKED);
+ rep->data = NULL;
+ rep->error = 0;
+
+ verify_state_gen_name((char *) out.path, sizeof(out.path), name, me,
+ threadnumber);
+ tag = (uint64_t) (uintptr_t) rep;
+ fio_net_queue_cmd(FIO_NET_CMD_SENDFILE, &out, sizeof(out), &tag,
+ SK_F_COPY);
+
+ /*
+ * Wait for the backend to receive the reply
+ */
+ if (fio_sem_down_timeout(&rep->lock, 10000)) {
+ log_err("fio: timed out waiting for reply\n");
+ ret = ETIMEDOUT;
+ goto fail;
+ }
+
+ if (rep->error) {
+ log_err("fio: failure on receiving state file %s: %s\n",
+ out.path, strerror(rep->error));
+ ret = rep->error;
+fail:
+ *datap = NULL;
+ sfree(rep);
+ fio_net_queue_quit();
+ return ret;
+ }
+
+ /*
+ * The format is verify_state_hdr, then thread_io_list. Verify
+ * the header, and the thread_io_list checksum
+ */
+ s = rep->data + sizeof(struct verify_state_hdr);
+ if (verify_state_hdr(rep->data, s)) {
+ ret = EILSEQ;
+ goto fail;
+ }