iolog: punt freeing of data back to original thread
authorJens Axboe <axboe@kernel.dk>
Thu, 22 Jun 2017 22:20:36 +0000 (16:20 -0600)
committerJens Axboe <axboe@kernel.dk>
Thu, 22 Jun 2017 22:20:36 +0000 (16:20 -0600)
This is a bit of a hack, since we can't touch the memory passed in.
But we should, at most have 1-2 entries deferred, so having an
array of 8 should suffice. Add a single-trigger warning if that
logic fails.

This should fix corruption on using log compression, when we have
to do runtime compressing.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
iolog.c
iolog.h

diff --git a/iolog.c b/iolog.c
index 05cabd0c05abb7ff69a75dbb39b1dd4a0e01f036..27c14eb3630fda9179722d17bf0229374190e042 100644 (file)
--- a/iolog.c
+++ b/iolog.c
@@ -643,6 +643,7 @@ void setup_log(struct io_log **log, struct log_params *p,
                l->log_gz = 0;
        else if (l->log_gz || l->log_gz_store) {
                mutex_init_pshared(&l->chunk_lock);
+               mutex_init_pshared(&l->deferred_free_lock);
                p->td->flags |= TD_F_COMPRESS_LOG;
        }
 
@@ -1144,6 +1145,42 @@ size_t log_chunk_sizes(struct io_log *log)
 
 #ifdef CONFIG_ZLIB
 
+static bool warned_on_drop;
+
+static void iolog_put_deferred(struct io_log *log, void *ptr)
+{
+       if (!ptr)
+               return;
+
+       pthread_mutex_lock(&log->deferred_free_lock);
+       if (log->deferred < IOLOG_MAX_DEFER) {
+               log->deferred_items[log->deferred] = ptr;
+               log->deferred++;
+       } else if (!warned_on_drop) {
+               log_err("fio: had to drop log entry free\n");
+               warned_on_drop = true;
+       }
+       pthread_mutex_unlock(&log->deferred_free_lock);
+}
+
+static void iolog_free_deferred(struct io_log *log)
+{
+       int i;
+
+       if (!log->deferred)
+               return;
+
+       pthread_mutex_lock(&log->deferred_free_lock);
+
+       for (i = 0; i < log->deferred; i++) {
+               free(log->deferred_items[i]);
+               log->deferred_items[i] = NULL;
+       }
+
+       log->deferred = 0;
+       pthread_mutex_unlock(&log->deferred_free_lock);
+}
+
 static int gz_work(struct iolog_flush_data *data)
 {
        struct iolog_compress *c = NULL;
@@ -1236,7 +1273,7 @@ static int gz_work(struct iolog_flush_data *data)
        if (ret != Z_OK)
                log_err("fio: deflateEnd %d\n", ret);
 
-       free(data->samples);
+       iolog_put_deferred(data->log, data->samples);
 
        if (!flist_empty(&list)) {
                pthread_mutex_lock(&data->log->chunk_lock);
@@ -1362,6 +1399,9 @@ int iolog_cur_flush(struct io_log *log, struct io_logs *cur_log)
        cur_log->log = NULL;
 
        workqueue_enqueue(&log->td->log_compress_wq, &data->work);
+
+       iolog_free_deferred(log);
+
        return 0;
 }
 #else
diff --git a/iolog.h b/iolog.h
index 0733ad33c3c8b5872b3f3f897a299f9b41d1e606..6274aef9e86c92b6dc44539651a7d234180c0e69 100644 (file)
--- a/iolog.h
+++ b/iolog.h
@@ -131,6 +131,11 @@ struct io_log {
        pthread_mutex_t chunk_lock;
        unsigned int chunk_seq;
        struct flist_head chunk_list;
+
+       pthread_mutex_t deferred_free_lock;
+#define IOLOG_MAX_DEFER        8
+       void *deferred_items[IOLOG_MAX_DEFER];
+       unsigned int deferred;
 };
 
 /*