The following changes since commit c0b69b92fb155424946b19228da9be0924e9e96c:

  dedupe: if percentage is 100, don't go through random + math (2014-09-22 
14:20:05 -0600)

are available in the git repository at:

  git://git.kernel.dk/fio.git master

for you to fetch changes up to 4877c1ab380b199ba6d9207b689bb1df127b0b4b:

  t/dedupe: Linux only for now (2014-09-23 18:36:52 -0600)

----------------------------------------------------------------
Jens Axboe (10):
      fifo: use minmax.h instead of rolling its own min/max
      Fix min/max typeof warnings
      memalign: fix off-by-one bug in alignment
      Checksumming updates
      Add small tool to check for dedupable contents in a file/device
      dedupe: improve wording in output
      dedupe: print progress indicator
      Build t/ tools by default
      Fix 32-bit compile warnings
      t/dedupe: Linux only for now

 Makefile       |   14 ++
 crc/md5.c      |   20 +++
 crc/md5.h      |    1 +
 crc/sha256.c   |   64 +++++---
 crc/sha256.h   |    8 +-
 crc/test.c     |    4 +
 fifo.h         |   19 +--
 lib/axmap.c    |    2 +-
 lib/zipf.c     |    4 +-
 memalign.c     |    2 +-
 minmax.h       |   13 +-
 parse.c        |    2 +-
 t/btrace2fio.c |    2 +-
 t/dedupe.c     |  481 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 t/lfsr-test.c  |   11 +-
 15 files changed, 595 insertions(+), 52 deletions(-)
 create mode 100644 t/dedupe.c

---

Diff of recent changes:

diff --git a/Makefile b/Makefile
index 4350e5a..fe439c1 100644
--- a/Makefile
+++ b/Makefile
@@ -189,12 +189,20 @@ T_BTRACE_FIO_OBJS += fifo.o lib/flist_sort.o t/log.o 
lib/linux-dev-lookup.o
 T_BTRACE_FIO_PROGS = t/btrace2fio
 endif
 
+ifeq ($(CONFIG_TARGET_OS), Linux)
+T_DEDUPE_OBJS = t/dedupe.o
+T_DEDUPE_OBJS += lib/rbtree.o t/log.o mutex.o smalloc.o gettime.o crc/md5.o \
+               memalign.o
+T_DEDUPE_PROGS = t/dedupe
+endif
+
 T_OBJS = $(T_SMALLOC_OBJS)
 T_OBJS += $(T_IEEE_OBJS)
 T_OBJS += $(T_ZIPF_OBJS)
 T_OBJS += $(T_AXMAP_OBJS)
 T_OBJS += $(T_LFSR_TEST_OBJS)
 T_OBJS += $(T_BTRACE_FIO_OBJS)
+T_OBJS += $(T_DEDUPE_OBJS)
 
 T_PROGS = $(T_SMALLOC_PROGS)
 T_PROGS += $(T_IEEE_PROGS)
@@ -202,6 +210,9 @@ T_PROGS += $(T_ZIPF_PROGS)
 T_PROGS += $(T_AXMAP_PROGS)
 T_PROGS += $(T_LFSR_TEST_PROGS)
 T_PROGS += $(T_BTRACE_FIO_PROGS)
+T_PROGS += $(T_DEDUPE_PROGS)
+
+PROGS += $(T_PROGS)
 
 ifneq ($(findstring $(MAKEFLAGS),s),s)
 ifndef V
@@ -303,6 +314,9 @@ t/btrace2fio: $(T_BTRACE_FIO_OBJS)
        $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_BTRACE_FIO_OBJS) 
$(LIBS)
 endif
 
+t/dedupe: $(T_DEDUPE_OBJS)
+       $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_DEDUPE_OBJS) $(LIBS)
+
 clean: FORCE
        -rm -f .depend $(FIO_OBJS) $(GFIO_OBJS) $(OBJS) $(T_OBJS) $(PROGS) 
