Ryan Grimm
2006-Aug-21  20:55 UTC
[Xen-devel] [PATCH 4 of 6] dscow plugin for dm-userspace userspace tool
# HG changeset patch
# User Ryan Grimm <grimm@us.ibm.com>
# Date 1156190589 18000
# Node ID 6a7ea5a3554309b4e37e3e8bcbd6a11b8cdc4386
# Parent  a19a066dea764a70f06b4e4341229db92c2eb5c3
dscow plugin for dm-userspace userspace tool
Signed-off-by: Ryan Grimm <grimm@us.ibm.com>
Signed-off-by: Dan Smith <danms@us.ibm.com>
diff -r a19a066dea76 -r 6a7ea5a35543 tools/cowd/Makefile.am
--- a/tools/cowd/Makefile.am	Mon Aug 21 15:03:09 2006 -0500
+++ b/tools/cowd/Makefile.am	Mon Aug 21 15:03:09 2006 -0500
@@ -1,3 +1,5 @@ EXTRA_DIST = libdmu/dmu.c libdmu/dmu.h
+SUBDIRS = plugins
+
 EXTRA_DIST = libdmu/dmu.c libdmu/dmu.h
 
 bin_PROGRAMS = cowd
diff -r a19a066dea76 -r 6a7ea5a35543 tools/cowd/configure.in
--- a/tools/cowd/configure.in	Mon Aug 21 15:03:09 2006 -0500
+++ b/tools/cowd/configure.in	Mon Aug 21 15:03:09 2006 -0500
@@ -93,11 +93,15 @@ AC_SUBST(PLUGIN_DIR)
 AC_SUBST(PLUGIN_DIR)
 AC_SUBST(GLOBAL_CFLAGS)
 
-AC_CONFIG_FILES([Makefile])
+AC_CONFIG_FILES([Makefile
+		 plugins/Makefile
+		 plugins/dscow/Makefile])
 
 # This just makes it easier to run cowd from the source directory
 # for testing
 mkdir -p lib
+ln -sf ../plugins/dscow/.libs/libcowd_dscow.so.0 lib/libcowd_dscow.so
+ln -sf ../plugins/dscow/.libs/libcowd_dscow.la lib/libcowd_dscow.la
 
 AC_OUTPUT
 
diff -r a19a066dea76 -r 6a7ea5a35543 tools/cowd/cowd_control_loop.c
--- a/tools/cowd/cowd_control_loop.c	Mon Aug 21 15:03:09 2006 -0500
+++ b/tools/cowd/cowd_control_loop.c	Mon Aug 21 15:03:09 2006 -0500
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) International Business Machines Corp., 2006
  * Author: Dan Smith <danms@us.ibm.com>
+ * Author: Ryan Grimm <grimm@us.ibm.com>
  *
  * This file is subject to the terms and conditions of the GNU Lesser
  * General Public License. See the file COPYING in the main directory
