Open disk images with O_DIRECT
v2 cover Open disk images with O_DIRECT
These patches allow to open file using O_DIRECT and bypass the host I/O cache.
The v2 is a new version including comments from Anthony Liguori ("directio" has been renamed "cache"), from Balazs Attila-Mihaly (for Win32 support, not tested) and Samuel Thibault (for the generic function qemu_memalign()".
This version is an updated version with last CVS changes.
[PATCH 1/2] Add "cache" parameter to "-drive"
Using "cache=off" with "-drive" will open the disk image file using "O_DIRECT".
[PATCH 2/2] Direct IDE I/O
This patch enhances the "-drive ,cache=off" mode with IDE drive emulation by removing the buffer used in the IDE emulation.
Laurent
PATCH v2 1/2 Add "cache" parameter to "-drive"
This patch adds a new parameter to "-drive"
Using "cache=off" with "-drive" will open the disk image file using "O_DIRECT".
By default, "cache" is set to "on" to keep original behavior of qemu.
example:
"-drive file=my_disk.qcow2,cache=off"
--- block-raw-posix.c | 8 ++++++++ block-raw-win32.c | 4 ++++ block.c | 2 +- block.h | 1 + hw/fdc.c | 7 ++++++- hw/ide.c | 18 ++++++++++++++---- hw/scsi-disk.c | 3 ++- hw/sd.c | 11 ++++++++++- osdep.c | 20 ++++++++++++++++++++ osdep.h | 1 + vl.c | 28 ++++++++++++++++++++++++---- 11 files changed, 91 insertions(+), 12 deletions(-)
block.c +1 -1
@@ -380,7 +380,7 @@ int bdrv_open2(BlockDriverState *bs, con/* Note: for compatibility, we open disk image files as RDWR, and RDONLY as fallback */ if (!(flags &BDRV_O_FILE )) - open_flags =BDRV_O_RDWR ; + open_flags =BDRV_O_RDWR | (flags &BDRV_O_DIRECT );else open_flags = flags & ~(BDRV_O_FILE |BDRV_O_SNAPSHOT ); ret = drv->bdrv_open (bs, filename, open_flags);
block.h +1 -0
@@ -44,6 +44,7 @@ typedef struct QEMUSnapshotInfo {use a disk image format on top of it (default for bdrv_file_open()) */ +#define BDRV_O_DIRECT 0x0020#ifndef QEMU_IMG void bdrv_info (void );
hw/fdc.c +6 -1
@@ -382,7 +382,7 @@ struct fdctrl_t {uint8_t cur_drv;uint8_t bootsel;/* Command FIFO */ -uint8_t fifo[FD_SECTOR_LEN ]; +uint8_t *fifo;uint32_t data_pos;uint32_t data_len;uint8_t data_state;
@@ -598,6 +598,11 @@ fdctrl_t *fdctrl_init (qemu_irq irq, int fdctrl =qemu_mallocz (sizeof (fdctrl_t));if (!fdctrl)return NULL ; + fdctrl->fifo =qemu_memalign (512 ,FD_SECTOR_LEN ); +if (fdctrl->fifo ==NULL ) { +qemu_free (fdctrl); +return NULL ; + } fdctrl->result_timer =qemu_new_timer (vm_clock, fdctrl_result_timer, fdctrl);
hw/ide.c +14 -4
@@ -365,7 +365,7 @@ typedef struct IDEState {EndTransferFunc *end_transfer_func;uint8_t *data_ptr;uint8_t *data_end; -uint8_t io_buffer[MAX_MULT_SECTORS *512 +4 ]; +uint8_t *io_buffer;QEMUTimer *sector_write_timer;/* only used for win2k install hack */ uint32_t irq_count;/* counts IRQs when using win2k install hack */ /* CF-ATA extended error */
@@ -2377,17 +2377,24 @@ struct partition {static int guess_disk_lchs (IDEState *s,int *pcylinders,int *pheads,int *psectors) { -uint8_t buf[512 ]; +uint8_t *buf;int ret, i, heads, sectors, cylinders;struct partition *p;uint32_t nr_sects; + buf =qemu_memalign (512 ,512 ); +if (buf ==NULL ) +return -1 ; ret =bdrv_read (s->bs,0 , buf,1 ); -if (ret <0 ) +if (ret <0 ) { +qemu_free (buf);return -1 ; + }/* test msdos magic */ -if (buf[510 ] !=0x55 || buf[511 ] !=0xaa ) +if (buf[510 ] !=0x55 || buf[511 ] !=0xaa ) { +qemu_free (buf);return -1 ; + }for (i =0 ; i <4 ; i++) { p = ((struct partition *)(buf +0x1be )) + i; nr_sects =le32_to_cpu (p->nr_sects);
@@ -2408,9 +2415,11 @@ static int guess_disk_lchs(IDEState *s,printf ("guessed geometry: LCHS=%d %d %d\n" , cylinders, heads, sectors);#endif +qemu_free (buf);return 0 ; } } +qemu_free (buf);return -1 ; }
@@ -2425,6 +2434,7 @@ static void ide_init2(IDEState *ide_statfor (i =0 ; i <2 ; i++) { s = ide_state + i; + s->io_buffer =qemu_memalign (512 ,MAX_MULT_SECTORS *512 +4 );if (i ==0 ) s->bs = hd0;else
hw/scsi-disk.c +2 -1
@@ -46,7 +46,7 @@ typedef struct SCSIRequest {int sector_count;/* The amounnt of data in the buffer. */ int buf_len; -uint8_t dma_buf[SCSI_DMA_BUF_SIZE ]; +uint8_t *dma_buf;BlockDriverAIOCB *aiocb;struct SCSIRequest *next; } SCSIRequest;
@@ -78,6 +78,7 @@ static SCSIRequest *scsi_new_request(SCS free_requests = r->next; }else { r =qemu_malloc (sizeof (SCSIRequest)); + r->dma_buf =qemu_memalign (512 ,SCSI_DMA_BUF_SIZE ); } r->dev = s; r->tag = tag;
hw/sd.c +10 -1
@@ -1284,10 +1284,17 @@ int sd_do_command(SDState *sd, struct sdstatic void sd_blk_read (BlockDriverState *bdrv,void *data,uint32_t addr,uint32_t len) { -uint8_t buf[512 ]; +uint8_t *buf;uint32_t end = addr + len; + buf =qemu_memalign (512 ,512 ); +if (buf ==NULL ) { +printf ("sd_blk_read: cannot allocate memory\n" ); +return ; + } +if (!bdrv ||bdrv_read (bdrv, addr >>9 , buf,1 ) ==-1 ) { +qemu_free (buf);printf ("sd_blk_read: read error on host side\n" );return ; }
@@ -1297,11 +1304,13 @@ static void sd_blk_read(BlockDriverStateif (bdrv_read (bdrv, end >>9 , buf,1 ) ==-1 ) {printf ("sd_blk_read: read error on host side\n" ); +qemu_free (buf);return ; }memcpy (data +512 - (addr &511 ), buf, end &511 ); }else memcpy (data, buf + (addr &511 ), len); +qemu_free (buf); } static void sd_blk_write(BlockDriverState *bdrv,
osdep.c +20 -0
@@ -61,6 +61,10 @@ void *qemu_malloc(size_t size) }#if defined(_WIN32) +void *qemu_memalign (size_t alignment,size_t size) +{ +return VirtualAlloc (NULL , size,MEM_COMMIT ,PAGE_READWRITE ); +}void *qemu_vmalloc (size_t size) {
@@ -172,6 +176,22 @@ static void kqemu_vfree(void *ptr)#endif +void *qemu_memalign (size_t alignment,size_t size) +{ +#if defined(_POSIX_C_SOURCE) +int ret; +void *ptr; + ret =posix_memalign (&ptr, alignment, size); +if (ret !=0 ) +return NULL ; +return ptr; +#elif defined(_BSD) +return valloc (size); +#else +return memalign (alignment, size); +#endif +} +/* alloc shared memory pages */ void *qemu_vmalloc (size_t size) {
osdep.h +1 -0
@@ -48,6 +48,7 @@ void *qemu_mallocz(size_t size);void qemu_free (void *ptr);char *qemu_strdup (const char *str); +void *qemu_memalign (size_t alignment,size_t size);void *qemu_vmalloc (size_t size);void qemu_vfree (void *ptr);
vl.c +24 -4
@@ -4880,8 +4880,11 @@ static int drive_init(const char *str, iBlockDriverState *bdrv;int max_devs;int index; +int cache; +int bdrv_flags;char *params[] = {"bus" ,"unit" ,"if" ,"index" ,"cyls" ,"heads" , -"secs" ,"trans" ,"media" ,"snapshot" ,"file" ,NULL }; +"secs" ,"trans" ,"media" ,"snapshot" ,"file" , +"cache" ,NULL };if (check_params (buf,sizeof (buf), params, str) <0 ) { fprintf(stderr, "qemu: unknowm parameter '%s' in '%s'\n",
@@ -4895,6 +4898,7 @@ static int drive_init(const char *str, i unit_id =-1 ; translation =BIOS_ATA_TRANSLATION_AUTO ; index =-1 ; + cache =1 ; if (!strcmp(machine->name, "realview") || !strcmp(machine->name, "SS-5") ||
@@ -5037,6 +5041,17 @@ static int drive_init(const char *str, i } } +if (get_param_value (buf,sizeof (buf),"cache" , str)) { +if (!strcmp (buf,"off" )) + cache =0 ; +else if (!strcmp (buf,"on" )) + cache =1 ; +else { +fprintf (stderr,"qemu: invalid cache option\n" ); +return -1 ; + } + } +get_param_value (file,sizeof (file),"file" , str);/* compute bus and unit according index */
@@ -5127,8 +5142,12 @@ static int drive_init(const char *str, i }if (!file[0 ])return 0 ; -if (bdrv_open (bdrv, file, snapshot ?BDRV_O_SNAPSHOT :0 ) <0 || -qemu_key_check (bdrv, file)) { + bdrv_flags =0 ; +if (snapshot) + bdrv_flags |=BDRV_O_SNAPSHOT ; +if (!cache) + bdrv_flags |=BDRV_O_DIRECT ; +if (bdrv_open (bdrv, file, bdrv_flags) <0 ||qemu_key_check (bdrv, file)) {fprintf (stderr,"qemu: could not open disk image %s\n" , file);return -1 ;
@@ -7476,7 +7495,8 @@ static void help(int exitcode)"-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][index=i]\n" -" [,cyls=c,heads=h,secs=s[,trans=t]][snapshot=on|off]\n" +" [,cyls=c,heads=h,secs=s[,trans=t]][snapshot=on|off]" +" [,cache=on|off]\n" " use 'file' as a drive image\n" "-mtdblock file use 'file' as on-board Flash memory image\n" "-sd file use 'file' as SecureDigital card image\n"
block-raw-posix.c +8 -0
@@ -106,6 +106,10 @@ static int raw_open(BlockDriverState *bs }if (flags &BDRV_O_CREAT ) open_flags |=O_CREAT |O_TRUNC ; +#ifdef O_DIRECT +if (flags &BDRV_O_DIRECT ) + open_flags |=O_DIRECT ; +#endif s->type =FTYPE_FILE ;
@@ -659,6 +663,10 @@ static int hdev_open(BlockDriverState *b open_flags |=O_RDONLY ; bs->read_only =1 ; } +#ifdef O_DIRECT +if (flags &BDRV_O_DIRECT ) + open_flags |=O_DIRECT ; +#endif s->type =FTYPE_FILE ;#if defined(__linux__)
block-raw-win32.c +4 -0
@@ -473,6 +473,10 @@ static int hdev_open(BlockDriverState *b#else overlapped =FILE_FLAG_OVERLAPPED ;#endif +if (flags &BDRV_O_DIRECT ) + overlapped |=FILE_FLAG_NO_BUFFERING |FILE_FLAG_WRITE_THROUGH ; +if (flags &BDRV_O_DIRECT ) + overlapped |=FILE_FLAG_NO_BUFFERING |FILE_FLAG_WRITE_THROUGH ; s->hfile =CreateFile (filename, access_flags,FILE_SHARE_READ ,NULL , create_flags, overlapped,NULL );
PATCH v2 2/2 Direct IDE I/O
This patch enhances the "-drive ,cache=off" mode with IDE drive emulation by removing the buffer used in the IDE emulation.
--- block.c | 10 +++ block.h | 2 block_int.h | 1 cpu-all.h | 1 exec.c | 19 ++++++ hw/ide.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- vl.c | 1 7 files changed, 204 insertions(+), 6 deletions(-)
block.c +10 -0
@@ -758,6 +758,11 @@ void bdrv_set_translation_hint(BlockDriv bs->translation = translation; } +void bdrv_set_cache_hint (BlockDriverState *bs,int cache) +{ + bs->cache = cache; +} +void bdrv_get_geometry_hint (BlockDriverState *bs,int *pcyls,int *pheads,int *psecs) {
@@ -786,6 +791,11 @@ int bdrv_is_read_only(BlockDriverState *return bs->read_only; } +int bdrv_is_cached (BlockDriverState *bs) +{ +return bs->cache; +} +/* XXX: no longer used */ void bdrv_set_change_cb (BlockDriverState *bs,void (*change_cb)(void *opaque),void *opaque)
block.h +2 -0
@@ -113,6 +113,7 @@ void bdrv_set_geometry_hint(BlockDriverS int cyls, int heads, int secs);void bdrv_set_type_hint (BlockDriverState *bs,int type);void bdrv_set_translation_hint (BlockDriverState *bs,int translation); +void bdrv_set_cache_hint (BlockDriverState *bs,int cache);void bdrv_get_geometry_hint (BlockDriverState *bs,int *pcyls,int *pheads,int *psecs);int bdrv_get_type_hint (BlockDriverState *bs);
@@ -120,6 +121,7 @@ int bdrv_get_translation_hint(BlockDriveint bdrv_is_removable (BlockDriverState *bs);int bdrv_is_read_only (BlockDriverState *bs);int bdrv_is_inserted (BlockDriverState *bs); +int bdrv_is_cached (BlockDriverState *bs);int bdrv_media_changed (BlockDriverState *bs);int bdrv_is_locked (BlockDriverState *bs);void bdrv_set_locked (BlockDriverState *bs,int locked);
block_int.h +1 -0
@@ -124,6 +124,7 @@ struct BlockDriverState {drivers. They are not used by the block driver */ int cyls, heads, secs, translation;int type; +int cache;char device_name[32 ];BlockDriverState *next; };
cpu-all.h +1 -0
@@ -838,6 +838,7 @@ int cpu_register_io_memory(int io_index,CPUWriteMemoryFunc **cpu_get_io_memory_write (int io_index);CPUReadMemoryFunc **cpu_get_io_memory_read (int io_index); +extern uint8_t *cpu_physical_page_addr (target_phys_addr_t addr);void cpu_physical_memory_rw (target_phys_addr_t addr,uint8_t *buf,int len,int is_write); static inline void cpu_physical_memory_read(target_phys_addr_t addr,
exec.c +19 -0
@@ -2071,6 +2071,25 @@ void cpu_register_physical_memory(target } } +uint8_t *cpu_physical_page_addr (target_phys_addr_t addr) +{ +target_phys_addr_t page; +unsigned long pd; +PhysPageDesc *p; +unsigned long addr1; + + page = addr &TARGET_PAGE_MASK ; + p =phys_page_find (page >>TARGET_PAGE_BITS ); +if (!p) +return (uint8_t *)-1 ; + + pd = p->phys_offset; + + addr1 = (pd &TARGET_PAGE_MASK ) + (addr & ~TARGET_PAGE_MASK ); + +return phys_ram_base + addr1; +} +/* XXX: temporary until new memory mapping API */ uint32_t cpu_get_physical_page_desc (target_phys_addr_t addr) {
hw/ide.c +170 -6
212 lines not on this page · raw message
vl.c +1 -0
@@ -5147,6 +5147,7 @@ static int drive_init(const char *str, i bdrv_flags |=BDRV_O_SNAPSHOT ;if (!cache) bdrv_flags |=BDRV_O_DIRECT ; +bdrv_set_cache_hint (bdrv, cache);if (bdrv_open (bdrv, file, bdrv_flags) <0 ||qemu_key_check (bdrv, file)) {fprintf (stderr,"qemu: could not open disk image %s\n" , file);
Re: [Qemu-devel] [PATCH 2/2 v2][UPDATED] Direct IDE I/O
Quoted 11 lines · Laurent Vivier
This patch enhances the "-drive ,cache=off" mode with IDE drive emulation by removing the buffer used in the IDE emulation.
--- block.c | 10 +++ block.h | 2 block_int.h | 1 cpu-all.h | 1 exec.c | 19 ++++++ hw/ide.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- vl.c | 1 7 files changed, 204 insertions(+), 6 deletions(-)
Quoted 1 line
[...]
Unfortunately it is more complicated to write to the CPU memory. In particular, specific action should be done when translated code is present. A consistent API must include something like cpu_page_lock() / unlock(). Look at cpu_physical_memory_rw() to see the various issues which must be handled. Moreover, it would be better to add bus specific APIs (at least for PCI), but I can accept a CPU memory API for now.
Fabrice.
Re: [Qemu-devel] [PATCH 2/2 v2][UPDATED] Direct IDE I/O
Quoted 15 lines · Fabrice Bellard
Quoted 12 lines · Laurent Vivier
This patch enhances the "-drive ,cache=off" mode with IDE drive emulation by removing the buffer used in the IDE emulation.
--- block.c | 10 +++ block.h | 2 block_int.h | 1 cpu-all.h | 1 exec.c | 19 ++++++ hw/ide.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- vl.c | 1 7 files changed, 204 insertions(+), 6 deletions(-)Quoted 1 line
[...]
Quoted 6 lines
Unfortunately it is more complicated to write to the CPU memory. In particular, specific action should be done when translated code is present. A consistent API must include something like
cpu_page_lock()/unlock(). Look atcpu_physical_memory_rw()to see the various issues which must be handled. Moreover, it would be better to add bus specific APIs (at least for PCI), but I can accept a CPU memory API for now.
In general it may also be unsafe to do async writes directly to guest memory because you break the atomicity of loads/stores.
Paul
Re: [Qemu-devel] [PATCH 2/2 v2][UPDATED] Direct IDE I/O
Quoted 23 lines · Paul Brook
Quoted 15 lines · Fabrice Bellard
Quoted 12 lines · Laurent Vivier
This patch enhances the "-drive ,cache=off" mode with IDE drive emulation by removing the buffer used in the IDE emulation.
--- block.c | 10 +++ block.h | 2 block_int.h | 1 cpu-all.h | 1 exec.c | 19 ++++++ hw/ide.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- vl.c | 1 7 files changed, 204 insertions(+), 6 deletions(-)Quoted 1 line
[...]
Quoted 6 lines
Unfortunately it is more complicated to write to the CPU memory. In particular, specific action should be done when translated code is present. A consistent API must include something like
cpu_page_lock()/unlock(). Look atcpu_physical_memory_rw()to see the various issues which must be handled. Moreover, it would be better to add bus specific APIs (at least for PCI), but I can accept a CPU memory API for now.
Quoted 2 lines
In general it may also be unsafe to do async writes directly to guest memory because you break the atomicity of loads/stores.
Thank you for your comments.
I had some doubts on this patch too. I will not resend it. I will resend only the first one corrected with comments from Fabrice (malloc()/free()).
Regards,
Laurent
Signature · 3 lines
----------------- [email protected] ------------------ "La perfection est atteinte non quand il ne reste rien à ajouter mais quand il ne reste rien à enlever." Saint Exupéry
Re: [Qemu-devel] [PATCH 2/2 v2][UPDATED] Direct IDE I/O
In reply to Paul BrookQuoted 11 lines · Paul Brook
Quoted 7 lines
Unfortunately it is more complicated to write to the CPU memory. In particular, specific action should be done when translated code is present. A consistent API must include something like
cpu_page_lock()/unlock(). Look atcpu_physical_memory_rw()to see the various issues which must be handled. Moreover, it would be better to add bus specific APIs (at least for PCI), but I can accept a CPU memory API for now.In general it may also be unsafe to do async writes directly to guest memory because you break the atomicity of loads/stores.
But that is true on real hardware as well, I think. The guest cannot expect atomicity if it dmas into the memory it is accessing.
Also, it would be a rare guest that accesses memory while dma is active.
Signature · 1 line
error compiling committee.c: too many arguments to function
Re: [Qemu-devel] [PATCH 1/2 v2][UPDATE] Add "cache" parameter to "-drive"
In reply to Laurent VivierQuoted 23 lines · Laurent Vivier
This patch adds a new parameter to "-drive"
Using "cache=off" with "-drive" will open the disk image file using "
O_DIRECT".By default, "cache" is set to "on" to keep original behavior of qemu.
example:
"-drive file=my_disk.qcow2,cache=off"
--- block-raw-posix.c | 8 ++++++++ block-raw-win32.c | 4 ++++ block.c | 2 +- block.h | 1 + hw/fdc.c | 7 ++++++- hw/ide.c | 18 ++++++++++++++---- hw/scsi-disk.c | 3 ++- hw/sd.c | 11 ++++++++++- osdep.c | 20 ++++++++++++++++++++ osdep.h | 1 + vl.c | 28 ++++++++++++++++++++++++---- 11 files changed, 91 insertions(+), 12 deletions(-)
Quoted 1 line
[...]
I suggest trying to remove the malloc/free which are done at every blk_read/write for sd.c.
Fabrice.