From 3abbc4d981159f2d53896808974ca7b07259ac58 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Sat, 1 May 2010 07:23:32 +0100 Subject: [PATCH 01/21] block: Remove semicolon in BDRV_SECTOR_MASK macro Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block.h b/block.h index f87d24e5c8..278259c2ba 100644 --- a/block.h +++ b/block.h @@ -38,7 +38,7 @@ typedef struct QEMUSnapshotInfo { #define BDRV_SECTOR_BITS 9 #define BDRV_SECTOR_SIZE (1 << BDRV_SECTOR_BITS) -#define BDRV_SECTOR_MASK ~(BDRV_SECTOR_SIZE - 1); +#define BDRV_SECTOR_MASK ~(BDRV_SECTOR_SIZE - 1) typedef enum { BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP From cb7cf0e3f471143136afb2ad1ff65890a978adc6 Mon Sep 17 00:00:00 2001 From: Ryota Ozaki Date: Mon, 3 May 2010 06:50:25 +0900 Subject: [PATCH 02/21] qemu-nbd: Improve error reporting - use err(3) instead of errx(3) if errno is available to report why failed - let fail prior to daemon(3) if opening a nbd file is likely to fail after daemonizing to avoid silent failure exit - add missing 'ret = 1' when unix_socket_outgoing failed Signed-off-by: Ryota Ozaki Signed-off-by: Kevin Wolf --- qemu-nbd.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/qemu-nbd.c b/qemu-nbd.c index 25aa913408..4e607cfb61 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -112,9 +112,12 @@ static int find_partition(BlockDriverState *bs, int partition, uint8_t data[512]; int i; int ext_partnum = 4; + int ret; - if (bdrv_read(bs, 0, data, 1)) - errx(EXIT_FAILURE, "error while reading"); + if ((ret = bdrv_read(bs, 0, data, 1)) < 0) { + errno = -ret; + err(EXIT_FAILURE, "error while reading"); + } if (data[510] != 0x55 || data[511] != 0xaa) { errno = -EINVAL; @@ -132,8 +135,10 @@ static int find_partition(BlockDriverState *bs, int partition, uint8_t data1[512]; int j; - if (bdrv_read(bs, mbr[i].start_sector_abs, data1, 1)) - errx(EXIT_FAILURE, "error while reading"); + if ((ret = bdrv_read(bs, mbr[i].start_sector_abs, data1, 1)) < 0) { + errno = -ret; + err(EXIT_FAILURE, "error while reading"); + } for (j = 0; j < 4; j++) { read_partition(&data1[446 + 16 * j], &ext[j]); @@ -316,7 +321,7 @@ int main(int argc, char **argv) if (disconnect) { fd = open(argv[optind], O_RDWR); if (fd == -1) - errx(EXIT_FAILURE, "Cannot open %s", argv[optind]); + err(EXIT_FAILURE, "Cannot open %s", argv[optind]); nbd_disconnect(fd); @@ -333,23 +338,30 @@ int main(int argc, char **argv) if (bs == NULL) return 1; - if (bdrv_open(bs, argv[optind], flags, NULL) < 0) - return 1; + if ((ret = bdrv_open(bs, argv[optind], flags, NULL)) < 0) { + errno = -ret; + err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]); + } fd_size = bs->total_sectors * 512; if (partition != -1 && find_partition(bs, partition, &dev_offset, &fd_size)) - errx(EXIT_FAILURE, "Could not find partition %d", partition); + err(EXIT_FAILURE, "Could not find partition %d", partition); if (device) { pid_t pid; int sock; + /* want to fail before daemonizing */ + if (access(device, R_OK|W_OK) == -1) { + err(EXIT_FAILURE, "Could not access '%s'", device); + } + if (!verbose) { /* detach client and server */ if (daemon(0, 0) == -1) { - errx(EXIT_FAILURE, "Failed to daemonize"); + err(EXIT_FAILURE, "Failed to daemonize"); } } @@ -372,8 +384,10 @@ int main(int argc, char **argv) do { sock = unix_socket_outgoing(socket); if (sock == -1) { - if (errno != ENOENT && errno != ECONNREFUSED) + if (errno != ENOENT && errno != ECONNREFUSED) { + ret = 1; goto out; + } sleep(1); /* wait children */ } } while (sock == -1); From c94304be3f07fc038f0d8d48ffdca11a28b5aaca Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 4 May 2010 12:44:38 +0200 Subject: [PATCH 03/21] cloop: use pread Use pread instead of lseek + read in preparation of using the qemu block API. Signed-off-by: Christoph Hellwig Signed-off-by: Kevin Wolf --- block/cloop.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/block/cloop.c b/block/cloop.c index e4f995b5d6..9fe2a42363 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -62,23 +62,22 @@ static int cloop_open(BlockDriverState *bs, const char *filename, int flags) bs->read_only = 1; /* read header */ - if(lseek(s->fd,128,SEEK_SET)<0) { -cloop_close: - close(s->fd); - return -1; + if (pread(s->fd, &s->block_size, 4, 128) < 4) { + goto cloop_close; } - if(read(s->fd,&s->block_size,4)<4) - goto cloop_close; - s->block_size=be32_to_cpu(s->block_size); - if(read(s->fd,&s->n_blocks,4)<4) - goto cloop_close; - s->n_blocks=be32_to_cpu(s->n_blocks); + s->block_size = be32_to_cpu(s->block_size); + + if (pread(s->fd, &s->n_blocks, 4, 128 + 4) < 4) { + goto cloop_close; + } + s->n_blocks = be32_to_cpu(s->n_blocks); /* read offsets */ - offsets_size=s->n_blocks*sizeof(uint64_t); - s->offsets=(uint64_t*)qemu_malloc(offsets_size); - if(read(s->fd,s->offsets,offsets_size)n_blocks * sizeof(uint64_t); + s->offsets = qemu_malloc(offsets_size); + if (pread(s->fd, s->offsets, offsets_size, 128 + 4 + 4) < offsets_size) { goto cloop_close; + } for(i=0;in_blocks;i++) { s->offsets[i]=be64_to_cpu(s->offsets[i]); if(i>0) { @@ -98,6 +97,10 @@ cloop_close: s->sectors_per_block = s->block_size/512; bs->total_sectors = s->n_blocks*s->sectors_per_block; return 0; + +cloop_close: + close(s->fd); + return -1; } static inline int cloop_read_block(BDRVCloopState *s,int block_num) @@ -106,8 +109,7 @@ static inline int cloop_read_block(BDRVCloopState *s,int block_num) int ret; uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num]; - lseek(s->fd, s->offsets[block_num], SEEK_SET); - ret = read(s->fd, s->compressed_block, bytes); + ret = pread(s->fd, s->compressed_block, bytes, s->offsets[block_num]); if (ret != bytes) return -1; From 20be49e47e82f1b9fdc33810e1c4d7121871eafa Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 4 May 2010 12:44:52 +0200 Subject: [PATCH 04/21] cloop: use qemu block API Use bdrv_pwrite to access the backing device instead of pread, and convert the driver to implementing the bdrv_open method which gives it an already opened BlockDriverState for the underlying device. Signed-off-by: Christoph Hellwig Signed-off-by: Kevin Wolf --- block/cloop.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/block/cloop.c b/block/cloop.c index 9fe2a42363..fe015c4255 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -27,7 +27,6 @@ #include typedef struct BDRVCloopState { - int fd; uint32_t block_size; uint32_t n_blocks; uint64_t* offsets; @@ -51,23 +50,20 @@ static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static int cloop_open(BlockDriverState *bs, const char *filename, int flags) +static int cloop_open(BlockDriverState *bs, int flags) { BDRVCloopState *s = bs->opaque; uint32_t offsets_size,max_compressed_block_size=1,i; - s->fd = open(filename, O_RDONLY | O_BINARY); - if (s->fd < 0) - return -errno; bs->read_only = 1; /* read header */ - if (pread(s->fd, &s->block_size, 4, 128) < 4) { + if (bdrv_pread(bs->file, 128, &s->block_size, 4) < 4) { goto cloop_close; } s->block_size = be32_to_cpu(s->block_size); - if (pread(s->fd, &s->n_blocks, 4, 128 + 4) < 4) { + if (bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4) < 4) { goto cloop_close; } s->n_blocks = be32_to_cpu(s->n_blocks); @@ -75,7 +71,8 @@ static int cloop_open(BlockDriverState *bs, const char *filename, int flags) /* read offsets */ offsets_size = s->n_blocks * sizeof(uint64_t); s->offsets = qemu_malloc(offsets_size); - if (pread(s->fd, s->offsets, offsets_size, 128 + 4 + 4) < offsets_size) { + if (bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size) < + offsets_size) { goto cloop_close; } for(i=0;in_blocks;i++) { @@ -99,17 +96,19 @@ static int cloop_open(BlockDriverState *bs, const char *filename, int flags) return 0; cloop_close: - close(s->fd); return -1; } -static inline int cloop_read_block(BDRVCloopState *s,int block_num) +static inline int cloop_read_block(BlockDriverState *bs, int block_num) { + BDRVCloopState *s = bs->opaque; + if(s->current_block != block_num) { int ret; uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num]; - ret = pread(s->fd, s->compressed_block, bytes, s->offsets[block_num]); + ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block, + bytes); if (ret != bytes) return -1; @@ -138,7 +137,7 @@ static int cloop_read(BlockDriverState *bs, int64_t sector_num, for(i=0;isectors_per_block), block_num=(sector_num+i)/s->sectors_per_block; - if(cloop_read_block(s, block_num) != 0) + if(cloop_read_block(bs, block_num) != 0) return -1; memcpy(buf+i*512,s->uncompressed_block+sector_offset_in_block*512,512); } @@ -148,7 +147,6 @@ static int cloop_read(BlockDriverState *bs, int64_t sector_num, static void cloop_close(BlockDriverState *bs) { BDRVCloopState *s = bs->opaque; - close(s->fd); if(s->n_blocks>0) free(s->offsets); free(s->compressed_block); @@ -160,7 +158,7 @@ static BlockDriver bdrv_cloop = { .format_name = "cloop", .instance_size = sizeof(BDRVCloopState), .bdrv_probe = cloop_probe, - .bdrv_file_open = cloop_open, + .bdrv_open = cloop_open, .bdrv_read = cloop_read, .bdrv_close = cloop_close, }; From 38d8dfa193e9a45f0f08b06aab2ba2a94f40a041 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 4 May 2010 16:35:24 +0200 Subject: [PATCH 05/21] ide: Fix ide_dma_cancel When cancelling a request, bdrv_aio_cancel may decide that it waits for completion of a request rather than for cancellation. IDE therefore can't abandon its DMA status before calling bdrv_aio_cancel; otherwise the callback of a completed request would use invalid data. Signed-off-by: Kevin Wolf --- hw/ide/core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index b0165bcc02..066fecb0c0 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2838,10 +2838,6 @@ static void ide_dma_restart(IDEState *s, int is_read) void ide_dma_cancel(BMDMAState *bm) { if (bm->status & BM_STATUS_DMAING) { - bm->status &= ~BM_STATUS_DMAING; - /* cancel DMA request */ - bm->unit = -1; - bm->dma_cb = NULL; if (bm->aiocb) { #ifdef DEBUG_AIO printf("aio_cancel\n"); @@ -2849,6 +2845,10 @@ void ide_dma_cancel(BMDMAState *bm) bdrv_aio_cancel(bm->aiocb); bm->aiocb = NULL; } + bm->status &= ~BM_STATUS_DMAING; + /* cancel DMA request */ + bm->unit = -1; + bm->dma_cb = NULL; } } From efbca10f10af2c0d7282e5dc49713479be98880b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 4 May 2010 12:44:08 +0200 Subject: [PATCH 06/21] bochs: use pread Use pread instead of lseek + read in preparation of using the qemu block API. Signed-off-by: Christoph Hellwig Signed-off-by: Kevin Wolf --- block/bochs.c | 63 ++++++++++++++++----------------------------------- 1 file changed, 20 insertions(+), 43 deletions(-) diff --git a/block/bochs.c b/block/bochs.c index e952670cd1..b54f54d477 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -125,7 +125,7 @@ static int bochs_open(BlockDriverState *bs, const char *filename, int flags) s->fd = fd; - if (read(fd, &bochs, sizeof(bochs)) != sizeof(bochs)) { + if (pread(fd, &bochs, sizeof(bochs), 0) != sizeof(bochs)) { goto fail; } @@ -144,14 +144,10 @@ static int bochs_open(BlockDriverState *bs, const char *filename, int flags) bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512; } - if (lseek(s->fd, le32_to_cpu(bochs.header), SEEK_SET) == (off_t)-1) { - goto fail; - } - s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog); s->catalog_bitmap = qemu_malloc(s->catalog_size * 4); - if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) != - s->catalog_size * 4) + if (pread(s->fd, s->catalog_bitmap, s->catalog_size * 4, + le32_to_cpu(bochs.header)) != s->catalog_size * 4) goto fail; for (i = 0; i < s->catalog_size; i++) le32_to_cpus(&s->catalog_bitmap[i]); @@ -169,54 +165,35 @@ static int bochs_open(BlockDriverState *bs, const char *filename, int flags) return -1; } -static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) +static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num) { BDRVBochsState *s = bs->opaque; int64_t offset = sector_num * 512; - int64_t extent_index, extent_offset, bitmap_offset, block_offset; + int64_t extent_index, extent_offset, bitmap_offset; char bitmap_entry; // seek to sector extent_index = offset / s->extent_size; extent_offset = (offset % s->extent_size) / 512; - if (s->catalog_bitmap[extent_index] == 0xffffffff) - { -// fprintf(stderr, "page not allocated [%x - %x:%x]\n", -// sector_num, extent_index, extent_offset); - return -1; // not allocated + if (s->catalog_bitmap[extent_index] == 0xffffffff) { + return -1; /* not allocated */ } bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] * (s->extent_blocks + s->bitmap_blocks)); - block_offset = bitmap_offset + (512 * (s->bitmap_blocks + extent_offset)); -// fprintf(stderr, "sect: %x [ext i: %x o: %x] -> %x bitmap: %x block: %x\n", -// sector_num, extent_index, extent_offset, -// le32_to_cpu(s->catalog_bitmap[extent_index]), -// bitmap_offset, block_offset); - - // read in bitmap for current extent - if (lseek(s->fd, bitmap_offset + (extent_offset / 8), SEEK_SET) == - (off_t)-1) { + /* read in bitmap for current extent */ + if (pread(s->fd, &bitmap_entry, 1, bitmap_offset + (extent_offset / 8)) + != 1) { return -1; } - if (read(s->fd, &bitmap_entry, 1) != 1) - return -1; - - if (!((bitmap_entry >> (extent_offset % 8)) & 1)) - { -// fprintf(stderr, "sector (%x) in bitmap not allocated\n", -// sector_num); - return -1; // not allocated + if (!((bitmap_entry >> (extent_offset % 8)) & 1)) { + return -1; /* not allocated */ } - if (lseek(s->fd, block_offset, SEEK_SET) == (off_t)-1) { - return -1; - } - - return 0; + return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset)); } static int bochs_read(BlockDriverState *bs, int64_t sector_num, @@ -226,13 +203,13 @@ static int bochs_read(BlockDriverState *bs, int64_t sector_num, int ret; while (nb_sectors > 0) { - if (!seek_to_sector(bs, sector_num)) - { - ret = read(s->fd, buf, 512); - if (ret != 512) - return -1; - } - else + int64_t block_offset = seek_to_sector(bs, sector_num); + if (block_offset >= 0) { + ret = pread(s->fd, buf, 512, block_offset); + if (ret != 512) { + return -1; + } + } else memset(buf, 0, 512); nb_sectors--; sector_num++; From 7a6f391376c61af1dce2d624a4fcff8eec4fa097 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 4 May 2010 12:44:21 +0200 Subject: [PATCH 07/21] bochs: use qemu block API Use bdrv_pwrite to access the backing device instead of pread, and convert the driver to implementing the bdrv_open method which gives it an already opened BlockDriverState for the underlying device. Signed-off-by: Christoph Hellwig Signed-off-by: Kevin Wolf --- block/bochs.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/block/bochs.c b/block/bochs.c index b54f54d477..5fe2fa3580 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -80,8 +80,6 @@ struct bochs_header { }; typedef struct BDRVBochsState { - int fd; - uint32_t *catalog_bitmap; int catalog_size; @@ -109,23 +107,16 @@ static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static int bochs_open(BlockDriverState *bs, const char *filename, int flags) +static int bochs_open(BlockDriverState *bs, int flags) { BDRVBochsState *s = bs->opaque; - int fd, i; + int i; struct bochs_header bochs; struct bochs_header_v1 header_v1; - fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) { - return -1; - } - bs->read_only = 1; // no write support yet - s->fd = fd; - - if (pread(fd, &bochs, sizeof(bochs), 0) != sizeof(bochs)) { + if (bdrv_pread(bs->file, 0, &bochs, sizeof(bochs)) != sizeof(bochs)) { goto fail; } @@ -146,8 +137,8 @@ static int bochs_open(BlockDriverState *bs, const char *filename, int flags) s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog); s->catalog_bitmap = qemu_malloc(s->catalog_size * 4); - if (pread(s->fd, s->catalog_bitmap, s->catalog_size * 4, - le32_to_cpu(bochs.header)) != s->catalog_size * 4) + if (bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap, + s->catalog_size * 4) != s->catalog_size * 4) goto fail; for (i = 0; i < s->catalog_size; i++) le32_to_cpus(&s->catalog_bitmap[i]); @@ -161,7 +152,6 @@ static int bochs_open(BlockDriverState *bs, const char *filename, int flags) return 0; fail: - close(fd); return -1; } @@ -184,8 +174,8 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num) (s->extent_blocks + s->bitmap_blocks)); /* read in bitmap for current extent */ - if (pread(s->fd, &bitmap_entry, 1, bitmap_offset + (extent_offset / 8)) - != 1) { + if (bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8), + &bitmap_entry, 1) != 1) { return -1; } @@ -199,13 +189,12 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num) static int bochs_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { - BDRVBochsState *s = bs->opaque; int ret; while (nb_sectors > 0) { int64_t block_offset = seek_to_sector(bs, sector_num); if (block_offset >= 0) { - ret = pread(s->fd, buf, 512, block_offset); + ret = bdrv_pread(bs->file, block_offset, buf, 512); if (ret != 512) { return -1; } @@ -222,14 +211,13 @@ static void bochs_close(BlockDriverState *bs) { BDRVBochsState *s = bs->opaque; qemu_free(s->catalog_bitmap); - close(s->fd); } static BlockDriver bdrv_bochs = { .format_name = "bochs", .instance_size = sizeof(BDRVBochsState), .bdrv_probe = bochs_probe, - .bdrv_file_open = bochs_open, + .bdrv_open = bochs_open, .bdrv_read = bochs_read, .bdrv_close = bochs_close, }; From b666d239509a0855740444c254a65cbf567bfb90 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 5 May 2010 11:44:39 +0200 Subject: [PATCH 08/21] block: Avoid unchecked casts for AIOCBs Use container_of for one direction and &acb->common for the other one. Signed-off-by: Kevin Wolf --- block.c | 3 ++- block/blkdebug.c | 4 ++-- block/qcow.c | 2 +- block/qcow2.c | 2 +- block/vdi.c | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/block.c b/block.c index 48305b7d7c..6345599de2 100644 --- a/block.c +++ b/block.c @@ -2108,7 +2108,8 @@ typedef struct BlockDriverAIOCBSync { static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb) { - BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb; + BlockDriverAIOCBSync *acb = + container_of(blockacb, BlockDriverAIOCBSync, common); qemu_bh_delete(acb->bh); acb->bh = NULL; qemu_aio_release(acb); diff --git a/block/blkdebug.c b/block/blkdebug.c index bb4a91abc7..8325f75f80 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -320,7 +320,7 @@ static void error_callback_bh(void *opaque) static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb) { - BlkdebugAIOCB *acb = (BlkdebugAIOCB*) blockacb; + BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common); qemu_aio_release(acb); } @@ -347,7 +347,7 @@ static BlockDriverAIOCB *inject_error(BlockDriverState *bs, acb->bh = bh; qemu_bh_schedule(bh); - return (BlockDriverAIOCB*) acb; + return &acb->common; } static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs, diff --git a/block/qcow.c b/block/qcow.c index 2883c40f87..449858fa47 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -502,7 +502,7 @@ typedef struct QCowAIOCB { static void qcow_aio_cancel(BlockDriverAIOCB *blockacb) { - QCowAIOCB *acb = (QCowAIOCB *)blockacb; + QCowAIOCB *acb = container_of(blockacb, QCowAIOCB, common); if (acb->hd_aiocb) bdrv_aio_cancel(acb->hd_aiocb); qemu_aio_release(acb); diff --git a/block/qcow2.c b/block/qcow2.c index ebad4e10ae..0ce71507e9 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -338,7 +338,7 @@ typedef struct QCowAIOCB { static void qcow_aio_cancel(BlockDriverAIOCB *blockacb) { - QCowAIOCB *acb = (QCowAIOCB *)blockacb; + QCowAIOCB *acb = container_of(blockacb, QCowAIOCB, common); if (acb->hd_aiocb) bdrv_aio_cancel(acb->hd_aiocb); qemu_aio_release(acb); diff --git a/block/vdi.c b/block/vdi.c index 1d257b4838..2b4d2c218d 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -469,7 +469,7 @@ static int vdi_is_allocated(BlockDriverState *bs, int64_t sector_num, static void vdi_aio_cancel(BlockDriverAIOCB *blockacb) { /* TODO: This code is untested. How can I get it executed? */ - VdiAIOCB *acb = (VdiAIOCB *)blockacb; + VdiAIOCB *acb = container_of(blockacb, VdiAIOCB, common); logout("\n"); if (acb->hd_aiocb) { bdrv_aio_cancel(acb->hd_aiocb); From 209930818bc0bb1400fbfa7d6448066c1b9e7b4c Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 6 May 2010 13:04:58 +0200 Subject: [PATCH 09/21] block: Fix protocol detection for Windows devices We can't assume the file protocol for Windows devices, they need the same detection as other files for which an explicit protocol is not specified. Signed-off-by: Kevin Wolf --- block.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/block.c b/block.c index 6345599de2..977d01f74e 100644 --- a/block.c +++ b/block.c @@ -287,16 +287,18 @@ static BlockDriver *find_protocol(const char *filename) char protocol[128]; int len; const char *p; + int is_drive; /* TODO Drivers without bdrv_file_open must be specified explicitly */ #ifdef _WIN32 - if (is_windows_drive(filename) || - is_windows_drive_prefix(filename)) - return bdrv_find_format("file"); + is_drive = is_windows_drive(filename) || + is_windows_drive_prefix(filename); +#else + is_drive = 0; #endif p = strchr(filename, ':'); - if (!p) { + if (!p || is_drive) { drv1 = find_hdev_driver(filename); if (!drv1) { drv1 = bdrv_find_format("file"); From c33491978c5c4c746cc0272d5f2df50aa14d1f02 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 6 May 2010 16:34:56 +0200 Subject: [PATCH 10/21] block: Fix bdrv_commit When reopening the image, don't guess the driver, but use the same driver as was used before. This is important if the format=... option was used for that image. Signed-off-by: Kevin Wolf --- block.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index 977d01f74e..c134c2bcb5 100644 --- a/block.c +++ b/block.c @@ -701,12 +701,12 @@ int bdrv_commit(BlockDriverState *bs) bdrv_delete(bs->backing_hd); bs->backing_hd = NULL; bs_rw = bdrv_new(""); - rw_ret = bdrv_open(bs_rw, filename, open_flags | BDRV_O_RDWR, NULL); + rw_ret = bdrv_open(bs_rw, filename, open_flags | BDRV_O_RDWR, drv); if (rw_ret < 0) { bdrv_delete(bs_rw); /* try to re-open read-only */ bs_ro = bdrv_new(""); - ret = bdrv_open(bs_ro, filename, open_flags & ~BDRV_O_RDWR, NULL); + ret = bdrv_open(bs_ro, filename, open_flags & ~BDRV_O_RDWR, drv); if (ret < 0) { bdrv_delete(bs_ro); /* drive not functional anymore */ @@ -758,7 +758,7 @@ ro_cleanup: bdrv_delete(bs->backing_hd); bs->backing_hd = NULL; bs_ro = bdrv_new(""); - ret = bdrv_open(bs_ro, filename, open_flags & ~BDRV_O_RDWR, NULL); + ret = bdrv_open(bs_ro, filename, open_flags & ~BDRV_O_RDWR, drv); if (ret < 0) { bdrv_delete(bs_ro); /* drive not functional anymore */ From b76b6e95b8edb1284ff41c75f6b5145cc79d09df Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Thu, 6 May 2010 20:53:47 +0200 Subject: [PATCH 11/21] block/vdi: Allow disk images of size 0 Even it is not very useful, users may create images of size 0. Without the special option CONFIG_ZERO_MALLOC, qemu_mallocz aborts execution when it is told to allocate 0 bytes, so avoid this kind of call. Cc: Kevin Wolf Signed-off-by: Stefan Weil Signed-off-by: Kevin Wolf --- block/vdi.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/block/vdi.c b/block/vdi.c index 2b4d2c218d..3ea4103341 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -435,7 +435,9 @@ static int vdi_open(BlockDriverState *bs, int flags) bmap_size = header.blocks_in_image * sizeof(uint32_t); bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE; - s->bmap = qemu_malloc(bmap_size * SECTOR_SIZE); + if (bmap_size > 0) { + s->bmap = qemu_malloc(bmap_size * SECTOR_SIZE); + } if (bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) { goto fail_free_bmap; } @@ -857,7 +859,10 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options) result = -errno; } - bmap = (uint32_t *)qemu_mallocz(bmap_size); + bmap = NULL; + if (bmap_size > 0) { + bmap = (uint32_t *)qemu_mallocz(bmap_size); + } for (i = 0; i < blocks; i++) { if (image_type == VDI_TYPE_STATIC) { bmap[i] = i; From 9d8b88f68c4f55e4f706408b39f720e1a7486da1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 6 May 2010 22:04:34 +0200 Subject: [PATCH 12/21] parallels: use pread Use pread instead of lseek + read in preparation of using the qemu block API. Signed-off-by: Christoph Hellwig Signed-off-by: Kevin Wolf --- block/parallels.c | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/block/parallels.c b/block/parallels.c index b2171016f1..efb6d4d6d4 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -83,7 +83,7 @@ static int parallels_open(BlockDriverState *bs, const char *filename, int flags) s->fd = fd; - if (read(fd, &ph, sizeof(ph)) != sizeof(ph)) + if (pread(fd, &ph, sizeof(ph), 0) != sizeof(ph)) goto fail; if (memcmp(ph.magic, HEADER_MAGIC, 16) || @@ -93,14 +93,11 @@ static int parallels_open(BlockDriverState *bs, const char *filename, int flags) bs->total_sectors = le32_to_cpu(ph.nb_sectors); - if (lseek(s->fd, 64, SEEK_SET) != 64) - goto fail; - s->tracks = le32_to_cpu(ph.tracks); s->catalog_size = le32_to_cpu(ph.catalog_entries); s->catalog_bitmap = qemu_malloc(s->catalog_size * 4); - if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) != + if (pread(s->fd, s->catalog_bitmap, s->catalog_size * 4, 64) != s->catalog_size * 4) goto fail; for (i = 0; i < s->catalog_size; i++) @@ -114,28 +111,18 @@ fail: return -1; } -static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) +static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num) { BDRVParallelsState *s = bs->opaque; uint32_t index, offset; - uint64_t position; index = sector_num / s->tracks; offset = sector_num % s->tracks; - // not allocated + /* not allocated */ if ((index > s->catalog_size) || (s->catalog_bitmap[index] == 0)) return -1; - - position = (uint64_t)(s->catalog_bitmap[index] + offset) * 512; - -// fprintf(stderr, "sector: %llx index=%x offset=%x pointer=%x position=%x\n", -// sector_num, index, offset, s->catalog_bitmap[index], position); - - if (lseek(s->fd, position, SEEK_SET) != position) - return -1; - - return 0; + return (uint64_t)(s->catalog_bitmap[index] + offset) * 512; } static int parallels_read(BlockDriverState *bs, int64_t sector_num, @@ -144,11 +131,13 @@ static int parallels_read(BlockDriverState *bs, int64_t sector_num, BDRVParallelsState *s = bs->opaque; while (nb_sectors > 0) { - if (!seek_to_sector(bs, sector_num)) { - if (read(s->fd, buf, 512) != 512) - return -1; - } else + int64_t position = seek_to_sector(bs, sector_num); + if (position >= 0) { + if (pread(s->fd, buf, 512, position) != 512) + return -1; + } else { memset(buf, 0, 512); + } nb_sectors--; sector_num++; buf += 512; From 1dec5a70973bde6138d7cf30e98e12a49397abf4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 6 May 2010 22:04:50 +0200 Subject: [PATCH 13/21] parallels: use qemu block API Use bdrv_pwrite to access the backing device instead of pread, and convert the driver to implementing the bdrv_open method which gives it an already opened BlockDriverState for the underlying device. Signed-off-by: Christoph Hellwig Signed-off-by: Kevin Wolf --- block/parallels.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/block/parallels.c b/block/parallels.c index efb6d4d6d4..35a14aa422 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -46,7 +46,6 @@ struct parallels_header { } __attribute__((packed)); typedef struct BDRVParallelsState { - int fd; uint32_t *catalog_bitmap; int catalog_size; @@ -68,22 +67,15 @@ static int parallels_probe(const uint8_t *buf, int buf_size, const char *filenam return 0; } -static int parallels_open(BlockDriverState *bs, const char *filename, int flags) +static int parallels_open(BlockDriverState *bs, int flags) { BDRVParallelsState *s = bs->opaque; - int fd, i; + int i; struct parallels_header ph; - fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); - if (fd < 0) { - return -1; - } - bs->read_only = 1; // no write support yet - s->fd = fd; - - if (pread(fd, &ph, sizeof(ph), 0) != sizeof(ph)) + if (bdrv_pread(bs->file, 0, &ph, sizeof(ph)) != sizeof(ph)) goto fail; if (memcmp(ph.magic, HEADER_MAGIC, 16) || @@ -97,7 +89,7 @@ static int parallels_open(BlockDriverState *bs, const char *filename, int flags) s->catalog_size = le32_to_cpu(ph.catalog_entries); s->catalog_bitmap = qemu_malloc(s->catalog_size * 4); - if (pread(s->fd, s->catalog_bitmap, s->catalog_size * 4, 64) != + if (bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4) != s->catalog_size * 4) goto fail; for (i = 0; i < s->catalog_size; i++) @@ -107,7 +99,6 @@ static int parallels_open(BlockDriverState *bs, const char *filename, int flags) fail: if (s->catalog_bitmap) qemu_free(s->catalog_bitmap); - close(fd); return -1; } @@ -128,12 +119,10 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num) static int parallels_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { - BDRVParallelsState *s = bs->opaque; - while (nb_sectors > 0) { int64_t position = seek_to_sector(bs, sector_num); if (position >= 0) { - if (pread(s->fd, buf, 512, position) != 512) + if (bdrv_pread(bs->file, position, buf, 512) != 512) return -1; } else { memset(buf, 0, 512); @@ -149,14 +138,13 @@ static void parallels_close(BlockDriverState *bs) { BDRVParallelsState *s = bs->opaque; qemu_free(s->catalog_bitmap); - close(s->fd); } static BlockDriver bdrv_parallels = { .format_name = "parallels", .instance_size = sizeof(BDRVParallelsState), .bdrv_probe = parallels_probe, - .bdrv_file_open = parallels_open, + .bdrv_open = parallels_open, .bdrv_read = parallels_read, .bdrv_close = parallels_close, }; From dede4188cc817a039154ed2ecd7f3285f6b94056 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Mon, 10 May 2010 21:46:26 +0200 Subject: [PATCH 14/21] block/vpc: Fix conversion from size to disk geometry The VHD algorithm calculates a disk geometry which is usually smaller than the requested size. QEMU tried to round up but failed for certain sizes: qemu-img create -f vpc disk.vpc 9437184 would create an image with 9435136 bytes (which is too small for qemu-img convert). Instead of hacking the geometry algorithm, the patch increases the number of sectors until we get enough sectors. Cc: Kevin Wolf Signed-off-by: Stefan Weil Signed-off-by: Kevin Wolf --- block/vpc.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/block/vpc.c b/block/vpc.c index f94e4698b7..214e9d121f 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -463,9 +463,7 @@ static int calculate_geometry(int64_t total_sectors, uint16_t* cyls, } } - // Note: Rounding up deviates from the Virtual PC behaviour - // However, we need this to avoid truncating images in qemu-img convert - *cyls = (cyls_times_heads + *heads - 1) / *heads; + *cyls = cyls_times_heads / *heads; return 0; } @@ -477,9 +475,9 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options) struct vhd_dyndisk_header* dyndisk_header = (struct vhd_dyndisk_header*) buf; int fd, i; - uint16_t cyls; - uint8_t heads; - uint8_t secs_per_cyl; + uint16_t cyls = 0; + uint8_t heads = 0; + uint8_t secs_per_cyl = 0; size_t block_size, num_bat_entries; int64_t total_sectors = 0; @@ -496,9 +494,14 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options) if (fd < 0) return -EIO; - // Calculate matching total_size and geometry - if (calculate_geometry(total_sectors, &cyls, &heads, &secs_per_cyl)) - return -EFBIG; + /* Calculate matching total_size and geometry. Increase the number of + sectors requested until we get enough (or fail). */ + for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) { + if (calculate_geometry(total_sectors + i, + &cyls, &heads, &secs_per_cyl)) { + return -EFBIG; + } + } total_sectors = (int64_t) cyls * heads * secs_per_cyl; // Prepare the Hard Disk Footer From cd02a24b6112da50816a8021d97a2b26038f7190 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 7 May 2010 16:55:33 +0200 Subject: [PATCH 15/21] dmg: fix reading of uncompressed chunks When dmg_read_chunk encounters an uncompressed chunk it currently calls read without any previous adjustment of the file postion. This seems very wrong, and the "reference" implementation in dmg2img does a search to the same offset as done in the various compression cases, so do the same here. Signed-off-by: Christoph Hellwig Signed-off-by: Kevin Wolf --- block/dmg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/block/dmg.c b/block/dmg.c index d5c1a687e4..02a3d67206 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -239,7 +239,8 @@ static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num) return -1; break; } case 1: /* copy */ - ret = read(s->fd, s->uncompressed_chunk, s->lengths[chunk]); + ret = pread(s->fd, s->uncompressed_chunk, s->lengths[chunk], + s->offsets[chunk]); if (ret != s->lengths[chunk]) return -1; break; From 16cdf7ce1a53dcab75f5206a89bf98bb907a8b9e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 12 May 2010 16:31:35 +0200 Subject: [PATCH 16/21] dmg: use pread Use pread instead of lseek + read in preparation of using the qemu block API. Note that dmg actually uses the implicit file offset a lot in dmg_open, and we had to replace it with an offset variable. Signed-off-by: Christoph Hellwig Signed-off-by: Kevin Wolf --- block/dmg.c | 88 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/block/dmg.c b/block/dmg.c index 02a3d67206..a0ba34fb89 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -58,18 +58,18 @@ static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static off_t read_off(int fd) +static off_t read_off(int fd, int64_t offset) { uint64_t buffer; - if(read(fd,&buffer,8)<8) + if (pread(fd, &buffer, 8, offset) < 8) return 0; return be64_to_cpu(buffer); } -static off_t read_uint32(int fd) +static off_t read_uint32(int fd, int64_t offset) { uint32_t buffer; - if(read(fd,&buffer,4)<4) + if (pread(fd, &buffer, 4, offset) < 4) return 0; return be32_to_cpu(buffer); } @@ -80,6 +80,7 @@ static int dmg_open(BlockDriverState *bs, const char *filename, int flags) off_t info_begin,info_end,last_in_offset,last_out_offset; uint32_t count; uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i; + int64_t offset; s->fd = open(filename, O_RDONLY | O_BINARY); if (s->fd < 0) @@ -89,38 +90,45 @@ static int dmg_open(BlockDriverState *bs, const char *filename, int flags) s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL; /* read offset of info blocks */ - if(lseek(s->fd,-0x1d8,SEEK_END)<0) { + offset = lseek(s->fd, -0x1d8, SEEK_END); + if (offset < 0) { goto fail; } - info_begin=read_off(s->fd); - if(info_begin==0) - goto fail; - if(lseek(s->fd,info_begin,SEEK_SET)<0) - goto fail; - if(read_uint32(s->fd)!=0x100) - goto fail; - if((count = read_uint32(s->fd))==0) - goto fail; - info_end = info_begin+count; - if(lseek(s->fd,0xf8,SEEK_CUR)<0) + info_begin = read_off(s->fd, offset); + if (info_begin == 0) { goto fail; + } + + if (read_uint32(s->fd, info_begin) != 0x100) { + goto fail; + } + + count = read_uint32(s->fd, info_begin + 4); + if (count == 0) { + goto fail; + } + info_end = info_begin + count; + + offset = info_begin + 0x100; /* read offsets */ last_in_offset = last_out_offset = 0; - while(lseek(s->fd,0,SEEK_CUR)fd); + count = read_uint32(s->fd, offset); if(count==0) goto fail; - type = read_uint32(s->fd); - if(type!=0x6d697368 || count<244) - lseek(s->fd,count-4,SEEK_CUR); - else { + offset += 4; + + type = read_uint32(s->fd, offset); + if (type == 0x6d697368 && count >= 244) { int new_size, chunk_count; - if(lseek(s->fd,200,SEEK_CUR)<0) - goto fail; + + offset += 4; + offset += 200; + chunk_count = (count-204)/40; new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count); s->types = qemu_realloc(s->types, new_size/2); @@ -130,7 +138,8 @@ static int dmg_open(BlockDriverState *bs, const char *filename, int flags) s->sectorcounts = qemu_realloc(s->sectorcounts, new_size); for(i=s->n_chunks;in_chunks+chunk_count;i++) { - s->types[i] = read_uint32(s->fd); + s->types[i] = read_uint32(s->fd, offset); + offset += 4; if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) { if(s->types[i]==0xffffffff) { last_in_offset = s->offsets[i-1]+s->lengths[i-1]; @@ -138,15 +147,23 @@ static int dmg_open(BlockDriverState *bs, const char *filename, int flags) } chunk_count--; i--; - if(lseek(s->fd,36,SEEK_CUR)<0) - goto fail; + offset += 36; continue; } - read_uint32(s->fd); - s->sectors[i] = last_out_offset+read_off(s->fd); - s->sectorcounts[i] = read_off(s->fd); - s->offsets[i] = last_in_offset+read_off(s->fd); - s->lengths[i] = read_off(s->fd); + offset += 4; + + s->sectors[i] = last_out_offset+read_off(s->fd, offset); + offset += 8; + + s->sectorcounts[i] = read_off(s->fd, offset); + offset += 8; + + s->offsets[i] = last_in_offset+read_off(s->fd, offset); + offset += 8; + + s->lengths[i] = read_off(s->fd, offset); + offset += 8; + if(s->lengths[i]>max_compressed_size) max_compressed_size = s->lengths[i]; if(s->sectorcounts[i]>max_sectors_per_chunk) @@ -210,15 +227,12 @@ static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num) case 0x80000005: { /* zlib compressed */ int i; - ret = lseek(s->fd, s->offsets[chunk], SEEK_SET); - if(ret<0) - return -1; - /* we need to buffer, because only the chunk as whole can be * inflated. */ i=0; do { - ret = read(s->fd, s->compressed_chunk+i, s->lengths[chunk]-i); + ret = pread(s->fd, s->compressed_chunk+i, s->lengths[chunk]-i, + s->offsets[chunk] + i); if(ret<0 && errno==EINTR) ret=0; i+=ret; From 64a31d5c3d73396a88563d7a504654edc85aa854 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 12 May 2010 16:31:49 +0200 Subject: [PATCH 17/21] dmg: use qemu block API Use bdrv_pwrite to access the backing device instead of pread, and convert the driver to implementing the bdrv_open method which gives it an already opened BlockDriverState for the underlying device. Dmg actually does an lseek to a negative offset in the open routine, which we replace with offset arithmetics after doing a bdrv_getlength. Signed-off-by: Christoph Hellwig Signed-off-by: Kevin Wolf --- block/dmg.c | 56 +++++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/block/dmg.c b/block/dmg.c index a0ba34fb89..a3c815b862 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -28,8 +28,6 @@ #include typedef struct BDRVDMGState { - int fd; - /* each chunk contains a certain number of sectors, * offsets[i] is the offset in the .dmg file, * lengths[i] is the length of the compressed chunk, @@ -58,23 +56,23 @@ static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static off_t read_off(int fd, int64_t offset) +static off_t read_off(BlockDriverState *bs, int64_t offset) { uint64_t buffer; - if (pread(fd, &buffer, 8, offset) < 8) + if (bdrv_pread(bs->file, offset, &buffer, 8) < 8) return 0; return be64_to_cpu(buffer); } -static off_t read_uint32(int fd, int64_t offset) +static off_t read_uint32(BlockDriverState *bs, int64_t offset) { uint32_t buffer; - if (pread(fd, &buffer, 4, offset) < 4) + if (bdrv_pread(bs->file, offset, &buffer, 4) < 4) return 0; return be32_to_cpu(buffer); } -static int dmg_open(BlockDriverState *bs, const char *filename, int flags) +static int dmg_open(BlockDriverState *bs, int flags) { BDRVDMGState *s = bs->opaque; off_t info_begin,info_end,last_in_offset,last_out_offset; @@ -82,29 +80,27 @@ static int dmg_open(BlockDriverState *bs, const char *filename, int flags) uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i; int64_t offset; - s->fd = open(filename, O_RDONLY | O_BINARY); - if (s->fd < 0) - return -errno; bs->read_only = 1; s->n_chunks = 0; s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL; /* read offset of info blocks */ - offset = lseek(s->fd, -0x1d8, SEEK_END); + offset = bdrv_getlength(bs->file); if (offset < 0) { goto fail; } + offset -= 0x1d8; - info_begin = read_off(s->fd, offset); + info_begin = read_off(bs, offset); if (info_begin == 0) { goto fail; } - if (read_uint32(s->fd, info_begin) != 0x100) { + if (read_uint32(bs, info_begin) != 0x100) { goto fail; } - count = read_uint32(s->fd, info_begin + 4); + count = read_uint32(bs, info_begin + 4); if (count == 0) { goto fail; } @@ -117,12 +113,12 @@ static int dmg_open(BlockDriverState *bs, const char *filename, int flags) while (offset < info_end) { uint32_t type; - count = read_uint32(s->fd, offset); + count = read_uint32(bs, offset); if(count==0) goto fail; offset += 4; - type = read_uint32(s->fd, offset); + type = read_uint32(bs, offset); if (type == 0x6d697368 && count >= 244) { int new_size, chunk_count; @@ -138,7 +134,7 @@ static int dmg_open(BlockDriverState *bs, const char *filename, int flags) s->sectorcounts = qemu_realloc(s->sectorcounts, new_size); for(i=s->n_chunks;in_chunks+chunk_count;i++) { - s->types[i] = read_uint32(s->fd, offset); + s->types[i] = read_uint32(bs, offset); offset += 4; if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) { if(s->types[i]==0xffffffff) { @@ -152,16 +148,16 @@ static int dmg_open(BlockDriverState *bs, const char *filename, int flags) } offset += 4; - s->sectors[i] = last_out_offset+read_off(s->fd, offset); + s->sectors[i] = last_out_offset+read_off(bs, offset); offset += 8; - s->sectorcounts[i] = read_off(s->fd, offset); + s->sectorcounts[i] = read_off(bs, offset); offset += 8; - s->offsets[i] = last_in_offset+read_off(s->fd, offset); + s->offsets[i] = last_in_offset+read_off(bs, offset); offset += 8; - s->lengths[i] = read_off(s->fd, offset); + s->lengths[i] = read_off(bs, offset); offset += 8; if(s->lengths[i]>max_compressed_size) @@ -183,7 +179,6 @@ static int dmg_open(BlockDriverState *bs, const char *filename, int flags) return 0; fail: - close(s->fd); return -1; } @@ -213,8 +208,10 @@ static inline uint32_t search_chunk(BDRVDMGState* s,int sector_num) return s->n_chunks; /* error */ } -static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num) +static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num) { + BDRVDMGState *s = bs->opaque; + if(!is_sector_in_chunk(s,s->current_chunk,sector_num)) { int ret; uint32_t chunk = search_chunk(s,sector_num); @@ -231,8 +228,8 @@ static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num) * inflated. */ i=0; do { - ret = pread(s->fd, s->compressed_chunk+i, s->lengths[chunk]-i, - s->offsets[chunk] + i); + ret = bdrv_pread(bs->file, s->offsets[chunk] + i, + s->compressed_chunk+i, s->lengths[chunk]-i); if(ret<0 && errno==EINTR) ret=0; i+=ret; @@ -253,8 +250,8 @@ static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num) return -1; break; } case 1: /* copy */ - ret = pread(s->fd, s->uncompressed_chunk, s->lengths[chunk], - s->offsets[chunk]); + ret = bdrv_pread(bs->file, s->offsets[chunk], + s->uncompressed_chunk, s->lengths[chunk]); if (ret != s->lengths[chunk]) return -1; break; @@ -275,7 +272,7 @@ static int dmg_read(BlockDriverState *bs, int64_t sector_num, for(i=0;isectors[s->current_chunk]; memcpy(buf+i*512,s->uncompressed_chunk+sector_offset_in_chunk*512,512); @@ -286,7 +283,6 @@ static int dmg_read(BlockDriverState *bs, int64_t sector_num, static void dmg_close(BlockDriverState *bs) { BDRVDMGState *s = bs->opaque; - close(s->fd); if(s->n_chunks>0) { free(s->types); free(s->offsets); @@ -303,7 +299,7 @@ static BlockDriver bdrv_dmg = { .format_name = "dmg", .instance_size = sizeof(BDRVDMGState), .bdrv_probe = dmg_probe, - .bdrv_file_open = dmg_open, + .bdrv_open = dmg_open, .bdrv_read = dmg_read, .bdrv_close = dmg_close, }; From f21dc3a4652eeb82117d7d55d975278fe1444b26 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Wed, 12 May 2010 20:25:45 +0200 Subject: [PATCH 18/21] block/vdi: Fix image opening and creation for odd disk sizes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fix is based on a patch from Kevin Wolf. Here his comment: "The number of blocks needs to be rounded up to cover all of the virtual hard disk. Without this fix, we can't even open our own images if their size is not a multiple of the block size." While Kevin's patch addressed vdi_create, my modification also fixes vdi_open which now accepts images with odd disk sizes. v3: Don't allow reading of disk images with too large disk sizes. Neither VBoxManage nor old versions of qemu-img read such images. This change requires rounding of odd disk sizes before we do the checks. Cc: Kevin Wolf Cc: François Revol Signed-off-by: Stefan Weil Signed-off-by: Kevin Wolf --- block/vdi.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/block/vdi.c b/block/vdi.c index 3ea4103341..ee8cc7b1aa 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -393,6 +393,15 @@ static int vdi_open(BlockDriverState *bs, int flags) vdi_header_print(&header); #endif + if (header.disk_size % SECTOR_SIZE != 0) { + /* 'VBoxManage convertfromraw' can create images with odd disk sizes. + We accept them but round the disk size to the next multiple of + SECTOR_SIZE. */ + logout("odd disk size %" PRIu64 " B, round up\n", header.disk_size); + header.disk_size += SECTOR_SIZE - 1; + header.disk_size &= ~(SECTOR_SIZE - 1); + } + if (header.version != VDI_VERSION_1_1) { logout("unsupported version %u.%u\n", header.version >> 16, header.version & 0xffff); @@ -405,18 +414,15 @@ static int vdi_open(BlockDriverState *bs, int flags) /* We only support data blocks which start on a sector boundary. */ logout("unsupported data offset 0x%x B\n", header.offset_data); goto fail; - } else if (header.disk_size % SECTOR_SIZE != 0) { - logout("unsupported disk size %" PRIu64 " B\n", header.disk_size); - goto fail; } else if (header.sector_size != SECTOR_SIZE) { logout("unsupported sector size %u B\n", header.sector_size); goto fail; } else if (header.block_size != 1 * MiB) { logout("unsupported block size %u B\n", header.block_size); goto fail; - } else if ((header.disk_size + header.block_size - 1) / header.block_size != - (uint64_t)header.blocks_in_image) { - logout("unexpected block number %u B\n", header.blocks_in_image); + } else if (header.disk_size > + (uint64_t)header.blocks_in_image * header.block_size) { + logout("unsupported disk size %" PRIu64 " B\n", header.disk_size); goto fail; } else if (!uuid_is_null(header.uuid_link)) { logout("link uuid != 0, unsupported\n"); @@ -829,7 +835,10 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options) return -errno; } - blocks = bytes / block_size; + /* We need enough blocks to store the given disk size, + so always round up. */ + blocks = (bytes + block_size - 1) / block_size; + bmap_size = blocks * sizeof(uint32_t); bmap_size = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1)); From af474591e5521978194ee099497202c6818f2359 Mon Sep 17 00:00:00 2001 From: Bruce Rogers Date: Thu, 13 May 2010 15:14:33 -0600 Subject: [PATCH 19/21] use qemu_free() instead of free() There is a call to free() where qemu_free() should instead be used. Signed-off-by: Bruce Rogers Signed-off-by: Kevin Wolf --- block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block.c b/block.c index c134c2bcb5..96ef1b1955 100644 --- a/block.c +++ b/block.c @@ -2075,7 +2075,7 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs) return 0; fail: - free(mcb); + qemu_free(mcb); return -1; } From 21955137eefb30e2137682046ea456f32c059300 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 13 May 2010 06:30:50 -0400 Subject: [PATCH 20/21] Fix docs for block stats monitor command The 'parent' field in the 'query-blockstats' monitor command is part of the top level block device QDict, not part of the 2nd level 'stats' QDict. * block.c: Fix docs for 'parent' field in block stats monitor command output Signed-off-by: Daniel P. Berrange Signed-off-by: Kevin Wolf --- block.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/block.c b/block.c index 96ef1b1955..782258016a 100644 --- a/block.c +++ b/block.c @@ -1582,9 +1582,9 @@ static QObject* bdrv_info_stats_bs(BlockDriverState *bs) * - "wr_operations": write operations * - "wr_highest_offset": Highest offset of a sector written since the * BlockDriverState has been opened - * - "parent": Contains recursively the statistics of the underlying - * protocol (e.g. the host file for a qcow2 image). If there is no - * underlying protocol, this field is omitted. + * - "parent": A QDict recursively holding the statistics of the underlying + * protocol (e.g. the host file for a qcow2 image). If there is no + * underlying protocol, this field is omitted. * * Example: * @@ -1593,15 +1593,14 @@ static QObject* bdrv_info_stats_bs(BlockDriverState *bs) * "wr_bytes": 0, * "rd_operations": 1, * "wr_operations": 0, - * "wr_highest_offset": 0, - * "parent": { - * "stats": { "rd_bytes": 1024, - * "wr_bytes": 0, - * "rd_operations": 2, - * "wr_operations": 0, - * "wr_highest_offset": 0, - * } - * } } }, + * "wr_highest_offset": 0 }, + * "parent": { + * "stats": { "rd_bytes": 1024, + * "wr_bytes": 0, + * "rd_operations": 2, + * "wr_operations": 0, + * "wr_highest_offset": 0, + * } } }, * { "device": "ide1-cd0", * "stats": { "rd_bytes": 0, * "wr_bytes": 0, From 35ed5de6be186d46ff3e33554f32151fba0f401f Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 12 May 2010 14:03:02 +0200 Subject: [PATCH 21/21] block: Remove special case for vvfat The special case doesn't really us buy anything. Without it vvfat works more consistently as a protocol. We get raw on top of vvfat now, which works just as well as using vvfat directly. Signed-off-by: Kevin Wolf --- block.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/block.c b/block.c index 782258016a..bfe46e3765 100644 --- a/block.c +++ b/block.c @@ -326,11 +326,6 @@ static BlockDriver *find_image_format(const char *filename) uint8_t buf[2048]; BlockDriverState *bs; - drv = find_protocol(filename); - /* no need to test disk image formats for vvfat */ - if (drv && strcmp(drv->format_name, "vvfat") == 0) - return drv; - ret = bdrv_file_open(&bs, filename, 0); if (ret < 0) return NULL;