blob: b3ab0f9b3e60589781b7088ec28871ea1987b782 [file] [log] [blame]
Jens Axboe5aa702c2014-09-23 14:10:35 -06001/*
2 * Small tool to check for dedupable blocks in a file or device. Basically
3 * just scans the filename for extents of the given size, checksums them,
4 * and orders them up.
5 */
6#include <stdio.h>
7#include <stdio.h>
8#include <unistd.h>
9#include <inttypes.h>
10#include <assert.h>
11#include <sys/types.h>
12#include <sys/stat.h>
13#include <sys/ioctl.h>
14#include <linux/fs.h>
15#include <fcntl.h>
16#include <string.h>
17
18#include "../lib/rbtree.h"
19#include "../flist.h"
20#include "../log.h"
21#include "../mutex.h"
22#include "../smalloc.h"
23#include "../minmax.h"
24#include "../crc/md5.h"
25#include "../memalign.h"
26#include "../os/os.h"
Jens Axboed11a5632014-09-24 09:30:52 -060027#include "../gettime.h"
28#include "../fio_time.h"
Jens Axboe5aa702c2014-09-23 14:10:35 -060029
Jens Axboe76b9b832014-09-26 09:51:33 -060030#include "../lib/bloom.h"
Jens Axboe7a741972014-09-26 09:58:29 -060031#include "debug.h"
Jens Axboe5aa702c2014-09-23 14:10:35 -060032
33struct worker_thread {
34 pthread_t thread;
35
Jens Axboe3f3415f2014-09-23 14:40:48 -060036 volatile int done;
37
Jens Axboe5aa702c2014-09-23 14:10:35 -060038 int fd;
39 uint64_t cur_offset;
40 uint64_t size;
41
42 unsigned long items;
Jens Axboe76b9b832014-09-26 09:51:33 -060043 unsigned long dupes;
Jens Axboe5aa702c2014-09-23 14:10:35 -060044 int err;
45};
46
47struct extent {
48 struct flist_head list;
49 uint64_t offset;
50};
51
52struct chunk {
53 struct rb_node rb_node;
Jens Axboe5aa702c2014-09-23 14:10:35 -060054 uint64_t count;
55 uint32_t hash[MD5_HASH_WORDS];
Jens Axboed11a5632014-09-24 09:30:52 -060056 struct flist_head extent_list[0];
Jens Axboe5aa702c2014-09-23 14:10:35 -060057};
58
59struct item {
60 uint64_t offset;
61 uint32_t hash[MD5_HASH_WORDS];
62};
63
64static struct rb_root rb_root;
Jens Axboe76b9b832014-09-26 09:51:33 -060065static struct bloom *bloom;
Jens Axboe5aa702c2014-09-23 14:10:35 -060066static struct fio_mutex *rb_lock;
67
68static unsigned int blocksize = 4096;
69static unsigned int num_threads;
70static unsigned int chunk_size = 1048576;
71static unsigned int dump_output;
72static unsigned int odirect;
73static unsigned int collision_check;
Jens Axboe3f3415f2014-09-23 14:40:48 -060074static unsigned int print_progress = 1;
Jens Axboe76b9b832014-09-26 09:51:33 -060075static unsigned int use_bloom = 1;
Jens Axboe5aa702c2014-09-23 14:10:35 -060076
77static uint64_t total_size;
78static uint64_t cur_offset;
79static struct fio_mutex *size_lock;
80
81static int dev_fd;
82
83static uint64_t get_size(int fd, struct stat *sb)
84{
85 uint64_t ret;
86
87 if (S_ISBLK(sb->st_mode)) {
88 if (ioctl(fd, BLKGETSIZE64, &ret) < 0) {
89 perror("ioctl");
90 return 0;
91 }
92 } else
93 ret = sb->st_size;
94
95 return (ret & ~((uint64_t)blocksize - 1));
96}
97
98static int get_work(uint64_t *offset, uint64_t *size)
99{
100 uint64_t this_chunk;
101 int ret = 1;
102
103 fio_mutex_down(size_lock);
104
105 if (cur_offset < total_size) {
106 *offset = cur_offset;
107 this_chunk = min((uint64_t)chunk_size, total_size - cur_offset);
108 *size = this_chunk;
109 cur_offset += this_chunk;
110 ret = 0;
111 }
112
113 fio_mutex_up(size_lock);
114 return ret;
115}
116
Jens Axboed393bcd2014-09-26 12:47:14 -0600117static int __read_block(int fd, void *buf, off_t offset, size_t count)
Jens Axboe5aa702c2014-09-23 14:10:35 -0600118{
119 ssize_t ret;
120
Jens Axboed393bcd2014-09-26 12:47:14 -0600121 ret = pread(fd, buf, count, offset);
Jens Axboe5aa702c2014-09-23 14:10:35 -0600122 if (ret < 0) {
123 perror("pread");
124 return 1;
125 } else if (!ret)
126 return 1;
Jens Axboed393bcd2014-09-26 12:47:14 -0600127 else if (ret != count) {
Jens Axboe5aa702c2014-09-23 14:10:35 -0600128 log_err("dedupe: short read on block\n");
129 return 1;
130 }
131
132 return 0;
133}
134
Jens Axboed393bcd2014-09-26 12:47:14 -0600135static int read_block(int fd, void *buf, off_t offset)
136{
137 return __read_block(fd, buf, offset, blocksize);
138}
139
Jens Axboe5aa702c2014-09-23 14:10:35 -0600140static void add_item(struct chunk *c, struct item *i)
141{
Jens Axboe4deca362014-09-24 08:21:15 -0600142 /*
143 * Save some memory and don't add extent items, if we don't
144 * use them.
145 */
146 if (dump_output || collision_check) {
147 struct extent *e;
Jens Axboe5aa702c2014-09-23 14:10:35 -0600148
Jens Axboe4deca362014-09-24 08:21:15 -0600149 e = malloc(sizeof(*e));
150 e->offset = i->offset;
Jens Axboed11a5632014-09-24 09:30:52 -0600151 flist_add_tail(&e->list, &c->extent_list[0]);
Jens Axboe4deca362014-09-24 08:21:15 -0600152 }
153
Jens Axboe5aa702c2014-09-23 14:10:35 -0600154 c->count++;
155}
156
157static int col_check(struct chunk *c, struct item *i)
158{
159 struct extent *e;
160 char *cbuf, *ibuf;
161 int ret = 1;
162
163 cbuf = fio_memalign(blocksize, blocksize);
164 ibuf = fio_memalign(blocksize, blocksize);
165
Jens Axboed11a5632014-09-24 09:30:52 -0600166 e = flist_entry(c->extent_list[0].next, struct extent, list);
Jens Axboe5aa702c2014-09-23 14:10:35 -0600167 if (read_block(dev_fd, cbuf, e->offset))
168 goto out;
169
170 if (read_block(dev_fd, ibuf, i->offset))
171 goto out;
172
173 ret = memcmp(ibuf, cbuf, blocksize);
174out:
175 fio_memfree(cbuf, blocksize);
176 fio_memfree(ibuf, blocksize);
177 return ret;
178}
179
Jens Axboed11a5632014-09-24 09:30:52 -0600180static struct chunk *alloc_chunk(void)
181{
182 struct chunk *c;
183
184 if (collision_check || dump_output) {
185 c = malloc(sizeof(struct chunk) + sizeof(struct flist_head));
186 INIT_FLIST_HEAD(&c->extent_list[0]);
187 } else
188 c = malloc(sizeof(struct chunk));
189
190 return c;
191}
192
Jens Axboe5aa702c2014-09-23 14:10:35 -0600193static void insert_chunk(struct item *i)
194{
195 struct rb_node **p, *parent;
196 struct chunk *c;
197 int diff;
198
199 p = &rb_root.rb_node;
200 parent = NULL;
201 while (*p) {
202 parent = *p;
203
204 c = rb_entry(parent, struct chunk, rb_node);
205 diff = memcmp(i->hash, c->hash, sizeof(i->hash));
206 if (diff < 0)
207 p = &(*p)->rb_left;
208 else if (diff > 0)
209 p = &(*p)->rb_right;
210 else {
211 int ret;
212
213 if (!collision_check)
214 goto add;
215
216 fio_mutex_up(rb_lock);
217 ret = col_check(c, i);
218 fio_mutex_down(rb_lock);
219
220 if (!ret)
221 goto add;
222
223 p = &(*p)->rb_right;
224 }
225 }
226
Jens Axboed11a5632014-09-24 09:30:52 -0600227 c = alloc_chunk();
Jens Axboe5aa702c2014-09-23 14:10:35 -0600228 RB_CLEAR_NODE(&c->rb_node);
Jens Axboe5aa702c2014-09-23 14:10:35 -0600229 c->count = 0;
230 memcpy(c->hash, i->hash, sizeof(i->hash));
231 rb_link_node(&c->rb_node, parent, p);
232 rb_insert_color(&c->rb_node, &rb_root);
233add:
234 add_item(c, i);
235}
236
Jens Axboe76b9b832014-09-26 09:51:33 -0600237static void insert_chunks(struct item *items, unsigned int nitems,
238 uint64_t *ndupes)
Jens Axboe5aa702c2014-09-23 14:10:35 -0600239{
240 int i;
241
242 fio_mutex_down(rb_lock);
243
Jens Axboe76b9b832014-09-26 09:51:33 -0600244 for (i = 0; i < nitems; i++) {
245 if (bloom) {
246 unsigned int s;
247 int r;
248
249 s = sizeof(items[i].hash) / sizeof(uint32_t);
250 r = bloom_set(bloom, items[i].hash, s);
251 *ndupes += r;
252 } else
253 insert_chunk(&items[i]);
254 }
Jens Axboe5aa702c2014-09-23 14:10:35 -0600255
256 fio_mutex_up(rb_lock);
257}
258
259static void crc_buf(void *buf, uint32_t *hash)
260{
261 struct fio_md5_ctx ctx = { .hash = hash };
262
263 fio_md5_init(&ctx);
264 fio_md5_update(&ctx, buf, blocksize);
265 fio_md5_final(&ctx);
266}
267
Jens Axboed393bcd2014-09-26 12:47:14 -0600268static unsigned int read_blocks(int fd, void *buf, off_t offset, size_t size)
269{
270 if (__read_block(fd, buf, offset, size))
271 return 0;
272
273 return size / blocksize;
274}
275
Jens Axboe5aa702c2014-09-23 14:10:35 -0600276static int do_work(struct worker_thread *thread, void *buf)
277{
278 unsigned int nblocks, i;
279 off_t offset;
Jens Axboed393bcd2014-09-26 12:47:14 -0600280 int nitems = 0;
Jens Axboe76b9b832014-09-26 09:51:33 -0600281 uint64_t ndupes = 0;
Jens Axboe5aa702c2014-09-23 14:10:35 -0600282 struct item *items;
283
Jens Axboe5aa702c2014-09-23 14:10:35 -0600284 offset = thread->cur_offset;
Jens Axboed393bcd2014-09-26 12:47:14 -0600285
286 nblocks = read_blocks(thread->fd, buf, offset, min(thread->size, (uint64_t)chunk_size));
287 if (!nblocks)
288 return 1;
289
Jens Axboe5aa702c2014-09-23 14:10:35 -0600290 items = malloc(sizeof(*items) * nblocks);
291
292 for (i = 0; i < nblocks; i++) {
Jens Axboed393bcd2014-09-26 12:47:14 -0600293 void *thisptr = buf + (i * blocksize);
294
Jens Axboe76b9b832014-09-26 09:51:33 -0600295 if (items)
296 items[i].offset = offset;
Jens Axboed393bcd2014-09-26 12:47:14 -0600297 crc_buf(thisptr, items[i].hash);
Jens Axboe5aa702c2014-09-23 14:10:35 -0600298 offset += blocksize;
299 nitems++;
300 }
301
Jens Axboe76b9b832014-09-26 09:51:33 -0600302 insert_chunks(items, nitems, &ndupes);
303
Jens Axboe5aa702c2014-09-23 14:10:35 -0600304 free(items);
Jens Axboe76b9b832014-09-26 09:51:33 -0600305 thread->items += nitems;
306 thread->dupes += ndupes;
Jens Axboed393bcd2014-09-26 12:47:14 -0600307 return 0;
Jens Axboe5aa702c2014-09-23 14:10:35 -0600308}
309
310static void *thread_fn(void *data)
311{
312 struct worker_thread *thread = data;
313 void *buf;
314
Jens Axboed393bcd2014-09-26 12:47:14 -0600315 buf = fio_memalign(blocksize, chunk_size);
Jens Axboe5aa702c2014-09-23 14:10:35 -0600316
317 do {
318 if (get_work(&thread->cur_offset, &thread->size)) {
319 thread->err = 1;
320 break;
321 }
322 if (do_work(thread, buf)) {
323 thread->err = 1;
324 break;
325 }
326 } while (1);
327
Jens Axboe3f3415f2014-09-23 14:40:48 -0600328 thread->done = 1;
Jens Axboed393bcd2014-09-26 12:47:14 -0600329 fio_memfree(buf, chunk_size);
Jens Axboe5aa702c2014-09-23 14:10:35 -0600330 return NULL;
331}
332
Jens Axboed11a5632014-09-24 09:30:52 -0600333static void show_progress(struct worker_thread *threads, unsigned long total)
334{
335 unsigned long last_nitems = 0;
336 struct timeval last_tv;
337
338 fio_gettime(&last_tv, NULL);
339
340 while (print_progress) {
341 unsigned long this_items;
342 unsigned long nitems = 0;
343 uint64_t tdiff;
344 float perc;
Jens Axboecb8a41d2014-09-28 19:10:24 -0600345 int some_done = 0;
Jens Axboed11a5632014-09-24 09:30:52 -0600346 int i;
347
348 for (i = 0; i < num_threads; i++) {
349 nitems += threads[i].items;
350 some_done = threads[i].done;
351 if (some_done)
352 break;
353 }
354
355 if (some_done)
356 break;
357
358 perc = (float) nitems / (float) total;
359 perc *= 100.0;
360 this_items = nitems - last_nitems;
361 this_items *= blocksize;
362 tdiff = mtime_since_now(&last_tv);
363 if (tdiff) {
Jens Axboe78340c02014-10-06 21:00:10 -0600364 this_items = (this_items * 1000) / (tdiff * 1024);
Jens Axboed11a5632014-09-24 09:30:52 -0600365 printf("%3.2f%% done (%luKB/sec)\r", perc, this_items);
366 last_nitems = nitems;
367 fio_gettime(&last_tv, NULL);
368 } else
369 printf("%3.2f%% done\r", perc);
370 fflush(stdout);
371 usleep(250000);
372 };
373}
374
Jens Axboe76b9b832014-09-26 09:51:33 -0600375static int run_dedupe_threads(int fd, uint64_t dev_size, uint64_t *nextents,
376 uint64_t *nchunks)
Jens Axboe5aa702c2014-09-23 14:10:35 -0600377{
378 struct worker_thread *threads;
Jens Axboe3f3415f2014-09-23 14:40:48 -0600379 unsigned long nitems, total_items;
Jens Axboe5aa702c2014-09-23 14:10:35 -0600380 int i, err = 0;
381
382 total_size = dev_size;
Jens Axboe3f3415f2014-09-23 14:40:48 -0600383 total_items = dev_size / blocksize;
Jens Axboe5aa702c2014-09-23 14:10:35 -0600384 cur_offset = 0;
385 size_lock = fio_mutex_init(FIO_MUTEX_UNLOCKED);
386
387 threads = malloc(num_threads * sizeof(struct worker_thread));
388 for (i = 0; i < num_threads; i++) {
389 threads[i].fd = fd;
390 threads[i].items = 0;
391 threads[i].err = 0;
Jens Axboe3f3415f2014-09-23 14:40:48 -0600392 threads[i].done = 0;
Jens Axboe5aa702c2014-09-23 14:10:35 -0600393
394 err = pthread_create(&threads[i].thread, NULL, thread_fn, &threads[i]);
395 if (err) {
396 log_err("fio: thread startup failed\n");
397 break;
398 }
399 }
400
Jens Axboed11a5632014-09-24 09:30:52 -0600401 show_progress(threads, total_items);
Jens Axboe3f3415f2014-09-23 14:40:48 -0600402
Jens Axboe5aa702c2014-09-23 14:10:35 -0600403 nitems = 0;
Jens Axboe76b9b832014-09-26 09:51:33 -0600404 *nextents = 0;
405 *nchunks = 1;
Jens Axboe5aa702c2014-09-23 14:10:35 -0600406 for (i = 0; i < num_threads; i++) {
407 void *ret;
408 pthread_join(threads[i].thread, &ret);
409 nitems += threads[i].items;
Jens Axboe76b9b832014-09-26 09:51:33 -0600410 *nchunks += threads[i].dupes;
Jens Axboe5aa702c2014-09-23 14:10:35 -0600411 }
412
413 printf("Threads(%u): %lu items processed\n", num_threads, nitems);
414
Jens Axboe76b9b832014-09-26 09:51:33 -0600415 *nextents = nitems;
416 *nchunks = nitems - *nchunks;
417
Jens Axboe5aa702c2014-09-23 14:10:35 -0600418 fio_mutex_remove(size_lock);
Jens Axboed11a5632014-09-24 09:30:52 -0600419 free(threads);
Jens Axboe5aa702c2014-09-23 14:10:35 -0600420 return err;
421}
422
Jens Axboe76b9b832014-09-26 09:51:33 -0600423static int dedupe_check(const char *filename, uint64_t *nextents,
424 uint64_t *nchunks)
Jens Axboe5aa702c2014-09-23 14:10:35 -0600425{
426 uint64_t dev_size;
427 struct stat sb;
428 int flags;
429
430 flags = O_RDONLY;
431 if (odirect)
432 flags |= O_DIRECT;
433
434 dev_fd = open(filename, flags);
435 if (dev_fd == -1) {
436 perror("open");
437 return 1;
438 }
439
440 if (fstat(dev_fd, &sb) < 0) {
441 perror("fstat");
442 close(dev_fd);
443 return 1;
444 }
445
446 dev_size = get_size(dev_fd, &sb);
447 if (!dev_size) {
448 close(dev_fd);
449 return 1;
450 }
451
Jens Axboe76b9b832014-09-26 09:51:33 -0600452 if (use_bloom) {
453 uint64_t bloom_entries;
454
Jens Axboe2ccf91a2014-09-27 21:29:03 -0600455 bloom_entries = 8 * (dev_size / blocksize);
Jens Axboe76b9b832014-09-26 09:51:33 -0600456 bloom = bloom_new(bloom_entries);
457 }
458
Jens Axboe0e794082014-09-24 09:34:47 -0600459 printf("Will check <%s>, size <%llu>, using %u threads\n", filename, (unsigned long long) dev_size, num_threads);
Jens Axboe5aa702c2014-09-23 14:10:35 -0600460
Jens Axboe76b9b832014-09-26 09:51:33 -0600461 return run_dedupe_threads(dev_fd, dev_size, nextents, nchunks);
Jens Axboe5aa702c2014-09-23 14:10:35 -0600462}
463
464static void show_chunk(struct chunk *c)
465{
466 struct flist_head *n;
467 struct extent *e;
468
Jens Axboeb2a657f2014-09-23 16:06:04 -0600469 printf("c hash %8x %8x %8x %8x, count %lu\n", c->hash[0], c->hash[1], c->hash[2], c->hash[3], (unsigned long) c->count);
Jens Axboed11a5632014-09-24 09:30:52 -0600470 flist_for_each(n, &c->extent_list[0]) {
Jens Axboe5aa702c2014-09-23 14:10:35 -0600471 e = flist_entry(n, struct extent, list);
Jens Axboeb2a657f2014-09-23 16:06:04 -0600472 printf("\toffset %llu\n", (unsigned long long) e->offset);
Jens Axboe5aa702c2014-09-23 14:10:35 -0600473 }
474}
475
Jens Axboe76b9b832014-09-26 09:51:33 -0600476static void show_stat(uint64_t nextents, uint64_t nchunks)
Jens Axboe5aa702c2014-09-23 14:10:35 -0600477{
Jens Axboeca79d442014-09-27 14:12:02 -0600478 double perc, ratio;
Jens Axboe5aa702c2014-09-23 14:10:35 -0600479
Jens Axboe76b9b832014-09-26 09:51:33 -0600480 printf("Extents=%lu, Unique extents=%lu\n", (unsigned long) nextents, (unsigned long) nchunks);
Jens Axboeca79d442014-09-27 14:12:02 -0600481 ratio = (double) nextents / (double) nchunks;
482 printf("De-dupe ratio: 1:%3.2f\n", ratio - 1.0);
Jens Axboe76b9b832014-09-26 09:51:33 -0600483
484 perc = 1.00 - ((double) nchunks / (double) nextents);
485 perc *= 100.0;
486 printf("Fio setting: dedupe_percentage=%u\n", (int) (perc + 0.50));
487
488}
489
490static void iter_rb_tree(uint64_t *nextents, uint64_t *nchunks)
491{
492 struct rb_node *n;
493
494 *nchunks = *nextents = 0;
Jens Axboe5aa702c2014-09-23 14:10:35 -0600495
496 n = rb_first(&rb_root);
497 if (!n)
498 return;
499
500 do {
501 struct chunk *c;
502
503 c = rb_entry(n, struct chunk, rb_node);
Jens Axboe76b9b832014-09-26 09:51:33 -0600504 (*nchunks)++;
505 *nextents += c->count;
Jens Axboe5aa702c2014-09-23 14:10:35 -0600506
507 if (dump_output)
508 show_chunk(c);
509
510 } while ((n = rb_next(n)) != NULL);
Jens Axboe5aa702c2014-09-23 14:10:35 -0600511}
512
513static int usage(char *argv[])
514{
515 log_err("Check for dedupable blocks on a device/file\n\n");
516 log_err("%s: [options] <device or file>\n", argv[0]);
517 log_err("\t-b\tChunk size to use\n");
518 log_err("\t-t\tNumber of threads to use\n");
519 log_err("\t-d\tFull extent/chunk debug output\n");
520 log_err("\t-o\tUse O_DIRECT\n");
521 log_err("\t-c\tFull collision check\n");
Jens Axboe76b9b832014-09-26 09:51:33 -0600522 log_err("\t-B\tUse probabilistic bloom filter\n");
Jens Axboe3f3415f2014-09-23 14:40:48 -0600523 log_err("\t-p\tPrint progress indicator\n");
Jens Axboe5aa702c2014-09-23 14:10:35 -0600524 return 1;
525}
526
527int main(int argc, char *argv[])
528{
Jens Axboec6f0f392014-09-26 10:16:53 -0600529 uint64_t nextents = 0, nchunks = 0;
Jens Axboe5aa702c2014-09-23 14:10:35 -0600530 int c, ret;
531
Jens Axboe7a741972014-09-26 09:58:29 -0600532 debug_init();
533
Jens Axboe76b9b832014-09-26 09:51:33 -0600534 while ((c = getopt(argc, argv, "b:t:d:o:c:p:B:")) != -1) {
Jens Axboe5aa702c2014-09-23 14:10:35 -0600535 switch (c) {
536 case 'b':
537 blocksize = atoi(optarg);
538 break;
539 case 't':
540 num_threads = atoi(optarg);
541 break;
542 case 'd':
543 dump_output = atoi(optarg);
544 break;
545 case 'o':
546 odirect = atoi(optarg);
547 break;
548 case 'c':
549 collision_check = atoi(optarg);
550 break;
Jens Axboe3f3415f2014-09-23 14:40:48 -0600551 case 'p':
552 print_progress = atoi(optarg);
553 break;
Jens Axboe76b9b832014-09-26 09:51:33 -0600554 case 'B':
555 use_bloom = atoi(optarg);
556 break;
Jens Axboe5aa702c2014-09-23 14:10:35 -0600557 case '?':
558 default:
559 return usage(argv);
560 }
561 }
562
Jens Axboe76b9b832014-09-26 09:51:33 -0600563 if (collision_check || dump_output)
564 use_bloom = 0;
565
Jens Axboe5aa702c2014-09-23 14:10:35 -0600566 if (!num_threads)
567 num_threads = cpus_online();
568
569 if (argc == optind)
570 return usage(argv);
571
572 sinit();
573
574 rb_root = RB_ROOT;
575 rb_lock = fio_mutex_init(FIO_MUTEX_UNLOCKED);
576
Jens Axboe76b9b832014-09-26 09:51:33 -0600577 ret = dedupe_check(argv[optind], &nextents, &nchunks);
Jens Axboe5aa702c2014-09-23 14:10:35 -0600578
Jens Axboe343334a2014-09-27 08:08:24 -0600579 if (!ret) {
580 if (!bloom)
581 iter_rb_tree(&nextents, &nchunks);
Jens Axboe76b9b832014-09-26 09:51:33 -0600582
Jens Axboe343334a2014-09-27 08:08:24 -0600583 show_stat(nextents, nchunks);
584 }
Jens Axboe5aa702c2014-09-23 14:10:35 -0600585
Jens Axboe997c9c32014-09-24 09:33:29 -0600586 fio_mutex_remove(rb_lock);
Jens Axboec6f0f392014-09-26 10:16:53 -0600587 if (bloom)
588 bloom_free(bloom);
Jens Axboe5aa702c2014-09-23 14:10:35 -0600589 scleanup();
590 return ret;
591}