iolog: fix 'cur_log' leaks
[fio.git] / iolog.c
diff --git a/iolog.c b/iolog.c
index 75958f2ea30c7e840caa81838c539f2e0134dab7..ff521df4719818e2ecf368ef021e1763be5a1f3b 100644 (file)
--- a/iolog.c
+++ b/iolog.c
@@ -587,6 +587,15 @@ void setup_log(struct io_log **log, struct log_params *p,
        l->filename = strdup(filename);
        l->td = p->td;
 
+       if (l->td && l->td->o.io_submit_mode != IO_MODE_OFFLOAD) {
+               struct io_logs *p;
+
+               p = calloc(1, sizeof(*l->pending));
+               p->max_samples = DEF_LOG_ENTRIES;
+               p->log = calloc(p->max_samples, log_entry_sz(l));
+               l->pending = p;
+       }
+
        if (l->log_offset)
                l->log_ddir_mask = LOG_OFFSET_SAMPLE_BIT;
 
@@ -595,7 +604,7 @@ void setup_log(struct io_log **log, struct log_params *p,
        if (l->log_gz && !p->td)
                l->log_gz = 0;
        else if (l->log_gz || l->log_gz_store) {
-               pthread_mutex_init(&l->chunk_lock, NULL);
+               mutex_init_pshared(&l->chunk_lock);
                p->td->flags |= TD_F_COMPRESS_LOG;
        }
 
@@ -636,8 +645,16 @@ void free_log(struct io_log *log)
                cur_log = flist_first_entry(&log->io_logs, struct io_logs, list);
                flist_del_init(&cur_log->list);
                free(cur_log->log);
+               sfree(cur_log);
+       }
+
+       if (log->pending) {
+               free(log->pending->log);
+               free(log->pending);
+               log->pending = NULL;
        }
 
+       free(log->pending);
        free(log->filename);
        sfree(log);
 }
@@ -745,7 +762,8 @@ static void finish_chunk(z_stream *stream, FILE *f,
 
        ret = inflateEnd(stream);
        if (ret != Z_OK)
-               log_err("fio: failed to end log inflation (%d)\n", ret);
+               log_err("fio: failed to end log inflation seq %d (%d)\n",
+                               iter->seq, ret);
 
        flush_samples(f, iter->buf, iter->buf_used);
        free(iter->buf);
@@ -809,7 +827,7 @@ static size_t inflate_chunk(struct iolog_compress *ic, int gz_hdr, FILE *f,
 
        ret = (void *) stream->next_in - ic->buf;
 
-       dprint(FD_COMPRESS, "inflated to size=%lu\n", (unsigned long) ret);
+       dprint(FD_COMPRESS, "inflated to size=%lu\n", (unsigned long) iter->buf_size);
 
        return ret;
 }
@@ -971,6 +989,7 @@ void flush_log(struct io_log *log, int do_append)
                cur_log = flist_first_entry(&log->io_logs, struct io_logs, list);
                flist_del_init(&cur_log->list);
                flush_samples(f, cur_log->log, cur_log->nr_samples * log_entry_sz(log));
+               sfree(cur_log);
        }
 
        fclose(f);
@@ -1022,7 +1041,7 @@ size_t log_chunk_sizes(struct io_log *log)
 
 static int gz_work(struct iolog_flush_data *data)
 {
-       struct iolog_compress *c;
+       struct iolog_compress *c = NULL;
        struct flist_head list;
        unsigned int seq;
        z_stream stream;
@@ -1047,9 +1066,12 @@ static int gz_work(struct iolog_flush_data *data)
        stream.next_in = (void *) data->samples;
        stream.avail_in = data->nr_samples * log_entry_sz(data->log);
 
-       dprint(FD_COMPRESS, "deflate input size=%lu, seq=%u\n",
-                               (unsigned long) stream.avail_in, seq);
+       dprint(FD_COMPRESS, "deflate input size=%lu, seq=%u, log=%s\n",
+                               (unsigned long) stream.avail_in, seq,
+                               data->log->filename);
        do {
+               if (c)
+                       dprint(FD_COMPRESS, "seq=%d, chunk=%lu\n", seq, c->len);
                c = get_new_chunk(seq);
                stream.avail_out = GZ_CHUNK;
                stream.next_out = c->buf;
@@ -1069,9 +1091,26 @@ static int gz_work(struct iolog_flush_data *data)
        stream.avail_out = GZ_CHUNK - c->len;
 
        ret = deflate(&stream, Z_FINISH);
-       if (ret == Z_STREAM_END)
-               c->len = GZ_CHUNK - stream.avail_out;
-       else {
+       if (ret < 0) {
+               /*
+                * Z_BUF_ERROR is special, it just means we need more
+                * output space. We'll handle that below. Treat any other
+                * error as fatal.
+                */
+               if (ret != Z_BUF_ERROR) {
+                       log_err("fio: deflate log (%d)\n", ret);
+                       flist_del(&c->list);
+                       free_chunk(c);
+                       goto err;
+               }
+       }
+
+       total -= c->len;
+       c->len = GZ_CHUNK - stream.avail_out;
+       total += c->len;
+       dprint(FD_COMPRESS, "seq=%d, chunk=%lu\n", seq, c->len);
+
+       if (ret != Z_STREAM_END) {
                do {
                        c = get_new_chunk(seq);
                        stream.avail_out = GZ_CHUNK;
@@ -1080,6 +1119,7 @@ static int gz_work(struct iolog_flush_data *data)
                        c->len = GZ_CHUNK - stream.avail_out;
                        total += c->len;
                        flist_add_tail(&c->list, &list);
+                       dprint(FD_COMPRESS, "seq=%d, chunk=%lu\n", seq, c->len);
                } while (ret != Z_STREAM_END);
        }
 
@@ -1188,9 +1228,7 @@ static int iolog_flush(struct io_log *log)
                data->samples = cur_log->log;
                data->nr_samples = cur_log->nr_samples;
 
-               cur_log->nr_samples = 0;
-               cur_log->max_samples = 0;
-               cur_log->log = NULL;
+               sfree(cur_log);
 
                gz_work(data);
        }