diff -r a19a066dea76 -r 6a7ea5a35543 tools/cowd/plugins/Makefile.am
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/cowd/plugins/Makefile.am	Mon Aug 21 15:03:09 2006 -0500
@@ -0,0 +1,1 @@
+SUBDIRS = dscow
diff -r a19a066dea76 -r 6a7ea5a35543 tools/cowd/plugins/dscow/Makefile.am
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/cowd/plugins/dscow/Makefile.am	Mon Aug 21 15:03:09 2006 -0500
@@ -0,0 +1,14 @@
+EXTRA_DIST = README
+
+lib_LTLIBRARIES = libcowd_dscow.la
+libcowd_dscow_la_CFLAGS = -I../.. -I../../../../module @GLOBAL_CFLAGS@
+libcowd_dscow_la_SOURCES = dscow_ops.c dscow_plugin.c dscow_ops.h
+libcowd_dscow_la_LIBADD = 
+
+bin_PROGRAMS = dscow_tool
+dscow_tool_SOURCES = dscow_tool.c dscow_ops.c ../../util.c
+dscow_tool_CFLAGS = @GLOBAL_CFLAGS@
+
+#noinst_PROGRAMS = dscow_test
+#dscow_test_SOURCES = dscow_test.c dscow_ops.c
+
diff -r a19a066dea76 -r 6a7ea5a35543 tools/cowd/plugins/dscow/README
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/cowd/plugins/dscow/README	Mon Aug 21 15:03:09 2006 -0500
@@ -0,0 +1,13 @@
+To create a dscow image, run "dscow_tool" as follows:
+
+ # dscow_tool -c foo.dscow /path/to/base.img
+
+Which will create a "foo.dscow" file that uses
''/path/to/base.img'' as
+its base and 64kb blocks.
+
+Then, start a cowd instance like this:
+
+ # cowd -p dscow mydev /path/to/foo.dscow
+
+The base image will be loaded automatically.
+
diff -r a19a066dea76 -r 6a7ea5a35543 tools/cowd/plugins/dscow/dscow_ops.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/cowd/plugins/dscow/dscow_ops.c	Mon Aug 21 15:03:09 2006 -0500
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) International Business Machines Corp., 2006
+ * Author: Dan Smith <danms@us.ibm.com>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License. See the file COPYING in the main directory
+ * of this archive for more details.
+ *
+ */
+
+#define _LARGEFILE64_SOURCE
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "dscow_ops.h"
+
+#define MAX_VERSION 1
+
+#if 0
+#define DPRINTF( s, arg... ) fprintf(stderr, s, ##arg)
+#else
+#define DPRINTF( s, arg... )
+#endif
+
+int dscow_errno = 0;
+
+void dscow_print_info(struct dscow *handle)
+{
+	uint32_t i;
+	uint64_t size_mb = handle->header.size >> 20;
+	uint32_t bsize_kb = handle->header.block_size >> 10;
+	uint64_t mapped_blocks = 0;
+
+	printf("Base Image:      %s\n", handle->base_filename);
+	printf("Size:            %llu (%llu MB)\n", 
+	       handle->header.size, size_mb);
+	printf("Block size:      %lu (%lu KB)\n",
+	       handle->header.block_size, bsize_kb);
+	printf("First block:     %llu\n", handle->header.first_block);
+	printf("Blocks:          %llu\n", handle->blocks);
+	printf("Bitmap count:    %u\n", handle->bitmap_count);
+	printf("Format Version:  %u (we support up to version %u)\n", 
+	       handle->header.version, MAX_VERSION);
+
+	if (!handle->bitmap)
+		return;
+
+	for (i = 0; i < handle->bitmap_count; i++) {
+		uint32_t field = handle->bitmap[i];
+		for (field = handle->bitmap[i]; field; field >>= 1)
+			mapped_blocks++;
+		DPRINTF(" Field %u: %08x\n", i, handle->bitmap[i]);
+	}
+
+	printf("Usage:           %2.1f%% %lluMB (%llu blocks)\n",
+	       ((float)mapped_blocks / handle->blocks) * 100.0,
+	       (mapped_blocks * handle->header.block_size) >> 20,
+	       mapped_blocks);
+
+}
+
+static int _dscow_read_bitmap(struct dscow *dscow)
+{
+	uint32_t i;
+	int ret = 0;
+
+	dscow_errno = 0;
+
+	dscow->bitmap = calloc(dscow->bitmap_count, sizeof(uint32_t));
+	if (!dscow->bitmap) {
+		dscow_errno = ENOMEM;
+		return -1;
+	}
+	
+	DPRINTF("Seeking to bitmap @ %llu for read\n",
+		dscow->header.bitmap_offset);
+
+	lseek64(dscow->fd, dscow->header.bitmap_offset, SEEK_SET);
+
+	for (i = 0; i < dscow->bitmap_count; i++) {
+		ret = read(dscow->fd, 
+			   &dscow->bitmap[i],
+			   sizeof(dscow->bitmap[i]));
+		if (ret < 0) {
+			dscow_errno = errno;
+			break;
+		}
+
+		if (dscow->bitmap[i] != 0)
+			DPRINTF("  Bitmap:%08x %08x\n", i, dscow->bitmap[i]);
+	}
+
+	return ret;
+}
+
+static int _dscow_write_bitmap(struct dscow *dscow)
+{
+	uint32_t i;
+	int ret = 0;
+
+	DPRINTF("Seeking to bitmap @ %llu for write \n",
+		dscow->header.bitmap_offset);
+
+	lseek64(dscow->fd, dscow->header.bitmap_offset, SEEK_SET);
+
+	for (i = 0; i < dscow->bitmap_count; i++) {
+		ret = write(dscow->fd,
+			    &dscow->bitmap[i],
+			    sizeof(dscow->bitmap[i]));
+		if (ret < 0) {
+			dscow_errno = errno;
+			break;
+		}
+
+		if (dscow->bitmap[i] != 0)
+			DPRINTF("  Bitmap:%08x %08x\n", i, dscow->bitmap[i]);
+	}
+	
+	return ret;
+}
+
+static int _dscow_read_base_file(struct dscow *dscow)
+{
+	int ret = 0;
+
+	dscow->base_filename = malloc(dscow->header.base_file_size+1);
+	memset(dscow->base_filename, 0, dscow->header.base_file_size);
+
+	lseek64(dscow->fd, dscow->header.base_file_offset, SEEK_SET);
+	ret = read(dscow->fd, 
+		   dscow->base_filename, 
+		   dscow->header.base_file_size);
+	dscow->base_filename[dscow->header.base_file_size] =
''\0'';
+
+	if (ret < 0) {
+		dscow_errno = errno;
+	}
+
+	return ret;
+}
+
+static int _dscow_write_base_file(struct dscow *dscow)
+{
+	int ret = 0;
+
+	lseek64(dscow->fd, dscow->header.base_file_offset, SEEK_SET);
+	ret = write(dscow->fd,
+		    dscow->base_filename, 
+		    dscow->header.base_file_size);
+
+	if (ret < 0)
+		dscow_errno = errno;
+
+	return ret;
+}
+
+static int _dscow_read_disk_header(struct dscow *dscow)
+{
+	int ret = 0;
+
+	lseek64(dscow->fd, 0, SEEK_SET);
+
+	ret = read(dscow->fd, &dscow->header, sizeof(dscow->header));
+	if (ret < 0) {
+		dscow_errno = errno;
+		return ret;
+	} else if (ret != sizeof(dscow->header)) {
+		return 1;
+	}
+
+	dscow->blocks = dscow->header.size / dscow->header.block_size;
+	dscow->bitmap_count = dscow->blocks / (sizeof(uint32_t) * 8) + 1;
+	
+	if (dscow->header.magic != DSCOW_MAGIC) {
+		dscow_errno = EINVAL;
+		return -1;
+	}
+
+	if (_dscow_read_bitmap(dscow) < 0)
+		return -1;
+
+	if (_dscow_read_base_file(dscow) < 0)
+		return -1;
+
+	return 0;
+}
+
+static int _dscow_write_disk_header(struct dscow *dscow)
+{
+	int ret = 0;
+
+	lseek64(dscow->fd, 0, SEEK_SET);
+	
+	ret = write(dscow->fd, &dscow->header, sizeof(dscow->header));
+	if (ret < 0) {
+		dscow_errno = errno;
+		return ret;
+	} else if (ret != sizeof(dscow->header)) {
+		return 1;
+	}
+
+	if (!_dscow_write_bitmap(dscow) < 0)
+		return -1;
+
+	if (!_dscow_write_base_file(dscow) < 0)
+		return -1;
+       
+	return 0;
+}
+
+void dscow_cleanup(struct dscow *dscow)
+{
+	if (!dscow)
+		return;
+
+	if (dscow->bitmap)
+		free(dscow->bitmap);
+	
+	if (dscow->base_filename)
+		free(dscow->base_filename);
+	
+	free(dscow);
+}
+
+struct dscow *dscow_open(char *path)
+{
+	struct dscow *handle;
+	int ret;
+
+	handle = malloc(sizeof(*handle));
+	if (!handle) {
+		dscow_errno = ENOMEM;
+		return NULL;
+	}
+
+	handle->fd = open(path, O_RDWR | O_SYNC);
+	if (handle->fd < 0) {
+		DPRINTF("Failed to open %s\n", path);
+		dscow_errno = errno;
+		return NULL;
+	}
+
+	ret = _dscow_read_disk_header(handle);
+	if (ret < 0) {
+		dscow_cleanup(handle);
+		dscow_errno = EINVAL;
+		return NULL;
+	} else if (ret != 0) {
+		dscow_errno = EIO;
+		return NULL;
+	}
+
+	if (handle->header.version > MAX_VERSION) {
+		DPRINTF("Unknown format version %u\n", 
+			handle->header.version);
+		/* FIXME: Leak */
+		dscow_errno = ENOTSUP;
+		return NULL;
+	}
+
+	handle->dirty = 0;
+
+	return handle;
+}
+
+struct dscow *dscow_create(char *filename, char *base, uint32_t block_size)
+{
+	struct dscow *handle;
+	struct stat st;
+	uint64_t bitmap_end;
+	uint64_t s2;
+	char x;
+	int ret;
+	off64_t offset;
+
+	handle = malloc(sizeof(*handle));
+	if (!handle) {
+		dscow_errno = ENOMEM;
+		return NULL;
+	}
+
+	handle->header.magic = DSCOW_MAGIC;
+	handle->header.version = 1;
+
+	handle->fd = open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+	if (handle->fd < 0) {
+		dscow_errno = errno;
+		perror("open");
+		dscow_cleanup(handle);
+		return NULL;
+	}
+
+	/* Virtual Size */
+	stat(base, &st);
+	if (S_ISREG(st.st_mode))
+		handle->header.size = st.st_size;
+	else if (S_ISBLK(st.st_mode)) {
+		get_device_size(base, &s2);
+		handle->header.size = s2;
+	}
+	else
+		return NULL; /* Unknown type */
+
+	handle->header.block_size = block_size;
+
+	handle->base_filename = malloc(strlen(base) + 1);
+	strcpy(handle->base_filename, base);
+
+	handle->blocks = handle->header.size / handle->header.block_size;
+	handle->bitmap_count = (handle->blocks / (sizeof(uint32_t) * 8)) + 1;
+	
+	/* Base Filename Location */
+	handle->header.base_file_offset = sizeof(handle->header);
+	handle->header.base_file_size = strlen(handle->base_filename);
+
+	/* Bitmap Location */
+	handle->header.bitmap_offset = handle->header.base_file_offset + 
+		handle->header.base_file_size;
+		
+	/* First Block Location */
+	bitmap_end = handle->header.bitmap_offset + 
+		(handle->bitmap_count * sizeof(uint32_t));
+	handle->header.first_block = 
+		(bitmap_end + (handle->header.block_size - 1)) &
+		~(handle->header.block_size - 1);
+
+	handle->bitmap = calloc(handle->bitmap_count, sizeof(uint32_t));
+
+	
+	ret = _dscow_write_disk_header(handle);
+	if (ret < 0) {
+		dscow_errno = errno;
+		dscow_cleanup(handle);
+		return NULL;
+	} else if (ret > 0) {
+		dscow_errno = EIO;
+		return NULL;
+	}		
+
+	/* Inflate by seeking to the last byte in the file and then
+	   writing to it */
+	offset = lseek64(handle->fd,
+		       (handle->header.size + handle->header.first_block) - 1, 
+		       SEEK_SET);
+	if (offset != (handle->header.size + handle->header.first_block) - 1) {
+		DPRINTF("Failed to lseek to %llu\n",
+			(handle->header.size + handle->header.first_block)-1);
+		dscow_errno = EIO;
+		/* FIXME: Leak */
+		return NULL;
+	}
+	if (write(handle->fd, &x, 1) != 1) {
+		DPRINTF("Failed to write inflation byte\n");
+		dscow_errno = EIO;
+		return NULL;
+	}
+
+	handle->dirty = 0;
+
+	return handle;
+}
+
+int dscow_sync(struct dscow *handle)
+{
+	int ret = 0;
+
+	ret = _dscow_write_disk_header(handle);
+	if (ret != 0)
+		dscow_errno = EIO;
+	else
+		handle->dirty = 0;
+
+	return ret;
+}
+
+void dscow_close(struct dscow *handle)
+{
+	if (handle->dirty)
+		dscow_sync(handle);
+
+	close(handle->fd);
+
+	dscow_cleanup(handle);
+}
+
+void dscow_map_block(struct dscow *handle, uint64_t block)
+{
+	uint32_t field;
+	uint32_t bit;
+
+	field = block / (sizeof(uint32_t) * 8);
+	bit = block % (sizeof(uint32_t) * 8);
+
+	handle->bitmap[field] |= (1 << bit);
+
+	handle->dirty = 1;
+}
+
+int dscow_is_block_mapped(struct dscow *handle, uint64_t block)
+{
+	uint32_t field;
+	uint32_t bit;
+	
+	field = block / (sizeof(uint32_t) * 8);
+	bit = block % (sizeof(uint32_t) * 8);
+	
+	return (handle->bitmap[field] & (1 << bit)) != 0;
+}
+
diff -r a19a066dea76 -r 6a7ea5a35543 tools/cowd/plugins/dscow/dscow_ops.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/cowd/plugins/dscow/dscow_ops.h	Mon Aug 21 15:03:09 2006 -0500
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) International Business Machines Corp., 2006
+ * Author: Dan Smith <danms@us.ibm.com>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License. See the file COPYING in the main directory
+ * of this archive for more details.
+ *
+ */
+
+#ifndef __DSCOW_OPS_H
+#define __DSCOW_OPS_H
+
+#include <stdint.h>
+
+#define DSCOW_MAGIC ((''D''<<24) |
(''a''<<16) | (''n''<<8) |
(''S''))
+
+struct dscow_disk_header {
+	uint32_t magic;
+	uint32_t version;
+	uint64_t size;
+	uint64_t base_file_offset;
+	uint32_t base_file_size;
+	uint64_t bitmap_offset;
+	uint64_t first_block;
+	uint32_t block_size;
+};
+
+struct dscow {
+        struct dscow_disk_header header;
+
+        uint64_t blocks;
+        uint32_t *bitmap;
+        uint32_t bitmap_count;
+        char *base_filename;
+
+        int fd;
+	int dirty;	
+};
+
+extern int dscow_errno;
+
+struct dscow *dscow_create(char *filename, char *base, uint32_t block_size);
+struct dscow *dscow_open(char *path);
+void dscow_close(struct dscow *handle);
+int dscow_sync(struct dscow *handle);
+int dscow_is_block_mapped(struct dscow *handle, uint64_t block);
+void dscow_map_block(struct dscow *handle, uint64_t block);
+void dscow_print_info(struct dscow *handle);
+#endif
diff -r a19a066dea76 -r 6a7ea5a35543 tools/cowd/plugins/dscow/dscow_plugin.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/cowd/plugins/dscow/dscow_plugin.c	Mon Aug 21 15:03:09 2006 -0500
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) International Business Machines Corp., 2006
+ * Author: Dan Smith <danms@us.ibm.com>
+ * Author: Ryan Grimm <grimm@us.ibm.com>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License. See the file COPYING in the main directory
+ * of this archive for more details.
+ *
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdint.h>
+
+#include <cowd_plugin.h>
+
+#include "dscow_ops.h"
+
+#define ERR_LEN 256
+#define PATH_LEN 256
+
+static char errmsg[ERR_LEN];
+
+struct dscow_prv {
+	char base_dev[PATH_LEN];
+	char cow_dev[PATH_LEN];
+	dev_t base;
+	dev_t cow;
+	struct dscow *dscow;
+};
+
+static dev_t *dscow_get_devs(struct cow_device *dev, int *count)
+{
+	struct dscow_prv *prv = dev->plugin_private;
+	dev_t *devs;
+
+	devs = malloc(sizeof(*devs) * 2);
+	if (!devs) {
+		*count = 0;
+		return NULL;
+	}
+	
+	devs[0] = prv->base;
+	devs[1] = prv->cow;
+
+	*count = 2;
+	return devs;
+}
+
+static int dscow_init(struct cow_device *dev, int debug)
+{
+	struct dscow_prv *prv;
+	struct stat s;
+	char loop_dev[128];
+
+	debug = 1;
+
+	if (dev->plugin_num_args != 2) {
+		snprintf(errmsg, ERR_LEN, "Need two arguments");
+		return PLUGIN_FAIL;
+	}
+
+	prv = malloc(sizeof(*prv));
+	if (!prv) {
+		snprintf(errmsg, ERR_LEN, "Failed to allocate memory");
+		return PLUGIN_FAIL;
+	}
+
+	/* Need some grace here */
+	prv->dscow = dscow_open(dev->plugin_args[1]);
+	if (!prv->dscow) {
+		free(prv);
+		snprintf(errmsg, ERR_LEN, "Failed to open dscow: %s",
+			 strerror(dscow_errno));
+		return PLUGIN_FAIL;
+	}
+
+	snprintf(prv->base_dev, PATH_LEN, "%s",
prv->dscow->base_filename);
+	snprintf(prv->cow_dev, PATH_LEN, "%s", dev->plugin_args[1]);
+
+	if (is_file(prv->base_dev)) {
+		int ret;
+		int i = 0;
+		for (i = 0; i < 256; i++) {
+			sprintf(loop_dev, "/dev/loop%d", i);
+			ret = loop_setup(loop_dev, prv->base_dev);
+			if (ret)
+				break;	
+		}
+		snprintf(prv->base_dev, PATH_LEN, loop_dev);
+	}
+
+	if (is_file(prv->cow_dev)) {
+		int ret;
+		int i = 0;
+		for (i = 0; i < 256; i++) {
+			sprintf(loop_dev, "/dev/loop%d", i);
+			ret = loop_setup(loop_dev, prv->cow_dev);
+			if (ret)
+				break;	
+		}
+		snprintf(prv->cow_dev, PATH_LEN, loop_dev);
+	}
+
+	/* FIXME: replace this with a call */
+	dev->block_size = (uint64_t)prv->dscow->header.block_size;
+	dev->blocks = prv->dscow->blocks;
+
+	fflush(stdout);
+	stat(prv->base_dev, &s);
+	prv->base = s.st_rdev;
+
+	stat(prv->cow_dev, &s);
+	prv->cow = s.st_rdev;
+
+	dev->plugin_private = prv;
+
+	return PLUGIN_OK;
+}
+
+static int dscow_write_metadata(struct cow_device *dev)
+{
+	struct dscow_prv *prv = dev->plugin_private;
+
+	if (dscow_sync(prv->dscow)) {
+		snprintf(errmsg, ERR_LEN, "Failed to sync: %s",
+			 strerror(dscow_errno));
+		return PLUGIN_FAIL;
+	} else {
+		return PLUGIN_OK;
+	}
+}
+
+static bool dscow_need_flush(struct cow_device *dev)
+{
+	struct dscow_prv *prv = dev->plugin_private;
+
+	return prv->dscow->dirty;
+}
+
+static int dscow_map(struct cow_device *dev, struct dmu_map_data *data)
+{
+	struct dscow_prv *prv = dev->plugin_private;
+	uint64_t block = dmu_map_get_block(data);
+
+	if (dscow_is_block_mapped(prv->dscow, block)) {
+		dmu_map_set_block(data, 
+				  block + (prv->dscow->header.first_block /
+					   prv->dscow->header.block_size));
+		dmu_map_set_dest_dev(data, prv->cow);
+		/* FIXME: Might as well mark as write here! */
+	} else if (dmu_map_is_write(data)) {
+		dmu_map_set_block(data,
+				  block + (prv->dscow->header.first_block / 
+					   prv->dscow->header.block_size));
+		dmu_map_set_copy_src_dev(data, prv->base);
+		dmu_map_set_dest_dev(data, prv->cow);
+	} else {
+		/* Don''t change block */
+		dmu_map_set_dest_dev(data, prv->base);
+	}
+	
+	return PLUGIN_OK;
+}
+
+static int dscow_map_complete(struct cow_device *dev, uint64_t org_block)
+{
+	struct dscow_prv *prv = dev->plugin_private;
+
+	dscow_map_block(prv->dscow, org_block);
+
+	return PLUGIN_OK;
+}
+
+static void dscow_cleanup(struct cow_device *dev)
+{
+	struct dscow_prv *prv = dev->plugin_private;
+
+	if (!prv)
+		return;
+
+	dscow_close(prv->dscow);
+
+	loop_destroy(prv->base_dev);
+	loop_destroy(prv->cow_dev);
+	
+	free(prv);
+}
+
+int load_plugin(struct cowd_plugin *p)
+{
+	p->init_plugin = dscow_init;
+	p->write_metadata = dscow_write_metadata;
+	p->map_prepare = dscow_map;
+	p->map_complete = dscow_map_complete;
+	p->cleanup_plugin = dscow_cleanup;
+	p->need_flush = dscow_need_flush;
+	p->errmsg = errmsg;
+	p->get_devs = dscow_get_devs;
+
+	return 1;
+}
diff -r a19a066dea76 -r 6a7ea5a35543 tools/cowd/plugins/dscow/dscow_test.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/cowd/plugins/dscow/dscow_test.c	Mon Aug 21 15:03:09 2006 -0500
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) International Business Machines Corp., 2006
+ * Author: Dan Smith <danms@us.ibm.com>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License. See the file COPYING in the main directory
+ * of this archive for more details.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+
+#include "dscow_ops.h"
+
+int main(int argc, char **argv)
+{
+	struct dscow *h;
+	uint64_t i;
+
+	h = dscow_create("test.dscow", "test.base", 512);
+
+	for (i = 0; i < 1024; i+=2) {
+		dscow_map_block(h, i);
+	}
+	
+	for (i = 0; i < 1024; i++) {
+		if ((i%2) == dscow_is_block_mapped(h, i))
+			printf("Error: %llu (%llu:%i)\n", 
+			       i, i%2, dscow_is_block_mapped(h, i));
+	}
+
+}
diff -r a19a066dea76 -r 6a7ea5a35543 tools/cowd/plugins/dscow/dscow_tool.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/cowd/plugins/dscow/dscow_tool.c	Mon Aug 21 15:03:09 2006 -0500
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) International Business Machines Corp., 2006
+ * Author: Dan Smith <danms@us.ibm.com>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License. See the file COPYING in the main directory
+ * of this archive for more details.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+
+#include "dscow_ops.h"
+
+enum verbosity {NORMAL, LOUD, QUIET};
+
+usage(char *name)
+{
+	printf("Usage: %s [OPTIONS] [IMAGE] [BASE]\n"
+	       "Create a dscow image\n"
+	       "\n"
+	       "Options:\n"
+	       "  -c,--create        Create a new dscow image\n"
+	       "  -i,--info          Display information about a dscow
image\n"
+	       "  -V,--version       Display version information\n"
+	       "  -v,--verbose       Be verbose during image creation\n"
+	       "  -b,--block-size=KB Set the block size in KB (default
64)\n"
+	       "  -q,--quiet         Be quiet\n"
+	       "\n"
+	       "  IMAGE is the file to contain the changes\n"
+	       "  BASE is the base read-only image\n",
+	       name);
+}
+
+int do_create(char *image, char *base, unsigned long bs, int verbose)
+{
+	struct dscow *handle;
+
+	if (access(base, R_OK)) {
+		perror(base);
+		return 1;
+	}
+
+	handle = dscow_create(image, base, bs << 10);
+
+	if (handle) {
+		if (verbose == LOUD)
+			dscow_print_info(handle);
+		else if (verbose == NORMAL)
+			fprintf(stderr, "Created %s\n", image);
+	} else {
+		fprintf(stderr, "Failed: %s\n", strerror(dscow_errno));
+		return 1;
+	}
+
+	dscow_close(handle);
+
+	return 0;
+}
+
+int do_info(char *image, int verbose)
+{
+	struct dscow *handle;
+	char msg[256];
+
+	memset(msg, 0, 256);
+
+	if (access(image, R_OK)) {
+		perror(image);
+		return 1;
+	}
+
+	handle = dscow_open(image);
+
+	if (handle) {
+		if (verbose != QUIET)
+			dscow_print_info(handle);
+	} else {
+		if (dscow_errno == EINVAL) {
+			snprintf(msg, 256, "Not a dscow file");
+		} else if (dscow_errno == ENOTSUP) {
+			snprintf(msg, 256, "File created with newer tools");
+		} else {
+			strerror_r(dscow_errno, msg, 256);
+		}
+		if (verbose != QUIET)
+			printf("Unable to read %s: %s\n", image, msg);
+		return 1;
+	}
+
+	dscow_close(handle);
+
+	return 0;
+}
+
+int do_version()
+{
+	printf("dscow_tool v0.1.0\n"
+	       "\n"
+	       "Copyright (C) International Business Machines Corp., 2006\n"
+	       "Dan Smith <danms@us.ibm.com>\n");
+
+	return 0;
+}
+
+int process_arguments(int argc, char **argv)
+{
+	int c;
+	enum {Create, Info, Version, Error} mode;
+	int verbose = NORMAL;
+	unsigned long block_size = 64;
+
+	while (1) { 
+		int this_optind = optind ? optind : 1;
+		int option_index = 0;
+		static struct option long_opts[] = {
+			{"create",     0, 0, ''c''},
+			{"info",       0, 0, ''i''},
+			{"version",    0, 0, ''V''},
+			{"verbose",    0, 0, ''v''},
+			{"block-size", 1, 0, ''b''},
+			{"quiet",      0, 0, ''q''},
+			{0, 0, 0, 0}
+		};
+		
+		c = getopt_long(argc, argv, "ciVvb:q", 
+				long_opts, &option_index);
+
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case ''c'':
+			mode = Create;
+			break;
+
+		case ''V'':
+			mode = Version;
+			break;
+
+		case ''i'':
+			mode = Info;
+			break;
+
+		case ''v'':
+			verbose = LOUD;
+			break;
+
+		case ''b'':
+			block_size = strtoul(optarg, NULL, 0);
+			break;
+
+		case ''q'':
+			verbose = QUIET;
+			break;
+		};
+	}
+
+	if (mode == Create) {
+		if ((argc - optind) != 2) {
+			usage(argv[0]);
+			return 1;
+		} else {
+			return do_create(argv[optind], argv[optind+1], 
+					 block_size, verbose);
+		}
+	} else if (mode == Info) {
+		if ((argc - optind) != 1) {
+			usage(argv[0]);
+			return 1;
+		} else {
+			return do_info(argv[optind], verbose);
+		}
+	} else if (mode == Version) {
+		return do_version();
+	} else {
+		usage(argv[0]);
+		return 1;
+	}
+}
+
+int main(int argc, char **argv)
+{
+	return process_arguments(argc, argv);
+}
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
Ryan Grimm
2006-Aug-25  21:24 UTC
[Xen-devel] [PATCH 4 of 6] dscow plugin for dm-userspace userspace tool
Signed-off-by: Ryan Grimm <grimm@us.ibm.com>
Signed-off-by: Dan Smith <danms@us.ibm.com>
# HG changeset patch
# User Ryan Grimm <grimm@us.ibm.com>
# Date 1156536095 18000
# Node ID a3656acd770b4f21ad54fa961032ff39562058eb
# Parent  8c8d5dc4eaf4f0044f7fdd5adb282359eff7263a
dscow plugin for dm-userspace userspace tool
diff -r 8c8d5dc4eaf4 -r a3656acd770b tools/cowd/Makefile.am
--- a/tools/cowd/Makefile.am	Fri Aug 25 15:01:34 2006 -0500
+++ b/tools/cowd/Makefile.am	Fri Aug 25 15:01:35 2006 -0500
@@ -1,3 +1,5 @@ EXTRA_DIST = libdmu/dmu.c libdmu/dmu.h l
+SUBDIRS = plugins
+
 EXTRA_DIST = libdmu/dmu.c libdmu/dmu.h libdmu/internal_renames
 
 bin_PROGRAMS = cowd
