qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/2 v2][UPDATED] Open disk images with O_DIRECT
@ 2007-12-17 22:09 Laurent Vivier
  2007-12-17 22:09 ` [Qemu-devel] [PATCH 1/2 v2][UPDATE] Add "cache" parameter to "-drive" Laurent Vivier
  0 siblings, 1 reply; 8+ messages in thread
From: Laurent Vivier @ 2007-12-17 22:09 UTC (permalink / raw)
  Cc: qemu-devel


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

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 1/2 v2][UPDATE] Add "cache" parameter to "-drive"
  2007-12-17 22:09 [Qemu-devel] [PATCH 0/2 v2][UPDATED] Open disk images with O_DIRECT Laurent Vivier
@ 2007-12-17 22:09 ` Laurent Vivier
  2007-12-17 22:09   ` [Qemu-devel] [PATCH 2/2 v2][UPDATED] Direct IDE I/O Laurent Vivier
  2007-12-17 23:08   ` [Qemu-devel] [PATCH 1/2 v2][UPDATE] Add "cache" parameter to "-drive" Fabrice Bellard
  0 siblings, 2 replies; 8+ messages in thread
From: Laurent Vivier @ 2007-12-17 22:09 UTC (permalink / raw)
  Cc: qemu-devel


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(-)

Index: qemu/block.c
===================================================================
--- qemu.orig/block.c	2007-12-17 21:39:22.000000000 +0100
+++ qemu/block.c	2007-12-17 21:48:30.000000000 +0100
@@ -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);
Index: qemu/block.h
===================================================================
--- qemu.orig/block.h	2007-12-17 21:39:22.000000000 +0100
+++ qemu/block.h	2007-12-17 21:48:30.000000000 +0100
@@ -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);
Index: qemu/hw/fdc.c
===================================================================
--- qemu.orig/hw/fdc.c	2007-12-17 09:09:56.000000000 +0100
+++ qemu/hw/fdc.c	2007-12-17 21:48:30.000000000 +0100
@@ -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);
 
Index: qemu/hw/ide.c
===================================================================
--- qemu.orig/hw/ide.c	2007-12-17 21:38:11.000000000 +0100
+++ qemu/hw/ide.c	2007-12-17 21:48:30.000000000 +0100
@@ -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_stat
 
     for(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
Index: qemu/hw/scsi-disk.c
===================================================================
--- qemu.orig/hw/scsi-disk.c	2007-12-17 09:09:56.000000000 +0100
+++ qemu/hw/scsi-disk.c	2007-12-17 21:48:30.000000000 +0100
@@ -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;
Index: qemu/hw/sd.c
===================================================================
--- qemu.orig/hw/sd.c	2007-12-12 17:21:25.000000000 +0100
+++ qemu/hw/sd.c	2007-12-17 21:48:30.000000000 +0100
@@ -1284,10 +1284,17 @@ int sd_do_command(SDState *sd, struct sd
 static 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(BlockDriverState
 
         if (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,
Index: qemu/osdep.c
===================================================================
--- qemu.orig/osdep.c	2007-12-17 09:09:56.000000000 +0100
+++ qemu/osdep.c	2007-12-17 21:48:30.000000000 +0100
@@ -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)
 {
Index: qemu/osdep.h
===================================================================
--- qemu.orig/osdep.h	2007-12-17 09:09:56.000000000 +0100
+++ qemu/osdep.h	2007-12-17 21:48:30.000000000 +0100
@@ -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);
 
Index: qemu/vl.c
===================================================================
--- qemu.orig/vl.c	2007-12-17 09:09:56.000000000 +0100
+++ qemu/vl.c	2007-12-17 22:03:52.000000000 +0100
@@ -4880,8 +4880,11 @@ static int drive_init(const char *str, i
     BlockDriverState *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"
Index: qemu/block-raw-posix.c
===================================================================
--- qemu.orig/block-raw-posix.c	2007-12-17 21:50:32.000000000 +0100
+++ qemu/block-raw-posix.c	2007-12-17 21:52:41.000000000 +0100
@@ -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__)
Index: qemu/block-raw-win32.c
===================================================================
--- qemu.orig/block-raw-win32.c	2007-12-17 21:50:32.000000000 +0100
+++ qemu/block-raw-win32.c	2007-12-17 21:52:55.000000000 +0100
@@ -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);

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 2/2 v2][UPDATED] Direct IDE I/O
  2007-12-17 22:09 ` [Qemu-devel] [PATCH 1/2 v2][UPDATE] Add "cache" parameter to "-drive" Laurent Vivier
@ 2007-12-17 22:09   ` Laurent Vivier
  2007-12-17 23:02     ` Fabrice Bellard
  2007-12-17 23:08   ` [Qemu-devel] [PATCH 1/2 v2][UPDATE] Add "cache" parameter to "-drive" Fabrice Bellard
  1 sibling, 1 reply; 8+ messages in thread
From: Laurent Vivier @ 2007-12-17 22:09 UTC (permalink / raw)
  Cc: qemu-devel


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(-)

Index: qemu/block.c
===================================================================
--- qemu.orig/block.c	2007-12-17 21:48:30.000000000 +0100
+++ qemu/block.c	2007-12-17 22:21:23.000000000 +0100
@@ -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)
Index: qemu/block.h
===================================================================
--- qemu.orig/block.h	2007-12-17 21:48:30.000000000 +0100
+++ qemu/block.h	2007-12-17 22:21:23.000000000 +0100
@@ -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(BlockDrive
 int 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);
