+ goto err;
+ }
+
+#ifdef CONFIG_TCP_NODELAY
+ if (o->nodelay && is_tcp(o)) {
+ int optval = 1;
+
+ if (setsockopt(f->fd, IPPROTO_TCP, TCP_NODELAY, (void *) &optval, sizeof(int)) < 0) {
+ log_err("fio: cannot set TCP_NODELAY option on socket (%s), disable with 'nodelay=0'\n", strerror(errno));
+ return 1;
+ }
+ }
+#endif
+
+ reset_all_stats(td);
+ td_set_runstate(td, state);
+ return 0;
+err:
+ td_set_runstate(td, state);
+ return 1;
+}
+
+static void fio_netio_send_close(struct thread_data *td, struct fio_file *f)
+{
+ struct netio_data *nd = td->io_ops->data;
+ struct netio_options *o = td->eo;
+ struct udp_close_msg msg;
+ struct sockaddr *to;
+ socklen_t len;
+ int ret;
+
+ if (is_ipv6(o)) {
+ to = (struct sockaddr *) &nd->addr6;
+ len = sizeof(nd->addr6);
+ } else {
+ to = (struct sockaddr *) &nd->addr;
+ len = sizeof(nd->addr);
+ }
+
+ msg.magic = cpu_to_le32((uint32_t) FIO_LINK_OPEN_CLOSE_MAGIC);
+ msg.cmd = cpu_to_le32((uint32_t) FIO_LINK_CLOSE);
+
+ ret = sendto(f->fd, (void *) &msg, sizeof(msg), MSG_WAITALL, to, len);
+ if (ret < 0)
+ td_verror(td, errno, "sendto udp link close");
+}
+
+static int fio_netio_close_file(struct thread_data *td, struct fio_file *f)
+{
+ /*
+ * Notify the receiver that we are closing down the link
+ */
+ fio_netio_send_close(td, f);
+
+ return generic_close_file(td, f);
+}
+
+static int fio_netio_udp_recv_open(struct thread_data *td, struct fio_file *f)
+{
+ struct netio_data *nd = td->io_ops->data;
+ struct netio_options *o = td->eo;
+ struct udp_close_msg msg;
+ struct sockaddr *to;
+ socklen_t len;
+ int ret;
+
+ if (is_ipv6(o)) {
+ len = sizeof(nd->addr6);
+ to = (struct sockaddr *) &nd->addr6;
+ } else {
+ len = sizeof(nd->addr);
+ to = (struct sockaddr *) &nd->addr;
+ }
+
+ ret = recvfrom(f->fd, (void *) &msg, sizeof(msg), MSG_WAITALL, to, &len);
+ if (ret < 0) {
+ td_verror(td, errno, "recvfrom udp link open");
+ return ret;
+ }
+
+ if (ntohl(msg.magic) != FIO_LINK_OPEN_CLOSE_MAGIC ||
+ ntohl(msg.cmd) != FIO_LINK_OPEN) {
+ log_err("fio: bad udp open magic %x/%x\n", ntohl(msg.magic),
+ ntohl(msg.cmd));
+ return -1;
+ }
+
+ fio_gettime(&td->start, NULL);
+ return 0;
+}
+
+static int fio_netio_send_open(struct thread_data *td, struct fio_file *f)
+{
+ struct netio_data *nd = td->io_ops->data;
+ struct netio_options *o = td->eo;
+ struct udp_close_msg msg;
+ struct sockaddr *to;
+ socklen_t len;
+ int ret;
+
+ if (is_ipv6(o)) {
+ len = sizeof(nd->addr6);
+ to = (struct sockaddr *) &nd->addr6;
+ } else {
+ len = sizeof(nd->addr);
+ to = (struct sockaddr *) &nd->addr;
+ }
+
+ msg.magic = htonl(FIO_LINK_OPEN_CLOSE_MAGIC);
+ msg.cmd = htonl(FIO_LINK_OPEN);
+
+ ret = sendto(f->fd, (void *) &msg, sizeof(msg), MSG_WAITALL, to, len);
+ if (ret < 0) {
+ td_verror(td, errno, "sendto udp link open");
+ return ret;