Merge remote-tracking branch 'kwolf/for-anthony' into staging

* kwolf/for-anthony: (26 commits)
  qemu-io: Use bdrv_drain_all instead of qemu_aio_flush
  megasas: Use bdrv_drain_all instead of qemu_aio_flush
  vmdk: Fix data corruption bug in WRITE and READ handling
  fdc: remove last usage of FD_STATE_SEEK
  fdc: fix typo in zero constant
  fdc: remove double affectation of FD_MSR_CMDBUSY flag
  fdc-tests: add tests for VERIFY command
  fdc: implement VERIFY command
  fdc-test: Check READ ID
  fdc: fix false FD_SR0_SEEK
  fdc: fix FD_SR0_SEEK for initial seek on DMA transfers
  fdc: fix FD_SR0_SEEK for non-DMA transfers and multi sectors transfers
  fdc: use status0 field instead of a local variable
  fdc-test: add tests for non-DMA READ command
  fdc-test: insert media before fuzzing registers
  fdc-test: split test_media_change() test, so insert part can be reused
  fdc: Remove status0 parameter from fdctrl_set_fifo()
  aio: rename AIOPool to AIOCBInfo
  aio: use g_slice_alloc() for AIOCB pooling
  aio: switch aiocb_size type int -> size_t
  ...

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Anthony Liguori 2012-11-19 09:27:00 -06:00
commit ad1db3b341
32 changed files with 556 additions and 142 deletions

View File

@ -553,6 +553,7 @@ T: git git://github.com/kvaneesh/QEMU.git
virtio-blk
M: Kevin Wolf <kwolf@redhat.com>
M: Stefan Hajnoczi <stefanha@redhat.com>
S: Supported
F: hw/virtio-blk*
@ -583,6 +584,7 @@ F: audio/
Block
M: Kevin Wolf <kwolf@redhat.com>
M: Stefan Hajnoczi <stefanha@redhat.com>
S: Supported
F: block*
F: block/

31
block.c
View File

@ -3521,7 +3521,7 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
void bdrv_aio_cancel(BlockDriverAIOCB *acb)
{
acb->pool->cancel(acb);
acb->aiocb_info->cancel(acb);
}
/* block I/O throttling */
@ -3711,7 +3711,7 @@ static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb)
qemu_aio_release(acb);
}
static AIOPool bdrv_em_aio_pool = {
static const AIOCBInfo bdrv_em_aiocb_info = {
.aiocb_size = sizeof(BlockDriverAIOCBSync),
.cancel = bdrv_aio_cancel_em,
};
@ -3740,7 +3740,7 @@ static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
{
BlockDriverAIOCBSync *acb;
acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque);
acb = qemu_aio_get(&bdrv_em_aiocb_info, bs, cb, opaque);
acb->is_write = is_write;
acb->qiov = qiov;
acb->bounce = qemu_blockalign(bs, qiov->size);
@ -3785,7 +3785,7 @@ static void bdrv_aio_co_cancel_em(BlockDriverAIOCB *blockacb)
qemu_aio_flush();
}
static AIOPool bdrv_em_co_aio_pool = {
static const AIOCBInfo bdrv_em_co_aiocb_info = {
.aiocb_size = sizeof(BlockDriverAIOCBCoroutine),
.cancel = bdrv_aio_co_cancel_em,
};
@ -3828,7 +3828,7 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
Coroutine *co;
BlockDriverAIOCBCoroutine *acb;
acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
acb->req.sector = sector_num;
acb->req.nb_sectors = nb_sectors;
acb->req.qiov = qiov;
@ -3858,7 +3858,7 @@ BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
Coroutine *co;
BlockDriverAIOCBCoroutine *acb;
acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
co = qemu_coroutine_create(bdrv_aio_flush_co_entry);
qemu_coroutine_enter(co, acb);
@ -3884,7 +3884,7 @@ BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
trace_bdrv_aio_discard(bs, sector_num, nb_sectors, opaque);
acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
acb->req.sector = sector_num;
acb->req.nb_sectors = nb_sectors;
co = qemu_coroutine_create(bdrv_aio_discard_co_entry);
@ -3904,18 +3904,13 @@ void bdrv_init_with_whitelist(void)
bdrv_init();
}
void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
BlockDriverAIOCB *acb;
if (pool->free_aiocb) {
acb = pool->free_aiocb;
pool->free_aiocb = acb->next;
} else {
acb = g_malloc0(pool->aiocb_size);
acb->pool = pool;
}
acb = g_slice_alloc(aiocb_info->aiocb_size);
acb->aiocb_info = aiocb_info;
acb->bs = bs;
acb->cb = cb;
acb->opaque = opaque;
@ -3924,10 +3919,8 @@ void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
void qemu_aio_release(void *p)
{
BlockDriverAIOCB *acb = (BlockDriverAIOCB *)p;
AIOPool *pool = acb->pool;
acb->next = pool->free_aiocb;
pool->free_aiocb = acb;
BlockDriverAIOCB *acb = p;
g_slice_free1(acb->aiocb_info->aiocb_size, acb);
}
/**************************************************************/

View File

@ -41,7 +41,7 @@ typedef struct BlkdebugAIOCB {
static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb);
static AIOPool blkdebug_aio_pool = {
static const AIOCBInfo blkdebug_aiocb_info = {
.aiocb_size = sizeof(BlkdebugAIOCB),
.cancel = blkdebug_aio_cancel,
};
@ -335,7 +335,7 @@ static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
return NULL;
}
acb = qemu_aio_get(&blkdebug_aio_pool, bs, cb, opaque);
acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
acb->ret = -error;
bh = qemu_bh_new(error_callback_bh, acb);

View File

@ -48,7 +48,7 @@ static void blkverify_aio_cancel(BlockDriverAIOCB *blockacb)
}
}
static AIOPool blkverify_aio_pool = {
static const AIOCBInfo blkverify_aiocb_info = {
.aiocb_size = sizeof(BlkverifyAIOCB),
.cancel = blkverify_aio_cancel,
};
@ -233,7 +233,7 @@ static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
BlockDriverCompletionFunc *cb,
void *opaque)
{
BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aio_pool, bs, cb, opaque);
BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque);
acb->bh = NULL;
acb->is_write = is_write;

View File

