From: Chandrika Srinivasan <chandrika.srinivasan@citrix.com>
Date: Wed, 26 Oct 2016 16:22:08 +0000
CP-20827: Enable block-log layer

Signed-off-by: Chandrika Srinivasan <chandrika.srinivasan@citrix.com>
Reviewed-by: Mark Syms <mark.syms@citrix.com>
---
 control/tap-ctl.c          |   8 +-
 drivers/Makefile.am        |   2 +
 drivers/block-log.c        | 620 +++++----------------------------------------
 drivers/tapdisk-control.c  |   5 +-
 drivers/tapdisk-disktype.c |   4 -
 drivers/tapdisk-vbd.c      |  12 +-
 drivers/tapdisk.h          |   4 +-
 include/tapdisk-message.h  |   2 +-
 8 files changed, 93 insertions(+), 564 deletions(-)

diff --git a/control/tap-ctl.c b/control/tap-ctl.c
index 7089ce0..2b6d5bb 100644
--- a/control/tap-ctl.c
+++ b/control/tap-ctl.c
@@ -749,7 +749,8 @@ tap_cli_open_usage(FILE *stream)
 		"[-r turn on read caching into leaf node] [-2 <path> "
 		"use secondary image (in mirror mode if no -s)] [-s "
 		"fail over to the secondary image on ENOSPC] "
-		"[-t request timeout in seconds] [-D no O_DIRECT]\n");
+		"[-t request timeout in seconds] [-D no O_DIRECT] "
+		"[-c insert dirty log layer to track changed blocks]\n");
 }
 
 static int
@@ -767,7 +768,7 @@ tap_cli_open(int argc, char **argv)
 	secondary  = NULL;
 
 	optind = 0;