Index: qemu/block_int.h
===================================================================
--- qemu.orig/block_int.h	2007-12-17 21:39:22.000000000 +0100
+++ qemu/block_int.h	2007-12-17 22:21:23.000000000 +0100
@@ -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;
 };
Index: qemu/cpu-all.h
===================================================================
--- qemu.orig/cpu-all.h	2007-12-13 09:19:28.000000000 +0100
+++ qemu/cpu-all.h	2007-12-17 22:21:23.000000000 +0100
@@ -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,
Index: qemu/exec.c
===================================================================
--- qemu.orig/exec.c	2007-12-17 09:09:56.000000000 +0100
+++ qemu/exec.c	2007-12-17 22:21:23.000000000 +0100
@@ -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)
 {
Index: qemu/hw/ide.c
===================================================================
--- qemu.orig/hw/ide.c	2007-12-17 21:48:30.000000000 +0100
+++ qemu/hw/ide.c	2007-12-17 22:21:23.000000000 +0100
@@ -815,7 +815,7 @@ static int dma_buf_rw(BMDMAState *bm, in
 }
 
 /* XXX: handle errors */
-static void ide_read_dma_cb(void *opaque, int ret)
+static void ide_read_dma_cb_buffered(void *opaque, int ret)
 {
     BMDMAState *bm = opaque;
     IDEState *s = bm->ide_if;
@@ -855,7 +855,86 @@ static void ide_read_dma_cb(void *opaque
     printf("aio_read: sector_num=%lld n=%d\n", sector_num, n);
 #endif
     bm->aiocb = bdrv_aio_read(s->bs, sector_num, s->io_buffer, n,
-                              ide_read_dma_cb, bm);
+                              ide_read_dma_cb_buffered, bm);
+}
+
+static void ide_read_dma_cb_unbuffered(void *opaque, int ret)
+{
+    BMDMAState *bm = opaque;
+    IDEState *s = bm->ide_if;
+    int64_t sector_num;
+    int nsector;
+    int len;
+    uint8_t *phy_addr;
+
+    if (s->nsector == 0) {
+        s->status = READY_STAT | SEEK_STAT;
+       ide_set_irq(s);
+    eot:
+       bm->status &= ~BM_STATUS_DMAING;
+       bm->status |= BM_STATUS_INT;
+       bm->dma_cb = NULL;
+       bm->ide_if = NULL;
+       bm->aiocb = NULL;
+       return;
+    }
+
+    /* launch next transfer */
+
+    if (bm->cur_prd_len == 0) {
+        struct {
+            uint32_t addr;
+            uint32_t size;
+        } prd;
+
+        cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
+
+        bm->cur_addr += 8;
+        prd.addr = le32_to_cpu(prd.addr);
+        prd.size = le32_to_cpu(prd.size);
+        len = prd.size & 0xfffe;
+        if (len == 0)
+            len = 0x10000;
+        bm->cur_prd_addr = prd.addr;
+       while ((bm->cur_addr - bm->addr) < 4096) {
+           int tmp_len;
+           cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
+           prd.addr = le32_to_cpu(prd.addr);
+           prd.size = le32_to_cpu(prd.size);
+           if (bm->cur_prd_addr + len != prd.addr)
+               break;
+            tmp_len = prd.size & 0xfffe;
+            if (tmp_len == 0)
+                tmp_len = 0x10000;
+           len += tmp_len;
+            bm->cur_addr += 8;
+           if (prd.size & 0x80000000)
+               break;
+       }
+        bm->cur_prd_len = len;
+    }
+
+    phy_addr = cpu_physical_page_addr(bm->cur_prd_addr);
+    if (phy_addr == (uint8_t *)-1)
+       goto eot;
+
+    len = (s->nsector<<9);
+    if (len > bm->cur_prd_len)
+       len = bm->cur_prd_len;
+
+    nsector = (len>>9);
+    bm->cur_prd_addr += (nsector<<9);
+    bm->cur_prd_len -= (nsector<<9);
+
+    sector_num = ide_get_sector(s);
+    ide_set_sector(s, sector_num + nsector);
+    s->nsector-=nsector;
+
+#ifdef DEBUG_AIO
+    printf("aio_read: sector_num=%lld n=%d\n", (unsigned long long)sector_num, nsector);
+#endif
+    bm->aiocb = bdrv_aio_read(s->bs, sector_num, phy_addr, nsector,
+                             ide_read_dma_cb_unbuffered, bm);
 }
 
 static void ide_sector_read_dma(IDEState *s)
@@ -863,7 +942,10 @@ static void ide_sector_read_dma(IDEState
     s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
     s->io_buffer_index = 0;
     s->io_buffer_size = 0;
-    ide_dma_start(s, ide_read_dma_cb);
+    if (bdrv_is_cached(s->bs))
+        ide_dma_start(s, ide_read_dma_cb_buffered);
+    else
+        ide_dma_start(s, ide_read_dma_cb_unbuffered);
 }
 
 static void ide_sector_write_timer_cb(void *opaque)
@@ -916,7 +998,7 @@ static void ide_sector_write(IDEState *s
 }
 
 /* XXX: handle errors */
-static void ide_write_dma_cb(void *opaque, int ret)
+static void ide_write_dma_cb_buffered(void *opaque, int ret)
 {
     BMDMAState *bm = opaque;
     IDEState *s = bm->ide_if;
@@ -957,7 +1039,86 @@ static void ide_write_dma_cb(void *opaqu
     printf("aio_write: sector_num=%lld n=%d\n", sector_num, n);
 #endif
     bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n,
-                               ide_write_dma_cb, bm);
+                               ide_write_dma_cb_buffered, bm);
+}
+
+static void ide_write_dma_cb_unbuffered(void *opaque, int ret)
+{
+    BMDMAState *bm = opaque;
+    IDEState *s = bm->ide_if;
+    int64_t sector_num;
+    int nsector;
+    int len;
+    uint8_t *phy_addr;
+
+    if (s->nsector == 0) {
+        s->status = READY_STAT | SEEK_STAT;
+       ide_set_irq(s);
+    eot:
+       bm->status &= ~BM_STATUS_DMAING;
+       bm->status |= BM_STATUS_INT;
+       bm->dma_cb = NULL;
+       bm->ide_if = NULL;
+       bm->aiocb = NULL;
+       return;
+    }
+
+    /* launch next transfer */
+
+    if (bm->cur_prd_len == 0) {
+        struct {
+            uint32_t addr;
+            uint32_t size;
+        } prd;
+
+        cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
+
+        bm->cur_addr += 8;
+        prd.addr = le32_to_cpu(prd.addr);
+        prd.size = le32_to_cpu(prd.size);
+        len = prd.size & 0xfffe;
+        if (len == 0)
+            len = 0x10000;
+        bm->cur_prd_addr = prd.addr;
+       while ((bm->cur_addr - bm->addr) < 4096) {
+           int tmp_len;
+           cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
+           prd.addr = le32_to_cpu(prd.addr);
+           prd.size = le32_to_cpu(prd.size);
+           if (bm->cur_prd_addr + len != prd.addr)
+               break;
+            tmp_len = prd.size & 0xfffe;
+            if (tmp_len == 0)
+                tmp_len = 0x10000;
+           len += tmp_len;
+            bm->cur_addr += 8;
+           if (prd.size & 0x80000000)
+               break;
+       }
+        bm->cur_prd_len = len;
+    }
+
+    phy_addr = cpu_physical_page_addr(bm->cur_prd_addr);
+    if (phy_addr == (uint8_t *)-1)
+       goto eot;
+
+    len = (s->nsector<<9);
+    if (len > bm->cur_prd_len)
+       len = bm->cur_prd_len;
+
+    nsector = (len>>9);
+    bm->cur_prd_addr += (nsector<<9);
+    bm->cur_prd_len -= (nsector<<9);
+
+    sector_num = ide_get_sector(s);
+    ide_set_sector(s, sector_num + nsector);
+    s->nsector-=nsector;
+
+#ifdef DEBUG_AIO
+    printf("aio_write: sector_num=%lld n=%d\n", (unsigned long long)sector_num, nsector);
+#endif
+    bm->aiocb = bdrv_aio_write(s->bs, sector_num, phy_addr, nsector,
+                             ide_write_dma_cb_unbuffered, bm);
 }
 
 static void ide_sector_write_dma(IDEState *s)
