Subject: [PATCH] Properly support the ide flush cache commands From: Jens Axboe <[EMAIL PROTECTED]> Date: 1136376567 +0100
Add a ->bdrv_sync() hook to the BlockDriver, as it should know how to sync the cached state with what is on disk. I updated the raw and dmg drivers, they just need to fsync() the file descriptor. This is needed for correctness reasons, as the OS expects drive cached data to be on platter when FLUSH_CACHE has completed successfully. At least Linux uses this extensively for journalled file systems, if they are mounted with the barrier= option. --- block-dmg.c | 11 +++++++++++ block.c | 19 +++++++++++++++++++ block_int.h | 1 + hw/ide.c | 18 +++++++++++++++--- vl.h | 1 + 5 files changed, 47 insertions(+), 3 deletions(-) 5a8639e3c23e7e312c5213c15dd40a24eee9b416 diff --git a/block-dmg.c b/block-dmg.c index 5df7235..486a938 100644 --- a/block-dmg.c +++ b/block-dmg.c @@ -269,6 +269,12 @@ static int dmg_read(BlockDriverState *bs return 0; } +static int dmg_sync(BlockDriverState *bs) +{ + BDRVDMGState *s = bs->opaque; + return fsync(s->fd); +} + static void dmg_close(BlockDriverState *bs) { BDRVDMGState *s = bs->opaque; @@ -293,5 +299,10 @@ BlockDriver bdrv_dmg = { dmg_read, NULL, dmg_close, + NULL, + NULL, + NULL, + NULL, + dmg_sync, }; diff --git a/block.c b/block.c index 6924cee..c37f29a 100644 --- a/block.c +++ b/block.c @@ -460,6 +460,14 @@ int bdrv_write(BlockDriverState *bs, int return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors); } +int bdrv_sync(BlockDriverState *bs) +{ + if (bs->drv->bdrv_sync) + return bs->drv->bdrv_sync(bs); + + return -EIO; +} + void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) { *nb_sectors_ptr = bs->total_sectors; @@ -752,6 +760,13 @@ static int raw_create(const char *filena return 0; } +static int raw_sync(BlockDriverState *bs) +{ + BDRVRawState *s = bs->opaque; + return fsync(s->fd); +} + + BlockDriver bdrv_raw = { "raw", sizeof(BDRVRawState), @@ -761,6 +776,10 @@ BlockDriver bdrv_raw = { raw_write, raw_close, raw_create, + NULL, + NULL, + NULL, + raw_sync, }; void bdrv_init(void) diff --git a/block_int.h b/block_int.h index e303816..30e830a 100644 --- a/block_int.h +++ b/block_int.h @@ -40,6 +40,7 @@ struct BlockDriver { int nb_sectors, int *pnum); int (*bdrv_set_key)(BlockDriverState *bs, const char *key); int (*bdrv_make_empty)(BlockDriverState *bs); + int (*bdrv_sync)(BlockDriverState *bs); struct BlockDriver *next; }; diff --git a/hw/ide.c b/hw/ide.c index 6a52347..3aadd9e 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "vl.h" +#include "block_int.h" /* debug IDE devices */ //#define DEBUG_IDE @@ -422,7 +423,7 @@ static void put_le16(uint16_t *p, unsign static void ide_identify(IDEState *s) { - uint16_t *p; + uint16_t *p, flush_flags = 0; unsigned int oldsize; char buf[20]; @@ -431,6 +432,10 @@ static void ide_identify(IDEState *s) return; } + /* flush_cache_ext is bit 13, flush_cache is bit 12 */ + if (s->bs->drv->bdrv_sync) + flush_flags = (1 << 13) | (1 << 12); + memset(s->io_buffer, 0, 512); p = (uint16_t *)s->io_buffer; put_le16(p + 0, 0x0040); @@ -473,11 +478,11 @@ static void ide_identify(IDEState *s) put_le16(p + 81, 0x16); /* conforms to ata5 */ put_le16(p + 82, (1 << 14)); /* 13=flush_cache_ext,12=flush_cache,10=lba48 */ - put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10)); + put_le16(p + 83, (1 << 14) | (1 << 10) | flush_flags); put_le16(p + 84, (1 << 14)); put_le16(p + 85, (1 << 14)); /* 13=flush_cache_ext,12=flush_cache,10=lba48 */ - put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10)); + put_le16(p + 86, (1 << 14) | (1 << 10) | flush_flags); put_le16(p + 87, (1 << 14)); put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */ put_le16(p + 93, 1 | (1 << 14) | 0x2000); @@ -1755,6 +1760,13 @@ static void ide_ioport_write(void *opaqu break; case WIN_FLUSH_CACHE: case WIN_FLUSH_CACHE_EXT: + if (s->is_cdrom) + goto abort_cmd; + if (bdrv_sync(s->bs)) + goto abort_cmd; + s->status = READY_STAT; + ide_set_irq(s); + break; case WIN_STANDBYNOW1: case WIN_IDLEIMMEDIATE: s->status = READY_STAT; diff --git a/vl.h b/vl.h index 7a10728..01a1985 100644 --- a/vl.h +++ b/vl.h @@ -460,6 +460,7 @@ int bdrv_write(BlockDriverState *bs, int void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr); int bdrv_commit(BlockDriverState *bs); void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size); +int bdrv_sync(BlockDriverState *bs); #define BDRV_TYPE_HD 0 #define BDRV_TYPE_CDROM 1 -- 1.0.GIT -- Jens Axboe _______________________________________________ Qemu-devel mailing list Qemu-devel@nongnu.org http://lists.nongnu.org/mailman/listinfo/qemu-devel