$(T_PROGS) core.* core gfio FIO-VERSION-FILE *.d lib/*.d crc/*.d engines/*.d 
profiles/*.d t/*.d config-host.mak config-host.h
 
diff --git a/crc/md5.c b/crc/md5.c
index 0da85e4..64fe48a 100644
--- a/crc/md5.c
+++ b/crc/md5.c
@@ -125,3 +125,23 @@ void fio_md5_update(struct fio_md5_ctx *mctx, const 
uint8_t *data,
 
        memcpy(mctx->block, data, len);
 }
+
+void fio_md5_final(struct fio_md5_ctx *mctx)
+{
+       const unsigned int offset = mctx->byte_count & 0x3f;
+       char *p = (char *)mctx->block + offset;
+       int padding = 56 - (offset + 1);
+
+       *p++ = 0x80;
+       if (padding < 0) {
+               memset(p, 0x00, padding + sizeof (uint64_t));
+               md5_transform(mctx->hash, mctx->block);
+               p = (char *)mctx->block;
+               padding = 56;
+       }
+
+       memset(p, 0, padding);
+       mctx->block[14] = mctx->byte_count << 3;
+       mctx->block[15] = mctx->byte_count >> 29;
+       md5_transform(mctx->hash, mctx->block);
+}
diff --git a/crc/md5.h b/crc/md5.h
index 668f0e9..54e350c 100644
--- a/crc/md5.h
+++ b/crc/md5.h
@@ -23,6 +23,7 @@ struct fio_md5_ctx {
 };
 
 extern void fio_md5_update(struct fio_md5_ctx *, const uint8_t *, unsigned 
int);
+extern void fio_md5_final(struct fio_md5_ctx *);
 extern void fio_md5_init(struct fio_md5_ctx *);
 
 #endif
diff --git a/crc/sha256.c b/crc/sha256.c
index 3a72a5b..ae9ff4d 100644
--- a/crc/sha256.c
+++ b/crc/sha256.c
@@ -237,37 +237,57 @@ void fio_sha256_init(struct fio_sha256_ctx *sctx)
        sctx->state[5] = H5;
        sctx->state[6] = H6;
        sctx->state[7] = H7;
-       sctx->count[0] = sctx->count[1] = 0;
+       sctx->count = 0;
 }
 
 void fio_sha256_update(struct fio_sha256_ctx *sctx, const uint8_t *data,
                       unsigned int len)
 {
-       unsigned int i, idx, part_len;
+       unsigned int partial, done;
+       const uint8_t *src;
 
-       /* Compute number of bytes mod 128 */
-       idx = (unsigned int)((sctx->count[0] >> 3) & 0x3f);
+       partial = sctx->count & 0x3f;
+       sctx->count += len;
+       done = 0;
+       src = data;
 
-       /* Update number of bits */
-       if ((sctx->count[0] += (len << 3)) < (len << 3)) {
-               sctx->count[1]++;
-               sctx->count[1] += (len >> 29);
+       if ((partial + len) > 63) {
+               if (partial) {
+                       done = -partial;
+                       memcpy(sctx->buf + partial, data, done + 64);
+                       src = sctx->buf;
+               }
+
+               do {
+                       sha256_transform(sctx->state, src);
+                       done += 64;
+                       src = data + done;
+               } while (done + 63 < len);
+
+               partial = 0;
        }
+       memcpy(sctx->buf + partial, src, len - done);
+}
+
+void fio_sha256_final(struct fio_sha256_ctx *sctx)
+{
+       uint64_t bits;
+       unsigned int index, pad_len;
+       int i;
+       static const uint8_t padding[64] = { 0x80, };
 
-       part_len = 64 - idx;
+       /* Save number of bits */
+       bits = sctx->count << 3;
 
-       /* Transform as many times as possible. */
-       if (len >= part_len) {
-               memcpy(&sctx->buf[idx], data, part_len);
-               sha256_transform(sctx->state, sctx->buf);
+       /* Pad out to 56 mod 64. */
+       index = sctx->count & 0x3f;
+       pad_len = (index < 56) ? (56 - index) : ((64+56) - index);
+       fio_sha256_update(sctx, padding, pad_len);
 
-               for (i = part_len; i + 63 < len; i += 64)
-                       sha256_transform(sctx->state, &data[i]);
-               idx = 0;
-       } else {
-               i = 0;
-       }
-       
-       /* Buffer remaining input */
-       memcpy(&sctx->buf[idx], &data[i], len-i);
+       /* Append length (before padding) */
+       fio_sha256_update(sctx, (const uint8_t *)&bits, sizeof(bits));
+
+       /* Store state in digest */
+       for (i = 0; i < 8; i++)
+               sctx->buf[i] = sctx->state[i];
 }