@@ -965,7 +1126,10 @@ static void ide_sector_write_dma(IDEStat
     s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
     s->io_buffer_index = 0;
     s->io_buffer_size = 0;
-    ide_dma_start(s, ide_write_dma_cb);
+    if (bdrv_is_cached(s->bs))
+        ide_dma_start(s, ide_write_dma_cb_buffered);
+    else
+        ide_dma_start(s, ide_write_dma_cb_unbuffered);
 }
 
 static void ide_atapi_cmd_ok(IDEState *s)
Index: qemu/vl.c
===================================================================
--- qemu.orig/vl.c	2007-12-17 22:03:52.000000000 +0100
+++ qemu/vl.c	2007-12-17 22:21:23.000000000 +0100
@@ -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);

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH 2/2 v2][UPDATED] Direct IDE I/O
  2007-12-17 22:09   ` [Qemu-devel] [PATCH 2/2 v2][UPDATED] Direct IDE I/O Laurent Vivier
@ 2007-12-17 23:02     ` Fabrice Bellard
  2007-12-18  0:03       ` Paul Brook
  0 siblings, 1 reply; 8+ messages in thread
From: Fabrice Bellard @ 2007-12-17 23:02 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel

Laurent Vivier wrote:
> 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(-)
> [...]

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.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH 1/2 v2][UPDATE] Add "cache" parameter to "-drive"
  2007-12-17 22:09 ` [Qemu-devel] [PATCH 1/2 v2][UPDATE] Add "cache" parameter to "-drive" Laurent Vivier
  2007-12-17 22:09   ` [Qemu-devel] [PATCH 2/2 v2][UPDATED] Direct IDE I/O Laurent Vivier
@ 2007-12-17 23:08   ` Fabrice Bellard
  1 sibling, 0 replies; 8+ messages in thread