-	while ((c = getopt(argc, argv, "a:RDm:p:e:r2:st:h")) != -1) {
+	while ((c = getopt(argc, argv, "a:RDm:p:e:r2:st:ch")) != -1) {
 		switch (c) {
 		case 'p':
 			pid = atoi(optarg);
@@ -801,6 +802,9 @@ tap_cli_open(int argc, char **argv)
 		case 't':
 			timeout = atoi(optarg);
 			break;
+		case 'c': 
+			flags |= TAPDISK_MESSAGE_FLAG_ADD_LOG;
+			break;
 		case '?':
 			goto usage;
 		case 'h':
diff --git a/drivers/Makefile.am b/drivers/Makefile.am
index fd96bcc..3e68175 100644
--- a/drivers/Makefile.am
+++ b/drivers/Makefile.am
@@ -76,6 +76,7 @@ libtapdisk_la_SOURCES += tapdisk-fdreceiver.h
 libtapdisk_la_SOURCES += md5.c
 libtapdisk_la_SOURCES += md5.h
 libtapdisk_la_SOURCES += ../cpumond/cpumond.h
+libtapdisk_la_SOURCES += log.h
 
 libtapdisk_la_SOURCES += block-aio.c
 libtapdisk_la_SOURCES += block-aio.h
@@ -90,6 +91,7 @@ libtapdisk_la_SOURCES += block-llcache.c
 libtapdisk_la_SOURCES += block-nbd.c
 libtapdisk_la_SOURCES += block-ntnx.c
 libtapdisk_la_SOURCES += block-ntnx.h
+libtapdisk_la_SOURCES += block-log.c
 
 # shared ring
 libtapdisk_la_SOURCES += td-blkif.c
diff --git a/drivers/block-log.c b/drivers/block-log.c
index 5645f56..be437fd 100644
--- a/drivers/block-log.c
+++ b/drivers/block-log.c
@@ -29,15 +29,7 @@
  */
 
 /* Driver to sit on top of another disk and log writes, in order
- * to synchronize two distinct disks
- *
- * On receipt of a control request it can export a list of dirty
- * sectors in the following format:
- * struct writerange {
- *   u64 sector;
- *   u32 count;
- * }
- * terminated by { 0, 0 }
+ * to track changed blocks
  */
 
 #ifdef HAVE_CONFIG_H
@@ -53,45 +45,26 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
-#include "log.h"
 #include "tapdisk.h"
 #include "tapdisk-server.h"
 #include "tapdisk-driver.h"
 #include "tapdisk-interface.h"
+#include "tapdisk-utils.h"
 #include "timeout-math.h"
+#include "log.h"
 
 #define MAX_CONNECTIONS 1
 
 typedef struct poll_fd {
-  int          fd;
-  event_id_t   id;
+	int          fd;
+	event_id_t   id;
 } poll_fd_t;
 
 struct tdlog_state {
-  uint64_t     size;
-
-  void*        writelog;
-
-  char*        ctlpath;
-  poll_fd_t    ctl;
-
-  int          connected;
-  poll_fd_t    connections[MAX_CONNECTIONS];
-
-  char*        shmpath;
-  void*        shm;
-
-  log_sring_t* sring;
-  log_back_ring_t bring;
+	uint64_t     size;
+  	void*        writelog;
 };
 
-#define BDPRINTF(_f, _a...) syslog (LOG_DEBUG, "log: " _f "\n", ## _a)
-
-#define BWPRINTF(_f, _a...) syslog (LOG_WARNING, "log: " _f "\n", ## _a)
-
-static void ctl_accept(event_id_t, char, void *);
-static void ctl_request(event_id_t, char, void *);
-
 /* -- write log -- */
 
 /* large flat bitmaps don't scale particularly well either in size or scan
@@ -104,592 +77,137 @@ static void ctl_request(event_id_t, char, void *);
 
 static inline int test_bit(int nr, void* bmap)
 {
-  return (BITMAP_ENTRY(nr, bmap) >> BITMAP_SHIFT(nr)) & 1;
+	return (BITMAP_ENTRY(nr, bmap) >> BITMAP_SHIFT(nr)) & 1;
 }
 
 static inline void clear_bit(int nr, void* bmap)
 {
-  BITMAP_ENTRY(nr, bmap) &= ~(1UL << BITMAP_SHIFT(nr));
+	BITMAP_ENTRY(nr, bmap) &= ~(1UL << BITMAP_SHIFT(nr));
 }
 
 static inline void set_bit(int nr, void* bmap)
 {
-  BITMAP_ENTRY(nr, bmap) |= (1UL << BITMAP_SHIFT(nr));
+	BITMAP_ENTRY(nr, bmap) |= (1UL << BITMAP_SHIFT(nr));
 }
 
 static inline int bitmap_size(uint64_t sz)
 {
-  return sz >> 3;
-}
-
-static int writelog_create(struct tdlog_state *s)
-{
-  uint64_t bmsize;
-
-  bmsize = bitmap_size(s->size);
-
-  BDPRINTF("allocating %"PRIu64" bytes for dirty bitmap", bmsize);
-
-  if (!(s->writelog = calloc(bmsize, 1))) {
-    BWPRINTF("could not allocate dirty bitmap of size %"PRIu64, bmsize);
-    return -1;
-  }
-
-  return 0;
-}
-
-static int writelog_free(struct tdlog_state *s)
-{
-  if (s->writelog)
-    free(s->writelog);
-
-  return 0;
-}
-
-static int writelog_set(struct tdlog_state* s, uint64_t sector, int count)
-{
-  int i;
-
-  for (i = 0; i < count; i++) 
-    set_bit(sector + i, s->writelog);
-
-  return 0;
+	return sz >> 3;
 }
 
 /* if end is 0, clear to end of disk */
 int writelog_clear(struct tdlog_state* s, uint64_t start, uint64_t end)
 {
-  if (!end)
-    end = s->size;
-
-  /* clear to word boundaries */
-  while (BITMAP_SHIFT(start))
-    clear_bit(start++, s->writelog);
-  while (BITMAP_SHIFT(end))
-    clear_bit(end--, s->writelog);
-
-  memset(s->writelog + start / BITS_PER_LONG, 0, (end - start) >> 3);
-
-  return 0;
-}
-
-/* returns last block exported (may not be end of disk if shm region
- * overflows) */
-static uint64_t writelog_export(struct tdlog_state* s)
-{
-  struct disk_range* range = s->shm;
-  uint64_t i = 0;
-
-  BDPRINTF("sector count: %"PRIu64, s->size);
-
-  for (i = 0; i < s->size; i++) {
-    if (test_bit(i, s->writelog)) {
-      /* range start */
-      range->sector = i;
-      range->count = 1;
-      /* find end */
-      for (i++; i < s->size && test_bit(i, s->writelog); i++)
-	range->count++;
-
-      BDPRINTF("export: dirty extent %"PRIu64":%u",
-	       range->sector, range->count);
-      range++;
-
-      /* out of space in shared memory region */
-      if ((void*)range >= bmend(s->shm)) {
-	BDPRINTF("out of space in shm region at sector %"PRIu64, i);
-	return i;
-      }
-
-      /* undo forloop increment */
-      i--;
-    }
-  }
-
-  /* NULL-terminate range list */
-  range->sector = 0;
-  range->count = 0;
-
-  return i;
-}
-
-/* -- communication channel -- */
-
-/* remove FS special characters in up to len bytes of path */
-static inline void path_escape(char* path, size_t len) {
-  int i;
-
-  for (i = 0; i < len && path[i]; i++)
-    if (strchr(":/", path[i]))
-      path[i] = '_';
-}
-
-static char* ctl_makepath(const char* name, const char* ext)
-{
-  char* res;
-  char *file;
+	if (!end)
+		end = s->size;
 
-  file = strrchr(name, '/');
-  if (!file) {
-    BWPRINTF("invalid name %s\n", name);
-    return NULL;
-  }
+	/* clear to word boundaries */
+	while (BITMAP_SHIFT(start))
+		clear_bit(start++, s->writelog);
+	while (BITMAP_SHIFT(end))
+		clear_bit(end--, s->writelog);
 
-  if (asprintf(&res, BLKTAP_CTRL_DIR "/log_%s.%s", file, ext) < 0) {
-    BWPRINTF("could not allocate path");
-    return NULL;
-  }
+	memset(s->writelog + start / BITS_PER_LONG, 0, (end - start) >> 3);
 
-  path_escape(res + strlen(BLKTAP_CTRL_DIR) + 5, strlen(file));
-
-  return res;
-}
-
-static int shmem_open(struct tdlog_state* s, const char* name)
-{
-  int i, l, fd;
-
-  /* device name -> path */
-  if (asprintf(&s->shmpath, "/log_%s.wlog", name) < 0) {
-    BWPRINTF("could not allocate shm path");
-    return -1;
-  }
-
-  path_escape(s->shmpath + 5, strlen(name));
-
-  if ((fd = shm_open(s->shmpath, O_CREAT|O_RDWR, 0750)) < 0) {
-    BWPRINTF("could not open shared memory file %s: %s", s->shmpath,
-	     strerror(errno));
-    goto err;
-  }
-  if (ftruncate(fd, SHMSIZE) < 0) {
-    BWPRINTF("error truncating shmem to size %u", SHMSIZE);
-    close(fd);
-    goto err;
-  }
-
-  s->shm = mmap(NULL, SHMSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
-  close(fd);
-  if (s->shm == MAP_FAILED) {
-    BWPRINTF("could not mmap write log shm: %s", strerror(errno));
-    goto err;
-  }
-  return 0;
-
-  err:
-  s->shm = NULL;
-  free(s->shmpath);
-  s->shmpath = NULL;
-  return -1;
+	return 0;
 }
 
-static int shmem_close(struct tdlog_state* s)
-{
-  if (s->shm) {
-    munmap(s->shm, SHMSIZE);
-    s->shm = NULL;
-  }
-
-  if (s->shmpath) {
-    shm_unlink(s->shmpath);
-    s->shmpath = NULL;
-  }
-
-  return 0;
-}
-
-/* control socket */
-
-static int ctl_open(struct tdlog_state* s, const char* name)
-{
-  struct sockaddr_un saddr;
-
-  if (!(s->ctlpath = ctl_makepath(name, "ctl")))
-    return -1;
-
-  if ((s->ctl.fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
-    BWPRINTF("error opening control socket: %s", strerror(errno));
-    goto err;
-  }
-
-  memset(&saddr, 0, sizeof(saddr));
-  saddr.sun_family = AF_UNIX;
-  memcpy(saddr.sun_path, s->ctlpath, strlen(s->ctlpath));
-  if (unlink(s->ctlpath) && errno != ENOENT) {
-    BWPRINTF("error unlinking old socket path %s: %s", s->ctlpath,
-	     strerror(errno));
-    goto err_sock;
-  }
-    
-  if (bind(s->ctl.fd, &saddr, sizeof(saddr)) < 0) {
-    BWPRINTF("error binding control socket to %s: %s", s->ctlpath,
-	     strerror(errno));
-    goto err_sock;
-  }
-
-  if (listen(s->ctl.fd, 1) < 0) {
-    BWPRINTF("error listening on control socket: %s", strerror(errno));
-    goto err_sock;
-  }
-
-  s->ctl.id = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
-					    s->ctl.fd, TV_ZERO, ctl_accept, s);
-  if (s->ctl.id < 0) {
-    BWPRINTF("error register event handler: %s", strerror(s->ctl.id));
-    goto err_sock;
-  }
-
-  return 0;
-
-  err_sock:
-  close(s->ctl.fd);
-  s->ctl.fd = -1;
-  err:
-  free(s->ctlpath);
-  s->ctlpath = NULL;
-
-  return -1;
-}
-
-static int ctl_close(struct tdlog_state* s)
-{
-  while (s->connected) {
-    tapdisk_server_unregister_event(s->connections[s->connected].id);
-    close(s->connections[s->connected].fd);
-    s->connections[s->connected].fd = -1;
-    s->connections[s->connected].id = 0;
-    s->connected--;
-  }
-
-  if (s->ctl.fd >= 0) {
-    tapdisk_server_unregister_event(s->ctl.id);
-    close(s->ctl.fd);
-    s->ctl.fd = -1;
-    s->ctl.id = 0;
-  }
-
-  if (s->ctlpath) {
-    unlink(s->ctlpath);
-    free(s->ctlpath);
-    s->ctlpath = NULL;
-  }
-
-  /* XXX this must be fixed once requests are actually in flight */
-  /* could just drain the existing ring here first */
-  if (s->sring) {
-    SHARED_RING_INIT(s->sring);
-    BACK_RING_INIT(&s->bring, s->sring, SRINGSIZE);
-  }
-
-  return 0;
-}
-
-/* walk list of open sockets, close matching fd */
-static int ctl_close_sock(struct tdlog_state* s, int fd)
-{
-  int i;
-
-  for (i = 0; i <= s->connected; i++) {
-    if (s->connections[i].fd == fd) {
-      tapdisk_server_unregister_event(s->connections[i].id);
-      close(s->connections[i].fd);
-      s->connections[i].fd = -1;
-      s->connections[i].id = 0;
-      s->connected--;
-      return 0;
-    }
-  }
-
-  BWPRINTF("requested to close unknown socket %d", fd);
-  return -1;
-}
-
-static void ctl_accept(event_id_t id, char mode, void *private)
-{
-  struct tdlog_state* s = (struct tdlog_state *)private;
-  int fd;
-  event_id_t cid;
-
-  if ((fd = accept(s->ctl.fd, NULL, NULL)) < 0) {
-    BWPRINTF("error accepting control connection: %s", strerror(errno));
-    return;
-  }
-
-  if (s->connected) {
-    BWPRINTF("control session in progress, closing new connection");
-    close(fd);
-    return;
-  }
-
-  cid = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
-				      fd, TV_ZERO, ctl_request, s);
-  if (cid < 0) {
-    BWPRINTF("error registering connection event handler: %s", strerror(cid));
-    close(fd);
-    return;
-  }
-
-  s->connections[s->connected].fd = fd;
-  s->connections[s->connected].id = cid;
-  s->connected++;
-}
-
-/* response format: 4 bytes shmsize, 0-terminated path */
-static int ctl_get_shmpath(struct tdlog_state* s, int fd)
-{
-  char msg[CTLRSPLEN_SHMP + 1];
-  uint32_t sz;
-  int rc;
-
-  BDPRINTF("ctl: sending shared memory parameters (size: %u, path: %s)",
-	   SHMSIZE, s->shmpath);
-
-  /* TMP: sanity-check shm */
-  sz = 0xdeadbeef;
-  memcpy(s->shm, &sz, sizeof(sz));
-
-  sz = SHMSIZE;
-  memcpy(msg, &sz, sizeof(sz));
-  snprintf(msg + sizeof(sz), sizeof(msg) - sizeof(sz), "%s", s->shmpath);
-  if ((rc = write(fd, msg, CTLRSPLEN_SHMP)) < 0) {
-    BWPRINTF("error writing shmpath: %s", strerror(errno));
-    return -1;
-  }
-
-  return 0;
-}
-
-static int ctl_peek_writes(struct tdlog_state* s, int fd)
+static int writelog_create(struct tdlog_state *s)
 {
-  int rc;
+	uint64_t bmsize;
 
-  BDPRINTF("ctl: peeking bitmap");
+	bmsize = bitmap_size(s->size);
 
-  writelog_export(s);
+	DPRINTF("allocating %"PRIu64" bytes for dirty bitmap", bmsize);
 
-  if ((rc = write(fd, "done", CTLRSPLEN_PEEK)) < 0) {
-    BWPRINTF("error writing peek ack: %s", strerror(errno));
-    return -1;
-  }
+	if (!(s->writelog = calloc(bmsize, 1))) {
+		EPRINTF("could not allocate dirty bitmap of size %"PRIu64, bmsize);
+		return -1;
+	}
 
-  return 0;
+	return 0;
 }
 
-static int ctl_clear_writes(struct tdlog_state* s, int fd)
+static int writelog_free(struct tdlog_state *s)
 {
-  int rc;
-
-  BDPRINTF("ctl: clearing bitmap");
-
-  writelog_clear(s, 0, 0);
-
-  if ((rc = write(fd, "done", CTLRSPLEN_CLEAR)) < 0) {
-    BWPRINTF("error writing clear ack: %s", strerror(errno));
-    return -1;
-  }
+	if (s->writelog)
+		free(s->writelog);
 
-  return 0;
+	return 0;
 }
 
-/* get dirty bitmap and clear it atomically */
-static int ctl_get_writes(struct tdlog_state* s, int fd)
+static int writelog_set(struct tdlog_state* s, uint64_t sector, int count)
 {
-  int rc;
-
-  BDPRINTF("ctl: getting bitmap");
-
-  writelog_export(s);
-  writelog_clear(s, 0, 0);
+	int i;
+	EPRINTF("Setting %d bits starting at sector %"PRIu64"\n", count, sector);
 
-  if ((rc = write(fd, "done", CTLRSPLEN_GET)) < 0) {
-    BWPRINTF("error writing get ack: %s", strerror(errno));
-    return -1;
-  }
+	for (i = 0; i < count; i++) 
+		set_bit(sector + i, s->writelog);
 
-  return 0;
+	return 0;
 }
 
-/* get requests from ring */
-static int ctl_kick(struct tdlog_state* s, int fd)
-{
-  RING_IDX reqstart, reqend;
-  log_request_t req;
-
-  /* XXX testing */
-  RING_IDX rspstart, rspend;
-  log_response_t rsp;
-  struct log_ctlmsg msg;
-  int rc;
-
-  reqstart = s->bring.req_cons;
-  reqend = s->sring->req_prod;
-
-  BDPRINTF("ctl: ring kicked (start = %u, end = %u)", reqstart, reqend);
-
-  while (reqstart != reqend) {
-    /* XXX actually submit these! */
-    memcpy(&req, RING_GET_REQUEST(&s->bring, reqstart), sizeof(req));
-    BDPRINTF("ctl: read request %"PRIu64":%u", req.sector, req.count);
-    s->bring.req_cons = ++reqstart;
-
-    rsp.sector = req.sector;
-    rsp.count = req.count;
-    memcpy(RING_GET_RESPONSE(&s->bring, s->bring.rsp_prod_pvt), &rsp,
-	   sizeof(rsp));
-    s->bring.rsp_prod_pvt++;
-  }
-
-  RING_PUSH_RESPONSES(&s->bring);
-  memset(&msg, 0, sizeof(msg));
-  memcpy(msg.msg, LOGCMD_KICK, 4);
-  if ((rc = write(fd, &msg, sizeof(msg))) < 0) {
-    BWPRINTF("error sending notify: %s", strerror(errno));
-    return -1;
-  } else if (rc < sizeof(msg)) {
-    BWPRINTF("short notify write (%d/%zd)", rc, sizeof(msg));
-    return -1;
-  }
-
-  return 0;
-}
 
-static int ctl_do_request(struct tdlog_state* s, int fd, struct log_ctlmsg* msg)
-{
-  if (!strncmp(msg->msg, LOGCMD_SHMP, 4)) {
-    return ctl_get_shmpath(s, fd);
-  } else if (!strncmp(msg->msg, LOGCMD_PEEK, 4)) {
-    return ctl_peek_writes(s, fd);
-  } else if (!strncmp(msg->msg, LOGCMD_CLEAR, 4)) {
-    return ctl_clear_writes(s, fd);
-  } else if (!strncmp(msg->msg, LOGCMD_GET, 4)) {
-    return ctl_get_writes(s, fd);
-  } else if (!strncmp(msg->msg, LOGCMD_KICK, 4)) {
-    return ctl_kick(s, fd);
-  }
-
-  BWPRINTF("unknown control request %.4s", msg->msg);
-  return -1;
-}
+/* -- interface -- */
 
-static inline int ctl_find_connection(struct tdlog_state *s, event_id_t id)
+static int tdlog_close(td_driver_t* driver)
 {
-  int i;
-
-  for (i = 0; i < s->connected; i++)
-    if (s->connections[i].id == id)
-      return s->connections[i].fd;
-
-  BWPRINTF("unrecognized event callback id %d", id);
-  return -1;
-}
+	struct tdlog_state* s = (struct tdlog_state*)driver->data;
+	writelog_free(s);
 
-static void ctl_request(event_id_t id, char mode, void *private)
-{
-  struct tdlog_state* s = (struct tdlog_state*)private;
-  struct log_ctlmsg msg;
-  int rc, i, fd = -1;
-
-  fd = ctl_find_connection(s, id);
-  if (fd == -1)
-    return;
-
-  if ((rc = read(fd, &msg, sizeof(msg))) < 0) {
-    BWPRINTF("error reading from ctl socket %d, closing: %s", fd,
-	     strerror(errno));
-    ctl_close_sock(s, fd);
-    return;
-  } else if (rc == 0) {
-    BDPRINTF("ctl_request: EOF, closing socket");
-    ctl_close_sock(s, fd);
-    return;
-  } else if (rc < sizeof(msg)) {
-    BWPRINTF("short request received (%d/%zd bytes), ignoring", rc,
-	     sizeof(msg));
-    return;
-  }
-
-  ctl_do_request(s, fd, &msg);
+	return 0;
 }
 
-/* -- interface -- */
-
-static int tdlog_close(td_driver_t*);
-
 static int tdlog_open(td_driver_t* driver, const char* name, td_flag_t flags)
 {
-  struct tdlog_state* s = (struct tdlog_state*)driver->data;
-  int rc;
-
-  memset(s, 0, sizeof(*s));
-
-  s->size = driver->info.size;
+	struct tdlog_state* s = (struct tdlog_state*)driver->data;
+	int rc;
 
-  if ((rc = writelog_create(s))) {
-    tdlog_close(driver);
-    return rc;
-  }
-  if ((rc = shmem_open(s, name))) {
-    tdlog_close(driver);
-    return rc;
-  }
-  if ((rc = ctl_open(s, name))) {
-    tdlog_close(driver);
-    return rc;
-  }
+	memset(s, 0, sizeof(*s));
 
-  s->sring = (log_sring_t*)sringstart(s->shm);
-  SHARED_RING_INIT(s->sring);
-  BACK_RING_INIT(&s->bring, s->sring, SRINGSIZE);
-
-  BDPRINTF("opened ctl socket");
-
-  return 0;
-}
-
-static int tdlog_close(td_driver_t* driver)
-{
-  struct tdlog_state* s = (struct tdlog_state*)driver->data;
+	s->size = driver->info.size;
 
-  ctl_close(s);
-  shmem_close(s);
-  writelog_free(s);
+	DPRINTF("Size of original image is %"PRIu64"\n", s->size);
+	if ((rc = writelog_create(s))) {
+		tdlog_close(driver);
+		return rc;
+	}
 
-  return 0;
+	return 0;
 }
 
 static void tdlog_queue_read(td_driver_t* driver, td_request_t treq)
 {
-  td_forward_request(treq);
+	td_forward_request(treq);
 }
 
 static void tdlog_queue_write(td_driver_t* driver, td_request_t treq)
 {
-  struct tdlog_state* s = (struct tdlog_state*)driver->data;
-  int rc;
+	struct tdlog_state* s = (struct tdlog_state*)driver->data;
 
-  writelog_set(s, treq.sec, treq.secs);
-  td_forward_request(treq);
+	writelog_set(s, treq.sec, treq.secs);
+	td_forward_request(treq);
 }
 
 static int tdlog_get_parent_id(td_driver_t* driver, td_disk_id_t* id)
 {
-  return -EINVAL;
+	return -EINVAL;
 }
 
 static int tdlog_validate_parent(td_driver_t *driver,
 				 td_driver_t *parent, td_flag_t flags)
 {
-  return 0;
+	return 0;
 }
 
 struct tap_disk tapdisk_log = {
-  .disk_type          = "tapdisk_log",
-  .private_data_size  = sizeof(struct tdlog_state),
-  .flags              = 0,
-  .td_open            = tdlog_open,
-  .td_close           = tdlog_close,
-  .td_queue_read      = tdlog_queue_read,
-  .td_queue_write     = tdlog_queue_write,
-  .td_get_parent_id   = tdlog_get_parent_id,
-  .td_validate_parent = tdlog_validate_parent,
+	.disk_type          = "tapdisk_log",
+	.private_data_size  = sizeof(struct tdlog_state),
+	.flags              = 0,
+	.td_open            = tdlog_open,
+	.td_close           = tdlog_close,
+	.td_queue_read      = tdlog_queue_read,
+	.td_queue_write     = tdlog_queue_write,
+	.td_get_parent_id   = tdlog_get_parent_id,
+	.td_validate_parent = tdlog_validate_parent,
 };
diff --git a/drivers/tapdisk-control.c b/drivers/tapdisk-control.c
index c90d1e5..a0b7d10 100644
--- a/drivers/tapdisk-control.c
+++ b/drivers/tapdisk-control.c
@@ -737,8 +737,8 @@ tapdisk_control_open_image(struct tapdisk_ctl_conn *conn,
 		flags |= TD_OPEN_ADD_CACHE;
 	if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_VHD_INDEX)
 		flags |= TD_OPEN_VHD_INDEX;
-	if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_LOG_DIRTY)
-		flags |= TD_OPEN_LOG_DIRTY;
+	if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_ADD_LOG)
+		flags |= TD_OPEN_ADD_LOG;
 	if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_ADD_LCACHE)
 		flags |= TD_OPEN_LOCAL_CACHE;
 	if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_REUSE_PRT)
