From 0777612739319296ee25047c1bdb56207187c463 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 13 Aug 2018 20:21:05 -0600 Subject: [PATCH] Fix double free of zone cache data We can't set it up in the parsing callback, as that happens before we fork off the thread. Fixes a segfault with: ./fio --ioengine=libaio --randrepeat=0 --norandommap --thread --direct=1 --name=pre_test --rw=randwrite --bssplit=4k/67:8k/10:16k/7:32k/3:64k/13 --random_distribution=zoned:50/5:30/15:20/80 --iodepth=32 --runtime=60 --time_based --numjobs=2 --filename=/dev/nvme0n1p9 --group_reporting=1 Fixes: https://github.com/axboe/fio/issues/650 Fixes: e0a04ac15f61 ("Add support for zones of random IO, with varying frequency of access") Signed-off-by: Jens Axboe --- Makefile | 2 +- backend.c | 13 +++------- options.c | 42 ------------------------------ zone-dist.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++ zone-dist.h | 7 +++++ 5 files changed, 86 insertions(+), 52 deletions(-) create mode 100644 zone-dist.c create mode 100644 zone-dist.h diff --git a/Makefile b/Makefile index 20d3ec12..f9bd7877 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ SOURCE := $(sort $(patsubst $(SRCDIR)/%,%,$(wildcard $(SRCDIR)/crc/*.c)) \ gettime-thread.c helpers.c json.c idletime.c td_error.c \ profiles/tiobench.c profiles/act.c io_u_queue.c filelock.c \ workqueue.c rate-submit.c optgroup.c helper_thread.c \ - steadystate.c + steadystate.c zone-dist.c ifdef CONFIG_LIBHDFS HDFSFLAGS= -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/linux -I $(FIO_LIBHDFS_INCLUDE) diff --git a/backend.c b/backend.c index f6cfbdd8..36bde6a5 100644 --- a/backend.c +++ b/backend.c @@ -47,6 +47,7 @@ #include "rate-submit.h" #include "helper_thread.h" #include "pshared.h" +#include "zone-dist.h" static struct fio_sem *startup_sem; static struct flist_head *cgroup_list; @@ -1592,6 +1593,8 @@ static void *thread_main(void *data) goto err; } + td_zone_gen_index(td); + /* * Do this early, we don't want the compress threads to be limited * to the same CPUs as the IO workers. So do this before we set @@ -1907,15 +1910,7 @@ err: close_ioengine(td); cgroup_shutdown(td, cgroup_mnt); verify_free_state(td); - - if (td->zone_state_index) { - int i; - - for (i = 0; i < DDIR_RWDIR_CNT; i++) - free(td->zone_state_index[i]); - free(td->zone_state_index); - td->zone_state_index = NULL; - } + td_zone_free_index(td); if (fio_option_is_set(o, cpumask)) { ret = fio_cpuset_exit(&o->cpumask); diff --git a/options.c b/options.c index f5920278..1c28a021 100644 --- a/options.c +++ b/options.c @@ -959,48 +959,6 @@ static int zone_split_ddir(struct thread_options *o, enum fio_ddir ddir, return 0; } -static void __td_zone_gen_index(struct thread_data *td, enum fio_ddir ddir) -{ - unsigned int i, j, sprev, aprev; - uint64_t sprev_sz; - - td->zone_state_index[ddir] = malloc(sizeof(struct zone_split_index) * 100); - - sprev_sz = sprev = aprev = 0; - for (i = 0; i < td->o.zone_split_nr[ddir]; i++) { - struct zone_split *zsp = &td->o.zone_split[ddir][i]; - - for (j = aprev; j < aprev + zsp->access_perc; j++) { - struct zone_split_index *zsi = &td->zone_state_index[ddir][j]; - - zsi->size_perc = sprev + zsp->size_perc; - zsi->size_perc_prev = sprev; - - zsi->size = sprev_sz + zsp->size; - zsi->size_prev = sprev_sz; - } - - aprev += zsp->access_perc; - sprev += zsp->size_perc; - sprev_sz += zsp->size; - } -} - -/* - * Generate state table for indexes, so we don't have to do it inline from - * the hot IO path - */ -static void td_zone_gen_index(struct thread_data *td) -{ - int i; - - td->zone_state_index = malloc(DDIR_RWDIR_CNT * - sizeof(struct zone_split_index *)); - - for (i = 0; i < DDIR_RWDIR_CNT; i++) - __td_zone_gen_index(td, i); -} - static int parse_zoned_distribution(struct thread_data *td, const char *input, bool absolute) { diff --git a/zone-dist.c b/zone-dist.c new file mode 100644 index 00000000..819d531c --- /dev/null +++ b/zone-dist.c @@ -0,0 +1,74 @@ +#include +#include "fio.h" +#include "zone-dist.h" + +static void __td_zone_gen_index(struct thread_data *td, enum fio_ddir ddir) +{ + unsigned int i, j, sprev, aprev; + uint64_t sprev_sz; + + td->zone_state_index[ddir] = malloc(sizeof(struct zone_split_index) * 100); + + sprev_sz = sprev = aprev = 0; + for (i = 0; i < td->o.zone_split_nr[ddir]; i++) { + struct zone_split *zsp = &td->o.zone_split[ddir][i]; + + for (j = aprev; j < aprev + zsp->access_perc; j++) { + struct zone_split_index *zsi = &td->zone_state_index[ddir][j]; + + zsi->size_perc = sprev + zsp->size_perc; + zsi->size_perc_prev = sprev; + + zsi->size = sprev_sz + zsp->size; + zsi->size_prev = sprev_sz; + } + + aprev += zsp->access_perc; + sprev += zsp->size_perc; + sprev_sz += zsp->size; + } +} + +static bool has_zones(struct thread_data *td) +{ + int i, zones = 0; + + for (i = 0; i < DDIR_RWDIR_CNT; i++) + zones += td->o.zone_split_nr[i]; + + return zones != 0; +} + +/* + * Generate state table for indexes, so we don't have to do it inline from + * the hot IO path + */ +void td_zone_gen_index(struct thread_data *td) +{ + int i; + + if (!has_zones(td)) + return; + + td->zone_state_index = malloc(DDIR_RWDIR_CNT * + sizeof(struct zone_split_index *)); + + for (i = 0; i < DDIR_RWDIR_CNT; i++) + __td_zone_gen_index(td, i); +} + +void td_zone_free_index(struct thread_data *td) +{ + int i; + + if (!td->zone_state_index) + return; + + for (i = 0; i < DDIR_RWDIR_CNT; i++) { + free(td->zone_state_index[i]); + td->zone_state_index[i] = NULL; + } + + free(td->zone_state_index); + td->zone_state_index = NULL; +} diff --git a/zone-dist.h b/zone-dist.h new file mode 100644 index 00000000..c0b28844 --- /dev/null +++ b/zone-dist.h @@ -0,0 +1,7 @@ +#ifndef FIO_ZONE_DIST_H +#define FIO_ZONE_DIST_H + +void td_zone_gen_index(struct thread_data *td); +void td_zone_free_index(struct thread_data *td); + +#endif -- 2.25.1