diff --git a/crc/sha256.h b/crc/sha256.h
index c7aa28f..b636033 100644
--- a/crc/sha256.h
+++ b/crc/sha256.h
@@ -1,13 +1,17 @@
 #ifndef FIO_SHA256_H
 #define FIO_SHA256_H
 
+#define SHA256_DIGEST_SIZE     32
+#define SHA256_BLOCK_SIZE      64
+
 struct fio_sha256_ctx {
-       uint32_t count[2];
-       uint32_t state[8];
+       uint32_t count;
+       uint32_t state[SHA256_DIGEST_SIZE / 4];
        uint8_t *buf;
 };
 
 void fio_sha256_init(struct fio_sha256_ctx *);
 void fio_sha256_update(struct fio_sha256_ctx *, const uint8_t *, unsigned int);
+void fio_sha256_final(struct fio_sha256_ctx *);
 
 #endif
diff --git a/crc/test.c b/crc/test.c
index 0c3b2da..36054e6 100644
--- a/crc/test.c
+++ b/crc/test.c
@@ -52,6 +52,8 @@ static void t_md5(void *buf, size_t size)
 
        for (i = 0; i < NR_CHUNKS; i++)
                fio_md5_update(&ctx, buf, size);
+
+       fio_md5_final(&ctx);
 }
 
 static void t_crc64(void *buf, size_t size)
@@ -116,6 +118,8 @@ static void t_sha256(void *buf, size_t size)
 
        for (i = 0; i < NR_CHUNKS; i++)
                fio_sha256_update(&ctx, buf, size);
+
+       fio_sha256_final(&ctx);
 }
 
 static void t_sha512(void *buf, size_t size)
diff --git a/fifo.h b/fifo.h
index 7491365..4b775b0 100644
--- a/fifo.h
+++ b/fifo.h
@@ -1,3 +1,5 @@
+#ifndef FIO_FIFO_H
+#define FIO_FIFO_H
 /*
  * A simple FIFO implementation.
  *
@@ -18,6 +20,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  */
+#include "minmax.h"
+
 struct fifo {
        unsigned char *buffer;  /* the buffer holding the data */
        unsigned int size;      /* the size of the allocated buffer */
@@ -40,19 +44,4 @@ static inline unsigned int fifo_room(struct fifo *fifo)
        return fifo->size - fifo->in + fifo->out;
 }
 
-#ifndef min
-#define min(x,y) ({ \
-       typeof(x) _x = (x);     \
-       typeof(y) _y = (y);     \
-       (void) (&_x == &_y);            \
-       _x < _y ? _x : _y; })
-#endif
-
-#ifndef max
-#define max(x,y) ({ \
-       typeof(x) _x = (x);     \
-       typeof(y) _y = (y);     \
-       (void) (&_x == &_y);            \
-       _x > _y ? _x : _y; })
-
 #endif
diff --git a/lib/axmap.c b/lib/axmap.c
index 15cd635..5b8cb30 100644
--- a/lib/axmap.c
+++ b/lib/axmap.c
@@ -33,7 +33,7 @@
 #error "Number of arch bits unknown"
 #endif
 
-#define BLOCKS_PER_UNIT                (1UL << UNIT_SHIFT)
+#define BLOCKS_PER_UNIT                (1U << UNIT_SHIFT)
 #define BLOCKS_PER_UNIT_MASK   (BLOCKS_PER_UNIT - 1)
 
 #define firstfree_valid(b)     ((b)->first_free != (uint64_t) -1)
diff --git a/lib/zipf.c b/lib/zipf.c
index 9b6ce63..c691bc5 100644
--- a/lib/zipf.c
+++ b/lib/zipf.c
@@ -11,7 +11,7 @@
 #include "../minmax.h"
 #include "../hash.h"
 
