From: Chandrika Srinivasan <chandrika.srinivasan@citrix.com>
Date: Mon, 8 May 2017 15:34:28 +0100
CP-22206: Added log-util tool for CBT metadata manipulation

Signed-off-by: Chandrika Srinivasan <chandrika.srinivasan@citrix.com>
Reviewed-by: Mark Syms <mark.syms@citrix.com>
---
 Makefile.am         |   1 +
 cbt/Makefile.am     |   9 ++
 cbt/cbt-util.c      | 315 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 configure.ac        |   1 +
 drivers/block-log.c |  20 +---
 drivers/block-log.h |   8 +-
 include/cbt-util.h  |  66 +++++++++++
 mk/blktap.spec.in   |   1 +
 8 files changed, 398 insertions(+), 23 deletions(-)
 create mode 100644 cbt/Makefile.am
 create mode 100644 cbt/cbt-util.c
 create mode 100644 include/cbt-util.h

diff --git a/Makefile.am b/Makefile.am
index d0715d9..3ad331f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,6 +11,7 @@ SUBDIRS += control
 SUBDIRS += drivers
 SUBDIRS += include
 SUBDIRS += tapback
+SUBDIRS += cbt
 
 if ENABLE_PART
 MAYBE_part = part
diff --git a/cbt/Makefile.am b/cbt/Makefile.am
new file mode 100644
index 0000000..c1c9026
--- /dev/null
+++ b/cbt/Makefile.am
@@ -0,0 +1,9 @@
+AM_CFLAGS  = -Wall
+AM_CFLAGS += -Werror
+
+AM_CPPFLAGS = -I$(top_srcdir)/include
+
+sbin_PROGRAMS = cbt-util
+
+cbt_util_SOURCES  = cbt-util.c
+cbt_util_LDADD  = -lrt -luuid
diff --git a/cbt/cbt-util.c b/cbt/cbt-util.c
new file mode 100644
index 0000000..9323afe
--- /dev/null
+++ b/cbt/cbt-util.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2017, Citrix Systems, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the copyright holder nor the names of its 
+ *     contributors may be used to endorse or promote products derived from 
+ *     this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "cbt-util.h"
+
+#if 1
+#define DFPRINTF(_f, _a...) fprintf(stdout, _f , ##_a)
+#else
+#define DFPRINTF(_f, _a...) ((void)0)
+#endif
+
+typedef int (*cbt_util_func_t) (int, char **);
+int cbt_util_create(int , char **);
+int cbt_util_set(int , char **);
+
+struct command {
+	char               *name;
+	cbt_util_func_t     func;
+};
+
+struct command commands[] = {
+	{ .name = "create",      .func = cbt_util_create        },
+	{ .name = "set",         .func = cbt_util_set        },
+};
+
+#define print_commands()					\
+	do {							\
+		int i, n;					\
+		n = sizeof(commands) / sizeof(struct command);	\
+		printf("COMMAND := { ");			\
+		printf("%s", commands[0].name);			\
+		for (i = 1; i < n; i++)				\
+			printf(" | %s", commands[i].name);	\
+		printf(" }\n");					\
+	} while (0)
+
+
+int 
+cbt_util_set(int argc, char **argv)
+{
+	char *name, *parent, *child;
+	int err, c, consistent, flag = 0, read; 
+	FILE *f = NULL;
+
+	err 	= 0;
+	name 	= NULL;
+	parent	= NULL;
+	child	= NULL;
+
+	if (!argc || !argv)
+		goto usage;
+
+	while ((c = getopt(argc, argv, "n:p:c:f:h")) != -1) {
+		switch (c) {
+			case 'n':
+				name = optarg;
+				break;
+			case 'p':
+				parent = optarg;
+				break;
+			case 'c':
+				child = optarg;
+				break;
+			case 'f':
+				flag = 1;
+				consistent = atoi(optarg);
+				break;
+			case 'h':
+			default:
+				goto usage;
+		}
+	}
+
+	if (!name) 
+		goto usage;
+
+	struct cbt_log_metadata *log_meta = malloc(sizeof(struct cbt_log_metadata));
+	if (!log_meta) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	f = fopen(name, "r+");
+	if (f == NULL) {
+		fprintf(stderr, "%s: failed to open log file: %d\n", name, -errno);
+		err = -errno;
+		goto error;
+	}
+	
+	read = fread(log_meta, sizeof(struct cbt_log_metadata), 1, f);
+
+	if (read == 0) {
+		err = -EINVAL;
+		goto error;
+	}
+
+	if (parent) {
+		uuid_parse(parent, log_meta->parent);
+	}
+
+	if (child) {
+		uuid_parse(child, log_meta->child);
+	}
+
+	if(flag) {
+		log_meta->consistent = consistent;
+	}
+
+	// Rewind pointer to start of file and rewrite data
+	fseek(f, 0, SEEK_SET);
+	fwrite(log_meta, sizeof(struct cbt_log_metadata), 1, f);
+
+error:
+	if(log_meta)
+		free(log_meta);
+	if(f)
+		fclose(f);
+	return err;
+
+usage:
+	printf("cbt-util set: Set field in log file\n\n");
+	printf("Options:\n\t-n Log file name\n\t[-p Parent log file UUID]\n"
+			"\t[-c Child log file UUID]\n\t[-f 0|1 Consistency flag]\n"
+			"\t[-h help]\n");
+
+	return -EINVAL;
+}
+
+int 
+cbt_util_create(int argc, char **argv)
+{
+	char *name;
+	int err, c;
+	FILE *f = NULL; 
+	uint64_t size, bitmap_sz;
+
+	err  = 0;
+	name = NULL;
+	size = 0;
+
+	if (!argc || !argv)
+		goto usage;
+
+	while ((c = getopt(argc, argv, "n:s:h")) != -1) {
+		switch (c) {
+			case 'n':
+				name = optarg;
+				break;
+			case 's':
+				size = strtoull(optarg, NULL, 10);
+				break;
+			case 'h':
+			default:
+				goto usage;
+		}
+	}
+
+	printf("Name parsed as: %s, size parsed as: %lu\n", name, size);
+
+	if (!name || !size) 
+		goto usage;
+
+	fprintf(stderr, "Initialising metadata for file %s\n", name);
+
+	/* Initialise metadata */
+	struct cbt_log_data *log_data = malloc(sizeof(struct cbt_log_data));
+	if (!log_data) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	uuid_clear(log_data->metadata.parent);
+	uuid_clear(log_data->metadata.child);
+	log_data->metadata.consistent = 0;
+    
+
+	bitmap_sz = bitmap_size(size);
+	log_data->bitmap = (char*)malloc(bitmap_sz);
+	if (!log_data->bitmap) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	memset(log_data->bitmap, 0, bitmap_sz);
+
+	f = fopen(name, "w+");
+	if (f == NULL) {
+		fprintf(stderr, "%s: failed to create: %d\n", name, -errno);
+		err = -errno;
+		goto error;
+	}
+	
+	fwrite(&log_data->metadata, sizeof(struct cbt_log_metadata), 1, f);
+	fwrite(log_data->bitmap, bitmap_sz, 1, f);
+
+error:
+	if(log_data) {
+		if(log_data->bitmap) {
+			free(log_data->bitmap);
+		}
+		free(log_data);
+	}
+	if(f)
+		fclose(f);
+
+	return err;
+
+usage:
+	printf("cbt-util create: Create new CBT metadata log with default values\n\n");
+	printf("Options:\n\t-n Log file name\n\t-s Num blocks in bitmap\n"
+			"\t[-h help]\n");
+
+	return -EINVAL;
+}
+
+void
+help(void)
+{
+	printf("usage: cbt-util COMMAND [OPTIONS]\n");
+	print_commands();
+	exit(0);
+}
+
+struct command *
+get_command(char *command)
+{
+	int i, n;
+
+	if (strnlen(command, 25) >= 25)
+		return NULL;
+
+	n = sizeof(commands) / sizeof (struct command);
+
+	for (i = 0; i < n; i++)
+		if (!strcmp(command, commands[i].name))
+			return &commands[i];
+
+	return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+	char **cargv;
+	struct command *cmd;
+	int cargc, i, cnt, ret;
+
+	ret = 0;
+
+	if (argc < 2)
+		help();
+
+	cargc = argc - 1;
+	cmd   = get_command(argv[1]);
+	if (!cmd) {
+		fprintf(stderr, "invalid COMMAND %s\n", argv[1]);
+		help();
+	}
+
+	cargv = malloc(sizeof(char *) * cargc);
+	if (!cargv)
+		exit(ENOMEM);
+
+	cnt      = 1;
+	cargv[0] = cmd->name;
+	for (i = 1; i < cargc; i++) {
+		char *arg = argv[i + (argc - cargc)];
+
+		cargv[cnt++] = arg;
+	}
+
+	ret = cmd->func(cnt, cargv);
+
+	free(cargv);
+
+	return (ret >= 0 ? ret : -ret);
+}
diff --git a/configure.ac b/configure.ac
index 71b60ff..b98ad7c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -74,6 +74,7 @@ Makefile
 lvm/Makefile
 part/Makefile
 cpumond/Makefile