@@ -1214,6 +1214,7 @@ out:
     return err;
 }
 
+
 struct tapdisk_control_info message_infos[] = {
 	[TAPDISK_MESSAGE_PID] = {
 		.handler = tapdisk_control_get_pid,
diff --git a/drivers/tapdisk-disktype.c b/drivers/tapdisk-disktype.c
index f4b84df..963f8a1 100644
--- a/drivers/tapdisk-disktype.c
+++ b/drivers/tapdisk-disktype.c
@@ -176,9 +176,7 @@ extern struct tap_disk tapdisk_qcow;
 #endif
 extern struct tap_disk tapdisk_block_cache;
 extern struct tap_disk tapdisk_vhd_index;
-#if 0
 extern struct tap_disk tapdisk_log;
-#endif
 extern struct tap_disk tapdisk_lcache;
 extern struct tap_disk tapdisk_llpcache;
 extern struct tap_disk tapdisk_llecache;
@@ -200,9 +198,7 @@ const struct tap_disk *tapdisk_disk_drivers[] = {
 #endif
 	[DISK_TYPE_BLOCK_CACHE] = &tapdisk_block_cache,
 	[DISK_TYPE_VINDEX]      = &tapdisk_vhd_index,
-#if 0
 	[DISK_TYPE_LOG]         = &tapdisk_log,
-#endif
 	[DISK_TYPE_LCACHE]      = &tapdisk_lcache,
 	[DISK_TYPE_LLPCACHE]    = &tapdisk_llpcache,
 	[DISK_TYPE_LLECACHE]    = &tapdisk_llecache,
diff --git a/drivers/tapdisk-vbd.c b/drivers/tapdisk-vbd.c
index 8329aa0..4cc6af1 100644
--- a/drivers/tapdisk-vbd.c
+++ b/drivers/tapdisk-vbd.c
@@ -530,8 +530,13 @@ tapdisk_vbd_add_dirty_log(td_vbd_t *vbd)
 	driver = NULL;
 	log    = NULL;
 
+	ERR(TLOG_WARN, "tapdisk_vbd_add_dirty_log called for %s\n", vbd->name);
+
 	parent = tapdisk_vbd_first_image(vbd);
 
+	ERR(TLOG_WARN, "Size in VBD: %"PRIu64"\n", vbd->disk_info.size);
+	ERR(TLOG_WARN, "Size in Image: %"PRIu64"\n", parent->info.size);
+
 	log    = tapdisk_image_allocate(parent->name,
 					DISK_TYPE_LOG,
 					parent->flags);
@@ -553,7 +558,10 @@ tapdisk_vbd_add_dirty_log(td_vbd_t *vbd)
 	if (err)
 		goto fail;
 
-	tapdisk_vbd_add_image(vbd, log);
+	/* insert cache before image */
+	list_add(&log->next, parent->next.prev);
+
+//	tapdisk_vbd_add_image(vbd, log);
 	return 0;
 
 fail:
@@ -592,7 +600,7 @@ tapdisk_vbd_open_vdi(td_vbd_t *vbd, const char *name, td_flag_t flags, int prt_d
 	td_flag_clear(vbd->state, TD_VBD_CLOSED);
 	vbd->flags = flags;
 
-	if (td_flag_test(vbd->flags, TD_OPEN_LOG_DIRTY)) {
+	if (td_flag_test(vbd->flags, TD_OPEN_ADD_LOG)) {
 		err = tapdisk_vbd_add_dirty_log(vbd);
 		if (err)
 			goto fail;
diff --git a/drivers/tapdisk.h b/drivers/tapdisk.h
index cedcbde..f93932e 100644
--- a/drivers/tapdisk.h
+++ b/drivers/tapdisk.h
@@ -95,7 +95,7 @@ extern unsigned int PAGE_SHIFT;
 #define TD_OPEN_SHAREABLE            0x00010
 #define TD_OPEN_ADD_CACHE            0x00020
 #define TD_OPEN_VHD_INDEX            0x00040
-#define TD_OPEN_LOG_DIRTY            0x00080
+#define TD_OPEN_ADD_LOG            0x00080
 #define TD_OPEN_LOCAL_CACHE          0x00100
 #define TD_OPEN_REUSE_PARENT         0x00200
 #define TD_OPEN_SECONDARY            0x00400
@@ -136,7 +136,7 @@ struct td_disk_id {
 
 struct td_disk_info {
 	td_sector_t                  size;
-        long                         sector_size;
+	long                         sector_size;
 	uint32_t                     info;
 };
 
diff --git a/include/tapdisk-message.h b/include/tapdisk-message.h
index 9d8d9a8..e9504b0 100644
--- a/include/tapdisk-message.h
+++ b/include/tapdisk-message.h
@@ -49,7 +49,7 @@
 #define TAPDISK_MESSAGE_FLAG_RDONLY      0x002
 #define TAPDISK_MESSAGE_FLAG_ADD_CACHE   0x004
 #define TAPDISK_MESSAGE_FLAG_VHD_INDEX   0x008
-#define TAPDISK_MESSAGE_FLAG_LOG_DIRTY   0x010
+#define TAPDISK_MESSAGE_FLAG_ADD_LOG     0x010
 #define TAPDISK_MESSAGE_FLAG_ADD_LCACHE  0x020
 #define TAPDISK_MESSAGE_FLAG_REUSE_PRT   0x040
 #define TAPDISK_MESSAGE_FLAG_SECONDARY   0x080
-- 
1.8.3.1

