aboutsummaryrefslogtreecommitdiffstats
path: root/tools/blktap2/drivers/block-aio.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/blktap2/drivers/block-aio.c')
-rw-r--r--tools/blktap2/drivers/block-aio.c272
1 files changed, 272 insertions, 0 deletions
diff --git a/tools/blktap2/drivers/block-aio.c b/tools/blktap2/drivers/block-aio.c
new file mode 100644
index 0000000000..2c5af1483c
--- /dev/null
+++ b/tools/blktap2/drivers/block-aio.c
@@ -0,0 +1,272 @@
+/*
+ * 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 <libaio.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 <linux/fs.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 (ioctl(fd,BLKGETSIZE,&info->size)!=0) {
+ DPRINTF("ERR: BLKGETSIZE failed, couldn't stat image");
+ 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 defined(BLKSSZGET)
+ {
+ int arg;
+ info->sector_size = DEFAULT_SECTOR_SIZE;
+ ioctl(fd, BLKSSZGET, &info->sector_size);
+
+ if (info->sector_size != DEFAULT_SECTOR_SIZE)
+ DPRINTF("Note: sector size is %ld (not %d)\n",
+ info->sector_size, DEFAULT_SECTOR_SIZE);
+ }
+#else
+ info->sector_size = DEFAULT_SECTOR_SIZE;
+#endif
+
+ } 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,
+};