+cbt/Makefile
 vhd/Makefile
 vhd/lib/Makefile
 vhd/lib/test/Makefile
diff --git a/drivers/block-log.c b/drivers/block-log.c
index 7d249a7..f86e587 100644
--- a/drivers/block-log.c
+++ b/drivers/block-log.c
@@ -68,8 +68,6 @@
 #define BITMAP_ENTRY(_nr, _bmap) ((unsigned long*)(_bmap))[(_nr)/BITS_PER_LONG]
 #define BITMAP_SHIFT(_nr) ((_nr) % BITS_PER_LONG)
 
-#define BLOCK_SIZE (64 * 1024)
-
 static inline int test_bit(int nr, void* bmap)
 {
 	return (BITMAP_ENTRY(nr, bmap) >> BITMAP_SHIFT(nr)) & 1;
@@ -80,22 +78,12 @@ static inline void set_bit(int nr, void* bmap)
 	BITMAP_ENTRY(nr, bmap) |= (1UL << BITMAP_SHIFT(nr));
 }
 
-static int bitmap_size(uint64_t sz)
-{
-	// Original disk size is in sectors
-	uint64_t size_in_bytes  = (sz * SECTOR_SIZE); 
-	uint64_t num_blocks = size_in_bytes / BLOCK_SIZE;
-
-	if (size_in_bytes % BLOCK_SIZE) 
-		return (num_blocks >> 3) + 1;
-	else
-		return (num_blocks >> 3);
-}
-
 static int bitmap_init(struct tdlog_data *data)
 {
 	uint64_t bmsize;
-	bmsize = bitmap_size(data->size);
+	//data->size is in number of sectors
+	//Convert it to bytes
+	bmsize = bitmap_size(data->size * SECTOR_SIZE);
 
 	DPRINTF("allocating %"PRIu64" bytes for dirty bitmap", bmsize);
 
@@ -151,7 +139,7 @@ static int tdlog_open(td_driver_t* driver, const char *name, td_flag_t flags)
 
 	/* Open on disk log file and map it into memory */
 	data->fd = open(driver->name, O_RDWR);
-	lseek(data->fd, SEEK_SET, sizeof(struct log_metadata));
+	lseek(data->fd, SEEK_SET, sizeof(struct cbt_log_metadata));
 
 	if ((rc = bitmap_init(data))) {
 		tdlog_close(driver);
diff --git a/drivers/block-log.h b/drivers/block-log.h
index 425e22c..4a52559 100644
--- a/drivers/block-log.h
+++ b/drivers/block-log.h
@@ -31,13 +31,7 @@
 #ifndef __BLOCK_LOG_H__
 #define __BLOCK_LOG_H__
 
-#include <uuid/uuid.h>
-
-struct log_metadata {
-	uuid_t 	parent_log;
-	uuid_t 	child_log; 
-	int 	consistent;
-};
+#include "cbt-util.h"
 
 struct tdlog_data {
     int         fd;
diff --git a/include/cbt-util.h b/include/cbt-util.h
new file mode 100644
index 0000000..e44a33d
--- /dev/null
+++ b/include/cbt-util.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017, Citrix Systems, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the copyright holder nor the names of its 
+ *     contributors may be used to endorse or promote products derived from 
+ *     this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CBT_UTIL_H_
+#define _CBT_UTIL_H_
+
+#include <uuid/uuid.h>
+
+#define CBT_BLOCK_SIZE (64 * 1024)
+
+struct cbt_log_metadata {
+	uuid_t parent;
+	uuid_t child;
+	int    consistent;
+};
+
+struct cbt_log_data {
+	struct cbt_log_metadata metadata;
+	char 					*bitmap;
+};
+
+int cbt_block_size = CBT_BLOCK_SIZE;
+
+static inline uint64_t
+roundup_div(uint64_t a, int b)
+{
+	return (a + b - 1) / b;
+}
+
+static inline uint64_t 
+bitmap_size(uint64_t sz)
+{
+	// Original disk size is in bytes
+	uint64_t num_blocks = roundup_div(sz, CBT_BLOCK_SIZE);
+	return (roundup_div(num_blocks, 8));
+}
+
+
+#endif
diff --git a/mk/blktap.spec.in b/mk/blktap.spec.in
index c7b8c4c..ae1fd3e 100644
--- a/mk/blktap.spec.in
+++ b/mk/blktap.spec.in
@@ -61,6 +61,7 @@ mkdir -p %{buildroot}%{_localstatedir}/log/blktap
 %{_bindir}/vhd-index
 %{_bindir}/tapback
 %{_bindir}/cpumond
+%{_sbindir}/cbt-util
 %{_sbindir}/lvm-util
 %{_sbindir}/tap-ctl
 %{_sbindir}/td-util
-- 
1.8.3.1

