bcache-tools: add printk_key.c into debug directory

The debug directory is for utilities for debug and trace purpose. The
first utility is print_key, it prints out each field value of a bkey
with the input raw value.

Signed-off-by: Coly Li <colyli@suse.de>
diff --git a/debug/Makefile b/debug/Makefile
new file mode 100644
index 0000000..88d6517
--- /dev/null
+++ b/debug/Makefile
@@ -0,0 +1,9 @@
+
+CFLAGS+=-g2 -Wall
+
+all: print_key
+
+clean:
+	$(RM) -f print_key print_key.o
+
+print_key: print_key.o
diff --git a/debug/print_key.c b/debug/print_key.c
new file mode 100644
index 0000000..be44b53
--- /dev/null
+++ b/debug/print_key.c
@@ -0,0 +1,90 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "../bcache.h"
+
+struct bkey {
+	__u64   high;
+	__u64   low;
+	__u64   ptr;
+};
+
+#define KEY_SIZE_BITS	   16
+#define KEY_MAX_U64S	    8
+
+
+#define KEY_FIELD(name, field, offset, size)		\
+	BITMASK(name, struct bkey, field, offset, size)
+
+#define PTR_FIELD(name, offset, size)			\
+static inline __u64 name(const struct bkey *k)		\
+{ return (k->ptr >> offset) & ~(~0ULL << size); }
+
+KEY_FIELD(KEY_PTRS,     high, 60, 3)
+KEY_FIELD(HEADER_SIZE,  high, 58, 2)
+KEY_FIELD(KEY_CSUM,     high, 56, 2)
+KEY_FIELD(KEY_PINNED,   high, 55, 1)
+KEY_FIELD(KEY_DIRTY,    high, 36, 1)
+KEY_FIELD(KEY_SIZE,     high, 20, KEY_SIZE_BITS)
+KEY_FIELD(KEY_INODE,    high, 0,  20)
+
+#define PTR_DEV_BITS		12
+
+PTR_FIELD(PTR_DEV,	51, PTR_DEV_BITS)
+PTR_FIELD(PTR_OFFSET,	8,  43)
+PTR_FIELD(PTR_GEN,	0,  8)
+
+void usage()
+{
+	printf("print_key <high> <low> <ptr>\n");
+	exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+	struct bkey k;
+
+	if (argc != 4)
+		usage();
+
+	k.high = strtoul(argv[1], NULL, 0);
+	if (k.high == ULLONG_MAX) {
+		printf("invalid key high %llu (0x%llx)\n",
+		       k.high, k.high);
+		exit(1);
+	}
+
+	k.low = strtoul(argv[2], NULL, 0);
+	if (k.high == ULLONG_MAX) {
+		printf("invalid key low %llu (0x%llx)\n",
+		       k.low, k.low);
+		exit(1);
+	}
+
+	k.ptr = strtoul(argv[3], NULL, 0);
+	if (k.high == ULLONG_MAX) {
+		printf("invalid key ptr %llu (0x%llx)\n",
+		       k.ptr, k.ptr);
+		exit(1);
+	}
+
+	printf("key {h: %llu, l: %llu, p: %llu} / {0x%llx, 0x%llx, 0x%llx}\n",
+	       k.high, k.low, k.ptr, k.high, k.low, k.ptr);
+
+	printf("KEY_INODE	%lu (0x%lx)\n", KEY_INODE(&k), KEY_INODE(&k));
+	printf("KEY_SIZE	%lu (0x%lx)\n", KEY_SIZE(&k), KEY_SIZE(&k));
+	printf("KEY_DIRTY	%lu (0x%lx)\n", KEY_DIRTY(&k), KEY_DIRTY(&k));
+	printf("KEY_PINNED	%lu (0x%lx)\n", KEY_PINNED(&k), KEY_PINNED(&k));
+	printf("KEY_CSUM	%lu (0x%lx)\n", KEY_CSUM(&k), KEY_CSUM(&k));
+	printf("HEADER_SIZE	%lu (0x%lx)\n", HEADER_SIZE(&k), HEADER_SIZE(&k));
+	printf("KEY_PTRS	%lu (0x%lx)\n", KEY_PTRS(&k), KEY_PTRS(&k));
+	printf("PTR_GEN		%llu (0x%llx)\n", PTR_GEN(&k), PTR_GEN(&k));
+	printf("PTR_OFFSET	%llu (0x%llx)\n", PTR_OFFSET(&k), PTR_OFFSET(&k));
+	printf("PTR_DEV		%llu (0x%llx)\n", PTR_DEV(&k), PTR_DEV(&k));
+	return 0;
+}