@ -438,7 +438,7 @@ static void curl_aio_cancel(BlockDriverAIOCB *blockacb)
// Do we have to implement canceling? Seems to work without...
}
static AIOPool curl_aio_pool = {
static const AIOCBInfo curl_aiocb_info = {
.aiocb_size = sizeof(CURLAIOCB),
.cancel = curl_aio_cancel,
};
@ -505,7 +505,7 @@ static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
{
CURLAIOCB *acb;
acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque);
acb = qemu_aio_get(&curl_aiocb_info, bs, cb, opaque);
acb->qiov = qiov;
acb->sector_num = sector_num;

View File

@ -388,7 +388,7 @@ static void qemu_gluster_aio_cancel(BlockDriverAIOCB *blockacb)
}
}
static AIOPool gluster_aio_pool = {
static const AIOCBInfo gluster_aiocb_info = {
.aiocb_size = sizeof(GlusterAIOCB),
.cancel = qemu_gluster_aio_cancel,
};
@ -439,7 +439,7 @@ static BlockDriverAIOCB *qemu_gluster_aio_rw(BlockDriverState *bs,
size = nb_sectors * BDRV_SECTOR_SIZE;
s->qemu_aio_count++;
acb = qemu_aio_get(&gluster_aio_pool, bs, cb, opaque);
acb = qemu_aio_get(&gluster_aiocb_info, bs, cb, opaque);
acb->size = size;
acb->ret = 0;
acb->finished = NULL;
@ -484,7 +484,7 @@ static BlockDriverAIOCB *qemu_gluster_aio_flush(BlockDriverState *bs,
GlusterAIOCB *acb;
BDRVGlusterState *s = bs->opaque;
acb = qemu_aio_get(&gluster_aio_pool, bs, cb, opaque);
acb = qemu_aio_get(&gluster_aiocb_info, bs, cb, opaque);
acb->size = 0;
acb->ret = 0;
acb->finished = NULL;

View File

@ -133,7 +133,7 @@ iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
}
}
static AIOPool iscsi_aio_pool = {
static const AIOCBInfo iscsi_aiocb_info = {
.aiocb_size = sizeof(IscsiAIOCB),
.cancel = iscsi_aio_cancel,
};
@ -234,7 +234,7 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
uint64_t lba;
struct iscsi_data data;
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb);
acb->iscsilun = iscsilun;
@ -325,7 +325,7 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors;
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb);
acb->iscsilun = iscsilun;
@ -430,7 +430,7 @@ iscsi_aio_flush(BlockDriverState *bs,
struct iscsi_context *iscsi = iscsilun->iscsi;
IscsiAIOCB *acb;
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
acb->iscsilun = iscsilun;
acb->canceled = 0;
@ -483,7 +483,7 @@ iscsi_aio_discard(BlockDriverState *bs,
IscsiAIOCB *acb;
struct unmap_list list[1];
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
acb->iscsilun = iscsilun;
acb->canceled = 0;
@ -558,7 +558,7 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
assert(req == SG_IO);
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque);
acb->iscsilun = iscsilun;
acb->canceled = 0;

View File

@ -140,7 +140,7 @@ static void laio_cancel(BlockDriverAIOCB *blockacb)
}
}
static AIOPool laio_pool = {
static const AIOCBInfo laio_aiocb_info = {
.aiocb_size = sizeof(struct qemu_laiocb),
.cancel = laio_cancel,
};
@ -154,7 +154,7 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
struct iocb *iocbs;
off_t offset = sector_num * 512;
laiocb = qemu_aio_get(&laio_pool, bs, cb, opaque);
laiocb = qemu_aio_get(&laio_aiocb_info, bs, cb, opaque);
laiocb->nbytes = nb_sectors * 512;
laiocb->ctx = s;
laiocb->ret = -EINPROGRESS;

View File

@ -301,7 +301,8 @@ static int alloc_refcount_block(BlockDriverState *bs,
uint64_t last_table_size;
uint64_t blocks_clusters;
do {
uint64_t table_clusters = size_to_clusters(s, table_size);
uint64_t table_clusters =
size_to_clusters(s, table_size * sizeof(uint64_t));
blocks_clusters = 1 +
((table_clusters + refcount_block_clusters - 1)
/ refcount_block_clusters);

View File

@ -30,7 +30,7 @@ static void qed_aio_cancel(BlockDriverAIOCB *blockacb)
}
}
static AIOPool qed_aio_pool = {
static const AIOCBInfo qed_aiocb_info = {
.aiocb_size = sizeof(QEDAIOCB),
.cancel = qed_aio_cancel,
};
@ -1311,7 +1311,7 @@ static BlockDriverAIOCB *qed_aio_setup(BlockDriverState *bs,
BlockDriverCompletionFunc *cb,
void *opaque, int flags)
{
QEDAIOCB *acb = qemu_aio_get(&qed_aio_pool, bs, cb, opaque);
QEDAIOCB *acb = qemu_aio_get(&qed_aiocb_info, bs, cb, opaque);
trace_qed_aio_setup(bs->opaque, acb, sector_num, nb_sectors,
opaque, flags);

View File

@ -570,7 +570,7 @@ static void qemu_rbd_aio_cancel(BlockDriverAIOCB *blockacb)
acb->cancelled = 1;
}
static AIOPool rbd_aio_pool = {
static const AIOCBInfo rbd_aiocb_info = {
.aiocb_size = sizeof(RBDAIOCB),
.cancel = qemu_rbd_aio_cancel,
};
@ -672,7 +672,7 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
BDRVRBDState *s = bs->opaque;
acb = qemu_aio_get(&rbd_aio_pool, bs, cb, opaque);
acb = qemu_aio_get(&rbd_aiocb_info, bs, cb, opaque);
acb->cmd = cmd;
acb->qiov = qiov;
if (cmd == RBD_AIO_DISCARD) {

View File

@ -420,7 +420,7 @@ static void sd_aio_cancel(BlockDriverAIOCB *blockacb)
acb->canceled = true;
}
static AIOPool sd_aio_pool = {
static const AIOCBInfo sd_aiocb_info = {
.aiocb_size = sizeof(SheepdogAIOCB),
.cancel = sd_aio_cancel,
};
@ -431,7 +431,7 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
{
SheepdogAIOCB *acb;
acb = qemu_aio_get(&sd_aio_pool, bs, cb, opaque);
acb = qemu_aio_get(&sd_aiocb_info, bs, cb, opaque);
acb->qiov = qiov;

View File

@ -1092,6 +1092,7 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
BDRVVmdkState *s = bs->opaque;
int ret;
uint64_t n, index_in_cluster;
uint64_t extent_begin_sector, extent_relative_sector_num;
VmdkExtent *extent = NULL;
uint64_t cluster_offset;
@ -1103,7 +1104,9 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
ret = get_cluster_offset(
bs, extent, NULL,
sector_num << 9, 0, &cluster_offset);
index_in_cluster = sector_num % extent->cluster_sectors;
extent_begin_sector = extent->end_sector - extent->sectors;
extent_relative_sector_num = sector_num - extent_begin_sector;
index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;
n = extent->cluster_sectors - index_in_cluster;
if (n > nb_sectors) {
n = nb_sectors;
@ -1154,6 +1157,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
VmdkExtent *extent = NULL;
int n, ret;
int64_t index_in_cluster;
uint64_t extent_begin_sector, extent_relative_sector_num;
uint64_t cluster_offset;
VmdkMetaData m_data;
@ -1196,7 +1200,9 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
if (ret) {
return -EINVAL;
}
index_in_cluster = sector_num % extent->cluster_sectors;
extent_begin_sector = extent->end_sector - extent->sectors;
extent_relative_sector_num = sector_num - extent_begin_sector;
index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;
n = extent->cluster_sectors - index_in_cluster;
if (n > nb_sectors) {
n = nb_sectors;

View File

@ -131,7 +131,7 @@ static void win32_aio_cancel(BlockDriverAIOCB *blockacb)
}
}
static AIOPool win32_aio_pool = {
static const AIOCBInfo win32_aiocb_info = {
.aiocb_size = sizeof(QEMUWin32AIOCB),
.cancel = win32_aio_cancel,
};
@ -145,7 +145,7 @@ BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
uint64_t offset = sector_num * 512;
DWORD rc;
waiocb = qemu_aio_get(&win32_aio_pool, bs, cb, opaque);
waiocb = qemu_aio_get(&win32_aiocb_info, bs, cb, opaque);
waiocb->nbytes = nb_sectors * 512;
waiocb->qiov = qiov;
waiocb->is_read = (type == QEMU_AIO_READ);
@ -167,11 +167,11 @@ BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
waiocb->is_linear = true;
}
waiocb->ov = (OVERLAPPED) {
.Offset = (DWORD) offset,
.OffsetHigh = (DWORD) (offset >> 32),
.hEvent = event_notifier_get_handle(&aio->e)
};
memset(&waiocb->ov, 0, sizeof(waiocb->ov));
waiocb->ov.Offset = (DWORD)offset;
waiocb->ov.OffsetHigh = (DWORD)(offset >> 32);
waiocb->ov.hEvent = event_notifier_get_handle(&aio->e);
aio->count++;
if (type & QEMU_AIO_READ) {

View File

@ -195,7 +195,7 @@ static void dma_aio_cancel(BlockDriverAIOCB *acb)
dma_complete(dbs, 0);
}
static AIOPool dma_aio_pool = {
static const AIOCBInfo dma_aiocb_info = {
.aiocb_size = sizeof(DMAAIOCB),
.cancel = dma_aio_cancel,
};
@ -205,7 +205,7 @@ BlockDriverAIOCB *dma_bdrv_io(
DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
void *opaque, DMADirection dir)
{
DMAAIOCB *dbs = qemu_aio_get(&dma_aio_pool, bs, cb, opaque);
DMAAIOCB *dbs = qemu_aio_get(&dma_aiocb_info, bs, cb, opaque);
trace_dma_bdrv_io(dbs, bs, sector_num, (dir == DMA_DIRECTION_TO_DEVICE));

109
hw/fdc.c
View File

@ -327,7 +327,7 @@ static void fdctrl_reset(FDCtrl *fdctrl, int do_irq);
static void fdctrl_reset_fifo(FDCtrl *fdctrl);
static int fdctrl_transfer_handler (void *opaque, int nchan,
int dma_pos, int dma_len);
static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0);
static void fdctrl_raise_irq(FDCtrl *fdctrl);
static FDrive *get_cur_drv(FDCtrl *fdctrl);
static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl);
@ -349,12 +349,12 @@ enum {
FD_DIR_SCANE = 2,
FD_DIR_SCANL = 3,
FD_DIR_SCANH = 4,
FD_DIR_VERIFY = 5,
};
enum {
FD_STATE_MULTI = 0x01, /* multi track flag */
FD_STATE_FORMAT = 0x02, /* format flag */
FD_STATE_SEEK = 0x04, /* seek flag */
};
enum {
@ -496,7 +496,6 @@ enum {
};
#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
#define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK)
#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
struct FDCtrl {
@ -799,6 +798,7 @@ static void fdctrl_handle_tc(void *opaque, int irq, int level)
/* Change IRQ state */
static void fdctrl_reset_irq(FDCtrl *fdctrl)
{
fdctrl->status0 = 0;
if (!(fdctrl->sra & FD_SRA_INTPEND))
return;
FLOPPY_DPRINTF("Reset interrupt\n");
@ -806,14 +806,13 @@ static void fdctrl_reset_irq(FDCtrl *fdctrl)
fdctrl->sra &= ~FD_SRA_INTPEND;
}
static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0)
static void fdctrl_raise_irq(FDCtrl *fdctrl)
{
/* Sparc mutation */
if (fdctrl->sun4m && (fdctrl->msr & FD_MSR_CMDBUSY)) {
/* XXX: not sure */
fdctrl->msr &= ~FD_MSR_CMDBUSY;
fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
fdctrl->status0 = status0;
return;
}
if (!(fdctrl->sra & FD_SRA_INTPEND)) {
@ -822,7 +821,6 @@ static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0)
}
fdctrl->reset_sensei = 0;
fdctrl->status0 = status0;
FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0);
}
@ -851,7 +849,8 @@ static void fdctrl_reset(FDCtrl *fdctrl, int do_irq)
fd_recalibrate(&fdctrl->drives[i]);
fdctrl_reset_fifo(fdctrl);
if (do_irq) {
fdctrl_raise_irq(fdctrl, FD_SR0_RDYCHG);
fdctrl->status0 |= FD_SR0_RDYCHG;
fdctrl_raise_irq(fdctrl);
fdctrl->reset_sensei = FD_RESET_SENSEI_COUNT;
}
}
@ -1079,15 +1078,12 @@ static void fdctrl_reset_fifo(FDCtrl *fdctrl)
}
/* Set FIFO status for the host to read */
static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len, uint8_t status0)
static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len)
{
fdctrl->data_dir = FD_DIR_READ;
fdctrl->data_len = fifo_len;
fdctrl->data_pos = 0;
fdctrl->msr |= FD_MSR_CMDBUSY | FD_MSR_RQM | FD_MSR_DIO;
if (status0) {
fdctrl_raise_irq(fdctrl, status0);
}
}
/* Set an error: unimplemented/unknown command */
@ -1096,7 +1092,7 @@ static void fdctrl_unimplemented(FDCtrl *fdctrl, int direction)
qemu_log_mask(LOG_UNIMP, "fdc: unimplemented command 0x%02x\n",
fdctrl->fifo[0]);
fdctrl->fifo[0] = FD_SR0_INVCMD;
fdctrl_set_fifo(fdctrl, 1, 0);
fdctrl_set_fifo(fdctrl, 1);
}
/* Seek to next sector
@ -1126,11 +1122,13 @@ static int fdctrl_seek_to_next_sect(FDCtrl *fdctrl, FDrive *cur_drv)
} else {
new_head = 0;
new_track++;
fdctrl->status0 |= FD_SR0_SEEK;
if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) {
ret = 0;
}
}
} else {
fdctrl->status0 |= FD_SR0_SEEK;
new_track++;
ret = 0;
}
@ -1150,10 +1148,14 @@ static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0,
uint8_t status1, uint8_t status2)
{
FDrive *cur_drv;
cur_drv = get_cur_drv(fdctrl);
fdctrl->status0 = status0 | FD_SR0_SEEK | (cur_drv->head << 2) |
GET_CUR_DRV(fdctrl);
fdctrl->status0 &= ~(FD_SR0_DS0 | FD_SR0_DS1 | FD_SR0_HEAD);
fdctrl->status0 |= GET_CUR_DRV(fdctrl);
if (cur_drv->head) {
fdctrl->status0 |= FD_SR0_HEAD;
}
fdctrl->status0 |= status0;
FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
status0, status1, status2, fdctrl->status0);
@ -1170,7 +1172,9 @@ static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0,
}
fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
fdctrl->msr &= ~FD_MSR_NONDMA;
fdctrl_set_fifo(fdctrl, 7, fdctrl->status0);
fdctrl_set_fifo(fdctrl, 7);
fdctrl_raise_irq(fdctrl);
}
/* Prepare a data transfer (either DMA or FIFO) */
@ -1178,7 +1182,6 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
{
FDrive *cur_drv;
uint8_t kh, kt, ks;
int did_seek = 0;
SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
cur_drv = get_cur_drv(fdctrl);
@ -1212,7 +1215,7 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
fdctrl->fifo[5] = ks;
return;
case 1:
did_seek = 1;
fdctrl->status0 |= FD_SR0_SEEK;
break;
default:
break;
@ -1234,16 +1237,12 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
/* Set the FIFO state */
fdctrl->data_dir = direction;
fdctrl->data_pos = 0;
fdctrl->msr |= FD_MSR_CMDBUSY;
assert(fdctrl->msr & FD_MSR_CMDBUSY);
if (fdctrl->fifo[0] & 0x80)
fdctrl->data_state |= FD_STATE_MULTI;
else
fdctrl->data_state &= ~FD_STATE_MULTI;
if (did_seek)
fdctrl->data_state |= FD_STATE_SEEK;
else
fdctrl->data_state &= ~FD_STATE_SEEK;
if (fdctrl->fifo[5] == 00) {
if (fdctrl->fifo[5] == 0) {
fdctrl->data_len = fdctrl->fifo[8];
} else {
int tmp;
@ -1266,14 +1265,21 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL ||
direction == FD_DIR_SCANH) && dma_mode == 0) ||
(direction == FD_DIR_WRITE && dma_mode == 2) ||
(direction == FD_DIR_READ && dma_mode == 1)) {
(direction == FD_DIR_READ && dma_mode == 1) ||
(direction == FD_DIR_VERIFY)) {
/* No access is allowed until DMA transfer has completed */
fdctrl->msr &= ~FD_MSR_RQM;
if (direction != FD_DIR_VERIFY) {
/* Now, we just have to wait for the DMA controller to
* recall us...
*/
DMA_hold_DREQ(fdctrl->dma_chann);
DMA_schedule(fdctrl->dma_chann);
} else {
/* Start transfer */
fdctrl_transfer_handler(fdctrl, fdctrl->dma_chann, 0,
fdctrl->data_len);
}
return;
} else {
FLOPPY_DPRINTF("bad dma_mode=%d direction=%d\n", dma_mode,
@ -1285,7 +1291,7 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
if (direction != FD_DIR_WRITE)
fdctrl->msr |= FD_MSR_DIO;
/* IO based transfer: calculate len */
fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
fdctrl_raise_irq(fdctrl);
}
/* Prepare a transfer of deleted data */
@ -1376,6 +1382,9 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
goto transfer_error;
}
break;
case FD_DIR_VERIFY:
/* VERIFY commands */
break;
default:
/* SCAN commands */
{
@ -1411,8 +1420,6 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
fdctrl->data_dir == FD_DIR_SCANL ||
fdctrl->data_dir == FD_DIR_SCANH)
status2 = FD_SR2_SEH;
if (FD_DID_SEEK(fdctrl->data_state))
status0 |= FD_SR0_SEEK;
fdctrl->data_len -= len;
fdctrl_stop_transfer(fdctrl, status0, status1, status2);
transfer_error:
@ -1458,7 +1465,7 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
* then from status mode to command mode
*/
if (fdctrl->msr & FD_MSR_NONDMA) {
fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
} else {
fdctrl_reset_fifo(fdctrl);
fdctrl_reset_irq(fdctrl);
@ -1506,7 +1513,7 @@ static void fdctrl_format_sector(FDCtrl *fdctrl)
fdctrl->fifo[5] = ks;
return;
case 1:
fdctrl->data_state |= FD_STATE_SEEK;
fdctrl->status0 |= FD_SR0_SEEK;
break;
default:
break;
@ -1520,9 +1527,6 @@ static void fdctrl_format_sector(FDCtrl *fdctrl)
if (cur_drv->sect == cur_drv->last_sect) {
fdctrl->data_state &= ~FD_STATE_FORMAT;
/* Last sector done */
if (FD_DID_SEEK(fdctrl->data_state))
fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
else
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
} else {
/* More to do */
@ -1536,7 +1540,7 @@ static void fdctrl_handle_lock(FDCtrl *fdctrl, int direction)
{
fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0;
fdctrl->fifo[0] = fdctrl->lock << 4;
fdctrl_set_fifo(fdctrl, 1, 0);
fdctrl_set_fifo(fdctrl, 1);
}
static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction)
@ -1561,20 +1565,20 @@ static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction)
(cur_drv->perpendicular << 2);
fdctrl->fifo[8] = fdctrl->config;
fdctrl->fifo[9] = fdctrl->precomp_trk;
fdctrl_set_fifo(fdctrl, 10, 0);
fdctrl_set_fifo(fdctrl, 10);
}
static void fdctrl_handle_version(FDCtrl *fdctrl, int direction)
{
/* Controller's version */
fdctrl->fifo[0] = fdctrl->version;
fdctrl_set_fifo(fdctrl, 1, 0);
fdctrl_set_fifo(fdctrl, 1);
}
static void fdctrl_handle_partid(FDCtrl *fdctrl, int direction)
{
fdctrl->fifo[0] = 0x41; /* Stepping 1 */
fdctrl_set_fifo(fdctrl, 1, 0);
fdctrl_set_fifo(fdctrl, 1);
}
static void fdctrl_handle_restore(FDCtrl *fdctrl, int direction)
@ -1627,7 +1631,7 @@ static void fdctrl_handle_save(FDCtrl *fdctrl, int direction)
fdctrl->fifo[12] = fdctrl->pwrd;
fdctrl->fifo[13] = 0;
fdctrl->fifo[14] = 0;
fdctrl_set_fifo(fdctrl, 15, 0);
fdctrl_set_fifo(fdctrl, 15);
}
static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction)
@ -1650,7 +1654,6 @@ static void fdctrl_handle_format_track(FDCtrl *fdctrl, int direction)
fdctrl->data_state |= FD_STATE_MULTI;
else
fdctrl->data_state &= ~FD_STATE_MULTI;
fdctrl->data_state &= ~FD_STATE_SEEK;
cur_drv->bps =
fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
#if 0
@ -1693,7 +1696,7 @@ static void fdctrl_handle_sense_drive_status(FDCtrl *fdctrl, int direction)
(cur_drv->head << 2) |
GET_CUR_DRV(fdctrl) |
0x28;
fdctrl_set_fifo(fdctrl, 1, 0);
fdctrl_set_fifo(fdctrl, 1);
}
static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction)
@ -1705,7 +1708,8 @@ static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction)
fd_recalibrate(cur_drv);
fdctrl_reset_fifo(fdctrl);
/* Raise Interrupt */
fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
fdctrl->status0 |= FD_SR0_SEEK;
fdctrl_raise_irq(fdctrl);
}
static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
@ -1718,7 +1722,7 @@ static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
fdctrl->reset_sensei--;
} else if (!(fdctrl->sra & FD_SRA_INTPEND)) {
fdctrl->fifo[0] = FD_SR0_INVCMD;
fdctrl_set_fifo(fdctrl, 1, 0);
fdctrl_set_fifo(fdctrl, 1);
return;
} else {
fdctrl->fifo[0] =
@ -1727,7 +1731,7 @@ static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
}
fdctrl->fifo[1] = cur_drv->track;
fdctrl_set_fifo(fdctrl, 2, 0);
fdctrl_set_fifo(fdctrl, 2);
fdctrl_reset_irq(fdctrl);
fdctrl->status0 = FD_SR0_RDYCHG;
}
@ -1744,7 +1748,8 @@ static void fdctrl_handle_seek(FDCtrl *fdctrl, int direction)
*/
fd_seek(cur_drv, cur_drv->head, fdctrl->fifo[2], cur_drv->sect, 1);
/* Raise Interrupt */
fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
fdctrl->status0 |= FD_SR0_SEEK;
fdctrl_raise_irq(fdctrl);
}
static void fdctrl_handle_perpendicular_mode(FDCtrl *fdctrl, int direction)
@ -1769,7 +1774,7 @@ static void fdctrl_handle_powerdown_mode(FDCtrl *fdctrl, int direction)
{
fdctrl->pwrd = fdctrl->fifo[1];
fdctrl->fifo[0] = fdctrl->fifo[1];
fdctrl_set_fifo(fdctrl, 1, 0);
fdctrl_set_fifo(fdctrl, 1);
}
static void fdctrl_handle_option(FDCtrl *fdctrl, int direction)
@ -1788,7 +1793,7 @@ static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direct
fdctrl->fifo[0] = fdctrl->fifo[1];
fdctrl->fifo[2] = 0;
fdctrl->fifo[3] = 0;
fdctrl_set_fifo(fdctrl, 4, 0);
fdctrl_set_fifo(fdctrl, 4);
} else {
fdctrl_reset_fifo(fdctrl);
}
@ -1796,7 +1801,7 @@ static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direct
/* ERROR */
fdctrl->fifo[0] = 0x80 |
(cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
fdctrl_set_fifo(fdctrl, 1, 0);
fdctrl_set_fifo(fdctrl, 1);
}
}
@ -1815,7 +1820,8 @@ static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction)
}
fdctrl_reset_fifo(fdctrl);
/* Raise Interrupt */
fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
fdctrl->status0 |= FD_SR0_SEEK;
fdctrl_raise_irq(fdctrl);
}
static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
@ -1832,7 +1838,8 @@ static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
}
fdctrl_reset_fifo(fdctrl);
/* Raise Interrupt */
fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
fdctrl->status0 |= FD_SR0_SEEK;
fdctrl_raise_irq(fdctrl);
}
static const struct {
@ -1854,7 +1861,7 @@ static const struct {
{ FD_CMD_SAVE, 0xff, "SAVE", 0, fdctrl_handle_save }, /* part of READ DELETED DATA */
{ FD_CMD_READ_DELETED, 0x1f, "READ DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_READ },
{ FD_CMD_SCAN_EQUAL, 0x1f, "SCAN EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANE },
{ FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_unimplemented },
{ FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_start_transfer, FD_DIR_VERIFY },
{ FD_CMD_SCAN_LOW_OR_EQUAL, 0x1f, "SCAN LOW OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANL },
{ FD_CMD_SCAN_HIGH_OR_EQUAL, 0x1f, "SCAN HIGH OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANH },
{ FD_CMD_WRITE_DELETED, 0x3f, "WRITE DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_WRITE },
@ -1918,7 +1925,7 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
* then from status mode to command mode
*/
if (fdctrl->data_pos == fdctrl->data_len)
fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
return;
}
if (fdctrl->data_pos == 0) {

View File

@ -336,7 +336,7 @@ static void trim_aio_cancel(BlockDriverAIOCB *acb)
qemu_aio_release(iocb);
}
static AIOPool trim_aio_pool = {
static const AIOCBInfo trim_aiocb_info = {
.aiocb_size = sizeof(TrimAIOCB),
.cancel = trim_aio_cancel,
};
@ -360,7 +360,7 @@ BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs,
TrimAIOCB *iocb;
int i, j, ret;
iocb = qemu_aio_get(&trim_aio_pool, bs, cb, opaque);
iocb = qemu_aio_get(&trim_aiocb_info, bs, cb, opaque);
iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb);
iocb->ret = 0;

View File

@ -1296,7 +1296,7 @@ static int megasas_dcmd_get_properties(MegasasState *s, MegasasCmd *cmd)
static int megasas_cache_flush(MegasasState *s, MegasasCmd *cmd)
{
qemu_aio_flush();
bdrv_drain_all();
return MFI_STAT_OK;
}

View File

@ -21,21 +21,19 @@
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
typedef void BlockDriverCompletionFunc(void *opaque, int ret);
typedef struct AIOPool {
typedef struct AIOCBInfo {
void (*cancel)(BlockDriverAIOCB *acb);
int aiocb_size;
BlockDriverAIOCB *free_aiocb;
} AIOPool;
size_t aiocb_size;
} AIOCBInfo;
struct BlockDriverAIOCB {
AIOPool *pool;
const AIOCBInfo *aiocb_info;
BlockDriverState *bs;
BlockDriverCompletionFunc *cb;
void *opaque;
BlockDriverAIOCB *next;
};
void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque);
void qemu_aio_release(void *p);

View File

@ -421,6 +421,7 @@ snapshots.
* disk_images_nbd:: NBD access
* disk_images_sheepdog:: Sheepdog disk images
* disk_images_iscsi:: iSCSI LUNs
* disk_images_gluster:: GlusterFS disk images
@end menu
@node disk_images_quickstart
@ -814,7 +815,55 @@ qemu-system-i386 -iscsi initiator-name=iqn.qemu.test:my-initiator \
-cdrom iscsi://127.0.0.1/iqn.qemu.test/2
@end example
@node disk_images_gluster
@subsection GlusterFS disk images
GlusterFS is an user space distributed file system.
You can boot from the GlusterFS disk image with the command:
@example
qemu-system-x86_64 -drive file=gluster[+@var{transport}]://[@var{server}[:@var{port}]]/@var{volname}/@var{image}[?socket=...]
@end example
@var{gluster} is the protocol.
@var{transport} specifies the transport type used to connect to gluster
management daemon (glusterd). Valid transport types are
tcp, unix and rdma. If a transport type isn't specified, then tcp
type is assumed.
@var{server} specifies the server where the volume file specification for
the given volume resides. This can be either hostname, ipv4 address
or ipv6 address. ipv6 address needs to be within square brackets [ ].
If transport type is unix, then @var{server} field should not be specifed.
Instead @var{socket} field needs to be populated with the path to unix domain
socket.
@var{port} is the port number on which glusterd is listening. This is optional
and if not specified, QEMU will send 0 which will make gluster to use the
default port. If the transport type is unix, then @var{port} should not be
specified.
@var{volname} is the name of the gluster volume which contains the disk image.
@var{image} is the path to the actual disk image that resides on gluster volume.
You can create a GlusterFS disk image with the command:
@example
qemu-img create gluster://@var{server}/@var{volname}/@var{image} @var{size}
@end example
Examples
@example
qemu-system-x86_64 -drive file=gluster://1.2.3.4/testvol/a.img
qemu-system-x86_64 -drive file=gluster+tcp://1.2.3.4/testvol/a.img
qemu-system-x86_64 -drive file=gluster+tcp://1.2.3.4:24007/testvol/dir/a.img
qemu-system-x86_64 -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]/testvol/dir/a.img
qemu-system-x86_64 -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]:24007/testvol/dir/a.img
qemu-system-x86_64 -drive file=gluster+tcp://server.domain.com:24007/testvol/dir/a.img
qemu-system-x86_64 -drive file=gluster+unix:///testvol/dir/a.img?socket=/tmp/glusterd.socket
qemu-system-x86_64 -drive file=gluster+rdma://1.2.3.4:24007/testvol/a.img
@end example
@node pcsys_network
@section Network emulation

View File

@ -1362,7 +1362,7 @@ static int aio_write_f(int argc, char **argv)
static int aio_flush_f(int argc, char **argv)
{
qemu_aio_flush();
bdrv_drain_all();
return 0;
}

View File

@ -2054,6 +2054,23 @@ qemu-system-i386 --drive file=sheepdog:192.0.2.1:30000:MyVirtualMachine
See also @url{http://http://www.osrg.net/sheepdog/}.
@item GlusterFS
GlusterFS is an user space distributed file system.
QEMU supports the use of GlusterFS volumes for hosting VM disk images using
TCP, Unix Domain Sockets and RDMA transport protocols.
Syntax for specifying a VM disk image on GlusterFS volume is
@example
gluster[+transport]://[server[:port]]/volname/image[?socket=...]
@end example
Example
@example
qemu-system-x86_84 --drive file=gluster://192.0.2.1/testvol/a.img
@end example
See also @url{http://www.gluster.org}.
@end table
ETEXI

View File

@ -48,13 +48,17 @@ enum {
enum {
CMD_SENSE_INT = 0x08,
CMD_READ_ID = 0x0a,
CMD_SEEK = 0x0f,
CMD_VERIFY = 0x16,
CMD_READ = 0xe6,
CMD_RELATIVE_SEEK_OUT = 0x8f,
CMD_RELATIVE_SEEK_IN = 0xcf,
};
enum {
BUSY = 0x10,
NONDMA = 0x20,
RQM = 0x80,
DIO = 0x40,
@ -110,7 +114,7 @@ static void ack_irq(uint8_t *pcn)
g_assert(!get_irq(FLOPPY_IRQ));
}
static uint8_t send_read_command(void)
static uint8_t send_read_command(uint8_t cmd)
{
uint8_t drive = 0;
uint8_t head = 0;
@ -126,7 +130,7 @@ static uint8_t send_read_command(void)
uint8_t ret = 0;
floppy_send(CMD_READ);
floppy_send(cmd);
floppy_send(head << 2 | drive);
g_assert(!get_irq(FLOPPY_IRQ));
floppy_send(cyl);
@ -152,7 +156,70 @@ static uint8_t send_read_command(void)
}
st0 = floppy_recv();
if (st0 != 0x60) {
if (st0 != 0x40) {
ret = 1;
}
floppy_recv();
floppy_recv();
floppy_recv();
floppy_recv();
floppy_recv();
floppy_recv();
return ret;
}
static uint8_t send_read_no_dma_command(int nb_sect, uint8_t expected_st0)
{
uint8_t drive = 0;
uint8_t head = 0;
uint8_t cyl = 0;
uint8_t sect_addr = 1;
uint8_t sect_size = 2;
uint8_t eot = nb_sect;
uint8_t gap = 0x1b;
uint8_t gpl = 0xff;
uint8_t msr = 0;
uint8_t st0;
uint8_t ret = 0;
floppy_send(CMD_READ);
floppy_send(head << 2 | drive);
g_assert(!get_irq(FLOPPY_IRQ));
floppy_send(cyl);
floppy_send(head);
floppy_send(sect_addr);
floppy_send(sect_size);
floppy_send(eot);
floppy_send(gap);
floppy_send(gpl);
uint16_t i = 0;
uint8_t n = 2;
for (; i < n; i++) {
msr = inb(FLOPPY_BASE + reg_msr);
if (msr == (BUSY | NONDMA | DIO | RQM)) {
break;
}
sleep(1);
}
if (i >= n) {
return 1;
}
/* Non-DMA mode */
for (i = 0; i < 512 * 2 * nb_sect; i++) {
msr = inb(FLOPPY_BASE + reg_msr);
assert_bit_set(msr, BUSY | RQM | DIO);
inb(FLOPPY_BASE + reg_fifo);
}
st0 = floppy_recv();
if (st0 != expected_st0) {
ret = 1;
}
@ -213,11 +280,11 @@ static void test_read_without_media(void)
{
uint8_t ret;
ret = send_read_command();
ret = send_read_command(CMD_READ);
g_assert(ret == 0);
}
static void test_media_change(void)
static void test_media_insert(void)
{
uint8_t dir;
@ -245,6 +312,13 @@ static void test_media_change(void)
assert_bit_clear(dir, DSKCHG);
dir = inb(FLOPPY_BASE + reg_dir);
assert_bit_clear(dir, DSKCHG);
}
static void test_media_change(void)
{
uint8_t dir;
test_media_insert();
/* Eject the floppy and check that DSKCHG is set. Reading it out doesn't
* reset the bit. */
@ -320,6 +394,108 @@ static void test_relative_seek(void)
g_assert(pcn == 0);
}
static void test_read_id(void)
{
uint8_t drive = 0;
uint8_t head = 0;
uint8_t cyl;
uint8_t st0;
/* Seek to track 0 and check with READ ID */
send_seek(0);
floppy_send(CMD_READ_ID);
g_assert(!get_irq(FLOPPY_IRQ));
floppy_send(head << 2 | drive);
while (!get_irq(FLOPPY_IRQ)) {
/* qemu involves a timer with READ ID... */
clock_step(1000000000LL / 50);
}
st0 = floppy_recv();
floppy_recv();
floppy_recv();
cyl = floppy_recv();
head = floppy_recv();
floppy_recv();
floppy_recv();
g_assert_cmpint(cyl, ==, 0);
g_assert_cmpint(head, ==, 0);
g_assert_cmpint(st0, ==, head << 2);
/* Seek to track 8 on head 1 and check with READ ID */
head = 1;
cyl = 8;
floppy_send(CMD_SEEK);
floppy_send(head << 2 | drive);
g_assert(!get_irq(FLOPPY_IRQ));
floppy_send(cyl);
g_assert(get_irq(FLOPPY_IRQ));
ack_irq(NULL);
floppy_send(CMD_READ_ID);
g_assert(!get_irq(FLOPPY_IRQ));
floppy_send(head << 2 | drive);
while (!get_irq(FLOPPY_IRQ)) {
/* qemu involves a timer with READ ID... */
clock_step(1000000000LL / 50);
}
st0 = floppy_recv();
floppy_recv();
floppy_recv();
cyl = floppy_recv();
head = floppy_recv();
floppy_recv();
floppy_recv();
g_assert_cmpint(cyl, ==, 8);
g_assert_cmpint(head, ==, 1);
g_assert_cmpint(st0, ==, head << 2);
}
static void test_read_no_dma_1(void)
{
uint8_t ret;
outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08);
send_seek(0);
ret = send_read_no_dma_command(1, 0x04);
g_assert(ret == 0);
}
static void test_read_no_dma_18(void)
{
uint8_t ret;
outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08);
send_seek(0);
ret = send_read_no_dma_command(18, 0x04);
g_assert(ret == 0);
}
static void test_read_no_dma_19(void)
{
uint8_t ret;
outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08);
send_seek(0);
ret = send_read_no_dma_command(19, 0x20);
g_assert(ret == 0);
}
static void test_verify(void)
{
uint8_t ret;
ret = send_read_command(CMD_VERIFY);
g_assert(ret == 0);
}
/* success if no crash or abort */
static void fuzz_registers(void)
{
@ -369,6 +545,12 @@ int main(int argc, char **argv)
qtest_add_func("/fdc/media_change", test_media_change);
qtest_add_func("/fdc/sense_interrupt", test_sense_interrupt);
qtest_add_func("/fdc/relative_seek", test_relative_seek);
qtest_add_func("/fdc/read_id", test_read_id);
qtest_add_func("/fdc/verify", test_verify);
qtest_add_func("/fdc/media_insert", test_media_insert);
qtest_add_func("/fdc/read_no_dma_1", test_read_no_dma_1);
qtest_add_func("/fdc/read_no_dma_18", test_read_no_dma_18);
qtest_add_func("/fdc/read_no_dma_19", test_read_no_dma_19);
qtest_add_func("/fdc/fuzz-registers", fuzz_registers);
ret = g_test_run();

117
tests/qemu-iotests/044 Executable file
View File

@ -0,0 +1,117 @@
#!/usr/bin/env python
#
# Tests growing a large refcount table.
#
# Copyright (C) 2012 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 time
import os
import qcow2
from qcow2 import QcowHeader
import iotests
from iotests import qemu_img, qemu_img_verbose, qemu_io
import struct
import subprocess
test_img = os.path.join(iotests.test_dir, 'test.img')
class TestRefcountTableGrowth(iotests.QMPTestCase):
'''Abstract base class for image mirroring test cases'''
def preallocate(self, name):
fd = open(name, "r+b")
try:
off_reftable = 512
off_refblock = off_reftable + (512 * 512)
off_l1 = off_refblock + (512 * 512 * 64)
off_l2 = off_l1 + (512 * 512 * 4 * 8)
off_data = off_l2 + (512 * 512 * 4 * 512)
# Write a new header
h = QcowHeader(fd)
h.refcount_table_offset = off_reftable
h.refcount_table_clusters = 512
h.l1_table_offset = off_l1
h.l1_size = 512 * 512 * 4
h.update(fd)
# Write a refcount table
fd.seek(off_reftable)
for i in xrange(0, h.refcount_table_clusters):
sector = ''.join(struct.pack('>Q',
off_refblock + i * 64 * 512 + j * 512)
for j in xrange(0, 64))
fd.write(sector)
# Write the refcount blocks
assert(fd.tell() == off_refblock)
sector = ''.join(struct.pack('>H', 1) for j in xrange(0, 64 * 256))
for block in xrange(0, h.refcount_table_clusters):
fd.write(sector)
# Write the L1 table
assert(fd.tell() == off_l1)
assert(off_l2 + 512 * h.l1_size == off_data)
table = ''.join(struct.pack('>Q', (1 << 63) | off_l2 + 512 * j)
for j in xrange(0, h.l1_size))
fd.write(table)
# Write the L2 tables
assert(fd.tell() == off_l2)
img_file_size = h.refcount_table_clusters * 64 * 256 * 512
remaining = img_file_size - off_data
off = off_data
while remaining > 1024 * 512:
pytable = list((1 << 63) | off + 512 * j
for j in xrange(0, 1024))
table = struct.pack('>1024Q', *pytable)
fd.write(table)
remaining = remaining - 1024 * 512
off = off + 1024 * 512
table = ''.join(struct.pack('>Q', (1 << 63) | off + 512 * j)
for j in xrange(0, remaining / 512))
fd.write(table)
# Data
fd.truncate(img_file_size)
finally:
fd.close()
def setUp(self):
qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=512', test_img, '16G')
self.preallocate(test_img)
pass
def tearDown(self):
os.remove(test_img)
pass
def test_grow_refcount_table(self):
qemu_io('-c', 'write 3800M 1M', test_img)
qemu_img_verbose('check' , test_img)
pass
if __name__ == '__main__':
iotests.main(supported_fmts=['qcow2'])

View File

@ -0,0 +1,6 @@
No errors were found on the image.
.
----------------------------------------------------------------------
Ran 1 tests
OK

View File

@ -136,6 +136,7 @@ check options
-vmdk test vmdk
-rbd test rbd
-sheepdog test sheepdog
-nbd test nbd
-xdiff graphical mode diff
-nocache use O_DIRECT on backing file
-misalign misalign memory allocations
@ -197,12 +198,14 @@ testlist options
IMGPROTO=rbd
xpand=false
;;
-sheepdog)
IMGPROTO=sheepdog
xpand=false
;;
-nbd)
IMGPROTO=nbd
xpand=false
;;
-nocache)
QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --nocache"
xpand=false
@ -350,7 +353,11 @@ fi
[ "$QEMU" = "" ] && _fatal "qemu not found"
[ "$QEMU_IMG" = "" ] && _fatal "qemu-img not found"
[ "$QEMU_IO" = "" ] && _fatal "qemu-img not found"
[ "$QEMU_IO" = "" ] && _fatal "qemu-io not found"
if [ "$IMGPROTO" = "nbd" ] ; then
[ "$QEMU_NBD" = "" ] && _fatal "qemu-nbd not found"
fi
if $valgrind; then
export REAL_QEMU_IO="$QEMU_IO_PROG"

View File

@ -90,21 +90,23 @@ export PS_ALL_FLAGS="-ef"
if [ -z "$QEMU_PROG" ]; then
export QEMU_PROG="`set_prog_path qemu`"
fi
[ "$QEMU_PROG" = "" ] && _fatal "qemu not found"
if [ -z "$QEMU_IMG_PROG" ]; then
export QEMU_IMG_PROG="`set_prog_path qemu-img`"
fi
[ "$QEMU_IMG_PROG" = "" ] && _fatal "qemu-img not found"
if [ -z "$QEMU_IO_PROG" ]; then
export QEMU_IO_PROG="`set_prog_path qemu-io`"
fi
[ "$QEMU_IO_PROG" = "" ] && _fatal "qemu-io not found"
if [ -z "$QEMU_NBD_PROG" ]; then
export QEMU_NBD_PROG="`set_prog_path qemu-nbd`"
fi
export QEMU=$QEMU_PROG
export QEMU_IMG=$QEMU_IMG_PROG
export QEMU_IO="$QEMU_IO_PROG $QEMU_IO_OPTIONS"
export QEMU_NBD=$QEMU_NBD_PROG
[ -f /etc/qemu-iotest.config ] && . /etc/qemu-iotest.config

View File

@ -49,6 +49,9 @@ umask 022
if [ "$IMGPROTO" = "file" ]; then
TEST_IMG=$TEST_DIR/t.$IMGFMT
elif [ "$IMGPROTO" = "nbd" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG="nbd:127.0.0.1:10810"
else
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
fi
@ -86,6 +89,13 @@ _make_test_img()
local extra_img_options=""
local image_size=$*
local optstr=""
local img_name=""
if [ -n "$TEST_IMG_FILE" ]; then
img_name=$TEST_IMG_FILE
else
img_name=$TEST_IMG
fi
if [ -n "$IMGOPTS" ]; then
optstr=$(_optstr_add "$optstr" "$IMGOPTS")
@ -104,7 +114,7 @@ _make_test_img()
fi
# XXX(hch): have global image options?
$QEMU_IMG create -f $IMGFMT $extra_img_options $TEST_IMG $image_size | \
$QEMU_IMG create -f $IMGFMT $extra_img_options $img_name $image_size | \
sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
-e "s#$TEST_DIR#TEST_DIR#g" \
-e "s#$IMGFMT#IMGFMT#g" \
@ -115,12 +125,23 @@ _make_test_img()
-e "s# compat6=\\(on\\|off\\)##g" \
-e "s# static=\\(on\\|off\\)##g" \
-e "s# lazy_refcounts=\\(on\\|off\\)##g"
# Start an NBD server on the image file, which is what we'll be talking to
if [ $IMGPROTO = "nbd" ]; then
eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 $TEST_IMG_FILE &"
QEMU_NBD_PID=$!
sleep 1 # FIXME: qemu-nbd needs to be listening before we continue
fi
}
_cleanup_test_img()
{
case "$IMGPROTO" in
nbd)
kill $QEMU_NBD_PID
rm -f $TEST_IMG_FILE
;;
file)
rm -f $TEST_DIR/t.$IMGFMT
rm -f $TEST_DIR/t.$IMGFMT.orig

View File

@ -50,3 +50,4 @@
041 rw auto backing
042 rw auto quick
043 rw auto backing
044 rw auto

View File

@ -42,6 +42,10 @@ def qemu_img(*args):
devnull = open('/dev/null', 'r+')
return subprocess.call(qemu_img_args + list(args), stdin=devnull, stdout=devnull)
def qemu_img_verbose(*args):
'''Run qemu-img without supressing its output and return the exit code'''
return subprocess.call(qemu_img_args + list(args))
def qemu_io(*args):
'''Run qemu-io and return the stdout data'''
args = qemu_io_args + list(args)
@ -182,4 +186,4 @@ def main(supported_fmts=[]):
try:
unittest.main(testRunner=MyTestRunner)
finally:
sys.stderr.write(re.sub(r'Ran (\d+) test[s] in [\d.]+s', r'Ran \1 tests', output.getvalue()))
sys.stderr.write(re.sub(r'Ran (\d+) tests? in [\d.]+s', r'Ran \1 tests', output.getvalue()))

View File

@ -233,6 +233,7 @@ def usage():
for name, handler, num_args, desc in cmds:
print " %-20s - %s" % (name, desc)
if __name__ == '__main__':
if len(sys.argv) < 3:
usage()
sys.exit(1)

View File

@ -216,7 +216,7 @@ static void thread_pool_cancel(BlockDriverAIOCB *acb)
qemu_mutex_unlock(&lock);
}
static AIOPool thread_pool_cb_pool = {
static const AIOCBInfo thread_pool_aiocb_info = {
.aiocb_size = sizeof(ThreadPoolElement),
.cancel = thread_pool_cancel,
};
@ -226,7 +226,7 @@ BlockDriverAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg,
{
ThreadPoolElement *req;
req = qemu_aio_get(&thread_pool_cb_pool, NULL, cb, opaque);
req = qemu_aio_get(&thread_pool_aiocb_info, NULL, cb, opaque);
req->func = func;
req->arg = arg;
req->state = THREAD_QUEUED;