提交 3dc10613 编写于 作者: P Peter Maydell

Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging

Pull request

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

# gpg: Signature made Mon Feb 16 15:45:53 2015 GMT using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg:                 aka "Stefan Hajnoczi <stefanha@gmail.com>"

* remotes/stefanha/tags/block-pull-request: (65 commits)
  block: Keep bdrv_check*_request()'s return value
  block: Remove "growable" from BDS
  block: Clamp BlockBackend requests
  qemu-io: Use BlockBackend
  qemu-io: Remove "growable" option
  qemu-io: Use blk_new_open() in openfile()
  qemu-nbd: Use blk_new_open() in main()
  qemu-img: Use BlockBackend as far as possible
  qemu-img: Use blk_new_open() in img_rebase()
  qemu-img: Use blk_new_open() in img_open()
  block/xen: Use blk_new_open() in blk_connect()
  blockdev: Use blk_new_open() in blockdev_init()
  iotests: Add test for driver=qcow2, format=qcow2
  block: Add Error parameter to bdrv_find_protocol()
  block: Add blk_new_open()
  block: Lift some BDS functions to the BlockBackend
  iotests: Add test for qemu-img convert to NBD
  qemu-img: Fix qemu-img convert -n
  qemu-iotests: Add 093 for IO throttling
  qemu-iotests: Allow caller to disable underscore convertion for qmp
  ...
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
...@@ -508,9 +508,8 @@ int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp) ...@@ -508,9 +508,8 @@ int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp)
Error *local_err = NULL; Error *local_err = NULL;
int ret; int ret;
drv = bdrv_find_protocol(filename, true); drv = bdrv_find_protocol(filename, true, errp);
if (drv == NULL) { if (drv == NULL) {
error_setg(errp, "Could not find protocol for file '%s'", filename);
return -ENOENT; return -ENOENT;
} }
...@@ -628,7 +627,8 @@ static BlockDriver *find_hdev_driver(const char *filename) ...@@ -628,7 +627,8 @@ static BlockDriver *find_hdev_driver(const char *filename)
} }
BlockDriver *bdrv_find_protocol(const char *filename, BlockDriver *bdrv_find_protocol(const char *filename,
bool allow_protocol_prefix) bool allow_protocol_prefix,
Error **errp)
{ {
BlockDriver *drv1; BlockDriver *drv1;
char protocol[128]; char protocol[128];
...@@ -666,6 +666,8 @@ BlockDriver *bdrv_find_protocol(const char *filename, ...@@ -666,6 +666,8 @@ BlockDriver *bdrv_find_protocol(const char *filename,
return drv1; return drv1;
} }
} }
error_setg(errp, "Unknown protocol '%s'", protocol);
return NULL; return NULL;
} }
...@@ -970,7 +972,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, ...@@ -970,7 +972,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
bs->zero_beyond_eof = true; bs->zero_beyond_eof = true;
open_flags = bdrv_open_flags(bs, flags); open_flags = bdrv_open_flags(bs, flags);
bs->read_only = !(open_flags & BDRV_O_RDWR); 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)) { if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) {
error_setg(errp, error_setg(errp,
...@@ -1136,9 +1137,8 @@ static int bdrv_fill_options(QDict **options, const char **pfilename, int flags, ...@@ -1136,9 +1137,8 @@ static int bdrv_fill_options(QDict **options, const char **pfilename, int flags,
} else { } else {
if (!drvname && protocol) { if (!drvname && protocol) {
if (filename) { if (filename) {
drv = bdrv_find_protocol(filename, parse_filename); drv = bdrv_find_protocol(filename, parse_filename, errp);
if (!drv) { if (!drv) {
error_setg(errp, "Unknown protocol");
return -EINVAL; return -EINVAL;
} }
...@@ -1885,7 +1885,6 @@ void bdrv_close(BlockDriverState *bs) ...@@ -1885,7 +1885,6 @@ void bdrv_close(BlockDriverState *bs)
bs->encrypted = 0; bs->encrypted = 0;
bs->valid_key = 0; bs->valid_key = 0;
bs->sg = 0; bs->sg = 0;
bs->growable = 0;
bs->zero_beyond_eof = false; bs->zero_beyond_eof = false;
QDECREF(bs->options); QDECREF(bs->options);
bs->options = NULL; bs->options = NULL;
...@@ -2645,25 +2644,17 @@ exit: ...@@ -2645,25 +2644,17 @@ exit:
static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset, static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
size_t size) size_t size)
{ {
int64_t len;
if (size > BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS) { if (size > BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS) {
return -EIO; return -EIO;
} }
if (!bdrv_is_inserted(bs)) if (!bdrv_is_inserted(bs)) {
return -ENOMEDIUM; return -ENOMEDIUM;
}
if (bs->growable) if (offset < 0) {
return 0;
len = bdrv_getlength(bs);
if (offset < 0)
return -EIO;
if ((offset > len) || (len - offset < size))
return -EIO; return -EIO;
}
return 0; return 0;
} }
...@@ -3042,10 +3033,10 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs, ...@@ -3042,10 +3033,10 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,
} }
/* Forward the request to the BlockDriver */ /* 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); ret = drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
} else { } else {
/* Read zeros after EOF of growable BDSes */ /* Read zeros after EOF */
int64_t total_sectors, max_nb_sectors; int64_t total_sectors, max_nb_sectors;
total_sectors = bdrv_nb_sectors(bs); total_sectors = bdrv_nb_sectors(bs);
...@@ -3107,8 +3098,10 @@ static int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs, ...@@ -3107,8 +3098,10 @@ static int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs,
if (!drv) { if (!drv) {
return -ENOMEDIUM; 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) { if (bs->copy_on_read) {
...@@ -3322,7 +3315,7 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs, ...@@ -3322,7 +3315,7 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
block_acct_highest_sector(&bs->stats, sector_num, nb_sectors); 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); bs->total_sectors = MAX(bs->total_sectors, sector_num + nb_sectors);
} }
...@@ -3351,8 +3344,10 @@ static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs, ...@@ -3351,8 +3344,10 @@ static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
if (bs->read_only) { if (bs->read_only) {
return -EACCES; 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 */ /* throttling disk I/O */
...@@ -4206,12 +4201,18 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, ...@@ -4206,12 +4201,18 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors) const uint8_t *buf, int nb_sectors)
{ {
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
if (!drv) int ret;
if (!drv) {
return -ENOMEDIUM; return -ENOMEDIUM;
if (!drv->bdrv_write_compressed) }
if (!drv->bdrv_write_compressed) {
return -ENOTSUP; 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)); assert(QLIST_EMPTY(&bs->dirty_bitmaps));
...@@ -5126,12 +5127,15 @@ static void coroutine_fn bdrv_discard_co_entry(void *opaque) ...@@ -5126,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 coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
int nb_sectors) int nb_sectors)
{ {
int max_discard; int max_discard, ret;
if (!bs->drv) { if (!bs->drv) {
return -ENOMEDIUM; 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) { } else if (bs->read_only) {
return -EROFS; return -EROFS;
} }
...@@ -5623,9 +5627,8 @@ void bdrv_img_create(const char *filename, const char *fmt, ...@@ -5623,9 +5627,8 @@ void bdrv_img_create(const char *filename, const char *fmt,
return; return;
} }
proto_drv = bdrv_find_protocol(filename, true); proto_drv = bdrv_find_protocol(filename, true, errp);
if (!proto_drv) { if (!proto_drv) {
error_setg(errp, "Unknown protocol '%s'", filename);
return; return;
} }
......
...@@ -31,6 +31,16 @@ struct BlockBackend { ...@@ -31,6 +31,16 @@ struct BlockBackend {
void *dev_opaque; 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); static void drive_info_del(DriveInfo *dinfo);
/* All the BlockBackends (except for hidden ones) */ /* All the BlockBackends (except for hidden ones) */
...@@ -91,6 +101,40 @@ BlockBackend *blk_new_with_bs(const char *name, Error **errp) ...@@ -91,6 +101,40 @@ BlockBackend *blk_new_with_bs(const char *name, Error **errp)
return blk; 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) static void blk_delete(BlockBackend *blk)
{ {
assert(!blk->refcnt); assert(!blk->refcnt);
...@@ -394,39 +438,137 @@ void blk_iostatus_enable(BlockBackend *blk) ...@@ -394,39 +438,137 @@ void blk_iostatus_enable(BlockBackend *blk)
bdrv_iostatus_enable(blk->bs); 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 blk_read(BlockBackend *blk, int64_t sector_num, uint8_t *buf,
int nb_sectors) 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); return bdrv_read(blk->bs, sector_num, buf, nb_sectors);
} }
int blk_read_unthrottled(BlockBackend *blk, int64_t sector_num, uint8_t *buf, int blk_read_unthrottled(BlockBackend *blk, int64_t sector_num, uint8_t *buf,
int nb_sectors) 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); 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 blk_write(BlockBackend *blk, int64_t sector_num, const uint8_t *buf,
int nb_sectors) 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); 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, BlockAIOCB *blk_aio_write_zeroes(BlockBackend *blk, int64_t sector_num,
int nb_sectors, BdrvRequestFlags flags, int nb_sectors, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque) 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, return bdrv_aio_write_zeroes(blk->bs, sector_num, nb_sectors, flags,
cb, opaque); cb, opaque);
} }
int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int count) 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); return bdrv_pread(blk->bs, offset, buf, count);
} }
int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int 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); return bdrv_pwrite(blk->bs, offset, buf, count);
} }
...@@ -440,10 +582,20 @@ void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr) ...@@ -440,10 +582,20 @@ void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr)
bdrv_get_geometry(blk->bs, 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, BlockAIOCB *blk_aio_readv(BlockBackend *blk, int64_t sector_num,
QEMUIOVector *iov, int nb_sectors, QEMUIOVector *iov, int nb_sectors,
BlockCompletionFunc *cb, void *opaque) 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); return bdrv_aio_readv(blk->bs, sector_num, iov, nb_sectors, cb, opaque);
} }
...@@ -451,6 +603,11 @@ BlockAIOCB *blk_aio_writev(BlockBackend *blk, int64_t sector_num, ...@@ -451,6 +603,11 @@ BlockAIOCB *blk_aio_writev(BlockBackend *blk, int64_t sector_num,
QEMUIOVector *iov, int nb_sectors, QEMUIOVector *iov, int nb_sectors,
BlockCompletionFunc *cb, void *opaque) 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); return bdrv_aio_writev(blk->bs, sector_num, iov, nb_sectors, cb, opaque);
} }
...@@ -464,6 +621,11 @@ BlockAIOCB *blk_aio_discard(BlockBackend *blk, ...@@ -464,6 +621,11 @@ BlockAIOCB *blk_aio_discard(BlockBackend *blk,
int64_t sector_num, int nb_sectors, int64_t sector_num, int nb_sectors,
BlockCompletionFunc *cb, void *opaque) 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); return bdrv_aio_discard(blk->bs, sector_num, nb_sectors, cb, opaque);
} }
...@@ -479,6 +641,15 @@ void blk_aio_cancel_async(BlockAIOCB *acb) ...@@ -479,6 +641,15 @@ void blk_aio_cancel_async(BlockAIOCB *acb)
int blk_aio_multiwrite(BlockBackend *blk, BlockRequest *reqs, int num_reqs) 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); return bdrv_aio_multiwrite(blk->bs, reqs, num_reqs);
} }
...@@ -495,6 +666,11 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, ...@@ -495,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 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); return bdrv_co_discard(blk->bs, sector_num, nb_sectors);
} }
...@@ -668,3 +844,51 @@ void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk, ...@@ -668,3 +844,51 @@ void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk,
{ {
return qemu_aio_get(aiocb_info, blk_bs(blk), cb, opaque); 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)
{
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);
}
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)
{
int ret = blk_check_request(blk, sector_num, nb_sectors);
if (ret < 0) {
return ret;
}
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);
}
...@@ -43,20 +43,23 @@ static void nbd_recv_coroutines_enter_all(NbdClientSession *s) ...@@ -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 */ /* finish any pending coroutines */
shutdown(client->sock, 2); shutdown(client->sock, 2);
nbd_recv_coroutines_enter_all(client); nbd_recv_coroutines_enter_all(client);
nbd_client_session_detach_aio_context(client); nbd_client_detach_aio_context(bs);
closesocket(client->sock); closesocket(client->sock);
client->sock = -1; client->sock = -1;
} }
static void nbd_reply_ready(void *opaque) static void nbd_reply_ready(void *opaque)
{ {
NbdClientSession *s = opaque; BlockDriverState *bs = opaque;
NbdClientSession *s = nbd_get_client_session(bs);
uint64_t i; uint64_t i;
int ret; int ret;
...@@ -89,28 +92,40 @@ static void nbd_reply_ready(void *opaque) ...@@ -89,28 +92,40 @@ static void nbd_reply_ready(void *opaque)
} }
fail: fail:
nbd_teardown_connection(s); nbd_teardown_connection(bs);
} }
static void nbd_restart_write(void *opaque) 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, static int nbd_co_send_request(BlockDriverState *bs,
struct nbd_request *request, struct nbd_request *request,
QEMUIOVector *qiov, int offset) QEMUIOVector *qiov, int offset)
{ {
NbdClientSession *s = nbd_get_client_session(bs);
AioContext *aio_context; AioContext *aio_context;
int rc, ret; int rc, ret, i;
qemu_co_mutex_lock(&s->send_mutex); 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(); 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, 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 (qiov) {
if (!s->is_unix) { if (!s->is_unix) {
socket_set_cork(s->sock, 1); socket_set_cork(s->sock, 1);
...@@ -129,7 +144,7 @@ static int nbd_co_send_request(NbdClientSession *s, ...@@ -129,7 +144,7 @@ static int nbd_co_send_request(NbdClientSession *s,
} else { } else {
rc = nbd_send_request(s->sock, request); 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; s->send_coroutine = NULL;
qemu_co_mutex_unlock(&s->send_mutex); qemu_co_mutex_unlock(&s->send_mutex);
return rc; return rc;
...@@ -164,8 +179,6 @@ static void nbd_co_receive_reply(NbdClientSession *s, ...@@ -164,8 +179,6 @@ static void nbd_co_receive_reply(NbdClientSession *s,
static void nbd_coroutine_start(NbdClientSession *s, static void nbd_coroutine_start(NbdClientSession *s,
struct nbd_request *request) struct nbd_request *request)
{ {
int i;
/* Poor man semaphore. The free_sema is locked when no other request /* Poor man semaphore. The free_sema is locked when no other request
* can be accepted, and unlocked after receiving one reply. */ * can be accepted, and unlocked after receiving one reply. */
if (s->in_flight >= MAX_NBD_REQUESTS - 1) { if (s->in_flight >= MAX_NBD_REQUESTS - 1) {
...@@ -174,15 +187,7 @@ static void nbd_coroutine_start(NbdClientSession *s, ...@@ -174,15 +187,7 @@ static void nbd_coroutine_start(NbdClientSession *s,
} }
s->in_flight++; s->in_flight++;
for (i = 0; i < MAX_NBD_REQUESTS; i++) { /* s->recv_coroutine[i] is set as soon as we get the send_lock. */
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);
} }
static void nbd_coroutine_end(NbdClientSession *s, static void nbd_coroutine_end(NbdClientSession *s,
...@@ -195,10 +200,11 @@ static void nbd_coroutine_end(NbdClientSession *s, ...@@ -195,10 +200,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 nb_sectors, QEMUIOVector *qiov,
int offset) int offset)
{ {
NbdClientSession *client = nbd_get_client_session(bs);
struct nbd_request request = { .type = NBD_CMD_READ }; struct nbd_request request = { .type = NBD_CMD_READ };
struct nbd_reply reply; struct nbd_reply reply;
ssize_t ret; ssize_t ret;
...@@ -207,7 +213,7 @@ static int nbd_co_readv_1(NbdClientSession *client, int64_t sector_num, ...@@ -207,7 +213,7 @@ static int nbd_co_readv_1(NbdClientSession *client, int64_t sector_num,
request.len = nb_sectors * 512; request.len = nb_sectors * 512;
nbd_coroutine_start(client, &request); 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) { if (ret < 0) {
reply.error = -ret; reply.error = -ret;
} else { } else {
...@@ -218,15 +224,16 @@ static int nbd_co_readv_1(NbdClientSession *client, int64_t sector_num, ...@@ -218,15 +224,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 nb_sectors, QEMUIOVector *qiov,
int offset) int offset)
{ {
NbdClientSession *client = nbd_get_client_session(bs);
struct nbd_request request = { .type = NBD_CMD_WRITE }; struct nbd_request request = { .type = NBD_CMD_WRITE };
struct nbd_reply reply; struct nbd_reply reply;
ssize_t ret; ssize_t ret;
if (!bdrv_enable_write_cache(client->bs) && if (!bdrv_enable_write_cache(bs) &&
(client->nbdflags & NBD_FLAG_SEND_FUA)) { (client->nbdflags & NBD_FLAG_SEND_FUA)) {
request.type |= NBD_CMD_FLAG_FUA; request.type |= NBD_CMD_FLAG_FUA;
} }
...@@ -235,7 +242,7 @@ static int nbd_co_writev_1(NbdClientSession *client, int64_t sector_num, ...@@ -235,7 +242,7 @@ static int nbd_co_writev_1(NbdClientSession *client, int64_t sector_num,
request.len = nb_sectors * 512; request.len = nb_sectors * 512;
nbd_coroutine_start(client, &request); 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) { if (ret < 0) {
reply.error = -ret; reply.error = -ret;
} else { } else {
...@@ -249,14 +256,13 @@ static int nbd_co_writev_1(NbdClientSession *client, int64_t sector_num, ...@@ -249,14 +256,13 @@ static int nbd_co_writev_1(NbdClientSession *client, int64_t sector_num,
* remain aligned to 4K. */ * remain aligned to 4K. */
#define NBD_MAX_SECTORS 2040 #define NBD_MAX_SECTORS 2040
int nbd_client_session_co_readv(NbdClientSession *client, int64_t sector_num, int nbd_client_co_readv(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov) int nb_sectors, QEMUIOVector *qiov)
{ {
int offset = 0; int offset = 0;
int ret; int ret;
while (nb_sectors > NBD_MAX_SECTORS) { while (nb_sectors > NBD_MAX_SECTORS) {
ret = nbd_co_readv_1(client, sector_num, ret = nbd_co_readv_1(bs, sector_num, NBD_MAX_SECTORS, qiov, offset);
NBD_MAX_SECTORS, qiov, offset);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
...@@ -264,17 +270,16 @@ int nbd_client_session_co_readv(NbdClientSession *client, int64_t sector_num, ...@@ -264,17 +270,16 @@ int nbd_client_session_co_readv(NbdClientSession *client, int64_t sector_num,
sector_num += NBD_MAX_SECTORS; sector_num += NBD_MAX_SECTORS;
nb_sectors -= 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 nbd_client_co_writev(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov) int nb_sectors, QEMUIOVector *qiov)
{ {
int offset = 0; int offset = 0;
int ret; int ret;
while (nb_sectors > NBD_MAX_SECTORS) { while (nb_sectors > NBD_MAX_SECTORS) {
ret = nbd_co_writev_1(client, sector_num, ret = nbd_co_writev_1(bs, sector_num, NBD_MAX_SECTORS, qiov, offset);
NBD_MAX_SECTORS, qiov, offset);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
...@@ -282,11 +287,12 @@ int nbd_client_session_co_writev(NbdClientSession *client, int64_t sector_num, ...@@ -282,11 +287,12 @@ int nbd_client_session_co_writev(NbdClientSession *client, int64_t sector_num,
sector_num += NBD_MAX_SECTORS; sector_num += NBD_MAX_SECTORS;
nb_sectors -= 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_request request = { .type = NBD_CMD_FLUSH };
struct nbd_reply reply; struct nbd_reply reply;
ssize_t ret; ssize_t ret;
...@@ -303,7 +309,7 @@ int nbd_client_session_co_flush(NbdClientSession *client) ...@@ -303,7 +309,7 @@ int nbd_client_session_co_flush(NbdClientSession *client)
request.len = 0; request.len = 0;
nbd_coroutine_start(client, &request); 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) { if (ret < 0) {
reply.error = -ret; reply.error = -ret;
} else { } else {
...@@ -313,9 +319,10 @@ int nbd_client_session_co_flush(NbdClientSession *client) ...@@ -313,9 +319,10 @@ int nbd_client_session_co_flush(NbdClientSession *client)
return -reply.error; return -reply.error;
} }
int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num, int nbd_client_co_discard(BlockDriverState *bs, int64_t sector_num,
int nb_sectors) int nb_sectors)
{ {
NbdClientSession *client = nbd_get_client_session(bs);
struct nbd_request request = { .type = NBD_CMD_TRIM }; struct nbd_request request = { .type = NBD_CMD_TRIM };
struct nbd_reply reply; struct nbd_reply reply;
ssize_t ret; ssize_t ret;
...@@ -327,7 +334,7 @@ int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num, ...@@ -327,7 +334,7 @@ int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num,
request.len = nb_sectors * 512; request.len = nb_sectors * 512;
nbd_coroutine_start(client, &request); 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) { if (ret < 0) {
reply.error = -ret; reply.error = -ret;
} else { } else {
...@@ -338,43 +345,41 @@ int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num, ...@@ -338,43 +345,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, aio_set_fd_handler(bdrv_get_aio_context(bs),
NULL, NULL, NULL); nbd_get_client_session(bs)->sock, NULL, NULL, NULL);
} }
void nbd_client_session_attach_aio_context(NbdClientSession *client, void nbd_client_attach_aio_context(BlockDriverState *bs,
AioContext *new_context) AioContext *new_context)
{ {
aio_set_fd_handler(new_context, client->sock, aio_set_fd_handler(new_context, nbd_get_client_session(bs)->sock,
nbd_reply_ready, NULL, client); 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 = { struct nbd_request request = {
.type = NBD_CMD_DISC, .type = NBD_CMD_DISC,
.from = 0, .from = 0,
.len = 0 .len = 0
}; };
if (!client->bs) {
return;
}
if (client->sock == -1) { if (client->sock == -1) {
return; return;
} }
nbd_send_request(client->sock, &request); nbd_send_request(client->sock, &request);
nbd_teardown_connection(client); nbd_teardown_connection(bs);
client->bs = NULL;
} }
int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs, int nbd_client_init(BlockDriverState *bs, int sock, const char *export,
int sock, const char *export, Error **errp) Error **errp)
{ {
NbdClientSession *client = nbd_get_client_session(bs);
int ret; int ret;
/* NBD handshake */ /* NBD handshake */
...@@ -391,13 +396,12 @@ int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs, ...@@ -391,13 +396,12 @@ int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs,
qemu_co_mutex_init(&client->send_mutex); qemu_co_mutex_init(&client->send_mutex);
qemu_co_mutex_init(&client->free_sema); qemu_co_mutex_init(&client->free_sema);
client->bs = bs;
client->sock = sock; client->sock = sock;
/* Now that we're connected, set the socket to be non-blocking and /* Now that we're connected, set the socket to be non-blocking and
* kick the reply mechanism. */ * kick the reply mechanism. */
qemu_set_nonblock(sock); 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"); logout("Established connection with NBD server\n");
return 0; return 0;
......
...@@ -31,24 +31,24 @@ typedef struct NbdClientSession { ...@@ -31,24 +31,24 @@ typedef struct NbdClientSession {
struct nbd_reply reply; struct nbd_reply reply;
bool is_unix; bool is_unix;
BlockDriverState *bs;
} NbdClientSession; } NbdClientSession;
int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs, NbdClientSession *nbd_get_client_session(BlockDriverState *bs);
int sock, const char *export_name, Error **errp);
void nbd_client_session_close(NbdClientSession *client); int nbd_client_init(BlockDriverState *bs, int sock, const char *export_name,
Error **errp);
int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num, void nbd_client_close(BlockDriverState *bs);
int nb_sectors);
int nbd_client_session_co_flush(NbdClientSession *client); int nbd_client_co_discard(BlockDriverState *bs, int64_t sector_num,
int nbd_client_session_co_writev(NbdClientSession *client, int64_t sector_num, int nb_sectors);
int nb_sectors, QEMUIOVector *qiov); int nbd_client_co_flush(BlockDriverState *bs);
int nbd_client_session_co_readv(NbdClientSession *client, int64_t sector_num, int nbd_client_co_writev(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov); int nb_sectors, QEMUIOVector *qiov);
int nbd_client_co_readv(BlockDriverState *bs, int64_t sector_num,
void nbd_client_session_detach_aio_context(NbdClientSession *client); int nb_sectors, QEMUIOVector *qiov);
void nbd_client_session_attach_aio_context(NbdClientSession *client,
AioContext *new_context); void nbd_client_detach_aio_context(BlockDriverState *bs);
void nbd_client_attach_aio_context(BlockDriverState *bs,
AioContext *new_context);
#endif /* NBD_CLIENT_H */ #endif /* NBD_CLIENT_H */
...@@ -224,6 +224,12 @@ static void nbd_config(BDRVNBDState *s, QDict *options, char **export, ...@@ -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) static int nbd_establish_connection(BlockDriverState *bs, Error **errp)
{ {
BDRVNBDState *s = bs->opaque; BDRVNBDState *s = bs->opaque;
...@@ -271,7 +277,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, ...@@ -271,7 +277,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
} }
/* NBD handshake */ /* NBD handshake */
result = nbd_client_session_init(&s->client, bs, sock, export, errp); result = nbd_client_init(bs, sock, export, errp);
g_free(export); g_free(export);
return result; return result;
} }
...@@ -279,26 +285,18 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, ...@@ -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, static int nbd_co_readv(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov) int nb_sectors, QEMUIOVector *qiov)
{ {
BDRVNBDState *s = bs->opaque; return nbd_client_co_readv(bs, sector_num, nb_sectors, qiov);
return nbd_client_session_co_readv(&s->client, sector_num,
nb_sectors, qiov);
} }
static int nbd_co_writev(BlockDriverState *bs, int64_t sector_num, static int nbd_co_writev(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov) int nb_sectors, QEMUIOVector *qiov)
{ {
BDRVNBDState *s = bs->opaque; return nbd_client_co_writev(bs, sector_num, nb_sectors, qiov);
return nbd_client_session_co_writev(&s->client, sector_num,
nb_sectors, qiov);
} }
static int nbd_co_flush(BlockDriverState *bs) static int nbd_co_flush(BlockDriverState *bs)
{ {
BDRVNBDState *s = bs->opaque; return nbd_client_co_flush(bs);
return nbd_client_session_co_flush(&s->client);
} }
static void nbd_refresh_limits(BlockDriverState *bs, Error **errp) static void nbd_refresh_limits(BlockDriverState *bs, Error **errp)
...@@ -310,10 +308,7 @@ 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, static int nbd_co_discard(BlockDriverState *bs, int64_t sector_num,
int nb_sectors) int nb_sectors)
{ {
BDRVNBDState *s = bs->opaque; return nbd_client_co_discard(bs, sector_num, nb_sectors);
return nbd_client_session_co_discard(&s->client, sector_num,
nb_sectors);
} }
static void nbd_close(BlockDriverState *bs) static void nbd_close(BlockDriverState *bs)
...@@ -321,7 +316,7 @@ static void nbd_close(BlockDriverState *bs) ...@@ -321,7 +316,7 @@ static void nbd_close(BlockDriverState *bs)
BDRVNBDState *s = bs->opaque; BDRVNBDState *s = bs->opaque;
qemu_opts_del(s->socket_opts); qemu_opts_del(s->socket_opts);
nbd_client_session_close(&s->client); nbd_client_close(bs);
} }
static int64_t nbd_getlength(BlockDriverState *bs) static int64_t nbd_getlength(BlockDriverState *bs)
...@@ -333,17 +328,13 @@ 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) static void nbd_detach_aio_context(BlockDriverState *bs)
{ {
BDRVNBDState *s = bs->opaque; nbd_client_detach_aio_context(bs);
nbd_client_session_detach_aio_context(&s->client);
} }
static void nbd_attach_aio_context(BlockDriverState *bs, static void nbd_attach_aio_context(BlockDriverState *bs,
AioContext *new_context) AioContext *new_context)
{ {
BDRVNBDState *s = bs->opaque; nbd_client_attach_aio_context(bs, new_context);
nbd_client_session_attach_aio_context(&s->client, new_context);
} }
static void nbd_refresh_filename(BlockDriverState *bs) static void nbd_refresh_filename(BlockDriverState *bs)
......
...@@ -2521,15 +2521,12 @@ static int qcow2_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, ...@@ -2521,15 +2521,12 @@ static int qcow2_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
{ {
BDRVQcowState *s = bs->opaque; BDRVQcowState *s = bs->opaque;
int64_t total_sectors = bs->total_sectors; int64_t total_sectors = bs->total_sectors;
int growable = bs->growable;
bool zero_beyond_eof = bs->zero_beyond_eof; bool zero_beyond_eof = bs->zero_beyond_eof;
int ret; int ret;
BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_SAVE); BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_SAVE);
bs->growable = 1;
bs->zero_beyond_eof = false; bs->zero_beyond_eof = false;
ret = bdrv_pwritev(bs, qcow2_vm_state_offset(s) + pos, qiov); ret = bdrv_pwritev(bs, qcow2_vm_state_offset(s) + pos, qiov);
bs->growable = growable;
bs->zero_beyond_eof = zero_beyond_eof; bs->zero_beyond_eof = zero_beyond_eof;
/* bdrv_co_do_writev will have increased the total_sectors value to include /* 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, ...@@ -2544,15 +2541,12 @@ static int qcow2_load_vmstate(BlockDriverState *bs, uint8_t *buf,
int64_t pos, int size) int64_t pos, int size)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcowState *s = bs->opaque;
int growable = bs->growable;
bool zero_beyond_eof = bs->zero_beyond_eof; bool zero_beyond_eof = bs->zero_beyond_eof;
int ret; int ret;
BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_LOAD); BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_LOAD);
bs->growable = 1;
bs->zero_beyond_eof = false; bs->zero_beyond_eof = false;
ret = bdrv_pread(bs, qcow2_vm_state_offset(s) + pos, buf, size); ret = bdrv_pread(bs, qcow2_vm_state_offset(s) + pos, buf, size);
bs->growable = growable;
bs->zero_beyond_eof = zero_beyond_eof; bs->zero_beyond_eof = zero_beyond_eof;
return ret; return ret;
......
...@@ -1047,7 +1047,7 @@ static int aio_worker(void *arg) ...@@ -1047,7 +1047,7 @@ static int aio_worker(void *arg)
switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) { switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
case QEMU_AIO_READ: case QEMU_AIO_READ:
ret = handle_aiocb_rw(aiocb); 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, iov_memset(aiocb->aio_iov, aiocb->aio_niov, ret,
0, aiocb->aio_nbytes - ret); 0, aiocb->aio_nbytes - ret);
......
...@@ -101,7 +101,7 @@ static int aio_worker(void *arg) ...@@ -101,7 +101,7 @@ static int aio_worker(void *arg)
switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) { switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
case QEMU_AIO_READ: case QEMU_AIO_READ:
count = handle_aiocb_rw(aiocb); 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 /* A short read means that we have reached EOF. Pad the buffer
* with zeros for bytes after EOF. */ * with zeros for bytes after EOF. */
iov_memset(aiocb->aio_iov, aiocb->aio_niov, count, iov_memset(aiocb->aio_iov, aiocb->aio_niov, count,
......
...@@ -1730,7 +1730,7 @@ static int sd_create(const char *filename, QemuOpts *opts, ...@@ -1730,7 +1730,7 @@ static int sd_create(const char *filename, QemuOpts *opts,
BlockDriver *drv; BlockDriver *drv;
/* Currently, only Sheepdog backing image is supported. */ /* 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) { if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) {
error_setg(errp, "backing_file must be a sheepdog image"); error_setg(errp, "backing_file must be a sheepdog image");
ret = -EINVAL; ret = -EINVAL;
...@@ -2117,7 +2117,7 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num, ...@@ -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; int64_t offset = (sector_num + nb_sectors) * BDRV_SECTOR_SIZE;
BDRVSheepdogState *s = bs->opaque; BDRVSheepdogState *s = bs->opaque;
if (bs->growable && offset > s->inode.vdi_size) { if (offset > s->inode.vdi_size) {
ret = sd_truncate(bs, offset); ret = sd_truncate(bs, offset);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
......
...@@ -843,8 +843,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, ...@@ -843,8 +843,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
} }
extent_path = g_malloc0(PATH_MAX); extent_path = g_malloc0(PATH_MAX);
path_combine(extent_path, sizeof(extent_path), path_combine(extent_path, PATH_MAX, desc_file_path, fname);
desc_file_path, fname);
extent_file = NULL; extent_file = NULL;
ret = bdrv_open(&extent_file, extent_path, NULL, NULL, ret = bdrv_open(&extent_file, extent_path, NULL, NULL,
bs->open_flags | BDRV_O_PROTOCOL, NULL, errp); bs->open_flags | BDRV_O_PROTOCOL, NULL, errp);
......
...@@ -354,13 +354,11 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, ...@@ -354,13 +354,11 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
ThrottleConfig cfg; ThrottleConfig cfg;
int snapshot = 0; int snapshot = 0;
bool copy_on_read; bool copy_on_read;
int ret;
Error *error = NULL; Error *error = NULL;
QemuOpts *opts; QemuOpts *opts;
const char *id; const char *id;
bool has_driver_specific_opts; bool has_driver_specific_opts;
BlockdevDetectZeroesOptions detect_zeroes; BlockdevDetectZeroesOptions detect_zeroes;
BlockDriver *drv = NULL;
/* Check common options by copying from bs_opts to opts, all other options /* Check common options by copying from bs_opts to opts, all other options
* stay in bs_opts for processing by bdrv_open(). */ * stay in bs_opts for processing by bdrv_open(). */
...@@ -426,11 +424,11 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, ...@@ -426,11 +424,11 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
goto early_err; goto early_err;
} }
drv = bdrv_find_format(buf); if (qdict_haskey(bs_opts, "driver")) {
if (!drv) { error_setg(errp, "Cannot specify both 'driver' and 'format'");
error_setg(errp, "'%s' invalid format", buf);
goto early_err; goto early_err;
} }
qdict_put(bs_opts, "driver", qstring_from_str(buf));
} }
/* disk I/O throttling */ /* disk I/O throttling */
...@@ -505,70 +503,64 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, ...@@ -505,70 +503,64 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
} }
/* init */ /* init */
blk = blk_new_with_bs(qemu_opts_id(opts), errp); if ((!file || !*file) && !has_driver_specific_opts) {
if (!blk) { blk = blk_new_with_bs(qemu_opts_id(opts), errp);
goto early_err; 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);
/* disk I/O throttling */ bs = blk_bs(blk);
if (throttle_enabled(&cfg)) { bs->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
bdrv_io_limits_enable(bs); bs->read_only = ro;
bdrv_set_io_limits(bs, &cfg);
}
if (!file || !*file) { QDECREF(bs_opts);
if (has_driver_specific_opts) { } else {
if (file && !*file) {
file = NULL; 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) { if (snapshot) {
bdrv_flags |= BDRV_O_COPY_ON_READ; /* 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 |= ro ? 0 : BDRV_O_RDWR;
bdrv_flags |= BDRV_O_INCOMING;
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); bdrv_set_on_error(bs, on_read_error, on_write_error);
ret = bdrv_open(&bs, file, NULL, bs_opts, bdrv_flags, drv, &error);
assert(bs == blk_bs(blk));
if (ret < 0) { /* disk I/O throttling */
error_setg(errp, "could not open disk image %s: %s", if (throttle_enabled(&cfg)) {
file ?: blk_name(blk), error_get_pretty(error)); bdrv_io_limits_enable(bs);
error_free(error); bdrv_set_io_limits(bs, &cfg);
goto err;
} }
if (bdrv_key_required(bs)) { if (bdrv_key_required(bs)) {
autostart = 0; autostart = 0;
} }
QDECREF(bs_opts); err_no_bs_opts:
qemu_opts_del(opts); qemu_opts_del(opts);
return blk; return blk;
err:
blk_unref(blk);
early_err: early_err:
qemu_opts_del(opts); qemu_opts_del(opts);
err_no_opts: err_no_opts:
......
...@@ -361,15 +361,19 @@ static void icount_warp_rt(void *opaque) ...@@ -361,15 +361,19 @@ static void icount_warp_rt(void *opaque)
void qtest_clock_warp(int64_t dest) void qtest_clock_warp(int64_t dest)
{ {
int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
AioContext *aio_context;
assert(qtest_enabled()); assert(qtest_enabled());
aio_context = qemu_get_aio_context();
while (clock < dest) { while (clock < dest) {
int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
int64_t warp = qemu_soonest_timeout(dest - clock, deadline); int64_t warp = qemu_soonest_timeout(dest - clock, deadline);
seqlock_write_lock(&timers_state.vm_clock_seqlock); seqlock_write_lock(&timers_state.vm_clock_seqlock);
timers_state.qemu_icount_bias += warp; timers_state.qemu_icount_bias += warp;
seqlock_write_unlock(&timers_state.vm_clock_seqlock); seqlock_write_unlock(&timers_state.vm_clock_seqlock);
qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL); 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); clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
} }
qemu_clock_notify(QEMU_CLOCK_VIRTUAL); qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "hmp.h" #include "hmp.h"
#include "net/net.h" #include "net/net.h"
#include "sysemu/char.h" #include "sysemu/char.h"
#include "sysemu/block-backend.h"
#include "qemu/option.h" #include "qemu/option.h"
#include "qemu/timer.h" #include "qemu/timer.h"
#include "qmp-commands.h" #include "qmp-commands.h"
...@@ -1720,14 +1721,14 @@ void hmp_chardev_remove(Monitor *mon, const QDict *qdict) ...@@ -1720,14 +1721,14 @@ void hmp_chardev_remove(Monitor *mon, const QDict *qdict)
void hmp_qemu_io(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* device = qdict_get_str(qdict, "device");
const char* command = qdict_get_str(qdict, "command"); const char* command = qdict_get_str(qdict, "command");
Error *err = NULL; Error *err = NULL;
bs = bdrv_find(device); blk = blk_by_name(device);
if (bs) { if (blk) {
qemuio_command(bs, command); qemuio_command(blk, command);
} else { } else {
error_set(&err, QERR_DEVICE_NOT_FOUND, device); error_set(&err, QERR_DEVICE_NOT_FOUND, device);
} }
......
...@@ -16,7 +16,9 @@ ...@@ -16,7 +16,9 @@
#include "qemu/iov.h" #include "qemu/iov.h"
#include "qemu/thread.h" #include "qemu/thread.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "hw/virtio/virtio-access.h"
#include "hw/virtio/dataplane/vring.h" #include "hw/virtio/dataplane/vring.h"
#include "hw/virtio/dataplane/vring-accessors.h"
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "hw/virtio/virtio-blk.h" #include "hw/virtio/virtio-blk.h"
#include "virtio-blk.h" #include "virtio-blk.h"
...@@ -75,7 +77,7 @@ static void complete_request_vring(VirtIOBlockReq *req, unsigned char status) ...@@ -75,7 +77,7 @@ static void complete_request_vring(VirtIOBlockReq *req, unsigned char status)
VirtIOBlockDataPlane *s = req->dev->dataplane; VirtIOBlockDataPlane *s = req->dev->dataplane;
stb_p(&req->in->status, status); 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)); req->qiov.size + sizeof(*req->in));
/* Suppress notification to guest by BH and its scheduled /* Suppress notification to guest by BH and its scheduled
......
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
#include "xen_blkif.h" #include "xen_blkif.h"
#include "sysemu/blockdev.h" #include "sysemu/blockdev.h"
#include "sysemu/block-backend.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) ...@@ -897,30 +899,23 @@ static int blk_connect(struct XenDevice *xendev)
blkdev->dinfo = drive_get(IF_XEN, 0, index); blkdev->dinfo = drive_get(IF_XEN, 0, index);
if (!blkdev->dinfo) { if (!blkdev->dinfo) {
Error *local_err = NULL; Error *local_err = NULL;
BlockBackend *blk; QDict *options = NULL;
BlockDriver *drv;
BlockDriverState *bs;
/* setup via xenbus -> create new block driver instance */ if (strcmp(blkdev->fileproto, "<unset>")) {
xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n"); options = qdict_new();
blk = blk_new_with_bs(blkdev->dev, NULL); qdict_put(options, "driver", qstring_from_str(blkdev->fileproto));
if (!blk) {
return -1;
} }
blkdev->blk = blk;
bs = blk_bs(blk); /* setup via xenbus -> create new block driver instance */
drv = bdrv_find_whitelisted_format(blkdev->fileproto, readonly); xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
if (bdrv_open(&bs, blkdev->filename, NULL, NULL, qflags, blkdev->blk = blk_new_open(blkdev->dev, blkdev->filename, NULL, options,
drv, &local_err) != 0) { qflags, &local_err);
if (!blkdev->blk) {
xen_be_printf(&blkdev->xendev, 0, "error: %s\n", xen_be_printf(&blkdev->xendev, 0, "error: %s\n",
error_get_pretty(local_err)); error_get_pretty(local_err));
error_free(local_err); error_free(local_err);
blk_unref(blk);
blkdev->blk = NULL;
return -1; return -1;
} }
assert(bs == blk_bs(blk));
} else { } else {
/* setup via qemu cmdline -> already setup for us */ /* setup via qemu cmdline -> already setup for us */
xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n"); xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
......
...@@ -94,7 +94,7 @@ void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req) ...@@ -94,7 +94,7 @@ void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req)
{ {
VirtIODevice *vdev = VIRTIO_DEVICE(req->vring->parent); 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); req->qsgl.size + req->resp_iov.size);
if (vring_should_notify(vdev, &req->vring->vring)) { if (vring_should_notify(vdev, &req->vring->vring)) {
......
...@@ -2,7 +2,7 @@ common-obj-y += virtio-rng.o ...@@ -2,7 +2,7 @@ common-obj-y += virtio-rng.o
common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
common-obj-y += virtio-bus.o common-obj-y += virtio-bus.o
common-obj-y += virtio-mmio.o common-obj-y += virtio-mmio.o
common-obj-$(CONFIG_VIRTIO) += dataplane/ obj-$(CONFIG_VIRTIO) += dataplane/
obj-y += virtio.o virtio-balloon.o obj-y += virtio.o virtio-balloon.o
obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o
common-obj-y += vring.o obj-y += vring.o
...@@ -18,7 +18,9 @@ ...@@ -18,7 +18,9 @@
#include "hw/hw.h" #include "hw/hw.h"
#include "exec/memory.h" #include "exec/memory.h"
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
#include "hw/virtio/virtio-access.h"
#include "hw/virtio/dataplane/vring.h" #include "hw/virtio/dataplane/vring.h"
#include "hw/virtio/dataplane/vring-accessors.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
/* vring_map can be coupled with vring_unmap or (if you still have the /* 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) ...@@ -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_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_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 = 0;
vring->signalled_used_valid = false; vring->signalled_used_valid = false;
...@@ -104,7 +106,7 @@ void vring_teardown(Vring *vring, VirtIODevice *vdev, int n) ...@@ -104,7 +106,7 @@ void vring_teardown(Vring *vring, VirtIODevice *vdev, int n)
void vring_disable_notification(VirtIODevice *vdev, Vring *vring) void vring_disable_notification(VirtIODevice *vdev, Vring *vring)
{ {
if (!(vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX))) { 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) ...@@ -117,10 +119,10 @@ bool vring_enable_notification(VirtIODevice *vdev, Vring *vring)
if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) { if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
vring_avail_event(&vring->vr) = vring->vr.avail->idx; vring_avail_event(&vring->vr) = vring->vr.avail->idx;
} else { } 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 */ 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() */ /* This is stolen from linux/drivers/vhost/vhost.c:vhost_notify() */
...@@ -134,12 +136,13 @@ bool vring_should_notify(VirtIODevice *vdev, Vring *vring) ...@@ -134,12 +136,13 @@ bool vring_should_notify(VirtIODevice *vdev, Vring *vring)
smp_mb(); smp_mb();
if ((vdev->guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) && 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; return true;
} }
if (!(vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX))) { 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; old = vring->signalled_used;
v = vring->signalled_used_valid; v = vring->signalled_used_valid;
...@@ -202,9 +205,19 @@ static int get_desc(Vring *vring, VirtQueueElement *elem, ...@@ -202,9 +205,19 @@ static int get_desc(Vring *vring, VirtQueueElement *elem,
return 0; 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. */ /* This is stolen from linux/drivers/vhost/vhost.c. */
static int get_indirect(Vring *vring, VirtQueueElement *elem, static int get_indirect(VirtIODevice *vdev, Vring *vring,
struct vring_desc *indirect) VirtQueueElement *elem, struct vring_desc *indirect)
{ {
struct vring_desc desc; struct vring_desc desc;
unsigned int i = 0, count, found = 0; unsigned int i = 0, count, found = 0;
...@@ -244,7 +257,7 @@ static int get_indirect(Vring *vring, VirtQueueElement *elem, ...@@ -244,7 +257,7 @@ static int get_indirect(Vring *vring, VirtQueueElement *elem,
vring->broken = true; vring->broken = true;
return -EFAULT; return -EFAULT;
} }
desc = *desc_ptr; copy_in_vring_desc(vdev, desc_ptr, &desc);
memory_region_unref(mr); memory_region_unref(mr);
/* Ensure descriptor has been loaded before accessing fields */ /* Ensure descriptor has been loaded before accessing fields */
...@@ -320,7 +333,7 @@ int vring_pop(VirtIODevice *vdev, Vring *vring, ...@@ -320,7 +333,7 @@ int vring_pop(VirtIODevice *vdev, Vring *vring,
/* Check it isn't doing very strange things with descriptor numbers. */ /* Check it isn't doing very strange things with descriptor numbers. */
last_avail_idx = vring->last_avail_idx; 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 */ barrier(); /* load indices now and not again later */
if (unlikely((uint16_t)(avail_idx - last_avail_idx) > num)) { if (unlikely((uint16_t)(avail_idx - last_avail_idx) > num)) {
...@@ -341,7 +354,7 @@ int vring_pop(VirtIODevice *vdev, Vring *vring, ...@@ -341,7 +354,7 @@ int vring_pop(VirtIODevice *vdev, Vring *vring,
/* Grab the next descriptor number they're advertising, and increment /* Grab the next descriptor number they're advertising, and increment
* the index we've seen. */ * 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; elem->index = head;
...@@ -365,13 +378,13 @@ int vring_pop(VirtIODevice *vdev, Vring *vring, ...@@ -365,13 +378,13 @@ int vring_pop(VirtIODevice *vdev, Vring *vring,
ret = -EFAULT; ret = -EFAULT;
goto out; goto out;
} }
desc = vring->vr.desc[i]; copy_in_vring_desc(vdev, &vring->vr.desc[i], &desc);
/* Ensure descriptor is loaded before accessing fields */ /* Ensure descriptor is loaded before accessing fields */
barrier(); barrier();
if (desc.flags & VRING_DESC_F_INDIRECT) { if (desc.flags & VRING_DESC_F_INDIRECT) {
ret = get_indirect(vring, elem, &desc); ret = get_indirect(vdev, vring, elem, &desc);
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }
...@@ -407,9 +420,9 @@ out: ...@@ -407,9 +420,9 @@ out:
* *
* Stolen from linux/drivers/vhost/vhost.c. * 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; unsigned int head = elem->index;
uint16_t new; uint16_t new;
...@@ -422,14 +435,16 @@ void vring_push(Vring *vring, VirtQueueElement *elem, int len) ...@@ -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 /* The virtqueue contains a ring of used buffers. Get a pointer to the
* next entry in that used ring. */ * next entry in that used ring. */
used = &vring->vr.used->ring[vring->last_used_idx % vring->vr.num]; vring_set_used_ring_id(vdev, vring, vring->last_used_idx % vring->vr.num,
used->id = head; head);
used->len = len; vring_set_used_ring_len(vdev, vring, vring->last_used_idx % vring->vr.num,
len);
/* Make sure buffer is written before we update index. */ /* Make sure buffer is written before we update index. */
smp_wmb(); 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)) { if (unlikely((int16_t)(new - vring->signalled_used) < (uint16_t)1)) {
vring->signalled_used_valid = false; vring->signalled_used_valid = false;
} }
......
...@@ -168,7 +168,8 @@ void bdrv_io_limits_disable(BlockDriverState *bs); ...@@ -168,7 +168,8 @@ void bdrv_io_limits_disable(BlockDriverState *bs);
void bdrv_init(void); void bdrv_init(void);
void bdrv_init_with_whitelist(void); void bdrv_init_with_whitelist(void);
BlockDriver *bdrv_find_protocol(const char *filename, 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_format(const char *format_name);
BlockDriver *bdrv_find_whitelisted_format(const char *format_name, BlockDriver *bdrv_find_whitelisted_format(const char *format_name,
bool readonly); bool readonly);
......
...@@ -369,9 +369,6 @@ struct BlockDriverState { ...@@ -369,9 +369,6 @@ struct BlockDriverState {
/* I/O Limits */ /* I/O Limits */
BlockLimits bl; BlockLimits bl;
/* Whether the disk can expand beyond total_sectors */
int growable;
/* Whether produces zeros when read beyond eof */ /* Whether produces zeros when read beyond eof */
bool zero_beyond_eof; bool zero_beyond_eof;
......
...@@ -99,7 +99,6 @@ void nbd_export_close_all(void); ...@@ -99,7 +99,6 @@ void nbd_export_close_all(void);
NBDClient *nbd_client_new(NBDExport *exp, int csock, NBDClient *nbd_client_new(NBDExport *exp, int csock,
void (*close)(NBDClient *)); void (*close)(NBDClient *));
void nbd_client_close(NBDClient *client);
void nbd_client_get(NBDClient *client); void nbd_client_get(NBDClient *client);
void nbd_client_put(NBDClient *client); void nbd_client_put(NBDClient *client);
......
#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
...@@ -31,17 +31,6 @@ typedef struct { ...@@ -31,17 +31,6 @@ typedef struct {
bool broken; /* was there a fatal error? */ bool broken; /* was there a fatal error? */
} Vring; } 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 */ /* Fail future vring_pop() and vring_push() calls until reset */
static inline void vring_set_broken(Vring *vring) static inline void vring_set_broken(Vring *vring)
{ {
...@@ -54,6 +43,7 @@ void vring_disable_notification(VirtIODevice *vdev, Vring *vring); ...@@ -54,6 +43,7 @@ void vring_disable_notification(VirtIODevice *vdev, Vring *vring);
bool vring_enable_notification(VirtIODevice *vdev, Vring *vring); bool vring_enable_notification(VirtIODevice *vdev, Vring *vring);
bool vring_should_notify(VirtIODevice *vdev, Vring *vring); bool vring_should_notify(VirtIODevice *vdev, Vring *vring);
int vring_pop(VirtIODevice *vdev, Vring *vring, VirtQueueElement *elem); 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 */ #endif /* VRING_H */
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#define CMD_FLAG_GLOBAL ((int)0x80000000) /* don't iterate "args" */ #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 void (*helpfunc_t)(void);
typedef struct cmdinfo { typedef struct cmdinfo {
...@@ -40,7 +40,7 @@ typedef struct cmdinfo { ...@@ -40,7 +40,7 @@ typedef struct cmdinfo {
extern bool qemuio_misalign; 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); void qemuio_add_command(const cmdinfo_t *ci);
int qemuio_command_usage(const cmdinfo_t *ci); int qemuio_command_usage(const cmdinfo_t *ci);
......
...@@ -62,6 +62,9 @@ typedef struct BlockDevOps { ...@@ -62,6 +62,9 @@ typedef struct BlockDevOps {
BlockBackend *blk_new(const char *name, Error **errp); BlockBackend *blk_new(const char *name, Error **errp);
BlockBackend *blk_new_with_bs(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_ref(BlockBackend *blk);
void blk_unref(BlockBackend *blk); void blk_unref(BlockBackend *blk);
const char *blk_name(BlockBackend *blk); const char *blk_name(BlockBackend *blk);
...@@ -91,6 +94,7 @@ int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int count); ...@@ -91,6 +94,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); int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int count);
int64_t blk_getlength(BlockBackend *blk); int64_t blk_getlength(BlockBackend *blk);
void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr); 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, BlockAIOCB *blk_aio_readv(BlockBackend *blk, int64_t sector_num,
QEMUIOVector *iov, int nb_sectors, QEMUIOVector *iov, int nb_sectors,
BlockCompletionFunc *cb, void *opaque); BlockCompletionFunc *cb, void *opaque);
...@@ -151,5 +155,14 @@ BlockAcctStats *blk_get_stats(BlockBackend *blk); ...@@ -151,5 +155,14 @@ BlockAcctStats *blk_get_stats(BlockBackend *blk);
void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk, void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk,
BlockCompletionFunc *cb, void *opaque); 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 #endif
...@@ -874,7 +874,7 @@ void nbd_client_put(NBDClient *client) ...@@ -874,7 +874,7 @@ void nbd_client_put(NBDClient *client)
{ {
if (--client->refcount == 0) { if (--client->refcount == 0) {
/* The last reference should be dropped by client->close, /* 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); assert(client->closing);
...@@ -889,7 +889,7 @@ void nbd_client_put(NBDClient *client) ...@@ -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) { if (client->closing) {
return; return;
...@@ -1026,7 +1026,7 @@ void nbd_export_close(NBDExport *exp) ...@@ -1026,7 +1026,7 @@ void nbd_export_close(NBDExport *exp)
nbd_export_get(exp); nbd_export_get(exp);
QTAILQ_FOREACH_SAFE(client, &exp->clients, next, next) { QTAILQ_FOREACH_SAFE(client, &exp->clients, next, next) {
nbd_client_close(client); client_close(client);
} }
nbd_export_set_name(exp, NULL); nbd_export_set_name(exp, NULL);
nbd_export_put(exp); nbd_export_put(exp);
...@@ -1311,7 +1311,7 @@ done: ...@@ -1311,7 +1311,7 @@ done:
out: out:
nbd_request_put(req); nbd_request_put(req);
nbd_client_close(client); client_close(client);
} }
static void nbd_read(void *opaque) static void nbd_read(void *opaque)
......
此差异已折叠。
此差异已折叠。
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
static char *progname; static char *progname;
static BlockBackend *qemuio_blk; static BlockBackend *qemuio_blk;
static BlockDriverState *qemuio_bs;
/* qemu-io commands passed using -c */ /* qemu-io commands passed using -c */
static int ncmdline; static int ncmdline;
...@@ -36,10 +35,9 @@ static char **cmdline; ...@@ -36,10 +35,9 @@ static char **cmdline;
static ReadLineState *readline_state; 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); blk_unref(qemuio_blk);
qemuio_bs = NULL;
qemuio_blk = NULL; qemuio_blk = NULL;
return 0; return 0;
} }
...@@ -51,32 +49,22 @@ static const cmdinfo_t close_cmd = { ...@@ -51,32 +49,22 @@ static const cmdinfo_t close_cmd = {
.oneline = "close the current open file", .oneline = "close the current open file",
}; };
static int openfile(char *name, BlockDriver *drv, int flags, int growable, static int openfile(char *name, int flags, QDict *opts)
QDict *opts)
{ {
Error *local_err = NULL; Error *local_err = NULL;
if (qemuio_bs) { if (qemuio_blk) {
fprintf(stderr, "file open already, try 'help close'\n"); fprintf(stderr, "file open already, try 'help close'\n");
QDECREF(opts); QDECREF(opts);
return 1; return 1;
} }
qemuio_blk = blk_new_with_bs("hda", &error_abort); qemuio_blk = blk_new_open("hda", name, NULL, opts, flags, &local_err);
qemuio_bs = blk_bs(qemuio_blk); if (!qemuio_blk) {
if (growable) {
flags |= BDRV_O_PROTOCOL;
}
if (bdrv_open(&qemuio_bs, name, NULL, opts, flags, drv, &local_err) < 0) {
fprintf(stderr, "%s: can't open%s%s: %s\n", progname, fprintf(stderr, "%s: can't open%s%s: %s\n", progname,
name ? " device " : "", name ?: "", name ? " device " : "", name ?: "",
error_get_pretty(local_err)); error_get_pretty(local_err));
error_free(local_err); error_free(local_err);
blk_unref(qemuio_blk);
qemuio_bs = NULL;
qemuio_blk = NULL;
return 1; return 1;
} }
...@@ -96,12 +84,11 @@ static void open_help(void) ...@@ -96,12 +84,11 @@ static void open_help(void)
" -r, -- open file read-only\n" " -r, -- open file read-only\n"
" -s, -- use snapshot file\n" " -s, -- use snapshot file\n"
" -n, -- disable host cache\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" " -o, -- options to be given to the block driver"
"\n"); "\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 = { static const cmdinfo_t open_cmd = {
.name = "open", .name = "open",
...@@ -125,11 +112,10 @@ static QemuOptsList empty_opts = { ...@@ -125,11 +112,10 @@ 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 flags = 0;
int readonly = 0; int readonly = 0;
int growable = 0;
int c; int c;
QemuOpts *qopts; QemuOpts *qopts;
QDict *opts; QDict *opts;
...@@ -145,9 +131,6 @@ static int open_f(BlockDriverState *bs, int argc, char **argv) ...@@ -145,9 +131,6 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
case 'r': case 'r':
readonly = 1; readonly = 1;
break; break;
case 'g':
growable = 1;
break;
case 'o': case 'o':
if (!qemu_opts_parse(&empty_opts, optarg, 0)) { if (!qemu_opts_parse(&empty_opts, optarg, 0)) {
printf("could not parse option list -- %s\n", optarg); printf("could not parse option list -- %s\n", optarg);
...@@ -170,16 +153,16 @@ static int open_f(BlockDriverState *bs, int argc, char **argv) ...@@ -170,16 +153,16 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
qemu_opts_reset(&empty_opts); qemu_opts_reset(&empty_opts);
if (optind == argc - 1) { if (optind == argc - 1) {
return openfile(argv[optind], NULL, flags, growable, opts); return openfile(argv[optind], flags, opts);
} else if (optind == argc) { } else if (optind == argc) {
return openfile(NULL, NULL, flags, growable, opts); return openfile(NULL, flags, opts);
} else { } else {
QDECREF(opts); QDECREF(opts);
return qemuio_command_usage(&open_cmd); return qemuio_command_usage(&open_cmd);
} }
} }
static int quit_f(BlockDriverState *bs, int argc, char **argv) static int quit_f(BlockBackend *blk, int argc, char **argv)
{ {
return 1; return 1;
} }
...@@ -206,7 +189,6 @@ static void usage(const char *name) ...@@ -206,7 +189,6 @@ static void usage(const char *name)
" -r, --read-only export read-only\n" " -r, --read-only export read-only\n"
" -s, --snapshot use snapshot file\n" " -s, --snapshot use snapshot file\n"
" -n, --nocache disable host cache\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" " -m, --misalign misalign allocations for O_DIRECT\n"
" -k, --native-aio use kernel AIO implementation (on Linux only)\n" " -k, --native-aio use kernel AIO implementation (on Linux only)\n"
" -t, --cache=MODE use the given cache mode for the image\n" " -t, --cache=MODE use the given cache mode for the image\n"
...@@ -317,7 +299,7 @@ static void command_loop(void) ...@@ -317,7 +299,7 @@ static void command_loop(void)
char *input; char *input;
for (i = 0; !done && i < ncmdline; i++) { for (i = 0; !done && i < ncmdline; i++) {
done = qemuio_command(qemuio_bs, cmdline[i]); done = qemuio_command(qemuio_blk, cmdline[i]);
} }
if (cmdline) { if (cmdline) {
g_free(cmdline); g_free(cmdline);
...@@ -342,7 +324,7 @@ static void command_loop(void) ...@@ -342,7 +324,7 @@ static void command_loop(void)
if (input == NULL) { if (input == NULL) {
break; break;
} }
done = qemuio_command(qemuio_bs, input); done = qemuio_command(qemuio_blk, input);
g_free(input); g_free(input);
prompted = 0; prompted = 0;
...@@ -365,7 +347,6 @@ static void reenable_tty_echo(void) ...@@ -365,7 +347,6 @@ static void reenable_tty_echo(void)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int readonly = 0; int readonly = 0;
int growable = 0;
const char *sopt = "hVc:d:f:rsnmgkt:T:"; const char *sopt = "hVc:d:f:rsnmgkt:T:";
const struct option lopt[] = { const struct option lopt[] = {
{ "help", 0, NULL, 'h' }, { "help", 0, NULL, 'h' },
...@@ -377,7 +358,6 @@ int main(int argc, char **argv) ...@@ -377,7 +358,6 @@ int main(int argc, char **argv)
{ "snapshot", 0, NULL, 's' }, { "snapshot", 0, NULL, 's' },
{ "nocache", 0, NULL, 'n' }, { "nocache", 0, NULL, 'n' },
{ "misalign", 0, NULL, 'm' }, { "misalign", 0, NULL, 'm' },
{ "growable", 0, NULL, 'g' },
{ "native-aio", 0, NULL, 'k' }, { "native-aio", 0, NULL, 'k' },
{ "discard", 1, NULL, 'd' }, { "discard", 1, NULL, 'd' },
{ "cache", 1, NULL, 't' }, { "cache", 1, NULL, 't' },
...@@ -387,8 +367,8 @@ int main(int argc, char **argv) ...@@ -387,8 +367,8 @@ int main(int argc, char **argv)
int c; int c;
int opt_index = 0; int opt_index = 0;
int flags = BDRV_O_UNMAP; int flags = BDRV_O_UNMAP;
BlockDriver *drv = NULL;
Error *local_error = NULL; Error *local_error = NULL;
QDict *opts = NULL;
#ifdef CONFIG_POSIX #ifdef CONFIG_POSIX
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
...@@ -414,11 +394,10 @@ int main(int argc, char **argv) ...@@ -414,11 +394,10 @@ int main(int argc, char **argv)
} }
break; break;
case 'f': case 'f':
drv = bdrv_find_format(optarg); if (!opts) {
if (!drv) { opts = qdict_new();
error_report("Invalid format '%s'", optarg);
exit(EXIT_FAILURE);
} }
qdict_put(opts, "driver", qstring_from_str(optarg));
break; break;
case 'c': case 'c':
add_user_command(optarg); add_user_command(optarg);
...@@ -429,9 +408,6 @@ int main(int argc, char **argv) ...@@ -429,9 +408,6 @@ int main(int argc, char **argv)
case 'm': case 'm':
qemuio_misalign = true; qemuio_misalign = true;
break; break;
case 'g':
growable = 1;
break;
case 'k': case 'k':
flags |= BDRV_O_NATIVE_AIO; flags |= BDRV_O_NATIVE_AIO;
break; break;
...@@ -489,7 +465,7 @@ int main(int argc, char **argv) ...@@ -489,7 +465,7 @@ int main(int argc, char **argv)
} }
if ((argc - optind) == 1) { if ((argc - optind) == 1) {
openfile(argv[optind], drv, flags, growable, NULL); openfile(argv[optind], flags, opts);
} }
command_loop(); command_loop();
......
...@@ -391,7 +391,6 @@ int main(int argc, char **argv) ...@@ -391,7 +391,6 @@ int main(int argc, char **argv)
{ {
BlockBackend *blk; BlockBackend *blk;
BlockDriverState *bs; BlockDriverState *bs;
BlockDriver *drv;
off_t dev_offset = 0; off_t dev_offset = 0;
uint32_t nbdflags = 0; uint32_t nbdflags = 0;
bool disconnect = false; bool disconnect = false;
...@@ -434,7 +433,7 @@ int main(int argc, char **argv) ...@@ -434,7 +433,7 @@ int main(int argc, char **argv)
char *end; char *end;
int flags = BDRV_O_RDWR; int flags = BDRV_O_RDWR;
int partition = -1; int partition = -1;
int ret; int ret = 0;
int fd; int fd;
bool seen_cache = false; bool seen_cache = false;
bool seen_discard = false; bool seen_discard = false;
...@@ -445,6 +444,7 @@ int main(int argc, char **argv) ...@@ -445,6 +444,7 @@ int main(int argc, char **argv)
const char *fmt = NULL; const char *fmt = NULL;
Error *local_err = NULL; Error *local_err = NULL;
BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF; BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
QDict *options = NULL;
/* The client thread uses SIGTERM to interrupt the server. A signal /* The client thread uses SIGTERM to interrupt the server. A signal
* handler ensures that "qemu-nbd -v -c" exits with a nice status code. * handler ensures that "qemu-nbd -v -c" exits with a nice status code.
...@@ -689,24 +689,17 @@ int main(int argc, char **argv) ...@@ -689,24 +689,17 @@ int main(int argc, char **argv)
atexit(bdrv_close_all); atexit(bdrv_close_all);
if (fmt) { if (fmt) {
drv = bdrv_find_format(fmt); options = qdict_new();
if (!drv) { qdict_put(options, "driver", qstring_from_str(fmt));
errx(EXIT_FAILURE, "Unknown file format '%s'", fmt);
}
} else {
drv = NULL;
} }
blk = blk_new_with_bs("hda", &error_abort);
bs = blk_bs(blk);
srcpath = argv[optind]; srcpath = argv[optind];
ret = bdrv_open(&bs, srcpath, NULL, NULL, flags, drv, &local_err); blk = blk_new_open("hda", srcpath, NULL, options, flags, &local_err);
if (ret < 0) { if (!blk) {
errno = -ret; errx(EXIT_FAILURE, "Failed to blk_new_open '%s': %s", argv[optind],
err(EXIT_FAILURE, "Failed to bdrv_open '%s': %s", argv[optind], error_get_pretty(local_err));
error_get_pretty(local_err));
} }
bs = blk_bs(blk);
if (sn_opts) { if (sn_opts) {
ret = bdrv_snapshot_load_tmp(bs, ret = bdrv_snapshot_load_tmp(bs,
......
...@@ -821,7 +821,7 @@ void qemu_savevm_state_cancel(void) ...@@ -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; int ret;
MigrationParams params = { MigrationParams params = {
...@@ -829,7 +829,7 @@ static int qemu_savevm_state(QEMUFile *f) ...@@ -829,7 +829,7 @@ static int qemu_savevm_state(QEMUFile *f)
.shared = 0 .shared = 0
}; };
if (qemu_savevm_state_blocked(NULL)) { if (qemu_savevm_state_blocked(errp)) {
return -EINVAL; return -EINVAL;
} }
...@@ -850,6 +850,7 @@ static int qemu_savevm_state(QEMUFile *f) ...@@ -850,6 +850,7 @@ static int qemu_savevm_state(QEMUFile *f)
} }
if (ret != 0) { if (ret != 0) {
qemu_savevm_state_cancel(); qemu_savevm_state_cancel();
error_setg_errno(errp, -ret, "Error while writing VM state");
} }
return ret; return ret;
} }
...@@ -1102,6 +1103,7 @@ void do_savevm(Monitor *mon, const QDict *qdict) ...@@ -1102,6 +1103,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
qemu_timeval tv; qemu_timeval tv;
struct tm tm; struct tm tm;
const char *name = qdict_get_try_str(qdict, "name"); 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 */ /* Verify if there is a device that doesn't support snapshots and is writable */
bs = NULL; bs = NULL;
...@@ -1160,11 +1162,12 @@ void do_savevm(Monitor *mon, const QDict *qdict) ...@@ -1160,11 +1162,12 @@ void do_savevm(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "Could not open VM state file\n"); monitor_printf(mon, "Could not open VM state file\n");
goto the_end; goto the_end;
} }
ret = qemu_savevm_state(f); ret = qemu_savevm_state(f, &local_err);
vm_state_size = qemu_ftell(f); vm_state_size = qemu_ftell(f);
qemu_fclose(f); qemu_fclose(f);
if (ret < 0) { 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; goto the_end;
} }
......
# 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)
...@@ -307,9 +307,10 @@ tests/test-mul64$(EXESUF): tests/test-mul64.o libqemuutil.a ...@@ -307,9 +307,10 @@ tests/test-mul64$(EXESUF): tests/test-mul64.o libqemuutil.a
tests/test-bitops$(EXESUF): tests/test-bitops.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/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 = $(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-pc-obj-y += tests/libqos/ahci.o
libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.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-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 libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
#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);
}
#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
#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"
/*** Test Setup & Teardown ***/
/**
* Launch QEMU with the given command line,
* and then set up interrupts and our guest malloc interface.
*/
QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap)
{
char *cmdline;
struct QOSState *qs = g_malloc(sizeof(QOSState));
cmdline = g_strdup_vprintf(cmdline_fmt, ap);
qs->qts = qtest_start(cmdline);
qs->ops = ops;
qtest_irq_intercept_in(global_qtest, "ioapic");
if (ops && ops->init_allocator) {
qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS);
}
g_free(cmdline);
return qs;
}
/**
* Launch QEMU with the given command line,
* and then set up interrupts and our guest malloc interface.
*/
QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...)
{
QOSState *qs;
va_list ap;
va_start(ap, cmdline_fmt);
qs = qtest_vboot(ops, cmdline_fmt, ap);
va_end(ap);
return qs;
}
/**
* Tear down the QEMU instance.
*/
void qtest_shutdown(QOSState *qs)
{
if (qs->alloc && qs->ops && qs->ops->uninit_allocator) {
qs->ops->uninit_allocator(qs->alloc);
qs->alloc = NULL;
}
qtest_quit(qs->qts);
g_free(qs);
}
#ifndef __libqos_h
#define __libqos_h
#include "libqtest.h"
#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(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)
{
return guest_alloc(q->alloc, bytes);
}
static inline void qfree(QOSState *q, uint64_t addr)
{
guest_free(q->alloc, addr);
}
#endif
...@@ -32,31 +32,17 @@ void pc_alloc_uninit(QGuestAllocator *allocator) ...@@ -32,31 +32,17 @@ void pc_alloc_uninit(QGuestAllocator *allocator)
QGuestAllocator *pc_alloc_init_flags(QAllocOpts flags) QGuestAllocator *pc_alloc_init_flags(QAllocOpts flags)
{ {
QGuestAllocator *s = g_malloc0(sizeof(*s)); QGuestAllocator *s;
uint64_t ram_size; uint64_t ram_size;
QFWCFG *fw_cfg = pc_fw_cfg_init(); 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); ram_size = qfw_cfg_get_u64(fw_cfg, FW_CFG_RAM_SIZE);
s = alloc_init_flags(flags, 1 << 20, MIN(ram_size, 0xE0000000));
/* Start at 1MB */ alloc_set_page_size(s, PAGE_SIZE);
s->start = 1 << 20;
/* Respect PCI hole */
s->end = MIN(ram_size, 0xE0000000);
/* clean-up */ /* clean-up */
g_free(fw_cfg); 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; return s;
} }
......
此差异已折叠。
...@@ -17,8 +17,6 @@ ...@@ -17,8 +17,6 @@
#include <sys/types.h> #include <sys/types.h>
#include "qemu/queue.h" #include "qemu/queue.h"
#define MLIST_ENTNAME entries
typedef enum { typedef enum {
ALLOC_NO_FLAGS = 0x00, ALLOC_NO_FLAGS = 0x00,
ALLOC_LEAK_WARN = 0x01, ALLOC_LEAK_WARN = 0x01,
...@@ -26,28 +24,18 @@ typedef enum { ...@@ -26,28 +24,18 @@ typedef enum {
ALLOC_PARANOID = 0x04 ALLOC_PARANOID = 0x04
} QAllocOpts; } QAllocOpts;
typedef QTAILQ_HEAD(MemList, MemBlock) MemList; typedef struct QGuestAllocator QGuestAllocator;
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;
MemList used;
MemList free;
} QGuestAllocator;
MemBlock *mlist_new(uint64_t addr, uint64_t size);
void alloc_uninit(QGuestAllocator *allocator); void alloc_uninit(QGuestAllocator *allocator);
/* Always returns page aligned values */ /* Always returns page aligned values */
uint64_t guest_alloc(QGuestAllocator *allocator, size_t size); uint64_t guest_alloc(QGuestAllocator *allocator, size_t size);
void guest_free(QGuestAllocator *allocator, uint64_t addr); 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);
void alloc_set_flags(QGuestAllocator *allocator, QAllocOpts opts);
#endif #endif
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
...@@ -93,6 +93,7 @@ echo ...@@ -93,6 +93,7 @@ echo
run_qemu -drive file="$TEST_IMG",format=foo run_qemu -drive file="$TEST_IMG",format=foo
run_qemu -drive file="$TEST_IMG",driver=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=raw,format=qcow2
run_qemu -drive file="$TEST_IMG",driver=qcow2,format=qcow2
echo echo
echo === Overriding backing file === echo === Overriding backing file ===
......
此差异已折叠。
...@@ -21,9 +21,9 @@ QMP_VERSION ...@@ -21,9 +21,9 @@ QMP_VERSION
{"return": {}} {"return": {}}
{"error": {"class": "GenericError", "desc": "Device with id 'disk' already exists"}} {"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": "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": "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": "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=disk3 is conflicting with a device id"}}
{"return": {}} {"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
...@@ -57,7 +57,7 @@ QMP_VERSION ...@@ -57,7 +57,7 @@ QMP_VERSION
Testing: Testing:
QMP_VERSION QMP_VERSION
{"return": {}} {"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": {}} {"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册