All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL v2 00/65] Block patches
@ 2015-02-16 15:45 Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 01/65] nbd: Drop BDS backpointer Stefan Hajnoczi
                   ` (65 more replies)
  0 siblings, 66 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi

The following changes since commit cd2d5541271f1934345d8ca42f5fafff1744eee7:

  Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20150212' into staging (2015-02-13 11:44:50 +0000)

are available in the git repository at:

  git://github.com/stefanha/qemu.git tags/block-pull-request

for you to fetch changes up to b9c649470ba0d4056b2d486105a0f8fb982654ae:

  block: Keep bdrv_check*_request()'s return value (2015-02-16 15:07:19 +0000)

----------------------------------------------------------------
Pull request

v2:
 * Fix C11 typedef redefinitions in ahci and libqos malloc [Peter]
 * Fix lx -> PRIx64 format specifiers in ahci [Peter]

----------------------------------------------------------------

Bin Wu (1):
  nbd: fix the co_queue multi-adding bug

Cornelia Huck (1):
  dataplane: endianness-aware accesses

Fam Zheng (6):
  qtest: Fix deadloop by running main loop AIO context's timers
  qemu-io: Account IO by aio_read and aio_write
  qtest: Add scripts/qtest.py
  qemu-iotests: Add VM method qtest() to iotests.py
  qemu-iotests: Allow caller to disable underscore convertion for qmp
  qemu-iotests: Add 093 for IO throttling

Jeff Cody (1):
  block: vmdk - fixed sizeof() error

John Snow (34):
  libqos: Split apart pc_alloc_init
  qtest/ahci: Create ahci.h
  libqos: create libqos.c
  libqos: add qtest_vboot
  libqos: add alloc_init_flags
  libqos: Update QGuestAllocator to be opaque
  libqos: add pc specific interface
  qtest/ahci: Store hba_base in AHCIQState
  qtest/ahci: finalize AHCIQState consolidation
  qtest/ahci: remove pcibus global
  qtest/ahci: remove guest_malloc global
  libqos/ahci: Functional register helpers
  qtest/ahci: remove getter/setter macros
  qtest/ahci: Bookmark FB and CLB pointers
  libqos/ahci: create libqos/ahci.c
  libqos/ahci: Add ahci_port_select helper
  libqos/ahci: Add ahci_port_clear helper
  qtest/ahci: rename 'Command' to 'CommandHeader'
  libqos/ahci: Add command header helpers
  libqos/ahci: Add ahci_port_check_error helper
  libqos/ahci: Add ahci_port_check_interrupts helper
  libqos/ahci: Add port_check_nonbusy helper
  libqos/ahci: Add cmd response sanity check helpers
  qtest/ahci: Demagic ahci tests.
  qtest/ahci: add ahci_write_fis
  libqos/ahci: Add ide cmd properties
  libqos/ahci: add ahci command functions
  libqos/ahci: add ahci command verify
  libqos/ahci: add ahci command size setters
  libqos/ahci: Add ahci_guest_io
  libqos/ahci: add ahci_io
  libqos/ahci: Add ahci_clean_mem
  qtest/ahci: Assert sector size in identify test
  qtest/ahci: Adding simple dma read-write test

Kevin Wolf (1):
  savevm: Improve error message for blocked migration

Max Reitz (21):
  nbd: Drop BDS backpointer
  iotests: Add "wait" functionality to _cleanup_qemu
  iotests: Add test for drive-mirror with NBD target
  qemu-img: Fix qemu-img convert -n
  iotests: Add test for qemu-img convert to NBD
  block: Lift some BDS functions to the BlockBackend
  block: Add blk_new_open()
  block: Add Error parameter to bdrv_find_protocol()
  iotests: Add test for driver=qcow2, format=qcow2
  blockdev: Use blk_new_open() in blockdev_init()
  block/xen: Use blk_new_open() in blk_connect()
  qemu-img: Use blk_new_open() in img_open()
  qemu-img: Use blk_new_open() in img_rebase()
  qemu-img: Use BlockBackend as far as possible
  qemu-nbd: Use blk_new_open() in main()
  qemu-io: Use blk_new_open() in openfile()
  qemu-io: Remove "growable" option
  qemu-io: Use BlockBackend
  block: Clamp BlockBackend requests
  block: Remove "growable" from BDS
  block: Keep bdrv_check*_request()'s return value

 block.c                                       |   73 +-
 block/block-backend.c                         |  224 ++++++
 block/nbd-client.c                            |  126 +--
 block/nbd-client.h                            |   34 +-
 block/nbd.c                                   |   37 +-
 block/qcow2.c                                 |    6 -
 block/raw-posix.c                             |    2 +-
 block/raw-win32.c                             |    2 +-
 block/sheepdog.c                              |    4 +-
 block/vmdk.c                                  |    3 +-
 blockdev.c                                    |   92 +--
 cpus.c                                        |    4 +
 hmp.c                                         |    9 +-
 hw/block/dataplane/virtio-blk.c               |    4 +-
 hw/block/xen_disk.c                           |   27 +-
 hw/scsi/virtio-scsi-dataplane.c               |    2 +-
 hw/virtio/Makefile.objs                       |    2 +-
 hw/virtio/dataplane/Makefile.objs             |    2 +-
 hw/virtio/dataplane/vring.c                   |   53 +-
 include/block/block.h                         |    3 +-
 include/block/block_int.h                     |    3 -
 include/block/nbd.h                           |    1 -
 include/hw/virtio/dataplane/vring-accessors.h |   75 ++
 include/hw/virtio/dataplane/vring.h           |   14 +-
 include/qemu-io.h                             |    4 +-
 include/sysemu/block-backend.h                |   13 +
 nbd.c                                         |    8 +-
 qemu-img.c                                    |  208 +++--
 qemu-io-cmds.c                                |  250 +++---
 qemu-io.c                                     |   58 +-
 qemu-nbd.c                                    |   25 +-
 savevm.c                                      |   11 +-
 scripts/qtest.py                              |   71 ++
 tests/Makefile                                |    5 +-
 tests/ahci-test.c                             | 1072 +++++--------------------
 tests/libqos/ahci.c                           |  838 +++++++++++++++++++
 tests/libqos/ahci.h                           |  549 +++++++++++++
 tests/libqos/libqos-pc.c                      |   24 +
 tests/libqos/libqos-pc.h                      |    9 +
 tests/libqos/libqos.c                         |   63 ++
 tests/libqos/libqos.h                         |   33 +
 tests/libqos/malloc-pc.c                      |   20 +-
 tests/libqos/malloc.c                         |   91 ++-
 tests/libqos/malloc.h                         |   26 +-
 tests/qemu-iotests/016                        |   73 --
 tests/qemu-iotests/016.out                    |   23 -
 tests/qemu-iotests/051                        |    1 +
 tests/qemu-iotests/051.out                    |   63 +-
 tests/qemu-iotests/087.out                    |    8 +-
 tests/qemu-iotests/093                        |  114 +++
 tests/qemu-iotests/093.out                    |    5 +
 tests/qemu-iotests/094                        |   81 ++
 tests/qemu-iotests/094.out                    |   11 +
 tests/qemu-iotests/123                        |   62 ++
 tests/qemu-iotests/123.out                    |    9 +
 tests/qemu-iotests/common.qemu                |   12 +-
 tests/qemu-iotests/group                      |    5 +-
 tests/qemu-iotests/iotests.py                 |   23 +-
 58 files changed, 3076 insertions(+), 1594 deletions(-)
 create mode 100644 include/hw/virtio/dataplane/vring-accessors.h
 create mode 100644 scripts/qtest.py
 create mode 100644 tests/libqos/ahci.c
 create mode 100644 tests/libqos/ahci.h
 create mode 100644 tests/libqos/libqos-pc.c
 create mode 100644 tests/libqos/libqos-pc.h
 create mode 100644 tests/libqos/libqos.c
 create mode 100644 tests/libqos/libqos.h
 delete mode 100755 tests/qemu-iotests/016
 delete mode 100644 tests/qemu-iotests/016.out
 create mode 100755 tests/qemu-iotests/093
 create mode 100644 tests/qemu-iotests/093.out
 create mode 100755 tests/qemu-iotests/094
 create mode 100644 tests/qemu-iotests/094.out
 create mode 100755 tests/qemu-iotests/123
 create mode 100644 tests/qemu-iotests/123.out

-- 
2.1.0

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

* [Qemu-devel] [PULL v2 01/65] nbd: Drop BDS backpointer
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 02/65] iotests: Add "wait" functionality to _cleanup_qemu Stefan Hajnoczi
                   ` (64 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

Before this patch, the "opaque" pointer in an NBD BDS points to a
BDRVNBDState, which contains an NbdClientSession object, which in turn
contains a pointer to the BDS. This pointer may become invalid due to
bdrv_swap(), so drop it, and instead pass the BDS directly to the
nbd-client.c functions which then retrieve the NbdClientSession object
from there.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1423256778-3340-2-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/nbd-client.c  | 101 +++++++++++++++++++++++++++-------------------------
 block/nbd-client.h  |  34 +++++++++---------
 block/nbd.c         |  37 ++++++++-----------
 include/block/nbd.h |   1 -
 nbd.c               |   8 ++---
 5 files changed, 87 insertions(+), 94 deletions(-)

diff --git a/block/nbd-client.c b/block/nbd-client.c
index 28bfb62..a01a37f 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -43,20 +43,23 @@ static void nbd_recv_coroutines_enter_all(NbdClientSession *s)
     }
 }
 
-static void nbd_teardown_connection(NbdClientSession *client)
+static void nbd_teardown_connection(BlockDriverState *bs)
 {
+    NbdClientSession *client = nbd_get_client_session(bs);
+
     /* finish any pending coroutines */
     shutdown(client->sock, 2);
     nbd_recv_coroutines_enter_all(client);
 
-    nbd_client_session_detach_aio_context(client);
+    nbd_client_detach_aio_context(bs);
     closesocket(client->sock);
     client->sock = -1;
 }
 
 static void nbd_reply_ready(void *opaque)
 {
-    NbdClientSession *s = opaque;
+    BlockDriverState *bs = opaque;
+    NbdClientSession *s = nbd_get_client_session(bs);
     uint64_t i;
     int ret;
 
@@ -89,28 +92,29 @@ static void nbd_reply_ready(void *opaque)
     }
 
 fail:
-    nbd_teardown_connection(s);
+    nbd_teardown_connection(bs);
 }
 
 static void nbd_restart_write(void *opaque)
 {
-    NbdClientSession *s = opaque;
+    BlockDriverState *bs = opaque;
 
-    qemu_coroutine_enter(s->send_coroutine, NULL);
+    qemu_coroutine_enter(nbd_get_client_session(bs)->send_coroutine, NULL);
 }
 
-static int nbd_co_send_request(NbdClientSession *s,
-    struct nbd_request *request,
-    QEMUIOVector *qiov, int offset)
+static int nbd_co_send_request(BlockDriverState *bs,
+                               struct nbd_request *request,
+                               QEMUIOVector *qiov, int offset)
 {
+    NbdClientSession *s = nbd_get_client_session(bs);
     AioContext *aio_context;
     int rc, ret;
 
     qemu_co_mutex_lock(&s->send_mutex);
     s->send_coroutine = qemu_coroutine_self();
-    aio_context = bdrv_get_aio_context(s->bs);
+    aio_context = bdrv_get_aio_context(bs);
     aio_set_fd_handler(aio_context, s->sock,
-                       nbd_reply_ready, nbd_restart_write, s);
+                       nbd_reply_ready, nbd_restart_write, bs);
     if (qiov) {
         if (!s->is_unix) {
             socket_set_cork(s->sock, 1);
@@ -129,7 +133,7 @@ static int nbd_co_send_request(NbdClientSession *s,
     } else {
         rc = nbd_send_request(s->sock, request);
     }
-    aio_set_fd_handler(aio_context, s->sock, nbd_reply_ready, NULL, s);
+    aio_set_fd_handler(aio_context, s->sock, nbd_reply_ready, NULL, bs);
     s->send_coroutine = NULL;
     qemu_co_mutex_unlock(&s->send_mutex);
     return rc;
@@ -195,10 +199,11 @@ static void nbd_coroutine_end(NbdClientSession *s,
     }
 }
 
-static int nbd_co_readv_1(NbdClientSession *client, int64_t sector_num,
+static int nbd_co_readv_1(BlockDriverState *bs, int64_t sector_num,
                           int nb_sectors, QEMUIOVector *qiov,
                           int offset)
 {
+    NbdClientSession *client = nbd_get_client_session(bs);
     struct nbd_request request = { .type = NBD_CMD_READ };
     struct nbd_reply reply;
     ssize_t ret;
@@ -207,7 +212,7 @@ static int nbd_co_readv_1(NbdClientSession *client, int64_t sector_num,
     request.len = nb_sectors * 512;
 
     nbd_coroutine_start(client, &request);
-    ret = nbd_co_send_request(client, &request, NULL, 0);
+    ret = nbd_co_send_request(bs, &request, NULL, 0);
     if (ret < 0) {
         reply.error = -ret;
     } else {
@@ -218,15 +223,16 @@ static int nbd_co_readv_1(NbdClientSession *client, int64_t sector_num,
 
 }
 
-static int nbd_co_writev_1(NbdClientSession *client, int64_t sector_num,
+static int nbd_co_writev_1(BlockDriverState *bs, int64_t sector_num,
                            int nb_sectors, QEMUIOVector *qiov,
                            int offset)
 {
+    NbdClientSession *client = nbd_get_client_session(bs);
     struct nbd_request request = { .type = NBD_CMD_WRITE };
     struct nbd_reply reply;
     ssize_t ret;
 
-    if (!bdrv_enable_write_cache(client->bs) &&
+    if (!bdrv_enable_write_cache(bs) &&
         (client->nbdflags & NBD_FLAG_SEND_FUA)) {
         request.type |= NBD_CMD_FLAG_FUA;
     }
@@ -235,7 +241,7 @@ static int nbd_co_writev_1(NbdClientSession *client, int64_t sector_num,
     request.len = nb_sectors * 512;
 
     nbd_coroutine_start(client, &request);
-    ret = nbd_co_send_request(client, &request, qiov, offset);
+    ret = nbd_co_send_request(bs, &request, qiov, offset);
     if (ret < 0) {
         reply.error = -ret;
     } else {
@@ -249,14 +255,13 @@ static int nbd_co_writev_1(NbdClientSession *client, int64_t sector_num,
  * remain aligned to 4K. */
 #define NBD_MAX_SECTORS 2040
 
-int nbd_client_session_co_readv(NbdClientSession *client, int64_t sector_num,
-    int nb_sectors, QEMUIOVector *qiov)
+int nbd_client_co_readv(BlockDriverState *bs, int64_t sector_num,
+                        int nb_sectors, QEMUIOVector *qiov)
 {
     int offset = 0;
     int ret;
     while (nb_sectors > NBD_MAX_SECTORS) {
-        ret = nbd_co_readv_1(client, sector_num,
-                             NBD_MAX_SECTORS, qiov, offset);
+        ret = nbd_co_readv_1(bs, sector_num, NBD_MAX_SECTORS, qiov, offset);
         if (ret < 0) {
             return ret;
         }
@@ -264,17 +269,16 @@ int nbd_client_session_co_readv(NbdClientSession *client, int64_t sector_num,
         sector_num += NBD_MAX_SECTORS;
         nb_sectors -= NBD_MAX_SECTORS;
     }
-    return nbd_co_readv_1(client, sector_num, nb_sectors, qiov, offset);
+    return nbd_co_readv_1(bs, sector_num, nb_sectors, qiov, offset);
 }
 
-int nbd_client_session_co_writev(NbdClientSession *client, int64_t sector_num,
-                                 int nb_sectors, QEMUIOVector *qiov)
+int nbd_client_co_writev(BlockDriverState *bs, int64_t sector_num,
+                         int nb_sectors, QEMUIOVector *qiov)
 {
     int offset = 0;
     int ret;
     while (nb_sectors > NBD_MAX_SECTORS) {
-        ret = nbd_co_writev_1(client, sector_num,
-                              NBD_MAX_SECTORS, qiov, offset);
+        ret = nbd_co_writev_1(bs, sector_num, NBD_MAX_SECTORS, qiov, offset);
         if (ret < 0) {
             return ret;
         }
@@ -282,11 +286,12 @@ int nbd_client_session_co_writev(NbdClientSession *client, int64_t sector_num,
         sector_num += NBD_MAX_SECTORS;
         nb_sectors -= NBD_MAX_SECTORS;
     }
-    return nbd_co_writev_1(client, sector_num, nb_sectors, qiov, offset);
+    return nbd_co_writev_1(bs, sector_num, nb_sectors, qiov, offset);
 }
 
-int nbd_client_session_co_flush(NbdClientSession *client)
+int nbd_client_co_flush(BlockDriverState *bs)
 {
+    NbdClientSession *client = nbd_get_client_session(bs);
     struct nbd_request request = { .type = NBD_CMD_FLUSH };
     struct nbd_reply reply;
     ssize_t ret;
@@ -303,7 +308,7 @@ int nbd_client_session_co_flush(NbdClientSession *client)
     request.len = 0;
 
     nbd_coroutine_start(client, &request);
-    ret = nbd_co_send_request(client, &request, NULL, 0);
+    ret = nbd_co_send_request(bs, &request, NULL, 0);
     if (ret < 0) {
         reply.error = -ret;
     } else {
@@ -313,9 +318,10 @@ int nbd_client_session_co_flush(NbdClientSession *client)
     return -reply.error;
 }
 
-int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num,
-    int nb_sectors)
+int nbd_client_co_discard(BlockDriverState *bs, int64_t sector_num,
+                          int nb_sectors)
 {
+    NbdClientSession *client = nbd_get_client_session(bs);
     struct nbd_request request = { .type = NBD_CMD_TRIM };
     struct nbd_reply reply;
     ssize_t ret;
@@ -327,7 +333,7 @@ int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num,
     request.len = nb_sectors * 512;
 
     nbd_coroutine_start(client, &request);
-    ret = nbd_co_send_request(client, &request, NULL, 0);
+    ret = nbd_co_send_request(bs, &request, NULL, 0);
     if (ret < 0) {
         reply.error = -ret;
     } else {
@@ -338,43 +344,41 @@ int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num,
 
 }
 
-void nbd_client_session_detach_aio_context(NbdClientSession *client)
+void nbd_client_detach_aio_context(BlockDriverState *bs)
 {
-    aio_set_fd_handler(bdrv_get_aio_context(client->bs), client->sock,
-                       NULL, NULL, NULL);
+    aio_set_fd_handler(bdrv_get_aio_context(bs),
+                       nbd_get_client_session(bs)->sock, NULL, NULL, NULL);
 }
 
-void nbd_client_session_attach_aio_context(NbdClientSession *client,
-                                           AioContext *new_context)
+void nbd_client_attach_aio_context(BlockDriverState *bs,
+                                   AioContext *new_context)
 {
-    aio_set_fd_handler(new_context, client->sock,
-                       nbd_reply_ready, NULL, client);
+    aio_set_fd_handler(new_context, nbd_get_client_session(bs)->sock,
+                       nbd_reply_ready, NULL, bs);
 }
 
-void nbd_client_session_close(NbdClientSession *client)
+void nbd_client_close(BlockDriverState *bs)
 {
+    NbdClientSession *client = nbd_get_client_session(bs);
     struct nbd_request request = {
         .type = NBD_CMD_DISC,
         .from = 0,
         .len = 0
     };
 
-    if (!client->bs) {
-        return;
-    }
     if (client->sock == -1) {
         return;
     }
 
     nbd_send_request(client->sock, &request);
 
-    nbd_teardown_connection(client);
-    client->bs = NULL;
+    nbd_teardown_connection(bs);
 }
 
-int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs,
-                            int sock, const char *export, Error **errp)
+int nbd_client_init(BlockDriverState *bs, int sock, const char *export,
+                    Error **errp)
 {
+    NbdClientSession *client = nbd_get_client_session(bs);
     int ret;
 
     /* NBD handshake */
@@ -391,13 +395,12 @@ int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs,
 
     qemu_co_mutex_init(&client->send_mutex);
     qemu_co_mutex_init(&client->free_sema);
-    client->bs = bs;
     client->sock = sock;
 
     /* Now that we're connected, set the socket to be non-blocking and
      * kick the reply mechanism.  */
     qemu_set_nonblock(sock);
-    nbd_client_session_attach_aio_context(client, bdrv_get_aio_context(bs));
+    nbd_client_attach_aio_context(bs, bdrv_get_aio_context(bs));
 
     logout("Established connection with NBD server\n");
     return 0;
diff --git a/block/nbd-client.h b/block/nbd-client.h
index cfeecc2..fa4ff42 100644
--- a/block/nbd-client.h
+++ b/block/nbd-client.h
@@ -31,24 +31,24 @@ typedef struct NbdClientSession {
     struct nbd_reply reply;
 
     bool is_unix;
-
-    BlockDriverState *bs;
 } NbdClientSession;
 
-int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs,
-                            int sock, const char *export_name, Error **errp);
-void nbd_client_session_close(NbdClientSession *client);
-
-int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num,
-                                  int nb_sectors);
-int nbd_client_session_co_flush(NbdClientSession *client);
-int nbd_client_session_co_writev(NbdClientSession *client, int64_t sector_num,
-                                 int nb_sectors, QEMUIOVector *qiov);
-int nbd_client_session_co_readv(NbdClientSession *client, int64_t sector_num,
-                                int nb_sectors, QEMUIOVector *qiov);
-
-void nbd_client_session_detach_aio_context(NbdClientSession *client);
-void nbd_client_session_attach_aio_context(NbdClientSession *client,
-                                           AioContext *new_context);
+NbdClientSession *nbd_get_client_session(BlockDriverState *bs);
+
+int nbd_client_init(BlockDriverState *bs, int sock, const char *export_name,
+                    Error **errp);
+void nbd_client_close(BlockDriverState *bs);
+
+int nbd_client_co_discard(BlockDriverState *bs, int64_t sector_num,
+                          int nb_sectors);
+int nbd_client_co_flush(BlockDriverState *bs);
+int nbd_client_co_writev(BlockDriverState *bs, int64_t sector_num,
+                         int nb_sectors, QEMUIOVector *qiov);
+int nbd_client_co_readv(BlockDriverState *bs, int64_t sector_num,
+                        int nb_sectors, QEMUIOVector *qiov);
+
+void nbd_client_detach_aio_context(BlockDriverState *bs);
+void nbd_client_attach_aio_context(BlockDriverState *bs,
+                                   AioContext *new_context);
 
 #endif /* NBD_CLIENT_H */
diff --git a/block/nbd.c b/block/nbd.c
index b05d1d0..2f3b9ad 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -224,6 +224,12 @@ static void nbd_config(BDRVNBDState *s, QDict *options, char **export,
     }
 }
 
+NbdClientSession *nbd_get_client_session(BlockDriverState *bs)
+{
+    BDRVNBDState *s = bs->opaque;
+    return &s->client;
+}
+
 static int nbd_establish_connection(BlockDriverState *bs, Error **errp)
 {
     BDRVNBDState *s = bs->opaque;
@@ -271,7 +277,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
     }
 
     /* NBD handshake */
-    result = nbd_client_session_init(&s->client, bs, sock, export, errp);
+    result = nbd_client_init(bs, sock, export, errp);
     g_free(export);
     return result;
 }
@@ -279,26 +285,18 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
 static int nbd_co_readv(BlockDriverState *bs, int64_t sector_num,
                         int nb_sectors, QEMUIOVector *qiov)
 {
-    BDRVNBDState *s = bs->opaque;
-
-    return nbd_client_session_co_readv(&s->client, sector_num,
-                                       nb_sectors, qiov);
+    return nbd_client_co_readv(bs, sector_num, nb_sectors, qiov);
 }
 
 static int nbd_co_writev(BlockDriverState *bs, int64_t sector_num,
                          int nb_sectors, QEMUIOVector *qiov)
 {
-    BDRVNBDState *s = bs->opaque;
-
-    return nbd_client_session_co_writev(&s->client, sector_num,
-                                        nb_sectors, qiov);
+    return nbd_client_co_writev(bs, sector_num, nb_sectors, qiov);
 }
 
 static int nbd_co_flush(BlockDriverState *bs)
 {
-    BDRVNBDState *s = bs->opaque;
-
-    return nbd_client_session_co_flush(&s->client);
+    return nbd_client_co_flush(bs);
 }
 
 static void nbd_refresh_limits(BlockDriverState *bs, Error **errp)
@@ -310,10 +308,7 @@ static void nbd_refresh_limits(BlockDriverState *bs, Error **errp)
 static int nbd_co_discard(BlockDriverState *bs, int64_t sector_num,
                           int nb_sectors)
 {
-    BDRVNBDState *s = bs->opaque;
-
-    return nbd_client_session_co_discard(&s->client, sector_num,
-                                         nb_sectors);
+    return nbd_client_co_discard(bs, sector_num, nb_sectors);
 }
 
 static void nbd_close(BlockDriverState *bs)
@@ -321,7 +316,7 @@ static void nbd_close(BlockDriverState *bs)
     BDRVNBDState *s = bs->opaque;
 
     qemu_opts_del(s->socket_opts);
-    nbd_client_session_close(&s->client);
+    nbd_client_close(bs);
 }
 
 static int64_t nbd_getlength(BlockDriverState *bs)
@@ -333,17 +328,13 @@ static int64_t nbd_getlength(BlockDriverState *bs)
 
 static void nbd_detach_aio_context(BlockDriverState *bs)
 {
-    BDRVNBDState *s = bs->opaque;
-
-    nbd_client_session_detach_aio_context(&s->client);
+    nbd_client_detach_aio_context(bs);
 }
 
 static void nbd_attach_aio_context(BlockDriverState *bs,
                                    AioContext *new_context)
 {
-    BDRVNBDState *s = bs->opaque;
-
-    nbd_client_session_attach_aio_context(&s->client, new_context);
+    nbd_client_attach_aio_context(bs, new_context);
 }
 
 static void nbd_refresh_filename(BlockDriverState *bs)
diff --git a/include/block/nbd.h b/include/block/nbd.h
index b759595..ca9a5ac 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -99,7 +99,6 @@ void nbd_export_close_all(void);
 
 NBDClient *nbd_client_new(NBDExport *exp, int csock,
                           void (*close)(NBDClient *));
-void nbd_client_close(NBDClient *client);
 void nbd_client_get(NBDClient *client);
 void nbd_client_put(NBDClient *client);
 
diff --git a/nbd.c b/nbd.c
index e56afbc1..71159af 100644
--- a/nbd.c
+++ b/nbd.c
@@ -874,7 +874,7 @@ void nbd_client_put(NBDClient *client)
 {
     if (--client->refcount == 0) {
         /* The last reference should be dropped by client->close,
-         * which is called by nbd_client_close.
+         * which is called by client_close.
          */
         assert(client->closing);
 
@@ -889,7 +889,7 @@ void nbd_client_put(NBDClient *client)
     }
 }
 
-void nbd_client_close(NBDClient *client)
+static void client_close(NBDClient *client)
 {
     if (client->closing) {
         return;
@@ -1026,7 +1026,7 @@ void nbd_export_close(NBDExport *exp)
 
     nbd_export_get(exp);
     QTAILQ_FOREACH_SAFE(client, &exp->clients, next, next) {
-        nbd_client_close(client);
+        client_close(client);
     }
     nbd_export_set_name(exp, NULL);
     nbd_export_put(exp);
@@ -1311,7 +1311,7 @@ done:
 
 out:
     nbd_request_put(req);
-    nbd_client_close(client);
+    client_close(client);
 }
 
 static void nbd_read(void *opaque)
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 02/65] iotests: Add "wait" functionality to _cleanup_qemu
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 01/65] nbd: Drop BDS backpointer Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 03/65] iotests: Add test for drive-mirror with NBD target Stefan Hajnoczi
                   ` (63 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

The qemu process does not always need to be killed, just waiting for it
can be fine, too. This introduces a way to do so.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1423256778-3340-3-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/qemu-iotests/common.qemu | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu
index 8e618b5..4e1996c 100644
--- a/tests/qemu-iotests/common.qemu
+++ b/tests/qemu-iotests/common.qemu
@@ -187,13 +187,23 @@ function _launch_qemu()
 
 
 # Silenty kills the QEMU process
+#
+# If $wait is set to anything other than the empty string, the process will not
+# be killed but only waited for, and any output will be forwarded to stdout. If
+# $wait is empty, the process will be killed and all output will be suppressed.
 function _cleanup_qemu()
 {
     # QEMU_PID[], QEMU_IN[], QEMU_OUT[] all use same indices
     for i in "${!QEMU_OUT[@]}"
     do
-        kill -KILL ${QEMU_PID[$i]} 2>/dev/null
+        if [ -z "${wait}" ]; then
+            kill -KILL ${QEMU_PID[$i]} 2>/dev/null
+        fi
         wait ${QEMU_PID[$i]} 2>/dev/null # silent kill
+        if [ -n "${wait}" ]; then
+            cat <&${QEMU_OUT[$i]} | _filter_testdir | _filter_qemu \
+                                  | _filter_qemu_io | _filter_qmp
+        fi
         rm -f "${QEMU_FIFO_IN}_${i}" "${QEMU_FIFO_OUT}_${i}"
         eval "exec ${QEMU_IN[$i]}<&-"   # close file descriptors
         eval "exec ${QEMU_OUT[$i]}<&-"
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 03/65] iotests: Add test for drive-mirror with NBD target
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 01/65] nbd: Drop BDS backpointer Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 02/65] iotests: Add "wait" functionality to _cleanup_qemu Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 04/65] libqos: Split apart pc_alloc_init Stefan Hajnoczi
                   ` (62 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

When the drive-mirror block job is completed, it will call bdrv_swap()
on the source and the target BDS; this should obviously not result in a
segmentation fault.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1423256778-3340-4-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/qemu-iotests/094     | 81 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/094.out | 11 +++++++
 tests/qemu-iotests/group   |  1 +
 3 files changed, 93 insertions(+)
 create mode 100755 tests/qemu-iotests/094
 create mode 100644 tests/qemu-iotests/094.out

diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094
new file mode 100755
index 0000000..27a2be2
--- /dev/null
+++ b/tests/qemu-iotests/094
@@ -0,0 +1,81 @@
+#!/bin/bash
+#
+# Test case for drive-mirror to NBD (especially bdrv_swap() on NBD BDS)
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=mreitz@redhat.com
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+here="$PWD"
+tmp=/tmp/$$
+status=1	# failure is the default!
+
+trap "exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.qemu
+
+_supported_fmt generic
+_supported_proto nbd
+_supported_os Linux
+_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
+
+_make_test_img 64M
+$QEMU_IMG create -f $IMGFMT "$TEST_DIR/source.$IMGFMT" 64M | _filter_img_create
+
+_launch_qemu -drive if=none,id=src,file="$TEST_DIR/source.$IMGFMT",format=raw \
+             -nodefaults
+
+_send_qemu_cmd $QEMU_HANDLE \
+    "{'execute': 'qmp_capabilities'}" \
+    'return'
+
+# 'format': 'nbd' is not actually "correct", but this is probably the only way
+# to test bdrv_swap() on an NBD BDS
+_send_qemu_cmd $QEMU_HANDLE  \
+    "{'execute': 'drive-mirror',
+      'arguments': {'device': 'src',
+                    'target': '$TEST_IMG',
+                    'format': 'nbd',
+                    'sync':'full',
+                    'mode':'existing'}}" \
+    'BLOCK_JOB_READY'
+
+_send_qemu_cmd $QEMU_HANDLE  \
+    "{'execute': 'block-job-complete',
+      'arguments': {'device': 'src'}}" \
+    'BLOCK_JOB_COMPLETE'
+
+_send_qemu_cmd $QEMU_HANDLE \
+    "{'execute': 'quit'}" \
+    'return'
+
+wait=1 _cleanup_qemu
+
+_cleanup_test_img
+rm -f "$TEST_DIR/source.$IMGFMT"
+
+# success, all done
+echo '*** done'
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/094.out b/tests/qemu-iotests/094.out
new file mode 100644
index 0000000..b66dc07
--- /dev/null
+++ b/tests/qemu-iotests/094.out
@@ -0,0 +1,11 @@
+QA output created by 094
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/source.IMGFMT', fmt=IMGFMT size=67108864
+{"return": {}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 4b2b93b..6e2447a 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -99,6 +99,7 @@
 090 rw auto quick
 091 rw auto
 092 rw auto quick
+094 rw auto quick
 095 rw auto quick
 097 rw auto backing
 098 rw auto backing quick
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 04/65] libqos: Split apart pc_alloc_init
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (2 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 03/65] iotests: Add test for drive-mirror with NBD target Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 05/65] qtest/ahci: Create ahci.h Stefan Hajnoczi
                   ` (61 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Move the list-specific initialization over into
malloc.c, to keep all of the list implementation
details within the same file.

The allocation and freeing of these structures are
now both back within the same layer.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1421698563-6977-2-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/libqos/malloc-pc.c | 20 ++++----------------
 tests/libqos/malloc.c    | 17 +++++++++++++++++
 tests/libqos/malloc.h    |  1 +
 3 files changed, 22 insertions(+), 16 deletions(-)

diff --git a/tests/libqos/malloc-pc.c b/tests/libqos/malloc-pc.c
index c9c48fd..36a0740 100644
--- a/tests/libqos/malloc-pc.c
+++ b/tests/libqos/malloc-pc.c
@@ -32,31 +32,19 @@ void pc_alloc_uninit(QGuestAllocator *allocator)
 
 QGuestAllocator *pc_alloc_init_flags(QAllocOpts flags)
 {
-    QGuestAllocator *s = g_malloc0(sizeof(*s));
+    QGuestAllocator *s;
     uint64_t ram_size;
     QFWCFG *fw_cfg = pc_fw_cfg_init();
-    MemBlock *node;
-
-    s->opts = flags;
-    s->page_size = PAGE_SIZE;
 
     ram_size = qfw_cfg_get_u64(fw_cfg, FW_CFG_RAM_SIZE);
+    s = alloc_init(1 << 20, MIN(ram_size, 0xE0000000));
 
-    /* Start at 1MB */
-    s->start = 1 << 20;
-
-    /* Respect PCI hole */
-    s->end = MIN(ram_size, 0xE0000000);
+    s->opts = flags;
+    s->page_size = PAGE_SIZE;
 
     /* clean-up */
     g_free(fw_cfg);
 
-    QTAILQ_INIT(&s->used);
-    QTAILQ_INIT(&s->free);
-
-    node = mlist_new(s->start, s->end - s->start);
-    QTAILQ_INSERT_HEAD(&s->free, node, MLIST_ENTNAME);
-
     return s;
 }
 
diff --git a/tests/libqos/malloc.c b/tests/libqos/malloc.c
index 5debf18..0d34ecd 100644
--- a/tests/libqos/malloc.c
+++ b/tests/libqos/malloc.c
@@ -268,3 +268,20 @@ void guest_free(QGuestAllocator *allocator, uint64_t addr)
         mlist_check(allocator);
     }
 }
+
+QGuestAllocator *alloc_init(uint64_t start, uint64_t end)
+{
+    QGuestAllocator *s = g_malloc0(sizeof(*s));
+    MemBlock *node;
+
+    s->start = start;
+    s->end = end;
+
+    QTAILQ_INIT(&s->used);
+    QTAILQ_INIT(&s->free);
+
+    node = mlist_new(s->start, s->end - s->start);
+    QTAILQ_INSERT_HEAD(&s->free, node, MLIST_ENTNAME);
+
+    return s;
+}
diff --git a/tests/libqos/malloc.h b/tests/libqos/malloc.h
index 465efeb..677db77 100644
--- a/tests/libqos/malloc.h
+++ b/tests/libqos/malloc.h
@@ -50,4 +50,5 @@ void alloc_uninit(QGuestAllocator *allocator);
 uint64_t guest_alloc(QGuestAllocator *allocator, size_t size);
 void guest_free(QGuestAllocator *allocator, uint64_t addr);
 
+QGuestAllocator *alloc_init(uint64_t start, uint64_t end);
 #endif
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 05/65] qtest/ahci: Create ahci.h
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (3 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 04/65] libqos: Split apart pc_alloc_init Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 06/65] libqos: create libqos.c Stefan Hajnoczi
                   ` (60 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Extract defines and other information to ahci.h, to be shared with other
tests if they so please.

At the very least, reduce clutter in the test file itself.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1421698563-6977-3-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   | 319 +----------------------------------------------
 tests/libqos/ahci.h | 352 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 353 insertions(+), 318 deletions(-)
 create mode 100644 tests/libqos/ahci.h

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index b1a59f2..5c9da12 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -29,6 +29,7 @@
 #include <glib.h>
 
 #include "libqtest.h"
+#include "libqos/ahci.h"
 #include "libqos/pci-pc.h"
 #include "libqos/malloc-pc.h"
 
@@ -41,313 +42,6 @@
 /* Test-specific defines. */
 #define TEST_IMAGE_SIZE    (64 * 1024 * 1024)
 
-/*** Supplementary PCI Config Space IDs & Masks ***/
-#define PCI_DEVICE_ID_INTEL_Q35_AHCI   (0x2922)
-#define PCI_MSI_FLAGS_RESERVED         (0xFF00)
-#define PCI_PM_CTRL_RESERVED             (0xFC)
-#define PCI_BCC(REG32)          ((REG32) >> 24)
-#define PCI_PI(REG32)   (((REG32) >> 8) & 0xFF)
-#define PCI_SCC(REG32) (((REG32) >> 16) & 0xFF)
-
-/*** Recognized AHCI Device Types ***/
-#define AHCI_INTEL_ICH9 (PCI_DEVICE_ID_INTEL_Q35_AHCI << 16 | \
-                         PCI_VENDOR_ID_INTEL)
-
-/*** AHCI/HBA Register Offsets and Bitmasks ***/
-#define AHCI_CAP                          (0)
-#define AHCI_CAP_NP                    (0x1F)
-#define AHCI_CAP_SXS                   (0x20)
-#define AHCI_CAP_EMS                   (0x40)
-#define AHCI_CAP_CCCS                  (0x80)
-#define AHCI_CAP_NCS                 (0x1F00)
-#define AHCI_CAP_PSC                 (0x2000)
-#define AHCI_CAP_SSC                 (0x4000)
-#define AHCI_CAP_PMD                 (0x8000)
-#define AHCI_CAP_FBSS               (0x10000)
-#define AHCI_CAP_SPM                (0x20000)
-#define AHCI_CAP_SAM                (0x40000)
-#define AHCI_CAP_RESERVED           (0x80000)
-#define AHCI_CAP_ISS               (0xF00000)
-#define AHCI_CAP_SCLO             (0x1000000)
-#define AHCI_CAP_SAL              (0x2000000)
-#define AHCI_CAP_SALP             (0x4000000)
-#define AHCI_CAP_SSS              (0x8000000)
-#define AHCI_CAP_SMPS            (0x10000000)
-#define AHCI_CAP_SSNTF           (0x20000000)
-#define AHCI_CAP_SNCQ            (0x40000000)
-#define AHCI_CAP_S64A            (0x80000000)
-
-#define AHCI_GHC                          (1)
-#define AHCI_GHC_HR                    (0x01)
-#define AHCI_GHC_IE                    (0x02)
-#define AHCI_GHC_MRSM                  (0x04)
-#define AHCI_GHC_RESERVED        (0x7FFFFFF8)
-#define AHCI_GHC_AE              (0x80000000)
-
-#define AHCI_IS                           (2)
-#define AHCI_PI                           (3)
-#define AHCI_VS                           (4)
-
-#define AHCI_CCCCTL                       (5)
-#define AHCI_CCCCTL_EN                 (0x01)
-#define AHCI_CCCCTL_RESERVED           (0x06)
-#define AHCI_CCCCTL_CC               (0xFF00)
-#define AHCI_CCCCTL_TV           (0xFFFF0000)
-
-#define AHCI_CCCPORTS                     (6)
-#define AHCI_EMLOC                        (7)
-
-#define AHCI_EMCTL                        (8)
-#define AHCI_EMCTL_STSMR               (0x01)
-#define AHCI_EMCTL_CTLTM              (0x100)
-#define AHCI_EMCTL_CTLRST             (0x200)
-#define AHCI_EMCTL_RESERVED      (0xF0F0FCFE)
-
-#define AHCI_CAP2                         (9)
-#define AHCI_CAP2_BOH                  (0x01)
-#define AHCI_CAP2_NVMP                 (0x02)
-#define AHCI_CAP2_APST                 (0x04)
-#define AHCI_CAP2_RESERVED       (0xFFFFFFF8)
-
-#define AHCI_BOHC                        (10)
-#define AHCI_RESERVED                    (11)
-#define AHCI_NVMHCI                      (24)
-#define AHCI_VENDOR                      (40)
-#define AHCI_PORTS                       (64)
-
-/*** Port Memory Offsets & Bitmasks ***/
-#define AHCI_PX_CLB                       (0)
-#define AHCI_PX_CLB_RESERVED          (0x1FF)
-
-#define AHCI_PX_CLBU                      (1)
-
-#define AHCI_PX_FB                        (2)
-#define AHCI_PX_FB_RESERVED            (0xFF)
-
-#define AHCI_PX_FBU                       (3)
-
-#define AHCI_PX_IS                        (4)
-#define AHCI_PX_IS_DHRS                 (0x1)
-#define AHCI_PX_IS_PSS                  (0x2)
-#define AHCI_PX_IS_DSS                  (0x4)
-#define AHCI_PX_IS_SDBS                 (0x8)
-#define AHCI_PX_IS_UFS                 (0x10)
-#define AHCI_PX_IS_DPS                 (0x20)
-#define AHCI_PX_IS_PCS                 (0x40)
-#define AHCI_PX_IS_DMPS                (0x80)
-#define AHCI_PX_IS_RESERVED       (0x23FFF00)
-#define AHCI_PX_IS_PRCS            (0x400000)
-#define AHCI_PX_IS_IPMS            (0x800000)
-#define AHCI_PX_IS_OFS            (0x1000000)
-#define AHCI_PX_IS_INFS           (0x4000000)
-#define AHCI_PX_IS_IFS            (0x8000000)
-#define AHCI_PX_IS_HBDS          (0x10000000)
-#define AHCI_PX_IS_HBFS          (0x20000000)
-#define AHCI_PX_IS_TFES          (0x40000000)
-#define AHCI_PX_IS_CPDS          (0x80000000)
-
-#define AHCI_PX_IE                        (5)
-#define AHCI_PX_IE_DHRE                 (0x1)
-#define AHCI_PX_IE_PSE                  (0x2)
-#define AHCI_PX_IE_DSE                  (0x4)
-#define AHCI_PX_IE_SDBE                 (0x8)
-#define AHCI_PX_IE_UFE                 (0x10)
-#define AHCI_PX_IE_DPE                 (0x20)
-#define AHCI_PX_IE_PCE                 (0x40)
-#define AHCI_PX_IE_DMPE                (0x80)
-#define AHCI_PX_IE_RESERVED       (0x23FFF00)
-#define AHCI_PX_IE_PRCE            (0x400000)
-#define AHCI_PX_IE_IPME            (0x800000)
-#define AHCI_PX_IE_OFE            (0x1000000)
-#define AHCI_PX_IE_INFE           (0x4000000)
-#define AHCI_PX_IE_IFE            (0x8000000)
-#define AHCI_PX_IE_HBDE          (0x10000000)
-#define AHCI_PX_IE_HBFE          (0x20000000)
-#define AHCI_PX_IE_TFEE          (0x40000000)
-#define AHCI_PX_IE_CPDE          (0x80000000)
-
-#define AHCI_PX_CMD                       (6)
-#define AHCI_PX_CMD_ST                  (0x1)
-#define AHCI_PX_CMD_SUD                 (0x2)
-#define AHCI_PX_CMD_POD                 (0x4)
-#define AHCI_PX_CMD_CLO                 (0x8)
-#define AHCI_PX_CMD_FRE                (0x10)
-#define AHCI_PX_CMD_RESERVED           (0xE0)
-#define AHCI_PX_CMD_CCS              (0x1F00)
-#define AHCI_PX_CMD_MPSS             (0x2000)
-#define AHCI_PX_CMD_FR               (0x4000)
-#define AHCI_PX_CMD_CR               (0x8000)
-#define AHCI_PX_CMD_CPS             (0x10000)
-#define AHCI_PX_CMD_PMA             (0x20000)
-#define AHCI_PX_CMD_HPCP            (0x40000)
-#define AHCI_PX_CMD_MPSP            (0x80000)
-#define AHCI_PX_CMD_CPD            (0x100000)
-#define AHCI_PX_CMD_ESP            (0x200000)
-#define AHCI_PX_CMD_FBSCP          (0x400000)
-#define AHCI_PX_CMD_APSTE          (0x800000)
-#define AHCI_PX_CMD_ATAPI         (0x1000000)
-#define AHCI_PX_CMD_DLAE          (0x2000000)
-#define AHCI_PX_CMD_ALPE          (0x4000000)
-#define AHCI_PX_CMD_ASP           (0x8000000)
-#define AHCI_PX_CMD_ICC          (0xF0000000)
-
-#define AHCI_PX_RES1                      (7)
-
-#define AHCI_PX_TFD                       (8)
-#define AHCI_PX_TFD_STS                (0xFF)
-#define AHCI_PX_TFD_STS_ERR            (0x01)
-#define AHCI_PX_TFD_STS_CS1            (0x06)
-#define AHCI_PX_TFD_STS_DRQ            (0x08)
-#define AHCI_PX_TFD_STS_CS2            (0x70)
-#define AHCI_PX_TFD_STS_BSY            (0x80)
-#define AHCI_PX_TFD_ERR              (0xFF00)
-#define AHCI_PX_TFD_RESERVED     (0xFFFF0000)
-
-#define AHCI_PX_SIG                       (9)
-#define AHCI_PX_SIG_SECTOR_COUNT       (0xFF)
-#define AHCI_PX_SIG_LBA_LOW          (0xFF00)
-#define AHCI_PX_SIG_LBA_MID        (0xFF0000)
-#define AHCI_PX_SIG_LBA_HIGH     (0xFF000000)
-
-#define AHCI_PX_SSTS                     (10)
-#define AHCI_PX_SSTS_DET               (0x0F)
-#define AHCI_PX_SSTS_SPD               (0xF0)
-#define AHCI_PX_SSTS_IPM              (0xF00)
-#define AHCI_PX_SSTS_RESERVED    (0xFFFFF000)
-#define SSTS_DET_NO_DEVICE             (0x00)
-#define SSTS_DET_PRESENT               (0x01)
-#define SSTS_DET_ESTABLISHED           (0x03)
-#define SSTS_DET_OFFLINE               (0x04)
-
-#define AHCI_PX_SCTL                     (11)
-
-#define AHCI_PX_SERR                     (12)
-#define AHCI_PX_SERR_ERR             (0xFFFF)
-#define AHCI_PX_SERR_DIAG        (0xFFFF0000)
-#define AHCI_PX_SERR_DIAG_X      (0x04000000)
-
-#define AHCI_PX_SACT                     (13)
-#define AHCI_PX_CI                       (14)
-#define AHCI_PX_SNTF                     (15)
-
-#define AHCI_PX_FBS                      (16)
-#define AHCI_PX_FBS_EN                  (0x1)
-#define AHCI_PX_FBS_DEC                 (0x2)
-#define AHCI_PX_FBS_SDE                 (0x4)
-#define AHCI_PX_FBS_DEV               (0xF00)
-#define AHCI_PX_FBS_ADO              (0xF000)
-#define AHCI_PX_FBS_DWE             (0xF0000)
-#define AHCI_PX_FBS_RESERVED     (0xFFF000F8)
-
-#define AHCI_PX_RES2                     (17)
-#define AHCI_PX_VS                       (28)
-
-#define HBA_DATA_REGION_SIZE            (256)
-#define HBA_PORT_DATA_SIZE              (128)
-#define HBA_PORT_NUM_REG (HBA_PORT_DATA_SIZE/4)
-
-#define AHCI_VERSION_0_95        (0x00000905)
-#define AHCI_VERSION_1_0         (0x00010000)
-#define AHCI_VERSION_1_1         (0x00010100)
-#define AHCI_VERSION_1_2         (0x00010200)
-#define AHCI_VERSION_1_3         (0x00010300)
-
-/*** Structures ***/
-
-/**
- * Generic FIS structure.
- */
-typedef struct FIS {
-    uint8_t fis_type;
-    uint8_t flags;
-    char data[0];
-} __attribute__((__packed__)) FIS;
-
-/**
- * Register device-to-host FIS structure.
- */
-typedef struct RegD2HFIS {
-    /* DW0 */
-    uint8_t fis_type;
-    uint8_t flags;
-    uint8_t status;
-    uint8_t error;
-    /* DW1 */
-    uint8_t lba_low;
-    uint8_t lba_mid;
-    uint8_t lba_high;
-    uint8_t device;
-    /* DW2 */
-    uint8_t lba3;
-    uint8_t lba4;
-    uint8_t lba5;
-    uint8_t res1;
-    /* DW3 */
-    uint16_t count;
-    uint8_t res2;
-    uint8_t res3;
-    /* DW4 */
-    uint16_t res4;
-    uint16_t res5;
-} __attribute__((__packed__)) RegD2HFIS;
-
-/**
- * Register host-to-device FIS structure.
- */
-typedef struct RegH2DFIS {
-    /* DW0 */
-    uint8_t fis_type;
-    uint8_t flags;
-    uint8_t command;
-    uint8_t feature_low;
-    /* DW1 */
-    uint8_t lba_low;
-    uint8_t lba_mid;
-    uint8_t lba_high;
-    uint8_t device;
-    /* DW2 */
-    uint8_t lba3;
-    uint8_t lba4;
-    uint8_t lba5;
-    uint8_t feature_high;
-    /* DW3 */
-    uint16_t count;
-    uint8_t icc;
-    uint8_t control;
-    /* DW4 */
-    uint32_t aux;
-} __attribute__((__packed__)) RegH2DFIS;
-
-/**
- * Command List entry structure.
- * The command list contains between 1-32 of these structures.
- */
-typedef struct AHCICommand {
-    uint8_t b1;
-    uint8_t b2;
-    uint16_t prdtl; /* Phys Region Desc. Table Length */
-    uint32_t prdbc; /* Phys Region Desc. Byte Count */
-    uint32_t ctba;  /* Command Table Descriptor Base Address */
-    uint32_t ctbau; /*                                    '' Upper */
-    uint32_t res[4];
-} __attribute__((__packed__)) AHCICommand;
-
-/**
- * Physical Region Descriptor; pointed to by the Command List Header,
- * struct ahci_command.
- */
-typedef struct PRD {
-    uint32_t dba;  /* Data Base Address */
-    uint32_t dbau; /* Data Base Address Upper */
-    uint32_t res;  /* Reserved */
-    uint32_t dbc;  /* Data Byte Count (0-indexed) & Interrupt Flag (bit 2^31) */
-} PRD;
-
-typedef struct HBACap {
-    uint32_t cap;
-    uint32_t cap2;
-} HBACap;
-
 /*** Globals ***/
 static QGuestAllocator *guest_malloc;
 static QPCIBus *pcibus;
@@ -356,13 +50,6 @@ static char tmp_path[] = "/tmp/qtest.XXXXXX";
 static bool ahci_pedantic;
 static uint32_t ahci_fingerprint;
 
-/*** Macro Utilities ***/
-#define BITANY(data, mask) (((data) & (mask)) != 0)
-#define BITSET(data, mask) (((data) & (mask)) == (mask))
-#define BITCLR(data, mask) (((data) & (mask)) == 0)
-#define ASSERT_BIT_SET(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
-#define ASSERT_BIT_CLEAR(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
-
 /*** IO macros for the AHCI memory registers. ***/
 #define AHCI_READ(OFST) qpci_io_readl(ahci, hba_base + (OFST))
 #define AHCI_WRITE(OFST, VAL) qpci_io_writel(ahci, hba_base + (OFST), (VAL))
@@ -380,10 +67,6 @@ static uint32_t ahci_fingerprint;
 #define PX_CLR(port, reg, mask)   PX_WREG((port), (reg),                \
                                           PX_RREG((port), (reg)) & ~(mask));
 
-/* For calculating how big the PRD table needs to be: */
-#define CMD_TBL_SIZ(n) ((0x80 + ((n) * sizeof(PRD)) + 0x7F) & ~0x7F)
-
-
 /*** Function Declarations ***/
 static QPCIDevice *get_ahci_device(void);
 static QPCIDevice *start_ahci_device(QPCIDevice *dev, void **hba_base);
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
new file mode 100644
index 0000000..6564c5a
--- /dev/null
+++ b/tests/libqos/ahci.h
@@ -0,0 +1,352 @@
+#ifndef __libqos_ahci_h
+#define __libqos_ahci_h
+
+/*
+ * AHCI qtest library functions and definitions
+ *
+ * Copyright (c) 2014 John Snow <jsnow@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "libqos/pci.h"
+#include "libqos/malloc-pc.h"
+
+/*** Supplementary PCI Config Space IDs & Masks ***/
+#define PCI_DEVICE_ID_INTEL_Q35_AHCI   (0x2922)
+#define PCI_MSI_FLAGS_RESERVED         (0xFF00)
+#define PCI_PM_CTRL_RESERVED             (0xFC)
+#define PCI_BCC(REG32)          ((REG32) >> 24)
+#define PCI_PI(REG32)   (((REG32) >> 8) & 0xFF)
+#define PCI_SCC(REG32) (((REG32) >> 16) & 0xFF)
+
+/*** Recognized AHCI Device Types ***/
+#define AHCI_INTEL_ICH9 (PCI_DEVICE_ID_INTEL_Q35_AHCI << 16 | \
+                         PCI_VENDOR_ID_INTEL)
+
+/*** AHCI/HBA Register Offsets and Bitmasks ***/
+#define AHCI_CAP                          (0)
+#define AHCI_CAP_NP                    (0x1F)
+#define AHCI_CAP_SXS                   (0x20)
+#define AHCI_CAP_EMS                   (0x40)
+#define AHCI_CAP_CCCS                  (0x80)
+#define AHCI_CAP_NCS                 (0x1F00)
+#define AHCI_CAP_PSC                 (0x2000)
+#define AHCI_CAP_SSC                 (0x4000)
+#define AHCI_CAP_PMD                 (0x8000)
+#define AHCI_CAP_FBSS               (0x10000)
+#define AHCI_CAP_SPM                (0x20000)
+#define AHCI_CAP_SAM                (0x40000)
+#define AHCI_CAP_RESERVED           (0x80000)
+#define AHCI_CAP_ISS               (0xF00000)
+#define AHCI_CAP_SCLO             (0x1000000)
+#define AHCI_CAP_SAL              (0x2000000)
+#define AHCI_CAP_SALP             (0x4000000)
+#define AHCI_CAP_SSS              (0x8000000)
+#define AHCI_CAP_SMPS            (0x10000000)
+#define AHCI_CAP_SSNTF           (0x20000000)
+#define AHCI_CAP_SNCQ            (0x40000000)
+#define AHCI_CAP_S64A            (0x80000000)
+
+#define AHCI_GHC                          (1)
+#define AHCI_GHC_HR                    (0x01)
+#define AHCI_GHC_IE                    (0x02)
+#define AHCI_GHC_MRSM                  (0x04)
+#define AHCI_GHC_RESERVED        (0x7FFFFFF8)
+#define AHCI_GHC_AE              (0x80000000)
+
+#define AHCI_IS                           (2)
+#define AHCI_PI                           (3)
+#define AHCI_VS                           (4)
+
+#define AHCI_CCCCTL                       (5)
+#define AHCI_CCCCTL_EN                 (0x01)
+#define AHCI_CCCCTL_RESERVED           (0x06)
+#define AHCI_CCCCTL_CC               (0xFF00)
+#define AHCI_CCCCTL_TV           (0xFFFF0000)
+
+#define AHCI_CCCPORTS                     (6)
+#define AHCI_EMLOC                        (7)
+
+#define AHCI_EMCTL                        (8)
+#define AHCI_EMCTL_STSMR               (0x01)
+#define AHCI_EMCTL_CTLTM              (0x100)
+#define AHCI_EMCTL_CTLRST             (0x200)
+#define AHCI_EMCTL_RESERVED      (0xF0F0FCFE)
+
+#define AHCI_CAP2                         (9)
+#define AHCI_CAP2_BOH                  (0x01)
+#define AHCI_CAP2_NVMP                 (0x02)
+#define AHCI_CAP2_APST                 (0x04)
+#define AHCI_CAP2_RESERVED       (0xFFFFFFF8)
+
+#define AHCI_BOHC                        (10)
+#define AHCI_RESERVED                    (11)
+#define AHCI_NVMHCI                      (24)
+#define AHCI_VENDOR                      (40)
+#define AHCI_PORTS                       (64)
+
+/*** Port Memory Offsets & Bitmasks ***/
+#define AHCI_PX_CLB                       (0)
+#define AHCI_PX_CLB_RESERVED          (0x1FF)
+
+#define AHCI_PX_CLBU                      (1)
+
+#define AHCI_PX_FB                        (2)
+#define AHCI_PX_FB_RESERVED            (0xFF)
+
+#define AHCI_PX_FBU                       (3)
+
+#define AHCI_PX_IS                        (4)
+#define AHCI_PX_IS_DHRS                 (0x1)
+#define AHCI_PX_IS_PSS                  (0x2)
+#define AHCI_PX_IS_DSS                  (0x4)
+#define AHCI_PX_IS_SDBS                 (0x8)
+#define AHCI_PX_IS_UFS                 (0x10)
+#define AHCI_PX_IS_DPS                 (0x20)
+#define AHCI_PX_IS_PCS                 (0x40)
+#define AHCI_PX_IS_DMPS                (0x80)
+#define AHCI_PX_IS_RESERVED       (0x23FFF00)
+#define AHCI_PX_IS_PRCS            (0x400000)
+#define AHCI_PX_IS_IPMS            (0x800000)
+#define AHCI_PX_IS_OFS            (0x1000000)
+#define AHCI_PX_IS_INFS           (0x4000000)
+#define AHCI_PX_IS_IFS            (0x8000000)
+#define AHCI_PX_IS_HBDS          (0x10000000)
+#define AHCI_PX_IS_HBFS          (0x20000000)
+#define AHCI_PX_IS_TFES          (0x40000000)
+#define AHCI_PX_IS_CPDS          (0x80000000)
+
+#define AHCI_PX_IE                        (5)
+#define AHCI_PX_IE_DHRE                 (0x1)
+#define AHCI_PX_IE_PSE                  (0x2)
+#define AHCI_PX_IE_DSE                  (0x4)
+#define AHCI_PX_IE_SDBE                 (0x8)
+#define AHCI_PX_IE_UFE                 (0x10)
+#define AHCI_PX_IE_DPE                 (0x20)
+#define AHCI_PX_IE_PCE                 (0x40)
+#define AHCI_PX_IE_DMPE                (0x80)
+#define AHCI_PX_IE_RESERVED       (0x23FFF00)
+#define AHCI_PX_IE_PRCE            (0x400000)
+#define AHCI_PX_IE_IPME            (0x800000)
+#define AHCI_PX_IE_OFE            (0x1000000)
+#define AHCI_PX_IE_INFE           (0x4000000)
+#define AHCI_PX_IE_IFE            (0x8000000)
+#define AHCI_PX_IE_HBDE          (0x10000000)
+#define AHCI_PX_IE_HBFE          (0x20000000)
+#define AHCI_PX_IE_TFEE          (0x40000000)
+#define AHCI_PX_IE_CPDE          (0x80000000)
+
+#define AHCI_PX_CMD                       (6)
+#define AHCI_PX_CMD_ST                  (0x1)
+#define AHCI_PX_CMD_SUD                 (0x2)
+#define AHCI_PX_CMD_POD                 (0x4)
+#define AHCI_PX_CMD_CLO                 (0x8)
+#define AHCI_PX_CMD_FRE                (0x10)
+#define AHCI_PX_CMD_RESERVED           (0xE0)
+#define AHCI_PX_CMD_CCS              (0x1F00)
+#define AHCI_PX_CMD_MPSS             (0x2000)
+#define AHCI_PX_CMD_FR               (0x4000)
+#define AHCI_PX_CMD_CR               (0x8000)
+#define AHCI_PX_CMD_CPS             (0x10000)
+#define AHCI_PX_CMD_PMA             (0x20000)
+#define AHCI_PX_CMD_HPCP            (0x40000)
+#define AHCI_PX_CMD_MPSP            (0x80000)
+#define AHCI_PX_CMD_CPD            (0x100000)
+#define AHCI_PX_CMD_ESP            (0x200000)
+#define AHCI_PX_CMD_FBSCP          (0x400000)
+#define AHCI_PX_CMD_APSTE          (0x800000)
+#define AHCI_PX_CMD_ATAPI         (0x1000000)
+#define AHCI_PX_CMD_DLAE          (0x2000000)
+#define AHCI_PX_CMD_ALPE          (0x4000000)
+#define AHCI_PX_CMD_ASP           (0x8000000)
+#define AHCI_PX_CMD_ICC          (0xF0000000)
+
+#define AHCI_PX_RES1                      (7)
+
+#define AHCI_PX_TFD                       (8)
+#define AHCI_PX_TFD_STS                (0xFF)
+#define AHCI_PX_TFD_STS_ERR            (0x01)
+#define AHCI_PX_TFD_STS_CS1            (0x06)
+#define AHCI_PX_TFD_STS_DRQ            (0x08)
+#define AHCI_PX_TFD_STS_CS2            (0x70)
+#define AHCI_PX_TFD_STS_BSY            (0x80)
+#define AHCI_PX_TFD_ERR              (0xFF00)
+#define AHCI_PX_TFD_RESERVED     (0xFFFF0000)
+
+#define AHCI_PX_SIG                       (9)
+#define AHCI_PX_SIG_SECTOR_COUNT       (0xFF)
+#define AHCI_PX_SIG_LBA_LOW          (0xFF00)
+#define AHCI_PX_SIG_LBA_MID        (0xFF0000)
+#define AHCI_PX_SIG_LBA_HIGH     (0xFF000000)
+
+#define AHCI_PX_SSTS                     (10)
+#define AHCI_PX_SSTS_DET               (0x0F)
+#define AHCI_PX_SSTS_SPD               (0xF0)
+#define AHCI_PX_SSTS_IPM              (0xF00)
+#define AHCI_PX_SSTS_RESERVED    (0xFFFFF000)
+#define SSTS_DET_NO_DEVICE             (0x00)
+#define SSTS_DET_PRESENT               (0x01)
+#define SSTS_DET_ESTABLISHED           (0x03)
+#define SSTS_DET_OFFLINE               (0x04)
+
+#define AHCI_PX_SCTL                     (11)
+
+#define AHCI_PX_SERR                     (12)
+#define AHCI_PX_SERR_ERR             (0xFFFF)
+#define AHCI_PX_SERR_DIAG        (0xFFFF0000)
+#define AHCI_PX_SERR_DIAG_X      (0x04000000)
+
+#define AHCI_PX_SACT                     (13)
+#define AHCI_PX_CI                       (14)
+#define AHCI_PX_SNTF                     (15)
+
+#define AHCI_PX_FBS                      (16)
+#define AHCI_PX_FBS_EN                  (0x1)
+#define AHCI_PX_FBS_DEC                 (0x2)
+#define AHCI_PX_FBS_SDE                 (0x4)
+#define AHCI_PX_FBS_DEV               (0xF00)
+#define AHCI_PX_FBS_ADO              (0xF000)
+#define AHCI_PX_FBS_DWE             (0xF0000)
+#define AHCI_PX_FBS_RESERVED     (0xFFF000F8)
+
+#define AHCI_PX_RES2                     (17)
+#define AHCI_PX_VS                       (28)
+
+#define HBA_DATA_REGION_SIZE            (256)
+#define HBA_PORT_DATA_SIZE              (128)
+#define HBA_PORT_NUM_REG (HBA_PORT_DATA_SIZE/4)
+
+#define AHCI_VERSION_0_95        (0x00000905)
+#define AHCI_VERSION_1_0         (0x00010000)
+#define AHCI_VERSION_1_1         (0x00010100)
+#define AHCI_VERSION_1_2         (0x00010200)
+#define AHCI_VERSION_1_3         (0x00010300)
+
+/*** Structures ***/
+
+/**
+ * Generic FIS structure.
+ */
+typedef struct FIS {
+    uint8_t fis_type;
+    uint8_t flags;
+    char data[0];
+} __attribute__((__packed__)) FIS;
+
+/**
+ * Register device-to-host FIS structure.
+ */
+typedef struct RegD2HFIS {
+    /* DW0 */
+    uint8_t fis_type;
+    uint8_t flags;
+    uint8_t status;
+    uint8_t error;
+    /* DW1 */
+    uint8_t lba_low;
+    uint8_t lba_mid;
+    uint8_t lba_high;
+    uint8_t device;
+    /* DW2 */
+    uint8_t lba3;
+    uint8_t lba4;
+    uint8_t lba5;
+    uint8_t res1;
+    /* DW3 */
+    uint16_t count;
+    uint8_t res2;
+    uint8_t res3;
+    /* DW4 */
+    uint16_t res4;
+    uint16_t res5;
+} __attribute__((__packed__)) RegD2HFIS;
+
+/**
+ * Register host-to-device FIS structure.
+ */
+typedef struct RegH2DFIS {
+    /* DW0 */
+    uint8_t fis_type;
+    uint8_t flags;
+    uint8_t command;
+    uint8_t feature_low;
+    /* DW1 */
+    uint8_t lba_low;
+    uint8_t lba_mid;
+    uint8_t lba_high;
+    uint8_t device;
+    /* DW2 */
+    uint8_t lba3;
+    uint8_t lba4;
+    uint8_t lba5;
+    uint8_t feature_high;
+    /* DW3 */
+    uint16_t count;
+    uint8_t icc;
+    uint8_t control;
+    /* DW4 */
+    uint32_t aux;
+} __attribute__((__packed__)) RegH2DFIS;
+
+/**
+ * Command List entry structure.
+ * The command list contains between 1-32 of these structures.
+ */
+typedef struct AHCICommand {
+    uint8_t b1;
+    uint8_t b2;
+    uint16_t prdtl; /* Phys Region Desc. Table Length */
+    uint32_t prdbc; /* Phys Region Desc. Byte Count */
+    uint32_t ctba;  /* Command Table Descriptor Base Address */
+    uint32_t ctbau; /*                                    '' Upper */
+    uint32_t res[4];
+} __attribute__((__packed__)) AHCICommand;
+
+/**
+ * Physical Region Descriptor; pointed to by the Command List Header,
+ * struct ahci_command.
+ */
+typedef struct PRD {
+    uint32_t dba;  /* Data Base Address */
+    uint32_t dbau; /* Data Base Address Upper */
+    uint32_t res;  /* Reserved */
+    uint32_t dbc;  /* Data Byte Count (0-indexed) & Interrupt Flag (bit 2^31) */
+} PRD;
+
+typedef struct HBACap {
+    uint32_t cap;
+    uint32_t cap2;
+} HBACap;
+
+/*** Macro Utilities ***/
+#define BITANY(data, mask) (((data) & (mask)) != 0)
+#define BITSET(data, mask) (((data) & (mask)) == (mask))
+#define BITCLR(data, mask) (((data) & (mask)) == 0)
+#define ASSERT_BIT_SET(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
+#define ASSERT_BIT_CLEAR(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
+
+/* For calculating how big the PRD table needs to be: */
+#define CMD_TBL_SIZ(n) ((0x80 + ((n) * sizeof(PRD)) + 0x7F) & ~0x7F)
+
+#endif
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 06/65] libqos: create libqos.c
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (4 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 05/65] qtest/ahci: Create ahci.h Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 07/65] libqos: add qtest_vboot Stefan Hajnoczi
                   ` (59 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

The intent of this file is to serve as a misc. utilities file to be
shared amongst tests that are utilizing libqos facilities.

In a later patch, migration test helpers will be added to libqos.c that
will allow simplified testing of migration cases where libqos is
"Just Enough OS" for migrations testing.

The addition of the AHCIQState structure will also allow us to eliminate
global variables inside of qtests to manage allocators and test instances
in a better, more functional way.

libqos.c:
        - Add qtest_boot
        - Add qtest_shutdown

libqos.h:
        - Create QOSState structure for allocator and QTestState.

ahci-test.c:
        - Move qtest_boot and qtest_shutdown to libqos.c/h
        - Create AHCIQState to interface with new qtest_boot/shutdown prototypes
        - Modify tests slightly to use new types.

For now, the new object file is only linked to ahci-test, because it still
relies on pc architecture specific code in libqos. The next two patches will
reorganize the code to be more general.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1421698563-6977-4-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/Makefile        |  2 +-
 tests/ahci-test.c     | 91 +++++++++++++++++++++------------------------------
 tests/libqos/ahci.h   |  5 +++
 tests/libqos/libqos.c | 48 +++++++++++++++++++++++++++
 tests/libqos/libqos.h | 26 +++++++++++++++
 5 files changed, 117 insertions(+), 55 deletions(-)
 create mode 100644 tests/libqos/libqos.c
 create mode 100644 tests/libqos/libqos.h

diff --git a/tests/Makefile b/tests/Makefile
index d5df168..0469bbd 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -320,7 +320,7 @@ tests/endianness-test$(EXESUF): tests/endianness-test.o
 tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y)
 tests/fdc-test$(EXESUF): tests/fdc-test.o
 tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
-tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y)
+tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y) tests/libqos/libqos.o
 tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
 tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y)
 tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o $(libqos-obj-y)
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 5c9da12..15542b9 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -29,6 +29,7 @@
 #include <glib.h>
 
 #include "libqtest.h"
+#include "libqos/libqos.h"
 #include "libqos/ahci.h"
 #include "libqos/pci-pc.h"
 #include "libqos/malloc-pc.h"
@@ -136,58 +137,40 @@ static void free_ahci_device(QPCIDevice *ahci)
 /*** Test Setup & Teardown ***/
 
 /**
- * Launch QEMU with the given command line,
- * and then set up interrupts and our guest malloc interface.
+ * Start a Q35 machine and bookmark a handle to the AHCI device.
  */
-static void qtest_boot(const char *cmdline_fmt, ...)
+static AHCIQState *ahci_boot(void)
 {
-    va_list ap;
-    char *cmdline;
-
-    va_start(ap, cmdline_fmt);
-    cmdline = g_strdup_vprintf(cmdline_fmt, ap);
-    va_end(ap);
+    AHCIQState *s;
+    const char *cli;
 
-    qtest_start(cmdline);
-    qtest_irq_intercept_in(global_qtest, "ioapic");
-    guest_malloc = pc_alloc_init();
+    s = g_malloc0(sizeof(AHCIQState));
 
-    g_free(cmdline);
-}
+    cli = "-drive if=none,id=drive0,file=%s,cache=writeback,serial=%s"
+        ",format=raw"
+        " -M q35 "
+        "-device ide-hd,drive=drive0 "
+        "-global ide-hd.ver=%s";
+    s->parent = qtest_boot(cli, tmp_path, "testdisk", "version");
 
-/**
- * Tear down the QEMU instance.
- */
-static void qtest_shutdown(void)
-{
-    g_free(guest_malloc);
-    guest_malloc = NULL;
-    qtest_end();
-}
+    /* Verify that we have an AHCI device present. */
+    s->dev = get_ahci_device();
 
-/**
- * Start a Q35 machine and bookmark a handle to the AHCI device.
- */
-static QPCIDevice *ahci_boot(void)
-{
-    qtest_boot("-drive if=none,id=drive0,file=%s,cache=writeback,serial=%s,"
-               "format=raw"
-               " -M q35 "
-               "-device ide-hd,drive=drive0 "
-               "-global ide-hd.ver=%s",
-               tmp_path, "testdisk", "version");
+    /* Stopgap: Copy the allocator reference */
+    guest_malloc = s->parent->alloc;
 
-    /* Verify that we have an AHCI device present. */
-    return get_ahci_device();
+    return s;
 }
 
 /**
  * Clean up the PCI device, then terminate the QEMU instance.
  */
-static void ahci_shutdown(QPCIDevice *ahci)
+static void ahci_shutdown(AHCIQState *ahci)
 {
-    free_ahci_device(ahci);
-    qtest_shutdown();
+    QOSState *qs = ahci->parent;
+    free_ahci_device(ahci->dev);
+    g_free(ahci);
+    qtest_shutdown(qs);
 }
 
 /*** Logical Device Initialization ***/
@@ -1104,7 +1087,7 @@ static void ahci_test_identify(QPCIDevice *ahci, void *hba_base)
  */
 static void test_sanity(void)
 {
-    QPCIDevice *ahci;
+    AHCIQState *ahci;
     ahci = ahci_boot();
     ahci_shutdown(ahci);
 }
@@ -1115,9 +1098,9 @@ static void test_sanity(void)
  */
 static void test_pci_spec(void)
 {
-    QPCIDevice *ahci;
+    AHCIQState *ahci;
     ahci = ahci_boot();
-    ahci_test_pci_spec(ahci);
+    ahci_test_pci_spec(ahci->dev);
     ahci_shutdown(ahci);
 }
 
@@ -1127,10 +1110,10 @@ static void test_pci_spec(void)
  */
 static void test_pci_enable(void)
 {
-    QPCIDevice *ahci;
+    AHCIQState *ahci;
     void *hba_base;
     ahci = ahci_boot();
-    ahci_pci_enable(ahci, &hba_base);
+    ahci_pci_enable(ahci->dev, &hba_base);
     ahci_shutdown(ahci);
 }
 
@@ -1140,12 +1123,12 @@ static void test_pci_enable(void)
  */
 static void test_hba_spec(void)
 {
-    QPCIDevice *ahci;
+    AHCIQState *ahci;
     void *hba_base;
 
     ahci = ahci_boot();
-    ahci_pci_enable(ahci, &hba_base);
-    ahci_test_hba_spec(ahci, hba_base);
+    ahci_pci_enable(ahci->dev, &hba_base);
+    ahci_test_hba_spec(ahci->dev, hba_base);
     ahci_shutdown(ahci);
 }
 
@@ -1155,12 +1138,12 @@ static void test_hba_spec(void)
  */
 static void test_hba_enable(void)
 {
-    QPCIDevice *ahci;
+    AHCIQState *ahci;
     void *hba_base;
 
     ahci = ahci_boot();
-    ahci_pci_enable(ahci, &hba_base);
-    ahci_hba_enable(ahci, hba_base);
+    ahci_pci_enable(ahci->dev, &hba_base);
+    ahci_hba_enable(ahci->dev, hba_base);
     ahci_shutdown(ahci);
 }
 
@@ -1170,13 +1153,13 @@ static void test_hba_enable(void)
  */
 static void test_identify(void)
 {
-    QPCIDevice *ahci;
+    AHCIQState *ahci;
     void *hba_base;
 
     ahci = ahci_boot();
-    ahci_pci_enable(ahci, &hba_base);
-    ahci_hba_enable(ahci, hba_base);
-    ahci_test_identify(ahci, hba_base);
+    ahci_pci_enable(ahci->dev, &hba_base);
+    ahci_hba_enable(ahci->dev, hba_base);
+    ahci_test_identify(ahci->dev, hba_base);
     ahci_shutdown(ahci);
 }
 
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 6564c5a..bc5f45d 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -245,6 +245,11 @@
 
 /*** Structures ***/
 
+typedef struct AHCIQState {
+    QOSState *parent;
+    QPCIDevice *dev;
+} AHCIQState;
+
 /**
  * Generic FIS structure.
  */
diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c
new file mode 100644
index 0000000..c478bc9
--- /dev/null
+++ b/tests/libqos/libqos.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+
+#include "libqtest.h"
+#include "libqos/libqos.h"
+#include "libqos/pci.h"
+#include "libqos/malloc-pc.h"
+
+/*** Test Setup & Teardown ***/
+
+/**
+ * Launch QEMU with the given command line,
+ * and then set up interrupts and our guest malloc interface.
+ */
+QOSState *qtest_boot(const char *cmdline_fmt, ...)
+{
+    QOSState *qs = g_malloc(sizeof(QOSState));
+    char *cmdline;
+    va_list ap;
+
+    va_start(ap, cmdline_fmt);
+    cmdline = g_strdup_vprintf(cmdline_fmt, ap);
+    va_end(ap);
+
+    qs->qts = qtest_start(cmdline);
+    qtest_irq_intercept_in(global_qtest, "ioapic");
+    qs->alloc = pc_alloc_init();
+
+    g_free(cmdline);
+    return qs;
+}
+
+/**
+ * Tear down the QEMU instance.
+ */
+void qtest_shutdown(QOSState *qs)
+{
+    if (qs->alloc) {
+        pc_alloc_uninit(qs->alloc);
+        qs->alloc = NULL;
+    }
+    qtest_quit(qs->qts);
+    g_free(qs);
+}
diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h
new file mode 100644
index 0000000..7a106f2
--- /dev/null
+++ b/tests/libqos/libqos.h
@@ -0,0 +1,26 @@
+#ifndef __libqos_h
+#define __libqos_h
+
+#include "libqtest.h"
+#include "libqos/pci.h"
+#include "libqos/malloc-pc.h"
+
+typedef struct QOSState {
+    QTestState *qts;
+    QGuestAllocator *alloc;
+} QOSState;
+
+QOSState *qtest_boot(const char *cmdline_fmt, ...);
+void qtest_shutdown(QOSState *qs);
+
+static inline uint64_t qmalloc(QOSState *q, size_t bytes)
+{
+    return guest_alloc(q->alloc, bytes);
+}
+
+static inline void qfree(QOSState *q, uint64_t addr)
+{
+    guest_free(q->alloc, addr);
+}
+
+#endif
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 07/65] libqos: add qtest_vboot
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (5 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 06/65] libqos: create libqos.c Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 08/65] libqos: add alloc_init_flags Stefan Hajnoczi
                   ` (58 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Add a va_list variant of the qtest_boot function.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1421698563-6977-5-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/libqos/libqos.c | 25 +++++++++++++++++++------
 tests/libqos/libqos.h |  1 +
 2 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c
index c478bc9..c8b3ef0 100644
--- a/tests/libqos/libqos.c
+++ b/tests/libqos/libqos.c
@@ -16,16 +16,13 @@
  * Launch QEMU with the given command line,
  * and then set up interrupts and our guest malloc interface.
  */
-QOSState *qtest_boot(const char *cmdline_fmt, ...)
+QOSState *qtest_vboot(const char *cmdline_fmt, va_list ap)
 {
-    QOSState *qs = g_malloc(sizeof(QOSState));
     char *cmdline;
-    va_list ap;
 
-    va_start(ap, cmdline_fmt);
-    cmdline = g_strdup_vprintf(cmdline_fmt, ap);
-    va_end(ap);
+    struct QOSState *qs = g_malloc(sizeof(QOSState));
 
+    cmdline = g_strdup_vprintf(cmdline_fmt, ap);
     qs->qts = qtest_start(cmdline);
     qtest_irq_intercept_in(global_qtest, "ioapic");
     qs->alloc = pc_alloc_init();
@@ -35,6 +32,22 @@ QOSState *qtest_boot(const char *cmdline_fmt, ...)
 }
 
 /**
+ * Launch QEMU with the given command line,
+ * and then set up interrupts and our guest malloc interface.
+ */
+QOSState *qtest_boot(const char *cmdline_fmt, ...)
+{
+    QOSState *qs;
+    va_list ap;
+
+    va_start(ap, cmdline_fmt);
+    qs = qtest_vboot(cmdline_fmt, ap);
+    va_end(ap);
+
+    return qs;
+}
+
+/**
  * Tear down the QEMU instance.
  */
 void qtest_shutdown(QOSState *qs)
diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h
index 7a106f2..7ae0a8d 100644
--- a/tests/libqos/libqos.h
+++ b/tests/libqos/libqos.h
@@ -10,6 +10,7 @@ typedef struct QOSState {
     QGuestAllocator *alloc;
 } QOSState;
 
+QOSState *qtest_vboot(const char *cmdline_fmt, va_list ap);
 QOSState *qtest_boot(const char *cmdline_fmt, ...);
 void qtest_shutdown(QOSState *qs);
 
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 08/65] libqos: add alloc_init_flags
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (6 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 07/65] libqos: add qtest_vboot Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 09/65] libqos: Update QGuestAllocator to be opaque Stefan Hajnoczi
                   ` (57 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Allow a generic interface to alloc_init_flags,
not just through pc_alloc_init_flags.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1421698563-6977-6-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/libqos/malloc-pc.c | 4 +---
 tests/libqos/malloc.c    | 8 ++++++++
 tests/libqos/malloc.h    | 2 ++
 3 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/tests/libqos/malloc-pc.c b/tests/libqos/malloc-pc.c
index 36a0740..6a5fdf3 100644
--- a/tests/libqos/malloc-pc.c
+++ b/tests/libqos/malloc-pc.c
@@ -37,9 +37,7 @@ QGuestAllocator *pc_alloc_init_flags(QAllocOpts flags)
     QFWCFG *fw_cfg = pc_fw_cfg_init();
 
     ram_size = qfw_cfg_get_u64(fw_cfg, FW_CFG_RAM_SIZE);
-    s = alloc_init(1 << 20, MIN(ram_size, 0xE0000000));
-
-    s->opts = flags;
+    s = alloc_init_flags(flags, 1 << 20, MIN(ram_size, 0xE0000000));
     s->page_size = PAGE_SIZE;
 
     /* clean-up */
diff --git a/tests/libqos/malloc.c b/tests/libqos/malloc.c
index 0d34ecd..4ff260f 100644
--- a/tests/libqos/malloc.c
+++ b/tests/libqos/malloc.c
@@ -285,3 +285,11 @@ QGuestAllocator *alloc_init(uint64_t start, uint64_t end)
 
     return s;
 }
+
+QGuestAllocator *alloc_init_flags(QAllocOpts opts,
+                                  uint64_t start, uint64_t end)
+{
+    QGuestAllocator *s = alloc_init(start, end);
+    s->opts = opts;
+    return s;
+}
diff --git a/tests/libqos/malloc.h b/tests/libqos/malloc.h
index 677db77..7b29547 100644
--- a/tests/libqos/malloc.h
+++ b/tests/libqos/malloc.h
@@ -51,4 +51,6 @@ uint64_t guest_alloc(QGuestAllocator *allocator, size_t size);
 void guest_free(QGuestAllocator *allocator, uint64_t addr);
 
 QGuestAllocator *alloc_init(uint64_t start, uint64_t end);
+QGuestAllocator *alloc_init_flags(QAllocOpts flags,
+                                  uint64_t start, uint64_t end);
 #endif
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 09/65] libqos: Update QGuestAllocator to be opaque
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (7 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 08/65] libqos: add alloc_init_flags Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 10/65] libqos: add pc specific interface Stefan Hajnoczi
                   ` (56 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

To avoid the architecture-specific implementations of the generic qtest
allocator having to know about fields within the allocator, add a
page_size setter method for users or arch specializations to use.
The allocator will assume a default page_size for general use, but it
can always be overridden.

Since this was the last instance of code directly using properties of the
QGuestAllocator object directly, modify the type to be opaque and move
the structure inside of malloc.c.

mlist_new, which was previously exported, is made static local to malloc.c,
as it has no external users.

[Peter Maydell <peter.maydell@linaro.org> reported the following clang
warning:
  tests/libqos/malloc.c:35:3: warning:
  redefinition of typedef 'QGuestAllocator' is a C11 feature
        [-Wtypedef-redefinition]
  } QGuestAllocator;

I converted typedef struct ... QGuestAllocator; to struct ...;
--Stefan]

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Marc Marí <marc.mari.barcelo@gmail.com>
Message-id: 1421698563-6977-7-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/libqos/malloc-pc.c |  2 +-
 tests/libqos/malloc.c    | 61 ++++++++++++++++++++++++++++++++++++------------
 tests/libqos/malloc.h    | 22 +++--------------
 3 files changed, 50 insertions(+), 35 deletions(-)

diff --git a/tests/libqos/malloc-pc.c b/tests/libqos/malloc-pc.c
index 6a5fdf3..6e253b6 100644
--- a/tests/libqos/malloc-pc.c
+++ b/tests/libqos/malloc-pc.c
@@ -38,7 +38,7 @@ QGuestAllocator *pc_alloc_init_flags(QAllocOpts flags)
 
     ram_size = qfw_cfg_get_u64(fw_cfg, FW_CFG_RAM_SIZE);
     s = alloc_init_flags(flags, 1 << 20, MIN(ram_size, 0xE0000000));
-    s->page_size = PAGE_SIZE;
+    alloc_set_page_size(s, PAGE_SIZE);
 
     /* clean-up */
     g_free(fw_cfg);
diff --git a/tests/libqos/malloc.c b/tests/libqos/malloc.c
index 4ff260f..42e3434 100644
--- a/tests/libqos/malloc.c
+++ b/tests/libqos/malloc.c
@@ -16,6 +16,26 @@
 #include <inttypes.h>
 #include <glib.h>
 
+typedef QTAILQ_HEAD(MemList, MemBlock) MemList;
+
+typedef struct MemBlock {
+    QTAILQ_ENTRY(MemBlock) MLIST_ENTNAME;
+    uint64_t size;
+    uint64_t addr;
+} MemBlock;
+
+struct QGuestAllocator {
+    QAllocOpts opts;
+    uint64_t start;
+    uint64_t end;
+    uint32_t page_size;
+
+    MemList used;
+    MemList free;
+};
+
+#define DEFAULT_PAGE_SIZE 4096
+
 static void mlist_delete(MemList *list, MemBlock *node)
 {
     g_assert(list && node);
@@ -103,6 +123,21 @@ static void mlist_coalesce(MemList *head, MemBlock *node)
     } while (merge);
 }
 
+static MemBlock *mlist_new(uint64_t addr, uint64_t size)
+{
+    MemBlock *block;
+
+    if (!size) {
+        return NULL;
+    }
+    block = g_malloc0(sizeof(MemBlock));
+
+    block->addr = addr;
+    block->size = size;
+
+    return block;
+}
+
 static uint64_t mlist_fulfill(QGuestAllocator *s, MemBlock *freenode,
                                                                 uint64_t size)
 {
@@ -187,21 +222,6 @@ static void mlist_free(QGuestAllocator *s, uint64_t addr)
     mlist_coalesce(&s->free, node);
 }
 
-MemBlock *mlist_new(uint64_t addr, uint64_t size)
-{
-    MemBlock *block;
-
-    if (!size) {
-        return NULL;
-    }
-    block = g_malloc0(sizeof(MemBlock));
-
-    block->addr = addr;
-    block->size = size;
-
-    return block;
-}
-
 /*
  * Mostly for valgrind happiness, but it does offer
  * a chokepoint for debugging guest memory leaks, too.
@@ -283,6 +303,8 @@ QGuestAllocator *alloc_init(uint64_t start, uint64_t end)
     node = mlist_new(s->start, s->end - s->start);
     QTAILQ_INSERT_HEAD(&s->free, node, MLIST_ENTNAME);
 
+    s->page_size = DEFAULT_PAGE_SIZE;
+
     return s;
 }
 
@@ -293,3 +315,12 @@ QGuestAllocator *alloc_init_flags(QAllocOpts opts,
     s->opts = opts;
     return s;
 }
+
+void alloc_set_page_size(QGuestAllocator *allocator, size_t page_size)
+{
+    /* Can't alter the page_size for an allocator in-use */
+    g_assert(QTAILQ_EMPTY(&allocator->used));
+
+    g_assert(is_power_of_2(page_size));
+    allocator->page_size = page_size;
+}
diff --git a/tests/libqos/malloc.h b/tests/libqos/malloc.h
index 7b29547..a39dba4 100644
--- a/tests/libqos/malloc.h
+++ b/tests/libqos/malloc.h
@@ -17,8 +17,6 @@
 #include <sys/types.h>
 #include "qemu/queue.h"
 
-#define MLIST_ENTNAME entries
-
 typedef enum {
     ALLOC_NO_FLAGS    = 0x00,
     ALLOC_LEAK_WARN   = 0x01,
@@ -26,24 +24,8 @@ typedef enum {
     ALLOC_PARANOID    = 0x04
 } QAllocOpts;
 
-typedef QTAILQ_HEAD(MemList, MemBlock) MemList;
-typedef struct MemBlock {
-    QTAILQ_ENTRY(MemBlock) MLIST_ENTNAME;
-    uint64_t size;
-    uint64_t addr;
-} MemBlock;
-
-typedef struct QGuestAllocator {
-    QAllocOpts opts;
-    uint64_t start;
-    uint64_t end;
-    uint32_t page_size;
+typedef struct QGuestAllocator QGuestAllocator;
 
-    MemList used;
-    MemList free;
-} QGuestAllocator;
-
-MemBlock *mlist_new(uint64_t addr, uint64_t size);
 void alloc_uninit(QGuestAllocator *allocator);
 
 /* Always returns page aligned values */
@@ -53,4 +35,6 @@ void guest_free(QGuestAllocator *allocator, uint64_t addr);
 QGuestAllocator *alloc_init(uint64_t start, uint64_t end);
 QGuestAllocator *alloc_init_flags(QAllocOpts flags,
                                   uint64_t start, uint64_t end);
+void alloc_set_page_size(QGuestAllocator *allocator, size_t page_size);
+
 #endif
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 10/65] libqos: add pc specific interface
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (8 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 09/65] libqos: Update QGuestAllocator to be opaque Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 11/65] qtest/ahci: Store hba_base in AHCIQState Stefan Hajnoczi
                   ` (55 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Create an operations structure so that the libqos interface can be
architecture agnostic, and create a pc-specific interface to functions
like qtest_boot.

Move the libqos object in the Makefile from being ahci-test only to
being linked with all tests that utilize the libqos features.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1421698563-6977-8-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/Makefile           |  6 +++---
 tests/ahci-test.c        |  4 ++--
 tests/libqos/libqos-pc.c | 24 ++++++++++++++++++++++++
 tests/libqos/libqos-pc.h |  9 +++++++++
 tests/libqos/libqos.c    | 16 +++++++++-------
 tests/libqos/libqos.h    | 10 ++++++++--
 6 files changed, 55 insertions(+), 14 deletions(-)
 create mode 100644 tests/libqos/libqos-pc.c
 create mode 100644 tests/libqos/libqos-pc.h

diff --git a/tests/Makefile b/tests/Makefile
index 0469bbd..415498c 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -307,9 +307,9 @@ tests/test-mul64$(EXESUF): tests/test-mul64.o libqemuutil.a
 tests/test-bitops$(EXESUF): tests/test-bitops.o libqemuutil.a
 
 libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
-libqos-obj-y += tests/libqos/i2c.o
+libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
 libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
-libqos-pc-obj-y += tests/libqos/malloc-pc.o
+libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
 libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o
 libqos-virtio-obj-y = $(libqos-obj-y) $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o
 libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o
@@ -320,7 +320,7 @@ tests/endianness-test$(EXESUF): tests/endianness-test.o
 tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y)
 tests/fdc-test$(EXESUF): tests/fdc-test.o
 tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
-tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y) tests/libqos/libqos.o
+tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y)
 tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
 tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y)
 tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o $(libqos-obj-y)
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 15542b9..3bc9772 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -29,7 +29,7 @@
 #include <glib.h>
 
 #include "libqtest.h"
-#include "libqos/libqos.h"
+#include "libqos/libqos-pc.h"
 #include "libqos/ahci.h"
 #include "libqos/pci-pc.h"
 #include "libqos/malloc-pc.h"
@@ -151,7 +151,7 @@ static AHCIQState *ahci_boot(void)
         " -M q35 "
         "-device ide-hd,drive=drive0 "
         "-global ide-hd.ver=%s";
-    s->parent = qtest_boot(cli, tmp_path, "testdisk", "version");
+    s->parent = qtest_pc_boot(cli, tmp_path, "testdisk", "version");
 
     /* Verify that we have an AHCI device present. */
     s->dev = get_ahci_device();
diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c
new file mode 100644
index 0000000..bbace89
--- /dev/null
+++ b/tests/libqos/libqos-pc.c
@@ -0,0 +1,24 @@
+#include "libqos/libqos-pc.h"
+#include "libqos/malloc-pc.h"
+
+static QOSOps qos_ops = {
+    .init_allocator = pc_alloc_init_flags,
+    .uninit_allocator = pc_alloc_uninit
+};
+
+QOSState *qtest_pc_boot(const char *cmdline_fmt, ...)
+{
+    QOSState *qs;
+    va_list ap;
+
+    va_start(ap, cmdline_fmt);
+    qs = qtest_vboot(&qos_ops, cmdline_fmt, ap);
+    va_end(ap);
+
+    return qs;
+}
+
+void qtest_pc_shutdown(QOSState *qs)
+{
+    return qtest_shutdown(qs);
+}
diff --git a/tests/libqos/libqos-pc.h b/tests/libqos/libqos-pc.h
new file mode 100644
index 0000000..316857d
--- /dev/null
+++ b/tests/libqos/libqos-pc.h
@@ -0,0 +1,9 @@
+#ifndef __libqos_pc_h
+#define __libqos_pc_h
+
+#include "libqos/libqos.h"
+
+QOSState *qtest_pc_boot(const char *cmdline_fmt, ...);
+void qtest_pc_shutdown(QOSState *qs);
+
+#endif
diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c
index c8b3ef0..bc8beb2 100644
--- a/tests/libqos/libqos.c
+++ b/tests/libqos/libqos.c
@@ -8,7 +8,6 @@
 #include "libqtest.h"
 #include "libqos/libqos.h"
 #include "libqos/pci.h"
-#include "libqos/malloc-pc.h"
 
 /*** Test Setup & Teardown ***/
 
@@ -16,7 +15,7 @@
  * Launch QEMU with the given command line,
  * and then set up interrupts and our guest malloc interface.
  */
-QOSState *qtest_vboot(const char *cmdline_fmt, va_list ap)
+QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap)
 {
     char *cmdline;
 
@@ -24,8 +23,11 @@ QOSState *qtest_vboot(const char *cmdline_fmt, va_list ap)
 
     cmdline = g_strdup_vprintf(cmdline_fmt, ap);
     qs->qts = qtest_start(cmdline);
+    qs->ops = ops;
     qtest_irq_intercept_in(global_qtest, "ioapic");
-    qs->alloc = pc_alloc_init();
+    if (ops && ops->init_allocator) {
+        qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS);
+    }
 
     g_free(cmdline);
     return qs;
@@ -35,13 +37,13 @@ QOSState *qtest_vboot(const char *cmdline_fmt, va_list ap)
  * Launch QEMU with the given command line,
  * and then set up interrupts and our guest malloc interface.
  */
-QOSState *qtest_boot(const char *cmdline_fmt, ...)
+QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...)
 {
     QOSState *qs;
     va_list ap;
 
     va_start(ap, cmdline_fmt);
-    qs = qtest_vboot(cmdline_fmt, ap);
+    qs = qtest_vboot(ops, cmdline_fmt, ap);
     va_end(ap);
 
     return qs;
@@ -52,8 +54,8 @@ QOSState *qtest_boot(const char *cmdline_fmt, ...)
  */
 void qtest_shutdown(QOSState *qs)
 {
-    if (qs->alloc) {
-        pc_alloc_uninit(qs->alloc);
+    if (qs->alloc && qs->ops && qs->ops->uninit_allocator) {
+        qs->ops->uninit_allocator(qs->alloc);
         qs->alloc = NULL;
     }
     qtest_quit(qs->qts);
diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h
index 7ae0a8d..612d41e 100644
--- a/tests/libqos/libqos.h
+++ b/tests/libqos/libqos.h
@@ -5,13 +5,19 @@
 #include "libqos/pci.h"
 #include "libqos/malloc-pc.h"
 
+typedef struct QOSOps {
+    QGuestAllocator *(*init_allocator)(QAllocOpts);
+    void (*uninit_allocator)(QGuestAllocator *);
+} QOSOps;
+
 typedef struct QOSState {
     QTestState *qts;
     QGuestAllocator *alloc;
+    QOSOps *ops;
 } QOSState;
 
-QOSState *qtest_vboot(const char *cmdline_fmt, va_list ap);
-QOSState *qtest_boot(const char *cmdline_fmt, ...);
+QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap);
+QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...);
 void qtest_shutdown(QOSState *qs);
 
 static inline uint64_t qmalloc(QOSState *q, size_t bytes)
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 11/65] qtest/ahci: Store hba_base in AHCIQState
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (9 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 10/65] libqos: add pc specific interface Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 12/65] qtest/ahci: finalize AHCIQState consolidation Stefan Hajnoczi
                   ` (54 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Store the HBA memory base address in the new state object, to simplify
function prototypes and encourage a more functional testing style.

This causes a lot of churn, but this patch is as "simplified" as I could
get it to be. This patch is therefore fairly mechanical and straightforward:
Any case where we pass "hba_base" has been consolidated into the AHCIQState
object and we pass the one unified parameter.

Any case where we reference "ahci" and "hba_state" have been modified to use
"ahci->dev" for the PCIDevice and "ahci->hba_state" to get at the base memory
address, accordingly.

Notes:

 - A needless return is removed from start_ahci_device.

 - For ease of reviewing, this patch can be reproduced (mostly) by:
   # Replace (ahci, hba_base) prototypes with unified parameter
   's/(QPCIDevice \*ahci, void \*\?\*hba_base/(AHCIQState *ahci/'

   # Replace (ahci->dev, hba_base) calls with unified parameter
   's/(ahci->dev, &\?hba_base)/(ahci)/'

   # Replace calls to PCI config space using "ahci" with "ahci->dev"
   's/qpci_config_\(read\|write\)\(.\)(ahci,/qpci_config_\1\2(ahci->dev,/'

   After these, the remaining differences are easy to review by hand.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1421698563-6977-9-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   | 136 +++++++++++++++++++++++++---------------------------
 tests/libqos/ahci.h |   1 +
 2 files changed, 65 insertions(+), 72 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 3bc9772..a6e507f 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -52,8 +52,9 @@ static bool ahci_pedantic;
 static uint32_t ahci_fingerprint;
 
 /*** IO macros for the AHCI memory registers. ***/
-#define AHCI_READ(OFST) qpci_io_readl(ahci, hba_base + (OFST))
-#define AHCI_WRITE(OFST, VAL) qpci_io_writel(ahci, hba_base + (OFST), (VAL))
+#define AHCI_READ(OFST) qpci_io_readl(ahci->dev, ahci->hba_base + (OFST))
+#define AHCI_WRITE(OFST, VAL) qpci_io_writel(ahci->dev,                 \
+                                             ahci->hba_base + (OFST), (VAL))
 #define AHCI_RREG(regno)      AHCI_READ(4 * (regno))
 #define AHCI_WREG(regno, val) AHCI_WRITE(4 * (regno), (val))
 #define AHCI_SET(regno, mask) AHCI_WREG((regno), AHCI_RREG(regno) | (mask))
@@ -70,16 +71,17 @@ static uint32_t ahci_fingerprint;
 
 /*** Function Declarations ***/
 static QPCIDevice *get_ahci_device(void);
-static QPCIDevice *start_ahci_device(QPCIDevice *dev, void **hba_base);
+static void start_ahci_device(AHCIQState *ahci);
 static void free_ahci_device(QPCIDevice *dev);
-static void ahci_test_port_spec(QPCIDevice *ahci, void *hba_base,
+
+static void ahci_test_port_spec(AHCIQState *ahci,
                                 HBACap *hcap, uint8_t port);
-static void ahci_test_pci_spec(QPCIDevice *ahci);
-static void ahci_test_pci_caps(QPCIDevice *ahci, uint16_t header,
+static void ahci_test_pci_spec(AHCIQState *ahci);
+static void ahci_test_pci_caps(AHCIQState *ahci, uint16_t header,
                                uint8_t offset);
-static void ahci_test_satacap(QPCIDevice *ahci, uint8_t offset);
-static void ahci_test_msicap(QPCIDevice *ahci, uint8_t offset);
-static void ahci_test_pmcap(QPCIDevice *ahci, uint8_t offset);
+static void ahci_test_satacap(AHCIQState *ahci, uint8_t offset);
+static void ahci_test_msicap(AHCIQState *ahci, uint8_t offset);
+static void ahci_test_pmcap(AHCIQState *ahci, uint8_t offset);
 
 /*** Utilities ***/
 
@@ -178,21 +180,21 @@ static void ahci_shutdown(AHCIQState *ahci)
 /**
  * Start the PCI device and sanity-check default operation.
  */
-static void ahci_pci_enable(QPCIDevice *ahci, void **hba_base)
+static void ahci_pci_enable(AHCIQState *ahci)
 {
     uint8_t reg;
 
-    start_ahci_device(ahci, hba_base);
+    start_ahci_device(ahci);
 
     switch (ahci_fingerprint) {
     case AHCI_INTEL_ICH9:
         /* ICH9 has a register at PCI 0x92 that
          * acts as a master port enabler mask. */
-        reg = qpci_config_readb(ahci, 0x92);
+        reg = qpci_config_readb(ahci->dev, 0x92);
         reg |= 0x3F;
-        qpci_config_writeb(ahci, 0x92, reg);
+        qpci_config_writeb(ahci->dev, 0x92, reg);
         /* 0...0111111b -- bit significant, ports 0-5 enabled. */
-        ASSERT_BIT_SET(qpci_config_readb(ahci, 0x92), 0x3F);
+        ASSERT_BIT_SET(qpci_config_readb(ahci->dev, 0x92), 0x3F);
         break;
     }
 
@@ -201,15 +203,13 @@ static void ahci_pci_enable(QPCIDevice *ahci, void **hba_base)
 /**
  * Map BAR5/ABAR, and engage the PCI device.
  */
-static QPCIDevice *start_ahci_device(QPCIDevice *ahci, void **hba_base)
+static void start_ahci_device(AHCIQState *ahci)
 {
     /* Map AHCI's ABAR (BAR5) */
-    *hba_base = qpci_iomap(ahci, 5, &barsize);
+    ahci->hba_base = qpci_iomap(ahci->dev, 5, &barsize);
 
     /* turns on pci.cmd.iose, pci.cmd.mse and pci.cmd.bme */
-    qpci_device_enable(ahci);
-
-    return ahci;
+    qpci_device_enable(ahci->dev);
 }
 
 /**
@@ -217,7 +217,7 @@ static QPCIDevice *start_ahci_device(QPCIDevice *ahci, void **hba_base)
  * Initialize and start any ports with devices attached.
  * Bring the HBA into the idle state.
  */
-static void ahci_hba_enable(QPCIDevice *ahci, void *hba_base)
+static void ahci_hba_enable(AHCIQState *ahci)
 {
     /* Bits of interest in this section:
      * GHC.AE     Global Host Control / AHCI Enable
@@ -230,14 +230,11 @@ static void ahci_hba_enable(QPCIDevice *ahci, void *hba_base)
      */
 
     g_assert(ahci != NULL);
-    g_assert(hba_base != NULL);
 
     uint32_t reg, ports_impl, clb, fb;
     uint16_t i;
     uint8_t num_cmd_slots;
 
-    g_assert(hba_base != 0);
-
     /* Set GHC.AE to 1 */
     AHCI_SET(AHCI_GHC, AHCI_GHC_AE);
     reg = AHCI_RREG(AHCI_GHC);
@@ -351,14 +348,14 @@ static void ahci_hba_enable(QPCIDevice *ahci, void *hba_base)
 /**
  * Implementation for test_pci_spec. Ensures PCI configuration space is sane.
  */
-static void ahci_test_pci_spec(QPCIDevice *ahci)
+static void ahci_test_pci_spec(AHCIQState *ahci)
 {
     uint8_t datab;
     uint16_t data;
     uint32_t datal;
 
     /* Most of these bits should start cleared until we turn them on. */
-    data = qpci_config_readw(ahci, PCI_COMMAND);
+    data = qpci_config_readw(ahci->dev, PCI_COMMAND);
     ASSERT_BIT_CLEAR(data, PCI_COMMAND_MEMORY);
     ASSERT_BIT_CLEAR(data, PCI_COMMAND_MASTER);
     ASSERT_BIT_CLEAR(data, PCI_COMMAND_SPECIAL);     /* Reserved */
@@ -370,7 +367,7 @@ static void ahci_test_pci_spec(QPCIDevice *ahci)
     ASSERT_BIT_CLEAR(data, PCI_COMMAND_INTX_DISABLE);
     ASSERT_BIT_CLEAR(data, 0xF800);                  /* Reserved */
 
-    data = qpci_config_readw(ahci, PCI_STATUS);
+    data = qpci_config_readw(ahci->dev, PCI_STATUS);
     ASSERT_BIT_CLEAR(data, 0x01 | 0x02 | 0x04);     /* Reserved */
     ASSERT_BIT_CLEAR(data, PCI_STATUS_INTERRUPT);
     ASSERT_BIT_SET(data, PCI_STATUS_CAP_LIST);      /* must be set */
@@ -383,7 +380,7 @@ static void ahci_test_pci_spec(QPCIDevice *ahci)
     ASSERT_BIT_CLEAR(data, PCI_STATUS_DETECTED_PARITY);
 
     /* RID occupies the low byte, CCs occupy the high three. */
-    datal = qpci_config_readl(ahci, PCI_CLASS_REVISION);
+    datal = qpci_config_readl(ahci->dev, PCI_CLASS_REVISION);
     if (ahci_pedantic) {
         /* AHCI 1.3 specifies that at-boot, the RID should reset to 0x00,
          * Though in practice this is likely seldom true. */
@@ -406,38 +403,38 @@ static void ahci_test_pci_spec(QPCIDevice *ahci)
         g_assert_not_reached();
     }
 
-    datab = qpci_config_readb(ahci, PCI_CACHE_LINE_SIZE);
+    datab = qpci_config_readb(ahci->dev, PCI_CACHE_LINE_SIZE);
     g_assert_cmphex(datab, ==, 0);
 
-    datab = qpci_config_readb(ahci, PCI_LATENCY_TIMER);
+    datab = qpci_config_readb(ahci->dev, PCI_LATENCY_TIMER);
     g_assert_cmphex(datab, ==, 0);
 
     /* Only the bottom 7 bits must be off. */
-    datab = qpci_config_readb(ahci, PCI_HEADER_TYPE);
+    datab = qpci_config_readb(ahci->dev, PCI_HEADER_TYPE);
     ASSERT_BIT_CLEAR(datab, 0x7F);
 
     /* BIST is optional, but the low 7 bits must always start off regardless. */
-    datab = qpci_config_readb(ahci, PCI_BIST);
+    datab = qpci_config_readb(ahci->dev, PCI_BIST);
     ASSERT_BIT_CLEAR(datab, 0x7F);
 
     /* BARS 0-4 do not have a boot spec, but ABAR/BAR5 must be clean. */
-    datal = qpci_config_readl(ahci, PCI_BASE_ADDRESS_5);
+    datal = qpci_config_readl(ahci->dev, PCI_BASE_ADDRESS_5);
     g_assert_cmphex(datal, ==, 0);
 
-    qpci_config_writel(ahci, PCI_BASE_ADDRESS_5, 0xFFFFFFFF);
-    datal = qpci_config_readl(ahci, PCI_BASE_ADDRESS_5);
+    qpci_config_writel(ahci->dev, PCI_BASE_ADDRESS_5, 0xFFFFFFFF);
+    datal = qpci_config_readl(ahci->dev, PCI_BASE_ADDRESS_5);
     /* ABAR must be 32-bit, memory mapped, non-prefetchable and
      * must be >= 512 bytes. To that end, bits 0-8 must be off. */
     ASSERT_BIT_CLEAR(datal, 0xFF);
 
     /* Capability list MUST be present, */
-    datal = qpci_config_readl(ahci, PCI_CAPABILITY_LIST);
+    datal = qpci_config_readl(ahci->dev, PCI_CAPABILITY_LIST);
     /* But these bits are reserved. */
     ASSERT_BIT_CLEAR(datal, ~0xFF);
     g_assert_cmphex(datal, !=, 0);
 
     /* Check specification adherence for capability extenstions. */
-    data = qpci_config_readw(ahci, datal);
+    data = qpci_config_readw(ahci->dev, datal);
 
     switch (ahci_fingerprint) {
     case AHCI_INTEL_ICH9:
@@ -452,18 +449,18 @@ static void ahci_test_pci_spec(QPCIDevice *ahci)
     ahci_test_pci_caps(ahci, data, (uint8_t)datal);
 
     /* Reserved. */
-    datal = qpci_config_readl(ahci, PCI_CAPABILITY_LIST + 4);
+    datal = qpci_config_readl(ahci->dev, PCI_CAPABILITY_LIST + 4);
     g_assert_cmphex(datal, ==, 0);
 
     /* IPIN might vary, but ILINE must be off. */
-    datab = qpci_config_readb(ahci, PCI_INTERRUPT_LINE);
+    datab = qpci_config_readb(ahci->dev, PCI_INTERRUPT_LINE);
     g_assert_cmphex(datab, ==, 0);
 }
 
 /**
  * Test PCI capabilities for AHCI specification adherence.
  */
-static void ahci_test_pci_caps(QPCIDevice *ahci, uint16_t header,
+static void ahci_test_pci_caps(AHCIQState *ahci, uint16_t header,
                                uint8_t offset)
 {
     uint8_t cid = header & 0xFF;
@@ -487,14 +484,14 @@ static void ahci_test_pci_caps(QPCIDevice *ahci, uint16_t header,
     }
 
     if (next) {
-        ahci_test_pci_caps(ahci, qpci_config_readw(ahci, next), next);
+        ahci_test_pci_caps(ahci, qpci_config_readw(ahci->dev, next), next);
     }
 }
 
 /**
  * Test SATA PCI capabilitity for AHCI specification adherence.
  */
-static void ahci_test_satacap(QPCIDevice *ahci, uint8_t offset)
+static void ahci_test_satacap(AHCIQState *ahci, uint8_t offset)
 {
     uint16_t dataw;
     uint32_t datal;
@@ -502,11 +499,11 @@ static void ahci_test_satacap(QPCIDevice *ahci, uint8_t offset)
     g_test_message("Verifying SATACAP");
 
     /* Assert that the SATACAP version is 1.0, And reserved bits are empty. */
-    dataw = qpci_config_readw(ahci, offset + 2);
+    dataw = qpci_config_readw(ahci->dev, offset + 2);
     g_assert_cmphex(dataw, ==, 0x10);
 
     /* Grab the SATACR1 register. */
-    datal = qpci_config_readw(ahci, offset + 4);
+    datal = qpci_config_readw(ahci->dev, offset + 4);
 
     switch (datal & 0x0F) {
     case 0x04: /* BAR0 */
@@ -529,30 +526,30 @@ static void ahci_test_satacap(QPCIDevice *ahci, uint8_t offset)
 /**
  * Test MSI PCI capability for AHCI specification adherence.
  */
-static void ahci_test_msicap(QPCIDevice *ahci, uint8_t offset)
+static void ahci_test_msicap(AHCIQState *ahci, uint8_t offset)
 {
     uint16_t dataw;
     uint32_t datal;
 
     g_test_message("Verifying MSICAP");
 
-    dataw = qpci_config_readw(ahci, offset + PCI_MSI_FLAGS);
+    dataw = qpci_config_readw(ahci->dev, offset + PCI_MSI_FLAGS);
     ASSERT_BIT_CLEAR(dataw, PCI_MSI_FLAGS_ENABLE);
     ASSERT_BIT_CLEAR(dataw, PCI_MSI_FLAGS_QSIZE);
     ASSERT_BIT_CLEAR(dataw, PCI_MSI_FLAGS_RESERVED);
 
-    datal = qpci_config_readl(ahci, offset + PCI_MSI_ADDRESS_LO);
+    datal = qpci_config_readl(ahci->dev, offset + PCI_MSI_ADDRESS_LO);
     g_assert_cmphex(datal, ==, 0);
 
     if (dataw & PCI_MSI_FLAGS_64BIT) {
         g_test_message("MSICAP is 64bit");
-        datal = qpci_config_readl(ahci, offset + PCI_MSI_ADDRESS_HI);
+        datal = qpci_config_readl(ahci->dev, offset + PCI_MSI_ADDRESS_HI);
         g_assert_cmphex(datal, ==, 0);
-        dataw = qpci_config_readw(ahci, offset + PCI_MSI_DATA_64);
+        dataw = qpci_config_readw(ahci->dev, offset + PCI_MSI_DATA_64);
         g_assert_cmphex(dataw, ==, 0);
     } else {
         g_test_message("MSICAP is 32bit");
-        dataw = qpci_config_readw(ahci, offset + PCI_MSI_DATA_32);
+        dataw = qpci_config_readw(ahci->dev, offset + PCI_MSI_DATA_32);
         g_assert_cmphex(dataw, ==, 0);
     }
 }
@@ -560,26 +557,26 @@ static void ahci_test_msicap(QPCIDevice *ahci, uint8_t offset)
 /**
  * Test Power Management PCI capability for AHCI specification adherence.
  */
-static void ahci_test_pmcap(QPCIDevice *ahci, uint8_t offset)
+static void ahci_test_pmcap(AHCIQState *ahci, uint8_t offset)
 {
     uint16_t dataw;
 
     g_test_message("Verifying PMCAP");
 
-    dataw = qpci_config_readw(ahci, offset + PCI_PM_PMC);
+    dataw = qpci_config_readw(ahci->dev, offset + PCI_PM_PMC);
     ASSERT_BIT_CLEAR(dataw, PCI_PM_CAP_PME_CLOCK);
     ASSERT_BIT_CLEAR(dataw, PCI_PM_CAP_RESERVED);
     ASSERT_BIT_CLEAR(dataw, PCI_PM_CAP_D1);
     ASSERT_BIT_CLEAR(dataw, PCI_PM_CAP_D2);
 
-    dataw = qpci_config_readw(ahci, offset + PCI_PM_CTRL);
+    dataw = qpci_config_readw(ahci->dev, offset + PCI_PM_CTRL);
     ASSERT_BIT_CLEAR(dataw, PCI_PM_CTRL_STATE_MASK);
     ASSERT_BIT_CLEAR(dataw, PCI_PM_CTRL_RESERVED);
     ASSERT_BIT_CLEAR(dataw, PCI_PM_CTRL_DATA_SEL_MASK);
     ASSERT_BIT_CLEAR(dataw, PCI_PM_CTRL_DATA_SCALE_MASK);
 }
 
-static void ahci_test_hba_spec(QPCIDevice *ahci, void *hba_base)
+static void ahci_test_hba_spec(AHCIQState *ahci)
 {
     HBACap hcap;
     unsigned i;
@@ -588,8 +585,7 @@ static void ahci_test_hba_spec(QPCIDevice *ahci, void *hba_base)
     uint8_t nports_impl;
     uint8_t maxports;
 
-    g_assert(ahci != 0);
-    g_assert(hba_base != 0);
+    g_assert(ahci != NULL);
 
     /*
      * Note that the AHCI spec does expect the BIOS to set up a few things:
@@ -731,7 +727,7 @@ static void ahci_test_hba_spec(QPCIDevice *ahci, void *hba_base)
     for (i = 0; ports || (i < maxports); ports >>= 1, ++i) {
         if (BITSET(ports, 0x1)) {
             g_test_message("Testing port %u for spec", i);
-            ahci_test_port_spec(ahci, hba_base, &hcap, i);
+            ahci_test_port_spec(ahci, &hcap, i);
         } else {
             uint16_t j;
             uint16_t low = AHCI_PORTS + (32 * i);
@@ -750,7 +746,7 @@ static void ahci_test_hba_spec(QPCIDevice *ahci, void *hba_base)
 /**
  * Test the memory space for one port for specification adherence.
  */
-static void ahci_test_port_spec(QPCIDevice *ahci, void *hba_base,
+static void ahci_test_port_spec(AHCIQState *ahci,
                                 HBACap *hcap, uint8_t port)
 {
     uint32_t reg;
@@ -902,7 +898,7 @@ static void ahci_test_port_spec(QPCIDevice *ahci, void *hba_base,
  * Utilizing an initialized AHCI HBA, issue an IDENTIFY command to the first
  * device we see, then read and check the response.
  */
-static void ahci_test_identify(QPCIDevice *ahci, void *hba_base)
+static void ahci_test_identify(AHCIQState *ahci)
 {
     RegD2HFIS *d2h = g_malloc0(0x20);
     RegD2HFIS *pio = g_malloc0(0x20);
@@ -915,7 +911,6 @@ static void ahci_test_identify(QPCIDevice *ahci, void *hba_base)
     int rc;
 
     g_assert(ahci != NULL);
-    g_assert(hba_base != NULL);
 
     /* We need to:
      * (1) Create a Command Table Buffer and update the Command List Slot #0
@@ -1100,7 +1095,7 @@ static void test_pci_spec(void)
 {
     AHCIQState *ahci;
     ahci = ahci_boot();
-    ahci_test_pci_spec(ahci->dev);
+    ahci_test_pci_spec(ahci);
     ahci_shutdown(ahci);
 }
 
@@ -1111,9 +1106,9 @@ static void test_pci_spec(void)
 static void test_pci_enable(void)
 {
     AHCIQState *ahci;
-    void *hba_base;
+
     ahci = ahci_boot();
-    ahci_pci_enable(ahci->dev, &hba_base);
+    ahci_pci_enable(ahci);
     ahci_shutdown(ahci);
 }
 
@@ -1124,11 +1119,10 @@ static void test_pci_enable(void)
 static void test_hba_spec(void)
 {
     AHCIQState *ahci;
-    void *hba_base;
 
     ahci = ahci_boot();
-    ahci_pci_enable(ahci->dev, &hba_base);
-    ahci_test_hba_spec(ahci->dev, hba_base);
+    ahci_pci_enable(ahci);
+    ahci_test_hba_spec(ahci);
     ahci_shutdown(ahci);
 }
 
@@ -1139,11 +1133,10 @@ static void test_hba_spec(void)
 static void test_hba_enable(void)
 {
     AHCIQState *ahci;
-    void *hba_base;
 
     ahci = ahci_boot();
-    ahci_pci_enable(ahci->dev, &hba_base);
-    ahci_hba_enable(ahci->dev, hba_base);
+    ahci_pci_enable(ahci);
+    ahci_hba_enable(ahci);
     ahci_shutdown(ahci);
 }
 
@@ -1154,12 +1147,11 @@ static void test_hba_enable(void)
 static void test_identify(void)
 {
     AHCIQState *ahci;
-    void *hba_base;
 
     ahci = ahci_boot();
-    ahci_pci_enable(ahci->dev, &hba_base);
-    ahci_hba_enable(ahci->dev, hba_base);
-    ahci_test_identify(ahci->dev, hba_base);
+    ahci_pci_enable(ahci);
+    ahci_hba_enable(ahci);
+    ahci_test_identify(ahci);
     ahci_shutdown(ahci);
 }
 
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index bc5f45d..e9e0206 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -248,6 +248,7 @@
 typedef struct AHCIQState {
     QOSState *parent;
     QPCIDevice *dev;
+    void *hba_base;
 } AHCIQState;
 
 /**
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 12/65] qtest/ahci: finalize AHCIQState consolidation
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (10 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 11/65] qtest/ahci: Store hba_base in AHCIQState Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 13/65] qtest/ahci: remove pcibus global Stefan Hajnoczi
                   ` (53 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Move barsize, ahci_fingerprint and capabilities registers into
the AHCIQState object, removing global ahci-related state
from the ahci-test.c file.

More churn, less globals.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1421698563-6977-10-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   | 80 +++++++++++++++++++++++++----------------------------
 tests/libqos/ahci.h |  9 +++---
 2 files changed, 42 insertions(+), 47 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index a6e507f..96fb45c 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -46,10 +46,8 @@
 /*** Globals ***/
 static QGuestAllocator *guest_malloc;
 static QPCIBus *pcibus;
-static uint64_t barsize;
 static char tmp_path[] = "/tmp/qtest.XXXXXX";
 static bool ahci_pedantic;
-static uint32_t ahci_fingerprint;
 
 /*** IO macros for the AHCI memory registers. ***/
 #define AHCI_READ(OFST) qpci_io_readl(ahci->dev, ahci->hba_base + (OFST))
@@ -70,12 +68,11 @@ static uint32_t ahci_fingerprint;
                                           PX_RREG((port), (reg)) & ~(mask));
 
 /*** Function Declarations ***/
-static QPCIDevice *get_ahci_device(void);
+static QPCIDevice *get_ahci_device(uint32_t *fingerprint);
 static void start_ahci_device(AHCIQState *ahci);
 static void free_ahci_device(QPCIDevice *dev);
 
-static void ahci_test_port_spec(AHCIQState *ahci,
-                                HBACap *hcap, uint8_t port);
+static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port);
 static void ahci_test_pci_spec(AHCIQState *ahci);
 static void ahci_test_pci_caps(AHCIQState *ahci, uint16_t header,
                                uint8_t offset);
@@ -99,9 +96,10 @@ static void string_bswap16(uint16_t *s, size_t bytes)
 /**
  * Locate, verify, and return a handle to the AHCI device.
  */
-static QPCIDevice *get_ahci_device(void)
+static QPCIDevice *get_ahci_device(uint32_t *fingerprint)
 {
     QPCIDevice *ahci;
+    uint32_t ahci_fingerprint;
 
     pcibus = qpci_init_pc();
 
@@ -119,6 +117,9 @@ static QPCIDevice *get_ahci_device(void)
         g_assert_not_reached();
     }
 
+    if (fingerprint) {
+        *fingerprint = ahci_fingerprint;
+    }
     return ahci;
 }
 
@@ -131,9 +132,6 @@ static void free_ahci_device(QPCIDevice *ahci)
         qpci_free_pc(pcibus);
         pcibus = NULL;
     }
-
-    /* Clear our cached barsize information. */
-    barsize = 0;
 }
 
 /*** Test Setup & Teardown ***/
@@ -156,7 +154,7 @@ static AHCIQState *ahci_boot(void)
     s->parent = qtest_pc_boot(cli, tmp_path, "testdisk", "version");
 
     /* Verify that we have an AHCI device present. */
-    s->dev = get_ahci_device();
+    s->dev = get_ahci_device(&s->fingerprint);
 
     /* Stopgap: Copy the allocator reference */
     guest_malloc = s->parent->alloc;
@@ -186,7 +184,7 @@ static void ahci_pci_enable(AHCIQState *ahci)
 
     start_ahci_device(ahci);
 
-    switch (ahci_fingerprint) {
+    switch (ahci->fingerprint) {
     case AHCI_INTEL_ICH9:
         /* ICH9 has a register at PCI 0x92 that
          * acts as a master port enabler mask. */
@@ -206,7 +204,7 @@ static void ahci_pci_enable(AHCIQState *ahci)
 static void start_ahci_device(AHCIQState *ahci)
 {
     /* Map AHCI's ABAR (BAR5) */
-    ahci->hba_base = qpci_iomap(ahci->dev, 5, &barsize);
+    ahci->hba_base = qpci_iomap(ahci->dev, 5, &ahci->barsize);
 
     /* turns on pci.cmd.iose, pci.cmd.mse and pci.cmd.bme */
     qpci_device_enable(ahci->dev);
@@ -228,21 +226,23 @@ static void ahci_hba_enable(AHCIQState *ahci)
      * PxCMD.FR   "FIS Receive Running"
      * PxCMD.CR   "Command List Running"
      */
-
-    g_assert(ahci != NULL);
-
     uint32_t reg, ports_impl, clb, fb;
     uint16_t i;
     uint8_t num_cmd_slots;
 
+    g_assert(ahci != NULL);
+
     /* Set GHC.AE to 1 */
     AHCI_SET(AHCI_GHC, AHCI_GHC_AE);
     reg = AHCI_RREG(AHCI_GHC);
     ASSERT_BIT_SET(reg, AHCI_GHC_AE);
 
+    /* Cache CAP and CAP2. */
+    ahci->cap = AHCI_RREG(AHCI_CAP);
+    ahci->cap2 = AHCI_RREG(AHCI_CAP2);
+
     /* Read CAP.NCS, how many command slots do we have? */
-    reg = AHCI_RREG(AHCI_CAP);
-    num_cmd_slots = ((reg & AHCI_CAP_NCS) >> ctzl(AHCI_CAP_NCS)) + 1;
+    num_cmd_slots = ((ahci->cap & AHCI_CAP_NCS) >> ctzl(AHCI_CAP_NCS)) + 1;
     g_test_message("Number of Command Slots: %u", num_cmd_slots);
 
     /* Determine which ports are implemented. */
@@ -436,7 +436,7 @@ static void ahci_test_pci_spec(AHCIQState *ahci)
     /* Check specification adherence for capability extenstions. */
     data = qpci_config_readw(ahci->dev, datal);
 
-    switch (ahci_fingerprint) {
+    switch (ahci->fingerprint) {
     case AHCI_INTEL_ICH9:
         /* Intel ICH9 Family Datasheet 14.1.19 p.550 */
         g_assert_cmphex((data & 0xFF), ==, PCI_CAP_ID_MSI);
@@ -578,9 +578,8 @@ static void ahci_test_pmcap(AHCIQState *ahci, uint8_t offset)
 
 static void ahci_test_hba_spec(AHCIQState *ahci)
 {
-    HBACap hcap;
     unsigned i;
-    uint32_t cap, cap2, reg;
+    uint32_t reg;
     uint32_t ports;
     uint8_t nports_impl;
     uint8_t maxports;
@@ -608,15 +607,15 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
      */
 
     /* 1 CAP - Capabilities Register */
-    cap = AHCI_RREG(AHCI_CAP);
-    ASSERT_BIT_CLEAR(cap, AHCI_CAP_RESERVED);
+    ahci->cap = AHCI_RREG(AHCI_CAP);
+    ASSERT_BIT_CLEAR(ahci->cap, AHCI_CAP_RESERVED);
 
     /* 2 GHC - Global Host Control */
     reg = AHCI_RREG(AHCI_GHC);
     ASSERT_BIT_CLEAR(reg, AHCI_GHC_HR);
     ASSERT_BIT_CLEAR(reg, AHCI_GHC_IE);
     ASSERT_BIT_CLEAR(reg, AHCI_GHC_MRSM);
-    if (BITSET(cap, AHCI_CAP_SAM)) {
+    if (BITSET(ahci->cap, AHCI_CAP_SAM)) {
         g_test_message("Supports AHCI-Only Mode: GHC_AE is Read-Only.");
         ASSERT_BIT_SET(reg, AHCI_GHC_AE);
     } else {
@@ -634,13 +633,13 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
     g_assert_cmphex(ports, !=, 0);
     /* Ports Implemented must be <= Number of Ports. */
     nports_impl = ctpopl(ports);
-    g_assert_cmpuint(((AHCI_CAP_NP & cap) + 1), >=, nports_impl);
+    g_assert_cmpuint(((AHCI_CAP_NP & ahci->cap) + 1), >=, nports_impl);
 
-    g_assert_cmphex(barsize, >, 0);
     /* Ports must be within the proper range. Given a mapping of SIZE,
      * 256 bytes are used for global HBA control, and the rest is used
      * for ports data, at 0x80 bytes each. */
-    maxports = (barsize - HBA_DATA_REGION_SIZE) / HBA_PORT_DATA_SIZE;
+    g_assert_cmphex(ahci->barsize, >, 0);
+    maxports = (ahci->barsize - HBA_DATA_REGION_SIZE) / HBA_PORT_DATA_SIZE;
     /* e.g, 30 ports for 4K of memory. (4096 - 256) / 128 = 30 */
     g_assert_cmphex((reg >> maxports), ==, 0);
 
@@ -659,7 +658,7 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
 
     /* 6 Command Completion Coalescing Control: depends on CAP.CCCS. */
     reg = AHCI_RREG(AHCI_CCCCTL);
-    if (BITSET(cap, AHCI_CAP_CCCS)) {
+    if (BITSET(ahci->cap, AHCI_CAP_CCCS)) {
         ASSERT_BIT_CLEAR(reg, AHCI_CCCCTL_EN);
         ASSERT_BIT_CLEAR(reg, AHCI_CCCCTL_RESERVED);
         ASSERT_BIT_SET(reg, AHCI_CCCCTL_CC);
@@ -675,13 +674,13 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
 
     /* 8 EM_LOC */
     reg = AHCI_RREG(AHCI_EMLOC);
-    if (BITCLR(cap, AHCI_CAP_EMS)) {
+    if (BITCLR(ahci->cap, AHCI_CAP_EMS)) {
         g_assert_cmphex(reg, ==, 0);
     }
 
     /* 9 EM_CTL */
     reg = AHCI_RREG(AHCI_EMCTL);
-    if (BITSET(cap, AHCI_CAP_EMS)) {
+    if (BITSET(ahci->cap, AHCI_CAP_EMS)) {
         ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_STSMR);
         ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_CTLTM);
         ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_CTLRST);
@@ -691,8 +690,8 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
     }
 
     /* 10 CAP2 -- Capabilities Extended */
-    cap2 = AHCI_RREG(AHCI_CAP2);
-    ASSERT_BIT_CLEAR(cap2, AHCI_CAP2_RESERVED);
+    ahci->cap2 = AHCI_RREG(AHCI_CAP2);
+    ASSERT_BIT_CLEAR(ahci->cap2, AHCI_CAP2_RESERVED);
 
     /* 11 BOHC -- Bios/OS Handoff Control */
     reg = AHCI_RREG(AHCI_BOHC);
@@ -706,7 +705,7 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
     }
 
     /* 24 -- 39: NVMHCI */
-    if (BITCLR(cap2, AHCI_CAP2_NVMP)) {
+    if (BITCLR(ahci->cap2, AHCI_CAP2_NVMP)) {
         g_test_message("Verifying HBA/NVMHCI area is empty.");
         for (i = AHCI_NVMHCI; i < AHCI_VENDOR; ++i) {
             reg = AHCI_RREG(i);
@@ -722,12 +721,10 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
     }
 
     /* 64 -- XX: Port Space */
-    hcap.cap = cap;
-    hcap.cap2 = cap2;
     for (i = 0; ports || (i < maxports); ports >>= 1, ++i) {
         if (BITSET(ports, 0x1)) {
             g_test_message("Testing port %u for spec", i);
-            ahci_test_port_spec(ahci, &hcap, i);
+            ahci_test_port_spec(ahci, i);
         } else {
             uint16_t j;
             uint16_t low = AHCI_PORTS + (32 * i);
@@ -746,8 +743,7 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
 /**
  * Test the memory space for one port for specification adherence.
  */
-static void ahci_test_port_spec(AHCIQState *ahci,
-                                HBACap *hcap, uint8_t port)
+static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port)
 {
     uint32_t reg;
     unsigned i;
@@ -757,7 +753,7 @@ static void ahci_test_port_spec(AHCIQState *ahci,
     ASSERT_BIT_CLEAR(reg, AHCI_PX_CLB_RESERVED);
 
     /* (1) CLBU */
-    if (BITCLR(hcap->cap, AHCI_CAP_S64A)) {
+    if (BITCLR(ahci->cap, AHCI_CAP_S64A)) {
         reg = PX_RREG(port, AHCI_PX_CLBU);
         g_assert_cmphex(reg, ==, 0);
     }
@@ -767,7 +763,7 @@ static void ahci_test_port_spec(AHCIQState *ahci,
     ASSERT_BIT_CLEAR(reg, AHCI_PX_FB_RESERVED);
 
     /* (3) FBU */
-    if (BITCLR(hcap->cap, AHCI_CAP_S64A)) {
+    if (BITCLR(ahci->cap, AHCI_CAP_S64A)) {
         reg = PX_RREG(port, AHCI_PX_FBU);
         g_assert_cmphex(reg, ==, 0);
     }
@@ -803,7 +799,7 @@ static void ahci_test_port_spec(AHCIQState *ahci,
         ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_MPSS);
     }
     /* If we do not support MPS, MPSS and MPSP must be off. */
-    if (BITCLR(hcap->cap, AHCI_CAP_SMPS)) {
+    if (BITCLR(ahci->cap, AHCI_CAP_SMPS)) {
         ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_MPSS);
         ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_MPSP);
     }
@@ -814,7 +810,7 @@ static void ahci_test_port_spec(AHCIQState *ahci,
     /* HPCP and ESP cannot both be active. */
     g_assert(!BITSET(reg, AHCI_PX_CMD_HPCP | AHCI_PX_CMD_ESP));
     /* If CAP.FBSS is not set, FBSCP must not be set. */
-    if (BITCLR(hcap->cap, AHCI_CAP_FBSS)) {
+    if (BITCLR(ahci->cap, AHCI_CAP_FBSS)) {
         ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FBSCP);
     }
 
@@ -874,7 +870,7 @@ static void ahci_test_port_spec(AHCIQState *ahci,
     ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_DEV);
     ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_DWE);
     ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_RESERVED);
-    if (BITSET(hcap->cap, AHCI_CAP_FBSS)) {
+    if (BITSET(ahci->cap, AHCI_CAP_FBSS)) {
         /* if Port-Multiplier FIS-based switching avail, ADO must >= 2 */
         g_assert((reg & AHCI_PX_FBS_ADO) >> ctzl(AHCI_PX_FBS_ADO) >= 2);
     }
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index e9e0206..8e92385 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -249,6 +249,10 @@ typedef struct AHCIQState {
     QOSState *parent;
     QPCIDevice *dev;
     void *hba_base;
+    uint64_t barsize;
+    uint32_t fingerprint;
+    uint32_t cap;
+    uint32_t cap2;
 } AHCIQState;
 
 /**
@@ -340,11 +344,6 @@ typedef struct PRD {
     uint32_t dbc;  /* Data Byte Count (0-indexed) & Interrupt Flag (bit 2^31) */
 } PRD;
 
-typedef struct HBACap {
-    uint32_t cap;
-    uint32_t cap2;
-} HBACap;
-
 /*** Macro Utilities ***/
 #define BITANY(data, mask) (((data) & (mask)) != 0)
 #define BITSET(data, mask) (((data) & (mask)) == (mask))
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 13/65] qtest/ahci: remove pcibus global
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (11 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 12/65] qtest/ahci: finalize AHCIQState consolidation Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 14/65] qtest/ahci: remove guest_malloc global Stefan Hajnoczi
                   ` (52 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Rely on the PCI Device's bus pointer instead.
One less global to worry about.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1421698563-6977-11-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 96fb45c..0cc56ab 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -45,7 +45,6 @@
 
 /*** Globals ***/
 static QGuestAllocator *guest_malloc;
-static QPCIBus *pcibus;
 static char tmp_path[] = "/tmp/qtest.XXXXXX";
 static bool ahci_pedantic;
 
@@ -100,6 +99,7 @@ static QPCIDevice *get_ahci_device(uint32_t *fingerprint)
 {
     QPCIDevice *ahci;
     uint32_t ahci_fingerprint;
+    QPCIBus *pcibus;
 
     pcibus = qpci_init_pc();
 
@@ -123,15 +123,13 @@ static QPCIDevice *get_ahci_device(uint32_t *fingerprint)
     return ahci;
 }
 
-static void free_ahci_device(QPCIDevice *ahci)
+static void free_ahci_device(QPCIDevice *dev)
 {
-    /* libqos doesn't have a function for this, so free it manually */
-    g_free(ahci);
+    QPCIBus *pcibus = dev ? dev->bus : NULL;
 
-    if (pcibus) {
-        qpci_free_pc(pcibus);
-        pcibus = NULL;
-    }
+    /* libqos doesn't have a function for this, so free it manually */
+    g_free(dev);
+    qpci_free_pc(pcibus);
 }
 
 /*** Test Setup & Teardown ***/
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 14/65] qtest/ahci: remove guest_malloc global
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (12 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 13/65] qtest/ahci: remove pcibus global Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 15/65] libqos/ahci: Functional register helpers Stefan Hajnoczi
                   ` (51 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Make helper routines rely on the earmarked
guest allocator object with AHCIQState/QOSSTate instead.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1421698563-6977-12-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 0cc56ab..bb98968 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -32,7 +32,6 @@
 #include "libqos/libqos-pc.h"
 #include "libqos/ahci.h"
 #include "libqos/pci-pc.h"
-#include "libqos/malloc-pc.h"
 
 #include "qemu-common.h"
 #include "qemu/host-utils.h"
@@ -44,7 +43,6 @@
 #define TEST_IMAGE_SIZE    (64 * 1024 * 1024)
 
 /*** Globals ***/
-static QGuestAllocator *guest_malloc;
 static char tmp_path[] = "/tmp/qtest.XXXXXX";
 static bool ahci_pedantic;
 
@@ -92,6 +90,11 @@ static void string_bswap16(uint16_t *s, size_t bytes)
     }
 }
 
+static uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes)
+{
+    return qmalloc(ahci->parent, bytes);
+}
+
 /**
  * Locate, verify, and return a handle to the AHCI device.
  */
@@ -154,9 +157,6 @@ static AHCIQState *ahci_boot(void)
     /* Verify that we have an AHCI device present. */
     s->dev = get_ahci_device(&s->fingerprint);
 
-    /* Stopgap: Copy the allocator reference */
-    guest_malloc = s->parent->alloc;
-
     return s;
 }
 
@@ -272,13 +272,13 @@ static void ahci_hba_enable(AHCIQState *ahci)
 
         /* Allocate Memory for the Command List Buffer & FIS Buffer */
         /* PxCLB space ... 0x20 per command, as in 4.2.2 p 36 */
-        clb = guest_alloc(guest_malloc, num_cmd_slots * 0x20);
+        clb = ahci_alloc(ahci, num_cmd_slots * 0x20);
         g_test_message("CLB: 0x%08x", clb);
         PX_WREG(i, AHCI_PX_CLB, clb);
         g_assert_cmphex(clb, ==, PX_RREG(i, AHCI_PX_CLB));
 
         /* PxFB space ... 0x100, as in 4.2.1 p 35 */
-        fb = guest_alloc(guest_malloc, 0x100);
+        fb = ahci_alloc(ahci, 0x100);
         g_test_message("FB: 0x%08x", fb);
         PX_WREG(i, AHCI_PX_FB, fb);
         g_assert_cmphex(fb, ==, PX_RREG(i, AHCI_PX_FB));
@@ -951,12 +951,12 @@ static void ahci_test_identify(AHCIQState *ahci)
 
     /* Create a Command Table buffer. 0x80 is the smallest with a PRDTL of 0. */
     /* We need at least one PRD, so round up to the nearest 0x80 multiple.    */
-    table = guest_alloc(guest_malloc, CMD_TBL_SIZ(1));
+    table = ahci_alloc(ahci, CMD_TBL_SIZ(1));
     g_assert(table);
     ASSERT_BIT_CLEAR(table, 0x7F);
 
     /* Create a data buffer ... where we will dump the IDENTIFY data to. */
-    data_ptr = guest_alloc(guest_malloc, 512);
+    data_ptr = ahci_alloc(ahci, 512);
     g_assert(data_ptr);
 
     /* Grab the Command List Buffer pointer */
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 15/65] libqos/ahci: Functional register helpers
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (13 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 14/65] qtest/ahci: remove guest_malloc global Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 16/65] qtest/ahci: remove getter/setter macros Stefan Hajnoczi
                   ` (50 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Introduce a set of "static inline" register helpers that are intended to
replace the current set of macros with more functional versions that are
better suited to inclusion in libqos than porcelain macros.

As a stopgap measure before eliminating the porcelain macros, define them
to use the new functions defined in the ahci.h header.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1421698563-6977-13-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   | 25 ++++++++++-----------
 tests/libqos/ahci.h | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+), 14 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index bb98968..25e54b8 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -47,22 +47,19 @@ static char tmp_path[] = "/tmp/qtest.XXXXXX";
 static bool ahci_pedantic;
 
 /*** IO macros for the AHCI memory registers. ***/
-#define AHCI_READ(OFST) qpci_io_readl(ahci->dev, ahci->hba_base + (OFST))
-#define AHCI_WRITE(OFST, VAL) qpci_io_writel(ahci->dev,                 \
-                                             ahci->hba_base + (OFST), (VAL))
-#define AHCI_RREG(regno)      AHCI_READ(4 * (regno))
-#define AHCI_WREG(regno, val) AHCI_WRITE(4 * (regno), (val))
-#define AHCI_SET(regno, mask) AHCI_WREG((regno), AHCI_RREG(regno) | (mask))
-#define AHCI_CLR(regno, mask) AHCI_WREG((regno), AHCI_RREG(regno) & ~(mask))
+#define AHCI_READ(OFST)       ahci_mread(ahci, (OFST))
+#define AHCI_WRITE(OFST, VAL) ahci_mwrite(ahci, (OFST), (VAL))
+#define AHCI_RREG(regno)      ahci_rreg(ahci, (regno))
+#define AHCI_WREG(regno, val) ahci_wreg(ahci, (regno), (val))
+#define AHCI_SET(regno, mask) ahci_set(ahci, (regno), (mask))
+#define AHCI_CLR(regno, mask) ahci_clr(ahci, (regno), (mask))
 
 /*** IO macros for port-specific offsets inside of AHCI memory. ***/
-#define PX_OFST(port, regno) (HBA_PORT_NUM_REG * (port) + AHCI_PORTS + (regno))
-#define PX_RREG(port, regno)      AHCI_RREG(PX_OFST((port), (regno)))
-#define PX_WREG(port, regno, val) AHCI_WREG(PX_OFST((port), (regno)), (val))
-#define PX_SET(port, reg, mask)   PX_WREG((port), (reg),                \
-                                          PX_RREG((port), (reg)) | (mask));
-#define PX_CLR(port, reg, mask)   PX_WREG((port), (reg),                \
-                                          PX_RREG((port), (reg)) & ~(mask));
+#define PX_OFST(port, regno)      ahci_px_ofst((port), (regno))
+#define PX_RREG(port, regno)      ahci_px_rreg(ahci, (port), (regno))
+#define PX_WREG(port, regno, val) ahci_px_wreg(ahci, (port), (regno), (val))
+#define PX_SET(port, reg, mask)   ahci_px_set(ahci, (port), (reg), (mask))
+#define PX_CLR(port, reg, mask)   ahci_px_clr(ahci, (port), (reg), (mask))
 
 /*** Function Declarations ***/
 static QPCIDevice *get_ahci_device(uint32_t *fingerprint);
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 8e92385..645f05b 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -354,4 +354,67 @@ typedef struct PRD {
 /* For calculating how big the PRD table needs to be: */
 #define CMD_TBL_SIZ(n) ((0x80 + ((n) * sizeof(PRD)) + 0x7F) & ~0x7F)
 
+/* Helpers for reading/writing AHCI HBA register values */
+
+static inline uint32_t ahci_mread(AHCIQState *ahci, size_t offset)
+{
+    return qpci_io_readl(ahci->dev, ahci->hba_base + offset);
+}
+
+static inline void ahci_mwrite(AHCIQState *ahci, size_t offset, uint32_t value)
+{
+    qpci_io_writel(ahci->dev, ahci->hba_base + offset, value);
+}
+
+static inline uint32_t ahci_rreg(AHCIQState *ahci, uint32_t reg_num)
+{
+    return ahci_mread(ahci, 4 * reg_num);
+}
+
+static inline void ahci_wreg(AHCIQState *ahci, uint32_t reg_num, uint32_t value)
+{
+    ahci_mwrite(ahci, 4 * reg_num, value);
+}
+
+static inline void ahci_set(AHCIQState *ahci, uint32_t reg_num, uint32_t mask)
+{
+    ahci_wreg(ahci, reg_num, ahci_rreg(ahci, reg_num) | mask);
+}
+
+static inline void ahci_clr(AHCIQState *ahci, uint32_t reg_num, uint32_t mask)
+{
+    ahci_wreg(ahci, reg_num, ahci_rreg(ahci, reg_num) & ~mask);
+}
+
+static inline size_t ahci_px_offset(uint8_t port, uint32_t reg_num)
+{
+    return AHCI_PORTS + (HBA_PORT_NUM_REG * port) + reg_num;
+}
+
+static inline uint32_t ahci_px_rreg(AHCIQState *ahci, uint8_t port,
+                                    uint32_t reg_num)
+{
+    return ahci_rreg(ahci, ahci_px_offset(port, reg_num));
+}
+
+static inline void ahci_px_wreg(AHCIQState *ahci, uint8_t port,
+                                uint32_t reg_num, uint32_t value)
+{
+    ahci_wreg(ahci, ahci_px_offset(port, reg_num), value);
+}
+
+static inline void ahci_px_set(AHCIQState *ahci, uint8_t port,
+                               uint32_t reg_num, uint32_t mask)
+{
+    ahci_px_wreg(ahci, port, reg_num,
+                 ahci_px_rreg(ahci, port, reg_num) | mask);
+}
+
+static inline void ahci_px_clr(AHCIQState *ahci, uint8_t port,
+                               uint32_t reg_num, uint32_t mask)
+{
+    ahci_px_wreg(ahci, port, reg_num,
+                 ahci_px_rreg(ahci, port, reg_num) & ~mask);
+}
+
 #endif
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 16/65] qtest/ahci: remove getter/setter macros
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (14 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 15/65] libqos/ahci: Functional register helpers Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 17/65] qtest/ahci: Bookmark FB and CLB pointers Stefan Hajnoczi
                   ` (49 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

These macros were a bad idea: They relied upon certain arguments being
present locally with a specific name.

With the endgoal being to factor out AHCI helper functions outside of
the test file itself, these have to be replaced by more explicit helper
setter/getter functions.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1421698563-6977-14-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c | 178 +++++++++++++++++++++++++-----------------------------
 1 file changed, 83 insertions(+), 95 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 25e54b8..aa1f66f 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -46,21 +46,6 @@
 static char tmp_path[] = "/tmp/qtest.XXXXXX";
 static bool ahci_pedantic;
 
-/*** IO macros for the AHCI memory registers. ***/
-#define AHCI_READ(OFST)       ahci_mread(ahci, (OFST))
-#define AHCI_WRITE(OFST, VAL) ahci_mwrite(ahci, (OFST), (VAL))
-#define AHCI_RREG(regno)      ahci_rreg(ahci, (regno))
-#define AHCI_WREG(regno, val) ahci_wreg(ahci, (regno), (val))
-#define AHCI_SET(regno, mask) ahci_set(ahci, (regno), (mask))
-#define AHCI_CLR(regno, mask) ahci_clr(ahci, (regno), (mask))
-
-/*** IO macros for port-specific offsets inside of AHCI memory. ***/
-#define PX_OFST(port, regno)      ahci_px_ofst((port), (regno))
-#define PX_RREG(port, regno)      ahci_px_rreg(ahci, (port), (regno))
-#define PX_WREG(port, regno, val) ahci_px_wreg(ahci, (port), (regno), (val))
-#define PX_SET(port, reg, mask)   ahci_px_set(ahci, (port), (reg), (mask))
-#define PX_CLR(port, reg, mask)   ahci_px_clr(ahci, (port), (reg), (mask))
-
 /*** Function Declarations ***/
 static QPCIDevice *get_ahci_device(uint32_t *fingerprint);
 static void start_ahci_device(AHCIQState *ahci);
@@ -228,20 +213,20 @@ static void ahci_hba_enable(AHCIQState *ahci)
     g_assert(ahci != NULL);
 
     /* Set GHC.AE to 1 */
-    AHCI_SET(AHCI_GHC, AHCI_GHC_AE);
-    reg = AHCI_RREG(AHCI_GHC);
+    ahci_set(ahci, AHCI_GHC, AHCI_GHC_AE);
+    reg = ahci_rreg(ahci, AHCI_GHC);
     ASSERT_BIT_SET(reg, AHCI_GHC_AE);
 
     /* Cache CAP and CAP2. */
-    ahci->cap = AHCI_RREG(AHCI_CAP);
-    ahci->cap2 = AHCI_RREG(AHCI_CAP2);
+    ahci->cap = ahci_rreg(ahci, AHCI_CAP);
+    ahci->cap2 = ahci_rreg(ahci, AHCI_CAP2);
 
     /* Read CAP.NCS, how many command slots do we have? */
     num_cmd_slots = ((ahci->cap & AHCI_CAP_NCS) >> ctzl(AHCI_CAP_NCS)) + 1;
     g_test_message("Number of Command Slots: %u", num_cmd_slots);
 
     /* Determine which ports are implemented. */
-    ports_impl = AHCI_RREG(AHCI_PI);
+    ports_impl = ahci_rreg(ahci, AHCI_PI);
 
     for (i = 0; ports_impl; ports_impl >>= 1, ++i) {
         if (!(ports_impl & 0x01)) {
@@ -250,16 +235,17 @@ static void ahci_hba_enable(AHCIQState *ahci)
 
         g_test_message("Initializing port %u", i);
 
-        reg = PX_RREG(i, AHCI_PX_CMD);
+        reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD);
         if (BITCLR(reg, AHCI_PX_CMD_ST | AHCI_PX_CMD_CR |
                    AHCI_PX_CMD_FRE | AHCI_PX_CMD_FR)) {
             g_test_message("port is idle");
         } else {
             g_test_message("port needs to be idled");
-            PX_CLR(i, AHCI_PX_CMD, (AHCI_PX_CMD_ST | AHCI_PX_CMD_FRE));
+            ahci_px_clr(ahci, i, AHCI_PX_CMD,
+                        (AHCI_PX_CMD_ST | AHCI_PX_CMD_FRE));
             /* The port has 500ms to disengage. */
             usleep(500000);
-            reg = PX_RREG(i, AHCI_PX_CMD);
+            reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD);
             ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CR);
             ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FR);
             g_test_message("port is now idle");
@@ -271,55 +257,56 @@ static void ahci_hba_enable(AHCIQState *ahci)
         /* PxCLB space ... 0x20 per command, as in 4.2.2 p 36 */
         clb = ahci_alloc(ahci, num_cmd_slots * 0x20);
         g_test_message("CLB: 0x%08x", clb);
-        PX_WREG(i, AHCI_PX_CLB, clb);
-        g_assert_cmphex(clb, ==, PX_RREG(i, AHCI_PX_CLB));
+        ahci_px_wreg(ahci, i, AHCI_PX_CLB, clb);
+        g_assert_cmphex(clb, ==, ahci_px_rreg(ahci, i, AHCI_PX_CLB));
 
         /* PxFB space ... 0x100, as in 4.2.1 p 35 */
         fb = ahci_alloc(ahci, 0x100);
         g_test_message("FB: 0x%08x", fb);
-        PX_WREG(i, AHCI_PX_FB, fb);
-        g_assert_cmphex(fb, ==, PX_RREG(i, AHCI_PX_FB));
+        ahci_px_wreg(ahci, i, AHCI_PX_FB, fb);
+        g_assert_cmphex(fb, ==, ahci_px_rreg(ahci, i, AHCI_PX_FB));
 
         /* Clear PxSERR, PxIS, then IS.IPS[x] by writing '1's. */
-        PX_WREG(i, AHCI_PX_SERR, 0xFFFFFFFF);
-        PX_WREG(i, AHCI_PX_IS, 0xFFFFFFFF);
-        AHCI_WREG(AHCI_IS, (1 << i));
+        ahci_px_wreg(ahci, i, AHCI_PX_SERR, 0xFFFFFFFF);
+        ahci_px_wreg(ahci, i, AHCI_PX_IS, 0xFFFFFFFF);
+        ahci_wreg(ahci, AHCI_IS, (1 << i));
 
         /* Verify Interrupts Cleared */
-        reg = PX_RREG(i, AHCI_PX_SERR);
+        reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR);
         g_assert_cmphex(reg, ==, 0);
 
-        reg = PX_RREG(i, AHCI_PX_IS);
+        reg = ahci_px_rreg(ahci, i, AHCI_PX_IS);
         g_assert_cmphex(reg, ==, 0);
 
-        reg = AHCI_RREG(AHCI_IS);
+        reg = ahci_rreg(ahci, AHCI_IS);
         ASSERT_BIT_CLEAR(reg, (1 << i));
 
         /* Enable All Interrupts: */
-        PX_WREG(i, AHCI_PX_IE, 0xFFFFFFFF);
-        reg = PX_RREG(i, AHCI_PX_IE);
+        ahci_px_wreg(ahci, i, AHCI_PX_IE, 0xFFFFFFFF);
+        reg = ahci_px_rreg(ahci, i, AHCI_PX_IE);
         g_assert_cmphex(reg, ==, ~((uint32_t)AHCI_PX_IE_RESERVED));
 
         /* Enable the FIS Receive Engine. */
-        PX_SET(i, AHCI_PX_CMD, AHCI_PX_CMD_FRE);
-        reg = PX_RREG(i, AHCI_PX_CMD);
+        ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_FRE);
+        reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD);
         ASSERT_BIT_SET(reg, AHCI_PX_CMD_FR);
 
         /* AHCI 1.3 spec: if !STS.BSY, !STS.DRQ and PxSSTS.DET indicates
          * physical presence, a device is present and may be started. However,
          * PxSERR.DIAG.X /may/ need to be cleared a priori. */
-        reg = PX_RREG(i, AHCI_PX_SERR);
+        reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR);
         if (BITSET(reg, AHCI_PX_SERR_DIAG_X)) {
-            PX_SET(i, AHCI_PX_SERR, AHCI_PX_SERR_DIAG_X);
+            ahci_px_set(ahci, i, AHCI_PX_SERR, AHCI_PX_SERR_DIAG_X);
         }
 
-        reg = PX_RREG(i, AHCI_PX_TFD);
+        reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD);
         if (BITCLR(reg, AHCI_PX_TFD_STS_BSY | AHCI_PX_TFD_STS_DRQ)) {
-            reg = PX_RREG(i, AHCI_PX_SSTS);
+            reg = ahci_px_rreg(ahci, i, AHCI_PX_SSTS);
             if ((reg & AHCI_PX_SSTS_DET) == SSTS_DET_ESTABLISHED) {
                 /* Device Found: set PxCMD.ST := 1 */
-                PX_SET(i, AHCI_PX_CMD, AHCI_PX_CMD_ST);
-                ASSERT_BIT_SET(PX_RREG(i, AHCI_PX_CMD), AHCI_PX_CMD_CR);
+                ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_ST);
+                ASSERT_BIT_SET(ahci_px_rreg(ahci, i, AHCI_PX_CMD),
+                               AHCI_PX_CMD_CR);
                 g_test_message("Started Device %u", i);
             } else if ((reg & AHCI_PX_SSTS_DET)) {
                 /* Device present, but in some unknown state. */
@@ -329,8 +316,8 @@ static void ahci_hba_enable(AHCIQState *ahci)
     }
 
     /* Enable GHC.IE */
-    AHCI_SET(AHCI_GHC, AHCI_GHC_IE);
-    reg = AHCI_RREG(AHCI_GHC);
+    ahci_set(ahci, AHCI_GHC, AHCI_GHC_IE);
+    reg = ahci_rreg(ahci, AHCI_GHC);
     ASSERT_BIT_SET(reg, AHCI_GHC_IE);
 
     /* TODO: The device should now be idling and waiting for commands.
@@ -602,11 +589,11 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
      */
 
     /* 1 CAP - Capabilities Register */
-    ahci->cap = AHCI_RREG(AHCI_CAP);
+    ahci->cap = ahci_rreg(ahci, AHCI_CAP);
     ASSERT_BIT_CLEAR(ahci->cap, AHCI_CAP_RESERVED);
 
     /* 2 GHC - Global Host Control */
-    reg = AHCI_RREG(AHCI_GHC);
+    reg = ahci_rreg(ahci, AHCI_GHC);
     ASSERT_BIT_CLEAR(reg, AHCI_GHC_HR);
     ASSERT_BIT_CLEAR(reg, AHCI_GHC_IE);
     ASSERT_BIT_CLEAR(reg, AHCI_GHC_MRSM);
@@ -619,11 +606,11 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
     }
 
     /* 3 IS - Interrupt Status */
-    reg = AHCI_RREG(AHCI_IS);
+    reg = ahci_rreg(ahci, AHCI_IS);
     g_assert_cmphex(reg, ==, 0);
 
     /* 4 PI - Ports Implemented */
-    ports = AHCI_RREG(AHCI_PI);
+    ports = ahci_rreg(ahci, AHCI_PI);
     /* Ports Implemented must be non-zero. */
     g_assert_cmphex(ports, !=, 0);
     /* Ports Implemented must be <= Number of Ports. */
@@ -639,7 +626,7 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
     g_assert_cmphex((reg >> maxports), ==, 0);
 
     /* 5 AHCI Version */
-    reg = AHCI_RREG(AHCI_VS);
+    reg = ahci_rreg(ahci, AHCI_VS);
     switch (reg) {
     case AHCI_VERSION_0_95:
     case AHCI_VERSION_1_0:
@@ -652,7 +639,7 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
     }
 
     /* 6 Command Completion Coalescing Control: depends on CAP.CCCS. */
-    reg = AHCI_RREG(AHCI_CCCCTL);
+    reg = ahci_rreg(ahci, AHCI_CCCCTL);
     if (BITSET(ahci->cap, AHCI_CAP_CCCS)) {
         ASSERT_BIT_CLEAR(reg, AHCI_CCCCTL_EN);
         ASSERT_BIT_CLEAR(reg, AHCI_CCCCTL_RESERVED);
@@ -663,18 +650,18 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
     }
 
     /* 7 CCC_PORTS */
-    reg = AHCI_RREG(AHCI_CCCPORTS);
+    reg = ahci_rreg(ahci, AHCI_CCCPORTS);
     /* Must be zeroes initially regardless of CAP.CCCS */
     g_assert_cmphex(reg, ==, 0);
 
     /* 8 EM_LOC */
-    reg = AHCI_RREG(AHCI_EMLOC);
+    reg = ahci_rreg(ahci, AHCI_EMLOC);
     if (BITCLR(ahci->cap, AHCI_CAP_EMS)) {
         g_assert_cmphex(reg, ==, 0);
     }
 
     /* 9 EM_CTL */
-    reg = AHCI_RREG(AHCI_EMCTL);
+    reg = ahci_rreg(ahci, AHCI_EMCTL);
     if (BITSET(ahci->cap, AHCI_CAP_EMS)) {
         ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_STSMR);
         ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_CTLTM);
@@ -685,17 +672,17 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
     }
 
     /* 10 CAP2 -- Capabilities Extended */
-    ahci->cap2 = AHCI_RREG(AHCI_CAP2);
+    ahci->cap2 = ahci_rreg(ahci, AHCI_CAP2);
     ASSERT_BIT_CLEAR(ahci->cap2, AHCI_CAP2_RESERVED);
 
     /* 11 BOHC -- Bios/OS Handoff Control */
-    reg = AHCI_RREG(AHCI_BOHC);
+    reg = ahci_rreg(ahci, AHCI_BOHC);
     g_assert_cmphex(reg, ==, 0);
 
     /* 12 -- 23: Reserved */
     g_test_message("Verifying HBA reserved area is empty.");
     for (i = AHCI_RESERVED; i < AHCI_NVMHCI; ++i) {
-        reg = AHCI_RREG(i);
+        reg = ahci_rreg(ahci, i);
         g_assert_cmphex(reg, ==, 0);
     }
 
@@ -703,7 +690,7 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
     if (BITCLR(ahci->cap2, AHCI_CAP2_NVMP)) {
         g_test_message("Verifying HBA/NVMHCI area is empty.");
         for (i = AHCI_NVMHCI; i < AHCI_VENDOR; ++i) {
-            reg = AHCI_RREG(i);
+            reg = ahci_rreg(ahci, i);
             g_assert_cmphex(reg, ==, 0);
         }
     }
@@ -711,7 +698,7 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
     /* 40 -- 63: Vendor */
     g_test_message("Verifying HBA/Vendor area is empty.");
     for (i = AHCI_VENDOR; i < AHCI_PORTS; ++i) {
-        reg = AHCI_RREG(i);
+        reg = ahci_rreg(ahci, i);
         g_assert_cmphex(reg, ==, 0);
     }
 
@@ -728,7 +715,7 @@ static void ahci_test_hba_spec(AHCIQState *ahci)
                            "(reg [%u-%u]) is empty.",
                            i, low, high - 1);
             for (j = low; j < high; ++j) {
-                reg = AHCI_RREG(j);
+                reg = ahci_rreg(ahci, j);
                 g_assert_cmphex(reg, ==, 0);
             }
         }
@@ -744,35 +731,35 @@ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port)
     unsigned i;
 
     /* (0) CLB */
-    reg = PX_RREG(port, AHCI_PX_CLB);
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_CLB);
     ASSERT_BIT_CLEAR(reg, AHCI_PX_CLB_RESERVED);
 
     /* (1) CLBU */
     if (BITCLR(ahci->cap, AHCI_CAP_S64A)) {
-        reg = PX_RREG(port, AHCI_PX_CLBU);
+        reg = ahci_px_rreg(ahci, port, AHCI_PX_CLBU);
         g_assert_cmphex(reg, ==, 0);
     }
 
     /* (2) FB */
-    reg = PX_RREG(port, AHCI_PX_FB);
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_FB);
     ASSERT_BIT_CLEAR(reg, AHCI_PX_FB_RESERVED);
 
     /* (3) FBU */
     if (BITCLR(ahci->cap, AHCI_CAP_S64A)) {
-        reg = PX_RREG(port, AHCI_PX_FBU);
+        reg = ahci_px_rreg(ahci, port, AHCI_PX_FBU);
         g_assert_cmphex(reg, ==, 0);
     }
 
     /* (4) IS */
-    reg = PX_RREG(port, AHCI_PX_IS);
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_IS);
     g_assert_cmphex(reg, ==, 0);
 
     /* (5) IE */
-    reg = PX_RREG(port, AHCI_PX_IE);
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_IE);
     g_assert_cmphex(reg, ==, 0);
 
     /* (6) CMD */
-    reg = PX_RREG(port, AHCI_PX_CMD);
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_CMD);
     ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FRE);
     ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_RESERVED);
     ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CCS);
@@ -810,11 +797,11 @@ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port)
     }
 
     /* (7) RESERVED */
-    reg = PX_RREG(port, AHCI_PX_RES1);
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_RES1);
     g_assert_cmphex(reg, ==, 0);
 
     /* (8) TFD */
-    reg = PX_RREG(port, AHCI_PX_TFD);
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD);
     /* At boot, prior to an FIS being received, the TFD register should be 0x7F,
      * which breaks down as follows, as seen in AHCI 1.3 sec 3.3.8, p. 27. */
     ASSERT_BIT_SET(reg, AHCI_PX_TFD_STS_ERR);
@@ -832,33 +819,33 @@ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port)
      * so we cannot expect a value here. AHCI 1.3, sec 3.3.9, pp 27-28 */
 
     /* (10) SSTS / SCR0: SStatus */
-    reg = PX_RREG(port, AHCI_PX_SSTS);
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_SSTS);
     ASSERT_BIT_CLEAR(reg, AHCI_PX_SSTS_RESERVED);
     /* Even though the register should be 0 at boot, it is asynchronous and
      * prone to change, so we cannot test any well known value. */
 
     /* (11) SCTL / SCR2: SControl */
-    reg = PX_RREG(port, AHCI_PX_SCTL);
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_SCTL);
     g_assert_cmphex(reg, ==, 0);
 
     /* (12) SERR / SCR1: SError */
-    reg = PX_RREG(port, AHCI_PX_SERR);
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_SERR);
     g_assert_cmphex(reg, ==, 0);
 
     /* (13) SACT / SCR3: SActive */
-    reg = PX_RREG(port, AHCI_PX_SACT);
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_SACT);
     g_assert_cmphex(reg, ==, 0);
 
     /* (14) CI */
-    reg = PX_RREG(port, AHCI_PX_CI);
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_CI);
     g_assert_cmphex(reg, ==, 0);
 
     /* (15) SNTF */
-    reg = PX_RREG(port, AHCI_PX_SNTF);
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_SNTF);
     g_assert_cmphex(reg, ==, 0);
 
     /* (16) FBS */
-    reg = PX_RREG(port, AHCI_PX_FBS);
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_FBS);
     ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_EN);
     ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_DEC);
     ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_SDE);
@@ -872,13 +859,13 @@ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port)
 
     /* [17 -- 27] RESERVED */
     for (i = AHCI_PX_RES2; i < AHCI_PX_VS; ++i) {
-        reg = PX_RREG(port, i);
+        reg = ahci_px_rreg(ahci, port, i);
         g_assert_cmphex(reg, ==, 0);
     }
 
     /* [28 -- 31] Vendor-Specific */
     for (i = AHCI_PX_VS; i < 32; ++i) {
-        reg = PX_RREG(port, i);
+        reg = ahci_px_rreg(ahci, port, i);
         if (reg) {
             g_test_message("INFO: Vendor register %u non-empty", i);
         }
@@ -918,7 +905,7 @@ static void ahci_test_identify(AHCIQState *ahci)
      */
 
     /* Pick the first implemented and running port */
-    ports = AHCI_RREG(AHCI_PI);
+    ports = ahci_rreg(ahci, AHCI_PI);
     for (i = 0; i < 32; ports >>= 1, ++i) {
         if (ports == 0) {
             i = 32;
@@ -928,7 +915,7 @@ static void ahci_test_identify(AHCIQState *ahci)
             continue;
         }
 
-        reg = PX_RREG(i, AHCI_PX_CMD);
+        reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD);
         if (BITSET(reg, AHCI_PX_CMD_ST)) {
             break;
         }
@@ -937,12 +924,12 @@ static void ahci_test_identify(AHCIQState *ahci)
     g_test_message("Selected port %u for test", i);
 
     /* Clear out this port's interrupts (ignore the init register d2h fis) */
-    reg = PX_RREG(i, AHCI_PX_IS);
-    PX_WREG(i, AHCI_PX_IS, reg);
-    g_assert_cmphex(PX_RREG(i, AHCI_PX_IS), ==, 0);
+    reg = ahci_px_rreg(ahci, i, AHCI_PX_IS);
+    ahci_px_wreg(ahci, i, AHCI_PX_IS, reg);
+    g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
 
     /* Wipe the FIS-Receive Buffer */
-    fb = PX_RREG(i, AHCI_PX_FB);
+    fb = ahci_px_rreg(ahci, i, AHCI_PX_FB);
     g_assert_cmphex(fb, !=, 0);
     qmemset(fb, 0x00, 0x100);
 
@@ -957,7 +944,7 @@ static void ahci_test_identify(AHCIQState *ahci)
     g_assert(data_ptr);
 
     /* Grab the Command List Buffer pointer */
-    clb = PX_RREG(i, AHCI_PX_CLB);
+    clb = ahci_px_rreg(ahci, i, AHCI_PX_CLB);
     g_assert(clb);
 
     /* Copy the existing Command #0 structure from the CLB into local memory,
@@ -985,7 +972,7 @@ static void ahci_test_identify(AHCIQState *ahci)
     fis.flags = 0x80;    /* Indicate this is a command FIS */
 
     /* We've committed nothing yet, no interrupts should be posted yet. */
-    g_assert_cmphex(PX_RREG(i, AHCI_PX_IS), ==, 0);
+    g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
 
     /* Commit the Command FIS to the Command Table */
     memwrite(table, &fis, sizeof(fis));
@@ -997,29 +984,30 @@ static void ahci_test_identify(AHCIQState *ahci)
     memwrite(clb, &cmd, sizeof(cmd));
 
     /* Everything is in place, but we haven't given the go-ahead yet. */
-    g_assert_cmphex(PX_RREG(i, AHCI_PX_IS), ==, 0);
+    g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
 
     /* Issue Command #0 via PxCI */
-    PX_WREG(i, AHCI_PX_CI, (1 << 0));
-    while (BITSET(PX_RREG(i, AHCI_PX_TFD), AHCI_PX_TFD_STS_BSY)) {
+    ahci_px_wreg(ahci, i, AHCI_PX_CI, (1 << 0));
+    while (BITSET(ahci_px_rreg(ahci, i, AHCI_PX_TFD), AHCI_PX_TFD_STS_BSY)) {
         usleep(50);
     }
 
     /* Check for expected interrupts */
-    reg = PX_RREG(i, AHCI_PX_IS);
+    reg = ahci_px_rreg(ahci, i, AHCI_PX_IS);
     ASSERT_BIT_SET(reg, AHCI_PX_IS_DHRS);
     ASSERT_BIT_SET(reg, AHCI_PX_IS_PSS);
     /* BUG: we expect AHCI_PX_IS_DPS to be set. */
     ASSERT_BIT_CLEAR(reg, AHCI_PX_IS_DPS);
 
     /* Clear expected interrupts and assert all interrupts now cleared. */
-    PX_WREG(i, AHCI_PX_IS, AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS | AHCI_PX_IS_DPS);
-    g_assert_cmphex(PX_RREG(i, AHCI_PX_IS), ==, 0);
+    ahci_px_wreg(ahci, i, AHCI_PX_IS,
+                 AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS | AHCI_PX_IS_DPS);
+    g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
 
     /* Check for errors. */
-    reg = PX_RREG(i, AHCI_PX_SERR);
+    reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR);
     g_assert_cmphex(reg, ==, 0);
-    reg = PX_RREG(i, AHCI_PX_TFD);
+    reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD);
     ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_ERR);
     ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR);
 
@@ -1036,7 +1024,7 @@ static void ahci_test_identify(AHCIQState *ahci)
     g_assert_cmphex(pio->status, ==, d2h->status);
     g_assert_cmphex(pio->error, ==, d2h->error);
 
-    reg = PX_RREG(i, AHCI_PX_TFD);
+    reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD);
     g_assert_cmphex((reg & AHCI_PX_TFD_ERR), ==, pio->error);
     g_assert_cmphex((reg & AHCI_PX_TFD_STS), ==, pio->status);
     /* The PIO Setup FIS contains a "bytes read" field, which is a
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 17/65] qtest/ahci: Bookmark FB and CLB pointers
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (15 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 16/65] qtest/ahci: remove getter/setter macros Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 18/65] libqos/ahci: create libqos/ahci.c Stefan Hajnoczi
                   ` (48 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Instead of re-querying the AHCI device for the FB and CLB buffers, save
the pointer we gave to the device during initialization and reference
these values instead.

[Peter Maydell <peter.maydell@linaro.org> reported the following clang
compiler warnings:

  tests/libqos/ahci.c:256:40: warning: format specifies type 'unsigned
      long' but the argument has type 'uint64_t'
      (aka 'unsigned long long') [-Wformat]
        g_test_message("CLB: 0x%08lx", ahci->port[i].clb);
  tests/libqos/ahci.c:264:39: warning: format specifies type 'unsigned
      long' but the argument has type 'uint64_t'
      (aka 'unsigned long long') [-Wformat]
        g_test_message("FB: 0x%08lx", ahci->port[i].fb);

The commit moved from uint32_t to uint64_t, so PRIx64 should be used for
the format specifier.
--Stefan]

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1421698563-6977-15-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   | 42 ++++++++++++++++++++----------------------
 tests/libqos/ahci.h |  6 ++++++
 2 files changed, 26 insertions(+), 22 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index aa1f66f..a0a7776 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -206,7 +206,7 @@ static void ahci_hba_enable(AHCIQState *ahci)
      * PxCMD.FR   "FIS Receive Running"
      * PxCMD.CR   "Command List Running"
      */
-    uint32_t reg, ports_impl, clb, fb;
+    uint32_t reg, ports_impl;
     uint16_t i;
     uint8_t num_cmd_slots;
 
@@ -255,16 +255,20 @@ static void ahci_hba_enable(AHCIQState *ahci)
 
         /* Allocate Memory for the Command List Buffer & FIS Buffer */
         /* PxCLB space ... 0x20 per command, as in 4.2.2 p 36 */
-        clb = ahci_alloc(ahci, num_cmd_slots * 0x20);
-        g_test_message("CLB: 0x%08x", clb);
-        ahci_px_wreg(ahci, i, AHCI_PX_CLB, clb);
-        g_assert_cmphex(clb, ==, ahci_px_rreg(ahci, i, AHCI_PX_CLB));
+        ahci->port[i].clb = ahci_alloc(ahci, num_cmd_slots * 0x20);
+        qmemset(ahci->port[i].clb, 0x00, 0x100);
+        g_test_message("CLB: 0x%08" PRIx64, ahci->port[i].clb);
+        ahci_px_wreg(ahci, i, AHCI_PX_CLB, ahci->port[i].clb);
+        g_assert_cmphex(ahci->port[i].clb, ==,
+                        ahci_px_rreg(ahci, i, AHCI_PX_CLB));
 
         /* PxFB space ... 0x100, as in 4.2.1 p 35 */
-        fb = ahci_alloc(ahci, 0x100);
-        g_test_message("FB: 0x%08x", fb);
-        ahci_px_wreg(ahci, i, AHCI_PX_FB, fb);
-        g_assert_cmphex(fb, ==, ahci_px_rreg(ahci, i, AHCI_PX_FB));
+        ahci->port[i].fb = ahci_alloc(ahci, 0x100);
+        qmemset(ahci->port[i].fb, 0x00, 0x100);
+        g_test_message("FB: 0x%08" PRIx64, ahci->port[i].fb);
+        ahci_px_wreg(ahci, i, AHCI_PX_FB, ahci->port[i].fb);
+        g_assert_cmphex(ahci->port[i].fb, ==,
+                        ahci_px_rreg(ahci, i, AHCI_PX_FB));
 
         /* Clear PxSERR, PxIS, then IS.IPS[x] by writing '1's. */
         ahci_px_wreg(ahci, i, AHCI_PX_SERR, 0xFFFFFFFF);
@@ -883,7 +887,7 @@ static void ahci_test_identify(AHCIQState *ahci)
     RegH2DFIS fis;
     AHCICommand cmd;
     PRD prd;
-    uint32_t ports, reg, clb, table, fb, data_ptr;
+    uint32_t ports, reg, table, data_ptr;
     uint16_t buff[256];
     unsigned i;
     int rc;
@@ -929,9 +933,7 @@ static void ahci_test_identify(AHCIQState *ahci)
     g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
 
     /* Wipe the FIS-Receive Buffer */
-    fb = ahci_px_rreg(ahci, i, AHCI_PX_FB);
-    g_assert_cmphex(fb, !=, 0);
-    qmemset(fb, 0x00, 0x100);
+    qmemset(ahci->port[i].fb, 0x00, 0x100);
 
     /* Create a Command Table buffer. 0x80 is the smallest with a PRDTL of 0. */
     /* We need at least one PRD, so round up to the nearest 0x80 multiple.    */
@@ -943,13 +945,9 @@ static void ahci_test_identify(AHCIQState *ahci)
     data_ptr = ahci_alloc(ahci, 512);
     g_assert(data_ptr);
 
-    /* Grab the Command List Buffer pointer */
-    clb = ahci_px_rreg(ahci, i, AHCI_PX_CLB);
-    g_assert(clb);
-
     /* Copy the existing Command #0 structure from the CLB into local memory,
      * and build a new command #0. */
-    memread(clb, &cmd, sizeof(cmd));
+    memread(ahci->port[i].clb, &cmd, sizeof(cmd));
     cmd.b1 = 5;    /* reg_h2d_fis is 5 double-words long */
     cmd.b2 = 0x04; /* clear PxTFD.STS.BSY when done */
     cmd.prdtl = cpu_to_le16(1); /* One PRD table entry. */
@@ -981,7 +979,7 @@ static void ahci_test_identify(AHCIQState *ahci)
     memwrite(table + 0x80, &prd, sizeof(prd));
 
     /* Commit Command #0, pointing to the Table, to the Command List Buffer. */
-    memwrite(clb, &cmd, sizeof(cmd));
+    memwrite(ahci->port[i].clb, &cmd, sizeof(cmd));
 
     /* Everything is in place, but we haven't given the go-ahead yet. */
     g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
@@ -1012,12 +1010,12 @@ static void ahci_test_identify(AHCIQState *ahci)
     ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR);
 
     /* Investigate CMD #0, assert that we read 512 bytes */
-    memread(clb, &cmd, sizeof(cmd));
+    memread(ahci->port[i].clb, &cmd, sizeof(cmd));
     g_assert_cmphex(512, ==, le32_to_cpu(cmd.prdbc));
 
     /* Investigate FIS responses */
-    memread(fb + 0x20, pio, 0x20);
-    memread(fb + 0x40, d2h, 0x20);
+    memread(ahci->port[i].fb + 0x20, pio, 0x20);
+    memread(ahci->port[i].fb + 0x40, d2h, 0x20);
     g_assert_cmphex(pio->fis_type, ==, 0x5f);
     g_assert_cmphex(d2h->fis_type, ==, 0x34);
     g_assert_cmphex(pio->flags, ==, d2h->flags);
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 645f05b..72c39bc 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -245,6 +245,11 @@
 
 /*** Structures ***/
 
+typedef struct AHCIPortQState {
+    uint64_t fb;
+    uint64_t clb;
+} AHCIPortQState;
+
 typedef struct AHCIQState {
     QOSState *parent;
     QPCIDevice *dev;
@@ -253,6 +258,7 @@ typedef struct AHCIQState {
     uint32_t fingerprint;
     uint32_t cap;
     uint32_t cap2;
+    AHCIPortQState port[32];
 } AHCIQState;
 
 /**
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 18/65] libqos/ahci: create libqos/ahci.c
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (16 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 17/65] qtest/ahci: Bookmark FB and CLB pointers Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 19/65] dataplane: endianness-aware accesses Stefan Hajnoczi
                   ` (47 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

With global state removed, code responsible for booting up,
verifying, and initializing the AHCI HBA is extracted and
inserted into libqos/ahci.c, which would allow for other
qtests in the future to quickly grab a meaningfully initialized
reference to an AHCI HBA.

Even without other users, functionalizing and isolating the code
assists future AHCI tests that exercise Q35 migration.

For now, libqos/ahci.o will be PC-only, but can be expanded into
something arch-agnostic in the future, if needed.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1421698563-6977-16-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/Makefile      |   1 +
 tests/ahci-test.c   | 225 -------------------------------------------
 tests/libqos/ahci.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/ahci.h |  11 ++-
 4 files changed, 280 insertions(+), 226 deletions(-)
 create mode 100644 tests/libqos/ahci.c

diff --git a/tests/Makefile b/tests/Makefile
index 415498c..53a4c30 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -310,6 +310,7 @@ libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
 libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
 libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
 libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
+libqos-pc-obj-y += tests/libqos/ahci.o
 libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o
 libqos-virtio-obj-y = $(libqos-obj-y) $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o
 libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index a0a7776..fca33d2 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -47,10 +47,6 @@ static char tmp_path[] = "/tmp/qtest.XXXXXX";
 static bool ahci_pedantic;
 
 /*** Function Declarations ***/
-static QPCIDevice *get_ahci_device(uint32_t *fingerprint);
-static void start_ahci_device(AHCIQState *ahci);
-static void free_ahci_device(QPCIDevice *dev);
-
 static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port);
 static void ahci_test_pci_spec(AHCIQState *ahci);
 static void ahci_test_pci_caps(AHCIQState *ahci, uint16_t header,
@@ -72,51 +68,6 @@ static void string_bswap16(uint16_t *s, size_t bytes)
     }
 }
 
-static uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes)
-{
-    return qmalloc(ahci->parent, bytes);
-}
-
-/**
- * Locate, verify, and return a handle to the AHCI device.
- */
-static QPCIDevice *get_ahci_device(uint32_t *fingerprint)
-{
-    QPCIDevice *ahci;
-    uint32_t ahci_fingerprint;
-    QPCIBus *pcibus;
-
-    pcibus = qpci_init_pc();
-
-    /* Find the AHCI PCI device and verify it's the right one. */
-    ahci = qpci_device_find(pcibus, QPCI_DEVFN(0x1F, 0x02));
-    g_assert(ahci != NULL);
-
-    ahci_fingerprint = qpci_config_readl(ahci, PCI_VENDOR_ID);
-
-    switch (ahci_fingerprint) {
-    case AHCI_INTEL_ICH9:
-        break;
-    default:
-        /* Unknown device. */
-        g_assert_not_reached();
-    }
-
-    if (fingerprint) {
-        *fingerprint = ahci_fingerprint;
-    }
-    return ahci;
-}
-
-static void free_ahci_device(QPCIDevice *dev)
-{
-    QPCIBus *pcibus = dev ? dev->bus : NULL;
-
-    /* libqos doesn't have a function for this, so free it manually */
-    g_free(dev);
-    qpci_free_pc(pcibus);
-}
-
 /*** Test Setup & Teardown ***/
 
 /**
@@ -153,182 +104,6 @@ static void ahci_shutdown(AHCIQState *ahci)
     qtest_shutdown(qs);
 }
 
-/*** Logical Device Initialization ***/
-
-/**
- * Start the PCI device and sanity-check default operation.
- */
-static void ahci_pci_enable(AHCIQState *ahci)
-{
-    uint8_t reg;
-
-    start_ahci_device(ahci);
-
-    switch (ahci->fingerprint) {
-    case AHCI_INTEL_ICH9:
-        /* ICH9 has a register at PCI 0x92 that
-         * acts as a master port enabler mask. */
-        reg = qpci_config_readb(ahci->dev, 0x92);
-        reg |= 0x3F;
-        qpci_config_writeb(ahci->dev, 0x92, reg);
-        /* 0...0111111b -- bit significant, ports 0-5 enabled. */
-        ASSERT_BIT_SET(qpci_config_readb(ahci->dev, 0x92), 0x3F);
-        break;
-    }
-
-}
-
-/**
- * Map BAR5/ABAR, and engage the PCI device.
- */
-static void start_ahci_device(AHCIQState *ahci)
-{
-    /* Map AHCI's ABAR (BAR5) */
-    ahci->hba_base = qpci_iomap(ahci->dev, 5, &ahci->barsize);
-
-    /* turns on pci.cmd.iose, pci.cmd.mse and pci.cmd.bme */
-    qpci_device_enable(ahci->dev);
-}
-
-/**
- * Test and initialize the AHCI's HBA memory areas.
- * Initialize and start any ports with devices attached.
- * Bring the HBA into the idle state.
- */
-static void ahci_hba_enable(AHCIQState *ahci)
-{
-    /* Bits of interest in this section:
-     * GHC.AE     Global Host Control / AHCI Enable
-     * PxCMD.ST   Port Command: Start
-     * PxCMD.SUD  "Spin Up Device"
-     * PxCMD.POD  "Power On Device"
-     * PxCMD.FRE  "FIS Receive Enable"
-     * PxCMD.FR   "FIS Receive Running"
-     * PxCMD.CR   "Command List Running"
-     */
-    uint32_t reg, ports_impl;
-    uint16_t i;
-    uint8_t num_cmd_slots;
-
-    g_assert(ahci != NULL);
-
-    /* Set GHC.AE to 1 */
-    ahci_set(ahci, AHCI_GHC, AHCI_GHC_AE);
-    reg = ahci_rreg(ahci, AHCI_GHC);
-    ASSERT_BIT_SET(reg, AHCI_GHC_AE);
-
-    /* Cache CAP and CAP2. */
-    ahci->cap = ahci_rreg(ahci, AHCI_CAP);
-    ahci->cap2 = ahci_rreg(ahci, AHCI_CAP2);
-
-    /* Read CAP.NCS, how many command slots do we have? */
-    num_cmd_slots = ((ahci->cap & AHCI_CAP_NCS) >> ctzl(AHCI_CAP_NCS)) + 1;
-    g_test_message("Number of Command Slots: %u", num_cmd_slots);
-
-    /* Determine which ports are implemented. */
-    ports_impl = ahci_rreg(ahci, AHCI_PI);
-
-    for (i = 0; ports_impl; ports_impl >>= 1, ++i) {
-        if (!(ports_impl & 0x01)) {
-            continue;
-        }
-
-        g_test_message("Initializing port %u", i);
-
-        reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD);
-        if (BITCLR(reg, AHCI_PX_CMD_ST | AHCI_PX_CMD_CR |
-                   AHCI_PX_CMD_FRE | AHCI_PX_CMD_FR)) {
-            g_test_message("port is idle");
-        } else {
-            g_test_message("port needs to be idled");
-            ahci_px_clr(ahci, i, AHCI_PX_CMD,
-                        (AHCI_PX_CMD_ST | AHCI_PX_CMD_FRE));
-            /* The port has 500ms to disengage. */
-            usleep(500000);
-            reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD);
-            ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CR);
-            ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FR);
-            g_test_message("port is now idle");
-            /* The spec does allow for possibly needing a PORT RESET
-             * or HBA reset if we fail to idle the port. */
-        }
-
-        /* Allocate Memory for the Command List Buffer & FIS Buffer */
-        /* PxCLB space ... 0x20 per command, as in 4.2.2 p 36 */
-        ahci->port[i].clb = ahci_alloc(ahci, num_cmd_slots * 0x20);
-        qmemset(ahci->port[i].clb, 0x00, 0x100);
-        g_test_message("CLB: 0x%08" PRIx64, ahci->port[i].clb);
-        ahci_px_wreg(ahci, i, AHCI_PX_CLB, ahci->port[i].clb);
-        g_assert_cmphex(ahci->port[i].clb, ==,
-                        ahci_px_rreg(ahci, i, AHCI_PX_CLB));
-
-        /* PxFB space ... 0x100, as in 4.2.1 p 35 */
-        ahci->port[i].fb = ahci_alloc(ahci, 0x100);
-        qmemset(ahci->port[i].fb, 0x00, 0x100);
-        g_test_message("FB: 0x%08" PRIx64, ahci->port[i].fb);
-        ahci_px_wreg(ahci, i, AHCI_PX_FB, ahci->port[i].fb);
-        g_assert_cmphex(ahci->port[i].fb, ==,
-                        ahci_px_rreg(ahci, i, AHCI_PX_FB));
-
-        /* Clear PxSERR, PxIS, then IS.IPS[x] by writing '1's. */
-        ahci_px_wreg(ahci, i, AHCI_PX_SERR, 0xFFFFFFFF);
-        ahci_px_wreg(ahci, i, AHCI_PX_IS, 0xFFFFFFFF);
-        ahci_wreg(ahci, AHCI_IS, (1 << i));
-
-        /* Verify Interrupts Cleared */
-        reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR);
-        g_assert_cmphex(reg, ==, 0);
-
-        reg = ahci_px_rreg(ahci, i, AHCI_PX_IS);
-        g_assert_cmphex(reg, ==, 0);
-
-        reg = ahci_rreg(ahci, AHCI_IS);
-        ASSERT_BIT_CLEAR(reg, (1 << i));
-
-        /* Enable All Interrupts: */
-        ahci_px_wreg(ahci, i, AHCI_PX_IE, 0xFFFFFFFF);
-        reg = ahci_px_rreg(ahci, i, AHCI_PX_IE);
-        g_assert_cmphex(reg, ==, ~((uint32_t)AHCI_PX_IE_RESERVED));
-
-        /* Enable the FIS Receive Engine. */
-        ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_FRE);
-        reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD);
-        ASSERT_BIT_SET(reg, AHCI_PX_CMD_FR);
-
-        /* AHCI 1.3 spec: if !STS.BSY, !STS.DRQ and PxSSTS.DET indicates
-         * physical presence, a device is present and may be started. However,
-         * PxSERR.DIAG.X /may/ need to be cleared a priori. */
-        reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR);
-        if (BITSET(reg, AHCI_PX_SERR_DIAG_X)) {
-            ahci_px_set(ahci, i, AHCI_PX_SERR, AHCI_PX_SERR_DIAG_X);
-        }
-
-        reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD);
-        if (BITCLR(reg, AHCI_PX_TFD_STS_BSY | AHCI_PX_TFD_STS_DRQ)) {
-            reg = ahci_px_rreg(ahci, i, AHCI_PX_SSTS);
-            if ((reg & AHCI_PX_SSTS_DET) == SSTS_DET_ESTABLISHED) {
-                /* Device Found: set PxCMD.ST := 1 */
-                ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_ST);
-                ASSERT_BIT_SET(ahci_px_rreg(ahci, i, AHCI_PX_CMD),
-                               AHCI_PX_CMD_CR);
-                g_test_message("Started Device %u", i);
-            } else if ((reg & AHCI_PX_SSTS_DET)) {
-                /* Device present, but in some unknown state. */
-                g_assert_not_reached();
-            }
-        }
-    }
-
-    /* Enable GHC.IE */
-    ahci_set(ahci, AHCI_GHC, AHCI_GHC_IE);
-    reg = ahci_rreg(ahci, AHCI_GHC);
-    ASSERT_BIT_SET(reg, AHCI_GHC_IE);
-
-    /* TODO: The device should now be idling and waiting for commands.
-     * In the future, a small test-case to inspect the Register D2H FIS
-     * and clear the initial interrupts might be good. */
-}
-
 /*** Specification Adherence Tests ***/
 
 /**
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
new file mode 100644
index 0000000..5164d42
--- /dev/null
+++ b/tests/libqos/ahci.c
@@ -0,0 +1,269 @@
+/*
+ * libqos AHCI functions
+ *
+ * Copyright (c) 2014 John Snow <jsnow@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <glib.h>
+
+#include "libqtest.h"
+#include "libqos/ahci.h"
+#include "libqos/pci-pc.h"
+
+#include "qemu-common.h"
+#include "qemu/host-utils.h"
+
+#include "hw/pci/pci_ids.h"
+#include "hw/pci/pci_regs.h"
+
+/**
+ * Allocate space in the guest using information in the AHCIQState object.
+ */
+uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes)
+{
+    g_assert(ahci);
+    g_assert(ahci->parent);
+    return qmalloc(ahci->parent, bytes);
+}
+
+void ahci_free(AHCIQState *ahci, uint64_t addr)
+{
+    g_assert(ahci);
+    g_assert(ahci->parent);
+    qfree(ahci->parent, addr);
+}
+
+/**
+ * Locate, verify, and return a handle to the AHCI device.
+ */
+QPCIDevice *get_ahci_device(uint32_t *fingerprint)
+{
+    QPCIDevice *ahci;
+    uint32_t ahci_fingerprint;
+    QPCIBus *pcibus;
+
+    pcibus = qpci_init_pc();
+
+    /* Find the AHCI PCI device and verify it's the right one. */
+    ahci = qpci_device_find(pcibus, QPCI_DEVFN(0x1F, 0x02));
+    g_assert(ahci != NULL);
+
+    ahci_fingerprint = qpci_config_readl(ahci, PCI_VENDOR_ID);
+
+    switch (ahci_fingerprint) {
+    case AHCI_INTEL_ICH9:
+        break;
+    default:
+        /* Unknown device. */
+        g_assert_not_reached();
+    }
+
+    if (fingerprint) {
+        *fingerprint = ahci_fingerprint;
+    }
+    return ahci;
+}
+
+void free_ahci_device(QPCIDevice *dev)
+{
+    QPCIBus *pcibus = dev ? dev->bus : NULL;
+
+    /* libqos doesn't have a function for this, so free it manually */
+    g_free(dev);
+    qpci_free_pc(pcibus);
+}
+
+/*** Logical Device Initialization ***/
+
+/**
+ * Start the PCI device and sanity-check default operation.
+ */
+void ahci_pci_enable(AHCIQState *ahci)
+{
+    uint8_t reg;
+
+    start_ahci_device(ahci);
+
+    switch (ahci->fingerprint) {
+    case AHCI_INTEL_ICH9:
+        /* ICH9 has a register at PCI 0x92 that
+         * acts as a master port enabler mask. */
+        reg = qpci_config_readb(ahci->dev, 0x92);
+        reg |= 0x3F;
+        qpci_config_writeb(ahci->dev, 0x92, reg);
+        /* 0...0111111b -- bit significant, ports 0-5 enabled. */
+        ASSERT_BIT_SET(qpci_config_readb(ahci->dev, 0x92), 0x3F);
+        break;
+    }
+
+}
+
+/**
+ * Map BAR5/ABAR, and engage the PCI device.
+ */
+void start_ahci_device(AHCIQState *ahci)
+{
+    /* Map AHCI's ABAR (BAR5) */
+    ahci->hba_base = qpci_iomap(ahci->dev, 5, &ahci->barsize);
+    g_assert(ahci->hba_base);
+
+    /* turns on pci.cmd.iose, pci.cmd.mse and pci.cmd.bme */
+    qpci_device_enable(ahci->dev);
+}
+
+/**
+ * Test and initialize the AHCI's HBA memory areas.
+ * Initialize and start any ports with devices attached.
+ * Bring the HBA into the idle state.
+ */
+void ahci_hba_enable(AHCIQState *ahci)
+{
+    /* Bits of interest in this section:
+     * GHC.AE     Global Host Control / AHCI Enable
+     * PxCMD.ST   Port Command: Start
+     * PxCMD.SUD  "Spin Up Device"
+     * PxCMD.POD  "Power On Device"
+     * PxCMD.FRE  "FIS Receive Enable"
+     * PxCMD.FR   "FIS Receive Running"
+     * PxCMD.CR   "Command List Running"
+     */
+    uint32_t reg, ports_impl;
+    uint16_t i;
+    uint8_t num_cmd_slots;
+
+    g_assert(ahci != NULL);
+
+    /* Set GHC.AE to 1 */
+    ahci_set(ahci, AHCI_GHC, AHCI_GHC_AE);
+    reg = ahci_rreg(ahci, AHCI_GHC);
+    ASSERT_BIT_SET(reg, AHCI_GHC_AE);
+
+    /* Cache CAP and CAP2. */
+    ahci->cap = ahci_rreg(ahci, AHCI_CAP);
+    ahci->cap2 = ahci_rreg(ahci, AHCI_CAP2);
+
+    /* Read CAP.NCS, how many command slots do we have? */
+    num_cmd_slots = ((ahci->cap & AHCI_CAP_NCS) >> ctzl(AHCI_CAP_NCS)) + 1;
+    g_test_message("Number of Command Slots: %u", num_cmd_slots);
+
+    /* Determine which ports are implemented. */
+    ports_impl = ahci_rreg(ahci, AHCI_PI);
+
+    for (i = 0; ports_impl; ports_impl >>= 1, ++i) {
+        if (!(ports_impl & 0x01)) {
+            continue;
+        }
+
+        g_test_message("Initializing port %u", i);
+
+        reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD);
+        if (BITCLR(reg, AHCI_PX_CMD_ST | AHCI_PX_CMD_CR |
+                   AHCI_PX_CMD_FRE | AHCI_PX_CMD_FR)) {
+            g_test_message("port is idle");
+        } else {
+            g_test_message("port needs to be idled");
+            ahci_px_clr(ahci, i, AHCI_PX_CMD,
+                        (AHCI_PX_CMD_ST | AHCI_PX_CMD_FRE));
+            /* The port has 500ms to disengage. */
+            usleep(500000);
+            reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD);
+            ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CR);
+            ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FR);
+            g_test_message("port is now idle");
+            /* The spec does allow for possibly needing a PORT RESET
+             * or HBA reset if we fail to idle the port. */
+        }
+
+        /* Allocate Memory for the Command List Buffer & FIS Buffer */
+        /* PxCLB space ... 0x20 per command, as in 4.2.2 p 36 */
+        ahci->port[i].clb = ahci_alloc(ahci, num_cmd_slots * 0x20);
+        qmemset(ahci->port[i].clb, 0x00, 0x100);
+        g_test_message("CLB: 0x%08" PRIx64, ahci->port[i].clb);
+        ahci_px_wreg(ahci, i, AHCI_PX_CLB, ahci->port[i].clb);
+        g_assert_cmphex(ahci->port[i].clb, ==,
+                        ahci_px_rreg(ahci, i, AHCI_PX_CLB));
+
+        /* PxFB space ... 0x100, as in 4.2.1 p 35 */
+        ahci->port[i].fb = ahci_alloc(ahci, 0x100);
+        qmemset(ahci->port[i].fb, 0x00, 0x100);
+        g_test_message("FB: 0x%08" PRIx64, ahci->port[i].fb);
+        ahci_px_wreg(ahci, i, AHCI_PX_FB, ahci->port[i].fb);
+        g_assert_cmphex(ahci->port[i].fb, ==,
+                        ahci_px_rreg(ahci, i, AHCI_PX_FB));
+
+        /* Clear PxSERR, PxIS, then IS.IPS[x] by writing '1's. */
+        ahci_px_wreg(ahci, i, AHCI_PX_SERR, 0xFFFFFFFF);
+        ahci_px_wreg(ahci, i, AHCI_PX_IS, 0xFFFFFFFF);
+        ahci_wreg(ahci, AHCI_IS, (1 << i));
+
+        /* Verify Interrupts Cleared */
+        reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR);
+        g_assert_cmphex(reg, ==, 0);
+
+        reg = ahci_px_rreg(ahci, i, AHCI_PX_IS);
+        g_assert_cmphex(reg, ==, 0);
+
+        reg = ahci_rreg(ahci, AHCI_IS);
+        ASSERT_BIT_CLEAR(reg, (1 << i));
+
+        /* Enable All Interrupts: */
+        ahci_px_wreg(ahci, i, AHCI_PX_IE, 0xFFFFFFFF);
+        reg = ahci_px_rreg(ahci, i, AHCI_PX_IE);
+        g_assert_cmphex(reg, ==, ~((uint32_t)AHCI_PX_IE_RESERVED));
+
+        /* Enable the FIS Receive Engine. */
+        ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_FRE);
+        reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD);
+        ASSERT_BIT_SET(reg, AHCI_PX_CMD_FR);
+
+        /* AHCI 1.3 spec: if !STS.BSY, !STS.DRQ and PxSSTS.DET indicates
+         * physical presence, a device is present and may be started. However,
+         * PxSERR.DIAG.X /may/ need to be cleared a priori. */
+        reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR);
+        if (BITSET(reg, AHCI_PX_SERR_DIAG_X)) {
+            ahci_px_set(ahci, i, AHCI_PX_SERR, AHCI_PX_SERR_DIAG_X);
+        }
+
+        reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD);
+        if (BITCLR(reg, AHCI_PX_TFD_STS_BSY | AHCI_PX_TFD_STS_DRQ)) {
+            reg = ahci_px_rreg(ahci, i, AHCI_PX_SSTS);
+            if ((reg & AHCI_PX_SSTS_DET) == SSTS_DET_ESTABLISHED) {
+                /* Device Found: set PxCMD.ST := 1 */
+                ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_ST);
+                ASSERT_BIT_SET(ahci_px_rreg(ahci, i, AHCI_PX_CMD),
+                               AHCI_PX_CMD_CR);
+                g_test_message("Started Device %u", i);
+            } else if ((reg & AHCI_PX_SSTS_DET)) {
+                /* Device present, but in some unknown state. */
+                g_assert_not_reached();
+            }
+        }
+    }
+
+    /* Enable GHC.IE */
+    ahci_set(ahci, AHCI_GHC, AHCI_GHC_IE);
+    reg = ahci_rreg(ahci, AHCI_GHC);
+    ASSERT_BIT_SET(reg, AHCI_GHC_IE);
+
+    /* TODO: The device should now be idling and waiting for commands.
+     * In the future, a small test-case to inspect the Register D2H FIS
+     * and clear the initial interrupts might be good. */
+}
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 72c39bc..77f2055 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -28,7 +28,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdbool.h>
-
+#include "libqos/libqos.h"
 #include "libqos/pci.h"
 #include "libqos/malloc-pc.h"
 
@@ -423,4 +423,13 @@ static inline void ahci_px_clr(AHCIQState *ahci, uint8_t port,
                  ahci_px_rreg(ahci, port, reg_num) & ~mask);
 }
 
+/*** Prototypes ***/
+uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes);
+void ahci_free(AHCIQState *ahci, uint64_t addr);
+QPCIDevice *get_ahci_device(uint32_t *fingerprint);
+void free_ahci_device(QPCIDevice *dev);
+void ahci_pci_enable(AHCIQState *ahci);
+void start_ahci_device(AHCIQState *ahci);
+void ahci_hba_enable(AHCIQState *ahci);
+
 #endif
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 19/65] dataplane: endianness-aware accesses
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (17 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 18/65] libqos/ahci: create libqos/ahci.c Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 20/65] libqos/ahci: Add ahci_port_select helper Stefan Hajnoczi
                   ` (46 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel
  Cc: Cornelia Huck, Peter Maydell, Fam Zheng, Stefan Hajnoczi, Paolo Bonzini

From: Cornelia Huck <cornelia.huck@de.ibm.com>

The vring.c code currently assumes that guest and host endianness match,
which is not true for a number of cases:

- emulating targets with a different endianness than the host
- bi-endian targets, where the correct endianness depends on the virtio
  device
- upcoming support for the virtio-1 standard mandates little-endian
  accesses even for big-endian targets and hosts

Make sure to use accessors that depend on the virtio device.

Note that dataplane now needs to be built per-target.

Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Fam Zheng <famz@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Tested-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-id: 1422289602-17874-2-git-send-email-cornelia.huck@de.ibm.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 hw/block/dataplane/virtio-blk.c               |  4 +-
 hw/scsi/virtio-scsi-dataplane.c               |  2 +-
 hw/virtio/Makefile.objs                       |  2 +-
 hw/virtio/dataplane/Makefile.objs             |  2 +-
 hw/virtio/dataplane/vring.c                   | 53 ++++++++++++-------
 include/hw/virtio/dataplane/vring-accessors.h | 75 +++++++++++++++++++++++++++
 include/hw/virtio/dataplane/vring.h           | 14 +----
 7 files changed, 117 insertions(+), 35 deletions(-)
 create mode 100644 include/hw/virtio/dataplane/vring-accessors.h

diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index be957d1..cd41478 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -16,7 +16,9 @@
 #include "qemu/iov.h"
 #include "qemu/thread.h"
 #include "qemu/error-report.h"
+#include "hw/virtio/virtio-access.h"
 #include "hw/virtio/dataplane/vring.h"
+#include "hw/virtio/dataplane/vring-accessors.h"
 #include "sysemu/block-backend.h"
 #include "hw/virtio/virtio-blk.h"
 #include "virtio-blk.h"
@@ -75,7 +77,7 @@ static void complete_request_vring(VirtIOBlockReq *req, unsigned char status)
     VirtIOBlockDataPlane *s = req->dev->dataplane;
     stb_p(&req->in->status, status);
 
-    vring_push(&req->dev->dataplane->vring, &req->elem,
+    vring_push(s->vdev, &req->dev->dataplane->vring, &req->elem,
                req->qiov.size + sizeof(*req->in));
 
     /* Suppress notification to guest by BH and its scheduled
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
index 03a1e8c..418d73b 100644
--- a/hw/scsi/virtio-scsi-dataplane.c
+++ b/hw/scsi/virtio-scsi-dataplane.c
@@ -94,7 +94,7 @@ void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(req->vring->parent);
 
-    vring_push(&req->vring->vring, &req->elem,
+    vring_push(vdev, &req->vring->vring, &req->elem,
                req->qsgl.size + req->resp_iov.size);
 
     if (vring_should_notify(vdev, &req->vring->vring)) {
diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs
index d21c397..19b224a 100644
--- a/hw/virtio/Makefile.objs
+++ b/hw/virtio/Makefile.objs
@@ -2,7 +2,7 @@ common-obj-y += virtio-rng.o
 common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
 common-obj-y += virtio-bus.o
 common-obj-y += virtio-mmio.o
-common-obj-$(CONFIG_VIRTIO) += dataplane/
+obj-$(CONFIG_VIRTIO) += dataplane/
 
 obj-y += virtio.o virtio-balloon.o 
 obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o
diff --git a/hw/virtio/dataplane/Makefile.objs b/hw/virtio/dataplane/Makefile.objs
index 9a8cfc0..753a9ca 100644
--- a/hw/virtio/dataplane/Makefile.objs
+++ b/hw/virtio/dataplane/Makefile.objs
@@ -1 +1 @@
-common-obj-y += vring.o
+obj-y += vring.o
diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c
index 78c6f45..0936f65 100644
--- a/hw/virtio/dataplane/vring.c
+++ b/hw/virtio/dataplane/vring.c
@@ -18,7 +18,9 @@
 #include "hw/hw.h"
 #include "exec/memory.h"
 #include "exec/address-spaces.h"
+#include "hw/virtio/virtio-access.h"
 #include "hw/virtio/dataplane/vring.h"
+#include "hw/virtio/dataplane/vring-accessors.h"
 #include "qemu/error-report.h"
 
 /* vring_map can be coupled with vring_unmap or (if you still have the
@@ -83,7 +85,7 @@ bool vring_setup(Vring *vring, VirtIODevice *vdev, int n)
     vring_init(&vring->vr, virtio_queue_get_num(vdev, n), vring_ptr, 4096);
 
     vring->last_avail_idx = virtio_queue_get_last_avail_idx(vdev, n);
-    vring->last_used_idx = vring->vr.used->idx;
+    vring->last_used_idx = vring_get_used_idx(vdev, vring);
     vring->signalled_used = 0;
     vring->signalled_used_valid = false;
 
@@ -104,7 +106,7 @@ void vring_teardown(Vring *vring, VirtIODevice *vdev, int n)
 void vring_disable_notification(VirtIODevice *vdev, Vring *vring)
 {
     if (!(vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
-        vring->vr.used->flags |= VRING_USED_F_NO_NOTIFY;
+        vring_set_used_flags(vdev, vring, VRING_USED_F_NO_NOTIFY);
     }
 }
 
@@ -117,10 +119,10 @@ bool vring_enable_notification(VirtIODevice *vdev, Vring *vring)
     if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
         vring_avail_event(&vring->vr) = vring->vr.avail->idx;
     } else {
-        vring->vr.used->flags &= ~VRING_USED_F_NO_NOTIFY;
+        vring_clear_used_flags(vdev, vring, VRING_USED_F_NO_NOTIFY);
     }
     smp_mb(); /* ensure update is seen before reading avail_idx */
-    return !vring_more_avail(vring);
+    return !vring_more_avail(vdev, vring);
 }
 
 /* This is stolen from linux/drivers/vhost/vhost.c:vhost_notify() */
@@ -134,12 +136,13 @@ bool vring_should_notify(VirtIODevice *vdev, Vring *vring)
     smp_mb();
 
     if ((vdev->guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) &&
-        unlikely(vring->vr.avail->idx == vring->last_avail_idx)) {
+        unlikely(!vring_more_avail(vdev, vring))) {
         return true;
     }
 
     if (!(vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
-        return !(vring->vr.avail->flags & VRING_AVAIL_F_NO_INTERRUPT);
+        return !(vring_get_avail_flags(vdev, vring) &
+                 VRING_AVAIL_F_NO_INTERRUPT);
     }
     old = vring->signalled_used;
     v = vring->signalled_used_valid;
@@ -202,9 +205,19 @@ static int get_desc(Vring *vring, VirtQueueElement *elem,
     return 0;
 }
 
+static void copy_in_vring_desc(VirtIODevice *vdev,
+                               const struct vring_desc *guest,
+                               struct vring_desc *host)
+{
+    host->addr = virtio_ldq_p(vdev, &guest->addr);
+    host->len = virtio_ldl_p(vdev, &guest->len);
+    host->flags = virtio_lduw_p(vdev, &guest->flags);
+    host->next = virtio_lduw_p(vdev, &guest->next);
+}
+
 /* This is stolen from linux/drivers/vhost/vhost.c. */
-static int get_indirect(Vring *vring, VirtQueueElement *elem,
-                        struct vring_desc *indirect)
+static int get_indirect(VirtIODevice *vdev, Vring *vring,
+                        VirtQueueElement *elem, struct vring_desc *indirect)
 {
     struct vring_desc desc;
     unsigned int i = 0, count, found = 0;
@@ -244,7 +257,7 @@ static int get_indirect(Vring *vring, VirtQueueElement *elem,
             vring->broken = true;
             return -EFAULT;
         }
-        desc = *desc_ptr;
+        copy_in_vring_desc(vdev, desc_ptr, &desc);
         memory_region_unref(mr);
 
         /* Ensure descriptor has been loaded before accessing fields */
@@ -320,7 +333,7 @@ int vring_pop(VirtIODevice *vdev, Vring *vring,
 
     /* Check it isn't doing very strange things with descriptor numbers. */
     last_avail_idx = vring->last_avail_idx;
-    avail_idx = vring->vr.avail->idx;
+    avail_idx = vring_get_avail_idx(vdev, vring);
     barrier(); /* load indices now and not again later */
 
     if (unlikely((uint16_t)(avail_idx - last_avail_idx) > num)) {
@@ -341,7 +354,7 @@ int vring_pop(VirtIODevice *vdev, Vring *vring,
 
     /* Grab the next descriptor number they're advertising, and increment
      * the index we've seen. */
-    head = vring->vr.avail->ring[last_avail_idx % num];
+    head = vring_get_avail_ring(vdev, vring, last_avail_idx % num);
 
     elem->index = head;
 
@@ -365,13 +378,13 @@ int vring_pop(VirtIODevice *vdev, Vring *vring,
             ret = -EFAULT;
             goto out;
         }
-        desc = vring->vr.desc[i];
+        copy_in_vring_desc(vdev, &vring->vr.desc[i], &desc);
 
         /* Ensure descriptor is loaded before accessing fields */
         barrier();
 
         if (desc.flags & VRING_DESC_F_INDIRECT) {
-            ret = get_indirect(vring, elem, &desc);
+            ret = get_indirect(vdev, vring, elem, &desc);
             if (ret < 0) {
                 goto out;
             }
@@ -407,9 +420,9 @@ out:
  *
  * Stolen from linux/drivers/vhost/vhost.c.
  */
-void vring_push(Vring *vring, VirtQueueElement *elem, int len)
+void vring_push(VirtIODevice *vdev, Vring *vring, VirtQueueElement *elem,
+                int len)
 {
-    struct vring_used_elem *used;
     unsigned int head = elem->index;
     uint16_t new;
 
@@ -422,14 +435,16 @@ void vring_push(Vring *vring, VirtQueueElement *elem, int len)
 
     /* The virtqueue contains a ring of used buffers.  Get a pointer to the
      * next entry in that used ring. */
-    used = &vring->vr.used->ring[vring->last_used_idx % vring->vr.num];
-    used->id = head;
-    used->len = len;
+    vring_set_used_ring_id(vdev, vring, vring->last_used_idx % vring->vr.num,
+                           head);
+    vring_set_used_ring_len(vdev, vring, vring->last_used_idx % vring->vr.num,
+                            len);
 
     /* Make sure buffer is written before we update index. */
     smp_wmb();
 
-    new = vring->vr.used->idx = ++vring->last_used_idx;
+    new = ++vring->last_used_idx;
+    vring_set_used_idx(vdev, vring, new);
     if (unlikely((int16_t)(new - vring->signalled_used) < (uint16_t)1)) {
         vring->signalled_used_valid = false;
     }
diff --git a/include/hw/virtio/dataplane/vring-accessors.h b/include/hw/virtio/dataplane/vring-accessors.h
new file mode 100644
index 0000000..b508b87
--- /dev/null
+++ b/include/hw/virtio/dataplane/vring-accessors.h
@@ -0,0 +1,75 @@
+#ifndef VRING_ACCESSORS_H
+#define VRING_ACCESSORS_H
+
+#include "hw/virtio/virtio_ring.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-access.h"
+
+static inline uint16_t vring_get_used_idx(VirtIODevice *vdev, Vring *vring)
+{
+    return virtio_tswap16(vdev, vring->vr.used->idx);
+}
+
+static inline void vring_set_used_idx(VirtIODevice *vdev, Vring *vring,
+                                      uint16_t idx)
+{
+    vring->vr.used->idx = virtio_tswap16(vdev, idx);
+}
+
+static inline uint16_t vring_get_avail_idx(VirtIODevice *vdev, Vring *vring)
+{
+    return virtio_tswap16(vdev, vring->vr.avail->idx);
+}
+
+static inline uint16_t vring_get_avail_ring(VirtIODevice *vdev, Vring *vring,
+                                            int i)
+{
+    return virtio_tswap16(vdev, vring->vr.avail->ring[i]);
+}
+
+static inline void vring_set_used_ring_id(VirtIODevice *vdev, Vring *vring,
+                                          int i, uint32_t id)
+{
+    vring->vr.used->ring[i].id = virtio_tswap32(vdev, id);
+}
+
+static inline void vring_set_used_ring_len(VirtIODevice *vdev, Vring *vring,
+                                          int i, uint32_t len)
+{
+    vring->vr.used->ring[i].len = virtio_tswap32(vdev, len);
+}
+
+static inline uint16_t vring_get_used_flags(VirtIODevice *vdev, Vring *vring)
+{
+    return virtio_tswap16(vdev, vring->vr.used->flags);
+}
+
+static inline uint16_t vring_get_avail_flags(VirtIODevice *vdev, Vring *vring)
+{
+    return virtio_tswap16(vdev, vring->vr.avail->flags);
+}
+
+static inline void vring_set_used_flags(VirtIODevice *vdev, Vring *vring,
+                                        uint16_t flags)
+{
+    vring->vr.used->flags |= virtio_tswap16(vdev, flags);
+}
+
+static inline void vring_clear_used_flags(VirtIODevice *vdev, Vring *vring,
+                                          uint16_t flags)
+{
+    vring->vr.used->flags &= virtio_tswap16(vdev, ~flags);
+}
+
+static inline unsigned int vring_get_num(Vring *vring)
+{
+    return vring->vr.num;
+}
+
+/* Are there more descriptors available? */
+static inline bool vring_more_avail(VirtIODevice *vdev, Vring *vring)
+{
+    return vring_get_avail_idx(vdev, vring) != vring->last_avail_idx;
+}
+
+#endif
diff --git a/include/hw/virtio/dataplane/vring.h b/include/hw/virtio/dataplane/vring.h
index d3e086a..e42c0fc 100644
--- a/include/hw/virtio/dataplane/vring.h
+++ b/include/hw/virtio/dataplane/vring.h
@@ -31,17 +31,6 @@ typedef struct {
     bool broken;                    /* was there a fatal error? */
 } Vring;
 
-static inline unsigned int vring_get_num(Vring *vring)
-{
-    return vring->vr.num;
-}
-
-/* Are there more descriptors available? */
-static inline bool vring_more_avail(Vring *vring)
-{
-    return vring->vr.avail->idx != vring->last_avail_idx;
-}
-
 /* Fail future vring_pop() and vring_push() calls until reset */
 static inline void vring_set_broken(Vring *vring)
 {
@@ -54,6 +43,7 @@ void vring_disable_notification(VirtIODevice *vdev, Vring *vring);
 bool vring_enable_notification(VirtIODevice *vdev, Vring *vring);
 bool vring_should_notify(VirtIODevice *vdev, Vring *vring);
 int vring_pop(VirtIODevice *vdev, Vring *vring, VirtQueueElement *elem);
-void vring_push(Vring *vring, VirtQueueElement *elem, int len);
+void vring_push(VirtIODevice *vdev, Vring *vring, VirtQueueElement *elem,
+                int len);
 
 #endif /* VRING_H */
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 20/65] libqos/ahci: Add ahci_port_select helper
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (18 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 19/65] dataplane: endianness-aware accesses Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 21/65] libqos/ahci: Add ahci_port_clear helper Stefan Hajnoczi
                   ` (45 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

This helper identifies which port of the
AHCI HBA has a device we may run tests on.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1423158090-25580-2-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   | 19 ++-----------------
 tests/libqos/ahci.c | 27 +++++++++++++++++++++++++++
 tests/libqos/ahci.h |  1 +
 3 files changed, 30 insertions(+), 17 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index fca33d2..c689b62 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -662,7 +662,7 @@ static void ahci_test_identify(AHCIQState *ahci)
     RegH2DFIS fis;
     AHCICommand cmd;
     PRD prd;
-    uint32_t ports, reg, table, data_ptr;
+    uint32_t reg, table, data_ptr;
     uint16_t buff[256];
     unsigned i;
     int rc;
@@ -684,22 +684,7 @@ static void ahci_test_identify(AHCIQState *ahci)
      */
 
     /* Pick the first implemented and running port */
-    ports = ahci_rreg(ahci, AHCI_PI);
-    for (i = 0; i < 32; ports >>= 1, ++i) {
-        if (ports == 0) {
-            i = 32;
-        }
-
-        if (!(ports & 0x01)) {
-            continue;
-        }
-
-        reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD);
-        if (BITSET(reg, AHCI_PX_CMD_ST)) {
-            break;
-        }
-    }
-    g_assert_cmphex(i, <, 32);
+    i = ahci_port_select(ahci);
     g_test_message("Selected port %u for test", i);
 
     /* Clear out this port's interrupts (ignore the init register d2h fis) */
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 5164d42..7ea55f9 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -267,3 +267,30 @@ void ahci_hba_enable(AHCIQState *ahci)
      * In the future, a small test-case to inspect the Register D2H FIS
      * and clear the initial interrupts might be good. */
 }
+
+/**
+ * Pick the first implemented and running port
+ */
+unsigned ahci_port_select(AHCIQState *ahci)
+{
+    uint32_t ports, reg;
+    unsigned i;
+
+    ports = ahci_rreg(ahci, AHCI_PI);
+    for (i = 0; i < 32; ports >>= 1, ++i) {
+        if (ports == 0) {
+            i = 32;
+        }
+
+        if (!(ports & 0x01)) {
+            continue;
+        }
+
+        reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD);
+        if (BITSET(reg, AHCI_PX_CMD_ST)) {
+            break;
+        }
+    }
+    g_assert(i < 32);
+    return i;
+}
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 77f2055..b3992e1 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -431,5 +431,6 @@ void free_ahci_device(QPCIDevice *dev);
 void ahci_pci_enable(AHCIQState *ahci);
 void start_ahci_device(AHCIQState *ahci);
 void ahci_hba_enable(AHCIQState *ahci);
+unsigned ahci_port_select(AHCIQState *ahci);
 
 #endif
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 21/65] libqos/ahci: Add ahci_port_clear helper
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (19 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 20/65] libqos/ahci: Add ahci_port_select helper Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 22/65] qtest/ahci: rename 'Command' to 'CommandHeader' Stefan Hajnoczi
                   ` (44 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Add a helper that assists in clearing out potentially old error and FIS
information from an AHCI port's data structures. This ensures we always
start with a blank slate for interrupt and FIS receipt information.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1423158090-25580-3-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   |  9 ++-------
 tests/libqos/ahci.c | 16 ++++++++++++++++
 tests/libqos/ahci.h |  1 +
 3 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index c689b62..90647f2 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -687,13 +687,8 @@ static void ahci_test_identify(AHCIQState *ahci)
     i = ahci_port_select(ahci);
     g_test_message("Selected port %u for test", i);
 
-    /* Clear out this port's interrupts (ignore the init register d2h fis) */
-    reg = ahci_px_rreg(ahci, i, AHCI_PX_IS);
-    ahci_px_wreg(ahci, i, AHCI_PX_IS, reg);
-    g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
-
-    /* Wipe the FIS-Receive Buffer */
-    qmemset(ahci->port[i].fb, 0x00, 0x100);
+    /* Clear out the FIS Receive area and any pending interrupts. */
+    ahci_port_clear(ahci, i);
 
     /* Create a Command Table buffer. 0x80 is the smallest with a PRDTL of 0. */
     /* We need at least one PRD, so round up to the nearest 0x80 multiple.    */
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 7ea55f9..3b1b9ba 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -294,3 +294,19 @@ unsigned ahci_port_select(AHCIQState *ahci)
     g_assert(i < 32);
     return i;
 }
+
+/**
+ * Clear a port's interrupts and status information prior to a test.
+ */
+void ahci_port_clear(AHCIQState *ahci, uint8_t port)
+{
+    uint32_t reg;
+
+    /* Clear out this port's interrupts (ignore the init register d2h fis) */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_IS);
+    ahci_px_wreg(ahci, port, AHCI_PX_IS, reg);
+    g_assert_cmphex(ahci_px_rreg(ahci, port, AHCI_PX_IS), ==, 0);
+
+    /* Wipe the FIS-Recieve Buffer */
+    qmemset(ahci->port[port].fb, 0x00, 0x100);
+}
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index b3992e1..39ba94e 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -432,5 +432,6 @@ void ahci_pci_enable(AHCIQState *ahci);
 void start_ahci_device(AHCIQState *ahci);
 void ahci_hba_enable(AHCIQState *ahci);
 unsigned ahci_port_select(AHCIQState *ahci);
+void ahci_port_clear(AHCIQState *ahci, uint8_t port);
 
 #endif
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 22/65] qtest/ahci: rename 'Command' to 'CommandHeader'
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (20 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 21/65] libqos/ahci: Add ahci_port_clear helper Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 23/65] libqos/ahci: Add command header helpers Stefan Hajnoczi
                   ` (43 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

The structure name is a bit of a misnomer; the structure currently named
command is actually the commandheader. A future patch in this series
will add an actual "Command" structure, so we'll rename it now before the
rest of the functions in this series try to use it.

In addition, rename the "b1" and "b2" fields
to be a unified uint16_t named "flags."

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
Message-id: 1423158090-25580-4-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   | 8 ++++----
 tests/libqos/ahci.h | 7 +++----
 2 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 90647f2..d420e5f 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -660,7 +660,7 @@ static void ahci_test_identify(AHCIQState *ahci)
     RegD2HFIS *d2h = g_malloc0(0x20);
     RegD2HFIS *pio = g_malloc0(0x20);
     RegH2DFIS fis;
-    AHCICommand cmd;
+    AHCICommandHeader cmd;
     PRD prd;
     uint32_t reg, table, data_ptr;
     uint16_t buff[256];
@@ -703,9 +703,9 @@ static void ahci_test_identify(AHCIQState *ahci)
     /* Copy the existing Command #0 structure from the CLB into local memory,
      * and build a new command #0. */
     memread(ahci->port[i].clb, &cmd, sizeof(cmd));
-    cmd.b1 = 5;    /* reg_h2d_fis is 5 double-words long */
-    cmd.b2 = 0x04; /* clear PxTFD.STS.BSY when done */
-    cmd.prdtl = cpu_to_le16(1); /* One PRD table entry. */
+    cmd.flags = cpu_to_le16(5);      /* reg_h2d_fis is 5 double-words long */
+    cmd.flags |= cpu_to_le16(0x400); /* clear PxTFD.STS.BSY when done */
+    cmd.prdtl = cpu_to_le16(1);      /* One PRD table entry. */
     cmd.prdbc = 0;
     cmd.ctba = cpu_to_le32(table);
     cmd.ctbau = 0;
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 39ba94e..1fddf33 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -329,15 +329,14 @@ typedef struct RegH2DFIS {
  * Command List entry structure.
  * The command list contains between 1-32 of these structures.
  */
-typedef struct AHCICommand {
-    uint8_t b1;
-    uint8_t b2;
+typedef struct AHCICommandHeader {
+    uint16_t flags; /* Cmd-Fis-Len, PMP#, and flags. */
     uint16_t prdtl; /* Phys Region Desc. Table Length */
     uint32_t prdbc; /* Phys Region Desc. Byte Count */
     uint32_t ctba;  /* Command Table Descriptor Base Address */
     uint32_t ctbau; /*                                    '' Upper */
     uint32_t res[4];
-} __attribute__((__packed__)) AHCICommand;
+} __attribute__((__packed__)) AHCICommandHeader;
 
 /**
  * Physical Region Descriptor; pointed to by the Command List Header,
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 23/65] libqos/ahci: Add command header helpers
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (21 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 22/65] qtest/ahci: rename 'Command' to 'CommandHeader' Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 24/65] libqos/ahci: Add ahci_port_check_error helper Stefan Hajnoczi
                   ` (42 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Adds command header helper functions:
-ahci_command_header_set
-ahci_command_header_get,
-ahci_command_destroy, and
-ahci_cmd_pick

These helpers help to quickly manage the command header information in
the AHCI device.

ahci_command_header_set and get will store or retrieve an AHCI command
header, respectively.

ahci_cmd_pick chooses the first available but least recently used
command slot to allow us to cycle through the available command slots.

ahci_command_destroy obliterates all information contained within a
given slot's command header, and frees its associated command table,
but not its DMA buffer!

Lastly, the command table pointer fields (dba and dbau) are merged into
a single 64bit value to make managing 64bit tests simpler.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-id: 1423158090-25580-5-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   | 43 ++++++++++++++++--------------
 tests/libqos/ahci.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/ahci.h | 17 ++++++++----
 3 files changed, 110 insertions(+), 25 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index d420e5f..fbf329e 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -662,10 +662,12 @@ static void ahci_test_identify(AHCIQState *ahci)
     RegH2DFIS fis;
     AHCICommandHeader cmd;
     PRD prd;
-    uint32_t reg, table, data_ptr;
+    uint32_t reg, data_ptr;
     uint16_t buff[256];
     unsigned i;
     int rc;
+    uint8_t cx;
+    uint64_t table;
 
     g_assert(ahci != NULL);
 
@@ -700,19 +702,19 @@ static void ahci_test_identify(AHCIQState *ahci)
     data_ptr = ahci_alloc(ahci, 512);
     g_assert(data_ptr);
 
-    /* Copy the existing Command #0 structure from the CLB into local memory,
-     * and build a new command #0. */
-    memread(ahci->port[i].clb, &cmd, sizeof(cmd));
-    cmd.flags = cpu_to_le16(5);      /* reg_h2d_fis is 5 double-words long */
-    cmd.flags |= cpu_to_le16(0x400); /* clear PxTFD.STS.BSY when done */
-    cmd.prdtl = cpu_to_le16(1);      /* One PRD table entry. */
+    /* pick a command slot (should be 0!) */
+    cx = ahci_pick_cmd(ahci, i);
+
+    /* Construct our Command Header (set_command_header handles endianness.) */
+    memset(&cmd, 0x00, sizeof(cmd));
+    cmd.flags = 5;      /* reg_h2d_fis is 5 double-words long */
+    cmd.flags |= 0x400; /* clear PxTFD.STS.BSY when done */
+    cmd.prdtl = 1;      /* One PRD table entry. */
     cmd.prdbc = 0;
-    cmd.ctba = cpu_to_le32(table);
-    cmd.ctbau = 0;
+    cmd.ctba = table;
 
     /* Construct our PRD, noting that DBC is 0-indexed. */
-    prd.dba = cpu_to_le32(data_ptr);
-    prd.dbau = 0;
+    prd.dba = cpu_to_le64(data_ptr);
     prd.res = 0;
     /* 511+1 bytes, request DPS interrupt */
     prd.dbc = cpu_to_le32(511 | 0x80000000);
@@ -733,14 +735,15 @@ static void ahci_test_identify(AHCIQState *ahci)
     /* Commit the PRD entry to the Command Table */
     memwrite(table + 0x80, &prd, sizeof(prd));
 
-    /* Commit Command #0, pointing to the Table, to the Command List Buffer. */
-    memwrite(ahci->port[i].clb, &cmd, sizeof(cmd));
+    /* Commit Command #cx, pointing to the Table, to the Command List Buffer. */
+    ahci_set_command_header(ahci, i, cx, &cmd);
 
-    /* Everything is in place, but we haven't given the go-ahead yet. */
+    /* Everything is in place, but we haven't given the go-ahead yet,
+     * so we should find that there are no pending interrupts yet. */
     g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
 
-    /* Issue Command #0 via PxCI */
-    ahci_px_wreg(ahci, i, AHCI_PX_CI, (1 << 0));
+    /* Issue Command #cx via PxCI */
+    ahci_px_wreg(ahci, i, AHCI_PX_CI, (1 << cx));
     while (BITSET(ahci_px_rreg(ahci, i, AHCI_PX_TFD), AHCI_PX_TFD_STS_BSY)) {
         usleep(50);
     }
@@ -764,9 +767,9 @@ static void ahci_test_identify(AHCIQState *ahci)
     ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_ERR);
     ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR);
 
-    /* Investigate CMD #0, assert that we read 512 bytes */
-    memread(ahci->port[i].clb, &cmd, sizeof(cmd));
-    g_assert_cmphex(512, ==, le32_to_cpu(cmd.prdbc));
+    /* Investigate the CMD, assert that we read 512 bytes */
+    ahci_get_command_header(ahci, i, cx, &cmd);
+    g_assert_cmphex(512, ==, cmd.prdbc);
 
     /* Investigate FIS responses */
     memread(ahci->port[i].fb + 0x20, pio, 0x20);
@@ -783,7 +786,7 @@ static void ahci_test_identify(AHCIQState *ahci)
     /* The PIO Setup FIS contains a "bytes read" field, which is a
      * 16-bit value. The Physical Region Descriptor Byte Count is
      * 32-bit, but for small transfers using one PRD, it should match. */
-    g_assert_cmphex(le16_to_cpu(pio->res4), ==, le32_to_cpu(cmd.prdbc));
+    g_assert_cmphex(le16_to_cpu(pio->res4), ==, cmd.prdbc);
 
     /* Last, but not least: Investigate the IDENTIFY response data. */
     memread(data_ptr, &buff, 512);
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 3b1b9ba..8c3f664 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -310,3 +310,78 @@ void ahci_port_clear(AHCIQState *ahci, uint8_t port)
     /* Wipe the FIS-Recieve Buffer */
     qmemset(ahci->port[port].fb, 0x00, 0x100);
 }
+
+/* Get the command in #slot of port #port. */
+void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
+                             uint8_t slot, AHCICommandHeader *cmd)
+{
+    uint64_t ba = ahci->port[port].clb;
+    ba += slot * sizeof(AHCICommandHeader);
+    memread(ba, cmd, sizeof(AHCICommandHeader));
+
+    cmd->flags = le16_to_cpu(cmd->flags);
+    cmd->prdtl = le16_to_cpu(cmd->prdtl);
+    cmd->prdbc = le32_to_cpu(cmd->prdbc);
+    cmd->ctba = le64_to_cpu(cmd->ctba);
+}
+
+/* Set the command in #slot of port #port. */
+void ahci_set_command_header(AHCIQState *ahci, uint8_t port,
+                             uint8_t slot, AHCICommandHeader *cmd)
+{
+    AHCICommandHeader tmp;
+    uint64_t ba = ahci->port[port].clb;
+    ba += slot * sizeof(AHCICommandHeader);
+
+    tmp.flags = cpu_to_le16(cmd->flags);
+    tmp.prdtl = cpu_to_le16(cmd->prdtl);
+    tmp.prdbc = cpu_to_le32(cmd->prdbc);
+    tmp.ctba = cpu_to_le64(cmd->ctba);
+
+    memwrite(ba, &tmp, sizeof(AHCICommandHeader));
+}
+
+void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot)
+{
+    AHCICommandHeader cmd;
+
+    /* Obtain the Nth Command Header */
+    ahci_get_command_header(ahci, port, slot, &cmd);
+    if (cmd.ctba == 0) {
+        /* No address in it, so just return -- it's empty. */
+        goto tidy;
+    }
+
+    /* Free the Table */
+    ahci_free(ahci, cmd.ctba);
+
+ tidy:
+    /* NULL the header. */
+    memset(&cmd, 0x00, sizeof(cmd));
+    ahci_set_command_header(ahci, port, slot, &cmd);
+    ahci->port[port].ctba[slot] = 0;
+    ahci->port[port].prdtl[slot] = 0;
+}
+
+unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port)
+{
+    unsigned i;
+    unsigned j;
+    uint32_t reg;
+
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_CI);
+
+    /* Pick the least recently used command slot that's available */
+    for (i = 0; i < 32; ++i) {
+        j = ((ahci->port[port].next + i) % 32);
+        if (reg & (1 << j)) {
+            continue;
+        }
+        ahci_destroy_command(ahci, port, i);
+        ahci->port[port].next = (j + 1) % 32;
+        return j;
+    }
+
+    g_test_message("All command slots were busy.");
+    g_assert_not_reached();
+}
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 1fddf33..0835be4 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -248,6 +248,9 @@
 typedef struct AHCIPortQState {
     uint64_t fb;
     uint64_t clb;
+    uint64_t ctba[32];
+    uint16_t prdtl[32];
+    uint8_t next; /** Next Command Slot to Use **/
 } AHCIPortQState;
 
 typedef struct AHCIQState {
@@ -333,8 +336,7 @@ typedef struct AHCICommandHeader {
     uint16_t flags; /* Cmd-Fis-Len, PMP#, and flags. */
     uint16_t prdtl; /* Phys Region Desc. Table Length */
     uint32_t prdbc; /* Phys Region Desc. Byte Count */
-    uint32_t ctba;  /* Command Table Descriptor Base Address */
-    uint32_t ctbau; /*                                    '' Upper */
+    uint64_t ctba;  /* Command Table Descriptor Base Address */
     uint32_t res[4];
 } __attribute__((__packed__)) AHCICommandHeader;
 
@@ -343,11 +345,10 @@ typedef struct AHCICommandHeader {
  * struct ahci_command.
  */
 typedef struct PRD {
-    uint32_t dba;  /* Data Base Address */
-    uint32_t dbau; /* Data Base Address Upper */
+    uint64_t dba;  /* Data Base Address */
     uint32_t res;  /* Reserved */
     uint32_t dbc;  /* Data Byte Count (0-indexed) & Interrupt Flag (bit 2^31) */
-} PRD;
+} __attribute__((__packed__)) PRD;
 
 /*** Macro Utilities ***/
 #define BITANY(data, mask) (((data) & (mask)) != 0)
@@ -432,5 +433,11 @@ void start_ahci_device(AHCIQState *ahci);
 void ahci_hba_enable(AHCIQState *ahci);
 unsigned ahci_port_select(AHCIQState *ahci);
 void ahci_port_clear(AHCIQState *ahci, uint8_t port);
+void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
+                             uint8_t slot, AHCICommandHeader *cmd);
+void ahci_set_command_header(AHCIQState *ahci, uint8_t port,
+                             uint8_t slot, AHCICommandHeader *cmd);
+void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot);
+unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port);
 
 #endif
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 24/65] libqos/ahci: Add ahci_port_check_error helper
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (22 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 23/65] libqos/ahci: Add command header helpers Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 25/65] libqos/ahci: Add ahci_port_check_interrupts helper Stefan Hajnoczi
                   ` (41 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

ahci_port_check_error checks a given port's error registers and asserts
that everything from the port-level view is still OK.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1423158090-25580-6-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   |  8 +-------
 tests/libqos/ahci.c | 22 ++++++++++++++++++++++
 tests/libqos/ahci.h |  1 +
 3 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index fbf329e..a3e8f12 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -747,6 +747,7 @@ static void ahci_test_identify(AHCIQState *ahci)
     while (BITSET(ahci_px_rreg(ahci, i, AHCI_PX_TFD), AHCI_PX_TFD_STS_BSY)) {
         usleep(50);
     }
+    ahci_port_check_error(ahci, i);
 
     /* Check for expected interrupts */
     reg = ahci_px_rreg(ahci, i, AHCI_PX_IS);
@@ -760,13 +761,6 @@ static void ahci_test_identify(AHCIQState *ahci)
                  AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS | AHCI_PX_IS_DPS);
     g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
 
-    /* Check for errors. */
-    reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR);
-    g_assert_cmphex(reg, ==, 0);
-    reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_ERR);
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR);
-
     /* Investigate the CMD, assert that we read 512 bytes */
     ahci_get_command_header(ahci, i, cx, &cmd);
     g_assert_cmphex(512, ==, cmd.prdbc);
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 8c3f664..3da168a 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -311,6 +311,28 @@ void ahci_port_clear(AHCIQState *ahci, uint8_t port)
     qmemset(ahci->port[port].fb, 0x00, 0x100);
 }
 
+/**
+ * Check a port for errors.
+ */
+void ahci_port_check_error(AHCIQState *ahci, uint8_t port)
+{
+    uint32_t reg;
+
+    /* The upper 9 bits of the IS register all indicate errors. */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_IS);
+    reg >>= 23;
+    g_assert_cmphex(reg, ==, 0);
+
+    /* The Sata Error Register should be empty. */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_SERR);
+    g_assert_cmphex(reg, ==, 0);
+
+    /* The TFD also has two error sections. */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_ERR);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR);
+}
+
 /* Get the command in #slot of port #port. */
 void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
                              uint8_t slot, AHCICommandHeader *cmd)
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 0835be4..af62a8a 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -433,6 +433,7 @@ void start_ahci_device(AHCIQState *ahci);
 void ahci_hba_enable(AHCIQState *ahci);
 unsigned ahci_port_select(AHCIQState *ahci);
 void ahci_port_clear(AHCIQState *ahci, uint8_t port);
+void ahci_port_check_error(AHCIQState *ahci, uint8_t port);
 void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
                              uint8_t slot, AHCICommandHeader *cmd);
 void ahci_set_command_header(AHCIQState *ahci, uint8_t port,
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 25/65] libqos/ahci: Add ahci_port_check_interrupts helper
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (23 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 24/65] libqos/ahci: Add ahci_port_check_error helper Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 26/65] libqos/ahci: Add port_check_nonbusy helper Stefan Hajnoczi
                   ` (40 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

A helper that compares a given port's current interrupts and checks them
against a supplied list of expected interrupt bits, and throws an error
if they do not match.

The helper then resets the requested interrupts on this port, and asserts
that the interrupt register is now empty.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1423158090-25580-7-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   | 13 ++-----------
 tests/libqos/ahci.c | 14 ++++++++++++++
 tests/libqos/ahci.h |  2 ++
 3 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index a3e8f12..32b6be3 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -747,19 +747,10 @@ static void ahci_test_identify(AHCIQState *ahci)
     while (BITSET(ahci_px_rreg(ahci, i, AHCI_PX_TFD), AHCI_PX_TFD_STS_BSY)) {
         usleep(50);
     }
+    /* Check registers for post-command consistency */
     ahci_port_check_error(ahci, i);
-
-    /* Check for expected interrupts */
-    reg = ahci_px_rreg(ahci, i, AHCI_PX_IS);
-    ASSERT_BIT_SET(reg, AHCI_PX_IS_DHRS);
-    ASSERT_BIT_SET(reg, AHCI_PX_IS_PSS);
     /* BUG: we expect AHCI_PX_IS_DPS to be set. */
-    ASSERT_BIT_CLEAR(reg, AHCI_PX_IS_DPS);
-
-    /* Clear expected interrupts and assert all interrupts now cleared. */
-    ahci_px_wreg(ahci, i, AHCI_PX_IS,
-                 AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS | AHCI_PX_IS_DPS);
-    g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
+    ahci_port_check_interrupts(ahci, i, AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS);
 
     /* Investigate the CMD, assert that we read 512 bytes */
     ahci_get_command_header(ahci, i, cx, &cmd);
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 3da168a..ef84cc6 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -333,6 +333,20 @@ void ahci_port_check_error(AHCIQState *ahci, uint8_t port)
     ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR);
 }
 
+void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port,
+                                uint32_t intr_mask)
+{
+    uint32_t reg;
+
+    /* Check for expected interrupts */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_IS);
+    ASSERT_BIT_SET(reg, intr_mask);
+
+    /* Clear expected interrupts and assert all interrupts now cleared. */
+    ahci_px_wreg(ahci, port, AHCI_PX_IS, intr_mask);
+    g_assert_cmphex(ahci_px_rreg(ahci, port, AHCI_PX_IS), ==, 0);
+}
+
 /* Get the command in #slot of port #port. */
 void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
                              uint8_t slot, AHCICommandHeader *cmd)
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index af62a8a..a2ffa70 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -434,6 +434,8 @@ void ahci_hba_enable(AHCIQState *ahci);
 unsigned ahci_port_select(AHCIQState *ahci);
 void ahci_port_clear(AHCIQState *ahci, uint8_t port);
 void ahci_port_check_error(AHCIQState *ahci, uint8_t port);
+void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port,
+                                uint32_t intr_mask);
 void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
                              uint8_t slot, AHCICommandHeader *cmd);
 void ahci_set_command_header(AHCIQState *ahci, uint8_t port,
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 26/65] libqos/ahci: Add port_check_nonbusy helper
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (24 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 25/65] libqos/ahci: Add ahci_port_check_interrupts helper Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 27/65] libqos/ahci: Add cmd response sanity check helpers Stefan Hajnoczi
                   ` (39 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

A simple helper that asserts a given port is not busy processing any
commands via the TFD, Command Issue and SACT registers.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1423158090-25580-8-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   |  1 +
 tests/libqos/ahci.c | 18 ++++++++++++++++++
 tests/libqos/ahci.h |  1 +
 3 files changed, 20 insertions(+)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 32b6be3..4cc7e21 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -751,6 +751,7 @@ static void ahci_test_identify(AHCIQState *ahci)
     ahci_port_check_error(ahci, i);
     /* BUG: we expect AHCI_PX_IS_DPS to be set. */
     ahci_port_check_interrupts(ahci, i, AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS);
+    ahci_port_check_nonbusy(ahci, i, cx);
 
     /* Investigate the CMD, assert that we read 512 bytes */
     ahci_get_command_header(ahci, i, cx, &cmd);
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index ef84cc6..7ed6494 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -347,6 +347,24 @@ void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port,
     g_assert_cmphex(ahci_px_rreg(ahci, port, AHCI_PX_IS), ==, 0);
 }
 
+void ahci_port_check_nonbusy(AHCIQState *ahci, uint8_t port, uint8_t slot)
+{
+    uint32_t reg;
+
+    /* Assert that the command slot is no longer busy (NCQ) */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_SACT);
+    ASSERT_BIT_CLEAR(reg, (1 << slot));
+
+    /* Non-NCQ */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_CI);
+    ASSERT_BIT_CLEAR(reg, (1 << slot));
+
+    /* And assert that we are generally not busy. */
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_BSY);
+    ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_DRQ);
+}
+
 /* Get the command in #slot of port #port. */
 void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
                              uint8_t slot, AHCICommandHeader *cmd)
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index a2ffa70..eaad076 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -436,6 +436,7 @@ void ahci_port_clear(AHCIQState *ahci, uint8_t port);
 void ahci_port_check_error(AHCIQState *ahci, uint8_t port);
 void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port,
                                 uint32_t intr_mask);
+void ahci_port_check_nonbusy(AHCIQState *ahci, uint8_t port, uint8_t slot);
 void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
                              uint8_t slot, AHCICommandHeader *cmd);
 void ahci_set_command_header(AHCIQState *ahci, uint8_t port,
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 27/65] libqos/ahci: Add cmd response sanity check helpers
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (25 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 26/65] libqos/ahci: Add port_check_nonbusy helper Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 28/65] qtest/ahci: Demagic ahci tests Stefan Hajnoczi
                   ` (38 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

This patch adds a few helpers to help sanity-check the response of the
AHCI device after a command.

ahci_d2h_check_sanity inspects the D2H Register FIS,
ahci_pio_check_sanity inspects the PIO Setup FIS, and
ahci_cmd_check_sanity inspects the command header.

To support the PIO sanity check, a new structure is added for the
PIO Setup FIS type. Existing FIS types (H2D and D2H) have had their
members renamed slightly to condense reserved members into fewer
fields; and LBA fields are now represented by arrays of 8 byte chunks
instead of independent variables.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1423158090-25580-9-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   | 29 ++++------------------------
 tests/libqos/ahci.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/ahci.h | 54 ++++++++++++++++++++++++++++++++++++-----------------
 3 files changed, 88 insertions(+), 42 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 4cc7e21..b67d935 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -657,12 +657,10 @@ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port)
  */
 static void ahci_test_identify(AHCIQState *ahci)
 {
-    RegD2HFIS *d2h = g_malloc0(0x20);
-    RegD2HFIS *pio = g_malloc0(0x20);
     RegH2DFIS fis;
     AHCICommandHeader cmd;
     PRD prd;
-    uint32_t reg, data_ptr;
+    uint32_t data_ptr;
     uint16_t buff[256];
     unsigned i;
     int rc;
@@ -752,27 +750,11 @@ static void ahci_test_identify(AHCIQState *ahci)
     /* BUG: we expect AHCI_PX_IS_DPS to be set. */
     ahci_port_check_interrupts(ahci, i, AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS);
     ahci_port_check_nonbusy(ahci, i, cx);
-
     /* Investigate the CMD, assert that we read 512 bytes */
-    ahci_get_command_header(ahci, i, cx, &cmd);
-    g_assert_cmphex(512, ==, cmd.prdbc);
-
+    ahci_port_check_cmd_sanity(ahci, i, cx, 512);
     /* Investigate FIS responses */
-    memread(ahci->port[i].fb + 0x20, pio, 0x20);
-    memread(ahci->port[i].fb + 0x40, d2h, 0x20);
-    g_assert_cmphex(pio->fis_type, ==, 0x5f);
-    g_assert_cmphex(d2h->fis_type, ==, 0x34);
-    g_assert_cmphex(pio->flags, ==, d2h->flags);
-    g_assert_cmphex(pio->status, ==, d2h->status);
-    g_assert_cmphex(pio->error, ==, d2h->error);
-
-    reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD);
-    g_assert_cmphex((reg & AHCI_PX_TFD_ERR), ==, pio->error);
-    g_assert_cmphex((reg & AHCI_PX_TFD_STS), ==, pio->status);
-    /* The PIO Setup FIS contains a "bytes read" field, which is a
-     * 16-bit value. The Physical Region Descriptor Byte Count is
-     * 32-bit, but for small transfers using one PRD, it should match. */
-    g_assert_cmphex(le16_to_cpu(pio->res4), ==, cmd.prdbc);
+    ahci_port_check_d2h_sanity(ahci, i, cx);
+    ahci_port_check_pio_sanity(ahci, i, cx, 512);
 
     /* Last, but not least: Investigate the IDENTIFY response data. */
     memread(data_ptr, &buff, 512);
@@ -789,9 +771,6 @@ static void ahci_test_identify(AHCIQState *ahci)
     string_bswap16(&buff[23], 8);
     rc = memcmp(&buff[23], "version ", 8);
     g_assert_cmphex(rc, ==, 0);
-
-    g_free(d2h);
-    g_free(pio);
 }
 
 /******************************************************************************/
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 7ed6494..8ecfdd3 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -365,6 +365,53 @@ void ahci_port_check_nonbusy(AHCIQState *ahci, uint8_t port, uint8_t slot)
     ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_DRQ);
 }
 
+void ahci_port_check_d2h_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot)
+{
+    RegD2HFIS *d2h = g_malloc0(0x20);
+    uint32_t reg;
+
+    memread(ahci->port[port].fb + 0x40, d2h, 0x20);
+    g_assert_cmphex(d2h->fis_type, ==, 0x34);
+
+    reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD);
+    g_assert_cmphex((reg & AHCI_PX_TFD_ERR) >> 8, ==, d2h->error);
+    g_assert_cmphex((reg & AHCI_PX_TFD_STS), ==, d2h->status);
+
+    g_free(d2h);
+}
+
+void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port,
+                                uint8_t slot, size_t buffsize)
+{
+    PIOSetupFIS *pio = g_malloc0(0x20);
+
+    /* We cannot check the Status or E_Status registers, becuase
+     * the status may have again changed between the PIO Setup FIS
+     * and the conclusion of the command with the D2H Register FIS. */
+    memread(ahci->port[port].fb + 0x20, pio, 0x20);
+    g_assert_cmphex(pio->fis_type, ==, 0x5f);
+
+    /* BUG: PIO Setup FIS as utilized by QEMU tries to fit the entire
+     * transfer size in a uint16_t field. The maximum transfer size can
+     * eclipse this; the field is meant to convey the size of data per
+     * each Data FIS, not the entire operation as a whole. For now,
+     * we will sanity check the broken case where applicable. */
+    if (buffsize <= UINT16_MAX) {
+        g_assert_cmphex(le16_to_cpu(pio->tx_count), ==, buffsize);
+    }
+
+    g_free(pio);
+}
+
+void ahci_port_check_cmd_sanity(AHCIQState *ahci, uint8_t port,
+                                uint8_t slot, size_t buffsize)
+{
+    AHCICommandHeader cmd;
+
+    ahci_get_command_header(ahci, port, slot, &cmd);
+    g_assert_cmphex(buffsize, ==, cmd.prdbc);
+}
+
 /* Get the command in #slot of port #port. */
 void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
                              uint8_t slot, AHCICommandHeader *cmd)
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index eaad076..f17aa23 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -283,25 +283,44 @@ typedef struct RegD2HFIS {
     uint8_t status;
     uint8_t error;
     /* DW1 */
-    uint8_t lba_low;
-    uint8_t lba_mid;
-    uint8_t lba_high;
+    uint8_t lba_lo[3];
     uint8_t device;
     /* DW2 */
-    uint8_t lba3;
-    uint8_t lba4;
-    uint8_t lba5;
-    uint8_t res1;
+    uint8_t lba_hi[3];
+    uint8_t res0;
     /* DW3 */
     uint16_t count;
-    uint8_t res2;
-    uint8_t res3;
+    uint16_t res1;
     /* DW4 */
-    uint16_t res4;
-    uint16_t res5;
+    uint32_t res2;
 } __attribute__((__packed__)) RegD2HFIS;
 
 /**
+ * Register device-to-host FIS structure;
+ * PIO Setup variety.
+ */
+typedef struct PIOSetupFIS {
+    /* DW0 */
+    uint8_t fis_type;
+    uint8_t flags;
+    uint8_t status;
+    uint8_t error;
+    /* DW1 */
+    uint8_t lba_lo[3];
+    uint8_t device;
+    /* DW2 */
+    uint8_t lba_hi[3];
+    uint8_t res0;
+    /* DW3 */
+    uint16_t count;
+    uint8_t res1;
+    uint8_t e_status;
+    /* DW4 */
+    uint16_t tx_count;
+    uint16_t res2;
+} __attribute__((__packed__)) PIOSetupFIS;
+
+/**
  * Register host-to-device FIS structure.
  */
 typedef struct RegH2DFIS {
@@ -311,14 +330,10 @@ typedef struct RegH2DFIS {
     uint8_t command;
     uint8_t feature_low;
     /* DW1 */
-    uint8_t lba_low;
-    uint8_t lba_mid;
-    uint8_t lba_high;
+    uint8_t lba_lo[3];
     uint8_t device;
     /* DW2 */
-    uint8_t lba3;
-    uint8_t lba4;
-    uint8_t lba5;
+    uint8_t lba_hi[3];
     uint8_t feature_high;
     /* DW3 */
     uint16_t count;
@@ -437,6 +452,11 @@ void ahci_port_check_error(AHCIQState *ahci, uint8_t port);
 void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port,
                                 uint32_t intr_mask);
 void ahci_port_check_nonbusy(AHCIQState *ahci, uint8_t port, uint8_t slot);
+void ahci_port_check_d2h_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot);
+void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port,
+                                uint8_t slot, size_t buffsize);
+void ahci_port_check_cmd_sanity(AHCIQState *ahci, uint8_t port,
+                                uint8_t slot, size_t buffsize);
 void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
                              uint8_t slot, AHCICommandHeader *cmd);
 void ahci_set_command_header(AHCIQState *ahci, uint8_t port,
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 28/65] qtest/ahci: Demagic ahci tests.
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (26 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 27/65] libqos/ahci: Add cmd response sanity check helpers Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 29/65] qtest/ahci: add ahci_write_fis Stefan Hajnoczi
                   ` (37 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Add human-readable command names and other miscellaneous #defines
to help make the code more readable.

Some of these definitions are not yet used in this current series,
but for convenience and sanity they have been lumped together here,
as it's more trouble than it is worth in a test suite to hand-pick,
one-by-one, which preprocessor definitions are useful per-each test.

These definitions include:

ATA Command Mnemonics
Current expected AHCI sector size
FIS magic bytes
REG_H2D_FIS flags
Command Header flags

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
Message-id: 1423158090-25580-10-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   | 12 ++++++------
 tests/libqos/ahci.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 6 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index b67d935..211274e 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -705,9 +705,9 @@ static void ahci_test_identify(AHCIQState *ahci)
 
     /* Construct our Command Header (set_command_header handles endianness.) */
     memset(&cmd, 0x00, sizeof(cmd));
-    cmd.flags = 5;      /* reg_h2d_fis is 5 double-words long */
-    cmd.flags |= 0x400; /* clear PxTFD.STS.BSY when done */
-    cmd.prdtl = 1;      /* One PRD table entry. */
+    cmd.flags = 5;             /* reg_h2d_fis is 5 double-words long */
+    cmd.flags |= CMDH_CLR_BSY; /* clear PxTFD.STS.BSY when done */
+    cmd.prdtl = 1;             /* One PRD table entry. */
     cmd.prdbc = 0;
     cmd.ctba = table;
 
@@ -719,10 +719,10 @@ static void ahci_test_identify(AHCIQState *ahci)
 
     /* Construct our Command FIS, Based on http://wiki.osdev.org/AHCI */
     memset(&fis, 0x00, sizeof(fis));
-    fis.fis_type = 0x27; /* Register Host-to-Device FIS */
-    fis.command = 0xEC;  /* IDENTIFY */
+    fis.fis_type = REG_H2D_FIS;  /* Register Host-to-Device FIS */
+    fis.command = CMD_IDENTIFY;
     fis.device = 0;
-    fis.flags = 0x80;    /* Indicate this is a command FIS */
+    fis.flags = REG_H2D_FIS_CMD; /* Indicate this is a command FIS */
 
     /* We've committed nothing yet, no interrupts should be posted yet. */
     g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index f17aa23..0837bf5 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -243,6 +243,59 @@
 #define AHCI_VERSION_1_2         (0x00010200)
 #define AHCI_VERSION_1_3         (0x00010300)
 
+#define AHCI_SECTOR_SIZE                (512)
+
+/* FIS types */
+enum {
+    REG_H2D_FIS = 0x27,
+    REG_D2H_FIS = 0x34,
+    DMA_ACTIVATE_FIS = 0x39,
+    DMA_SETUP_FIS = 0x41,
+    DATA_FIS = 0x46,
+    BIST_ACTIVATE_FIS = 0x58,
+    PIO_SETUP_FIS = 0x5F,
+    SDB_FIS = 0xA1
+};
+
+/* FIS flags */
+#define REG_H2D_FIS_CMD  0x80
+
+/* ATA Commands */
+enum {
+    /* DMA */
+    CMD_READ_DMA      = 0xC8,
+    CMD_READ_DMA_EXT  = 0x25,
+    CMD_WRITE_DMA     = 0xCA,
+    CMD_WRITE_DMA_EXT = 0x35,
+    /* PIO */
+    CMD_READ_PIO      = 0x20,
+    CMD_READ_PIO_EXT  = 0x24,
+    CMD_WRITE_PIO     = 0x30,
+    CMD_WRITE_PIO_EXT = 0x34,
+    /* Misc */
+    CMD_READ_MAX      = 0xF8,
+    CMD_READ_MAX_EXT  = 0x27,
+    CMD_FLUSH_CACHE   = 0xE7,
+    CMD_IDENTIFY      = 0xEC
+};
+
+/* AHCI Command Header Flags & Masks*/
+#define CMDH_CFL        (0x1F)
+#define CMDH_ATAPI      (0x20)
+#define CMDH_WRITE      (0x40)
+#define CMDH_PREFETCH   (0x80)
+#define CMDH_RESET     (0x100)
+#define CMDH_BIST      (0x200)
+#define CMDH_CLR_BSY   (0x400)
+#define CMDH_RES       (0x800)
+#define CMDH_PMP      (0xF000)
+
+/* ATA device register masks */
+#define ATA_DEVICE_MAGIC 0xA0
+#define ATA_DEVICE_LBA   0x40
+#define ATA_DEVICE_DRIVE 0x10
+#define ATA_DEVICE_HEAD  0x0F
+
 /*** Structures ***/
 
 typedef struct AHCIPortQState {
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 29/65] qtest/ahci: add ahci_write_fis
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (27 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 28/65] qtest/ahci: Demagic ahci tests Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 30/65] libqos/ahci: Add ide cmd properties Stefan Hajnoczi
                   ` (36 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Similar to ahci_set_command_header, add a helper that takes an
in-memory representation of a command FIS and writes it to guest
memory, handling endianness as-needed.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-id: 1423158090-25580-11-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   |  2 +-
 tests/libqos/ahci.c | 14 ++++++++++++++
 tests/libqos/ahci.h |  3 ++-
 3 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 211274e..658956d 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -728,7 +728,7 @@ static void ahci_test_identify(AHCIQState *ahci)
     g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
 
     /* Commit the Command FIS to the Command Table */
-    memwrite(table, &fis, sizeof(fis));
+    ahci_write_fis(ahci, &fis, table);
 
     /* Commit the PRD entry to the Command Table */
     memwrite(table + 0x80, &prd, sizeof(prd));
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 8ecfdd3..1294f80 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -464,6 +464,20 @@ void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot)
     ahci->port[port].prdtl[slot] = 0;
 }
 
+void ahci_write_fis(AHCIQState *ahci, RegH2DFIS *fis, uint64_t addr)
+{
+    RegH2DFIS tmp = *fis;
+
+    /* The auxiliary FIS fields are defined per-command and are not
+     * currently implemented in libqos/ahci.o, but may or may not need
+     * to be flipped. */
+
+    /* All other FIS fields are 8 bit and do not need to be flipped. */
+    tmp.count = cpu_to_le16(tmp.count);
+
+    memwrite(addr, &tmp, sizeof(tmp));
+}
+
 unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port)
 {
     unsigned i;
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 0837bf5..83a62ac 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -393,7 +393,7 @@ typedef struct RegH2DFIS {
     uint8_t icc;
     uint8_t control;
     /* DW4 */
-    uint32_t aux;
+    uint8_t aux[4];
 } __attribute__((__packed__)) RegH2DFIS;
 
 /**
@@ -515,6 +515,7 @@ void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
 void ahci_set_command_header(AHCIQState *ahci, uint8_t port,
                              uint8_t slot, AHCICommandHeader *cmd);
 void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot);
+void ahci_write_fis(AHCIQState *ahci, RegH2DFIS *fis, uint64_t addr);
 unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port);
 
 #endif
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 30/65] libqos/ahci: Add ide cmd properties
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (28 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 29/65] qtest/ahci: add ahci_write_fis Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 31/65] libqos/ahci: add ahci command functions Stefan Hajnoczi
                   ` (35 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Add a structure that defines some properties of various IDE commands.
These will be used to simplify the interface to the libqos AHCI calls,
lessening the redundancy of specifying and respecifying properties of
commands to various helper functions.

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
Message-id: 1423158090-25580-12-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/libqos/ahci.c | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 1294f80..148aa1b 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -34,6 +34,45 @@
 #include "hw/pci/pci_ids.h"
 #include "hw/pci/pci_regs.h"
 
+typedef struct AHCICommandProp {
+    uint8_t  cmd;        /* Command Code */
+    bool     data;       /* Data transfer command? */
+    bool     pio;
+    bool     dma;
+    bool     lba28;
+    bool     lba48;
+    bool     read;
+    bool     write;
+    bool     atapi;
+    bool     ncq;
+    uint64_t size;       /* Static transfer size, for commands like IDENTIFY. */
+    uint32_t interrupts; /* Expected interrupts for this command. */
+} AHCICommandProp;
+
+AHCICommandProp ahci_command_properties[] = {
+    { .cmd = CMD_READ_PIO,      .data = true,  .pio = true,
+                                .lba28 = true, .read = true },
+    { .cmd = CMD_WRITE_PIO,     .data = true,  .pio = true,
+                                .lba28 = true, .write = true },
+    { .cmd = CMD_READ_PIO_EXT,  .data = true,  .pio = true,
+                                .lba48 = true, .read = true },
+    { .cmd = CMD_WRITE_PIO_EXT, .data = true,  .pio = true,
+                                .lba48 = true, .write = true },
+    { .cmd = CMD_READ_DMA,      .data = true,  .dma = true,
+                                .lba28 = true, .read = true },
+    { .cmd = CMD_WRITE_DMA,     .data = true,  .dma = true,
+                                .lba28 = true, .write = true },
+    { .cmd = CMD_READ_DMA_EXT,  .data = true,  .dma = true,
+                                .lba48 = true, .read = true },
+    { .cmd = CMD_WRITE_DMA_EXT, .data = true,  .dma = true,
+                                .lba48 = true, .write = true },
+    { .cmd = CMD_IDENTIFY,      .data = true,  .pio = true,
+                                .size = 512,   .read = true },
+    { .cmd = CMD_READ_MAX,      .lba28 = true },
+    { .cmd = CMD_READ_MAX_EXT,  .lba48 = true },
+    { .cmd = CMD_FLUSH_CACHE,   .data = false }
+};
+
 /**
  * Allocate space in the guest using information in the AHCIQState object.
  */
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 31/65] libqos/ahci: add ahci command functions
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (29 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 30/65] libqos/ahci: Add ide cmd properties Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 32/65] libqos/ahci: add ahci command verify Stefan Hajnoczi
                   ` (34 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

This patch adds the AHCICommand structure, and a set of functions to
operate on the structure.

ahci_command_create - Initialize and create a new AHCICommand in memory
ahci_command_free - Destroy this object.
ahci_command_set_buffer - Set where the guest memory DMA buffer is.
ahci_command_commit - Write this command to the AHCI HBA.
ahci_command_issue - Issue the committed command synchronously.
ahci_command_issue_async - Issue the committed command asynchronously.
ahci_command_wait - Wait for an asynchronous command to finish.
ahci_command_slot - Get the number of the command slot we committed to.

Helpers:
size_to_prdtl       - Calculate the required minimum PRDTL size from
                      a buffer size.
ahci_command_find   - Given an ATA command mnemonic, look it up in the
                      properties table to obtain info about the command.
command_header_init - Initialize the command header with sane values.
command_table_init  - Initialize the command table with sane values.

[Peter Maydell <peter.maydell@linaro.org> reported the following clang
warning:

  tests/libqos/ahci.c:598:3: warning: redefinition
  of typedef 'AHCICommand' is a C11 feature
      [-Wtypedef-redefinition]
  } AHCICommand;

I have replaced typedef struct ... AHCICommand; with struct ... ;
--Stefan]

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
Message-id: 1423158090-25580-13-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   |  73 +++++--------------
 tests/libqos/ahci.c | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/ahci.h |  18 +++++
 3 files changed, 237 insertions(+), 56 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 658956d..0834020 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -657,30 +657,28 @@ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port)
  */
 static void ahci_test_identify(AHCIQState *ahci)
 {
-    RegH2DFIS fis;
-    AHCICommandHeader cmd;
-    PRD prd;
     uint32_t data_ptr;
     uint16_t buff[256];
     unsigned i;
     int rc;
+    AHCICommand *cmd;
     uint8_t cx;
-    uint64_t table;
 
     g_assert(ahci != NULL);
 
     /* We need to:
-     * (1) Create a Command Table Buffer and update the Command List Slot #0
-     *     to point to this buffer.
-     * (2) Construct an FIS host-to-device command structure, and write it to
+     * (1) Create a data buffer for the IDENTIFY response to be sent to,
+     * (2) Create a Command Table Buffer
+     * (3) Construct an FIS host-to-device command structure, and write it to
      *     the top of the command table buffer.
-     * (3) Create a data buffer for the IDENTIFY response to be sent to
      * (4) Create a Physical Region Descriptor that points to the data buffer,
      *     and write it to the bottom (offset 0x80) of the command table.
-     * (5) Now, PxCLB points to the command list, command 0 points to
+     * (5) Obtain a Command List slot, and update this header to point to
+     *     the Command Table we built above.
+     * (6) Now, PxCLB points to the command list, command 0 points to
      *     our table, and our table contains an FIS instruction and a
      *     PRD that points to our rx buffer.
-     * (6) We inform the HBA via PxCI that there is a command ready in slot #0.
+     * (7) We inform the HBA via PxCI that there is a command ready in slot #0.
      */
 
     /* Pick the first implemented and running port */
@@ -690,61 +688,24 @@ static void ahci_test_identify(AHCIQState *ahci)
     /* Clear out the FIS Receive area and any pending interrupts. */
     ahci_port_clear(ahci, i);
 
-    /* Create a Command Table buffer. 0x80 is the smallest with a PRDTL of 0. */
-    /* We need at least one PRD, so round up to the nearest 0x80 multiple.    */
-    table = ahci_alloc(ahci, CMD_TBL_SIZ(1));
-    g_assert(table);
-    ASSERT_BIT_CLEAR(table, 0x7F);
-
-    /* Create a data buffer ... where we will dump the IDENTIFY data to. */
+    /* Create a data buffer where we will dump the IDENTIFY data to. */
     data_ptr = ahci_alloc(ahci, 512);
     g_assert(data_ptr);
 
-    /* pick a command slot (should be 0!) */
-    cx = ahci_pick_cmd(ahci, i);
-
-    /* Construct our Command Header (set_command_header handles endianness.) */
-    memset(&cmd, 0x00, sizeof(cmd));
-    cmd.flags = 5;             /* reg_h2d_fis is 5 double-words long */
-    cmd.flags |= CMDH_CLR_BSY; /* clear PxTFD.STS.BSY when done */
-    cmd.prdtl = 1;             /* One PRD table entry. */
-    cmd.prdbc = 0;
-    cmd.ctba = table;
-
-    /* Construct our PRD, noting that DBC is 0-indexed. */
-    prd.dba = cpu_to_le64(data_ptr);
-    prd.res = 0;
-    /* 511+1 bytes, request DPS interrupt */
-    prd.dbc = cpu_to_le32(511 | 0x80000000);
-
-    /* Construct our Command FIS, Based on http://wiki.osdev.org/AHCI */
-    memset(&fis, 0x00, sizeof(fis));
-    fis.fis_type = REG_H2D_FIS;  /* Register Host-to-Device FIS */
-    fis.command = CMD_IDENTIFY;
-    fis.device = 0;
-    fis.flags = REG_H2D_FIS_CMD; /* Indicate this is a command FIS */
-
-    /* We've committed nothing yet, no interrupts should be posted yet. */
-    g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
-
-    /* Commit the Command FIS to the Command Table */
-    ahci_write_fis(ahci, &fis, table);
-
-    /* Commit the PRD entry to the Command Table */
-    memwrite(table + 0x80, &prd, sizeof(prd));
-
-    /* Commit Command #cx, pointing to the Table, to the Command List Buffer. */
-    ahci_set_command_header(ahci, i, cx, &cmd);
+    /* Construct the Command Table (FIS and PRDT) and Command Header */
+    cmd = ahci_command_create(CMD_IDENTIFY);
+    ahci_command_set_buffer(cmd, data_ptr);
+    /* Write the command header and PRDT to guest memory */
+    ahci_command_commit(ahci, cmd, i);
 
     /* Everything is in place, but we haven't given the go-ahead yet,
      * so we should find that there are no pending interrupts yet. */
     g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
 
     /* Issue Command #cx via PxCI */
-    ahci_px_wreg(ahci, i, AHCI_PX_CI, (1 << cx));
-    while (BITSET(ahci_px_rreg(ahci, i, AHCI_PX_TFD), AHCI_PX_TFD_STS_BSY)) {
-        usleep(50);
-    }
+    ahci_command_issue(ahci, cmd);
+    cx = ahci_command_slot(cmd);
+
     /* Check registers for post-command consistency */
     ahci_port_check_error(ahci, i);
     /* BUG: we expect AHCI_PX_IS_DPS to be set. */
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 148aa1b..21f86c0 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -539,3 +539,205 @@ unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port)
     g_test_message("All command slots were busy.");
     g_assert_not_reached();
 }
+
+inline unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd)
+{
+    /* Each PRD can describe up to 4MiB */
+    g_assert_cmphex(bytes_per_prd, <=, 4096 * 1024);
+    g_assert_cmphex(bytes_per_prd & 0x01, ==, 0x00);
+    return (bytes + bytes_per_prd - 1) / bytes_per_prd;
+}
+
+struct AHCICommand {
+    /* Test Management Data */
+    uint8_t name;
+    uint8_t port;
+    uint8_t slot;
+    uint32_t interrupts;
+    uint64_t xbytes;
+    uint32_t prd_size;
+    uint64_t buffer;
+    AHCICommandProp *props;
+    /* Data to be transferred to the guest */
+    AHCICommandHeader header;
+    RegH2DFIS fis;
+    void *atapi_cmd;
+};
+
+static AHCICommandProp *ahci_command_find(uint8_t command_name)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(ahci_command_properties); i++) {
+        if (ahci_command_properties[i].cmd == command_name) {
+            return &ahci_command_properties[i];
+        }
+    }
+
+    return NULL;
+}
+
+/**
+ * Initializes a basic command header in memory.
+ * We assume that this is for an ATA command using RegH2DFIS.
+ */
+static void command_header_init(AHCICommand *cmd)
+{
+    AHCICommandHeader *hdr = &cmd->header;
+    AHCICommandProp *props = cmd->props;
+
+    hdr->flags = 5;             /* RegH2DFIS is 5 DW long. Must be < 32 */
+    hdr->flags |= CMDH_CLR_BSY; /* Clear the BSY bit when done */
+    if (props->write) {
+        hdr->flags |= CMDH_WRITE;
+    }
+    if (props->atapi) {
+        hdr->flags |= CMDH_ATAPI;
+    }
+    /* Other flags: PREFETCH, RESET, and BIST */
+    hdr->prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size);
+    hdr->prdbc = 0;
+    hdr->ctba = 0;
+}
+
+static void command_table_init(AHCICommand *cmd)
+{
+    RegH2DFIS *fis = &(cmd->fis);
+
+    fis->fis_type = REG_H2D_FIS;
+    fis->flags = REG_H2D_FIS_CMD; /* "Command" bit */
+    fis->command = cmd->name;
+    cmd->fis.feature_low = 0x00;
+    cmd->fis.feature_high = 0x00;
+    if (cmd->props->lba28 || cmd->props->lba48) {
+        cmd->fis.device = ATA_DEVICE_LBA;
+    }
+    cmd->fis.count = (cmd->xbytes / AHCI_SECTOR_SIZE);
+    cmd->fis.icc = 0x00;
+    cmd->fis.control = 0x00;
+    memset(cmd->fis.aux, 0x00, ARRAY_SIZE(cmd->fis.aux));
+}
+
+AHCICommand *ahci_command_create(uint8_t command_name)
+{
+    AHCICommandProp *props = ahci_command_find(command_name);
+    AHCICommand *cmd;
+
+    g_assert(props);
+    cmd = g_malloc0(sizeof(AHCICommand));
+    g_assert(!(props->dma && props->pio));
+    g_assert(!(props->lba28 && props->lba48));
+    g_assert(!(props->read && props->write));
+    g_assert(!props->size || props->data);
+
+    /* Defaults and book-keeping */
+    cmd->props = props;
+    cmd->name = command_name;
+    cmd->xbytes = props->size;
+    cmd->prd_size = 4096;
+    cmd->buffer = 0xabad1dea;
+
+    cmd->interrupts = AHCI_PX_IS_DHRS;
+    /* BUG: We expect the DPS interrupt for data commands */
+    /* cmd->interrupts |= props->data ? AHCI_PX_IS_DPS : 0; */
+    /* BUG: We expect the DMA Setup interrupt for DMA commands */
+    /* cmd->interrupts |= props->dma ? AHCI_PX_IS_DSS : 0; */
+    cmd->interrupts |= props->pio ? AHCI_PX_IS_PSS : 0;
+
+    command_header_init(cmd);
+    command_table_init(cmd);
+
+    return cmd;
+}
+
+void ahci_command_free(AHCICommand *cmd)
+{
+    g_free(cmd);
+}
+
+void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer)
+{
+    cmd->buffer = buffer;
+}
+
+void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port)
+{
+    uint16_t i, prdtl;
+    uint64_t table_size, table_ptr, remaining;
+    PRD prd;
+
+    /* This command is now tied to this port/command slot */
+    cmd->port = port;
+    cmd->slot = ahci_pick_cmd(ahci, port);
+
+    /* Create a buffer for the command table */
+    prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size);
+    table_size = CMD_TBL_SIZ(prdtl);
+    table_ptr = ahci_alloc(ahci, table_size);
+    g_assert(table_ptr);
+    /* AHCI 1.3: Must be aligned to 0x80 */
+    g_assert((table_ptr & 0x7F) == 0x00);
+    cmd->header.ctba = table_ptr;
+
+    /* Commit the command header and command FIS */
+    ahci_set_command_header(ahci, port, cmd->slot, &(cmd->header));
+    ahci_write_fis(ahci, &(cmd->fis), table_ptr);
+
+    /* Construct and write the PRDs to the command table */
+    g_assert_cmphex(prdtl, ==, cmd->header.prdtl);
+    remaining = cmd->xbytes;
+    for (i = 0; i < prdtl; ++i) {
+        prd.dba = cpu_to_le64(cmd->buffer + (cmd->prd_size * i));
+        prd.res = 0;
+        if (remaining > cmd->prd_size) {
+            /* Note that byte count is 0-based. */
+            prd.dbc = cpu_to_le32(cmd->prd_size - 1);
+            remaining -= cmd->prd_size;
+        } else {
+            /* Again, dbc is 0-based. */
+            prd.dbc = cpu_to_le32(remaining - 1);
+            remaining = 0;
+        }
+        prd.dbc |= cpu_to_le32(0x80000000); /* Request DPS Interrupt */
+
+        /* Commit the PRD entry to the Command Table */
+        memwrite(table_ptr + 0x80 + (i * sizeof(PRD)),
+                 &prd, sizeof(PRD));
+    }
+
+    /* Bookmark the PRDTL and CTBA values */
+    ahci->port[port].ctba[cmd->slot] = table_ptr;
+    ahci->port[port].prdtl[cmd->slot] = prdtl;
+}
+
+void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd)
+{
+    if (cmd->props->ncq) {
+        ahci_px_wreg(ahci, cmd->port, AHCI_PX_SACT, (1 << cmd->slot));
+    }
+
+    ahci_px_wreg(ahci, cmd->port, AHCI_PX_CI, (1 << cmd->slot));
+}
+
+void ahci_command_wait(AHCIQState *ahci, AHCICommand *cmd)
+{
+    /* We can't rely on STS_BSY until the command has started processing.
+     * Therefore, we also use the Command Issue bit as indication of
+     * a command in-flight. */
+    while (BITSET(ahci_px_rreg(ahci, cmd->port, AHCI_PX_TFD),
+                  AHCI_PX_TFD_STS_BSY) ||
+           BITSET(ahci_px_rreg(ahci, cmd->port, AHCI_PX_CI), (1 << cmd->slot))) {
+        usleep(50);
+    }
+}
+
+void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd)
+{
+    ahci_command_issue_async(ahci, cmd);
+    ahci_command_wait(ahci, cmd);
+}
+
+uint8_t ahci_command_slot(AHCICommand *cmd)
+{
+    return cmd->slot;
+}
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 83a62ac..6ca1a6e 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -418,6 +418,9 @@ typedef struct PRD {
     uint32_t dbc;  /* Data Byte Count (0-indexed) & Interrupt Flag (bit 2^31) */
 } __attribute__((__packed__)) PRD;
 
+/* Opaque, defined within ahci.c */
+typedef struct AHCICommand AHCICommand;
+
 /*** Macro Utilities ***/
 #define BITANY(data, mask) (((data) & (mask)) != 0)
 #define BITSET(data, mask) (((data) & (mask)) == (mask))
@@ -517,5 +520,20 @@ void ahci_set_command_header(AHCIQState *ahci, uint8_t port,
 void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot);
 void ahci_write_fis(AHCIQState *ahci, RegH2DFIS *fis, uint64_t addr);
 unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port);
+unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd);
+
+/* Command Lifecycle */
+AHCICommand *ahci_command_create(uint8_t command_name);
+void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port);
+void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd);
+void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd);
+void ahci_command_wait(AHCIQState *ahci, AHCICommand *cmd);
+void ahci_command_free(AHCICommand *cmd);
+
+/* Command adjustments */
+void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer);
+
+/* Command Misc */
+uint8_t ahci_command_slot(AHCICommand *cmd);
 
 #endif
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 32/65] libqos/ahci: add ahci command verify
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (30 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 31/65] libqos/ahci: add ahci command functions Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 33/65] libqos/ahci: add ahci command size setters Stefan Hajnoczi
                   ` (33 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Helps to verify that a command completed successfully.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1423158090-25580-14-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   | 16 ++--------------
 tests/libqos/ahci.c | 15 +++++++++++++++
 tests/libqos/ahci.h |  1 +
 3 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 0834020..6e7b765 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -662,7 +662,6 @@ static void ahci_test_identify(AHCIQState *ahci)
     unsigned i;
     int rc;
     AHCICommand *cmd;
-    uint8_t cx;
 
     g_assert(ahci != NULL);
 
@@ -702,20 +701,9 @@ static void ahci_test_identify(AHCIQState *ahci)
      * so we should find that there are no pending interrupts yet. */
     g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
 
-    /* Issue Command #cx via PxCI */
+    /* Issue command and sanity check response. */
     ahci_command_issue(ahci, cmd);
-    cx = ahci_command_slot(cmd);
-
-    /* Check registers for post-command consistency */
-    ahci_port_check_error(ahci, i);
-    /* BUG: we expect AHCI_PX_IS_DPS to be set. */
-    ahci_port_check_interrupts(ahci, i, AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS);
-    ahci_port_check_nonbusy(ahci, i, cx);
-    /* Investigate the CMD, assert that we read 512 bytes */
-    ahci_port_check_cmd_sanity(ahci, i, cx, 512);
-    /* Investigate FIS responses */
-    ahci_port_check_d2h_sanity(ahci, i, cx);
-    ahci_port_check_pio_sanity(ahci, i, cx, 512);
+    ahci_command_verify(ahci, cmd);
 
     /* Last, but not least: Investigate the IDENTIFY response data. */
     memread(data_ptr, &buff, 512);
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 21f86c0..09e7159 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -737,6 +737,21 @@ void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd)
     ahci_command_wait(ahci, cmd);
 }
 
+void ahci_command_verify(AHCIQState *ahci, AHCICommand *cmd)
+{
+    uint8_t slot = cmd->slot;
+    uint8_t port = cmd->port;
+
+    ahci_port_check_error(ahci, port);
+    ahci_port_check_interrupts(ahci, port, cmd->interrupts);
+    ahci_port_check_nonbusy(ahci, port, slot);
+    ahci_port_check_cmd_sanity(ahci, port, slot, cmd->xbytes);
+    ahci_port_check_d2h_sanity(ahci, port, slot);
+    if (cmd->props->pio) {
+        ahci_port_check_pio_sanity(ahci, port, slot, cmd->xbytes);
+    }
+}
+
 uint8_t ahci_command_slot(AHCICommand *cmd)
 {
     return cmd->slot;
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 6ca1a6e..26ccdd6 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -528,6 +528,7 @@ void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port);
 void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd);
 void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd);
 void ahci_command_wait(AHCIQState *ahci, AHCICommand *cmd);
+void ahci_command_verify(AHCIQState *ahci, AHCICommand *cmd);
 void ahci_command_free(AHCICommand *cmd);
 
 /* Command adjustments */
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 33/65] libqos/ahci: add ahci command size setters
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (31 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 32/65] libqos/ahci: add ahci command verify Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 34/65] libqos/ahci: Add ahci_guest_io Stefan Hajnoczi
                   ` (32 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Adds setters for size, prd_size and both via set_sizes.

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
Message-id: 1423158090-25580-15-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/libqos/ahci.c | 22 ++++++++++++++++++++++
 tests/libqos/ahci.h |  4 ++++
 2 files changed, 26 insertions(+)

diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 09e7159..cd1f3ff 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -660,6 +660,28 @@ void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer)
     cmd->buffer = buffer;
 }
 
+void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
+                            unsigned prd_size)
+{
+    /* Each PRD can describe up to 4MiB, and must not be odd. */
+    g_assert_cmphex(prd_size, <=, 4096 * 1024);
+    g_assert_cmphex(prd_size & 0x01, ==, 0x00);
+    cmd->prd_size = prd_size;
+    cmd->xbytes = xbytes;
+    cmd->fis.count = (cmd->xbytes / AHCI_SECTOR_SIZE);
+    cmd->header.prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size);
+}
+
+void ahci_command_set_size(AHCICommand *cmd, uint64_t xbytes)
+{
+    ahci_command_set_sizes(cmd, xbytes, cmd->prd_size);
+}
+
+void ahci_command_set_prd_size(AHCICommand *cmd, unsigned prd_size)
+{
+    ahci_command_set_sizes(cmd, cmd->xbytes, prd_size);
+}
+
 void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port)
 {
     uint16_t i, prdtl;
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 26ccdd6..57ff344 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -533,6 +533,10 @@ void ahci_command_free(AHCICommand *cmd);
 
 /* Command adjustments */
 void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer);
+void ahci_command_set_size(AHCICommand *cmd, uint64_t xbytes);
+void ahci_command_set_prd_size(AHCICommand *cmd, unsigned prd_size);
+void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
+                            unsigned prd_size);
 
 /* Command Misc */
 uint8_t ahci_command_slot(AHCICommand *cmd);
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 34/65] libqos/ahci: Add ahci_guest_io
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (32 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 33/65] libqos/ahci: add ahci command size setters Stefan Hajnoczi
@ 2015-02-16 15:45 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 35/65] libqos/ahci: add ahci_io Stefan Hajnoczi
                   ` (31 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:45 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

ahci_guest_io is a shorthand function that will, in one shot,
execute a data command on the guest to the specified guest buffer
location, in the requested amount.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1423158090-25580-16-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/libqos/ahci.c | 15 +++++++++++++++
 tests/libqos/ahci.h |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index cd1f3ff..345d1f1 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -548,6 +548,21 @@ inline unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd)
     return (bytes + bytes_per_prd - 1) / bytes_per_prd;
 }
 
+/* Given a guest buffer address, perform an IO operation */
+void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
+                   uint64_t buffer, size_t bufsize)
+{
+    AHCICommand *cmd;
+
+    cmd = ahci_command_create(ide_cmd);
+    ahci_command_set_buffer(cmd, buffer);
+    ahci_command_set_size(cmd, bufsize);
+    ahci_command_commit(ahci, cmd, port);
+    ahci_command_issue(ahci, cmd);
+    ahci_command_verify(ahci, cmd);
+    ahci_command_free(cmd);
+}
+
 struct AHCICommand {
     /* Test Management Data */
     uint8_t name;
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 57ff344..1206c7a 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -521,6 +521,8 @@ void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot);
 void ahci_write_fis(AHCIQState *ahci, RegH2DFIS *fis, uint64_t addr);
 unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port);
 unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd);
+void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
+                   uint64_t gbuffer, size_t size);
 
 /* Command Lifecycle */
 AHCICommand *ahci_command_create(uint8_t command_name);
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 35/65] libqos/ahci: add ahci_io
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (33 preceding siblings ...)
  2015-02-16 15:45 ` [Qemu-devel] [PULL v2 34/65] libqos/ahci: Add ahci_guest_io Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 36/65] libqos/ahci: Add ahci_clean_mem Stefan Hajnoczi
                   ` (30 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

ahci_io is a wrapper around ahci_guest_io that takes a pointer to host
memory instead, and will create a guest memory buffer and copy the data
to/from as needed and as appropriate for a read/write command, such that
after a read, the guest data will be in a host buffer, and for a write,
the data will be transmitted to guest memory prior to the block operation.

Now that we have all the syntactic sugar functions in place for AHCI,
we can convert the identify test to be very, very short.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1423158090-25580-17-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c   | 63 +++++++++++++++++++++--------------------------------
 tests/libqos/ahci.c | 25 +++++++++++++++++++++
 tests/libqos/ahci.h |  2 ++
 3 files changed, 52 insertions(+), 38 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 6e7b765..47491fe 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -657,56 +657,43 @@ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port)
  */
 static void ahci_test_identify(AHCIQState *ahci)
 {
-    uint32_t data_ptr;
     uint16_t buff[256];
-    unsigned i;
+    unsigned px;
     int rc;
-    AHCICommand *cmd;
+    const size_t buffsize = 512;
 
     g_assert(ahci != NULL);
 
-    /* We need to:
-     * (1) Create a data buffer for the IDENTIFY response to be sent to,
-     * (2) Create a Command Table Buffer
+    /**
+     * This serves as a bit of a tutorial on AHCI device programming:
+     *
+     * (1) Create a data buffer for the IDENTIFY response to be sent to
+     * (2) Create a Command Table buffer, where we will store the
+     *     command and PRDT (Physical Region Descriptor Table)
      * (3) Construct an FIS host-to-device command structure, and write it to
-     *     the top of the command table buffer.
-     * (4) Create a Physical Region Descriptor that points to the data buffer,
-     *     and write it to the bottom (offset 0x80) of the command table.
-     * (5) Obtain a Command List slot, and update this header to point to
-     *     the Command Table we built above.
-     * (6) Now, PxCLB points to the command list, command 0 points to
-     *     our table, and our table contains an FIS instruction and a
-     *     PRD that points to our rx buffer.
-     * (7) We inform the HBA via PxCI that there is a command ready in slot #0.
+     *     the top of the Command Table buffer.
+     * (4) Create one or more Physical Region Descriptors (PRDs) that describe
+     *     a location in memory where data may be stored/retrieved.
+     * (5) Write these PRDTs to the bottom (offset 0x80) of the Command Table.
+     * (6) Each AHCI port has up to 32 command slots. Each slot contains a
+     *     header that points to a Command Table buffer. Pick an unused slot
+     *     and update it to point to the Command Table we have built.
+     * (7) Now: Command #n points to our Command Table, and our Command Table
+     *     contains the FIS (that describes our command) and the PRDTL, which
+     *     describes our buffer.
+     * (8) We inform the HBA via PxCI (Command Issue) that the command in slot
+     *     #n is ready for processing.
      */
 
     /* Pick the first implemented and running port */
-    i = ahci_port_select(ahci);
-    g_test_message("Selected port %u for test", i);
+    px = ahci_port_select(ahci);
+    g_test_message("Selected port %u for test", px);
 
     /* Clear out the FIS Receive area and any pending interrupts. */
-    ahci_port_clear(ahci, i);
-
-    /* Create a data buffer where we will dump the IDENTIFY data to. */
-    data_ptr = ahci_alloc(ahci, 512);
-    g_assert(data_ptr);
-
-    /* Construct the Command Table (FIS and PRDT) and Command Header */
-    cmd = ahci_command_create(CMD_IDENTIFY);
-    ahci_command_set_buffer(cmd, data_ptr);
-    /* Write the command header and PRDT to guest memory */
-    ahci_command_commit(ahci, cmd, i);
-
-    /* Everything is in place, but we haven't given the go-ahead yet,
-     * so we should find that there are no pending interrupts yet. */
-    g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0);
-
-    /* Issue command and sanity check response. */
-    ahci_command_issue(ahci, cmd);
-    ahci_command_verify(ahci, cmd);
+    ahci_port_clear(ahci, px);
 
-    /* Last, but not least: Investigate the IDENTIFY response data. */
-    memread(data_ptr, &buff, 512);
+    /* "Read" 512 bytes using CMD_IDENTIFY into the host buffer. */
+    ahci_io(ahci, px, CMD_IDENTIFY, &buff, buffsize);
 
     /* Check serial number/version in the buffer */
     /* NB: IDENTIFY strings are packed in 16bit little endian chunks.
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 345d1f1..8522224 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -592,6 +592,31 @@ static AHCICommandProp *ahci_command_find(uint8_t command_name)
     return NULL;
 }
 
+/* Given a HOST buffer, create a buffer address and perform an IO operation. */
+void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
+             void *buffer, size_t bufsize)
+{
+    uint64_t ptr;
+    AHCICommandProp *props;
+
+    props = ahci_command_find(ide_cmd);
+    g_assert(props);
+    ptr = ahci_alloc(ahci, bufsize);
+    g_assert(ptr);
+
+    if (props->write) {
+        memwrite(ptr, buffer, bufsize);
+    }
+
+    ahci_guest_io(ahci, port, ide_cmd, ptr, bufsize);
+
+    if (props->read) {
+        memread(ptr, buffer, bufsize);
+    }
+
+    ahci_free(ahci, ptr);
+}
+
 /**
  * Initializes a basic command header in memory.
  * We assume that this is for an ATA command using RegH2DFIS.
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 1206c7a..9133033 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -523,6 +523,8 @@ unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port);
 unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd);
 void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
                    uint64_t gbuffer, size_t size);
+void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
+             void *buffer, size_t bufsize);
 
 /* Command Lifecycle */
 AHCICommand *ahci_command_create(uint8_t command_name);
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 36/65] libqos/ahci: Add ahci_clean_mem
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (34 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 35/65] libqos/ahci: add ahci_io Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 37/65] qtest/ahci: Assert sector size in identify test Stefan Hajnoczi
                   ` (29 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Clean up guest memory being used in ahci_clean_mem, to be
called during ahci_shutdown. With all guest memory leaks removed,
add an option to the allocator to throw an assertion if a leak
occurs.

This test adds some sanity to both the AHCI library and the
allocator.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1423158090-25580-18-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c     |  3 +++
 tests/libqos/ahci.c   | 18 ++++++++++++++++++
 tests/libqos/ahci.h   |  1 +
 tests/libqos/malloc.c |  5 +++++
 tests/libqos/malloc.h |  1 +
 5 files changed, 28 insertions(+)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 47491fe..3a0131a 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -86,6 +86,7 @@ static AHCIQState *ahci_boot(void)
         "-device ide-hd,drive=drive0 "
         "-global ide-hd.ver=%s";
     s->parent = qtest_pc_boot(cli, tmp_path, "testdisk", "version");
+    alloc_set_flags(s->parent->alloc, ALLOC_LEAK_ASSERT);
 
     /* Verify that we have an AHCI device present. */
     s->dev = get_ahci_device(&s->fingerprint);
@@ -99,6 +100,8 @@ static AHCIQState *ahci_boot(void)
 static void ahci_shutdown(AHCIQState *ahci)
 {
     QOSState *qs = ahci->parent;
+
+    ahci_clean_mem(ahci);
     free_ahci_device(ahci->dev);
     g_free(ahci);
     qtest_shutdown(qs);
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 8522224..a6105c7 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -130,6 +130,24 @@ void free_ahci_device(QPCIDevice *dev)
     qpci_free_pc(pcibus);
 }
 
+/* Free all memory in-use by the AHCI device. */
+void ahci_clean_mem(AHCIQState *ahci)
+{
+    uint8_t port, slot;
+
+    for (port = 0; port < 32; ++port) {
+        if (ahci->port[port].fb) {
+            ahci_free(ahci, ahci->port[port].fb);
+        }
+        if (ahci->port[port].clb) {
+            for (slot = 0; slot < 32; slot++) {
+                ahci_destroy_command(ahci, port, slot);
+            }
+            ahci_free(ahci, ahci->port[port].clb);
+        }
+    }
+}
+
 /*** Logical Device Initialization ***/
 
 /**
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 9133033..39b99d3 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -499,6 +499,7 @@ uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes);
 void ahci_free(AHCIQState *ahci, uint64_t addr);
 QPCIDevice *get_ahci_device(uint32_t *fingerprint);
 void free_ahci_device(QPCIDevice *dev);
+void ahci_clean_mem(AHCIQState *ahci);
 void ahci_pci_enable(AHCIQState *ahci);
 void start_ahci_device(AHCIQState *ahci);
 void ahci_hba_enable(AHCIQState *ahci);
diff --git a/tests/libqos/malloc.c b/tests/libqos/malloc.c
index 42e3434..67f3190 100644
--- a/tests/libqos/malloc.c
+++ b/tests/libqos/malloc.c
@@ -324,3 +324,8 @@ void alloc_set_page_size(QGuestAllocator *allocator, size_t page_size)
     g_assert(is_power_of_2(page_size));
     allocator->page_size = page_size;
 }
+
+void alloc_set_flags(QGuestAllocator *allocator, QAllocOpts opts)
+{
+    allocator->opts |= opts;
+}
diff --git a/tests/libqos/malloc.h b/tests/libqos/malloc.h
index a39dba4..71ac407 100644
--- a/tests/libqos/malloc.h
+++ b/tests/libqos/malloc.h
@@ -36,5 +36,6 @@ QGuestAllocator *alloc_init(uint64_t start, uint64_t end);
 QGuestAllocator *alloc_init_flags(QAllocOpts flags,
                                   uint64_t start, uint64_t end);
 void alloc_set_page_size(QGuestAllocator *allocator, size_t page_size);
+void alloc_set_flags(QGuestAllocator *allocator, QAllocOpts opts);
 
 #endif
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 37/65] qtest/ahci: Assert sector size in identify test
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (35 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 36/65] libqos/ahci: Add ahci_clean_mem Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 38/65] qtest/ahci: Adding simple dma read-write test Stefan Hajnoczi
                   ` (28 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

A minor sanity check to assert that the sector size is 512.
The current block layer code deeply assumes that the IDE
sector size will be 512 bytes, so we carry forward that assumption
here.

This is useful for the DMA tests, which currently assume that
a sector will always be 512 bytes.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1423158090-25580-19-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 3a0131a..f595b96 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -663,6 +663,7 @@ static void ahci_test_identify(AHCIQState *ahci)
     uint16_t buff[256];
     unsigned px;
     int rc;
+    uint16_t sect_size;
     const size_t buffsize = 512;
 
     g_assert(ahci != NULL);
@@ -710,6 +711,9 @@ static void ahci_test_identify(AHCIQState *ahci)
     string_bswap16(&buff[23], 8);
     rc = memcmp(&buff[23], "version ", 8);
     g_assert_cmphex(rc, ==, 0);
+
+    sect_size = le16_to_cpu(*((uint16_t *)(&buff[5])));
+    g_assert_cmphex(sect_size, ==, 0x200);
 }
 
 /******************************************************************************/
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 38/65] qtest/ahci: Adding simple dma read-write test
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (36 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 37/65] qtest/ahci: Assert sector size in identify test Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 39/65] nbd: fix the co_queue multi-adding bug Stefan Hajnoczi
                   ` (27 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, John Snow, Stefan Hajnoczi

From: John Snow <jsnow@redhat.com>

Adds a test case for AHCI wherein we write a 4K
block of a changing pattern to sector 0, then
read back that 4K and compare the transmit and
receive buffers.

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
Message-id: 1423158090-25580-20-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/ahci-test.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index f595b96..53fd068 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -716,6 +716,46 @@ static void ahci_test_identify(AHCIQState *ahci)
     g_assert_cmphex(sect_size, ==, 0x200);
 }
 
+static void ahci_test_dma_rw_simple(AHCIQState *ahci)
+{
+    uint64_t ptr;
+    uint8_t port;
+    unsigned i;
+    const unsigned bufsize = 4096;
+    unsigned char *tx = g_malloc(bufsize);
+    unsigned char *rx = g_malloc0(bufsize);
+
+    g_assert(ahci != NULL);
+
+    /* Pick the first running port and clear it. */
+    port = ahci_port_select(ahci);
+    ahci_port_clear(ahci, port);
+
+    /*** Create pattern and transfer to guest ***/
+    /* Data buffer in the guest */
+    ptr = ahci_alloc(ahci, bufsize);
+    g_assert(ptr);
+
+    /* Write some indicative pattern to our 4K buffer. */
+    for (i = 0; i < bufsize; i++) {
+        tx[i] = (bufsize - i);
+    }
+    memwrite(ptr, tx, bufsize);
+
+    /* Write this buffer to disk, then read it back to the DMA buffer. */
+    ahci_guest_io(ahci, port, CMD_WRITE_DMA, ptr, bufsize);
+    qmemset(ptr, 0x00, bufsize);
+    ahci_guest_io(ahci, port, CMD_READ_DMA, ptr, bufsize);
+
+    /*** Read back the Data ***/
+    memread(ptr, rx, bufsize);
+    g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0);
+
+    ahci_free(ahci, ptr);
+    g_free(tx);
+    g_free(rx);
+}
+
 /******************************************************************************/
 /* Test Interfaces                                                            */
 /******************************************************************************/
@@ -798,6 +838,20 @@ static void test_identify(void)
     ahci_shutdown(ahci);
 }
 
+/**
+ * Perform a simple DMA R/W test, using a single PRD and non-NCQ commands.
+ */
+static void test_dma_rw_simple(void)
+{
+    AHCIQState *ahci;
+
+    ahci = ahci_boot();
+    ahci_pci_enable(ahci);
+    ahci_hba_enable(ahci);
+    ahci_test_dma_rw_simple(ahci);
+    ahci_shutdown(ahci);
+}
+
 /******************************************************************************/
 
 int main(int argc, char **argv)
@@ -853,6 +907,7 @@ int main(int argc, char **argv)
     qtest_add_func("/ahci/hba_spec",   test_hba_spec);
     qtest_add_func("/ahci/hba_enable", test_hba_enable);
     qtest_add_func("/ahci/identify",   test_identify);
+    qtest_add_func("/ahci/dma/simple", test_dma_rw_simple);
 
     ret = g_test_run();
 
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 39/65] nbd: fix the co_queue multi-adding bug
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (37 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 38/65] qtest/ahci: Adding simple dma read-write test Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 40/65] savevm: Improve error message for blocked migration Stefan Hajnoczi
                   ` (26 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Bin Wu, Paolo Bonzini

From: Bin Wu <wu.wubin@huawei.com>

When we tested the VM migartion between different hosts with NBD
devices, we found if we sent a cancel command after the drive_mirror
was just started, a coroutine re-enter error would occur. The stack
was as follow:

(gdb) bt
00)  0x00007fdfc744d885 in raise () from /lib64/libc.so.6
01)  0x00007fdfc744ee61 in abort () from /lib64/libc.so.6
02)  0x00007fdfca467cc5 in qemu_coroutine_enter (co=0x7fdfcaedb400, opaque=0x0)
at qemu-coroutine.c:118
03)  0x00007fdfca467f6c in qemu_co_queue_run_restart (co=0x7fdfcaedb400) at
qemu-coroutine-lock.c:59
04)  0x00007fdfca467be5 in coroutine_swap (from=0x7fdfcaf3c4e8,
to=0x7fdfcaedb400) at qemu-coroutine.c:96
05)  0x00007fdfca467cea in qemu_coroutine_enter (co=0x7fdfcaedb400, opaque=0x0)
at qemu-coroutine.c:123
06)  0x00007fdfca467f6c in qemu_co_queue_run_restart (co=0x7fdfcaedbdc0) at
qemu-coroutine-lock.c:59
07)  0x00007fdfca467be5 in coroutine_swap (from=0x7fdfcaf3c4e8,
to=0x7fdfcaedbdc0) at qemu-coroutine.c:96
08)  0x00007fdfca467cea in qemu_coroutine_enter (co=0x7fdfcaedbdc0, opaque=0x0)
at qemu-coroutine.c:123
09)  0x00007fdfca4a1fa4 in nbd_recv_coroutines_enter_all (s=0x7fdfcaef7dd0) at
block/nbd-client.c:41
10) 0x00007fdfca4a1ff9 in nbd_teardown_connection (client=0x7fdfcaef7dd0) at
block/nbd-client.c:50
11) 0x00007fdfca4a20f0 in nbd_reply_ready (opaque=0x7fdfcaef7dd0) at
block/nbd-client.c:92
12) 0x00007fdfca45ed80 in aio_dispatch (ctx=0x7fdfcae15e90) at aio-posix.c:144
13) 0x00007fdfca45ef1b in aio_poll (ctx=0x7fdfcae15e90, blocking=false) at
aio-posix.c:222
14) 0x00007fdfca448c34 in aio_ctx_dispatch (source=0x7fdfcae15e90, callback=0x0,
user_data=0x0) at async.c:212
15) 0x00007fdfc8f2f69a in g_main_context_dispatch () from
/usr/lib64/libglib-2.0.so.0
16) 0x00007fdfca45c391 in glib_pollfds_poll () at main-loop.c:190
17) 0x00007fdfca45c489 in os_host_main_loop_wait (timeout=1483677098) at
main-loop.c:235
18) 0x00007fdfca45c57b in main_loop_wait (nonblocking=0) at main-loop.c:484
19) 0x00007fdfca25f403 in main_loop () at vl.c:2249
20) 0x00007fdfca266fc2 in main (argc=42, argv=0x7ffff517d638,
envp=0x7ffff517d790) at vl.c:4814

We find the nbd_recv_coroutines_enter_all function (triggered by a cancel
command or a network connection breaking down) will enter a coroutine which
is waiting for the sending lock. If the lock is still held by another coroutine,
the entering coroutine will be added into the co_queue again. Latter, when the
lock is released, a coroutine re-enter error will occur.

This bug can be fixed simply by delaying the setting of recv_coroutine as
suggested by paolo. After applying this patch, we have tested the cancel
operation in mirror phase looply for more than 5 hous and everything is fine.
Without this patch, a coroutine re-enter error will occur in 5 minutes.

Signed-off-by: Bn Wu <wu.wubin@huawei.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1423552846-3896-1-git-send-email-wu.wubin@huawei.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/nbd-client.c | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/block/nbd-client.c b/block/nbd-client.c
index a01a37f..259f5a3 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -108,11 +108,22 @@ static int nbd_co_send_request(BlockDriverState *bs,
 {
     NbdClientSession *s = nbd_get_client_session(bs);
     AioContext *aio_context;
-    int rc, ret;
+    int rc, ret, i;
 
     qemu_co_mutex_lock(&s->send_mutex);
+
+    for (i = 0; i < MAX_NBD_REQUESTS; i++) {
+        if (s->recv_coroutine[i] == NULL) {
+            s->recv_coroutine[i] = qemu_coroutine_self();
+            break;
+        }
+    }
+
+    assert(i < MAX_NBD_REQUESTS);
+    request->handle = INDEX_TO_HANDLE(s, i);
     s->send_coroutine = qemu_coroutine_self();
     aio_context = bdrv_get_aio_context(bs);
+
     aio_set_fd_handler(aio_context, s->sock,
                        nbd_reply_ready, nbd_restart_write, bs);
     if (qiov) {
@@ -168,8 +179,6 @@ static void nbd_co_receive_reply(NbdClientSession *s,
 static void nbd_coroutine_start(NbdClientSession *s,
    struct nbd_request *request)
 {
-    int i;
-
     /* Poor man semaphore.  The free_sema is locked when no other request
      * can be accepted, and unlocked after receiving one reply.  */
     if (s->in_flight >= MAX_NBD_REQUESTS - 1) {
@@ -178,15 +187,7 @@ static void nbd_coroutine_start(NbdClientSession *s,
     }
     s->in_flight++;
 
-    for (i = 0; i < MAX_NBD_REQUESTS; i++) {
-        if (s->recv_coroutine[i] == NULL) {
-            s->recv_coroutine[i] = qemu_coroutine_self();
-            break;
-        }
-    }
-
-    assert(i < MAX_NBD_REQUESTS);
-    request->handle = INDEX_TO_HANDLE(s, i);
+    /* s->recv_coroutine[i] is set as soon as we get the send_lock.  */
 }
 
 static void nbd_coroutine_end(NbdClientSession *s,
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 40/65] savevm: Improve error message for blocked migration
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (38 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 39/65] nbd: fix the co_queue multi-adding bug Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 41/65] block: vmdk - fixed sizeof() error Stefan Hajnoczi
                   ` (25 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Peter Maydell, Stefan Hajnoczi

From: Kevin Wolf <kwolf@redhat.com>

If an internal snapshot can't be saved because migration is blocked
(most commonly probably because of AHCI), we had a really bad error
message:

$ echo -e "savevm foo\nquit" | qemu -M q35 /tmp/test.qcow2 -monitor stdio
QEMU 2.2.50 monitor - type 'help' for more information
(qemu) savevm foo
Error -22 while writing VM
(qemu) quit

This patch converts qemu_savevm_state() to the Error infrastructure so
that a useful error pointing to the problematic device is produced now:

$ echo -e "savevm foo\nquit" | qemu -M q35 /tmp/test.qcow2 -monitor stdio
QEMU 2.2.50 monitor - type 'help' for more information
(qemu) savevm foo
State blocked by non-migratable device '0000:00:1f.2/ich9_ahci'
(qemu) quit

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1423574702-23072-1-git-send-email-kwolf@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 savevm.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/savevm.c b/savevm.c
index 8040766..1d08165 100644
--- a/savevm.c
+++ b/savevm.c
@@ -821,7 +821,7 @@ void qemu_savevm_state_cancel(void)
     }
 }
 
-static int qemu_savevm_state(QEMUFile *f)
+static int qemu_savevm_state(QEMUFile *f, Error **errp)
 {
     int ret;
     MigrationParams params = {
@@ -829,7 +829,7 @@ static int qemu_savevm_state(QEMUFile *f)
         .shared = 0
     };
 
-    if (qemu_savevm_state_blocked(NULL)) {
+    if (qemu_savevm_state_blocked(errp)) {
         return -EINVAL;
     }
 
@@ -850,6 +850,7 @@ static int qemu_savevm_state(QEMUFile *f)
     }
     if (ret != 0) {
         qemu_savevm_state_cancel();
+        error_setg_errno(errp, -ret, "Error while writing VM state");
     }
     return ret;
 }
@@ -1102,6 +1103,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
     qemu_timeval tv;
     struct tm tm;
     const char *name = qdict_get_try_str(qdict, "name");
+    Error *local_err = NULL;
 
     /* Verify if there is a device that doesn't support snapshots and is writable */
     bs = NULL;
@@ -1160,11 +1162,12 @@ void do_savevm(Monitor *mon, const QDict *qdict)
         monitor_printf(mon, "Could not open VM state file\n");
         goto the_end;
     }
-    ret = qemu_savevm_state(f);
+    ret = qemu_savevm_state(f, &local_err);
     vm_state_size = qemu_ftell(f);
     qemu_fclose(f);
     if (ret < 0) {
-        monitor_printf(mon, "Error %d while writing VM\n", ret);
+        monitor_printf(mon, "%s\n", error_get_pretty(local_err));
+        error_free(local_err);
         goto the_end;
     }
 
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 41/65] block: vmdk - fixed sizeof() error
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (39 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 40/65] savevm: Improve error message for blocked migration Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 42/65] qtest: Fix deadloop by running main loop AIO context's timers Stefan Hajnoczi
                   ` (24 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jeff Cody, Stefan Hajnoczi

From: Jeff Cody <jcody@redhat.com>

The size compared should be PATH_MAX, rather than sizeof(char *).

Reported-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Jeff Cody <jcody@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-id: 46d873261433f4527e88885582f96942d61758d6.1423592487.git.jcody@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/vmdk.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/block/vmdk.c b/block/vmdk.c
index 7d079ad..8410a15 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -843,8 +843,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
         }
 
         extent_path = g_malloc0(PATH_MAX);
-        path_combine(extent_path, sizeof(extent_path),
-                desc_file_path, fname);
+        path_combine(extent_path, PATH_MAX, desc_file_path, fname);
         extent_file = NULL;
         ret = bdrv_open(&extent_file, extent_path, NULL, NULL,
                         bs->open_flags | BDRV_O_PROTOCOL, NULL, errp);
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 42/65] qtest: Fix deadloop by running main loop AIO context's timers
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (40 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 41/65] block: vmdk - fixed sizeof() error Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 43/65] qemu-io: Account IO by aio_read and aio_write Stefan Hajnoczi
                   ` (23 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Fam Zheng, Stefan Hajnoczi

From: Fam Zheng <famz@redhat.com>

qemu_clock_run_timers() only takes care of main_loop_tlg, we shouldn't
forget aio timer list groups.

Currently, the qemu_clock_deadline_ns_all (a few lines above) counts all
the timergroups of this clock type, including aio tlg, but we don't fire
them, so they are never cleared, which makes a dead loop.

For example, this function hangs when trying to drive throttled block
request queue with qtest clock_step.

Signed-off-by: Fam Zheng <famz@redhat.com>
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1421661103-29153-1-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 cpus.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/cpus.c b/cpus.c
index 0cdd1d7..97939e4 100644
--- a/cpus.c
+++ b/cpus.c
@@ -361,15 +361,19 @@ static void icount_warp_rt(void *opaque)
 void qtest_clock_warp(int64_t dest)
 {
     int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    AioContext *aio_context;
     assert(qtest_enabled());
+    aio_context = qemu_get_aio_context();
     while (clock < dest) {
         int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
         int64_t warp = qemu_soonest_timeout(dest - clock, deadline);
+
         seqlock_write_lock(&timers_state.vm_clock_seqlock);
         timers_state.qemu_icount_bias += warp;
         seqlock_write_unlock(&timers_state.vm_clock_seqlock);
 
         qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL);
+        timerlist_run_timers(aio_context->tlg.tl[QEMU_CLOCK_VIRTUAL]);
         clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
     }
     qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 43/65] qemu-io: Account IO by aio_read and aio_write
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (41 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 42/65] qtest: Fix deadloop by running main loop AIO context's timers Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 44/65] qtest: Add scripts/qtest.py Stefan Hajnoczi
                   ` (22 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Fam Zheng, Stefan Hajnoczi

From: Fam Zheng <famz@redhat.com>

This will enable accounting of aio requests issued from qemu-io aio
read/write commands.

Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-id: 1422586186-9925-2-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 qemu-io-cmds.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index e708552..29377cd 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -13,6 +13,7 @@
 #include "block/qapi.h"
 #include "qemu/main-loop.h"
 #include "qemu/timer.h"
+#include "sysemu/block-backend.h"
 
 #define CMD_NOFILE_OK   0x01
 
@@ -1337,6 +1338,7 @@ out:
 }
 
 struct aio_ctx {
+    BlockDriverState *bs;
     QEMUIOVector qiov;
     int64_t offset;
     char *buf;
@@ -1344,6 +1346,7 @@ struct aio_ctx {
     int vflag;
     int Cflag;
     int Pflag;
+    BlockAcctCookie acct;
     int pattern;
     struct timeval t1;
 };
@@ -1361,6 +1364,8 @@ static void aio_write_done(void *opaque, int ret)
         goto out;
     }
 
+    block_acct_done(&ctx->bs->stats, &ctx->acct);
+
     if (ctx->qflag) {
         goto out;
     }
@@ -1398,6 +1403,8 @@ static void aio_read_done(void *opaque, int ret)
         g_free(cmp_buf);
     }
 
+    block_acct_done(&ctx->bs->stats, &ctx->acct);
+
     if (ctx->qflag) {
         goto out;
     }
@@ -1453,6 +1460,7 @@ static int aio_read_f(BlockDriverState *bs, int argc, char **argv)
     int nr_iov, c;
     struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
 
+    ctx->bs = bs;
     while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
         switch (c) {
         case 'C':
@@ -1506,6 +1514,7 @@ static int aio_read_f(BlockDriverState *bs, int argc, char **argv)
     }
 
     gettimeofday(&ctx->t1, NULL);
+    block_acct_start(&bs->stats, &ctx->acct, ctx->qiov.size, BLOCK_ACCT_READ);
     bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
                    ctx->qiov.size >> 9, aio_read_done, ctx);
     return 0;
@@ -1549,6 +1558,7 @@ static int aio_write_f(BlockDriverState *bs, int argc, char **argv)
     int pattern = 0xcd;
     struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
 
+    ctx->bs = bs;
     while ((c = getopt(argc, argv, "CqP:")) != EOF) {
         switch (c) {
         case 'C':
@@ -1598,6 +1608,7 @@ static int aio_write_f(BlockDriverState *bs, int argc, char **argv)
     }
 
     gettimeofday(&ctx->t1, NULL);
+    block_acct_start(&bs->stats, &ctx->acct, ctx->qiov.size, BLOCK_ACCT_WRITE);
     bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
                     ctx->qiov.size >> 9, aio_write_done, ctx);
     return 0;
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 44/65] qtest: Add scripts/qtest.py
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (42 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 43/65] qemu-io: Account IO by aio_read and aio_write Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 45/65] qemu-iotests: Add VM method qtest() to iotests.py Stefan Hajnoczi
                   ` (21 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Fam Zheng, Stefan Hajnoczi

From: Fam Zheng <famz@redhat.com>

This adds scripts/qtest.py as a python library for qtest protocol.

This is a skeleton with a basic "cmd" method to execute a command,
reading and parsing of qtest output could be added later on demand.

Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-id: 1422586186-9925-3-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 scripts/qtest.py | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)
 create mode 100644 scripts/qtest.py

diff --git a/scripts/qtest.py b/scripts/qtest.py
new file mode 100644
index 0000000..a971445
--- /dev/null
+++ b/scripts/qtest.py
@@ -0,0 +1,71 @@
+# QEMU qtest library
+#
+# Copyright (C) 2015 Red Hat Inc.
+#
+# Authors:
+#  Fam Zheng <famz@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+#
+# Based on qmp.py.
+#
+
+import errno
+import socket
+
+class QEMUQtestProtocol(object):
+    def __init__(self, address, server=False):
+        """
+        Create a QEMUQtestProtocol object.
+
+        @param address: QEMU address, can be either a unix socket path (string)
+                        or a tuple in the form ( address, port ) for a TCP
+                        connection
+        @param server: server mode, listens on the socket (bool)
+        @raise socket.error on socket connection errors
+        @note No connection is established, this is done by the connect() or
+              accept() methods
+        """
+        self._address = address
+        self._sock = self._get_sock()
+        if server:
+            self._sock.bind(self._address)
+            self._sock.listen(1)
+
+    def _get_sock(self):
+        if isinstance(self._address, tuple):
+            family = socket.AF_INET
+        else:
+            family = socket.AF_UNIX
+        return socket.socket(family, socket.SOCK_STREAM)
+
+    def connect(self):
+        """
+        Connect to the qtest socket.
+
+        @raise socket.error on socket connection errors
+        """
+        self._sock.connect(self._address)
+
+    def accept(self):
+        """
+        Await connection from QEMU.
+
+        @raise socket.error on socket connection errors
+        """
+        self._sock, _ = self._sock.accept()
+
+    def cmd(self, qtest_cmd):
+        """
+        Send a qtest command on the wire.
+
+        @param qtest_cmd: qtest command text to be sent
+        """
+        self._sock.sendall(qtest_cmd + "\n")
+
+    def close(self):
+        self._sock.close()
+
+    def settimeout(self, timeout):
+        self._sock.settimeout(timeout)
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 45/65] qemu-iotests: Add VM method qtest() to iotests.py
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (43 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 44/65] qtest: Add scripts/qtest.py Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 46/65] qemu-iotests: Allow caller to disable underscore convertion for qmp Stefan Hajnoczi
                   ` (20 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Fam Zheng, Stefan Hajnoczi

From: Fam Zheng <famz@redhat.com>

This will allow test cases to run command in qtest protocol. It's
write-only for now.

Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-id: 1422586186-9925-4-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/qemu-iotests/iotests.py | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 241b5ee..85cb9a5 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -21,8 +21,11 @@ import re
 import subprocess
 import string
 import unittest
-import sys; sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts', 'qmp'))
+import sys
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts'))
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts', 'qmp'))
 import qmp
+import qtest
 import struct
 
 __all__ = ['imgfmt', 'imgproto', 'test_dir' 'qemu_img', 'qemu_io',
@@ -81,10 +84,12 @@ class VM(object):
     def __init__(self):
         self._monitor_path = os.path.join(test_dir, 'qemu-mon.%d' % os.getpid())
         self._qemu_log_path = os.path.join(test_dir, 'qemu-log.%d' % os.getpid())
+        self._qtest_path = os.path.join(test_dir, 'qemu-qtest.%d' % os.getpid())
         self._args = qemu_args + ['-chardev',
                      'socket,id=mon,path=' + self._monitor_path,
                      '-mon', 'chardev=mon,mode=control',
-                     '-qtest', 'stdio', '-machine', 'accel=qtest',
+                     '-qtest', 'unix:path=' + self._qtest_path,
+                     '-machine', 'accel=qtest',
                      '-display', 'none', '-vga', 'none']
         self._num_drives = 0
 
@@ -160,9 +165,11 @@ class VM(object):
         qemulog = open(self._qemu_log_path, 'wb')
         try:
             self._qmp = qmp.QEMUMonitorProtocol(self._monitor_path, server=True)
+            self._qtest = qtest.QEMUQtestProtocol(self._qtest_path, server=True)
             self._popen = subprocess.Popen(self._args, stdin=devnull, stdout=qemulog,
                                            stderr=subprocess.STDOUT)
             self._qmp.accept()
+            self._qtest.accept()
         except:
             os.remove(self._monitor_path)
             raise
@@ -173,6 +180,7 @@ class VM(object):
             self._qmp.cmd('quit')
             self._popen.wait()
             os.remove(self._monitor_path)
+            os.remove(self._qtest_path)
             os.remove(self._qemu_log_path)
             self._popen = None
 
@@ -185,6 +193,10 @@ class VM(object):
 
         return self._qmp.cmd(cmd, args=qmp_args)
 
+    def qtest(self, cmd):
+        '''Send a qtest command to guest'''
+        return self._qtest.cmd(cmd)
+
     def get_qmp_event(self, wait=False):
         '''Poll for one queued QMP events and return it'''
         return self._qmp.pull_event(wait=wait)
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 46/65] qemu-iotests: Allow caller to disable underscore convertion for qmp
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (44 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 45/65] qemu-iotests: Add VM method qtest() to iotests.py Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 47/65] qemu-iotests: Add 093 for IO throttling Stefan Hajnoczi
                   ` (19 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Fam Zheng, Stefan Hajnoczi

From: Fam Zheng <famz@redhat.com>

QMP command "block_set_io_throttle" expects underscores in parameters
instead of dashes: {iops,bps}_{rd,wr,max}.

Add optional argument conv_keys (defaults to True, backward compatible),
it will be used in IO throttling test case.

Reviewed-by: Benoit Canet <benoit@irqsave.net>
Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-id: 1422586186-9925-5-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/qemu-iotests/iotests.py | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 85cb9a5..1402854 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -185,11 +185,14 @@ class VM(object):
             self._popen = None
 
     underscore_to_dash = string.maketrans('_', '-')
-    def qmp(self, cmd, **args):
+    def qmp(self, cmd, conv_keys=True, **args):
         '''Invoke a QMP command and return the result dict'''
         qmp_args = dict()
         for k in args.keys():
-            qmp_args[k.translate(self.underscore_to_dash)] = args[k]
+            if conv_keys:
+                qmp_args[k.translate(self.underscore_to_dash)] = args[k]
+            else:
+                qmp_args[k] = args[k]
 
         return self._qmp.cmd(cmd, args=qmp_args)
 
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 47/65] qemu-iotests: Add 093 for IO throttling
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (45 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 46/65] qemu-iotests: Allow caller to disable underscore convertion for qmp Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 48/65] qemu-img: Fix qemu-img convert -n Stefan Hajnoczi
                   ` (18 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Fam Zheng, Stefan Hajnoczi

From: Fam Zheng <famz@redhat.com>

This case utilizes qemu-io command "aio_{read,write} -q" to verify the
effectiveness of IO throttling options.

It's implemented by driving the vm timer from qtest protocol, so the
throttling timers are signaled with determinied time duration. Then we
verify the completed IO requests are within 10% error of bps and iops
limits.

"null" protocol is used as the disk backend so that no actual disk IO is
performed on host, this will make the blockstats much more
deterministic. Both "null-aio" and "null-co" are covered, which is also
a simple cross validation test for the driver code.

Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-id: 1422586186-9925-6-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/qemu-iotests/093     | 114 +++++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/093.out |   5 ++
 tests/qemu-iotests/group   |   1 +
 3 files changed, 120 insertions(+)
 create mode 100755 tests/qemu-iotests/093
 create mode 100644 tests/qemu-iotests/093.out

diff --git a/tests/qemu-iotests/093 b/tests/qemu-iotests/093
new file mode 100755
index 0000000..b9096a5
--- /dev/null
+++ b/tests/qemu-iotests/093
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+#
+# Tests for IO throttling
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import iotests
+
+class ThrottleTestCase(iotests.QMPTestCase):
+    test_img = "null-aio://"
+
+    def blockstats(self, device):
+        result = self.vm.qmp("query-blockstats")
+        for r in result['return']:
+            if r['device'] == device:
+                stat = r['stats']
+                return stat['rd_bytes'], stat['rd_operations'], stat['wr_bytes'], stat['wr_operations']
+        raise Exception("Device not found for blockstats: %s" % device)
+
+    def setUp(self):
+        self.vm = iotests.VM().add_drive(self.test_img)
+        self.vm.launch()
+
+    def tearDown(self):
+        self.vm.shutdown()
+
+    def do_test_throttle(self, seconds, params):
+        def check_limit(limit, num):
+            # IO throttling algorithm is discrete, allow 10% error so the test
+            # is more robust
+            return limit == 0 or \
+                   (num < seconds * limit * 1.1
+                   and num > seconds * limit * 0.9)
+
+        nsec_per_sec = 1000000000
+
+        params['device'] = 'drive0'
+
+        result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **params)
+        self.assert_qmp(result, 'return', {})
+
+        # Set vm clock to a known value
+        ns = seconds * nsec_per_sec
+        self.vm.qtest("clock_step %d" % ns)
+
+        # Submit enough requests. They will drain bps_max and iops_max, but the
+        # rest requests won't get executed until we advance the virtual clock
+        # with qtest interface
+        rq_size = 512
+        rd_nr = max(params['bps'] / rq_size / 2,
+                    params['bps_rd'] / rq_size,
+                    params['iops'] / 2,
+                    params['iops_rd'])
+        rd_nr *= seconds * 2
+        wr_nr = max(params['bps'] / rq_size / 2,
+                    params['bps_wr'] / rq_size,
+                    params['iops'] / 2,
+                    params['iops_wr'])
+        wr_nr *= seconds * 2
+        for i in range(rd_nr):
+            self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % (i * rq_size, rq_size))
+        for i in range(wr_nr):
+            self.vm.hmp_qemu_io("drive0", "aio_write %d %d" % (i * rq_size, rq_size))
+
+        start_rd_bytes, start_rd_iops, start_wr_bytes, start_wr_iops = self.blockstats('drive0')
+
+        self.vm.qtest("clock_step %d" % ns)
+        end_rd_bytes, end_rd_iops, end_wr_bytes, end_wr_iops = self.blockstats('drive0')
+
+        rd_bytes = end_rd_bytes - start_rd_bytes
+        rd_iops = end_rd_iops - start_rd_iops
+        wr_bytes = end_wr_bytes - start_wr_bytes
+        wr_iops = end_wr_iops - start_wr_iops
+
+        self.assertTrue(check_limit(params['bps'], rd_bytes + wr_bytes))
+        self.assertTrue(check_limit(params['bps_rd'], rd_bytes))
+        self.assertTrue(check_limit(params['bps_wr'], wr_bytes))
+        self.assertTrue(check_limit(params['iops'], rd_iops + wr_iops))
+        self.assertTrue(check_limit(params['iops_rd'], rd_iops))
+        self.assertTrue(check_limit(params['iops_wr'], wr_iops))
+
+    def test_all(self):
+        params = {"bps": 4096,
+                  "bps_rd": 4096,
+                  "bps_wr": 4096,
+                  "iops": 10,
+                  "iops_rd": 10,
+                  "iops_wr": 10,
+                 }
+        # Pick each out of all possible params and test
+        for tk in params:
+            limits = dict([(k, 0) for k in params])
+            limits[tk] = params[tk]
+            self.do_test_throttle(5, limits)
+
+class ThrottleTestCoroutine(ThrottleTestCase):
+    test_img = "null-co://"
+
+if __name__ == '__main__':
+    iotests.main(supported_fmts=["raw"])
diff --git a/tests/qemu-iotests/093.out b/tests/qemu-iotests/093.out
new file mode 100644
index 0000000..fbc63e6
--- /dev/null
+++ b/tests/qemu-iotests/093.out
@@ -0,0 +1,5 @@
+..
+----------------------------------------------------------------------
+Ran 2 tests
+
+OK
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 6e2447a..186c7df 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -99,6 +99,7 @@
 090 rw auto quick
 091 rw auto
 092 rw auto quick
+093 auto
 094 rw auto quick
 095 rw auto quick
 097 rw auto backing
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 48/65] qemu-img: Fix qemu-img convert -n
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (46 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 47/65] qemu-iotests: Add 093 for IO throttling Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 49/65] iotests: Add test for qemu-img convert to NBD Stefan Hajnoczi
                   ` (17 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

If -n is specified, it does not matter whether the output format and
protocol support image creation; building the creation options should
simply be skipped.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1423666727-20777-2-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 qemu-img.c | 50 ++++++++++++++++++++++++++------------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index e148af8..26ec3c1 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1531,34 +1531,36 @@ static int img_convert(int argc, char **argv)
         goto out;
     }
 
-    if (!drv->create_opts) {
-        error_report("Format driver '%s' does not support image creation",
-                     drv->format_name);
-        ret = -1;
-        goto out;
-    }
+    if (!skip_create) {
+        if (!drv->create_opts) {
+            error_report("Format driver '%s' does not support image creation",
+                         drv->format_name);
+            ret = -1;
+            goto out;
+        }
 
-    if (!proto_drv->create_opts) {
-        error_report("Protocol driver '%s' does not support image creation",
-                     proto_drv->format_name);
-        ret = -1;
-        goto out;
-    }
+        if (!proto_drv->create_opts) {
+            error_report("Protocol driver '%s' does not support image creation",
+                         proto_drv->format_name);
+            ret = -1;
+            goto out;
+        }
 
-    create_opts = qemu_opts_append(create_opts, drv->create_opts);
-    create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
+        create_opts = qemu_opts_append(create_opts, drv->create_opts);
+        create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
 
-    opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
-    if (options && qemu_opts_do_parse(opts, options, NULL)) {
-        error_report("Invalid options for file format '%s'", out_fmt);
-        ret = -1;
-        goto out;
-    }
+        opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
+        if (options && qemu_opts_do_parse(opts, options, NULL)) {
+            error_report("Invalid options for file format '%s'", out_fmt);
+            ret = -1;
+            goto out;
+        }
 
-    qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_sectors * 512);
-    ret = add_old_style_options(out_fmt, opts, out_baseimg, NULL);
-    if (ret < 0) {
-        goto out;
+        qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_sectors * 512);
+        ret = add_old_style_options(out_fmt, opts, out_baseimg, NULL);
+        if (ret < 0) {
+            goto out;
+        }
     }
 
     /* Get backing file name if -o backing_file was used */
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 49/65] iotests: Add test for qemu-img convert to NBD
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (47 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 48/65] qemu-img: Fix qemu-img convert -n Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 50/65] block: Lift some BDS functions to the BlockBackend Stefan Hajnoczi
                   ` (16 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1423666727-20777-3-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/qemu-iotests/123     | 62 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/123.out |  9 +++++++
 tests/qemu-iotests/group   |  1 +
 3 files changed, 72 insertions(+)
 create mode 100755 tests/qemu-iotests/123
 create mode 100644 tests/qemu-iotests/123.out

diff --git a/tests/qemu-iotests/123 b/tests/qemu-iotests/123
new file mode 100755
index 0000000..ad60803
--- /dev/null
+++ b/tests/qemu-iotests/123
@@ -0,0 +1,62 @@
+#!/bin/bash
+#
+# Test case for qemu-img convert to NBD
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=mreitz@redhat.com
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+here="$PWD"
+tmp=/tmp/$$
+status=1	# failure is the default!
+
+_cleanup()
+{
+    _cleanup_test_img
+    rm -f "$SRC_IMG"
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt raw
+_supported_proto nbd
+_supported_os Linux
+
+SRC_IMG="$TEST_DIR/source.$IMGFMT"
+
+_make_test_img 1M
+$QEMU_IMG create -f $IMGFMT "$SRC_IMG" 1M | _filter_img_create
+
+$QEMU_IO -c 'write -P 42 0 1M' "$SRC_IMG" | _filter_qemu_io
+
+$QEMU_IMG convert -n -f $IMGFMT -O raw "$SRC_IMG" "$TEST_IMG"
+
+$QEMU_IO -c 'read -P 42 0 1M' "$TEST_IMG" | _filter_qemu_io
+
+
+# success, all done
+echo
+echo '*** done'
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/123.out b/tests/qemu-iotests/123.out
new file mode 100644
index 0000000..0b818d3
--- /dev/null
+++ b/tests/qemu-iotests/123.out
@@ -0,0 +1,9 @@
+QA output created by 123
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
+Formatting 'TEST_DIR/source.IMGFMT', fmt=IMGFMT size=1048576
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 186c7df..86f072e 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -119,3 +119,4 @@
 113 rw auto quick
 114 rw auto quick
 116 rw auto quick
+123 rw auto quick
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 50/65] block: Lift some BDS functions to the BlockBackend
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (48 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 49/65] iotests: Add test for qemu-img convert to NBD Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 51/65] block: Add blk_new_open() Stefan Hajnoczi
                   ` (15 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

Create the blk_* counterparts for the following bdrv_* functions (which
make sense to call on the BlockBackend level):
- bdrv_co_write_zeroes()
- bdrv_write_compressed()
- bdrv_truncate()
- bdrv_nb_sectors()
- bdrv_discard()
- bdrv_load_vmstate()
- bdrv_save_vmstate()

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1423162705-32065-2-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/block-backend.c          | 38 ++++++++++++++++++++++++++++++++++++++
 include/sysemu/block-backend.h | 10 ++++++++++
 2 files changed, 48 insertions(+)

diff --git a/block/block-backend.c b/block/block-backend.c
index c28e240..7dc985c 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -440,6 +440,11 @@ void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr)
     bdrv_get_geometry(blk->bs, nb_sectors_ptr);
 }
 
+int64_t blk_nb_sectors(BlockBackend *blk)
+{
+    return bdrv_nb_sectors(blk->bs);
+}
+
 BlockAIOCB *blk_aio_readv(BlockBackend *blk, int64_t sector_num,
                           QEMUIOVector *iov, int nb_sectors,
                           BlockCompletionFunc *cb, void *opaque)
@@ -668,3 +673,36 @@ void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk,
 {
     return qemu_aio_get(aiocb_info, blk_bs(blk), cb, opaque);
 }
+
+int coroutine_fn blk_co_write_zeroes(BlockBackend *blk, int64_t sector_num,
+                                     int nb_sectors, BdrvRequestFlags flags)
+{
+    return bdrv_co_write_zeroes(blk->bs, sector_num, nb_sectors, flags);
+}
+
+int blk_write_compressed(BlockBackend *blk, int64_t sector_num,
+                         const uint8_t *buf, int nb_sectors)
+{
+    return bdrv_write_compressed(blk->bs, sector_num, buf, nb_sectors);
+}
+
+int blk_truncate(BlockBackend *blk, int64_t offset)
+{
+    return bdrv_truncate(blk->bs, offset);
+}
+
+int blk_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors)
+{
+    return bdrv_discard(blk->bs, sector_num, nb_sectors);
+}
+
+int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
+                     int64_t pos, int size)
+{
+    return bdrv_save_vmstate(blk->bs, buf, pos, size);
+}
+
+int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size)
+{
+    return bdrv_load_vmstate(blk->bs, buf, pos, size);
+}
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index aab12b9..4ef0407 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -91,6 +91,7 @@ int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int count);
 int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int count);
 int64_t blk_getlength(BlockBackend *blk);
 void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr);
+int64_t blk_nb_sectors(BlockBackend *blk);
 BlockAIOCB *blk_aio_readv(BlockBackend *blk, int64_t sector_num,
                           QEMUIOVector *iov, int nb_sectors,
                           BlockCompletionFunc *cb, void *opaque);
@@ -151,5 +152,14 @@ BlockAcctStats *blk_get_stats(BlockBackend *blk);
 
 void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk,
                   BlockCompletionFunc *cb, void *opaque);
+int coroutine_fn blk_co_write_zeroes(BlockBackend *blk, int64_t sector_num,
+                                     int nb_sectors, BdrvRequestFlags flags);
+int blk_write_compressed(BlockBackend *blk, int64_t sector_num,
+                         const uint8_t *buf, int nb_sectors);
+int blk_truncate(BlockBackend *blk, int64_t offset);
+int blk_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors);
+int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
+                     int64_t pos, int size);
+int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size);
 
 #endif
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 51/65] block: Add blk_new_open()
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (49 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 50/65] block: Lift some BDS functions to the BlockBackend Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 52/65] block: Add Error parameter to bdrv_find_protocol() Stefan Hajnoczi
                   ` (14 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

blk_new_with_bs() creates a BlockBackend with an empty BlockDriverState
attached to it. Empty BDSs are not nice, therefore add an alternative
function which combines blk_new_with_bs() with bdrv_open().

Note: In contrast to bdrv_open() which takes a BlockDriver parameter,
blk_new_open() does not take such a parameter. This is because
bdrv_open() opens a BlockDriverState, therefore it is natural to be able
to set the BlockDriver for that BDS. The fact that bdrv_open() can open
more than a single BDS is merely some form of a byproduct.

blk_new_open() on the other hand is intended to be used to create a
whole tree of BlockDriverStates. Therefore, setting a single BlockDriver
does not make much sense. Instead, the drivers to be used for each of
the nodes must be configured through the "options" QDict; including the
driver of the root BDS.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Message-id: 1423162705-32065-3-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/block-backend.c          | 34 ++++++++++++++++++++++++++++++++++
 include/sysemu/block-backend.h |  3 +++
 2 files changed, 37 insertions(+)

diff --git a/block/block-backend.c b/block/block-backend.c
index 7dc985c..d083b85 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -91,6 +91,40 @@ BlockBackend *blk_new_with_bs(const char *name, Error **errp)
     return blk;
 }
 
+/*
+ * Calls blk_new_with_bs() and then calls bdrv_open() on the BlockDriverState.
+ *
+ * Just as with bdrv_open(), after having called this function the reference to
+ * @options belongs to the block layer (even on failure).
+ *
+ * TODO: Remove @filename and @flags; it should be possible to specify a whole
+ * BDS tree just by specifying the @options QDict (or @reference,
+ * alternatively). At the time of adding this function, this is not possible,
+ * though, so callers of this function have to be able to specify @filename and
+ * @flags.
+ */
+BlockBackend *blk_new_open(const char *name, const char *filename,
+                           const char *reference, QDict *options, int flags,
+                           Error **errp)
+{
+    BlockBackend *blk;
+    int ret;
+
+    blk = blk_new_with_bs(name, errp);
+    if (!blk) {
+        QDECREF(options);
+        return NULL;
+    }
+
+    ret = bdrv_open(&blk->bs, filename, reference, options, flags, NULL, errp);
+    if (ret < 0) {
+        blk_unref(blk);
+        return NULL;
+    }
+
+    return blk;
+}
+
 static void blk_delete(BlockBackend *blk)
 {
     assert(!blk->refcnt);
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 4ef0407..2e8ebb2 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -62,6 +62,9 @@ typedef struct BlockDevOps {
 
 BlockBackend *blk_new(const char *name, Error **errp);
 BlockBackend *blk_new_with_bs(const char *name, Error **errp);
+BlockBackend *blk_new_open(const char *name, const char *filename,
+                           const char *reference, QDict *options, int flags,
+                           Error **errp);
 void blk_ref(BlockBackend *blk);
 void blk_unref(BlockBackend *blk);
 const char *blk_name(BlockBackend *blk);
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 52/65] block: Add Error parameter to bdrv_find_protocol()
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (50 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 51/65] block: Add blk_new_open() Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 53/65] iotests: Add test for driver=qcow2, format=qcow2 Stefan Hajnoczi
                   ` (13 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

The argument given to bdrv_find_protocol() is just a file name, which
makes it difficult for the caller to reconstruct what protocol
bdrv_find_protocol() was hoping to find. This patch adds an Error
parameter to that function to solve this issue.

Suggested-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1423162705-32065-4-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 block.c                    | 14 +++++++-------
 block/sheepdog.c           |  2 +-
 include/block/block.h      |  3 ++-
 qemu-img.c                 | 11 +++++++----
 tests/qemu-iotests/051.out |  4 ++--
 5 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/block.c b/block.c
index 210fd5f..2edff6c 100644
--- a/block.c
+++ b/block.c
@@ -508,9 +508,8 @@ int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp)
     Error *local_err = NULL;
     int ret;
 
-    drv = bdrv_find_protocol(filename, true);
+    drv = bdrv_find_protocol(filename, true, errp);
     if (drv == NULL) {
-        error_setg(errp, "Could not find protocol for file '%s'", filename);
         return -ENOENT;
     }
 
@@ -628,7 +627,8 @@ static BlockDriver *find_hdev_driver(const char *filename)
 }
 
 BlockDriver *bdrv_find_protocol(const char *filename,
-                                bool allow_protocol_prefix)
+                                bool allow_protocol_prefix,
+                                Error **errp)
 {
     BlockDriver *drv1;
     char protocol[128];
@@ -666,6 +666,8 @@ BlockDriver *bdrv_find_protocol(const char *filename,
             return drv1;
         }
     }
+
+    error_setg(errp, "Unknown protocol '%s'", protocol);
     return NULL;
 }
 
@@ -1136,9 +1138,8 @@ static int bdrv_fill_options(QDict **options, const char **pfilename, int flags,
     } else {
         if (!drvname && protocol) {
             if (filename) {
-                drv = bdrv_find_protocol(filename, parse_filename);
+                drv = bdrv_find_protocol(filename, parse_filename, errp);
                 if (!drv) {
-                    error_setg(errp, "Unknown protocol");
                     return -EINVAL;
                 }
 
@@ -5623,9 +5624,8 @@ void bdrv_img_create(const char *filename, const char *fmt,
         return;
     }
 
-    proto_drv = bdrv_find_protocol(filename, true);
+    proto_drv = bdrv_find_protocol(filename, true, errp);
     if (!proto_drv) {
-        error_setg(errp, "Unknown protocol '%s'", filename);
         return;
     }
 
diff --git a/block/sheepdog.c b/block/sheepdog.c
index be3176f..e9b0ca1 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -1730,7 +1730,7 @@ static int sd_create(const char *filename, QemuOpts *opts,
         BlockDriver *drv;
 
         /* Currently, only Sheepdog backing image is supported. */
-        drv = bdrv_find_protocol(backing_file, true);
+        drv = bdrv_find_protocol(backing_file, true, NULL);
         if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) {
             error_setg(errp, "backing_file must be a sheepdog image");
             ret = -EINVAL;
diff --git a/include/block/block.h b/include/block/block.h
index 321295e..471d11d 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -168,7 +168,8 @@ void bdrv_io_limits_disable(BlockDriverState *bs);
 void bdrv_init(void);
 void bdrv_init_with_whitelist(void);
 BlockDriver *bdrv_find_protocol(const char *filename,
-                                bool allow_protocol_prefix);
+                                bool allow_protocol_prefix,
+                                Error **errp);
 BlockDriver *bdrv_find_format(const char *format_name);
 BlockDriver *bdrv_find_whitelisted_format(const char *format_name,
                                           bool readonly);
diff --git a/qemu-img.c b/qemu-img.c
index 26ec3c1..8790546 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -261,6 +261,7 @@ static int print_block_option_help(const char *filename, const char *fmt)
 {
     BlockDriver *drv, *proto_drv;
     QemuOptsList *create_opts = NULL;
+    Error *local_err = NULL;
 
     /* Find driver and parse its options */
     drv = bdrv_find_format(fmt);
@@ -271,9 +272,10 @@ static int print_block_option_help(const char *filename, const char *fmt)
 
     create_opts = qemu_opts_append(create_opts, drv->create_opts);
     if (filename) {
-        proto_drv = bdrv_find_protocol(filename, true);
+        proto_drv = bdrv_find_protocol(filename, true, &local_err);
         if (!proto_drv) {
-            error_report("Unknown protocol '%s'", filename);
+            qerror_report_err(local_err);
+            error_free(local_err);
             qemu_opts_free(create_opts);
             return 1;
         }
@@ -1524,9 +1526,10 @@ static int img_convert(int argc, char **argv)
         goto out;
     }
 
-    proto_drv = bdrv_find_protocol(out_filename, true);
+    proto_drv = bdrv_find_protocol(out_filename, true, &local_err);
     if (!proto_drv) {
-        error_report("Unknown protocol '%s'", out_filename);
+        qerror_report_err(local_err);
+        error_free(local_err);
         ret = -1;
         goto out;
     }
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
index f497c57..9596e20 100644
--- a/tests/qemu-iotests/051.out
+++ b/tests/qemu-iotests/051.out
@@ -323,10 +323,10 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,readonly=on,read-only=off: 'read-only' a
 === Parsing protocol from file name ===
 
 Testing: -hda foo:bar
-QEMU_PROG: -hda foo:bar: could not open disk image foo:bar: Unknown protocol
+QEMU_PROG: -hda foo:bar: could not open disk image foo:bar: Unknown protocol 'foo'
 
 Testing: -drive file=foo:bar
-QEMU_PROG: -drive file=foo:bar: could not open disk image foo:bar: Unknown protocol
+QEMU_PROG: -drive file=foo:bar: could not open disk image foo:bar: Unknown protocol 'foo'
 
 Testing: -drive file.filename=foo:bar
 QEMU_PROG: -drive file.filename=foo:bar: could not open disk image ide0-hd0: Could not open 'foo:bar': No such file or directory
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 53/65] iotests: Add test for driver=qcow2, format=qcow2
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (51 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 52/65] block: Add Error parameter to bdrv_find_protocol() Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 54/65] blockdev: Use blk_new_open() in blockdev_init() Stefan Hajnoczi
                   ` (12 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

While specifying a different driver and format is obviously invalid,
specifying the same driver once through driver and once through format
is invalid as well. Add a test for it.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1423162705-32065-5-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/qemu-iotests/051     | 1 +
 tests/qemu-iotests/051.out | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index 11c858f..27138a2 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -93,6 +93,7 @@ echo
 run_qemu -drive file="$TEST_IMG",format=foo
 run_qemu -drive file="$TEST_IMG",driver=foo
 run_qemu -drive file="$TEST_IMG",driver=raw,format=qcow2
+run_qemu -drive file="$TEST_IMG",driver=qcow2,format=qcow2
 
 echo
 echo === Overriding backing file ===
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
index 9596e20..e727dc1 100644
--- a/tests/qemu-iotests/051.out
+++ b/tests/qemu-iotests/051.out
@@ -43,6 +43,9 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=foo: could not open disk image TE
 Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2
 QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2: could not open disk image TEST_DIR/t.qcow2: Driver specified twice
 
+Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: could not open disk image TEST_DIR/t.qcow2: Driver specified twice
+
 
 === Overriding backing file ===
 
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 54/65] blockdev: Use blk_new_open() in blockdev_init()
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (52 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 53/65] iotests: Add test for driver=qcow2, format=qcow2 Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 55/65] block/xen: Use blk_new_open() in blk_connect() Stefan Hajnoczi
                   ` (11 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

Due to different error propagation, this breaks tests 051 and 087; fix
their output.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1423162705-32065-6-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 blockdev.c                 | 92 +++++++++++++++++++++-------------------------
 tests/qemu-iotests/051.out | 62 +++++++++++++++----------------
 tests/qemu-iotests/087.out |  8 ++--
 3 files changed, 77 insertions(+), 85 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 7d34960..6eedcf5 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -354,13 +354,11 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
     ThrottleConfig cfg;
     int snapshot = 0;
     bool copy_on_read;
-    int ret;
     Error *error = NULL;
     QemuOpts *opts;
     const char *id;
     bool has_driver_specific_opts;
     BlockdevDetectZeroesOptions detect_zeroes;
-    BlockDriver *drv = NULL;
 
     /* Check common options by copying from bs_opts to opts, all other options
      * stay in bs_opts for processing by bdrv_open(). */
@@ -426,11 +424,11 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
             goto early_err;
         }
 
-        drv = bdrv_find_format(buf);
-        if (!drv) {
-            error_setg(errp, "'%s' invalid format", buf);
+        if (qdict_haskey(bs_opts, "driver")) {
+            error_setg(errp, "Cannot specify both 'driver' and 'format'");
             goto early_err;
         }
+        qdict_put(bs_opts, "driver", qstring_from_str(buf));
     }
 
     /* disk I/O throttling */
@@ -505,70 +503,64 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
     }
 
     /* init */
-    blk = blk_new_with_bs(qemu_opts_id(opts), errp);
-    if (!blk) {
-        goto early_err;
-    }
-    bs = blk_bs(blk);
-    bs->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
-    bs->read_only = ro;
-    bs->detect_zeroes = detect_zeroes;
-
-    bdrv_set_on_error(bs, on_read_error, on_write_error);
+    if ((!file || !*file) && !has_driver_specific_opts) {
+        blk = blk_new_with_bs(qemu_opts_id(opts), errp);
+        if (!blk) {
+            goto early_err;
+        }
 
-    /* disk I/O throttling */
-    if (throttle_enabled(&cfg)) {
-        bdrv_io_limits_enable(bs);
-        bdrv_set_io_limits(bs, &cfg);
-    }
+        bs = blk_bs(blk);
+        bs->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
+        bs->read_only = ro;
 
-    if (!file || !*file) {
-        if (has_driver_specific_opts) {
+        QDECREF(bs_opts);
+    } else {
+        if (file && !*file) {
             file = NULL;
-        } else {
-            QDECREF(bs_opts);
-            qemu_opts_del(opts);
-            return blk;
         }
-    }
-    if (snapshot) {
-        /* always use cache=unsafe with snapshot */
-        bdrv_flags &= ~BDRV_O_CACHE_MASK;
-        bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH);
-    }
 
-    if (copy_on_read) {
-        bdrv_flags |= BDRV_O_COPY_ON_READ;
-    }
+        if (snapshot) {
+            /* always use cache=unsafe with snapshot */
+            bdrv_flags &= ~BDRV_O_CACHE_MASK;
+            bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH);
+        }
+
+        if (copy_on_read) {
+            bdrv_flags |= BDRV_O_COPY_ON_READ;
+        }
+
+        if (runstate_check(RUN_STATE_INMIGRATE)) {
+            bdrv_flags |= BDRV_O_INCOMING;
+        }
 
-    if (runstate_check(RUN_STATE_INMIGRATE)) {
-        bdrv_flags |= BDRV_O_INCOMING;
+        bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
+
+        blk = blk_new_open(qemu_opts_id(opts), file, NULL, bs_opts, bdrv_flags,
+                           errp);
+        if (!blk) {
+            goto err_no_bs_opts;
+        }
+        bs = blk_bs(blk);
     }
 
-    bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
+    bs->detect_zeroes = detect_zeroes;
 
-    QINCREF(bs_opts);
-    ret = bdrv_open(&bs, file, NULL, bs_opts, bdrv_flags, drv, &error);
-    assert(bs == blk_bs(blk));
+    bdrv_set_on_error(bs, on_read_error, on_write_error);
 
-    if (ret < 0) {
-        error_setg(errp, "could not open disk image %s: %s",
-                   file ?: blk_name(blk), error_get_pretty(error));
-        error_free(error);
-        goto err;
+    /* disk I/O throttling */
+    if (throttle_enabled(&cfg)) {
+        bdrv_io_limits_enable(bs);
+        bdrv_set_io_limits(bs, &cfg);
     }
 
     if (bdrv_key_required(bs)) {
         autostart = 0;
     }
 
-    QDECREF(bs_opts);
+err_no_bs_opts:
     qemu_opts_del(opts);
-
     return blk;
 
-err:
-    blk_unref(blk);
 early_err:
     qemu_opts_del(opts);
 err_no_opts:
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
index e727dc1..bf52bf0 100644
--- a/tests/qemu-iotests/051.out
+++ b/tests/qemu-iotests/051.out
@@ -5,46 +5,46 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file='TEST_DIR
 === Unknown option ===
 
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=: could not open disk image TEST_DIR/t.qcow2: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
 
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on: could not open disk image TEST_DIR/t.qcow2: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
 
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234: could not open disk image TEST_DIR/t.qcow2: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
 
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo: could not open disk image TEST_DIR/t.qcow2: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
 
 
 === Unknown protocol option ===
 
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=: could not open disk image TEST_DIR/t.qcow2: Block protocol 'file' doesn't support the option 'unknown_opt'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=: Block protocol 'file' doesn't support the option 'unknown_opt'
 
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=on
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=on: could not open disk image TEST_DIR/t.qcow2: Block protocol 'file' doesn't support the option 'unknown_opt'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=on: Block protocol 'file' doesn't support the option 'unknown_opt'
 
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=1234
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=1234: could not open disk image TEST_DIR/t.qcow2: Block protocol 'file' doesn't support the option 'unknown_opt'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=1234: Block protocol 'file' doesn't support the option 'unknown_opt'
 
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=foo
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=foo: could not open disk image TEST_DIR/t.qcow2: Block protocol 'file' doesn't support the option 'unknown_opt'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=foo: Block protocol 'file' doesn't support the option 'unknown_opt'
 
 
 === Invalid format ===
 
 Testing: -drive file=TEST_DIR/t.qcow2,format=foo
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=foo: 'foo' invalid format
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=foo: Unknown driver 'foo'
 
 Testing: -drive file=TEST_DIR/t.qcow2,driver=foo
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=foo: could not open disk image TEST_DIR/t.qcow2: Unknown driver 'foo'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=foo: Unknown driver 'foo'
 
 Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2: could not open disk image TEST_DIR/t.qcow2: Driver specified twice
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2: Cannot specify both 'driver' and 'format'
 
 Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: could not open disk image TEST_DIR/t.qcow2: Driver specified twice
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: Cannot specify both 'driver' and 'format'
 
 
 === Overriding backing file ===
@@ -58,13 +58,13 @@ ide0-hd0: TEST_DIR/t.qcow2 (qcow2)
 (qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
 
 Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig: could not open disk image TEST_DIR/t.qcow2: Driver doesn't support backing files
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files
 
 Testing: -drive file=TEST_DIR/t.qcow2,file.backing.driver=file,file.backing.filename=TEST_DIR/t.qcow2.orig
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=file,file.backing.filename=TEST_DIR/t.qcow2.orig: could not open disk image TEST_DIR/t.qcow2: Driver doesn't support backing files
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=file,file.backing.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files
 
 Testing: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.file.filename=TEST_DIR/t.qcow2.orig
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.file.filename=TEST_DIR/t.qcow2.orig: could not open disk image TEST_DIR/t.qcow2: Driver doesn't support backing files
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.file.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files
 
 
 === Enable and disable lazy refcounting on the command line, plus some invalid values ===
@@ -78,20 +78,20 @@ QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
 
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: could not open disk image TEST_DIR/t.qcow2: Parameter 'lazy-refcounts' expects 'on' or 'off'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: Parameter 'lazy-refcounts' expects 'on' or 'off'
 
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42: could not open disk image TEST_DIR/t.qcow2: Parameter 'lazy-refcounts' expects 'on' or 'off'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42: Parameter 'lazy-refcounts' expects 'on' or 'off'
 
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo: could not open disk image TEST_DIR/t.qcow2: Parameter 'lazy-refcounts' expects 'on' or 'off'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo: Parameter 'lazy-refcounts' expects 'on' or 'off'
 
 
 === With version 2 images enabling lazy refcounts must fail ===
 
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: could not open disk image TEST_DIR/t.qcow2: Lazy refcounts require a qcow2 image with at least qemu 1.1 compatibility level
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: Lazy refcounts require a qcow2 image with at least qemu 1.1 compatibility level
 
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off
 QEMU X.Y.Z monitor - type 'help' for more information
@@ -251,31 +251,31 @@ QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
 
 Testing: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2: could not open disk image TEST_DIR/t.qcow2: Block format 'qcow2' used by device '' doesn't support the option 'filename'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2: Block format 'qcow2' used by device '' doesn't support the option 'filename'
 
 
 === Leaving out required options ===
 
 Testing: -drive driver=file
-QEMU_PROG: -drive driver=file: could not open disk image ide0-hd0: The 'file' block driver requires a file name
+QEMU_PROG: -drive driver=file: The 'file' block driver requires a file name
 
 Testing: -drive driver=nbd
-QEMU_PROG: -drive driver=nbd: could not open disk image ide0-hd0: one of path and host must be specified.
+QEMU_PROG: -drive driver=nbd: one of path and host must be specified.
 
 Testing: -drive driver=raw
-QEMU_PROG: -drive driver=raw: could not open disk image ide0-hd0: Can't use 'raw' as a block driver for the protocol level
+QEMU_PROG: -drive driver=raw: Can't use 'raw' as a block driver for the protocol level
 
 Testing: -drive file.driver=file
-QEMU_PROG: -drive file.driver=file: could not open disk image ide0-hd0: The 'file' block driver requires a file name
+QEMU_PROG: -drive file.driver=file: The 'file' block driver requires a file name
 
 Testing: -drive file.driver=nbd
-QEMU_PROG: -drive file.driver=nbd: could not open disk image ide0-hd0: one of path and host must be specified.
+QEMU_PROG: -drive file.driver=nbd: one of path and host must be specified.
 
 Testing: -drive file.driver=raw
-QEMU_PROG: -drive file.driver=raw: could not open disk image ide0-hd0: Can't use 'raw' as a block driver for the protocol level
+QEMU_PROG: -drive file.driver=raw: Can't use 'raw' as a block driver for the protocol level
 
 Testing: -drive foo=bar
-QEMU_PROG: -drive foo=bar: could not open disk image ide0-hd0: Must specify either driver or file
+QEMU_PROG: -drive foo=bar: Must specify either driver or file
 
 
 === Specifying both an option and its legacy alias ===
@@ -326,13 +326,13 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,readonly=on,read-only=off: 'read-only' a
 === Parsing protocol from file name ===
 
 Testing: -hda foo:bar
-QEMU_PROG: -hda foo:bar: could not open disk image foo:bar: Unknown protocol 'foo'
+QEMU_PROG: -hda foo:bar: Unknown protocol 'foo'
 
 Testing: -drive file=foo:bar
-QEMU_PROG: -drive file=foo:bar: could not open disk image foo:bar: Unknown protocol 'foo'
+QEMU_PROG: -drive file=foo:bar: Unknown protocol 'foo'
 
 Testing: -drive file.filename=foo:bar
-QEMU_PROG: -drive file.filename=foo:bar: could not open disk image ide0-hd0: Could not open 'foo:bar': No such file or directory
+QEMU_PROG: -drive file.filename=foo:bar: Could not open 'foo:bar': No such file or directory
 
 Testing: -hda file:TEST_DIR/t.qcow2
 QEMU X.Y.Z monitor - type 'help' for more information
@@ -343,7 +343,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
 
 Testing: -drive file.filename=file:TEST_DIR/t.qcow2
-QEMU_PROG: -drive file.filename=file:TEST_DIR/t.qcow2: could not open disk image ide0-hd0: Could not open 'file:TEST_DIR/t.qcow2': No such file or directory
+QEMU_PROG: -drive file.filename=file:TEST_DIR/t.qcow2: Could not open 'file:TEST_DIR/t.qcow2': No such file or directory
 
 
 === Snapshot mode ===
diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out
index 91f4ea1..0ba2e43 100644
--- a/tests/qemu-iotests/087.out
+++ b/tests/qemu-iotests/087.out
@@ -21,9 +21,9 @@ QMP_VERSION
 {"return": {}}
 {"error": {"class": "GenericError", "desc": "Device with id 'disk' already exists"}}
 {"error": {"class": "GenericError", "desc": "Device name 'test-node' conflicts with an existing node name"}}
-{"error": {"class": "GenericError", "desc": "could not open disk image disk2: node-name=disk is conflicting with a device id"}}
-{"error": {"class": "GenericError", "desc": "could not open disk image disk2: Duplicate node name"}}
-{"error": {"class": "GenericError", "desc": "could not open disk image disk3: node-name=disk3 is conflicting with a device id"}}
+{"error": {"class": "GenericError", "desc": "node-name=disk is conflicting with a device id"}}
+{"error": {"class": "GenericError", "desc": "Duplicate node name"}}
+{"error": {"class": "GenericError", "desc": "node-name=disk3 is conflicting with a device id"}}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
@@ -57,7 +57,7 @@ QMP_VERSION
 Testing:
 QMP_VERSION
 {"return": {}}
-{"error": {"class": "GenericError", "desc": "could not open disk image disk: Guest must be stopped for opening of encrypted image"}}
+{"error": {"class": "GenericError", "desc": "Guest must be stopped for opening of encrypted image"}}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 55/65] block/xen: Use blk_new_open() in blk_connect()
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (53 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 54/65] blockdev: Use blk_new_open() in blockdev_init() Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 56/65] qemu-img: Use blk_new_open() in img_open() Stefan Hajnoczi
                   ` (10 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

As part of the required changes, this fixes a bug where specifying an
invalid driver would result in the block layer probing the image format;
now it will result in an error, unless "<unset>" is specified as the
driver name. Fixing this would require further work on the xen_disk code
which does not seem worth it (at this point and for this patch).

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1423162705-32065-7-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 hw/block/xen_disk.c | 27 +++++++++++----------------
 1 file changed, 11 insertions(+), 16 deletions(-)

diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
index 21842a0..267d8a8 100644
--- a/hw/block/xen_disk.c
+++ b/hw/block/xen_disk.c
@@ -40,6 +40,8 @@
 #include "xen_blkif.h"
 #include "sysemu/blockdev.h"
 #include "sysemu/block-backend.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qstring.h"
 
 /* ------------------------------------------------------------- */
 
@@ -897,30 +899,23 @@ static int blk_connect(struct XenDevice *xendev)
     blkdev->dinfo = drive_get(IF_XEN, 0, index);
     if (!blkdev->dinfo) {
         Error *local_err = NULL;
-        BlockBackend *blk;
-        BlockDriver *drv;
-        BlockDriverState *bs;
+        QDict *options = NULL;
 
-        /* setup via xenbus -> create new block driver instance */
-        xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
-        blk = blk_new_with_bs(blkdev->dev, NULL);
-        if (!blk) {
-            return -1;
+        if (strcmp(blkdev->fileproto, "<unset>")) {
+            options = qdict_new();
+            qdict_put(options, "driver", qstring_from_str(blkdev->fileproto));
         }
-        blkdev->blk = blk;
 
-        bs = blk_bs(blk);
-        drv = bdrv_find_whitelisted_format(blkdev->fileproto, readonly);
-        if (bdrv_open(&bs, blkdev->filename, NULL, NULL, qflags,
-                      drv, &local_err) != 0) {
+        /* setup via xenbus -> create new block driver instance */
+        xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
+        blkdev->blk = blk_new_open(blkdev->dev, blkdev->filename, NULL, options,
+                                   qflags, &local_err);
+        if (!blkdev->blk) {
             xen_be_printf(&blkdev->xendev, 0, "error: %s\n",
                           error_get_pretty(local_err));
             error_free(local_err);
-            blk_unref(blk);
-            blkdev->blk = NULL;
             return -1;
         }
-        assert(bs == blk_bs(blk));
     } else {
         /* setup via qemu cmdline -> already setup for us */
         xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 56/65] qemu-img: Use blk_new_open() in img_open()
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (54 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 55/65] block/xen: Use blk_new_open() in blk_connect() Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 57/65] qemu-img: Use blk_new_open() in img_rebase() Stefan Hajnoczi
                   ` (9 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1423162705-32065-8-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 qemu-img.c | 20 ++++++--------------
 1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 8790546..7dea370 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -293,32 +293,24 @@ static BlockBackend *img_open(const char *id, const char *filename,
 {
     BlockBackend *blk;
     BlockDriverState *bs;
-    BlockDriver *drv;
     char password[256];
     Error *local_err = NULL;
-    int ret;
-
-    blk = blk_new_with_bs(id, &error_abort);
-    bs = blk_bs(blk);
+    QDict *options = NULL;
 
     if (fmt) {
-        drv = bdrv_find_format(fmt);
-        if (!drv) {
-            error_report("Unknown file format '%s'", fmt);
-            goto fail;
-        }
-    } else {
-        drv = NULL;
+        options = qdict_new();
+        qdict_put(options, "driver", qstring_from_str(fmt));
     }
 
-    ret = bdrv_open(&bs, filename, NULL, NULL, flags, drv, &local_err);
-    if (ret < 0) {
+    blk = blk_new_open(id, filename, NULL, options, flags, &local_err);
+    if (!blk) {
         error_report("Could not open '%s': %s", filename,
                      error_get_pretty(local_err));
         error_free(local_err);
         goto fail;
     }
 
+    bs = blk_bs(blk);
     if (bdrv_is_encrypted(bs) && require_io) {
         qprintf(quiet, "Disk image '%s' is encrypted.\n", filename);
         if (read_password(password, sizeof(password)) < 0) {
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 57/65] qemu-img: Use blk_new_open() in img_rebase()
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (55 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 56/65] qemu-img: Use blk_new_open() in img_open() Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 58/65] qemu-img: Use BlockBackend as far as possible Stefan Hajnoczi
                   ` (8 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1423162705-32065-9-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 qemu-img.c | 49 +++++++++++++++++++++++--------------------------
 1 file changed, 23 insertions(+), 26 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 7dea370..dbb7437 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -2435,7 +2435,6 @@ static int img_rebase(int argc, char **argv)
 {
     BlockBackend *blk = NULL, *blk_old_backing = NULL, *blk_new_backing = NULL;
     BlockDriverState *bs = NULL, *bs_old_backing = NULL, *bs_new_backing = NULL;
-    BlockDriver *old_backing_drv, *new_backing_drv;
     char *filename;
     const char *fmt, *cache, *src_cache, *out_basefmt, *out_baseimg;
     int c, flags, src_flags, ret;
@@ -2529,22 +2528,8 @@ static int img_rebase(int argc, char **argv)
     }
     bs = blk_bs(blk);
 
-    /* Find the right drivers for the backing files */
-    old_backing_drv = NULL;
-    new_backing_drv = NULL;
-
-    if (!unsafe && bs->backing_format[0] != '\0') {
-        old_backing_drv = bdrv_find_format(bs->backing_format);
-        if (old_backing_drv == NULL) {
-            error_report("Invalid format name: '%s'", bs->backing_format);
-            ret = -1;
-            goto out;
-        }
-    }
-
     if (out_basefmt != NULL) {
-        new_backing_drv = bdrv_find_format(out_basefmt);
-        if (new_backing_drv == NULL) {
+        if (bdrv_find_format(out_basefmt) == NULL) {
             error_report("Invalid format name: '%s'", out_basefmt);
             ret = -1;
             goto out;
@@ -2554,29 +2539,41 @@ static int img_rebase(int argc, char **argv)
     /* For safe rebasing we need to compare old and new backing file */
     if (!unsafe) {
         char backing_name[PATH_MAX];
+        QDict *options = NULL;
+
+        if (bs->backing_format[0] != '\0') {
+            options = qdict_new();
+            qdict_put(options, "driver", qstring_from_str(bs->backing_format));
+        }
 
-        blk_old_backing = blk_new_with_bs("old_backing", &error_abort);
-        bs_old_backing = blk_bs(blk_old_backing);
         bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
-        ret = bdrv_open(&bs_old_backing, backing_name, NULL, NULL, src_flags,
-                        old_backing_drv, &local_err);
-        if (ret) {
+        blk_old_backing = blk_new_open("old_backing", backing_name, NULL,
+                                       options, src_flags, &local_err);
+        if (!blk_old_backing) {
             error_report("Could not open old backing file '%s': %s",
                          backing_name, error_get_pretty(local_err));
             error_free(local_err);
             goto out;
         }
+        bs_old_backing = blk_bs(blk_old_backing);
+
         if (out_baseimg[0]) {
-            blk_new_backing = blk_new_with_bs("new_backing", &error_abort);
-            bs_new_backing = blk_bs(blk_new_backing);
-            ret = bdrv_open(&bs_new_backing, out_baseimg, NULL, NULL, src_flags,
-                            new_backing_drv, &local_err);
-            if (ret) {
+            if (out_basefmt) {
+                options = qdict_new();
+                qdict_put(options, "driver", qstring_from_str(out_basefmt));
+            } else {
+                options = NULL;
+            }
+
+            blk_new_backing = blk_new_open("new_backing", out_baseimg, NULL,
+                                           options, src_flags, &local_err);
+            if (!blk_new_backing) {
                 error_report("Could not open new backing file '%s': %s",
                              out_baseimg, error_get_pretty(local_err));
                 error_free(local_err);
                 goto out;
             }
+            bs_new_backing = blk_bs(blk_new_backing);
         }
     }
 
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 58/65] qemu-img: Use BlockBackend as far as possible
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (56 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 57/65] qemu-img: Use blk_new_open() in img_rebase() Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 59/65] qemu-nbd: Use blk_new_open() in main() Stefan Hajnoczi
                   ` (7 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

Although qemu-img already creates BlockBackends, it does not do accesses
to the images through them. This patch converts all of the bdrv_* calls
for which this is currently possible to blk_* calls. Most of the
remaining calls will probably stay bdrv_* calls because they really do
operate on the BDS level instead of the BB level.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1423162705-32065-10-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 qemu-img.c | 82 ++++++++++++++++++++++++++++++--------------------------------
 1 file changed, 39 insertions(+), 43 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index dbb7437..0155e36 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1010,19 +1010,19 @@ static int64_t sectors_to_process(int64_t total, int64_t from)
  * Returns 0 in case sectors are filled with 0, 1 if sectors contain non-zero
  * data and negative value on error.
  *
- * @param bs:  Driver used for accessing file
+ * @param blk:  BlockBackend for the image
  * @param sect_num: Number of first sector to check
  * @param sect_count: Number of sectors to check
  * @param filename: Name of disk file we are checking (logging purpose)
  * @param buffer: Allocated buffer for storing read data
  * @param quiet: Flag for quiet mode
  */
-static int check_empty_sectors(BlockDriverState *bs, int64_t sect_num,
+static int check_empty_sectors(BlockBackend *blk, int64_t sect_num,
                                int sect_count, const char *filename,
                                uint8_t *buffer, bool quiet)
 {
     int pnum, ret = 0;
-    ret = bdrv_read(bs, sect_num, buffer, sect_count);
+    ret = blk_read(blk, sect_num, buffer, sect_count);
     if (ret < 0) {
         error_report("Error while reading offset %" PRId64 " of %s: %s",
                      sectors_to_bytes(sect_num), filename, strerror(-ret));
@@ -1132,16 +1132,16 @@ static int img_compare(int argc, char **argv)
     }
     bs2 = blk_bs(blk2);
 
-    buf1 = qemu_blockalign(bs1, IO_BUF_SIZE);
-    buf2 = qemu_blockalign(bs2, IO_BUF_SIZE);
-    total_sectors1 = bdrv_nb_sectors(bs1);
+    buf1 = blk_blockalign(blk1, IO_BUF_SIZE);
+    buf2 = blk_blockalign(blk2, IO_BUF_SIZE);
+    total_sectors1 = blk_nb_sectors(blk1);
     if (total_sectors1 < 0) {
         error_report("Can't get size of %s: %s",
                      filename1, strerror(-total_sectors1));
         ret = 4;
         goto out;
     }
-    total_sectors2 = bdrv_nb_sectors(bs2);
+    total_sectors2 = blk_nb_sectors(blk2);
     if (total_sectors2 < 0) {
         error_report("Can't get size of %s: %s",
                      filename2, strerror(-total_sectors2));
@@ -1183,7 +1183,7 @@ static int img_compare(int argc, char **argv)
 
         if (allocated1 == allocated2) {
             if (allocated1) {
-                ret = bdrv_read(bs1, sector_num, buf1, nb_sectors);
+                ret = blk_read(blk1, sector_num, buf1, nb_sectors);
                 if (ret < 0) {
                     error_report("Error while reading offset %" PRId64 " of %s:"
                                  " %s", sectors_to_bytes(sector_num), filename1,
@@ -1191,7 +1191,7 @@ static int img_compare(int argc, char **argv)
                     ret = 4;
                     goto out;
                 }
-                ret = bdrv_read(bs2, sector_num, buf2, nb_sectors);
+                ret = blk_read(blk2, sector_num, buf2, nb_sectors);
                 if (ret < 0) {
                     error_report("Error while reading offset %" PRId64
                                  " of %s: %s", sectors_to_bytes(sector_num),
@@ -1218,10 +1218,10 @@ static int img_compare(int argc, char **argv)
             }
 
             if (allocated1) {
-                ret = check_empty_sectors(bs1, sector_num, nb_sectors,
+                ret = check_empty_sectors(blk1, sector_num, nb_sectors,
                                           filename1, buf1, quiet);
             } else {
-                ret = check_empty_sectors(bs2, sector_num, nb_sectors,
+                ret = check_empty_sectors(blk2, sector_num, nb_sectors,
                                           filename2, buf1, quiet);
             }
             if (ret) {
@@ -1238,18 +1238,18 @@ static int img_compare(int argc, char **argv)
     }
 
     if (total_sectors1 != total_sectors2) {
-        BlockDriverState *bs_over;
+        BlockBackend *blk_over;
         int64_t total_sectors_over;
         const char *filename_over;
 
         qprintf(quiet, "Warning: Image size mismatch!\n");
         if (total_sectors1 > total_sectors2) {
             total_sectors_over = total_sectors1;
-            bs_over = bs1;
+            blk_over = blk1;
             filename_over = filename1;
         } else {
             total_sectors_over = total_sectors2;
-            bs_over = bs2;
+            blk_over = blk2;
             filename_over = filename2;
         }
 
@@ -1258,7 +1258,7 @@ static int img_compare(int argc, char **argv)
             if (nb_sectors <= 0) {
                 break;
             }
-            ret = bdrv_is_allocated_above(bs_over, NULL, sector_num,
+            ret = bdrv_is_allocated_above(blk_bs(blk_over), NULL, sector_num,
                                           nb_sectors, &pnum);
             if (ret < 0) {
                 ret = 3;
@@ -1269,7 +1269,7 @@ static int img_compare(int argc, char **argv)
             }
             nb_sectors = pnum;
             if (ret) {
-                ret = check_empty_sectors(bs_over, sector_num, nb_sectors,
+                ret = check_empty_sectors(blk_over, sector_num, nb_sectors,
                                           filename_over, buf1, quiet);
                 if (ret) {
                     if (ret < 0) {
@@ -1478,7 +1478,7 @@ static int img_convert(int argc, char **argv)
             goto out;
         }
         bs[bs_i] = blk_bs(blk[bs_i]);
-        bs_sectors[bs_i] = bdrv_nb_sectors(bs[bs_i]);
+        bs_sectors[bs_i] = blk_nb_sectors(blk[bs_i]);
         if (bs_sectors[bs_i] < 0) {
             error_report("Could not get size of %s: %s",
                          argv[optind + bs_i], strerror(-bs_sectors[bs_i]));
@@ -1630,10 +1630,10 @@ static int img_convert(int argc, char **argv)
                                          out_bs->bl.discard_alignment))
                     );
 
-    buf = qemu_blockalign(out_bs, bufsectors * BDRV_SECTOR_SIZE);
+    buf = blk_blockalign(out_blk, bufsectors * BDRV_SECTOR_SIZE);
 
     if (skip_create) {
-        int64_t output_sectors = bdrv_nb_sectors(out_bs);
+        int64_t output_sectors = blk_nb_sectors(out_blk);
         if (output_sectors < 0) {
             error_report("unable to get output image length: %s\n",
                          strerror(-output_sectors));
@@ -1701,7 +1701,7 @@ static int img_convert(int argc, char **argv)
                 nlow = remainder > bs_sectors[bs_i] - bs_num
                     ? bs_sectors[bs_i] - bs_num : remainder;
 
-                ret = bdrv_read(bs[bs_i], bs_num, buf2, nlow);
+                ret = blk_read(blk[bs_i], bs_num, buf2, nlow);
                 if (ret < 0) {
                     error_report("error while reading sector %" PRId64 ": %s",
                                  bs_num, strerror(-ret));
@@ -1716,7 +1716,7 @@ static int img_convert(int argc, char **argv)
             assert (remainder == 0);
 
             if (!buffer_is_zero(buf, n * BDRV_SECTOR_SIZE)) {
-                ret = bdrv_write_compressed(out_bs, sector_num, buf, n);
+                ret = blk_write_compressed(out_blk, sector_num, buf, n);
                 if (ret != 0) {
                     error_report("error while compressing sector %" PRId64
                                  ": %s", sector_num, strerror(-ret));
@@ -1727,7 +1727,7 @@ static int img_convert(int argc, char **argv)
             qemu_progress_print(100.0 * sector_num / total_sectors, 0);
         }
         /* signal EOF to align */
-        bdrv_write_compressed(out_bs, 0, NULL, 0);
+        blk_write_compressed(out_blk, 0, NULL, 0);
     } else {
         int64_t sectors_to_read, sectors_read, sector_num_next_status;
         bool count_allocated_sectors;
@@ -1828,7 +1828,7 @@ restart:
             }
 
             n1 = n;
-            ret = bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n);
+            ret = blk_read(blk[bs_i], sector_num - bs_offset, buf, n);
             if (ret < 0) {
                 error_report("error while reading sector %" PRId64 ": %s",
                              sector_num - bs_offset, strerror(-ret));
@@ -1841,7 +1841,7 @@ restart:
             while (n > 0) {
                 if (!has_zero_init ||
                     is_allocated_sectors_min(buf1, n, &n1, min_sparse)) {
-                    ret = bdrv_write(out_bs, sector_num, buf1, n1);
+                    ret = blk_write(out_blk, sector_num, buf1, n1);
                     if (ret < 0) {
                         error_report("error while writing sector %" PRId64
                                      ": %s", sector_num, strerror(-ret));
@@ -2265,7 +2265,7 @@ static int img_map(int argc, char **argv)
         printf("%-16s%-16s%-16s%s\n", "Offset", "Length", "Mapped to", "File");
     }
 
-    length = bdrv_getlength(bs);
+    length = blk_getlength(blk);
     while (curr.start + curr.length < length) {
         int64_t nsectors_left;
         int64_t sector_num;
@@ -2434,7 +2434,7 @@ static int img_snapshot(int argc, char **argv)
 static int img_rebase(int argc, char **argv)
 {
     BlockBackend *blk = NULL, *blk_old_backing = NULL, *blk_new_backing = NULL;
-    BlockDriverState *bs = NULL, *bs_old_backing = NULL, *bs_new_backing = NULL;
+    BlockDriverState *bs = NULL;
     char *filename;
     const char *fmt, *cache, *src_cache, *out_basefmt, *out_baseimg;
     int c, flags, src_flags, ret;
@@ -2555,7 +2555,6 @@ static int img_rebase(int argc, char **argv)
             error_free(local_err);
             goto out;
         }
-        bs_old_backing = blk_bs(blk_old_backing);
 
         if (out_baseimg[0]) {
             if (out_basefmt) {
@@ -2573,7 +2572,6 @@ static int img_rebase(int argc, char **argv)
                 error_free(local_err);
                 goto out;
             }
-            bs_new_backing = blk_bs(blk_new_backing);
         }
     }
 
@@ -2596,17 +2594,17 @@ static int img_rebase(int argc, char **argv)
         uint8_t * buf_new;
         float local_progress = 0;
 
-        buf_old = qemu_blockalign(bs, IO_BUF_SIZE);
-        buf_new = qemu_blockalign(bs, IO_BUF_SIZE);
+        buf_old = blk_blockalign(blk, IO_BUF_SIZE);
+        buf_new = blk_blockalign(blk, IO_BUF_SIZE);
 
-        num_sectors = bdrv_nb_sectors(bs);
+        num_sectors = blk_nb_sectors(blk);
         if (num_sectors < 0) {
             error_report("Could not get size of '%s': %s",
                          filename, strerror(-num_sectors));
             ret = -1;
             goto out;
         }
-        old_backing_num_sectors = bdrv_nb_sectors(bs_old_backing);
+        old_backing_num_sectors = blk_nb_sectors(blk_old_backing);
         if (old_backing_num_sectors < 0) {
             char backing_name[PATH_MAX];
 
@@ -2616,8 +2614,8 @@ static int img_rebase(int argc, char **argv)
             ret = -1;
             goto out;
         }
-        if (bs_new_backing) {
-            new_backing_num_sectors = bdrv_nb_sectors(bs_new_backing);
+        if (blk_new_backing) {
+            new_backing_num_sectors = blk_nb_sectors(blk_new_backing);
             if (new_backing_num_sectors < 0) {
                 error_report("Could not get size of '%s': %s",
                              out_baseimg, strerror(-new_backing_num_sectors));
@@ -2662,21 +2660,21 @@ static int img_rebase(int argc, char **argv)
                     n = old_backing_num_sectors - sector;
                 }
 
-                ret = bdrv_read(bs_old_backing, sector, buf_old, n);
+                ret = blk_read(blk_old_backing, sector, buf_old, n);
                 if (ret < 0) {
                     error_report("error while reading from old backing file");
                     goto out;
                 }
             }
 
-            if (sector >= new_backing_num_sectors || !bs_new_backing) {
+            if (sector >= new_backing_num_sectors || !blk_new_backing) {
                 memset(buf_new, 0, n * BDRV_SECTOR_SIZE);
             } else {
                 if (sector + n > new_backing_num_sectors) {
                     n = new_backing_num_sectors - sector;
                 }
 
-                ret = bdrv_read(bs_new_backing, sector, buf_new, n);
+                ret = blk_read(blk_new_backing, sector, buf_new, n);
                 if (ret < 0) {
                     error_report("error while reading from new backing file");
                     goto out;
@@ -2692,8 +2690,8 @@ static int img_rebase(int argc, char **argv)
                 if (compare_sectors(buf_old + written * 512,
                     buf_new + written * 512, n - written, &pnum))
                 {
-                    ret = bdrv_write(bs, sector + written,
-                        buf_old + written * 512, pnum);
+                    ret = blk_write(blk, sector + written,
+                                    buf_old + written * 512, pnum);
                     if (ret < 0) {
                         error_report("Error while writing to COW image: %s",
                             strerror(-ret));
@@ -2758,7 +2756,6 @@ static int img_resize(int argc, char **argv)
     int64_t n, total_size;
     bool quiet = false;
     BlockBackend *blk = NULL;
-    BlockDriverState *bs = NULL;
     QemuOpts *param;
     static QemuOptsList resize_options = {
         .name = "resize_options",
@@ -2840,10 +2837,9 @@ static int img_resize(int argc, char **argv)
         ret = -1;
         goto out;
     }
-    bs = blk_bs(blk);
 
     if (relative) {
-        total_size = bdrv_getlength(bs) + n * relative;
+        total_size = blk_getlength(blk) + n * relative;
     } else {
         total_size = n;
     }
@@ -2853,7 +2849,7 @@ static int img_resize(int argc, char **argv)
         goto out;
     }
 
-    ret = bdrv_truncate(bs, total_size);
+    ret = blk_truncate(blk, total_size);
     switch (ret) {
     case 0:
         qprintf(quiet, "Image resized.\n");
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 59/65] qemu-nbd: Use blk_new_open() in main()
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (57 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 58/65] qemu-img: Use BlockBackend as far as possible Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 60/65] qemu-io: Use blk_new_open() in openfile() Stefan Hajnoczi
                   ` (6 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Message-id: 1423162705-32065-11-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 qemu-nbd.c | 25 +++++++++----------------
 1 file changed, 9 insertions(+), 16 deletions(-)

diff --git a/qemu-nbd.c b/qemu-nbd.c
index 4d8df08..ac1e5d6 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -391,7 +391,6 @@ int main(int argc, char **argv)
 {
     BlockBackend *blk;
     BlockDriverState *bs;
-    BlockDriver *drv;
     off_t dev_offset = 0;
     uint32_t nbdflags = 0;
     bool disconnect = false;
@@ -434,7 +433,7 @@ int main(int argc, char **argv)
     char *end;
     int flags = BDRV_O_RDWR;
     int partition = -1;
-    int ret;
+    int ret = 0;
     int fd;
     bool seen_cache = false;
     bool seen_discard = false;
@@ -445,6 +444,7 @@ int main(int argc, char **argv)
     const char *fmt = NULL;
     Error *local_err = NULL;
     BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
+    QDict *options = NULL;
 
     /* The client thread uses SIGTERM to interrupt the server.  A signal
      * handler ensures that "qemu-nbd -v -c" exits with a nice status code.
@@ -689,24 +689,17 @@ int main(int argc, char **argv)
     atexit(bdrv_close_all);
 
     if (fmt) {
-        drv = bdrv_find_format(fmt);
-        if (!drv) {
-            errx(EXIT_FAILURE, "Unknown file format '%s'", fmt);
-        }
-    } else {
-        drv = NULL;
+        options = qdict_new();
+        qdict_put(options, "driver", qstring_from_str(fmt));
     }
 
-    blk = blk_new_with_bs("hda", &error_abort);
-    bs = blk_bs(blk);
-
     srcpath = argv[optind];
-    ret = bdrv_open(&bs, srcpath, NULL, NULL, flags, drv, &local_err);
-    if (ret < 0) {
-        errno = -ret;
-        err(EXIT_FAILURE, "Failed to bdrv_open '%s': %s", argv[optind],
-            error_get_pretty(local_err));
+    blk = blk_new_open("hda", srcpath, NULL, options, flags, &local_err);
+    if (!blk) {
+        errx(EXIT_FAILURE, "Failed to blk_new_open '%s': %s", argv[optind],
+             error_get_pretty(local_err));
     }
+    bs = blk_bs(blk);
 
     if (sn_opts) {
         ret = bdrv_snapshot_load_tmp(bs,
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 60/65] qemu-io: Use blk_new_open() in openfile()
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (58 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 59/65] qemu-nbd: Use blk_new_open() in main() Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 61/65] qemu-io: Remove "growable" option Stefan Hajnoczi
                   ` (5 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1423162705-32065-12-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 qemu-io.c | 30 ++++++++++++------------------
 1 file changed, 12 insertions(+), 18 deletions(-)

diff --git a/qemu-io.c b/qemu-io.c
index 91a445a..fa072df 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -51,34 +51,29 @@ static const cmdinfo_t close_cmd = {
     .oneline    = "close the current open file",
 };
 
-static int openfile(char *name, BlockDriver *drv, int flags, int growable,
-                    QDict *opts)
+static int openfile(char *name, int flags, int growable, QDict *opts)
 {
     Error *local_err = NULL;
 
-    if (qemuio_bs) {
+    if (qemuio_blk) {
         fprintf(stderr, "file open already, try 'help close'\n");
         QDECREF(opts);
         return 1;
     }
 
-    qemuio_blk = blk_new_with_bs("hda", &error_abort);
-    qemuio_bs = blk_bs(qemuio_blk);
-
     if (growable) {
         flags |= BDRV_O_PROTOCOL;
     }
 
-    if (bdrv_open(&qemuio_bs, name, NULL, opts, flags, drv, &local_err) < 0) {
+    qemuio_blk = blk_new_open("hda", name, NULL, opts, flags, &local_err);
+    if (!qemuio_blk) {
         fprintf(stderr, "%s: can't open%s%s: %s\n", progname,
                 name ? " device " : "", name ?: "",
                 error_get_pretty(local_err));
         error_free(local_err);
-        blk_unref(qemuio_blk);
-        qemuio_bs = NULL;
-        qemuio_blk = NULL;
         return 1;
     }
+    qemuio_bs = blk_bs(qemuio_blk);
 
     return 0;
 }
@@ -170,9 +165,9 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
     qemu_opts_reset(&empty_opts);
 
     if (optind == argc - 1) {
-        return openfile(argv[optind], NULL, flags, growable, opts);
+        return openfile(argv[optind], flags, growable, opts);
     } else if (optind == argc) {
-        return openfile(NULL, NULL, flags, growable, opts);
+        return openfile(NULL, flags, growable, opts);
     } else {
         QDECREF(opts);
         return qemuio_command_usage(&open_cmd);
@@ -387,8 +382,8 @@ int main(int argc, char **argv)
     int c;
     int opt_index = 0;
     int flags = BDRV_O_UNMAP;
-    BlockDriver *drv = NULL;
     Error *local_error = NULL;
+    QDict *opts = NULL;
 
 #ifdef CONFIG_POSIX
     signal(SIGPIPE, SIG_IGN);
@@ -414,11 +409,10 @@ int main(int argc, char **argv)
             }
             break;
         case 'f':
-            drv = bdrv_find_format(optarg);
-            if (!drv) {
-                error_report("Invalid format '%s'", optarg);
-                exit(EXIT_FAILURE);
+            if (!opts) {
+                opts = qdict_new();
             }
+            qdict_put(opts, "driver", qstring_from_str(optarg));
             break;
         case 'c':
             add_user_command(optarg);
@@ -489,7 +483,7 @@ int main(int argc, char **argv)
     }
 
     if ((argc - optind) == 1) {
-        openfile(argv[optind], drv, flags, growable, NULL);
+        openfile(argv[optind], flags, growable, opts);
     }
     command_loop();
 
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 61/65] qemu-io: Remove "growable" option
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (59 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 60/65] qemu-io: Use blk_new_open() in openfile() Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 62/65] qemu-io: Use BlockBackend Stefan Hajnoczi
                   ` (4 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

Remove "growable" option from the "open" command and from the qemu-io
command line. qemu-io is about to be converted to BlockBackend which
will make sure that no request exceeds the image size, so the only way
to keep "growable" would be to use BlockBackend if it is not given and
to directly access the BDS if it is.

qemu-io is a debugging tool, therefore removing a rarely used option
will have only a very small impact, if any. There was only one
qemu-iotest which used the option; since it is not critical, this patch
just removes it.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1423162705-32065-13-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 qemu-io.c                  | 23 +++------------
 tests/qemu-iotests/016     | 73 ----------------------------------------------
 tests/qemu-iotests/016.out | 23 ---------------
 tests/qemu-iotests/group   |  2 +-
 4 files changed, 5 insertions(+), 116 deletions(-)
 delete mode 100755 tests/qemu-iotests/016
 delete mode 100644 tests/qemu-iotests/016.out

diff --git a/qemu-io.c b/qemu-io.c
index fa072df..a85522a 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -51,7 +51,7 @@ static const cmdinfo_t close_cmd = {
     .oneline    = "close the current open file",
 };
 
-static int openfile(char *name, int flags, int growable, QDict *opts)
+static int openfile(char *name, int flags, QDict *opts)
 {
     Error *local_err = NULL;
 
@@ -61,10 +61,6 @@ static int openfile(char *name, int flags, int growable, QDict *opts)
         return 1;
     }
 
-    if (growable) {
-        flags |= BDRV_O_PROTOCOL;
-    }
-
     qemuio_blk = blk_new_open("hda", name, NULL, opts, flags, &local_err);
     if (!qemuio_blk) {
         fprintf(stderr, "%s: can't open%s%s: %s\n", progname,
@@ -91,7 +87,6 @@ static void open_help(void)
 " -r, -- open file read-only\n"
 " -s, -- use snapshot file\n"
 " -n, -- disable host cache\n"
-" -g, -- allow file to grow (only applies to protocols)\n"
 " -o, -- options to be given to the block driver"
 "\n");
 }
@@ -124,7 +119,6 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
 {
     int flags = 0;
     int readonly = 0;
-    int growable = 0;
     int c;
     QemuOpts *qopts;
     QDict *opts;
@@ -140,9 +134,6 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
         case 'r':
             readonly = 1;
             break;
-        case 'g':
-            growable = 1;
-            break;
         case 'o':
             if (!qemu_opts_parse(&empty_opts, optarg, 0)) {
                 printf("could not parse option list -- %s\n", optarg);
@@ -165,9 +156,9 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
     qemu_opts_reset(&empty_opts);
 
     if (optind == argc - 1) {
-        return openfile(argv[optind], flags, growable, opts);
+        return openfile(argv[optind], flags, opts);
     } else if (optind == argc) {
-        return openfile(NULL, flags, growable, opts);
+        return openfile(NULL, flags, opts);
     } else {
         QDECREF(opts);
         return qemuio_command_usage(&open_cmd);
@@ -201,7 +192,6 @@ static void usage(const char *name)
 "  -r, --read-only      export read-only\n"
 "  -s, --snapshot       use snapshot file\n"
 "  -n, --nocache        disable host cache\n"
-"  -g, --growable       allow file to grow (only applies to protocols)\n"
 "  -m, --misalign       misalign allocations for O_DIRECT\n"
 "  -k, --native-aio     use kernel AIO implementation (on Linux only)\n"
 "  -t, --cache=MODE     use the given cache mode for the image\n"
@@ -360,7 +350,6 @@ static void reenable_tty_echo(void)
 int main(int argc, char **argv)
 {
     int readonly = 0;
-    int growable = 0;
     const char *sopt = "hVc:d:f:rsnmgkt:T:";
     const struct option lopt[] = {
         { "help", 0, NULL, 'h' },
@@ -372,7 +361,6 @@ int main(int argc, char **argv)
         { "snapshot", 0, NULL, 's' },
         { "nocache", 0, NULL, 'n' },
         { "misalign", 0, NULL, 'm' },
-        { "growable", 0, NULL, 'g' },
         { "native-aio", 0, NULL, 'k' },
         { "discard", 1, NULL, 'd' },
         { "cache", 1, NULL, 't' },
@@ -423,9 +411,6 @@ int main(int argc, char **argv)
         case 'm':
             qemuio_misalign = true;
             break;
-        case 'g':
-            growable = 1;
-            break;
         case 'k':
             flags |= BDRV_O_NATIVE_AIO;
             break;
@@ -483,7 +468,7 @@ int main(int argc, char **argv)
     }
 
     if ((argc - optind) == 1) {
-        openfile(argv[optind], flags, growable, opts);
+        openfile(argv[optind], flags, opts);
     }
     command_loop();
 
diff --git a/tests/qemu-iotests/016 b/tests/qemu-iotests/016
deleted file mode 100755
index 52397aa..0000000
--- a/tests/qemu-iotests/016
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/bin/bash
-#
-# Test I/O after EOF for growable images.
-#
-# Copyright (C) 2009 Red Hat, Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-
-# creator
-owner=hch@lst.de
-
-seq=`basename $0`
-echo "QA output created by $seq"
-
-here=`pwd`
-tmp=/tmp/$$
-status=1	# failure is the default!
-
-_cleanup()
-{
-	_cleanup_test_img
-}
-trap "_cleanup; exit \$status" 0 1 2 3 15
-
-# get standard environment, filters and checks
-. ./common.rc
-. ./common.filter
-
-_supported_fmt raw
-_supported_proto file sheepdog nfs
-_supported_os Linux
-
-
-# No -f, use probing for the protocol driver
-QEMU_IO_PROTO="$QEMU_IO_PROG -g --cache $CACHEMODE"
-
-size=128M
-_make_test_img $size
-
-echo
-echo "== reading at EOF =="
-$QEMU_IO_PROTO -c "read -P 0 $size 512" "$TEST_IMG" | _filter_qemu_io
-
-echo
-echo "== reading far past EOF =="
-$QEMU_IO_PROTO -c "read -P 0 256M 512" "$TEST_IMG" | _filter_qemu_io
-
-echo
-echo "== writing at EOF =="
-$QEMU_IO_PROTO -c "write -P 66 $size 512" "$TEST_IMG" | _filter_qemu_io
-$QEMU_IO -c "read -P 66 $size 512" "$TEST_IMG" | _filter_qemu_io
-
-echo
-echo "== writing far past EOF =="
-$QEMU_IO_PROTO -c "write -P 66 256M 512" "$TEST_IMG" | _filter_qemu_io
-$QEMU_IO -c "read -P 66 256M 512" "$TEST_IMG" | _filter_qemu_io
-
-# success, all done
-echo "*** done"
-rm -f $seq.full
-status=0
diff --git a/tests/qemu-iotests/016.out b/tests/qemu-iotests/016.out
deleted file mode 100644
index acbd60b..0000000
--- a/tests/qemu-iotests/016.out
+++ /dev/null
@@ -1,23 +0,0 @@
-QA output created by 016
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
-
-== reading at EOF ==
-read 512/512 bytes at offset 134217728
-512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-
-== reading far past EOF ==
-read 512/512 bytes at offset 268435456
-512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-
-== writing at EOF ==
-wrote 512/512 bytes at offset 134217728
-512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-read 512/512 bytes at offset 134217728
-512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-
-== writing far past EOF ==
-wrote 512/512 bytes at offset 268435456
-512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-read 512/512 bytes at offset 268435456
-512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 86f072e..0d3b95c 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -22,7 +22,7 @@
 013 rw auto
 014 rw auto
 015 rw snapshot auto
-016 rw auto quick
+# 016 was removed, do not reuse
 017 rw backing auto quick
 018 rw backing auto quick
 019 rw backing auto quick
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 62/65] qemu-io: Use BlockBackend
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (60 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 61/65] qemu-io: Remove "growable" option Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 63/65] block: Clamp BlockBackend requests Stefan Hajnoczi
                   ` (3 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

qemu-io should behave like a guest, therefore it should use BlockBackend
to access the block layer.

There are a couple of places where that is infeasible: First, the
bdrv_debug_* functions could theoretically be mirrored in the
BlockBackend, but since these are functions internal to the block layer,
they should not be visible externally (qemu-io as a test tool is exempt
from this).

Second, bdrv_get_info() and bdrv_get_specific_info() work on a single
BDS alone, therefore they should stay BDS-specific.

Third, bdrv_is_allocated() mainly works on a single BDS as well. Some
data may be passed through from the BDS's file (if sectors which are
apparently allocated in the file are not really allocated there but just
zero).

[Fixed conflicts around block_acct_start() usage from Fam Zheng's
"qemu-io: Account IO by aio_read and aio_write" commit.  Use
BlockBackend and blk_get_stats() instead of BlockDriverState.
--Stefan]

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1423162705-32065-14-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 hmp.c             |   9 +-
 include/qemu-io.h |   4 +-
 qemu-io-cmds.c    | 253 ++++++++++++++++++++++++++++--------------------------
 qemu-io.c         |  15 ++--
 4 files changed, 146 insertions(+), 135 deletions(-)

diff --git a/hmp.c b/hmp.c
index b47f331..3825b29 100644
--- a/hmp.c
+++ b/hmp.c
@@ -16,6 +16,7 @@
 #include "hmp.h"
 #include "net/net.h"
 #include "sysemu/char.h"
+#include "sysemu/block-backend.h"
 #include "qemu/option.h"
 #include "qemu/timer.h"
 #include "qmp-commands.h"
@@ -1720,14 +1721,14 @@ void hmp_chardev_remove(Monitor *mon, const QDict *qdict)
 
 void hmp_qemu_io(Monitor *mon, const QDict *qdict)
 {
-    BlockDriverState *bs;
+    BlockBackend *blk;
     const char* device = qdict_get_str(qdict, "device");
     const char* command = qdict_get_str(qdict, "command");
     Error *err = NULL;
 
-    bs = bdrv_find(device);
-    if (bs) {
-        qemuio_command(bs, command);
+    blk = blk_by_name(device);
+    if (blk) {
+        qemuio_command(blk, command);
     } else {
         error_set(&err, QERR_DEVICE_NOT_FOUND, device);
     }
diff --git a/include/qemu-io.h b/include/qemu-io.h
index 5d6006f..4d402b9 100644
--- a/include/qemu-io.h
+++ b/include/qemu-io.h
@@ -22,7 +22,7 @@
 
 #define CMD_FLAG_GLOBAL ((int)0x80000000) /* don't iterate "args" */
 
-typedef int (*cfunc_t)(BlockDriverState *bs, int argc, char **argv);
+typedef int (*cfunc_t)(BlockBackend *blk, int argc, char **argv);
 typedef void (*helpfunc_t)(void);
 
 typedef struct cmdinfo {
@@ -40,7 +40,7 @@ typedef struct cmdinfo {
 
 extern bool qemuio_misalign;
 
-bool qemuio_command(BlockDriverState *bs, const char *cmd);
+bool qemuio_command(BlockBackend *blk, const char *cmd);
 
 void qemuio_add_command(const cmdinfo_t *ci);
 int qemuio_command_usage(const cmdinfo_t *ci);
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 29377cd..1afcfc0 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -9,7 +9,9 @@
  */
 
 #include "qemu-io.h"
-#include "block/block_int.h"
+#include "sysemu/block-backend.h"
+#include "block/block.h"
+#include "block/block_int.h" /* for info_f() */
 #include "block/qapi.h"
 #include "qemu/main-loop.h"
 #include "qemu/timer.h"
@@ -41,24 +43,24 @@ int qemuio_command_usage(const cmdinfo_t *ci)
     return 0;
 }
 
-static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct)
+static int init_check_command(BlockBackend *blk, const cmdinfo_t *ct)
 {
     if (ct->flags & CMD_FLAG_GLOBAL) {
         return 1;
     }
-    if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
+    if (!(ct->flags & CMD_NOFILE_OK) && !blk) {
         fprintf(stderr, "no file open, try 'help open'\n");
         return 0;
     }
     return 1;
 }
 
-static int command(BlockDriverState *bs, const cmdinfo_t *ct, int argc,
+static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc,
                    char **argv)
 {
     char *cmd = argv[0];
 
-    if (!init_check_command(bs, ct)) {
+    if (!init_check_command(blk, ct)) {
         return 0;
     }
 
@@ -79,7 +81,7 @@ static int command(BlockDriverState *bs, const cmdinfo_t *ct, int argc,
         return 0;
     }
     optind = 0;
-    return ct->cfunc(bs, argc, argv);
+    return ct->cfunc(blk, argc, argv);
 }
 
 static const cmdinfo_t *find_command(const char *cmd)
@@ -268,14 +270,14 @@ static int parse_pattern(const char *arg)
  */
 
 #define MISALIGN_OFFSET     16
-static void *qemu_io_alloc(BlockDriverState *bs, size_t len, int pattern)
+static void *qemu_io_alloc(BlockBackend *blk, size_t len, int pattern)
 {
     void *buf;
 
     if (qemuio_misalign) {
         len += MISALIGN_OFFSET;
     }
-    buf = qemu_blockalign(bs, len);
+    buf = blk_blockalign(blk, len);
     memset(buf, pattern, len);
     if (qemuio_misalign) {
         buf += MISALIGN_OFFSET;
@@ -341,7 +343,7 @@ static void print_report(const char *op, struct timeval *t, int64_t offset,
  * vector matching it.
  */
 static void *
-create_iovec(BlockDriverState *bs, QEMUIOVector *qiov, char **argv, int nr_iov,
+create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov,
              int pattern)
 {
     size_t *sizes = g_new0(size_t, nr_iov);
@@ -378,7 +380,7 @@ create_iovec(BlockDriverState *bs, QEMUIOVector *qiov, char **argv, int nr_iov,
 
     qemu_iovec_init(qiov, nr_iov);
 
-    buf = p = qemu_io_alloc(bs, count, pattern);
+    buf = p = qemu_io_alloc(blk, count, pattern);
 
     for (i = 0; i < nr_iov; i++) {
         qemu_iovec_add(qiov, p, sizes[i]);
@@ -390,12 +392,12 @@ fail:
     return buf;
 }
 
-static int do_read(BlockDriverState *bs, char *buf, int64_t offset, int count,
+static int do_read(BlockBackend *blk, char *buf, int64_t offset, int count,
                    int *total)
 {
     int ret;
 
-    ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+    ret = blk_read(blk, offset >> 9, (uint8_t *)buf, count >> 9);
     if (ret < 0) {
         return ret;
     }
@@ -403,12 +405,12 @@ static int do_read(BlockDriverState *bs, char *buf, int64_t offset, int count,
     return 1;
 }
 
-static int do_write(BlockDriverState *bs, char *buf, int64_t offset, int count,
+static int do_write(BlockBackend *blk, char *buf, int64_t offset, int count,
                     int *total)
 {
     int ret;
 
-    ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+    ret = blk_write(blk, offset >> 9, (uint8_t *)buf, count >> 9);
     if (ret < 0) {
         return ret;
     }
@@ -416,20 +418,20 @@ static int do_write(BlockDriverState *bs, char *buf, int64_t offset, int count,
     return 1;
 }
 
-static int do_pread(BlockDriverState *bs, char *buf, int64_t offset, int count,
+static int do_pread(BlockBackend *blk, char *buf, int64_t offset, int count,
                     int *total)
 {
-    *total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
+    *total = blk_pread(blk, offset, (uint8_t *)buf, count);
     if (*total < 0) {
         return *total;
     }
     return 1;
 }
 
-static int do_pwrite(BlockDriverState *bs, char *buf, int64_t offset, int count,
+static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset, int count,
                      int *total)
 {
-    *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
+    *total = blk_pwrite(blk, offset, (uint8_t *)buf, count);
     if (*total < 0) {
         return *total;
     }
@@ -437,7 +439,7 @@ static int do_pwrite(BlockDriverState *bs, char *buf, int64_t offset, int count,
 }
 
 typedef struct {
-    BlockDriverState *bs;
+    BlockBackend *blk;
     int64_t offset;
     int count;
     int *total;
@@ -449,8 +451,8 @@ static void coroutine_fn co_write_zeroes_entry(void *opaque)
 {
     CoWriteZeroes *data = opaque;
 
-    data->ret = bdrv_co_write_zeroes(data->bs, data->offset / BDRV_SECTOR_SIZE,
-                                     data->count / BDRV_SECTOR_SIZE, 0);
+    data->ret = blk_co_write_zeroes(data->blk, data->offset / BDRV_SECTOR_SIZE,
+                                    data->count / BDRV_SECTOR_SIZE, 0);
     data->done = true;
     if (data->ret < 0) {
         *data->total = data->ret;
@@ -460,12 +462,12 @@ static void coroutine_fn co_write_zeroes_entry(void *opaque)
     *data->total = data->count;
 }
 
-static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count,
+static int do_co_write_zeroes(BlockBackend *blk, int64_t offset, int count,
                               int *total)
 {
     Coroutine *co;
     CoWriteZeroes data = {
-        .bs     = bs,
+        .blk    = blk,
         .offset = offset,
         .count  = count,
         .total  = total,
@@ -475,7 +477,7 @@ static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count,
     co = qemu_coroutine_create(co_write_zeroes_entry);
     qemu_coroutine_enter(co, &data);
     while (!data.done) {
-        aio_poll(bdrv_get_aio_context(bs), true);
+        aio_poll(blk_get_aio_context(blk), true);
     }
     if (data.ret < 0) {
         return data.ret;
@@ -484,12 +486,12 @@ static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count,
     }
 }
 
-static int do_write_compressed(BlockDriverState *bs, char *buf, int64_t offset,
+static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset,
                                int count, int *total)
 {
     int ret;
 
-    ret = bdrv_write_compressed(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+    ret = blk_write_compressed(blk, offset >> 9, (uint8_t *)buf, count >> 9);
     if (ret < 0) {
         return ret;
     }
@@ -497,20 +499,20 @@ static int do_write_compressed(BlockDriverState *bs, char *buf, int64_t offset,
     return 1;
 }
 
-static int do_load_vmstate(BlockDriverState *bs, char *buf, int64_t offset,
+static int do_load_vmstate(BlockBackend *blk, char *buf, int64_t offset,
                            int count, int *total)
 {
-    *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
+    *total = blk_load_vmstate(blk, (uint8_t *)buf, offset, count);
     if (*total < 0) {
         return *total;
     }
     return 1;
 }
 
-static int do_save_vmstate(BlockDriverState *bs, char *buf, int64_t offset,
+static int do_save_vmstate(BlockBackend *blk, char *buf, int64_t offset,
                            int count, int *total)
 {
-    *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count);
+    *total = blk_save_vmstate(blk, (uint8_t *)buf, offset, count);
     if (*total < 0) {
         return *total;
     }
@@ -523,13 +525,13 @@ static void aio_rw_done(void *opaque, int ret)
     *(int *)opaque = ret;
 }
 
-static int do_aio_readv(BlockDriverState *bs, QEMUIOVector *qiov,
+static int do_aio_readv(BlockBackend *blk, QEMUIOVector *qiov,
                         int64_t offset, int *total)
 {
     int async_ret = NOT_DONE;
 
-    bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
-                   aio_rw_done, &async_ret);
+    blk_aio_readv(blk, offset >> 9, qiov, qiov->size >> 9,
+                  aio_rw_done, &async_ret);
     while (async_ret == NOT_DONE) {
         main_loop_wait(false);
     }
@@ -538,13 +540,13 @@ static int do_aio_readv(BlockDriverState *bs, QEMUIOVector *qiov,
     return async_ret < 0 ? async_ret : 1;
 }
 
-static int do_aio_writev(BlockDriverState *bs, QEMUIOVector *qiov,
+static int do_aio_writev(BlockBackend *blk, QEMUIOVector *qiov,
                          int64_t offset, int *total)
 {
     int async_ret = NOT_DONE;
 
-    bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
-                    aio_rw_done, &async_ret);
+    blk_aio_writev(blk, offset >> 9, qiov, qiov->size >> 9,
+                   aio_rw_done, &async_ret);
     while (async_ret == NOT_DONE) {
         main_loop_wait(false);
     }
@@ -568,7 +570,7 @@ static void multiwrite_cb(void *opaque, int ret)
     }
 }
 
-static int do_aio_multiwrite(BlockDriverState *bs, BlockRequest* reqs,
+static int do_aio_multiwrite(BlockBackend *blk, BlockRequest* reqs,
                              int num_reqs, int *total)
 {
     int i, ret;
@@ -584,7 +586,7 @@ static int do_aio_multiwrite(BlockDriverState *bs, BlockRequest* reqs,
         *total += reqs[i].qiov->size;
     }
 
-    ret = bdrv_aio_multiwrite(bs, reqs, num_reqs);
+    ret = blk_aio_multiwrite(blk, reqs, num_reqs);
     if (ret < 0) {
         return ret;
     }
@@ -610,7 +612,7 @@ static void read_help(void)
 " -b, -- read from the VM state rather than the virtual disk\n"
 " -C, -- report statistics in a machine parsable format\n"
 " -l, -- length for pattern verification (only with -P)\n"
-" -p, -- use bdrv_pread to read the file\n"
+" -p, -- use blk_pread to read the file\n"
 " -P, -- use a pattern to verify read data\n"
 " -q, -- quiet mode, do not show I/O statistics\n"
 " -s, -- start offset for pattern verification (only with -P)\n"
@@ -618,7 +620,7 @@ static void read_help(void)
 "\n");
 }
 
-static int read_f(BlockDriverState *bs, int argc, char **argv);
+static int read_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t read_cmd = {
     .name       = "read",
@@ -631,7 +633,7 @@ static const cmdinfo_t read_cmd = {
     .help       = read_help,
 };
 
-static int read_f(BlockDriverState *bs, int argc, char **argv)
+static int read_f(BlockBackend *blk, int argc, char **argv)
 {
     struct timeval t1, t2;
     int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
@@ -737,15 +739,15 @@ static int read_f(BlockDriverState *bs, int argc, char **argv)
         }
     }
 
-    buf = qemu_io_alloc(bs, count, 0xab);
+    buf = qemu_io_alloc(blk, count, 0xab);
 
     gettimeofday(&t1, NULL);
     if (pflag) {
-        cnt = do_pread(bs, buf, offset, count, &total);
+        cnt = do_pread(blk, buf, offset, count, &total);
     } else if (bflag) {
-        cnt = do_load_vmstate(bs, buf, offset, count, &total);
+        cnt = do_load_vmstate(blk, buf, offset, count, &total);
     } else {
-        cnt = do_read(bs, buf, offset, count, &total);
+        cnt = do_read(blk, buf, offset, count, &total);
     }
     gettimeofday(&t2, NULL);
 
@@ -802,7 +804,7 @@ static void readv_help(void)
 "\n");
 }
 
-static int readv_f(BlockDriverState *bs, int argc, char **argv);
+static int readv_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t readv_cmd = {
     .name       = "readv",
@@ -814,7 +816,7 @@ static const cmdinfo_t readv_cmd = {
     .help       = readv_help,
 };
 
-static int readv_f(BlockDriverState *bs, int argc, char **argv)
+static int readv_f(BlockBackend *blk, int argc, char **argv)
 {
     struct timeval t1, t2;
     int Cflag = 0, qflag = 0, vflag = 0;
@@ -870,13 +872,13 @@ static int readv_f(BlockDriverState *bs, int argc, char **argv)
     }
 
     nr_iov = argc - optind;
-    buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, 0xab);
+    buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab);
     if (buf == NULL) {
         return 0;
     }
 
     gettimeofday(&t1, NULL);
-    cnt = do_aio_readv(bs, &qiov, offset, &total);
+    cnt = do_aio_readv(blk, &qiov, offset, &total);
     gettimeofday(&t2, NULL);
 
     if (cnt < 0) {
@@ -924,16 +926,16 @@ static void write_help(void)
 " Writes into a segment of the currently open file, using a buffer\n"
 " filled with a set pattern (0xcdcdcdcd).\n"
 " -b, -- write to the VM state rather than the virtual disk\n"
-" -c, -- write compressed data with bdrv_write_compressed\n"
-" -p, -- use bdrv_pwrite to write the file\n"
+" -c, -- write compressed data with blk_write_compressed\n"
+" -p, -- use blk_pwrite to write the file\n"
 " -P, -- use different pattern to fill file\n"
 " -C, -- report statistics in a machine parsable format\n"
 " -q, -- quiet mode, do not show I/O statistics\n"
-" -z, -- write zeroes using bdrv_co_write_zeroes\n"
+" -z, -- write zeroes using blk_co_write_zeroes\n"
 "\n");
 }
 
-static int write_f(BlockDriverState *bs, int argc, char **argv);
+static int write_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t write_cmd = {
     .name       = "write",
@@ -946,7 +948,7 @@ static const cmdinfo_t write_cmd = {
     .help       = write_help,
 };
 
-static int write_f(BlockDriverState *bs, int argc, char **argv)
+static int write_f(BlockBackend *blk, int argc, char **argv)
 {
     struct timeval t1, t2;
     int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0;
@@ -1033,20 +1035,20 @@ static int write_f(BlockDriverState *bs, int argc, char **argv)
     }
 
     if (!zflag) {
-        buf = qemu_io_alloc(bs, count, pattern);
+        buf = qemu_io_alloc(blk, count, pattern);
     }
 
     gettimeofday(&t1, NULL);
     if (pflag) {
-        cnt = do_pwrite(bs, buf, offset, count, &total);
+        cnt = do_pwrite(blk, buf, offset, count, &total);
     } else if (bflag) {
-        cnt = do_save_vmstate(bs, buf, offset, count, &total);
+        cnt = do_save_vmstate(blk, buf, offset, count, &total);
     } else if (zflag) {
-        cnt = do_co_write_zeroes(bs, offset, count, &total);
+        cnt = do_co_write_zeroes(blk, offset, count, &total);
     } else if (cflag) {
-        cnt = do_write_compressed(bs, buf, offset, count, &total);
+        cnt = do_write_compressed(blk, buf, offset, count, &total);
     } else {
-        cnt = do_write(bs, buf, offset, count, &total);
+        cnt = do_write(blk, buf, offset, count, &total);
     }
     gettimeofday(&t2, NULL);
 
@@ -1089,7 +1091,7 @@ writev_help(void)
 "\n");
 }
 
-static int writev_f(BlockDriverState *bs, int argc, char **argv);
+static int writev_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t writev_cmd = {
     .name       = "writev",
@@ -1101,7 +1103,7 @@ static const cmdinfo_t writev_cmd = {
     .help       = writev_help,
 };
 
-static int writev_f(BlockDriverState *bs, int argc, char **argv)
+static int writev_f(BlockBackend *blk, int argc, char **argv)
 {
     struct timeval t1, t2;
     int Cflag = 0, qflag = 0;
@@ -1151,13 +1153,13 @@ static int writev_f(BlockDriverState *bs, int argc, char **argv)
     }
 
     nr_iov = argc - optind;
-    buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, pattern);
+    buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern);
     if (buf == NULL) {
         return 0;
     }
 
     gettimeofday(&t1, NULL);
-    cnt = do_aio_writev(bs, &qiov, offset, &total);
+    cnt = do_aio_writev(blk, &qiov, offset, &total);
     gettimeofday(&t2, NULL);
 
     if (cnt < 0) {
@@ -1198,7 +1200,7 @@ static void multiwrite_help(void)
 "\n");
 }
 
-static int multiwrite_f(BlockDriverState *bs, int argc, char **argv);
+static int multiwrite_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t multiwrite_cmd = {
     .name       = "multiwrite",
@@ -1210,7 +1212,7 @@ static const cmdinfo_t multiwrite_cmd = {
     .help       = multiwrite_help,
 };
 
-static int multiwrite_f(BlockDriverState *bs, int argc, char **argv)
+static int multiwrite_f(BlockBackend *blk, int argc, char **argv)
 {
     struct timeval t1, t2;
     int Cflag = 0, qflag = 0;
@@ -1291,7 +1293,7 @@ static int multiwrite_f(BlockDriverState *bs, int argc, char **argv)
         nr_iov = j - optind;
 
         /* Build request */
-        buf[i] = create_iovec(bs, &qiovs[i], &argv[optind], nr_iov, pattern);
+        buf[i] = create_iovec(blk, &qiovs[i], &argv[optind], nr_iov, pattern);
         if (buf[i] == NULL) {
             goto out;
         }
@@ -1309,7 +1311,7 @@ static int multiwrite_f(BlockDriverState *bs, int argc, char **argv)
     nr_reqs = i;
 
     gettimeofday(&t1, NULL);
-    cnt = do_aio_multiwrite(bs, reqs, nr_reqs, &total);
+    cnt = do_aio_multiwrite(blk, reqs, nr_reqs, &total);
     gettimeofday(&t2, NULL);
 
     if (cnt < 0) {
@@ -1338,7 +1340,7 @@ out:
 }
 
 struct aio_ctx {
-    BlockDriverState *bs;
+    BlockBackend *blk;
     QEMUIOVector qiov;
     int64_t offset;
     char *buf;
@@ -1364,7 +1366,7 @@ static void aio_write_done(void *opaque, int ret)
         goto out;
     }
 
-    block_acct_done(&ctx->bs->stats, &ctx->acct);
+    block_acct_done(blk_get_stats(ctx->blk), &ctx->acct);
 
     if (ctx->qflag) {
         goto out;
@@ -1403,7 +1405,7 @@ static void aio_read_done(void *opaque, int ret)
         g_free(cmp_buf);
     }
 
-    block_acct_done(&ctx->bs->stats, &ctx->acct);
+    block_acct_done(blk_get_stats(ctx->blk), &ctx->acct);
 
     if (ctx->qflag) {
         goto out;
@@ -1443,7 +1445,7 @@ static void aio_read_help(void)
 "\n");
 }
 
-static int aio_read_f(BlockDriverState *bs, int argc, char **argv);
+static int aio_read_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t aio_read_cmd = {
     .name       = "aio_read",
@@ -1455,12 +1457,12 @@ static const cmdinfo_t aio_read_cmd = {
     .help       = aio_read_help,
 };
 
-static int aio_read_f(BlockDriverState *bs, int argc, char **argv)
+static int aio_read_f(BlockBackend *blk, int argc, char **argv)
 {
     int nr_iov, c;
     struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
 
-    ctx->bs = bs;
+    ctx->blk = blk;
     while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
         switch (c) {
         case 'C':
@@ -1507,16 +1509,17 @@ static int aio_read_f(BlockDriverState *bs, int argc, char **argv)
     }
 
     nr_iov = argc - optind;
-    ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, 0xab);
+    ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab);
     if (ctx->buf == NULL) {
         g_free(ctx);
         return 0;
     }
 
     gettimeofday(&ctx->t1, NULL);
-    block_acct_start(&bs->stats, &ctx->acct, ctx->qiov.size, BLOCK_ACCT_READ);
-    bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
-                   ctx->qiov.size >> 9, aio_read_done, ctx);
+    block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
+                     BLOCK_ACCT_READ);
+    blk_aio_readv(blk, ctx->offset >> 9, &ctx->qiov,
+                  ctx->qiov.size >> 9, aio_read_done, ctx);
     return 0;
 }
 
@@ -1540,7 +1543,7 @@ static void aio_write_help(void)
 "\n");
 }
 
-static int aio_write_f(BlockDriverState *bs, int argc, char **argv);
+static int aio_write_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t aio_write_cmd = {
     .name       = "aio_write",
@@ -1552,13 +1555,13 @@ static const cmdinfo_t aio_write_cmd = {
     .help       = aio_write_help,
 };
 
-static int aio_write_f(BlockDriverState *bs, int argc, char **argv)
+static int aio_write_f(BlockBackend *blk, int argc, char **argv)
 {
     int nr_iov, c;
     int pattern = 0xcd;
     struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
 
-    ctx->bs = bs;
+    ctx->blk = blk;
     while ((c = getopt(argc, argv, "CqP:")) != EOF) {
         switch (c) {
         case 'C':
@@ -1601,22 +1604,23 @@ static int aio_write_f(BlockDriverState *bs, int argc, char **argv)
     }
 
     nr_iov = argc - optind;
-    ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, pattern);
+    ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, pattern);
     if (ctx->buf == NULL) {
         g_free(ctx);
         return 0;
     }
 
     gettimeofday(&ctx->t1, NULL);
-    block_acct_start(&bs->stats, &ctx->acct, ctx->qiov.size, BLOCK_ACCT_WRITE);
-    bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
-                    ctx->qiov.size >> 9, aio_write_done, ctx);
+    block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
+                     BLOCK_ACCT_WRITE);
+    blk_aio_writev(blk, ctx->offset >> 9, &ctx->qiov,
+                   ctx->qiov.size >> 9, aio_write_done, ctx);
     return 0;
 }
 
-static int aio_flush_f(BlockDriverState *bs, int argc, char **argv)
+static int aio_flush_f(BlockBackend *blk, int argc, char **argv)
 {
-    bdrv_drain_all();
+    blk_drain_all();
     return 0;
 }
 
@@ -1626,9 +1630,9 @@ static const cmdinfo_t aio_flush_cmd = {
     .oneline    = "completes all outstanding aio requests"
 };
 
-static int flush_f(BlockDriverState *bs, int argc, char **argv)
+static int flush_f(BlockBackend *blk, int argc, char **argv)
 {
-    bdrv_flush(bs);
+    blk_flush(blk);
     return 0;
 }
 
@@ -1639,7 +1643,7 @@ static const cmdinfo_t flush_cmd = {
     .oneline    = "flush all in-core file state to disk",
 };
 
-static int truncate_f(BlockDriverState *bs, int argc, char **argv)
+static int truncate_f(BlockBackend *blk, int argc, char **argv)
 {
     int64_t offset;
     int ret;
@@ -1650,7 +1654,7 @@ static int truncate_f(BlockDriverState *bs, int argc, char **argv)
         return 0;
     }
 
-    ret = bdrv_truncate(bs, offset);
+    ret = blk_truncate(blk, offset);
     if (ret < 0) {
         printf("truncate: %s\n", strerror(-ret));
         return 0;
@@ -1669,12 +1673,12 @@ static const cmdinfo_t truncate_cmd = {
     .oneline    = "truncates the current file at the given offset",
 };
 
-static int length_f(BlockDriverState *bs, int argc, char **argv)
+static int length_f(BlockBackend *blk, int argc, char **argv)
 {
     int64_t size;
     char s1[64];
 
-    size = bdrv_getlength(bs);
+    size = blk_getlength(blk);
     if (size < 0) {
         printf("getlength: %s\n", strerror(-size));
         return 0;
@@ -1694,8 +1698,9 @@ static const cmdinfo_t length_cmd = {
 };
 
 
-static int info_f(BlockDriverState *bs, int argc, char **argv)
+static int info_f(BlockBackend *blk, int argc, char **argv)
 {
+    BlockDriverState *bs = blk_bs(blk);
     BlockDriverInfo bdi;
     ImageInfoSpecific *spec_info;
     char s1[64], s2[64];
@@ -1753,7 +1758,7 @@ static void discard_help(void)
 "\n");
 }
 
-static int discard_f(BlockDriverState *bs, int argc, char **argv);
+static int discard_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t discard_cmd = {
     .name       = "discard",
@@ -1766,7 +1771,7 @@ static const cmdinfo_t discard_cmd = {
     .help       = discard_help,
 };
 
-static int discard_f(BlockDriverState *bs, int argc, char **argv)
+static int discard_f(BlockBackend *blk, int argc, char **argv)
 {
     struct timeval t1, t2;
     int Cflag = 0, qflag = 0;
@@ -1805,8 +1810,8 @@ static int discard_f(BlockDriverState *bs, int argc, char **argv)
     }
 
     gettimeofday(&t1, NULL);
-    ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS,
-                       count >> BDRV_SECTOR_BITS);
+    ret = blk_discard(blk, offset >> BDRV_SECTOR_BITS,
+                      count >> BDRV_SECTOR_BITS);
     gettimeofday(&t2, NULL);
 
     if (ret < 0) {
@@ -1824,8 +1829,9 @@ out:
     return 0;
 }
 
-static int alloc_f(BlockDriverState *bs, int argc, char **argv)
+static int alloc_f(BlockBackend *blk, int argc, char **argv)
 {
+    BlockDriverState *bs = blk_bs(blk);
     int64_t offset, sector_num;
     int nb_sectors, remaining;
     char s1[64];
@@ -1921,20 +1927,27 @@ static int map_is_allocated(BlockDriverState *bs, int64_t sector_num,
     return firstret;
 }
 
-static int map_f(BlockDriverState *bs, int argc, char **argv)
+static int map_f(BlockBackend *blk, int argc, char **argv)
 {
     int64_t offset;
-    int64_t nb_sectors;
+    int64_t nb_sectors, total_sectors;
     char s1[64];
     int64_t num;
     int ret;
     const char *retstr;
 
     offset = 0;
-    nb_sectors = bs->total_sectors;
+    total_sectors = blk_nb_sectors(blk);
+    if (total_sectors < 0) {
+        error_report("Failed to query image length: %s",
+                     strerror(-total_sectors));
+        return 0;
+    }
+
+    nb_sectors = total_sectors;
 
     do {
-        ret = map_is_allocated(bs, offset, nb_sectors, &num);
+        ret = map_is_allocated(blk_bs(blk), offset, nb_sectors, &num);
         if (ret < 0) {
             error_report("Failed to get allocation status: %s", strerror(-ret));
             return 0;
@@ -1951,7 +1964,7 @@ static int map_f(BlockDriverState *bs, int argc, char **argv)
 
         offset += num;
         nb_sectors -= num;
-    } while (offset < bs->total_sectors);
+    } while (offset < total_sectors);
 
     return 0;
 }
@@ -1965,11 +1978,11 @@ static const cmdinfo_t map_cmd = {
        .oneline        = "prints the allocated areas of a file",
 };
 
-static int break_f(BlockDriverState *bs, int argc, char **argv)
+static int break_f(BlockBackend *blk, int argc, char **argv)
 {
     int ret;
 
-    ret = bdrv_debug_breakpoint(bs, argv[1], argv[2]);
+    ret = bdrv_debug_breakpoint(blk_bs(blk), argv[1], argv[2]);
     if (ret < 0) {
         printf("Could not set breakpoint: %s\n", strerror(-ret));
     }
@@ -1977,11 +1990,11 @@ static int break_f(BlockDriverState *bs, int argc, char **argv)
     return 0;
 }
 
-static int remove_break_f(BlockDriverState *bs, int argc, char **argv)
+static int remove_break_f(BlockBackend *blk, int argc, char **argv)
 {
     int ret;
 
-    ret = bdrv_debug_remove_breakpoint(bs, argv[1]);
+    ret = bdrv_debug_remove_breakpoint(blk_bs(blk), argv[1]);
     if (ret < 0) {
         printf("Could not remove breakpoint %s: %s\n", argv[1], strerror(-ret));
     }
@@ -2008,11 +2021,11 @@ static const cmdinfo_t remove_break_cmd = {
        .oneline        = "remove a breakpoint by tag",
 };
 
-static int resume_f(BlockDriverState *bs, int argc, char **argv)
+static int resume_f(BlockBackend *blk, int argc, char **argv)
 {
     int ret;
 
-    ret = bdrv_debug_resume(bs, argv[1]);
+    ret = bdrv_debug_resume(blk_bs(blk), argv[1]);
     if (ret < 0) {
         printf("Could not resume request: %s\n", strerror(-ret));
     }
@@ -2029,10 +2042,10 @@ static const cmdinfo_t resume_cmd = {
        .oneline        = "resumes the request tagged as tag",
 };
 
-static int wait_break_f(BlockDriverState *bs, int argc, char **argv)
+static int wait_break_f(BlockBackend *blk, int argc, char **argv)
 {
-    while (!bdrv_debug_is_suspended(bs, argv[1])) {
-        aio_poll(bdrv_get_aio_context(bs), true);
+    while (!bdrv_debug_is_suspended(blk_bs(blk), argv[1])) {
+        aio_poll(blk_get_aio_context(blk), true);
     }
 
     return 0;
@@ -2047,7 +2060,7 @@ static const cmdinfo_t wait_break_cmd = {
        .oneline        = "waits for the suspension of a request",
 };
 
-static int abort_f(BlockDriverState *bs, int argc, char **argv)
+static int abort_f(BlockBackend *blk, int argc, char **argv)
 {
     abort();
 }
@@ -2073,7 +2086,7 @@ static void sigraise_help(void)
 "\n", SIGTERM);
 }
 
-static int sigraise_f(BlockDriverState *bs, int argc, char **argv);
+static int sigraise_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t sigraise_cmd = {
     .name       = "sigraise",
@@ -2086,7 +2099,7 @@ static const cmdinfo_t sigraise_cmd = {
     .help       = sigraise_help,
 };
 
-static int sigraise_f(BlockDriverState *bs, int argc, char **argv)
+static int sigraise_f(BlockBackend *blk, int argc, char **argv)
 {
     int sig = cvtnum(argv[1]);
     if (sig < 0) {
@@ -2110,7 +2123,7 @@ static void sleep_cb(void *opaque)
     *expired = true;
 }
 
-static int sleep_f(BlockDriverState *bs, int argc, char **argv)
+static int sleep_f(BlockBackend *blk, int argc, char **argv)
 {
     char *endptr;
     long ms;
@@ -2179,7 +2192,7 @@ static void help_all(void)
     printf("\nUse 'help commandname' for extended help.\n");
 }
 
-static int help_f(BlockDriverState *bs, int argc, char **argv)
+static int help_f(BlockBackend *blk, int argc, char **argv)
 {
     const cmdinfo_t *ct;
 
@@ -2209,7 +2222,7 @@ static const cmdinfo_t help_cmd = {
     .oneline    = "help for one or all commands",
 };
 
-bool qemuio_command(BlockDriverState *bs, const char *cmd)
+bool qemuio_command(BlockBackend *blk, const char *cmd)
 {
     char *input;
     const cmdinfo_t *ct;
@@ -2222,7 +2235,7 @@ bool qemuio_command(BlockDriverState *bs, const char *cmd)
     if (c) {
         ct = find_command(v[0]);
         if (ct) {
-            done = command(bs, ct, c, v);
+            done = command(blk, ct, c, v);
         } else {
             fprintf(stderr, "command \"%s\" not found\n", v[0]);
         }
diff --git a/qemu-io.c b/qemu-io.c
index a85522a..4a3e719 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -28,7 +28,6 @@
 static char *progname;
 
 static BlockBackend *qemuio_blk;
-static BlockDriverState *qemuio_bs;
 
 /* qemu-io commands passed using -c */
 static int ncmdline;
@@ -36,10 +35,9 @@ static char **cmdline;
 
 static ReadLineState *readline_state;
 
-static int close_f(BlockDriverState *bs, int argc, char **argv)
+static int close_f(BlockBackend *blk, int argc, char **argv)
 {
     blk_unref(qemuio_blk);
-    qemuio_bs = NULL;
     qemuio_blk = NULL;
     return 0;
 }
@@ -69,7 +67,6 @@ static int openfile(char *name, int flags, QDict *opts)
         error_free(local_err);
         return 1;
     }
-    qemuio_bs = blk_bs(qemuio_blk);
 
     return 0;
 }
@@ -91,7 +88,7 @@ static void open_help(void)
 "\n");
 }
 
-static int open_f(BlockDriverState *bs, int argc, char **argv);
+static int open_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t open_cmd = {
     .name       = "open",
@@ -115,7 +112,7 @@ static QemuOptsList empty_opts = {
     },
 };
 
-static int open_f(BlockDriverState *bs, int argc, char **argv)
+static int open_f(BlockBackend *blk, int argc, char **argv)
 {
     int flags = 0;
     int readonly = 0;
@@ -165,7 +162,7 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
     }
 }
 
-static int quit_f(BlockDriverState *bs, int argc, char **argv)
+static int quit_f(BlockBackend *blk, int argc, char **argv)
 {
     return 1;
 }
@@ -302,7 +299,7 @@ static void command_loop(void)
     char *input;
 
     for (i = 0; !done && i < ncmdline; i++) {
-        done = qemuio_command(qemuio_bs, cmdline[i]);
+        done = qemuio_command(qemuio_blk, cmdline[i]);
     }
     if (cmdline) {
         g_free(cmdline);
@@ -327,7 +324,7 @@ static void command_loop(void)
         if (input == NULL) {
             break;
         }
-        done = qemuio_command(qemuio_bs, input);
+        done = qemuio_command(qemuio_blk, input);
         g_free(input);
 
         prompted = 0;
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 63/65] block: Clamp BlockBackend requests
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (61 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 62/65] qemu-io: Use BlockBackend Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 64/65] block: Remove "growable" from BDS Stefan Hajnoczi
                   ` (2 subsequent siblings)
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

BlockBackend is used as the interface between the block layer and guest
devices. It should therefore assure that all requests are clamped to the
image size.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Message-id: 1423162705-32065-15-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 block/block-backend.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 152 insertions(+)

diff --git a/block/block-backend.c b/block/block-backend.c
index d083b85..aabe569 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -31,6 +31,16 @@ struct BlockBackend {
     void *dev_opaque;
 };
 
+typedef struct BlockBackendAIOCB {
+    BlockAIOCB common;
+    QEMUBH *bh;
+    int ret;
+} BlockBackendAIOCB;
+
+static const AIOCBInfo block_backend_aiocb_info = {
+    .aiocb_size = sizeof(BlockBackendAIOCB),
+};
+
 static void drive_info_del(DriveInfo *dinfo);
 
 /* All the BlockBackends (except for hidden ones) */
@@ -428,39 +438,137 @@ void blk_iostatus_enable(BlockBackend *blk)
     bdrv_iostatus_enable(blk->bs);
 }
 
+static int blk_check_byte_request(BlockBackend *blk, int64_t offset,
+                                  size_t size)
+{
+    int64_t len;
+
+    if (size > INT_MAX) {
+        return -EIO;
+    }
+
+    if (!blk_is_inserted(blk)) {
+        return -ENOMEDIUM;
+    }
+
+    len = blk_getlength(blk);
+    if (len < 0) {
+        return len;
+    }
+
+    if (offset < 0) {
+        return -EIO;
+    }
+
+    if (offset > len || len - offset < size) {
+        return -EIO;
+    }
+
+    return 0;
+}
+
+static int blk_check_request(BlockBackend *blk, int64_t sector_num,
+                             int nb_sectors)
+{
+    if (sector_num < 0 || sector_num > INT64_MAX / BDRV_SECTOR_SIZE) {
+        return -EIO;
+    }
+
+    if (nb_sectors < 0 || nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) {
+        return -EIO;
+    }
+
+    return blk_check_byte_request(blk, sector_num * BDRV_SECTOR_SIZE,
+                                  nb_sectors * BDRV_SECTOR_SIZE);
+}
+
 int blk_read(BlockBackend *blk, int64_t sector_num, uint8_t *buf,
              int nb_sectors)
 {
+    int ret = blk_check_request(blk, sector_num, nb_sectors);
+    if (ret < 0) {
+        return ret;
+    }
+
     return bdrv_read(blk->bs, sector_num, buf, nb_sectors);
 }
 
 int blk_read_unthrottled(BlockBackend *blk, int64_t sector_num, uint8_t *buf,
                          int nb_sectors)
 {
+    int ret = blk_check_request(blk, sector_num, nb_sectors);
+    if (ret < 0) {
+        return ret;
+    }
+
     return bdrv_read_unthrottled(blk->bs, sector_num, buf, nb_sectors);
 }
 
 int blk_write(BlockBackend *blk, int64_t sector_num, const uint8_t *buf,
               int nb_sectors)
 {
+    int ret = blk_check_request(blk, sector_num, nb_sectors);
+    if (ret < 0) {
+        return ret;
+    }
+
     return bdrv_write(blk->bs, sector_num, buf, nb_sectors);
 }
 
+static void error_callback_bh(void *opaque)
+{
+    struct BlockBackendAIOCB *acb = opaque;
+    qemu_bh_delete(acb->bh);
+    acb->common.cb(acb->common.opaque, acb->ret);
+    qemu_aio_unref(acb);
+}
+
+static BlockAIOCB *abort_aio_request(BlockBackend *blk, BlockCompletionFunc *cb,
+                                     void *opaque, int ret)
+{
+    struct BlockBackendAIOCB *acb;
+    QEMUBH *bh;
+
+    acb = blk_aio_get(&block_backend_aiocb_info, blk, cb, opaque);
+    acb->ret = ret;
+
+    bh = aio_bh_new(blk_get_aio_context(blk), error_callback_bh, acb);
+    acb->bh = bh;
+    qemu_bh_schedule(bh);
+
+    return &acb->common;
+}
+
 BlockAIOCB *blk_aio_write_zeroes(BlockBackend *blk, int64_t sector_num,
                                  int nb_sectors, BdrvRequestFlags flags,
                                  BlockCompletionFunc *cb, void *opaque)
 {
+    int ret = blk_check_request(blk, sector_num, nb_sectors);
+    if (ret < 0) {
+        return abort_aio_request(blk, cb, opaque, ret);
+    }
+
     return bdrv_aio_write_zeroes(blk->bs, sector_num, nb_sectors, flags,
                                  cb, opaque);
 }
 
 int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int count)
 {
+    int ret = blk_check_byte_request(blk, offset, count);
+    if (ret < 0) {
+        return ret;
+    }
+
     return bdrv_pread(blk->bs, offset, buf, count);
 }
 
 int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int count)
 {
+    int ret = blk_check_byte_request(blk, offset, count);
+    if (ret < 0) {
+        return ret;
+    }
+
     return bdrv_pwrite(blk->bs, offset, buf, count);
 }
 
@@ -483,6 +591,11 @@ BlockAIOCB *blk_aio_readv(BlockBackend *blk, int64_t sector_num,
                           QEMUIOVector *iov, int nb_sectors,
                           BlockCompletionFunc *cb, void *opaque)
 {
+    int ret = blk_check_request(blk, sector_num, nb_sectors);
+    if (ret < 0) {
+        return abort_aio_request(blk, cb, opaque, ret);
+    }
+
     return bdrv_aio_readv(blk->bs, sector_num, iov, nb_sectors, cb, opaque);
 }
 
@@ -490,6 +603,11 @@ BlockAIOCB *blk_aio_writev(BlockBackend *blk, int64_t sector_num,
                            QEMUIOVector *iov, int nb_sectors,
                            BlockCompletionFunc *cb, void *opaque)
 {
+    int ret = blk_check_request(blk, sector_num, nb_sectors);
+    if (ret < 0) {
+        return abort_aio_request(blk, cb, opaque, ret);
+    }
+
     return bdrv_aio_writev(blk->bs, sector_num, iov, nb_sectors, cb, opaque);
 }
 
@@ -503,6 +621,11 @@ BlockAIOCB *blk_aio_discard(BlockBackend *blk,
                             int64_t sector_num, int nb_sectors,
                             BlockCompletionFunc *cb, void *opaque)
 {
+    int ret = blk_check_request(blk, sector_num, nb_sectors);
+    if (ret < 0) {
+        return abort_aio_request(blk, cb, opaque, ret);
+    }
+
     return bdrv_aio_discard(blk->bs, sector_num, nb_sectors, cb, opaque);
 }
 
@@ -518,6 +641,15 @@ void blk_aio_cancel_async(BlockAIOCB *acb)
 
 int blk_aio_multiwrite(BlockBackend *blk, BlockRequest *reqs, int num_reqs)
 {
+    int i, ret;
+
+    for (i = 0; i < num_reqs; i++) {
+        ret = blk_check_request(blk, reqs[i].sector, reqs[i].nb_sectors);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
     return bdrv_aio_multiwrite(blk->bs, reqs, num_reqs);
 }
 
@@ -534,6 +666,11 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
 
 int blk_co_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors)
 {
+    int ret = blk_check_request(blk, sector_num, nb_sectors);
+    if (ret < 0) {
+        return ret;
+    }
+
     return bdrv_co_discard(blk->bs, sector_num, nb_sectors);
 }
 
@@ -711,12 +848,22 @@ void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk,
 int coroutine_fn blk_co_write_zeroes(BlockBackend *blk, int64_t sector_num,
                                      int nb_sectors, BdrvRequestFlags flags)
 {
+    int ret = blk_check_request(blk, sector_num, nb_sectors);
+    if (ret < 0) {
+        return ret;
+    }
+
     return bdrv_co_write_zeroes(blk->bs, sector_num, nb_sectors, flags);
 }
 
 int blk_write_compressed(BlockBackend *blk, int64_t sector_num,
                          const uint8_t *buf, int nb_sectors)
 {
+    int ret = blk_check_request(blk, sector_num, nb_sectors);
+    if (ret < 0) {
+        return ret;
+    }
+
     return bdrv_write_compressed(blk->bs, sector_num, buf, nb_sectors);
 }
 
@@ -727,6 +874,11 @@ int blk_truncate(BlockBackend *blk, int64_t offset)
 
 int blk_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors)
 {
+    int ret = blk_check_request(blk, sector_num, nb_sectors);
+    if (ret < 0) {
+        return ret;
+    }
+
     return bdrv_discard(blk->bs, sector_num, nb_sectors);
 }
 
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 64/65] block: Remove "growable" from BDS
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (62 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 63/65] block: Clamp BlockBackend requests Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 65/65] block: Keep bdrv_check*_request()'s return value Stefan Hajnoczi
  2015-02-24 13:57 ` [Qemu-devel] [PULL v2 00/65] Block patches Peter Maydell
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

Now that request clamping is done in the BlockBackend, the "growable"
field can be removed from the BlockDriverState. All BDSs are now treated
as being "growable" (that is, they are allowed to grow; they are not
necessarily actually able to).

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1423162705-32065-16-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 block.c                   | 24 +++++++-----------------
 block/qcow2.c             |  6 ------
 block/raw-posix.c         |  2 +-
 block/raw-win32.c         |  2 +-
 block/sheepdog.c          |  2 +-
 include/block/block_int.h |  3 ---
 6 files changed, 10 insertions(+), 29 deletions(-)

diff --git a/block.c b/block.c
index 2edff6c..4d5ae99 100644
--- a/block.c
+++ b/block.c
@@ -972,7 +972,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
     bs->zero_beyond_eof = true;
     open_flags = bdrv_open_flags(bs, flags);
     bs->read_only = !(open_flags & BDRV_O_RDWR);
-    bs->growable = !!(flags & BDRV_O_PROTOCOL);
 
     if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) {
         error_setg(errp,
@@ -1886,7 +1885,6 @@ void bdrv_close(BlockDriverState *bs)
         bs->encrypted = 0;
         bs->valid_key = 0;
         bs->sg = 0;
-        bs->growable = 0;
         bs->zero_beyond_eof = false;
         QDECREF(bs->options);
         bs->options = NULL;
@@ -2646,25 +2644,17 @@ exit:
 static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
                                    size_t size)
 {
-    int64_t len;
-
     if (size > BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS) {
         return -EIO;
     }
 
-    if (!bdrv_is_inserted(bs))
+    if (!bdrv_is_inserted(bs)) {
         return -ENOMEDIUM;
+    }
 
-    if (bs->growable)
-        return 0;
-
-    len = bdrv_getlength(bs);
-
-    if (offset < 0)
-        return -EIO;
-
-    if ((offset > len) || (len - offset < size))
+    if (offset < 0) {
         return -EIO;
+    }
 
     return 0;
 }
@@ -3043,10 +3033,10 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,
     }
 
     /* Forward the request to the BlockDriver */
-    if (!(bs->zero_beyond_eof && bs->growable)) {
+    if (!bs->zero_beyond_eof) {
         ret = drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
     } else {
-        /* Read zeros after EOF of growable BDSes */
+        /* Read zeros after EOF */
         int64_t total_sectors, max_nb_sectors;
 
         total_sectors = bdrv_nb_sectors(bs);
@@ -3323,7 +3313,7 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
 
     block_acct_highest_sector(&bs->stats, sector_num, nb_sectors);
 
-    if (bs->growable && ret >= 0) {
+    if (ret >= 0) {
         bs->total_sectors = MAX(bs->total_sectors, sector_num + nb_sectors);
     }
 
diff --git a/block/qcow2.c b/block/qcow2.c
index 7e614d7..2ed8d95 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2521,15 +2521,12 @@ static int qcow2_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
 {
     BDRVQcowState *s = bs->opaque;
     int64_t total_sectors = bs->total_sectors;
-    int growable = bs->growable;
     bool zero_beyond_eof = bs->zero_beyond_eof;
     int ret;
 
     BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_SAVE);
-    bs->growable = 1;
     bs->zero_beyond_eof = false;
     ret = bdrv_pwritev(bs, qcow2_vm_state_offset(s) + pos, qiov);
-    bs->growable = growable;
     bs->zero_beyond_eof = zero_beyond_eof;
 
     /* bdrv_co_do_writev will have increased the total_sectors value to include
@@ -2544,15 +2541,12 @@ static int qcow2_load_vmstate(BlockDriverState *bs, uint8_t *buf,
                               int64_t pos, int size)
 {
     BDRVQcowState *s = bs->opaque;
-    int growable = bs->growable;
     bool zero_beyond_eof = bs->zero_beyond_eof;
     int ret;
 
     BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_LOAD);
-    bs->growable = 1;
     bs->zero_beyond_eof = false;
     ret = bdrv_pread(bs, qcow2_vm_state_offset(s) + pos, buf, size);
-    bs->growable = growable;
     bs->zero_beyond_eof = zero_beyond_eof;
 
     return ret;
diff --git a/block/raw-posix.c b/block/raw-posix.c
index e474c17..b5f077a 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -1047,7 +1047,7 @@ static int aio_worker(void *arg)
     switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
     case QEMU_AIO_READ:
         ret = handle_aiocb_rw(aiocb);
-        if (ret >= 0 && ret < aiocb->aio_nbytes && aiocb->bs->growable) {
+        if (ret >= 0 && ret < aiocb->aio_nbytes) {
             iov_memset(aiocb->aio_iov, aiocb->aio_niov, ret,
                       0, aiocb->aio_nbytes - ret);
 
diff --git a/block/raw-win32.c b/block/raw-win32.c
index 06243d7..dae5d2f 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -101,7 +101,7 @@ static int aio_worker(void *arg)
     switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
     case QEMU_AIO_READ:
         count = handle_aiocb_rw(aiocb);
-        if (count < aiocb->aio_nbytes && aiocb->bs->growable) {
+        if (count < aiocb->aio_nbytes) {
             /* A short read means that we have reached EOF. Pad the buffer
              * with zeros for bytes after EOF. */
             iov_memset(aiocb->aio_iov, aiocb->aio_niov, count,
diff --git a/block/sheepdog.c b/block/sheepdog.c
index e9b0ca1..b320871 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -2117,7 +2117,7 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
     int64_t offset = (sector_num + nb_sectors) * BDRV_SECTOR_SIZE;
     BDRVSheepdogState *s = bs->opaque;
 
-    if (bs->growable && offset > s->inode.vdi_size) {
+    if (offset > s->inode.vdi_size) {
         ret = sd_truncate(bs, offset);
         if (ret < 0) {
             return ret;
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 7ad1950..b340e7e 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -369,9 +369,6 @@ struct BlockDriverState {
     /* I/O Limits */
     BlockLimits bl;
 
-    /* Whether the disk can expand beyond total_sectors */
-    int growable;
-
     /* Whether produces zeros when read beyond eof */
     bool zero_beyond_eof;
 
-- 
2.1.0

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

* [Qemu-devel] [PULL v2 65/65] block: Keep bdrv_check*_request()'s return value
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (63 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 64/65] block: Remove "growable" from BDS Stefan Hajnoczi
@ 2015-02-16 15:46 ` Stefan Hajnoczi
  2015-02-24 13:57 ` [Qemu-devel] [PULL v2 00/65] Block patches Peter Maydell
  65 siblings, 0 replies; 67+ messages in thread
From: Stefan Hajnoczi @ 2015-02-16 15:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Stefan Hajnoczi, Max Reitz

From: Max Reitz <mreitz@redhat.com>

Do not throw away the value returned by bdrv_check_request() and
bdrv_check_byte_request().

Fix up some coding style issues in the proximity of the affected hunks.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Message-id: 1423162705-32065-17-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 block.c | 35 ++++++++++++++++++++++++-----------
 1 file changed, 24 insertions(+), 11 deletions(-)

diff --git a/block.c b/block.c
index 4d5ae99..9b707e3 100644
--- a/block.c
+++ b/block.c
@@ -3098,8 +3098,10 @@ static int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs,
     if (!drv) {
         return -ENOMEDIUM;
     }
-    if (bdrv_check_byte_request(bs, offset, bytes)) {
-        return -EIO;
+
+    ret = bdrv_check_byte_request(bs, offset, bytes);
+    if (ret < 0) {
+        return ret;
     }
 
     if (bs->copy_on_read) {
@@ -3342,8 +3344,10 @@ static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
     if (bs->read_only) {
         return -EACCES;
     }
-    if (bdrv_check_byte_request(bs, offset, bytes)) {
-        return -EIO;
+
+    ret = bdrv_check_byte_request(bs, offset, bytes);
+    if (ret < 0) {
+        return ret;
     }
 
     /* throttling disk I/O */
@@ -4197,12 +4201,18 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
                           const uint8_t *buf, int nb_sectors)
 {
     BlockDriver *drv = bs->drv;
-    if (!drv)
+    int ret;
+
+    if (!drv) {
         return -ENOMEDIUM;
-    if (!drv->bdrv_write_compressed)
+    }
+    if (!drv->bdrv_write_compressed) {
         return -ENOTSUP;
-    if (bdrv_check_request(bs, sector_num, nb_sectors))
-        return -EIO;
+    }
+    ret = bdrv_check_request(bs, sector_num, nb_sectors);
+    if (ret < 0) {
+        return ret;
+    }
 
     assert(QLIST_EMPTY(&bs->dirty_bitmaps));
 
@@ -5117,12 +5127,15 @@ static void coroutine_fn bdrv_discard_co_entry(void *opaque)
 int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
                                  int nb_sectors)
 {
-    int max_discard;
+    int max_discard, ret;
 
     if (!bs->drv) {
         return -ENOMEDIUM;
-    } else if (bdrv_check_request(bs, sector_num, nb_sectors)) {
-        return -EIO;
+    }
+
+    ret = bdrv_check_request(bs, sector_num, nb_sectors);
+    if (ret < 0) {
+        return ret;
     } else if (bs->read_only) {
         return -EROFS;
     }
-- 
2.1.0

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

* Re: [Qemu-devel] [PULL v2 00/65] Block patches
  2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
                   ` (64 preceding siblings ...)
  2015-02-16 15:46 ` [Qemu-devel] [PULL v2 65/65] block: Keep bdrv_check*_request()'s return value Stefan Hajnoczi
@ 2015-02-24 13:57 ` Peter Maydell
  65 siblings, 0 replies; 67+ messages in thread
From: Peter Maydell @ 2015-02-24 13:57 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: QEMU Developers

On 17 February 2015 at 00:45, Stefan Hajnoczi <stefanha@redhat.com> wrote:
> The following changes since commit cd2d5541271f1934345d8ca42f5fafff1744eee7:
>
>   Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20150212' into staging (2015-02-13 11:44:50 +0000)
>
> are available in the git repository at:
>
>   git://github.com/stefanha/qemu.git tags/block-pull-request
>
> for you to fetch changes up to b9c649470ba0d4056b2d486105a0f8fb982654ae:
>
>   block: Keep bdrv_check*_request()'s return value (2015-02-16 15:07:19 +0000)
>
> ----------------------------------------------------------------
> Pull request
>
> v2:
>  * Fix C11 typedef redefinitions in ahci and libqos malloc [Peter]
>  * Fix lx -> PRIx64 format specifiers in ahci [Peter]
>
> ----------------------------------------------------------------

Applied, thanks.

-- PMM

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

end of thread, other threads:[~2015-02-24 13:58 UTC | newest]

Thread overview: 67+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-16 15:45 [Qemu-devel] [PULL v2 00/65] Block patches Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 01/65] nbd: Drop BDS backpointer Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 02/65] iotests: Add "wait" functionality to _cleanup_qemu Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 03/65] iotests: Add test for drive-mirror with NBD target Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 04/65] libqos: Split apart pc_alloc_init Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 05/65] qtest/ahci: Create ahci.h Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 06/65] libqos: create libqos.c Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 07/65] libqos: add qtest_vboot Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 08/65] libqos: add alloc_init_flags Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 09/65] libqos: Update QGuestAllocator to be opaque Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 10/65] libqos: add pc specific interface Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 11/65] qtest/ahci: Store hba_base in AHCIQState Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 12/65] qtest/ahci: finalize AHCIQState consolidation Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 13/65] qtest/ahci: remove pcibus global Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 14/65] qtest/ahci: remove guest_malloc global Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 15/65] libqos/ahci: Functional register helpers Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 16/65] qtest/ahci: remove getter/setter macros Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 17/65] qtest/ahci: Bookmark FB and CLB pointers Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 18/65] libqos/ahci: create libqos/ahci.c Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 19/65] dataplane: endianness-aware accesses Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 20/65] libqos/ahci: Add ahci_port_select helper Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 21/65] libqos/ahci: Add ahci_port_clear helper Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 22/65] qtest/ahci: rename 'Command' to 'CommandHeader' Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 23/65] libqos/ahci: Add command header helpers Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 24/65] libqos/ahci: Add ahci_port_check_error helper Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 25/65] libqos/ahci: Add ahci_port_check_interrupts helper Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 26/65] libqos/ahci: Add port_check_nonbusy helper Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 27/65] libqos/ahci: Add cmd response sanity check helpers Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 28/65] qtest/ahci: Demagic ahci tests Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 29/65] qtest/ahci: add ahci_write_fis Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 30/65] libqos/ahci: Add ide cmd properties Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 31/65] libqos/ahci: add ahci command functions Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 32/65] libqos/ahci: add ahci command verify Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 33/65] libqos/ahci: add ahci command size setters Stefan Hajnoczi
2015-02-16 15:45 ` [Qemu-devel] [PULL v2 34/65] libqos/ahci: Add ahci_guest_io Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 35/65] libqos/ahci: add ahci_io Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 36/65] libqos/ahci: Add ahci_clean_mem Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 37/65] qtest/ahci: Assert sector size in identify test Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 38/65] qtest/ahci: Adding simple dma read-write test Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 39/65] nbd: fix the co_queue multi-adding bug Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 40/65] savevm: Improve error message for blocked migration Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 41/65] block: vmdk - fixed sizeof() error Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 42/65] qtest: Fix deadloop by running main loop AIO context's timers Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 43/65] qemu-io: Account IO by aio_read and aio_write Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 44/65] qtest: Add scripts/qtest.py Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 45/65] qemu-iotests: Add VM method qtest() to iotests.py Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 46/65] qemu-iotests: Allow caller to disable underscore convertion for qmp Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 47/65] qemu-iotests: Add 093 for IO throttling Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 48/65] qemu-img: Fix qemu-img convert -n Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 49/65] iotests: Add test for qemu-img convert to NBD Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 50/65] block: Lift some BDS functions to the BlockBackend Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 51/65] block: Add blk_new_open() Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 52/65] block: Add Error parameter to bdrv_find_protocol() Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 53/65] iotests: Add test for driver=qcow2, format=qcow2 Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 54/65] blockdev: Use blk_new_open() in blockdev_init() Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 55/65] block/xen: Use blk_new_open() in blk_connect() Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 56/65] qemu-img: Use blk_new_open() in img_open() Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 57/65] qemu-img: Use blk_new_open() in img_rebase() Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 58/65] qemu-img: Use BlockBackend as far as possible Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 59/65] qemu-nbd: Use blk_new_open() in main() Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 60/65] qemu-io: Use blk_new_open() in openfile() Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 61/65] qemu-io: Remove "growable" option Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 62/65] qemu-io: Use BlockBackend Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 63/65] block: Clamp BlockBackend requests Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 64/65] block: Remove "growable" from BDS Stefan Hajnoczi
2015-02-16 15:46 ` [Qemu-devel] [PULL v2 65/65] block: Keep bdrv_check*_request()'s return value Stefan Hajnoczi
2015-02-24 13:57 ` [Qemu-devel] [PULL v2 00/65] Block patches Peter Maydell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.