-#define ZIPF_MAX_GEN   10000000
+#define ZIPF_MAX_GEN   10000000UL
 
 static void zipf_update(struct zipf_state *zs)
 {
@@ -23,7 +23,7 @@ static void zipf_update(struct zipf_state *zs)
         * 10M max, that should be doable in 1-2s on even slow machines.
         * Precision will take a slight hit, but nothing major.
         */
-       to_gen = min(zs->nranges, ZIPF_MAX_GEN);
+       to_gen = min(zs->nranges, (uint64_t) ZIPF_MAX_GEN);
 
        for (i = 0; i < to_gen; i++)
                zs->zetan += pow(1.0 / (double) (i + 1), zs->theta);
diff --git a/memalign.c b/memalign.c
index 7a04ffd..cfd6e46 100644
--- a/memalign.c
+++ b/memalign.c
@@ -20,7 +20,7 @@ void *fio_memalign(size_t alignment, size_t size)
 
        ptr = malloc(size + alignment + size + sizeof(*f) - 1);
        if (ptr) {
-               ret = PTR_ALIGN(ptr, alignment);
+               ret = PTR_ALIGN(ptr, alignment - 1);
                f = ret + size;
                f->offset = (uintptr_t) ret - (uintptr_t) ptr;
        }
diff --git a/minmax.h b/minmax.h
index e5c2f58..97957c8 100644
--- a/minmax.h
+++ b/minmax.h
@@ -2,10 +2,19 @@
 #define FIO_MIN_MAX_H
 
 #ifndef min
-#define min(a, b)      ((a) < (b) ? (a) : (b))
+#define min(x,y) ({ \
+       typeof(x) _x = (x);     \
+       typeof(y) _y = (y);     \
+       (void) (&_x == &_y);            \
+       _x < _y ? _x : _y; })
 #endif
+
 #ifndef max
-#define max(a, b)      ((a) > (b) ? (a) : (b))
+#define max(x,y) ({ \
+       typeof(x) _x = (x);     \
+       typeof(y) _y = (y);     \
+       (void) (&_x == &_y);            \
+       _x > _y ? _x : _y; })
 #endif
 
 #endif
diff --git a/parse.c b/parse.c
index e6d9406..40cd465 100644
--- a/parse.c
+++ b/parse.c
@@ -380,7 +380,7 @@ static int check_int(const char *p, int *val)
        return 1;
 }
 