diff -r 8c8d5dc4eaf4 -r a3656acd770b tools/cowd/configure.in
--- a/tools/cowd/configure.in	Fri Aug 25 15:01:34 2006 -0500
+++ b/tools/cowd/configure.in	Fri Aug 25 15:01:35 2006 -0500
@@ -93,11 +93,15 @@ AC_SUBST(PLUGIN_DIR)
 AC_SUBST(PLUGIN_DIR)
 AC_SUBST(GLOBAL_CFLAGS)
 
-AC_CONFIG_FILES([Makefile])
+AC_CONFIG_FILES([Makefile
+		 plugins/Makefile
+		 plugins/dscow/Makefile])
 
 # This just makes it easier to run cowd from the source directory
 # for testing
 mkdir -p lib
+ln -sf ../plugins/dscow/.libs/libcowd_dscow.so.0 lib/libcowd_dscow.so
+ln -sf ../plugins/dscow/.libs/libcowd_dscow.la lib/libcowd_dscow.la
 
 AC_OUTPUT
 
diff -r 8c8d5dc4eaf4 -r a3656acd770b tools/cowd/cowd_control_loop.c
--- a/tools/cowd/cowd_control_loop.c	Fri Aug 25 15:01:34 2006 -0500
+++ b/tools/cowd/cowd_control_loop.c	Fri Aug 25 15:01:35 2006 -0500
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) International Business Machines Corp., 2006
  * Author: Dan Smith <danms@us.ibm.com>
