qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Kevin Wolf <kwolf@redhat.com>
To: anthony@codemonkey.ws
Cc: kwolf@redhat.com, qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH 02/15] Do not delete BlockDriverState when deleting the drive
Date: Thu,  7 Apr 2011 16:49:11 +0200	[thread overview]
Message-ID: <1302187764-16421-3-git-send-email-kwolf@redhat.com> (raw)
In-Reply-To: <1302187764-16421-1-git-send-email-kwolf@redhat.com>

From: Ryan Harper <ryanh@us.ibm.com>

When removing a drive from the host-side via drive_del we currently have
the following path:

drive_del
qemu_aio_flush()
bdrv_close()    // zaps bs->drv, which makes any subsequent I/O get
                // dropped.  Works as designed
drive_uninit()
bdrv_delete()   // frees the bs.  Since the device is still connected to
                // bs, any subsequent I/O is a use-after-free.

The value of bs->drv becomes unpredictable on free.  As long as it
remains null, I/O still gets dropped, however it could become non-null
at any point after the free resulting SEGVs or other QEMU state
corruption.

To resolve this issue as simply as possible, we can chose to not
actually delete the BlockDriverState pointer.  Since bdrv_close()
handles setting the drv pointer to NULL, we just need to remove the
BlockDriverState from the QLIST that is used to enumerate the block
devices.  This is currently handled within bdrv_delete, so move this
into its own function, bdrv_make_anon().

The result is that we can now invoke drive_del, this closes the file
descriptors and sets BlockDriverState->drv to NULL which prevents futher
IO to the device, and since we do not free BlockDriverState, we don't
have to worry about the copy retained in the block devices.

We also don't attempt to remove the qdev property since we are no longer
deleting the BlockDriverState on drives with associated drives.  This
also allows for removing Drives with no devices associated either.

Reported-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Ryan Harper <ryanh@us.ibm.com>
Acked-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c    |   14 +++++++++++---
 block.h    |    1 +
 blockdev.c |   25 ++++++++-----------------
 3 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/block.c b/block.c
index c8e2f97..c93ec6d 100644
--- a/block.c
+++ b/block.c
@@ -697,14 +697,22 @@ void bdrv_close_all(void)
     }
 }
 
+/* make a BlockDriverState anonymous by removing from bdrv_state list.
+   Also, NULL terminate the device_name to prevent double remove */
+void bdrv_make_anon(BlockDriverState *bs)
+{
+    if (bs->device_name[0] != '\0') {
+        QTAILQ_REMOVE(&bdrv_states, bs, list);
+    }
+    bs->device_name[0] = '\0';
+}
+
 void bdrv_delete(BlockDriverState *bs)
 {
     assert(!bs->peer);
 
     /* remove from list, if necessary */
-    if (bs->device_name[0] != '\0') {
-        QTAILQ_REMOVE(&bdrv_states, bs, list);
-    }
+    bdrv_make_anon(bs);
 
     bdrv_close(bs);
     if (bs->file != NULL) {
diff --git a/block.h b/block.h
index 5d78fc0..52e9cad 100644
--- a/block.h
+++ b/block.h
@@ -66,6 +66,7 @@ int bdrv_create(BlockDriver *drv, const char* filename,
     QEMUOptionParameter *options);
 int bdrv_create_file(const char* filename, QEMUOptionParameter *options);
 BlockDriverState *bdrv_new(const char *device_name);
+void bdrv_make_anon(BlockDriverState *bs);
 void bdrv_delete(BlockDriverState *bs);
 int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
 int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
diff --git a/blockdev.c b/blockdev.c
index bbe92fe..5429621 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -737,8 +737,6 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     const char *id = qdict_get_str(qdict, "id");
     BlockDriverState *bs;
-    BlockDriverState **ptr;
-    Property *prop;
 
     bs = bdrv_find(id);
     if (!bs) {
@@ -755,24 +753,17 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
     bdrv_flush(bs);
     bdrv_close(bs);
 
-    /* clean up guest state from pointing to host resource by
-     * finding and removing DeviceState "drive" property */
+    /* if we have a device associated with this BlockDriverState (bs->peer)
+     * then we need to make the drive anonymous until the device
+     * can be removed.  If this is a drive with no device backing
+     * then we can just get rid of the block driver state right here.
+     */
     if (bs->peer) {
-        for (prop = bs->peer->info->props; prop && prop->name; prop++) {
-            if (prop->info->type == PROP_TYPE_DRIVE) {
-                ptr = qdev_get_prop_ptr(bs->peer, prop);
-                if (*ptr == bs) {
-                    bdrv_detach(bs, bs->peer);
-                    *ptr = NULL;
-                    break;
-                }
-            }
-        }
+        bdrv_make_anon(bs);
+    } else {
+        drive_uninit(drive_get_by_blockdev(bs));
     }
 
-    /* clean up host side */
-    drive_uninit(drive_get_by_blockdev(bs));
-
     return 0;
 }
 
-- 
1.7.2.3

  parent reply	other threads:[~2011-04-07 14:47 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-04-07 14:49 [Qemu-devel] [PULL 00/15] Block patches Kevin Wolf
2011-04-07 14:49 ` [Qemu-devel] [PATCH 01/15] hw/xen_disk: ioreq not finished on error Kevin Wolf
2011-04-07 14:49 ` Kevin Wolf [this message]
2011-04-07 14:49 ` [Qemu-devel] [PATCH 03/15] trace: Trace bdrv_set_locked() Kevin Wolf
2011-04-07 14:49 ` [Qemu-devel] [PATCH 04/15] block: Do not cache device size for removable media Kevin Wolf
2011-04-07 14:49 ` [Qemu-devel] [PATCH 05/15] qemu-img: Initial progress printing support Kevin Wolf
2011-04-07 14:49 ` [Qemu-devel] [PATCH 06/15] qemu-img rebase: Fix segfault if backing file can't be opened Kevin Wolf
2011-04-07 14:49 ` [Qemu-devel] [PATCH 07/15] exit if -drive specified is invalid instead of ignoring the "wrong" -drive Kevin Wolf
2011-04-07 14:49 ` [Qemu-devel] [PATCH 08/15] ide: consolidate drive_get(IF_IDE) Kevin Wolf
2011-04-07 14:49 ` [Qemu-devel] [PATCH 09/15] NBD library: whitespace changes Kevin Wolf
2011-04-07 14:49 ` [Qemu-devel] [PATCH 10/15] Set errno=ENOTSUP for attempts to use UNIX sockets on Windows platforms Kevin Wolf
2011-04-07 14:49 ` [Qemu-devel] [PATCH 11/15] NBD: Use qemu_socket functions to open TCP and UNIX sockets Kevin Wolf
2011-04-07 14:49 ` [Qemu-devel] [PATCH 12/15] NBD device: Separate out parsing configuration and opening sockets Kevin Wolf
2011-04-07 14:49 ` [Qemu-devel] [PATCH 13/15] floppy: save and restore DIR register Kevin Wolf
2011-04-07 14:49 ` [Qemu-devel] [PATCH 14/15] Fix integer overflow in block migration bandwidth calculation Kevin Wolf
2011-04-07 14:49 ` [Qemu-devel] [PATCH 15/15] virtio-blk: fail unaligned requests Kevin Wolf
2011-04-07 15:44 ` [Qemu-devel] [PULL 00/15] Block patches Anthony Liguori

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1302187764-16421-3-git-send-email-kwolf@redhat.com \
    --to=kwolf@redhat.com \
    --cc=anthony@codemonkey.ws \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).