12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <stdio.h> 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <stdlib.h> 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <stdarg.h> 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <unistd.h> 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <limits.h> 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <errno.h> 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/poll.h> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/types.h> 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/wait.h> 10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <sys/socket.h> 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <sys/stat.h> 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/un.h> 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/uio.h> 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <netinet/in.h> 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <arpa/inet.h> 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <netdb.h> 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <syslog.h> 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <signal.h> 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#ifdef CONFIG_ZLIB 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <zlib.h> 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "fio.h" 2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "server.h" 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "crc/crc16.h" 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "lib/ieee754.h" 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint fio_net_port = FIO_NET_PORT; 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint exit_backend = 0; 31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int server_fd = -1; 33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic char *fio_server_arg; 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static char *bind_sock; 35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic struct sockaddr_in saddr_in; 36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic struct sockaddr_in6 saddr_in6; 37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)static int use_ipv6; 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#ifdef CONFIG_ZLIB 39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic unsigned int has_zlib = 1; 40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#else 41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic unsigned int has_zlib = 0; 42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif 43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)static unsigned int use_zlib; 44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstruct fio_fork_item { 46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch struct flist_head list; 47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int exitval; 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int signal; 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int exited; 50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pid_t pid; 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)static const char *fio_server_ops[FIO_NET_CMD_NR] = { 54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) "", 55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) "QUIT", 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "EXIT", 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "JOB", 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "JOBLINE", 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "TEXT", 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "TS", 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "GS", 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "SEND_ETA", 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "ETA", 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "PROBE", 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "START", 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "STOP", 67558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch "DISK_UTIL", 68558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch "SERVER_START", 69558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch "ADD_JOB", 70558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch "CMD_RUN", 71558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch "CMD_IOLOG", 72558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}; 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 74558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochconst char *fio_server_op(unsigned int op) 75558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch{ 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static char buf[32]; 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (op < FIO_NET_CMD_NR) 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return fio_server_ops[op]; 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sprintf(buf, "UNKNOWN/%d", op); 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return buf; 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static ssize_t iov_total_len(const struct iovec *iov, int count) 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){ 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ssize_t ret = 0; 88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (count--) { 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ret += iov->iov_len; 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) iov++; 92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return ret; 95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)static int fio_sendv_data(int sk, struct iovec *iov, int count) 98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles){ 99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ssize_t total_len = iov_total_len(iov, count); 100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ssize_t ret; 101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) do { 103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ret = writev(sk, iov, count); 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (ret > 0) { 105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) total_len -= ret; 106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!total_len) 107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) break; 108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) while (ret) { 110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (ret >= iov->iov_len) { 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ret -= iov->iov_len; 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) iov++; 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) iov->iov_base += ret; 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) iov->iov_len -= ret; 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ret = 0; 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (!ret) 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) else if (errno == EAGAIN || errno == EINTR) 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) else 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } while (!exit_backend); 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!total_len) 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (errno) 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return -errno; 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 1; 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int fio_send_data(int sk, const void *p, unsigned int len) 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){ 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct iovec iov = { .iov_base = (void *) p, .iov_len = len }; 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) assert(len <= sizeof(struct fio_net_cmd) + FIO_SERVER_MAX_FRAGMENT_PDU); 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return fio_sendv_data(sk, &iov, 1); 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int fio_recv_data(int sk, void *p, unsigned int len) 146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles){ 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) do { 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int ret = recv(sk, p, len, MSG_WAITALL); 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ret > 0) { 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) len -= ret; 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!len) 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) p += ret; 155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue; 156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else if (!ret) 157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) break; 158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) else if (errno == EAGAIN || errno == EINTR) 159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue; 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) else 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } while (!exit_backend); 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!len) 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return -1; 168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static int verify_convert_cmd(struct fio_net_cmd *cmd) 171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles){ 172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) uint16_t crc; 173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cmd->cmd_crc16 = le16_to_cpu(cmd->cmd_crc16); 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cmd->pdu_crc16 = le16_to_cpu(cmd->pdu_crc16); 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) crc = fio_crc16(cmd, FIO_NET_CMD_CRC_SZ); 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (crc != cmd->cmd_crc16) { 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) log_err("fio: server bad crc on command (got %x, wanted %x)\n", 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cmd->cmd_crc16, crc); 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 1; 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cmd->version = le16_to_cpu(cmd->version); 185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch cmd->opcode = le16_to_cpu(cmd->opcode); 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cmd->flags = le32_to_cpu(cmd->flags); 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cmd->tag = le64_to_cpu(cmd->tag); 188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cmd->pdu_len = le32_to_cpu(cmd->pdu_len); 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (cmd->version) { 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case FIO_SERVER_VER: 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) log_err("fio: bad server cmd version %d\n", cmd->version); 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 1; 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (cmd->pdu_len > FIO_SERVER_MAX_FRAGMENT_PDU) { 199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) log_err("fio: command payload too large: %u\n", cmd->pdu_len); 200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return 1; 201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return 0; 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/* 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Read (and defragment, if necessary) incoming commands 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct fio_net_cmd *fio_net_recv_cmd(int sk) 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){ 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct fio_net_cmd cmd, *tmp, *cmdret = NULL; 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t cmd_size = 0, pdu_offset = 0; 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint16_t crc; 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int ret, first = 1; 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void *pdu = NULL; 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) do { 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ret = fio_recv_data(sk, &cmd, sizeof(cmd)); 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ret) 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /* We have a command, verify it and swap if need be */ 223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ret = verify_convert_cmd(&cmd); 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ret) 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (first) { 228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /* if this is text, add room for \0 at the end */ 229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch cmd_size = sizeof(cmd) + cmd.pdu_len + 1; 230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch assert(!cmdret); 231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cmd_size += cmd.pdu_len; 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (cmd_size / 1024 > FIO_SERVER_MAX_CMD_MB * 1024) { 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) log_err("fio: cmd+pdu too large (%llu)\n", (unsigned long long) cmd_size); 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ret = 1; 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) tmp = realloc(cmdret, cmd_size); 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!tmp) { 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) log_err("fio: server failed allocating cmd\n"); 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ret = 1; 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cmdret = tmp; 247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (first) 249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) memcpy(cmdret, &cmd, sizeof(cmd)); 250eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch else if (cmdret->opcode != cmd.opcode) { 251eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch log_err("fio: fragment opcode mismatch (%d != %d)\n", 252eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch cmdret->opcode, cmd.opcode); 253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ret = 1; 254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) break; 255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!cmd.pdu_len) 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /* There's payload, get it */ 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pdu = (void *) cmdret->payload + pdu_offset; 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ret = fio_recv_data(sk, pdu, cmd.pdu_len); 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ret) 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /* Verify payload crc */ 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) crc = fio_crc16(pdu, cmd.pdu_len); 268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (crc != cmd.pdu_crc16) { 269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) log_err("fio: server bad crc on payload "); 270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) log_err("(got %x, wanted %x)\n", cmd.pdu_crc16, crc); 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ret = 1; 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pdu_offset += cmd.pdu_len; 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!first) 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cmdret->pdu_len += cmd.pdu_len; 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) first = 0; 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } while (cmd.flags & FIO_NET_CMD_F_MORE); 280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (ret) { 282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) free(cmdret); 283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cmdret = NULL; 284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else if (cmdret) { 285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /* zero-terminate text input */ 286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (cmdret->pdu_len) { 287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (cmdret->opcode == FIO_NET_CMD_TEXT) { 288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) struct cmd_text_pdu *pdu = (struct cmd_text_pdu *) cmdret->payload; 289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) char *buf = (char *) pdu->buf; 290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) buf[pdu->buf_len] = '\0'; 292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else if (cmdret->opcode == FIO_NET_CMD_JOB) { 293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch struct cmd_job_pdu *pdu = (struct cmd_job_pdu *) cmdret->payload; 294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch char *buf = (char *) pdu->buf; 295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int len = le32_to_cpu(pdu->buf_len); 296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) buf[len] = '\0'; 298868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) /* frag flag is internal */ 302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch cmdret->flags &= ~FIO_NET_CMD_F_MORE; 303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return cmdret; 306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 308eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic void add_reply(uint64_t tag, struct flist_head *list) 309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{ 310eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch struct fio_net_cmd_reply *reply; 311eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 312eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch reply = (struct fio_net_cmd_reply *) (uintptr_t) tag; 313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch flist_add_tail(&reply->list, list); 314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic uint64_t alloc_reply(uint64_t tag, uint16_t opcode) 317868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles){ 318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) struct fio_net_cmd_reply *reply; 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) reply = calloc(1, sizeof(*reply)); 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) INIT_FLIST_HEAD(&reply->list); 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gettimeofday(&reply->tv, NULL); 323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) reply->saved_tag = tag; 324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) reply->opcode = opcode; 325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return (uintptr_t) reply; 327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static void free_reply(uint64_t tag) 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){ 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct fio_net_cmd_reply *reply; 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) reply = (struct fio_net_cmd_reply *) (uintptr_t) tag; 334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) free(reply); 335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void fio_net_cmd_crc_pdu(struct fio_net_cmd *cmd, const void *pdu) 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){ 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint32_t pdu_len; 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cmd->cmd_crc16 = __cpu_to_le16(fio_crc16(cmd, FIO_NET_CMD_CRC_SZ)); 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pdu_len = le32_to_cpu(cmd->pdu_len); 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cmd->pdu_crc16 = __cpu_to_le16(fio_crc16(pdu, pdu_len)); 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void fio_net_cmd_crc(struct fio_net_cmd *cmd) 348868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles){ 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fio_net_cmd_crc_pdu(cmd, cmd->payload); 350868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 351868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int fio_net_send_cmd(int fd, uint16_t opcode, const void *buf, off_t size, 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint64_t *tagptr, struct flist_head *list) 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){ 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct fio_net_cmd *cmd = NULL; 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t this_len, cur_len = 0; 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint64_t tag; 358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int ret; 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 360868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (list) { 361868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) assert(tagptr); 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) tag = *tagptr = alloc_reply(*tagptr, opcode); 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else 3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) tag = tagptr ? *tagptr : 0; 365868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 366868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) do { 367868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) this_len = size; 368868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (this_len > FIO_SERVER_MAX_FRAGMENT_PDU) 369868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) this_len = FIO_SERVER_MAX_FRAGMENT_PDU; 370868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!cmd || cur_len < sizeof(*cmd) + this_len) { 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (cmd) 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) free(cmd); 374868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 375868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) cur_len = sizeof(*cmd) + this_len; 376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cmd = malloc(cur_len); 377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fio_init_net_cmd(cmd, opcode, buf, this_len, tag); 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (this_len < size) 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cmd->flags = __cpu_to_le32(FIO_NET_CMD_F_MORE); 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fio_net_cmd_crc(cmd); 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ret = fio_send_data(fd, cmd, sizeof(*cmd) + this_len); 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size -= this_len; 3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) buf += this_len; 3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } while (!ret && size); 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (list) { 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ret) 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) free_reply(tag); 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) else 3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) add_reply(tag, list); 3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (cmd) 3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) free(cmd); 4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ret; 4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static int fio_net_send_simple_stack_cmd(int sk, uint16_t opcode, uint64_t tag) 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){ 4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct fio_net_cmd cmd; 4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fio_init_net_cmd(&cmd, opcode, NULL, 0, tag); 4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fio_net_cmd_crc(&cmd); 410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return fio_send_data(sk, &cmd, sizeof(cmd)); 412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 414eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/* 415eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * If 'list' is non-NULL, then allocate and store the sent command for 416eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * later verification. 4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int fio_net_send_simple_cmd(int sk, uint16_t opcode, uint64_t tag, 4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct flist_head *list) 4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){ 4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int ret; 4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (list) 4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) tag = alloc_reply(tag, opcode); 4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 42690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ret = fio_net_send_simple_stack_cmd(sk, opcode, tag); 4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ret) { 4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (list) 4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) free_reply(tag); 430c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 431c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return ret; 4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (list) 4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) add_reply(tag, list); 4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 439c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int fio_net_send_quit(int sk) 441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles){ 442c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) dprint(FD_NET, "server: sending quit\n"); 443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return fio_net_send_simple_cmd(sk, FIO_NET_CMD_QUIT, 0, NULL); 445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static int fio_net_send_ack(int sk, struct fio_net_cmd *cmd, int error, 448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int signal) 449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles){ 450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) struct cmd_end_pdu epdu; 4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint64_t tag = 0; 4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (cmd) 4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) tag = cmd->tag; 4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) epdu.error = __cpu_to_le32(error); 4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) epdu.signal = __cpu_to_le32(signal); 4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return fio_net_send_cmd(sk, FIO_NET_CMD_STOP, &epdu, sizeof(epdu), &tag, NULL); 4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 460c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int fio_net_send_stop(int sk, int error, int signal) 4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){ 4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dprint(FD_NET, "server: sending stop (%d, %d)\n", error, signal); 4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return fio_net_send_ack(sk, NULL, error, signal); 4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static void fio_server_add_fork_item(pid_t pid, struct flist_head *list) 4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){ 4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct fio_fork_item *ffi; 4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 471c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ffi = malloc(sizeof(*ffi)); 472c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ffi->exitval = 0; 473c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ffi->signal = 0; 474c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ffi->exited = 0; 475c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ffi->pid = pid; 4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) flist_add_tail(&ffi->list, list); 4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 478c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 479c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static void fio_server_add_conn_pid(struct flist_head *conn_list, pid_t pid) 480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles){ 481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) dprint(FD_NET, "server: forked off connection job (pid=%u)\n", (int) pid); 482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) fio_server_add_fork_item(pid, conn_list); 483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 484c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static void fio_server_add_job_pid(struct flist_head *job_list, pid_t pid) 486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles){ 487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) dprint(FD_NET, "server: forked off job job (pid=%u)\n", (int) pid); 488c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) fio_server_add_fork_item(pid, job_list); 489eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 490eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 491c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static void fio_server_check_fork_item(struct fio_fork_item *ffi) 492eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{ 493c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int ret, status; 494c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ret = waitpid(ffi->pid, &status, WNOHANG); 4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ret < 0) { 4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (errno == ECHILD) { 4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) log_err("fio: connection pid %u disappeared\n", (int) ffi->pid); 4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ffi->exited = 1; 5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else 5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) log_err("fio: waitpid: %s\n", strerror(errno)); 5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (ret == ffi->pid) { 5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (WIFSIGNALED(status)) { 5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ffi->signal = WTERMSIG(status); 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ffi->exited = 1; 5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (WIFEXITED(status)) { 508868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (WEXITSTATUS(status)) 509868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ffi->exitval = WEXITSTATUS(status); 510868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ffi->exited = 1; 511868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 512868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 513868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 514868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static void fio_server_fork_item_done(struct fio_fork_item *ffi) 5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){ 5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dprint(FD_NET, "pid %u exited, sig=%u, exitval=%d\n", (int) ffi->pid, ffi->signal, ffi->exitval); 5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /* 5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Fold STOP and QUIT... 5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fio_net_send_stop(server_fd, ffi->exitval, ffi->signal); 5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fio_net_send_quit(server_fd); 5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) flist_del(&ffi->list); 5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) free(ffi); 5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static void fio_server_check_fork_items(struct flist_head *list) 5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){ 5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct flist_head *entry, *tmp; 531c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) struct fio_fork_item *ffi; 532c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 533c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) flist_for_each_safe(entry, tmp, list) { 5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ffi = flist_entry(entry, struct fio_fork_item, list); 5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 536 fio_server_check_fork_item(ffi); 537 538 if (ffi->exited) 539 fio_server_fork_item_done(ffi); 540 } 541} 542 543static void fio_server_check_jobs(struct flist_head *job_list) 544{ 545 fio_server_check_fork_items(job_list); 546} 547 548static void fio_server_check_conns(struct flist_head *conn_list) 549{ 550 fio_server_check_fork_items(conn_list); 551} 552 553static int handle_run_cmd(struct flist_head *job_list, struct fio_net_cmd *cmd) 554{ 555 pid_t pid; 556 int ret; 557 558 set_genesis_time(); 559 560 pid = fork(); 561 if (pid) { 562 fio_server_add_job_pid(job_list, pid); 563 return 0; 564 } 565 566 ret = fio_backend(); 567 free_threads_shm(); 568 _exit(ret); 569} 570 571static int handle_job_cmd(struct fio_net_cmd *cmd) 572{ 573 struct cmd_job_pdu *pdu = (struct cmd_job_pdu *) cmd->payload; 574 void *buf = pdu->buf; 575 struct cmd_start_pdu spdu; 576 577 pdu->buf_len = le32_to_cpu(pdu->buf_len); 578 pdu->client_type = le32_to_cpu(pdu->client_type); 579 580 if (parse_jobs_ini(buf, 1, 0, pdu->client_type)) { 581 fio_net_send_quit(server_fd); 582 return -1; 583 } 584 585 spdu.jobs = cpu_to_le32(thread_number); 586 spdu.stat_outputs = cpu_to_le32(stat_number); 587 fio_net_send_cmd(server_fd, FIO_NET_CMD_START, &spdu, sizeof(spdu), NULL, NULL); 588 return 0; 589} 590 591static int handle_jobline_cmd(struct fio_net_cmd *cmd) 592{ 593 void *pdu = cmd->payload; 594 struct cmd_single_line_pdu *cslp; 595 struct cmd_line_pdu *clp; 596 unsigned long offset; 597 struct cmd_start_pdu spdu; 598 char **argv; 599 int i; 600 601 clp = pdu; 602 clp->lines = le16_to_cpu(clp->lines); 603 clp->client_type = le16_to_cpu(clp->client_type); 604 argv = malloc(clp->lines * sizeof(char *)); 605 offset = sizeof(*clp); 606 607 dprint(FD_NET, "server: %d command line args\n", clp->lines); 608 609 for (i = 0; i < clp->lines; i++) { 610 cslp = pdu + offset; 611 argv[i] = (char *) cslp->text; 612 613 offset += sizeof(*cslp) + le16_to_cpu(cslp->len); 614 dprint(FD_NET, "server: %d: %s\n", i, argv[i]); 615 } 616 617 if (parse_cmd_line(clp->lines, argv, clp->client_type)) { 618 fio_net_send_quit(server_fd); 619 free(argv); 620 return -1; 621 } 622 623 free(argv); 624 625 spdu.jobs = cpu_to_le32(thread_number); 626 spdu.stat_outputs = cpu_to_le32(stat_number); 627 fio_net_send_cmd(server_fd, FIO_NET_CMD_START, &spdu, sizeof(spdu), NULL, NULL); 628 return 0; 629} 630 631static int handle_probe_cmd(struct fio_net_cmd *cmd) 632{ 633 struct cmd_client_probe_pdu *pdu = (struct cmd_client_probe_pdu *) cmd->payload; 634 struct cmd_probe_reply_pdu probe; 635 uint64_t tag = cmd->tag; 636 637 dprint(FD_NET, "server: sending probe reply\n"); 638 639 memset(&probe, 0, sizeof(probe)); 640 gethostname((char *) probe.hostname, sizeof(probe.hostname)); 641#ifdef CONFIG_BIG_ENDIAN 642 probe.bigendian = 1; 643#endif 644 strncpy((char *) probe.fio_version, fio_version_string, sizeof(probe.fio_version)); 645 646 probe.os = FIO_OS; 647 probe.arch = FIO_ARCH; 648 probe.bpp = sizeof(void *); 649 probe.cpus = __cpu_to_le32(cpus_online()); 650 651 /* 652 * If the client supports compression and we do too, then enable it 653 */ 654 if (has_zlib && le64_to_cpu(pdu->flags) & FIO_PROBE_FLAG_ZLIB) { 655 probe.flags = __cpu_to_le64(FIO_PROBE_FLAG_ZLIB); 656 use_zlib = 1; 657 } else { 658 probe.flags = 0; 659 use_zlib = 0; 660 } 661 662 return fio_net_send_cmd(server_fd, FIO_NET_CMD_PROBE, &probe, sizeof(probe), &tag, NULL); 663} 664 665static int handle_send_eta_cmd(struct fio_net_cmd *cmd) 666{ 667 struct jobs_eta *je; 668 size_t size; 669 uint64_t tag = cmd->tag; 670 int i; 671 672 if (!thread_number) 673 return 0; 674 675 size = sizeof(*je) + thread_number * sizeof(char) + 1; 676 je = malloc(size); 677 memset(je, 0, size); 678 679 if (!calc_thread_status(je, 1)) { 680 free(je); 681 return 0; 682 } 683 684 dprint(FD_NET, "server sending status\n"); 685 686 je->nr_running = cpu_to_le32(je->nr_running); 687 je->nr_ramp = cpu_to_le32(je->nr_ramp); 688 je->nr_pending = cpu_to_le32(je->nr_pending); 689 je->nr_setting_up = cpu_to_le32(je->nr_setting_up); 690 je->files_open = cpu_to_le32(je->files_open); 691 692 for (i = 0; i < DDIR_RWDIR_CNT; i++) { 693 je->m_rate[i] = cpu_to_le32(je->m_rate[i]); 694 je->t_rate[i] = cpu_to_le32(je->t_rate[i]); 695 je->m_iops[i] = cpu_to_le32(je->m_iops[i]); 696 je->t_iops[i] = cpu_to_le32(je->t_iops[i]); 697 je->rate[i] = cpu_to_le32(je->rate[i]); 698 je->iops[i] = cpu_to_le32(je->iops[i]); 699 } 700 701 je->elapsed_sec = cpu_to_le64(je->elapsed_sec); 702 je->eta_sec = cpu_to_le64(je->eta_sec); 703 je->nr_threads = cpu_to_le32(je->nr_threads); 704 je->is_pow2 = cpu_to_le32(je->is_pow2); 705 je->unit_base = cpu_to_le32(je->unit_base); 706 707 fio_net_send_cmd(server_fd, FIO_NET_CMD_ETA, je, size, &tag, NULL); 708 free(je); 709 return 0; 710} 711 712static int send_update_job_reply(int fd, uint64_t __tag, int error) 713{ 714 uint64_t tag = __tag; 715 uint32_t pdu_error; 716 717 pdu_error = __cpu_to_le32(error); 718 return fio_net_send_cmd(fd, FIO_NET_CMD_UPDATE_JOB, &pdu_error, sizeof(pdu_error), &tag, NULL); 719} 720 721static int handle_update_job_cmd(struct fio_net_cmd *cmd) 722{ 723 struct cmd_add_job_pdu *pdu = (struct cmd_add_job_pdu *) cmd->payload; 724 struct thread_data *td; 725 uint32_t tnumber; 726 727 tnumber = le32_to_cpu(pdu->thread_number); 728 729 dprint(FD_NET, "server: updating options for job %u\n", tnumber); 730 731 if (!tnumber || tnumber > thread_number) { 732 send_update_job_reply(server_fd, cmd->tag, ENODEV); 733 return 0; 734 } 735 736 td = &threads[tnumber - 1]; 737 convert_thread_options_to_cpu(&td->o, &pdu->top); 738 send_update_job_reply(server_fd, cmd->tag, 0); 739 return 0; 740} 741 742static int handle_command(struct flist_head *job_list, struct fio_net_cmd *cmd) 743{ 744 int ret; 745 746 dprint(FD_NET, "server: got op [%s], pdu=%u, tag=%llx\n", 747 fio_server_op(cmd->opcode), cmd->pdu_len, 748 (unsigned long long) cmd->tag); 749 750 switch (cmd->opcode) { 751 case FIO_NET_CMD_QUIT: 752 fio_terminate_threads(TERMINATE_ALL); 753 return -1; 754 case FIO_NET_CMD_EXIT: 755 exit_backend = 1; 756 return -1; 757 case FIO_NET_CMD_JOB: 758 ret = handle_job_cmd(cmd); 759 break; 760 case FIO_NET_CMD_JOBLINE: 761 ret = handle_jobline_cmd(cmd); 762 break; 763 case FIO_NET_CMD_PROBE: 764 ret = handle_probe_cmd(cmd); 765 break; 766 case FIO_NET_CMD_SEND_ETA: 767 ret = handle_send_eta_cmd(cmd); 768 break; 769 case FIO_NET_CMD_RUN: 770 ret = handle_run_cmd(job_list, cmd); 771 break; 772 case FIO_NET_CMD_UPDATE_JOB: 773 ret = handle_update_job_cmd(cmd); 774 break; 775 default: 776 log_err("fio: unknown opcode: %s\n", fio_server_op(cmd->opcode)); 777 ret = 1; 778 } 779 780 return ret; 781} 782 783static int handle_connection(int sk) 784{ 785 struct fio_net_cmd *cmd = NULL; 786 FLIST_HEAD(job_list); 787 int ret = 0; 788 789 reset_fio_state(); 790 server_fd = sk; 791 792 /* read forever */ 793 while (!exit_backend) { 794 struct pollfd pfd = { 795 .fd = sk, 796 .events = POLLIN, 797 }; 798 799 ret = 0; 800 do { 801 int timeout = 1000; 802 803 if (!flist_empty(&job_list)) 804 timeout = 100; 805 806 ret = poll(&pfd, 1, timeout); 807 if (ret < 0) { 808 if (errno == EINTR) 809 break; 810 log_err("fio: poll: %s\n", strerror(errno)); 811 break; 812 } else if (!ret) { 813 fio_server_check_jobs(&job_list); 814 continue; 815 } 816 817 if (pfd.revents & POLLIN) 818 break; 819 if (pfd.revents & (POLLERR|POLLHUP)) { 820 ret = 1; 821 break; 822 } 823 } while (!exit_backend); 824 825 fio_server_check_jobs(&job_list); 826 827 if (ret < 0) 828 break; 829 830 cmd = fio_net_recv_cmd(sk); 831 if (!cmd) { 832 ret = -1; 833 break; 834 } 835 836 ret = handle_command(&job_list, cmd); 837 if (ret) 838 break; 839 840 free(cmd); 841 cmd = NULL; 842 } 843 844 if (cmd) 845 free(cmd); 846 847 close(sk); 848 _exit(ret); 849} 850 851static int accept_loop(int listen_sk) 852{ 853 struct sockaddr_in addr; 854 struct sockaddr_in6 addr6; 855 socklen_t len = use_ipv6 ? sizeof(addr6) : sizeof(addr); 856 struct pollfd pfd; 857 int ret = 0, sk, exitval = 0; 858 FLIST_HEAD(conn_list); 859 860 dprint(FD_NET, "server enter accept loop\n"); 861 862 fio_set_fd_nonblocking(listen_sk, "server"); 863 864 while (!exit_backend) { 865 const char *from; 866 char buf[64]; 867 pid_t pid; 868 869 pfd.fd = listen_sk; 870 pfd.events = POLLIN; 871 do { 872 int timeout = 1000; 873 874 if (!flist_empty(&conn_list)) 875 timeout = 100; 876 877 ret = poll(&pfd, 1, timeout); 878 if (ret < 0) { 879 if (errno == EINTR) 880 break; 881 log_err("fio: poll: %s\n", strerror(errno)); 882 break; 883 } else if (!ret) { 884 fio_server_check_conns(&conn_list); 885 continue; 886 } 887 888 if (pfd.revents & POLLIN) 889 break; 890 } while (!exit_backend); 891 892 fio_server_check_conns(&conn_list); 893 894 if (exit_backend || ret < 0) 895 break; 896 897 if (use_ipv6) 898 sk = accept(listen_sk, (struct sockaddr *) &addr6, &len); 899 else 900 sk = accept(listen_sk, (struct sockaddr *) &addr, &len); 901 902 if (sk < 0) { 903 log_err("fio: accept: %s\n", strerror(errno)); 904 return -1; 905 } 906 907 if (use_ipv6) 908 from = inet_ntop(AF_INET6, (struct sockaddr *) &addr6.sin6_addr, buf, sizeof(buf)); 909 else 910 from = inet_ntop(AF_INET, (struct sockaddr *) &addr.sin_addr, buf, sizeof(buf)); 911 912 dprint(FD_NET, "server: connect from %s\n", from); 913 914 pid = fork(); 915 if (pid) { 916 close(sk); 917 fio_server_add_conn_pid(&conn_list, pid); 918 continue; 919 } 920 921 /* exits */ 922 handle_connection(sk); 923 } 924 925 return exitval; 926} 927 928int fio_server_text_output(int level, const char *buf, size_t len) 929{ 930 struct cmd_text_pdu *pdu; 931 unsigned int tlen; 932 struct timeval tv; 933 934 if (server_fd == -1) 935 return log_local_buf(buf, len); 936 937 tlen = sizeof(*pdu) + len; 938 pdu = malloc(tlen); 939 940 pdu->level = __cpu_to_le32(level); 941 pdu->buf_len = __cpu_to_le32(len); 942 943 gettimeofday(&tv, NULL); 944 pdu->log_sec = __cpu_to_le64(tv.tv_sec); 945 pdu->log_usec = __cpu_to_le64(tv.tv_usec); 946 947 memcpy(pdu->buf, buf, len); 948 949 fio_net_send_cmd(server_fd, FIO_NET_CMD_TEXT, pdu, tlen, NULL, NULL); 950 free(pdu); 951 return len; 952} 953 954static void convert_io_stat(struct io_stat *dst, struct io_stat *src) 955{ 956 dst->max_val = cpu_to_le64(src->max_val); 957 dst->min_val = cpu_to_le64(src->min_val); 958 dst->samples = cpu_to_le64(src->samples); 959 960 /* 961 * Encode to IEEE 754 for network transfer 962 */ 963 dst->mean.u.i = __cpu_to_le64(fio_double_to_uint64(src->mean.u.f)); 964 dst->S.u.i = __cpu_to_le64(fio_double_to_uint64(src->S.u.f)); 965} 966 967static void convert_gs(struct group_run_stats *dst, struct group_run_stats *src) 968{ 969 int i; 970 971 for (i = 0; i < DDIR_RWDIR_CNT; i++) { 972 dst->max_run[i] = cpu_to_le64(src->max_run[i]); 973 dst->min_run[i] = cpu_to_le64(src->min_run[i]); 974 dst->max_bw[i] = cpu_to_le64(src->max_bw[i]); 975 dst->min_bw[i] = cpu_to_le64(src->min_bw[i]); 976 dst->io_kb[i] = cpu_to_le64(src->io_kb[i]); 977 dst->agg[i] = cpu_to_le64(src->agg[i]); 978 } 979 980 dst->kb_base = cpu_to_le32(src->kb_base); 981 dst->unit_base = cpu_to_le32(src->unit_base); 982 dst->groupid = cpu_to_le32(src->groupid); 983 dst->unified_rw_rep = cpu_to_le32(src->unified_rw_rep); 984} 985 986/* 987 * Send a CMD_TS, which packs struct thread_stat and group_run_stats 988 * into a single payload. 989 */ 990void fio_server_send_ts(struct thread_stat *ts, struct group_run_stats *rs) 991{ 992 struct cmd_ts_pdu p; 993 int i, j; 994 995 dprint(FD_NET, "server sending end stats\n"); 996 997 memset(&p, 0, sizeof(p)); 998 999 strncpy(p.ts.name, ts->name, FIO_JOBNAME_SIZE - 1); 1000 strncpy(p.ts.verror, ts->verror, FIO_VERROR_SIZE - 1); 1001 strncpy(p.ts.description, ts->description, FIO_JOBDESC_SIZE - 1); 1002 1003 p.ts.error = cpu_to_le32(ts->error); 1004 p.ts.thread_number = cpu_to_le32(ts->thread_number); 1005 p.ts.groupid = cpu_to_le32(ts->groupid); 1006 p.ts.pid = cpu_to_le32(ts->pid); 1007 p.ts.members = cpu_to_le32(ts->members); 1008 p.ts.unified_rw_rep = cpu_to_le32(ts->unified_rw_rep); 1009 1010 for (i = 0; i < DDIR_RWDIR_CNT; i++) { 1011 convert_io_stat(&p.ts.clat_stat[i], &ts->clat_stat[i]); 1012 convert_io_stat(&p.ts.slat_stat[i], &ts->slat_stat[i]); 1013 convert_io_stat(&p.ts.lat_stat[i], &ts->lat_stat[i]); 1014 convert_io_stat(&p.ts.bw_stat[i], &ts->bw_stat[i]); 1015 } 1016 1017 p.ts.usr_time = cpu_to_le64(ts->usr_time); 1018 p.ts.sys_time = cpu_to_le64(ts->sys_time); 1019 p.ts.ctx = cpu_to_le64(ts->ctx); 1020 p.ts.minf = cpu_to_le64(ts->minf); 1021 p.ts.majf = cpu_to_le64(ts->majf); 1022 p.ts.clat_percentiles = cpu_to_le64(ts->clat_percentiles); 1023 1024 for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) { 1025 fio_fp64_t *src = &ts->percentile_list[i]; 1026 fio_fp64_t *dst = &p.ts.percentile_list[i]; 1027 1028 dst->u.i = __cpu_to_le64(fio_double_to_uint64(src->u.f)); 1029 } 1030 1031 for (i = 0; i < FIO_IO_U_MAP_NR; i++) { 1032 p.ts.io_u_map[i] = cpu_to_le32(ts->io_u_map[i]); 1033 p.ts.io_u_submit[i] = cpu_to_le32(ts->io_u_submit[i]); 1034 p.ts.io_u_complete[i] = cpu_to_le32(ts->io_u_complete[i]); 1035 } 1036 1037 for (i = 0; i < FIO_IO_U_LAT_U_NR; i++) { 1038 p.ts.io_u_lat_u[i] = cpu_to_le32(ts->io_u_lat_u[i]); 1039 p.ts.io_u_lat_m[i] = cpu_to_le32(ts->io_u_lat_m[i]); 1040 } 1041 1042 for (i = 0; i < DDIR_RWDIR_CNT; i++) 1043 for (j = 0; j < FIO_IO_U_PLAT_NR; j++) 1044 p.ts.io_u_plat[i][j] = cpu_to_le32(ts->io_u_plat[i][j]); 1045 1046 for (i = 0; i < DDIR_RWDIR_CNT; i++) { 1047 p.ts.total_io_u[i] = cpu_to_le64(ts->total_io_u[i]); 1048 p.ts.short_io_u[i] = cpu_to_le64(ts->short_io_u[i]); 1049 } 1050 1051 p.ts.total_submit = cpu_to_le64(ts->total_submit); 1052 p.ts.total_complete = cpu_to_le64(ts->total_complete); 1053 1054 for (i = 0; i < DDIR_RWDIR_CNT; i++) { 1055 p.ts.io_bytes[i] = cpu_to_le64(ts->io_bytes[i]); 1056 p.ts.runtime[i] = cpu_to_le64(ts->runtime[i]); 1057 } 1058 1059 p.ts.total_run_time = cpu_to_le64(ts->total_run_time); 1060 p.ts.continue_on_error = cpu_to_le16(ts->continue_on_error); 1061 p.ts.total_err_count = cpu_to_le64(ts->total_err_count); 1062 p.ts.first_error = cpu_to_le32(ts->first_error); 1063 p.ts.kb_base = cpu_to_le32(ts->kb_base); 1064 p.ts.unit_base = cpu_to_le32(ts->unit_base); 1065 1066 p.ts.latency_depth = cpu_to_le32(ts->latency_depth); 1067 p.ts.latency_target = cpu_to_le64(ts->latency_target); 1068 p.ts.latency_window = cpu_to_le64(ts->latency_window); 1069 p.ts.latency_percentile.u.i = __cpu_to_le64(fio_double_to_uint64(ts->latency_percentile.u.f)); 1070 1071 convert_gs(&p.rs, rs); 1072 1073 fio_net_send_cmd(server_fd, FIO_NET_CMD_TS, &p, sizeof(p), NULL, NULL); 1074} 1075 1076void fio_server_send_gs(struct group_run_stats *rs) 1077{ 1078 struct group_run_stats gs; 1079 1080 dprint(FD_NET, "server sending group run stats\n"); 1081 1082 convert_gs(&gs, rs); 1083 fio_net_send_cmd(server_fd, FIO_NET_CMD_GS, &gs, sizeof(gs), NULL, NULL); 1084} 1085 1086static void convert_agg(struct disk_util_agg *dst, struct disk_util_agg *src) 1087{ 1088 int i; 1089 1090 for (i = 0; i < 2; i++) { 1091 dst->ios[i] = cpu_to_le32(src->ios[i]); 1092 dst->merges[i] = cpu_to_le32(src->merges[i]); 1093 dst->sectors[i] = cpu_to_le64(src->sectors[i]); 1094 dst->ticks[i] = cpu_to_le32(src->ticks[i]); 1095 } 1096 1097 dst->io_ticks = cpu_to_le32(src->io_ticks); 1098 dst->time_in_queue = cpu_to_le32(src->time_in_queue); 1099 dst->slavecount = cpu_to_le32(src->slavecount); 1100 dst->max_util.u.i = __cpu_to_le64(fio_double_to_uint64(src->max_util.u.f)); 1101} 1102 1103static void convert_dus(struct disk_util_stat *dst, struct disk_util_stat *src) 1104{ 1105 int i; 1106 1107 dst->name[FIO_DU_NAME_SZ - 1] = '\0'; 1108 strncpy((char *) dst->name, (char *) src->name, FIO_DU_NAME_SZ - 1); 1109 1110 for (i = 0; i < 2; i++) { 1111 dst->s.ios[i] = cpu_to_le32(src->s.ios[i]); 1112 dst->s.merges[i] = cpu_to_le32(src->s.merges[i]); 1113 dst->s.sectors[i] = cpu_to_le64(src->s.sectors[i]); 1114 dst->s.ticks[i] = cpu_to_le32(src->s.ticks[i]); 1115 } 1116 1117 dst->s.io_ticks = cpu_to_le32(src->s.io_ticks); 1118 dst->s.time_in_queue = cpu_to_le32(src->s.time_in_queue); 1119 dst->s.msec = cpu_to_le64(src->s.msec); 1120} 1121 1122void fio_server_send_du(void) 1123{ 1124 struct disk_util *du; 1125 struct flist_head *entry; 1126 struct cmd_du_pdu pdu; 1127 1128 dprint(FD_NET, "server: sending disk_util %d\n", !flist_empty(&disk_list)); 1129 1130 memset(&pdu, 0, sizeof(pdu)); 1131 1132 flist_for_each(entry, &disk_list) { 1133 du = flist_entry(entry, struct disk_util, list); 1134 1135 convert_dus(&pdu.dus, &du->dus); 1136 convert_agg(&pdu.agg, &du->agg); 1137 1138 fio_net_send_cmd(server_fd, FIO_NET_CMD_DU, &pdu, sizeof(pdu), NULL, NULL); 1139 } 1140} 1141 1142/* 1143 * Send a command with a separate PDU, not inlined in the command 1144 */ 1145static int fio_send_cmd_ext_pdu(int sk, uint16_t opcode, const void *buf, 1146 off_t size, uint64_t tag, uint32_t flags) 1147{ 1148 struct fio_net_cmd cmd; 1149 struct iovec iov[2]; 1150 1151 iov[0].iov_base = (void *) &cmd; 1152 iov[0].iov_len = sizeof(cmd); 1153 iov[1].iov_base = (void *) buf; 1154 iov[1].iov_len = size; 1155 1156 __fio_init_net_cmd(&cmd, opcode, size, tag); 1157 cmd.flags = __cpu_to_le32(flags); 1158 fio_net_cmd_crc_pdu(&cmd, buf); 1159 1160 return fio_sendv_data(sk, iov, 2); 1161} 1162 1163static int fio_send_iolog_gz(struct cmd_iolog_pdu *pdu, struct io_log *log) 1164{ 1165 int ret = 0; 1166#ifdef CONFIG_ZLIB 1167 z_stream stream; 1168 void *out_pdu; 1169 1170 /* 1171 * Dirty - since the log is potentially huge, compress it into 1172 * FIO_SERVER_MAX_FRAGMENT_PDU chunks and let the receiving 1173 * side defragment it. 1174 */ 1175 out_pdu = malloc(FIO_SERVER_MAX_FRAGMENT_PDU); 1176 1177 stream.zalloc = Z_NULL; 1178 stream.zfree = Z_NULL; 1179 stream.opaque = Z_NULL; 1180 1181 if (deflateInit(&stream, Z_DEFAULT_COMPRESSION) != Z_OK) { 1182 ret = 1; 1183 goto err; 1184 } 1185 1186 stream.next_in = (void *) log->log; 1187 stream.avail_in = log->nr_samples * sizeof(struct io_sample); 1188 1189 do { 1190 unsigned int this_len, flags = 0; 1191 int ret; 1192 1193 stream.avail_out = FIO_SERVER_MAX_FRAGMENT_PDU; 1194 stream.next_out = out_pdu; 1195 ret = deflate(&stream, Z_FINISH); 1196 /* may be Z_OK, or Z_STREAM_END */ 1197 if (ret < 0) 1198 goto err_zlib; 1199 1200 this_len = FIO_SERVER_MAX_FRAGMENT_PDU - stream.avail_out; 1201 1202 if (stream.avail_in) 1203 flags = FIO_NET_CMD_F_MORE; 1204 1205 ret = fio_send_cmd_ext_pdu(server_fd, FIO_NET_CMD_IOLOG, 1206 out_pdu, this_len, 0, flags); 1207 if (ret) 1208 goto err_zlib; 1209 } while (stream.avail_in); 1210 1211err_zlib: 1212 deflateEnd(&stream); 1213err: 1214 free(out_pdu); 1215#endif 1216 return ret; 1217} 1218 1219int fio_send_iolog(struct thread_data *td, struct io_log *log, const char *name) 1220{ 1221 struct cmd_iolog_pdu pdu; 1222 int i, ret = 0; 1223 1224 pdu.thread_number = cpu_to_le32(td->thread_number); 1225 pdu.nr_samples = __cpu_to_le32(log->nr_samples); 1226 pdu.log_type = cpu_to_le32(log->log_type); 1227 pdu.compressed = cpu_to_le32(use_zlib); 1228 1229 strncpy((char *) pdu.name, name, FIO_NET_NAME_MAX); 1230 pdu.name[FIO_NET_NAME_MAX - 1] = '\0'; 1231 1232 for (i = 0; i < log->nr_samples; i++) { 1233 struct io_sample *s = &log->log[i]; 1234 1235 s->time = cpu_to_le64(s->time); 1236 s->val = cpu_to_le64(s->val); 1237 s->ddir = cpu_to_le32(s->ddir); 1238 s->bs = cpu_to_le32(s->bs); 1239 } 1240 1241 /* 1242 * Send header first, it's not compressed. 1243 */ 1244 ret = fio_send_cmd_ext_pdu(server_fd, FIO_NET_CMD_IOLOG, &pdu, 1245 sizeof(pdu), 0, FIO_NET_CMD_F_MORE); 1246 if (ret) 1247 return ret; 1248 1249 /* 1250 * Now send actual log, compress if we can, otherwise just plain 1251 */ 1252 if (use_zlib) 1253 return fio_send_iolog_gz(&pdu, log); 1254 1255 return fio_send_cmd_ext_pdu(server_fd, FIO_NET_CMD_IOLOG, log->log, 1256 log->nr_samples * sizeof(struct io_sample), 0, 0); 1257} 1258 1259void fio_server_send_add_job(struct thread_data *td) 1260{ 1261 struct cmd_add_job_pdu pdu; 1262 1263 memset(&pdu, 0, sizeof(pdu)); 1264 pdu.thread_number = cpu_to_le32(td->thread_number); 1265 pdu.groupid = cpu_to_le32(td->groupid); 1266 convert_thread_options_to_net(&pdu.top, &td->o); 1267 1268 fio_net_send_cmd(server_fd, FIO_NET_CMD_ADD_JOB, &pdu, sizeof(pdu), NULL, NULL); 1269} 1270 1271void fio_server_send_start(struct thread_data *td) 1272{ 1273 assert(server_fd != -1); 1274 1275 fio_net_send_simple_cmd(server_fd, FIO_NET_CMD_SERVER_START, 0, NULL); 1276} 1277 1278static int fio_init_server_ip(void) 1279{ 1280 struct sockaddr *addr; 1281 socklen_t socklen; 1282 char buf[80]; 1283 const char *str; 1284 int sk, opt; 1285 1286 if (use_ipv6) 1287 sk = socket(AF_INET6, SOCK_STREAM, 0); 1288 else 1289 sk = socket(AF_INET, SOCK_STREAM, 0); 1290 1291 if (sk < 0) { 1292 log_err("fio: socket: %s\n", strerror(errno)); 1293 return -1; 1294 } 1295 1296 opt = 1; 1297 if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt)) < 0) { 1298 log_err("fio: setsockopt: %s\n", strerror(errno)); 1299 close(sk); 1300 return -1; 1301 } 1302#ifdef SO_REUSEPORT 1303 if (setsockopt(sk, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)) < 0) { 1304 log_err("fio: setsockopt: %s\n", strerror(errno)); 1305 close(sk); 1306 return -1; 1307 } 1308#endif 1309 1310 if (use_ipv6) { 1311 const void *src = &saddr_in6.sin6_addr; 1312 1313 addr = (struct sockaddr *) &saddr_in6; 1314 socklen = sizeof(saddr_in6); 1315 saddr_in6.sin6_family = AF_INET6; 1316 str = inet_ntop(AF_INET6, src, buf, sizeof(buf)); 1317 } else { 1318 const void *src = &saddr_in.sin_addr; 1319 1320 addr = (struct sockaddr *) &saddr_in; 1321 socklen = sizeof(saddr_in); 1322 saddr_in.sin_family = AF_INET; 1323 str = inet_ntop(AF_INET, src, buf, sizeof(buf)); 1324 } 1325 1326 if (bind(sk, addr, socklen) < 0) { 1327 log_err("fio: bind: %s\n", strerror(errno)); 1328 log_info("fio: failed with IPv%c %s\n", use_ipv6 ? '6' : '4', str); 1329 close(sk); 1330 return -1; 1331 } 1332 1333 return sk; 1334} 1335 1336static int fio_init_server_sock(void) 1337{ 1338 struct sockaddr_un addr; 1339 socklen_t len; 1340 mode_t mode; 1341 int sk; 1342 1343 sk = socket(AF_UNIX, SOCK_STREAM, 0); 1344 if (sk < 0) { 1345 log_err("fio: socket: %s\n", strerror(errno)); 1346 return -1; 1347 } 1348 1349 mode = umask(000); 1350 1351 memset(&addr, 0, sizeof(addr)); 1352 addr.sun_family = AF_UNIX; 1353 strncpy(addr.sun_path, bind_sock, sizeof(addr.sun_path) - 1); 1354 1355 len = sizeof(addr.sun_family) + strlen(bind_sock) + 1; 1356 1357 if (bind(sk, (struct sockaddr *) &addr, len) < 0) { 1358 log_err("fio: bind: %s\n", strerror(errno)); 1359 close(sk); 1360 return -1; 1361 } 1362 1363 umask(mode); 1364 return sk; 1365} 1366 1367static int fio_init_server_connection(void) 1368{ 1369 char bind_str[128]; 1370 int sk; 1371 1372 dprint(FD_NET, "starting server\n"); 1373 1374 if (!bind_sock) 1375 sk = fio_init_server_ip(); 1376 else 1377 sk = fio_init_server_sock(); 1378 1379 if (sk < 0) 1380 return sk; 1381 1382 memset(bind_str, 0, sizeof(bind_str)); 1383 1384 if (!bind_sock) { 1385 char *p, port[16]; 1386 const void *src; 1387 int af; 1388 1389 if (use_ipv6) { 1390 af = AF_INET6; 1391 src = &saddr_in6.sin6_addr; 1392 } else { 1393 af = AF_INET; 1394 src = &saddr_in.sin_addr; 1395 } 1396 1397 p = (char *) inet_ntop(af, src, bind_str, sizeof(bind_str)); 1398 1399 sprintf(port, ",%u", fio_net_port); 1400 if (p) 1401 strcat(p, port); 1402 else 1403 strncpy(bind_str, port, sizeof(bind_str) - 1); 1404 } else 1405 strncpy(bind_str, bind_sock, sizeof(bind_str) - 1); 1406 1407 log_info("fio: server listening on %s\n", bind_str); 1408 1409 if (listen(sk, 0) < 0) { 1410 log_err("fio: listen: %s\n", strerror(errno)); 1411 close(sk); 1412 return -1; 1413 } 1414 1415 return sk; 1416} 1417 1418int fio_server_parse_host(const char *host, int ipv6, struct in_addr *inp, 1419 struct in6_addr *inp6) 1420 1421{ 1422 int ret = 0; 1423 1424 if (ipv6) 1425 ret = inet_pton(AF_INET6, host, inp6); 1426 else 1427 ret = inet_pton(AF_INET, host, inp); 1428 1429 if (ret != 1) { 1430 struct addrinfo hints, *res; 1431 1432 memset(&hints, 0, sizeof(hints)); 1433 hints.ai_family = ipv6 ? AF_INET6 : AF_INET; 1434 hints.ai_socktype = SOCK_STREAM; 1435 1436 ret = getaddrinfo(host, NULL, &hints, &res); 1437 if (ret) { 1438 log_err("fio: failed to resolve <%s> (%s)\n", host, 1439 gai_strerror(ret)); 1440 return 1; 1441 } 1442 1443 if (ipv6) 1444 memcpy(inp6, &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr, sizeof(*inp6)); 1445 else 1446 memcpy(inp, &((struct sockaddr_in *) res->ai_addr)->sin_addr, sizeof(*inp)); 1447 1448 ret = 1; 1449 freeaddrinfo(res); 1450 } 1451 1452 return !(ret == 1); 1453} 1454 1455/* 1456 * Parse a host/ip/port string. Reads from 'str'. 1457 * 1458 * Outputs: 1459 * 1460 * For IPv4: 1461 * *ptr is the host, *port is the port, inp is the destination. 1462 * For IPv6: 1463 * *ptr is the host, *port is the port, inp6 is the dest, and *ipv6 is 1. 1464 * For local domain sockets: 1465 * *ptr is the filename, *is_sock is 1. 1466 */ 1467int fio_server_parse_string(const char *str, char **ptr, int *is_sock, 1468 int *port, struct in_addr *inp, 1469 struct in6_addr *inp6, int *ipv6) 1470{ 1471 const char *host = str; 1472 char *portp; 1473 int lport = 0; 1474 1475 *ptr = NULL; 1476 *is_sock = 0; 1477 *port = fio_net_port; 1478 *ipv6 = 0; 1479 1480 if (!strncmp(str, "sock:", 5)) { 1481 *ptr = strdup(str + 5); 1482 *is_sock = 1; 1483 1484 return 0; 1485 } 1486 1487 /* 1488 * Is it ip:<ip or host>:port 1489 */ 1490 if (!strncmp(host, "ip:", 3)) 1491 host += 3; 1492 else if (!strncmp(host, "ip4:", 4)) 1493 host += 4; 1494 else if (!strncmp(host, "ip6:", 4)) { 1495 host += 4; 1496 *ipv6 = 1; 1497 } else if (host[0] == ':') { 1498 /* String is :port */ 1499 host++; 1500 lport = atoi(host); 1501 if (!lport || lport > 65535) { 1502 log_err("fio: bad server port %u\n", lport); 1503 return 1; 1504 } 1505 /* no hostname given, we are done */ 1506 *port = lport; 1507 return 0; 1508 } 1509 1510 /* 1511 * If no port seen yet, check if there's a last ',' at the end 1512 */ 1513 if (!lport) { 1514 portp = strchr(host, ','); 1515 if (portp) { 1516 *portp = '\0'; 1517 portp++; 1518 lport = atoi(portp); 1519 if (!lport || lport > 65535) { 1520 log_err("fio: bad server port %u\n", lport); 1521 return 1; 1522 } 1523 } 1524 } 1525 1526 if (lport) 1527 *port = lport; 1528 1529 if (!strlen(host)) 1530 return 0; 1531 1532 *ptr = strdup(host); 1533 1534 if (fio_server_parse_host(*ptr, *ipv6, inp, inp6)) { 1535 free(*ptr); 1536 *ptr = NULL; 1537 return 1; 1538 } 1539 1540 if (*port == 0) 1541 *port = fio_net_port; 1542 1543 return 0; 1544} 1545 1546/* 1547 * Server arg should be one of: 1548 * 1549 * sock:/path/to/socket 1550 * ip:1.2.3.4 1551 * 1.2.3.4 1552 * 1553 * Where sock uses unix domain sockets, and ip binds the server to 1554 * a specific interface. If no arguments are given to the server, it 1555 * uses IP and binds to 0.0.0.0. 1556 * 1557 */ 1558static int fio_handle_server_arg(void) 1559{ 1560 int port = fio_net_port; 1561 int is_sock, ret = 0; 1562 1563 saddr_in.sin_addr.s_addr = htonl(INADDR_ANY); 1564 1565 if (!fio_server_arg) 1566 goto out; 1567 1568 ret = fio_server_parse_string(fio_server_arg, &bind_sock, &is_sock, 1569 &port, &saddr_in.sin_addr, 1570 &saddr_in6.sin6_addr, &use_ipv6); 1571 1572 if (!is_sock && bind_sock) { 1573 free(bind_sock); 1574 bind_sock = NULL; 1575 } 1576 1577out: 1578 fio_net_port = port; 1579 saddr_in.sin_port = htons(port); 1580 saddr_in6.sin6_port = htons(port); 1581 return ret; 1582} 1583 1584static void sig_int(int sig) 1585{ 1586 if (bind_sock) 1587 unlink(bind_sock); 1588} 1589 1590static void set_sig_handlers(void) 1591{ 1592 struct sigaction act; 1593 1594 memset(&act, 0, sizeof(act)); 1595 act.sa_handler = sig_int; 1596 act.sa_flags = SA_RESTART; 1597 sigaction(SIGINT, &act, NULL); 1598} 1599 1600static int fio_server(void) 1601{ 1602 int sk, ret; 1603 1604 dprint(FD_NET, "starting server\n"); 1605 1606 if (fio_handle_server_arg()) 1607 return -1; 1608 1609 sk = fio_init_server_connection(); 1610 if (sk < 0) 1611 return -1; 1612 1613 set_sig_handlers(); 1614 1615 ret = accept_loop(sk); 1616 1617 close(sk); 1618 1619 if (fio_server_arg) { 1620 free(fio_server_arg); 1621 fio_server_arg = NULL; 1622 } 1623 if (bind_sock) 1624 free(bind_sock); 1625 1626 return ret; 1627} 1628 1629void fio_server_got_signal(int signal) 1630{ 1631 if (signal == SIGPIPE) 1632 server_fd = -1; 1633 else { 1634 log_info("\nfio: terminating on signal %d\n", signal); 1635 exit_backend = 1; 1636 } 1637} 1638 1639static int check_existing_pidfile(const char *pidfile) 1640{ 1641 struct stat sb; 1642 char buf[16]; 1643 pid_t pid; 1644 FILE *f; 1645 1646 if (stat(pidfile, &sb)) 1647 return 0; 1648 1649 f = fopen(pidfile, "r"); 1650 if (!f) 1651 return 0; 1652 1653 if (fread(buf, sb.st_size, 1, f) <= 0) { 1654 fclose(f); 1655 return 1; 1656 } 1657 fclose(f); 1658 1659 pid = atoi(buf); 1660 if (kill(pid, SIGCONT) < 0) 1661 return errno != ESRCH; 1662 1663 return 1; 1664} 1665 1666static int write_pid(pid_t pid, const char *pidfile) 1667{ 1668 FILE *fpid; 1669 1670 fpid = fopen(pidfile, "w"); 1671 if (!fpid) { 1672 log_err("fio: failed opening pid file %s\n", pidfile); 1673 return 1; 1674 } 1675 1676 fprintf(fpid, "%u\n", (unsigned int) pid); 1677 fclose(fpid); 1678 return 0; 1679} 1680 1681/* 1682 * If pidfile is specified, background us. 1683 */ 1684int fio_start_server(char *pidfile) 1685{ 1686 pid_t pid; 1687 int ret; 1688 1689#if defined(WIN32) 1690 WSADATA wsd; 1691 WSAStartup(MAKEWORD(2, 2), &wsd); 1692#endif 1693 1694 if (!pidfile) 1695 return fio_server(); 1696 1697 if (check_existing_pidfile(pidfile)) { 1698 log_err("fio: pidfile %s exists and server appears alive\n", 1699 pidfile); 1700 free(pidfile); 1701 return -1; 1702 } 1703 1704 pid = fork(); 1705 if (pid < 0) { 1706 log_err("fio: failed server fork: %s", strerror(errno)); 1707 free(pidfile); 1708 return -1; 1709 } else if (pid) { 1710 int ret = write_pid(pid, pidfile); 1711 1712 free(pidfile); 1713 exit(ret); 1714 } 1715 1716 setsid(); 1717 openlog("fio", LOG_NDELAY|LOG_NOWAIT|LOG_PID, LOG_USER); 1718 log_syslog = 1; 1719 close(STDIN_FILENO); 1720 close(STDOUT_FILENO); 1721 close(STDERR_FILENO); 1722 f_out = NULL; 1723 f_err = NULL; 1724 1725 ret = fio_server(); 1726 1727 closelog(); 1728 unlink(pidfile); 1729 free(pidfile); 1730 return ret; 1731} 1732 1733void fio_server_set_arg(const char *arg) 1734{ 1735 fio_server_arg = strdup(arg); 1736} 1737