-static int opt_len(const char *str)
+static size_t opt_len(const char *str)
 {
        char *postfix;
 
diff --git a/t/btrace2fio.c b/t/btrace2fio.c
index e4e05ca..5666a56 100644
--- a/t/btrace2fio.c
+++ b/t/btrace2fio.c
@@ -589,7 +589,7 @@ static void __output_p_ascii(struct btrace_pid *p, unsigned 
long *ios)
                perc = ((float) o->merges[i] * 100.0) / (float) total;
                printf("\tmerges: %lu (perc=%3.2f%%)\n", o->merges[i], perc);
                perc = ((float) o->seq[i] * 100.0) / (float) o->ios[i];
-               printf("\tseq:    %lu (perc=%3.2f%%)\n", o->seq[i], perc);
+               printf("\tseq:    %lu (perc=%3.2f%%)\n", (unsigned long) 
o->seq[i], perc);
                printf("\trate:   %lu KB/sec\n", o_to_kb_rate(o, i));
 
                for (j = 0; j < o->nr_bs[i]; j++) {
diff --git a/t/dedupe.c b/t/dedupe.c
new file mode 100644
index 0000000..e51e444
--- /dev/null
+++ b/t/dedupe.c
@@ -0,0 +1,481 @@
+/*
+ * Small tool to check for dedupable blocks in a file or device. Basically
+ * just scans the filename for extents of the given size, checksums them,
+ * and orders them up.
+ */
+#include <stdio.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "../lib/rbtree.h"
+#include "../flist.h"
+#include "../log.h"
+#include "../mutex.h"
+#include "../smalloc.h"
+#include "../minmax.h"
+#include "../crc/md5.h"
+#include "../memalign.h"
+#include "../os/os.h"
+
+FILE *f_err;
+struct timeval *fio_tv = NULL;
+unsigned int fio_debug = 0;
+
+void __dprint(int type, const char *str, ...)
+{
+}
+
+struct worker_thread {
+       pthread_t thread;
+
+       volatile int done;
+
+       int fd;
+       uint64_t cur_offset;
+       uint64_t size;
+
+       unsigned long items;
+       int err;
+};
+
+struct extent {
+       struct flist_head list;
+       uint64_t offset;
+};
+
+struct chunk {
+       struct rb_node rb_node;
+       struct flist_head extent_list;
+       uint64_t count;
+       uint32_t hash[MD5_HASH_WORDS];
+};
+
+struct item {
+       uint64_t offset;
+       uint32_t hash[MD5_HASH_WORDS];
+};
+
+static struct rb_root rb_root;
+static struct fio_mutex *rb_lock;
+
+static unsigned int blocksize = 4096;
+static unsigned int num_threads;
+static unsigned int chunk_size = 1048576;
+static unsigned int dump_output;
+static unsigned int odirect;
+static unsigned int collision_check;
+static unsigned int print_progress = 1;
+
+static uint64_t total_size;
+static uint64_t cur_offset;
+static struct fio_mutex *size_lock;
+
+static int dev_fd;
+
+static uint64_t get_size(int fd, struct stat *sb)
+{
+       uint64_t ret;
+
+       if (S_ISBLK(sb->st_mode)) {
+               if (ioctl(fd, BLKGETSIZE64, &ret) < 0) {
+                       perror("ioctl");
+                       return 0;
+               }
+       } else
+               ret = sb->st_size;
+
+       return (ret & ~((uint64_t)blocksize - 1));
+}
+
+static int get_work(uint64_t *offset, uint64_t *size)
+{
+       uint64_t this_chunk;
+       int ret = 1;
+
+       fio_mutex_down(size_lock);
+
+       if (cur_offset < total_size) {
+               *offset = cur_offset;
+               this_chunk = min((uint64_t)chunk_size, total_size - cur_offset);
+               *size = this_chunk;
+               cur_offset += this_chunk;
+               ret = 0;
+       }
+
+       fio_mutex_up(size_lock);
+       return ret;
+}
+
+static int read_block(int fd, void *buf, off_t offset)
+{
+       ssize_t ret;
+
+       ret = pread(fd, buf, blocksize, offset);
+       if (ret < 0) {
+               perror("pread");
+               return 1;
+       } else if (!ret)
+               return 1;
+       else if (ret != blocksize) {
+               log_err("dedupe: short read on block\n");
+               return 1;
+       }
+
+       return 0;
+}
+
+static void add_item(struct chunk *c, struct item *i)
+{
+       struct extent *e;
+
+       e = malloc(sizeof(*e));
+       e->offset = i->offset;
+       flist_add_tail(&e->list, &c->extent_list);
+       c->count++;
+}
+
+static int col_check(struct chunk *c, struct item *i)
+{
+       struct extent *e;
+       char *cbuf, *ibuf;
+       int ret = 1;
+
+       cbuf = fio_memalign(blocksize, blocksize);
+       ibuf = fio_memalign(blocksize, blocksize);
+
+       e = flist_entry(c->extent_list.next, struct extent, list);
+       if (read_block(dev_fd, cbuf, e->offset))
+               goto out;
+
+       if (read_block(dev_fd, ibuf, i->offset))
+               goto out;
+
+       ret = memcmp(ibuf, cbuf, blocksize);
+out:
+       fio_memfree(cbuf, blocksize);
+       fio_memfree(ibuf, blocksize);
+       return ret;
+}
+
+static void insert_chunk(struct item *i)
+{
+       struct rb_node **p, *parent;
+       struct chunk *c;
+       int diff;
+
+       p = &rb_root.rb_node;
+       parent = NULL;
+       while (*p) {
+               parent = *p;
+
+               c = rb_entry(parent, struct chunk, rb_node);
+               diff = memcmp(i->hash, c->hash, sizeof(i->hash));
+               if (diff < 0)
+                       p = &(*p)->rb_left;
+               else if (diff > 0)
+                       p = &(*p)->rb_right;
+               else {
+                       int ret;
+
+                       if (!collision_check)
+                               goto add;
+
+                       fio_mutex_up(rb_lock);
+                       ret = col_check(c, i);
+                       fio_mutex_down(rb_lock);
+
+                       if (!ret)
+                               goto add;
+
+                       p = &(*p)->rb_right;
+               }
+       }
+
+       c = malloc(sizeof(*c));
+       RB_CLEAR_NODE(&c->rb_node);
+       INIT_FLIST_HEAD(&c->extent_list);
+       c->count = 0;
+       memcpy(c->hash, i->hash, sizeof(i->hash));
+       rb_link_node(&c->rb_node, parent, p);
+       rb_insert_color(&c->rb_node, &rb_root);
+add:
+       add_item(c, i);
+}
+
+static void insert_chunks(struct item *items, unsigned int nitems)
+{
+       int i;
+
+       fio_mutex_down(rb_lock);
+
+       for (i = 0; i < nitems; i++)
+               insert_chunk(&items[i]);
+
+       fio_mutex_up(rb_lock);
+}
+
+static void crc_buf(void *buf, uint32_t *hash)
+{
+       struct fio_md5_ctx ctx = { .hash = hash };
+
+       fio_md5_init(&ctx);
+       fio_md5_update(&ctx, buf, blocksize);
+       fio_md5_final(&ctx);
+}
+
+static int do_work(struct worker_thread *thread, void *buf)
+{
+       unsigned int nblocks, i;
+       off_t offset;
+       int err = 0, nitems = 0;
+       struct item *items;
+
+       nblocks = thread->size / blocksize;
+       offset = thread->cur_offset;
+       items = malloc(sizeof(*items) * nblocks);
+
+       for (i = 0; i < nblocks; i++) {
+               if (read_block(thread->fd, buf, offset))
+                       break;
+               items[i].offset = offset;
+               crc_buf(buf, items[i].hash);
+               offset += blocksize;
+               nitems++;
+       }
+
+       insert_chunks(items, nitems);
+       thread->items += nitems;
+       free(items);
+       return err;
+}
+
+static void *thread_fn(void *data)
+{
+       struct worker_thread *thread = data;
+       void *buf;
+
+       buf = fio_memalign(blocksize, blocksize);
+
+       do {
+               if (get_work(&thread->cur_offset, &thread->size)) {
+                       thread->err = 1;
+                       break;
+               }
+               if (do_work(thread, buf)) {
+                       thread->err = 1;
+                       break;
+               }
+       } while (1);
+
+       thread->done = 1;
+       fio_memfree(buf, blocksize);
+       return NULL;
+}
+
+static int __dedupe_check(int fd, uint64_t dev_size)
+{
+       struct worker_thread *threads;
+       unsigned long nitems, total_items;
+       int i, err = 0;
+
+       total_size = dev_size;
+       total_items = dev_size / blocksize;
+       cur_offset = 0;
+       size_lock = fio_mutex_init(FIO_MUTEX_UNLOCKED);
+
+       threads = malloc(num_threads * sizeof(struct worker_thread));
+       for (i = 0; i < num_threads; i++) {
+               threads[i].fd = fd;
+               threads[i].items = 0;
+               threads[i].err = 0;
+               threads[i].done = 0;
+
+               err = pthread_create(&threads[i].thread, NULL, thread_fn, 
&threads[i]);
+               if (err) {
+                       log_err("fio: thread startup failed\n");
+                       break;
+               }
+       }
+
+       while (print_progress) {
+               float perc;
+               int some_done;
+
+               nitems = 0;
+               for (i = 0; i < num_threads; i++) {
+                       nitems += threads[i].items;
+                       some_done = threads[i].done;
+                       if (some_done)
+                               break;
+               }
+
+               if (some_done)
+                       break;
+
+               perc = (float) nitems / (float) total_items;
+               perc *= 100.0;
+               printf("%3.2f%% done\r", perc);
+               fflush(stdout);
+               usleep(200000);
+       };
+
+       nitems = 0;
+       for (i = 0; i < num_threads; i++) {
+               void *ret;
+               pthread_join(threads[i].thread, &ret);
+               nitems += threads[i].items;
+       }
+
+       printf("Threads(%u): %lu items processed\n", num_threads, nitems);
+
+       fio_mutex_remove(size_lock);
+       return err;
+}
+
+static int dedupe_check(const char *filename)
+{
+       uint64_t dev_size;
+       struct stat sb;
+       int flags;
+
+       flags = O_RDONLY;
+       if (odirect)
+               flags |= O_DIRECT;
+
+       dev_fd = open(filename, flags);
+       if (dev_fd == -1) {
+               perror("open");
+               return 1;
+       }
+
+       if (fstat(dev_fd, &sb) < 0) {
+               perror("fstat");
+               close(dev_fd);
+               return 1;
+       }
+
+       dev_size = get_size(dev_fd, &sb);
+       if (!dev_size) {
+               close(dev_fd);
+               return 1;
+       }
+
+       printf("Will check <%s>, size <%llu>\n", filename, (unsigned long long) 
dev_size);
+
+       return __dedupe_check(dev_fd, dev_size);
+}
+
+static void show_chunk(struct chunk *c)
+{
+       struct flist_head *n;
+       struct extent *e;
+
+       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);
+       flist_for_each(n, &c->extent_list) {
+               e = flist_entry(n, struct extent, list);
+               printf("\toffset %llu\n", (unsigned long long) e->offset);
+       }
+}
+
+static void iter_rb_tree(void)
+{
+       struct rb_node *n;
+       uint64_t nchunks;
+       uint64_t nextents;
+       double perc;
+
+       nchunks = nextents = 0;
+
+       n = rb_first(&rb_root);
+       if (!n)
+               return;
+
+       do {
+               struct chunk *c;
+
+               c = rb_entry(n, struct chunk, rb_node);
+               nchunks++;
+               nextents += c->count;
+
+               if (dump_output)
+                       show_chunk(c);
+
+       } while ((n = rb_next(n)) != NULL);
+
+       printf("Extents=%lu, Unique extents=%lu\n", (unsigned long) nextents, 
(unsigned long) nchunks);
+       printf("De-dupe factor: %3.2f\n", (double) nextents / (double) nchunks);
+
+       perc = 1.00 - ((double) nchunks / (double) nextents);
+       perc *= 100.0;
+       printf("Fio setting: dedupe_percentage=%u\n", (int) (perc + 0.50));
+}
+
+static int usage(char *argv[])
+{
+       log_err("Check for dedupable blocks on a device/file\n\n");
+       log_err("%s: [options] <device or file>\n", argv[0]);
+       log_err("\t-b\tChunk size to use\n");
+       log_err("\t-t\tNumber of threads to use\n");
+       log_err("\t-d\tFull extent/chunk debug output\n");
+       log_err("\t-o\tUse O_DIRECT\n");
+       log_err("\t-c\tFull collision check\n");
+       log_err("\t-p\tPrint progress indicator\n");
+       return 1;
+}
+
+int main(int argc, char *argv[])
+{
+       int c, ret;
+
+       while ((c = getopt(argc, argv, "b:t:d:o:c:p:")) != -1) {
+               switch (c) {
+               case 'b':
+                       blocksize = atoi(optarg);
+                       break;
+               case 't':
+                       num_threads = atoi(optarg);
+                       break;
+               case 'd':
+                       dump_output = atoi(optarg);
+                       break;
+               case 'o':
+                       odirect = atoi(optarg);
+                       break;
+               case 'c':
+                       collision_check = atoi(optarg);
+                       break;
+               case 'p':
+                       print_progress = atoi(optarg);
+                       break;
+               case '?':
+               default:
+                       return usage(argv);
+               }
+       }
+
+       if (!num_threads)
+               num_threads = cpus_online();
+
+       if (argc == optind)
+               return usage(argv);
+
+       sinit();
+
+       rb_root = RB_ROOT;
+       rb_lock = fio_mutex_init(FIO_MUTEX_UNLOCKED);
+
+       ret = dedupe_check(argv[optind]);
+
+       iter_rb_tree();
+
+       scleanup();
+       return ret;
+}
diff --git a/t/lfsr-test.c b/t/lfsr-test.c
index d371087..481f37e 100644
--- a/t/lfsr-test.c
+++ b/t/lfsr-test.c
@@ -65,11 +65,11 @@ int main(int argc, char *argv[])
        printf("LFSR specs\n");
        printf("==========================\n");
        printf("Size is         %u\n", 64 - __builtin_clzl(fl->cached_bit));
-       printf("Max val is      %lu\n", fl->max_val);
-       printf("XOR-mask is     0x%lX\n", fl->xormask);
-       printf("Seed is         %lu\n", fl->last_val);
+       printf("Max val is      %lu\n", (unsigned long) fl->max_val);
+       printf("XOR-mask is     0x%lX\n", (unsigned long) fl->xormask);
+       printf("Seed is         %lu\n", (unsigned long) fl->last_val);
        printf("Spin is         %u\n", fl->spin);
-       printf("Cycle length is %lu\n", fl->cycle_length);
+       printf("Cycle length is %lu\n", (unsigned long) fl->cycle_length);
 
        /* Create verification table */
        if (verify) {
@@ -102,7 +102,8 @@ int main(int argc, char *argv[])
                for (i = 0; i < numbers; i++) {
                        if (*(uint8_t *)(v + i) != 1) {
                                fprintf(stderr, "failed (%lu = %d).\n",
-                                               i, *(uint8_t *)(v + i));
+                                               (unsigned long) i,
+                                               *(uint8_t *)(v + i));
                                r = 1;
                                break;
                        }
--
To unsubscribe from this list: send the line "unsubscribe fio" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to