From: Fabrice Bellard @ 2007-12-17 23:08 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel

Laurent Vivier wrote:
> 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(-)
> [...]

I suggest trying to remove the malloc/free which are done at every
blk_read/write for sd.c.

Fabrice.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH 2/2 v2][UPDATED] Direct IDE I/O
  2007-12-17 23:02     ` Fabrice Bellard
@ 2007-12-18  0:03       ` Paul Brook
  2007-12-18  9:55         ` Laurent Vivier
  2007-12-18 16:38         ` Avi Kivity
  0 siblings, 2 replies; 8+ messages in thread
From: Paul Brook @ 2007-12-18  0:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: Laurent Vivier

On Monday 17 December 2007, Fabrice Bellard wrote:
> Laurent Vivier wrote:
> > 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(-)
> > [...]
>
> 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.

In general it may also be unsafe to do async writes directly to guest memory 
because you break the atomicity of loads/stores.

Paul

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH 2/2 v2][UPDATED] Direct IDE I/O
  2007-12-18  0:03       ` Paul Brook
@ 2007-12-18  9:55         ` Laurent Vivier
  2007-12-18 16:38         ` Avi Kivity
  1 sibling, 0 replies; 8+ messages in thread
From: Laurent Vivier @ 2007-12-18  9:55 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1623 bytes --]

Le mardi 18 décembre 2007 à 00:03 +0000, Paul Brook a écrit :
> On Monday 17 December 2007, Fabrice Bellard wrote:
> > Laurent Vivier wrote:
> > > 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(-)
> > > [...]
> >
> > 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.
> 
> 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
-- 
----------------- Laurent.Vivier@bull.net  ------------------
  "La perfection est atteinte non quand il ne reste rien à
ajouter mais quand il ne reste rien à enlever." Saint Exupéry

[-- Attachment #2: Ceci est une partie de message numériquement signée --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH 2/2 v2][UPDATED] Direct IDE I/O
  2007-12-18  0:03       ` Paul Brook
  2007-12-18  9:55         ` Laurent Vivier
@ 2007-12-18 16:38         ` Avi Kivity
  1 sibling, 0 replies; 8+ messages in thread
From: Avi Kivity @ 2007-12-18 16:38 UTC (permalink / raw)
  To: qemu-devel; +Cc: Laurent Vivier

Paul Brook wrote:
>> 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.
>>     
>
> 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.

-- 
error compiling committee.c: too many arguments to function

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2007-12-18 16:38 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-12-17 22:09 [Qemu-devel] [PATCH 0/2 v2][UPDATED] Open disk images with O_DIRECT Laurent Vivier
2007-12-17 22:09 ` [Qemu-devel] [PATCH 1/2 v2][UPDATE] Add "cache" parameter to "-drive" Laurent Vivier
2007-12-17 22:09   ` [Qemu-devel] [PATCH 2/2 v2][UPDATED] Direct IDE I/O Laurent Vivier
2007-12-17 23:02     ` Fabrice Bellard
2007-12-18  0:03       ` Paul Brook
2007-12-18  9:55         ` Laurent Vivier
2007-12-18 16:38         ` Avi Kivity
2007-12-17 23:08   ` [Qemu-devel] [PATCH 1/2 v2][UPDATE] Add "cache" parameter to "-drive" Fabrice Bellard

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).