Ryan Grimm
2006-Aug-21 20:55 UTC
[Xen-devel] [PATCH 3 of 6] dm-userspace internal libdmu support for userspace tool
# HG changeset patch # User Ryan Grimm <grimm@us.ibm.com> # Date 1156190589 18000 # Node ID a19a066dea764a70f06b4e4341229db92c2eb5c3 # Parent 53c5bcecfcfdb70cb3a2aed0adb564312988fbdd dm-userspace internal libdmu support for userspace tool Signed-off-by: Ryan Grimm <grimm@us.ibm.com> Signed-off-by: Dan Smith <danms@us.ibm.com> diff -r 53c5bcecfcfd -r a19a066dea76 tools/Makefile --- a/tools/Makefile Mon Aug 21 15:03:07 2006 -0500 +++ b/tools/Makefile Mon Aug 21 15:03:09 2006 -0500 @@ -76,7 +76,7 @@ endif .PHONY: cowd cowdinstall cowclean cowd/Makefile: - cd cowd && sh autogen && sh configure + cd cowd && sh autogen && sh configure --enable-internal-dmu cowd cowdinstall: cowd/Makefile $(MAKE) -C cowd $(patsubst cowd%,%,$@) cowdclean: diff -r 53c5bcecfcfd -r a19a066dea76 tools/cowd/Makefile.am --- a/tools/cowd/Makefile.am Mon Aug 21 15:03:07 2006 -0500 +++ b/tools/cowd/Makefile.am Mon Aug 21 15:03:09 2006 -0500 @@ -1,3 +1,5 @@ bin_PROGRAMS = cowd +EXTRA_DIST = libdmu/dmu.c libdmu/dmu.h + bin_PROGRAMS = cowd cowd_SOURCES = cowd.c util.c cowd_loader.c cowd_control_loop.c \ @@ -7,5 +9,9 @@ cowd_LDADD = -ldevmapper -lltdl cowd_LDADD = -ldevmapper -lltdl cowd_LDFLAGS = -rdynamic -L./lib +if INTERNAL_DMU +cowd_SOURCES += libdmu/dmu.c +endif + clean-local: rm -f *~ diff -r 53c5bcecfcfd -r a19a066dea76 tools/cowd/configure.in --- a/tools/cowd/configure.in Mon Aug 21 15:03:07 2006 -0500 +++ b/tools/cowd/configure.in Mon Aug 21 15:03:09 2006 -0500 @@ -11,7 +11,19 @@ libdevmapper_error() { echo "* The version of libdevmapper on this system does *" echo "* not contain dm-userspace support *" echo "* *" + echo "* If you cannot reinstall libdevmapper, you can include *" + echo "* rough internal support with --enable-internal-dmu *" echo "*************************************************************" + + exit +} + +libdevmapper_conflict() { + echo "*************************************************************" + echo "* ERROR: The system libdevmapper library has dm-userspace *" + echo "* support, which cannot be used in combination with *" + echo "* internal support. *" + echo "*************************************************************" exit } @@ -30,6 +42,13 @@ AC_ARG_ENABLE(gcov, COVERAGE="-fprofile-arcs -ftest-coverage", COVERAGE="") +AC_ARG_ENABLE(internal-dmu, + [AC_HELP_STRING([--enable-internal-dmu], + [Enable internal dm-user library support])], + need_internal_dmu="yes", + need_internal_dmu="") +AM_CONDITIONAL(INTERNAL_DMU, test x$need_internal_dmu = xyes) + # Checks for programs. AC_PROG_CC AC_PROG_LIBTOOL @@ -37,7 +56,14 @@ AC_PROG_LIBTOOL # Checks for libraries. AC_CHECK_LIB([devmapper], [dm_task_create],, exit) AC_CHECK_LIB([ltdl], [lt_dlsym],, exit) -AC_CHECK_LIB([devmapper], [dmu_ctl_open],, libdevmapper_error) + +if test x$need_internal_dmu = xyes; then + AC_CHECK_LIB([devmapper], [dmu_ctl_open], libdevmapper_conflict) + abs_libdmu_dir=$(readlink -f .)/libdmu + GLOBAL_CFLAGS="$GLOBAL_CFLAGS -DINTERNAL_DMU -I$abs_libdmu_dir" +else + AC_CHECK_LIB([devmapper], [dmu_ctl_open],, libdevmapper_error) +fi if test -z "$COVERAGE"; then GLOBAL_CFLAGS="$GLOBAL_CFLAGS" diff -r 53c5bcecfcfd -r a19a066dea76 tools/cowd/cowd.c --- a/tools/cowd/cowd.c Mon Aug 21 15:03:07 2006 -0500 +++ b/tools/cowd/cowd.c Mon Aug 21 15:03:09 2006 -0500 @@ -24,6 +24,10 @@ #include <syslog.h> #include <libdevmapper.h> + +#ifdef INTERNAL_DMU +# include <dmu.h> +#endif #include "cowd.h" #include "cowd_plugin.h" diff -r 53c5bcecfcfd -r a19a066dea76 tools/cowd/libdmu/dmu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/cowd/libdmu/dmu.c Mon Aug 21 15:03:09 2006 -0500 @@ -0,0 +1,554 @@ +/* + * 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 <fcntl.h> +#include <linux/fs.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include <errno.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <libdevmapper.h> +#include <linux/dm-userspace.h> + +#include <dmu.h> + +#define DMU_MSG_DEBUG 0 + +#define QUEUE_SIZE_KB 4096 + +#if DMU_MSG_DEBUG +#define DPRINTF( s, arg... ) fprintf(stderr, s, ##arg) +#else +#define DPRINTF( s, arg... ) +#endif + +struct dmu_events { + status_handler status_fn; + map_req_handler map_fn; +}; + +struct dmu_event_data { + void *status_user_data; + void *map_user_data; +}; + +struct dmu_context { + int fd; + unsigned int buf_size; + unsigned int in_ptr; + unsigned int out_ptr; + uint8_t *in_buf; + uint8_t *out_buf; + uint32_t id_ctr; + struct dmu_events events; + struct dmu_event_data event_data; +}; + +struct dmu_map_data { + uint64_t block; + int64_t offset; + uint32_t id; + uint32_t flags; + dev_t dest_dev; + dev_t copy_src_dev; +}; + +void dmu_map_set_block(struct dmu_map_data *data, uint64_t block) +{ + data->block = block; +} + +uint64_t dmu_map_get_block(struct dmu_map_data *data) +{ + return data->block; +} + +void dmu_map_set_offset(struct dmu_map_data *data, int64_t offset) +{ + data->offset = offset; +} + +uint32_t dmu_map_get_id(struct dmu_map_data *data) +{ + return data->id; +} + +void dmu_map_set_dest_dev(struct dmu_map_data *data, dev_t dev) +{ + data->dest_dev = dev; +} + +void dmu_map_set_copy_src_dev(struct dmu_map_data *data, dev_t dev) +{ + data->copy_src_dev = dev; + dmu_set_flag(&data->flags, DMU_FLAG_COPY_FIRST); +} + +void dmu_map_set_writable(struct dmu_map_data *data, int writable) +{ + if (writable) + dmu_set_flag(&data->flags, DMU_FLAG_WR); + else + dmu_clr_flag(&data->flags, DMU_FLAG_WR); +} + +int dmu_map_is_write(struct dmu_map_data *data) +{ + return dmu_get_flag(&data->flags, DMU_FLAG_WR); +} + +void dmu_map_set_sync(struct dmu_map_data *data) +{ + dmu_set_flag(&data->flags, DMU_FLAG_SYNC); +} + +/* + * Get the major/minor of the character control device that @dm_device + * has exported for us. We do this by looking at the device status + * string. + */ +static int get_dm_control_dev(char *dm_device, + unsigned *maj, unsigned *min) +{ + struct dm_task *task; + int ret; + void *next = NULL; + uint64_t start, length; + char *ttype = NULL, *params = NULL; + + task = dm_task_create(DM_DEVICE_STATUS); + + ret = dm_task_set_name(task, dm_device); + if (!ret) { + DPRINTF("Failed to set device-mapper target name\n"); + dm_task_destroy(task); + return -1; + } + + ret = dm_task_run(task); + if (!ret) { + DPRINTF("Failed to run device-mapper task\n"); + dm_task_destroy(task); + return -1; + } + + ret = 0; + do { + next = dm_get_next_target(task, next, &start, &length, + &ttype, ¶ms); + + if (strcmp(ttype, "userspace") == 0) { + ret = sscanf(params, "%x:%x", maj, min); + if (ret == 2) + break; + } + + } while (next); + + return 0; +} + +/* + * Create the character device node for our control channel + */ +static int make_device_node(unsigned major, unsigned minor) +{ + char path[256]; + + sprintf(path, "/dev/dmu%i", minor); + + return mknod(path, S_IFCHR, makedev(major, minor)); +} + +static char *dmu_get_ctl_device(char *dm_device) +{ + unsigned ctl_major, ctl_minor; + static char path[256]; + + if (get_dm_control_dev(dm_device, &ctl_major, &ctl_minor) < 0) + return NULL; + + if (ctl_major == 0) { + DPRINTF("Unable to get device number\n"); + return NULL; + } + + sprintf(path, "/dev/dmu%i", ctl_minor); + + if (access(path, R_OK | W_OK)) { + if (make_device_node(ctl_major, ctl_minor)) { + DPRINTF("Failed to create device node: %s", + strerror(errno)); + return NULL; + } + } + + return path; +} + +static uint32_t make_version(int maj, int min, int patch) +{ + return 0 | (maj << 16) | (min << 8) | patch; +} + +static void dmu_split_dev(dev_t dev, uint32_t *maj, uint32_t *min) +{ + *maj = (dev & 0xFF00) >> 8; + *min = (dev & 0x00FF); +} + +/* Queue a message for sending */ +static int dmu_ctl_queue_msg(struct dmu_context *ctx, int type, void *msg) +{ + struct dmu_msg_header hdr; + + hdr.msg_type = type; + hdr.payload_len = dmu_get_msg_len(type); + hdr.id = ctx->id_ctr++; + + if ((ctx->out_ptr + (sizeof(hdr) + hdr.payload_len)) > ctx->buf_size) + return 0; /* No room for this */ + + memcpy(ctx->out_buf+ctx->out_ptr, &hdr, sizeof(hdr)); + ctx->out_ptr += sizeof(hdr); + + memcpy(ctx->out_buf+ctx->out_ptr, msg, hdr.payload_len); + ctx->out_ptr += hdr.payload_len; + + return 1; +} + +int dmu_invalidate_block(struct dmu_context *ctx, uint64_t block) +{ + struct dmu_msg_invalidate_map inv_msg; + + inv_msg.org_block = block; + + DPRINTF("Queuing invalidation for block %llu\n", block); + + return dmu_ctl_queue_msg(ctx, DM_USERSPACE_MAP_INVALIDATE, + &inv_msg); +} + +int dmu_sync_complete(struct dmu_context *ctx, uint32_t id) +{ + struct dmu_msg_status status_msg; + + status_msg.id_of_op = id; + status_msg.status = DM_USERSPACE_SYNC_COMPLETE; + + DPRINTF("Queuing metadata written for block %llu\n", block); + + return dmu_ctl_queue_msg(ctx, DM_USERSPACE_STATUS, + &status_msg); +} + +static int dmu_ctl_peek_queue(struct dmu_context *ctx, + int *type, void **msg) +{ + struct dmu_msg_header *hdr; + + if (ctx->in_ptr < sizeof(*hdr)) + return 0; + + hdr = (struct dmu_msg_header *)ctx->in_buf; + + *type = hdr->msg_type; + *msg = ctx->in_buf + sizeof(*hdr); + + return 1; +} + +/* Flush queue of messages to the kernel */ +int dmu_ctl_send_queue(struct dmu_context *ctx) +{ + int r; + + DPRINTF("Flushing outgoing queue\n"); + + r = write(ctx->fd, ctx->out_buf, ctx->out_ptr); + + if (r == ctx->out_ptr) + r = 1; + else + r = 0; + + ctx->out_ptr = 0; + + DPRINTF("Finished flushing queue\n"); + + return r; +} + +/* Fill the queue with requests from the kernel */ +static int dmu_ctl_recv_queue(struct dmu_context *ctx) +{ + int r; + + r = read(ctx->fd, ctx->in_buf, ctx->buf_size); + + ctx->in_ptr = r; + + if (r >= 0) + r = 1; + else + r = 0; + + return r; +} + +struct dmu_context *dmu_ctl_open(char *dev, int flags) +{ + int fd, r, type = 0; + struct dmu_msg_version msg; + struct dmu_msg_version *response; + struct dmu_context *ctx = NULL; + char *ctl_dev; + + ctl_dev = dmu_get_ctl_device(dev); + if (ctl_dev == NULL) + return NULL; + else if (access(ctl_dev, R_OK | W_OK)) + return NULL; + + fd = open(ctl_dev, O_RDWR | flags); + if (fd < 0) + goto out; + + ctx = calloc(sizeof(*ctx), 1); + if (!ctx) + goto out; + + ctx->in_buf = malloc(QUEUE_SIZE_KB << 10); + if (!ctx->in_buf) + goto out; + ctx->out_buf = malloc(QUEUE_SIZE_KB << 10); + if (!ctx->out_buf) + goto out; + + ctx->fd = fd; + ctx->in_ptr = ctx->out_ptr = 0; + ctx->id_ctr = 0; + ctx->buf_size = 4 << 20; + memset(&ctx->events, 0, sizeof(ctx->events)); + memset(&ctx->event_data, 0, sizeof(ctx->event_data)); + + msg.userspace_ver = make_version(0, 1, 0); + + r = dmu_ctl_queue_msg(ctx, DM_USERSPACE_GET_VERSION, &msg); + if (r < 0) + goto out; + + dmu_ctl_send_queue(ctx); + dmu_ctl_recv_queue(ctx); + + r = dmu_ctl_peek_queue(ctx, &type, (void**)&response); + if (r < 0) + goto out; + + if (type != DM_USERSPACE_GET_VERSION) { + DPRINTF(stderr, "Got non-version ping back: %i\n", type); + goto out; + } + + if (response->kernel_ver != msg.userspace_ver) { + DPRINTF(stderr, "Version mismatch: %x != %x\n", + msg.userspace_ver, response->kernel_ver); + goto out; + } else { + DPRINTF("Version match: %x == %x\n", + msg.userspace_ver, response->kernel_ver); + } + + return ctx; + + out: + if (ctx && ctx->in_buf) + free(ctx->in_buf); + + if (ctx && ctx->out_buf) + free(ctx->out_buf); + + if (ctx) + free(ctx); + + return NULL; +} + +int dmu_ctl_close(struct dmu_context *ctx) +{ + return close(ctx->fd); +} + +void dmu_register_status_handler(struct dmu_context *ctx, + status_handler handler, + void *data) +{ + ctx->events.status_fn = handler; + ctx->event_data.status_user_data = data; +} + +void dmu_register_map_handler(struct dmu_context *ctx, + map_req_handler handler, + void *data) +{ + ctx->events.map_fn = handler; + ctx->event_data.map_user_data = data; +} + +int dmu_events_pending(struct dmu_context *ctx, unsigned int msec) +{ + fd_set fds; + struct timeval tv; + + FD_ZERO(&fds); + FD_SET(ctx->fd, &fds); + + tv.tv_sec = msec / 1000; + tv.tv_usec = (msec % 1000) * 1000; + + if (select(ctx->fd + 1, &fds, NULL, NULL, &tv) < 0) + return 0; + + if (FD_ISSET(ctx->fd, &fds)) + return 1; + else + return 0; +} + +static int fire_map_req_event(struct dmu_context *ctx, + struct dmu_msg_map_request *req, + uint32_t id) +{ + struct dmu_msg_map_response resp; + struct dmu_map_data data; + int ret; + + if (!ctx->events.map_fn) + return 1; + + DPRINTF("Map event for %llu %c\n", + req->org_block, + dmu_get_flag(&req->flags, DMU_FLAG_WR) ? ''W'':''R''); + + data.block = req->org_block; + data.offset = 0; + data.id = id; + data.flags = req->flags; + data.dest_dev = data.copy_src_dev = 0; + + dmu_clr_flag(&data.flags, DMU_FLAG_COPY_FIRST); + dmu_clr_flag(&data.flags, DMU_FLAG_SYNC); + + ret = ctx->events.map_fn(ctx->event_data.map_user_data, &data); + + resp.org_block = req->org_block; + resp.new_block = data.block; + resp.offset = data.offset; + resp.flags = data.flags; + resp.id_of_req = data.id; + + dmu_split_dev(data.copy_src_dev, &resp.src_maj, &resp.src_min); + dmu_split_dev(data.dest_dev, &resp.dst_maj, &resp.dst_min); + + DPRINTF("Mapped %llu -> %llu\n", resp.org_block, resp.new_block); + + if (ret < 0) + dmu_ctl_queue_msg(ctx, DM_USERSPACE_MAP_FAILED, &resp); + else + dmu_ctl_queue_msg(ctx, DM_USERSPACE_MAP_BLOCK_RESP, &resp); + + return ret; +} + +static int fire_status_event(struct dmu_context *ctx, + struct dmu_msg_status *status, + uint32_t id) +{ + uint32_t user_code; + + switch (status->status) { + case DM_USERSPACE_INVAL_COMPLETE: + user_code = DMU_STATUS_INVAL_COMPLETE; + break; + case DM_USERSPACE_INVAL_FAILED: + user_code = DMU_STATUS_INVAL_FAILED; + break; + case DM_USERSPACE_SYNC_COMPLETE: + user_code = DMU_STATUS_SYNC_COMPLETE; + break; + default: + user_code = DMU_STATUS_UNKNOWN; + }; + + if (ctx->events.status_fn) + ctx->events.status_fn(ctx->event_data.status_user_data, + status->id_of_op, user_code); + + return 0; +} + +static int decode_message(struct dmu_context *ctx, int type, uint32_t id, + uint8_t *msg) +{ + switch (type) { + case DM_USERSPACE_MAP_BLOCK_REQ: + DPRINTF("Request event: %u\n", id); + return fire_map_req_event(ctx, + (struct dmu_msg_map_request *)msg, + id); + case DM_USERSPACE_STATUS: + DPRINTF("Status event\n"); + return fire_status_event(ctx, + (struct dmu_msg_status *)msg, + id); + default: + DPRINTF("Unknown message type: %i\n", type); + return -1; /* Unknown message type */ + }; +} + +int dmu_process_events(struct dmu_context *ctx) +{ + struct dmu_msg_header *hdr; + int ptr = 0, ret, do_flush = 0; + + if (!dmu_ctl_recv_queue(ctx)) + return -1; /* Receive failed */ + + DPRINTF("Got %i bytes\n", ctx->in_ptr); + + ptr = 0; + while (ptr < ctx->in_ptr) { + hdr = (struct dmu_msg_header *)&ctx->in_buf[ptr]; + ptr += sizeof(*hdr); + + ret = decode_message(ctx, hdr->msg_type, hdr->id, + &ctx->in_buf[ptr]); + if (ret > 0) + do_flush = 1; + + ptr += hdr->payload_len; + }; + + ctx->in_ptr = 0; + + if (do_flush) { + DPRINTF("Flushing outgoing message queue as requested\n"); + dmu_ctl_send_queue(ctx); + } + + return 1; +} + diff -r 53c5bcecfcfd -r a19a066dea76 tools/cowd/libdmu/dmu.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/cowd/libdmu/dmu.h Mon Aug 21 15:03:09 2006 -0500 @@ -0,0 +1,50 @@ +#ifndef __DMU_H +#define __DMU_H + +#include <stdint.h> + +/************** + * dm-userspace + **************/ + +enum { + DMU_STATUS_UNKNOWN = 0, + DMU_STATUS_BLOCK_FLUSHED, + DMU_STATUS_INVAL_COMPLETE, + DMU_STATUS_INVAL_FAILED, + DMU_STATUS_SYNC_COMPLETE +}; + +struct dmu_context; +struct dmu_map_data; + +typedef int (*status_handler)(void *data, uint32_t id, uint32_t status); +typedef int (*map_req_handler)(void *data, struct dmu_map_data *map_data); + +/* High-level control operations */ +struct dmu_context *dmu_ctl_open(char *dev, int flags); +int dmu_ctl_close(struct dmu_context *ctx); +int dmu_ctl_send_queue(struct dmu_context *ctx); +void dmu_register_status_handler(struct dmu_context *ctx, + status_handler handler, + void *data); +void dmu_register_map_handler(struct dmu_context *ctx, + map_req_handler handler, + void *data); +int dmu_invalidate_block(struct dmu_context *ctx, uint64_t block); +int dmu_sync_complete(struct dmu_context *ctx, uint32_t id); +int dmu_events_pending(struct dmu_context *ctx, unsigned int msec); +int dmu_process_events(struct dmu_context *ctx); + +/* Map manipulation functions */ +void dmu_map_set_block(struct dmu_map_data *data, uint64_t block); +uint64_t dmu_map_get_block(struct dmu_map_data *data); +void dmu_map_set_offset(struct dmu_map_data *data, int64_t offset); +uint32_t dmu_map_get_id(struct dmu_map_data *data); +void dmu_map_set_dest_dev(struct dmu_map_data *data, dev_t dev); +void dmu_map_set_copy_src_dev(struct dmu_map_data *data, dev_t dev); +void dmu_map_set_writable(struct dmu_map_data *data, int writable); +int dmu_map_is_write(struct dmu_map_data *data); +void dmu_map_set_sync(struct dmu_map_data *data); + +#endif diff -r 53c5bcecfcfd -r a19a066dea76 tools/cowd/libdmu/linux/dm-userspace.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/cowd/libdmu/linux/dm-userspace.h Mon Aug 21 15:03:09 2006 -0500 @@ -0,0 +1,147 @@ +/* + * Copyright (C) International Business Machines Corp., 2006 + * Author: Dan Smith <danms@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __DM_USERSPACE_H +#define __DM_USERSPACE_H + +#include <linux/types.h> + +/* + * Message Types + */ +#define DM_USERSPACE_GET_VERSION 1 +#define DM_USERSPACE_MAP_BLOCK_REQ 2 +#define DM_USERSPACE_MAP_BLOCK_RESP 3 +#define DM_USERSPACE_MAP_FAILED 4 +#define DM_USERSPACE_MAP_INVALIDATE 5 +#define DM_USERSPACE_STATUS 6 + +/* + * Status codes + */ +#define DM_USERSPACE_INVAL_COMPLETE 101 +#define DM_USERSPACE_INVAL_FAILED 102 +#define DM_USERSPACE_SYNC_COMPLETE 103 + +/* + * Flags and associated macros + */ +#define DMU_FLAG_VALID 1 +#define DMU_FLAG_RD 2 +#define DMU_FLAG_WR 4 +#define DMU_FLAG_COPY_FIRST 8 +#define DMU_FLAG_TEMPORARY 16 +#define DMU_FLAG_INUSE 32 +#define DMU_FLAG_SYNC 64 +#define DMU_FLAG_WAITING 128 + +static int dmu_get_flag(uint32_t *flags, uint32_t flag) +{ + return (*flags & flag) != 0; +} + +static void dmu_set_flag(uint32_t *flags, uint32_t flag) +{ + *flags |= flag; +} + +static void dmu_clr_flag(uint32_t *flags, uint32_t flag) +{ + *flags &= (~flag); +} + +static void dmu_cpy_flag(uint32_t *flags, uint32_t src, uint32_t flag) +{ + *flags = (*flags & ~flag) | (src & flag); +} + +/* + * This message header is sent in front of every message, in both + * directions + */ +struct dmu_msg_header { + uint32_t msg_type; + uint32_t payload_len; + uint32_t id; +}; + +/* DM_USERSPACE_GET_VERSION */ +struct dmu_msg_version { + uint32_t userspace_ver; + uint32_t kernel_ver; +}; + +/* For status codes */ +struct dmu_msg_status { + uint32_t id_of_op; + uint32_t status; +}; + +/* DM_USERSPACE_MAP_BLOCK_REQ */ +struct dmu_msg_map_request { + uint64_t org_block; + + uint32_t flags; +}; + +/* DM_USERSPACE_MAP_BLOCK_RESP + * DM_USERSPACE_MAP_BLOCK_FAILED + */ +struct dmu_msg_map_response { + uint64_t org_block; + uint64_t new_block; + int64_t offset; + + uint32_t id_of_req; + uint32_t flags; + + uint32_t src_maj; + uint32_t src_min; + + uint32_t dst_maj; + uint32_t dst_min; +}; + +/* DM_USERSPACE_MAP_INVALIDATE */ +struct dmu_msg_invalidate_map { + uint64_t org_block; +}; + +static inline int dmu_get_msg_len(int type) +{ + switch (type) { + case DM_USERSPACE_GET_VERSION: + return sizeof(struct dmu_msg_version); + case DM_USERSPACE_INVAL_COMPLETE: + case DM_USERSPACE_INVAL_FAILED: + case DM_USERSPACE_STATUS: + return sizeof(struct dmu_msg_status); + case DM_USERSPACE_MAP_BLOCK_REQ: + return sizeof(struct dmu_msg_map_request); + case DM_USERSPACE_MAP_BLOCK_RESP: + case DM_USERSPACE_MAP_FAILED: + return sizeof(struct dmu_msg_map_response); + case DM_USERSPACE_MAP_INVALIDATE: + return sizeof(struct dmu_msg_invalidate_map); + default: + return -1; + }; +} + +#endif _______________________________________________ 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 3 of 6] dm-userspace internal libdmu support for 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 1156536094 18000 # Node ID 8c8d5dc4eaf4f0044f7fdd5adb282359eff7263a # Parent 7ca9885684d9eaeef4422d52f9ae9efd033650d0 dm-userspace internal libdmu support for userspace tool diff -r 7ca9885684d9 -r 8c8d5dc4eaf4 tools/Makefile --- a/tools/Makefile Fri Aug 25 15:01:33 2006 -0500 +++ b/tools/Makefile Fri Aug 25 15:01:34 2006 -0500 @@ -77,7 +77,7 @@ endif .PHONY: cowd cowdinstall cowclean cowd/Makefile: -which libtoolize && which aclocal && which automake && \ - cd cowd && sh autogen && sh configure + cd cowd && sh autogen && sh configure --enable-internal-dmu cowd cowdinstall: cowd/Makefile -$(MAKE) -C cowd $(patsubst cowd%,%,$@) cowdclean: diff -r 7ca9885684d9 -r 8c8d5dc4eaf4 tools/cowd/Makefile.am --- a/tools/cowd/Makefile.am Fri Aug 25 15:01:33 2006 -0500 +++ b/tools/cowd/Makefile.am Fri Aug 25 15:01:34 2006 -0500 @@ -1,3 +1,5 @@ bin_PROGRAMS = cowd +EXTRA_DIST = libdmu/dmu.c libdmu/dmu.h libdmu/internal_renames + bin_PROGRAMS = cowd cowd_SOURCES = cowd.c util.c cowd_loader.c cowd_control_loop.c \ @@ -7,5 +9,13 @@ cowd_LDADD = -ldevmapper -lltdl cowd_LDADD = -ldevmapper -lltdl cowd_LDFLAGS = -rdynamic -L./lib +if INTERNAL_DMU +cowd_SOURCES += libdmu/dmu.c +all-local: + for obj in cowd lib/*.so; do \ + objcopy --redefine-syms libdmu/internal_renames $$obj; \ + done +endif + clean-local: rm -f *~ diff -r 7ca9885684d9 -r 8c8d5dc4eaf4 tools/cowd/configure.in --- a/tools/cowd/configure.in Fri Aug 25 15:01:33 2006 -0500 +++ b/tools/cowd/configure.in Fri Aug 25 15:01:34 2006 -0500 @@ -11,7 +11,19 @@ libdevmapper_error() { echo "* The version of libdevmapper on this system does *" echo "* not contain dm-userspace support *" echo "* *" + echo "* If you cannot reinstall libdevmapper, you can include *" + echo "* rough internal support with --enable-internal-dmu *" echo "*************************************************************" + + exit +} + +libdevmapper_conflict() { + echo "*************************************************************" + echo "* ERROR: The system libdevmapper library has dm-userspace *" + echo "* support, which cannot be used in combination with *" + echo "* internal support. *" + echo "*************************************************************" exit 1 } @@ -30,6 +42,13 @@ AC_ARG_ENABLE(gcov, COVERAGE="-fprofile-arcs -ftest-coverage", COVERAGE="") +AC_ARG_ENABLE(internal-dmu, + [AC_HELP_STRING([--enable-internal-dmu], + [Enable internal dm-user library support])], + need_internal_dmu="yes", + need_internal_dmu="") +AM_CONDITIONAL(INTERNAL_DMU, test x$need_internal_dmu = xyes) + # Checks for programs. AC_PROG_CC AC_PROG_LIBTOOL @@ -37,7 +56,14 @@ AC_PROG_LIBTOOL # Checks for libraries. AC_CHECK_LIB([devmapper], [dm_task_create],, exit) AC_CHECK_LIB([ltdl], [lt_dlsym],, exit) -AC_CHECK_LIB([devmapper], [dmu_ctl_open],, libdevmapper_error) + +if test x$need_internal_dmu = xyes; then + AC_CHECK_LIB([devmapper], [dmu_ctl_open], libdevmapper_conflict) + abs_libdmu_dir=$(readlink -f .)/libdmu + GLOBAL_CFLAGS="$GLOBAL_CFLAGS -DINTERNAL_DMU -I$abs_libdmu_dir" +else + AC_CHECK_LIB([devmapper], [dmu_ctl_open],, libdevmapper_error) +fi if test -z "$COVERAGE"; then GLOBAL_CFLAGS="$GLOBAL_CFLAGS" diff -r 7ca9885684d9 -r 8c8d5dc4eaf4 tools/cowd/cowd.c --- a/tools/cowd/cowd.c Fri Aug 25 15:01:33 2006 -0500 +++ b/tools/cowd/cowd.c Fri Aug 25 15:01:34 2006 -0500 @@ -24,6 +24,10 @@ #include <syslog.h> #include <libdevmapper.h> + +#ifdef INTERNAL_DMU +# include <dmu.h> +#endif #include "cowd.h" #include "cowd_plugin.h" diff -r 7ca9885684d9 -r 8c8d5dc4eaf4 tools/cowd/libdmu/dmu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/cowd/libdmu/dmu.c Fri Aug 25 15:01:34 2006 -0500 @@ -0,0 +1,554 @@ +/* + * 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 <fcntl.h> +#include <linux/fs.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include <errno.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <libdevmapper.h> +#include <linux/dm-userspace.h> + +#include <dmu.h> + +#define DMU_MSG_DEBUG 0 + +#define QUEUE_SIZE_KB 4096 + +#if DMU_MSG_DEBUG +#define DPRINTF( s, arg... ) fprintf(stderr, s, ##arg) +#else +#define DPRINTF( s, arg... ) +#endif + +struct dmu_events { + status_handler status_fn; + map_req_handler map_fn; +}; + +struct dmu_event_data { + void *status_user_data; + void *map_user_data; +}; + +struct dmu_context { + int fd; + unsigned int buf_size; + unsigned int in_ptr; + unsigned int out_ptr; + uint8_t *in_buf; + uint8_t *out_buf; + uint32_t id_ctr; + struct dmu_events events; + struct dmu_event_data event_data; +}; + +struct dmu_map_data { + uint64_t block; + int64_t offset; + uint32_t id; + uint32_t flags; + dev_t dest_dev; + dev_t copy_src_dev; +}; + +void dmu_map_set_block(struct dmu_map_data *data, uint64_t block) +{ + data->block = block; +} + +uint64_t dmu_map_get_block(struct dmu_map_data *data) +{ + return data->block; +} + +void dmu_map_set_offset(struct dmu_map_data *data, int64_t offset) +{ + data->offset = offset; +} + +uint32_t dmu_map_get_id(struct dmu_map_data *data) +{ + return data->id; +} + +void dmu_map_set_dest_dev(struct dmu_map_data *data, dev_t dev) +{ + data->dest_dev = dev; +} + +void dmu_map_set_copy_src_dev(struct dmu_map_data *data, dev_t dev) +{ + data->copy_src_dev = dev; + dmu_set_flag(&data->flags, DMU_FLAG_COPY_FIRST); +} + +void dmu_map_set_writable(struct dmu_map_data *data, int writable) +{ + if (writable) + dmu_set_flag(&data->flags, DMU_FLAG_WR); + else + dmu_clr_flag(&data->flags, DMU_FLAG_WR); +} + +int dmu_map_is_write(struct dmu_map_data *data) +{ + return dmu_get_flag(&data->flags, DMU_FLAG_WR); +} + +void dmu_map_set_sync(struct dmu_map_data *data) +{ + dmu_set_flag(&data->flags, DMU_FLAG_SYNC); +} + +/* + * Get the major/minor of the character control device that @dm_device + * has exported for us. We do this by looking at the device status + * string. + */ +static int get_dm_control_dev(char *dm_device, + unsigned *maj, unsigned *min) +{ + struct dm_task *task; + int ret; + void *next = NULL; + uint64_t start, length; + char *ttype = NULL, *params = NULL; + + task = dm_task_create(DM_DEVICE_STATUS); + + ret = dm_task_set_name(task, dm_device); + if (!ret) { + DPRINTF("Failed to set device-mapper target name\n"); + dm_task_destroy(task); + return -1; + } + + ret = dm_task_run(task); + if (!ret) { + DPRINTF("Failed to run device-mapper task\n"); + dm_task_destroy(task); + return -1; + } + + ret = 0; + do { + next = dm_get_next_target(task, next, &start, &length, + &ttype, ¶ms); + + if (strcmp(ttype, "userspace") == 0) { + ret = sscanf(params, "%x:%x", maj, min); + if (ret == 2) + break; + } + + } while (next); + + return 0; +} + +/* + * Create the character device node for our control channel + */ +static int make_device_node(unsigned major, unsigned minor) +{ + char path[256]; + + sprintf(path, "/dev/dmu%i", minor); + + return mknod(path, S_IFCHR, makedev(major, minor)); +} + +static char *dmu_get_ctl_device(char *dm_device) +{ + unsigned ctl_major, ctl_minor; + static char path[256]; + + if (get_dm_control_dev(dm_device, &ctl_major, &ctl_minor) < 0) + return NULL; + + if (ctl_major == 0) { + DPRINTF("Unable to get device number\n"); + return NULL; + } + + sprintf(path, "/dev/dmu%i", ctl_minor); + + if (access(path, R_OK | W_OK)) { + if (make_device_node(ctl_major, ctl_minor)) { + DPRINTF("Failed to create device node: %s", + strerror(errno)); + return NULL; + } + } + + return path; +} + +static uint32_t make_version(int maj, int min, int patch) +{ + return 0 | (maj << 16) | (min << 8) | patch; +} + +static void dmu_split_dev(dev_t dev, uint32_t *maj, uint32_t *min) +{ + *maj = (dev & 0xFF00) >> 8; + *min = (dev & 0x00FF); +} + +/* Queue a message for sending */ +static int dmu_ctl_queue_msg(struct dmu_context *ctx, int type, void *msg) +{ + struct dmu_msg_header hdr; + + hdr.msg_type = type; + hdr.payload_len = dmu_get_msg_len(type); + hdr.id = ctx->id_ctr++; + + if ((ctx->out_ptr + (sizeof(hdr) + hdr.payload_len)) > ctx->buf_size) + return 0; /* No room for this */ + + memcpy(ctx->out_buf+ctx->out_ptr, &hdr, sizeof(hdr)); + ctx->out_ptr += sizeof(hdr); + + memcpy(ctx->out_buf+ctx->out_ptr, msg, hdr.payload_len); + ctx->out_ptr += hdr.payload_len; + + return 1; +} + +int dmu_invalidate_block(struct dmu_context *ctx, uint64_t block) +{ + struct dmu_msg_invalidate_map inv_msg; + + inv_msg.org_block = block; + + DPRINTF("Queuing invalidation for block %llu\n", block); + + return dmu_ctl_queue_msg(ctx, DM_USERSPACE_MAP_INVALIDATE, + &inv_msg); +} + +int dmu_sync_complete(struct dmu_context *ctx, uint32_t id) +{ + struct dmu_msg_status status_msg; + + status_msg.id_of_op = id; + status_msg.status = DM_USERSPACE_SYNC_COMPLETE; + + DPRINTF("Queuing metadata written for block %llu\n", block); + + return dmu_ctl_queue_msg(ctx, DM_USERSPACE_STATUS, + &status_msg); +} + +static int dmu_ctl_peek_queue(struct dmu_context *ctx, + int *type, void **msg) +{ + struct dmu_msg_header *hdr; + + if (ctx->in_ptr < sizeof(*hdr)) + return 0; + + hdr = (struct dmu_msg_header *)ctx->in_buf; + + *type = hdr->msg_type; + *msg = ctx->in_buf + sizeof(*hdr); + + return 1; +} + +/* Flush queue of messages to the kernel */ +int dmu_ctl_send_queue(struct dmu_context *ctx) +{ + int r; + + DPRINTF("Flushing outgoing queue\n"); + + r = write(ctx->fd, ctx->out_buf, ctx->out_ptr); + + if (r == ctx->out_ptr) + r = 1; + else + r = 0; + + ctx->out_ptr = 0; + + DPRINTF("Finished flushing queue\n"); + + return r; +} + +/* Fill the queue with requests from the kernel */ +static int dmu_ctl_recv_queue(struct dmu_context *ctx) +{ + int r; + + r = read(ctx->fd, ctx->in_buf, ctx->buf_size); + + ctx->in_ptr = r; + + if (r >= 0) + r = 1; + else + r = 0; + + return r; +} + +struct dmu_context *dmu_ctl_open(char *dev, int flags) +{ + int fd, r, type = 0; + struct dmu_msg_version msg; + struct dmu_msg_version *response; + struct dmu_context *ctx = NULL; + char *ctl_dev; + + ctl_dev = dmu_get_ctl_device(dev); + if (ctl_dev == NULL) + return NULL; + else if (access(ctl_dev, R_OK | W_OK)) + return NULL; + + fd = open(ctl_dev, O_RDWR | flags); + if (fd < 0) + goto out; + + ctx = calloc(sizeof(*ctx), 1); + if (!ctx) + goto out; + + ctx->in_buf = malloc(QUEUE_SIZE_KB << 10); + if (!ctx->in_buf) + goto out; + ctx->out_buf = malloc(QUEUE_SIZE_KB << 10); + if (!ctx->out_buf) + goto out; + + ctx->fd = fd; + ctx->in_ptr = ctx->out_ptr = 0; + ctx->id_ctr = 0; + ctx->buf_size = 4 << 20; + memset(&ctx->events, 0, sizeof(ctx->events)); + memset(&ctx->event_data, 0, sizeof(ctx->event_data)); + + msg.userspace_ver = make_version(0, 1, 0); + + r = dmu_ctl_queue_msg(ctx, DM_USERSPACE_GET_VERSION, &msg); + if (r < 0) + goto out; + + dmu_ctl_send_queue(ctx); + dmu_ctl_recv_queue(ctx); + + r = dmu_ctl_peek_queue(ctx, &type, (void**)&response); + if (r < 0) + goto out; + + if (type != DM_USERSPACE_GET_VERSION) { + DPRINTF(stderr, "Got non-version ping back: %i\n", type); + goto out; + } + + if (response->kernel_ver != msg.userspace_ver) { + DPRINTF(stderr, "Version mismatch: %x != %x\n", + msg.userspace_ver, response->kernel_ver); + goto out; + } else { + DPRINTF("Version match: %x == %x\n", + msg.userspace_ver, response->kernel_ver); + } + + return ctx; + + out: + if (ctx && ctx->in_buf) + free(ctx->in_buf); + + if (ctx && ctx->out_buf) + free(ctx->out_buf); + + if (ctx) + free(ctx); + + return NULL; +} + +int dmu_ctl_close(struct dmu_context *ctx) +{ + return close(ctx->fd); +} + +void dmu_register_status_handler(struct dmu_context *ctx, + status_handler handler, + void *data) +{ + ctx->events.status_fn = handler; + ctx->event_data.status_user_data = data; +} + +void dmu_register_map_handler(struct dmu_context *ctx, + map_req_handler handler, + void *data) +{ + ctx->events.map_fn = handler; + ctx->event_data.map_user_data = data; +} + +int dmu_events_pending(struct dmu_context *ctx, unsigned int msec) +{ + fd_set fds; + struct timeval tv; + + FD_ZERO(&fds); + FD_SET(ctx->fd, &fds); + + tv.tv_sec = msec / 1000; + tv.tv_usec = (msec % 1000) * 1000; + + if (select(ctx->fd + 1, &fds, NULL, NULL, &tv) < 0) + return 0; + + if (FD_ISSET(ctx->fd, &fds)) + return 1; + else + return 0; +} + +static int fire_map_req_event(struct dmu_context *ctx, + struct dmu_msg_map_request *req, + uint32_t id) +{ + struct dmu_msg_map_response resp; + struct dmu_map_data data; + int ret; + + if (!ctx->events.map_fn) + return 1; + + DPRINTF("Map event for %llu %c\n", + req->org_block, + dmu_get_flag(&req->flags, DMU_FLAG_WR) ? ''W'':''R''); + + data.block = req->org_block; + data.offset = 0; + data.id = id; + data.flags = req->flags; + data.dest_dev = data.copy_src_dev = 0; + + dmu_clr_flag(&data.flags, DMU_FLAG_COPY_FIRST); + dmu_clr_flag(&data.flags, DMU_FLAG_SYNC); + + ret = ctx->events.map_fn(ctx->event_data.map_user_data, &data); + + resp.org_block = req->org_block; + resp.new_block = data.block; + resp.offset = data.offset; + resp.flags = data.flags; + resp.id_of_req = data.id; + + dmu_split_dev(data.copy_src_dev, &resp.src_maj, &resp.src_min); + dmu_split_dev(data.dest_dev, &resp.dst_maj, &resp.dst_min); + + DPRINTF("Mapped %llu -> %llu\n", resp.org_block, resp.new_block); + + if (ret < 0) + dmu_ctl_queue_msg(ctx, DM_USERSPACE_MAP_FAILED, &resp); + else + dmu_ctl_queue_msg(ctx, DM_USERSPACE_MAP_BLOCK_RESP, &resp); + + return ret; +} + +static int fire_status_event(struct dmu_context *ctx, + struct dmu_msg_status *status, + uint32_t id) +{ + uint32_t user_code; + + switch (status->status) { + case DM_USERSPACE_INVAL_COMPLETE: + user_code = DMU_STATUS_INVAL_COMPLETE; + break; + case DM_USERSPACE_INVAL_FAILED: + user_code = DMU_STATUS_INVAL_FAILED; + break; + case DM_USERSPACE_SYNC_COMPLETE: + user_code = DMU_STATUS_SYNC_COMPLETE; + break; + default: + user_code = DMU_STATUS_UNKNOWN; + }; + + if (ctx->events.status_fn) + ctx->events.status_fn(ctx->event_data.status_user_data, + status->id_of_op, user_code); + + return 0; +} + +static int decode_message(struct dmu_context *ctx, int type, uint32_t id, + uint8_t *msg) +{ + switch (type) { + case DM_USERSPACE_MAP_BLOCK_REQ: + DPRINTF("Request event: %u\n", id); + return fire_map_req_event(ctx, + (struct dmu_msg_map_request *)msg, + id); + case DM_USERSPACE_STATUS: + DPRINTF("Status event\n"); + return fire_status_event(ctx, + (struct dmu_msg_status *)msg, + id); + default: + DPRINTF("Unknown message type: %i\n", type); + return -1; /* Unknown message type */ + }; +} + +int dmu_process_events(struct dmu_context *ctx) +{ + struct dmu_msg_header *hdr; + int ptr = 0, ret, do_flush = 0; + + if (!dmu_ctl_recv_queue(ctx)) + return -1; /* Receive failed */ + + DPRINTF("Got %i bytes\n", ctx->in_ptr); + + ptr = 0; + while (ptr < ctx->in_ptr) { + hdr = (struct dmu_msg_header *)&ctx->in_buf[ptr]; + ptr += sizeof(*hdr); + + ret = decode_message(ctx, hdr->msg_type, hdr->id, + &ctx->in_buf[ptr]); + if (ret > 0) + do_flush = 1; + + ptr += hdr->payload_len; + }; + + ctx->in_ptr = 0; + + if (do_flush) { + DPRINTF("Flushing outgoing message queue as requested\n"); + dmu_ctl_send_queue(ctx); + } + + return 1; +} + diff -r 7ca9885684d9 -r 8c8d5dc4eaf4 tools/cowd/libdmu/dmu.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/cowd/libdmu/dmu.h Fri Aug 25 15:01:34 2006 -0500 @@ -0,0 +1,50 @@ +#ifndef __DMU_H +#define __DMU_H + +#include <stdint.h> + +/************** + * dm-userspace + **************/ + +enum { + DMU_STATUS_UNKNOWN = 0, + DMU_STATUS_BLOCK_FLUSHED, + DMU_STATUS_INVAL_COMPLETE, + DMU_STATUS_INVAL_FAILED, + DMU_STATUS_SYNC_COMPLETE +}; + +struct dmu_context; +struct dmu_map_data; + +typedef int (*status_handler)(void *data, uint32_t id, uint32_t status); +typedef int (*map_req_handler)(void *data, struct dmu_map_data *map_data); + +/* High-level control operations */ +struct dmu_context *dmu_ctl_open(char *dev, int flags); +int dmu_ctl_close(struct dmu_context *ctx); +int dmu_ctl_send_queue(struct dmu_context *ctx); +void dmu_register_status_handler(struct dmu_context *ctx, + status_handler handler, + void *data); +void dmu_register_map_handler(struct dmu_context *ctx, + map_req_handler handler, + void *data); +int dmu_invalidate_block(struct dmu_context *ctx, uint64_t block); +int dmu_sync_complete(struct dmu_context *ctx, uint32_t id); +int dmu_events_pending(struct dmu_context *ctx, unsigned int msec); +int dmu_process_events(struct dmu_context *ctx); + +/* Map manipulation functions */ +void dmu_map_set_block(struct dmu_map_data *data, uint64_t block); +uint64_t dmu_map_get_block(struct dmu_map_data *data); +void dmu_map_set_offset(struct dmu_map_data *data, int64_t offset); +uint32_t dmu_map_get_id(struct dmu_map_data *data); +void dmu_map_set_dest_dev(struct dmu_map_data *data, dev_t dev); +void dmu_map_set_copy_src_dev(struct dmu_map_data *data, dev_t dev); +void dmu_map_set_writable(struct dmu_map_data *data, int writable); +int dmu_map_is_write(struct dmu_map_data *data); +void dmu_map_set_sync(struct dmu_map_data *data); + +#endif diff -r 7ca9885684d9 -r 8c8d5dc4eaf4 tools/cowd/libdmu/internal_renames --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/cowd/libdmu/internal_renames Fri Aug 25 15:01:34 2006 -0500 @@ -0,0 +1,23 @@ +dmu_ctl_open int__dmu_ctl_open +dmu_clr_flag int__dmu_clr_flag +dmu_ctl_close int__dmu_ctl_close +dmu_ctl_queue_msg int__dmu_ctl_queue_msg +dmu_ctl_recv_queue int__dmu_ctl_recv_queue +dmu_ctl_send_queue int__dmu_ctl_send_queue +dmu_events_pending int__dmu_events_pending +dmu_invalidate_block int__dmu_invalidate_block +dmu_map_get_block int__dmu_map_get_block +dmu_map_get_id int__dmu_map_get_id +dmu_map_is_write int__dmu_map_is_write +dmu_map_set_block int__dmu_map_set_block +dmu_map_set_copy_src_dev int__dmu_map_set_copy_src_dev +dmu_map_set_dest_dev int__dmu_map_set_dest_dev +dmu_map_set_offset int__dmu_map_set_offset +dmu_map_set_sync int__dmu_map_set_sync +dmu_map_set_writable int__dmu_map_set_writable +dmu_process_events int__dmu_process_events +dmu_register_map_handler int__dmu_register_map_handler +dmu_register_status_handler int__dmu_register_status_handler +dmu_set_flag int__dmu_set_flag +dmu_split_dev int__dmu_split_dev +dmu_sync_complete int__dmu_sync_complete diff -r 7ca9885684d9 -r 8c8d5dc4eaf4 tools/cowd/libdmu/linux/dm-userspace.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/cowd/libdmu/linux/dm-userspace.h Fri Aug 25 15:01:34 2006 -0500 @@ -0,0 +1,147 @@ +/* + * Copyright (C) International Business Machines Corp., 2006 + * Author: Dan Smith <danms@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __DM_USERSPACE_H +#define __DM_USERSPACE_H + +#include <linux/types.h> + +/* + * Message Types + */ +#define DM_USERSPACE_GET_VERSION 1 +#define DM_USERSPACE_MAP_BLOCK_REQ 2 +#define DM_USERSPACE_MAP_BLOCK_RESP 3 +#define DM_USERSPACE_MAP_FAILED 4 +#define DM_USERSPACE_MAP_INVALIDATE 5 +#define DM_USERSPACE_STATUS 6 + +/* + * Status codes + */ +#define DM_USERSPACE_INVAL_COMPLETE 101 +#define DM_USERSPACE_INVAL_FAILED 102 +#define DM_USERSPACE_SYNC_COMPLETE 103 + +/* + * Flags and associated macros + */ +#define DMU_FLAG_VALID 1 +#define DMU_FLAG_RD 2 +#define DMU_FLAG_WR 4 +#define DMU_FLAG_COPY_FIRST 8 +#define DMU_FLAG_TEMPORARY 16 +#define DMU_FLAG_INUSE 32 +#define DMU_FLAG_SYNC 64 +#define DMU_FLAG_WAITING 128 + +static int dmu_get_flag(uint32_t *flags, uint32_t flag) +{ + return (*flags & flag) != 0; +} + +static void dmu_set_flag(uint32_t *flags, uint32_t flag) +{ + *flags |= flag; +} + +static void dmu_clr_flag(uint32_t *flags, uint32_t flag) +{ + *flags &= (~flag); +} + +static void dmu_cpy_flag(uint32_t *flags, uint32_t src, uint32_t flag) +{ + *flags = (*flags & ~flag) | (src & flag); +} + +/* + * This message header is sent in front of every message, in both + * directions + */ +struct dmu_msg_header { + uint32_t msg_type; + uint32_t payload_len; + uint32_t id; +}; + +/* DM_USERSPACE_GET_VERSION */ +struct dmu_msg_version { + uint32_t userspace_ver; + uint32_t kernel_ver; +}; + +/* For status codes */ +struct dmu_msg_status { + uint32_t id_of_op; + uint32_t status; +}; + +/* DM_USERSPACE_MAP_BLOCK_REQ */ +struct dmu_msg_map_request { + uint64_t org_block; + + uint32_t flags; +}; + +/* DM_USERSPACE_MAP_BLOCK_RESP + * DM_USERSPACE_MAP_BLOCK_FAILED + */ +struct dmu_msg_map_response { + uint64_t org_block; + uint64_t new_block; + int64_t offset; + + uint32_t id_of_req; + uint32_t flags; + + uint32_t src_maj; + uint32_t src_min; + + uint32_t dst_maj; + uint32_t dst_min; +}; + +/* DM_USERSPACE_MAP_INVALIDATE */ +struct dmu_msg_invalidate_map { + uint64_t org_block; +}; + +static inline int dmu_get_msg_len(int type) +{ + switch (type) { + case DM_USERSPACE_GET_VERSION: + return sizeof(struct dmu_msg_version); + case DM_USERSPACE_INVAL_COMPLETE: + case DM_USERSPACE_INVAL_FAILED: + case DM_USERSPACE_STATUS: + return sizeof(struct dmu_msg_status); + case DM_USERSPACE_MAP_BLOCK_REQ: + return sizeof(struct dmu_msg_map_request); + case DM_USERSPACE_MAP_BLOCK_RESP: + case DM_USERSPACE_MAP_FAILED: + return sizeof(struct dmu_msg_map_response); + case DM_USERSPACE_MAP_INVALIDATE: + return sizeof(struct dmu_msg_invalidate_map); + default: + return -1; + }; +} + +#endif _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel