From 942da08c6c66aa8ebd0db4d7cbe0b06426bc6c53 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Mon, 20 Oct 2008 15:08:24 +0100 Subject: blktap: Handle qcow backing files correctly. Signed-off-by: Stefano Stabellini --- tools/blktap/drivers/block-qcow.c | 16 +++++----- tools/blktap/drivers/block-qcow2.c | 60 +++++++++++++++++++++++++++++++++----- 2 files changed, 59 insertions(+), 17 deletions(-) (limited to 'tools/blktap') diff --git a/tools/blktap/drivers/block-qcow.c b/tools/blktap/drivers/block-qcow.c index 51a2e324a1..97cc5c6b6b 100644 --- a/tools/blktap/drivers/block-qcow.c +++ b/tools/blktap/drivers/block-qcow.c @@ -734,8 +734,8 @@ static int tdqcow_open (struct disk_driver *dd, const char *name, td_flag_t flag DPRINTF("QCOW: Opening %s\n",name); - o_flags = O_DIRECT | O_LARGEFILE | - ((flags == TD_RDONLY) ? O_RDONLY : O_RDWR); + /* Since we don't handle O_DIRECT correctly, don't use it */ + o_flags = O_LARGEFILE | ((flags == TD_RDONLY) ? O_RDONLY : O_RDWR); fd = open(name, o_flags); if (fd < 0) { DPRINTF("Unable to open %s (%d)\n",name,0 - errno); @@ -1385,7 +1385,7 @@ static int tdqcow_get_parent_id(struct disk_driver *dd, struct disk_id *id) filename[len] = '\0'; id->name = strdup(filename); - id->drivertype = DISK_TYPE_QCOW; + id->drivertype = DISK_TYPE_AIO; err = 0; out: free(buf); @@ -1397,17 +1397,15 @@ static int tdqcow_validate_parent(struct disk_driver *child, { struct stat stats; uint64_t psize, csize; - struct tdqcow_state *c = (struct tdqcow_state *)child->private; - struct tdqcow_state *p = (struct tdqcow_state *)parent->private; - if (stat(p->name, &stats)) + if (stat(parent->name, &stats)) return -EINVAL; - if (get_filesize(p->name, &psize, &stats)) + if (get_filesize(parent->name, &psize, &stats)) return -EINVAL; - if (stat(c->name, &stats)) + if (stat(child->name, &stats)) return -EINVAL; - if (get_filesize(c->name, &csize, &stats)) + if (get_filesize(child->name, &csize, &stats)) return -EINVAL; if (csize != psize) diff --git a/tools/blktap/drivers/block-qcow2.c b/tools/blktap/drivers/block-qcow2.c index fe28a2ecb0..8bdd33ea37 100644 --- a/tools/blktap/drivers/block-qcow2.c +++ b/tools/blktap/drivers/block-qcow2.c @@ -34,6 +34,7 @@ #include "tapdisk.h" #include "tapaio.h" #include "bswap.h" +#include "blk.h" #define USE_AIO @@ -1902,6 +1903,42 @@ repeat: #endif +static int get_filesize(char *filename, uint64_t *size, struct stat *st) +{ + int fd; + QCowHeader header; + + /*Set to the backing file size*/ + fd = open(filename, O_RDONLY); + if (fd < 0) + return -1; + if (read(fd, &header, sizeof(header)) < sizeof(header)) { + close(fd); + return -1; + } + close(fd); + + be32_to_cpus(&header.magic); + be32_to_cpus(&header.version); + be64_to_cpus(&header.size); + if (header.magic == QCOW_MAGIC && header.version == QCOW_VERSION) { + *size = header.size >> SECTOR_SHIFT; + return 0; + } + + if(S_ISBLK(st->st_mode)) { + fd = open(filename, O_RDONLY); + if (fd < 0) + return -1; + if (blk_getimagesize(fd, size) != 0) { + close(fd); + return -1; + } + close(fd); + } else *size = (st->st_size >> SECTOR_SHIFT); + return 0; +} + /** * @return * 0 if parent id successfully retrieved; @@ -1916,7 +1953,7 @@ static int qcow_get_parent_id(struct disk_driver *dd, struct disk_id *id) return TD_NO_PARENT; id->name = strdup(s->backing_file); - id->drivertype = DISK_TYPE_QCOW2; + id->drivertype = DISK_TYPE_AIO; return 0; } @@ -1924,15 +1961,22 @@ static int qcow_get_parent_id(struct disk_driver *dd, struct disk_id *id) static int qcow_validate_parent(struct disk_driver *child, struct disk_driver *parent, td_flag_t flags) { - struct BDRVQcowState *cs = (struct BDRVQcowState*) child->private; - struct BDRVQcowState *ps = (struct BDRVQcowState*) parent->private; + struct stat stats; + uint64_t psize, csize; + + if (stat(parent->name, &stats)) + return -EINVAL; + if (get_filesize(parent->name, &psize, &stats)) + return -EINVAL; - if (ps->total_sectors != cs->total_sectors) { - DPRINTF("qcow_validate_parent(): %#"PRIx64" != %#"PRIx64"\n", - ps->total_sectors, cs->total_sectors); + if (stat(child->name, &stats)) return -EINVAL; - } - + if (get_filesize(child->name, &csize, &stats)) + return -EINVAL; + + if (csize != psize) + return -EINVAL; + return 0; } -- cgit v1.2.3