tools: remove blktap2 source code

Signed-off-by: Wei Liu <wei.liu2@citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
This commit is contained in:
Wei Liu committed 2016-09-06 11:02:36 +01:00
1 parent 3f0ae679f2
commit 44b2829a8b
126 files changed
-40123

No files matched your search

-20
View File
@@ -1,20 +0,0 @@
XEN_ROOT = $(CURDIR)/../..
include $(XEN_ROOT)/tools/Rules.mk
CFLAGS += $(CFLAGS_libxenctrl)
LDLIBS += $(LDLIBS_libxenctrl)
SUBDIRS-y :=
SUBDIRS-y += include
SUBDIRS-y += lvm
SUBDIRS-y += vhd
SUBDIRS-$(CONFIG_Linux) += drivers
SUBDIRS-$(CONFIG_Linux) += control
clean:
rm -rf *.a *.so *.o *.rpm $(LIB) *~ $(DEPS) TAGS
distclean: clean
.PHONY: all clean install distclean
all clean install distclean: %: subdirs-%
-321
View File
@@ -1,321 +0,0 @@
Blktap2 Userspace Tools + Library
================================
Dutch Meyer
4th June 2009
Andrew Warfield and Julian Chesterfield
16th June 2006
The blktap2 userspace toolkit provides a user-level disk I/O
interface. The blktap2 mechanism involves a kernel driver that acts
similarly to the existing Xen/Linux blkback driver, and a set of
associated user-level libraries. Using these tools, blktap2 allows
virtual block devices presented to VMs to be implemented in userspace
and to be backed by raw partitions, files, network, etc.
The key benefit of blktap2 is that it makes it easy and fast to write
arbitrary block backends, and that these user-level backends actually
perform very well. Specifically:
- Metadata disk formats such as Copy-on-Write, encrypted disks, sparse
formats and other compression features can be easily implemented.
- Accessing file-based images from userspace avoids problems related
to flushing dirty pages which are present in the Linux loopback
driver. (Specifically, doing a large number of writes to an
NFS-backed image don't result in the OOM killer going berserk.)
- Per-disk handler processes enable easier userspace policing of block
resources, and process-granularity QoS techniques (disk scheduling
and related tools) may be trivially applied to block devices.
- It's very easy to take advantage of userspace facilities such as
networking libraries, compression utilities, peer-to-peer
file-sharing systems and so on to build more complex block backends.
- Crashes are contained -- incremental development/debugging is very
fast.
How it works (in one paragraph):
Working in conjunction with the kernel blktap2 driver, all disk I/O
requests from VMs are passed to the userspace deamon (using a shared
memory interface) through a character device. Each active disk is
mapped to an individual device node, allowing per-disk processes to
implement individual block devices where desired. The userspace
drivers are implemented using asynchronous (Linux libaio),
O_DIRECT-based calls to preserve the unbuffered, batched and
asynchronous request dispatch achieved with the existing blkback
code. We provide a simple, asynchronous virtual disk interface that
makes it quite easy to add new disk implementations.
As of June 2009 the current supported disk formats are:
- Raw Images (both on partitions and in image files)
- Fast sharable RAM disk between VMs (requires some form of
cluster-based filesystem support e.g. OCFS2 in the guest kernel)
- VHD, including snapshots and sparse images
- Qcow, including snapshots and sparse images
Build and Installation Instructions
===================================
Make to configure the blktap2 backend driver in your dom0 kernel. It
will inter-operate with the existing backend and frontend drivers. It
will also cohabitate with the original blktap driver. However, some
formats (currently aio and qcow) will default to their blktap2
versions when specified in a vm configuration file.
To build the tools separately, "make && make install" in
tools/blktap2.
Using the Tools
===============
Preparing an image for boot:
The userspace disk agent is configured to start automatically via xend
Customize the VM config file to use the 'tap:tapdisk' handler,
followed by the driver type. e.g. for a raw image such as a file or
partition:
disk = ['tap:tapdisk:aio:<FILENAME>,sda1,w']
Alternatively, the vhd-util tool (installed with make install, or in
/blktap2/vhd) can be used to build sparse copy-on-write vhd images.
For example, to build a sparse image -
vhd-util create -n MyVHDFile -s 1024
This creates a sparse 1GB file named "MyVHDFile" that can be mounted
and populated with data.
One can also base the image on a raw file -
vhd-util snapshot -n MyVHDFile -p SomeRawFile -m
This creates a sparse VHD file named "MyVHDFile" using "SomeRawFile"
as a parent image. Copy-on-write semantics ensure that writes will be
stored in "MyVHDFile" while reads will be directed to the most
recently written version of the data, either in "MyVHDFile" or
"SomeRawFile" as is appropriate. Other options exist as well, consult
the vhd-util application for the complete set of VHD tools.
VHD files can be mounted automatically in a guest similarly to the
above AIO example simply by specifying the vhd driver.
disk = ['tap:tapdisk:vhd:<VHD FILENAME>,sda1,w']
Snapshots:
Pausing a guest will also plug the corresponding IO queue for blktap2
devices and stop blktap2 drivers. This can be used to implement a
safe live snapshot of qcow and vhd disks. An example script "xmsnap"
is shown in the tools/blktap2/drivers directory. This script will
perform a live snapshot of a qcow disk. VHD files can use the
"vhd-util snapshot" tool discussed above. If this snapshot command is
applied to a raw file mounted with tap:tapdisk:AIO, include the -m
flag and the driver will be reloaded as VHD. If applied to an already
mounted VHD file, omit the -m flag.
Mounting images in Dom0 using the blktap2 driver
===============================================
Tap (and blkback) disks are also mountable in Dom0 without requiring an
active VM to attach.
The syntax is -
tapdisk2 -n <type>:<full path to file>
For example -
tapdisk2 -n aio:/home/images/rawFile.img
When successful the location of the new device will be provided by
tapdisk2 to stdout and tapdisk2 will terminate. From that point
forward control of the device is provided through sysfs in the
directory-
/sys/class/blktap2/blktap#/
Where # is a blktap2 device number present in the path that tapdisk2
printed before terminating. The sysfs interface is largely intuitive,
for example, to remove tap device 0 one would-
echo 1 > /sys/class/blktap2/blktap0/remove
Similarly, a pause control is available, which is can be used to plug
the request queue of a live running guest.
Previous versions of blktap mounted devices in dom0 by using blkfront
in dom0 and the xm block-attach command. This approach is still
available, though slightly more cumbersome.
Tapdisk Development
===============================================
People regularly ask how to develop their own tapdisk drivers, and
while it has not yet been well documented, the process is relatively
easy. Here I will provide a brief overview. The best reference, of
course, comes from the existing drivers. Specifically,
blktap2/drivers/block-ram.c and blktap2/drivers/block-aio.c provide
the clearest examples of simple drivers.
Setup:
First you need to register your new driver with blktap. This is done
in disktypes.h. There are five things that you must do. To
demonstrate, I will create a disk called "mynewdisk", you can name
yours freely.
1) Forward declare an instance of struct tap_disk.
e.g. -
extern struct tap_disk tapdisk_mynewdisk;
2) Claim one of the unused disk type numbers, take care to observe the
MAX_DISK_TYPES macro, increasing the number if necessary.
e.g. -
#define DISK_TYPE_MYNEWDISK 10
3) Create an instance of disk_info_t. The bulk of this file contains examples of these.
e.g. -
static disk_info_t mynewdisk_disk = {
DISK_TYPE_MYNEWDISK,
"My New Disk (mynewdisk)",
"mynewdisk",
0,
#ifdef TAPDISK
&tapdisk_mynewdisk,
#endif
};
A few words about what these mean. The first field must be the disk
type number you claimed in step (2). The second field is a string
describing your disk, and may contain any relevant info. The third
field is the name of your disk as will be used by the tapdisk2 utility
and xend (for example tapdisk2 -n mynewdisk:/path/to/disk.image, or in
your xm create config file). The forth is binary and determines
whether you will have one instance of your driver, or many. Here, a 1
means that your driver is a singleton and will coordinate access to
any number of tap devices. 0 is more common, meaning that you will
have one driver for each device that is created. The final field
should contain a reference to the struct tap_disk you created in step
(1).
4) Add a reference to your disk info structure (from step (3)) to the
dtypes array. Take care here - you need to place it in the position
corresponding to the device type number you claimed in step (2). So
we would place &mynewdisk_disk in dtypes[10]. Look at the other
devices in this array and pad with "&null_disk," as necessary.
5) Modify the xend python scripts. You need to add your disk name to
the list of disks that xend recognizes.
edit:
tools/python/xen/xend/server/BlktapController.py
And add your disk to the "blktap_disk_types" array near the top of
your file. Use the same name you specified in the third field of step
(3). The order of this list is not important.
Now your driver is ready to be written. Create a block-mynewdisk.c in
tools/blktap2/drivers and add it to the Makefile.
Development:
Copying block-aio.c and block-ram.c would be a good place to start.
Read those files as you go through this, I will be assisting by
commenting on a few useful functions and structures.
struct tap_disk:
Remember the forward declaration in step (1) of the setup phase above?
Now is the time to make that structure a reality. This structure
contains a list of function pointers for all the routines that will be
asked of your driver. Currently the required functions are open,
close, read, write, get_parent_id, validate_parent, and debug.
e.g. -
struct tap_disk tapdisk_mynewdisk = {
.disk_type = "tapdisk_mynewdisk",
.flags = 0,
.private_data_size = sizeof(struct tdmynewdisk_state),
.td_open = tdmynewdisk_open,
....
The private_data_size field is used to provide a structure to store
the state of your device. It is very likely that you will want
something here, but you are free to design whatever structure you
want. Blktap will allocate this space for you, you just need to tell
it how much space you want.
tdmynewdisk_open:
This is the open routine. The first argument is a structure
representing your driver. Two fields in this array are
interesting.
driver->data will contain a block of memory of the size your requested
in in the .private_data_size field of your struct tap_disk (above).
driver->info contains a structure that details information about your
disk. You need to fill this out. By convention this is done with a
_get_image_info() function. Assign a size (the total number of
sectors), sector_size (the size of each sector in bytes, and set
driver->info->info to 0.
The second parameter contains the name that was specified in the
creation of your device, either through xend, or on the command line
with tapdisk2. Usually this specifies a file that you will open in
this routine. The final parameter, flags, contains one of a number of
flags specified in tapdisk.h that may change the way you treat the
disk.
_queue_read/write:
These are your read and write operations. What you do here will
depend on your disk, but you should do exactly one of-
1) call td_complete_request with either error or success code.
2) Call td_forward_request, which will forward the request to the next
driver in the stack.
3) Queue the request for asynchronous processing with
td_prep_read/write. In doing so, you will also register a callback
for request completion. When the request completes you must do one of
options (1) or (2) above. Finally, call td_queue_tiocb to submit the
request to a wait queue.
The above functions are defined in tapdisk-interface.c. If you don't
use them as specified you will run into problems as your driver will
fail to inform blktap of the state of requests that have been
submitted. Blktap keeps track of all requests and does not like losing track.
_close, _get_parent_id, _validate_parent:
These last few tend to be very routine. _close is called when the
device is closed, and also when it is paused (in this case, open will
also be called later). The other functions are used in stacking
drivers. Most often drivers will return TD_NO_PARENT and -EINVAL,
respectively.
-80
View File
@@ -1,80 +0,0 @@
XEN_ROOT := $(CURDIR)/../../../
include $(XEN_ROOT)/tools/Rules.mk
MAJOR = 1.0
MINOR = 0
LIBNAME = libblktapctl
LIBSONAME = $(LIBNAME).so.$(MAJOR)
IBIN = tap-ctl
CFLAGS += -Werror
CFLAGS += -Wno-unused
CFLAGS += -I../include -I../drivers
CFLAGS += $(CFLAGS_xeninclude)
CFLAGS += $(CFLAGS_libxenctrl)
CFLAGS += -D_GNU_SOURCE
CFLAGS += -DTAPCTL
CTL_OBJS := tap-ctl-ipc.o
CTL_OBJS += tap-ctl-list.o
CTL_OBJS += tap-ctl-allocate.o
CTL_OBJS += tap-ctl-free.o
CTL_OBJS += tap-ctl-create.o
CTL_OBJS += tap-ctl-destroy.o
CTL_OBJS += tap-ctl-spawn.o
CTL_OBJS += tap-ctl-attach.o
CTL_OBJS += tap-ctl-detach.o
CTL_OBJS += tap-ctl-open.o
CTL_OBJS += tap-ctl-close.o
CTL_OBJS += tap-ctl-pause.o
CTL_OBJS += tap-ctl-unpause.o
CTL_OBJS += tap-ctl-major.o
CTL_OBJS += tap-ctl-check.o
CTL_PICS = $(patsubst %.o,%.opic,$(CTL_OBJS))
OBJS = $(CTL_OBJS) tap-ctl.o
PICS = $(CTL_PICS)
LIB_STATIC = $(LIBNAME).a
LIB_SHARED = $(LIBSONAME).$(MINOR)
IBIN = tap-ctl
all: build
build: $(IBIN) $(LIB_STATIC) $(LIB_SHARED)
$(LIBNAME).so: $(LIBSONAME)
ln -sf $< $@
$(LIBSONAME): $(LIB_SHARED)
ln -sf $< $@
tap-ctl: tap-ctl.o $(LIBNAME).so
$(CC) $(LDFLAGS) -o $@ $^ $(APPEND_LDFLAGS)
$(LIB_STATIC): $(CTL_OBJS)
$(AR) r $@ $^
$(LIB_SHARED): $(CTL_PICS)
$(CC) $(LDFLAGS) -fPIC -Wl,$(SONAME_LDFLAG) -Wl,$(LIBSONAME) $(SHLIB_LDFLAGS) -rdynamic $^ -o $@ $(APPEND_LDFLAGS)
install: $(IBIN) $(LIB_STATIC) $(LIB_SHARED)
$(INSTALL_DIR) -p $(DESTDIR)$(sbindir)
$(INSTALL_PROG) $(IBIN) $(DESTDIR)$(sbindir)
$(INSTALL_DATA) $(LIB_STATIC) $(DESTDIR)$(libdir)
$(INSTALL_PROG) $(LIB_SHARED) $(DESTDIR)$(libdir)
ln -sf $(LIBSONAME) $(DESTDIR)$(libdir)/$(LIBNAME).so
ln -sf $(LIB_SHARED) $(DESTDIR)$(libdir)/$(LIBSONAME)
clean:
rm -f $(OBJS) $(PICS) $(DEPS) $(IBIN) $(LIB_STATIC) $(LIB_SHARED)
rm -f $(LIBNAME).so $(LIBSONAME)
rm -f *~
distclean: clean
.PHONY: all build clean distclean install
-include $(DEPS)
-242
View File
@@ -1,242 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include <libgen.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <linux/major.h>
#include "tap-ctl.h"
#include "blktap2.h"
static int
tap_ctl_prepare_directory(const char *dir)
{
int err;
char *ptr, *name, *start;
err = access(dir, W_OK | R_OK);
if (!err)
return 0;
name = strdup(dir);
if (!name)
return ENOMEM;
start = name;
for (;;) {
ptr = strchr(start + 1, '/');
if (ptr)
*ptr = '\0';
err = mkdir(name, 0755);
if (err && errno != EEXIST) {
PERROR("mkdir %s", name);
err = errno;
break;
}
if (!ptr)
break;
else {
*ptr = '/';
start = ptr + 1;
}
}
free(name);
return err;
}
static int
tap_ctl_make_device(const char *devname, const int major,
const int minor, const int perm)
{
int err;
char *copy, *dir;
copy = strdup(devname);
if (!copy)
return ENOMEM;
dir = dirname(copy);
err = tap_ctl_prepare_directory(dir);
free(copy);
if (err)
return err;
if (!access(devname, F_OK))
if (unlink(devname)) {
PERROR("unlink %s", devname);
return errno;
}
err = mknod(devname, perm, makedev(major, minor));
if (err) {
PERROR("mknod %s", devname);
return errno;
}
return 0;
}
static int
tap_ctl_check_environment(void)
{
FILE *f;
int err, minor;
char name[256];
err = tap_ctl_prepare_directory(BLKTAP2_CONTROL_DIR);
if (err)
return err;
if (!access(BLKTAP2_CONTROL_DEVICE, R_OK | W_OK))
return 0;
memset(name, 0, sizeof(name));
f = fopen("/proc/misc", "r");
if (!f) {
EPRINTF("failed to open /proc/misc: %d\n", errno);
return errno;
}
while (fscanf(f, "%d %256s", &minor, name) == 2)
if (!strcmp(name, BLKTAP2_CONTROL_NAME)) {
err = tap_ctl_make_device(BLKTAP2_CONTROL_DEVICE,
MISC_MAJOR,
minor, S_IFCHR | 0600);
goto out;
}
err = ENOSYS;
EPRINTF("didn't find %s in /proc/misc\n", BLKTAP2_CONTROL_NAME);
out:
fclose(f);
return err;
}
static int
tap_ctl_allocate_device(int *minor, char **devname)
{
char *name;
int fd, err;
struct blktap2_handle handle;
*minor = -1;
if (!devname)
return EINVAL;
fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY);
if (fd == -1) {
EPRINTF("failed to open control device: %d\n", errno);
return errno;
}
err = ioctl(fd, BLKTAP2_IOCTL_ALLOC_TAP, &handle);
close(fd);
if (err == -1) {
EPRINTF("failed to allocate new device: %d\n", errno);
return errno;
}
err = asprintf(&name, "%s%d", BLKTAP2_RING_DEVICE, handle.minor);
if (err == -1) {
err = ENOMEM;
goto fail;
}
err = tap_ctl_make_device(name, handle.ring,
handle.minor, S_IFCHR | 0600);
free(name);
if (err) {
EPRINTF("creating ring device for %d failed: %d\n",
handle.minor, err);
goto fail;
}
if (*devname)
name = *devname;
else {
err = asprintf(&name, "%s%d",
BLKTAP2_IO_DEVICE, handle.minor);
if (err == -1) {
err = ENOMEM;
goto fail;
}
*devname = name;
}
err = tap_ctl_make_device(name, handle.device,
handle.minor, S_IFBLK | 0600);
if (err) {
EPRINTF("creating IO device for %d failed: %d\n",
handle.minor, err);
goto fail;
}
DBG("new interface: ring: %u, device: %u, minor: %u\n",
handle.ring, handle.device, handle.minor);
*minor = handle.minor;
return 0;
fail:
tap_ctl_free(handle.minor);
return err;
}
int
tap_ctl_allocate(int *minor, char **devname)
{
int err;
*minor = -1;
err = tap_ctl_check_environment();
if (err)
return err;
err = tap_ctl_allocate_device(minor, devname);
if (err)
return err;
return 0;
}
-61
View File
@@ -1,61 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include "tap-ctl.h"
int
tap_ctl_attach(const int id, const int minor)
{
int err;
tapdisk_message_t message;
memset(&message, 0, sizeof(message));
message.type = TAPDISK_MESSAGE_ATTACH;
message.cookie = minor;
err = tap_ctl_connect_send_and_receive(id, &message, 5);
if (err)
return err;
if (message.type == TAPDISK_MESSAGE_ATTACH_RSP) {
err = message.u.response.error;
if (err)
EPRINTF("attach failed: %d\n", err);
} else {
EPRINTF("got unexpected result '%s' from %d\n",
tapdisk_message_name(message.type), id);
err = EINVAL;
}
return err;
}
-79
View File
@@ -1,79 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include "tap-ctl.h"
#include "blktap2.h"
int
tap_ctl_check_blktap(const char **msg)
{
FILE *f;
int err = 0, minor;
char name[32];
memset(name, 0, sizeof(name));
f = fopen("/proc/misc", "r");
if (!f) {
*msg = "failed to open /proc/misc";
return -errno;
}
while (fscanf(f, "%d %32s", &minor, name) == 2) {
if (!strcmp(name, BLKTAP2_CONTROL_NAME))
goto out;
}
err = -ENOSYS;
*msg = "blktap kernel module not installed";
out:
fclose(f);
return err;
}
int
tap_ctl_check(const char **msg)
{
int err;
uid_t uid;
err = tap_ctl_check_blktap(msg);
if (err)
goto out;
err = 0;
*msg = "ok";
out:
return err;
}
-87
View File
@@ -1,87 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include "tap-ctl.h"
static int
__tap_ctl_close(const int id, const int minor, const int force)
{
int err;
tapdisk_message_t message;
memset(&message, 0, sizeof(message));
message.type = TAPDISK_MESSAGE_CLOSE;
if (force)
message.type = TAPDISK_MESSAGE_FORCE_SHUTDOWN;
message.cookie = minor;
err = tap_ctl_connect_send_and_receive(id, &message, 5);
if (err)
return err;
if (message.type == TAPDISK_MESSAGE_CLOSE_RSP) {
err = message.u.response.error;
if (err)
EPRINTF("close failed: %d\n", err);
} else {
EPRINTF("got unexpected result '%s' from %d\n",
tapdisk_message_name(message.type), id);
err = EINVAL;
}
return err;
}
int
tap_ctl_close(const int id, const int minor, const int force)
{
int i, err;
for (i = 0; i < 20; i++) {
err = __tap_ctl_close(id, minor, force);
if (!err)
return 0;
err = (err < 0 ? -err : err);
if (err != EAGAIN) {
EPRINTF("close failed: %d\n", err);
return err;
}
usleep(1000);
}
EPRINTF("close timed out\n");
return EIO;
}
-67
View File
@@ -1,67 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include "tap-ctl.h"
#include "blktap2.h"
int
tap_ctl_create(const char *params, char **devname)
{
int err, id, minor;
err = tap_ctl_allocate(&minor, devname);
if (err)
return err;
id = tap_ctl_spawn();
if (id < 0) {
err = id;
goto destroy;
}
err = tap_ctl_attach(id, minor);
if (err)
goto destroy;
err = tap_ctl_open(id, minor, params);
if (err)
goto detach;
return 0;
detach:
tap_ctl_detach(id, minor);
destroy:
tap_ctl_free(minor);
return err;
}
-56
View File
@@ -1,56 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include "tap-ctl.h"
#include "blktap2.h"
int
tap_ctl_destroy(const int id, const int minor)
{
int err;
err = tap_ctl_close(id, minor, 0);
if (err)
return err;
err = tap_ctl_detach(id, minor);
if (err)
return err;
err = tap_ctl_free(minor);
if (err)
return err;
return 0;
}
-61
View File
@@ -1,61 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include "tap-ctl.h"
int
tap_ctl_detach(const int id, const int minor)
{
int err;
tapdisk_message_t message;
memset(&message, 0, sizeof(message));
message.type = TAPDISK_MESSAGE_DETACH;
message.cookie = minor;
err = tap_ctl_connect_send_and_receive(id, &message, 5);
if (err)
return err;
if (message.type == TAPDISK_MESSAGE_DETACH_RSP) {
err = message.u.response.error;
if (err < 0)
printf("detach failed: %d\n", err);
} else {
printf("got unexpected result '%s' from %d\n",
tapdisk_message_name(message.type), id);
err = EINVAL;
}
return err;
}
-54
View File
@@ -1,54 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include "tap-ctl.h"
#include "blktap2.h"
int
tap_ctl_free(const int minor)
{
int fd, err;
fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY);
if (fd == -1) {
EPRINTF("failed to open control device: %d\n", errno);
return errno;
}
err = ioctl(fd, BLKTAP2_IOCTL_FREE_TAP, minor);
close(fd);
return err;
}
-249
View File
@@ -1,249 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "tap-ctl.h"
#include "blktap2.h"
int tap_ctl_debug = 0;
int
tap_ctl_read_message(int fd, tapdisk_message_t *message, int timeout)
{
fd_set readfds;
int ret, len, offset;
struct timeval tv, *t;
t = NULL;
offset = 0;
len = sizeof(tapdisk_message_t);
if (timeout) {
tv.tv_sec = timeout;
tv.tv_usec = 0;
t = &tv;
}
memset(message, 0, sizeof(tapdisk_message_t));
while (offset < len) {
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
ret = select(fd + 1, &readfds, NULL, NULL, t);
if (ret == -1) {
if (errno == EINTR)
continue;
break;
}
else if (FD_ISSET(fd, &readfds)) {
ret = read(fd, message + offset, len - offset);
if (ret <= 0) {
if (errno == EINTR)
continue;
break;
}
offset += ret;
} else
break;
}
if (offset != len) {
EPRINTF("failure reading message\n");
return -EIO;
}
DBG("received '%s' message (uuid = %u)\n",
tapdisk_message_name(message->type), message->cookie);
return 0;
}
int
tap_ctl_write_message(int fd, tapdisk_message_t *message, int timeout)
{
fd_set writefds;
int ret, len, offset;
struct timeval tv, *t;
t = NULL;
offset = 0;
len = sizeof(tapdisk_message_t);
if (timeout) {
tv.tv_sec = timeout;
tv.tv_usec = 0;
t = &tv;
}
DBG("sending '%s' message (uuid = %u)\n",
tapdisk_message_name(message->type), message->cookie);
while (offset < len) {
FD_ZERO(&writefds);
FD_SET(fd, &writefds);
/* we don't bother reinitializing tv. at worst, it will wait a
* bit more time than expected. */
ret = select(fd + 1, NULL, &writefds, NULL, t);
if (ret == -1) {
if (errno == EINTR)
continue;
break;
}
else if (FD_ISSET(fd, &writefds)) {
ret = write(fd, message + offset, len - offset);
if (ret <= 0) {
if (errno == EINTR)
continue;
break;
}
offset += ret;
} else
break;
}
if (offset != len) {
EPRINTF("failure writing message\n");
return -EIO;
}
return 0;
}
int
tap_ctl_send_and_receive(int sfd, tapdisk_message_t *message, int timeout)
{
int err;
err = tap_ctl_write_message(sfd, message, timeout);
if (err) {
EPRINTF("failed to send '%s' message\n",
tapdisk_message_name(message->type));
return err;
}
err = tap_ctl_read_message(sfd, message, timeout);
if (err) {
EPRINTF("failed to receive '%s' message\n",
tapdisk_message_name(message->type));
return err;
}
return 0;
}
char *
tap_ctl_socket_name(int id)
{
char *name;
if (asprintf(&name, "%s/%s%d",
BLKTAP2_CONTROL_DIR, BLKTAP2_CONTROL_SOCKET, id) == -1)
return NULL;
return name;
}
int
tap_ctl_connect(const char *name, int *sfd)
{
int fd, err;
struct sockaddr_un saddr;
*sfd = -1;
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == -1) {
EPRINTF("couldn't create socket for %s: %d\n", name, errno);
return -errno;
}
memset(&saddr, 0, sizeof(saddr));
saddr.sun_family = AF_UNIX;
strcpy(saddr.sun_path, name);
err = connect(fd, (const struct sockaddr *)&saddr, sizeof(saddr));
if (err) {
EPRINTF("couldn't connect to %s: %d\n", name, errno);
close(fd);
return -errno;
}
*sfd = fd;
return 0;
}
int
tap_ctl_connect_id(int id, int *sfd)
{
int err;
char *name;
*sfd = -1;
if (id < 0) {
EPRINTF("invalid id %d\n", id);
return -EINVAL;
}
name = tap_ctl_socket_name(id);
if (!name) {
EPRINTF("couldn't name socket for %d\n", id);
return -ENOMEM;
}
err = tap_ctl_connect(name, sfd);
free(name);
return err;
}
int
tap_ctl_connect_send_and_receive(int id, tapdisk_message_t *message, int timeout)
{
int err, sfd;
err = tap_ctl_connect_id(id, &sfd);
if (err)
return err;
err = tap_ctl_send_and_receive(sfd, message, timeout);
close(sfd);
return err;
}
-536
View File
@@ -1,536 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <glob.h>
#include "tap-ctl.h"
#include "blktap2.h"
#include "list.h"
static void
free_list(tap_list_t *entry)
{
if (entry->type) {
free(entry->type);
entry->type = NULL;
}
if (entry->path) {
free(entry->path);
entry->path = NULL;
}
free(entry);
}
int
_parse_params(const char *params, char **type, char **path)
{
char *ptr;
size_t len;
ptr = strchr(params, ':');
if (!ptr)
return -EINVAL;
len = ptr - params;
*type = strndup(params, len);
*path = strdup(params + len + 1);
if (!*type || !*path) {
free(*type);
*type = NULL;
free(*path);
*path = NULL;
return -errno;
}
return 0;
}
static int
init_list(tap_list_t *entry,
int tap_id, pid_t tap_pid, int vbd_minor, int vbd_state,
const char *params)
{
int err = 0;
entry->id = tap_id;
entry->pid = tap_pid;
entry->minor = vbd_minor;
entry->state = vbd_state;
if (params)
err = _parse_params(params, &entry->type, &entry->path);
return err;
}
void
tap_ctl_free_list(tap_list_t **list)
{
tap_list_t **_entry;
for (_entry = list; *_entry != NULL; ++_entry)
free_list(*_entry);
free(list);
}
static tap_list_t**
tap_ctl_alloc_list(int n)
{
tap_list_t **list, *entry;
size_t size;
int i;
size = sizeof(tap_list_t*) * (n+1);
list = malloc(size);
if (!list)
goto fail;
memset(list, 0, size);
for (i = 0; i < n; ++i) {
tap_list_t *entry;
entry = malloc(sizeof(tap_list_t));
if (!entry)
goto fail;
memset(entry, 0, sizeof(tap_list_t));
list[i] = entry;
}
return list;
fail:
if (list)
tap_ctl_free_list(list);
return NULL;
}
static int
tap_ctl_list_length(const tap_list_t **list)
{
const tap_list_t **_entry;
int n;
n = 0;
for (_entry = list; *_entry != NULL; ++_entry)
n++;
return n;
}
static int
_tap_minor_cmp(const void *a, const void *b)
{
return *(int*)a - *(int*)b;
}
int
_tap_ctl_find_minors(int **_minorv)
{
glob_t glbuf = { 0 };
const char *pattern, *format;
int *minorv = NULL, n_minors = 0;
int err, i;
pattern = BLKTAP2_SYSFS_DIR"/blktap*";
format = BLKTAP2_SYSFS_DIR"/blktap%d";
n_minors = 0;
minorv = NULL;
err = glob(pattern, 0, NULL, &glbuf);
switch (err) {
case GLOB_NOMATCH:
goto done;
case GLOB_ABORTED:
case GLOB_NOSPACE:
err = -errno;
EPRINTF("%s: glob failed, err %d", pattern, err);
goto fail;
}
minorv = malloc(sizeof(int) * glbuf.gl_pathc);
if (!minorv) {
err = -errno;
goto fail;
}
for (i = 0; i < glbuf.gl_pathc; ++i) {
int n;
n = sscanf(glbuf.gl_pathv[i], format, &minorv[n_minors]);
if (n != 1)
continue;
n_minors++;
}
qsort(minorv, n_minors, sizeof(int), _tap_minor_cmp);
done:
*_minorv = minorv;
err = 0;
out:
if (glbuf.gl_pathv)
globfree(&glbuf);
return err ? : n_minors;
fail:
if (minorv)
free(minorv);
goto out;
}
struct tapdisk {
int id;
pid_t pid;
struct list_head list;
};
static int
_tap_tapdisk_cmp(const void *a, const void *b)
{
return ((struct tapdisk*)a)->id - ((struct tapdisk*)b)->id;
}
int
_tap_ctl_find_tapdisks(struct tapdisk **_tapv)
{
glob_t glbuf = { 0 };
const char *pattern, *format;
struct tapdisk *tapv = NULL;
int err, i, n_taps = 0;
pattern = BLKTAP2_CONTROL_DIR"/"BLKTAP2_CONTROL_SOCKET"*";
format = BLKTAP2_CONTROL_DIR"/"BLKTAP2_CONTROL_SOCKET"%d";
n_taps = 0;
tapv = NULL;
err = glob(pattern, 0, NULL, &glbuf);
switch (err) {
case GLOB_NOMATCH:
goto done;
case GLOB_ABORTED:
case GLOB_NOSPACE:
err = -errno;
EPRINTF("%s: glob failed, err %d", pattern, err);
goto fail;
}
tapv = malloc(sizeof(struct tapdisk) * glbuf.gl_pathc);
if (!tapv) {
err = -errno;
goto fail;
}
for (i = 0; i < glbuf.gl_pathc; ++i) {
struct tapdisk *tap;
int n;
tap = &tapv[n_taps];
err = sscanf(glbuf.gl_pathv[i], format, &tap->id);
if (err != 1)
continue;
tap->pid = tap_ctl_get_pid(tap->id);
if (tap->pid < 0)
continue;
n_taps++;
}
qsort(tapv, n_taps, sizeof(struct tapdisk), _tap_tapdisk_cmp);
for (i = 0; i < n_taps; ++i)
INIT_LIST_HEAD(&tapv[i].list);
done:
*_tapv = tapv;
err = 0;
out:
if (glbuf.gl_pathv)
globfree(&glbuf);
return err ? : n_taps;
fail:
if (tapv)
free(tapv);
goto out;
}
struct tapdisk_list {
int minor;
int state;
char *params;
struct list_head entry;
};
int
_tap_ctl_list_tapdisk(int id, struct list_head *_list)
{
tapdisk_message_t message;
struct list_head list;
struct tapdisk_list *tl, *next;
int err, sfd;
err = tap_ctl_connect_id(id, &sfd);
if (err)
return err;
memset(&message, 0, sizeof(message));
message.type = TAPDISK_MESSAGE_LIST;
message.cookie = -1;
err = tap_ctl_write_message(sfd, &message, 2);
if (err)
return err;
INIT_LIST_HEAD(&list);
do {
err = tap_ctl_read_message(sfd, &message, 2);
if (err) {
err = -EPROTO;
break;
}
if (message.u.list.count == 0)
break;
tl = malloc(sizeof(struct tapdisk_list));
if (!tl) {
err = -ENOMEM;
break;
}
tl->minor = message.u.list.minor;
tl->state = message.u.list.state;
if (message.u.list.path[0] != 0) {
tl->params = strndup(message.u.list.path,
sizeof(message.u.list.path));
if (!tl->params) {
err = -errno;
break;
}
} else
tl->params = NULL;
list_add(&tl->entry, &list);
} while (1);
if (err)
list_for_each_entry_safe(tl, next, &list, entry) {
list_del(&tl->entry);
free(tl->params);
free(tl);
}
close(sfd);
list_splice(&list, _list);
return err;
}
void
_tap_ctl_free_tapdisks(struct tapdisk *tapv, int n_taps)
{
struct tapdisk *tap;
for (tap = tapv; tap < &tapv[n_taps]; ++tap) {
struct tapdisk_list *tl, *next;
list_for_each_entry_safe(tl, next, &tap->list, entry) {
free(tl->params);
free(tl);
}
}
free(tapv);
}
int
_tap_list_join3(int n_minors, int *minorv, int n_taps, struct tapdisk *tapv,
tap_list_t ***_list)
{
tap_list_t **list, **_entry;
int i, _m, err;
list = tap_ctl_alloc_list(n_minors + n_taps);
if (!list) {
err = -ENOMEM;
goto fail;
}
_entry = list;
for (i = 0; i < n_taps; ++i) {
struct tapdisk *tap = &tapv[i];
struct tapdisk_list *tl;
/* orphaned tapdisk */
if (list_empty(&tap->list)) {
err = init_list(*_entry++, tap->id, tap->pid, -1, -1, NULL);
if (err)
goto fail;
continue;
}
list_for_each_entry(tl, &tap->list, entry) {
err = init_list(*_entry++,
tap->id, tap->pid,
tl->minor, tl->state, tl->params);
if (err)
goto fail;
if (tl->minor >= 0) {
/* clear minor */
for (_m = 0; _m < n_minors; ++_m) {
if (minorv[_m] == tl->minor) {
minorv[_m] = -1;
break;
}
}
}
}
}
/* orphaned minors */
for (_m = 0; _m < n_minors; ++_m) {
int minor = minorv[_m];
if (minor >= 0) {
err = init_list(*_entry++, -1, -1, minor, -1, NULL);
if (err)
goto fail;
}
}
/* free extraneous list entries */
for (; *_entry != NULL; ++_entry) {
free_list(*_entry);
*_entry = NULL;
}
*_list = list;
return 0;
fail:
if (list)
tap_ctl_free_list(list);
return err;
}
int
tap_ctl_list(tap_list_t ***list)
{
int n_taps, n_minors, err, *minorv;
struct tapdisk *tapv, *tap;
n_taps = -1;
n_minors = -1;
err = n_minors = _tap_ctl_find_minors(&minorv);
if (err < 0)
goto out;
err = n_taps = _tap_ctl_find_tapdisks(&tapv);
if (err < 0)
goto out;
for (tap = tapv; tap < &tapv[n_taps]; ++tap) {
err = _tap_ctl_list_tapdisk(tap->id, &tap->list);
if (err)
goto out;
}
err = _tap_list_join3(n_minors, minorv, n_taps, tapv, list);
out:
if (n_taps > 0)
_tap_ctl_free_tapdisks(tapv, n_taps);
if (n_minors > 0)
free(minorv);
return err;
}
int
tap_ctl_find(const char *type, const char *path, tap_list_t *tap)
{
tap_list_t **list, **_entry;
int ret = -ENOENT, err;
err = tap_ctl_list(&list);
if (err)
return err;
for (_entry = list; *_entry != NULL; ++_entry) {
tap_list_t *entry = *_entry;
if (type && (!entry->type || strcmp(entry->type, type)))
continue;
if (path && (!entry->path || strcmp(entry->path, path)))
continue;
*tap = *entry;
tap->type = tap->path = NULL;
ret = 0;
break;
}
tap_ctl_free_list(list);
return ret;
}
-69
View File
@@ -1,69 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include "tap-ctl.h"
int
tap_ctl_blk_major(void)
{
FILE *devices;
int rv, major;
devices = fopen("/proc/devices", "r");
if (!devices) {
rv = -errno;
goto out;
}
do {
char buf[32], *s;
int n, offset;
s = fgets(buf, sizeof(buf), devices);
if (!s)
break;
major = -ENODEV;
offset = 0;
n = sscanf(buf, "%d tapdev%n", &major, &offset);
if (n == 1 && offset)
break;
} while (1);
rv = major;
out:
if (devices)
fclose(devices);
return rv;
}
-75
View File
@@ -1,75 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include "tap-ctl.h"
#include "blktaplib.h"
int
tap_ctl_open(const int id, const int minor, const char *params)
{
int err;
tapdisk_message_t message;
memset(&message, 0, sizeof(message));
message.type = TAPDISK_MESSAGE_OPEN;
message.cookie = minor;
message.u.params.storage = TAPDISK_STORAGE_TYPE_DEFAULT;
message.u.params.devnum = minor;
err = snprintf(message.u.params.path,
sizeof(message.u.params.path) - 1, "%s", params);
if (err >= sizeof(message.u.params.path)) {
EPRINTF("name too long\n");
return ENAMETOOLONG;
}
err = tap_ctl_connect_send_and_receive(id, &message, 5);
if (err)
return err;
switch (message.type) {
case TAPDISK_MESSAGE_OPEN_RSP:
break;
case TAPDISK_MESSAGE_ERROR:
err = -message.u.response.error;
EPRINTF("open failed, err %d\n", err);
break;
default:
EPRINTF("got unexpected result '%s' from %d\n",
tapdisk_message_name(message.type), id);
err = EINVAL;
}
return err;
}
-59
View File
@@ -1,59 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "tap-ctl.h"
int
tap_ctl_pause(const int id, const int minor)
{
int err;
tapdisk_message_t message;
memset(&message, 0, sizeof(message));
message.type = TAPDISK_MESSAGE_PAUSE;
message.cookie = minor;
err = tap_ctl_connect_send_and_receive(id, &message, 5);
if (err)
return err;
if (message.type == TAPDISK_MESSAGE_PAUSE_RSP)
err = message.u.response.error;
else {
err = EINVAL;
EPRINTF("got unexpected result '%s' from %d\n",
tapdisk_message_name(message.type), id);
}
return err;
}
-174
View File
@@ -1,174 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include "tap-ctl.h"
#include "blktap2.h"
static pid_t
__tap_ctl_spawn(int *readfd)
{
int err, child, channel[2];
char *tapdisk;
if (pipe(channel)) {
EPRINTF("pipe failed: %d\n", errno);
return -errno;
}
if ((child = fork()) == -1) {
EPRINTF("fork failed: %d\n", errno);
return -errno;
}
if (child) {
close(channel[1]);
*readfd = channel[0];
return child;
}
if (dup2(channel[1], STDOUT_FILENO) == -1) {
EPRINTF("dup2 failed: %d\n", errno);
exit(errno);
}
if (dup2(channel[1], STDERR_FILENO) == -1) {
EPRINTF("dup2 failed: %d\n", errno);
exit(errno);
}
close(channel[0]);
close(channel[1]);
tapdisk = getenv("TAPDISK2");
if (!tapdisk)
tapdisk = "tapdisk2";
execlp(tapdisk, tapdisk, NULL);
EPRINTF("exec failed\n");
exit(1);
}
pid_t
tap_ctl_get_pid(const int id)
{
int err;
tapdisk_message_t message;
memset(&message, 0, sizeof(message));
message.type = TAPDISK_MESSAGE_PID;
err = tap_ctl_connect_send_and_receive(id, &message, 2);
if (err)
return err;
return message.u.tapdisk_pid;
}
static int
tap_ctl_wait(pid_t child)
{
pid_t pid;
int status;
pid = waitpid(child, &status, 0);
if (pid < 0) {
EPRINTF("wait(%d) failed, err %d\n", child, errno);
return -errno;
}
if (WIFEXITED(status)) {
int code = WEXITSTATUS(status);
if (code)
EPRINTF("tapdisk2[%d] failed, status %d\n", child, code);
return -code;
}
if (WIFSIGNALED(status)) {
int signo = WTERMSIG(status);
EPRINTF("tapdisk2[%d] killed by signal %d\n", child, signo);
return -EINTR;
}
EPRINTF("tapdisk2[%d]: unexpected status %#x\n", child, status);
return -EAGAIN;
}
static int
tap_ctl_get_child_id(int readfd)
{
int id;
FILE *f;
f = fdopen(readfd, "r");
if (!f) {
EPRINTF("fdopen failed: %d\n", errno);
return -1;
}
errno = 0;
if (fscanf(f, BLKTAP2_CONTROL_DIR"/"
BLKTAP2_CONTROL_SOCKET"%d", &id) != 1) {
errno = (errno ? : EINVAL);
EPRINTF("parsing id failed: %d\n", errno);
id = -1;
}
fclose(f);
return id;
}
int
tap_ctl_spawn(void)
{
pid_t child;
int err, id, readfd;
readfd = -1;
child = __tap_ctl_spawn(&readfd);
if (child < 0)
return child;
err = tap_ctl_wait(child);
if (err)
return err;
id = tap_ctl_get_child_id(readfd);
if (id < 0)
EPRINTF("get_id failed, child %d err %d\n", child, errno);
return id;
}
-64
View File
@@ -1,64 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include "tap-ctl.h"
int
tap_ctl_unpause(const int id, const int minor, const char *params)
{
int err;
tapdisk_message_t message;
memset(&message, 0, sizeof(message));
message.type = TAPDISK_MESSAGE_RESUME;
message.cookie = minor;
if (params)
strncpy(message.u.params.path, params,
sizeof(message.u.params.path) - 1);
err = tap_ctl_connect_send_and_receive(id, &message, 15);
if (err)
return err;
if (message.type == TAPDISK_MESSAGE_RESUME_RSP)
err = message.u.response.error;
else {
err = EINVAL;
EPRINTF("got unexpected result '%s' from %d\n",
tapdisk_message_name(message.type), id);
}
return err;
}
-815
View File
@@ -1,815 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include "tap-ctl.h"
typedef int (*tap_ctl_func_t) (int, char **);
struct command {
char *name;
tap_ctl_func_t func;
};
static void
tap_cli_list_usage(FILE *stream)
{
fprintf(stream,
"usage: list [-h] [-p pid] [-m minor] [-t type] [-f file]\n");
}
static void
tap_ctl_list_row(tap_list_t *entry)
{
char minor_str[10] = "-";
char state_str[10] = "-";
char pid_str[10] = "-";
if (entry->pid != -1)
sprintf(pid_str, "%d", entry->pid);
if (entry->minor != -1)
sprintf(minor_str, "%d", entry->minor);
if (entry->state != -1)
sprintf(state_str, "%x", entry->state);
printf("%8s %2s %4s %10s %s\n",
pid_str, minor_str, state_str,
entry->type ? : "-", entry->path ? : "-");
}
static void
tap_ctl_list_dict(tap_list_t *entry)
{
int d = 0;
if (entry->pid != -1) {
if (d) putc(' ', stdout);
d = printf("pid=%d", entry->pid);
}
if (entry->minor != -1) {
if (d) putc(' ', stdout);
d = printf("minor=%d", entry->minor);
}
if (entry->state != -1) {
if (d) putc(' ', stdout);
d = printf("state=%d", entry->state);
}
if (entry->type && entry->path) {
if (d) putc(' ', stdout);
d = printf("args=%s:%s", entry->type, entry->path);
}
putc('\n', stdout);
}
int
tap_cli_list(int argc, char **argv)
{
tap_list_t **list, **_entry;
int c, minor, tty, err;
const char *type, *file;
pid_t pid;
err = tap_ctl_list(&list);
if (err)
return -err;
pid = -1;
minor = -1;
type = NULL;
file = NULL;
while ((c = getopt(argc, argv, "m:p:t:f:h")) != -1) {
switch (c) {
case 'm':
minor = atoi(optarg);
break;
case 'p':
pid = atoi(optarg);
break;
case 't':
type = optarg;
break;
case 'f':
file = optarg;
break;
case '?':
goto usage;
case 'h':
tap_cli_list_usage(stdout);
return 0;
}
}
tty = isatty(STDOUT_FILENO);
for (_entry = list; *_entry != NULL; ++_entry) {
tap_list_t *entry = *_entry;
if (minor >= 0 && entry->minor != minor)
continue;
if (pid >= 0 && entry->pid != pid)
continue;
if (type && (!entry->type || strcmp(entry->type, type)))
continue;
if (file && (!entry->path || strcmp(entry->path, file)))
continue;
if (tty)
tap_ctl_list_row(entry);
else
tap_ctl_list_dict(entry);
}
tap_ctl_free_list(list);
return 0;
usage:
tap_cli_list_usage(stderr);
return EINVAL;
}
static void
tap_cli_allocate_usage(FILE *stream)
{
fprintf(stream, "usage: allocate [-d device name]>\n");
}
static int
tap_cli_allocate(int argc, char **argv)
{
char *devname;
int c, minor, err;
devname = NULL;
optind = 0;
while ((c = getopt(argc, argv, "d:h")) != -1) {
switch (c) {
case 'd':
devname = optarg;
break;
case '?':
goto usage;
case 'h':
tap_cli_allocate_usage(stdout);
return 0;
}
}
err = tap_ctl_allocate(&minor, &devname);
if (!err)
printf("%s\n", devname);
return err;
usage:
tap_cli_allocate_usage(stderr);
return EINVAL;
}
static void
tap_cli_free_usage(FILE *stream)
{
fprintf(stream, "usage: free <-m minor>\n");
}
static int
tap_cli_free(int argc, char **argv)
{
int c, minor;
minor = -1;
optind = 0;
while ((c = getopt(argc, argv, "m:h")) != -1) {
switch (c) {
case 'm':
minor = atoi(optarg);
break;
case '?':
goto usage;
case 'h':
tap_cli_free_usage(stdout);
return 0;
}
}
if (minor == -1)
goto usage;
return tap_ctl_free(minor);
usage:
tap_cli_free_usage(stderr);
return EINVAL;
}
static void
tap_cli_create_usage(FILE *stream)
{
fprintf(stream, "usage: create <-a args> [-d device name]\n");
}
static int
tap_cli_create(int argc, char **argv)
{
int c, err;
char *args, *devname;
args = NULL;
devname = NULL;
optind = 0;
while ((c = getopt(argc, argv, "a:d:h")) != -1) {
switch (c) {
case 'a':
args = optarg;
break;
case 'd':
devname = optarg;
break;
case '?':
goto usage;
case 'h':
tap_cli_create_usage(stdout);
return 0;
}
}
if (!args)
goto usage;
err = tap_ctl_create(args, &devname);
if (!err)
printf("%s\n", devname);
return err;
usage:
tap_cli_create_usage(stderr);
return EINVAL;
}
static void
tap_cli_destroy_usage(FILE *stream)
{
fprintf(stream, "usage: destroy <-p pid> <-m minor>\n");
}
static int
tap_cli_destroy(int argc, char **argv)
{
int c, pid, minor;
pid = -1;
minor = -1;
optind = 0;
while ((c = getopt(argc, argv, "p:m:h")) != -1) {
switch (c) {
case 'p':
pid = atoi(optarg);
break;
case 'm':
minor = atoi(optarg);
break;
case '?':
goto usage;
case 'h':
tap_cli_destroy_usage(stdout);
return 0;
}
}
if (pid == -1 || minor == -1)
goto usage;
return tap_ctl_destroy(pid, minor);
usage:
tap_cli_destroy_usage(stderr);
return EINVAL;
}
static void
tap_cli_spawn_usage(FILE *stream)
{
fprintf(stream, "usage: spawn\n");
}
static int
tap_cli_spawn(int argc, char **argv)
{
int c;
pid_t task;
optind = 0;
while ((c = getopt(argc, argv, "h")) != -1) {
switch (c) {
case '?':
goto usage;
case 'h':
tap_cli_spawn_usage(stdout);
return 0;
}
}
task = tap_ctl_spawn();
if (task < 0) {
printf("spawn failed: %d\n", errno);
return task;
}
printf("tapdisk spawned with pid %d\n", task);
return 0;
usage:
tap_cli_spawn_usage(stderr);
return EINVAL;
}
static void
tap_cli_attach_usage(FILE *stream)
{
fprintf(stream, "usage: attach <-p pid> <-m minor>\n");
}
static int
tap_cli_attach(int argc, char **argv)
{
int c, pid, minor;
pid = -1;
minor = -1;
optind = 0;
while ((c = getopt(argc, argv, "p:m:h")) != -1) {
switch (c) {
case 'p':
pid = atoi(optarg);
break;
case 'm':
minor = atoi(optarg);
break;
case '?':
goto usage;
case 'h':
tap_cli_attach_usage(stderr);
return 0;
}
}
if (pid == -1 || minor == -1)
goto usage;
return tap_ctl_attach(pid, minor);
usage:
tap_cli_attach_usage(stderr);
return EINVAL;
}
static void
tap_cli_detach_usage(FILE *stream)
{
fprintf(stream, "usage: detach <-p pid> <-m minor>\n");
}
static int
tap_cli_detach(int argc, char **argv)
{
int c, pid, minor;
pid = -1;
minor = -1;
optind = 0;
while ((c = getopt(argc, argv, "p:m:h")) != -1) {
switch (c) {
case 'p':
pid = atoi(optarg);
break;
case 'm':
minor = atoi(optarg);
break;
case '?':
goto usage;
case 'h':
tap_cli_detach_usage(stdout);
return 0;
}
}
if (pid == -1 || minor == -1)
goto usage;
return tap_ctl_detach(pid, minor);
usage:
tap_cli_detach_usage(stderr);
return EINVAL;
}
static void
tap_cli_close_usage(FILE *stream)
{
fprintf(stream, "usage: close <-p pid> <-m minor> [-f force]\n");
}
static int
tap_cli_close(int argc, char **argv)
{
int c, pid, minor, force;
pid = -1;
minor = -1;
force = 0;
optind = 0;
while ((c = getopt(argc, argv, "p:m:fh")) != -1) {
switch (c) {
case 'p':
pid = atoi(optarg);
break;
case 'm':
minor = atoi(optarg);
break;
case 'f':
force = -1;
break;
case '?':
goto usage;
case 'h':
tap_cli_close_usage(stdout);
return 0;
}
}
if (pid == -1 || minor == -1)
goto usage;
return tap_ctl_close(pid, minor, force);
usage:
tap_cli_close_usage(stderr);
return EINVAL;
}
static void
tap_cli_pause_usage(FILE *stream)
{
fprintf(stream, "usage: pause <-p pid> <-m minor>\n");
}
static int
tap_cli_pause(int argc, char **argv)
{
int c, pid, minor;
pid = -1;
minor = -1;
optind = 0;
while ((c = getopt(argc, argv, "p:m:h")) != -1) {
switch (c) {
case 'p':
pid = atoi(optarg);
break;
case 'm':
minor = atoi(optarg);
break;
case '?':
goto usage;
case 'h':
tap_cli_pause_usage(stdout);
return 0;
}
}
if (pid == -1 || minor == -1)
goto usage;
return tap_ctl_pause(pid, minor);
usage:
tap_cli_pause_usage(stderr);
return EINVAL;
}
static void
tap_cli_unpause_usage(FILE *stream)
{
fprintf(stream, "usage: unpause <-p pid> <-m minor> [-a args]\n");
}
int
tap_cli_unpause(int argc, char **argv)
{
const char *args;
int c, pid, minor;
pid = -1;
minor = -1;
args = NULL;
optind = 0;
while ((c = getopt(argc, argv, "p:m:a:h")) != -1) {
switch (c) {
case 'p':
pid = atoi(optarg);
break;
case 'm':
minor = atoi(optarg);
break;
case 'a':
args = optarg;
break;
case '?':
goto usage;
case 'h':
tap_cli_unpause_usage(stdout);
return 0;
}
}
if (pid == -1 || minor == -1)
goto usage;
return tap_ctl_unpause(pid, minor, args);
usage:
tap_cli_unpause_usage(stderr);
return EINVAL;
}
static void
tap_cli_major_usage(FILE *stream)
{
fprintf(stream, "usage: major [-h]\n");
}
static int
tap_cli_major(int argc, char **argv)
{
int c, chr, major;
chr = 0;
while ((c = getopt(argc, argv, "bch")) != -1) {
switch (c) {
case 'b':
chr = 0;
break;
case 'c':
chr = 1;
break;
case '?':
goto usage;
case 'h':
tap_cli_major_usage(stdout);
return 0;
default:
goto usage;
}
}
if (chr)
major = -EINVAL;
else
major = tap_ctl_blk_major();
if (major < 0)
return -major;
printf("%d\n", major);
return 0;
usage:
tap_cli_major_usage(stderr);
return EINVAL;
}
static void
tap_cli_open_usage(FILE *stream)
{
fprintf(stream, "usage: open <-p pid> <-m minor> <-a args>\n");
}
static int
tap_cli_open(int argc, char **argv)
{
const char *args;
int c, pid, minor;
pid = -1;
minor = -1;
args = NULL;
optind = 0;
while ((c = getopt(argc, argv, "a:m:p:h")) != -1) {
switch (c) {
case 'p':
pid = atoi(optarg);
break;
case 'm':
minor = atoi(optarg);
break;
case 'a':
args = optarg;
break;
case '?':
goto usage;
case 'h':
tap_cli_open_usage(stdout);
return 0;
}
}
if (pid == -1 || minor == -1 || !args)
goto usage;
return tap_ctl_open(pid, minor, args);
usage:
tap_cli_open_usage(stderr);
return EINVAL;
}
static void
tap_cli_check_usage(FILE *stream)
{
fprintf(stream, "usage: check\n"
"(checks whether environment is suitable for tapdisk2)\n");
}
static int
tap_cli_check(int argc, char **argv)
{
int err;
const char *msg;
if (argc != 1)
goto usage;
err = tap_ctl_check(&msg);
printf("%s\n", msg);
return err;
usage:
tap_cli_check_usage(stderr);
return EINVAL;
}
struct command commands[] = {
{ .name = "list", .func = tap_cli_list },
{ .name = "allocate", .func = tap_cli_allocate },
{ .name = "free", .func = tap_cli_free },
{ .name = "create", .func = tap_cli_create },
{ .name = "destroy", .func = tap_cli_destroy },
{ .name = "spawn", .func = tap_cli_spawn },
{ .name = "attach", .func = tap_cli_attach },
{ .name = "detach", .func = tap_cli_detach },
{ .name = "open", .func = tap_cli_open },
{ .name = "close", .func = tap_cli_close },
{ .name = "pause", .func = tap_cli_pause },
{ .name = "unpause", .func = tap_cli_unpause },
{ .name = "major", .func = tap_cli_major },
{ .name = "check", .func = tap_cli_check },
};
#define print_commands() \
do { \
int i, n; \
n = sizeof(commands) / sizeof(struct command); \
printf("COMMAND := { "); \
printf("%s", commands[0].name); \
for (i = 1; i < n; i++) \
printf(" | %s", commands[i].name); \
printf(" }\n"); \
} while (0)
void
help(void)
{
printf("usage: tap-ctl COMMAND [OPTIONS]\n");
print_commands();
exit(0);
}
struct command *
get_command(char *command)
{
int i, n;
if (strnlen(command, 25) >= 25)
return NULL;
n = sizeof(commands) / sizeof (struct command);
for (i = 0; i < n; i++)
if (!strcmp(command, commands[i].name))
return &commands[i];
return NULL;
}
int
main(int argc, char *argv[])
{
char **cargv;
const char *msg;
struct command *cmd;
int cargc, i, cnt, ret;
#ifdef CORE_DUMP
#include <sys/resource.h>
struct rlimit rlim;
rlim.rlim_cur = RLIM_INFINITY;
rlim.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
PERROR("setrlimit failed");
#endif
ret = 0;
if (argc < 2)
help();
cargc = argc - 1;
cmd = get_command(argv[1]);
if (!cmd) {
EPRINTF("invalid COMMAND %s", argv[1]);
help();
}
ret = tap_ctl_check(&msg);
if (ret) {
printf("%s\n", msg);
return ret;
}
cargv = malloc(sizeof(char *) * cargc);
if (!cargv)
exit(ENOMEM);
cnt = 1;
cargv[0] = cmd->name;
for (i = 1; i < cargc; i++) {
char *arg = argv[i + (argc - cargc)];
if (!strcmp(arg, "--debug")) {
tap_ctl_debug = 1;
continue;
}
cargv[cnt++] = arg;
}
ret = cmd->func(cnt, cargv);
free(cargv);
return (ret >= 0 ? ret : -ret);
}
-101
View File
@@ -1,101 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __TAP_CTL_H__
#define __TAP_CTL_H__
#include <syslog.h>
#include <errno.h>
#include <tapdisk-message.h>
extern int tap_ctl_debug;
#ifdef TAPCTL
#define DBG(_f, _a...) \
do { \
if (tap_ctl_debug) \
printf(_f, ##_a); \
} while (0)
#define DPRINTF(_f, _a...) syslog(LOG_INFO, _f, ##_a)
#define EPRINTF(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f, __func__, ##_a)
#define PERROR(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f ": %s", __func__, ##_a, \
strerror(errno))
#endif
void tap_ctl_version(int *major, int *minor);
int tap_ctl_kernel_version(int *major, int *minor);
int tap_ctl_check_blktap(const char **message);
int tap_ctl_check_version(const char **message);
int tap_ctl_check(const char **message);
int tap_ctl_connect(const char *path, int *socket);
int tap_ctl_connect_id(int id, int *socket);
int tap_ctl_read_message(int fd, tapdisk_message_t *message, int timeout);
int tap_ctl_write_message(int fd, tapdisk_message_t *message, int timeout);
int tap_ctl_send_and_receive(int fd, tapdisk_message_t *message, int timeout);
int tap_ctl_connect_send_and_receive(int id,
tapdisk_message_t *message, int timeout);
char *tap_ctl_socket_name(int id);
typedef struct {
int id;
pid_t pid;
int minor;
int state;
char *type;
char *path;
} tap_list_t;
int tap_ctl_get_driver_id(const char *handle);
int tap_ctl_list(tap_list_t ***list);
void tap_ctl_free_list(tap_list_t **list);
int tap_ctl_find(const char *type, const char *path, tap_list_t *tap);
int tap_ctl_allocate(int *minor, char **devname);
int tap_ctl_free(const int minor);
int tap_ctl_create(const char *params, char **devname);
int tap_ctl_destroy(const int id, const int minor);
int tap_ctl_spawn(void);
pid_t tap_ctl_get_pid(const int id);
int tap_ctl_attach(const int id, const int minor);
int tap_ctl_detach(const int id, const int minor);
int tap_ctl_open(const int id, const int minor, const char *params);
int tap_ctl_close(const int id, const int minor, const int force);
int tap_ctl_pause(const int id, const int minor);
int tap_ctl_unpause(const int id, const int minor, const char *params);
int tap_ctl_blk_major(void);
#endif
-113
View File
@@ -1,113 +0,0 @@
XEN_ROOT=$(CURDIR)/../../..
BLKTAP_ROOT= ..
include $(XEN_ROOT)/tools/Rules.mk
LIBVHDDIR = $(BLKTAP_ROOT)/vhd/lib
IBIN = tapdisk2 td-util tapdisk-client tapdisk-stream tapdisk-diff
QCOW_UTIL = img2qcow qcow-create qcow2raw
LOCK_UTIL = lock-util
INST_DIR = $(sbindir)
CFLAGS += -Werror
CFLAGS += -Wno-unused
CFLAGS += -fno-strict-aliasing
CFLAGS += -I$(BLKTAP_ROOT)/include -I$(BLKTAP_ROOT)/drivers
CFLAGS += $(CFLAGS_libxenctrl)
CFLAGS += -D_GNU_SOURCE
CFLAGS += -DUSE_NFS_LOCKS
# drivers/block-log.c incorrectly uses libxc internals
CFLAGS += -I$(XEN_ROOT)/tools/libxc
ifeq ($(CONFIG_X86_64),y)
CFLAGS += -fPIC
endif
VHDLIBS := -L$(LIBVHDDIR) -lvhd
REMUS-OBJS := block-remus.o
REMUS-OBJS += hashtable.o
REMUS-OBJS += hashtable_itr.o
REMUS-OBJS += hashtable_utility.o
tapdisk2 tapdisk-stream tapdisk-diff $(QCOW_UTIL): AIOLIBS := -laio
MEMSHRLIBS :=
ifeq ($(CONFIG_Linux), __fixme__)
MEMSHR_DIR = $(XEN_ROOT)/tools/memshr
CFLAGS += -DMEMSHR
CFLAGS += -I $(MEMSHR_DIR)
MEMSHRLIBS += -L$(XEN_ROOT)/tools/libxc -lxenctrl $(MEMSHR_DIR)/libmemshr.a
endif
ifeq ($(VHD_STATIC),y)
td-util: CFLAGS += -static
endif
PORTABLE-OBJS-y :=
PORTABLE-OBJS-$(CONFIG_Linux) += blk_linux.o
PORTABLE-OBJS-$(CONFIG_NetBSD) += blk_netbsd.o
TAP-OBJS-y := scheduler.o
TAP-OBJS-y += tapdisk-vbd.o
TAP-OBJS-y += tapdisk-control.o
TAP-OBJS-y += tapdisk-image.o
TAP-OBJS-y += tapdisk-driver.o
TAP-OBJS-y += tapdisk-disktype.o
TAP-OBJS-y += tapdisk-interface.o
TAP-OBJS-y += tapdisk-server.o
TAP-OBJS-y += tapdisk-queue.o
TAP-OBJS-y += tapdisk-filter.o
TAP-OBJS-y += tapdisk-log.o
TAP-OBJS-y += tapdisk-utils.o
TAP-OBJS-y += io-optimize.o
TAP-OBJS-y += lock.o
TAP-OBJS-y += $(PORTABLE-OBJS-y)
MISC-OBJS-y := atomicio.o
BLK-OBJS-y := block-aio.o
BLK-OBJS-y += block-ram.o
BLK-OBJS-y += block-cache.o
BLK-OBJS-y += block-vhd.o
BLK-OBJS-y += block-log.o
BLK-OBJS-y += block-qcow.o
BLK-OBJS-y += aes.o
BLK-OBJS-y += md5.o
BLK-OBJS-y += $(PORTABLE-OBJS-y)
BLK-OBJS-y += $(REMUS-OBJS)
all: $(IBIN) lock-util qcow-util
tapdisk2: $(TAP-OBJS-y) $(BLK-OBJS-y) $(MISC-OBJS-y) tapdisk2.o
$(CC) -o $@ $^ $(LDFLAGS) -lrt -lz $(VHDLIBS) $(AIOLIBS) $(MEMSHRLIBS) -lm $(APPEND_LDFLAGS)
tapdisk-client: tapdisk-client.o
$(CC) -o $@ $^ $(LDFLAGS) -lrt $(APPEND_LDFLAGS)
tapdisk-stream tapdisk-diff: %: %.o $(TAP-OBJS-y) $(BLK-OBJS-y)
$(CC) -o $@ $^ $(LDFLAGS) -lrt -lz $(VHDLIBS) $(AIOLIBS) $(MEMSHRLIBS) -lm $(APPEND_LDFLAGS)
td-util: td.o tapdisk-utils.o tapdisk-log.o $(PORTABLE-OBJS-y)
$(CC) -o $@ $^ $(LDFLAGS) $(VHDLIBS) $(APPEND_LDFLAGS)
lock-util: lock.c
$(CC) $(CFLAGS) -DUTIL -o lock-util lock.c $(LDFLAGS) $(APPEND_LDFLAGS)
.PHONY: qcow-util
qcow-util: img2qcow qcow2raw qcow-create
img2qcow qcow2raw qcow-create: %: %.o $(TAP-OBJS-y) $(BLK-OBJS-y)
$(CC) -o $@ $^ $(LDFLAGS) -lrt -lz $(VHDLIBS) $(AIOLIBS) $(MEMSHRLIBS) -lm $(APPEND_LDFLAGS)
install: all
$(INSTALL_DIR) -p $(DESTDIR)$(INST_DIR)
$(INSTALL_PROG) $(IBIN) $(LOCK_UTIL) $(QCOW_UTIL) $(DESTDIR)$(INST_DIR)
clean:
rm -rf .*.d *.o *~ xen TAGS $(IBIN) $(LIB) $(LOCK_UTIL) $(QCOW_UTIL)
distclean: clean
.PHONY: clean install distclean
File diff suppressed because it is too large. Load diff
-28
View File
@@ -1,28 +0,0 @@
#ifndef QEMU_AES_H
#define QEMU_AES_H
#include <stdint.h>
#define AES_MAXNR 14
#define AES_BLOCK_SIZE 16
struct aes_key_st {
uint32_t rd_key[4 *(AES_MAXNR + 1)];
int rounds;
};
typedef struct aes_key_st AES_KEY;
int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
AES_KEY *key);
int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
AES_KEY *key);
void AES_encrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key);
void AES_decrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key);
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
const unsigned long length, const AES_KEY *key,
unsigned char *ivec, const int enc);
#endif
-61
View File
@@ -1,61 +0,0 @@
/*
* Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <errno.h>
#include "atomicio.h"
/*
* ensure all of data on socket comes through. f==read || f==vwrite
*/
size_t
atomicio(f, fd, _s, n)
ssize_t (*f) (int, void *, size_t);
int fd;
void *_s;
size_t n;
{
char *s = _s;
size_t pos = 0;
ssize_t res;
while (n > pos) {
res = (f) (fd, s + pos, n - pos);
switch (res) {
case -1:
if (errno == EINTR || errno == EAGAIN)
continue;
return 0;
case 0:
errno = EPIPE;
return pos;
default:
pos += (size_t)res;
}
}
return (pos);
}
-36
View File
@@ -1,36 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <inttypes.h>
int blk_getimagesize(int fd, uint64_t *size);
int blk_getsectorsize(int fd, uint64_t *sector_size);
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif
-43
View File
@@ -1,43 +0,0 @@
#include <inttypes.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include "tapdisk.h"
#include "blk.h"
int blk_getimagesize(int fd, uint64_t *size)
{
int rc;
*size = 0;
rc = ioctl(fd, BLKGETSIZE, size);
if (rc) {
DPRINTF("ERR: BLKGETSIZE failed, couldn't stat image");
return -EINVAL;
}
return 0;
}
int blk_getsectorsize(int fd, uint64_t *sector_size)
{
#if defined(BLKSSZGET)
int rc;
*sector_size = DEFAULT_SECTOR_SIZE;
rc = ioctl(fd, BLKSSZGET, sector_size);
if (rc) {
DPRINTF("ERR: BLKSSZGET failed. Falling back to use default sector size");
*sector_size = DEFAULT_SECTOR_SIZE;
}
if (*sector_size != DEFAULT_SECTOR_SIZE)
DPRINTF("Note: sector size is %"PRIu64" (not %u)\n",
*sector_size, DEFAULT_SECTOR_SIZE);
#else
*sector_size = DEFAULT_SECTOR_SIZE;
#endif
return 0;
}
-41
View File
@@ -1,41 +0,0 @@
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/disklabel.h>
#include <errno.h>
#include <inttypes.h>
#include "tapdisk.h"
#include "blk.h"
int blk_getimagesize(int fd, uint64_t *size)
{
int rc;
struct disklabel dl;
*size = 0;
rc = ioctl(fd, DIOCGDINFO, &dl);
if (rc) {
DPRINTF("ERR: DIOCGDINFO failed, couldn't stat image");
return -EINVAL;
}
*size = dl.d_secsize * dl.d_secpercyl;
return 0;
}
int blk_getsectorsize(int fd, uint64_t *sector_size)
{
int rc;
struct disklabel dl;
*sector_size = DEV_BSIZE;
rc = ioctl(fd, DIOCGDINFO, &dl);
if (rc) {
DPRINTF("ERR: DIOCGDINFO failed, couldn't stat image");
return 0; /* fallback to DEV_BSIZE */
}
*sector_size = dl.d_secsize;
return 0;
}
-258
View File
@@ -1,258 +0,0 @@
/*
* Copyright (c) 2007, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/statvfs.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include "blk.h"
#include "tapdisk.h"
#include "tapdisk-driver.h"
#include "tapdisk-interface.h"
#define MAX_AIO_REQS TAPDISK_DATA_REQUESTS
struct tdaio_state;
struct aio_request {
td_request_t treq;
struct tiocb tiocb;
struct tdaio_state *state;
};
struct tdaio_state {
int fd;
td_driver_t *driver;
int aio_free_count;
struct aio_request aio_requests[MAX_AIO_REQS];
struct aio_request *aio_free_list[MAX_AIO_REQS];
};
/*Get Image size, secsize*/
static int tdaio_get_image_info(int fd, td_disk_info_t *info)
{
int ret;
long size;
unsigned long total_size;
struct statvfs statBuf;
struct stat stat;
ret = fstat(fd, &stat);
if (ret != 0) {
DPRINTF("ERROR: fstat failed, Couldn't stat image");
return -EINVAL;
}
if (S_ISBLK(stat.st_mode)) {
/*Accessing block device directly*/
info->size = 0;
if (blk_getimagesize(fd, &info->size) != 0)
return -EINVAL;
DPRINTF("Image size: \n\tpre sector_shift [%llu]\n\tpost "
"sector_shift [%llu]\n",
(long long unsigned)(info->size << SECTOR_SHIFT),
(long long unsigned)info->size);
/*Get the sector size*/
if (blk_getsectorsize(fd, &info->sector_size) != 0)
info->sector_size = DEFAULT_SECTOR_SIZE;
} else {
/*Local file? try fstat instead*/
info->size = (stat.st_size >> SECTOR_SHIFT);
info->sector_size = DEFAULT_SECTOR_SIZE;
DPRINTF("Image size: \n\tpre sector_shift [%llu]\n\tpost "
"sector_shift [%llu]\n",
(long long unsigned)(info->size << SECTOR_SHIFT),
(long long unsigned)info->size);
}
if (info->size == 0) {
info->size =((uint64_t) 16836057);
info->sector_size = DEFAULT_SECTOR_SIZE;
}
info->info = 0;
return 0;
}
/* Open the disk file and initialize aio state. */
int tdaio_open(td_driver_t *driver, const char *name, td_flag_t flags)
{
int i, fd, ret, o_flags;
struct tdaio_state *prv;
ret = 0;
prv = (struct tdaio_state *)driver->data;
DPRINTF("block-aio open('%s')", name);
memset(prv, 0, sizeof(struct tdaio_state));
prv->aio_free_count = MAX_AIO_REQS;
for (i = 0; i < MAX_AIO_REQS; i++)
prv->aio_free_list[i] = &prv->aio_requests[i];
/* Open the file */
o_flags = O_DIRECT | O_LARGEFILE |
((flags & TD_OPEN_RDONLY) ? O_RDONLY : O_RDWR);
fd = open(name, o_flags);
if ( (fd == -1) && (errno == EINVAL) ) {
/* Maybe O_DIRECT isn't supported. */
o_flags &= ~O_DIRECT;
fd = open(name, o_flags);
if (fd != -1) DPRINTF("WARNING: Accessing image without"
"O_DIRECT! (%s)\n", name);
} else if (fd != -1) DPRINTF("open(%s) with O_DIRECT\n", name);
if (fd == -1) {
DPRINTF("Unable to open [%s] (%d)!\n", name, 0 - errno);
ret = 0 - errno;
goto done;
}
ret = tdaio_get_image_info(fd, &driver->info);
if (ret) {
close(fd);
goto done;
}
prv->fd = fd;
done:
return ret;
}
void tdaio_complete(void *arg, struct tiocb *tiocb, int err)
{
struct aio_request *aio = (struct aio_request *)arg;
struct tdaio_state *prv = aio->state;
td_complete_request(aio->treq, err);
prv->aio_free_list[prv->aio_free_count++] = aio;
}
void tdaio_queue_read(td_driver_t *driver, td_request_t treq)
{
int size;
uint64_t offset;
struct aio_request *aio;
struct tdaio_state *prv;
prv = (struct tdaio_state *)driver->data;
size = treq.secs * driver->info.sector_size;
offset = treq.sec * (uint64_t)driver->info.sector_size;
if (prv->aio_free_count == 0)
goto fail;
aio = prv->aio_free_list[--prv->aio_free_count];
aio->treq = treq;
aio->state = prv;
td_prep_read(&aio->tiocb, prv->fd, treq.buf,
size, offset, tdaio_complete, aio);
td_queue_tiocb(driver, &aio->tiocb);
return;
fail:
td_complete_request(treq, -EBUSY);
}
void tdaio_queue_write(td_driver_t *driver, td_request_t treq)
{
int size;
uint64_t offset;
struct aio_request *aio;
struct tdaio_state *prv;
prv = (struct tdaio_state *)driver->data;
size = treq.secs * driver->info.sector_size;
offset = treq.sec * (uint64_t)driver->info.sector_size;
if (prv->aio_free_count == 0)
goto fail;
aio = prv->aio_free_list[--prv->aio_free_count];
aio->treq = treq;
aio->state = prv;
td_prep_write(&aio->tiocb, prv->fd, treq.buf,
size, offset, tdaio_complete, aio);
td_queue_tiocb(driver, &aio->tiocb);
return;
fail:
td_complete_request(treq, -EBUSY);
}
int tdaio_close(td_driver_t *driver)
{
struct tdaio_state *prv = (struct tdaio_state *)driver->data;
close(prv->fd);
return 0;
}
int tdaio_get_parent_id(td_driver_t *driver, td_disk_id_t *id)
{
return TD_NO_PARENT;
}
int tdaio_validate_parent(td_driver_t *driver,
td_driver_t *pdriver, td_flag_t flags)
{
return -EINVAL;
}
struct tap_disk tapdisk_aio = {
.disk_type = "tapdisk_aio",
.flags = 0,
.private_data_size = sizeof(struct tdaio_state),
.td_open = tdaio_open,
.td_close = tdaio_close,
.td_queue_read = tdaio_queue_read,
.td_queue_write = tdaio_queue_write,
.td_get_parent_id = tdaio_get_parent_id,
.td_validate_parent = tdaio_validate_parent,
.td_debug = NULL,
};
-787
View File
@@ -1,787 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
#include "tapdisk.h"
#include "tapdisk-utils.h"
#include "tapdisk-driver.h"
#include "tapdisk-server.h"
#include "tapdisk-interface.h"
#ifdef DEBUG
#define DBG(_f, _a...) tlog_write(TLOG_DBG, _f, ##_a)
#else
#define DBG(_f, _a...) ((void)0)
#endif
#define WARN(_f, _a...) tlog_write(TLOG_WARN, _f, ##_a)
#define RADIX_TREE_PAGE_SHIFT 12 /* 4K pages */
#define RADIX_TREE_PAGE_SIZE (1 << RADIX_TREE_PAGE_SHIFT)
#define RADIX_TREE_NODE_SHIFT 9 /* 512B nodes */
#define RADIX_TREE_NODE_SIZE (1 << RADIX_TREE_NODE_SHIFT)
#define RADIX_TREE_NODE_MASK (RADIX_TREE_NODE_SIZE - 1)
#define BLOCK_CACHE_NODES_PER_PAGE (1 << (RADIX_TREE_PAGE_SHIFT - RADIX_TREE_NODE_SHIFT))
#define BLOCK_CACHE_MAX_SIZE (10 << 20) /* 100MB cache */
#define BLOCK_CACHE_REQUESTS (TAPDISK_DATA_REQUESTS << 3)
#define BLOCK_CACHE_PAGE_IDLETIME 60
typedef struct radix_tree radix_tree_t;
typedef struct radix_tree_node radix_tree_node_t;
typedef struct radix_tree_link radix_tree_link_t;
typedef struct radix_tree_leaf radix_tree_leaf_t;
typedef struct radix_tree_page radix_tree_page_t;
typedef struct block_cache block_cache_t;
typedef struct block_cache_request block_cache_request_t;
typedef struct block_cache_stats block_cache_stats_t;
struct radix_tree_page {
char *buf;
size_t size;
uint64_t sec;
radix_tree_link_t *owners[BLOCK_CACHE_NODES_PER_PAGE];
};
struct radix_tree_leaf {
radix_tree_page_t *page;
char *buf;
};
struct radix_tree_link {
uint32_t time;
union {
radix_tree_node_t *next;
radix_tree_leaf_t leaf;
} u;
};
struct radix_tree_node {
int height;
radix_tree_link_t links[RADIX_TREE_NODE_SIZE];
};
struct radix_tree {
int height;
uint64_t size;
uint32_t nodes;
radix_tree_node_t *root;
block_cache_t *cache;
};
struct block_cache_request {
int err;
char *buf;
uint64_t secs;
td_request_t treq;
block_cache_t *cache;
};
struct block_cache_stats {
uint64_t reads;
uint64_t hits;
uint64_t misses;
uint64_t prunes;
};
struct block_cache {
int ptype;
char *name;
uint64_t sectors;
block_cache_request_t requests[BLOCK_CACHE_REQUESTS];
block_cache_request_t *request_free_list[BLOCK_CACHE_REQUESTS];
int requests_free;
event_id_t timeout_id;
radix_tree_t tree;
block_cache_stats_t stats;
};
static inline uint64_t
radix_tree_calculate_size(int height)
{
return (uint64_t)RADIX_TREE_NODE_SIZE <<
(height * RADIX_TREE_NODE_SHIFT);
}
static inline int
radix_tree_calculate_height(uint64_t sectors)
{
int height;
uint64_t tree_size;
height = 1; /* always allocate root node */
tree_size = radix_tree_calculate_size(height);
while (sectors > tree_size)
tree_size = radix_tree_calculate_size(++height);
return height;
}
static inline int
radix_tree_index(radix_tree_node_t *node, uint64_t sector)
{
return ((sector >> (node->height * RADIX_TREE_NODE_SHIFT)) &
RADIX_TREE_NODE_MASK);
}
static inline int
radix_tree_node_contains_leaves(radix_tree_t *tree, radix_tree_node_t *node)
{
return (node->height == 0);
}
static inline int
radix_tree_node_is_root(radix_tree_t *tree, radix_tree_node_t *node)
{
return (node->height == tree->height);
}
static inline uint64_t
radix_tree_size(radix_tree_t *tree)
{
return tree->size + tree->nodes * sizeof(radix_tree_node_t);
}
static inline void
radix_tree_clear_link(radix_tree_link_t *link)
{
if (link)
memset(link, 0, sizeof(radix_tree_link_t));
}
static inline radix_tree_node_t *
radix_tree_allocate_node(radix_tree_t *tree, int height)
{
radix_tree_node_t *node;
node = calloc(1, sizeof(radix_tree_node_t));
if (!node)
return NULL;
node->height = height;
tree->nodes++;
return node;
}
static inline radix_tree_node_t *
radix_tree_allocate_child_node(radix_tree_t *tree, radix_tree_node_t *parent)
{
return radix_tree_allocate_node(tree, parent->height - 1);
}
void
radix_tree_free_node(radix_tree_t *tree, radix_tree_node_t *node)
{
if (!node)
return;
free(node);
tree->nodes--;
}
static inline radix_tree_page_t *
radix_tree_allocate_page(radix_tree_t *tree,
char *buf, uint64_t sec, size_t size)
{
radix_tree_page_t *page;
page = calloc(1, sizeof(radix_tree_page_t));
if (!page)
return NULL;
page->buf = buf;
page->sec = sec;
page->size = size;
tree->size += size;
return page;
}
static inline void
radix_tree_free_page(radix_tree_t *tree, radix_tree_page_t *page)
{
int i;
for (i = 0; i < page->size >> RADIX_TREE_NODE_SHIFT; i++)
DBG("%s: ejecting sector 0x%llx\n",
tree->cache->name, page->sec + i);
tree->cache->stats.prunes += (page->size >> RADIX_TREE_NODE_SHIFT);
tree->size -= page->size;
free(page->buf);
free(page);
}
/*
* remove a leaf and the shared radix_tree_page_t containing its buffer.
* leaves are deleted, nodes are not; gc will reap the nodes later.
*/
static void
radix_tree_remove_page(radix_tree_t *tree, radix_tree_page_t *page)
{
int i;
if (!page)
return;
for (i = 0; i < BLOCK_CACHE_NODES_PER_PAGE; i++)
radix_tree_clear_link(page->owners[i]);
radix_tree_free_page(tree, page);
}
static void
radix_tree_insert_leaf(radix_tree_t *tree, radix_tree_link_t *link,
radix_tree_page_t *page, off_t off)
{
int i;
if (off + RADIX_TREE_NODE_SIZE > page->size)
return;
for (i = 0; i < BLOCK_CACHE_NODES_PER_PAGE; i++) {
if (page->owners[i])
continue;
page->owners[i] = link;
link->u.leaf.page = page;
link->u.leaf.buf = page->buf + off;
break;
}
}
static char *
radix_tree_find_leaf(radix_tree_t *tree, uint64_t sector)
{
int idx;
struct timeval now;
radix_tree_link_t *link;
radix_tree_node_t *node;
node = tree->root;
gettimeofday(&now, NULL);
do {
idx = radix_tree_index(node, sector);
link = node->links + idx;
link->time = now.tv_sec;
if (radix_tree_node_contains_leaves(tree, node))
return link->u.leaf.buf;
if (!link->u.next)
return NULL;
node = link->u.next;
} while (1);
}
static char *
radix_tree_add_leaf(radix_tree_t *tree, uint64_t sector,
radix_tree_page_t *page, off_t off)
{
int idx;
struct timeval now;
radix_tree_link_t *link;
radix_tree_node_t *node;
node = tree->root;
gettimeofday(&now, NULL);
do {
idx = radix_tree_index(node, sector);
link = node->links + idx;
link->time = now.tv_sec;
if (radix_tree_node_contains_leaves(tree, node)) {
radix_tree_remove_page(tree, link->u.leaf.page);
radix_tree_insert_leaf(tree, link, page, off);
return link->u.leaf.buf;
}
if (!link->u.next) {
link->u.next = radix_tree_allocate_child_node(tree,
node);
if (!link->u.next)
return NULL;
}
node = link->u.next;
} while (1);
}
static int
radix_tree_add_leaves(radix_tree_t *tree, char *buf,
uint64_t sector, uint64_t sectors)
{
int i;
radix_tree_page_t *page;
page = radix_tree_allocate_page(tree, buf, sector,
sectors << RADIX_TREE_NODE_SHIFT);
if (!page)
return -ENOMEM;
for (i = 0; i < sectors; i++)
if (!radix_tree_add_leaf(tree, sector + i,
page, (i << RADIX_TREE_NODE_SHIFT)))
goto fail;
return 0;
fail:
page->buf = NULL;
radix_tree_remove_page(tree, page);
return -ENOMEM;
}
static void
radix_tree_delete_branch(radix_tree_t *tree, radix_tree_node_t *node)
{
int i;
radix_tree_link_t *link;
if (!node)
return;
for (i = 0; i < RADIX_TREE_NODE_SIZE; i++) {
link = node->links + i;
if (radix_tree_node_contains_leaves(tree, node))
radix_tree_remove_page(tree, link->u.leaf.page);
else
radix_tree_delete_branch(tree, link->u.next);
radix_tree_clear_link(link);
}
radix_tree_free_node(tree, node);
}
static inline void
radix_tree_destroy(radix_tree_t *tree)
{
radix_tree_delete_branch(tree, tree->root);
tree->root = NULL;
}
/*
* returns 1 if @node is empty after pruning, 0 otherwise
*/
static int
radix_tree_prune_branch(radix_tree_t *tree,
radix_tree_node_t *node, uint32_t now)
{
int i, empty;
radix_tree_link_t *link;
empty = 1;
if (!node)
return empty;
for (i = 0; i < RADIX_TREE_NODE_SIZE; i++) {
link = node->links + i;
if (now - link->time < BLOCK_CACHE_PAGE_IDLETIME) {
if (radix_tree_node_contains_leaves(tree, node)) {
empty = 0;
continue;
}
if (radix_tree_prune_branch(tree, link->u.next, now))
radix_tree_clear_link(link);
else
empty = 0;
continue;
}
if (radix_tree_node_contains_leaves(tree, node))
radix_tree_remove_page(tree, link->u.leaf.page);
else
radix_tree_delete_branch(tree, link->u.next);
radix_tree_clear_link(link);
}
if (empty && !radix_tree_node_is_root(tree, node))
radix_tree_free_node(tree, node);
return empty;
}
/*
* walk tree and free any node that has been idle for too long
*/
static void
radix_tree_prune(radix_tree_t *tree)
{
struct timeval now;
if (!tree->root)
return;
DPRINTF("tree %s has %"PRIu64" bytes\n",
tree->cache->name, tree->size);
gettimeofday(&now, NULL);
radix_tree_prune_branch(tree, tree->root, now.tv_sec);
DPRINTF("tree %s now has %"PRIu64" bytes\n",
tree->cache->name, tree->size);
}
static inline int
radix_tree_initialize(radix_tree_t *tree, uint64_t sectors)
{
tree->height = radix_tree_calculate_height(sectors);
tree->root = radix_tree_allocate_node(tree, tree->height);
if (!tree->root)
return -ENOMEM;
return 0;
}
static inline void
radix_tree_free(radix_tree_t *tree)
{
radix_tree_destroy(tree);
}
static void
block_cache_prune_event(event_id_t id, char mode, void *private)
{
radix_tree_t *tree;
block_cache_t *cache;
cache = (block_cache_t *)private;
tree = &cache->tree;
radix_tree_prune(tree);
}
static inline block_cache_request_t *
block_cache_get_request(block_cache_t *cache)
{
if (!cache->requests_free)
return NULL;
return cache->request_free_list[--cache->requests_free];
}
static inline void
block_cache_put_request(block_cache_t *cache, block_cache_request_t *breq)
{
memset(breq, 0, sizeof(block_cache_request_t));
cache->request_free_list[cache->requests_free++] = breq;
}
static int
block_cache_open(td_driver_t *driver, const char *name, td_flag_t flags)
{
int i, err;
radix_tree_t *tree;
block_cache_t *cache;
if (!td_flag_test(flags, TD_OPEN_RDONLY))
return -EINVAL;
if (driver->info.sector_size != RADIX_TREE_NODE_SIZE)
return -EINVAL;
cache = (block_cache_t *)driver->data;
err = tapdisk_namedup(&cache->name, (char *)name);
if (err)
return -ENOMEM;
cache->sectors = driver->info.size;
tree = &cache->tree;
err = radix_tree_initialize(tree, cache->sectors);
if (err)
goto fail;
tree->cache = cache;
cache->requests_free = BLOCK_CACHE_REQUESTS;
for (i = 0; i < BLOCK_CACHE_REQUESTS; i++)
cache->request_free_list[i] = cache->requests + i;
cache->timeout_id = tapdisk_server_register_event(SCHEDULER_POLL_TIMEOUT,
-1, /* dummy fd */
BLOCK_CACHE_PAGE_IDLETIME << 1,
block_cache_prune_event,
cache);
if (cache->timeout_id < 0)
goto fail;
DPRINTF("opening cache for %s, sectors: %"PRIu64", "
"tree: %p, height: %d\n",
cache->name, cache->sectors, tree, tree->height);
if (mlockall(MCL_CURRENT | MCL_FUTURE))
DPRINTF("mlockall failed: %d\n", -errno);
return 0;
fail:
free(cache->name);
radix_tree_free(&cache->tree);
return err;
}
static int
block_cache_close(td_driver_t *driver)
{
radix_tree_t *tree;
block_cache_t *cache;
cache = (block_cache_t *)driver->data;
tree = &cache->tree;
DPRINTF("closing cache for %s\n", cache->name);
tapdisk_server_unregister_event(cache->timeout_id);
radix_tree_free(tree);
free(cache->name);
return 0;
}
static inline uint64_t
block_cache_hash(block_cache_t *cache, char *buf)
{
int i, n;
uint64_t cksm, *data;
return 0;
cksm = 0;
data = (uint64_t *)buf;
n = RADIX_TREE_NODE_SIZE / sizeof(uint64_t);
for (i = 0; i < n; i++)
cksm += data[i];
return ~cksm;
}
static void
block_cache_hit(block_cache_t *cache, td_request_t treq, char *iov[])
{
int i;
off_t off;
cache->stats.hits += treq.secs;
for (i = 0; i < treq.secs; i++) {
DBG("%s: block cache hit: sec 0x%08llx, hash: 0x%08llx\n",
cache->name, treq.sec + i, block_cache_hash(cache, iov[i]));
off = i << RADIX_TREE_NODE_SHIFT;
memcpy(treq.buf + off, iov[i], RADIX_TREE_NODE_SIZE);
}
td_complete_request(treq, 0);
}
static void
block_cache_populate_cache(td_request_t clone, int err)
{
int i;
radix_tree_t *tree;
block_cache_t *cache;
block_cache_request_t *breq;
breq = (block_cache_request_t *)clone.cb_data;
cache = breq->cache;
tree = &cache->tree;
breq->secs -= clone.secs;
breq->err = (breq->err ? breq->err : err);
if (breq->secs)
return;
if (breq->err) {
free(breq->buf);
goto out;
}
for (i = 0; i < breq->treq.secs; i++) {
off_t off = i << RADIX_TREE_NODE_SHIFT;
DBG("%s: populating sec 0x%08llx\n",
cache->name, breq->treq.sec + i);
memcpy(breq->treq.buf + off,
breq->buf + off, RADIX_TREE_NODE_SIZE);
}
if (radix_tree_add_leaves(tree, breq->buf,
breq->treq.sec, breq->treq.secs))
free(breq->buf);
out:
td_complete_request(breq->treq, breq->err);
block_cache_put_request(cache, breq);
}
static void
block_cache_miss(block_cache_t *cache, td_request_t treq)
{
char *buf;
size_t size;
td_request_t clone;
radix_tree_t *tree;
block_cache_request_t *breq;
DBG("%s: block cache miss: sec 0x%08llx\n", cache->name, treq.sec);
clone = treq;
tree = &cache->tree;
size = treq.secs << RADIX_TREE_NODE_SHIFT;
cache->stats.misses += treq.secs;
if (radix_tree_size(tree) + size >= BLOCK_CACHE_MAX_SIZE)
goto out;
breq = block_cache_get_request(cache);
if (!breq)
goto out;
if (posix_memalign((void **)&buf, RADIX_TREE_NODE_SIZE, size)) {
block_cache_put_request(cache, breq);
goto out;
}
breq->treq = treq;
breq->secs = treq.secs;
breq->err = 0;
breq->buf = buf;
breq->cache = cache;
clone.buf = buf;
clone.cb = block_cache_populate_cache;
clone.cb_data = breq;
out:
td_forward_request(clone);
}
static void
block_cache_queue_read(td_driver_t *driver, td_request_t treq)
{
int i;
radix_tree_t *tree;
block_cache_t *cache;
char *iov[BLOCK_CACHE_NODES_PER_PAGE];
cache = (block_cache_t *)driver->data;
tree = &cache->tree;
cache->stats.reads += treq.secs;
if (treq.secs > BLOCK_CACHE_NODES_PER_PAGE)
return td_forward_request(treq);
for (i = 0; i < treq.secs; i++) {
iov[i] = radix_tree_find_leaf(tree, treq.sec + i);
if (!iov[i])
return block_cache_miss(cache, treq);
}
return block_cache_hit(cache, treq, iov);
}
static void
block_cache_queue_write(td_driver_t *driver, td_request_t treq)
{
td_complete_request(treq, -EPERM);
}
static int
block_cache_get_parent_id(td_driver_t *driver, td_disk_id_t *id)
{
return -EINVAL;
}
static int
block_cache_validate_parent(td_driver_t *driver,
td_driver_t *pdriver, td_flag_t flags)
{
block_cache_t *cache;
if (!td_flag_test(pdriver->state, TD_DRIVER_RDONLY))
return -EINVAL;
cache = (block_cache_t *)driver->data;
if (strcmp(driver->name, pdriver->name))
return -EINVAL;
return 0;
}
static void
block_cache_debug(td_driver_t *driver)
{
block_cache_t *cache;
block_cache_stats_t *stats;
cache = (block_cache_t *)driver->data;
stats = &cache->stats;
WARN("BLOCK CACHE %s\n", cache->name);
WARN("reads: %"PRIu64", hits: %"PRIu64", misses: %"PRIu64", prunes: %"PRIu64"\n",
stats->reads, stats->hits, stats->misses, stats->prunes);
}
struct tap_disk tapdisk_block_cache = {
.disk_type = "tapdisk_block_cache",
.flags = 0,
.private_data_size = sizeof(block_cache_t),
.td_open = block_cache_open,
.td_close = block_cache_close,
.td_queue_read = block_cache_queue_read,
.td_queue_write = block_cache_queue_write,
.td_get_parent_id = block_cache_get_parent_id,
.td_validate_parent = block_cache_validate_parent,
.td_debug = block_cache_debug,
};
-665
View File
@@ -1,665 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Driver to sit on top of another disk and log writes, in order
* to synchronize two distinct disks
*
* On receipt of a control request it can export a list of dirty
* sectors in the following format:
* struct writerange {
* u64 sector;
* u32 count;
* }
* terminated by { 0, 0 }
*/
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "xc_bitops.h"
#include "log.h"
#include "tapdisk.h"
#include "tapdisk-server.h"
#include "tapdisk-driver.h"
#include "tapdisk-interface.h"
#define MAX_CONNECTIONS 1
typedef struct poll_fd {
int fd;
event_id_t id;
} poll_fd_t;
struct tdlog_state {
uint64_t size;
void* writelog;
char* ctlpath;
poll_fd_t ctl;
int connected;
poll_fd_t connections[MAX_CONNECTIONS];
char* shmpath;
void* shm;
log_sring_t* sring;
log_back_ring_t bring;
};
#define BDPRINTF(_f, _a...) syslog (LOG_DEBUG, "log: " _f "\n", ## _a)
#define BWPRINTF(_f, _a...) syslog (LOG_WARNING, "log: " _f "\n", ## _a)
static void ctl_accept(event_id_t, char, void *);
static void ctl_request(event_id_t, char, void *);
/* -- write log -- */
/* large flat bitmaps don't scale particularly well either in size or scan
* time, but they'll do for now */
static int writelog_create(struct tdlog_state *s)
{
uint64_t bmsize;
bmsize = bitmap_size(s->size);
BDPRINTF("allocating %"PRIu64" bytes for dirty bitmap", bmsize);
s->writelog = bitmap_alloc(s->size);
if (!s->writelog) {
BWPRINTF("could not allocate dirty bitmap of size %"PRIu64, bmsize);
return -1;
}
return 0;
}
static int writelog_free(struct tdlog_state *s)
{
if (s->writelog)
free(s->writelog);
return 0;
}
static int writelog_set(struct tdlog_state* s, uint64_t sector, int count)
{
int i;
for (i = 0; i < count; i++)
set_bit(sector + i, s->writelog);
return 0;
}
/* if end is 0, clear to end of disk */
int writelog_clear(struct tdlog_state* s, uint64_t start, uint64_t end)
{
if (!end)
end = s->size;
/* clear to word boundaries */
while (BITMAP_SHIFT(start))
clear_bit(start++, s->writelog);
while (BITMAP_SHIFT(end))
clear_bit(end--, s->writelog);
memset(s->writelog + start / BITS_PER_LONG, 0, (end - start) >> 3);
return 0;
}
/* returns last block exported (may not be end of disk if shm region
* overflows) */
static uint64_t writelog_export(struct tdlog_state* s)
{
struct disk_range* range = s->shm;
uint64_t i = 0;
BDPRINTF("sector count: %"PRIu64, s->size);
for (i = 0; i < s->size; i++) {
if (test_bit(i, s->writelog)) {
/* range start */
range->sector = i;
range->count = 1;
/* find end */
for (i++; i < s->size && test_bit(i, s->writelog); i++)
range->count++;
BDPRINTF("export: dirty extent %"PRIu64":%u",
range->sector, range->count);
range++;
/* out of space in shared memory region */
if ((void*)range >= bmend(s->shm)) {
BDPRINTF("out of space in shm region at sector %"PRIu64, i);
return i;
}
/* undo forloop increment */
i--;
}
}
/* NULL-terminate range list */
range->sector = 0;
range->count = 0;
return i;
}
/* -- communication channel -- */
/* remove FS special characters in up to len bytes of path */
static inline void path_escape(char* path, size_t len) {
int i;
for (i = 0; i < len && path[i]; i++)
if (strchr(":/", path[i]))
path[i] = '_';
}
static char* ctl_makepath(const char* name, const char* ext)
{
char* res;
char *file;
file = strrchr(name, '/');
if (!file) {
BWPRINTF("invalid name %s\n", name);
return NULL;
}
if (asprintf(&res, BLKTAP_CTRL_DIR "/log_%s.%s", file, ext) < 0) {
BWPRINTF("could not allocate path");
return NULL;
}
path_escape(res + strlen(BLKTAP_CTRL_DIR) + 5, strlen(file));
return res;
}
static int shmem_open(struct tdlog_state* s, const char* name)
{
int i, l, fd;
/* device name -> path */
if (asprintf(&s->shmpath, "/log_%s.wlog", name) < 0) {
BWPRINTF("could not allocate shm path");
return -1;
}
path_escape(s->shmpath + 5, strlen(name));
if ((fd = shm_open(s->shmpath, O_CREAT|O_RDWR, 0750)) < 0) {
BWPRINTF("could not open shared memory file %s: %s", s->shmpath,
strerror(errno));
goto err;
}
if (ftruncate(fd, SHMSIZE) < 0) {
BWPRINTF("error truncating shmem to size %u", SHMSIZE);
close(fd);
goto err;
}
s->shm = mmap(NULL, SHMSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
if (s->shm == MAP_FAILED) {
BWPRINTF("could not mmap write log shm: %s", strerror(errno));
goto err;
}
return 0;
err:
s->shm = NULL;
free(s->shmpath);
s->shmpath = NULL;
return -1;
}
static int shmem_close(struct tdlog_state* s)
{
if (s->shm) {
munmap(s->shm, SHMSIZE);
s->shm = NULL;
}
if (s->shmpath) {
shm_unlink(s->shmpath);
s->shmpath = NULL;
}
return 0;
}
/* control socket */
static int ctl_open(struct tdlog_state* s, const char* name)
{
struct sockaddr_un saddr;
if (!(s->ctlpath = ctl_makepath(name, "ctl")))
return -1;
if ((s->ctl.fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
BWPRINTF("error opening control socket: %s", strerror(errno));
goto err;
}
memset(&saddr, 0, sizeof(saddr));
saddr.sun_family = AF_UNIX;
memcpy(saddr.sun_path, s->ctlpath, strlen(s->ctlpath));
if (unlink(s->ctlpath) && errno != ENOENT) {
BWPRINTF("error unlinking old socket path %s: %s", s->ctlpath,
strerror(errno));
goto err_sock;
}
if (bind(s->ctl.fd, (const struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
BWPRINTF("error binding control socket to %s: %s", s->ctlpath,
strerror(errno));
goto err_sock;
}
if (listen(s->ctl.fd, 1) < 0) {
BWPRINTF("error listening on control socket: %s", strerror(errno));
goto err_sock;
}
s->ctl.id = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
s->ctl.fd, 0, ctl_accept, s);
if (s->ctl.id < 0) {
BWPRINTF("error register event handler: %s", strerror(s->ctl.id));
goto err_sock;
}
return 0;
err_sock:
close(s->ctl.fd);
s->ctl.fd = -1;
err:
free(s->ctlpath);
s->ctlpath = NULL;
return -1;
}
static int ctl_close(struct tdlog_state* s)
{
while (s->connected) {
s->connected--;
tapdisk_server_unregister_event(s->connections[s->connected].id);
close(s->connections[s->connected].fd);
s->connections[s->connected].fd = -1;
s->connections[s->connected].id = 0;
}
if (s->ctl.fd >= 0) {
tapdisk_server_unregister_event(s->ctl.id);
close(s->ctl.fd);
s->ctl.fd = -1;
s->ctl.id = 0;
}
if (s->ctlpath) {
unlink(s->ctlpath);
free(s->ctlpath);
s->ctlpath = NULL;
}
/* XXX this must be fixed once requests are actually in flight */
/* could just drain the existing ring here first */
if (s->sring) {
SHARED_RING_INIT(s->sring);
BACK_RING_INIT(&s->bring, s->sring, SRINGSIZE);
}
return 0;
}
/* walk list of open sockets, close matching fd */
static int ctl_close_sock(struct tdlog_state* s, int fd)
{
int i;
for (i = 0; i < s->connected; i++) {
if (s->connections[i].fd == fd) {
tapdisk_server_unregister_event(s->connections[i].id);
close(s->connections[i].fd);
s->connections[i].fd = -1;
s->connections[i].id = 0;
s->connected--;
return 0;
}
}
BWPRINTF("requested to close unknown socket %d", fd);
return -1;
}
static void ctl_accept(event_id_t id, char mode, void *private)
{
struct tdlog_state* s = (struct tdlog_state *)private;
int fd;
event_id_t cid;
if ((fd = accept(s->ctl.fd, NULL, NULL)) < 0) {
BWPRINTF("error accepting control connection: %s", strerror(errno));
return;
}
if (s->connected) {
BWPRINTF("control session in progress, closing new connection");
close(fd);
return;
}
cid = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
fd, 0, ctl_request, s);
if (cid < 0) {
BWPRINTF("error registering connection event handler: %s", strerror(cid));
close(fd);
return;
}
s->connections[s->connected].fd = fd;
s->connections[s->connected].id = cid;
s->connected++;
}
/* response format: 4 bytes shmsize, 0-terminated path */
static int ctl_get_shmpath(struct tdlog_state* s, int fd)
{
char msg[CTLRSPLEN_SHMP + 1];
uint32_t sz;
int rc;
BDPRINTF("ctl: sending shared memory parameters (size: %u, path: %s)",
SHMSIZE, s->shmpath);
/* TMP: sanity-check shm */
sz = 0xdeadbeef;
memcpy(s->shm, &sz, sizeof(sz));
sz = SHMSIZE;
memcpy(msg, &sz, sizeof(sz));
snprintf(msg + sizeof(sz), sizeof(msg) - sizeof(sz), "%s", s->shmpath);
if ((rc = write(fd, msg, CTLRSPLEN_SHMP)) < 0) {
BWPRINTF("error writing shmpath: %s", strerror(errno));
return -1;
}
return 0;
}
static int ctl_peek_writes(struct tdlog_state* s, int fd)
{
int rc;
BDPRINTF("ctl: peeking bitmap");
writelog_export(s);
if ((rc = write(fd, "done", CTLRSPLEN_PEEK)) < 0) {
BWPRINTF("error writing peek ack: %s", strerror(errno));
return -1;
}
return 0;
}
static int ctl_clear_writes(struct tdlog_state* s, int fd)
{
int rc;
BDPRINTF("ctl: clearing bitmap");
writelog_clear(s, 0, 0);
if ((rc = write(fd, "done", CTLRSPLEN_CLEAR)) < 0) {
BWPRINTF("error writing clear ack: %s", strerror(errno));
return -1;
}
return 0;
}
/* get dirty bitmap and clear it atomically */
static int ctl_get_writes(struct tdlog_state* s, int fd)
{
int rc;
BDPRINTF("ctl: getting bitmap");
writelog_export(s);
writelog_clear(s, 0, 0);
if ((rc = write(fd, "done", CTLRSPLEN_GET)) < 0) {
BWPRINTF("error writing get ack: %s", strerror(errno));
return -1;
}
return 0;
}
/* get requests from ring */
static int ctl_kick(struct tdlog_state* s, int fd)
{
RING_IDX reqstart, reqend;
log_request_t req;
/* XXX testing */
RING_IDX rspstart, rspend;
log_response_t rsp;
struct log_ctlmsg msg;
int rc;
reqstart = s->bring.req_cons;
reqend = s->sring->req_prod;
BDPRINTF("ctl: ring kicked (start = %u, end = %u)", reqstart, reqend);
while (reqstart != reqend) {
/* XXX actually submit these! */
memcpy(&req, RING_GET_REQUEST(&s->bring, reqstart), sizeof(req));
BDPRINTF("ctl: read request %"PRIu64":%u", req.sector, req.count);
s->bring.req_cons = ++reqstart;
rsp.sector = req.sector;
rsp.count = req.count;
memcpy(RING_GET_RESPONSE(&s->bring, s->bring.rsp_prod_pvt), &rsp,
sizeof(rsp));
s->bring.rsp_prod_pvt++;
}
RING_PUSH_RESPONSES(&s->bring);
memset(&msg, 0, sizeof(msg));
memcpy(msg.msg, LOGCMD_KICK, 4);
if ((rc = write(fd, &msg, sizeof(msg))) < 0) {
BWPRINTF("error sending notify: %s", strerror(errno));
return -1;
} else if (rc < sizeof(msg)) {
BWPRINTF("short notify write (%d/%zd)", rc, sizeof(msg));
return -1;
}
return 0;
}
static int ctl_do_request(struct tdlog_state* s, int fd, struct log_ctlmsg* msg)
{
if (!strncmp(msg->msg, LOGCMD_SHMP, 4)) {
return ctl_get_shmpath(s, fd);
} else if (!strncmp(msg->msg, LOGCMD_PEEK, 4)) {
return ctl_peek_writes(s, fd);
} else if (!strncmp(msg->msg, LOGCMD_CLEAR, 4)) {
return ctl_clear_writes(s, fd);
} else if (!strncmp(msg->msg, LOGCMD_GET, 4)) {
return ctl_get_writes(s, fd);
} else if (!strncmp(msg->msg, LOGCMD_KICK, 4)) {
return ctl_kick(s, fd);
}
BWPRINTF("unknown control request %.4s", msg->msg);
return -1;
}
static inline int ctl_find_connection(struct tdlog_state *s, event_id_t id)
{
int i;
for (i = 0; i < s->connected; i++)
if (s->connections[i].id == id)
return s->connections[i].fd;
BWPRINTF("unrecognized event callback id %d", id);
return -1;
}
static void ctl_request(event_id_t id, char mode, void *private)
{
struct tdlog_state* s = (struct tdlog_state*)private;
struct log_ctlmsg msg;
int rc, i, fd = -1;
fd = ctl_find_connection(s, id);
if (fd == -1)
return;
if ((rc = read(fd, &msg, sizeof(msg))) < 0) {
BWPRINTF("error reading from ctl socket %d, closing: %s", fd,
strerror(errno));
ctl_close_sock(s, fd);
return;
} else if (rc == 0) {
BDPRINTF("ctl_request: EOF, closing socket");
ctl_close_sock(s, fd);
return;
} else if (rc < sizeof(msg)) {
BWPRINTF("short request received (%d/%zd bytes), ignoring", rc,
sizeof(msg));
return;
}
ctl_do_request(s, fd, &msg);
}
/* -- interface -- */
static int tdlog_close(td_driver_t*);
static int tdlog_open(td_driver_t* driver, const char* name, td_flag_t flags)
{
struct tdlog_state* s = (struct tdlog_state*)driver->data;
int rc;
memset(s, 0, sizeof(*s));
s->size = driver->info.size;
if ((rc = writelog_create(s))) {
tdlog_close(driver);
return rc;
}
if ((rc = shmem_open(s, name))) {
tdlog_close(driver);
return rc;
}
if ((rc = ctl_open(s, name))) {
tdlog_close(driver);
return rc;
}
s->sring = (log_sring_t*)sringstart(s->shm);
SHARED_RING_INIT(s->sring);
BACK_RING_INIT(&s->bring, s->sring, SRINGSIZE);
BDPRINTF("opened ctl socket");
return 0;
}
static int tdlog_close(td_driver_t* driver)
{
struct tdlog_state* s = (struct tdlog_state*)driver->data;
ctl_close(s);
shmem_close(s);
writelog_free(s);
return 0;
}
static void tdlog_queue_read(td_driver_t* driver, td_request_t treq)
{
td_forward_request(treq);
}
static void tdlog_queue_write(td_driver_t* driver, td_request_t treq)
{
struct tdlog_state* s = (struct tdlog_state*)driver->data;
int rc;
writelog_set(s, treq.sec, treq.secs);
td_forward_request(treq);
}
static int tdlog_get_parent_id(td_driver_t* driver, td_disk_id_t* id)
{
return -EINVAL;
}
static int tdlog_validate_parent(td_driver_t *driver,
td_driver_t *parent, td_flag_t flags)
{
return 0;
}
struct tap_disk tapdisk_log = {
.disk_type = "tapdisk_log",
.private_data_size = sizeof(struct tdlog_state),
.flags = 0,
.td_open = tdlog_open,
.td_close = tdlog_close,
.td_queue_read = tdlog_queue_read,
.td_queue_write = tdlog_queue_write,
.td_get_parent_id = tdlog_get_parent_id,
.td_validate_parent = tdlog_validate_parent,
};
File diff suppressed because it is too large. Load diff
-256
View File
@@ -1,256 +0,0 @@
/*
* Copyright (c) 2007, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/statvfs.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <string.h>
#include "blk.h"
#include "tapdisk.h"
#include "tapdisk-driver.h"
#include "tapdisk-interface.h"
char *img;
long int disksector_size;
long int disksize;
long int diskinfo;
static int connections = 0;
struct tdram_state {
int fd;
};
/*Get Image size, secsize*/
static int get_image_info(int fd, td_disk_info_t *info)
{
int ret;
long size;
unsigned long total_size;
struct statvfs statBuf;
struct stat stat;
ret = fstat(fd, &stat);
if (ret != 0) {
DPRINTF("ERROR: fstat failed, Couldn't stat image");
return -EINVAL;
}
if (S_ISBLK(stat.st_mode)) {
/*Accessing block device directly*/
info->size = 0;
if (blk_getimagesize(fd, &info->size) != 0)
return -EINVAL;
DPRINTF("Image size: \n\tpre sector_shift [%llu]\n\tpost "
"sector_shift [%llu]\n",
(long long unsigned)(info->size << SECTOR_SHIFT),
(long long unsigned)info->size);
/*Get the sector size*/
if (blk_getsectorsize(fd, &info->sector_size) != 0)
info->sector_size = DEFAULT_SECTOR_SIZE;
} else {
/*Local file? try fstat instead*/
info->size = (stat.st_size >> SECTOR_SHIFT);
info->sector_size = DEFAULT_SECTOR_SIZE;
DPRINTF("Image size: \n\tpre sector_shift [%llu]\n\tpost "
"sector_shift [%llu]\n",
(long long unsigned)(info->size << SECTOR_SHIFT),
(long long unsigned)info->size);
}
if (info->size == 0) {
info->size =((uint64_t) MAX_RAMDISK_SIZE);
info->sector_size = DEFAULT_SECTOR_SIZE;
}
info->info = 0;
/*Store variables locally*/
disksector_size = info->sector_size;
disksize = info->size;
diskinfo = info->info;
DPRINTF("Image sector_size: \n\t[%"PRIu64"]\n",
info->sector_size);
return 0;
}
/* Open the disk file and initialize ram state. */
int tdram_open (td_driver_t *driver, const char *name, td_flag_t flags)
{
char *p;
uint64_t size;
int i, fd, ret = 0, count = 0, o_flags;
struct tdram_state *prv = (struct tdram_state *)driver->data;
connections++;
if (connections > 1) {
driver->info.sector_size = disksector_size;
driver->info.size = disksize;
driver->info.info = diskinfo;
DPRINTF("Image already open, returning parameters:\n");
DPRINTF("Image size: \n\tpre sector_shift [%llu]\n\tpost "
"sector_shift [%llu]\n",
(long long unsigned)(driver->info.size << SECTOR_SHIFT),
(long long unsigned)driver->info.size);
DPRINTF("Image sector_size: \n\t[%"PRIu64"]\n",
driver->info.sector_size);
prv->fd = -1;
goto done;
}
/* Open the file */
o_flags = O_DIRECT | O_LARGEFILE |
((flags == TD_OPEN_RDONLY) ? O_RDONLY : O_RDWR);
fd = open(name, o_flags);
if ((fd == -1) && (errno == EINVAL)) {
/* Maybe O_DIRECT isn't supported. */
o_flags &= ~O_DIRECT;
fd = open(name, o_flags);
if (fd != -1) DPRINTF("WARNING: Accessing image without"
"O_DIRECT! (%s)\n", name);
} else if (fd != -1) DPRINTF("open(%s) with O_DIRECT\n", name);
if (fd == -1) {
DPRINTF("Unable to open [%s]!\n",name);
ret = 0 - errno;
goto done;
}
prv->fd = fd;
ret = get_image_info(fd, &driver->info);
size = MAX_RAMDISK_SIZE;
if (driver->info.size > size) {
DPRINTF("Disk exceeds limit, must be less than [%d]MB",
(MAX_RAMDISK_SIZE<<SECTOR_SHIFT)>>20);
return -ENOMEM;
}
/*Read the image into memory*/
if (posix_memalign((void **)&img,
DEFAULT_SECTOR_SIZE,
driver->info.size << SECTOR_SHIFT)) {
DPRINTF("Mem malloc failed\n");
return -errno;
}
p = img;
DPRINTF("Reading %llu bytes.......",
(long long unsigned)driver->info.size << SECTOR_SHIFT);
for (i = 0; i < driver->info.size; i++) {
ret = read(prv->fd, p, driver->info.sector_size);
if (ret != driver->info.sector_size) {
DPRINTF("ret = %d, errno = %d\n", ret, errno);
ret = 0 - errno;
break;
} else {
count += ret;
p = img + count;
}
}
DPRINTF("[%d]\n",count);
if (count != driver->info.size << SECTOR_SHIFT) {
ret = -1;
} else {
ret = 0;
}
done:
return ret;
}
void tdram_queue_read(td_driver_t *driver, td_request_t treq)
{
struct tdram_state *prv = (struct tdram_state *)driver->data;
int size = treq.secs * driver->info.sector_size;
uint64_t offset = treq.sec * (uint64_t)driver->info.sector_size;
memcpy(treq.buf, img + offset, size);
td_complete_request(treq, 0);
}
void tdram_queue_write(td_driver_t *driver, td_request_t treq)
{
struct tdram_state *prv = (struct tdram_state *)driver->data;
int size = treq.secs * driver->info.sector_size;
uint64_t offset = treq.sec * (uint64_t)driver->info.sector_size;
/* We assume that write access is controlled
* at a higher level for multiple disks */
memcpy(img + offset, treq.buf, size);
td_complete_request(treq, 0);
}
int tdram_close(td_driver_t *driver)
{
struct tdram_state *prv = (struct tdram_state *)driver->data;
connections--;
return 0;
}
int tdram_get_parent_id(td_driver_t *driver, td_disk_id_t *id)
{
return TD_NO_PARENT;
}
int tdram_validate_parent(td_driver_t *driver,
td_driver_t *pdriver, td_flag_t flags)
{
return -EINVAL;
}
struct tap_disk tapdisk_ram = {
.disk_type = "tapdisk_ram",
.flags = 0,
.private_data_size = sizeof(struct tdram_state),
.td_open = tdram_open,
.td_close = tdram_close,
.td_queue_read = tdram_queue_read,
.td_queue_write = tdram_queue_write,
.td_get_parent_id = tdram_get_parent_id,
.td_validate_parent = tdram_validate_parent,
.td_debug = NULL,
};
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
-179
View File
@@ -1,179 +0,0 @@
#ifndef BSWAP_H
#define BSWAP_H
//#include "config-host.h"
#include <inttypes.h>
#if defined(__NetBSD__)
#include <sys/endian.h>
#include <sys/types.h>
#elif defined(__OpenBSD__)
#include <machine/endian.h>
#define bswap_16(x) swap16(x)
#define bswap_32(x) swap32(x)
#define bswap_64(x) swap64(x)
#elif defined(__linux__)
#include <endian.h>
#include <byteswap.h>
static inline uint16_t bswap16(uint16_t x)
{
return bswap_16(x);
}
static inline uint32_t bswap32(uint32_t x)
{
return bswap_32(x);
}
static inline uint64_t bswap64(uint64_t x)
{
return bswap_64(x);
}
static inline void bswap16s(uint16_t *s)
{
*s = bswap16(*s);
}
static inline void bswap32s(uint32_t *s)
{
*s = bswap32(*s);
}
static inline void bswap64s(uint64_t *s)
{
*s = bswap64(*s);
}
#endif
#if defined(WORDS_BIGENDIAN)
#define be_bswap(v, size) (v)
#define le_bswap(v, size) bswap ## size(v)
#define be_bswaps(v, size)
#define le_bswaps(p, size) *p = bswap ## size(*p);
#else
#define le_bswap(v, size) (v)
#define be_bswap(v, size) bswap ## size(v)
#define le_bswaps(v, size)
#define be_bswaps(p, size) *p = bswap ## size(*p);
#endif
#define CPU_CONVERT(endian, size, type)\
static inline type endian ## size ## _to_cpu(type v)\
{\
return endian ## _bswap(v, size);\
}\
\
static inline type cpu_to_ ## endian ## size(type v)\
{\
return endian ## _bswap(v, size);\
}\
\
static inline void endian ## size ## _to_cpus(type *p)\
{\
endian ## _bswaps(p, size)\
}\
\
static inline void cpu_to_ ## endian ## size ## s(type *p)\
{\
endian ## _bswaps(p, size)\
}\
\
static inline type endian ## size ## _to_cpup(const type *p)\
{\
return endian ## size ## _to_cpu(*p);\
}\
\
static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\
{\
*p = cpu_to_ ## endian ## size(v);\
}
CPU_CONVERT(be, 16, uint16_t)
CPU_CONVERT(be, 32, uint32_t)
CPU_CONVERT(be, 64, uint64_t)
CPU_CONVERT(le, 16, uint16_t)
CPU_CONVERT(le, 32, uint32_t)
CPU_CONVERT(le, 64, uint64_t)
/* unaligned versions (optimized for frequent unaligned accesses)*/
#if defined(__i386__) || defined(__powerpc__)
#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v)
#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v)
#define le16_to_cpupu(p) le16_to_cpup(p)
#define le32_to_cpupu(p) le32_to_cpup(p)
#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v)
#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v)
#else
static inline void cpu_to_le16wu(uint16_t *p, uint16_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v;
p1[1] = v >> 8;
}
static inline void cpu_to_le32wu(uint32_t *p, uint32_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v;
p1[1] = v >> 8;
p1[2] = v >> 16;
p1[3] = v >> 24;
}
static inline uint16_t le16_to_cpupu(const uint16_t *p)
{
const uint8_t *p1 = (const uint8_t *)p;
return p1[0] | (p1[1] << 8);
}
static inline uint32_t le32_to_cpupu(const uint32_t *p)
{
const uint8_t *p1 = (const uint8_t *)p;
return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24);
}
static inline void cpu_to_be16wu(uint16_t *p, uint16_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v >> 8;
p1[1] = v;
}
static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v >> 24;
p1[1] = v >> 16;
p1[2] = v >> 8;
p1[3] = v;
}
#endif
#ifdef WORDS_BIGENDIAN
#define cpu_to_32wu cpu_to_be32wu
#else
#define cpu_to_32wu cpu_to_le32wu
#endif
#undef le_bswap
#undef be_bswap
#undef le_bswaps
#undef be_bswaps
#endif /* BSWAP_H */
-18
View File
@@ -1,18 +0,0 @@
#!/bin/sh
cat > .gcrypt.c << EOF
#include <gcrypt.h>
int main(void)
{
gcry_md_hash_buffer(GCRY_MD_MD5, NULL, NULL, 0);
return 0;
}
EOF
if $1 -o .gcrypt .gcrypt.c -lgcrypt 2>/dev/null ; then
echo "yes"
else
echo "no"
fi
rm -f .gcrypt*
-279
View File
@@ -1,279 +0,0 @@
/* Copyright (C) 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
/*
* There are duplicates of this code in:
* - tools/xenstore/hashtable.c
*/
#include "hashtable.h"
#include "hashtable_private.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
/*
Credit for primes table: Aaron Krowne
http://br.endernet.org/~akrowne/
http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
*/
static const unsigned int primes[] = {
53, 97, 193, 389,
769, 1543, 3079, 6151,
12289, 24593, 49157, 98317,
196613, 393241, 786433, 1572869,
3145739, 6291469, 12582917, 25165843,
50331653, 100663319, 201326611, 402653189,
805306457, 1610612741
};
const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]);
const float max_load_factor = 0.65;
/*****************************************************************************/
struct hashtable *
create_hashtable(unsigned int minsize,
unsigned int (*hashf) (void*),
int (*eqf) (void*,void*))
{
struct hashtable *h;
unsigned int pindex, size = primes[0];
/* Check requested hashtable isn't too large */
if (minsize > (1u << 30)) return NULL;
/* Enforce size as prime */
for (pindex=0; pindex < prime_table_length; pindex++) {
if (primes[pindex] > minsize) { size = primes[pindex]; break; }
}
h = (struct hashtable *)malloc(sizeof(struct hashtable));
if (NULL == h) return NULL; /*oom*/
h->table = (struct entry **)malloc(sizeof(struct entry*) * size);
if (NULL == h->table) { free(h); return NULL; } /*oom*/
memset(h->table, 0, size * sizeof(struct entry *));
h->tablelength = size;
h->primeindex = pindex;
h->entrycount = 0;
h->hashfn = hashf;
h->eqfn = eqf;
h->loadlimit = (unsigned int) ceil(size * max_load_factor);
return h;
}
/*****************************************************************************/
unsigned int
hash(struct hashtable *h, void *k)
{
/* Aim to protect against poor hash functions by adding logic here
* - logic taken from java 1.4 hashtable source */
unsigned int i = h->hashfn(k);
i += ~(i << 9);
i ^= ((i >> 14) | (i << 18)); /* >>> */
i += (i << 4);
i ^= ((i >> 10) | (i << 22)); /* >>> */
return i;
}
/*****************************************************************************/
static int
hashtable_expand(struct hashtable *h)
{
/* Double the size of the table to accomodate more entries */
struct entry **newtable;
struct entry *e;
struct entry **pE;
unsigned int newsize, i, index;
/* Check we're not hitting max capacity */
if (h->primeindex == (prime_table_length - 1)) return 0;
newsize = primes[++(h->primeindex)];
newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize);
if (NULL != newtable)
{
memset(newtable, 0, newsize * sizeof(struct entry *));
/* This algorithm is not 'stable'. ie. it reverses the list
* when it transfers entries between the tables */
for (i = 0; i < h->tablelength; i++) {
while (NULL != (e = h->table[i])) {
h->table[i] = e->next;
index = indexFor(newsize,e->h);
e->next = newtable[index];
newtable[index] = e;
}
}
free(h->table);
h->table = newtable;
}
/* Plan B: realloc instead */
else
{
newtable = (struct entry **)
realloc(h->table, newsize * sizeof(struct entry *));
if (NULL == newtable) { (h->primeindex)--; return 0; }
h->table = newtable;
memset(newtable[h->tablelength], 0, newsize - h->tablelength);
for (i = 0; i < h->tablelength; i++) {
for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {
index = indexFor(newsize,e->h);
if (index == i)
{
pE = &(e->next);
}
else
{
*pE = e->next;
e->next = newtable[index];
newtable[index] = e;
}
}
}
}
h->tablelength = newsize;
h->loadlimit = (unsigned int) ceil(newsize * max_load_factor);
return -1;
}
/*****************************************************************************/
unsigned int
hashtable_count(struct hashtable *h)
{
return h->entrycount;
}
/*****************************************************************************/
int
hashtable_insert(struct hashtable *h, void *k, void *v)
{
/* This method allows duplicate keys - but they shouldn't be used */
unsigned int index;
struct entry *e;
if (++(h->entrycount) > h->loadlimit)
{
/* Ignore the return value. If expand fails, we should
* still try cramming just this value into the existing table
* -- we may not have memory for a larger table, but one more
* element may be ok. Next time we insert, we'll try expanding again.*/
hashtable_expand(h);
}
e = (struct entry *)malloc(sizeof(struct entry));
if (NULL == e) { --(h->entrycount); return 0; } /*oom*/
e->h = hash(h,k);
index = indexFor(h->tablelength,e->h);
e->k = k;
e->v = v;
e->next = h->table[index];
h->table[index] = e;
return -1;
}
/*****************************************************************************/
void * /* returns value associated with key */
hashtable_search(struct hashtable *h, void *k)
{
struct entry *e;
unsigned int hashvalue, index;
hashvalue = hash(h,k);
index = indexFor(h->tablelength,hashvalue);
e = h->table[index];
while (NULL != e)
{
/* Check hash value to short circuit heavier comparison */
if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v;
e = e->next;
}
return NULL;
}
/*****************************************************************************/
void * /* returns value associated with key */
hashtable_remove(struct hashtable *h, void *k)
{
/* TODO: consider compacting the table when the load factor drops enough,
* or provide a 'compact' method. */
struct entry *e;
struct entry **pE;
void *v;
unsigned int hashvalue, index;
hashvalue = hash(h,k);
index = indexFor(h->tablelength,hash(h,k));
pE = &(h->table[index]);
e = *pE;
while (NULL != e)
{
/* Check hash value to short circuit heavier comparison */
if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
{
*pE = e->next;
h->entrycount--;
v = e->v;
freekey(e->k);
free(e);
return v;
}
pE = &(e->next);
e = e->next;
}
return NULL;
}
/*****************************************************************************/
/* destroy */
void
hashtable_destroy(struct hashtable *h, int free_values)
{
unsigned int i;
struct entry *e, *f;
struct entry **table = h->table;
if (free_values)
{
for (i = 0; i < h->tablelength; i++)
{
e = table[i];
while (NULL != e)
{ f = e; e = e->next; freekey(f->k); free(f->v); free(f); }
}
}
else
{
for (i = 0; i < h->tablelength; i++)
{
e = table[i];
while (NULL != e)
{ f = e; e = e->next; freekey(f->k); free(f); }
}
}
free(h->table);
free(h);
}
/*
* Copyright (c) 2002, Christopher Clark
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-204
View File
@@ -1,204 +0,0 @@
/* Copyright (C) 2002 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
/*
* There are duplicates of this code in:
* - tools/xenstore/hashtable.h
*/
#ifndef __HASHTABLE_CWC22_H__
#define __HASHTABLE_CWC22_H__
struct hashtable;
/* Example of use:
*
* struct hashtable *h;
* struct some_key *k;
* struct some_value *v;
*
* static unsigned int hash_from_key_fn( void *k );
* static int keys_equal_fn ( void *key1, void *key2 );
*
* h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
* k = (struct some_key *) malloc(sizeof(struct some_key));
* v = (struct some_value *) malloc(sizeof(struct some_value));
*
* (initialise k and v to suitable values)
*
* if (! hashtable_insert(h,k,v) )
* { exit(-1); }
*
* if (NULL == (found = hashtable_search(h,k) ))
* { printf("not found!"); }
*
* if (NULL == (found = hashtable_remove(h,k) ))
* { printf("Not found\n"); }
*
*/
/* Macros may be used to define type-safe(r) hashtable access functions, with
* methods specialized to take known key and value types as parameters.
*
* Example:
*
* Insert this at the start of your file:
*
* DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
* DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
* DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
*
* This defines the functions 'insert_some', 'search_some' and 'remove_some'.
* These operate just like hashtable_insert etc., with the same parameters,
* but their function signatures have 'struct some_key *' rather than
* 'void *', and hence can generate compile time errors if your program is
* supplying incorrect data as a key (and similarly for value).
*
* Note that the hash and key equality functions passed to create_hashtable
* still take 'void *' parameters instead of 'some key *'. This shouldn't be
* a difficult issue as they're only defined and passed once, and the other
* functions will ensure that only valid keys are supplied to them.
*
* The cost for this checking is increased code size and runtime overhead
* - if performance is important, it may be worth switching back to the
* unsafe methods once your program has been debugged with the safe methods.
* This just requires switching to some simple alternative defines - eg:
* #define insert_some hashtable_insert
*
*/
/*****************************************************************************
* create_hashtable
* @name create_hashtable
* @param minsize minimum initial size of hashtable
* @param hashfunction function for hashing keys
* @param key_eq_fn function for determining key equality
* @return newly created hashtable or NULL on failure
*/
struct hashtable *
create_hashtable(unsigned int minsize,
unsigned int (*hashfunction) (void*),
int (*key_eq_fn) (void*,void*));
/*****************************************************************************
* hashtable_insert
* @name hashtable_insert
* @param h the hashtable to insert into
* @param k the key - hashtable claims ownership and will free on removal
* @param v the value - does not claim ownership
* @return non-zero for successful insertion
*
* This function will cause the table to expand if the insertion would take
* the ratio of entries to table size over the maximum load factor.
*
* This function does not check for repeated insertions with a duplicate key.
* The value returned when using a duplicate key is undefined -- when
* the hashtable changes size, the order of retrieval of duplicate key
* entries is reversed.
* If in doubt, remove before insert.
*/
int
hashtable_insert(struct hashtable *h, void *k, void *v);
#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
int fnname (struct hashtable *h, keytype *k, valuetype *v) \
{ \
return hashtable_insert(h,k,v); \
}
/*****************************************************************************
* hashtable_search
* @name hashtable_search
* @param h the hashtable to search
* @param k the key to search for - does not claim ownership
* @return the value associated with the key, or NULL if none found
*/
void *
hashtable_search(struct hashtable *h, void *k);
#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
valuetype * fnname (struct hashtable *h, keytype *k) \
{ \
return (valuetype *) (hashtable_search(h,k)); \
}
/*****************************************************************************
* hashtable_remove
* @name hashtable_remove
* @param h the hashtable to remove the item from
* @param k the key to search for - does not claim ownership
* @return the value associated with the key, or NULL if none found
*/
void * /* returns value */
hashtable_remove(struct hashtable *h, void *k);
#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
valuetype * fnname (struct hashtable *h, keytype *k) \
{ \
return (valuetype *) (hashtable_remove(h,k)); \
}
/*****************************************************************************
* hashtable_count
* @name hashtable_count
* @param h the hashtable
* @return the number of items stored in the hashtable
*/
unsigned int
hashtable_count(struct hashtable *h);
/*****************************************************************************
* hashtable_destroy
* @name hashtable_destroy
* @param h the hashtable
* @param free_values whether to call 'free' on the remaining values
*/
void
hashtable_destroy(struct hashtable *h, int free_values);
#endif /* __HASHTABLE_CWC22_H__ */
/*
* Copyright (c) 2002, Christopher Clark
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-195
View File
@@ -1,195 +0,0 @@
/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
#include "hashtable.h"
#include "hashtable_private.h"
#include "hashtable_itr.h"
#include <stdlib.h> /* defines NULL */
struct hashtable_itr {
struct hashtable *h;
struct entry *e;
struct entry *parent;
unsigned int index;
};
/*****************************************************************************/
/* hashtable_iterator - iterator constructor */
struct hashtable_itr *
hashtable_iterator(struct hashtable *h)
{
unsigned int i, tablelength;
struct hashtable_itr *itr = (struct hashtable_itr *)
malloc(sizeof(struct hashtable_itr));
if (NULL == itr) return NULL;
itr->h = h;
itr->e = NULL;
itr->parent = NULL;
tablelength = h->tablelength;
itr->index = tablelength;
if (0 == h->entrycount) return itr;
for (i = 0; i < tablelength; i++)
{
if (NULL != h->table[i])
{
itr->e = h->table[i];
itr->index = i;
break;
}
}
return itr;
}
/*****************************************************************************/
/* key - return the key of the (key,value) pair at the current position */
/* value - return the value of the (key,value) pair at the current position */
void *
hashtable_iterator_key(struct hashtable_itr *i)
{ return i->e->k; }
void *
hashtable_iterator_value(struct hashtable_itr *i)
{ return i->e->v; }
/*****************************************************************************/
/* advance - advance the iterator to the next element
* returns zero if advanced to end of table */
int
hashtable_iterator_advance(struct hashtable_itr *itr)
{
unsigned int j,tablelength;
struct entry **table;
struct entry *next;
if (NULL == itr->e) return 0; /* stupidity check */
next = itr->e->next;
if (NULL != next)
{
itr->parent = itr->e;
itr->e = next;
return -1;
}
tablelength = itr->h->tablelength;
itr->parent = NULL;
if (tablelength <= (j = ++(itr->index)))
{
itr->e = NULL;
return 0;
}
table = itr->h->table;
while (NULL == (next = table[j]))
{
if (++j >= tablelength)
{
itr->index = tablelength;
itr->e = NULL;
return 0;
}
}
itr->index = j;
itr->e = next;
return -1;
}
/*****************************************************************************/
/* remove - remove the entry at the current iterator position
* and advance the iterator, if there is a successive
* element.
* If you want the value, read it before you remove:
* beware memory leaks if you don't.
* Returns zero if end of iteration. */
int
hashtable_iterator_remove(struct hashtable_itr *itr)
{
struct entry *remember_e, *remember_parent;
int ret;
/* Do the removal */
if (NULL == (itr->parent))
{
/* element is head of a chain */
itr->h->table[itr->index] = itr->e->next;
} else {
/* element is mid-chain */
itr->parent->next = itr->e->next;
}
/* itr->e is now outside the hashtable */
remember_e = itr->e;
itr->h->entrycount--;
freekey(remember_e->k);
/* Advance the iterator, correcting the parent */
remember_parent = itr->parent;
ret = hashtable_iterator_advance(itr);
if (itr->parent == remember_e) { itr->parent = remember_parent; }
free(remember_e);
return ret;
}
/*****************************************************************************/
int /* returns zero if not found */
hashtable_iterator_search(struct hashtable_itr *itr,
struct hashtable *h, void *k)
{
struct entry *e, *parent;
unsigned int hashvalue, index;
hashvalue = hash(h,k);
index = indexFor(h->tablelength,hashvalue);
e = h->table[index];
parent = NULL;
while (NULL != e)
{
/* Check hash value to short circuit heavier comparison */
if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
{
itr->index = index;
itr->e = e;
itr->parent = parent;
itr->h = h;
return -1;
}
parent = e;
e = e->next;
}
return 0;
}
/*
* Copyright (c) 2002, 2004, Christopher Clark
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-96
View File
@@ -1,96 +0,0 @@
/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
#ifndef __HASHTABLE_ITR_CWC22__
#define __HASHTABLE_ITR_CWC22__
#include "hashtable.h"
#include "hashtable_private.h" /* needed to enable inlining */
struct hashtable_itr;
/*****************************************************************************/
/* hashtable_iterator
*/
struct hashtable_itr *
hashtable_iterator(struct hashtable *h);
/*****************************************************************************/
/* hashtable_iterator_key
* - return the value of the (key,value) pair at the current position */
void *
hashtable_iterator_key(struct hashtable_itr *i);
/*****************************************************************************/
/* value - return the value of the (key,value) pair at the current position */
void *
hashtable_iterator_value(struct hashtable_itr *i);
/*****************************************************************************/
/* advance - advance the iterator to the next element
* returns zero if advanced to end of table */
int
hashtable_iterator_advance(struct hashtable_itr *itr);
/*****************************************************************************/
/* remove - remove current element and advance the iterator to the next element
* NB: if you need the value to free it, read it before
* removing. ie: beware memory leaks!
* returns zero if advanced to end of table */
int
hashtable_iterator_remove(struct hashtable_itr *itr);
/*****************************************************************************/
/* search - overwrite the supplied iterator, to point to the entry
* matching the supplied key.
h points to the hashtable to be searched.
* returns zero if not found. */
int
hashtable_iterator_search(struct hashtable_itr *itr,
struct hashtable *h, void *k);
#define DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \
int fnname (struct hashtable_itr *i, struct hashtable *h, keytype *k) \
{ \
return (hashtable_iterator_search(i,h,k)); \
}
#endif /* __HASHTABLE_ITR_CWC22__*/
/*
* Copyright (c) 2002, 2004, Christopher Clark
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-90
View File
@@ -1,90 +0,0 @@
/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
/*
* There are duplicates of this code in:
* - tools/xenstore/hashtable_private.h
*/
#ifndef __HASHTABLE_PRIVATE_CWC22_H__
#define __HASHTABLE_PRIVATE_CWC22_H__
#include "hashtable.h"
/*****************************************************************************/
struct entry
{
void *k, *v;
unsigned int h;
struct entry *next;
};
struct hashtable {
unsigned int tablelength;
struct entry **table;
unsigned int entrycount;
unsigned int loadlimit;
unsigned int primeindex;
unsigned int (*hashfn) (void *k);
int (*eqfn) (void *k1, void *k2);
};
/*****************************************************************************/
unsigned int
hash(struct hashtable *h, void *k);
/*****************************************************************************/
/* indexFor */
static inline unsigned int
indexFor(unsigned int tablelength, unsigned int hashvalue) {
return (hashvalue % tablelength);
};
/* Only works if tablelength == 2^N */
/*static inline unsigned int
indexFor(unsigned int tablelength, unsigned int hashvalue)
{
return (hashvalue & (tablelength - 1u));
}
*/
/*****************************************************************************/
#define freekey(X) free(X)
/*define freekey(X) ; */
/*****************************************************************************/
#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/
/*
* Copyright (c) 2002, Christopher Clark
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-71
View File
@@ -1,71 +0,0 @@
/* Copyright (C) 2002 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
#include "hashtable.h"
#include "hashtable_private.h"
#include "hashtable_utility.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/*****************************************************************************/
/* hashtable_change
*
* function to change the value associated with a key, where there already
* exists a value bound to the key in the hashtable.
* Source due to Holger Schemel.
*
* */
int
hashtable_change(struct hashtable *h, void *k, void *v)
{
struct entry *e;
unsigned int hashvalue, index;
hashvalue = hash(h,k);
index = indexFor(h->tablelength,hashvalue);
e = h->table[index];
while (NULL != e)
{
/* Check hash value to short circuit heavier comparison */
if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
{
free(e->v);
e->v = v;
return -1;
}
e = e->next;
}
return 0;
}
/*
* Copyright (c) 2002, Christopher Clark
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-55
View File
@@ -1,55 +0,0 @@
/* Copyright (C) 2002 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
#ifndef __HASHTABLE_CWC22_UTILITY_H__
#define __HASHTABLE_CWC22_UTILITY_H__
/*****************************************************************************
* hashtable_change
*
* function to change the value associated with a key, where there already
* exists a value bound to the key in the hashtable.
* Source due to Holger Schemel.
*
* @name hashtable_change
* @param h the hashtable
* @param key
* @param value
*
*/
int
hashtable_change(struct hashtable *h, void *k, void *v);
#endif /* __HASHTABLE_CWC22_H__ */
/*
* Copyright (c) 2002, Christopher Clark
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-316
View File
@@ -1,316 +0,0 @@
/* img2qcow.c
*
* Generates a qcow format disk and fills it from an existing image.
*
* (c) 2006 Julian Chesterfield and Andrew Warfield
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation; or, when distributed
* separately from the Linux kernel or incorporated into other
* software packages, subject to the following license:
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this source file (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/statvfs.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <string.h>
#include <zlib.h>
#include <inttypes.h>
#include <libaio.h>
#include "bswap.h"
#include "aes.h"
#include "tapdisk.h"
#include "tapdisk-server.h"
#include "tapdisk-driver.h"
#include "tapdisk-interface.h"
#include "tapdisk-disktype.h"
#include "qcow.h"
#include "blk.h"
#if 1
#define DFPRINTF(_f, _a...) fprintf ( stderr, _f , ## _a )
#else
#define DFPRINTF(_f, _a...) ((void)0)
#endif
/* *BSD has no O_LARGEFILE */
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif
#define BLOCK_PROCESSSZ 4096
#define QCOW_VBD 0
#define PROGRESS_QUANT 2
static int running = 1, complete = 0;
static int returned_events = 0, submit_events = 0;
static uint32_t read_idx = 0;
td_driver_t *ddqcow;
td_vbd_t* qcow_vbd;
static uint64_t prev = 0, written = 0;
static char output[(100/PROGRESS_QUANT) + 5];
extern tapdisk_server_t server;
static void print_bytes(void *ptr, int length)
{
int i,k;
unsigned char *p = ptr;
DFPRINTF("Buf dump, length %d:\n",length);
for (k = 0; k < length; k++) {
DFPRINTF("%x",*p);
*p++;
if(k % 16 == 0) DFPRINTF("\n");
else if(k % 2 == 0) DFPRINTF(" ");
}
DFPRINTF("\n");
return;
}
static void debug_output(uint64_t progress, uint64_t size)
{
//Output progress every PROGRESS_QUANT
uint64_t blocks = size/(100/PROGRESS_QUANT);
if (progress/blocks > prev) {
memcpy(output+prev+1,"=>",2);
prev++;
DFPRINTF("\r%s %"PRIi64"%%",
output, (int64_t)((prev-1)*PROGRESS_QUANT));
}
return;
}
static int get_image_info(td_disk_info_t *driver, int fd)
{
int ret;
long size;
unsigned long total_size;
struct statvfs statBuf;
struct stat stat;
uint64_t sector_size=DEFAULT_SECTOR_SIZE;
ret = fstat(fd, &stat);
if (ret != 0) {
DFPRINTF("ERROR: fstat failed, Couldn't stat image");
return -EINVAL;
}
if (S_ISBLK(stat.st_mode)) {
/*Accessing block device directly*/
if (blk_getimagesize(fd, &driver->size) != 0)
return -EINVAL;
DFPRINTF("Image size: \n\tpre sector_shift [%"PRIu64"]\n\tpost "
"sector_shift [%"PRIu64"]\n",
(uint64_t)(driver->size << SECTOR_SHIFT),
(uint64_t)driver->size);
/*Get the sector size*/
if (!blk_getsectorsize(fd, &sector_size))
driver->sector_size = sector_size;
} else {
/*Local file? try fstat instead*/
driver->size = (stat.st_size >> SECTOR_SHIFT);
driver->sector_size = DEFAULT_SECTOR_SIZE;
DFPRINTF("Image size: [%"PRIu64"]\n",
(uint64_t)driver->size);
}
return 0;
}
void send_responses(td_request_t treq, int err)
{
if (err < 0) {
DFPRINTF("AIO FAILURE: res [%d]!\n",err);
return;
}
returned_events++;
free(treq.buf);
}
int main(int argc, const char *argv[])
{
int ret = -1, fd, len, err;
struct timeval timeout;
uint64_t i;
char *buf = NULL;
td_request_t treq;
td_disk_info_t info;
td_vbd_request_t* vreq;
if (argc != 3) {
fprintf(stderr, "Qcow-utils: v1.0.0\n");
fprintf(stderr, "usage: %s <QCOW FILENAME> <SRC IMAGE>\n",
argv[0]);
exit(-1);
}
/*Open image*/
fd = open(argv[2], O_RDONLY | O_LARGEFILE);
if (fd == -1) {
DFPRINTF("Unable to open [%s], (err %d)!\n",argv[2],0 - errno);
exit(-1);
}
get_image_info(&info, fd);
/*Create qcow file*/
ret = qcow_create(argv[1],info.size<<SECTOR_SHIFT,NULL,0);
if (ret < 0) {
DFPRINTF("Unable to create QCOW file\n");
exit(-1);
} else DFPRINTF("Qcow file created: size %"PRIu64" sectors\n",
(uint64_t)info.size);
/* Open Qcow image*/
err = tapdisk_server_initialize();
if( err ) {
DPRINTF("qcow2raw Couldn't initialize server instance.\n");
return err;
}
err=tapdisk_vbd_initialize(QCOW_VBD);
if( err ) {
DPRINTF("qcow2raw Couldn't initialize qcow vbd.\n");
return err;
}
qcow_vbd = tapdisk_server_get_vbd(QCOW_VBD);
if (!qcow_vbd) {
err = -ENODEV;
DPRINTF("qcow2raw Couldn't create qcow vbd.\n");
return err;
}
err = tapdisk_vbd_open_vdi(qcow_vbd, argv[1], DISK_TYPE_QCOW,
TAPDISK_STORAGE_TYPE_DEFAULT,
0);
if( err ) {
DPRINTF("qcow2raw Couldn't open qcow file.\n");
return err;
}
ddqcow=(tapdisk_vbd_first_image(qcow_vbd))->driver;
/*Initialise the output string*/
memset(output,0x20,(100/PROGRESS_QUANT)+5);
output[0] = '[';
output[(100/PROGRESS_QUANT)+2] = ']';
output[(100/PROGRESS_QUANT)+3] = '\0';
DFPRINTF("%s",output);
i = 0;
while (running) {
if (!complete) {
/*Read sector from image*/
if (lseek(fd, i*512, SEEK_SET) == (off_t)-1) {
DFPRINTF("Unable to access file offset %"PRIu64"\n",
(uint64_t)i*512);
exit(-1);
}
if( (ret = posix_memalign((void **)&buf,
BLOCK_PROCESSSZ,
BLOCK_PROCESSSZ)) != 0) {
DFPRINTF("Unable to read memalign buf (%d)\n",ret);
exit(-1);
}
/*We attempt to read 4k sized blocks*/
len = read(fd, buf, BLOCK_PROCESSSZ);
if (len < 512) {
DFPRINTF("Unable to read sector %"PRIu64"\n",
(uint64_t) (i));
complete = 1;
continue;
}
len = (len >> 9);
treq.op = TD_OP_WRITE;
treq.buf = buf;
treq.sec = i;
treq.secs = len;
treq.image = 0;
treq.cb = send_responses;
treq.cb_data = buf;
treq.id = 0;
treq.sidx = 0;
vreq = calloc(1, sizeof(td_vbd_request_t));
treq.private = vreq;
vreq->submitting = 1;
INIT_LIST_HEAD(&vreq->next);
tapdisk_vbd_move_request(treq.private,
&qcow_vbd->pending_requests);
ddqcow->ops->td_queue_write(ddqcow,treq);
--vreq->submitting;
submit_events++;
i += len;
if (i == info.size)
complete = 1;
tapdisk_submit_all_tiocbs(&server.aio_queue);
debug_output(i,info.size);
}
while(returned_events != submit_events) {
ret = scheduler_wait_for_events(&server.scheduler);
if (ret < 0) {
DFPRINTF("server wait returned %d\n", ret);
sleep(2);
}
}
if (complete && (returned_events == submit_events))
running = 0;
}
memcpy(output+prev+1,"=",1);
DFPRINTF("\r%s 100%%\nTRANSFER COMPLETE\n\n", output);
ddqcow->ops->td_close(ddqcow);
free(ddqcow->data);
return 0;
}
-671
View File
@@ -1,671 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <time.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include "io-optimize.h"
#include "tapdisk-log.h"
#if (!defined(TEST) && defined(DEBUG))
#define DBG(ctx, f, a...) tlog_write(TLOG_DBG, f, ##a)
#elif defined(TEST)
#define DBG(ctx, f, a...) printf(f, ##a)
#else
#define DBG(ctx, f, a...) ((void)0)
#endif
static void print_merged_iocbs(struct opioctx *ctx,
struct iocb **iocbs, int num_iocbs);
void
opio_free(struct opioctx *ctx)
{
free(ctx->opios);
ctx->opios = NULL;
free(ctx->free_opios);
ctx->free_opios = NULL;
free(ctx->iocb_queue);
ctx->iocb_queue = NULL;
free(ctx->event_queue);
ctx->event_queue = NULL;
}
int
opio_init(struct opioctx *ctx, int num_iocbs)
{
int i;
memset(ctx, 0, sizeof(struct opioctx));
ctx->num_opios = num_iocbs;
ctx->free_opio_cnt = num_iocbs;
ctx->opios = calloc(1, sizeof(struct opio) * num_iocbs);
ctx->free_opios = calloc(1, sizeof(struct opio *) * num_iocbs);
ctx->iocb_queue = calloc(1, sizeof(struct iocb *) * num_iocbs);
ctx->event_queue = calloc(1, sizeof(struct io_event) * num_iocbs);
if (!ctx->opios || !ctx->free_opios ||
!ctx->iocb_queue || !ctx->event_queue)
goto fail;
for (i = 0; i < num_iocbs; i++)
ctx->free_opios[i] = &ctx->opios[i];
return 0;
fail:
opio_free(ctx);
return -ENOMEM;
}
static inline struct opio *
alloc_opio(struct opioctx *ctx)
{
if (ctx->free_opio_cnt <= 0)
return NULL;
return ctx->free_opios[--ctx->free_opio_cnt];
}
static inline void
free_opio(struct opioctx *ctx, struct opio *op)
{
memset(op, 0, sizeof(struct opio));
ctx->free_opios[ctx->free_opio_cnt++] = op;
}
static inline void
restore_iocb(struct opio *op)
{
struct iocb *io = op->iocb;
io->data = op->data;
io->u.c.buf = op->buf;
io->u.c.nbytes = op->nbytes;
}
static inline int
iocb_optimized(struct opioctx *ctx, struct iocb *io)
{
unsigned long iop = (unsigned long)io->data;
unsigned long start = (unsigned long)ctx->opios;
unsigned long end = start + (ctx->num_opios * sizeof(struct opio));
return (iop >= start && iop < end);
}
static inline int
contiguous_sectors(struct iocb *l, struct iocb *r)
{
return (l->u.c.offset + l->u.c.nbytes == r->u.c.offset);
}
static inline int
contiguous_buffers(struct iocb *l, struct iocb *r)
{
return (l->u.c.buf + l->u.c.nbytes == r->u.c.buf);
}
static inline int
contiguous_iocbs(struct iocb *l, struct iocb *r)
{
return ((l->aio_fildes == r->aio_fildes) &&
contiguous_sectors(l, r) &&
contiguous_buffers(l, r));
}
static inline void
init_opio_list(struct opio *op)
{
op->list.head = op->list.tail = op;
}
static struct opio *
opio_iocb_init(struct opioctx *ctx, struct iocb *io)
{
struct opio *op;
op = alloc_opio(ctx);
if (!op)
return NULL;
op->buf = io->u.c.buf;
op->nbytes = io->u.c.nbytes;
op->offset = io->u.c.offset;
op->data = io->data;
op->iocb = io;
io->data = op;
init_opio_list(op);
return op;
}
static inline struct opio *
opio_get(struct opioctx *ctx, struct iocb *io)
{
if (iocb_optimized(ctx, io))
return (struct opio *)io->data;
else
return opio_iocb_init(ctx, io);
}
static int
merge_tail(struct opioctx *ctx, struct iocb *head, struct iocb *io)
{
struct opio *ophead, *opio;
ophead = opio_get(ctx, head);
if (!ophead)
return -ENOMEM;
opio = opio_get(ctx, io);
if (!opio)
return -ENOMEM;
opio->head = ophead;
head->u.c.nbytes += io->u.c.nbytes;
ophead->list.tail = ophead->list.tail->next = opio;
return 0;
}
static int
merge(struct opioctx *ctx, struct iocb *head, struct iocb *io)
{
if (head->aio_lio_opcode != io->aio_lio_opcode)
return -EINVAL;
if (!contiguous_iocbs(head, io))
return -EINVAL;
return merge_tail(ctx, head, io);
}
int
io_merge(struct opioctx *ctx, struct iocb **queue, int num)
{
int i, on_queue;
struct iocb *io, **q;
struct opio *ophead;
if (!num)
return 0;
on_queue = 0;
q = ctx->iocb_queue;
memcpy(q, queue, num * sizeof(struct iocb *));
for (i = 1; i < num; i++) {
io = q[i];
if (merge(ctx, queue[on_queue], io) != 0)
queue[++on_queue] = io;
}
#if (defined(TEST) || defined(DEBUG))
print_merged_iocbs(ctx, queue, on_queue + 1);
#endif
return ++on_queue;
}
static int
expand_iocb(struct opioctx *ctx, struct iocb **queue, struct iocb *io)
{
int idx;
struct opio *op, *next;
idx = 0;
op = (struct opio *)io->data;
while (op) {
next = op->next;
restore_iocb(op);
queue[idx++] = op->iocb;
free_opio(ctx, op);
op = next;
}
return idx;
}
int
io_expand_iocbs(struct opioctx *ctx, struct iocb **queue, int idx, int num)
{
int i, on_queue;
struct iocb *io, **q;
if (!num)
return 0;
on_queue = 0;
q = ctx->iocb_queue;
memcpy(q, queue, num * sizeof(struct iocb *));
for (i = idx; i < num; i++) {
io = q[i];
if (!iocb_optimized(ctx, io))
queue[on_queue++] = io;
else
on_queue += expand_iocb(ctx, queue + on_queue, io);
}
return on_queue;
}
static int
expand_event(struct opioctx *ctx,
struct io_event *event, struct io_event *queue, int idx)
{
int err;
struct iocb *io;
struct io_event *ep;
struct opio *ophead, *op, *next;
io = event->obj;
ophead = (struct opio *)io->data;
op = ophead;
if (event->res == io->u.c.nbytes)
err = 0;
else if ((int)event->res < 0)
err = (int)event->res;
else
err = -EIO;
while (op) {
next = op->next;
ep = &queue[idx++];
ep->obj = op->iocb;
ep->res = (err ? err : op->nbytes);
restore_iocb(op);
free_opio(ctx, op);
op = next;
}
return idx;
}
int
io_split(struct opioctx *ctx, struct io_event *events, int num)
{
int on_queue;
struct iocb *io;
struct io_event *ep, *q;
if (!num)
return 0;
on_queue = 0;
q = ctx->event_queue;
memcpy(q, events, num * sizeof(struct io_event));
for (ep = q; num-- > 0; ep++) {
io = ep->obj;
if (!iocb_optimized(ctx, io))
events[on_queue++] = *ep;
else
on_queue = expand_event(ctx, ep, events, on_queue);
}
return on_queue;
}
/******************************************************************************
debug print functions
******************************************************************************/
static inline void
__print_iocb(struct opioctx *ctx, struct iocb *io, char *prefix)
{
char *type;
type = (io->aio_lio_opcode == IO_CMD_PREAD ? "read" : "write");
DBG(ctx, "%soff: %08llx, nbytes: %04lx, buf: %p, type: %s, data: %08lx,"
" optimized: %d\n", prefix, io->u.c.offset, io->u.c.nbytes,
io->u.c.buf, type, (unsigned long)io->data,
iocb_optimized(ctx, io));
}
static char *null_prefix = "";
#define print_iocb(ctx, io) __print_iocb(ctx, io, null_prefix)
static void
print_iocbs(struct opioctx *ctx, struct iocb **iocbs, int num_iocbs)
{
int i;
char pref[10];
struct iocb *io;
DBG(ctx, "iocbs:\n");
for (i = 0; i < num_iocbs; i++) {
io = iocbs[i];
snprintf(pref, 10, "%d: ", i);
__print_iocb(ctx, io, pref);
}
}
static void
print_optimized_iocbs(struct opioctx *ctx, struct opio *op, int *cnt)
{
char pref[10];
while (op) {
snprintf(pref, 10, " %d: ", (*cnt)++);
__print_iocb(ctx, op->iocb, pref);
op = op->next;
}
}
static void
print_merged_iocbs(struct opioctx *ctx, struct iocb **iocbs, int num_iocbs)
{
int i, cnt;
char pref[10];
struct iocb *io;
struct opio *op;
DBG(ctx, "merged iocbs:\n");
for (i = 0, cnt = 0; i < num_iocbs; i++) {
io = iocbs[i];
snprintf(pref, 10, "%d: ", cnt++);
__print_iocb(ctx, io, pref);
if (iocb_optimized(ctx, io)) {
op = (struct opio *)io->data;
print_optimized_iocbs(ctx, op->next, &cnt);
}
}
}
static void
print_events(struct opioctx *ctx, struct io_event *events, int num_events)
{
int i;
struct iocb *io;
for (i = 0; i < num_events; i++) {
io = events[i].obj;
print_iocb(ctx, io);
}
}
/******************************************************************************
end debug print functions
******************************************************************************/
#if defined(TEST)
#define hmask 0x80000000UL
#define smask 0x40000000UL
#define make_data(idx, is_head, sparse) \
(void *)((idx) | ((is_head) ? hmask : 0) | ((sparse) ? smask : 0))
#define data_idx(data) (int)((unsigned long)(data) & (0x0fffffff))
#define data_is_head(data) (((unsigned long)(data) & hmask) ? 1 : 0)
#define data_is_sparse(data) (((unsigned long)(data) & smask) ? 1 : 0)
static void
usage(void)
{
fprintf(stderr, "usage: io_optimize [-n num_runs] "
"[-i num_iocbs] [-s num_secs] [-r random_seed]\n");
exit(-1);
}
static int xalloc_cnt, xfree_cnt;
static inline char *
xalloc(int size)
{
char *buf = malloc(size);
if (!buf) {
fprintf(stderr, "xalloc failed\n");
exit(ENOMEM);
}
xalloc_cnt++;
return buf;
}
static inline void
xfree(void *buf)
{
free(buf);
xfree_cnt++;
}
static void
randomize_iocbs(struct iocb **iocbs, int num_iocbs, int num_secs)
{
int i, j;
i = 0;
while (i < num_iocbs) {
char *buf;
short type;
int segs, sparse_mem;
uint64_t offset, nbytes;
type = (random() % 10 < 5 ? IO_CMD_PREAD : IO_CMD_PWRITE);
offset = ((random() % num_secs) << 9);
if (random() % 10 < 4) {
segs = 1;
nbytes = (((random() % 7) + 1) << 9);
} else {
segs = (random() % 10) + 1;
nbytes = 4096;
}
if (i + segs > num_iocbs)
segs = (num_iocbs - i);
sparse_mem = (random() % 10 < 2 ? 1 : 0);
if (sparse_mem)
buf = xalloc(nbytes);
else
buf = xalloc(segs * nbytes);
for (j = 0; j < segs; j++) {
struct iocb *io = iocbs[i + j];
io->aio_lio_opcode = type;
io->u.c.nbytes = nbytes;
io->u.c.offset = offset;
io->u.c.buf = buf;
offset += nbytes;
io->data = make_data(i + j, (j == 0), sparse_mem);
if (j + 1 < segs && sparse_mem)
buf = xalloc(nbytes);
else
buf += nbytes;
}
i += segs;
}
}
static int
simulate_io(struct iocb **iocbs, struct io_event *events, int num_iocbs)
{
int i, done;
struct iocb *io;
struct io_event *ep;
if (num_iocbs > 1)
done = (random() % (num_iocbs - 1)) + 1;
else
done = num_iocbs;
for (i = 0; i < done; i++) {
io = iocbs[i];
ep = &events[i];
ep->obj = io;
ep->res = (random() % 10 < 8 ? io->u.c.nbytes : 0);
}
return done;
}
static inline void
process_events(struct opioctx *ctx,
struct iocb *iocb_list, struct io_event *events, int num)
{
int i;
struct iocb *io;
for (i = 0; i < num; i++) {
io = events[i].obj;
print_iocb(ctx, io);
if (data_idx(io->data) != (io - iocb_list)) {
printf("corrupt data! data_idx = %d, io = %d\n",
data_idx(io->data), (io - iocb_list));
exit(-1);
}
if (data_is_head(io->data) || data_is_sparse(io->data))
xfree(io->u.c.buf);
memset(io, 0, sizeof(struct iocb));
}
}
static inline void
init_optest(struct iocb *iocb_list,
struct iocb **iocbs, struct io_event *events, int num)
{
int i;
memset(iocb_list, 0, num * sizeof(struct iocb));
memset(events, 0, num * sizeof(struct io_event));
for (i = 0; i < num; i++)
iocbs[i] = &iocb_list[i];
}
int
main(int argc, char **argv)
{
uint64_t num_secs;
struct opioctx ctx;
struct io_event *events;
int i, c, num_runs, num_iocbs, seed;
struct iocb *iocb_list, **iocbs, **ioqueue;
num_runs = 1;
num_iocbs = 300;
seed = time(NULL);
num_secs = ((4ULL << 20) >> 9); /* 4GB disk */
while ((c = getopt(argc, argv, "n:i:s:r:h")) != -1) {
switch (c) {
case 'n':
num_runs = atoi(optarg);
break;
case 'i':
num_iocbs = atoi(optarg);
break;
case 's':
num_secs = strtoull(optarg, NULL, 10);
break;
case 'r':
seed = atoi(optarg);
break;
case 'h':
usage();
case '?':
fprintf(stderr, "Unrecognized option: -%c\n", optopt);
usage();
}
}
printf("Running %d tests with %d iocbs on %llu sectors, seed = %d\n",
num_runs, num_iocbs, num_secs, seed);
srand(seed);
iocb_list = malloc(num_iocbs * sizeof(struct iocb));
iocbs = malloc(num_iocbs * sizeof(struct iocb *));
events = malloc(num_iocbs * sizeof(struct io_event));
if (!iocb_list || !iocbs || !events || opio_init(&ctx, num_iocbs)) {
fprintf(stderr, "initialization failed\n");
exit(ENOMEM);
}
for (i = 0; i < num_runs; i++) {
int op_rem, op_done, num_split, num_events, num_done;
ioqueue = iocbs;
init_optest(iocb_list, ioqueue, events, num_iocbs);
randomize_iocbs(ioqueue, num_iocbs, num_secs);
print_iocbs(&ctx, ioqueue, num_iocbs);
op_done = 0;
num_done = 0;
op_rem = io_merge(&ctx, ioqueue, num_iocbs);
print_iocbs(&ctx, ioqueue, op_rem);
print_merged_iocbs(&ctx, ioqueue, op_rem);
while (num_done < num_iocbs) {
DBG(&ctx, "optimized remaining: %d\n", op_rem);
DBG(&ctx, "simulating\n");
num_events = simulate_io(ioqueue + op_done, events, op_rem);
print_events(&ctx, events, num_events);
DBG(&ctx, "splitting %d\n", num_events);
num_split = io_split(&ctx, events, num_events);
print_events(&ctx, events, num_split);
DBG(&ctx, "processing %d\n", num_split);
process_events(&ctx, iocb_list, events, num_split);
op_rem -= num_events;
op_done += num_events;
num_done += num_split;
}
DBG(&ctx, "run %d: processed: %d, xallocs: %d, xfrees: %d\n",
i, num_done, xalloc_cnt, xfree_cnt);
if (xalloc_cnt != xfree_cnt)
exit(-1);
xalloc_cnt = xfree_cnt = 0;
}
free(iocbs);
free(events);
free(iocb_list);
opio_free(&ctx);
return 0;
}
#endif
-68
View File
@@ -1,68 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __IO_OPTIMIZE_H__
#define __IO_OPTIMIZE_H__
#include <libaio.h>
struct opio;
struct opio_list {
struct opio *head;
struct opio *tail;
};
struct opio {
char *buf;
unsigned long nbytes;
long long offset;
void *data;
struct iocb *iocb;
struct io_event event;
struct opio *head;
struct opio *next;
struct opio_list list;
};
struct opioctx {
int num_opios;
int free_opio_cnt;
struct opio *opios;
struct opio **free_opios;
struct iocb **iocb_queue;
struct io_event *event_queue;
};
int opio_init(struct opioctx *ctx, int num_iocbs);
void opio_free(struct opioctx *ctx);
int io_merge(struct opioctx *ctx, struct iocb **queue, int num);
int io_split(struct opioctx *ctx, struct io_event *events, int num);
int io_expand_iocbs(struct opioctx *ctx, struct iocb **queue, int idx, int num);
#endif
-102
View File
@@ -1,102 +0,0 @@
/*
* Copyright (c) 2010, XenSource Inc.
* All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; If not, see <http://www.gnu.org/licenses/>.
*/
/*
* kernel 2.6.21 added eventfd(2) support, kernel 2.6.22 eventfds for
* aio. libaio 0.3.107 updated the header file, but few systems have
* it. define a custom iocb_common struct instead, and work around a
* potentially missing sys/eventfd.h. this header should vanish over
* time.
*/
#ifndef __LIBAIO_COMPAT
#define __LIBAIO_COMPAT
#include "../../config.h"
#include <libaio.h>
#include <unistd.h>
#include <sys/syscall.h>
struct __compat_io_iocb_common {
char __pad_buf[8];
char __pad_nbytes[8];
long long offset;
long long __pad3;
unsigned flags;
unsigned resfd;
};
static inline void __io_set_eventfd(struct iocb *iocb, int eventfd)
{
struct __compat_io_iocb_common *c;
c = (struct __compat_io_iocb_common*)&iocb->u.c;
c->flags |= (1 << 0);
c->resfd = eventfd;
}
#ifdef HAVE_SYS_EVENTFD_H
#include <sys/eventfd.h>
static inline int tapdisk_sys_eventfd(int initval)
{
return eventfd(initval, 0);
}
#else /* Fallback */
#ifndef SYS_eventfd
#ifndef __NR_eventfd
# if defined(__alpha__)
# define __NR_eventfd 478
# elif defined(__arm__)
# define __NR_eventfd (__NR_SYSCALL_BASE+351)
# elif defined(__ia64__)
# define __NR_eventfd 1309
# elif defined(__i386__)
# define __NR_eventfd 323
# elif defined(__m68k__)
# define __NR_eventfd 319
# elif 0 && defined(__mips__)
# error __NR_eventfd?
# define __NR_eventfd (__NR_Linux + 319)
# define __NR_eventfd (__NR_Linux + 278)
# define __NR_eventfd (__NR_Linux + 282)
# elif defined(__hppa__)
# define __NR_eventfd (__NR_Linux + 304)
# elif defined(__PPC__) || defined(__powerpc64__)
# define __NR_eventfd 307
# elif defined(__s390__) || defined(__s390x__)
# define __NR_eventfd 318
# elif defined(__sparc__)
# define __NR_eventfd 313
# elif defined(__x86_64__)
# define __NR_eventfd 284
# endif
#else
# error __NR_eventfd?
#endif
#define SYS_eventfd __NR_eventfd
#endif
static inline int tapdisk_sys_eventfd(int initval)
{
return syscall(SYS_eventfd, initval, 0);
}
#endif
#endif /* __LIBAIO_COMPAT */
-1000
View File
@@ -1,1000 +0,0 @@
/*
* Copyright (c) 2007, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This module implements a "dot locking" style advisory file locking algorithm.
*/
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <dirent.h>
#include <limits.h>
#include "lock.h"
#define unlikely(x) __builtin_expect(!!(x), 0)
/* format: xenlk.hostname.uuid.<xf><rw>*/
#define LF_POSTFIX ".xenlk"
#define LFXL_FORMAT LF_POSTFIX ".%s.%s.x%s"
#define LFFL_FORMAT LF_POSTFIX ".%s.%s.f%s"
#define RETRY_MAX 16
#if defined(LOGS)
#define LOG(format, args...) printf("%d: ", __LINE__); printf(format, ## args)
#else
#define LOG(format, args...)
#endif
/* random wait - up to .5 seconds */
#define XSLEEP usleep(random() & 0x7ffff)
typedef int (*eval_func)(char *name, int readonly);
static char *create_lockfn(char *fn_to_lock)
{
char *lockfn;
/* allocate string to hold constructed lock file */
lockfn = malloc(strlen(fn_to_lock) + strlen(LF_POSTFIX) + 1);
if (unlikely(!lockfn)) {
return 0;
}
/* append postfix to file to lock */
strcpy(lockfn, fn_to_lock);
strcat(lockfn, LF_POSTFIX);
return lockfn;
}
static char *create_lockfn_link(char *fn_to_lock, char *format,
char *uuid, int readonly)
{
char hostname[128];
char *lockfn_link;
char *ptr;
/* get hostname */
if (unlikely(gethostname(hostname, sizeof(hostname)) == -1)) {
return 0;
}
/* allocate string to hold constructed lock file link */
lockfn_link = malloc(strlen(fn_to_lock) + strlen(LF_POSTFIX) +
strlen(hostname) + strlen(uuid) + 8);
if (unlikely(!lockfn_link)) {
return 0;
}
/* construct lock file link with specific format */
strcpy(lockfn_link, fn_to_lock);
ptr = lockfn_link + strlen(lockfn_link);
sprintf(ptr, format, hostname, uuid, readonly ? "r" : "w");
return lockfn_link;
}
static int NFSnormalizedStatTime(char *fn, struct stat *statnow, int *reterrno)
{
int result = LOCK_OK;
int uniq;
char *buf;
int fd;
int pid = (int)getpid();
int clstat;
*reterrno = 0;
/* create file to normalize time */
srandom((int)time(0) ^ pid);
uniq = random() % 0xffffff;
buf = malloc(strlen(fn) + 24);
if (unlikely(!buf)) { result = LOCK_ENOMEM; goto finish; }
strcpy(buf, fn);
sprintf(buf + strlen(buf), ".xen%08d.tmp", uniq);
fd = open(buf, O_WRONLY | O_CREAT, 0644);
if (fd == -1) { *reterrno = errno; result = LOCK_EOPEN; goto finish; }
clstat = close(fd);
if (unlikely(clstat == -1)) {
LOG("fail on close\n");
}
if (lstat(buf, statnow) == -1) {
unlink(buf);
*reterrno = errno;
result = LOCK_ESTAT;
goto finish;
}
unlink(buf);
finish:
return result;
}
static int writer_eval(char *name, int readonly)
{
return name[strlen(name)-1] == 'w';
}
static int reader_eval(char *name, int readonly)
{
return name[strlen(name)-1] == 'r' && !readonly;
}
static int lock_holder(char *fn, char *lockfn, char *lockfn_link,
int force, int readonly, int *stole, eval_func eval,
int *elt, int *ioerror)
{
int status = 0;
int ustat;
DIR *pd = 0;
struct dirent *dptr;
char *ptr;
char *dirname = malloc(strlen(lockfn));
char *uname = malloc(strlen(lockfn_link) + 8);
int elt_established = 0;
int fd;
char tmpbuf[4096];
*stole = 0;
*ioerror = 0;
*elt = 0;
if (!dirname) goto finish;
if (!uname) goto finish;
/* get directory */
ptr = strrchr(lockfn, '/');
if (!ptr) {
strcpy(dirname, ".");
} else {
int numbytes = ptr - lockfn;
strncpy(dirname, lockfn, numbytes);
dirname[numbytes] = '\0';
}
pd = opendir(dirname);
if (!pd) {
*ioerror = errno ? errno : EIO;
goto finish;
}
/*
* scan through directory entries and use eval function
* if we have a match (i.e. reader or writer lock) but
* note that if we are forcing, we will remove any and
* all locks that appear for target of our lock, regardless
* if it a reader/writer owns the lock.
*/
errno = 0;
dptr = readdir(pd);
if (!dptr) {
*ioerror = EIO;
}
while (dptr) {
char *p1 = strrchr(fn, '/');
char *p2 = strrchr(lockfn, '/');
char *p3 = strrchr(lockfn_link, '/');
if (p1) p1+=1;
if (p2) p2+=1;
if (p3) p3+=1;
if (strcmp(dptr->d_name, p1 ? p1 : fn) &&
strcmp(dptr->d_name, p2 ? p2 : lockfn) &&
strcmp(dptr->d_name, p3 ? p3 : lockfn_link) &&
!strncmp(dptr->d_name, p1 ? p1 : fn, strlen(p1?p1:fn))) {
strcpy(uname, dirname);
strcat(uname, "/");
strcat(uname, dptr->d_name);
if (!elt_established) {
/* read final lock file and extract lease time */
fd = open(uname, O_RDONLY, 0644);
memset(tmpbuf, 0, sizeof(tmpbuf));
if (read(fd, tmpbuf, sizeof(tmpbuf)) < 0) {
*ioerror = errno;
status = 1;
close(fd);
goto finish;
}
close(fd);
ptr = strrchr(tmpbuf, '.');
if (ptr) {
*elt = atoi(ptr+1);
elt_established = 1;
}
}
if (force) {
ustat = unlink(uname);
if (ustat == -1) {
LOG("failed to unlink %s\n", uname);
}
*stole = 1;
*elt = 0;
} else {
if ((*eval)(dptr->d_name, readonly)) {
closedir(pd);
status = 1;
goto finish;
}
}
}
dptr = readdir(pd);
if (!dptr && errno) {
*ioerror = EIO;
}
}
closedir(pd);
finish:
free(dirname);
free(uname);
/* if IO error, force a taken status */
return (*ioerror) ? 1 : status;
}
int lock(char *fn_to_lock, char *uuid, int force, int readonly, int *lease_time, int *retstatus)
{
char *lockfn = 0;
char *lockfn_xlink = 0;
char *lockfn_flink = 0;
char *buf = 0;
int fd;
int status = 0;
struct stat stat1, stat2;
int retry_attempts = 0;
int clstat;
int tmpstat;
int stealx = 0;
int stealw = 0;
int stealr = 0;
int established_lease_time = 0;
char tmpbuf[4096];
int ioerr;
if (!fn_to_lock || !uuid) {
*retstatus = LOCK_EBADPARM;
return EINVAL;
}
*retstatus = 0;
/* seed random with time/pid combo */
srandom((int)time(0) ^ getpid());
/* build lock file strings */
lockfn = create_lockfn(fn_to_lock);
if (unlikely(!lockfn)) { status = ENOMEM; *retstatus = LOCK_ENOMEM; goto finish; }
lockfn_xlink = create_lockfn_link(fn_to_lock, LFXL_FORMAT,
uuid, readonly);
if (unlikely(!lockfn_xlink)) { status = ENOMEM; *retstatus = LOCK_ENOMEM; goto finish; }
lockfn_flink = create_lockfn_link(fn_to_lock, LFFL_FORMAT, uuid,
readonly);
if (unlikely(!lockfn_flink)) { status = ENOMEM; *retstatus = LOCK_ENOMEM; goto finish; }
try_again:
if (retry_attempts++ > RETRY_MAX) {
if (*retstatus == LOCK_EXLOCK_OPEN) {
struct stat statnow, stat_exlock;
int diff;
if (lstat(lockfn, &stat_exlock) == -1) {
goto finish;
}
if (NFSnormalizedStatTime(fn_to_lock, &statnow, &ioerr)) {
goto finish;
}
diff = (int)statnow.st_mtime - (int)stat_exlock.st_mtime;
if (diff > DEFAULT_LEASE_TIME_SECS) {
unlink(lockfn);
retry_attempts = 0;
goto try_again;
}
}
goto finish;
}
/* try to open exlusive lockfile */
fd = open(lockfn, O_WRONLY | O_CREAT | O_EXCL, 0644);
if (fd == -1) {
LOG("Initial lockfile creation failed %s force=%d, errno=%d\n",
lockfn, force, errno);
if (errno == EIO) {
*retstatus = LOCK_EXLOCK_OPEN;
status = EIO;
goto finish;
}
/* already owned? (hostname & uuid match, skip time bits) */
errno = 0;
fd = open(lockfn, O_RDWR, 0644);
if (fd != -1) {
buf = malloc(strlen(lockfn_xlink)+1);
if (!buf) {
clstat = close(fd);
if (unlikely(clstat == -1)) {
LOG("fail on close\n");
}
*retstatus = LOCK_ENOMEM;
status = ENOMEM;
goto finish;
}
if (read(fd, buf, strlen(lockfn_xlink)) !=
(strlen(lockfn_xlink))) {
clstat = close(fd);
if (unlikely(clstat == -1)) {
LOG("fail on close\n");
}
free(buf);
goto force_lock;
}
if (!strncmp(buf, lockfn_xlink, strlen(lockfn_xlink)-1)) {
LOG("lock owned by us, reasserting\n");
/* our lock, reassert by rewriting below */
if (lseek(fd, 0, SEEK_SET) == -1) {
clstat = close(fd);
if (unlikely(clstat == -1)) {
LOG("fail on close\n");
}
goto force_lock;
}
free(buf);
goto skip;
}
free(buf);
clstat = close(fd);
if (unlikely(clstat == -1)) {
LOG("fail on close\n");
}
}
force_lock:
if (errno == EIO) {
*retstatus = LOCK_EXLOCK_OPEN;
status = EIO;
goto finish;
}
if (force) {
/* remove lock file, we are forcing lock, try again */
status = unlink(lockfn);
if (unlikely(status == -1)) {
if (errno == EIO) {
*retstatus = LOCK_EXLOCK_OPEN;
status = EIO;
goto finish;
}
LOG("force removal of %s lockfile failed, "
"errno=%d, trying again\n", lockfn, errno);
}
stealx = 1;
}
XSLEEP;
*retstatus = LOCK_EXLOCK_OPEN;
goto try_again;
}
LOG("lockfile created %s\n", lockfn);
skip:
/*
* write into the temporary xlock
*/
if (write(fd, lockfn_xlink, strlen(lockfn_xlink)) !=
strlen(lockfn_xlink)) {
if (errno == EIO) {
*retstatus = LOCK_EXLOCK_WRITE;
status = EIO;
goto finish;
}
status = errno;
clstat = close(fd);
if (unlikely(clstat == -1)) {
LOG("fail on close\n");
}
XSLEEP;
*retstatus = LOCK_EXLOCK_WRITE;
if (unlink(lockfn) == -1) {
LOG("removal of %s lockfile failed, "
"errno=%d, trying again\n", lockfn, errno);
}
goto try_again;
}
clstat = close(fd);
if (unlikely(clstat == -1)) {
LOG("fail on close\n");
}
while (retry_attempts++ < RETRY_MAX) {
tmpstat = link(lockfn, lockfn_xlink);
LOG("linking %s and %s\n", lockfn, lockfn_xlink);
if ((tmpstat == -1) && (errno != EEXIST)) {
LOG("link status is %d, errno=%d\n", tmpstat, errno);
}
if ((lstat(lockfn, &stat1) == -1) ||
(lstat(lockfn_xlink, &stat2) == -1)) {
/* try again, cleanup first */
tmpstat = unlink(lockfn);
if (unlikely(tmpstat == -1)) {
LOG("error removing lock file %s", lockfn);
}
tmpstat = unlink(lockfn_xlink);
if (unlikely(tmpstat == -1)) {
LOG("error removing linked lock file %s",
lockfn_xlink);
}
XSLEEP;
status = LOCK_ESTAT;
goto finish;
}
/* compare inodes */
if (stat1.st_ino == stat2.st_ino) {
/* success, inodes are the same */
/* should we check that st_nlink's are also 2?? */
*retstatus = LOCK_OK;
status = 0;
tmpstat = unlink(lockfn_xlink);
if (unlikely(tmpstat == -1)) {
LOG("error removing linked lock file %s",
lockfn_xlink);
}
goto finish;
} else {
status = errno;
/* try again, cleanup first */
tmpstat = unlink(lockfn);
if (unlikely(tmpstat == -1)) {
LOG("error removing lock file %s", lockfn);
}
tmpstat = unlink(lockfn_xlink);
if (unlikely(tmpstat == -1)) {
LOG("error removing linked lock file %s",
lockfn_xlink);
}
XSLEEP;
*retstatus = LOCK_EINODE;
goto try_again;
}
}
finish:
if (!*retstatus) {
/* we have exclusive lock */
status = 0;
/* fast check, see if we own a final lock and are reasserting */
if (!lstat(lockfn_flink, &stat1)) {
char *ptr;
/* set the return value to notice this is a reassert */
*retstatus = 1;
/* read existing lock file and extract
established lease time */
fd = open(lockfn_flink, O_RDONLY, 0644);
memset(tmpbuf, 0, sizeof(tmpbuf));
if (read(fd, tmpbuf, sizeof(tmpbuf)) < 0) {
if (errno == EIO) {
close(fd);
*retstatus = LOCK_EINODE;
status = EIO;
goto skip_scan;
}
}
close(fd);
ptr = strrchr(tmpbuf, '.');
if (ptr) {
*lease_time = atoi(ptr+1);
} else {
*lease_time = 10; /* wkchack */
}
goto skip_scan;
} else {
if (errno == EIO) {
*retstatus = LOCK_EINODE;
status = EIO;
goto skip_scan;
}
}
/* we allow exclusive writer, or multiple readers */
if (lock_holder(fn_to_lock, lockfn, lockfn_flink, force,
readonly, &stealw, writer_eval,
&established_lease_time, &ioerr)) {
if (ioerr) {
*retstatus = LOCK_EREAD;
status = ioerr;
goto skip_scan;
}
*retstatus = LOCK_EHELD_WR;
} else if (lock_holder(fn_to_lock, lockfn, lockfn_flink, force,
readonly, &stealr, reader_eval,
&established_lease_time, &ioerr)) {
if (ioerr) {
*retstatus = LOCK_EREAD;
status = ioerr;
goto skip_scan;
}
*retstatus = LOCK_EHELD_RD;
}
if (established_lease_time) *lease_time =
established_lease_time;
}
skip_scan:
if (*retstatus >= 0) {
/* update file, changes last modify time */
fd = open(lockfn_flink, O_WRONLY | O_CREAT, 0644);
if (fd == -1) {
*retstatus = LOCK_EOPEN;
status = errno;
} else {
char tmpbuf[32];
int failed_write;
memset(tmpbuf, 0, sizeof(tmpbuf));
sprintf(tmpbuf, ".%d", *lease_time);
failed_write = write(fd, lockfn_flink,
strlen(lockfn_flink)) !=
strlen(lockfn_flink);
if (failed_write) status = errno;
failed_write |= write(fd, tmpbuf, strlen(tmpbuf)) !=
strlen(tmpbuf);
if (failed_write) status = errno;
if (failed_write) {
clstat = close(fd);
if (unlikely(clstat == -1)) {
LOG("fail on close\n");
}
XSLEEP;
*retstatus = LOCK_EUPDATE;
goto try_again;
}
}
clstat = close(fd);
if (unlikely(clstat == -1)) {
LOG("fail on close\n");
}
}
if (!*retstatus && force && (stealx || stealw || stealr)) {
struct timeval timeout;
/* enforce quiet time on steal */
timeout.tv_sec = *lease_time;
timeout.tv_usec = 0;
select(0, 0, 0, 0, &timeout);
}
/* remove exclusive lock, final read/write locks will hold */
tmpstat = unlink(lockfn);
if (unlikely(tmpstat == -1)) {
LOG("error removing exclusive lock file %s",
lockfn);
}
free(lockfn);
free(lockfn_xlink);
free(lockfn_flink);
/* set lease time to -1 if error, so no one is apt to use it */
if (*retstatus < 0) *lease_time = -1;
LOG("returning status %d, errno=%d\n", status, errno);
return status;
}
int unlock(char *fn_to_unlock, char *uuid, int readonly, int *status)
{
char *lockfn_link = 0;
int reterrno = 0;
if (!fn_to_unlock || !uuid) {
*status = LOCK_EBADPARM;
return 0;
}
lockfn_link = create_lockfn_link(fn_to_unlock, LFFL_FORMAT, uuid,
readonly);
if (unlikely(!lockfn_link)) { *status = LOCK_ENOMEM; goto finish; }
if (unlink(lockfn_link) == -1) {
LOG("error removing linked lock file %s", lockfn_link);
reterrno = errno;
*status = LOCK_ENOLOCK;
goto finish;
}
*status = LOCK_OK;
finish:
free(lockfn_link);
return reterrno;
}
int lock_delta(char *fn, int *ret_lease, int *max_lease)
{
int reterrno = 0;
DIR *pd = 0;
struct dirent *dptr;
char *ptr;
int result = INT_MAX;
struct stat statbuf, statnow;
char *dirname = malloc(strlen(fn));
char *uname = malloc(strlen(fn) + 8);
int elt_established = 0;
char *dotptr;
char tmpbuf[4096];
int fd;
if (!fn || !dirname || !uname) {
*ret_lease = LOCK_EBADPARM;
*max_lease = -1;
return 0;
}
if (NFSnormalizedStatTime(fn, &statnow, &reterrno)) {
result = LOCK_ESTAT;
goto finish;
}
/* get directory */
ptr = strrchr(fn, '/');
if (!ptr) {
strcpy(dirname, ".");
ptr = fn;
} else {
int numbytes = ptr - fn;
strncpy(dirname, fn, numbytes);
ptr += 1;
}
pd = opendir(dirname);
if (!pd) { reterrno = errno; goto finish; }
dptr = readdir(pd);
while (dptr) {
if (strcmp(dptr->d_name, ptr) &&
!strncmp(dptr->d_name, ptr, strlen(ptr))) {
char *fpath = malloc(strlen(dptr->d_name) +
strlen(dirname) + 2);
if (!fpath) {
closedir(pd);
result = LOCK_ENOMEM;
goto finish;
}
strcpy(fpath, dirname);
strcat(fpath, "/");
strcat(fpath, dptr->d_name);
if (lstat(fpath, &statbuf) != -1) {
int diff = (int)statnow.st_mtime -
(int)statbuf.st_mtime;
/* adjust diff if someone updated the lock
between now and when we created the "now"
file
*/
diff = (diff < 0) ? 0 : diff;
result = diff < result ? diff : result;
} else {
closedir(pd);
reterrno = errno;
goto finish;
}
if (!elt_established) {
/* read final lock file and extract lease time */
fd = open(fpath, O_RDONLY, 0644);
memset(tmpbuf, 0, sizeof(tmpbuf));
if (read(fd, tmpbuf, sizeof(tmpbuf)) < 0) {
/* error on read? */
}
close(fd);
dotptr = strrchr(tmpbuf, '.');
if (dotptr) {
*max_lease = atoi(dotptr+1);
elt_established = 1;
}
}
free(fpath);
}
dptr = readdir(pd);
}
closedir(pd);
finish:
free(dirname);
free(uname);
/* returns smallest lock time, or error */
if (result == INT_MAX) result = LOCK_ENOLOCK;
/* set lease time to -1 if error, so no one is apt to use it */
if ((result < 0) || reterrno) *max_lease = -1;
*ret_lease = result;
return reterrno;
}
#if defined(TEST)
/*
* the following is for sanity testing.
*/
static void usage(char *prg)
{
printf("usage %s\n"
" dtr <filename>]\n"
" p <filename> [num iterations]\n"
" u <filename> [0|1] [<uniqid>]\n"
" l <filename> [0|1] [0|1] [<uniqid>] [<leasetime>]\n", prg);
printf(" p : perf test lock take and reassert\n");
printf(" d : delta lock time\n");
printf(" t : test the file (after random locks)\n");
printf(" r : random lock tests (must ^C)\n");
printf(" u : unlock, readonly? uniqID (default is PID)\n");
printf(" l : lock, readonly? force?, uniqID (default is PID), lease time\n");
}
static void test_file(char *fn)
{
FILE *fptr;
int prev_count = 0;
int count, pid, time;
fptr = fopen(fn, "r");
if (!fptr) {
LOG("ERROR on file %s open, errno=%d\n", fn, errno);
return;
}
while (!feof(fptr)) {
fscanf(fptr, "%d %d %d\n", &count, &pid, &time);
if (prev_count != count) {
LOG("ERROR: prev_count=%d, count=%d, pid=%d, time=%d\n",
prev_count, count, pid, time);
}
prev_count = count + 1;
}
}
static void random_locks(char *fn)
{
int pid = getpid();
int status;
char *filebuf = malloc(256);
int count = 0;
int dummy;
int clstat;
char uuid[12];
int readonly;
int lease = DEFAULT_LEASE_TIME_SECS;
int err;
/* this will never return, kill to exit */
srandom((int)time(0) ^ pid);
LOG("pid: %d using file %s\n", pid, fn);
sprintf(uuid, "%08d", pid);
while (1) {
XSLEEP;
readonly = random() & 1;
sysstatus = lock(fn, uuid, 0, readonly, &lease, status);
if (status == LOCK_OK) {
/* got lock, open, read, modify write close file */
int fd = open(fn, O_RDWR, 0644);
if (fd == -1) {
LOG("pid: %d ERROR on file %s open, errno=%d\n",
pid, fn, errno);
} else {
if (!readonly) {
/* ugly code to read data in test format */
/* format is "%d %d %d" 'count pid time' */
struct stat statbuf;
int bytes;
status = stat(fn, &statbuf);
if (status != -1) {
if (statbuf.st_size > 256) {
lseek(fd, -256, SEEK_END);
}
memset(filebuf, 0, 256);
bytes = read(fd, filebuf, 256);
if (bytes) {
int bw = bytes-2;
while (bw && filebuf[bw]!='\n')
bw--;
if (!bw) bw = -1;
sscanf(&filebuf[bw+1],
"%d %d %d",
&count, &dummy, &dummy);
count += 1;
}
lseek(fd, 0, SEEK_END);
sprintf(filebuf, "%d %d %d\n",
count, pid, (int)time(0));
write(fd, filebuf, strlen(filebuf));
} else {
LOG("pid: %d ERROR on file %s stat, "
"errno=%d\n", pid, fn, errno);
}
}
clstat = close(fd);
if (unlikely(clstat == -1)) {
LOG("fail on close\n");
}
}
XSLEEP;
err = unlock(fn, uuid, readonly, &status);
LOG("unlock status is %d (err=%d)\n", status, err);
}
}
}
static void perf_lock(char *fn, int loops)
{
int sysstatus;
char buf[9];
int start = loops;
int lease = DEFAULT_LEASE_TIME_SECS;
sprintf(buf, "%08d", getpid());
while (loops--) {
sysstatus = lock(fn, buf, 0, 0, &lease, &status);
if (status < 0) {
printf("failed to get lock at iteration %d errno=%d\n",
start - loops, errno);
return;
}
}
unlock(fn, buf, 0, &status);
}
int main(int argc, char *argv[])
{
int status;
char *ptr;
char uuid[12];
int force;
int readonly;
int max_lease, cur_lease;
int intstatus;
int lease = DEFAULT_LEASE_TIME_SECS;
if (argc < 3) {
usage(argv[0]);
return 0;
}
sprintf(uuid, "%08d", getpid());
ptr = uuid;
if (!strcmp(argv[1],"d")) {
status = lock_delta(argv[2], &cur_lease, &max_lease);
printf("lock delta for %s is %d seconds, max lease is %d\n",
argv[2], cur_lease, max_lease);
} else if (!strcmp(argv[1],"t")) {
test_file(argv[2]);
} else if (!strcmp(argv[1],"r")) {
random_locks(argv[2]);
} else if (!strcmp(argv[1],"p")) {
perf_lock(argv[2], argc < 3 ? 100000 : atoi(argv[3]));
} else if (!strcmp(argv[1],"l")) {
if (argc < 4) force = 0; else force = atoi(argv[3]);
if (argc < 5) readonly = 0; else readonly = atoi(argv[4]);
if (argc >= 6) ptr = argv[5];
if (argc == 7) lease = atoi(argv[6]);
status = lock(argv[2], ptr, readonly, force, &lease, &intstatus);
printf("lock status = %d\n", status);
} else if (!strcmp(argv[1],"u") ) {
if (argc < 5) readonly = 0; else readonly = atoi(argv[3]);
if (argc == 5) ptr = argv[4];
status = unlock(argv[2], ptr, readonly, &intstatus);
printf("unlock status = %d\n", intstatus);
} else {
usage(argv[0]);
}
return status;
}
#elif defined(UTIL)
/*
* the following is used for non-libary, standalone
* program utility as a shell program
*/
static void usage(char *prg)
{
printf("usage %s\n"
" delta <filename>\n"
" unlock <filename> <r|w> <uniqid>\n"
" lock <filename> <r|w> <0|1> <uniqid> <leasetime>\n", prg);
printf(" delta : get time since lock last refreshed\n");
printf(" returns delta time and max lease time in seconds\n");
printf(" unlock: unlock request filename, r|w, uniqID\n");
printf(" returns status (success is 0)\n");
printf(" lock : lock request filename, r|w, force?, uniqID, lease time request\n");
printf(" returns status (success is 0) and established lease time in seconds\n");
}
int main(int argc, char *argv[])
{
int status = 0;
int dlock;
char *ptr;
int force;
int readonly;
int cur_lease, max_lease, intstatus;
int lease = DEFAULT_LEASE_TIME_SECS;
if (argc < 3) {
if (argc == 2 && !strcmp(argv[1], "-h")) {
usage(argv[0]);
} else {
printf("%d\n", LOCK_EUSAGE);
}
return 0;
}
if (!strcmp(argv[1],"delta") && (argc == 3)) {
status = lock_delta(argv[2], &cur_lease, &max_lease);
printf("%d %d\n", cur_lease, max_lease);
} else if (!strcmp(argv[1],"lock") && (argc == 7)) {
readonly = (strcmp(argv[3], "r") == 0) ? 1 : 0;
force = atoi(argv[4]);
ptr = argv[5];
lease = atoi(argv[6]);
status = lock(argv[2], ptr, force, readonly, &lease, &intstatus);
printf("%d %d\n", intstatus, lease);
} else if (!strcmp(argv[1],"unlock") && (argc == 5)) {
readonly = (strcmp(argv[3], "r") == 0) ? 1 : 0;
ptr = argv[4];
status = unlock(argv[2], ptr, readonly, &intstatus);
printf("%d\n", intstatus);
} else {
printf("%d\n", LOCK_EUSAGE);
}
/* this is either 0 or a system defined errno */
return status;
}
#endif
-51
View File
@@ -1,51 +0,0 @@
/*
* Copyright (c) 2007, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define DEFAULT_LEASE_TIME_SECS 30
int lock(char *fn_to_lock, char *uuid, int force, int readonly, int *lease_time, int *retstat);
int unlock(char *fn_to_unlock, char *uuid, int readonly, int *retstat);
int lock_delta(char *fn_to_check, int *cur_lease_time, int *max_lease_time);
typedef enum {
LOCK_OK = 0,
LOCK_EBADPARM = -1,
LOCK_ENOMEM = -2,
LOCK_ESTAT = -3,
LOCK_EHELD_WR = -4,
LOCK_EHELD_RD = -5,
LOCK_EOPEN = -6,
LOCK_EXLOCK_OPEN = -7,
LOCK_EXLOCK_WRITE= -8,
LOCK_EINODE = -9,
LOCK_EUPDATE = -10,
LOCK_EREAD = -11,
LOCK_EREMOVE = -12,
LOCK_ENOLOCK = -13,
LOCK_EUSAGE = -14,
} lock_error;
-123
View File
@@ -1,123 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* log.h: API for writelog communication */
#ifndef __LOG_H__
#define __LOG_H__ 1
#include <inttypes.h>
#include <xen/io/ring.h>
/* for wmb et al */
#include <xenctrl.h>
#define LOGCMD_SHMP "shmp"
#define LOGCMD_PEEK "peek"
#define LOGCMD_CLEAR "clrw"
#define LOGCMD_GET "getw"
#define LOGCMD_KICK "kick"
#define CTLRSPLEN_SHMP 256
#define CTLRSPLEN_PEEK 4
#define CTLRSPLEN_CLEAR 4
#define CTLRSPLEN_GET 4
#define CTLRSPLEN_KICK 0
/* shmregion is arbitrarily capped at 8 megs for a minimum of
* 64 MB of data per read (if there are no contiguous regions)
* In the off-chance that there is more dirty data, multiple
* reads must be done */
#define SHMSIZE (8 * 1024 * 1024)
#define SRINGSIZE 4096
/* The shared memory region is split up into 3 subregions:
* The first half is reserved for the dirty bitmap log.
* The second half begins with 1 page for read request descriptors,
* followed by a big area for supplying read data.
*/
static inline void* bmstart(void* shm)
{
return shm;
}
static inline void* bmend(void* shm)
{
return shm + SHMSIZE/2;
}
static inline void* sringstart(void* shm)
{
return bmend(shm);
}
static inline void* sdatastart(void* shm)
{
return sringstart(shm) + SRINGSIZE;
}
static inline void* sdataend(void* shm)
{
return shm + SHMSIZE;
}
/* format for messages between log client and server */
struct log_ctlmsg {
char msg[4];
char params[16];
};
/* extent descriptor */
struct disk_range {
uint64_t sector;
uint32_t count;
};
/* dirty write logging space. This is an extent ring at the front,
* full of disk_ranges plus a pointer into the data area */
/* I think I'd rather have the header in front of each data section to
* avoid having two separate spaces that can run out, but then I'd either
* lose page alignment on the data blocks or spend an entire page on the
* header */
struct log_extent {
uint64_t sector;
uint32_t count;
uint32_t offset; /* offset from start of data area to start of extent */
};
/* struct above should be 16 bytes, or 256 extents/page */
typedef struct log_extent log_request_t;
typedef struct log_extent log_response_t;
DEFINE_RING_TYPES(log, log_request_t, log_response_t);
#define LOG_HEADER_PAGES 4
#endif
-278
View File
@@ -1,278 +0,0 @@
/* start - public domain MD5 implementation */
/*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
#include <string.h>
#include <stdint.h>
struct MD5Context {
uint32_t buf[4];
uint32_t bits[2];
uint8_t in[64];
};
static void MD5Init(struct MD5Context *context);
static void MD5Update(struct MD5Context *context, unsigned char const *buf,
unsigned len);
static void MD5Final(unsigned char digest[16], struct MD5Context *context);
static void MD5Transform(uint32_t buf[4], uint32_t const in[16]);
typedef struct MD5Context MD5_CTX;
/**
* md5_sum - MD5 hash for a data block
* @addr: Pointers to the data area
* @len: Lengths of the data block
* @mac: Buffer for the hash
*/
void md5_sum(const uint8_t *addr, const size_t len, uint8_t *mac)
{
MD5_CTX ctx;
MD5Init(&ctx);
MD5Update(&ctx, addr, len);
MD5Final(mac, &ctx);
}
#ifndef WORDS_BIGENDIAN
#define byteReverse(buf, len) /* Nothing */
#else
/*
* Note: this code is harmless on little-endian machines.
*/
static void byteReverse(unsigned char *buf, unsigned longs)
{
uint32_t t;
do {
t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
*(uint32_t *) buf = t;
buf += 4;
} while (--longs);
}
#endif
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
void MD5Init(struct MD5Context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
{
uint32_t t;
/* Update bitcount */
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if (t) {
unsigned char *p = (unsigned char *) ctx->in + t;
t = 64 - t;
if (len < t) {
memcpy(p, buf, len);
return;
}
memcpy(p, buf, t);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32_t *) ctx->in);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64) {
memcpy(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32_t *) ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memcpy(ctx->in, buf, len);
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
{
unsigned count;
unsigned char *p;
/* Compute number of bytes mod 64 */
count = (ctx->bits[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32_t *) ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
} else {
/* Pad block to 56 bytes */
memset(p, 0, count - 8);
}
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
((uint32_t *) ctx->in)[14] = ctx->bits[0];
((uint32_t *) ctx->in)[15] = ctx->bits[1];
MD5Transform(ctx->buf, (uint32_t *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
}
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void MD5Transform(uint32_t buf[4], uint32_t const in[16])
{
register uint32_t a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
-15
View File
@@ -1,15 +0,0 @@
#ifndef MD5_H
#define MD5_H
#include <stdint.h>
#include <stddef.h>
/**
* md5_sum - MD5 hash for a data block
* @addr: Pointers to the data area
* @len: Lengths of the data block
* @mac: Buffer for the hash
*/
void md5_sum(const uint8_t *addr, const size_t len, uint8_t *mac);
#endif
-191
View File
@@ -1,191 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __TAP_PROFILE_H__
#define __TAP_PROFILE_H__
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <syslog.h>
#include <sys/time.h>
#include <time.h>
#include <fcntl.h>
#include <inttypes.h>
//#define PROFILING
//#define LOGGING
#define TAPPROF_IN 1
#define TAPPROF_OUT 2
struct profile_times {
char *fn_name;
uint64_t in, out_sum, cnt;
};
struct profile_info {
FILE *log;
int size;
char *name;
unsigned long long seq;
struct profile_times *pt;
};
#ifdef PROFILING
static inline void
tp_open(struct profile_info *prof, char *tap_name, char *log_name, int size)
{
memset(prof, 0, sizeof(struct profile_info));
#ifdef LOGGING
prof->log = fopen(log_name, "w");
#endif
prof->size = size;
prof->name = strdup(tap_name);
prof->pt = malloc(sizeof(struct profile_times) * prof->size);
if (prof->pt)
memset(prof->pt, 0, sizeof(struct profile_times) * prof->size);
}
static inline void
tp_close(struct profile_info *prof)
{
int i;
struct profile_times *pt;
for (i = 0; i < prof->size; i++) {
pt = &prof->pt[i];
if (pt->fn_name) {
syslog(LOG_DEBUG, "%s: %s: cnt: %llu, avg time: %llu\n",
prof->name, pt->fn_name, pt->cnt,
((pt->cnt) ? (pt->out_sum / pt->cnt) : 0));
free(pt->fn_name);
}
}
#ifdef LOGGING
if (prof->log)
fclose(prof->log);
#endif
free(prof->name);
if (prof->pt)
free(prof->pt);
}
static inline u64
tp_get_id(struct profile_info *prof)
{
return prof->seq++;
}
static inline int
tp_fn_id(struct profile_info *prof, const char *name)
{
int i;
struct profile_times *pt;
for (i = 0; i < prof->size; i++) {
pt = &prof->pt[i];
if (!pt->fn_name)
return i;
if (!strcmp(pt->fn_name, name))
return i;
}
return prof->size - 1;
}
static inline void
__tp_in(struct profile_info *prof, const char *func)
{
long long _time;
int idx = tp_fn_id(prof, func);
struct profile_times *pt = &prof->pt[idx];
if (!pt->fn_name)
pt->fn_name = strdup(func);
asm volatile(".byte 0x0f, 0x31" : "=A" (_time));
pt->in = _time;
}
#define tp_in(prof) __tp_in(prof, __func__)
static inline void
__tp_out(struct profile_info *prof, const char *func)
{
long long _time;
int idx = tp_fn_id(prof, func);
struct profile_times *pt = &prof->pt[idx];
if (!pt->fn_name || !pt->in)
return;
asm volatile(".byte 0x0f, 0x31" : "=A" (_time));
pt->cnt++;
pt->out_sum += (_time - pt->in);
pt->in = 0;
}
#define tp_out(prof) __tp_out(prof, __func__)
static inline void
__tp_log(struct profile_info *prof, u64 id, const char *func, int direction)
{
long long _time;
asm volatile(".byte 0x0f, 0x31" : "=A" (_time));
if (direction == TAPPROF_IN)
__tp_in(prof, func);
else
__tp_out(prof, func);
#ifdef LOGGING
if (prof->log)
fprintf(prof->log, "%s: %s: %llu, %lld\n", func,
((direction == TAPPROF_IN) ? "in" : "out"), id, _time);
#endif
}
#define tp_log(prof, id, direction) __tp_log(prof, id, __func__, direction)
#else
#define tp_open(prof, tname, lname, size) ((void)0)
#define tp_close(prof) ((void)0)
#define tp_in(prof) ((void)0)
#define tp_out(prof) ((void)0)
#define tp_log(prof, sec, direction) ((void)0)
#endif
#endif
-121
View File
@@ -1,121 +0,0 @@
/* qcow-create.c
*
* Generates a qcow format disk.
*
* (c) 2006 Andrew Warfield and Julian Chesterfield
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation; or, when distributed
* separately from the Linux kernel or incorporated into other
* software packages, subject to the following license:
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this source file (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/statvfs.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <string.h>
#include "tapdisk.h"
#include "qcow.h"
#if 1
#define DFPRINTF(_f, _a...) fprintf ( stderr, _f , ## _a )
#else
#define DFPRINTF(_f, _a...) ((void)0)
#endif
#define MAX_NAME_LEN 1000
void help(void)
{
fprintf(stderr, "Qcow-utils: v1.0.0\n");
fprintf(stderr,
"usage: qcow-create [-h help] [-r reserve] <SIZE(MB)> <FILENAME> "
"[<BACKING_FILENAME>]\n");
exit(-1);
}
int main(int argc, char *argv[])
{
int ret = -1, c, backed = 0;
int sparse = 1;
uint64_t size;
char filename[MAX_NAME_LEN], bfilename[MAX_NAME_LEN];
for(;;) {
c = getopt(argc, argv, "hr");
if (c == -1)
break;
switch(c) {
case 'h':
help();
exit(0);
break;
case 'r':
sparse = 0;
break;
default:
fprintf(stderr, "Unknown option\n");
help();
}
}
printf("Optind %d, argc %d\n", optind, argc);
if ( !(optind == (argc - 2) || optind == (argc - 3)) )
help();
size = atoi(argv[optind++]);
size = size << 20;
if (snprintf(filename, MAX_NAME_LEN, "%s",argv[optind++]) >=
MAX_NAME_LEN) {
fprintf(stderr,"Device name too long\n");
exit(-1);
}
if (optind != argc) {
/*Backing file argument*/
backed = 1;
if (snprintf(bfilename, MAX_NAME_LEN, "%s",argv[optind++]) >=
MAX_NAME_LEN) {
fprintf(stderr,"Device name too long\n");
exit(-1);
}
}
DFPRINTF("Creating file size %"PRIu64", name %s\n",(uint64_t)size, filename);
if (!backed)
ret = qcow_create(filename,size,NULL,sparse);
else
ret = qcow_create(filename,size,bfilename,sparse);
if (ret < 0)
DPRINTF("Unable to create QCOW file\n");
else
DPRINTF("QCOW file successfully created\n");
return 0;
}
-131
View File
@@ -1,131 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _QCOW_H_
#define _QCOW_H_
#include "aes.h"
/**************************************************************/
/* QEMU COW block driver with compression and encryption support */
#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
#define XEN_MAGIC (('X' << 24) | ('E' << 16) | ('N' << 8) | 0xfb)
#define QCOW_VERSION 1
#define QCOW_CRYPT_NONE 0x00
#define QCOW_CRYPT_AES 0x01
#define QCOW_OFLAG_COMPRESSED (1LL << 63)
#define SPARSE_FILE 0x01
#define EXTHDR_L1_BIG_ENDIAN 0x02
#ifndef O_BINARY
#define O_BINARY 0
#endif
#define ROUNDUP(l, s) \
({ \
(uint64_t)( \
(l + (s - 1)) - ((l + (s - 1)) % s)); \
})
typedef struct QCowHeader {
uint32_t magic;
uint32_t version;
uint64_t backing_file_offset;
uint32_t backing_file_size;
uint32_t mtime;
uint64_t size; /* in bytes */
uint8_t cluster_bits;
uint8_t l2_bits;
uint32_t crypt_method;
uint64_t l1_table_offset;
} QCowHeader;
/*Extended header for Xen enhancements*/
typedef struct QCowHeader_ext {
uint32_t xmagic;
uint32_t cksum;
uint32_t min_cluster_alloc;
uint32_t flags;
} QCowHeader_ext;
uint32_t gen_cksum(char *ptr, int len);
int get_filesize(char *filename, uint64_t *size, struct stat *st);
int qtruncate(int fd, off_t length, int sparse);
#define L2_CACHE_SIZE 16 /*Fixed allocation in Qemu*/
struct tdqcow_state {
int fd; /*Main Qcow file descriptor */
uint64_t fd_end; /*Store a local record of file length */
char *name; /*Record of the filename*/
uint32_t backing_file_size;
uint64_t backing_file_offset;
uint8_t extended; /*File contains extended header*/
int encrypted; /*File contents are encrypted or plain*/
int cluster_bits; /*Determines length of cluster as
*indicated by file hdr*/
int cluster_size; /*Length of cluster*/
int cluster_sectors; /*Number of sectors per cluster*/
int cluster_alloc; /*Blktap fix for allocating full
*extents*/
int min_cluster_alloc; /*Blktap historical extent alloc*/
int sparse; /*Indicates whether to preserve sparseness*/
int l2_bits; /*Size of L2 table entry*/
int l2_size; /*Full table size*/
int l1_size; /*L1 table size*/
uint64_t cluster_offset_mask;
uint64_t l1_table_offset; /*L1 table offset from beginning of
*file*/
uint64_t *l1_table; /*L1 table entries*/
uint64_t *l2_cache; /*We maintain a cache of size
*L2_CACHE_SIZE of most read entries*/
uint64_t l2_cache_offsets[L2_CACHE_SIZE]; /*L2 cache entries*/
uint32_t l2_cache_counts[L2_CACHE_SIZE]; /*Cache access record*/
uint8_t *cluster_cache;
uint8_t *cluster_data;
uint64_t cluster_cache_offset; /**/
uint32_t crypt_method; /*current crypt method, 0 if no
*key yet */
uint32_t crypt_method_header; /**/
AES_KEY aes_encrypt_key; /*AES key*/
AES_KEY aes_decrypt_key; /*AES key*/
/* libaio state */
int aio_free_count;
int max_aio_reqs;
struct qcow_request *aio_requests;
struct qcow_request **aio_free_list;
};
int qcow_create(const char *filename, uint64_t total_size,
const char *backing_file, int sparse);
#endif //_QCOW_H_
-443
View File
@@ -1,443 +0,0 @@
/* qcow2raw.c
*
* Generates raw image data from an existing qcow image
*
* (c) 2006 Julian Chesterfield and Andrew Warfield
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation; or, when distributed
* separately from the Linux kernel or incorporated into other
* software packages, subject to the following license:
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this source file (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <unistd.h>
#include <sys/statvfs.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <string.h>
#include "bswap.h"
#include "aes.h"
#include "blk.h"
#include "tapdisk.h"
#include "tapdisk-server.h"
#include "tapdisk-driver.h"
#include "tapdisk-interface.h"
#include "tapdisk-disktype.h"
#include "qcow.h"
#if 1
#define DFPRINTF(_f, _a...) fprintf ( stderr, _f , ## _a )
#else
#define DFPRINTF(_f, _a...) ((void)0)
#endif
/* *BSD has no O_LARGEFILE */
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif
#define BLOCK_PROCESSSZ 4096
#define QCOW_VBD 0
#define AIO_VBD 1
#define WINDOW 32
#define PROGRESS_QUANT 2
static int running = 1, complete = 0;
static int returned_read_events = 0, returned_write_events = 0;
static int submit_events = 0;
static uint32_t read_idx = 0;
td_driver_t *ddqcow, *ddaio;
td_vbd_t* qcow_vbd, *aio_vbd;
static uint64_t prev = 0, written = 0;
static char output[(100/PROGRESS_QUANT) + 5];
extern tapdisk_server_t server;
struct request_info {
void* buf;
uint64_t logical_sec;
int pending;
};
static void print_bytes(void *ptr, int length)
{
int i,k;
unsigned char *p = ptr;
DFPRINTF("Buf dump, length %d:\n",length);
for (k = 0; k < length; k++) {
DFPRINTF("%x",*p);
*p++;
if (k % 16 == 0) DFPRINTF("\n");
else if (k % 2 == 0) DFPRINTF(" ");
}
DFPRINTF("\n");
return;
}
static void debug_output(uint64_t progress, uint64_t size)
{
//Output progress every PROGRESS_QUANT
uint64_t blocks = size/(100/PROGRESS_QUANT);
if (progress/blocks > prev) {
memcpy(output+prev+1,"=>",2);
prev++;
DFPRINTF("\r%s %"PRIu64"%%",
output, (uint64_t)((prev-1)*PROGRESS_QUANT));
}
return;
}
static void send_write_responses(td_request_t treq, int err)
{
struct request_info* req;
if (err < 0) {
DFPRINTF("AIO FAILURE: res [%d]!\n",err);
return;
}
returned_write_events+=treq.secs;
written += treq.secs;
req= (struct request_info*)treq.cb_data;
//Wait for whole request to complete.
req->pending-=treq.secs;
if(req->pending)
return;
//Whole request has completed, we can free buffers.
free(req->buf);
free(req);
debug_output(written, ddaio->info.size);
return;
}
static void send_read_responses(td_request_t treq, int err)
{
int ret;
struct request_info* req;
td_vbd_request_t* vreq;
if (err < 0) {
DFPRINTF("AIO FAILURE: res [%d]!\n",err);
return;
}
returned_read_events+=treq.secs;
req= (struct request_info*)treq.cb_data;
//do nothing until all fragments complete.
req->pending-=treq.secs;
if(req->pending)
return;
//This read is done.
tapdisk_vbd_complete_vbd_request(qcow_vbd, treq.private);
treq.op = TD_OP_WRITE;
treq.buf = req->buf;
treq.sec = req->logical_sec;
treq.secs = BLOCK_PROCESSSZ>>9;
treq.image = tapdisk_vbd_first_image(aio_vbd);
treq.cb = send_write_responses;
treq.id = 0;
treq.sidx = 0;
req->pending = BLOCK_PROCESSSZ>>9;
treq.cb_data = req;
vreq = calloc(1, sizeof(td_vbd_request_t));
treq.private = vreq;
//Put it in the VBD's queue, so we don't lose
//track of it.
vreq->submitting = 1;
INIT_LIST_HEAD(&vreq->next);
tapdisk_vbd_move_request(treq.private,
&aio_vbd->pending_requests);
ddaio->ops->td_queue_write(ddaio,treq);
--vreq->submitting;
tapdisk_submit_all_tiocbs(&server.aio_queue);
return;
}
int main(int argc, const char *argv[])
{
int ret = -1, fd, len,input;
uint64_t size;
struct timeval timeout;
uint64_t i;
char *buf = NULL;
struct stat finfo;
td_request_t treq;
td_vbd_request_t* vreq;
struct request_info* req;
int err;
if (argc != 3) {
fprintf(stderr, "Qcow-utils: v1.0.0\n");
fprintf(stderr, "usage: %s <Dest File descriptor> "
"<Qcow SRC IMAGE>\n",
argv[0]);
exit(-1);
}
err = tapdisk_server_initialize();
if( err ) {
DPRINTF("qcow2raw Couldn't initialize server instance.\n");
return err;
}
err=tapdisk_vbd_initialize(QCOW_VBD);
if( err ) {
DPRINTF("qcow2raw Couldn't initialize qcow vbd.\n");
return err;
}
qcow_vbd = tapdisk_server_get_vbd(QCOW_VBD);
if (!qcow_vbd) {
err = -ENODEV;
DPRINTF("qcow2raw Couldn't create qcow vbd.\n");
return err;
}
err = tapdisk_vbd_open_vdi(qcow_vbd, argv[2], DISK_TYPE_QCOW,
TAPDISK_STORAGE_TYPE_DEFAULT,
TD_OPEN_RDONLY);
if( err ) {
DPRINTF("qcow2raw Couldn't open qcow file.\n");
return err;
}
ddqcow=(tapdisk_vbd_first_image(qcow_vbd))->driver;
/*Setup aio destination file*/
ret = stat(argv[1],&finfo);
if (ret == -1) {
/*Check errno*/
switch(errno) {
case ENOENT:
/*File doesn't exist, create*/
fd = open(argv[1],
O_RDWR | O_LARGEFILE | O_CREAT, 0644);
if (fd < 0) {
DFPRINTF("ERROR creating file [%s] "
"(errno %d)\n",
argv[1], 0 - errno);
exit(-1);
}
if (ftruncate(fd, (off_t)ddqcow->info.size<<9) < 0) {
DFPRINTF("Unable to create file "
"[%s] of size %"PRIu64" (errno %d). "
"Exiting...\n",
argv[1],
(uint64_t)ddqcow->info.size<<9,
0 - errno);
close(fd);
exit(-1);
}
close(fd);
break;
case ENXIO:
DFPRINTF("ERROR Device [%s] does not exist\n",argv[1]);
exit(-1);
default:
DFPRINTF("An error occurred opening Device [%s] "
"(errno %d)\n",
argv[1], 0 - errno);
exit(-1);
}
} else {
fprintf(stderr, "WARNING: All existing data in "
"%s will be overwritten.\nDo you wish to continue? "
"(y or n) ",
argv[1]);
if (getchar() != 'y') {
DFPRINTF("Exiting...\n");
exit(-1);
}
/*TODO - Test the existing file or device for adequate space*/
fd = open(argv[1], O_RDWR | O_LARGEFILE);
if (fd < 0) {
DFPRINTF("ERROR: opening file [%s] (errno %d)\n",
argv[1], 0 - errno);
exit(-1);
}
if (S_ISBLK(finfo.st_mode)) {
if (blk_getimagesize(fd, &size) != 0) {
close(fd);
return -1;
}
if (size < ddqcow->info.size<<9) {
DFPRINTF("ERROR: Not enough space on device "
"%s (%"PRIu64" bytes available, "
"%"PRIu64" bytes required\n",
argv[1], size,
(uint64_t)ddqcow->info.size<<9);
close(fd);
exit(-1);
}
} else {
if (ftruncate(fd, (off_t)ddqcow->info.size<<9) < 0) {
DFPRINTF("Unable to create file "
"[%s] of size %"PRIu64" (errno %d). "
"Exiting...\n",
argv[1],
(uint64_t)ddqcow->info.size<<9,
0 - errno);
close(fd);
exit(-1);
} else DFPRINTF("File [%s] truncated to length %"PRIu64" "
"(%"PRIu64")\n",
argv[1],
(uint64_t)ddqcow->info.size<<9,
(uint64_t)ddqcow->info.size);
}
close(fd);
}
//Now the output file should be there, reopen it as an aio VBD
err=tapdisk_vbd_initialize(AIO_VBD);
if( err ) {
DPRINTF("qcow2raw Couldn't initialize aio vbd.\n");
return err;
}
aio_vbd = tapdisk_server_get_vbd(AIO_VBD);
if (!aio_vbd) {
err = -ENODEV;
DPRINTF("qcow2raw Couldn't create aio vbd.\n");
return err;
}
err = tapdisk_vbd_open_vdi(aio_vbd, argv[1], DISK_TYPE_AIO,
TAPDISK_STORAGE_TYPE_DEFAULT,
0);
if( err ) {
DPRINTF("qcow2raw Couldn't open aio file.\n");
return err;
}
ddaio=(tapdisk_vbd_first_image(aio_vbd))->driver;
/*Initialise the output string*/
memset(output,0x20,(100/PROGRESS_QUANT)+5);
output[0] = '[';
output[(100/PROGRESS_QUANT)+2] = ']';
output[(100/PROGRESS_QUANT)+3] = '\0';
DFPRINTF("%s",output);
i = 0;
while (running) {
timeout.tv_sec = 0;
if (!complete) {
/*Read Pages from qcow image*/
if ( (ret = posix_memalign((void **)&buf,
BLOCK_PROCESSSZ,
BLOCK_PROCESSSZ))
!= 0) {
DFPRINTF("Unable to alloc memory (%d)\n",ret);
exit(-1);
}
/*Attempt to read 4k sized blocks*/
submit_events+=BLOCK_PROCESSSZ>>9;
//Set up the read request
treq.op = TD_OP_READ;
treq.buf = buf;
treq.sec = i;
treq.secs = BLOCK_PROCESSSZ>>9;
treq.image = tapdisk_vbd_first_image(qcow_vbd);
treq.cb = send_read_responses;
treq.id = 0;
treq.sidx = 0;
req = calloc(1, sizeof(struct request_info));
req->buf = buf;
req->logical_sec = i;
req->pending = BLOCK_PROCESSSZ>>9;
treq.cb_data = req;
vreq = calloc(1, sizeof(td_vbd_request_t));
treq.private = vreq;
//Put it in the VBD's queue, so we don't lose
//track of it.
vreq->submitting = 1;
INIT_LIST_HEAD(&vreq->next);
tapdisk_vbd_move_request(treq.private,
&qcow_vbd->pending_requests);
ddqcow->ops->td_queue_read(ddqcow, treq);
--vreq->submitting;
i += BLOCK_PROCESSSZ>>9;
if (i >= ddqcow->info.size)
complete = 1;
tapdisk_submit_all_tiocbs(&server.aio_queue);
}
while(returned_write_events != submit_events) {
ret = scheduler_wait_for_events(&server.scheduler);
if (ret < 0) {
DFPRINTF("server wait returned %d\n", ret);
sleep(2);
}
}
if (complete && (returned_write_events == submit_events))
running = 0;
}
memcpy(output+prev+1,"=",1);
DFPRINTF("\r%s 100%%\nTRANSFER COMPLETE\n\n", output);
ddqcow->ops->td_close(ddqcow);
ddaio->ops->td_close(ddaio);
free(ddqcow->data);
free(ddaio->data);
return 0;
}
-265
View File
@@ -1,265 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include "scheduler.h"
#include "tapdisk-log.h"
#define DBG(_f, _a...) tlog_write(TLOG_DBG, _f, ##_a)
#define SCHEDULER_MAX_TIMEOUT 600
#define SCHEDULER_POLL_FD (SCHEDULER_POLL_READ_FD | \
SCHEDULER_POLL_WRITE_FD | \
SCHEDULER_POLL_EXCEPT_FD)
#define MIN(a, b) ((a) <= (b) ? (a) : (b))
#define MAX(a, b) ((a) >= (b) ? (a) : (b))
#define scheduler_for_each_event(s, event, tmp) \
list_for_each_entry_safe(event, tmp, &(s)->events, next)
typedef struct event {
char mode;
event_id_t id;
int fd;
int timeout;
int deadline;
event_cb_t cb;
void *private;
struct list_head next;
} event_t;
static void
scheduler_prepare_events(scheduler_t *s)
{
int diff;
struct timeval now;
event_t *event, *tmp;
FD_ZERO(&s->read_fds);
FD_ZERO(&s->write_fds);
FD_ZERO(&s->except_fds);
s->max_fd = 0;
s->timeout = SCHEDULER_MAX_TIMEOUT;
gettimeofday(&now, NULL);
scheduler_for_each_event(s, event, tmp) {
if (event->mode & SCHEDULER_POLL_READ_FD) {
FD_SET(event->fd, &s->read_fds);
s->max_fd = MAX(event->fd, s->max_fd);
}
if (event->mode & SCHEDULER_POLL_WRITE_FD) {
FD_SET(event->fd, &s->write_fds);
s->max_fd = MAX(event->fd, s->max_fd);
}
if (event->mode & SCHEDULER_POLL_EXCEPT_FD) {
FD_SET(event->fd, &s->except_fds);
s->max_fd = MAX(event->fd, s->max_fd);
}
if (event->mode & SCHEDULER_POLL_TIMEOUT) {
diff = event->deadline - now.tv_sec;
if (diff > 0)
s->timeout = MIN(s->timeout, diff);
else
s->timeout = 0;
}
}
s->timeout = MIN(s->timeout, s->max_timeout);
}
static void
scheduler_event_callback(event_t *event, char mode)
{
if (event->mode & SCHEDULER_POLL_TIMEOUT) {
struct timeval now;
gettimeofday(&now, NULL);
event->deadline = now.tv_sec + event->timeout;
}
event->cb(event->id, mode, event->private);
}
static void
scheduler_run_events(scheduler_t *s)
{
struct timeval now;
event_t *event, *tmp;
gettimeofday(&now, NULL);
again:
s->restart = 0;
scheduler_for_each_event(s, event, tmp) {
if ((event->mode & SCHEDULER_POLL_READ_FD) &&
FD_ISSET(event->fd, &s->read_fds)) {
FD_CLR(event->fd, &s->read_fds);
scheduler_event_callback(event, SCHEDULER_POLL_READ_FD);
goto next;
}
if ((event->mode & SCHEDULER_POLL_WRITE_FD) &&
FD_ISSET(event->fd, &s->write_fds)) {
FD_CLR(event->fd, &s->write_fds);
scheduler_event_callback(event, SCHEDULER_POLL_WRITE_FD);
goto next;
}
if ((event->mode & SCHEDULER_POLL_EXCEPT_FD) &&
FD_ISSET(event->fd, &s->except_fds)) {
FD_CLR(event->fd, &s->except_fds);
scheduler_event_callback(event, SCHEDULER_POLL_EXCEPT_FD);
goto next;
}
if ((event->mode & SCHEDULER_POLL_TIMEOUT) &&
(event->deadline <= now.tv_sec))
scheduler_event_callback(event, SCHEDULER_POLL_TIMEOUT);
next:
if (s->restart)
goto again;
}
}
int
scheduler_register_event(scheduler_t *s, char mode, int fd,
int timeout, event_cb_t cb, void *private)
{
event_t *event;
struct timeval now;
if (!cb)
return -EINVAL;
if (!(mode & SCHEDULER_POLL_TIMEOUT) && !(mode & SCHEDULER_POLL_FD))
return -EINVAL;
event = calloc(1, sizeof(event_t));
if (!event)
return -ENOMEM;
gettimeofday(&now, NULL);
INIT_LIST_HEAD(&event->next);
event->mode = mode;
event->fd = fd;
event->timeout = timeout;
event->deadline = now.tv_sec + timeout;
event->cb = cb;
event->private = private;
event->id = s->uuid++;
if (!s->uuid)
s->uuid++;
list_add_tail(&event->next, &s->events);
return event->id;
}
void
scheduler_unregister_event(scheduler_t *s, event_id_t id)
{
event_t *event, *tmp;
if (!id)
return;
scheduler_for_each_event(s, event, tmp)
if (event->id == id) {
list_del(&event->next);
free(event);
s->restart = 1;
break;
}
}
void
scheduler_set_max_timeout(scheduler_t *s, int timeout)
{
if (timeout >= 0)
s->max_timeout = MIN(s->max_timeout, timeout);
}
int
scheduler_wait_for_events(scheduler_t *s)
{
int ret;
struct timeval tv;
scheduler_prepare_events(s);
tv.tv_sec = s->timeout;
tv.tv_usec = 0;
DBG("timeout: %d, max_timeout: %d\n",
s->timeout, s->max_timeout);
ret = select(s->max_fd + 1, &s->read_fds,
&s->write_fds, &s->except_fds, &tv);
s->restart = 0;
s->timeout = SCHEDULER_MAX_TIMEOUT;
s->max_timeout = SCHEDULER_MAX_TIMEOUT;
if (ret < 0)
return ret;
scheduler_run_events(s);
return ret;
}
void
scheduler_initialize(scheduler_t *s)
{
memset(s, 0, sizeof(scheduler_t));
s->uuid = 1;
FD_ZERO(&s->read_fds);
FD_ZERO(&s->write_fds);
FD_ZERO(&s->except_fds);
INIT_LIST_HEAD(&s->events);
}
-65
View File
@@ -1,65 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SCHEDULER_H_
#define _SCHEDULER_H_
#include <sys/select.h>
#include "list.h"
#define SCHEDULER_POLL_READ_FD 0x1
#define SCHEDULER_POLL_WRITE_FD 0x2
#define SCHEDULER_POLL_EXCEPT_FD 0x4
#define SCHEDULER_POLL_TIMEOUT 0x8
typedef int event_id_t;
typedef void (*event_cb_t) (event_id_t id, char mode, void *private);
typedef struct scheduler {
fd_set read_fds;
fd_set write_fds;
fd_set except_fds;
struct list_head events;
int uuid;
int max_fd;
int timeout;
int restart;
int max_timeout;
} scheduler_t;
void scheduler_initialize(scheduler_t *);
event_id_t scheduler_register_event(scheduler_t *, char mode,
int fd, int timeout,
event_cb_t cb, void *private);
void scheduler_unregister_event(scheduler_t *, event_id_t);
void scheduler_set_max_timeout(scheduler_t *, int);
int scheduler_wait_for_events(scheduler_t *);
#endif
-496
View File
@@ -1,496 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* client harness for tapdisk log */
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include "log.h"
#define BDPRINTF(_f, _a...) fprintf (stderr, "log: " _f "\n", ## _a)
#define BWPRINTF(_f, _a...) fprintf (stderr, "log: " _f "\n", ## _a)
struct writelog {
char* shmpath;
uint32_t shmsize;
void* shm;
/* next unprocessed item in the writelog */
void* cur;
unsigned int inflight;
/* pointer to start and end of free data space for requests */
void* dhd;
void* dtl;
log_sring_t* sring;
log_front_ring_t fring;
};
/* bytes free on the data ring */
static inline unsigned int dring_avail(struct writelog* wl)
{
/* one byte reserved to distinguish empty from full */
if (wl->dhd == wl->dtl)
return sdataend(wl->shm) - sdatastart(wl->shm) - 1;
if (wl->dhd < wl->dtl)
return wl->dtl - wl->dhd - 1;
return (sdataend(wl->shm) - wl->dhd) + (wl->dtl - sdatastart(wl->shm)) - 1;
}
/* advance ring pointer by len bytes */
static inline void* dring_advance(struct writelog* wl, void* start, size_t len)
{
void* next;
int dsz = sdataend(wl->shm) - sdatastart(wl->shm);
next = start + (len % dsz);
if (next > sdataend(wl->shm))
next -= dsz;
return next;
}
static void usage(void)
{
fprintf(stderr, "usage: tapdisk-client <sock>\n");
}
/* returns socket file descriptor */
static int tdctl_open(const char* sockpath)
{
struct sockaddr_un saddr;
int fd;
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
BWPRINTF("error creating socket: %s", strerror(errno));
return -1;
}
memset(&saddr, 0, sizeof(saddr));
saddr.sun_family = AF_UNIX;
memcpy(saddr.sun_path, sockpath, strlen(sockpath));
if (connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
BWPRINTF("error connecting to socket %s: %s", sockpath, strerror(errno));
close(fd);
return -1;
}
return fd;
}
static int ctl_talk(int fd, struct log_ctlmsg* msg, char* rsp, int rsplen)
{
int rc;
if ((rc = write(fd, msg, sizeof(*msg))) < 0) {
BWPRINTF("error sending ctl request: %s", strerror(errno));
return -1;
} else if (rc < sizeof(*msg)) {
BWPRINTF("short ctl write (%d/%zd bytes)", rc, sizeof(*msg));
return -1;
}
if (!rsplen)
return 0;
if ((rc = read(fd, rsp, rsplen)) < 0) {
BWPRINTF("error reading ctl response: %s", strerror(errno));
return -1;
} else if (rc < rsplen) {
BWPRINTF("short ctl read (%d/%d bytes)", rc, rsplen);
return -1;
}
return 0;
}
static int ctl_get_shmem(int fd, struct writelog* wl)
{
struct log_ctlmsg req;
char rsp[CTLRSPLEN_SHMP + 1];
int rc;
memset(&req, 0, sizeof(req));
memset(rsp, 0, sizeof(rsp));
memcpy(req.msg, LOGCMD_SHMP, 4);
if ((rc = ctl_talk(fd, &req, rsp, CTLRSPLEN_SHMP)) < 0) {
BWPRINTF("error getting shared memory parameters");
return -1;
}
memcpy(&wl->shmsize, rsp, sizeof(wl->shmsize));
wl->shmpath = strdup(rsp + sizeof(wl->shmsize));
BDPRINTF("shared memory parameters: size: %u, path: %s",
wl->shmsize, wl->shmpath);
return 0;
}
static void ctlmsg_init(struct log_ctlmsg* msg, const char* cmd)
{
memset(msg, 0, sizeof(*msg));
memcpy(msg->msg, cmd, 4);
}
static int ctl_get_writes(int fd)
{
struct log_ctlmsg req;
char rsp[CTLRSPLEN_GET];
int rc;
ctlmsg_init(&req, LOGCMD_GET);
if ((rc = ctl_talk(fd, &req, rsp, CTLRSPLEN_GET)) < 0) {
BWPRINTF("error getting writes");
return -1;
}
return 0;
}
static int ctl_peek_writes(int fd)
{
struct log_ctlmsg req;
char rsp[CTLRSPLEN_PEEK];
int rc;
ctlmsg_init(&req, LOGCMD_PEEK);
if ((rc = ctl_talk(fd, &req, rsp, CTLRSPLEN_PEEK)) < 0) {
BWPRINTF("error peeking writes");
return -1;
}
return 0;
}
/* submit pending requests */
static int ctl_kick(int fd)
{
struct log_ctlmsg req;
int rc;
ctlmsg_init(&req, LOGCMD_KICK);
if ((rc = ctl_talk(fd, &req, NULL, 0)) < 0) {
BWPRINTF("error kicking ring");
return -1;
}
return 0;
}
static int ctl_clear_writes(int fd)
{
struct log_ctlmsg req;
char rsp[CTLRSPLEN_CLEAR];
int rc;
ctlmsg_init(&req, LOGCMD_CLEAR);
if ((rc = ctl_talk(fd, &req, rsp, CTLRSPLEN_CLEAR)) < 0) {
BWPRINTF("error clearing writes");
return -1;
}
return 0;
}
static int writelog_map(struct writelog* wl)
{
int fd;
void* shm;
if ((fd = shm_open(wl->shmpath, O_RDWR, 0750)) < 0) {
BWPRINTF("could not open shared memory at %s: %s", wl->shmpath,
strerror(errno));
return -1;
}
wl->shm = mmap(NULL, wl->shmsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
if (wl->shm == MAP_FAILED) {
BWPRINTF("could not mmap write log shm: %s", strerror(errno));
return -1;
}
wl->cur = wl->shm;
wl->inflight = 0;
wl->dhd = wl->dtl = sdatastart(wl->shm);
BDPRINTF("shm cookie: 0x%x, data size: %u", *((uint32_t*)wl->shm),
dring_avail(wl));
wl->sring = sringstart(wl->shm);
/* need some thought about what to do on reconnect */
FRONT_RING_INIT(&wl->fring, wl->sring, SRINGSIZE);
return 0;
}
static int writelog_dump(struct writelog* wl)
{
struct disk_range* range = wl->shm;
for (range = wl->shm; (void*)range < bmend(wl->shm); range++) {
if (!range->count)
break;
BDPRINTF("dirty extent: %"PRIu64":%u",
range->sector, range->count);
}
return 0;
}
/* walk dirty map and enqueue read requests.
* returns: 0 when entire bitmap has been enqueued,
* 1 when the ring is full
* -1 on error
*/
static int writelog_enqueue_requests(struct writelog* wl)
{
struct disk_range* range = wl->shm;
log_request_t* req;
for (range = wl->cur; (void*)range < bmend(wl->shm); range++) {
if (!range->count)
break;
if (RING_FULL(&wl->fring))
break;
/* insert range into request stream */
/* 1. get next request slot from ring */
/* 2. ensure enough shm space is available */
BDPRINTF("enqueueing dirty extent: %"PRIu64":%u (ring space: %d/%d)",
range->sector, range->count, RING_FREE_REQUESTS(&wl->fring),
RING_SIZE(&wl->fring));
req = RING_GET_REQUEST(&wl->fring, wl->fring.req_prod_pvt);
req->sector = range->sector;
req->count = range->count;
/* ... */
req->offset = 0;
wl->fring.req_prod_pvt++;
wl->inflight++;
}
wl->cur = range;
if (range->count)
return 1;
return 0;
}
static int writelog_dequeue_responses(struct writelog* wl)
{
RING_IDX rstart, rend;
log_response_t rsp;
rstart = wl->fring.rsp_cons;
rend = wl->sring->rsp_prod;
BDPRINTF("ring kicked (start = %u, end = %u)", rstart, rend);
while (rstart != rend) {
memcpy(&rsp, RING_GET_RESPONSE(&wl->fring, rstart), sizeof(rsp));
BDPRINTF("ctl: read response %"PRIu64":%u", rsp.sector, rsp.count);
wl->fring.rsp_cons = ++rstart;
wl->inflight--;
}
return 0;
}
static int writelog_free(struct writelog* wl)
{
if (wl->shmpath) {
free(wl->shmpath);
wl->shmpath = NULL;
}
if (wl->shm) {
munmap(wl->shm, wl->shmsize);
wl->shm = NULL;
}
return 0;
}
int get_writes(struct writelog* wl, int fd, int peek)
{
int rc;
if (peek)
rc = ctl_peek_writes(fd);
else
rc = ctl_get_writes(fd);
if (rc < 0)
return rc;
wl->cur = wl->shm;
return 0;
}
int await_responses(struct writelog* wl, int fd)
{
struct log_ctlmsg msg;
int rc;
/* sit on socket waiting for kick */
if ((rc = read(fd, &msg, sizeof(msg))) < 0) {
BWPRINTF("error reading from control socket: %s", strerror(errno));
return -1;
} else if (!rc) {
BWPRINTF("EOF on control socket");
return -1;
} else if (rc < sizeof(msg)) {
BWPRINTF("short reply (%d/%d bytes)", rc, (int) sizeof(msg));
return -1;
}
if (strncmp(msg.msg, LOGCMD_KICK, 4)) {
BWPRINTF("Unknown message received: %.4s", msg.msg);
return -1;
}
if (writelog_dequeue_responses(wl) < 0)
return -1;
return 0;
}
/* read_loop:
* 1. extract dirty bitmap
* 2. feed as much as possible onto ring
* 3. kick
* 4. as responses come back, feed more of the dirty bitmap
* into the ring
* 5. when entire bitmap has been queued, go to 1?
*/
int read_loop(struct writelog* wl, int fd)
{
int rc;
if (get_writes(wl, fd, 1) < 0)
return -1;
writelog_dump(wl);
do {
rc = writelog_enqueue_requests(wl);
if (RING_FREE_REQUESTS(&wl->fring) < RING_SIZE(&wl->fring))
RING_PUSH_REQUESTS(&wl->fring);
if (ctl_kick(fd) < 0)
return -1;
/* collect responses */
if (wl->inflight && await_responses(wl, fd) < 0)
return -1;
} while (rc > 0);
return rc;
}
int main(int argc, char* argv[])
{
int fd;
struct writelog wl;
char cmd;
if (argc < 2) {
usage();
return 1;
}
if (argc < 3)
cmd = 'p';
else
cmd = argv[2][0];
fd = tdctl_open(argv[1]);
if (ctl_get_shmem(fd, &wl) < 0)
return 1;
if (writelog_map(&wl) < 0) {
BWPRINTF("Error mapping write log: %s", strerror(errno));
return 1;
}
switch (cmd) {
case 'p':
if (get_writes(&wl, fd, 1) < 0)
return 1;
writelog_dump(&wl);
break;
case 'c':
if (ctl_clear_writes(fd) < 0)
return 1;
break;
case 'g':
if (get_writes(&wl, fd, 0) < 0)
return 1;
writelog_dump(&wl);
break;
case 'r':
if (read_loop(&wl, fd) < 0)
return 1;
break;
default:
usage();
return 1;
}
writelog_free(&wl);
close(fd);
return 0;
}
-837
View File
@@ -1,837 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include "list.h"
#include "tapdisk.h"
#include "blktap2.h"
#include "blktaplib.h"
#include "tapdisk-vbd.h"
#include "tapdisk-utils.h"
#include "tapdisk-server.h"
#include "tapdisk-message.h"
#include "tapdisk-disktype.h"
struct tapdisk_control {
char *path;
int socket;
int event_id;
};
struct tapdisk_control_connection {
int socket;
event_id_t event_id;
};
static struct tapdisk_control td_control;
static void
tapdisk_control_initialize(void)
{
td_control.socket = -1;
td_control.event_id = -1;
signal(SIGPIPE, SIG_IGN);
}
void
tapdisk_control_close(void)
{
if (td_control.path) {
unlink(td_control.path);
free(td_control.path);
td_control.path = NULL;
}
if (td_control.socket != -1) {
close(td_control.socket);
td_control.socket = -1;
}
}
static struct tapdisk_control_connection *
tapdisk_control_allocate_connection(int fd)
{
struct tapdisk_control_connection *connection;
size_t sz;
connection = calloc(1, sizeof(*connection));
if (!connection) {
EPRINTF("calloc");
return NULL;
}
connection->socket = fd;
return connection;
}
static void
tapdisk_control_close_connection(struct tapdisk_control_connection *connection)
{
tapdisk_server_unregister_event(connection->event_id);
close(connection->socket);
free(connection);
}
static int
tapdisk_control_read_message(int fd, tapdisk_message_t *message, int timeout)
{
fd_set readfds;
int ret, len, offset;
struct timeval tv, *t;
t = NULL;
offset = 0;
len = sizeof(tapdisk_message_t);
if (timeout) {
tv.tv_sec = timeout;
tv.tv_usec = 0;
t = &tv;
}
memset(message, 0, sizeof(tapdisk_message_t));
while (offset < len) {
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
ret = select(fd + 1, &readfds, NULL, NULL, t);
if (ret == -1)
break;
else if (FD_ISSET(fd, &readfds)) {
ret = read(fd, message + offset, len - offset);
if (ret <= 0)
break;
offset += ret;
} else
break;
}
if (offset != len) {
EPRINTF("failure reading message (wanted %d but got %d)\n",
len, offset);
return -EIO;
}
DPRINTF("received '%s' message (uuid = %u)\n",
tapdisk_message_name(message->type), message->cookie);
return 0;
}
static int
tapdisk_control_write_message(int fd, tapdisk_message_t *message, int timeout)
{
fd_set writefds;
int ret, len, offset;
struct timeval tv, *t;
t = NULL;
offset = 0;
len = sizeof(tapdisk_message_t);
if (timeout) {
tv.tv_sec = timeout;
tv.tv_usec = 0;
t = &tv;
}
DPRINTF("sending '%s' message (uuid = %u)\n",
tapdisk_message_name(message->type), message->cookie);
while (offset < len) {
FD_ZERO(&writefds);
FD_SET(fd, &writefds);
/* we don't bother reinitializing tv. at worst, it will wait a
* bit more time than expected. */
ret = select(fd + 1, NULL, &writefds, NULL, t);
if (ret == -1)
break;
else if (FD_ISSET(fd, &writefds)) {
ret = write(fd, message + offset, len - offset);
if (ret <= 0)
break;
offset += ret;
} else
break;
}
if (offset != len) {
EPRINTF("failure writing message\n");
return -EIO;
}
return 0;
}
static int
tapdisk_control_validate_request(tapdisk_message_t *request)
{
if (strnlen(request->u.params.path,
TAPDISK_MESSAGE_MAX_PATH_LENGTH) >=
TAPDISK_MESSAGE_MAX_PATH_LENGTH)
return EINVAL;
return 0;
}
static void
tapdisk_control_list_minors(struct tapdisk_control_connection *connection,
tapdisk_message_t *request)
{
int i;
td_vbd_t *vbd;
struct list_head *head;
tapdisk_message_t response;
i = 0;
memset(&response, 0, sizeof(response));
response.type = TAPDISK_MESSAGE_LIST_MINORS_RSP;
response.cookie = request->cookie;
head = tapdisk_server_get_all_vbds();
list_for_each_entry(vbd, head, next) {
response.u.minors.list[i++] = vbd->minor;
if (i >= TAPDISK_MESSAGE_MAX_MINORS) {
response.type = TAPDISK_MESSAGE_ERROR;
response.u.response.error = ERANGE;
break;
}
}
response.u.minors.count = i;
tapdisk_control_write_message(connection->socket, &response, 2);
tapdisk_control_close_connection(connection);
}
static void
tapdisk_control_list(struct tapdisk_control_connection *connection,
tapdisk_message_t *request)
{
td_vbd_t *vbd;
struct list_head *head;
tapdisk_message_t response;
int count, i;
memset(&response, 0, sizeof(response));
response.type = TAPDISK_MESSAGE_LIST_RSP;
response.cookie = request->cookie;
head = tapdisk_server_get_all_vbds();
count = 0;
list_for_each_entry(vbd, head, next)
count++;
list_for_each_entry(vbd, head, next) {
response.u.list.count = count--;
response.u.list.minor = vbd->minor;
response.u.list.state = vbd->state;
response.u.list.path[0] = 0;
if (!list_empty(&vbd->images)) {
td_image_t *image = list_entry(vbd->images.next,
td_image_t, next);
snprintf(response.u.list.path,
sizeof(response.u.list.path),
"%s:%s",
tapdisk_disk_types[image->type]->name,
image->name);
}
tapdisk_control_write_message(connection->socket, &response, 2);
}
response.u.list.count = count;
response.u.list.minor = -1;
response.u.list.path[0] = 0;
tapdisk_control_write_message(connection->socket, &response, 2);
tapdisk_control_close_connection(connection);
}
static void
tapdisk_control_get_pid(struct tapdisk_control_connection *connection,
tapdisk_message_t *request)
{
tapdisk_message_t response;
memset(&response, 0, sizeof(response));
response.type = TAPDISK_MESSAGE_PID_RSP;
response.cookie = request->cookie;
response.u.tapdisk_pid = getpid();
tapdisk_control_write_message(connection->socket, &response, 2);
tapdisk_control_close_connection(connection);
}
static void
tapdisk_control_attach_vbd(struct tapdisk_control_connection *connection,
tapdisk_message_t *request)
{
tapdisk_message_t response;
char *devname;
td_vbd_t *vbd;
struct blktap2_params params;
image_t image;
int minor, err;
/*
* TODO: check for max vbds per process
*/
vbd = tapdisk_server_get_vbd(request->cookie);
if (vbd) {
err = -EEXIST;
goto out;
}
minor = request->cookie;
if (minor < 0) {
err = -EINVAL;
goto out;
}
vbd = tapdisk_vbd_create(minor);
if (!vbd) {
err = -ENOMEM;
goto out;
}
err = asprintf(&devname, BLKTAP2_RING_DEVICE"%d", minor);
if (err == -1) {
err = -ENOMEM;
goto fail_vbd;
}
err = tapdisk_vbd_attach(vbd, devname, minor);
free(devname);
if (err)
goto fail_vbd;
tapdisk_server_add_vbd(vbd);
out:
memset(&response, 0, sizeof(response));
response.type = TAPDISK_MESSAGE_ATTACH_RSP;
response.cookie = request->cookie;
response.u.response.error = -err;
tapdisk_control_write_message(connection->socket, &response, 2);
tapdisk_control_close_connection(connection);
return;
fail_vbd:
tapdisk_vbd_detach(vbd);
free(vbd);
goto out;
}
static void
tapdisk_control_detach_vbd(struct tapdisk_control_connection *connection,
tapdisk_message_t *request)
{
tapdisk_message_t response;
td_vbd_t *vbd;
int err;
vbd = tapdisk_server_get_vbd(request->cookie);
if (!vbd) {
err = -EINVAL;
goto out;
}
tapdisk_vbd_detach(vbd);
if (list_empty(&vbd->images)) {
tapdisk_server_remove_vbd(vbd);
free(vbd);
}
err = 0;
out:
memset(&response, 0, sizeof(response));
response.type = TAPDISK_MESSAGE_DETACH_RSP;
response.cookie = request->cookie;
response.u.response.error = -err;
tapdisk_control_write_message(connection->socket, &response, 2);
tapdisk_control_close_connection(connection);
}
static void
tapdisk_control_open_image(struct tapdisk_control_connection *connection,
tapdisk_message_t *request)
{
int err;
image_t image;
td_vbd_t *vbd;
td_flag_t flags;
tapdisk_message_t response;
struct blktap2_params params;
vbd = tapdisk_server_get_vbd(request->cookie);
if (!vbd) {
err = -EINVAL;
goto out;
}
if (vbd->minor == -1) {
err = -EINVAL;
goto out;
}
if (vbd->name) {
err = -EALREADY;
goto out;
}
flags = 0;
if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_RDONLY)
flags |= TD_OPEN_RDONLY;
if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_SHARED)
flags |= TD_OPEN_SHAREABLE;
if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_ADD_CACHE)
flags |= TD_OPEN_ADD_CACHE;
if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_VHD_INDEX)
flags |= TD_OPEN_VHD_INDEX;
if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_LOG_DIRTY)
flags |= TD_OPEN_LOG_DIRTY;
vbd->name = strndup(request->u.params.path,
sizeof(request->u.params.path));
if (!vbd->name) {
err = -ENOMEM;
goto out;
}
err = tapdisk_vbd_parse_stack(vbd, request->u.params.path);
if (err)
goto out;
err = tapdisk_vbd_open_stack(vbd, request->u.params.storage, flags);
if (err)
goto out;
err = tapdisk_vbd_get_image_info(vbd, &image);
if (err)
goto fail_close;
params.capacity = image.size;
params.sector_size = image.secsize;
strncpy(params.name, vbd->name, BLKTAP2_MAX_MESSAGE_LEN);
err = ioctl(vbd->ring.fd, BLKTAP2_IOCTL_CREATE_DEVICE, &params);
if (err && errno != EEXIST) {
err = -errno;
EPRINTF("create device failed: %d\n", err);
goto fail_close;
}
err = 0;
out:
memset(&response, 0, sizeof(response));
response.cookie = request->cookie;
if (err) {
response.type = TAPDISK_MESSAGE_ERROR;
response.u.response.error = -err;
} else {
response.u.image.sectors = image.size;
response.u.image.sector_size = image.secsize;
response.u.image.info = image.info;
response.type = TAPDISK_MESSAGE_OPEN_RSP;
}
tapdisk_control_write_message(connection->socket, &response, 2);
tapdisk_control_close_connection(connection);
return;
fail_close:
tapdisk_vbd_close_vdi(vbd);
free(vbd->name);
vbd->name = NULL;
goto out;
}
static void
tapdisk_control_close_image(struct tapdisk_control_connection *connection,
tapdisk_message_t *request)
{
tapdisk_message_t response;
td_vbd_t *vbd;
int err;
vbd = tapdisk_server_get_vbd(request->cookie);
if (!vbd) {
err = -EINVAL;
goto out;
}
if (!list_empty(&vbd->pending_requests)) {
err = -EAGAIN;
goto out;
}
tapdisk_vbd_close_vdi(vbd);
/* NB. vbd->name free should probably belong into close_vdi,
but the current blktap1 reopen-stuff likely depends on a
lifetime extended until shutdown. */
free(vbd->name);
vbd->name = NULL;
if (vbd->minor == -1) {
tapdisk_server_remove_vbd(vbd);
tapdisk_vbd_free(vbd);
}
err = 0;
out:
memset(&response, 0, sizeof(response));
response.type = TAPDISK_MESSAGE_CLOSE_RSP;
response.cookie = request->cookie;
response.u.response.error = -err;
tapdisk_control_write_message(connection->socket, &response, 2);
tapdisk_control_close_connection(connection);
}
static void
tapdisk_control_pause_vbd(struct tapdisk_control_connection *connection,
tapdisk_message_t *request)
{
int err;
td_vbd_t *vbd;
tapdisk_message_t response;
memset(&response, 0, sizeof(response));
response.type = TAPDISK_MESSAGE_PAUSE_RSP;
vbd = tapdisk_server_get_vbd(request->cookie);
if (!vbd) {
err = -EINVAL;
goto out;
}
do {
err = tapdisk_vbd_pause(vbd);
if (!err || err != -EAGAIN)
break;
tapdisk_server_iterate();
} while (1);
out:
response.cookie = request->cookie;
response.u.response.error = -err;
tapdisk_control_write_message(connection->socket, &response, 2);
tapdisk_control_close_connection(connection);
}
static void
tapdisk_control_resume_vbd(struct tapdisk_control_connection *connection,
tapdisk_message_t *request)
{
int err;
td_vbd_t *vbd;
tapdisk_message_t response;
memset(&response, 0, sizeof(response));
response.type = TAPDISK_MESSAGE_RESUME_RSP;
vbd = tapdisk_server_get_vbd(request->cookie);
if (!vbd) {
err = -EINVAL;
goto out;
}
if (!td_flag_test(vbd->state, TD_VBD_PAUSED)) {
err = -EINVAL;
goto out;
}
if (request->u.params.path[0]) {
free(vbd->name);
vbd->name = strndup(request->u.params.path,
sizeof(request->u.params.path));
if (!vbd->name) {
err = -ENOMEM;
goto out;
}
} else if (!vbd->name) {
err = -EINVAL;
goto out;
}
err = tapdisk_vbd_parse_stack(vbd, vbd->name);
if (err)
goto out;
err = tapdisk_vbd_resume(vbd, NULL, -1);
if (err)
goto out;
out:
response.cookie = request->cookie;
response.u.response.error = -err;
tapdisk_control_write_message(connection->socket, &response, 2);
tapdisk_control_close_connection(connection);
}
static void
tapdisk_control_handle_request(event_id_t id, char mode, void *private)
{
int err;
tapdisk_message_t message;
struct tapdisk_control_connection *connection =
(struct tapdisk_control_connection *)private;
if (tapdisk_control_read_message(connection->socket, &message, 2)) {
EPRINTF("failed to read message from %d\n", connection->socket);
tapdisk_control_close_connection(connection);
return;
}
err = tapdisk_control_validate_request(&message);
if (err)
goto fail;
switch (message.type) {
case TAPDISK_MESSAGE_PID:
return tapdisk_control_get_pid(connection, &message);
case TAPDISK_MESSAGE_LIST_MINORS:
return tapdisk_control_list_minors(connection, &message);
case TAPDISK_MESSAGE_LIST:
return tapdisk_control_list(connection, &message);
case TAPDISK_MESSAGE_ATTACH:
return tapdisk_control_attach_vbd(connection, &message);
case TAPDISK_MESSAGE_DETACH:
return tapdisk_control_detach_vbd(connection, &message);
case TAPDISK_MESSAGE_OPEN:
return tapdisk_control_open_image(connection, &message);
case TAPDISK_MESSAGE_PAUSE:
return tapdisk_control_pause_vbd(connection, &message);
case TAPDISK_MESSAGE_RESUME:
return tapdisk_control_resume_vbd(connection, &message);
case TAPDISK_MESSAGE_CLOSE:
return tapdisk_control_close_image(connection, &message);
default: {
tapdisk_message_t response;
fail:
EPRINTF("received unsupported message '%s'\n",
tapdisk_message_name(message.type));
memset(&response, 0, sizeof(response));
response.type = TAPDISK_MESSAGE_ERROR;
response.u.response.error = (err ? -err : EINVAL);
tapdisk_control_write_message(connection->socket, &response, 2);
tapdisk_control_close_connection(connection);
break;
}
}
}
static void
tapdisk_control_accept(event_id_t id, char mode, void *private)
{
int err, fd;
struct tapdisk_control_connection *connection;
fd = accept(td_control.socket, NULL, NULL);
if (fd == -1) {
EPRINTF("failed to accept new control connection: %d\n", errno);
return;
}
connection = tapdisk_control_allocate_connection(fd);
if (!connection) {
close(fd);
EPRINTF("failed to allocate new control connection\n");
}
err = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
connection->socket, 0,
tapdisk_control_handle_request,
connection);
if (err == -1) {
close(fd);
free(connection);
EPRINTF("failed to register new control event: %d\n", err);
}
connection->event_id = err;
}
static int
tapdisk_control_mkdir(const char *dir)
{
int err;
char *ptr, *name, *start;
err = access(dir, W_OK | R_OK);
if (!err)
return 0;
name = strdup(dir);
if (!name)
return -ENOMEM;
start = name;
for (;;) {
ptr = strchr(start + 1, '/');
if (ptr)
*ptr = '\0';
err = mkdir(name, 0755);
if (err && errno != EEXIST) {
err = -errno;
EPRINTF("failed to create directory %s: %d\n",
name, err);
break;
}
if (!ptr)
break;
else {
*ptr = '/';
start = ptr + 1;
}
}
free(name);
return err;
}
static int
tapdisk_control_create_socket(char **socket_path)
{
int err, flags;
struct sockaddr_un saddr;
err = tapdisk_control_mkdir(BLKTAP2_CONTROL_DIR);
if (err) {
EPRINTF("failed to create directory %s: %d\n",
BLKTAP2_CONTROL_DIR, err);
return err;
}
err = asprintf(&td_control.path, "%s/%s%d",
BLKTAP2_CONTROL_DIR, BLKTAP2_CONTROL_SOCKET, getpid());
if (err == -1) {
td_control.path = NULL;
err = (errno ? : ENOMEM);
goto fail;
}
if (unlink(td_control.path) && errno != ENOENT) {
err = errno;
EPRINTF("failed to unlink %s: %d\n", td_control.path, errno);
goto fail;
}
td_control.socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (td_control.socket == -1) {
err = errno;
EPRINTF("failed to create control socket: %d\n", err);
goto fail;
}
memset(&saddr, 0, sizeof(saddr));
strncpy(saddr.sun_path, td_control.path, sizeof(saddr.sun_path));
saddr.sun_family = AF_UNIX;
err = bind(td_control.socket,
(const struct sockaddr *)&saddr, sizeof(saddr));
if (err == -1) {
err = errno;
EPRINTF("failed to bind to %s: %d\n", saddr.sun_path, err);
goto fail;
}
err = listen(td_control.socket, 10);
if (err == -1) {
err = errno;
EPRINTF("failed to listen: %d\n", err);
goto fail;
}
err = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
td_control.socket, 0,
tapdisk_control_accept, NULL);
if (err < 0) {
EPRINTF("failed to add watch: %d\n", err);
goto fail;
}
td_control.event_id = err;
*socket_path = td_control.path;
return 0;
fail:
tapdisk_control_close();
return err;
}
int
tapdisk_control_open(char **path)
{
int err;
tapdisk_control_initialize();
return tapdisk_control_create_socket(path);
}
-35
View File
@@ -1,35 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __TAPDISK_CONTROL_H__
#define __TAPDISK_CONTROL_H__
int tapdisk_control_open(char **path);
void tapdisk_control_close(void);
#endif
-802
View File
@@ -1,802 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <libgen.h> /* for basename(3) */
#include <unistd.h>
#include "list.h"
#include "scheduler.h"
#include "tapdisk-vbd.h"
#include "tapdisk-server.h"
#include "tapdisk-disktype.h"
#include "tapdisk-utils.h"
#include "libvhd.h"
#define POLL_READ 0
#define POLL_WRITE 1
#define SPB_SHIFT (VHD_BLOCK_SHIFT - SECTOR_SHIFT)
struct tapdisk_stream_poll {
int pipe[2];
int set;
};
struct tapdisk_stream_request {
uint64_t sec;
uint32_t secs;
uint64_t seqno;
blkif_request_t blkif_req;
struct list_head next;
};
struct tapdisk_stream {
td_vbd_t *vbd;
unsigned int id;
int err;
uint64_t cur;
uint64_t start;
uint64_t end;
uint64_t started;
uint64_t completed;
struct tapdisk_stream_poll poll;
event_id_t enqueue_event_id;
struct list_head free_list;
struct list_head pending_list;
struct list_head completed_list;
struct tapdisk_stream_request requests[MAX_REQUESTS];
};
static unsigned int tapdisk_stream_count;
static void tapdisk_stream_close_image(struct tapdisk_stream *);
static char *program;
static struct tapdisk_stream stream1, stream2;
static vhd_context_t vhd1;
static void
usage(FILE *stream)
{
printf("usage: %s <-n type:/path/to/image> <-m type:/path/to/image>\n",
program);
}
static int
open_vhd(const char *path, vhd_context_t *vhd)
{
int err;
err = vhd_open(vhd, path, VHD_OPEN_RDONLY);
if (err) {
printf("error opening %s: %d\n", path, err);
return err;
}
err = vhd_get_bat(vhd);
if (err)
{
printf("error reading BAT for %s: %d\n", path, err);
vhd_close(vhd);
return err;
}
return 0;
}
static inline void
tapdisk_stream_poll_initialize(struct tapdisk_stream_poll *p)
{
p->set = 0;
p->pipe[POLL_READ] = p->pipe[POLL_WRITE] = -1;
}
static int
tapdisk_stream_poll_open(struct tapdisk_stream_poll *p)
{
int err;
tapdisk_stream_poll_initialize(p);
err = pipe(p->pipe);
if (err)
return -errno;
err = fcntl(p->pipe[POLL_READ], F_SETFL, O_NONBLOCK);
if (err)
goto out;
err = fcntl(p->pipe[POLL_WRITE], F_SETFL, O_NONBLOCK);
if (err)
goto out;
return 0;
out:
close(p->pipe[POLL_READ]);
close(p->pipe[POLL_WRITE]);
tapdisk_stream_poll_initialize(p);
return -errno;
}
static void
tapdisk_stream_poll_close(struct tapdisk_stream_poll *p)
{
if (p->pipe[POLL_READ] != -1)
close(p->pipe[POLL_READ]);
if (p->pipe[POLL_WRITE] != -1)
close(p->pipe[POLL_WRITE]);
tapdisk_stream_poll_initialize(p);
}
static inline void
tapdisk_stream_poll_clear(struct tapdisk_stream_poll *p)
{
int dummy;
read_exact(p->pipe[POLL_READ], &dummy, sizeof(dummy));
p->set = 0;
}
static inline void
tapdisk_stream_poll_set(struct tapdisk_stream_poll *p)
{
int dummy = 0;
if (!p->set) {
write_exact(p->pipe[POLL_WRITE], &dummy, sizeof(dummy));
p->set = 1;
}
}
static inline int
tapdisk_stream_stop(struct tapdisk_stream *s)
{
return ((s->cur == s->end || s->err) &&
list_empty(&s->pending_list) &&
list_empty(&s->completed_list));
}
static inline void
tapdisk_stream_initialize_request(struct tapdisk_stream_request *req)
{
memset(req, 0, sizeof(*req));
INIT_LIST_HEAD(&req->next);
}
static inline int
tapdisk_stream_request_idx(struct tapdisk_stream *s,
struct tapdisk_stream_request *req)
{
return (req - s->requests);
}
static inline struct tapdisk_stream_request *
tapdisk_stream_get_request(struct tapdisk_stream *s)
{
struct tapdisk_stream_request *req;
if (list_empty(&s->free_list))
return NULL;
req = list_entry(s->free_list.next,
struct tapdisk_stream_request, next);
list_del_init(&req->next);
tapdisk_stream_initialize_request(req);
return req;
}
static inline void
tapdisk_stream_queue_completed(struct tapdisk_stream *s,
struct tapdisk_stream_request *sreq)
{
struct tapdisk_stream_request *itr;
list_for_each_entry(itr, &s->completed_list, next)
if (sreq->seqno < itr->seqno) {
list_add_tail(&sreq->next, &itr->next);
return;
}
list_add_tail(&sreq->next, &s->completed_list);
}
static int
tapdisk_result_compare(struct tapdisk_stream_request *sreq1,
struct tapdisk_stream_request *sreq2)
{
unsigned long idx1, idx2;
char *buf1, *buf2;
int result;
assert(sreq1->seqno == sreq2->seqno);
assert(sreq1->secs == sreq2->secs);
idx1 = (unsigned long)tapdisk_stream_request_idx(&stream1,
sreq1);
idx2 = (unsigned long)tapdisk_stream_request_idx(&stream2,
sreq2);
buf1 = (char *)MMAP_VADDR(stream1.vbd->ring.vstart, idx1, 0);
buf2 = (char *)MMAP_VADDR(stream2.vbd->ring.vstart, idx2, 0);
result = memcmp(buf1, buf2, sreq1->secs << SECTOR_SHIFT);
return result;
}
static int
tapdisk_stream_process_data(void)
{
struct tapdisk_stream_request *sreq1, *sreq2, *tmp1, *tmp2;
int advance_both;
int result = 0;
sreq1 = list_entry(stream1.completed_list.next,
struct tapdisk_stream_request, next);
sreq2 = list_entry(stream2.completed_list.next,
struct tapdisk_stream_request, next);
tmp1 = list_entry(sreq1->next.next,
struct tapdisk_stream_request, next);
tmp2 = list_entry(sreq2->next.next,
struct tapdisk_stream_request, next);
while (result == 0 &&
&sreq1->next != &stream1.completed_list &&
&sreq2->next != &stream2.completed_list) {
//printf("checking: %llu|%llu\n", sreq1->seqno, sreq2->seqno);
advance_both = 1;
if (sreq1->seqno < sreq2->seqno) {
advance_both = 0;
goto advance1;
}
if (sreq1->seqno > sreq2->seqno)
goto advance2;
result = tapdisk_result_compare(sreq1, sreq2);
stream1.completed++;
stream2.completed++;
list_del_init(&sreq1->next);
list_add_tail(&sreq1->next, &stream1.free_list);
list_del_init(&sreq2->next);
list_add_tail(&sreq2->next, &stream2.free_list);
advance1:
sreq1 = tmp1;
tmp1 = list_entry(tmp1->next.next,
struct tapdisk_stream_request, next);
if (!advance_both)
continue;
advance2:
sreq2 = tmp2;
tmp2 = list_entry(tmp2->next.next,
struct tapdisk_stream_request, next);
}
return result;
}
static void
tapdisk_stream_dequeue(void *arg, blkif_response_t *rsp)
{
struct tapdisk_stream *s = (struct tapdisk_stream *)arg;
struct tapdisk_stream_request *sreq = s->requests + rsp->id;
list_del_init(&sreq->next);
if (rsp->status == BLKIF_RSP_OKAY)
tapdisk_stream_queue_completed(s, sreq);
else {
s->err = EIO;
list_add_tail(&sreq->next, &s->free_list);
fprintf(stderr, "error reading sector 0x%"PRIx64"\n", sreq->sec);
}
if (tapdisk_stream_process_data()) {
fprintf(stderr, "mismatch at sector 0x%"PRIx64"\n",
sreq->sec);
stream1.err = EINVAL;
stream2.err = EINVAL;
}
tapdisk_stream_poll_set(&stream1.poll);
tapdisk_stream_poll_set(&stream2.poll);
}
static inline int
tapdisk_stream_enqueue_copy(struct tapdisk_stream *s,
struct tapdisk_stream_request *r)
{
td_vbd_t *vbd;
blkif_request_t *breq;
td_vbd_request_t *vreq;
struct tapdisk_stream_request *sreq;
int idx;
vbd = stream2.vbd;
sreq = tapdisk_stream_get_request(s);
if (!sreq)
return 1;
idx = tapdisk_stream_request_idx(s, sreq);
sreq->sec = r->sec;
sreq->secs = r->secs;
sreq->seqno = r->seqno;
breq = &sreq->blkif_req;
breq->id = idx;
breq->nr_segments = r->blkif_req.nr_segments;
breq->sector_number = r->blkif_req.sector_number;
breq->operation = BLKIF_OP_READ;
for (int i = 0; i < r->blkif_req.nr_segments; i++) {
struct blkif_request_segment *seg = breq->seg + i;
seg->first_sect = r->blkif_req.seg[i].first_sect;
seg->last_sect = r->blkif_req.seg[i].last_sect;
}
s->cur += sreq->secs;
vreq = vbd->request_list + idx;
assert(list_empty(&vreq->next));
assert(vreq->secs_pending == 0);
memcpy(&vreq->req, breq, sizeof(*breq));
vbd->received++;
vreq->vbd = vbd;
tapdisk_vbd_move_request(vreq, &vbd->new_requests);
list_add_tail(&sreq->next, &s->pending_list);
return 0;
}
static void
tapdisk_stream_enqueue1(void)
{
td_vbd_t *vbd;
int i, idx, psize, blk;
struct tapdisk_stream *s = &stream1;
vbd = s->vbd;
psize = getpagesize();
while (s->cur < s->end && !s->err) {
blkif_request_t *breq;
td_vbd_request_t *vreq;
struct tapdisk_stream_request *sreq;
/* skip any blocks that are not present in this image */
blk = s->cur >> SPB_SHIFT;
while (s->cur < s->end && vhd1.bat.bat[blk] == DD_BLK_UNUSED) {
//printf("skipping block %d\n", blk);
blk++;
s->cur = blk << SPB_SHIFT;
}
if (s->cur >= s->end)
break;
sreq = tapdisk_stream_get_request(s);
if (!sreq)
break;
idx = tapdisk_stream_request_idx(s, sreq);
sreq->sec = s->cur;
sreq->secs = 0;
sreq->seqno = s->started++;
breq = &sreq->blkif_req;
breq->id = idx;
breq->nr_segments = 0;
breq->sector_number = sreq->sec;
breq->operation = BLKIF_OP_READ;
for (i = 0; i < BLKIF_MAX_SEGMENTS_PER_REQUEST; i++) {
uint32_t secs;
struct blkif_request_segment *seg = breq->seg + i;
secs = MIN(s->end - s->cur, psize >> SECTOR_SHIFT);
secs = MIN(((blk + 1) << SPB_SHIFT) - s->cur, secs);
if (!secs)
break;
sreq->secs += secs;
s->cur += secs;
seg->first_sect = 0;
seg->last_sect = secs - 1;
breq->nr_segments++;
}
vreq = vbd->request_list + idx;
assert(list_empty(&vreq->next));
assert(vreq->secs_pending == 0);
memcpy(&vreq->req, breq, sizeof(*breq));
vbd->received++;
vreq->vbd = vbd;
tapdisk_vbd_move_request(vreq, &vbd->new_requests);
list_add_tail(&sreq->next, &s->pending_list);
}
tapdisk_vbd_issue_requests(vbd);
}
static void
tapdisk_stream_enqueue2(void)
{
td_vbd_t *vbd;
int i, blk;
struct tapdisk_stream_request *itr;
struct tapdisk_stream *s = &stream2;
vbd = s->vbd;
/* issue the same requests that we issued on stream1 */
list_for_each_entry(itr, &stream1.completed_list, next) {
if (itr->sec < s->cur)
continue;
if (tapdisk_stream_enqueue_copy(s, itr))
goto done;
}
list_for_each_entry(itr, &stream1.pending_list, next) {
if (itr->sec < s->cur)
continue;
if (tapdisk_stream_enqueue_copy(s, itr))
goto done;
}
stream2.cur = stream1.cur;
done:
tapdisk_vbd_issue_requests(vbd);
}
static inline int
tapdisk_diff_done(void)
{
return (tapdisk_stream_stop(&stream1) && tapdisk_stream_stop(&stream2));
}
static void
tapdisk_diff_stop(void)
{
tapdisk_stream_close_image(&stream1);
tapdisk_stream_close_image(&stream2);
}
static void
tapdisk_stream_enqueue(event_id_t id, char mode, void *arg)
{
struct tapdisk_stream *s = (struct tapdisk_stream *)arg;
tapdisk_stream_poll_clear(&s->poll);
if (tapdisk_diff_done()) {
tapdisk_diff_stop();
return;
}
if (s == &stream1)
tapdisk_stream_enqueue1();
else if (s == &stream2)
tapdisk_stream_enqueue2();
else
assert(0);
if (tapdisk_diff_done()) {
// we have to check again for the case when stream1 had no
// blocks at all
tapdisk_diff_stop();
return;
}
}
static int
tapdisk_stream_open_image(struct tapdisk_stream *s, const char *path, int type)
{
int err;
image_t image;
s->id = tapdisk_stream_count++;
err = tapdisk_vbd_initialize(s->id);
if (err)
goto out;
s->vbd = tapdisk_server_get_vbd(s->id);
if (!s->vbd) {
err = ENODEV;
goto out;
}
tapdisk_vbd_set_callback(s->vbd, tapdisk_stream_dequeue, s);
err = tapdisk_vbd_open_vdi(s->vbd, path, type,
TAPDISK_STORAGE_TYPE_DEFAULT,
TD_OPEN_RDONLY);
if (err)
goto out;
s->vbd->reopened = 1;
err = tapdisk_vbd_get_image_info(s->vbd, &image);
if (err) {
fprintf(stderr, "failed getting image size: %d\n", err);
return err;
}
s->start = 0;
s->cur = s->start;
s->end = image.size;
err = 0;
out:
if (err)
fprintf(stderr, "failed to open image %s: %d\n", path, err);
return err;
}
static void
tapdisk_stream_close_image(struct tapdisk_stream *s)
{
td_vbd_t *vbd;
vbd = tapdisk_server_get_vbd(s->id);
if (vbd) {
tapdisk_vbd_close_vdi(vbd);
tapdisk_server_remove_vbd(vbd);
free((void *)vbd->ring.vstart);
free(vbd->name);
free(vbd);
s->vbd = NULL;
}
}
static int
tapdisk_stream_initialize_requests(struct tapdisk_stream *s)
{
size_t size;
td_ring_t *ring;
int err, i, psize;
ring = &s->vbd->ring;
psize = getpagesize();
size = psize * BLKTAP_MMAP_REGION_SIZE;
/* sneaky -- set up ring->vstart so tapdisk_vbd will use our buffers */
err = posix_memalign((void **)&ring->vstart, psize, size);
if (err) {
fprintf(stderr, "failed to allocate buffers: %d\n", err);
ring->vstart = 0;
return err;
}
for (i = 0; i < MAX_REQUESTS; i++) {
struct tapdisk_stream_request *req = s->requests + i;
tapdisk_stream_initialize_request(req);
list_add_tail(&req->next, &s->free_list);
}
return 0;
}
static int
tapdisk_stream_register_enqueue_event(struct tapdisk_stream *s)
{
int err;
struct tapdisk_stream_poll *p = &s->poll;
err = tapdisk_stream_poll_open(p);
if (err)
goto out;
err = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
p->pipe[POLL_READ], 0,
tapdisk_stream_enqueue, s);
if (err < 0)
goto out;
s->enqueue_event_id = err;
err = 0;
out:
if (err)
fprintf(stderr, "failed to register event: %d\n", err);
return err;
}
static void
tapdisk_stream_unregister_enqueue_event(struct tapdisk_stream *s)
{
if (s->enqueue_event_id) {
tapdisk_server_unregister_event(s->enqueue_event_id);
s->enqueue_event_id = 0;
}
tapdisk_stream_poll_close(&s->poll);
}
static inline void
tapdisk_stream_initialize(struct tapdisk_stream *s)
{
memset(s, 0, sizeof(*s));
INIT_LIST_HEAD(&s->free_list);
INIT_LIST_HEAD(&s->pending_list);
INIT_LIST_HEAD(&s->completed_list);
}
static int
tapdisk_stream_open(struct tapdisk_stream *s, const char *arg)
{
int err, type;
const char *path;
type = tapdisk_disktype_parse_params(arg, &path);
if (type < 0)
return type;
tapdisk_stream_initialize(s);
err = tapdisk_stream_open_image(s, path, type);
if (err)
return err;
err = tapdisk_stream_initialize_requests(s);
if (err)
return err;
err = tapdisk_stream_register_enqueue_event(s);
if (err)
return err;
tapdisk_stream_enqueue(s->enqueue_event_id,
SCHEDULER_POLL_READ_FD, s);
return 0;
}
static void
tapdisk_stream_release(struct tapdisk_stream *s)
{
tapdisk_stream_close_image(s);
tapdisk_stream_unregister_enqueue_event(s);
}
static int
tapdisk_stream_run(struct tapdisk_stream *s)
{
tapdisk_stream_enqueue(s->enqueue_event_id, SCHEDULER_POLL_READ_FD, s);
tapdisk_server_run();
return s->err;
}
int
main(int argc, char *argv[])
{
int c, err, type1;
const char *arg1 = NULL, *arg2 = NULL;
const disk_info_t *info;
const char *path1;
err = 0;
program = basename(argv[0]);
while ((c = getopt(argc, argv, "n:m:h")) != -1) {
switch (c) {
case 'n':
arg1 = optarg;
break;
case 'm':
arg2 = optarg;
break;
case 'h':
usage(stdout);
return 0;
default:
goto fail_usage;
}
}
if (!arg1 || !arg2)
goto fail_usage;
type1 = tapdisk_disktype_parse_params(arg1, &path1);
if (type1 < 0)
return type1;
if (type1 != DISK_TYPE_VHD) {
printf("error: first VDI is not VHD\n");
return EINVAL;
}
err = open_vhd(path1, &vhd1);
if (err)
return err;
tapdisk_start_logging("tapdisk-diff");
err = tapdisk_server_initialize();
if (err)
goto out;
err = tapdisk_stream_open(&stream1, arg1);
if (err) {
fprintf(stderr, "Failed to open %s: %s\n",
arg1, strerror(-err));
goto out;
}
err = tapdisk_stream_open(&stream2, arg2);
if (err) {
fprintf(stderr, "Failed to open %s: %s\n",
arg2, strerror(-err));
goto out1;
}
if (stream1.end != stream2.end) {
fprintf(stderr, "Image sizes differ: %"PRIu64" != %"PRIu64"\n",
stream1.end, stream2.end);
err = EINVAL;
goto out2;
}
tapdisk_server_run();
out2:
tapdisk_stream_release(&stream2);
out1:
tapdisk_stream_release(&stream1);
out:
vhd_close(&vhd1);
tapdisk_stop_logging();
return err ? : stream1.err;
fail_usage:
usage(stderr);
return 1;
}
-200
View File
@@ -1,200 +0,0 @@
/*
* Copyright (c) 2007, 2010, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include "tapdisk-disktype.h"
#include "tapdisk-message.h"
#define ARRAY_SIZE(a) (sizeof (a) / sizeof *(a))
static const disk_info_t aio_disk = {
"aio",
"raw image (aio)",
0,
};
static const disk_info_t sync_disk = {
"sync",
"raw image (sync)",
0,
};
static const disk_info_t vmdk_disk = {
"vmdk",
"vmware image (vmdk)",
1,
};
static const disk_info_t vhdsync_disk = {
"vhdsync",
"virtual server image (vhd) - synchronous",
1,
};
static const disk_info_t vhd_disk = {
"vhd",
"virtual server image (vhd)",
0,
};
static const disk_info_t ram_disk = {
"ram",
"ramdisk image (ram)",
1,
};
static const disk_info_t qcow_disk = {
"qcow",
"qcow disk (qcow)",
0,
};
static const disk_info_t block_cache_disk = {
"bc",
"block cache image (bc)",
1,
};
static const disk_info_t vhd_index_disk = {
"vhdi",
"vhd index image (vhdi)",
1,
};
static const disk_info_t log_disk = {
"log",
"write logger (log)",
0,
};
static const disk_info_t remus_disk = {
"remus",
"remus disk replicator (remus)",
0,
};
const disk_info_t *tapdisk_disk_types[] = {
[DISK_TYPE_AIO] = &aio_disk,
[DISK_TYPE_SYNC] = &sync_disk,
[DISK_TYPE_VMDK] = &vmdk_disk,
[DISK_TYPE_VHDSYNC] = &vhdsync_disk,
[DISK_TYPE_VHD] = &vhd_disk,
[DISK_TYPE_RAM] = &ram_disk,
[DISK_TYPE_QCOW] = &qcow_disk,
[DISK_TYPE_BLOCK_CACHE] = &block_cache_disk,
[DISK_TYPE_LOG] = &log_disk,
[DISK_TYPE_VINDEX] = &vhd_index_disk,
[DISK_TYPE_REMUS] = &remus_disk,
};
extern struct tap_disk tapdisk_aio;
extern struct tap_disk tapdisk_vhdsync;
extern struct tap_disk tapdisk_vhd;
extern struct tap_disk tapdisk_ram;
extern struct tap_disk tapdisk_qcow;
extern struct tap_disk tapdisk_block_cache;
extern struct tap_disk tapdisk_log;
extern struct tap_disk tapdisk_remus;
const struct tap_disk *tapdisk_disk_drivers[ARRAY_SIZE(tapdisk_disk_types)] = {
[DISK_TYPE_AIO] = &tapdisk_aio,
[DISK_TYPE_VHD] = &tapdisk_vhd,
[DISK_TYPE_RAM] = &tapdisk_ram,
[DISK_TYPE_QCOW] = &tapdisk_qcow,
[DISK_TYPE_BLOCK_CACHE] = &tapdisk_block_cache,
[DISK_TYPE_LOG] = &tapdisk_log,
[DISK_TYPE_REMUS] = &tapdisk_remus,
};
int
tapdisk_disktype_find(const char *name)
{
const disk_info_t *info;
int i;
for (i = 0; i < ARRAY_SIZE(tapdisk_disk_types); ++i) {
info = tapdisk_disk_types[i];
if (!info)
continue;
if (strcmp(name, info->name))
continue;
if (!tapdisk_disk_drivers[i])
return -ENOSYS;
return i;
}
return -ENOENT;
}
int
tapdisk_disktype_parse_params(const char *params, const char **_path)
{
char name[DISK_TYPE_NAME_MAX], *ptr;
size_t len;
int type;
ptr = strchr(params, ':');
if (!ptr)
return -EINVAL;
len = ptr - params;
if (len > sizeof(name) - 1)
return -ENAMETOOLONG;
memset(name, 0, sizeof(name));
strncpy(name, params, len);
type = tapdisk_disktype_find(name);
if (type >= 0)
*_path = params + len + 1;
return type;
}
int
tapdisk_parse_disk_type(const char *params, const char **_path, int *_type)
{
int type;
type = tapdisk_disktype_parse_params(params, _path);
if (type < 0)
return type;
*_type = type;
return 0;
}
-62
View File
@@ -1,62 +0,0 @@
/*
* Copyright (c) 2007, 2010, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __DISKTYPES_H__
#define __DISKTYPES_H__
#define DISK_TYPE_AIO 0
#define DISK_TYPE_SYNC 1
#define DISK_TYPE_VMDK 2
#define DISK_TYPE_VHDSYNC 3
#define DISK_TYPE_VHD 4
#define DISK_TYPE_RAM 5
#define DISK_TYPE_QCOW 6
#define DISK_TYPE_BLOCK_CACHE 7
#define DISK_TYPE_LOG 8
#define DISK_TYPE_REMUS 9
#define DISK_TYPE_VINDEX 10
#define DISK_TYPE_NAME_MAX 32
typedef struct disk_info {
const char *name; /* driver name, e.g. 'aio' */
char *desc; /* e.g. "raw image" */
unsigned int flags;
} disk_info_t;
extern const disk_info_t *tapdisk_disk_types[];
extern const struct tap_disk *tapdisk_disk_drivers[];
/* one single controller for all instances of disk type */
#define DISK_TYPE_SINGLE_CONTROLLER (1<<0)
int tapdisk_disktype_find(const char *name);
int tapdisk_disktype_parse_params(const char *params, const char **_path);
int tapdisk_parse_disk_type(const char *, const char **, int *);
#endif
-101
View File
@@ -1,101 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include "tapdisk-driver.h"
#include "tapdisk-server.h"
#include "tapdisk-disktype.h"
td_driver_t *
tapdisk_driver_allocate(int type, char *name, td_flag_t flags, int storage)
{
int err;
td_driver_t *driver;
const struct tap_disk *ops;
ops = tapdisk_disk_drivers[type];
if (!ops)
return NULL;
driver = calloc(1, sizeof(td_driver_t));
if (!driver)
return NULL;
err = tapdisk_namedup(&driver->name, name);
if (err)
goto fail;
driver->ops = ops;
driver->type = type;
driver->storage = storage;
driver->data = calloc(1, ops->private_data_size);
if (!driver->data)
goto fail;
if (td_flag_test(flags, TD_OPEN_RDONLY))
td_flag_set(driver->state, TD_DRIVER_RDONLY);
return driver;
fail:
free(driver->name);
free(driver->data);
free(driver);
return NULL;
}
void
tapdisk_driver_free(td_driver_t *driver)
{
if (!driver)
return;
if (driver->refcnt)
return;
if (td_flag_test(driver->state, TD_DRIVER_OPEN))
EPRINTF("freeing open driver %s (state 0x%08x)\n",
driver->name, driver->state);
free(driver->name);
free(driver->data);
free(driver);
}
void
tapdisk_driver_queue_tiocb(td_driver_t *driver, struct tiocb *tiocb)
{
tapdisk_server_queue_tiocb(tiocb);
}
void
tapdisk_driver_debug(td_driver_t *driver)
{
if (driver->ops->td_debug)
driver->ops->td_debug(driver);
}
-62
View File
@@ -1,62 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TAPDISK_DRIVER_H_
#define _TAPDISK_DRIVER_H_
#include "tapdisk.h"
#include "scheduler.h"
#include "tapdisk-queue.h"
#define TD_DRIVER_OPEN 0x0001
#define TD_DRIVER_RDONLY 0x0002
struct td_driver_handle {
int type;
char *name;
int storage;
int refcnt;
td_flag_t state;
td_disk_info_t info;
void *data;
const struct tap_disk *ops;
struct list_head next;
};
td_driver_t *tapdisk_driver_allocate(int, char *, td_flag_t, int);
void tapdisk_driver_free(td_driver_t *);
void tapdisk_driver_queue_tiocb(td_driver_t *, struct tiocb *);
void tapdisk_driver_debug(td_driver_t *);
#endif
-272
View File
@@ -1,272 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <unistd.h>
#include <libaio.h>
#include <syslog.h>
#include <sys/time.h>
#include "tapdisk-log.h"
#include "tapdisk-filter.h"
#define RSEED 7
#define PRE_CHECK 0
#define POST_CHECK 1
#define WRITE_INTEGRITY "buffer integrity failure after write"
#define READ_INTEGRITY "disk integrity failure after read"
#define DBG(f, a...) tlog_write(TLOG_WARN, f, ##a)
/*
* simulate IO errors by knocking request size to zero before
* submitting and restoring original size before returning
*/
static inline void
inject_fault(struct tfilter *filter, struct iocb *io)
{
struct fiocb *fio;
if (!filter->ffree)
return;
fio = filter->flist[--filter->ffree];
fio->bytes = io->u.c.nbytes;
fio->data = io->data;
io->u.c.nbytes = 0;
io->data = fio;
}
static inline int
fault_injected(struct tfilter *filter, struct iocb *io)
{
unsigned long iop = (unsigned long)io->data;
unsigned long start = (unsigned long)filter->fiocbs;
unsigned long end = start + (filter->iocbs * sizeof(struct fiocb));
return (iop >= start && iop < end);
}
static inline void
recover_fault(struct tfilter *filter, struct iocb *io)
{
struct fiocb *fio = (struct fiocb *)io->data;
io->u.c.nbytes = fio->bytes;
io->data = fio->data;
memset(fio, 0, sizeof(struct fiocb));
filter->flist[filter->ffree++] = fio;
}
static inline uint64_t
chksum(char *buf)
{
int i, num = 512 >> 3;
uint64_t *p = (uint64_t *)buf;
uint64_t sum = 0;
for (i = 0; i < num; i++)
sum += p[i];
return sum;
}
static inline void
check_hash(struct tfilter *filter, uint64_t sec, char *buf, char *type)
{
uint64_t sum;
struct dhash *hash;
hash = filter->dhash + sec;
if (!hash->time.tv_sec)
return;
sum = chksum(buf);
if (hash->hash != chksum(buf)) {
struct timeval now;
gettimeofday(&now, NULL);
DBG("%s: hash table: 0x%020" PRIx64 " at %012lu.%06llu, "
"from disk: 0x%020" PRIx64 " at %012lu.%06llu\n",
type, hash->hash, hash->time.tv_sec,
(unsigned long long)hash->time.tv_usec, sum,
now.tv_sec, (unsigned long long)now.tv_usec);
}
}
static inline void
insert_hash(struct tfilter *filter, uint64_t sec, char *buf)
{
struct dhash *hash;
hash = filter->dhash + sec;
hash->hash = chksum(buf);
gettimeofday(&hash->time, NULL);
}
static void
check_sector(struct tfilter *filter, int type, int rw, uint64_t sec, char *buf)
{
struct dhash *hash;
if (sec >= filter->secs)
return;
hash = filter->dhash + sec;
if (rw) {
if (type == PRE_CHECK)
insert_hash(filter, sec, buf);
else
check_hash(filter, sec, buf, WRITE_INTEGRITY);
} else if (type == POST_CHECK) {
check_hash(filter, sec, buf, READ_INTEGRITY);
insert_hash(filter, sec, buf);
}
}
static void
check_data(struct tfilter *filter, int type, struct iocb *io)
{
int rw;
uint64_t i, sec;
rw = (io->aio_lio_opcode == IO_CMD_PWRITE);
for (i = 0; i < io->u.c.nbytes; i += 512) {
char *buf = io->u.c.buf + i;
uint64_t sec = (io->u.c.offset + i) >> 9;
check_sector(filter, type, rw, sec, buf);
}
}
struct tfilter *
tapdisk_init_tfilter(int mode, int iocbs, uint64_t secs)
{
int i;
struct tfilter *filter = NULL;
if (!mode)
return NULL;
filter = calloc(1, sizeof(struct tfilter));
if (!filter)
goto fail;
filter->mode = mode;
filter->secs = secs;
filter->iocbs = iocbs;
if (filter->mode & TD_INJECT_FAULTS) {
filter->fiocbs = calloc(iocbs, sizeof(struct fiocb));
filter->flist = calloc(iocbs, sizeof(struct fiocb *));
if (!filter->fiocbs || !filter->flist)
filter->mode &= ~TD_INJECT_FAULTS;
else {
srand(RSEED);
filter->ffree = iocbs;
for (i = 0; i < iocbs; i++)
filter->flist[i] = filter->fiocbs + i;
}
}
if (filter->mode & TD_CHECK_INTEGRITY) {
filter->dhash = calloc(secs, sizeof(struct dhash));
if (!filter->dhash)
filter->mode &= ~TD_CHECK_INTEGRITY;
}
syslog(LOG_WARNING, "WARNING: "
"FILTERING IN MODE 0x%04x\n", filter->mode);
return filter;
fail:
tapdisk_free_tfilter(filter);
return NULL;
}
void
tapdisk_free_tfilter(struct tfilter *filter)
{
if (!filter)
return;
free(filter->dhash);
free(filter->flist);
free(filter->fiocbs);
free(filter);
}
void
tapdisk_filter_iocbs(struct tfilter *filter, struct iocb **iocbs, int num)
{
int i;
if (!filter)
return;
for (i = 0; i < num; i++) {
struct iocb *io = iocbs[i];
if (filter->mode & TD_INJECT_FAULTS) {
if ((random() % 100) <= TD_FAULT_RATE) {
inject_fault(filter, io);
continue;
}
}
if (filter->mode & TD_CHECK_INTEGRITY)
check_data(filter, PRE_CHECK, io);
}
}
void
tapdisk_filter_events(struct tfilter *filter, struct io_event *events, int num)
{
int i;
if (!filter)
return;
for (i = 0; i < num; i++) {
struct iocb *io = events[i].obj;
if (filter->mode & TD_INJECT_FAULTS) {
if (fault_injected(filter, io)) {
recover_fault(filter, io);
continue;
}
}
if (filter->mode & TD_CHECK_INTEGRITY)
check_data(filter, POST_CHECK, io);
}
}
-67
View File
@@ -1,67 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TAPDISK_FILTER_H
#define TAPDISK_FILTER_H
#include <libaio.h>
#include <inttypes.h>
#include <time.h>
#define TD_INJECT_FAULTS 0x00001 /* simulate random IO failures */
#define TD_CHECK_INTEGRITY 0x00002 /* check data integrity */
#define TD_FAULT_RATE 5
struct dhash {
uint64_t hash;
struct timeval time;
};
struct fiocb {
size_t bytes;
void *data;
};
struct tfilter {
int mode;
uint64_t secs;
int iocbs;
struct dhash *dhash;
int ffree;
struct fiocb *fiocbs;
struct fiocb **flist;
};
struct tfilter *tapdisk_init_tfilter(int mode, int iocbs, uint64_t secs);
void tapdisk_free_tfilter(struct tfilter *);
void tapdisk_filter_iocbs(struct tfilter *, struct iocb **, int);
void tapdisk_filter_events(struct tfilter *, struct io_event *, int);
#endif
-169
View File
@@ -1,169 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#ifdef MEMSHR
#include <memshr.h>
#endif
#include "tapdisk-image.h"
#include "tapdisk-driver.h"
#include "tapdisk-server.h"
#define ERR(_err, _f, _a...) tlog_error(_err, _f, ##_a)
td_image_t *
tapdisk_image_allocate(const char *file, int type, int storage,
td_flag_t flags, void *private)
{
int err;
td_image_t *image;
image = calloc(1, sizeof(td_image_t));
if (!image)
return NULL;
err = tapdisk_namedup(&image->name, file);
if (err) {
free(image);
return NULL;
}
image->type = type;
image->flags = flags;
image->storage = storage;
image->private = private;
#ifdef MEMSHR
image->memshr_id = memshr_vbd_image_get(file);
#endif
INIT_LIST_HEAD(&image->next);
return image;
}
void
tapdisk_image_free(td_image_t *image)
{
if (!image)
return;
list_del(&image->next);
#ifdef MEMSHR
memshr_vbd_image_put(image->memshr_id);
#endif
free(image->name);
tapdisk_driver_free(image->driver);
free(image);
}
int
tapdisk_image_check_td_request(td_image_t *image, td_request_t treq)
{
int rdonly;
td_driver_t *driver;
td_disk_info_t *info;
driver = image->driver;
if (!driver)
return -ENODEV;
info = &driver->info;
rdonly = td_flag_test(image->flags, TD_OPEN_RDONLY);
if (treq.op != TD_OP_READ && treq.op != TD_OP_WRITE)
goto fail;
if (treq.op == TD_OP_WRITE && rdonly)
goto fail;
if (treq.secs <= 0 || treq.sec + treq.secs > info->size)
goto fail;
return 0;
fail:
ERR(-EINVAL, "bad td request on %s (%s, %"PRIu64"): %d at %"PRIu64,
image->name, (rdonly ? "ro" : "rw"), info->size, treq.op,
treq.sec + treq.secs);
return -EINVAL;
}
int
tapdisk_image_check_ring_request(td_image_t *image, blkif_request_t *req)
{
td_driver_t *driver;
td_disk_info_t *info;
int i, psize, rdonly;
uint64_t nsects, total;
driver = image->driver;
if (!driver)
return -ENODEV;
nsects = 0;
total = 0;
info = &driver->info;
rdonly = td_flag_test(image->flags, TD_OPEN_RDONLY);
if (req->operation != BLKIF_OP_READ &&
req->operation != BLKIF_OP_WRITE)
goto fail;
if (req->operation == BLKIF_OP_WRITE && rdonly)
goto fail;
if (!req->nr_segments || req->nr_segments > MAX_SEGMENTS_PER_REQ)
goto fail;
total = 0;
psize = getpagesize();
for (i = 0; i < req->nr_segments; i++) {
nsects = req->seg[i].last_sect - req->seg[i].first_sect + 1;
if (req->seg[i].last_sect >= psize >> 9 || nsects <= 0)
goto fail;
total += nsects;
}
if (req->sector_number + nsects > info->size)
goto fail;
return 0;
fail:
ERR(-EINVAL, "bad request on %s (%s, %"PRIu64"): id: %"PRIu64": %d at %"PRIu64,
image->name, (rdonly ? "ro" : "rw"), info->size, req->id,
req->operation, req->sector_number + total);
return -EINVAL;
}
-56
View File
@@ -1,56 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TAPDISK_IMAGE_H_
#define _TAPDISK_IMAGE_H_
#include "tapdisk.h"
#include <xen/io/blkif.h>
struct td_image_handle {
int type;
char *name;
uint16_t memshr_id;
td_flag_t flags;
int storage;
td_driver_t *driver;
td_disk_info_t info;
void *private;
struct list_head next;
};
td_image_t *tapdisk_image_allocate(const char *, int, int, td_flag_t, void *);
void tapdisk_image_free(td_image_t *);
int tapdisk_image_check_td_request(td_image_t *, td_request_t);
int tapdisk_image_check_ring_request(td_image_t *, blkif_request_t *);
#endif
-259
View File
@@ -1,259 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include "tapdisk.h"
#include "tapdisk-vbd.h"
#include "tapdisk-image.h"
#include "tapdisk-driver.h"
#include "tapdisk-server.h"
#include "tapdisk-interface.h"
int
td_load(td_image_t *image)
{
int err;
td_image_t *shared;
td_driver_t *driver;
shared = tapdisk_server_get_shared_image(image);
if (!shared)
return -ENODEV;
driver = shared->driver;
if (!driver)
return -EBADF;
driver->refcnt++;
image->driver = driver;
image->info = driver->info;
DPRINTF("loaded shared image %s (%d users, state: 0x%08x, type: %d)\n",
driver->name, driver->refcnt, driver->state, driver->type);
return 0;
}
int
__td_open(td_image_t *image, td_disk_info_t *info)
{
int err;
td_driver_t *driver;
driver = image->driver;
if (!driver) {
driver = tapdisk_driver_allocate(image->type,
image->name,
image->flags,
image->storage);
if (!driver)
return -ENOMEM;
if (info) /* pre-seed driver->info for virtual drivers */
driver->info = *info;
}
if (!td_flag_test(driver->state, TD_DRIVER_OPEN)) {
err = driver->ops->td_open(driver, image->name, image->flags);
if (err) {
if (!image->driver)
tapdisk_driver_free(driver);
return err;
}
td_flag_set(driver->state, TD_DRIVER_OPEN);
DPRINTF("opened image %s (%d users, state: 0x%08x, type: %d)\n",
driver->name, driver->refcnt + 1,
driver->state, driver->type);
}
image->driver = driver;
image->info = driver->info;
driver->refcnt++;
return 0;
}
int
td_open(td_image_t *image)
{
return __td_open(image, NULL);
}
int
td_close(td_image_t *image)
{
td_driver_t *driver;
driver = image->driver;
if (!driver)
return -ENODEV;
driver->refcnt--;
if (!driver->refcnt && td_flag_test(driver->state, TD_DRIVER_OPEN)) {
driver->ops->td_close(driver);
td_flag_clear(driver->state, TD_DRIVER_OPEN);
}
DPRINTF("closed image %s (%d users, state: 0x%08x, type: %d)\n",
driver->name, driver->refcnt, driver->state, driver->type);
return 0;
}
int
td_get_parent_id(td_image_t *image, td_disk_id_t *id)
{
td_driver_t *driver;
driver = image->driver;
if (!driver)
return -ENODEV;
if (!td_flag_test(driver->state, TD_DRIVER_OPEN))
return -EBADF;
return driver->ops->td_get_parent_id(driver, id);
}
int
td_validate_parent(td_image_t *image, td_image_t *parent)
{
td_driver_t *driver, *pdriver;
driver = image->driver;
pdriver = parent->driver;
if (!driver || !pdriver)
return -ENODEV;
if (!td_flag_test(driver->state, TD_DRIVER_OPEN) ||
!td_flag_test(pdriver->state, TD_DRIVER_OPEN))
return -EBADF;
return 0;
return driver->ops->td_validate_parent(driver, pdriver, 0);
}
void
td_queue_write(td_image_t *image, td_request_t treq)
{
int err;
td_driver_t *driver;
driver = image->driver;
if (!driver) {
err = -ENODEV;
goto fail;
}
if (!td_flag_test(driver->state, TD_DRIVER_OPEN)) {
err = -EBADF;
goto fail;
}
err = tapdisk_image_check_td_request(image, treq);
if (err)
goto fail;
driver->ops->td_queue_write(driver, treq);
return;
fail:
td_complete_request(treq, err);
}
void
td_queue_read(td_image_t *image, td_request_t treq)
{
int err;
td_driver_t *driver;
driver = image->driver;
if (!driver) {
err = -ENODEV;
goto fail;
}
if (!td_flag_test(driver->state, TD_DRIVER_OPEN)) {
err = -EBADF;
goto fail;
}
err = tapdisk_image_check_td_request(image, treq);
if (err)
goto fail;
driver->ops->td_queue_read(driver, treq);
return;
fail:
td_complete_request(treq, err);
}
void
td_forward_request(td_request_t treq)
{
tapdisk_vbd_forward_request(treq);
}
void
td_complete_request(td_request_t treq, int res)
{
((td_callback_t)treq.cb)(treq, res);
}
void
td_queue_tiocb(td_driver_t *driver, struct tiocb *tiocb)
{
tapdisk_driver_queue_tiocb(driver, tiocb);
}
void
td_prep_read(struct tiocb *tiocb, int fd, char *buf, size_t bytes,
long long offset, td_queue_callback_t cb, void *arg)
{
tapdisk_prep_tiocb(tiocb, fd, 0, buf, bytes, offset, cb, arg);
}
void
td_prep_write(struct tiocb *tiocb, int fd, char *buf, size_t bytes,
long long offset, td_queue_callback_t cb, void *arg)
{
tapdisk_prep_tiocb(tiocb, fd, 1, buf, bytes, offset, cb, arg);
}
void
td_debug(td_image_t *image)
{
td_driver_t *driver;
driver = image->driver;
if (!driver || !td_flag_test(driver->state, TD_DRIVER_OPEN))
return;
tapdisk_driver_debug(driver);
}
-54
View File
@@ -1,54 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TAPDISK_INTERFACE_H_
#define _TAPDISK_INTERFACE_H_
#include "tapdisk.h"
#include "tapdisk-queue.h"
int td_open(td_image_t *);
int __td_open(td_image_t *, td_disk_info_t *);
int td_load(td_image_t *);
int td_close(td_image_t *);
int td_get_parent_id(td_image_t *, td_disk_id_t *);
int td_validate_parent(td_image_t *, td_image_t *);
void td_queue_write(td_image_t *, td_request_t);
void td_queue_read(td_image_t *, td_request_t);
void td_forward_request(td_request_t);
void td_complete_request(td_request_t, int);
void td_debug(td_image_t *);
void td_queue_tiocb(td_driver_t *, struct tiocb *);
void td_prep_read(struct tiocb *, int, char *, size_t,
long long, td_queue_callback_t, void *);
void td_prep_write(struct tiocb *, int, char *, size_t,
long long, td_queue_callback_t, void *);
#endif
-257
View File
@@ -1,257 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <syslog.h>
#include <inttypes.h>
#include <sys/time.h>
#include "tapdisk-log.h"
#include "tapdisk-utils.h"
#define MAX_ENTRY_LEN 512
#define MAX_ERROR_MESSAGES 16
struct error {
int cnt;
int err;
char *func;
char msg[MAX_ENTRY_LEN];
};
struct ehandle {
int cnt;
int dropped;
struct error errors[MAX_ERROR_MESSAGES];
};
struct tlog {
char *p;
int size;
uint64_t cnt;
char *buf;
int level;
char *file;
int append;
};
static struct ehandle tapdisk_err;
static struct tlog tapdisk_log;
void
open_tlog(char *file, size_t bytes, int level, int append)
{
tapdisk_log.size = ((bytes + 511) & (~511));
if (asprintf(&tapdisk_log.file, "%s.%d", file, getpid()) == -1)
return;
if (posix_memalign((void **)&tapdisk_log.buf, 512, tapdisk_log.size)) {
free(tapdisk_log.file);
tapdisk_log.buf = NULL;
return;
}
memset(tapdisk_log.buf, 0, tapdisk_log.size);
tapdisk_log.p = tapdisk_log.buf;
tapdisk_log.level = level;
tapdisk_log.append = append;
}
void
close_tlog(void)
{
if (!tapdisk_log.buf)
return;
if (tapdisk_log.append)
tlog_flush();
free(tapdisk_log.buf);
free(tapdisk_log.file);
memset(&tapdisk_log, 0, sizeof(struct tlog));
}
void
__tlog_write(int level, const char *func, const char *fmt, ...)
{
char *buf;
va_list ap;
struct timeval t;
int ret, len, avail;
if (!tapdisk_log.buf)
return;
if (level > tapdisk_log.level)
return;
avail = tapdisk_log.size - (tapdisk_log.p - tapdisk_log.buf);
if (avail < MAX_ENTRY_LEN) {
if (tapdisk_log.append)
tlog_flush();
tapdisk_log.p = tapdisk_log.buf;
}
buf = tapdisk_log.p;
gettimeofday(&t, NULL);
len = snprintf(buf, MAX_ENTRY_LEN - 1, "%08"PRIu64":%010ld.%06lld:"
"%s ", tapdisk_log.cnt,
t.tv_sec, (unsigned long long)t.tv_usec, func);
va_start(ap, fmt);
ret = vsnprintf(buf + len, MAX_ENTRY_LEN - (len + 1), fmt, ap);
va_end(ap);
len = (ret < MAX_ENTRY_LEN - (len + 1) ?
len + ret : MAX_ENTRY_LEN - 1);
buf[len] = '\0';
tapdisk_log.cnt++;
tapdisk_log.p += len;
}
void
__tlog_error(int err, const char *func, const char *fmt, ...)
{
va_list ap;
int i, len, ret;
struct error *e;
struct timeval t;
err = (err > 0 ? err : -err);
for (i = 0; i < tapdisk_err.cnt; i++) {
e = &tapdisk_err.errors[i];
if (e->err == err && e->func == func) {
e->cnt++;
return;
}
}
if (tapdisk_err.cnt >= MAX_ERROR_MESSAGES) {
tapdisk_err.dropped++;
return;
}
gettimeofday(&t, NULL);
e = &tapdisk_err.errors[tapdisk_err.cnt];
len = snprintf(e->msg, MAX_ENTRY_LEN - 1, "%010ld.%06lld:%s ",
t.tv_sec, (unsigned long long)t.tv_usec, func);
va_start(ap, fmt);
ret = vsnprintf(e->msg + len, MAX_ENTRY_LEN - (len + 1), fmt, ap);
va_end(ap);
len = (ret < MAX_ENTRY_LEN - (len + 1) ?
len + ret : MAX_ENTRY_LEN - 1);
e->msg[len] = '\0';
e->cnt++;
e->err = err;
e->func = (char *)func;
tapdisk_err.cnt++;
}
void
tlog_print_errors(void)
{
int i;
struct error *e;
for (i = 0; i < tapdisk_err.cnt; i++) {
e = &tapdisk_err.errors[i];
syslog(LOG_INFO, "TAPDISK ERROR: errno %d at %s (cnt = %d): "
"%s\n", e->err, e->func, e->cnt, e->msg);
}
if (tapdisk_err.dropped)
syslog(LOG_INFO, "TAPDISK ERROR: %d other error messages "
"dropped\n", tapdisk_err.dropped);
}
void
tlog_flush_errors(void)
{
int i;
struct error *e;
for (i = 0; i < tapdisk_err.cnt; i++) {
e = &tapdisk_err.errors[i];
tlog_write(TLOG_WARN, "TAPDISK ERROR: errno %d at %s "
"(cnt = %d): %s\n", e->err, e->func, e->cnt,
e->msg);
}
if (tapdisk_err.dropped)
tlog_write(TLOG_WARN, "TAPDISK ERROR: %d other error messages "
"dropped\n", tapdisk_err.dropped);
}
void
tlog_flush(void)
{
int fd, flags;
size_t size, wsize;
if (!tapdisk_log.buf)
return;
flags = O_CREAT | O_WRONLY | O_DIRECT | O_NONBLOCK;
if (!tapdisk_log.append)
flags |= O_TRUNC;
fd = open(tapdisk_log.file, flags, 0644);
if (fd == -1)
return;
if (tapdisk_log.append)
if (lseek(fd, 0, SEEK_END) == (off_t)-1)
goto out;
tlog_flush_errors();
size = tapdisk_log.p - tapdisk_log.buf;
wsize = ((size + 511) & (~511));
memset(tapdisk_log.buf + size, '\n', wsize - size);
write_exact(fd, tapdisk_log.buf, wsize);
tapdisk_log.p = tapdisk_log.buf;
out:
close(fd);
}
-51
View File
@@ -1,51 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TAPDISK_LOG_H_
#define _TAPDISK_LOG_H_
#define TLOG_WARN 0
#define TLOG_INFO 1
#define TLOG_DBG 2
void open_tlog(char *file, size_t bytes, int level, int append);
void close_tlog(void);
void tlog_flush(void);
void tlog_print_errors(void);
void __tlog_write(int level, const char *func, const char *fmt, ...)
__attribute__((format(printf, 3, 4)));
void __tlog_error(int err, const char *func, const char *fmt, ...)
__attribute__((format(printf, 3, 4)));
#define tlog_write(_level, _f, _a...) \
__tlog_write(_level, __func__, _f, ##_a)
#define tlog_error(_err, _f, _a...) \
__tlog_error(_err, __func__, _f, ##_a)
#endif
-743
View File
@@ -1,743 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <libaio.h>
#ifdef __linux__
#include <linux/version.h>
#endif
#include "tapdisk.h"
#include "tapdisk-log.h"
#include "tapdisk-queue.h"
#include "tapdisk-filter.h"
#include "tapdisk-server.h"
#include "tapdisk-utils.h"
#include "libaio-compat.h"
#include "atomicio.h"
#define WARN(_f, _a...) tlog_write(TLOG_WARN, _f, ##_a)
#define DBG(_f, _a...) tlog_write(TLOG_DBG, _f, ##_a)
#define ERR(_err, _f, _a...) tlog_error(_err, _f, ##_a)
/*
* We used a kernel patch to return an fd associated with the AIO context
* so that we can concurrently poll on synchronous and async descriptors.
* This is signalled by passing 1 as the io context to io_setup.
*/
#define REQUEST_ASYNC_FD ((io_context_t)1)
static inline void
queue_tiocb(struct tqueue *queue, struct tiocb *tiocb)
{
struct iocb *iocb = &tiocb->iocb;
if (queue->queued) {
struct tiocb *prev = (struct tiocb *)
queue->iocbs[queue->queued - 1]->data;
prev->next = tiocb;
}
queue->iocbs[queue->queued++] = iocb;
}
static inline int
deferred_tiocbs(struct tqueue *queue)
{
return (queue->deferred.head != NULL);
}
static inline void
defer_tiocb(struct tqueue *queue, struct tiocb *tiocb)
{
struct tlist *list = &queue->deferred;
if (!list->head)
list->head = list->tail = tiocb;
else
list->tail = list->tail->next = tiocb;
queue->tiocbs_deferred++;
queue->deferrals++;
}
static inline void
queue_deferred_tiocb(struct tqueue *queue)
{
struct tlist *list = &queue->deferred;
if (list->head) {
struct tiocb *tiocb = list->head;
list->head = tiocb->next;
if (!list->head)
list->tail = NULL;
queue_tiocb(queue, tiocb);
queue->tiocbs_deferred--;
}
}
static inline void
queue_deferred_tiocbs(struct tqueue *queue)
{
while (!tapdisk_queue_full(queue) && deferred_tiocbs(queue))
queue_deferred_tiocb(queue);
}
/*
* td_complete may queue more tiocbs
*/
static void
complete_tiocb(struct tqueue *queue, struct tiocb *tiocb, unsigned long res)
{
int err;
struct iocb *iocb = &tiocb->iocb;
if (res == iocb->u.c.nbytes)
err = 0;
else if ((int)res < 0)
err = (int)res;
else
err = -EIO;
tiocb->cb(tiocb->arg, tiocb, err);
}
static int
cancel_tiocbs(struct tqueue *queue, int err)
{
int queued;
struct tiocb *tiocb;
if (!queue->queued)
return 0;
/*
* td_complete may queue more tiocbs, which
* will overwrite the contents of queue->iocbs.
* use a private linked list to keep track
* of the tiocbs we're cancelling.
*/
tiocb = queue->iocbs[0]->data;
queued = queue->queued;
queue->queued = 0;
for (; tiocb != NULL; tiocb = tiocb->next)
complete_tiocb(queue, tiocb, err);
return queued;
}
static int
fail_tiocbs(struct tqueue *queue, int succeeded, int total, int err)
{
ERR(err, "io_submit error: %d of %d failed",
total - succeeded, total);
/* take any non-submitted, merged iocbs
* off of the queue, split them, and fail them */
queue->queued = io_expand_iocbs(&queue->opioctx,
queue->iocbs, succeeded, total);
return cancel_tiocbs(queue, err);
}
/*
* rwio
*/
struct rwio {
struct io_event *aio_events;
};
static void
tapdisk_rwio_destroy(struct tqueue *queue)
{
struct rwio *rwio = queue->tio_data;
if (rwio->aio_events) {
free(rwio->aio_events);
rwio->aio_events = NULL;
}
}
static int
tapdisk_rwio_setup(struct tqueue *queue, int size)
{
struct rwio *rwio = queue->tio_data;
int err;
rwio->aio_events = calloc(size, sizeof(struct io_event));
if (!rwio->aio_events)
return -errno;
return 0;
}
static inline ssize_t
tapdisk_rwio_rw(const struct iocb *iocb)
{
int fd = iocb->aio_fildes;
char *buf = iocb->u.c.buf;
long long off = iocb->u.c.offset;
size_t size = iocb->u.c.nbytes;
ssize_t (*func)(int, void *, size_t) =
(iocb->aio_lio_opcode == IO_CMD_PWRITE ? vwrite : read);
if (lseek(fd, off, SEEK_SET) == (off_t)-1)
return -errno;
if (atomicio(func, fd, buf, size) != size)
return -errno;
return size;
}
static int
tapdisk_rwio_submit(struct tqueue *queue)
{
struct rwio *rwio = queue->tio_data;
int i, merged, split;
struct iocb *iocb;
struct tiocb *tiocb;
struct io_event *ep;
if (!queue->queued)
return 0;
tapdisk_filter_iocbs(queue->filter, queue->iocbs, queue->queued);
merged = io_merge(&queue->opioctx, queue->iocbs, queue->queued);
queue->queued = 0;
for (i = 0; i < merged; i++) {
ep = rwio->aio_events + i;
iocb = queue->iocbs[i];
ep->obj = iocb;
ep->res = tapdisk_rwio_rw(iocb);
}
split = io_split(&queue->opioctx, rwio->aio_events, merged);
tapdisk_filter_events(queue->filter, rwio->aio_events, split);
for (i = split, ep = rwio->aio_events; i-- > 0; ep++) {
iocb = ep->obj;
tiocb = iocb->data;
complete_tiocb(queue, tiocb, ep->res);
}
queue_deferred_tiocbs(queue);
return split;
}
static const struct tio td_tio_rwio = {
.name = "rwio",
.data_size = 0,
.tio_setup = NULL,
.tio_destroy = NULL,
.tio_submit = tapdisk_rwio_submit
};
/*
* libaio
*/
struct lio {
io_context_t aio_ctx;
struct io_event *aio_events;
int event_fd;
int event_id;
int flags;
};
#define LIO_FLAG_EVENTFD (1<<0)
static int
tapdisk_lio_check_resfd(void)
{
#if defined(__linux__)
return tapdisk_linux_version() >= KERNEL_VERSION(2, 6, 22);
#else
return 1;
#endif
}
static void
tapdisk_lio_destroy_aio(struct tqueue *queue)
{
struct lio *lio = queue->tio_data;
if (lio->event_fd >= 0) {
close(lio->event_fd);
lio->event_fd = -1;
}
if (lio->aio_ctx) {
io_destroy(lio->aio_ctx);
lio->aio_ctx = 0;
}
}
static int
__lio_setup_aio_poll(struct tqueue *queue, int qlen)
{
struct lio *lio = queue->tio_data;
int err, fd;
lio->aio_ctx = REQUEST_ASYNC_FD;
fd = io_setup(qlen, &lio->aio_ctx);
if (fd < 0) {
lio->aio_ctx = 0;
err = -errno;
if (err == -EINVAL)
goto fail_fd;
goto fail;
}
lio->event_fd = fd;
return 0;
fail_fd:
DPRINTF("Couldn't get fd for AIO poll support. This is probably "
"because your kernel does not have the aio-poll patch "
"applied.\n");
fail:
return err;
}
static int
__lio_setup_aio_eventfd(struct tqueue *queue, int qlen)
{
struct lio *lio = queue->tio_data;
int err;
err = io_setup(qlen, &lio->aio_ctx);
if (err < 0) {
lio->aio_ctx = 0;
return err;
}
lio->event_fd = tapdisk_sys_eventfd(0);
if (lio->event_fd < 0)
return -errno;
lio->flags |= LIO_FLAG_EVENTFD;
return 0;
}
static int
tapdisk_lio_setup_aio(struct tqueue *queue, int qlen)
{
struct lio *lio = queue->tio_data;
int err;
lio->aio_ctx = 0;
lio->event_fd = -1;
/*
* prefer the mainline eventfd(2) api, if available.
* if not, fall back to the poll fd patch.
*/
err = !tapdisk_lio_check_resfd();
if (!err)
err = __lio_setup_aio_eventfd(queue, qlen);
if (err)
err = __lio_setup_aio_poll(queue, qlen);
if (err == -EAGAIN)
goto fail_rsv;
fail:
return err;
fail_rsv:
DPRINTF("Couldn't setup AIO context. If you are trying to "
"concurrently use a large number of blktap-based disks, you may "
"need to increase the system-wide aio request limit. "
"(e.g. 'echo 1048576 > /proc/sys/fs/aio-max-nr')\n");
goto fail;
}
static void
tapdisk_lio_destroy(struct tqueue *queue)
{
struct lio *lio = queue->tio_data;
if (!lio)
return;
if (lio->event_id >= 0) {
tapdisk_server_unregister_event(lio->event_id);
lio->event_id = -1;
}
tapdisk_lio_destroy_aio(queue);
if (lio->aio_events) {
free(lio->aio_events);
lio->aio_events = NULL;
}
}
static void
tapdisk_lio_set_eventfd(struct tqueue *queue, int n, struct iocb **iocbs)
{
struct lio *lio = queue->tio_data;
int i;
if (lio->flags & LIO_FLAG_EVENTFD)
for (i = 0; i < n; ++i)
__io_set_eventfd(iocbs[i], lio->event_fd);
}
static void
tapdisk_lio_ack_event(struct tqueue *queue)
{
struct lio *lio = queue->tio_data;
uint64_t val;
if (lio->flags & LIO_FLAG_EVENTFD)
read_exact(lio->event_fd, &val, sizeof(val));
}
static void
tapdisk_lio_event(event_id_t id, char mode, void *private)
{
struct tqueue *queue = private;
struct lio *lio;
int i, ret, split;
struct iocb *iocb;
struct tiocb *tiocb;
struct io_event *ep;
tapdisk_lio_ack_event(queue);
lio = queue->tio_data;
ret = io_getevents(lio->aio_ctx, 0,
queue->size, lio->aio_events, NULL);
split = io_split(&queue->opioctx, lio->aio_events, ret);
tapdisk_filter_events(queue->filter, lio->aio_events, split);
DBG("events: %d, tiocbs: %d\n", ret, split);
queue->iocbs_pending -= ret;
queue->tiocbs_pending -= split;
for (i = split, ep = lio->aio_events; i-- > 0; ep++) {
iocb = ep->obj;
tiocb = iocb->data;
complete_tiocb(queue, tiocb, ep->res);
}
queue_deferred_tiocbs(queue);
}
static int
tapdisk_lio_setup(struct tqueue *queue, int qlen)
{
struct lio *lio = queue->tio_data;
size_t sz;
int err;
lio->event_id = -1;
err = tapdisk_lio_setup_aio(queue, qlen);
if (err)
goto fail;
lio->event_id =
tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
lio->event_fd, 0,
tapdisk_lio_event,
queue);
err = lio->event_id;
if (err < 0)
goto fail;
lio->aio_events = calloc(qlen, sizeof(struct io_event));
if (!lio->aio_events) {
err = -errno;
goto fail;
}
return 0;
fail:
tapdisk_lio_destroy(queue);
return err;
}
static int
tapdisk_lio_submit(struct tqueue *queue)
{
struct lio *lio = queue->tio_data;
int merged, submitted, err = 0;
if (!queue->queued)
return 0;
tapdisk_filter_iocbs(queue->filter, queue->iocbs, queue->queued);
merged = io_merge(&queue->opioctx, queue->iocbs, queue->queued);
tapdisk_lio_set_eventfd(queue, merged, queue->iocbs);
submitted = io_submit(lio->aio_ctx, merged, queue->iocbs);
DBG("queued: %d, merged: %d, submitted: %d\n",
queue->queued, merged, submitted);
if (submitted < 0) {
err = submitted;
submitted = 0;
} else if (submitted < merged)
err = -EIO;
queue->iocbs_pending += submitted;
queue->tiocbs_pending += queue->queued;
queue->queued = 0;
if (err)
queue->tiocbs_pending -=
fail_tiocbs(queue, submitted, merged, err);
return submitted;
}
static const struct tio td_tio_lio = {
.name = "lio",
.data_size = sizeof(struct lio),
.tio_setup = tapdisk_lio_setup,
.tio_destroy = tapdisk_lio_destroy,
.tio_submit = tapdisk_lio_submit,
};
static void
tapdisk_queue_free_io(struct tqueue *queue)
{
if (queue->tio) {
if (queue->tio->tio_destroy)
queue->tio->tio_destroy(queue);
queue->tio = NULL;
}
if (queue->tio_data) {
free(queue->tio_data);
queue->tio_data = NULL;
}
}
static int
tapdisk_queue_init_io(struct tqueue *queue, int drv)
{
const struct tio *tio;
int err;
switch (drv) {
case TIO_DRV_LIO:
tio = &td_tio_lio;
break;
case TIO_DRV_RWIO:
tio = &td_tio_rwio;
break;
default:
err = -EINVAL;
goto fail;
}
queue->tio_data = calloc(1, tio->data_size);
if (!queue->tio_data) {
PERROR("malloc(%zu)", tio->data_size);
err = -errno;
goto fail;
}
queue->tio = tio;
if (tio->tio_setup) {
err = tio->tio_setup(queue, queue->size);
if (err)
goto fail;
}
DPRINTF("I/O queue driver: %s\n", tio->name);
return 0;
fail:
tapdisk_queue_free_io(queue);
return err;
}
int
tapdisk_init_queue(struct tqueue *queue, int size,
int drv, struct tfilter *filter)
{
int i, err;
memset(queue, 0, sizeof(struct tqueue));
queue->size = size;
queue->filter = filter;
if (!size)
return 0;
err = tapdisk_queue_init_io(queue, drv);
if (err)
goto fail;
queue->iocbs = calloc(size, sizeof(struct iocb *));
if (!queue->iocbs) {
err = -errno;
goto fail;
}
err = opio_init(&queue->opioctx, size);
if (err)
goto fail;
return 0;
fail:
tapdisk_free_queue(queue);
return err;
}
void
tapdisk_free_queue(struct tqueue *queue)
{
tapdisk_queue_free_io(queue);
free(queue->iocbs);
queue->iocbs = NULL;
opio_free(&queue->opioctx);
}
void
tapdisk_debug_queue(struct tqueue *queue)
{
struct tiocb *tiocb = queue->deferred.head;
WARN("TAPDISK QUEUE:\n");
WARN("size: %d, tio: %s, queued: %d, iocbs_pending: %d, "
"tiocbs_pending: %d, tiocbs_deferred: %d, deferrals: %"PRIx64"\n",
queue->size, queue->tio->name, queue->queued, queue->iocbs_pending,
queue->tiocbs_pending, queue->tiocbs_deferred, queue->deferrals);
if (tiocb) {
WARN("deferred:\n");
for (; tiocb != NULL; tiocb = tiocb->next) {
struct iocb *io = &tiocb->iocb;
WARN("%s of %lu bytes at %lld\n",
(io->aio_lio_opcode == IO_CMD_PWRITE ?
"write" : "read"),
io->u.c.nbytes, io->u.c.offset);
}
}
}
void
tapdisk_prep_tiocb(struct tiocb *tiocb, int fd, int rw, char *buf, size_t size,
long long offset, td_queue_callback_t cb, void *arg)
{
struct iocb *iocb = &tiocb->iocb;
if (rw)
io_prep_pwrite(iocb, fd, buf, size, offset);
else
io_prep_pread(iocb, fd, buf, size, offset);
iocb->data = tiocb;
tiocb->cb = cb;
tiocb->arg = arg;
tiocb->next = NULL;
}
void
tapdisk_queue_tiocb(struct tqueue *queue, struct tiocb *tiocb)
{
if (!tapdisk_queue_full(queue))
queue_tiocb(queue, tiocb);
else
defer_tiocb(queue, tiocb);
}
/*
* fail_tiocbs may queue more tiocbs
*/
int
tapdisk_submit_tiocbs(struct tqueue *queue)
{
return queue->tio->tio_submit(queue);
}
int
tapdisk_submit_all_tiocbs(struct tqueue *queue)
{
int submitted = 0;
do {
submitted += tapdisk_submit_tiocbs(queue);
} while (!tapdisk_queue_empty(queue));
return submitted;
}
/*
* cancel_tiocbs may queue more tiocbs
*/
int
tapdisk_cancel_tiocbs(struct tqueue *queue)
{
return cancel_tiocbs(queue, -EIO);
}
int
tapdisk_cancel_all_tiocbs(struct tqueue *queue)
{
int cancelled = 0;
do {
cancelled += tapdisk_cancel_tiocbs(queue);
} while (!tapdisk_queue_empty(queue));
return cancelled;
}
-125
View File
@@ -1,125 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TAPDISK_QUEUE_H
#define TAPDISK_QUEUE_H
#include <libaio.h>
#include "io-optimize.h"
#include "scheduler.h"
struct tiocb;
struct tfilter;
typedef void (*td_queue_callback_t)(void *arg, struct tiocb *, int err);
struct tiocb {
td_queue_callback_t cb;
void *arg;
struct iocb iocb;
struct tiocb *next;
};
struct tlist {
struct tiocb *head;
struct tiocb *tail;
};
struct tqueue {
int size;
const struct tio *tio;
void *tio_data;
struct opioctx opioctx;
int queued;
struct iocb **iocbs;
/* number of iocbs pending in the aio layer */
int iocbs_pending;
/* number of tiocbs pending in the queue --
* this is likely to be larger than iocbs_pending
* due to request coalescing */
int tiocbs_pending;
/* iocbs may be deferred if the aio ring is full.
* tapdisk_queue_complete will ensure deferred
* iocbs are queued as slots become available. */
struct tlist deferred;
int tiocbs_deferred;
/* optional tapdisk filter */
struct tfilter *filter;
uint64_t deferrals;
};
struct tio {
const char *name;
size_t data_size;
int (*tio_setup) (struct tqueue *queue, int qlen);
void (*tio_destroy) (struct tqueue *queue);
int (*tio_submit) (struct tqueue *queue);
};
enum {
TIO_DRV_LIO = 1,
TIO_DRV_RWIO = 2,
};
/*
* Interface for request producer (i.e., tapdisk)
* NB: the following functions may cause additional tiocbs to be queued:
* - tapdisk_submit_tiocbs
* - tapdisk_cancel_tiocbs
* - tapdisk_complete_tiocbs
* The *_all_tiocbs variants will handle the first two cases;
* be sure to call submit after calling complete in the third case.
*/
#define tapdisk_queue_count(q) ((q)->queued)
#define tapdisk_queue_empty(q) ((q)->queued == 0)
#define tapdisk_queue_full(q) \
(((q)->tiocbs_pending + (q)->queued) >= (q)->size)
int tapdisk_init_queue(struct tqueue *, int size, int drv, struct tfilter *);
void tapdisk_free_queue(struct tqueue *);
void tapdisk_debug_queue(struct tqueue *);
void tapdisk_queue_tiocb(struct tqueue *, struct tiocb *);
int tapdisk_submit_tiocbs(struct tqueue *);
int tapdisk_submit_all_tiocbs(struct tqueue *);
int tapdisk_cancel_tiocbs(struct tqueue *);
int tapdisk_cancel_all_tiocbs(struct tqueue *);
void tapdisk_prep_tiocb(struct tiocb *, int, int, char *, size_t,
long long, td_queue_callback_t, void *);
#endif
-439
View File
@@ -1,439 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include "tapdisk-ring.h"
static int
tapdisk_uring_create_ctlfd(td_uring_t *ring)
{
int fd, err;
struct sockaddr_un saddr;
if (strnlen(ring->ctlfd_path, sizeof(saddr.sun_family)) >=
sizeof(saddr.sun_family))
return -ENAMETOOLONG;
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == -1)
return -errno;
memset(&saddr, 0, sizeof(struct sockaddr_un));
saddr.sun_family = AF_UNIX;
memcpy(saddr.sun_path, ring->ctlfd_path, strlen(ring->ctlfd_path));
err = unlink(ring->ctlfd_path);
if (err == -1 && errno != ENOENT) {
err = -errno;
goto fail;
}
err = bind(fd, &saddr, sizeof(struct sockaddr_un));
if (err == -1) {
err = -errno;
goto fail;
}
err = listen(fd, 1);
if (err == -1) {
err = -errno;
goto fail;
}
ring->ctlfd = fd;
return 0;
fail:
close(fd);
return err;
}
static void
tapdisk_uring_destroy_ctlfd(td_uring_t *ring)
{
if (ring->ctlfd) {
close(ring->ctlfd);
ring->ctlfd = 0;
}
if (ring->ctlfd_path) {
unlink(ring->ctlfd_path);
free(ring->ctlfd_path);
ring->ctlfd_path = NULL;
}
}
static int
tapdisk_uring_connect_ctlfd(td_uring_t *ring)
{
int fd, err;
struct sockaddr_un saddr;
if (strnlen(ring->ctlfd_path, sizeof(saddr.sun_path)) >=
sizeof(saddr.sun_path))
return -ENAMETOOLONG;
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == -1)
return -errno;
memset(&saddr, 0, sizeof(struct sockaddr_un));
saddr.sun_family = AF_UNIX;
memcpy(saddr.sun_path, ring->ctlfd_path, strlen(ring->ctlfd_path));
err = connect(fd, &saddr, sizeof(saddr));
if (err == -1) {
err = -errno;
goto fail;
}
ring->ctlfd = fd;
return 0;
fail:
close(fd);
return err;
}
static void
tapdisk_uring_disconnect_ctlfd(td_uring_t *ring)
{
if (ring->ctlfd)
close(ring->ctlfd);
free(ring->ctlfd_path);
ring->ctlfd_path = NULL;
}
static int
tapdisk_uring_create_shmem(td_uring_t *ring)
{
int fd, err;
fd = shm_open(ring->shmem_path, O_CREAT | O_RDWR, 0750);
if (fd == -1)
return -errno;
err = ftruncate(fd, ring->shmem_size);
if (err == -1) {
err = -errno;
goto out;
}
ring->shmem = mmap(NULL, ring->shmem_size,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ring->shmem == MAP_FAILED) {
ring->shmem = NULL;
err = -errno;
goto out;
}
err = 0;
out:
close(fd);
return err;
}
static void
tapdisk_uring_destroy_shmem(td_uring_t *ring)
{
if (ring->shmem) {
munmap(ring->shmem, ring->shmem_size);
ring->shmem = NULL;
}
if (ring->shmem_path) {
shm_unlink(ring->shmem_path);
free(ring->shmem_path);
ring->shmem_path = NULL;
}
}
static int
tapdisk_uring_connect_shmem(td_uring_t *ring)
{
int fd, err;
td_uring_header_t header, *p;
fd = shm_open(ring->shmem_path, O_RDWR);
if (fd == -1)
return -errno;
p = mmap(NULL, sizeof(td_uring_header_t),
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (p == MAP_FAILED) {
err = -errno;
goto out;
}
memcpy(&header, p, sizeof(td_uring_header_t));
munmap(p, sizeof(td_uring_header_t));
if (memcmp(header.cookie,
TAPDISK_URING_COOKIE, sizeof(header.cookie))) {
err = -EINVAL;
goto out;
}
if (header.version != TD_URING_CURRENT_VERSION) {
err = -EINVAL;
goto out;
}
ring->ring_size = header.ring_size;
ring->data_size = header.data_size;
ring->shmem_size = header.shmem_size;
ring->shmem = mmap(NULL, ring->shmem_size,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ring->shmem == MAP_FAILED) {
rint->shmem = NULL;
err = -errno;
goto out;
}
err = 0;
out:
close(fd);
return err;
}
static void
tapdisk_uring_disconnect_shmem(td_uring_t *ring)
{
if (ring->shmem)
munmap(ring->shmem, ring->shmem_size);
free(ring->shmem_path);
ring->shmem_path = NULL;
}
int
tapdisk_uring_create(td_uring_t *ring, const char *location,
uint32_t ring_size, uint32_t data_size)
{
int fd, err;
memset(ring, 0, sizeof(td_uring_t));
ring->ring_size = ring_size;
ring->data_size = data_size;
ring->shmem_size = ring_size + data_size + sizeof(td_uring_header_t);
err = asprintf(&ring->shmem_path, "%s.shm", location);
if (err == -1) {
ring->shmem_path = NULL;
err = -errno;
goto fail;
}
err = asprintf(&ring->ctlfd_path, "%s.cfd", location);
if (err == -1) {
ring->ctlfd_path = NULL;
err = -errno;
goto fail;
}
err = tapdisk_uring_create_ctlfd(ring);
if (err)
goto fail;
err = tapdisk_uring_create_shmem(ring);
if (err)
goto fail;
ring->ring_area = (unsigned long)ring->shmem + sizeof(td_uring_header_t);
ring->data_area = (unsigned long)ring->ring_area + ring->ring_size;
return 0;
fail:
tapdisk_uring_destroy(ring);
return err;
}
int
tapdisk_uring_destroy(td_uring_t *ring)
{
tapdisk_uring_destroy_shmem(ring);
tapdisk_uring_destroy_ctlfd(ring);
return 0;
}
int
tapdisk_uring_connect(td_uring_t *ring, const char *location)
{
int fd, err;
memset(ring, 0, sizeof(td_uring_t));
err = asprintf(&ring->shmem_path, "%s.shm", location);
if (err == -1) {
ring->shmem_path = NULL;
err = -errno;
goto fail;
}
err = asprintf(&ring->ctlfd_path, "%s.cfd", location);
if (err == -1) {
ring->ctlfd_path = NULL;
err = -errno;
goto fail;
}
err = tapdisk_uring_connect_ctlfd(ring);
if (err)
goto fail;
err = tapdisk_uring_connect_shmem(ring);
if (err)
goto fail;
err = 0;
fail:
}
int
tapdisk_uring_disconnect(td_uring_t *ring)
{
tapdisk_uring_disconnect_shmem(ring);
tapdisk_uring_disconnect_ctlfd(ring);
return 0;
}
static int
tapdisk_ring_read_message(int fd, td_uring_message_t *message, int timeout)
{
fd_set readfds;
int ret, len, offset;
struct timeval tv, *t;
t = NULL;
offset = 0;
len = sizeof(td_uring_message_t);
if (timeout) {
tv.tv_sec = timeout;
tv.tv_usec = 0;
t = &tv;
}
while (offset < len) {
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
/* we don't bother reinitializing tv. at worst, it will wait a
* bit more time than expected. */
ret = select(fd + 1, &readfds, NULL, NULL, t);
if (ret == -1)
break;
else if (FD_ISSET(fd, &readfds)) {
ret = read(fd, message + offset, len - offset);
if (ret <= 0)
break;
offset += ret;
} else
break;
}
if (offset != len)
return -EIO;
return 0;
}
static int
tapdisk_ring_write_message(int fd, td_uring_message_t *message, int timeout)
{
fd_set writefds;
int ret, len, offset;
struct timeval tv, *t;
t = NULL;
offset = 0;
len = sizeof(td_uring_message_t);
if (timeout) {
tv.tv_sec = timeout;
tv.tv_usec = 0;
t = &tv;
}
while (offset < len) {
FD_ZERO(&writefds);
FD_SET(fd, &writefds);
/* we don't bother reinitializing tv. at worst, it will wait a
* bit more time than expected. */
ret = select(fd + 1, NULL, &writefds, NULL, t);
if (ret == -1)
break;
else if (FD_ISSET(fd, &writefds)) {
ret = write(fd, message + offset, len - offset);
if (ret <= 0)
break;
offset += ret;
} else
break;
}
if (offset != len)
return -EIO;
return 0;
}
int
tapdisk_uring_poll(td_uring_t *ring)
{
int err;
td_uring_message_t message;
err = tapdisk_uring_read_message(ring->ctlfd, &message, 1);
if (err)
return err;
if (message.type != TAPDISK_URING_MESSAGE_KICK)
return -EINVAL;
return 0;
}
int
tapdisk_uring_kick(td_uring_t *ring)
{
td_uring_message_t message;
memset(&message, 0, sizeof(td_uring_message_t));
message.type = TAPDISK_URING_MESSAGE_KICK;
return tapdisk_uring_write_message(ring->ctlfd, &message, 1);
}
-87
View File
@@ -1,87 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TAPDISK_RING_H_
#define _TAPDISK_RING_H_
#include <inttypes.h>
#include <xenctrl.h>
#include <xen/io/ring.h>
typedef struct td_uring td_uring_t;
typedef struct td_uring_header td_uring_header_t;
typedef struct td_uring_request td_uring_request_t;
typedef struct td_uring_response td_uring_response_t;
struct td_uring {
int ctlfd;
char *shmem_path;
char *ctlfd_path;
void *shmem;
void *ring_area;
void *data_area;
};
struct td_uring_header {
char cookie[8];
uint32_t version;
uint32_t shmem_size;
uint32_t ring_size;
uint32_t data_size;
char reserved[4064];
};
struct td_uring_request {
uint8_t op;
uint64_t id;
uint64_t sec;
uint32_t secs;
uint32_t offset;
};
struct td_uring_response {
uint8_t op;
uint64_t id;
uint8_t status;
};
DEFINE_RING_TYPES(td_uring, td_uring_request_t, td_uring_response_t);
int tapdisk_uring_create(td_uring_t *, const char *location,
uint32_t ring_size, uint32_t data_size);
int tapdisk_uring_destroy(td_uring_t *);
int tapdisk_uring_connect(td_uring_t *, const char *location);
int tapdisk_uring_disconnect(td_uring_t *);
int tapdisk_uring_poll(td_uring_t *);
int tapdisk_uring_kick(td_uring_t *);
#endif
-345
View File
@@ -1,345 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include "tapdisk-utils.h"
#include "tapdisk-server.h"
#include "tapdisk-driver.h"
#include "tapdisk-interface.h"
#define DBG(_level, _f, _a...) tlog_write(_level, _f, ##_a)
#define ERR(_err, _f, _a...) tlog_error(_err, _f, ##_a)
tapdisk_server_t server;
#define tapdisk_server_for_each_vbd(vbd, tmp) \
list_for_each_entry_safe(vbd, tmp, &server.vbds, next)
td_image_t *
tapdisk_server_get_shared_image(td_image_t *image)
{
td_vbd_t *vbd, *tmpv;
td_image_t *img, *tmpi;
if (!td_flag_test(image->flags, TD_OPEN_SHAREABLE))
return NULL;
tapdisk_server_for_each_vbd(vbd, tmpv)
tapdisk_vbd_for_each_image(vbd, img, tmpi)
if (img->type == image->type &&
!strcmp(img->name, image->name))
return img;
return NULL;
}
struct list_head *
tapdisk_server_get_all_vbds(void)
{
return &server.vbds;
}
td_vbd_t *
tapdisk_server_get_vbd(uint16_t uuid)
{
td_vbd_t *vbd, *tmp;
tapdisk_server_for_each_vbd(vbd, tmp)
if (vbd->uuid == uuid)
return vbd;
return NULL;
}
void
tapdisk_server_add_vbd(td_vbd_t *vbd)
{
list_add_tail(&vbd->next, &server.vbds);
}
void
tapdisk_server_remove_vbd(td_vbd_t *vbd)
{
list_del(&vbd->next);
INIT_LIST_HEAD(&vbd->next);
tapdisk_server_check_state();
}
void
tapdisk_server_queue_tiocb(struct tiocb *tiocb)
{
tapdisk_queue_tiocb(&server.aio_queue, tiocb);
}
void
tapdisk_server_debug(void)
{
td_vbd_t *vbd, *tmp;
tapdisk_debug_queue(&server.aio_queue);
tapdisk_server_for_each_vbd(vbd, tmp)
tapdisk_vbd_debug(vbd);
tlog_flush();
}
void
tapdisk_server_check_state(void)
{
if (list_empty(&server.vbds))
server.run = 0;
}
event_id_t
tapdisk_server_register_event(char mode, int fd,
int timeout, event_cb_t cb, void *data)
{
return scheduler_register_event(&server.scheduler,
mode, fd, timeout, cb, data);
}
void
tapdisk_server_unregister_event(event_id_t event)
{
return scheduler_unregister_event(&server.scheduler, event);
}
void
tapdisk_server_set_max_timeout(int seconds)
{
scheduler_set_max_timeout(&server.scheduler, seconds);
}
static void
tapdisk_server_assert_locks(void)
{
}
static void
tapdisk_server_set_retry_timeout(void)
{
td_vbd_t *vbd, *tmp;
tapdisk_server_for_each_vbd(vbd, tmp)
if (tapdisk_vbd_retry_needed(vbd)) {
tapdisk_server_set_max_timeout(TD_VBD_RETRY_INTERVAL);
return;
}
}
static void
tapdisk_server_check_progress(void)
{
struct timeval now;
td_vbd_t *vbd, *tmp;
gettimeofday(&now, NULL);
tapdisk_server_for_each_vbd(vbd, tmp)
tapdisk_vbd_check_progress(vbd);
}
static void
tapdisk_server_submit_tiocbs(void)
{
tapdisk_submit_all_tiocbs(&server.aio_queue);
}
static void
tapdisk_server_kick_responses(void)
{
int n;
td_vbd_t *vbd, *tmp;
tapdisk_server_for_each_vbd(vbd, tmp)
tapdisk_vbd_kick(vbd);
}
static void
tapdisk_server_check_vbds(void)
{
td_vbd_t *vbd, *tmp;
tapdisk_server_for_each_vbd(vbd, tmp)
tapdisk_vbd_check_state(vbd);
}
static void
tapdisk_server_stop_vbds(void)
{
td_vbd_t *vbd, *tmp;
tapdisk_server_for_each_vbd(vbd, tmp)
tapdisk_vbd_kill_queue(vbd);
}
static int
tapdisk_server_init_aio(void)
{
return tapdisk_init_queue(&server.aio_queue, TAPDISK_TIOCBS,
TIO_DRV_LIO, NULL);
}
static void
tapdisk_server_close_aio(void)
{
tapdisk_free_queue(&server.aio_queue);
}
static void
tapdisk_server_close(void)
{
tapdisk_server_close_aio();
}
void
tapdisk_server_iterate(void)
{
int ret;
tapdisk_server_assert_locks();
tapdisk_server_set_retry_timeout();
tapdisk_server_check_progress();
ret = scheduler_wait_for_events(&server.scheduler);
if (ret < 0)
DBG(TLOG_WARN, "server wait returned %d\n", ret);
tapdisk_server_check_vbds();
tapdisk_server_submit_tiocbs();
tapdisk_server_kick_responses();
}
static void
__tapdisk_server_run(void)
{
while (server.run)
tapdisk_server_iterate();
}
static void
tapdisk_server_signal_handler(int signal)
{
td_vbd_t *vbd, *tmp;
static int xfsz_error_sent = 0;
switch (signal) {
case SIGBUS:
case SIGINT:
tapdisk_server_for_each_vbd(vbd, tmp)
tapdisk_vbd_close(vbd);
break;
case SIGXFSZ:
ERR(EFBIG, "received SIGXFSZ");
tapdisk_server_stop_vbds();
if (xfsz_error_sent)
break;
xfsz_error_sent = 1;
break;
case SIGUSR1:
tapdisk_server_debug();
break;
}
}
int
tapdisk_server_init(void)
{
memset(&server, 0, sizeof(server));
INIT_LIST_HEAD(&server.vbds);
scheduler_initialize(&server.scheduler);
return 0;
}
int
tapdisk_server_complete(void)
{
int err;
err = tapdisk_server_init_aio();
if (err)
goto fail;
server.run = 1;
return 0;
fail:
tapdisk_server_close_aio();
return err;
}
int
tapdisk_server_initialize(void)
{
int err;
tapdisk_server_init();
err = tapdisk_server_complete();
if (err)
goto fail;
return 0;
fail:
tapdisk_server_close();
return err;
}
int
tapdisk_server_run()
{
int err;
err = tapdisk_set_resource_limits();
if (err)
return err;
signal(SIGBUS, tapdisk_server_signal_handler);
signal(SIGINT, tapdisk_server_signal_handler);
signal(SIGUSR1, tapdisk_server_signal_handler);
signal(SIGXFSZ, tapdisk_server_signal_handler);
__tapdisk_server_run();
tapdisk_server_close();
return 0;
}
-67
View File
@@ -1,67 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TAPDISK_SERVER_H_
#define _TAPDISK_SERVER_H_
#include "list.h"
#include "tapdisk-vbd.h"
#include "tapdisk-queue.h"
struct tap_disk *tapdisk_server_find_driver_interface(int);
td_image_t *tapdisk_server_get_shared_image(td_image_t *);
struct list_head *tapdisk_server_get_all_vbds(void);
td_vbd_t *tapdisk_server_get_vbd(td_uuid_t);
void tapdisk_server_add_vbd(td_vbd_t *);
void tapdisk_server_remove_vbd(td_vbd_t *);
void tapdisk_server_queue_tiocb(struct tiocb *);
void tapdisk_server_check_state(void);
event_id_t tapdisk_server_register_event(char, int, int, event_cb_t, void *);
void tapdisk_server_unregister_event(event_id_t);
void tapdisk_server_set_max_timeout(int);
int tapdisk_server_init(void);
int tapdisk_server_initialize(void);
int tapdisk_server_complete(void);
int tapdisk_server_run(void);
void tapdisk_server_iterate(void);
#define TAPDISK_TIOCBS (TAPDISK_DATA_REQUESTS + 50)
typedef struct tapdisk_server {
int run;
struct list_head vbds;
scheduler_t scheduler;
struct tqueue aio_queue;
} tapdisk_server_t;
#endif
-605
View File
@@ -1,605 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include "list.h"
#include "scheduler.h"
#include "tapdisk-vbd.h"
#include "tapdisk-server.h"
#include "tapdisk-disktype.h"
#include "tapdisk-utils.h"
#define POLL_READ 0
#define POLL_WRITE 1
#define MIN(a, b) ((a) < (b) ? (a) : (b))
struct tapdisk_stream_poll {
int pipe[2];
int set;
};
struct tapdisk_stream_request {
uint64_t sec;
uint32_t secs;
uint64_t seqno;
blkif_request_t blkif_req;
struct list_head next;
};
struct tapdisk_stream {
td_vbd_t *vbd;
unsigned int id;
int in_fd;
int out_fd;
int err;
uint64_t cur;
uint64_t start;
uint64_t end;
uint64_t started;
uint64_t completed;
struct tapdisk_stream_poll poll;
event_id_t enqueue_event_id;
struct list_head free_list;
struct list_head pending_list;
struct list_head completed_list;
struct tapdisk_stream_request requests[MAX_REQUESTS];
};
static unsigned int tapdisk_stream_count;
static void tapdisk_stream_close_image(struct tapdisk_stream *);
static void
usage(const char *app, int err)
{
printf("usage: %s <-n type:/path/to/image> "
"[-c sector count] [-s skip sectors]\n", app);
exit(err);
}
static inline void
tapdisk_stream_poll_initialize(struct tapdisk_stream_poll *p)
{
p->set = 0;
p->pipe[POLL_READ] = p->pipe[POLL_WRITE] = -1;
}
static int
tapdisk_stream_poll_open(struct tapdisk_stream_poll *p)
{
int err;
tapdisk_stream_poll_initialize(p);
err = pipe(p->pipe);
if (err)
return -errno;
err = fcntl(p->pipe[POLL_READ], F_SETFL, O_NONBLOCK);
if (err)
goto out;
err = fcntl(p->pipe[POLL_WRITE], F_SETFL, O_NONBLOCK);
if (err)
goto out;
return 0;
out:
close(p->pipe[POLL_READ]);
close(p->pipe[POLL_WRITE]);
tapdisk_stream_poll_initialize(p);
return -errno;
}
static void
tapdisk_stream_poll_close(struct tapdisk_stream_poll *p)
{
if (p->pipe[POLL_READ] != -1)
close(p->pipe[POLL_READ]);
if (p->pipe[POLL_WRITE] != -1)
close(p->pipe[POLL_WRITE]);
tapdisk_stream_poll_initialize(p);
}
static inline void
tapdisk_stream_poll_clear(struct tapdisk_stream_poll *p)
{
int dummy;
read_exact(p->pipe[POLL_READ], &dummy, sizeof(dummy));
p->set = 0;
}
static inline void
tapdisk_stream_poll_set(struct tapdisk_stream_poll *p)
{
int dummy = 0;
if (!p->set) {
write_exact(p->pipe[POLL_WRITE], &dummy, sizeof(dummy));
p->set = 1;
}
}
static inline int
tapdisk_stream_stop(struct tapdisk_stream *s)
{
return (list_empty(&s->pending_list) && (s->cur == s->end || s->err));
}
static inline void
tapdisk_stream_initialize_request(struct tapdisk_stream_request *req)
{
memset(req, 0, sizeof(*req));
INIT_LIST_HEAD(&req->next);
}
static inline int
tapdisk_stream_request_idx(struct tapdisk_stream *s,
struct tapdisk_stream_request *req)
{
return (req - s->requests);
}
static inline struct tapdisk_stream_request *
tapdisk_stream_get_request(struct tapdisk_stream *s)
{
struct tapdisk_stream_request *req;
if (list_empty(&s->free_list))
return NULL;
req = list_entry(s->free_list.next,
struct tapdisk_stream_request, next);
list_del_init(&req->next);
tapdisk_stream_initialize_request(req);
return req;
}
static void
tapdisk_stream_print_request(struct tapdisk_stream *s,
struct tapdisk_stream_request *sreq)
{
unsigned long idx = (unsigned long)tapdisk_stream_request_idx(s, sreq);
char *buf = (char *)MMAP_VADDR(s->vbd->ring.vstart, idx, 0);
write_exact(s->out_fd, buf, sreq->secs << SECTOR_SHIFT);
}
static void
tapdisk_stream_write_data(struct tapdisk_stream *s)
{
struct tapdisk_stream_request *sreq, *tmp;
list_for_each_entry_safe(sreq, tmp, &s->completed_list, next) {
if (sreq->seqno != s->completed)
break;
s->completed++;
tapdisk_stream_print_request(s, sreq);
list_del_init(&sreq->next);
list_add_tail(&sreq->next, &s->free_list);
}
}
static inline void
tapdisk_stream_queue_completed(struct tapdisk_stream *s,
struct tapdisk_stream_request *sreq)
{
struct tapdisk_stream_request *itr;
list_for_each_entry(itr, &s->completed_list, next)
if (sreq->seqno < itr->seqno) {
list_add_tail(&sreq->next, &itr->next);
return;
}
list_add_tail(&sreq->next, &s->completed_list);
}
static void
tapdisk_stream_dequeue(void *arg, blkif_response_t *rsp)
{
struct tapdisk_stream *s = (struct tapdisk_stream *)arg;
struct tapdisk_stream_request *sreq = s->requests + rsp->id;
list_del_init(&sreq->next);
if (rsp->status == BLKIF_RSP_OKAY)
tapdisk_stream_queue_completed(s, sreq);
else {
s->err = EIO;
list_add_tail(&sreq->next, &s->free_list);
fprintf(stderr, "error reading sector 0x%"PRIu64"\n", sreq->sec);
}
tapdisk_stream_write_data(s);
tapdisk_stream_poll_set(&s->poll);
}
static void
tapdisk_stream_enqueue(event_id_t id, char mode, void *arg)
{
td_vbd_t *vbd;
int i, idx, psize;
struct tapdisk_stream *s = (struct tapdisk_stream *)arg;
vbd = s->vbd;
tapdisk_stream_poll_clear(&s->poll);
if (tapdisk_stream_stop(s)) {
tapdisk_stream_close_image(s);
return;
}
psize = getpagesize();
while (s->cur < s->end && !s->err) {
blkif_request_t *breq;
td_vbd_request_t *vreq;
struct tapdisk_stream_request *sreq;
sreq = tapdisk_stream_get_request(s);
if (!sreq)
break;
idx = tapdisk_stream_request_idx(s, sreq);
sreq->sec = s->cur;
sreq->secs = 0;
sreq->seqno = s->started++;
breq = &sreq->blkif_req;
breq->id = idx;
breq->nr_segments = 0;
breq->sector_number = sreq->sec;
breq->operation = BLKIF_OP_READ;
for (i = 0; i < BLKIF_MAX_SEGMENTS_PER_REQUEST; i++) {
uint32_t secs = MIN(s->end - s->cur, psize >> SECTOR_SHIFT);
struct blkif_request_segment *seg = breq->seg + i;
if (!secs)
break;
sreq->secs += secs;
s->cur += secs;
seg->first_sect = 0;
seg->last_sect = secs - 1;
breq->nr_segments++;
}
vreq = vbd->request_list + idx;
assert(list_empty(&vreq->next));
assert(vreq->secs_pending == 0);
memcpy(&vreq->req, breq, sizeof(*breq));
vbd->received++;
vreq->vbd = vbd;
tapdisk_vbd_move_request(vreq, &vbd->new_requests);
list_add_tail(&sreq->next, &s->pending_list);
}
tapdisk_vbd_issue_requests(vbd);
}
static int
tapdisk_stream_open_image(struct tapdisk_stream *s, const char *path, int type)
{
int err;
s->id = tapdisk_stream_count++;
err = tapdisk_server_initialize();
if (err)
goto out;
err = tapdisk_vbd_initialize(s->id);
if (err)
goto out;
s->vbd = tapdisk_server_get_vbd(s->id);
if (!s->vbd) {
err = ENODEV;
goto out;
}
tapdisk_vbd_set_callback(s->vbd, tapdisk_stream_dequeue, s);
err = tapdisk_vbd_open_vdi(s->vbd, path, type,
TAPDISK_STORAGE_TYPE_DEFAULT,
TD_OPEN_RDONLY);
if (err)
goto out;
s->vbd->reopened = 1;
err = 0;
out:
if (err)
fprintf(stderr, "failed to open %s: %d\n", path, err);
return err;
}
static void
tapdisk_stream_close_image(struct tapdisk_stream *s)
{
td_vbd_t *vbd;
vbd = tapdisk_server_get_vbd(s->id);
if (vbd) {
tapdisk_vbd_close_vdi(vbd);
tapdisk_server_remove_vbd(vbd);
free((void *)vbd->ring.vstart);
free(vbd->name);
free(vbd);
s->vbd = NULL;
}
}
static int
tapdisk_stream_set_position(struct tapdisk_stream *s,
uint64_t count, uint64_t skip)
{
int err;
image_t image;
err = tapdisk_vbd_get_image_info(s->vbd, &image);
if (err) {
fprintf(stderr, "failed getting image size: %d\n", err);
return err;
}
if (count == (uint64_t)-1)
count = image.size - skip;
if (count + skip > image.size) {
fprintf(stderr, "0x%"PRIx64" past end of image 0x%"PRIx64"\n",
(uint64_t) (count + skip), (uint64_t) image.size);
return -EINVAL;
}
s->start = skip;
s->cur = s->start;
s->end = s->start + count;
return 0;
}
static int
tapdisk_stream_initialize_requests(struct tapdisk_stream *s)
{
size_t size;
td_ring_t *ring;
int err, i, psize;
ring = &s->vbd->ring;
psize = getpagesize();
size = psize * BLKTAP_MMAP_REGION_SIZE;
/* sneaky -- set up ring->vstart so tapdisk_vbd will use our buffers */
err = posix_memalign((void **)&ring->vstart, psize, size);
if (err) {
fprintf(stderr, "failed to allocate buffers: %d\n", err);
ring->vstart = 0;
return err;
}
for (i = 0; i < MAX_REQUESTS; i++) {
struct tapdisk_stream_request *req = s->requests + i;
tapdisk_stream_initialize_request(req);
list_add_tail(&req->next, &s->free_list);
}
return 0;
}
static int
tapdisk_stream_register_enqueue_event(struct tapdisk_stream *s)
{
int err;
struct tapdisk_stream_poll *p = &s->poll;
err = tapdisk_stream_poll_open(p);
if (err)
goto out;
err = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
p->pipe[POLL_READ], 0,
tapdisk_stream_enqueue, s);
if (err < 0)
goto out;
s->enqueue_event_id = err;
err = 0;
out:
if (err)
fprintf(stderr, "failed to register event: %d\n", err);
return err;
}
static void
tapdisk_stream_unregister_enqueue_event(struct tapdisk_stream *s)
{
if (s->enqueue_event_id) {
tapdisk_server_unregister_event(s->enqueue_event_id);
s->enqueue_event_id = 0;
}
tapdisk_stream_poll_close(&s->poll);
}
static inline void
tapdisk_stream_initialize(struct tapdisk_stream *s)
{
memset(s, 0, sizeof(*s));
s->in_fd = s->out_fd = -1;
INIT_LIST_HEAD(&s->free_list);
INIT_LIST_HEAD(&s->pending_list);
INIT_LIST_HEAD(&s->completed_list);
}
static int
tapdisk_stream_open_fds(struct tapdisk_stream *s)
{
s->out_fd = dup(STDOUT_FILENO);
if (s->out_fd == -1) {
fprintf(stderr, "failed to open output: %d\n", errno);
return errno;
}
return 0;
}
static int
tapdisk_stream_open(struct tapdisk_stream *s, const char *path,
int type, uint64_t count, uint64_t skip)
{
int err;
tapdisk_stream_initialize(s);
err = tapdisk_stream_open_fds(s);
if (err)
return err;
err = tapdisk_stream_open_image(s, path, type);
if (err)
return err;
err = tapdisk_stream_set_position(s, count, skip);
if (err)
return err;
err = tapdisk_stream_initialize_requests(s);
if (err)
return err;
err = tapdisk_stream_register_enqueue_event(s);
if (err)
return err;
return 0;
}
static void
tapdisk_stream_release(struct tapdisk_stream *s)
{
close(s->out_fd);
tapdisk_stream_close_image(s);
tapdisk_stream_unregister_enqueue_event(s);
}
static int
tapdisk_stream_run(struct tapdisk_stream *s)
{
tapdisk_stream_enqueue(s->enqueue_event_id, SCHEDULER_POLL_READ_FD, s);
tapdisk_server_run();
return s->err;
}
int
main(int argc, char *argv[])
{
int c, err, type;
const char *params;
const disk_info_t *info;
const char *path;
uint64_t count, skip;
struct tapdisk_stream stream;
err = 0;
skip = 0;
count = (uint64_t)-1;
params = NULL;
while ((c = getopt(argc, argv, "n:c:s:h")) != -1) {
switch (c) {
case 'n':
params = optarg;
break;
case 'c':
count = strtoull(optarg, NULL, 10);
break;
case 's':
skip = strtoull(optarg, NULL, 10);
break;
default:
err = EINVAL;
case 'h':
usage(argv[0], err);
}
}
if (!params)
usage(argv[0], EINVAL);
type = tapdisk_disktype_parse_params(params, &path);
if (type < 0) {
err = type;
fprintf(stderr, "invalid argument %s: %d\n", params, err);
return err;
}
tapdisk_start_logging("tapdisk-stream");
err = tapdisk_stream_open(&stream, path, type, count, skip);
if (err)
goto out;
err = tapdisk_stream_run(&stream);
if (err)
goto out;
err = 0;
out:
tapdisk_stream_release(&stream);
tapdisk_stop_logging();
return err;
}
-214
View File
@@ -1,214 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/utsname.h>
#ifdef __linux__
#include <linux/version.h>
#endif
#include "blk.h"
#include "tapdisk.h"
#include "blktaplib.h"
#include "tapdisk-log.h"
#include "tapdisk-utils.h"
void
tapdisk_start_logging(const char *name)
{
static char buf[128];
snprintf(buf, sizeof(buf), "%s[%d]", name, getpid());
openlog(buf, LOG_CONS | LOG_ODELAY, LOG_DAEMON);
open_tlog("/tmp/tapdisk.log", (64 << 10), TLOG_WARN, 0);
}
void
tapdisk_stop_logging(void)
{
closelog();
close_tlog();
}
int
tapdisk_set_resource_limits(void)
{
int err;
struct rlimit rlim;
rlim.rlim_cur = RLIM_INFINITY;
rlim.rlim_max = RLIM_INFINITY;
err = setrlimit(RLIMIT_MEMLOCK, &rlim);
if (err == -1) {
EPRINTF("RLIMIT_MEMLOCK failed: %d\n", errno);
return -errno;
}
err = mlockall(MCL_CURRENT | MCL_FUTURE);
if (err == -1) {
EPRINTF("mlockall failed: %d\n", errno);
return -errno;
}
#define CORE_DUMP
#if defined(CORE_DUMP)
err = setrlimit(RLIMIT_CORE, &rlim);
if (err == -1)
EPRINTF("RLIMIT_CORE failed: %d\n", errno);
#endif
return 0;
}
int
tapdisk_namedup(char **dup, const char *name)
{
*dup = NULL;
if (strnlen(name, MAX_NAME_LEN) >= MAX_NAME_LEN)
return -ENAMETOOLONG;
*dup = strdup(name);
if (!*dup)
return -ENOMEM;
return 0;
}
/*Get Image size, secsize*/
int
tapdisk_get_image_size(int fd, uint64_t *_sectors, uint32_t *_sector_size)
{
int ret;
struct stat stat;
uint64_t sectors;
uint64_t sector_size;
sectors = 0;
sector_size = 0;
*_sectors = 0;
*_sector_size = 0;
if (fstat(fd, &stat)) {
DPRINTF("ERROR: fstat failed, Couldn't stat image");
return -EINVAL;
}
if (S_ISBLK(stat.st_mode)) {
/*Accessing block device directly*/
if (blk_getimagesize(fd, &sectors) != 0)
return -EINVAL;
/*Get the sector size*/
if (blk_getsectorsize(fd, &sector_size) != 0)
sector_size = DEFAULT_SECTOR_SIZE;
} else {
/*Local file? try fstat instead*/
sectors = (stat.st_size >> SECTOR_SHIFT);
sector_size = DEFAULT_SECTOR_SIZE;
}
if (sectors == 0) {
sectors = 16836057ULL;
sector_size = DEFAULT_SECTOR_SIZE;
}
return 0;
}
#ifdef __linux__
int tapdisk_linux_version(void)
{
struct utsname uts;
unsigned int version, patchlevel, sublevel;
int n, err;
err = uname(&uts);
if (err)
return -errno;
n = sscanf(uts.release, "%u.%u.%u", &version, &patchlevel, &sublevel);
if (n != 3)
return -ENOSYS;
return KERNEL_VERSION(version, patchlevel, sublevel);
}
#else
int tapdisk_linux_version(void)
{
return -ENOSYS;
}
#endif
int read_exact(int fd, void *data, size_t size)
{
size_t offset = 0;
ssize_t len;
while ( offset < size )
{
len = read(fd, (char *)data + offset, size - offset);
if ( (len == -1) && (errno == EINTR) )
continue;
if ( len == 0 )
errno = 0;
if ( len <= 0 )
return -1;
offset += len;
}
return 0;
}
int write_exact(int fd, const void *data, size_t size)
{
size_t offset = 0;
ssize_t len;
while ( offset < size )
{
len = write(fd, (const char *)data + offset, size - offset);
if ( (len == -1) && (errno == EINTR) )
continue;
if ( len <= 0 )
return -1;
offset += len;
}
return 0;
}
-45
View File
@@ -1,45 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TAPDISK_UTILS_H_
#define _TAPDISK_UTILS_H_
#include <inttypes.h>
#define MAX_NAME_LEN 1000
void tapdisk_start_logging(const char *);
void tapdisk_stop_logging(void);
int tapdisk_set_resource_limits(void);
int tapdisk_namedup(char **, const char *);
int tapdisk_get_image_size(int, uint64_t *, uint32_t *);
int tapdisk_linux_version(void);
int read_exact(int fd, void *data, size_t size); /* EOF => -1, errno=0 */
int write_exact(int fd, const void *data, size_t size);
#endif
File diff suppressed because it is too large. Load diff
-207
View File
@@ -1,207 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TAPDISK_VBD_H_
#define _TAPDISK_VBD_H_
#include <sys/time.h>
#include <xenctrl.h>
#include <xen/io/blkif.h>
#include "tapdisk.h"
#include "scheduler.h"
#include "tapdisk-image.h"
#define TD_VBD_MAX_RETRIES 100
#define TD_VBD_RETRY_INTERVAL 1
#define TD_VBD_DEAD 0x0001
#define TD_VBD_CLOSED 0x0002
#define TD_VBD_QUIESCE_REQUESTED 0x0004
#define TD_VBD_QUIESCED 0x0008
#define TD_VBD_PAUSE_REQUESTED 0x0010
#define TD_VBD_PAUSED 0x0020
#define TD_VBD_SHUTDOWN_REQUESTED 0x0040
#define TD_VBD_LOCKING 0x0080
#define TD_VBD_RETRY_NEEDED 0x0100
#define TD_VBD_LOG_DROPPED 0x0200
typedef struct td_ring td_ring_t;
typedef struct td_vbd_request td_vbd_request_t;
typedef struct td_vbd_driver_info td_vbd_driver_info_t;
typedef struct td_vbd_handle td_vbd_t;
typedef void (*td_vbd_cb_t) (void *, blkif_response_t *);
struct td_ring {
int fd;
char *mem;
blkif_sring_t *sring;
blkif_back_ring_t fe_ring;
unsigned long vstart;
};
struct td_vbd_request {
blkif_request_t req;
int16_t status;
int error;
int blocked; /* blocked on a dependency */
int submitting;
int secs_pending;
int num_retries;
struct timeval last_try;
td_vbd_t *vbd;
struct list_head next;
};
struct td_vbd_driver_info {
char *params;
int type;
struct list_head next;
};
struct td_vbd_handle {
char *name;
td_uuid_t uuid;
int minor;
struct list_head driver_stack;
int storage;
uint8_t reopened;
uint8_t reactivated;
td_flag_t flags;
td_flag_t state;
struct list_head images;
struct list_head new_requests;
struct list_head pending_requests;
struct list_head failed_requests;
struct list_head completed_requests;
td_vbd_request_t request_list[MAX_REQUESTS];
td_ring_t ring;
event_id_t ring_event_id;
td_vbd_cb_t callback;
void *argument;
struct list_head next;
struct timeval ts;
uint64_t received;
uint64_t returned;
uint64_t kicked;
uint64_t secs_pending;
uint64_t retries;
uint64_t errors;
};
#define tapdisk_vbd_for_each_request(vreq, tmp, list) \
list_for_each_entry_safe((vreq), (tmp), (list), next)
#define tapdisk_vbd_for_each_image(vbd, image, tmp) \
list_for_each_entry_safe((image), (tmp), &(vbd)->images, next)
static inline void
tapdisk_vbd_move_request(td_vbd_request_t *vreq, struct list_head *dest)
{
list_del(&vreq->next);
INIT_LIST_HEAD(&vreq->next);
list_add_tail(&vreq->next, dest);
}
static inline void
tapdisk_vbd_add_image(td_vbd_t *vbd, td_image_t *image)
{
list_add_tail(&image->next, &vbd->images);
}
static inline int
tapdisk_vbd_is_last_image(td_vbd_t *vbd, td_image_t *image)
{
return list_is_last(&image->next, &vbd->images);
}
td_image_t *
tapdisk_vbd_first_image(td_vbd_t *vbd);
static inline td_image_t *
tapdisk_vbd_last_image(td_vbd_t *vbd)
{
return list_entry(vbd->images.prev, td_image_t, next);
}
static inline td_image_t *
tapdisk_vbd_next_image(td_image_t *image)
{
return list_entry(image->next.next, td_image_t, next);
}
td_vbd_t *tapdisk_vbd_create(td_uuid_t);
int tapdisk_vbd_initialize(td_uuid_t);
void tapdisk_vbd_set_callback(td_vbd_t *, td_vbd_cb_t, void *);
int tapdisk_vbd_parse_stack(td_vbd_t *vbd, const char *path);
int tapdisk_vbd_open(td_vbd_t *, const char *, uint16_t,
uint16_t, int, const char *, td_flag_t);
int tapdisk_vbd_close(td_vbd_t *);
void tapdisk_vbd_free(td_vbd_t *);
void tapdisk_vbd_free_stack(td_vbd_t *);
int tapdisk_vbd_open_stack(td_vbd_t *, uint16_t, td_flag_t);
int tapdisk_vbd_open_vdi(td_vbd_t *, const char *,
uint16_t, uint16_t, td_flag_t);
void tapdisk_vbd_close_vdi(td_vbd_t *);
int tapdisk_vbd_attach(td_vbd_t *, const char *, int);
void tapdisk_vbd_detach(td_vbd_t *);
void tapdisk_vbd_forward_request(td_request_t);
int tapdisk_vbd_get_image_info(td_vbd_t *, image_t *);
int tapdisk_vbd_queue_ready(td_vbd_t *);
int tapdisk_vbd_retry_needed(td_vbd_t *);
int tapdisk_vbd_quiesce_queue(td_vbd_t *);
int tapdisk_vbd_start_queue(td_vbd_t *);
int tapdisk_vbd_issue_requests(td_vbd_t *);
int tapdisk_vbd_kill_queue(td_vbd_t *);
int tapdisk_vbd_pause(td_vbd_t *);
int tapdisk_vbd_resume(td_vbd_t *, const char *, uint16_t);
int tapdisk_vbd_kick(td_vbd_t *);
void tapdisk_vbd_check_state(td_vbd_t *);
void tapdisk_vbd_check_progress(td_vbd_t *);
void tapdisk_vbd_debug(td_vbd_t *);
void tapdisk_vbd_complete_vbd_request(td_vbd_t *, td_vbd_request_t *);
#endif
-169
View File
@@ -1,169 +0,0 @@
/*
* Copyright (c) 2007, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Some notes on the tap_disk interface:
*
* tap_disk aims to provide a generic interface to easily implement new
* types of image accessors. The structure-of-function-calls is similar
* to disk interfaces used in qemu/denali/etc, with the significant
* difference being the expectation of asynchronous rather than synchronous
* I/O. The asynchronous interface is intended to allow lots of requests to
* be pipelined through a disk, without the disk requiring any of its own
* threads of control. As such, a batch of requests is delivered to the disk
* using:
*
* td_queue_[read,write]()
*
* and passing in a completion callback, which the disk is responsible for
* tracking. Disks should transform these requests as necessary and return
* the resulting iocbs to tapdisk using td_prep_[read,write]() and
* td_queue_tiocb().
*
* NOTE: tapdisk uses the number of sectors submitted per request as a
* ref count. Plugins must use the callback function to communicate the
* completion -- or error -- of every sector submitted to them.
*
* td_get_parent_id returns:
* 0 if parent id successfully retrieved
* TD_NO_PARENT if no parent exists
* -errno on error
*/
#ifndef _TAPDISK_H_
#define _TAPDISK_H_
#include <time.h>
#include <stdint.h>
#include "list.h"
#include "blktaplib.h"
#include "tapdisk-log.h"
#include "tapdisk-utils.h"
#ifdef MEMSHR
#include "memshr.h"
#endif
#define DPRINTF(_f, _a...) syslog(LOG_INFO, _f, ##_a)
#define EPRINTF(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f, __func__, ##_a)
#define PERROR(_f, _a...) EPRINTF(_f ": %s", ##_a, strerror(errno))
#define MAX_SEGMENTS_PER_REQ 11
#define SECTOR_SHIFT 9
#define DEFAULT_SECTOR_SIZE 512
#define TAPDISK_DATA_REQUESTS (MAX_REQUESTS * MAX_SEGMENTS_PER_REQ)
//#define BLK_NOT_ALLOCATED (-99)
#define TD_NO_PARENT 1
#define MAX_RAMDISK_SIZE 1024000 /*500MB disk limit*/
#define TD_OP_READ 0
#define TD_OP_WRITE 1
#define TD_OPEN_QUIET 0x00001
#define TD_OPEN_QUERY 0x00002
#define TD_OPEN_RDONLY 0x00004
#define TD_OPEN_STRICT 0x00008
#define TD_OPEN_SHAREABLE 0x00010
#define TD_OPEN_ADD_CACHE 0x00020
#define TD_OPEN_VHD_INDEX 0x00040
#define TD_OPEN_LOG_DIRTY 0x00080
#define TD_CREATE_SPARSE 0x00001
#define TD_CREATE_MULTITYPE 0x00002
#define td_flag_set(word, flag) ((word) |= (flag))
#define td_flag_clear(word, flag) ((word) &= ~(flag))
#define td_flag_test(word, flag) ((word) & (flag))
typedef uint16_t td_uuid_t;
typedef uint32_t td_flag_t;
typedef uint64_t td_sector_t;
typedef struct td_disk_id td_disk_id_t;
typedef struct td_disk_info td_disk_info_t;
typedef struct td_request td_request_t;
typedef struct td_driver_handle td_driver_t;
typedef struct td_image_handle td_image_t;
struct td_disk_id {
char *name;
int drivertype;
};
struct td_disk_info {
td_sector_t size;
uint64_t sector_size;
uint32_t info;
};
struct td_request {
int op;
char *buf;
td_sector_t sec;
int secs;
uint8_t blocked; /* blocked on a dependency */
td_image_t *image;
void * /*td_callback_t*/ cb;
void *cb_data;
uint64_t id;
int sidx;
void *private;
#ifdef MEMSHR
share_tuple_t memshr_hnd;
#endif
};
/*
* Prototype of the callback to activate as requests complete.
*/
typedef void (*td_callback_t)(td_request_t, int);
/*
* Structure describing the interface to a virtual disk implementation.
* See note at the top of this file describing this interface.
*/
struct tap_disk {
const char *disk_type;
td_flag_t flags;
int private_data_size;
int (*td_open) (td_driver_t *, const char *, td_flag_t);
int (*td_close) (td_driver_t *);
int (*td_get_parent_id) (td_driver_t *, td_disk_id_t *);
int (*td_validate_parent) (td_driver_t *, td_driver_t *, td_flag_t);
void (*td_queue_read) (td_driver_t *, td_request_t);
void (*td_queue_write) (td_driver_t *, td_request_t);
void (*td_debug) (td_driver_t *);
};
#endif
-138
View File
@@ -1,138 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef MEMSHR
#include <memshr.h>
#endif
#include "tapdisk.h"
#include "tapdisk-utils.h"
#include "tapdisk-server.h"
#include "tapdisk-control.h"
static void
usage(const char *app, int err)
{
fprintf(stderr, "usage: %s [-D] <-u uuid> <-c control socket>\n", app);
exit(err);
}
int
main(int argc, char *argv[])
{
char *control;
int c, err, nodaemon;
control = NULL;
nodaemon = 0;
while ((c = getopt(argc, argv, "s:Dh")) != -1) {
switch (c) {
case 'D':
nodaemon = 1;
break;
case 'h':
usage(argv[0], 0);
break;
case 's':
#ifdef MEMSHR
memshr_set_domid(atoi(optarg));
#else
fprintf(stderr, "MEMSHR support not compiled in.\n");
exit(EXIT_FAILURE);
#endif
break;
default:
usage(argv[0], EINVAL);
}
}
if (optind != argc)
usage(argv[0], EINVAL);
if (chdir("/")) {
DPRINTF("failed to chdir(/): %d\n", errno);
err = 1;
goto out;
}
tapdisk_start_logging("tapdisk2");
err = tapdisk_server_init();
if (err) {
DPRINTF("failed to initialize server: %d\n", err);
goto out;
}
if (!nodaemon) {
err = daemon(0, 1);
if (err) {
DPRINTF("failed to daemonize: %d\n", errno);
goto out;
}
}
err = tapdisk_control_open(&control);
if (err) {
DPRINTF("failed to open control socket: %d\n", err);
goto out;
}
fprintf(stdout, "%s\n", control);
fflush(stdout);
if (!nodaemon) {
int fd;
fd = open("/dev/null", O_RDWR);
if (fd != -1) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > 2)
close(fd);
}
}
err = tapdisk_server_complete();
if (err) {
DPRINTF("failed to complete server: %d\n", err);
goto out;
}
err = tapdisk_server_run();
out:
tapdisk_control_close();
tapdisk_stop_logging();
return err;
}
-691
View File
@@ -1,691 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <unistd.h>
#include <string.h>
#include "libvhd.h"
#include "vhd-util.h"
#include "tapdisk-utils.h"
#if 1
#define DFPRINTF(_f, _a...) fprintf ( stdout, _f , ## _a )
#else
#define DFPRINTF(_f, _a...) ((void)0)
#endif
typedef enum {
TD_FIELD_HIDDEN = 0,
TD_FIELD_INVALID = 1
} td_field_t;
struct vdi_field {
char *name;
td_field_t id;
};
static struct vdi_field td_vdi_fields[TD_FIELD_INVALID] = {
{ .id = TD_FIELD_HIDDEN, .name = "hidden" }
};
typedef enum {
TD_CMD_CREATE = 0,
TD_CMD_SNAPSHOT,
/* TD_CMD_COALESCE, */
TD_CMD_QUERY,
/* TD_CMD_RESIZE, */
TD_CMD_SET,
/* TD_CMD_REPAIR, */
/* TD_CMD_FILL, */
/* TD_CMD_READ, */
TD_CMD_INVALID,
} td_command_t;
struct command {
td_command_t id;
char *name;
int needs_type;
};
struct command commands[TD_CMD_INVALID] = {
{ .id = TD_CMD_CREATE, .name = "create", .needs_type = 1 },
{ .id = TD_CMD_SNAPSHOT, .name = "snapshot", .needs_type = 1 },
/* { .id = TD_CMD_COALESCE, .name = "coalesce", .needs_type = 1 }, */
{ .id = TD_CMD_QUERY, .name = "query", .needs_type = 1 },
/* { .id = TD_CMD_RESIZE, .name = "resize", .needs_type = 1 }, */
{ .id = TD_CMD_SET, .name = "set", .needs_type = 1 },
/* { .id = TD_CMD_REPAIR, .name = "repair", .needs_type = 1 }, */
/* { .id = TD_CMD_FILL, .name = "fill", .needs_type = 1 }, */
/* { .id = TD_CMD_READ, .name = "read", .needs_type = 1 }, */
};
typedef enum {
TD_TYPE_VHD = 0,
TD_TYPE_AIO,
TD_TYPE_INVALID,
} td_disk_t;
const char *td_disk_types[TD_TYPE_INVALID] = {
"vhd",
"aio",
};
#define print_commands() \
do { \
int i; \
fprintf(stderr, "COMMAND := { "); \
fprintf(stderr, "%s", commands[0].name); \
for (i = 1; i < TD_CMD_INVALID; i++) \
fprintf(stderr, " | %s", commands[i].name); \
fprintf(stderr, " }\n"); \
} while (0)
#define print_disk_types() \
do { \
int i; \
fprintf(stderr, "TYPE := { "); \
fprintf(stderr, "%s", td_disk_types[0]); \
for (i = 1; i < TD_TYPE_INVALID; i++) \
fprintf(stderr, " | %s", td_disk_types[i]); \
fprintf(stderr, " }\n"); \
} while (0);
#define print_field_names() \
do { \
int i; \
fprintf(stderr, "FIELD := { "); \
fprintf(stderr, "%s", td_vdi_fields[0].name); \
for (i = 1; i < TD_FIELD_INVALID; i++) \
fprintf(stderr, " | %s", td_vdi_fields[i].name); \
fprintf(stderr, " }\n"); \
} while (0)
void
help(void)
{
fprintf(stderr, "Tapdisk Utilities: v1.0.0\n");
fprintf(stderr, "usage: td-util COMMAND [TYPE] [OPTIONS]\n");
print_commands();
print_disk_types();
exit(-1);
}
struct command *
get_command(char *command)
{
int i;
for (i = 0; i < TD_CMD_INVALID; i++)
if (!strcmp(command, commands[i].name))
return &commands[i];
return NULL;
}
struct vdi_field *
get_field(char *field)
{
int i;
for (i = 0; i < TD_FIELD_INVALID; i++)
if (!strcmp(field, td_vdi_fields[i].name))
return &td_vdi_fields[i];
return NULL;
}
int
get_driver_type(char *type)
{
int i;
if (strnlen(type, 25) >= 25)
return -ENAMETOOLONG;
for (i = 0; i < TD_TYPE_INVALID; i++)
if (!strcmp(type, td_disk_types[i]))
return i;
return -TD_TYPE_INVALID;
}
int
td_create(int type, int argc, char *argv[])
{
ssize_t mb;
uint64_t size;
char *name, *buf;
int c, i, fd, sparse = 1, fixedsize = 0;
while ((c = getopt(argc, argv, "hrb")) != -1) {
switch(c) {
case 'r':
sparse = 0;
break;
case 'b':
fixedsize = 1;
break;
default:
fprintf(stderr, "Unknown option %c\n", (char)c);
case 'h':
goto usage;
}
}
if (optind != (argc - 2))
goto usage;
mb = 1 << 20;
size = atoi(argv[optind++]);
size = size << 20;
name = argv[optind];
if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN) {
fprintf(stderr, "Device name too long\n");
return ENAMETOOLONG;
}
if (type == TD_TYPE_VHD) {
int cargc = 0;
char sbuf[32], *cargv[10];
size >>= 20;
memset(cargv, 0, sizeof(cargv));
snprintf(sbuf, sizeof(sbuf) - 1, "%"PRIu64, size);
cargv[cargc++] = "create";
cargv[cargc++] = "-n";
cargv[cargc++] = name;
cargv[cargc++] = "-s";
cargv[cargc++] = sbuf;
if (!sparse)
cargv[cargc++] = "-r";
if (fixedsize)
cargv[cargc++] = "-b";
return vhd_util_create(cargc, cargv);
}
/* generic create */
if (sparse) {
fprintf(stderr, "Cannot create sparse %s image\n",
td_disk_types[type]);
return EINVAL;
}
buf = calloc(1, mb);
if (!buf)
return ENOMEM;
fd = open(name, O_WRONLY | O_DIRECT | O_CREAT | O_TRUNC, 0644);
if (fd == -1) {
free(buf);
return errno;
}
size >>= 20;
for (i = 0; i < size; i++)
if (write(fd, buf, mb) != mb) {
close(fd);
unlink(name);
free(buf);
return EIO;
}
close(fd);
free(buf);
return 0;
usage:
fprintf(stderr, "usage: td-util create %s [-h help] [-r reserve] "
"[-b file_is_fixed_size] <SIZE(MB)> <FILENAME>\n",
td_disk_types[type]);
return EINVAL;
}
int
td_snapshot(int type, int argc, char *argv[])
{
char *cargv[10];
int c, err, cargc;
struct stat stats;
char *name, *backing, *limit = NULL;
int fixedsize = 0, rawparent = 0;
if (type != TD_TYPE_VHD) {
fprintf(stderr, "Cannot create snapshot of %s image type\n",
td_disk_types[type]);
return EINVAL;
}
while ((c = getopt(argc, argv, "hbml:")) != -1) {
switch(c) {
case 'b':
fixedsize = 1;
break;
case 'm':
rawparent = 1;
break;
case 'l':
limit = optarg;
break;
case 'h':
err = 0;
goto usage;
default:
err = EINVAL;
goto usage;
}
}
if (optind != (argc - 2)) {
err = EINVAL;
goto usage;
}
name = argv[optind++];
backing = argv[optind++];
if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN ||
strnlen(backing, MAX_NAME_LEN) == MAX_NAME_LEN) {
fprintf(stderr, "Device name too long\n");
return ENAMETOOLONG;
}
if (stat(backing, &stats) == -1) {
fprintf(stderr, "File %s not found\n", backing);
return errno;
}
cargc = 0;
memset(cargv, 0, sizeof(cargv));
cargv[cargc++] = "snapshot";
cargv[cargc++] = "-n";
cargv[cargc++] = name;
cargv[cargc++] = "-p";
cargv[cargc++] = backing;
if (fixedsize)
cargv[cargc++] = "-b";
if (rawparent)
cargv[cargc++] = "-m";
if (limit) {
cargv[cargc++] = "-l";
cargv[cargc++] = limit;
}
return vhd_util_snapshot(cargc, cargv);
usage:
fprintf(stderr, "usage: td-util snapshot %s [-h help] [-m parent_raw] "
"[-b file_is_fixed_size] [-l snapshot depth limit] "
"<FILENAME> <BACKING_FILENAME>\n", td_disk_types[type]);
return err;
}
int
td_coalesce(int type, int argc, char *argv[])
{
int c, ret, cargc;
char *name, *pname, *cargv[3];
if (type != TD_TYPE_VHD) {
fprintf(stderr, "Cannot create snapshot of %s image type\n",
td_disk_types[type]);
return EINVAL;
}
while ((c = getopt(argc, argv, "h")) != -1) {
switch(c) {
default:
fprintf(stderr, "Unknown option %c\n", (char)c);
case 'h':
goto usage;
}
}
if (optind != (argc - 1))
goto usage;
name = argv[optind++];
if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN) {
fprintf(stderr, "Device name too long\n");
return ENAMETOOLONG;
}
cargc = 0;
memset(cargv, 0, sizeof(cargv));
cargv[cargc++] = "coalesce";
cargv[cargc++] = "-n";
cargv[cargc++] = name;
ret = vhd_util_coalesce(cargc, cargv);
if (ret)
printf("coalesce failed: %d\n", ret);
return ret;
usage:
fprintf(stderr, "usage: td-util coalesce %s [-h help] "
"<FILENAME>\n", td_disk_types[type]);
return EINVAL;
}
int
td_query(int type, int argc, char *argv[])
{
char *name;
int c, size = 0, parent = 0, fields = 0, depth = 0, err = 0;
while ((c = getopt(argc, argv, "hvpfd")) != -1) {
switch(c) {
case 'v':
size = 1;
break;
case 'p':
parent = 1;
break;
case 'f':
fields = 1;
break;
case 'd':
depth = 1;
break;
case 'h':
err = 0;
goto usage;
default:
err = EINVAL;
goto usage;
}
}
if (optind != (argc - 1)) {
err = EINVAL;
goto usage;
}
name = argv[optind++];
if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN) {
fprintf(stderr, "Device name too long\n");
return ENAMETOOLONG;
}
if (type == TD_TYPE_VHD) {
vhd_context_t vhd;
err = vhd_open(&vhd, name, VHD_OPEN_RDONLY);
if (err) {
printf("failed opening %s: %d\n", name, err);
return err;
}
if (size)
printf("%"PRIu64"\n", vhd.footer.curr_size >> 20);
if (parent) {
if (vhd.footer.type != HD_TYPE_DIFF)
printf("%s has no parent\n", name);
else {
char *pname;
err = vhd_parent_locator_get(&vhd, &pname);
if (err)
printf("failed getting parent: %d\n",
err);
else {
printf("%s\n", pname);
free(pname);
}
}
}
if (fields) {
int ret, hidden;
ret = vhd_hidden(&vhd, &hidden);
if (ret) {
printf("failed checking 'hidden' field: %d\n",
ret);
err = (err ? : ret);
} else
printf("%s: %d\n",
td_vdi_fields[TD_FIELD_HIDDEN].name,
hidden);
}
if (depth) {
int ret, length;
ret = vhd_chain_depth(&vhd, &length);
if (ret)
printf("error checking chain depth: %d\n", ret);
else
printf("chain depth: %d\n", length);
err = (err ? : ret);
}
vhd_close(&vhd);
} else if (type == TD_TYPE_AIO) {
if (size) {
int fd;
uint64_t secs;
uint32_t ssize;
fd = open(name, O_RDONLY | O_LARGEFILE);
if (fd == -1) {
printf("failed opening %s: %d\n", name, errno);
return -errno;
}
err = tapdisk_get_image_size(fd, &secs, &ssize);
close(fd);
if (err) {
printf("failed getting size for %s: %d\n:",
name, err);
return err;
}
printf("%"PRIu64"\n", secs >> 11);
}
if (parent)
printf("%s has no parent\n", name);
if (fields) {
int i;
for (i = 0; i < TD_FIELD_INVALID; i++)
printf("%s: 0\n", td_vdi_fields[i].name);
}
}
return err;
usage:
fprintf(stderr, "usage: td-util query %s [-h help] [-v virtsize] "
"[-p parent] [-f fields] <FILENAME>\n", td_disk_types[type]);
return err;
}
int
td_set_field(int type, int argc, char *argv[])
{
int ret, i, c, cargc;
struct vdi_field *field;
char *name, *value, *cargv[7];
if (type != TD_TYPE_VHD) {
fprintf(stderr, "Cannot set fields of %s images\n",
td_disk_types[type]);
return EINVAL;
}
while ((c = getopt(argc, argv, "h")) != -1) {
switch(c) {
default:
fprintf(stderr, "Unknown option %c\n", (char)c);
case 'h':
goto usage;
}
}
if (optind != (argc - 3))
goto usage;
name = argv[optind++];
field = get_field(argv[optind]);
if (!field || field->id != TD_FIELD_HIDDEN) {
fprintf(stderr, "Invalid field %s\n", argv[optind]);
goto usage;
}
value = argv[++optind];
cargc = 0;
memset(cargv, 0, sizeof(cargv));
cargv[cargc++] = "set";
cargv[cargc++] = "-n";
cargv[cargc++] = name;
cargv[cargc++] = "-f";
cargv[cargc++] = field->name;
cargv[cargc++] = "-v";
cargv[cargc++] = value;
return vhd_util_set_field(cargc, cargv);
usage:
fprintf(stderr, "usage: td-util set %s [-h help] "
"<FILENAME> <FIELD> <VALUE>\n", td_disk_types[type]);
print_field_names();
return EINVAL;
}
int
main(int argc, char *argv[])
{
char **cargv;
struct command *cmd;
int cargc, i, type = -1, ret = 0;
#ifdef CORE_DUMP
struct rlimit rlim;
rlim.rlim_cur = RLIM_INFINITY;
rlim.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
fprintf(stderr, "setrlimit failed: %d\n", errno);
#endif
if (argc < 2)
help();
cargc = argc - 1;
cmd = get_command(argv[1]);
if (!cmd) {
fprintf(stderr, "invalid COMMAND %s\n", argv[1]);
help();
}
if (cmd->needs_type) {
if (argc < 3) {
fprintf(stderr, "td-util %s requires a TYPE\n",
cmd->name);
print_disk_types();
exit(-1);
}
type = get_driver_type(argv[2]);
if (type < 0) {
fprintf(stderr, "invalid TYPE '%s'.\n", argv[2]);
print_disk_types();
exit(-1);
}
--cargc;
}
cargv = malloc(sizeof(char *) * cargc);
if (!cargv)
exit(ENOMEM);
cargv[0] = cmd->name;
for (i = 1; i < cargc; i++)
cargv[i] = argv[i + (argc - cargc)];
switch(cmd->id) {
case TD_CMD_CREATE:
ret = td_create(type, cargc, cargv);
break;
case TD_CMD_SNAPSHOT:
ret = td_snapshot(type, cargc, cargv);
break;
/*
case TD_CMD_COALESCE:
ret = td_coalesce(type, cargc, cargv);
break;
*/
case TD_CMD_QUERY:
ret = td_query(type, cargc, cargv);
break;
/*
case TD_CMD_RESIZE:
ret = td_resize(type, cargc, cargv);
break;
*/
case TD_CMD_SET:
ret = td_set_field(type, cargc, cargv);
break;
/*
case TD_CMD_REPAIR:
ret = td_repair(type, cargc, cargv);
break;
case TD_CMD_FILL:
ret = td_fill(type, cargc, cargv);
break;
case TD_CMD_READ:
ret = td_read(type, cargc, cargv);
break;
*/
default:
case TD_CMD_INVALID:
ret = EINVAL;
break;
}
free(cargv);
return (ret >= 0 ? ret : -ret);
}
-78
View File
@@ -1,78 +0,0 @@
#!/bin/bash
usage () { echo "USAGE: xmsnap <VM ID> <Backing File>"; }
#
# Check Usage
#
if [ -n "$1" ]
then
vmid=$1
else
usage
exit 1
fi
if [ -n "$2" ]
then
target=$2
else
usage
exit 1
fi
if [ -e "$target" ]
then
echo "Creating snapshot of file $target for VM $vmid."
else
usage
echo "File $target not found."
exit 1
fi
#
# Find the snapshot name
#
directory=`dirname "$target"`
target=`basename "$target"`
let maxidx=0
if [ -e $directory/${target}.snap1 ]
then
for idx in $(ls $directory/${target}.snap*)
do
let idx=${idx#$directory/${target}.snap}
if [ "$idx" -gt "$maxidx" ]
then
let maxidx=$idx
fi
done
fi
snap=${target}.snap`expr $maxidx + 1`
#
# Pause VM
#
xm pause $vmid
if [ "$?" -ne "0" ]; then
exit 1
fi
#
# Snap and reposition the files
#
mv $directory/$target $directory/$snap
if [ "$?" -ne "0" ]; then
exit 1
fi
qcow-create 0 $directory/$target $directory/$snap
#
# Unpause
#
xm unpause $vmid
exit
-17
View File
@@ -1,17 +0,0 @@
XEN_ROOT := $(CURDIR)/../../..
include $(XEN_ROOT)/tools/Rules.mk
.PHONY: all
all:
.PHONY: install
install:
$(INSTALL_DIR) -p $(DESTDIR)$(includedir)
.PHONY: clean
clean:
@:
.PHONY: distclean
distclean: clean
-33
View File
@@ -1,33 +0,0 @@
/* $OpenBSD: atomicio.h,v 1.6 2005/05/24 17:32:43 avsm Exp $ */
/*
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Ensure all of data on socket comes through. f==read || f==vwrite
*/
size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t);
#define vwrite (ssize_t (*)(int, void *, size_t))write
-67
View File
@@ -1,67 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _BLKTAP_2_H_
#define _BLKTAP_2_H_
#define BLKTAP2_MAX_MESSAGE_LEN 256
#define BLKTAP2_RING_MESSAGE_PAUSE 1
#define BLKTAP2_RING_MESSAGE_RESUME 2
#define BLKTAP2_RING_MESSAGE_CLOSE 3
#define BLKTAP2_IOCTL_KICK_FE 1
#define BLKTAP2_IOCTL_ALLOC_TAP 200
#define BLKTAP2_IOCTL_FREE_TAP 201
#define BLKTAP2_IOCTL_CREATE_DEVICE 202
#define BLKTAP2_IOCTL_SET_PARAMS 203
#define BLKTAP2_IOCTL_PAUSE 204
#define BLKTAP2_IOCTL_REOPEN 205
#define BLKTAP2_IOCTL_RESUME 206
#define BLKTAP2_SYSFS_DIR "/sys/class/blktap2"
#define BLKTAP2_CONTROL_NAME "blktap-control"
#define BLKTAP2_CONTROL_DIR "/var/run/"BLKTAP2_CONTROL_NAME
#define BLKTAP2_CONTROL_SOCKET "ctl"
#define BLKTAP2_DIRECTORY "/dev/xen/blktap-2"
#define BLKTAP2_CONTROL_DEVICE BLKTAP2_DIRECTORY"/control"
#define BLKTAP2_RING_DEVICE BLKTAP2_DIRECTORY"/blktap"
#define BLKTAP2_IO_DEVICE BLKTAP2_DIRECTORY"/tapdev"
struct blktap2_handle {
unsigned int ring;
unsigned int device;
unsigned int minor;
};
struct blktap2_params {
char name[BLKTAP2_MAX_MESSAGE_LEN];
unsigned long long capacity;
unsigned long sector_size;
};
#endif
-242
View File
@@ -1,242 +0,0 @@
/* blktaplib.h
*
* Blktap library userspace code.
*
* Copyright (c) 2007, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __BLKTAPLIB_H__
#define __BLKTAPLIB_H__
#include <syslog.h>
#include <sys/time.h>
#include <xenctrl.h>
#include <xen/io/blkif.h>
#define BLK_RING_SIZE __CONST_RING_SIZE(blkif, XC_PAGE_SIZE)
/* size of the extra VMA area to map in attached pages. */
#define BLKTAP_VMA_PAGES BLK_RING_SIZE
/* blktap IOCTLs: These must correspond with the blktap driver ioctls */
#define BLKTAP_IOCTL_KICK_FE 1
#define BLKTAP_IOCTL_KICK_BE 2
#define BLKTAP_IOCTL_SETMODE 3
#define BLKTAP_IOCTL_SENDPID 4
#define BLKTAP_IOCTL_NEWINTF 5
#define BLKTAP_IOCTL_MINOR 6
#define BLKTAP_IOCTL_MAJOR 7
#define BLKTAP_QUERY_ALLOC_REQS 8
#define BLKTAP_IOCTL_FREEINTF 9
#define BLKTAP_IOCTL_PRINT_IDXS 100
#define BLKTAP_IOCTL_BACKDEV_SETUP 200
#define PRIO_SPECIAL_IO -9999
/* blktap switching modes: (Set with BLKTAP_IOCTL_SETMODE) */
#define BLKTAP_MODE_PASSTHROUGH 0x00000000 /* default */
#define BLKTAP_MODE_INTERCEPT_FE 0x00000001
#define BLKTAP_MODE_INTERCEPT_BE 0x00000002
#define BLKTAP_MODE_INTERPOSE \
(BLKTAP_MODE_INTERCEPT_FE | BLKTAP_MODE_INTERCEPT_BE)
static inline int BLKTAP_MODE_VALID(unsigned long arg)
{
return (
( arg == BLKTAP_MODE_PASSTHROUGH ) ||
( arg == BLKTAP_MODE_INTERCEPT_FE ) ||
( arg == BLKTAP_MODE_INTERPOSE ) );
}
#define MAX_REQUESTS BLK_RING_SIZE
#define BLKTAP_IOCTL_KICK 1
#define MAX_PENDING_REQS BLK_RING_SIZE
#define BLKTAP_DEV_DIR "/dev/xen"
#define BLKTAP_DEV_NAME "blktap"
#define BACKDEV_NAME "backdev"
#define BLKTAP_DEV_MINOR 0
#define BLKTAP_CTRL_DIR "/var/run/tap"
extern int blktap_major;
#define BLKTAP_RING_PAGES 1 /* Front */
#define BLKTAP_MMAP_REGION_SIZE (BLKTAP_RING_PAGES + MMAP_PAGES)
struct blkif;
struct blkif_info;
typedef struct {
blkif_request_t req;
int submitting;
int secs_pending;
int16_t status;
int num_retries;
struct timeval last_try;
} pending_req_t;
typedef struct blkif {
domid_t domid;
long int handle;
long int pdev;
long int readonly;
enum { DISCONNECTED, DISCONNECTING, CONNECTED } state;
struct blkif_ops *ops;
struct blkif *hash_next;
void *prv; /* device-specific data */
struct blkif_info *info; /*Image parameter passing */
pending_req_t pending_list[MAX_REQUESTS];
int devnum;
int fds[2];
int be_id;
char *backend_path;
int major;
int minor;
pid_t tappid;
int drivertype;
uint16_t cookie;
int err;
} blkif_t;
typedef struct blkif_info {
char *params;
int readonly;
int storage;
} blkif_info_t;
typedef struct tapdev_info {
int fd;
char *mem;
blkif_sring_t *sring;
blkif_back_ring_t fe_ring;
unsigned long vstart;
blkif_t *blkif;
} tapdev_info_t;
typedef struct domid_translate {
unsigned short domid;
unsigned short busid;
} domid_translate_t ;
typedef struct image {
unsigned long long size;
unsigned long secsize;
unsigned int info;
} image_t;
typedef struct msg_hdr {
uint16_t type;
uint16_t len;
uint16_t drivertype;
uint16_t cookie;
} msg_hdr_t;
typedef struct msg_params {
uint8_t readonly;
int path_off;
int path_len;
int storage;
} msg_params_t;
typedef struct msg_newdev {
uint8_t devnum;
uint16_t domid;
} msg_newdev_t;
typedef struct msg_pid {
pid_t pid;
} msg_pid_t;
typedef struct msg_cp {
int cp_uuid_off;
int cp_uuid_len;
int cp_drivertype;
} msg_cp_t;
typedef struct msg_lock {
int ro;
int enforce;
int uuid_off;
int uuid_len;
} msg_lock_t;
#define READ 0
#define WRITE 1
/*Control Messages between manager and tapdev*/
#define CTLMSG_PARAMS 1
#define CTLMSG_IMG 2
#define CTLMSG_IMG_FAIL 3
#define CTLMSG_NEWDEV 4
#define CTLMSG_NEWDEV_RSP 5
#define CTLMSG_NEWDEV_FAIL 6
#define CTLMSG_CLOSE 7
#define CTLMSG_CLOSE_RSP 8
#define CTLMSG_PID 9
#define CTLMSG_PID_RSP 10
#define CTLMSG_CHECKPOINT 11
#define CTLMSG_CHECKPOINT_RSP 12
#define CTLMSG_LOCK 13
#define CTLMSG_LOCK_RSP 14
#define CTLMSG_PAUSE 15
#define CTLMSG_PAUSE_RSP 16
#define CTLMSG_RESUME 17
#define CTLMSG_RESUME_RSP 18
#define TAPDISK_STORAGE_TYPE_NFS 1
#define TAPDISK_STORAGE_TYPE_EXT 2
#define TAPDISK_STORAGE_TYPE_LVM 3
#define TAPDISK_STORAGE_TYPE_DEFAULT TAPDISK_STORAGE_TYPE_EXT
/* Abitrary values, must match the underlying driver... */
#define MAX_TAP_DEV 256
/* Accessing attached data page mappings */
#define MMAP_PAGES \
(MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST)
#define MMAP_VADDR(_vstart,_req,_seg) \
((_vstart) + \
((_req) * BLKIF_MAX_SEGMENTS_PER_REQUEST * getpagesize()) + \
((_seg) * getpagesize()))
/* Defines that are only used by library clients */
#ifndef __COMPILING_BLKTAP_LIB
static char *blkif_op_name[] = {
[BLKIF_OP_READ] = "READ",
[BLKIF_OP_WRITE] = "WRITE",
};
#endif /* __COMPILING_BLKTAP_LIB */
#endif /* __BLKTAPLIB_H__ */
-68
View File
@@ -1,68 +0,0 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _VHD_JOURNAL_H_
#define _VHD_JOURNAL_H_
#include <inttypes.h>
#include "libvhd.h"
#define VHD_JOURNAL_METADATA 0x01
#define VHD_JOURNAL_DATA 0x02
#define VHD_JOURNAL_HEADER_COOKIE "vjournal"
#define VHD_JOURNAL_ENTRY_COOKIE 0xaaaa12344321aaaa
typedef struct vhd_journal_header {
char cookie[8];
vhd_uuid_t uuid;
uint64_t vhd_footer_offset;
uint32_t journal_data_entries;
uint32_t journal_metadata_entries;
uint64_t journal_data_offset;
uint64_t journal_metadata_offset;
uint64_t journal_eof;
char pad[448];
} vhd_journal_header_t;
typedef struct vhd_journal {
char *jname;
int jfd;
int is_block; /* is jfd a block device */
vhd_journal_header_t header;
vhd_context_t vhd;
} vhd_journal_t;
int vhd_journal_create(vhd_journal_t *, const char *file, const char *jfile);
int vhd_journal_open(vhd_journal_t *, const char *file, const char *jfile);
int vhd_journal_add_block(vhd_journal_t *, uint32_t block, char mode);
int vhd_journal_commit(vhd_journal_t *);
int vhd_journal_revert(vhd_journal_t *);
int vhd_journal_close(vhd_journal_t *);
int vhd_journal_remove(vhd_journal_t *);
#endif
-326
View File
@@ -1,326 +0,0 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _VHD_LIB_H_
#define _VHD_LIB_H_
#include <string.h>
#if defined(__linux__)
#include <endian.h>
#include <byteswap.h>
#elif defined(__NetBSD__)
#include <sys/endian.h>
#include <sys/bswap.h>
#endif
#include "vhd-uuid.h"
#include "vhd.h"
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
#if defined(__linux__)
#define BE16_IN(foo) (*(foo)) = bswap_16(*(foo))
#define BE32_IN(foo) (*(foo)) = bswap_32(*(foo))
#define BE64_IN(foo) (*(foo)) = bswap_64(*(foo))
#define BE16_OUT(foo) (*(foo)) = bswap_16(*(foo))
#define BE32_OUT(foo) (*(foo)) = bswap_32(*(foo))
#define BE64_OUT(foo) (*(foo)) = bswap_64(*(foo))
#elif defined(__NetBSD__)
#define BE16_IN(foo) (*(foo)) = bswap16(*(foo))
#define BE32_IN(foo) (*(foo)) = bswap32(*(foo))
#define BE64_IN(foo) (*(foo)) = bswap64(*(foo))
#define BE16_OUT(foo) (*(foo)) = bswap16(*(foo))
#define BE32_OUT(foo) (*(foo)) = bswap32(*(foo))
#define BE64_OUT(foo) (*(foo)) = bswap64(*(foo))
#endif
#else
#define BE16_IN(foo)
#define BE32_IN(foo)
#define BE64_IN(foo)
#define BE32_OUT(foo)
#define BE32_OUT(foo)
#define BE64_OUT(foo)
#endif
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define VHD_MAX_NAME_LEN 1024
#define VHD_BLOCK_SHIFT 21
#define VHD_BLOCK_SIZE (1ULL << VHD_BLOCK_SHIFT)
#define UTF_16 "UTF-16"
#define UTF_16LE "UTF-16LE"
#define UTF_16BE "UTF-16BE"
#define VHD_OPEN_RDONLY 0x00001
#define VHD_OPEN_RDWR 0x00002
#define VHD_OPEN_FAST 0x00004
#define VHD_OPEN_STRICT 0x00008
#define VHD_OPEN_IGNORE_DISABLED 0x00010
#define VHD_FLAG_CREAT_PARENT_RAW 0x00001
#define vhd_flag_set(word, flag) ((word) |= (flag))
#define vhd_flag_clear(word, flag) ((word) &= ~(flag))
#define vhd_flag_test(word, flag) ((word) & (flag))
#define ENABLE_FAILURE_TESTING
#define FAIL_REPARENT_BEGIN 0
#define FAIL_REPARENT_LOCATOR 1
#define FAIL_REPARENT_END 2
#define FAIL_RESIZE_BEGIN 3
#define FAIL_RESIZE_DATA_MOVED 4
#define FAIL_RESIZE_METADATA_MOVED 5
#define FAIL_RESIZE_END 6
#define NUM_FAIL_TESTS 7
#ifdef ENABLE_FAILURE_TESTING
#define TEST_FAIL_AT(point) \
if (TEST_FAIL[point]) { \
printf("Failing at %s\n", ENV_VAR_FAIL[point]); exit(EINVAL); }
#define TEST_FAIL_EXTERN_VARS \
extern const char* ENV_VAR_FAIL[]; \
extern int TEST_FAIL[];
#else
#define TEST_FAIL_AT(point)
#define TEST_FAIL_EXTERN_VARS
#endif // ENABLE_FAILURE_TESTING
static const char VHD_POISON_COOKIE[] = "v_poison";
typedef struct hd_ftr vhd_footer_t;
typedef struct dd_hdr vhd_header_t;
typedef struct vhd_bat vhd_bat_t;
typedef struct vhd_batmap vhd_batmap_t;
typedef struct dd_batmap_hdr vhd_batmap_header_t;
typedef struct prt_loc vhd_parent_locator_t;
typedef struct vhd_context vhd_context_t;
typedef uint32_t vhd_flag_creat_t;
struct vhd_bat {
uint32_t spb;
uint32_t entries;
uint32_t *bat;
};
struct vhd_batmap {
vhd_batmap_header_t header;
char *map;
};
struct vhd_context {
int fd;
char *file;
int oflags;
int is_block;
uint32_t spb;
uint32_t bm_secs;
vhd_header_t header;
vhd_footer_t footer;
vhd_bat_t bat;
vhd_batmap_t batmap;
};
static inline uint32_t
secs_round_up(uint64_t bytes)
{
return ((bytes + (VHD_SECTOR_SIZE - 1)) >> VHD_SECTOR_SHIFT);
}
static inline uint32_t
secs_round_up_no_zero(uint64_t bytes)
{
return (secs_round_up(bytes) ? : 1);
}
static inline uint64_t
vhd_sectors_to_bytes(uint64_t sectors)
{
return sectors << VHD_SECTOR_SHIFT;
}
static inline uint64_t
vhd_bytes_padded(uint64_t bytes)
{
return vhd_sectors_to_bytes(secs_round_up_no_zero(bytes));
}
static inline int
vhd_type_dynamic(vhd_context_t *ctx)
{
return (ctx->footer.type == HD_TYPE_DYNAMIC ||
ctx->footer.type == HD_TYPE_DIFF);
}
static inline int
vhd_creator_tapdisk(vhd_context_t *ctx)
{
return !strncmp(ctx->footer.crtr_app, "tap", 3);
}
static inline int
vhd_disabled(vhd_context_t *ctx)
{
return (!memcmp(ctx->footer.cookie,
VHD_POISON_COOKIE, sizeof(ctx->footer.cookie)));
}
static inline size_t
vhd_parent_locator_size(vhd_parent_locator_t *loc)
{
/*
* MICROSOFT_COMPAT
* data_space *should* be in sectors,
* but sometimes we find it in bytes
*/
if (loc->data_space < 512)
return vhd_sectors_to_bytes(loc->data_space);
else if (loc->data_space % 512 == 0)
return loc->data_space;
else
return 0;
}
static inline int
vhd_parent_raw(vhd_context_t *ctx)
{
return vhd_uuid_is_nil(&ctx->header.prt_uuid);
}
void libvhd_set_log_level(int);
int vhd_test_file_fixed(const char *, int *);
uint32_t vhd_time(time_t time);
size_t vhd_time_to_string(uint32_t timestamp, char *target);
uint32_t vhd_chs(uint64_t size);
uint32_t vhd_checksum_footer(vhd_footer_t *);
uint32_t vhd_checksum_header(vhd_header_t *);
uint32_t vhd_checksum_batmap(vhd_batmap_t *);
void vhd_footer_in(vhd_footer_t *);
void vhd_footer_out(vhd_footer_t *);
void vhd_header_in(vhd_header_t *);
void vhd_header_out(vhd_header_t *);
void vhd_bat_in(vhd_bat_t *);
void vhd_bat_out(vhd_bat_t *);
void vhd_batmap_header_in(vhd_batmap_t *);
void vhd_batmap_header_out(vhd_batmap_t *);
int vhd_validate_footer(vhd_footer_t *footer);
int vhd_validate_header(vhd_header_t *header);
int vhd_validate_batmap_header(vhd_batmap_t *batmap);
int vhd_validate_batmap(vhd_batmap_t *batmap);
int vhd_validate_platform_code(uint32_t code);
int vhd_open(vhd_context_t *, const char *file, int flags);
void vhd_close(vhd_context_t *);
int vhd_create(const char *name, uint64_t bytes, int type, vhd_flag_creat_t);
/* vhd_snapshot: the bytes parameter is optional and can be 0 if the snapshot
* is to have the same size as the (first non-empty) parent */
int vhd_snapshot(const char *snapshot, uint64_t bytes, const char *parent,
vhd_flag_creat_t);
int vhd_hidden(vhd_context_t *, int *);
int vhd_chain_depth(vhd_context_t *, int *);
off_t vhd_position(vhd_context_t *);
int vhd_seek(vhd_context_t *, off_t, int);
int vhd_read(vhd_context_t *, void *, size_t);
int vhd_write(vhd_context_t *, void *, size_t);
int vhd_offset(vhd_context_t *, uint32_t, uint32_t *);
int vhd_end_of_headers(vhd_context_t *ctx, off_t *off);
int vhd_end_of_data(vhd_context_t *ctx, off_t *off);
int vhd_batmap_header_offset(vhd_context_t *ctx, off_t *off);
int vhd_get_header(vhd_context_t *);
int vhd_get_footer(vhd_context_t *);
int vhd_get_bat(vhd_context_t *);
int vhd_get_batmap(vhd_context_t *);
void vhd_put_header(vhd_context_t *);
void vhd_put_footer(vhd_context_t *);
void vhd_put_bat(vhd_context_t *);
void vhd_put_batmap(vhd_context_t *);
int vhd_has_batmap(vhd_context_t *);
int vhd_batmap_test(vhd_context_t *, vhd_batmap_t *, uint32_t);
void vhd_batmap_set(vhd_context_t *, vhd_batmap_t *, uint32_t);
void vhd_batmap_clear(vhd_context_t *, vhd_batmap_t *, uint32_t);
int vhd_get_phys_size(vhd_context_t *, off_t *);
int vhd_set_phys_size(vhd_context_t *, off_t);
int vhd_bitmap_test(vhd_context_t *, char *, uint32_t);
void vhd_bitmap_set(vhd_context_t *, char *, uint32_t);
void vhd_bitmap_clear(vhd_context_t *, char *, uint32_t);
int vhd_parent_locator_count(vhd_context_t *);
int vhd_parent_locator_get(vhd_context_t *, char **);
int vhd_parent_locator_read(vhd_context_t *, vhd_parent_locator_t *, char **);
int vhd_find_parent(vhd_context_t *, const char *, char **);
int vhd_parent_locator_write_at(vhd_context_t *, const char *,
off_t, uint32_t, size_t,
vhd_parent_locator_t *);
int vhd_header_decode_parent(vhd_context_t *, vhd_header_t *, char **);
int vhd_change_parent(vhd_context_t *, char *parent_path, int raw);
int vhd_read_footer(vhd_context_t *, vhd_footer_t *);
int vhd_read_footer_at(vhd_context_t *, vhd_footer_t *, off_t);
int vhd_read_footer_strict(vhd_context_t *, vhd_footer_t *);
int vhd_read_header(vhd_context_t *, vhd_header_t *);
int vhd_read_header_at(vhd_context_t *, vhd_header_t *, off_t);
int vhd_read_bat(vhd_context_t *, vhd_bat_t *);
int vhd_read_batmap(vhd_context_t *, vhd_batmap_t *);
int vhd_read_bitmap(vhd_context_t *, uint32_t block, char **bufp);
int vhd_read_block(vhd_context_t *, uint32_t block, char **bufp);
int vhd_write_footer(vhd_context_t *, vhd_footer_t *);
int vhd_write_footer_at(vhd_context_t *, vhd_footer_t *, off_t);
int vhd_write_header(vhd_context_t *, vhd_header_t *);
int vhd_write_header_at(vhd_context_t *, vhd_header_t *, off_t);
int vhd_write_bat(vhd_context_t *, vhd_bat_t *);
int vhd_write_batmap(vhd_context_t *, vhd_batmap_t *);
int vhd_write_bitmap(vhd_context_t *, uint32_t block, char *bitmap);
int vhd_write_block(vhd_context_t *, uint32_t block, char *data);
int vhd_io_read(vhd_context_t *, char *, uint64_t, uint32_t);
int vhd_io_write(vhd_context_t *, char *, uint64_t, uint32_t);
#endif
-125
View File
@@ -1,125 +0,0 @@
/*
* list.h
*
* This is a subset of linux's list.h intended to be used in user-space.
* XXX The namespace conflicts with NetBSD's <sys/queue.h>
*
*/
#ifndef __LIST_H__
#define __LIST_H__
#define LIST_POISON1 ((void *) 0x00100100)
#define LIST_POISON2 ((void *) 0x00200200)
struct list_head {
struct list_head *next, *prev;
};
/* XXX workaround for conflicts. The list API should use its own
* namespace prefix, i.e. BLK_
*/
#ifdef LIST_HEAD_INIT
#undef LIST_HEAD_INIT
#endif
#ifndef LIST_HEAD
#undef LIST_HEAD
#endif
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
static inline int list_is_last(const struct list_head *list,
const struct list_head *head)
{
return list->next == head;
}
static inline void __list_splice(const struct list_head *list,
struct list_head *prev,
struct list_head *next)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
first->prev = prev;
prev->next = first;
last->next = next;
next->prev = last;
}
static inline void list_splice(const struct list_head *list,
struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head, head->next);
}
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#endif /* __LIST_H__ */
-71
View File
@@ -1,71 +0,0 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LVM_UTIL_H_
#define _LVM_UTIL_H_
#include <inttypes.h>
#define MAX_NAME_SIZE 256
#define LVM_SEG_TYPE_LINEAR 1
#define LVM_SEG_TYPE_UNKNOWN 2
struct lv_segment {
uint8_t type;
char device[MAX_NAME_SIZE];
uint64_t pe_start;
uint64_t pe_size;
};
struct lv {
char name[MAX_NAME_SIZE];
uint64_t size;
uint32_t segments;
struct lv_segment first_segment;
};
struct pv {
char name[MAX_NAME_SIZE];
uint64_t start;
};
struct vg {
char name[MAX_NAME_SIZE];
uint64_t extent_size;
int pv_cnt;
struct pv *pvs;
int lv_cnt;
struct lv *lvs;
};
int lvm_scan_vg(const char *vg_name, struct vg *vg);
void lvm_free_vg(struct vg *vg);
#endif
-43
View File
@@ -1,43 +0,0 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _RELATIVE_PATH_H_
#define _RELATIVE_PATH_H_
#include <syslog.h>
#define DELIMITER '/'
#define MAX_NAME_LEN 1000
#define EPRINTF(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f, __func__, ##_a)
/*
* returns a relative path from @src to @dest
* result should be freed
*/
char *relative_path_to(char *src, char *dest, int *err);
#endif
-203
View File
@@ -1,203 +0,0 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TAPDISK_MESSAGE_H_
#define _TAPDISK_MESSAGE_H_
#include <inttypes.h>
#include <sys/types.h>
#define TAPDISK_MESSAGE_MAX_PATH_LENGTH 256
#define TAPDISK_MESSAGE_STRING_LENGTH 256
#define TAPDISK_MESSAGE_MAX_MINORS \
((TAPDISK_MESSAGE_MAX_PATH_LENGTH / sizeof(int)) - 1)
#define TAPDISK_MESSAGE_FLAG_SHARED 0x01
#define TAPDISK_MESSAGE_FLAG_RDONLY 0x02
#define TAPDISK_MESSAGE_FLAG_ADD_CACHE 0x04
#define TAPDISK_MESSAGE_FLAG_VHD_INDEX 0x08
#define TAPDISK_MESSAGE_FLAG_LOG_DIRTY 0x10
typedef struct tapdisk_message tapdisk_message_t;
typedef uint8_t tapdisk_message_flag_t;
typedef struct tapdisk_message_image tapdisk_message_image_t;
typedef struct tapdisk_message_params tapdisk_message_params_t;
typedef struct tapdisk_message_string tapdisk_message_string_t;
typedef struct tapdisk_message_response tapdisk_message_response_t;
typedef struct tapdisk_message_minors tapdisk_message_minors_t;
typedef struct tapdisk_message_list tapdisk_message_list_t;
struct tapdisk_message_params {
tapdisk_message_flag_t flags;
uint8_t storage;
uint32_t devnum;
uint32_t domid;
uint16_t path_len;
char path[TAPDISK_MESSAGE_MAX_PATH_LENGTH];
};
struct tapdisk_message_image {
uint64_t sectors;
uint32_t sector_size;
uint32_t info;
};
struct tapdisk_message_string {
char text[TAPDISK_MESSAGE_STRING_LENGTH];
};
struct tapdisk_message_response {
int error;
char message[TAPDISK_MESSAGE_STRING_LENGTH];
};
struct tapdisk_message_minors {
int count;
int list[TAPDISK_MESSAGE_MAX_MINORS];
};
struct tapdisk_message_list {
int count;
int minor;
int state;
char path[TAPDISK_MESSAGE_MAX_PATH_LENGTH];
};
struct tapdisk_message {
uint16_t type;
uint16_t cookie;
union {
pid_t tapdisk_pid;
tapdisk_message_image_t image;
tapdisk_message_params_t params;
tapdisk_message_string_t string;
tapdisk_message_minors_t minors;
tapdisk_message_response_t response;
tapdisk_message_list_t list;
} u;
};
enum tapdisk_message_id {
TAPDISK_MESSAGE_ERROR = 1,
TAPDISK_MESSAGE_RUNTIME_ERROR,
TAPDISK_MESSAGE_PID,
TAPDISK_MESSAGE_PID_RSP,
TAPDISK_MESSAGE_ATTACH,
TAPDISK_MESSAGE_ATTACH_RSP,
TAPDISK_MESSAGE_OPEN,
TAPDISK_MESSAGE_OPEN_RSP,
TAPDISK_MESSAGE_PAUSE,
TAPDISK_MESSAGE_PAUSE_RSP,
TAPDISK_MESSAGE_RESUME,
TAPDISK_MESSAGE_RESUME_RSP,
TAPDISK_MESSAGE_CLOSE,
TAPDISK_MESSAGE_CLOSE_RSP,
TAPDISK_MESSAGE_DETACH,
TAPDISK_MESSAGE_DETACH_RSP,
TAPDISK_MESSAGE_LIST_MINORS,
TAPDISK_MESSAGE_LIST_MINORS_RSP,
TAPDISK_MESSAGE_LIST,
TAPDISK_MESSAGE_LIST_RSP,
TAPDISK_MESSAGE_FORCE_SHUTDOWN,
TAPDISK_MESSAGE_EXIT,
};
static inline char *
tapdisk_message_name(enum tapdisk_message_id id)
{
switch (id) {
case TAPDISK_MESSAGE_ERROR:
return "error";
case TAPDISK_MESSAGE_PID:
return "pid";
case TAPDISK_MESSAGE_PID_RSP:
return "pid response";
case TAPDISK_MESSAGE_OPEN:
return "open";
case TAPDISK_MESSAGE_OPEN_RSP:
return "open response";
case TAPDISK_MESSAGE_PAUSE:
return "pause";
case TAPDISK_MESSAGE_PAUSE_RSP:
return "pause response";
case TAPDISK_MESSAGE_RESUME:
return "resume";
case TAPDISK_MESSAGE_RESUME_RSP:
return "resume response";
case TAPDISK_MESSAGE_CLOSE:
return "close";
case TAPDISK_MESSAGE_FORCE_SHUTDOWN:
return "force shutdown";
case TAPDISK_MESSAGE_CLOSE_RSP:
return "close response";
case TAPDISK_MESSAGE_ATTACH:
return "attach";
case TAPDISK_MESSAGE_ATTACH_RSP:
return "attach response";
case TAPDISK_MESSAGE_DETACH:
return "detach";
case TAPDISK_MESSAGE_DETACH_RSP:
return "detach response";
case TAPDISK_MESSAGE_LIST_MINORS:
return "list minors";
case TAPDISK_MESSAGE_LIST_MINORS_RSP:
return "list minors response";
case TAPDISK_MESSAGE_LIST:
return "list";
case TAPDISK_MESSAGE_LIST_RSP:
return "list response";
case TAPDISK_MESSAGE_EXIT:
return "exit";
default:
return "unknown";
}
}
#endif
-44
View File
@@ -1,44 +0,0 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _VHD_UTIL_H_
#define _VHD_UTIL_H_
int vhd_util_create(int argc, char **argv);
int vhd_util_snapshot(int argc, char **argv);
int vhd_util_query(int argc, char **argv);
int vhd_util_read(int argc, char **argv);
int vhd_util_set_field(int argc, char **argv);
int vhd_util_repair(int argc, char **argv);
int vhd_util_fill(int argc, char **argv);
int vhd_util_resize(int argc, char **argv);
int vhd_util_coalesce(int argc, char **argv);
int vhd_util_modify(int argc, char **argv);
int vhd_util_scan(int argc, char **argv);
int vhd_util_check(int argc, char **argv);
int vhd_util_revert(int argc, char **argv);
#endif
Loaded 100 of 126 files, more files were not shown because too many files have changed in this diff. Show more
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.