-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1 iQEcBAABAgAGBQJVisx5AAoJEJykq7OBq3PIbasIALJC/7BEyCSEubcjH25CIzao D20ufmo8/Et6KGuD1r2zdGRXQ79q/SDCGStQK8QEEfvRxPMehngfCUb5aJXkcGbu /bRIaHh7DFxSiPGJI1/1wwR1MC7tjjR6ZrpSd2OTF0VOZvuXlP3noWpX1eiRAcvu ekK2vvYtDi03/Xzhbx8MIRSuYPAdh/tXZ3mrDfUQNrtO47QYAxh0C9ABzZVrHJCa RFCFXPoqZroOcrVe20ZHLt82AUL0H3cfHvF74Z+LbOlPJ7JbP/5+PzLisAqX7VeE VYvK78mQih41Ww+qYYx4lwhUMUW1fYYnN/MHpdU2LBHcF/tPqxz5kyvQ6GJhD5w= =rdVl -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging # gpg: Signature made Wed Jun 24 16:27:53 2015 BST 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: virito-blk: drop duplicate check qemu-iotests: fix 051.out after qdev error message change iov: don't touch iov in iov_send_recv() raw-posix: Introduce hdev_is_sg() raw-posix: Use DPRINTF for DEBUG_FLOPPY raw-posix: DPRINTF instead of DEBUG_BLOCK_PRINT Fix migration in case of scsi-generic block: Use bdrv_is_sg() everywhere nvme: Fix memleak in nvme_dma_read_prp vvfat: add a label option util/hbitmap: Add an API to reset all set bits in hbitmap virtio-blk: Use blk_drain() to drain IO requests block-backend: Introduce blk_drain() throttle: Check current timers before updating any_timer_armed[] block: Let bdrv_drain_all() to call aio_poll() for each AioContext Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
58e8b33518
8
block.c
8
block.c
@ -585,7 +585,7 @@ static int find_image_format(BlockDriverState *bs, const char *filename,
|
||||
int ret = 0;
|
||||
|
||||
/* Return the raw BlockDriver * to scsi-generic devices or empty drives */
|
||||
if (bs->sg || !bdrv_is_inserted(bs) || bdrv_getlength(bs) == 0) {
|
||||
if (bdrv_is_sg(bs) || !bdrv_is_inserted(bs) || bdrv_getlength(bs) == 0) {
|
||||
*pdrv = &bdrv_raw;
|
||||
return ret;
|
||||
}
|
||||
@ -617,7 +617,7 @@ static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
|
||||
BlockDriver *drv = bs->drv;
|
||||
|
||||
/* Do not attempt drv->bdrv_getlength() on scsi-generic devices */
|
||||
if (bs->sg)
|
||||
if (bdrv_is_sg(bs))
|
||||
return 0;
|
||||
|
||||
/* query actual device if possible, otherwise just trust the hint */
|
||||
@ -948,7 +948,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
|
||||
|
||||
assert(bdrv_opt_mem_align(bs) != 0);
|
||||
assert(bdrv_min_mem_align(bs) != 0);
|
||||
assert((bs->request_alignment != 0) || bs->sg);
|
||||
assert((bs->request_alignment != 0) || bdrv_is_sg(bs));
|
||||
|
||||
qemu_opts_del(opts);
|
||||
return 0;
|
||||
@ -3513,7 +3513,7 @@ void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
||||
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
assert(bdrv_dirty_bitmap_enabled(bitmap));
|
||||
hbitmap_reset(bitmap->bitmap, 0, bitmap->size);
|
||||
hbitmap_reset_all(bitmap->bitmap);
|
||||
}
|
||||
|
||||
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
|
@ -700,6 +700,11 @@ int blk_flush_all(void)
|
||||
return bdrv_flush_all();
|
||||
}
|
||||
|
||||
void blk_drain(BlockBackend *blk)
|
||||
{
|
||||
bdrv_drain(blk->bs);
|
||||
}
|
||||
|
||||
void blk_drain_all(void)
|
||||
{
|
||||
bdrv_drain_all();
|
||||
|
45
block/io.c
45
block/io.c
@ -233,17 +233,6 @@ static bool bdrv_requests_pending(BlockDriverState *bs)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool bdrv_drain_one(BlockDriverState *bs)
|
||||
{
|
||||
bool bs_busy;
|
||||
|
||||
bdrv_flush_io_queue(bs);
|
||||
bdrv_start_throttled_reqs(bs);
|
||||
bs_busy = bdrv_requests_pending(bs);
|
||||
bs_busy |= aio_poll(bdrv_get_aio_context(bs), bs_busy);
|
||||
return bs_busy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for pending requests to complete on a single BlockDriverState subtree
|
||||
*
|
||||
@ -256,8 +245,13 @@ static bool bdrv_drain_one(BlockDriverState *bs)
|
||||
*/
|
||||
void bdrv_drain(BlockDriverState *bs)
|
||||
{
|
||||
while (bdrv_drain_one(bs)) {
|
||||
bool busy = true;
|
||||
|
||||
while (busy) {
|
||||
/* Keep iterating */
|
||||
bdrv_flush_io_queue(bs);
|
||||
busy = bdrv_requests_pending(bs);
|
||||
busy |= aio_poll(bdrv_get_aio_context(bs), busy);
|
||||
}
|
||||
}
|
||||
|
||||
@ -278,6 +272,7 @@ void bdrv_drain_all(void)
|
||||
/* Always run first iteration so any pending completion BHs run */
|
||||
bool busy = true;
|
||||
BlockDriverState *bs = NULL;
|
||||
GSList *aio_ctxs = NULL, *ctx;
|
||||
|
||||
while ((bs = bdrv_next(bs))) {
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
@ -287,17 +282,30 @@ void bdrv_drain_all(void)
|
||||
block_job_pause(bs->job);
|
||||
}
|
||||
aio_context_release(aio_context);
|
||||
|
||||
if (!aio_ctxs || !g_slist_find(aio_ctxs, aio_context)) {
|
||||
aio_ctxs = g_slist_prepend(aio_ctxs, aio_context);
|
||||
}
|
||||
}
|
||||
|
||||
while (busy) {
|
||||
busy = false;
|
||||
bs = NULL;
|
||||
|
||||
while ((bs = bdrv_next(bs))) {
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
for (ctx = aio_ctxs; ctx != NULL; ctx = ctx->next) {
|
||||
AioContext *aio_context = ctx->data;
|
||||
bs = NULL;
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
busy |= bdrv_drain_one(bs);
|
||||
while ((bs = bdrv_next(bs))) {
|
||||
if (aio_context == bdrv_get_aio_context(bs)) {
|
||||
bdrv_flush_io_queue(bs);
|
||||
if (bdrv_requests_pending(bs)) {
|
||||
busy = true;
|
||||
aio_poll(aio_context, busy);
|
||||
}
|
||||
}
|
||||
}
|
||||
busy |= aio_poll(aio_context, false);
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
}
|
||||
@ -312,6 +320,7 @@ void bdrv_drain_all(void)
|
||||
}
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
g_slist_free(aio_ctxs);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2256,7 +2265,8 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!bs || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
|
||||
if (!bs || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs) ||
|
||||
bdrv_is_sg(bs)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2562,4 +2572,5 @@ void bdrv_flush_io_queue(BlockDriverState *bs)
|
||||
} else if (bs->file) {
|
||||
bdrv_flush_io_queue(bs->file);
|
||||
}
|
||||
bdrv_start_throttled_reqs(bs);
|
||||
}
|
||||
|
@ -628,10 +628,6 @@ static int coroutine_fn iscsi_co_flush(BlockDriverState *bs)
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct IscsiTask iTask;
|
||||
|
||||
if (bs->sg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!iscsilun->force_next_flush) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include <linux/fd.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <scsi/sg.h>
|
||||
#ifdef __s390__
|
||||
#include <asm/dasd.h>
|
||||
#endif
|
||||
@ -96,15 +97,19 @@
|
||||
#include <xfs/xfs.h>
|
||||
#endif
|
||||
|
||||
//#define DEBUG_FLOPPY
|
||||
|
||||
//#define DEBUG_BLOCK
|
||||
#if defined(DEBUG_BLOCK)
|
||||
#define DEBUG_BLOCK_PRINT(formatCstr, ...) do { if (qemu_log_enabled()) \
|
||||
{ qemu_log(formatCstr, ## __VA_ARGS__); qemu_log_flush(); } } while (0)
|
||||
|
||||
#ifdef DEBUG_BLOCK
|
||||
# define DEBUG_BLOCK_PRINT 1
|
||||
#else
|
||||
#define DEBUG_BLOCK_PRINT(formatCstr, ...)
|
||||
# define DEBUG_BLOCK_PRINT 0
|
||||
#endif
|
||||
#define DPRINTF(fmt, ...) \
|
||||
do { \
|
||||
if (DEBUG_BLOCK_PRINT) { \
|
||||
printf(fmt, ## __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* OS X does not have O_DSYNC */
|
||||
#ifndef O_DSYNC
|
||||
@ -305,9 +310,9 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
|
||||
char *buf;
|
||||
size_t max_align = MAX(MAX_BLOCKSIZE, getpagesize());
|
||||
|
||||
/* For /dev/sg devices the alignment is not really used.
|
||||
/* For SCSI generic devices the alignment is not really used.
|
||||
With buffered I/O, we don't have any restrictions. */
|
||||
if (bs->sg || !s->needs_alignment) {
|
||||
if (bdrv_is_sg(bs) || !s->needs_alignment) {
|
||||
bs->request_alignment = 1;
|
||||
s->buf_align = 1;
|
||||
return;
|
||||
@ -1020,6 +1025,7 @@ static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb)
|
||||
static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes)
|
||||
{
|
||||
struct xfs_flock64 fl;
|
||||
int err;
|
||||
|
||||
memset(&fl, 0, sizeof(fl));
|
||||
fl.l_whence = SEEK_SET;
|
||||
@ -1027,8 +1033,9 @@ static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes)
|
||||
fl.l_len = bytes;
|
||||
|
||||
if (xfsctl(NULL, s->fd, XFS_IOC_ZERO_RANGE, &fl) < 0) {
|
||||
DEBUG_BLOCK_PRINT("cannot write zero range (%s)\n", strerror(errno));
|
||||
return -errno;
|
||||
err = errno;
|
||||
DPRINTF("cannot write zero range (%s)\n", strerror(errno));
|
||||
return -err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1037,6 +1044,7 @@ static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes)
|
||||
static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes)
|
||||
{
|
||||
struct xfs_flock64 fl;
|
||||
int err;
|
||||
|
||||
memset(&fl, 0, sizeof(fl));
|
||||
fl.l_whence = SEEK_SET;
|
||||
@ -1044,8 +1052,9 @@ static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes)
|
||||
fl.l_len = bytes;
|
||||
|
||||
if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) {
|
||||
DEBUG_BLOCK_PRINT("cannot punch hole (%s)\n", strerror(errno));
|
||||
return -errno;
|
||||
err = errno;
|
||||
DPRINTF("cannot punch hole (%s)\n", strerror(errno));
|
||||
return -err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -2078,15 +2087,38 @@ static void hdev_parse_filename(const char *filename, QDict *options,
|
||||
qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
|
||||
}
|
||||
|
||||
static bool hdev_is_sg(BlockDriverState *bs)
|
||||
{
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
struct stat st;
|
||||
struct sg_scsi_id scsiid;
|
||||
int sg_version;
|
||||
|
||||
if (stat(bs->filename, &st) >= 0 && S_ISCHR(st.st_mode) &&
|
||||
!bdrv_ioctl(bs, SG_GET_VERSION_NUM, &sg_version) &&
|
||||
!bdrv_ioctl(bs, SG_GET_SCSI_ID, &scsiid)) {
|
||||
DPRINTF("SG device found: type=%d, version=%d\n",
|
||||
scsiid.scsi_type, sg_version);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
const char *filename = qdict_get_str(options, "filename");
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
const char *filename = qdict_get_str(options, "filename");
|
||||
|
||||
if (strstart(filename, "/dev/cdrom", NULL)) {
|
||||
kern_return_t kernResult;
|
||||
io_iterator_t mediaIterator;
|
||||
@ -2115,16 +2147,6 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
#endif
|
||||
|
||||
s->type = FTYPE_FILE;
|
||||
#if defined(__linux__)
|
||||
{
|
||||
char resolved_path[ MAXPATHLEN ], *temp;
|
||||
|
||||
temp = realpath(filename, resolved_path);
|
||||
if (temp && strstart(temp, "/dev/sg", NULL)) {
|
||||
bs->sg = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = raw_open_common(bs, options, flags, 0, &local_err);
|
||||
if (ret < 0) {
|
||||
@ -2134,6 +2156,9 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Since this does ioctl the device must be already opened */
|
||||
bs->sg = hdev_is_sg(bs);
|
||||
|
||||
if (flags & BDRV_O_RDWR) {
|
||||
ret = check_hdev_writable(s);
|
||||
if (ret < 0) {
|
||||
@ -2162,16 +2187,12 @@ static int fd_open(BlockDriverState *bs)
|
||||
(qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
|
||||
qemu_close(s->fd);
|
||||
s->fd = -1;
|
||||
#ifdef DEBUG_FLOPPY
|
||||
printf("Floppy closed\n");
|
||||
#endif
|
||||
DPRINTF("Floppy closed\n");
|
||||
}
|
||||
if (s->fd < 0) {
|
||||
if (s->fd_got_error &&
|
||||
(qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
|
||||
#ifdef DEBUG_FLOPPY
|
||||
printf("No floppy (open delayed)\n");
|
||||
#endif
|
||||
DPRINTF("No floppy (open delayed)\n");
|
||||
return -EIO;
|
||||
}
|
||||
s->fd = qemu_open(bs->filename, s->open_flags & ~O_NONBLOCK);
|
||||
@ -2180,14 +2201,10 @@ static int fd_open(BlockDriverState *bs)
|
||||
s->fd_got_error = 1;
|
||||
if (last_media_present)
|
||||
s->fd_media_changed = 1;
|
||||
#ifdef DEBUG_FLOPPY
|
||||
printf("No floppy\n");
|
||||
#endif
|
||||
DPRINTF("No floppy\n");
|
||||
return -EIO;
|
||||
}
|
||||
#ifdef DEBUG_FLOPPY
|
||||
printf("Floppy opened\n");
|
||||
#endif
|
||||
DPRINTF("Floppy opened\n");
|
||||
}
|
||||
if (!last_media_present)
|
||||
s->fd_media_changed = 1;
|
||||
@ -2455,9 +2472,7 @@ static int floppy_media_changed(BlockDriverState *bs)
|
||||
fd_open(bs);
|
||||
ret = s->fd_media_changed;
|
||||
s->fd_media_changed = 0;
|
||||
#ifdef DEBUG_FLOPPY
|
||||
printf("Floppy changed=%d\n", ret);
|
||||
#endif
|
||||
DPRINTF("Floppy changed=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -324,9 +324,14 @@ void throttle_group_config(BlockDriverState *bs, ThrottleConfig *cfg)
|
||||
ThrottleState *ts = bs->throttle_state;
|
||||
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
|
||||
qemu_mutex_lock(&tg->lock);
|
||||
throttle_config(ts, tt, cfg);
|
||||
/* throttle_config() cancels the timers */
|
||||
tg->any_timer_armed[0] = tg->any_timer_armed[1] = false;
|
||||
if (timer_pending(tt->timers[0])) {
|
||||
tg->any_timer_armed[0] = false;
|
||||
}
|
||||
if (timer_pending(tt->timers[1])) {
|
||||
tg->any_timer_armed[1] = false;
|
||||
}
|
||||
throttle_config(ts, tt, cfg);
|
||||
qemu_mutex_unlock(&tg->lock);
|
||||
}
|
||||
|
||||
|
@ -323,6 +323,7 @@ typedef struct BDRVVVFATState {
|
||||
|
||||
int fat_type; /* 16 or 32 */
|
||||
array_t fat,directory,mapping;
|
||||
char volume_label[11];
|
||||
|
||||
unsigned int cluster_size;
|
||||
unsigned int sectors_per_cluster;
|
||||
@ -860,7 +861,7 @@ static int init_directories(BDRVVVFATState* s,
|
||||
{
|
||||
direntry_t* entry=array_get_next(&(s->directory));
|
||||
entry->attributes=0x28; /* archive | volume label */
|
||||
memcpy(entry->name, "QEMU VVFAT ", sizeof(entry->name));
|
||||
memcpy(entry->name, s->volume_label, sizeof(entry->name));
|
||||
}
|
||||
|
||||
/* Now build FAT, and write back information into directory */
|
||||
@ -969,7 +970,8 @@ static int init_directories(BDRVVVFATState* s,
|
||||
bootsector->u.fat16.signature=0x29;
|
||||
bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
|
||||
|
||||
memcpy(bootsector->u.fat16.volume_label,"QEMU VVFAT ",11);
|
||||
memcpy(bootsector->u.fat16.volume_label, s->volume_label,
|
||||
sizeof(bootsector->u.fat16.volume_label));
|
||||
memcpy(bootsector->fat_type,(s->fat_type==12?"FAT12 ":s->fat_type==16?"FAT16 ":"FAT32 "),8);
|
||||
bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa;
|
||||
|
||||
@ -1008,6 +1010,11 @@ static QemuOptsList runtime_opts = {
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Create a floppy rather than a hard disk image",
|
||||
},
|
||||
{
|
||||
.name = "label",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Use a volume label other than QEMU VVFAT",
|
||||
},
|
||||
{
|
||||
.name = "rw",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
@ -1070,7 +1077,7 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
BDRVVVFATState *s = bs->opaque;
|
||||
int cyls, heads, secs;
|
||||
bool floppy;
|
||||
const char *dirname;
|
||||
const char *dirname, *label;
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
@ -1097,6 +1104,18 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
s->fat_type = qemu_opt_get_number(opts, "fat-type", 0);
|
||||
floppy = qemu_opt_get_bool(opts, "floppy", false);
|
||||
|
||||
memset(s->volume_label, ' ', sizeof(s->volume_label));
|
||||
label = qemu_opt_get(opts, "label");
|
||||
if (label) {
|
||||
size_t label_length = strlen(label);
|
||||
if (label_length > 11) {
|
||||
error_setg(errp, "vvfat label cannot be longer than 11 bytes");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
memcpy(s->volume_label, label, label_length);
|
||||
}
|
||||
|
||||
if (floppy) {
|
||||
/* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
|
||||
if (!s->fat_type) {
|
||||
|
@ -154,6 +154,7 @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
|
||||
qemu_sglist_destroy(&qsg);
|
||||
return NVME_INVALID_FIELD | NVME_DNR;
|
||||
}
|
||||
qemu_sglist_destroy(&qsg);
|
||||
return NVME_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -499,8 +499,7 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
||||
|
||||
iov_discard_front(&iov, &out_num, sizeof(req->out));
|
||||
|
||||
if (in_num < 1 ||
|
||||
in_iov[in_num - 1].iov_len < sizeof(struct virtio_blk_inhdr)) {
|
||||
if (in_iov[in_num - 1].iov_len < sizeof(struct virtio_blk_inhdr)) {
|
||||
error_report("virtio-blk request inhdr too short");
|
||||
exit(1);
|
||||
}
|
||||
@ -651,16 +650,21 @@ static void virtio_blk_dma_restart_cb(void *opaque, int running,
|
||||
static void virtio_blk_reset(VirtIODevice *vdev)
|
||||
{
|
||||
VirtIOBlock *s = VIRTIO_BLK(vdev);
|
||||
|
||||
if (s->dataplane) {
|
||||
virtio_blk_data_plane_stop(s->dataplane);
|
||||
}
|
||||
AioContext *ctx;
|
||||
|
||||
/*
|
||||
* This should cancel pending requests, but can't do nicely until there
|
||||
* are per-device request lists.
|
||||
*/
|
||||
blk_drain_all();
|
||||
ctx = blk_get_aio_context(s->blk);
|
||||
aio_context_acquire(ctx);
|
||||
blk_drain(s->blk);
|
||||
|
||||
if (s->dataplane) {
|
||||
virtio_blk_data_plane_stop(s->dataplane);
|
||||
}
|
||||
aio_context_release(ctx);
|
||||
|
||||
blk_set_enable_write_cache(s->blk, s->original_wce);
|
||||
}
|
||||
|
||||
|
@ -131,6 +131,14 @@ void hbitmap_set(HBitmap *hb, uint64_t start, uint64_t count);
|
||||
*/
|
||||
void hbitmap_reset(HBitmap *hb, uint64_t start, uint64_t count);
|
||||
|
||||
/**
|
||||
* hbitmap_reset_all:
|
||||
* @hb: HBitmap to operate on.
|
||||
*
|
||||
* Reset all bits in an HBitmap.
|
||||
*/
|
||||
void hbitmap_reset_all(HBitmap *hb);
|
||||
|
||||
/**
|
||||
* hbitmap_get:
|
||||
* @hb: HBitmap to operate on.
|
||||
|
@ -75,7 +75,7 @@ size_t iov_memset(const struct iovec *iov, const unsigned int iov_cnt,
|
||||
* For iov_send_recv() _whole_ area being sent or received
|
||||
* should be within the iovec, not only beginning of it.
|
||||
*/
|
||||
ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt,
|
||||
ssize_t iov_send_recv(int sockfd, const struct iovec *iov, unsigned iov_cnt,
|
||||
size_t offset, size_t bytes, bool do_send);
|
||||
#define iov_recv(sockfd, iov, iov_cnt, offset, bytes) \
|
||||
iov_send_recv(sockfd, iov, iov_cnt, offset, bytes, false)
|
||||
|
@ -118,6 +118,7 @@ int blk_co_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors);
|
||||
int blk_co_flush(BlockBackend *blk);
|
||||
int blk_flush(BlockBackend *blk);
|
||||
int blk_flush_all(void);
|
||||
void blk_drain(BlockBackend *blk);
|
||||
void blk_drain_all(void);
|
||||
BlockdevOnError blk_get_on_error(BlockBackend *blk, bool is_read);
|
||||
BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read,
|
||||
|
@ -1453,13 +1453,17 @@
|
||||
# @fat-type: #optional FAT type: 12, 16 or 32
|
||||
# @floppy: #optional whether to export a floppy image (true) or
|
||||
# partitioned hard disk (false; default)
|
||||
# @label: #optional set the volume label, limited to 11 bytes. FAT16 and
|
||||
# FAT32 traditionally have some restrictions on labels, which are
|
||||
# ignored by most operating systems. Defaults to "QEMU VVFAT".
|
||||
# (since 2.4)
|
||||
# @rw: #optional whether to allow write operations (default: false)
|
||||
#
|
||||
# Since: 1.7
|
||||
##
|
||||
{ 'struct': 'BlockdevOptionsVVFAT',
|
||||
'data': { 'dir': 'str', '*fat-type': 'int', '*floppy': 'bool',
|
||||
'*rw': 'bool' } }
|
||||
'*label': 'str', '*rw': 'bool' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsGenericFormat
|
||||
|
@ -52,7 +52,6 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: Cannot specif
|
||||
Testing: -device virtio-scsi-pci -device scsi-hd
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) QEMU_PROG: -device scsi-hd: drive property not set
|
||||
QEMU_PROG: -device scsi-hd: Device 'scsi-hd' could not be initialized
|
||||
|
||||
|
||||
=== Overriding backing file ===
|
||||
@ -128,7 +127,6 @@ QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed.
|
||||
Testing: -drive if=virtio
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty
|
||||
QEMU_PROG: -drive if=virtio: Device 'virtio-blk-pci' could not be initialized
|
||||
|
||||
Testing: -drive if=scsi
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
@ -146,23 +144,19 @@ Testing: -drive if=none,id=disk -device ide-drive,drive=disk
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) QEMU_PROG: -device ide-drive,drive=disk: Device needs media, but drive is empty
|
||||
QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed.
|
||||
QEMU_PROG: -device ide-drive,drive=disk: Device 'ide-drive' could not be initialized
|
||||
|
||||
Testing: -drive if=none,id=disk -device ide-hd,drive=disk
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) QEMU_PROG: -device ide-hd,drive=disk: Device needs media, but drive is empty
|
||||
QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed.
|
||||
QEMU_PROG: -device ide-hd,drive=disk: Device 'ide-hd' could not be initialized
|
||||
|
||||
Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) QEMU_PROG: -device scsi-disk,drive=disk: Device needs media, but drive is empty
|
||||
QEMU_PROG: -device scsi-disk,drive=disk: Device 'scsi-disk' could not be initialized
|
||||
|
||||
Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty
|
||||
QEMU_PROG: -device scsi-hd,drive=disk: Device 'scsi-hd' could not be initialized
|
||||
|
||||
|
||||
=== Read-only ===
|
||||
@ -204,13 +198,11 @@ Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-dr
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) QEMU_PROG: -device ide-drive,drive=disk: Can't use a read-only drive
|
||||
QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed.
|
||||
QEMU_PROG: -device ide-drive,drive=disk: Device 'ide-drive' could not be initialized
|
||||
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-hd,drive=disk
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) QEMU_PROG: -device ide-hd,drive=disk: Can't use a read-only drive
|
||||
QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed.
|
||||
QEMU_PROG: -device ide-hd,drive=disk: Device 'ide-hd' could not be initialized
|
||||
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
|
@ -184,6 +184,23 @@ static void hbitmap_test_reset(TestHBitmapData *data,
|
||||
}
|
||||
}
|
||||
|
||||
static void hbitmap_test_reset_all(TestHBitmapData *data)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
hbitmap_reset_all(data->hb);
|
||||
|
||||
n = (data->size + BITS_PER_LONG - 1) / BITS_PER_LONG;
|
||||
if (n == 0) {
|
||||
n = 1;
|
||||
}
|
||||
memset(data->bits, 0, n * sizeof(unsigned long));
|
||||
|
||||
if (data->granularity == 0) {
|
||||
hbitmap_test_check(data, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void hbitmap_test_check_get(TestHBitmapData *data)
|
||||
{
|
||||
uint64_t count = 0;
|
||||
@ -364,6 +381,26 @@ static void test_hbitmap_reset(TestHBitmapData *data,
|
||||
hbitmap_test_set(data, L3 / 2, L3);
|
||||
}
|
||||
|
||||
static void test_hbitmap_reset_all(TestHBitmapData *data,
|
||||
const void *unused)
|
||||
{
|
||||
hbitmap_test_init(data, L3 * 2, 0);
|
||||
hbitmap_test_set(data, L1 - 1, L1 + 2);
|
||||
hbitmap_test_reset_all(data);
|
||||
hbitmap_test_set(data, 0, L1 * 3);
|
||||
hbitmap_test_reset_all(data);
|
||||
hbitmap_test_set(data, L2, L1);
|
||||
hbitmap_test_reset_all(data);
|
||||
hbitmap_test_set(data, L2, L3 - L2 + 1);
|
||||
hbitmap_test_reset_all(data);
|
||||
hbitmap_test_set(data, L3 - 1, 3);
|
||||
hbitmap_test_reset_all(data);
|
||||
hbitmap_test_set(data, 0, L3 * 2);
|
||||
hbitmap_test_reset_all(data);
|
||||
hbitmap_test_set(data, L3 / 2, L3);
|
||||
hbitmap_test_reset_all(data);
|
||||
}
|
||||
|
||||
static void test_hbitmap_granularity(TestHBitmapData *data,
|
||||
const void *unused)
|
||||
{
|
||||
@ -627,6 +664,7 @@ int main(int argc, char **argv)
|
||||
hbitmap_test_add("/hbitmap/set/overlap", test_hbitmap_set_overlap);
|
||||
hbitmap_test_add("/hbitmap/reset/empty", test_hbitmap_reset_empty);
|
||||
hbitmap_test_add("/hbitmap/reset/general", test_hbitmap_reset);
|
||||
hbitmap_test_add("/hbitmap/reset/all", test_hbitmap_reset_all);
|
||||
hbitmap_test_add("/hbitmap/granularity", test_hbitmap_granularity);
|
||||
|
||||
hbitmap_test_add("/hbitmap/truncate/nop", test_hbitmap_truncate_nop);
|
||||
|
@ -356,6 +356,19 @@ void hbitmap_reset(HBitmap *hb, uint64_t start, uint64_t count)
|
||||
hb_reset_between(hb, HBITMAP_LEVELS - 1, start, last);
|
||||
}
|
||||
|
||||
void hbitmap_reset_all(HBitmap *hb)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* Same as hbitmap_alloc() except for memset() instead of malloc() */
|
||||
for (i = HBITMAP_LEVELS; --i >= 1; ) {
|
||||
memset(hb->levels[i], 0, hb->sizes[i] * sizeof(unsigned long));
|
||||
}
|
||||
|
||||
hb->levels[0][0] = 1UL << (BITS_PER_LONG - 1);
|
||||
hb->count = 0;
|
||||
}
|
||||
|
||||
bool hbitmap_get(const HBitmap *hb, uint64_t item)
|
||||
{
|
||||
/* Compute position and bit in the last layer. */
|
||||
|
14
util/iov.c
14
util/iov.c
@ -133,7 +133,7 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt,
|
||||
ssize_t iov_send_recv(int sockfd, const struct iovec *_iov, unsigned iov_cnt,
|
||||
size_t offset, size_t bytes,
|
||||
bool do_send)
|
||||
{
|
||||
@ -141,6 +141,16 @@ ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt,
|
||||
ssize_t ret;
|
||||
size_t orig_len, tail;
|
||||
unsigned niov;
|
||||
struct iovec *local_iov, *iov;
|
||||
|
||||
if (bytes <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
local_iov = g_new0(struct iovec, iov_cnt);
|
||||
iov_copy(local_iov, iov_cnt, _iov, iov_cnt, offset, bytes);
|
||||
offset = 0;
|
||||
iov = local_iov;
|
||||
|
||||
while (bytes > 0) {
|
||||
/* Find the start position, skipping `offset' bytes:
|
||||
@ -187,6 +197,7 @@ ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt,
|
||||
|
||||
if (ret < 0) {
|
||||
assert(errno != EINTR);
|
||||
g_free(local_iov);
|
||||
if (errno == EAGAIN && total > 0) {
|
||||
return total;
|
||||
}
|
||||
@ -205,6 +216,7 @@ ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt,
|
||||
bytes -= ret;
|
||||
}
|
||||
|
||||
g_free(local_iov);
|
||||
return total;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user