The following changes since commit a3b4cf7dcae447729f0f4a4ea122f605b909ed70: diskutil: separate out stats from name (2014-04-11 12:17:53 -0600) are available in the git repository at: git://git.kernel.dk/fio.git master for you to fetch changes up to fb73340c52bcab712dfb175dafbcb5156abdda12: Windows: set sizeof(sun_path) to 260 (MAX_PATH). (2014-04-14 20:19:54 -0600) ---------------------------------------------------------------- Bruce Cran (1): Windows: set sizeof(sun_path) to 260 (MAX_PATH). Jens Axboe (43): init: fix more cases of leaking pid_file stat: check that TEMP environment variable is half-way sane server: ensure that dus->name is always NULL terminated init: fix potential buffer overrun in make_filename() verify: fix potential buffer overrun in dump_buf() file: fix potential buffer overrun in get_fs_free_counts() net engine: fix potential buffer overrun in socket path client: fix potential buffer overrun in socket path server: fix potential buffer overrun in bind string server: fix potential buffer overrun in socket setup path stat: fix wrong check for whether we have a description or not Fix missing sign conversion in ignore_error_type() Make td_verror() use an unsigned type gettime: use unsigned loop counter server: fix missing comma in fio_server_ops[] strings eta: fix potential divide by zero idletime: fix potential divide-by-zero stat: fix potential divide-by-zero backend: fix potential divide-by-zero init: remove dead code Error check fcntl() calls make_filename: another off-by-one buffer issue num2str: ensure we never access postfix[] out-of-bounds backend: better NULL termination fix for IO scheduler switching server: sanity check incoming command size (and payload) server: ensure that incoming iolog name is NULL terminated net engine: get rid of unused struct sockaddr_in6 td_verror() needs errno style error e4defrag: pass 'error' into td_verror() filesetup: silence bogus warning on close(-1) init: silence bogus td == NULL warning gettime: handle pthread_create() failure stat: warn on failure to detach DU thread gettime: init 'failed' before use Avoid overwriting allocated pid_file idletime: unlock ->start_lock in error cases Fix is_power_of_2() for longs parse: make it clear that 'cp' can't be NULL for o->off1 diskutil: make it clear that parent != NULL for json output Fix potential NULL dereference in alloc_mem_mmap() disk util: fix bug in strncpy() conversion init: fix leak bug fix from commit 60c5ec73 init: improve command line check for when to print usage/help backend.c | 11 ++++-- client.c | 2 +- diskutil.c | 12 ++++-- engines/binject.c | 7 ++-- engines/e4defrag.c | 4 +- engines/net.c | 9 ++--- engines/sg.c | 7 ++-- eta.c | 24 ++++++++--- filesetup.c | 16 ++++++-- fio.h | 5 ++- gettime.c | 12 ++++-- idletime.c | 13 ++++-- init.c | 79 +++++++++++++++++++++++++++++-------- io_u.c | 2 +- lib/num2str.c | 5 +++ libfio.c | 16 ++++++++ memory.c | 5 ++- options.c | 2 +- os/windows/posix/include/sys/un.h | 2 +- parse.c | 2 +- server.c | 40 +++++++++++++------ server.h | 1 + stat.c | 26 +++++++++--- verify.c | 22 +++++++++-- 24 files changed, 239 insertions(+), 85 deletions(-) --- Diff of recent changes: diff --git a/backend.c b/backend.c index b05e543..62bca29 100644 --- a/backend.c +++ b/backend.c @@ -182,7 +182,11 @@ static int __check_min_rate(struct thread_data *td, struct timeval *now, ratemin); return 1; } else { - rate = ((bytes - td->rate_bytes[ddir]) * 1000) / spent; + if (spent) + rate = ((bytes - td->rate_bytes[ddir]) * 1000) / spent; + else + rate = 0; + if (rate < ratemin || bytes < td->rate_bytes[ddir]) { log_err("%s: min rate %u not met, got" @@ -1110,13 +1114,14 @@ static int switch_ioscheduler(struct thread_data *td) /* * Read back and check that the selected scheduler is now the default. */ - memset(tmp, 0, sizeof(tmp)); - ret = fread(tmp, 1, sizeof(tmp) - 1, f); + ret = fread(tmp, sizeof(tmp), 1, f); if (ferror(f) || ret < 0) { td_verror(td, errno, "fread"); fclose(f); return 1; } + tmp[sizeof(tmp) - 1] = '\0'; + sprintf(tmp2, "[%s]", td->o.ioscheduler); if (!strstr(tmp, tmp2)) { diff --git a/client.c b/client.c index 05439e1..af6621d 100644 --- a/client.c +++ b/client.c @@ -388,7 +388,7 @@ static int fio_client_connect_sock(struct fio_client *client) memset(addr, 0, sizeof(*addr)); addr->sun_family = AF_UNIX; - strcpy(addr->sun_path, client->hostname); + strncpy(addr->sun_path, client->hostname, sizeof(addr->sun_path) - 1); fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { diff --git a/diskutil.c b/diskutil.c index d97c5ca..cb285cf 100644 --- a/diskutil.c +++ b/diskutil.c @@ -6,6 +6,7 @@ #include <dirent.h> #include <libgen.h> #include <math.h> +#include <assert.h> #include "fio.h" #include "smalloc.h" @@ -299,7 +300,7 @@ static struct disk_util *disk_util_add(struct thread_data *td, int majdev, sfree(du); return NULL; } - strncpy((char *) du->dus.name, basename(path) - 1, FIO_DU_NAME_SZ); + strncpy((char *) du->dus.name, basename(path), FIO_DU_NAME_SZ - 1); du->sysfs_root = path; du->major = majdev; du->minor = mindev; @@ -686,12 +687,15 @@ void show_disk_util(int terse, struct json_object *parent) return; } - if (!terse && !parent) + if (output_format == FIO_OUTPUT_JSON) + assert(parent); + + if (!terse && output_format != FIO_OUTPUT_JSON) log_info("\nDisk stats (read/write):\n"); - if (output_format == FIO_OUTPUT_JSON) { + if (output_format == FIO_OUTPUT_JSON) json_object_add_disk_utils(parent, &disk_list); - } else + else flist_for_each(entry, &disk_list) { du = flist_entry(entry, struct disk_util, list); diff --git a/engines/binject.c b/engines/binject.c index fb19062..0264d0a 100644 --- a/engines/binject.c +++ b/engines/binject.c @@ -109,10 +109,9 @@ static int fio_binject_getevents(struct thread_data *td, unsigned int min, /* * don't block for min events == 0 */ - if (!min) { - bd->fd_flags[i] = fcntl(bf->fd, F_GETFL); - fcntl(bf->fd, F_SETFL, bd->fd_flags[i] | O_NONBLOCK); - } + if (!min) + fio_set_fd_nonblocking(bf->fd, "binject"); + bd->pfds[i].fd = bf->fd; bd->pfds[i].events = POLLIN; } diff --git a/engines/e4defrag.c b/engines/e4defrag.c index 4d87f67..3599ab8 100644 --- a/engines/e4defrag.c +++ b/engines/e4defrag.c @@ -80,7 +80,7 @@ static int fio_e4defrag_init(struct thread_data *td) ed = malloc(sizeof(*ed)); if (!ed) { - td_verror(td, -ENOMEM, "io_queue_init"); + td_verror(td, ENOMEM, "io_queue_init"); return 1; } memset(ed, 0 ,sizeof(*ed)); @@ -91,7 +91,7 @@ static int fio_e4defrag_init(struct thread_data *td) ed->donor_fd = open(donor_name, O_CREAT|O_WRONLY, 0644); if (ed->donor_fd < 0) { - td_verror(td, ed->donor_fd, "io_queue_init"); + td_verror(td, errno, "io_queue_init"); log_err("Can't open donor file %s err:%d", donor_name, ed->donor_fd); free(ed); return 1; diff --git a/engines/net.c b/engines/net.c index d036a58..8087207 100644 --- a/engines/net.c +++ b/engines/net.c @@ -945,7 +945,8 @@ static int fio_netio_setup_connect_unix(struct thread_data *td, struct sockaddr_un *soun = &nd->addr_un; soun->sun_family = AF_UNIX; - strcpy(soun->sun_path, path); + memset(soun->sun_path, 0, sizeof(soun->sun_path)); + strncpy(soun->sun_path, path, sizeof(soun->sun_path) - 1); return 0; } @@ -976,7 +977,7 @@ static int fio_netio_setup_listen_unix(struct thread_data *td, const char *path) memset(addr, 0, sizeof(*addr)); addr->sun_family = AF_UNIX; - strcpy(addr->sun_path, path); + strncpy(addr->sun_path, path, sizeof(addr->sun_path) - 1); unlink(path); len = sizeof(addr->sun_family) + strlen(path) + 1; @@ -998,13 +999,11 @@ static int fio_netio_setup_listen_inet(struct thread_data *td, short port) struct netio_options *o = td->eo; struct ip_mreq mr; struct sockaddr_in sin; - struct sockaddr_in6 sin6; struct sockaddr *saddr; int fd, opt, type, domain; socklen_t len; memset(&sin, 0, sizeof(sin)); - memset(&sin6, 0, sizeof(sin6)); if (o->proto == FIO_TYPE_TCP) { type = SOCK_STREAM; @@ -1087,7 +1086,7 @@ static int fio_netio_setup_listen_inet(struct thread_data *td, short port) len = sizeof(nd->addr6); nd->addr6.sin6_family = AF_INET6; - nd->addr6.sin6_addr = sin6.sin6_addr.s6_addr ? sin6.sin6_addr : in6addr_any; + nd->addr6.sin6_addr = in6addr_any; nd->addr6.sin6_port = htons(port); } diff --git a/engines/sg.c b/engines/sg.c index 88d9125..fcd9c41 100644 --- a/engines/sg.c +++ b/engines/sg.c @@ -77,10 +77,9 @@ static int fio_sgio_getevents(struct thread_data *td, unsigned int min, /* * don't block for min events == 0 */ - if (!min) { - sd->fd_flags[i] = fcntl(f->fd, F_GETFL); - fcntl(f->fd, F_SETFL, sd->fd_flags[i] | O_NONBLOCK); - } + if (!min) + fio_set_fd_nonblocking(f->fd, "sg"); + sd->pfds[i].fd = f->fd; sd->pfds[i].events = POLLIN; } diff --git a/eta.c b/eta.c index 42066e0..7500082 100644 --- a/eta.c +++ b/eta.c @@ -174,14 +174,26 @@ static int thread_eta(struct thread_data *td) double perc, perc_t; bytes_done = ddir_rw_sum(td->io_bytes); - perc = (double) bytes_done / (double) bytes_total; - if (perc > 1.0) - perc = 1.0; + + if (bytes_total) { + perc = (double) bytes_done / (double) bytes_total; + if (perc > 1.0) + perc = 1.0; + } else + perc = 0.0; if (td->o.time_based) { - perc_t = (double) elapsed / (double) timeout; - if (perc_t < perc) - perc = perc_t; + if (timeout) { + perc_t = (double) elapsed / (double) timeout; + if (perc_t < perc) + perc = perc_t; + } else { + /* + * Will never hit, we can't have time_based + * without a timeout set. + */ + perc = 0.0; + } } eta_sec = (unsigned long) (elapsed * (1.0 / perc)) - elapsed; diff --git a/filesetup.c b/filesetup.c index bf56112..490f0fc 100644 --- a/filesetup.c +++ b/filesetup.c @@ -688,7 +688,8 @@ static unsigned long long get_fs_free_counts(struct thread_data *td) } else if (f->filetype != FIO_TYPE_FILE) continue; - strcpy(buf, f->file_name); + buf[255] = '\0'; + strncpy(buf, f->file_name, 255); if (stat(buf, &sb) < 0) { if (errno != ENOENT) @@ -914,7 +915,13 @@ int setup_files(struct thread_data *td) err = __file_invalidate_cache(td, f, old_len, extend_len); - close(f->fd); + + /* + * Shut up static checker + */ + if (f->fd != -1) + close(f->fd); + f->fd = -1; if (err) break; @@ -1325,8 +1332,11 @@ int put_file(struct thread_data *td, struct fio_file *f) if (--f->references) return 0; - if (should_fsync(td) && td->o.fsync_on_close) + if (should_fsync(td) && td->o.fsync_on_close) { f_ret = fsync(f->fd); + if (f_ret < 0) + f_ret = errno; + } if (td->io_ops->close_file) ret = td->io_ops->close_file(td, f); diff --git a/fio.h b/fio.h index 3df5bd9..544916f 100644 --- a/fio.h +++ b/fio.h @@ -351,7 +351,7 @@ enum { #define __td_verror(td, err, msg, func) \ do { \ - int ____e = (err); \ + unsigned int ____e = (err); \ if ((td)->error) \ break; \ (td)->error = ____e; \ @@ -441,6 +441,7 @@ extern char *num2str(unsigned long, int, int, int, int); extern int ioengine_load(struct thread_data *); extern int parse_dryrun(void); extern int fio_running_or_pending_io_threads(void); +extern void fio_set_fd_nonblocking(int, const char *); extern uintptr_t page_mask; extern uintptr_t page_size; @@ -587,7 +588,7 @@ static inline unsigned int td_min_bs(struct thread_data *td) return min(td->o.min_bs[DDIR_TRIM], min_bs); } -static inline int is_power_of_2(unsigned int val) +static inline int is_power_of_2(unsigned long val) { return (val != 0 && ((val & (val - 1)) == 0)); } diff --git a/gettime.c b/gettime.c index c6d45f8..fa750ec 100644 --- a/gettime.c +++ b/gettime.c @@ -534,10 +534,10 @@ int fio_monotonic_clocktest(void) struct clock_thread *threads; unsigned int nr_cpus = cpus_online(); struct clock_entry *entries; - unsigned long tentries, failed; + unsigned long tentries, failed = 0; struct clock_entry *prev, *this; uint32_t seq = 0; - int i; + unsigned int i; log_info("cs: reliable_tsc: %s\n", tsc_reliable ? "yes" : "no"); @@ -560,7 +560,11 @@ int fio_monotonic_clocktest(void) pthread_mutex_init(&t->lock, NULL); pthread_mutex_init(&t->started, NULL); pthread_mutex_lock(&t->lock); - pthread_create(&t->thread, NULL, clock_thread_fn, t); + if (pthread_create(&t->thread, NULL, clock_thread_fn, t)) { + failed++; + nr_cpus = i; + break; + } } for (i = 0; i < nr_cpus; i++) { @@ -575,7 +579,7 @@ int fio_monotonic_clocktest(void) pthread_mutex_unlock(&t->lock); } - for (failed = i = 0; i < nr_cpus; i++) { + for (i = 0; i < nr_cpus; i++) { struct clock_thread *t = &threads[i]; void *ret; diff --git a/idletime.c b/idletime.c index c0bc0bf..8d23154 100644 --- a/idletime.c +++ b/idletime.c @@ -109,12 +109,16 @@ static void *idle_prof_thread_fn(void *data) pthread_mutex_lock(&ipt->start_lock); /* exit if other threads failed to initialize */ - if (ipc.status == IDLE_PROF_STATUS_ABORT) + if (ipc.status == IDLE_PROF_STATUS_ABORT) { + pthread_mutex_unlock(&ipt->start_lock); return NULL; + } /* exit if we are doing calibration only */ - if (ipc.status == IDLE_PROF_STATUS_CALI_STOP) + if (ipc.status == IDLE_PROF_STATUS_CALI_STOP) { + pthread_mutex_unlock(&ipt->start_lock); return NULL; + } fio_gettime(&ipt->tps, NULL); ipt->state = TD_RUNNING; @@ -336,7 +340,10 @@ void fio_idle_prof_stop(void) /* calculate idleness */ if (ipc.cali_mean != 0.0) { runt = utime_since(&ipt->tps, &ipt->tpe); - ipt->idleness = ipt->loops * ipc.cali_mean / runt; + if (runt) + ipt->idleness = ipt->loops * ipc.cali_mean / runt; + else + ipt->idleness = 0.0; } else ipt->idleness = 0.0; } diff --git a/init.c b/init.c index 215b60d..7630978 100644 --- a/init.c +++ b/init.c @@ -942,6 +942,7 @@ static char *make_filename(char *buf, struct thread_options *o, { struct fpre_keyword *f; char copy[PATH_MAX]; + size_t dst_left = PATH_MAX - 1; if (!o->filename_format || !strlen(o->filename_format)) { sprintf(buf, "%s.%d.%d", jobname, jobnum, filenum); @@ -969,25 +970,47 @@ static char *make_filename(char *buf, struct thread_options *o, if (pre_len) { strncpy(dst, buf, pre_len); dst += pre_len; + dst_left -= pre_len; } switch (f->key) { - case FPRE_JOBNAME: - dst += sprintf(dst, "%s", jobname); + case FPRE_JOBNAME: { + int ret; + + ret = snprintf(dst, dst_left, "%s", jobname); + if (ret < 0) + break; + dst += ret; + dst_left -= ret; break; - case FPRE_JOBNUM: - dst += sprintf(dst, "%d", jobnum); + } + case FPRE_JOBNUM: { + int ret; + + ret = snprintf(dst, dst_left, "%d", jobnum); + if (ret < 0) + break; + dst += ret; + dst_left -= ret; break; - case FPRE_FILENUM: - dst += sprintf(dst, "%d", filenum); + } + case FPRE_FILENUM: { + int ret; + + ret = snprintf(dst, dst_left, "%d", filenum); + if (ret < 0) + break; + dst += ret; + dst_left -= ret; break; + } default: assert(0); break; } if (post_start) - strcpy(dst, buf + post_start); + strncpy(dst, buf + post_start, dst_left); strcpy(buf, copy); } while (1); @@ -1435,9 +1458,6 @@ int parse_jobs_ini(char *file, int is_buf, int stonewall_flag, int type) i++; } - for (i = 0; i < num_opts; i++) - free(opts[i]); - free(string); free(name); free(opts); @@ -1694,8 +1714,6 @@ int parse_cmd_line(int argc, char *argv[], int client_type) optind = 1; while ((c = getopt_long_only(argc, argv, ostr, l_opts, &lidx)) != -1) { - did_arg = 1; - if ((c & FIO_CLIENT_FLAG) || client_flag_set(c)) { parse_cmd_client(cur_client, argv[optind - 1]); c &= ~FIO_CLIENT_FLAG; @@ -1752,30 +1770,35 @@ int parse_cmd_line(int argc, char *argv[], int client_type) append_terse_output = 1; break; case 'h': + did_arg = 1; if (!cur_client) { usage(argv[0]); do_exit++; } break; case 'c': + did_arg = 1; if (!cur_client) { fio_show_option_help(optarg); do_exit++; } break; case 'i': + did_arg = 1; if (!cur_client) { fio_show_ioengine_help(optarg); do_exit++; } break; case 's': + did_arg = 1; dump_cmdline = 1; break; case 'r': read_only = 1; break; case 'v': + did_arg = 1; if (!cur_client) { log_info("%s\n", fio_version_string); do_exit++; @@ -1812,6 +1835,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type) do_exit++; break; case 'P': + did_arg = 1; parse_only = 1; break; case 'x': { @@ -1831,6 +1855,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type) break; } case 'p': + did_arg = 1; if (exec_profile) free(exec_profile); exec_profile = strdup(optarg); @@ -1842,8 +1867,9 @@ int parse_cmd_line(int argc, char *argv[], int client_type) if (!strncmp(opt, "name", 4) && td) { ret = add_job(td, td->o.name ?: "fio", 0, 0, client_type); if (ret) - return 0; + goto out_free; td = NULL; + did_arg = 1; } if (!td) { int is_section = !strncmp(opt, "name", 4); @@ -1857,7 +1883,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type) td = get_new_job(global, &def_thread, 1); if (!td || ioengine_load(td)) - return 0; + goto out_free; fio_options_set_ioengine_opts(l_opts, td); } @@ -1879,7 +1905,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type) if (!ret && !strcmp(opt, "ioengine")) { free_ioengine(td); if (ioengine_load(td)) - return 0; + goto out_free; fio_options_set_ioengine_opts(l_opts, td); } break; @@ -1887,7 +1913,12 @@ int parse_cmd_line(int argc, char *argv[], int client_type) case FIO_GETOPT_IOENGINE: { const char *opt = l_opts[lidx].name; char *val = optarg; + + if (!td) + break; + ret = fio_cmd_ioengine_option_parse(td, opt, val); + did_arg = 1; break; } case 'w': @@ -1902,6 +1933,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type) } break; case 'S': + did_arg = 1; if (nr_clients) { log_err("fio: can't be both client and server\n"); do_exit++; @@ -1914,17 +1946,21 @@ int parse_cmd_line(int argc, char *argv[], int client_type) backend = 1; break; case 'D': + if (pid_file) + free(pid_file); pid_file = strdup(optarg); break; case 'I': if ((ret = fio_idle_prof_parse_opt(optarg))) { /* exit on error and calibration only */ + did_arg = 1; do_exit++; - if (ret == -1) + if (ret == -1) exit_val = 1; } break; case 'C': + did_arg = 1; if (is_backend) { log_err("fio: can't be both client and server\n"); do_exit++; @@ -1951,10 +1987,12 @@ int parse_cmd_line(int argc, char *argv[], int client_type) } break; case 'T': + did_arg = 1; do_exit++; exit_val = fio_monotonic_clocktest(); break; case 'G': + did_arg = 1; do_exit++; exit_val = fio_crctest(optarg); break; @@ -1994,8 +2032,11 @@ int parse_cmd_line(int argc, char *argv[], int client_type) free(pid_file); if (td) { - if (!ret) + if (!ret) { ret = add_job(td, td->o.name ?: "fio", 0, 0, client_type); + if (ret) + did_arg = 1; + } } while (!ret && optind < argc) { @@ -2005,6 +2046,10 @@ int parse_cmd_line(int argc, char *argv[], int client_type) optind++; } +out_free: + if (pid_file) + free(pid_file); + return ini_idx; } diff --git a/io_u.c b/io_u.c index 411da32..4b0b5a7 100644 --- a/io_u.c +++ b/io_u.c @@ -678,7 +678,7 @@ static void set_rw_ddir(struct thread_data *td, struct io_u *io_u) void put_file_log(struct thread_data *td, struct fio_file *f) { - int ret = put_file(td, f); + unsigned int ret = put_file(td, f); if (ret) td_verror(td, ret, "file close"); diff --git a/lib/num2str.c b/lib/num2str.c index 12d6f39..8961868 100644 --- a/lib/num2str.c +++ b/lib/num2str.c @@ -4,6 +4,8 @@ #include "../fio.h" +#define ARRAY_LENGTH(arr) sizeof(arr) / sizeof((arr)[0]) + /* * Cheesy number->string conversion, complete with carry rounding error. */ @@ -46,6 +48,9 @@ char *num2str(unsigned long num, int maxlen, int base, int pow2, int unit_base) if (modulo == -1U) { done: + if (post_index >= ARRAY_LENGTH(postfix)) + post_index = 0; + sprintf(buf, "%lu%s%s", num, postfix[post_index], byte_postfix[byte_post_index]); return buf; diff --git a/libfio.c b/libfio.c index 3fde492..5ed8c60 100644 --- a/libfio.c +++ b/libfio.c @@ -27,6 +27,7 @@ #include <signal.h> #include <stdint.h> #include <locale.h> +#include <fcntl.h> #include "fio.h" #include "smalloc.h" @@ -233,6 +234,21 @@ int fio_running_or_pending_io_threads(void) return 0; } +void fio_set_fd_nonblocking(int fd, const char *who) +{ + int flags; + + flags = fcntl(fd, F_GETFL); + if (flags < 0) + log_err("fio: %s failed to get file flags: %s\n", who, strerror(errno)); + else { + flags |= O_NONBLOCK; + flags = fcntl(fd, F_SETFL, flags); + if (flags < 0) + log_err("fio: %s failed to get file flags: %s\n", who, strerror(errno)); + } +} + static int endian_check(void) { union { diff --git a/memory.c b/memory.c index b208320..8c06d94 100644 --- a/memory.c +++ b/memory.c @@ -158,9 +158,10 @@ static int alloc_mem_mmap(struct thread_data *td, size_t total_mem) if (td->orig_buffer == MAP_FAILED) { td_verror(td, errno, "mmap"); td->orig_buffer = NULL; - if (td->mmapfd) { + if (td->mmapfd != 1) { close(td->mmapfd); - unlink(td->o.mmapfile); + if (td->o.mmapfile) + unlink(td->o.mmapfile); } return 1; diff --git a/options.c b/options.c index 9096a32..50af7b4 100644 --- a/options.c +++ b/options.c @@ -269,7 +269,7 @@ static int ignore_error_type(struct thread_data *td, int etype, char *str) } else { error[i] = atoi(fname); if (error[i] < 0) - error[i] = error[i]; + error[i] = -error[i]; } if (!error[i]) { log_err("Unknown error %s, please use number value \n", diff --git a/os/windows/posix/include/sys/un.h b/os/windows/posix/include/sys/un.h index b9ea630..e418c6d 100644 --- a/os/windows/posix/include/sys/un.h +++ b/os/windows/posix/include/sys/un.h @@ -7,7 +7,7 @@ typedef int in_port_t; struct sockaddr_un { sa_family_t sun_family; /* Address family */ - char sun_path[]; /* Socket pathname */ + char sun_path[260]; /* Socket pathname */ }; #endif /* SYS_UN_H */ diff --git a/parse.c b/parse.c index 83c59f7..188f728 100644 --- a/parse.c +++ b/parse.c @@ -624,7 +624,7 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data, ret = 1; for (i = 0; i < PARSE_MAX_VP; i++) { vp = &posval[i]; - if (!vp->ival || vp->ival[0] == '\0') + if (!vp->ival || vp->ival[0] == '\0' || !cp) continue; all_skipped = 0; if (!strncmp(vp->ival, ptr, str_match_len(vp, ptr))) { diff --git a/server.c b/server.c index 3346445..077dce5 100644 --- a/server.c +++ b/server.c @@ -4,7 +4,6 @@ #include <unistd.h> #include <limits.h> #include <errno.h> -#include <fcntl.h> #include <sys/poll.h> #include <sys/types.h> #include <sys/wait.h> @@ -68,7 +67,7 @@ static const char *fio_server_ops[FIO_NET_CMD_NR] = { "DISK_UTIL", "SERVER_START", "ADD_JOB", - "CMD_RUN" + "CMD_RUN", "CMD_IOLOG", }; @@ -209,7 +208,7 @@ static int verify_convert_cmd(struct fio_net_cmd *cmd) */ struct fio_net_cmd *fio_net_recv_cmd(int sk) { - struct fio_net_cmd cmd, *cmdret = NULL; + struct fio_net_cmd cmd, *tmp, *cmdret = NULL; size_t cmd_size = 0, pdu_offset = 0; uint16_t crc; int ret, first = 1; @@ -232,7 +231,19 @@ struct fio_net_cmd *fio_net_recv_cmd(int sk) } else cmd_size += cmd.pdu_len; - cmdret = realloc(cmdret, cmd_size); + if (cmd_size / 1024 > FIO_SERVER_MAX_CMD_MB * 1024) { + log_err("fio: cmd+pdu too large (%llu)\n", (unsigned long long) cmd_size); + ret = 1; + break; + } + + tmp = realloc(cmdret, cmd_size); + if (!tmp) { + log_err("fio: server failed allocating cmd\n"); + ret = 1; + break; + } + cmdret = tmp; if (first) memcpy(cmdret, &cmd, sizeof(cmd)); @@ -843,14 +854,12 @@ static int accept_loop(int listen_sk) struct sockaddr_in6 addr6; socklen_t len = use_ipv6 ? sizeof(addr6) : sizeof(addr); struct pollfd pfd; - int ret = 0, sk, flags, exitval = 0; + int ret = 0, sk, exitval = 0; FLIST_HEAD(conn_list); dprint(FD_NET, "server enter accept loop\n"); - flags = fcntl(listen_sk, F_GETFL); - flags |= O_NONBLOCK; - fcntl(listen_sk, F_SETFL, flags); + fio_set_fd_nonblocking(listen_sk, "server"); while (!exit_backend) { const char *from; @@ -1095,7 +1104,8 @@ static void convert_dus(struct disk_util_stat *dst, struct disk_util_stat *src) { int i; - strcpy((char *) dst->name, (char *) src->name); + dst->name[FIO_DU_NAME_SZ - 1] = '\0'; + strncpy((char *) dst->name, (char *) src->name, FIO_DU_NAME_SZ - 1); for (i = 0; i < 2; i++) { dst->s.ios[i] = cpu_to_le32(src->s.ios[i]); @@ -1215,7 +1225,9 @@ int fio_send_iolog(struct thread_data *td, struct io_log *log, const char *name) pdu.nr_samples = __cpu_to_le32(log->nr_samples); pdu.log_type = cpu_to_le32(log->log_type); pdu.compressed = cpu_to_le32(use_zlib); - strcpy((char *) pdu.name, name); + + strncpy((char *) pdu.name, name, FIO_NET_NAME_MAX); + pdu.name[FIO_NET_NAME_MAX - 1] = '\0'; for (i = 0; i < log->nr_samples; i++) { struct io_sample *s = &log->log[i]; @@ -1338,7 +1350,7 @@ static int fio_init_server_sock(void) memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, bind_sock); + strncpy(addr.sun_path, bind_sock, sizeof(addr.sun_path) - 1); len = sizeof(addr.sun_family) + strlen(bind_sock) + 1; @@ -1367,6 +1379,8 @@ static int fio_init_server_connection(void) if (sk < 0) return sk; + memset(bind_str, 0, sizeof(bind_str)); + if (!bind_sock) { char *p, port[16]; const void *src; @@ -1386,9 +1400,9 @@ static int fio_init_server_connection(void) if (p) strcat(p, port); else - strcpy(bind_str, port); + strncpy(bind_str, port, sizeof(bind_str) - 1); } else - strcpy(bind_str, bind_sock); + strncpy(bind_str, bind_sock, sizeof(bind_str) - 1); log_info("fio: server listening on %s\n", bind_str); diff --git a/server.h b/server.h index 3a279f0..2958e73 100644 --- a/server.h +++ b/server.h @@ -41,6 +41,7 @@ enum { FIO_SERVER_VER = 33, FIO_SERVER_MAX_FRAGMENT_PDU = 1024, + FIO_SERVER_MAX_CMD_MB = 2048, FIO_NET_CMD_QUIT = 1, FIO_NET_CMD_EXIT = 2, diff --git a/stat.c b/stat.c index 509c6f0..fbf0118 100644 --- a/stat.c +++ b/stat.c @@ -831,7 +831,7 @@ static void show_thread_status_terse_v2(struct thread_stat *ts, log_info("\n"); /* Additional output if description is set */ - if (ts->description) + if (strlen(ts->description)) log_info(";%s", ts->description); log_info("\n"); @@ -1471,7 +1471,12 @@ void show_running_run_stats(void) fio_mutex_down(stat_mutex); if (!pthread_create(&thread, NULL, __show_running_run_stats, NULL)) { - pthread_detach(thread); + int err; + + err = pthread_detach(thread); + if (err) + log_err("fio: DU thread detach failed: %s\n", strerror(err)); + return; } @@ -1494,8 +1499,11 @@ static int check_status_file(void) return 0; temp_dir = getenv("TMPDIR"); - if (temp_dir == NULL) + if (temp_dir == NULL) { temp_dir = getenv("TEMP"); + if (temp_dir && strlen(temp_dir) >= PATH_MAX) + temp_dir = NULL; + } if (temp_dir == NULL) temp_dir = "/tmp"; @@ -1800,7 +1808,11 @@ void add_bw_sample(struct thread_data *td, enum fio_ddir ddir, unsigned int bs, if (!delta) continue; /* No entries for interval */ - rate = delta * 1000 / spent / 1024; + if (spent) + rate = delta * 1000 / spent / 1024; + else + rate = 0; + add_stat_sample(&ts->bw_stat[ddir], rate); if (td->bw_log) @@ -1835,7 +1847,11 @@ void add_iops_sample(struct thread_data *td, enum fio_ddir ddir, unsigned int bs if (!delta) continue; /* No entries for interval */ - iops = (delta * 1000) / spent; + if (spent) + iops = (delta * 1000) / spent; + else + iops = 0; + add_stat_sample(&ts->iops_stat[ddir], iops); if (td->iops_log) diff --git a/verify.c b/verify.c index 9eb532a..282a8cf 100644 --- a/verify.c +++ b/verify.c @@ -226,16 +226,32 @@ struct vcont { unsigned int crc_len; }; +#define DUMP_BUF_SZ 255 +static int dump_buf_warned; + static void dump_buf(char *buf, unsigned int len, unsigned long long offset, const char *type, struct fio_file *f) { - char *ptr, fname[256]; + char *ptr, fname[DUMP_BUF_SZ]; + size_t buf_left = DUMP_BUF_SZ; int ret, fd; ptr = strdup(f->file_name); - strcpy(fname, basename(ptr)); - sprintf(fname + strlen(fname), ".%llu.%s", offset, type); + fname[DUMP_BUF_SZ - 1] = '\0'; + strncpy(fname, basename(ptr), DUMP_BUF_SZ - 1); + + buf_left -= strlen(fname); + if (buf_left <= 0) { + if (!dump_buf_warned) { + log_err("fio: verify failure dump buffer too small\n"); + dump_buf_warned = 1; + } + free(ptr); + return; + } + + snprintf(fname + strlen(fname), buf_left, ".%llu.%s", offset, type); fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY, 0644); if (fd < 0) { -- To unsubscribe from this list: send the line "unsubscribe fio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html