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