+ * Author: Ryan Grimm <grimm@us.ibm.com>
  *
  * This file is subject to the terms and conditions of the GNU Lesser
  * General Public License. See the file COPYING in the main directory
diff -r 8c8d5dc4eaf4 -r a3656acd770b tools/cowd/plugins/Makefile.am
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/cowd/plugins/Makefile.am	Fri Aug 25 15:01:35 2006 -0500
@@ -0,0 +1,1 @@
+SUBDIRS = dscow
diff -r 8c8d5dc4eaf4 -r a3656acd770b tools/cowd/plugins/dscow/Makefile.am
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/cowd/plugins/dscow/Makefile.am	Fri Aug 25 15:01:35 2006 -0500
@@ -0,0 +1,10 @@
+EXTRA_DIST = README
+
+lib_LTLIBRARIES = libcowd_dscow.la
+libcowd_dscow_la_CFLAGS = -I../.. -I../../../../module @GLOBAL_CFLAGS@
+libcowd_dscow_la_SOURCES = dscow_ops.c dscow_plugin.c dscow_ops.h
+libcowd_dscow_la_LIBADD = 
+
+bin_PROGRAMS = dscow_tool
+dscow_tool_SOURCES = dscow_tool.c dscow_ops.c ../../util.c
+dscow_tool_CFLAGS = @GLOBAL_CFLAGS@
diff -r 8c8d5dc4eaf4 -r a3656acd770b tools/cowd/plugins/dscow/README
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/cowd/plugins/dscow/README	Fri Aug 25 15:01:35 2006 -0500
@@ -0,0 +1,13 @@
+To create a dscow image, run "dscow_tool" as follows:
+
+ # dscow_tool -c foo.dscow /path/to/base.img
+
+Which will create a "foo.dscow" file that uses
''/path/to/base.img'' as
+its base and 64kb blocks.
+
+Then, start a cowd instance like this:
+
+ # cowd -p dscow mydev /path/to/foo.dscow
+
+The base image will be loaded automatically.
+
diff -r 8c8d5dc4eaf4 -r a3656acd770b tools/cowd/plugins/dscow/dscow_ops.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/cowd/plugins/dscow/dscow_ops.c	Fri Aug 25 15:01:35 2006 -0500
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) International Business Machines Corp., 2006
+ * Author: Dan Smith <danms@us.ibm.com>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License. See the file COPYING in the main directory
+ * of this archive for more details.
+ *
+ */
+
+#define _LARGEFILE64_SOURCE
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "dscow_ops.h"
+
+#define MAX_VERSION 1
+
+#if 0
+#define DPRINTF( s, arg... ) fprintf(stderr, s, ##arg)
+#else
+#define DPRINTF( s, arg... )
+#endif
+
+int dscow_errno = 0;
+
+void dscow_print_info(struct dscow *handle)
+{
+	uint32_t i;
+	uint64_t size_mb = handle->header.size >> 20;
+	uint32_t bsize_kb = handle->header.block_size >> 10;
+	uint64_t mapped_blocks = 0;
+
+	printf("Base Image:      %s\n", handle->base_filename);
+	printf("Size:            %llu (%llu MB)\n", 
+	       handle->header.size, size_mb);
+	printf("Block size:      %lu (%lu KB)\n",
+	       handle->header.block_size, bsize_kb);
+	printf("First block:     %llu\n", handle->header.first_block);
+	printf("Blocks:          %llu\n", handle->blocks);
+	printf("Bitmap count:    %u\n", handle->bitmap_count);
+	printf("Format Version:  %u (we support up to version %u)\n", 
+	       handle->header.version, MAX_VERSION);
+
+	if (!handle->bitmap)
+		return;
+
+	for (i = 0; i < handle->bitmap_count; i++) {
+		uint32_t field = handle->bitmap[i];
+		for (field = handle->bitmap[i]; field; field >>= 1)
+			mapped_blocks++;
+		DPRINTF(" Field %u: %08x\n", i, handle->bitmap[i]);
+	}
+
+	printf("Usage:           %2.1f%% %lluMB (%llu blocks)\n",
+	       ((float)mapped_blocks / handle->blocks) * 100.0,
+	       (mapped_blocks * handle->header.block_size) >> 20,
+	       mapped_blocks);
+
+}
+
+static int _dscow_read_bitmap(struct dscow *dscow)
+{
+	uint32_t i;
+	int ret = 0;
+
+	dscow_errno = 0;
+
+	dscow->bitmap = calloc(dscow->bitmap_count, sizeof(uint32_t));
+	if (!dscow->bitmap) {
+		dscow_errno = ENOMEM;
+		return -1;
+	}
+	
+	DPRINTF("Seeking to bitmap @ %llu for read\n",
+		dscow->header.bitmap_offset);
+
+	lseek64(dscow->fd, dscow->header.bitmap_offset, SEEK_SET);
+
+	for (i = 0; i < dscow->bitmap_count; i++) {
+		ret = read(dscow->fd, 
+			   &dscow->bitmap[i],
+			   sizeof(dscow->bitmap[i]));
+		if (ret < 0) {
+			dscow_errno = errno;
+			break;
+		}
+
+		if (dscow->bitmap[i] != 0)
+			DPRINTF("  Bitmap:%08x %08x\n", i, dscow->bitmap[i]);
+	}
+
+	return ret;
+}
+
+
+static int _dscow_write_bitmap(struct dscow *dscow)
+{
+	uint32_t i;
+	int ret = 0;
+
+	DPRINTF("Seeking to bitmap @ %llu for write \n",
+		dscow->header.bitmap_offset);
+
+	lseek64(dscow->fd, dscow->header.bitmap_offset, SEEK_SET);
+
+	for (i = 0; i < dscow->bitmap_count; i++) {
+		if (dscow->dirty_bitmaps[i]) {
+			lseek64(dscow->fd, i * sizeof(uint32_t), SEEK_CUR);
+						
+			ret = write(dscow->fd,
+				    &dscow->bitmap[i],
+				    sizeof(dscow->bitmap[i]));
+			if (ret < 0) {
+				dscow_errno = errno;
+				break;
+			}
+			dscow->dirty_bitmaps[i] = 0;
+		}
+
+		if (dscow->bitmap[i] != 0)
+			DPRINTF("  Bitmap:%08x %08x\n", i, dscow->bitmap[i]);
+	}
+	
+	return ret;
+}
+
+static int _dscow_read_base_file(struct dscow *dscow)
+{
+	int ret = 0;
+
+	dscow->base_filename = malloc(dscow->header.base_file_size+1);
+	memset(dscow->base_filename, 0, dscow->header.base_file_size);
+
+	lseek64(dscow->fd, dscow->header.base_file_offset, SEEK_SET);
+	ret = read(dscow->fd, 
+		   dscow->base_filename, 
+		   dscow->header.base_file_size);
+	dscow->base_filename[dscow->header.base_file_size] =
''\0'';
+
+	if (ret < 0) {
+		dscow_errno = errno;
+	}
+
+	return ret;
+}
+
+static int _dscow_write_base_file(struct dscow *dscow)
+{
+	int ret = 0;
+
+	lseek64(dscow->fd, dscow->header.base_file_offset, SEEK_SET);
+	ret = write(dscow->fd,
+		    dscow->base_filename, 
+		    dscow->header.base_file_size);
+
+	if (ret < 0)
+		dscow_errno = errno;
+
+	return ret;
+}
+
+static int _dscow_read_disk_header(struct dscow *dscow)
+{
+	int ret = 0;
+
+	lseek64(dscow->fd, 0, SEEK_SET);
+
+	ret = read(dscow->fd, &dscow->header, sizeof(dscow->header));
+	if (ret < 0) {
+		dscow_errno = errno;
+		return ret;
+	} else if (ret != sizeof(dscow->header)) {
+		return 1;
+	}
+
+	dscow->blocks = dscow->header.size / dscow->header.block_size;
+	dscow->bitmap_count = dscow->blocks / (sizeof(uint32_t) * 8) + 1;
+	
+	if (dscow->header.magic != DSCOW_MAGIC) {
+		dscow_errno = EINVAL;
+		return -1;
+	}
+
+	if (_dscow_read_bitmap(dscow) < 0)
+		return -1;
+
+	if (_dscow_read_base_file(dscow) < 0)
+		return -1;
+
+	return 0;
+}
+
+static int _dscow_write_disk_header(struct dscow *dscow)
+{
+	int ret = 0;
+
+	lseek64(dscow->fd, 0, SEEK_SET);
+	
+	ret = write(dscow->fd, &dscow->header, sizeof(dscow->header));
+	if (ret < 0) {
+		dscow_errno = errno;
+		return ret;
+	} else if (ret != sizeof(dscow->header)) {
+		return 1;
+	}
+
+	if (!_dscow_write_bitmap(dscow) < 0)
+		return -1;
+
+	if (!_dscow_write_base_file(dscow) < 0)
+		return -1;
+       
+	return 0;
+}
+
+void dscow_cleanup(struct dscow *dscow)
+{
+	if (!dscow)
+		return;
+
+	if (dscow->bitmap)
+		free(dscow->bitmap);
+	
+	if (dscow->base_filename)
+		free(dscow->base_filename);
+	
+	free(dscow);
+}
+
+struct dscow *dscow_open(char *path)
+{
+	struct dscow *handle;
+	int ret;
+
+	handle = malloc(sizeof(*handle));
+	if (!handle) {
+		dscow_errno = ENOMEM;
+		return NULL;
+	}
+
+	handle->fd = open(path, O_RDWR | O_SYNC | O_LARGEFILE);
+	if (handle->fd < 0) {
+		DPRINTF("Failed to open %s\n", path);
+		dscow_errno = errno;
+		return NULL;
+	}
+
+	ret = _dscow_read_disk_header(handle);
+	if (ret < 0) {
+		dscow_cleanup(handle);
+		dscow_errno = EINVAL;
+		return NULL;
+	} else if (ret != 0) {
+		dscow_errno = EIO;
+		return NULL;
+	}
+
+	if (handle->header.version > MAX_VERSION) {
+		DPRINTF("Unknown format version %u\n", 
+			handle->header.version);
+		/* FIXME: Leak */
+		dscow_errno = ENOTSUP;
+		return NULL;
+	}
+
+	handle->dirty_bitmaps = calloc(handle->bitmap_count, 
+					sizeof(uint32_t));
+	handle->dirty = 0;
+
+	return handle;
+}
+
+struct dscow *dscow_create(char *filename, char *base, uint32_t block_size)
+{
+	struct dscow *handle;
+	struct stat st;
+	uint64_t bitmap_end;
+	uint64_t s2;
+	char x;
+	int ret;
+	off64_t offset;
+
+	handle = malloc(sizeof(*handle));
+	if (!handle) {
+		dscow_errno = ENOMEM;
+		return NULL;
+	}
+
+	handle->header.magic = DSCOW_MAGIC;
+	handle->header.version = 1;
+
+	handle->fd = open(filename, 
+			  O_RDWR | O_CREAT | O_LARGEFILE, 
+			  S_IRUSR | S_IWUSR);
+	if (handle->fd < 0) {
+		dscow_errno = errno;
+		perror("open");
+		dscow_cleanup(handle);
+		return NULL;
+	}
+
+	/* Virtual Size */
+	stat(base, &st);
+	if (S_ISREG(st.st_mode))
+		handle->header.size = st.st_size;
+	else if (S_ISBLK(st.st_mode)) {
+		get_device_size(base, &s2);
+		handle->header.size = s2;
+	}
+	else
+		return NULL; /* Unknown type */
+
+	handle->header.block_size = block_size;
+
+	handle->base_filename = malloc(strlen(base) + 1);
+	strcpy(handle->base_filename, base);
+
+	handle->blocks = handle->header.size / handle->header.block_size;
+	handle->bitmap_count = (handle->blocks / (sizeof(uint32_t) * 8)) + 1;
+	
+	/* Base Filename Location */
+	handle->header.base_file_offset = sizeof(handle->header);
+	handle->header.base_file_size = strlen(handle->base_filename);
+
+	/* Bitmap Location */
+	handle->header.bitmap_offset = handle->header.base_file_offset + 
+		handle->header.base_file_size;
+		
+	/* First Block Location */
+	bitmap_end = handle->header.bitmap_offset + 
+		(handle->bitmap_count * sizeof(uint32_t));
+	handle->header.first_block = 
+		(bitmap_end + (handle->header.block_size - 1)) &
+		~(handle->header.block_size - 1);
+
+	handle->bitmap = calloc(handle->bitmap_count, sizeof(uint32_t));
+ 	handle->dirty_bitmaps = calloc(handle->bitmap_count, sizeof(uint32_t));
+	
+	ret = _dscow_write_disk_header(handle);
+	if (ret < 0) {
+		dscow_errno = errno;
+		dscow_cleanup(handle);
+		return NULL;
+	} else if (ret > 0) {
+		dscow_errno = EIO;
+		return NULL;
+	}		
+
+	/* Inflate by seeking to the last byte in the file and then
+	   writing to it */
+	offset = lseek64(handle->fd,
+		       (handle->header.size + handle->header.first_block) - 1, 
+		       SEEK_SET);
+	if (offset != (handle->header.size + handle->header.first_block) - 1) {
+		DPRINTF("Failed to lseek to %llu\n",
+			(handle->header.size + handle->header.first_block)-1);
+		dscow_errno = EIO;
+		/* FIXME: Leak */
+		return NULL;
+	}
+	if (write(handle->fd, &x, 1) != 1) {
+		DPRINTF("Failed to write inflation byte\n");
+		dscow_errno = EIO;
+		return NULL;
+	}
+
+	handle->dirty = 0;
+
+	return handle;
+}
+
+int dscow_sync(struct dscow *handle)
+{
+	int ret = 0;
+
+	ret = _dscow_write_disk_header(handle);
+	if (ret != 0)
+		dscow_errno = EIO;
+	else
+		handle->dirty = 0;
+
+	return ret;
+}
+
+void dscow_close(struct dscow *handle)
+{
+	if (handle->dirty)
+		dscow_sync(handle);
+
+	close(handle->fd);
+
+	dscow_cleanup(handle);
+}
+
+void dscow_map_block(struct dscow *handle, uint64_t block)
+{
+	uint32_t field;
+	uint32_t bit;
+
+	field = block / (sizeof(uint32_t) * 8);
+	bit = block % (sizeof(uint32_t) * 8);
+
+	handle->dirty_bitmaps[field] = 1;
+	handle->bitmap[field] |= (1 << bit);
+
+	handle->dirty = 1;
+}
+
+int dscow_is_block_mapped(struct dscow *handle, uint64_t block)
+{
+	uint32_t field;
+	uint32_t bit;
+	
+	field = block / (sizeof(uint32_t) * 8);
+	bit = block % (sizeof(uint32_t) * 8);
+	
+	return (handle->bitmap[field] & (1 << bit)) != 0;
+}
+
diff -r 8c8d5dc4eaf4 -r a3656acd770b tools/cowd/plugins/dscow/dscow_ops.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/cowd/plugins/dscow/dscow_ops.h	Fri Aug 25 15:01:35 2006 -0500
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) International Business Machines Corp., 2006
+ * Author: Dan Smith <danms@us.ibm.com>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License. See the file COPYING in the main directory
+ * of this archive for more details.
+ *
+ */
+
+#ifndef __DSCOW_OPS_H
+#define __DSCOW_OPS_H
+
+#include <stdint.h>
+
+#define DSCOW_MAGIC ((''D''<<24) |
(''a''<<16) | (''n''<<8) |
(''S''))
+
+struct dscow_disk_header {
+	uint32_t magic;
+	uint32_t version;
+	uint64_t size;
+	uint64_t base_file_offset;
+	uint32_t base_file_size;
+	uint64_t bitmap_offset;
+	uint64_t first_block;
+	uint32_t block_size;
+};
+
+struct dscow {
+        struct dscow_disk_header header;
+
+        uint64_t blocks;
+        uint32_t *bitmap;
+        uint32_t bitmap_count;
+        uint32_t *dirty_bitmaps;
+        char *base_filename;
+
+        int fd;
+	int dirty;	
+};
+
+extern int dscow_errno;
+
+struct dscow *dscow_create(char *filename, char *base, uint32_t block_size);
+struct dscow *dscow_open(char *path);
+void dscow_close(struct dscow *handle);
+int dscow_sync(struct dscow *handle);
+int dscow_is_block_mapped(struct dscow *handle, uint64_t block);
+void dscow_map_block(struct dscow *handle, uint64_t block);
+void dscow_print_info(struct dscow *handle);
+#endif
diff -r 8c8d5dc4eaf4 -r a3656acd770b tools/cowd/plugins/dscow/dscow_plugin.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/cowd/plugins/dscow/dscow_plugin.c	Fri Aug 25 15:01:35 2006 -0500
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) International Business Machines Corp., 2006
+ * Author: Dan Smith <danms@us.ibm.com>
+ * Author: Ryan Grimm <grimm@us.ibm.com>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License. See the file COPYING in the main directory
+ * of this archive for more details.
+ *
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdint.h>
+
+#include <cowd_plugin.h>
+
+#include "dscow_ops.h"
+
+#define ERR_LEN 256
+#define PATH_LEN 256
+
+static char errmsg[ERR_LEN];
+
+struct dscow_prv {
+	char base_dev[PATH_LEN];
+	char cow_dev[PATH_LEN];
+	dev_t base;
+	dev_t cow;
+	struct dscow *dscow;
+};
+
+static dev_t *dscow_get_devs(struct cow_device *dev, int *count)
+{
+	struct dscow_prv *prv = dev->plugin_private;
+	dev_t *devs;
+
+	devs = malloc(sizeof(*devs) * 2);
+	if (!devs) {
+		*count = 0;
+		return NULL;
+	}
+	
+	devs[0] = prv->base;
+	devs[1] = prv->cow;
+
+	*count = 2;
+	return devs;
+}
+
+static int dscow_init(struct cow_device *dev, int debug)
+{
+	struct dscow_prv *prv;
+	struct stat s;
+	char loop_dev[128];
+
+	debug = 1;
+
+	if (dev->plugin_num_args != 2) {
+		snprintf(errmsg, ERR_LEN, "Need two arguments");
+		return PLUGIN_FAIL;
+	}
+
+	prv = malloc(sizeof(*prv));
+	if (!prv) {
+		snprintf(errmsg, ERR_LEN, "Failed to allocate memory");
+		return PLUGIN_FAIL;
+	}
+
+	/* Need some grace here */
+	prv->dscow = dscow_open(dev->plugin_args[1]);
+	if (!prv->dscow) {
+		free(prv);
+		snprintf(errmsg, ERR_LEN, "Failed to open dscow: %s",
+			 strerror(dscow_errno));
+		return PLUGIN_FAIL;
+	}
+
+	snprintf(prv->base_dev, PATH_LEN, "%s",
prv->dscow->base_filename);
+	snprintf(prv->cow_dev, PATH_LEN, "%s", dev->plugin_args[1]);
+
+	if (is_file(prv->base_dev)) {
+		int ret;
+		int i = 0;
+		for (i = 0; i < 256; i++) {
+			sprintf(loop_dev, "/dev/loop%d", i);
+			ret = loop_setup(loop_dev, prv->base_dev);
+			if (ret)
+				break;	
+		}
+		snprintf(prv->base_dev, PATH_LEN, loop_dev);
+	}
+
+	if (is_file(prv->cow_dev)) {
+		int ret;
+		int i = 0;
+		for (i = 0; i < 256; i++) {
+			sprintf(loop_dev, "/dev/loop%d", i);
+			ret = loop_setup(loop_dev, prv->cow_dev);
+			if (ret)
+				break;	
+		}
+		snprintf(prv->cow_dev, PATH_LEN, loop_dev);
+	}
+
+	/* FIXME: replace this with a call */
+	dev->block_size = (uint64_t)prv->dscow->header.block_size;
+	dev->blocks = prv->dscow->blocks;
+
+	fflush(stdout);
+	stat(prv->base_dev, &s);
+	prv->base = s.st_rdev;
+
+	stat(prv->cow_dev, &s);
+	prv->cow = s.st_rdev;
+
+	dev->plugin_private = prv;
+
+	return PLUGIN_OK;
+}
+
+static int dscow_write_metadata(struct cow_device *dev)
+{
+	struct dscow_prv *prv = dev->plugin_private;
+
+	if (dscow_sync(prv->dscow)) {
+		snprintf(errmsg, ERR_LEN, "Failed to sync: %s",
+			 strerror(dscow_errno));
+		return PLUGIN_FAIL;
+	} else {
+		return PLUGIN_OK;
+	}
+}
+
+static bool dscow_need_flush(struct cow_device *dev)
+{
+	struct dscow_prv *prv = dev->plugin_private;
+
+	return prv->dscow->dirty;
+}
+
+static int dscow_map(struct cow_device *dev, struct dmu_map_data *data)
+{
+	struct dscow_prv *prv = dev->plugin_private;
+	uint64_t block = dmu_map_get_block(data);
+
+	if (dscow_is_block_mapped(prv->dscow, block)) {
+		dmu_map_set_block(data, 
+				  block + (prv->dscow->header.first_block /
+					   prv->dscow->header.block_size));
+		dmu_map_set_dest_dev(data, prv->cow);
+		/* FIXME: Might as well mark as write here! */
+	} else if (dmu_map_is_write(data)) {
+		dmu_map_set_block(data,
+				  block + (prv->dscow->header.first_block / 
+					   prv->dscow->header.block_size));
+		dmu_map_set_copy_src_dev(data, prv->base);
+		dmu_map_set_dest_dev(data, prv->cow);
+	} else {
+		/* Don''t change block */
+		dmu_map_set_dest_dev(data, prv->base);
+	}
+	
+	return PLUGIN_OK;
+}
+
+static int dscow_map_complete(struct cow_device *dev, uint64_t org_block)
+{
+	struct dscow_prv *prv = dev->plugin_private;
+
+	dscow_map_block(prv->dscow, org_block);
+
+	return PLUGIN_OK;
+}
+
+static void dscow_cleanup(struct cow_device *dev)
+{
+	struct dscow_prv *prv = dev->plugin_private;
+
+	if (!prv)
+		return;
+
+	dscow_close(prv->dscow);
+
+	loop_destroy(prv->base_dev);
+	loop_destroy(prv->cow_dev);
+	
+	free(prv);
+}
+
+int load_plugin(struct cowd_plugin *p)
+{
+	p->init_plugin = dscow_init;
+	p->write_metadata = dscow_write_metadata;
+	p->map_prepare = dscow_map;
+	p->map_complete = dscow_map_complete;
+	p->cleanup_plugin = dscow_cleanup;
+	p->need_flush = dscow_need_flush;
+	p->errmsg = errmsg;
+	p->get_devs = dscow_get_devs;
+
+	return 1;
+}
diff -r 8c8d5dc4eaf4 -r a3656acd770b tools/cowd/plugins/dscow/dscow_tool.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/cowd/plugins/dscow/dscow_tool.c	Fri Aug 25 15:01:35 2006 -0500
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) International Business Machines Corp., 2006
+ * Author: Dan Smith <danms@us.ibm.com>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License. See the file COPYING in the main directory
+ * of this archive for more details.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+
+#include "dscow_ops.h"
+
+enum verbosity {NORMAL, LOUD, QUIET};
+
+usage(char *name)
+{
+	printf("Usage: %s [OPTIONS] [IMAGE] [BASE]\n"
+	       "Create a dscow image\n"
+	       "\n"
+	       "Options:\n"
+	       "  -c,--create        Create a new dscow image\n"
+	       "  -i,--info          Display information about a dscow
image\n"
+	       "  -V,--version       Display version information\n"
+	       "  -v,--verbose       Be verbose during image creation\n"
+	       "  -b,--block-size=KB Set the block size in KB (default
64)\n"
+	       "  -q,--quiet         Be quiet\n"
+	       "\n"
+	       "  IMAGE is the file to contain the changes\n"
+	       "  BASE is the base read-only image\n",
+	       name);
+}
+
+int do_create(char *image, char *base, unsigned long bs, int verbose)
+{
+	struct dscow *handle;
+
+	if (access(base, R_OK)) {
+		perror(base);
+		return 1;
+	}
+
+	handle = dscow_create(image, base, bs << 10);
+
+	if (handle) {
+		if (verbose == LOUD)
+			dscow_print_info(handle);
+		else if (verbose == NORMAL)
+			fprintf(stderr, "Created %s\n", image);
+	} else {
+		fprintf(stderr, "Failed: %s\n", strerror(dscow_errno));
+		return 1;
+	}
+
+	dscow_close(handle);
+
+	return 0;
+}
+
+int do_info(char *image, int verbose)
+{
+	struct dscow *handle;
+	char msg[256];
+
+	memset(msg, 0, 256);
+
+	if (access(image, R_OK)) {
+		perror(image);
+		return 1;
+	}
+
+	handle = dscow_open(image);
+
+	if (handle) {
+		if (verbose != QUIET)
+			dscow_print_info(handle);
+	} else {
+		if (dscow_errno == EINVAL) {
+			snprintf(msg, 256, "Not a dscow file");
+		} else if (dscow_errno == ENOTSUP) {
+			snprintf(msg, 256, "File created with newer tools");
+		} else {
+			strerror_r(dscow_errno, msg, 256);
+		}
+		if (verbose != QUIET)
+			printf("Unable to read %s: %s\n", image, msg);
+		return 1;
+	}
+
+	dscow_close(handle);
+
+	return 0;
+}
+
+int do_version()
+{
+	printf("dscow_tool v0.1.0\n"
+	       "\n"
+	       "Copyright (C) International Business Machines Corp., 2006\n"
+	       "Dan Smith <danms@us.ibm.com>\n");
+
+	return 0;
+}
+
+int process_arguments(int argc, char **argv)
+{
+	int c;
+	enum {Create, Info, Version, Error} mode;
+	int verbose = NORMAL;
+	unsigned long block_size = 64;
+
+	while (1) { 
+		int this_optind = optind ? optind : 1;
+		int option_index = 0;
+		static struct option long_opts[] = {
+			{"create",     0, 0, ''c''},
+			{"info",       0, 0, ''i''},
+			{"version",    0, 0, ''V''},
+			{"verbose",    0, 0, ''v''},
+			{"block-size", 1, 0, ''b''},
+			{"quiet",      0, 0, ''q''},
+			{0, 0, 0, 0}
+		};
+		
+		c = getopt_long(argc, argv, "ciVvb:q", 
+				long_opts, &option_index);
+
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case ''c'':
+			mode = Create;
+			break;
+
+		case ''V'':
+			mode = Version;
+			break;
+
+		case ''i'':
+			mode = Info;
+			break;
+
+		case ''v'':
+			verbose = LOUD;
+			break;
+
+		case ''b'':
+			block_size = strtoul(optarg, NULL, 0);
+			break;
+
+		case ''q'':
+			verbose = QUIET;
+			break;
+		};
+	}
+
+	if (mode == Create) {
+		if ((argc - optind) != 2) {
+			usage(argv[0]);
+			return 1;
+		} else {
+			return do_create(argv[optind], argv[optind+1], 
+					 block_size, verbose);
+		}
+	} else if (mode == Info) {
+		if ((argc - optind) != 1) {
+			usage(argv[0]);
+			return 1;
+		} else {
+			return do_info(argv[optind], verbose);
+		}
+	} else if (mode == Version) {
+		return do_version();
+	} else {
+		usage(argv[0]);
+		return 1;
+	}
+}
+
+int main(int argc, char **argv)
+{
+	return process_arguments(argc, argv);
+}
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel