block: add a CoMutex to synchronous read drivers

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>
This commit is contained in:
Paolo Bonzini 2011-10-20 13:16:21 +02:00 committed by Kevin Wolf
parent bae0a0cc38
commit 848c66e8f5
9 changed files with 18 additions and 0 deletions

View File

@ -80,6 +80,7 @@ struct bochs_header {
}; };
typedef struct BDRVBochsState { typedef struct BDRVBochsState {
CoMutex lock;
uint32_t *catalog_bitmap; uint32_t *catalog_bitmap;
int catalog_size; 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); s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
qemu_co_mutex_init(&s->lock);
return 0; return 0;
fail: fail:
return -1; return -1;

View File

@ -27,6 +27,7 @@
#include <zlib.h> #include <zlib.h>
typedef struct BDRVCloopState { typedef struct BDRVCloopState {
CoMutex lock;
uint32_t block_size; uint32_t block_size;
uint32_t n_blocks; uint32_t n_blocks;
uint64_t* offsets; uint64_t* offsets;
@ -93,6 +94,7 @@ static int cloop_open(BlockDriverState *bs, int flags)
s->sectors_per_block = s->block_size/512; s->sectors_per_block = s->block_size/512;
bs->total_sectors = s->n_blocks*s->sectors_per_block; bs->total_sectors = s->n_blocks*s->sectors_per_block;
qemu_co_mutex_init(&s->lock);
return 0; return 0;
cloop_close: cloop_close:

View File

@ -42,6 +42,7 @@ struct cow_header_v2 {
}; };
typedef struct BDRVCowState { typedef struct BDRVCowState {
CoMutex lock;
int64_t cow_sectors_offset; int64_t cow_sectors_offset;
} BDRVCowState; } BDRVCowState;
@ -84,6 +85,7 @@ static int cow_open(BlockDriverState *bs, int flags)
bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
s->cow_sectors_offset = (bitmap_size + 511) & ~511; s->cow_sectors_offset = (bitmap_size + 511) & ~511;
qemu_co_mutex_init(&s->lock);
return 0; return 0;
fail: fail:
return -1; return -1;

View File

@ -28,6 +28,7 @@
#include <zlib.h> #include <zlib.h>
typedef struct BDRVDMGState { typedef struct BDRVDMGState {
CoMutex lock;
/* each chunk contains a certain number of sectors, /* each chunk contains a certain number of sectors,
* offsets[i] is the offset in the .dmg file, * offsets[i] is the offset in the .dmg file,
* lengths[i] is the length of the compressed chunk, * 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; s->current_chunk = s->n_chunks;
qemu_co_mutex_init(&s->lock);
return 0; return 0;
fail: fail:
return -1; return -1;

View File

@ -47,6 +47,7 @@
#endif #endif
typedef struct BDRVNBDState { typedef struct BDRVNBDState {
CoMutex lock;
int sock; int sock;
uint32_t nbdflags; uint32_t nbdflags;
off_t size; off_t size;
@ -175,6 +176,7 @@ static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
*/ */
result = nbd_establish_connection(bs); result = nbd_establish_connection(bs);
qemu_co_mutex_init(&s->lock);
return result; return result;
} }

View File

@ -46,6 +46,7 @@ struct parallels_header {
} QEMU_PACKED; } QEMU_PACKED;
typedef struct BDRVParallelsState { typedef struct BDRVParallelsState {
CoMutex lock;
uint32_t *catalog_bitmap; uint32_t *catalog_bitmap;
int catalog_size; int catalog_size;
@ -95,6 +96,7 @@ static int parallels_open(BlockDriverState *bs, int flags)
for (i = 0; i < s->catalog_size; i++) for (i = 0; i < s->catalog_size; i++)
le32_to_cpus(&s->catalog_bitmap[i]); le32_to_cpus(&s->catalog_bitmap[i]);
qemu_co_mutex_init(&s->lock);
return 0; return 0;
fail: fail:
if (s->catalog_bitmap) if (s->catalog_bitmap)

View File

@ -90,6 +90,7 @@ typedef struct VmdkExtent {
} VmdkExtent; } VmdkExtent;
typedef struct BDRVVmdkState { typedef struct BDRVVmdkState {
CoMutex lock;
int desc_offset; int desc_offset;
bool cid_updated; bool cid_updated;
uint32_t parent_cid; uint32_t parent_cid;
@ -646,6 +647,7 @@ static int vmdk_open(BlockDriverState *bs, int flags)
goto fail; goto fail;
} }
s->parent_cid = vmdk_read_cid(bs, 1); s->parent_cid = vmdk_read_cid(bs, 1);
qemu_co_mutex_init(&s->lock);
return ret; return ret;
fail: fail:

View File

@ -110,6 +110,7 @@ struct vhd_dyndisk_header {
}; };
typedef struct BDRVVPCState { typedef struct BDRVVPCState {
CoMutex lock;
uint8_t footer_buf[HEADER_SIZE]; uint8_t footer_buf[HEADER_SIZE];
uint64_t free_data_block_offset; uint64_t free_data_block_offset;
int max_table_entries; int max_table_entries;
@ -226,6 +227,7 @@ static int vpc_open(BlockDriverState *bs, int flags)
s->last_pagetable = -1; s->last_pagetable = -1;
#endif #endif
qemu_co_mutex_init(&s->lock);
return 0; return 0;
fail: fail:
return err; return err;

View File

@ -317,6 +317,7 @@ static void print_mapping(const struct mapping_t* mapping);
/* here begins the real VVFAT driver */ /* here begins the real VVFAT driver */
typedef struct BDRVVVFATState { typedef struct BDRVVVFATState {
CoMutex lock;
BlockDriverState* bs; /* pointer to parent */ BlockDriverState* bs; /* pointer to parent */
unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */ unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
unsigned char first_sectors[0x40*0x200]; unsigned char first_sectors[0x40*0x200];
@ -1065,6 +1066,7 @@ DLOG(if (stderr == NULL) {
bs->heads = bs->cyls = bs->secs = 0; bs->heads = bs->cyls = bs->secs = 0;
// assert(is_consistent(s)); // assert(is_consistent(s));
qemu_co_mutex_init(&s->lock);
return 0; return 0;
} }