From 90eff1c9f01d2f8b4ff8bc75a2bf120a1789b37c Mon Sep 17 00:00:00 2001 From: Sitsofe Wheeler Date: Sun, 20 Nov 2016 20:55:06 +0000 Subject: [PATCH] fio: Fix (unsigned) integer overflow issues This patch tries to address issues found when compiling fio with clang's undefined behaviour sanitizer on 32 bit Linux. While this generated many false positives it did identify a number of subtle issues when rates/amounts/time calculations went above 32 bit values. The following job was used: [global] time_based runtime=180m bs=256k rw=randrw norandommap rate=512M ioengine=null direct=1 iodepth=8 thread numjobs=10 ramp_time=20m [null] size=1P It should fix https://github.com/axboe/fio/issues/270 because various 32 bit ETA variables were overflowing due to the microsecond arithmetic being done on them (even on 64 bit systems). This patch should also fix https://github.com/axboe/fio/issues/194 and https://github.com/axboe/fio/issues/266 because 64 bit Windows is a LLP64 platform so ints and longs still default to 32 bits. Signed-off-by: Sitsofe Wheeler --- backend.c | 7 ++++--- cconv.c | 8 ++++---- client.c | 6 +++--- eta.c | 10 +++++----- fio.h | 4 ++-- gettime.c | 2 +- io_u.c | 3 ++- mutex.c | 2 +- server.c | 6 +++--- stat.h | 4 ++-- thread_options.h | 8 ++++---- 11 files changed, 31 insertions(+), 29 deletions(-) diff --git a/backend.c b/backend.c index 60cea3c6..8616fc2a 100644 --- a/backend.c +++ b/backend.c @@ -1864,8 +1864,8 @@ static void dump_td_info(struct thread_data *td) /* * Run over the job map and reap the threads that have exited, if any. */ -static void reap_threads(unsigned int *nr_running, unsigned int *t_rate, - unsigned int *m_rate) +static void reap_threads(unsigned int *nr_running, uint64_t *t_rate, + uint64_t *m_rate) { struct thread_data *td; unsigned int cputhreads, realthreads, pending; @@ -2103,7 +2103,8 @@ static bool waitee_running(struct thread_data *me) static void run_threads(struct sk_out *sk_out) { struct thread_data *td; - unsigned int i, todo, nr_running, m_rate, t_rate, nr_started; + unsigned int i, todo, nr_running, nr_started; + uint64_t m_rate, t_rate; uint64_t spent; if (fio_gtod_offload && fio_start_gtod_thread()) diff --git a/cconv.c b/cconv.c index 6e0f6094..0032cc04 100644 --- a/cconv.c +++ b/cconv.c @@ -131,8 +131,8 @@ void convert_thread_options_to_cpu(struct thread_options *o, } o->rwmix[i] = le32_to_cpu(top->rwmix[i]); - o->rate[i] = le32_to_cpu(top->rate[i]); - o->ratemin[i] = le32_to_cpu(top->ratemin[i]); + o->rate[i] = le64_to_cpu(top->rate[i]); + o->ratemin[i] = le64_to_cpu(top->ratemin[i]); o->rate_iops[i] = le32_to_cpu(top->rate_iops[i]); o->rate_iops_min[i] = le32_to_cpu(top->rate_iops_min[i]); @@ -505,8 +505,8 @@ void convert_thread_options_to_net(struct thread_options_pack *top, } top->rwmix[i] = cpu_to_le32(o->rwmix[i]); - top->rate[i] = cpu_to_le32(o->rate[i]); - top->ratemin[i] = cpu_to_le32(o->ratemin[i]); + top->rate[i] = cpu_to_le64(o->rate[i]); + top->ratemin[i] = cpu_to_le64(o->ratemin[i]); top->rate_iops[i] = cpu_to_le32(o->rate_iops[i]); top->rate_iops_min[i] = cpu_to_le32(o->rate_iops_min[i]); diff --git a/client.c b/client.c index 9698122d..9a8cf17e 100644 --- a/client.c +++ b/client.c @@ -1135,11 +1135,11 @@ static void convert_jobs_eta(struct jobs_eta *je) je->files_open = le32_to_cpu(je->files_open); for (i = 0; i < DDIR_RWDIR_CNT; i++) { - je->m_rate[i] = le32_to_cpu(je->m_rate[i]); - je->t_rate[i] = le32_to_cpu(je->t_rate[i]); + je->m_rate[i] = le64_to_cpu(je->m_rate[i]); + je->t_rate[i] = le64_to_cpu(je->t_rate[i]); je->m_iops[i] = le32_to_cpu(je->m_iops[i]); je->t_iops[i] = le32_to_cpu(je->t_iops[i]); - je->rate[i] = le32_to_cpu(je->rate[i]); + je->rate[i] = le64_to_cpu(je->rate[i]); je->iops[i] = le32_to_cpu(je->iops[i]); } diff --git a/eta.c b/eta.c index 3c1aeeee..c2c9d4e8 100644 --- a/eta.c +++ b/eta.c @@ -235,7 +235,7 @@ static unsigned long thread_eta(struct thread_data *td) || td->runstate == TD_SETTING_UP || td->runstate == TD_RAMP || td->runstate == TD_PRE_READING) { - int t_eta = 0, r_eta = 0; + int64_t t_eta = 0, r_eta = 0; unsigned long long rate_bytes; /* @@ -285,7 +285,7 @@ static unsigned long thread_eta(struct thread_data *td) static void calc_rate(int unified_rw_rep, unsigned long mtime, unsigned long long *io_bytes, - unsigned long long *prev_io_bytes, unsigned int *rate) + unsigned long long *prev_io_bytes, uint64_t *rate) { int i; @@ -341,7 +341,7 @@ bool calc_thread_status(struct jobs_eta *je, int force) { struct thread_data *td; int i, unified_rw_rep; - unsigned long rate_time, disp_time, bw_avg_time, *eta_secs; + uint64_t rate_time, disp_time, bw_avg_time, *eta_secs; unsigned long long io_bytes[DDIR_RWDIR_CNT]; unsigned long long io_iops[DDIR_RWDIR_CNT]; struct timeval now; @@ -367,8 +367,8 @@ bool calc_thread_status(struct jobs_eta *je, int force) if (!ddir_rw_sum(disp_io_bytes)) fill_start_time(&disp_prev_time); - eta_secs = malloc(thread_number * sizeof(unsigned long)); - memset(eta_secs, 0, thread_number * sizeof(unsigned long)); + eta_secs = malloc(thread_number * sizeof(uint64_t)); + memset(eta_secs, 0, thread_number * sizeof(uint64_t)); je->elapsed_sec = (mtime_since_genesis() + 999) / 1000; diff --git a/fio.h b/fio.h index 74c1b306..7e327887 100644 --- a/fio.h +++ b/fio.h @@ -269,10 +269,10 @@ struct thread_data { * Rate state */ uint64_t rate_bps[DDIR_RWDIR_CNT]; - unsigned long rate_next_io_time[DDIR_RWDIR_CNT]; + uint64_t rate_next_io_time[DDIR_RWDIR_CNT]; unsigned long rate_bytes[DDIR_RWDIR_CNT]; unsigned long rate_blocks[DDIR_RWDIR_CNT]; - unsigned long rate_io_issue_bytes[DDIR_RWDIR_CNT]; + unsigned long long rate_io_issue_bytes[DDIR_RWDIR_CNT]; struct timeval lastrate[DDIR_RWDIR_CNT]; int64_t last_usec; struct frand_state poisson_state; diff --git a/gettime.c b/gettime.c index 73b48b04..85ba7cba 100644 --- a/gettime.c +++ b/gettime.c @@ -381,7 +381,7 @@ void fio_clock_init(void) uint64_t utime_since(const struct timeval *s, const struct timeval *e) { - long sec, usec; + int64_t sec, usec; sec = e->tv_sec - s->tv_sec; usec = e->tv_usec - s->tv_usec; diff --git a/io_u.c b/io_u.c index 7b51dd2e..428d4b7f 100644 --- a/io_u.c +++ b/io_u.c @@ -659,7 +659,8 @@ int io_u_quiesce(struct thread_data *td) static enum fio_ddir rate_ddir(struct thread_data *td, enum fio_ddir ddir) { enum fio_ddir odir = ddir ^ 1; - long usec, now; + long usec; + uint64_t now; assert(ddir_rw(ddir)); now = utime_since_now(&td->start); diff --git a/mutex.c b/mutex.c index e5b045ec..5e5a0648 100644 --- a/mutex.c +++ b/mutex.c @@ -162,7 +162,7 @@ int fio_mutex_down_timeout(struct fio_mutex *mutex, unsigned int msecs) t.tv_nsec = tv_s.tv_usec * 1000; t.tv_sec += msecs / 1000; - t.tv_nsec += ((msecs * 1000000) % 1000000000); + t.tv_nsec += ((msecs * 1000000ULL) % 1000000000); if (t.tv_nsec >= 1000000000) { t.tv_nsec -= 1000000000; t.tv_sec++; diff --git a/server.c b/server.c index 091c1613..c520b6bb 100644 --- a/server.c +++ b/server.c @@ -912,11 +912,11 @@ static int handle_send_eta_cmd(struct fio_net_cmd *cmd) je->files_open = cpu_to_le32(je->files_open); for (i = 0; i < DDIR_RWDIR_CNT; i++) { - je->m_rate[i] = cpu_to_le32(je->m_rate[i]); - je->t_rate[i] = cpu_to_le32(je->t_rate[i]); + je->m_rate[i] = cpu_to_le64(je->m_rate[i]); + je->t_rate[i] = cpu_to_le64(je->t_rate[i]); je->m_iops[i] = cpu_to_le32(je->m_iops[i]); je->t_iops[i] = cpu_to_le32(je->t_iops[i]); - je->rate[i] = cpu_to_le32(je->rate[i]); + je->rate[i] = cpu_to_le64(je->rate[i]); je->iops[i] = cpu_to_le32(je->iops[i]); } diff --git a/stat.h b/stat.h index e6f77599..de5c12a5 100644 --- a/stat.h +++ b/stat.h @@ -224,9 +224,9 @@ struct jobs_eta { uint32_t files_open; - uint32_t m_rate[DDIR_RWDIR_CNT], t_rate[DDIR_RWDIR_CNT]; + uint64_t m_rate[DDIR_RWDIR_CNT], t_rate[DDIR_RWDIR_CNT]; uint32_t m_iops[DDIR_RWDIR_CNT], t_iops[DDIR_RWDIR_CNT]; - uint32_t rate[DDIR_RWDIR_CNT]; + uint64_t rate[DDIR_RWDIR_CNT]; uint32_t iops[DDIR_RWDIR_CNT]; uint64_t elapsed_sec; uint64_t eta_sec; diff --git a/thread_options.h b/thread_options.h index 5e379e32..8ec6b971 100644 --- a/thread_options.h +++ b/thread_options.h @@ -251,8 +251,8 @@ struct thread_options { char *exec_prerun; char *exec_postrun; - unsigned int rate[DDIR_RWDIR_CNT]; - unsigned int ratemin[DDIR_RWDIR_CNT]; + uint64_t rate[DDIR_RWDIR_CNT]; + uint64_t ratemin[DDIR_RWDIR_CNT]; unsigned int ratecycle; unsigned int io_submit_mode; unsigned int rate_iops[DDIR_RWDIR_CNT]; @@ -516,8 +516,8 @@ struct thread_options_pack { uint8_t exec_prerun[FIO_TOP_STR_MAX]; uint8_t exec_postrun[FIO_TOP_STR_MAX]; - uint32_t rate[DDIR_RWDIR_CNT]; - uint32_t ratemin[DDIR_RWDIR_CNT]; + uint64_t rate[DDIR_RWDIR_CNT]; + uint64_t ratemin[DDIR_RWDIR_CNT]; uint32_t ratecycle; uint32_t io_submit_mode; uint32_t rate_iops[DDIR_RWDIR_CNT]; -- 2.25.1