[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen master] Revert "tools: remove blktap2 source code"
commit d383c07e8bc6df81afb5fb250cc55c507d75ac75 Author: Wei Liu <wei.liu2@xxxxxxxxxx> AuthorDate: Thu Sep 8 16:15:47 2016 +0100 Commit: Wei Liu <wei.liu2@xxxxxxxxxx> CommitDate: Thu Sep 8 16:15:47 2016 +0100 Revert "tools: remove blktap2 source code" This reverts commit 44b2829a8b97a8b04e063a93303dbe3a468642e3. --- tools/blktap2/Makefile | 20 + tools/blktap2/README | 321 +++ tools/blktap2/control/Makefile | 80 + tools/blktap2/control/tap-ctl-allocate.c | 242 ++ tools/blktap2/control/tap-ctl-attach.c | 61 + tools/blktap2/control/tap-ctl-check.c | 79 + tools/blktap2/control/tap-ctl-close.c | 87 + tools/blktap2/control/tap-ctl-create.c | 67 + tools/blktap2/control/tap-ctl-destroy.c | 56 + tools/blktap2/control/tap-ctl-detach.c | 61 + tools/blktap2/control/tap-ctl-free.c | 54 + tools/blktap2/control/tap-ctl-ipc.c | 249 +++ tools/blktap2/control/tap-ctl-list.c | 536 +++++ tools/blktap2/control/tap-ctl-major.c | 69 + tools/blktap2/control/tap-ctl-open.c | 75 + tools/blktap2/control/tap-ctl-pause.c | 59 + tools/blktap2/control/tap-ctl-spawn.c | 174 ++ tools/blktap2/control/tap-ctl-unpause.c | 64 + tools/blktap2/control/tap-ctl.c | 815 +++++++ tools/blktap2/control/tap-ctl.h | 101 + tools/blktap2/drivers/Makefile | 113 + tools/blktap2/drivers/aes.c | 1319 +++++++++++ tools/blktap2/drivers/aes.h | 28 + tools/blktap2/drivers/atomicio.c | 61 + tools/blktap2/drivers/blk.h | 36 + tools/blktap2/drivers/blk_linux.c | 43 + tools/blktap2/drivers/blk_netbsd.c | 41 + tools/blktap2/drivers/block-aio.c | 258 +++ tools/blktap2/drivers/block-cache.c | 787 +++++++ tools/blktap2/drivers/block-log.c | 665 ++++++ tools/blktap2/drivers/block-qcow.c | 1501 +++++++++++++ tools/blktap2/drivers/block-ram.c | 256 +++ tools/blktap2/drivers/block-remus.c | 1733 ++++++++++++++ tools/blktap2/drivers/block-vhd.c | 2322 +++++++++++++++++++ tools/blktap2/drivers/bswap.h | 179 ++ tools/blktap2/drivers/check_gcrypt | 18 + tools/blktap2/drivers/hashtable.c | 279 +++ tools/blktap2/drivers/hashtable.h | 204 ++ tools/blktap2/drivers/hashtable_itr.c | 195 ++ tools/blktap2/drivers/hashtable_itr.h | 96 + tools/blktap2/drivers/hashtable_private.h | 90 + tools/blktap2/drivers/hashtable_utility.c | 71 + tools/blktap2/drivers/hashtable_utility.h | 55 + tools/blktap2/drivers/img2qcow.c | 316 +++ tools/blktap2/drivers/io-optimize.c | 671 ++++++ tools/blktap2/drivers/io-optimize.h | 68 + tools/blktap2/drivers/libaio-compat.h | 102 + tools/blktap2/drivers/lock.c | 1000 +++++++++ tools/blktap2/drivers/lock.h | 51 + tools/blktap2/drivers/log.h | 123 + tools/blktap2/drivers/md5.c | 278 +++ tools/blktap2/drivers/md5.h | 15 + tools/blktap2/drivers/profile.h | 191 ++ tools/blktap2/drivers/qcow-create.c | 121 + tools/blktap2/drivers/qcow.h | 131 ++ tools/blktap2/drivers/qcow2raw.c | 443 ++++ tools/blktap2/drivers/scheduler.c | 265 +++ tools/blktap2/drivers/scheduler.h | 65 + tools/blktap2/drivers/tapdisk-client.c | 496 +++++ tools/blktap2/drivers/tapdisk-control.c | 837 +++++++ tools/blktap2/drivers/tapdisk-control.h | 35 + tools/blktap2/drivers/tapdisk-diff.c | 802 +++++++ tools/blktap2/drivers/tapdisk-disktype.c | 200 ++ tools/blktap2/drivers/tapdisk-disktype.h | 62 + tools/blktap2/drivers/tapdisk-driver.c | 101 + tools/blktap2/drivers/tapdisk-driver.h | 62 + tools/blktap2/drivers/tapdisk-filter.c | 272 +++ tools/blktap2/drivers/tapdisk-filter.h | 67 + tools/blktap2/drivers/tapdisk-image.c | 169 ++ tools/blktap2/drivers/tapdisk-image.h | 56 + tools/blktap2/drivers/tapdisk-interface.c | 259 +++ tools/blktap2/drivers/tapdisk-interface.h | 54 + tools/blktap2/drivers/tapdisk-log.c | 257 +++ tools/blktap2/drivers/tapdisk-log.h | 51 + tools/blktap2/drivers/tapdisk-queue.c | 743 ++++++ tools/blktap2/drivers/tapdisk-queue.h | 125 ++ tools/blktap2/drivers/tapdisk-ring.c | 439 ++++ tools/blktap2/drivers/tapdisk-ring.h | 87 + tools/blktap2/drivers/tapdisk-server.c | 345 +++ tools/blktap2/drivers/tapdisk-server.h | 67 + tools/blktap2/drivers/tapdisk-stream.c | 605 +++++ tools/blktap2/drivers/tapdisk-utils.c | 214 ++ tools/blktap2/drivers/tapdisk-utils.h | 45 + tools/blktap2/drivers/tapdisk-vbd.c | 1723 ++++++++++++++ tools/blktap2/drivers/tapdisk-vbd.h | 207 ++ tools/blktap2/drivers/tapdisk.h | 169 ++ tools/blktap2/drivers/tapdisk2.c | 138 ++ tools/blktap2/drivers/td.c | 691 ++++++ tools/blktap2/drivers/xmsnap | 78 + tools/blktap2/include/Makefile | 17 + tools/blktap2/include/atomicio.h | 33 + tools/blktap2/include/blktap2.h | 67 + tools/blktap2/include/blktaplib.h | 242 ++ tools/blktap2/include/libvhd-journal.h | 68 + tools/blktap2/include/libvhd.h | 326 +++ tools/blktap2/include/list.h | 125 ++ tools/blktap2/include/lvm-util.h | 71 + tools/blktap2/include/relative-path.h | 43 + tools/blktap2/include/tapdisk-message.h | 203 ++ tools/blktap2/include/vhd-util.h | 44 + tools/blktap2/include/vhd-uuid.h | 63 + tools/blktap2/include/vhd.h | 219 ++ tools/blktap2/lvm/Makefile | 36 + tools/blktap2/lvm/lvm-util.c | 349 +++ tools/blktap2/vhd/Makefile | 51 + tools/blktap2/vhd/lib/Makefile | 82 + tools/blktap2/vhd/lib/atomicio.c | 61 + tools/blktap2/vhd/lib/libvhd-journal.c | 1534 +++++++++++++ tools/blktap2/vhd/lib/libvhd.c | 3348 ++++++++++++++++++++++++++++ tools/blktap2/vhd/lib/relative-path.c | 299 +++ tools/blktap2/vhd/lib/vhd-util-check.c | 980 ++++++++ tools/blktap2/vhd/lib/vhd-util-coalesce.c | 218 ++ tools/blktap2/vhd/lib/vhd-util-create.c | 80 + tools/blktap2/vhd/lib/vhd-util-fill.c | 105 + tools/blktap2/vhd/lib/vhd-util-modify.c | 132 ++ tools/blktap2/vhd/lib/vhd-util-query.c | 159 ++ tools/blktap2/vhd/lib/vhd-util-read.c | 742 ++++++ tools/blktap2/vhd/lib/vhd-util-repair.c | 84 + tools/blktap2/vhd/lib/vhd-util-resize.c | 1131 ++++++++++ tools/blktap2/vhd/lib/vhd-util-revert.c | 106 + tools/blktap2/vhd/lib/vhd-util-scan.c | 1317 +++++++++++ tools/blktap2/vhd/lib/vhd-util-set-field.c | 106 + tools/blktap2/vhd/lib/vhd-util-snapshot.c | 216 ++ tools/blktap2/vhd/lib/vhd-util-uuid.c | 128 ++ tools/blktap2/vhd/vhd-update.c | 259 +++ tools/blktap2/vhd/vhd-util.c | 163 ++ 126 files changed, 40123 insertions(+) diff --git a/tools/blktap2/Makefile b/tools/blktap2/Makefile new file mode 100644 index 0000000..94200dc --- /dev/null +++ b/tools/blktap2/Makefile @@ -0,0 +1,20 @@ +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-% diff --git a/tools/blktap2/README b/tools/blktap2/README new file mode 100644 index 0000000..75fc614 --- /dev/null +++ b/tools/blktap2/README @@ -0,0 +1,321 @@ +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. + + + + + + diff --git a/tools/blktap2/control/Makefile b/tools/blktap2/control/Makefile new file mode 100644 index 0000000..767f52a --- /dev/null +++ b/tools/blktap2/control/Makefile @@ -0,0 +1,80 @@ +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) diff --git a/tools/blktap2/control/tap-ctl-allocate.c b/tools/blktap2/control/tap-ctl-allocate.c new file mode 100644 index 0000000..8a6471e --- /dev/null +++ b/tools/blktap2/control/tap-ctl-allocate.c @@ -0,0 +1,242 @@ +/* + * 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; +} diff --git a/tools/blktap2/control/tap-ctl-attach.c b/tools/blktap2/control/tap-ctl-attach.c new file mode 100644 index 0000000..3cb933c --- /dev/null +++ b/tools/blktap2/control/tap-ctl-attach.c @@ -0,0 +1,61 @@ +/* + * 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; +} diff --git a/tools/blktap2/control/tap-ctl-check.c b/tools/blktap2/control/tap-ctl-check.c new file mode 100644 index 0000000..e98583a --- /dev/null +++ b/tools/blktap2/control/tap-ctl-check.c @@ -0,0 +1,79 @@ +/* + * 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; +} diff --git a/tools/blktap2/control/tap-ctl-close.c b/tools/blktap2/control/tap-ctl-close.c new file mode 100644 index 0000000..2e5f80b --- /dev/null +++ b/tools/blktap2/control/tap-ctl-close.c @@ -0,0 +1,87 @@ +/* + * 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; +} diff --git a/tools/blktap2/control/tap-ctl-create.c b/tools/blktap2/control/tap-ctl-create.c new file mode 100644 index 0000000..f4c47f1 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-create.c @@ -0,0 +1,67 @@ +/* + * 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; +} diff --git a/tools/blktap2/control/tap-ctl-destroy.c b/tools/blktap2/control/tap-ctl-destroy.c new file mode 100644 index 0000000..dc5dbaa --- /dev/null +++ b/tools/blktap2/control/tap-ctl-destroy.c @@ -0,0 +1,56 @@ +/* + * 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; +} diff --git a/tools/blktap2/control/tap-ctl-detach.c b/tools/blktap2/control/tap-ctl-detach.c new file mode 100644 index 0000000..7d7bbf3 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-detach.c @@ -0,0 +1,61 @@ +/* + * 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; +} diff --git a/tools/blktap2/control/tap-ctl-free.c b/tools/blktap2/control/tap-ctl-free.c new file mode 100644 index 0000000..9ae7295 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-free.c @@ -0,0 +1,54 @@ +/* + * 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; +} diff --git a/tools/blktap2/control/tap-ctl-ipc.c b/tools/blktap2/control/tap-ctl-ipc.c new file mode 100644 index 0000000..c7e42d9 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-ipc.c @@ -0,0 +1,249 @@ +/* + * 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; +} diff --git a/tools/blktap2/control/tap-ctl-list.c b/tools/blktap2/control/tap-ctl-list.c new file mode 100644 index 0000000..f8d49c3 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-list.c @@ -0,0 +1,536 @@ +/* + * 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; +} diff --git a/tools/blktap2/control/tap-ctl-major.c b/tools/blktap2/control/tap-ctl-major.c new file mode 100644 index 0000000..847af28 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-major.c @@ -0,0 +1,69 @@ +/* + * 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; +} diff --git a/tools/blktap2/control/tap-ctl-open.c b/tools/blktap2/control/tap-ctl-open.c new file mode 100644 index 0000000..5961c99 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-open.c @@ -0,0 +1,75 @@ +/* + * 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; +} diff --git a/tools/blktap2/control/tap-ctl-pause.c b/tools/blktap2/control/tap-ctl-pause.c new file mode 100644 index 0000000..5e31a58 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-pause.c @@ -0,0 +1,59 @@ +/* + * 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; +} diff --git a/tools/blktap2/control/tap-ctl-spawn.c b/tools/blktap2/control/tap-ctl-spawn.c new file mode 100644 index 0000000..31a651e --- /dev/null +++ b/tools/blktap2/control/tap-ctl-spawn.c @@ -0,0 +1,174 @@ +/* + * 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; +} diff --git a/tools/blktap2/control/tap-ctl-unpause.c b/tools/blktap2/control/tap-ctl-unpause.c new file mode 100644 index 0000000..dfb7450 --- /dev/null +++ b/tools/blktap2/control/tap-ctl-unpause.c @@ -0,0 +1,64 @@ +/* + * 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; +} diff --git a/tools/blktap2/control/tap-ctl.c b/tools/blktap2/control/tap-ctl.c new file mode 100644 index 0000000..e254f07 --- /dev/null +++ b/tools/blktap2/control/tap-ctl.c @@ -0,0 +1,815 @@ +/* + * 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); _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx https://lists.xenproject.org/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |