From 22bc0b986d392e96634ce0c74dfad777736ddbab Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
Date: Tue, 14 Feb 2012 11:14:56 +0100
Subject: [PATCH 91/99] block: add a CoMutex to synchronous read drivers

RH-Author: Kevin Wolf <kwolf@redhat.com>
Message-id: <1329218101-24213-92-git-send-email-kwolf@redhat.com>
Patchwork-id: 37289
O-Subject: [RHEL-6.3 qemu-kvm PATCH v2 91/96] block: add a CoMutex to synchronous read drivers
Bugzilla: 783950
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
RH-Acked-by: Marcelo Tosatti <mtosatti@redhat.com>
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>

From: Paolo Bonzini <pbonzini@redhat.com>

Bugzilla: 783950

The big conversion of bdrv_read/write to coroutines caused the two
homonymous callbacks in BlockDriver to become reentrant.  It goes
like this:

1) bdrv_read is now called in a coroutine, and calls bdrv_read or
bdrv_pread.

2) the nested bdrv_read goes through the fast path in bdrv_rw_co_entry;

3) in the common case when the protocol is file, bdrv_co_do_readv calls
bdrv_co_readv_em (and from here goes to bdrv_co_io_em), which yields
until the AIO operation is complete;

4) if bdrv_read had been called from a bottom half, the main loop
is free to iterate again: a device model or another bottom half
can then come and call bdrv_read again.

This applies to all four of read/write/flush/discard.  It would also
apply to is_allocated, but it is not used from within coroutines:
besides qemu-img.c and qemu-io.c, which operate synchronously, the
only user is the monitor.  Copy-on-read will introduce a use in the
block layer, and will require converting it.

The solution is "simply" to convert all drivers to coroutines!  We
just need to add a CoMutex that is taken around affected operations.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 848c66e8f5b631961580f7f010a5831430dc84c2)

Conflicts:

	block/nbd.c
	block/vmdk.c

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/bochs.c     |    2 ++
 block/cloop.c     |    2 ++
 block/cow.c       |    2 ++
 block/dmg.c       |    2 ++
 block/nbd.c       |    3 +++
 block/parallels.c |    2 ++
 block/vmdk.c      |    3 +++
 block/vpc.c       |    2 ++
 block/vvfat.c     |    2 ++
 9 files changed, 20 insertions(+), 0 deletions(-)

Signed-off-by: Michal Novotny <minovotn@redhat.com>
---
 block/bochs.c     |    2 ++
 block/cloop.c     |    2 ++
 block/cow.c       |    2 ++
 block/dmg.c       |    2 ++
 block/nbd.c       |    3 +++
 block/parallels.c |    2 ++
 block/vmdk.c      |    3 +++
 block/vpc.c       |    2 ++
 block/vvfat.c     |    2 ++
 9 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/block/bochs.c b/block/bochs.c
index 3c2f8d1..b0f8072 100644
--- a/block/bochs.c
+++ b/block/bochs.c
@@ -80,6 +80,7 @@ struct bochs_header {
 };
 
 typedef struct BDRVBochsState {
+    CoMutex lock;
     uint32_t *catalog_bitmap;
     int catalog_size;
 
@@ -150,6 +151,7 @@ static int bochs_open(BlockDriverState *bs, int flags)
 
     s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
 
+    qemu_co_mutex_init(&s->lock);
     return 0;
  fail:
     return -1;
diff --git a/block/cloop.c b/block/cloop.c
index 8cff9f2..a91f372 100644
--- a/block/cloop.c
+++ b/block/cloop.c
@@ -27,6 +27,7 @@
 #include <zlib.h>
 
 typedef struct BDRVCloopState {
+    CoMutex lock;
     uint32_t block_size;
     uint32_t n_blocks;
     uint64_t* offsets;
@@ -93,6 +94,7 @@ static int cloop_open(BlockDriverState *bs, int flags)
 
     s->sectors_per_block = s->block_size/512;
     bs->total_sectors = s->n_blocks*s->sectors_per_block;
+    qemu_co_mutex_init(&s->lock);
     return 0;
 
 cloop_close:
diff --git a/block/cow.c b/block/cow.c
index 799569c..23833a2 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -42,6 +42,7 @@ struct cow_header_v2 {
 };
 
 typedef struct BDRVCowState {
+    CoMutex lock;
     int64_t cow_sectors_offset;
 } BDRVCowState;
 
@@ -84,6 +85,7 @@ static int cow_open(BlockDriverState *bs, int flags)
 
     bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
     s->cow_sectors_offset = (bitmap_size + 511) & ~511;
+    qemu_co_mutex_init(&s->lock);
     return 0;
  fail:
     return -1;
diff --git a/block/dmg.c b/block/dmg.c
index 64c3cce..111aeae 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -28,6 +28,7 @@
 #include <zlib.h>
 
 typedef struct BDRVDMGState {
+    CoMutex lock;
     /* each chunk contains a certain number of sectors,
      * offsets[i] is the offset in the .dmg file,
      * lengths[i] is the length of the compressed chunk,
@@ -177,6 +178,7 @@ static int dmg_open(BlockDriverState *bs, int flags)
 
     s->current_chunk = s->n_chunks;
 
+    qemu_co_mutex_init(&s->lock);
     return 0;
 fail:
     return -1;
diff --git a/block/nbd.c b/block/nbd.c
index b5cb06c..4afb6d0 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -34,6 +34,7 @@
 #include <unistd.h>
 
 typedef struct BDRVNBDState {
+    CoMutex lock;
     int sock;
     off_t size;
     size_t blocksize;
@@ -93,6 +94,8 @@ static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
     s->size = size;
     s->blocksize = blocksize;
 
+    qemu_co_mutex_init(&s->lock);
+
     return 0;
 }
 
diff --git a/block/parallels.c b/block/parallels.c
index 37d151d..ad20687 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -46,6 +46,7 @@ struct parallels_header {
 } __attribute__((packed));
 
 typedef struct BDRVParallelsState {
+    CoMutex lock;
 
     uint32_t *catalog_bitmap;
     int catalog_size;
@@ -95,6 +96,7 @@ static int parallels_open(BlockDriverState *bs, int flags)
     for (i = 0; i < s->catalog_size; i++)
 	le32_to_cpus(&s->catalog_bitmap[i]);
 
+    qemu_co_mutex_init(&s->lock);
     return 0;
 fail:
     if (s->catalog_bitmap)
diff --git a/block/vmdk.c b/block/vmdk.c
index e2cfcad..4a48f9e 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -75,6 +75,8 @@ typedef struct BDRVVmdkState {
     uint32_t l2_cache_counts[L2_CACHE_SIZE];
 
     unsigned int cluster_sectors;
+
+    CoMutex lock;
     uint32_t parent_cid;
 } BDRVVmdkState;
 
@@ -425,6 +427,7 @@ static int vmdk_open(BlockDriverState *bs, int flags)
     }
 
     s->l2_cache = g_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
+    qemu_co_mutex_init(&s->lock);
     return 0;
  fail:
     g_free(s->l1_backup_table);
diff --git a/block/vpc.c b/block/vpc.c
index d9f5e6e..b7a2e33 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -110,6 +110,7 @@ struct vhd_dyndisk_header {
 };
 
 typedef struct BDRVVPCState {
+    CoMutex lock;
     uint8_t footer_buf[HEADER_SIZE];
     uint64_t free_data_block_offset;
     int max_table_entries;
@@ -220,6 +221,7 @@ static int vpc_open(BlockDriverState *bs, int flags)
     s->last_pagetable = -1;
 #endif
 
+    qemu_co_mutex_init(&s->lock);
     return 0;
  fail:
     return -1;
diff --git a/block/vvfat.c b/block/vvfat.c
index 1d88070..a2bec26 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -318,6 +318,7 @@ static void print_mapping(const struct mapping_t* mapping);
 /* here begins the real VVFAT driver */
 
 typedef struct BDRVVVFATState {
+    CoMutex lock;
     BlockDriverState* bs; /* pointer to parent */
     unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
     unsigned char first_sectors[0x40*0x200];
@@ -1079,6 +1080,7 @@ DLOG(if (stderr == NULL) {
 	bs->heads = bs->cyls = bs->secs = 0;
 
     //    assert(is_consistent(s));
+    qemu_co_mutex_init(&s->lock);
     return 0;
 }
 
-- 
1.7.7.5

