Compare commits
63 Commits
pull-audio
...
v1.7.1
Author | SHA1 | Date | |
---|---|---|---|
|
ba014af39c | ||
|
d689974b51 | ||
|
e50218c269 | ||
|
fa98e47a25 | ||
|
ff51a1d589 | ||
|
5444df1581 | ||
|
e498311693 | ||
|
4736fb34f7 | ||
|
6d0a48acd8 | ||
|
5e5d4fc68e | ||
|
68e3bb1128 | ||
|
c885105bf3 | ||
|
2cd72adb1c | ||
|
819ddf7d1f | ||
|
ec6428b598 | ||
|
424388980d | ||
|
6b579c8c53 | ||
|
47c6edce7a | ||
|
a5221ee143 | ||
|
30a0fc3607 | ||
|
ad0a6444ad | ||
|
6b7ed87665 | ||
|
b54720b5d6 | ||
|
c426a2da12 | ||
|
15a14f2eeb | ||
|
88d08de7e5 | ||
|
109b2439f0 | ||
|
c2f6dc66bc | ||
|
dc9e1e798c | ||
|
02e1c55ddd | ||
|
9692bad34d | ||
|
6ec62b79e3 | ||
|
0e282aca86 | ||
|
75b4b747a2 | ||
|
0bc4142e7f | ||
|
b9cabc36a2 | ||
|
03bc4f6628 | ||
|
8b6d92a565 | ||
|
44c68b84ae | ||
|
4c3e00d83f | ||
|
6a108c4802 | ||
|
e480a1b8ff | ||
|
29b0fcc181 | ||
|
b8fca09eec | ||
|
50a203c3b9 | ||
|
f227ed1842 | ||
|
2dc7975300 | ||
|
8fa58fe910 | ||
|
97f74de48c | ||
|
30a08ab4e1 | ||
|
df3e347891 | ||
|
810766d9dd | ||
|
3220207c27 | ||
|
def56d28cf | ||
|
478f1f6ccf | ||
|
8f08550ee2 | ||
|
e6c007056c | ||
|
e84e23de35 | ||
|
40699a469e | ||
|
cbf23fdf21 | ||
|
a9b9ca7e0e | ||
|
d765275bb1 | ||
|
f47542925e |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,7 +3,6 @@ config-all-devices.*
|
||||
config-all-disas.*
|
||||
config-host.*
|
||||
config-target.*
|
||||
config.status
|
||||
trace/generated-tracers.h
|
||||
trace/generated-tracers.c
|
||||
trace/generated-tracers-dtrace.h
|
||||
|
@@ -879,7 +879,6 @@ F: block/rbd.c
|
||||
Sheepdog
|
||||
M: MORITA Kazutaka <morita.kazutaka@lab.ntt.co.jp>
|
||||
M: Liu Yuan <namei.unix@gmail.com>
|
||||
L: sheepdog@lists.wpkg.org
|
||||
S: Supported
|
||||
F: block/sheepdog.c
|
||||
|
||||
|
@@ -217,6 +217,11 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
||||
|
||||
ctx->walking_handlers--;
|
||||
|
||||
/* early return if we only have the aio_notify() fd */
|
||||
if (ctx->pollfds->len == 1) {
|
||||
return progress;
|
||||
}
|
||||
|
||||
/* wait until next event */
|
||||
ret = qemu_poll_ns((GPollFD *)ctx->pollfds->data,
|
||||
ctx->pollfds->len,
|
||||
|
@@ -161,6 +161,11 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
||||
|
||||
ctx->walking_handlers--;
|
||||
|
||||
/* early return if we only have the aio_notify() fd */
|
||||
if (count == 1) {
|
||||
return progress;
|
||||
}
|
||||
|
||||
/* wait until next event */
|
||||
while (count > 0) {
|
||||
int ret;
|
||||
|
@@ -95,7 +95,7 @@ static struct {
|
||||
}
|
||||
},
|
||||
|
||||
.period = { .hertz = 100 },
|
||||
.period = { .hertz = 250 },
|
||||
.plive = 0,
|
||||
.log_to_monitor = 0,
|
||||
.try_poll_in = 1,
|
||||
|
@@ -547,11 +547,11 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
|
||||
ss.rate = as->freq;
|
||||
|
||||
/*
|
||||
* qemu audio tick runs at 100 Hz (by default), so processing
|
||||
* data chunks worth 10 ms of sound should be a good fit.
|
||||
* qemu audio tick runs at 250 Hz (by default), so processing
|
||||
* data chunks worth 4 ms of sound should be a good fit.
|
||||
*/
|
||||
ba.tlength = pa_usec_to_bytes (10 * 1000, &ss);
|
||||
ba.minreq = pa_usec_to_bytes (5 * 1000, &ss);
|
||||
ba.tlength = pa_usec_to_bytes (4 * 1000, &ss);
|
||||
ba.minreq = pa_usec_to_bytes (2 * 1000, &ss);
|
||||
ba.maxlength = -1;
|
||||
ba.prebuf = -1;
|
||||
|
||||
|
@@ -58,7 +58,6 @@ typedef struct BlkMigDevState {
|
||||
/* Protected by block migration lock. */
|
||||
unsigned long *aio_bitmap;
|
||||
int64_t completed_sectors;
|
||||
BdrvDirtyBitmap *dirty_bitmap;
|
||||
} BlkMigDevState;
|
||||
|
||||
typedef struct BlkMigBlock {
|
||||
@@ -310,21 +309,12 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
|
||||
|
||||
/* Called with iothread lock taken. */
|
||||
|
||||
static void set_dirty_tracking(void)
|
||||
static void set_dirty_tracking(int enable)
|
||||
{
|
||||
BlkMigDevState *bmds;
|
||||
|
||||
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
||||
bmds->dirty_bitmap = bdrv_create_dirty_bitmap(bmds->bs, BLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
static void unset_dirty_tracking(void)
|
||||
{
|
||||
BlkMigDevState *bmds;
|
||||
|
||||
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
||||
bdrv_release_dirty_bitmap(bmds->bs, bmds->dirty_bitmap);
|
||||
bdrv_set_dirty_tracking(bmds->bs, enable ? BLOCK_SIZE : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,7 +432,7 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
|
||||
} else {
|
||||
blk_mig_unlock();
|
||||
}
|
||||
if (bdrv_get_dirty(bmds->bs, bmds->dirty_bitmap, sector)) {
|
||||
if (bdrv_get_dirty(bmds->bs, sector)) {
|
||||
|
||||
if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) {
|
||||
nr_sectors = total_sectors - sector;
|
||||
@@ -564,7 +554,7 @@ static int64_t get_remaining_dirty(void)
|
||||
int64_t dirty = 0;
|
||||
|
||||
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
|
||||
dirty += bdrv_get_dirty_count(bmds->bs, bmds->dirty_bitmap);
|
||||
dirty += bdrv_get_dirty_count(bmds->bs);
|
||||
}
|
||||
|
||||
return dirty << BDRV_SECTOR_BITS;
|
||||
@@ -579,7 +569,7 @@ static void blk_mig_cleanup(void)
|
||||
|
||||
bdrv_drain_all();
|
||||
|
||||
unset_dirty_tracking();
|
||||
set_dirty_tracking(0);
|
||||
|
||||
blk_mig_lock();
|
||||
while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
|
||||
@@ -614,7 +604,7 @@ static int block_save_setup(QEMUFile *f, void *opaque)
|
||||
init_blk_migration(f);
|
||||
|
||||
/* start track dirty blocks */
|
||||
set_dirty_tracking();
|
||||
set_dirty_tracking(1);
|
||||
qemu_mutex_unlock_iothread();
|
||||
|
||||
ret = flush_blks(f);
|
||||
@@ -790,8 +780,7 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
|
||||
}
|
||||
|
||||
if (flags & BLK_MIG_FLAG_ZERO_BLOCK) {
|
||||
ret = bdrv_write_zeroes(bs, addr, nr_sectors,
|
||||
BDRV_REQ_MAY_UNMAP);
|
||||
ret = bdrv_write_zeroes(bs, addr, nr_sectors);
|
||||
} else {
|
||||
buf = g_malloc(BLOCK_SIZE);
|
||||
qemu_get_buffer(f, buf, BLOCK_SIZE);
|
||||
|
456
block.c
456
block.c
@@ -49,13 +49,13 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
struct BdrvDirtyBitmap {
|
||||
HBitmap *bitmap;
|
||||
QLIST_ENTRY(BdrvDirtyBitmap) list;
|
||||
};
|
||||
|
||||
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
|
||||
|
||||
typedef enum {
|
||||
BDRV_REQ_COPY_ON_READ = 0x1,
|
||||
BDRV_REQ_ZERO_WRITE = 0x2,
|
||||
} BdrvRequestFlags;
|
||||
|
||||
static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
|
||||
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
@@ -79,13 +79,12 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BdrvRequestFlags flags,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque,
|
||||
bool is_write);
|
||||
static void coroutine_fn bdrv_co_do_rw(void *opaque);
|
||||
static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags);
|
||||
int64_t sector_num, int nb_sectors);
|
||||
|
||||
static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
|
||||
QTAILQ_HEAD_INITIALIZER(bdrv_states);
|
||||
@@ -324,7 +323,6 @@ BlockDriverState *bdrv_new(const char *device_name)
|
||||
BlockDriverState *bs;
|
||||
|
||||
bs = g_malloc0(sizeof(BlockDriverState));
|
||||
QLIST_INIT(&bs->dirty_bitmaps);
|
||||
pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
|
||||
if (device_name[0] != '\0') {
|
||||
QTAILQ_INSERT_TAIL(&bdrv_states, bs, list);
|
||||
@@ -1054,16 +1052,21 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
|
||||
int64_t total_size;
|
||||
BlockDriver *bdrv_qcow2;
|
||||
QEMUOptionParameter *create_options;
|
||||
QDict *snapshot_options;
|
||||
char backing_filename[PATH_MAX];
|
||||
|
||||
if (qdict_size(options) != 0) {
|
||||
error_setg(errp, "Can't use snapshot=on with driver-specific options");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
assert(filename != NULL);
|
||||
|
||||
/* if snapshot, we create a temporary backing file and open it
|
||||
instead of opening 'filename' directly */
|
||||
|
||||
/* Get the required size from the image */
|
||||
/* if there is a backing file, use it */
|
||||
bs1 = bdrv_new("");
|
||||
QINCREF(options);
|
||||
ret = bdrv_open(bs1, filename, options, BDRV_O_NO_BACKING,
|
||||
drv, &local_err);
|
||||
ret = bdrv_open(bs1, filename, NULL, 0, drv, &local_err);
|
||||
if (ret < 0) {
|
||||
bdrv_unref(bs1);
|
||||
goto fail;
|
||||
@@ -1072,18 +1075,33 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
|
||||
|
||||
bdrv_unref(bs1);
|
||||
|
||||
/* Create the temporary image */
|
||||
ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not get temporary filename");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Real path is meaningless for protocols */
|
||||
if (path_has_protocol(filename)) {
|
||||
snprintf(backing_filename, sizeof(backing_filename),
|
||||
"%s", filename);
|
||||
} else if (!realpath(filename, backing_filename)) {
|
||||
ret = -errno;
|
||||
error_setg_errno(errp, errno, "Could not resolve path '%s'", filename);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bdrv_qcow2 = bdrv_find_format("qcow2");
|
||||
create_options = parse_option_parameters("", bdrv_qcow2->create_options,
|
||||
NULL);
|
||||
|
||||
set_option_parameter_int(create_options, BLOCK_OPT_SIZE, total_size);
|
||||
set_option_parameter(create_options, BLOCK_OPT_BACKING_FILE,
|
||||
backing_filename);
|
||||
if (drv) {
|
||||
set_option_parameter(create_options, BLOCK_OPT_BACKING_FMT,
|
||||
drv->format_name);
|
||||
}
|
||||
|
||||
ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, &local_err);
|
||||
free_option_parameters(create_options);
|
||||
@@ -1096,22 +1114,6 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Prepare a new options QDict for the temporary file, where user
|
||||
* options refer to the backing file */
|
||||
if (filename) {
|
||||
qdict_put(options, "file.filename", qstring_from_str(filename));
|
||||
}
|
||||
if (drv) {
|
||||
qdict_put(options, "driver", qstring_from_str(drv->format_name));
|
||||
}
|
||||
|
||||
snapshot_options = qdict_new();
|
||||
qdict_put(snapshot_options, "backing", options);
|
||||
qdict_flatten(snapshot_options);
|
||||
|
||||
bs->options = snapshot_options;
|
||||
options = qdict_clone_shallow(bs->options);
|
||||
|
||||
filename = tmp_filename;
|
||||
drv = bdrv_qcow2;
|
||||
bs->is_temporary = 1;
|
||||
@@ -1557,8 +1559,13 @@ void bdrv_drain_all(void)
|
||||
BlockDriverState *bs;
|
||||
|
||||
while (busy) {
|
||||
/* FIXME: We do not have timer support here, so this is effectively
|
||||
* a busy wait.
|
||||
*/
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, list) {
|
||||
bdrv_start_throttled_reqs(bs);
|
||||
if (bdrv_start_throttled_reqs(bs)) {
|
||||
busy = true;
|
||||
}
|
||||
}
|
||||
|
||||
busy = bdrv_requests_pending_all();
|
||||
@@ -1615,7 +1622,7 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
|
||||
bs_dest->iostatus = bs_src->iostatus;
|
||||
|
||||
/* dirty bitmap */
|
||||
bs_dest->dirty_bitmaps = bs_src->dirty_bitmaps;
|
||||
bs_dest->dirty_bitmap = bs_src->dirty_bitmap;
|
||||
|
||||
/* reference count */
|
||||
bs_dest->refcnt = bs_src->refcnt;
|
||||
@@ -1648,7 +1655,7 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
|
||||
|
||||
/* bs_new must be anonymous and shouldn't have anything fancy enabled */
|
||||
assert(bs_new->device_name[0] == '\0');
|
||||
assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
|
||||
assert(bs_new->dirty_bitmap == NULL);
|
||||
assert(bs_new->job == NULL);
|
||||
assert(bs_new->dev == NULL);
|
||||
assert(bs_new->in_use == 0);
|
||||
@@ -1709,7 +1716,6 @@ static void bdrv_delete(BlockDriverState *bs)
|
||||
assert(!bs->job);
|
||||
assert(!bs->in_use);
|
||||
assert(!bs->refcnt);
|
||||
assert(QLIST_EMPTY(&bs->dirty_bitmaps));
|
||||
|
||||
bdrv_close(bs);
|
||||
|
||||
@@ -2391,48 +2397,10 @@ int bdrv_writev(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov)
|
||||
return bdrv_rwv_co(bs, sector_num, qiov, true, 0);
|
||||
}
|
||||
|
||||
int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, BdrvRequestFlags flags)
|
||||
int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
|
||||
{
|
||||
return bdrv_rw_co(bs, sector_num, NULL, nb_sectors, true,
|
||||
BDRV_REQ_ZERO_WRITE | flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Completely zero out a block device with the help of bdrv_write_zeroes.
|
||||
* The operation is sped up by checking the block status and only writing
|
||||
* zeroes to the device if they currently do not return zeroes. Optional
|
||||
* flags are passed through to bdrv_write_zeroes (e.g. BDRV_REQ_MAY_UNMAP).
|
||||
*
|
||||
* Returns < 0 on error, 0 on success. For error codes see bdrv_write().
|
||||
*/
|
||||
int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
|
||||
{
|
||||
int64_t target_size = bdrv_getlength(bs) / BDRV_SECTOR_SIZE;
|
||||
int64_t ret, nb_sectors, sector_num = 0;
|
||||
int n;
|
||||
|
||||
for (;;) {
|
||||
nb_sectors = target_size - sector_num;
|
||||
if (nb_sectors <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if (nb_sectors > INT_MAX) {
|
||||
nb_sectors = INT_MAX;
|
||||
}
|
||||
ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n);
|
||||
if (ret & BDRV_BLOCK_ZERO) {
|
||||
sector_num += n;
|
||||
continue;
|
||||
}
|
||||
ret = bdrv_write_zeroes(bs, sector_num, n, flags);
|
||||
if (ret < 0) {
|
||||
error_report("error writing zeroes at sector %" PRId64 ": %s",
|
||||
sector_num, strerror(-ret));
|
||||
return ret;
|
||||
}
|
||||
sector_num += n;
|
||||
}
|
||||
BDRV_REQ_ZERO_WRITE);
|
||||
}
|
||||
|
||||
int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
||||
@@ -2614,7 +2582,7 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
|
||||
if (drv->bdrv_co_write_zeroes &&
|
||||
buffer_is_zero(bounce_buffer, iov.iov_len)) {
|
||||
ret = bdrv_co_do_write_zeroes(bs, cluster_sector_num,
|
||||
cluster_nb_sectors, 0);
|
||||
cluster_nb_sectors);
|
||||
} else {
|
||||
/* This does not change the data on the disk, it is not necessary
|
||||
* to flush even in cache=writethrough mode.
|
||||
@@ -2747,77 +2715,33 @@ int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs,
|
||||
BDRV_REQ_COPY_ON_READ);
|
||||
}
|
||||
|
||||
/* if no limit is specified in the BlockLimits use a default
|
||||
* of 32768 512-byte sectors (16 MiB) per request.
|
||||
*/
|
||||
#define MAX_WRITE_ZEROES_DEFAULT 32768
|
||||
|
||||
static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
|
||||
int64_t sector_num, int nb_sectors)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
QEMUIOVector qiov;
|
||||
struct iovec iov = {0};
|
||||
int ret = 0;
|
||||
struct iovec iov;
|
||||
int ret;
|
||||
|
||||
int max_write_zeroes = bs->bl.max_write_zeroes ?
|
||||
bs->bl.max_write_zeroes : MAX_WRITE_ZEROES_DEFAULT;
|
||||
/* TODO Emulate only part of misaligned requests instead of letting block
|
||||
* drivers return -ENOTSUP and emulate everything */
|
||||
|
||||
while (nb_sectors > 0 && !ret) {
|
||||
int num = nb_sectors;
|
||||
|
||||
/* Align request. Block drivers can expect the "bulk" of the request
|
||||
* to be aligned.
|
||||
*/
|
||||
if (bs->bl.write_zeroes_alignment
|
||||
&& num > bs->bl.write_zeroes_alignment) {
|
||||
if (sector_num % bs->bl.write_zeroes_alignment != 0) {
|
||||
/* Make a small request up to the first aligned sector. */
|
||||
num = bs->bl.write_zeroes_alignment;
|
||||
num -= sector_num % bs->bl.write_zeroes_alignment;
|
||||
} else if ((sector_num + num) % bs->bl.write_zeroes_alignment != 0) {
|
||||
/* Shorten the request to the last aligned sector. num cannot
|
||||
* underflow because num > bs->bl.write_zeroes_alignment.
|
||||
*/
|
||||
num -= (sector_num + num) % bs->bl.write_zeroes_alignment;
|
||||
}
|
||||
/* First try the efficient write zeroes operation */
|
||||
if (drv->bdrv_co_write_zeroes) {
|
||||
ret = drv->bdrv_co_write_zeroes(bs, sector_num, nb_sectors);
|
||||
if (ret != -ENOTSUP) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* limit request size */
|
||||
if (num > max_write_zeroes) {
|
||||
num = max_write_zeroes;
|
||||
}
|
||||
|
||||
ret = -ENOTSUP;
|
||||
/* First try the efficient write zeroes operation */
|
||||
if (drv->bdrv_co_write_zeroes) {
|
||||
ret = drv->bdrv_co_write_zeroes(bs, sector_num, num, flags);
|
||||
}
|
||||
|
||||
if (ret == -ENOTSUP) {
|
||||
/* Fall back to bounce buffer if write zeroes is unsupported */
|
||||
iov.iov_len = num * BDRV_SECTOR_SIZE;
|
||||
if (iov.iov_base == NULL) {
|
||||
iov.iov_base = qemu_blockalign(bs, num * BDRV_SECTOR_SIZE);
|
||||
memset(iov.iov_base, 0, num * BDRV_SECTOR_SIZE);
|
||||
}
|
||||
qemu_iovec_init_external(&qiov, &iov, 1);
|
||||
|
||||
ret = drv->bdrv_co_writev(bs, sector_num, num, &qiov);
|
||||
|
||||
/* Keep bounce buffer around if it is big enough for all
|
||||
* all future requests.
|
||||
*/
|
||||
if (num < max_write_zeroes) {
|
||||
qemu_vfree(iov.iov_base);
|
||||
iov.iov_base = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
sector_num += num;
|
||||
nb_sectors -= num;
|
||||
}
|
||||
|
||||
/* Fall back to bounce buffer if write zeroes is unsupported */
|
||||
iov.iov_len = nb_sectors * BDRV_SECTOR_SIZE;
|
||||
iov.iov_base = qemu_blockalign(bs, iov.iov_len);
|
||||
memset(iov.iov_base, 0, iov.iov_len);
|
||||
qemu_iovec_init_external(&qiov, &iov, 1);
|
||||
|
||||
ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, &qiov);
|
||||
|
||||
qemu_vfree(iov.iov_base);
|
||||
return ret;
|
||||
}
|
||||
@@ -2859,7 +2783,7 @@ static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
|
||||
if (ret < 0) {
|
||||
/* Do nothing, write notifier decided to fail this request */
|
||||
} else if (flags & BDRV_REQ_ZERO_WRITE) {
|
||||
ret = bdrv_co_do_write_zeroes(bs, sector_num, nb_sectors, flags);
|
||||
ret = bdrv_co_do_write_zeroes(bs, sector_num, nb_sectors);
|
||||
} else {
|
||||
ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
|
||||
}
|
||||
@@ -2868,7 +2792,9 @@ static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
|
||||
ret = bdrv_co_flush(bs);
|
||||
}
|
||||
|
||||
bdrv_set_dirty(bs, sector_num, nb_sectors);
|
||||
if (bs->dirty_bitmap) {
|
||||
bdrv_set_dirty(bs, sector_num, nb_sectors);
|
||||
}
|
||||
|
||||
if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
|
||||
bs->wr_highest_sector = sector_num + nb_sectors - 1;
|
||||
@@ -2891,17 +2817,12 @@ int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
|
||||
int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
BdrvRequestFlags flags)
|
||||
int64_t sector_num, int nb_sectors)
|
||||
{
|
||||
trace_bdrv_co_write_zeroes(bs, sector_num, nb_sectors, flags);
|
||||
|
||||
if (!(bs->open_flags & BDRV_O_UNMAP)) {
|
||||
flags &= ~BDRV_REQ_MAY_UNMAP;
|
||||
}
|
||||
trace_bdrv_co_write_zeroes(bs, sector_num, nb_sectors);
|
||||
|
||||
return bdrv_co_do_writev(bs, sector_num, nb_sectors, NULL,
|
||||
BDRV_REQ_ZERO_WRITE | flags);
|
||||
BDRV_REQ_ZERO_WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3181,36 +3102,6 @@ int bdrv_has_zero_init(BlockDriverState *bs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs)
|
||||
{
|
||||
BlockDriverInfo bdi;
|
||||
|
||||
if (bs->backing_hd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bdrv_get_info(bs, &bdi) == 0) {
|
||||
return bdi.unallocated_blocks_are_zero;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs)
|
||||
{
|
||||
BlockDriverInfo bdi;
|
||||
|
||||
if (bs->backing_hd || !(bs->open_flags & BDRV_O_UNMAP)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bdrv_get_info(bs, &bdi) == 0) {
|
||||
return bdi.can_write_zeroes_with_unmap;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef struct BdrvCoGetBlockStatusData {
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *base;
|
||||
@@ -3280,8 +3171,8 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
||||
*pnum, pnum);
|
||||
}
|
||||
|
||||
if (!(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO)) {
|
||||
if (bdrv_unallocated_blocks_are_zero(bs)) {
|
||||
if (!(ret & BDRV_BLOCK_DATA)) {
|
||||
if (bdrv_has_zero_init(bs)) {
|
||||
ret |= BDRV_BLOCK_ZERO;
|
||||
} else if (bs->backing_hd) {
|
||||
BlockDriverState *bs2 = bs->backing_hd;
|
||||
@@ -3439,7 +3330,7 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
if (bdrv_check_request(bs, sector_num, nb_sectors))
|
||||
return -EIO;
|
||||
|
||||
assert(QLIST_EMPTY(&bs->dirty_bitmaps));
|
||||
assert(!bs->dirty_bitmap);
|
||||
|
||||
return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
|
||||
}
|
||||
@@ -3528,19 +3419,6 @@ int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag)
|
||||
{
|
||||
while (bs && bs->drv && !bs->drv->bdrv_debug_remove_breakpoint) {
|
||||
bs = bs->file;
|
||||
}
|
||||
|
||||
if (bs && bs->drv && bs->drv->bdrv_debug_remove_breakpoint) {
|
||||
return bs->drv->bdrv_debug_remove_breakpoint(bs, tag);
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
int bdrv_debug_resume(BlockDriverState *bs, const char *tag)
|
||||
{
|
||||
while (bs && bs->drv && !bs->drv->bdrv_debug_resume) {
|
||||
@@ -3676,7 +3554,7 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
{
|
||||
trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
|
||||
|
||||
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, 0,
|
||||
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors,
|
||||
cb, opaque, false);
|
||||
}
|
||||
|
||||
@@ -3686,18 +3564,7 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
{
|
||||
trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
|
||||
|
||||
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, 0,
|
||||
cb, opaque, true);
|
||||
}
|
||||
|
||||
BlockDriverAIOCB *bdrv_aio_write_zeroes(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
trace_bdrv_aio_write_zeroes(bs, sector_num, nb_sectors, flags, opaque);
|
||||
|
||||
return bdrv_co_aio_rw_vector(bs, sector_num, NULL, nb_sectors,
|
||||
BDRV_REQ_ZERO_WRITE | flags,
|
||||
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors,
|
||||
cb, opaque, true);
|
||||
}
|
||||
|
||||
@@ -3869,10 +3736,8 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
|
||||
/* Run the aio requests. */
|
||||
mcb->num_requests = num_reqs;
|
||||
for (i = 0; i < num_reqs; i++) {
|
||||
bdrv_co_aio_rw_vector(bs, reqs[i].sector, reqs[i].qiov,
|
||||
reqs[i].nb_sectors, reqs[i].flags,
|
||||
multiwrite_cb, mcb,
|
||||
true);
|
||||
bdrv_aio_writev(bs, reqs[i].sector, reqs[i].qiov,
|
||||
reqs[i].nb_sectors, multiwrite_cb, mcb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -4014,10 +3879,10 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque)
|
||||
|
||||
if (!acb->is_write) {
|
||||
acb->req.error = bdrv_co_do_readv(bs, acb->req.sector,
|
||||
acb->req.nb_sectors, acb->req.qiov, acb->req.flags);
|
||||
acb->req.nb_sectors, acb->req.qiov, 0);
|
||||
} else {
|
||||
acb->req.error = bdrv_co_do_writev(bs, acb->req.sector,
|
||||
acb->req.nb_sectors, acb->req.qiov, acb->req.flags);
|
||||
acb->req.nb_sectors, acb->req.qiov, 0);
|
||||
}
|
||||
|
||||
acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
|
||||
@@ -4028,7 +3893,6 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BdrvRequestFlags flags,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque,
|
||||
bool is_write)
|
||||
@@ -4040,7 +3904,6 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
||||
acb->req.sector = sector_num;
|
||||
acb->req.nb_sectors = nb_sectors;
|
||||
acb->req.qiov = qiov;
|
||||
acb->req.flags = flags;
|
||||
acb->is_write = is_write;
|
||||
acb->done = NULL;
|
||||
|
||||
@@ -4316,16 +4179,9 @@ static void coroutine_fn bdrv_discard_co_entry(void *opaque)
|
||||
rwco->ret = bdrv_co_discard(rwco->bs, rwco->sector_num, rwco->nb_sectors);
|
||||
}
|
||||
|
||||
/* if no limit is specified in the BlockLimits use a default
|
||||
* of 32768 512-byte sectors (16 MiB) per request.
|
||||
*/
|
||||
#define MAX_DISCARD_DEFAULT 32768
|
||||
|
||||
int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
{
|
||||
int max_discard;
|
||||
|
||||
if (!bs->drv) {
|
||||
return -ENOMEDIUM;
|
||||
} else if (bdrv_check_request(bs, sector_num, nb_sectors)) {
|
||||
@@ -4334,62 +4190,34 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
|
||||
return -EROFS;
|
||||
}
|
||||
|
||||
bdrv_reset_dirty(bs, sector_num, nb_sectors);
|
||||
if (bs->dirty_bitmap) {
|
||||
bdrv_reset_dirty(bs, sector_num, nb_sectors);
|
||||
}
|
||||
|
||||
/* Do nothing if disabled. */
|
||||
if (!(bs->open_flags & BDRV_O_UNMAP)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!bs->drv->bdrv_co_discard && !bs->drv->bdrv_aio_discard) {
|
||||
if (bs->drv->bdrv_co_discard) {
|
||||
return bs->drv->bdrv_co_discard(bs, sector_num, nb_sectors);
|
||||
} else if (bs->drv->bdrv_aio_discard) {
|
||||
BlockDriverAIOCB *acb;
|
||||
CoroutineIOCompletion co = {
|
||||
.coroutine = qemu_coroutine_self(),
|
||||
};
|
||||
|
||||
acb = bs->drv->bdrv_aio_discard(bs, sector_num, nb_sectors,
|
||||
bdrv_co_io_em_complete, &co);
|
||||
if (acb == NULL) {
|
||||
return -EIO;
|
||||
} else {
|
||||
qemu_coroutine_yield();
|
||||
return co.ret;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
max_discard = bs->bl.max_discard ? bs->bl.max_discard : MAX_DISCARD_DEFAULT;
|
||||
while (nb_sectors > 0) {
|
||||
int ret;
|
||||
int num = nb_sectors;
|
||||
|
||||
/* align request */
|
||||
if (bs->bl.discard_alignment &&
|
||||
num >= bs->bl.discard_alignment &&
|
||||
sector_num % bs->bl.discard_alignment) {
|
||||
if (num > bs->bl.discard_alignment) {
|
||||
num = bs->bl.discard_alignment;
|
||||
}
|
||||
num -= sector_num % bs->bl.discard_alignment;
|
||||
}
|
||||
|
||||
/* limit request size */
|
||||
if (num > max_discard) {
|
||||
num = max_discard;
|
||||
}
|
||||
|
||||
if (bs->drv->bdrv_co_discard) {
|
||||
ret = bs->drv->bdrv_co_discard(bs, sector_num, num);
|
||||
} else {
|
||||
BlockDriverAIOCB *acb;
|
||||
CoroutineIOCompletion co = {
|
||||
.coroutine = qemu_coroutine_self(),
|
||||
};
|
||||
|
||||
acb = bs->drv->bdrv_aio_discard(bs, sector_num, nb_sectors,
|
||||
bdrv_co_io_em_complete, &co);
|
||||
if (acb == NULL) {
|
||||
return -EIO;
|
||||
} else {
|
||||
qemu_coroutine_yield();
|
||||
ret = co.ret;
|
||||
}
|
||||
}
|
||||
if (ret && ret != -ENOTSUP) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
sector_num += num;
|
||||
nb_sectors -= num;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
|
||||
@@ -4526,90 +4354,58 @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov)
|
||||
return true;
|
||||
}
|
||||
|
||||
BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity)
|
||||
void bdrv_set_dirty_tracking(BlockDriverState *bs, int granularity)
|
||||
{
|
||||
int64_t bitmap_size;
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
|
||||
assert((granularity & (granularity - 1)) == 0);
|
||||
|
||||
granularity >>= BDRV_SECTOR_BITS;
|
||||
assert(granularity);
|
||||
bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS);
|
||||
bitmap = g_malloc0(sizeof(BdrvDirtyBitmap));
|
||||
bitmap->bitmap = hbitmap_alloc(bitmap_size, ffs(granularity) - 1);
|
||||
QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
BdrvDirtyBitmap *bm, *next;
|
||||
QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
|
||||
if (bm == bitmap) {
|
||||
QLIST_REMOVE(bitmap, list);
|
||||
hbitmap_free(bitmap->bitmap);
|
||||
g_free(bitmap);
|
||||
return;
|
||||
if (granularity) {
|
||||
granularity >>= BDRV_SECTOR_BITS;
|
||||
assert(!bs->dirty_bitmap);
|
||||
bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS);
|
||||
bs->dirty_bitmap = hbitmap_alloc(bitmap_size, ffs(granularity) - 1);
|
||||
} else {
|
||||
if (bs->dirty_bitmap) {
|
||||
hbitmap_free(bs->dirty_bitmap);
|
||||
bs->dirty_bitmap = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
|
||||
int bdrv_get_dirty(BlockDriverState *bs, int64_t sector)
|
||||
{
|
||||
BdrvDirtyBitmap *bm;
|
||||
BlockDirtyInfoList *list = NULL;
|
||||
BlockDirtyInfoList **plist = &list;
|
||||
|
||||
QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
|
||||
BlockDirtyInfo *info = g_malloc0(sizeof(BlockDirtyInfo));
|
||||
BlockDirtyInfoList *entry = g_malloc0(sizeof(BlockDirtyInfoList));
|
||||
info->count = bdrv_get_dirty_count(bs, bm);
|
||||
info->granularity =
|
||||
((int64_t) BDRV_SECTOR_SIZE << hbitmap_granularity(bm->bitmap));
|
||||
entry->value = info;
|
||||
*plist = entry;
|
||||
plist = &entry->next;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector)
|
||||
{
|
||||
if (bitmap) {
|
||||
return hbitmap_get(bitmap->bitmap, sector);
|
||||
if (bs->dirty_bitmap) {
|
||||
return hbitmap_get(bs->dirty_bitmap, sector);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_dirty_iter_init(BlockDriverState *bs,
|
||||
BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
|
||||
void bdrv_dirty_iter_init(BlockDriverState *bs, HBitmapIter *hbi)
|
||||
{
|
||||
hbitmap_iter_init(hbi, bitmap->bitmap, 0);
|
||||
hbitmap_iter_init(hbi, bs->dirty_bitmap, 0);
|
||||
}
|
||||
|
||||
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int nr_sectors)
|
||||
{
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
|
||||
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
|
||||
}
|
||||
hbitmap_set(bs->dirty_bitmap, cur_sector, nr_sectors);
|
||||
}
|
||||
|
||||
void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors)
|
||||
void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int nr_sectors)
|
||||
{
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
|
||||
hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
|
||||
}
|
||||
hbitmap_reset(bs->dirty_bitmap, cur_sector, nr_sectors);
|
||||
}
|
||||
|
||||
int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
|
||||
int64_t bdrv_get_dirty_count(BlockDriverState *bs)
|
||||
{
|
||||
return hbitmap_count(bitmap->bitmap);
|
||||
if (bs->dirty_bitmap) {
|
||||
return hbitmap_count(bs->dirty_bitmap);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get a reference to bs */
|
||||
@@ -4708,6 +4504,7 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
||||
{
|
||||
QEMUOptionParameter *param = NULL, *create_options = NULL;
|
||||
QEMUOptionParameter *backing_fmt, *backing_file, *size;
|
||||
BlockDriverState *bs = NULL;
|
||||
BlockDriver *drv, *proto_drv;
|
||||
BlockDriver *backing_drv = NULL;
|
||||
Error *local_err = NULL;
|
||||
@@ -4786,7 +4583,6 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
||||
size = get_option_parameter(param, BLOCK_OPT_SIZE);
|
||||
if (size && size->value.n == -1) {
|
||||
if (backing_file && backing_file->value.s) {
|
||||
BlockDriverState *bs;
|
||||
uint64_t size;
|
||||
char buf[32];
|
||||
int back_flags;
|
||||
@@ -4805,7 +4601,6 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
||||
error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
local_err = NULL;
|
||||
bdrv_unref(bs);
|
||||
goto out;
|
||||
}
|
||||
bdrv_get_geometry(bs, &size);
|
||||
@@ -4813,8 +4608,6 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
||||
|
||||
snprintf(buf, sizeof(buf), "%" PRId64, size);
|
||||
set_option_parameter(param, BLOCK_OPT_SIZE, buf);
|
||||
|
||||
bdrv_unref(bs);
|
||||
} else {
|
||||
error_setg(errp, "Image creation needs a size parameter");
|
||||
goto out;
|
||||
@@ -4845,6 +4638,9 @@ out:
|
||||
free_option_parameters(create_options);
|
||||
free_option_parameters(param);
|
||||
|
||||
if (bs) {
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
if (error_is_set(&local_err)) {
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
@@ -138,8 +138,7 @@ static int coroutine_fn backup_do_cow(BlockDriverState *bs,
|
||||
|
||||
if (buffer_is_zero(iov.iov_base, iov.iov_len)) {
|
||||
ret = bdrv_co_write_zeroes(job->target,
|
||||
start * BACKUP_SECTORS_PER_CLUSTER,
|
||||
n, BDRV_REQ_MAY_UNMAP);
|
||||
start * BACKUP_SECTORS_PER_CLUSTER, n);
|
||||
} else {
|
||||
ret = bdrv_co_writev(job->target,
|
||||
start * BACKUP_SECTORS_PER_CLUSTER, n,
|
||||
|
@@ -605,31 +605,6 @@ static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
|
||||
const char *tag)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
BlkdebugSuspendedReq *r;
|
||||
BlkdebugRule *rule, *next;
|
||||
int i, ret = -ENOENT;
|
||||
|
||||
for (i = 0; i < BLKDBG_EVENT_MAX; i++) {
|
||||
QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
|
||||
if (rule->action == ACTION_SUSPEND &&
|
||||
!strcmp(rule->options.suspend.tag, tag)) {
|
||||
remove_rule(rule);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
QLIST_FOREACH(r, &s->suspended_reqs, next) {
|
||||
if (!strcmp(r->tag, tag)) {
|
||||
qemu_coroutine_enter(r->co, NULL);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
|
||||
{
|
||||
@@ -664,8 +639,6 @@ static BlockDriver bdrv_blkdebug = {
|
||||
|
||||
.bdrv_debug_event = blkdebug_debug_event,
|
||||
.bdrv_debug_breakpoint = blkdebug_debug_breakpoint,
|
||||
.bdrv_debug_remove_breakpoint
|
||||
= blkdebug_debug_remove_breakpoint,
|
||||
.bdrv_debug_resume = blkdebug_debug_resume,
|
||||
.bdrv_debug_is_suspended = blkdebug_debug_is_suspended,
|
||||
};
|
||||
|
126
block/cow.c
126
block/cow.c
@@ -103,18 +103,40 @@ static int cow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void cow_set_bits(uint8_t *bitmap, int start, int64_t nb_sectors)
|
||||
/*
|
||||
* XXX(hch): right now these functions are extremely inefficient.
|
||||
* We should just read the whole bitmap we'll need in one go instead.
|
||||
*/
|
||||
static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum, bool *first)
|
||||
{
|
||||
int64_t bitnum = start, last = start + nb_sectors;
|
||||
while (bitnum < last) {
|
||||
if ((bitnum & 7) == 0 && bitnum + 8 <= last) {
|
||||
bitmap[bitnum / 8] = 0xFF;
|
||||
bitnum += 8;
|
||||
continue;
|
||||
}
|
||||
bitmap[bitnum/8] |= (1 << (bitnum % 8));
|
||||
bitnum++;
|
||||
uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8;
|
||||
uint8_t bitmap;
|
||||
int ret;
|
||||
|
||||
ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (bitmap & (1 << (bitnum % 8))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*first) {
|
||||
ret = bdrv_flush(bs->file);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
*first = false;
|
||||
}
|
||||
|
||||
bitmap |= (1 << (bitnum % 8));
|
||||
|
||||
ret = bdrv_pwrite(bs->file, offset, &bitmap, sizeof(bitmap));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BITS_PER_BITMAP_SECTOR (512 * 8)
|
||||
@@ -152,34 +174,18 @@ static int coroutine_fn cow_co_is_allocated(BlockDriverState *bs,
|
||||
{
|
||||
int64_t bitnum = sector_num + sizeof(struct cow_header_v2) * 8;
|
||||
uint64_t offset = (bitnum / 8) & -BDRV_SECTOR_SIZE;
|
||||
bool first = true;
|
||||
int changed = 0, same = 0;
|
||||
uint8_t bitmap[BDRV_SECTOR_SIZE];
|
||||
int ret;
|
||||
int changed;
|
||||
|
||||
do {
|
||||
int ret;
|
||||
uint8_t bitmap[BDRV_SECTOR_SIZE];
|
||||
ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
bitnum &= BITS_PER_BITMAP_SECTOR - 1;
|
||||
int sector_bits = MIN(nb_sectors, BITS_PER_BITMAP_SECTOR - bitnum);
|
||||
|
||||
ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (first) {
|
||||
changed = cow_test_bit(bitnum, bitmap);
|
||||
first = false;
|
||||
}
|
||||
|
||||
same += cow_find_streak(bitmap, changed, bitnum, nb_sectors);
|
||||
|
||||
bitnum += sector_bits;
|
||||
nb_sectors -= sector_bits;
|
||||
offset += BDRV_SECTOR_SIZE;
|
||||
} while (nb_sectors);
|
||||
|
||||
*num_same = same;
|
||||
bitnum &= BITS_PER_BITMAP_SECTOR - 1;
|
||||
changed = cow_test_bit(bitnum, bitmap);
|
||||
*num_same = cow_find_streak(bitmap, changed, bitnum, nb_sectors);
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -198,52 +204,18 @@ static int64_t coroutine_fn cow_co_get_block_status(BlockDriverState *bs,
|
||||
static int cow_update_bitmap(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
{
|
||||
int64_t bitnum = sector_num + sizeof(struct cow_header_v2) * 8;
|
||||
uint64_t offset = (bitnum / 8) & -BDRV_SECTOR_SIZE;
|
||||
int error = 0;
|
||||
int i;
|
||||
bool first = true;
|
||||
int sector_bits;
|
||||
|
||||
for ( ; nb_sectors;
|
||||
bitnum += sector_bits,
|
||||
nb_sectors -= sector_bits,
|
||||
offset += BDRV_SECTOR_SIZE) {
|
||||
int ret, set;
|
||||
uint8_t bitmap[BDRV_SECTOR_SIZE];
|
||||
|
||||
bitnum &= BITS_PER_BITMAP_SECTOR - 1;
|
||||
sector_bits = MIN(nb_sectors, BITS_PER_BITMAP_SECTOR - bitnum);
|
||||
|
||||
ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Skip over any already set bits */
|
||||
set = cow_find_streak(bitmap, 1, bitnum, sector_bits);
|
||||
bitnum += set;
|
||||
sector_bits -= set;
|
||||
nb_sectors -= set;
|
||||
if (!sector_bits) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (first) {
|
||||
ret = bdrv_flush(bs->file);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
|
||||
cow_set_bits(bitmap, bitnum, sector_bits);
|
||||
|
||||
ret = bdrv_pwrite(bs->file, offset, &bitmap, sizeof(bitmap));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
for (i = 0; i < nb_sectors; i++) {
|
||||
error = cow_set_bit(bs, sector_num + i, &first);
|
||||
if (error) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
static int coroutine_fn cow_read(BlockDriverState *bs, int64_t sector_num,
|
||||
|
81
block/curl.c
81
block/curl.c
@@ -34,6 +34,11 @@
|
||||
#define DPRINTF(fmt, ...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#if LIBCURL_VERSION_NUM >= 0x071000
|
||||
/* The multi interface timer callback was introduced in 7.16.0 */
|
||||
#define NEED_CURL_TIMER_CALLBACK
|
||||
#endif
|
||||
|
||||
#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
|
||||
CURLPROTO_FTP | CURLPROTO_FTPS | \
|
||||
CURLPROTO_TFTP)
|
||||
@@ -77,6 +82,7 @@ typedef struct CURLState
|
||||
|
||||
typedef struct BDRVCURLState {
|
||||
CURLM *multi;
|
||||
QEMUTimer timer;
|
||||
size_t len;
|
||||
CURLState states[CURL_NUM_STATES];
|
||||
char *url;
|
||||
@@ -87,6 +93,23 @@ typedef struct BDRVCURLState {
|
||||
static void curl_clean_state(CURLState *s);
|
||||
static void curl_multi_do(void *arg);
|
||||
|
||||
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||
static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
|
||||
{
|
||||
BDRVCURLState *s = opaque;
|
||||
|
||||
DPRINTF("CURL: timer callback timeout_ms %ld\n", timeout_ms);
|
||||
if (timeout_ms == -1) {
|
||||
timer_del(&s->timer);
|
||||
} else {
|
||||
int64_t timeout_ns = (int64_t)timeout_ms * 1000 * 1000;
|
||||
timer_mod(&s->timer,
|
||||
qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + timeout_ns);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
||||
void *s, void *sp)
|
||||
{
|
||||
@@ -209,20 +232,10 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
||||
return FIND_RET_NONE;
|
||||
}
|
||||
|
||||
static void curl_multi_do(void *arg)
|
||||
static void curl_multi_read(BDRVCURLState *s)
|
||||
{
|
||||
BDRVCURLState *s = (BDRVCURLState *)arg;
|
||||
int running;
|
||||
int r;
|
||||
int msgs_in_queue;
|
||||
|
||||
if (!s->multi)
|
||||
return;
|
||||
|
||||
do {
|
||||
r = curl_multi_socket_all(s->multi, &running);
|
||||
} while(r == CURLM_CALL_MULTI_PERFORM);
|
||||
|
||||
/* Try to find done transfers, so we can free the easy
|
||||
* handle again. */
|
||||
do {
|
||||
@@ -266,6 +279,41 @@ static void curl_multi_do(void *arg)
|
||||
} while(msgs_in_queue);
|
||||
}
|
||||
|
||||
static void curl_multi_do(void *arg)
|
||||
{
|
||||
BDRVCURLState *s = (BDRVCURLState *)arg;
|
||||
int running;
|
||||
int r;
|
||||
|
||||
if (!s->multi) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
r = curl_multi_socket_all(s->multi, &running);
|
||||
} while(r == CURLM_CALL_MULTI_PERFORM);
|
||||
|
||||
curl_multi_read(s);
|
||||
}
|
||||
|
||||
static void curl_multi_timeout_do(void *arg)
|
||||
{
|
||||
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||
BDRVCURLState *s = (BDRVCURLState *)arg;
|
||||
int running;
|
||||
|
||||
if (!s->multi) {
|
||||
return;
|
||||
}
|
||||
|
||||
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
||||
|
||||
curl_multi_read(s);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
static CURLState *curl_init_state(BDRVCURLState *s)
|
||||
{
|
||||
CURLState *state = NULL;
|
||||
@@ -473,12 +521,20 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
curl_easy_cleanup(state->curl);
|
||||
state->curl = NULL;
|
||||
|
||||
aio_timer_init(bdrv_get_aio_context(bs), &s->timer,
|
||||
QEMU_CLOCK_REALTIME, SCALE_NS,
|
||||
curl_multi_timeout_do, s);
|
||||
|
||||
// Now we know the file exists and its size, so let's
|
||||
// initialize the multi interface!
|
||||
|
||||
s->multi = curl_multi_init();
|
||||
curl_multi_setopt(s->multi, CURLMOPT_SOCKETDATA, s);
|
||||
curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
|
||||
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||
curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
|
||||
curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
|
||||
#endif
|
||||
curl_multi_do(s);
|
||||
|
||||
qemu_opts_del(opts);
|
||||
@@ -597,6 +653,9 @@ static void curl_close(BlockDriverState *bs)
|
||||
}
|
||||
if (s->multi)
|
||||
curl_multi_cleanup(s->multi);
|
||||
|
||||
timer_del(&s->timer);
|
||||
|
||||
g_free(s->url);
|
||||
}
|
||||
|
||||
|
198
block/iscsi.c
198
block/iscsi.c
@@ -2,7 +2,6 @@
|
||||
* QEMU Block driver for iSCSI images
|
||||
*
|
||||
* Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
||||
* Copyright (c) 2012-2013 Peter Lieven <pl@kamp.de>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -55,10 +54,8 @@ typedef struct IscsiLun {
|
||||
QEMUTimer *nop_timer;
|
||||
uint8_t lbpme;
|
||||
uint8_t lbprz;
|
||||
uint8_t has_write_same;
|
||||
struct scsi_inquiry_logical_block_provisioning lbp;
|
||||
struct scsi_inquiry_block_limits bl;
|
||||
unsigned char *zeroblock;
|
||||
} IscsiLun;
|
||||
|
||||
typedef struct IscsiTask {
|
||||
@@ -68,6 +65,7 @@ typedef struct IscsiTask {
|
||||
int do_retry;
|
||||
struct scsi_task *task;
|
||||
Coroutine *co;
|
||||
QEMUBH *bh;
|
||||
} IscsiTask;
|
||||
|
||||
typedef struct IscsiAIOCB {
|
||||
@@ -90,6 +88,7 @@ typedef struct IscsiAIOCB {
|
||||
#define NOP_INTERVAL 5000
|
||||
#define MAX_NOP_FAILURES 3
|
||||
#define ISCSI_CMD_RETRIES 5
|
||||
#define ISCSI_MAX_UNMAP 131072
|
||||
|
||||
static void
|
||||
iscsi_bh_cb(void *p)
|
||||
@@ -123,6 +122,13 @@ iscsi_schedule_bh(IscsiAIOCB *acb)
|
||||
qemu_bh_schedule(acb->bh);
|
||||
}
|
||||
|
||||
static void iscsi_co_generic_bh_cb(void *opaque)
|
||||
{
|
||||
struct IscsiTask *iTask = opaque;
|
||||
qemu_bh_delete(iTask->bh);
|
||||
qemu_coroutine_enter(iTask->co, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
|
||||
void *command_data, void *opaque)
|
||||
@@ -147,7 +153,8 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
|
||||
|
||||
out:
|
||||
if (iTask->co) {
|
||||
qemu_coroutine_enter(iTask->co, NULL);
|
||||
iTask->bh = qemu_bh_new(iscsi_co_generic_bh_cb, iTask);
|
||||
qemu_bh_schedule(iTask->bh);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -914,6 +921,8 @@ coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num,
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct IscsiTask iTask;
|
||||
struct unmap_list list;
|
||||
uint32_t nb_blocks;
|
||||
uint32_t max_unmap;
|
||||
|
||||
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||
return -EINVAL;
|
||||
@@ -925,115 +934,57 @@ coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
|
||||
list.lba = sector_qemu2lun(sector_num, iscsilun);
|
||||
list.num = sector_qemu2lun(nb_sectors, iscsilun);
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
retry:
|
||||
if (iscsi_unmap_task(iscsilun->iscsi, iscsilun->lun, 0, 0, &list, 1,
|
||||
iscsi_co_generic_cb, &iTask) == NULL) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
while (!iTask.complete) {
|
||||
iscsi_set_events(iscsilun);
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
iTask.task = NULL;
|
||||
}
|
||||
|
||||
if (iTask.do_retry) {
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (iTask.status == SCSI_STATUS_CHECK_CONDITION) {
|
||||
/* the target might fail with a check condition if it
|
||||
is not happy with the alignment of the UNMAP request
|
||||
we silently fail in this case */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(SCSI_SENSE_ASCQ_CAPACITY_DATA_HAS_CHANGED)
|
||||
|
||||
static int
|
||||
coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, BdrvRequestFlags flags)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct IscsiTask iTask;
|
||||
uint64_t lba;
|
||||
uint32_t nb_blocks;
|
||||
|
||||
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) {
|
||||
/* WRITE SAME without UNMAP is not supported by the target */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) {
|
||||
/* WRITE SAME with UNMAP is not supported by the target */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
lba = sector_qemu2lun(sector_num, iscsilun);
|
||||
nb_blocks = sector_qemu2lun(nb_sectors, iscsilun);
|
||||
|
||||
if (iscsilun->zeroblock == NULL) {
|
||||
iscsilun->zeroblock = g_malloc0(iscsilun->block_size);
|
||||
max_unmap = iscsilun->bl.max_unmap;
|
||||
if (max_unmap == 0xffffffff) {
|
||||
max_unmap = ISCSI_MAX_UNMAP;
|
||||
}
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
while (nb_blocks > 0) {
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
list.num = nb_blocks;
|
||||
if (list.num > max_unmap) {
|
||||
list.num = max_unmap;
|
||||
}
|
||||
retry:
|
||||
if (iscsi_writesame16_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
iscsilun->zeroblock, iscsilun->block_size,
|
||||
nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP),
|
||||
0, 0, iscsi_co_generic_cb, &iTask) == NULL) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
while (!iTask.complete) {
|
||||
iscsi_set_events(iscsilun);
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
iTask.task = NULL;
|
||||
}
|
||||
|
||||
if (iTask.do_retry) {
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
|
||||
iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
|
||||
iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
|
||||
/* WRITE SAME is not supported by the target */
|
||||
iscsilun->has_write_same = false;
|
||||
return -ENOTSUP;
|
||||
if (iscsi_unmap_task(iscsilun->iscsi, iscsilun->lun, 0, 0, &list, 1,
|
||||
iscsi_co_generic_cb, &iTask) == NULL) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
while (!iTask.complete) {
|
||||
iscsi_set_events(iscsilun);
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
iTask.task = NULL;
|
||||
}
|
||||
|
||||
if (iTask.do_retry) {
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (iTask.status == SCSI_STATUS_CHECK_CONDITION) {
|
||||
/* the target might fail with a check condition if it
|
||||
is not happy with the alignment of the UNMAP request
|
||||
we silently fail in this case */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
list.lba += list.num;
|
||||
nb_blocks -= list.num;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* SCSI_SENSE_ASCQ_CAPACITY_DATA_HAS_CHANGED */
|
||||
|
||||
static int parse_chap(struct iscsi_context *iscsi, const char *target)
|
||||
{
|
||||
QemuOptsList *list;
|
||||
@@ -1389,7 +1340,6 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
iscsilun->type = inq->periperal_device_type;
|
||||
iscsilun->has_write_same = true;
|
||||
|
||||
if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) {
|
||||
goto out;
|
||||
@@ -1443,23 +1393,6 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
sizeof(struct scsi_inquiry_block_limits));
|
||||
scsi_free_scsi_task(task);
|
||||
task = NULL;
|
||||
|
||||
if (iscsilun->bl.max_unmap < 0xffffffff) {
|
||||
bs->bl.max_discard = sector_lun2qemu(iscsilun->bl.max_unmap,
|
||||
iscsilun);
|
||||
}
|
||||
bs->bl.discard_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
||||
iscsilun);
|
||||
|
||||
if (iscsilun->bl.max_ws_len < 0xffffffff) {
|
||||
bs->bl.max_write_zeroes = sector_lun2qemu(iscsilun->bl.max_ws_len,
|
||||
iscsilun);
|
||||
}
|
||||
bs->bl.write_zeroes_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
||||
iscsilun);
|
||||
|
||||
bs->bl.opt_transfer_length = sector_lun2qemu(iscsilun->bl.opt_xfer_len,
|
||||
iscsilun);
|
||||
}
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
|
||||
@@ -1500,7 +1433,6 @@ static void iscsi_close(BlockDriverState *bs)
|
||||
}
|
||||
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL);
|
||||
iscsi_destroy_context(iscsi);
|
||||
g_free(iscsilun->zeroblock);
|
||||
memset(iscsilun, 0, sizeof(IscsiLun));
|
||||
}
|
||||
|
||||
@@ -1524,6 +1456,11 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iscsi_has_zero_init(BlockDriverState *bs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iscsi_create(const char *filename, QEMUOptionParameter *options,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -1578,21 +1515,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
bdi->unallocated_blocks_are_zero = !!iscsilun->lbprz;
|
||||
bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws;
|
||||
/* Guess the internal cluster (page) size of the iscsi target by the means
|
||||
* of opt_unmap_gran. Transfer the unmap granularity only if it has a
|
||||
* reasonable size for bdi->cluster_size */
|
||||
if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 64 * 1024 &&
|
||||
iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
|
||||
bdi->cluster_size = iscsilun->bl.opt_unmap_gran * iscsilun->block_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static QEMUOptionParameter iscsi_create_options[] = {
|
||||
{
|
||||
.name = BLOCK_OPT_SIZE,
|
||||
@@ -1614,21 +1536,19 @@ static BlockDriver bdrv_iscsi = {
|
||||
.create_options = iscsi_create_options,
|
||||
|
||||
.bdrv_getlength = iscsi_getlength,
|
||||
.bdrv_get_info = iscsi_get_info,
|
||||
.bdrv_truncate = iscsi_truncate,
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
.bdrv_co_get_block_status = iscsi_co_get_block_status,
|
||||
#endif
|
||||
.bdrv_co_discard = iscsi_co_discard,
|
||||
#if defined(SCSI_SENSE_ASCQ_CAPACITY_DATA_HAS_CHANGED)
|
||||
.bdrv_co_write_zeroes = iscsi_co_write_zeroes,
|
||||
#endif
|
||||
|
||||
.bdrv_aio_readv = iscsi_aio_readv,
|
||||
.bdrv_aio_writev = iscsi_aio_writev,
|
||||
.bdrv_aio_flush = iscsi_aio_flush,
|
||||
|
||||
.bdrv_has_zero_init = iscsi_has_zero_init,
|
||||
|
||||
#ifdef __linux__
|
||||
.bdrv_ioctl = iscsi_ioctl,
|
||||
.bdrv_aio_ioctl = iscsi_aio_ioctl,
|
||||
|
@@ -39,7 +39,6 @@ typedef struct MirrorBlockJob {
|
||||
int64_t granularity;
|
||||
size_t buf_size;
|
||||
unsigned long *cow_bitmap;
|
||||
BdrvDirtyBitmap *dirty_bitmap;
|
||||
HBitmapIter hbi;
|
||||
uint8_t *buf;
|
||||
QSIMPLEQ_HEAD(, MirrorBuffer) buf_free;
|
||||
@@ -146,10 +145,9 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
|
||||
s->sector_num = hbitmap_iter_next(&s->hbi);
|
||||
if (s->sector_num < 0) {
|
||||
bdrv_dirty_iter_init(source, s->dirty_bitmap, &s->hbi);
|
||||
bdrv_dirty_iter_init(source, &s->hbi);
|
||||
s->sector_num = hbitmap_iter_next(&s->hbi);
|
||||
trace_mirror_restart_iter(s,
|
||||
bdrv_get_dirty_count(source, s->dirty_bitmap));
|
||||
trace_mirror_restart_iter(s, bdrv_get_dirty_count(source));
|
||||
assert(s->sector_num >= 0);
|
||||
}
|
||||
|
||||
@@ -185,7 +183,7 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
do {
|
||||
int added_sectors, added_chunks;
|
||||
|
||||
if (!bdrv_get_dirty(source, s->dirty_bitmap, next_sector) ||
|
||||
if (!bdrv_get_dirty(source, next_sector) ||
|
||||
test_bit(next_chunk, s->in_flight_bitmap)) {
|
||||
assert(nb_sectors > 0);
|
||||
break;
|
||||
@@ -251,8 +249,7 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
/* Advance the HBitmapIter in parallel, so that we do not examine
|
||||
* the same sector twice.
|
||||
*/
|
||||
if (next_sector > hbitmap_next_sector
|
||||
&& bdrv_get_dirty(source, s->dirty_bitmap, next_sector)) {
|
||||
if (next_sector > hbitmap_next_sector && bdrv_get_dirty(source, next_sector)) {
|
||||
hbitmap_next_sector = hbitmap_iter_next(&s->hbi);
|
||||
}
|
||||
|
||||
@@ -358,7 +355,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
bdrv_dirty_iter_init(bs, s->dirty_bitmap, &s->hbi);
|
||||
bdrv_dirty_iter_init(bs, &s->hbi);
|
||||
last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||
for (;;) {
|
||||
uint64_t delay_ns;
|
||||
@@ -370,7 +367,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
goto immediate_exit;
|
||||
}
|
||||
|
||||
cnt = bdrv_get_dirty_count(bs, s->dirty_bitmap);
|
||||
cnt = bdrv_get_dirty_count(bs);
|
||||
|
||||
/* Note that even when no rate limit is applied we need to yield
|
||||
* periodically with no pending I/O so that qemu_aio_flush() returns.
|
||||
@@ -412,7 +409,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
|
||||
should_complete = s->should_complete ||
|
||||
block_job_is_cancelled(&s->common);
|
||||
cnt = bdrv_get_dirty_count(bs, s->dirty_bitmap);
|
||||
cnt = bdrv_get_dirty_count(bs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,7 +424,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
*/
|
||||
trace_mirror_before_drain(s, cnt);
|
||||
bdrv_drain_all();
|
||||
cnt = bdrv_get_dirty_count(bs, s->dirty_bitmap);
|
||||
cnt = bdrv_get_dirty_count(bs);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
@@ -474,7 +471,7 @@ immediate_exit:
|
||||
qemu_vfree(s->buf);
|
||||
g_free(s->cow_bitmap);
|
||||
g_free(s->in_flight_bitmap);
|
||||
bdrv_release_dirty_bitmap(bs, s->dirty_bitmap);
|
||||
bdrv_set_dirty_tracking(bs, 0);
|
||||
bdrv_iostatus_disable(s->target);
|
||||
if (s->should_complete && ret == 0) {
|
||||
if (bdrv_get_flags(s->target) != bdrv_get_flags(s->common.bs)) {
|
||||
@@ -578,7 +575,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
s->granularity = granularity;
|
||||
s->buf_size = MAX(buf_size, granularity);
|
||||
|
||||
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity);
|
||||
bdrv_set_dirty_tracking(bs, granularity);
|
||||
bdrv_set_enable_write_cache(s->target, true);
|
||||
bdrv_set_on_error(s->target, on_target_error, on_target_error);
|
||||
bdrv_iostatus_enable(s->target);
|
||||
|
@@ -204,9 +204,12 @@ void bdrv_query_info(BlockDriverState *bs,
|
||||
info->io_status = bs->iostatus;
|
||||
}
|
||||
|
||||
if (!QLIST_EMPTY(&bs->dirty_bitmaps)) {
|
||||
info->has_dirty_bitmaps = true;
|
||||
info->dirty_bitmaps = bdrv_query_dirty_bitmaps(bs);
|
||||
if (bs->dirty_bitmap) {
|
||||
info->has_dirty = true;
|
||||
info->dirty = g_malloc0(sizeof(*info->dirty));
|
||||
info->dirty->count = bdrv_get_dirty_count(bs) * BDRV_SECTOR_SIZE;
|
||||
info->dirty->granularity =
|
||||
((int64_t) BDRV_SECTOR_SIZE << hbitmap_granularity(bs->dirty_bitmap));
|
||||
}
|
||||
|
||||
if (bs->drv) {
|
||||
|
@@ -1401,7 +1401,7 @@ int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
|
||||
|
||||
/* Round start up and end down */
|
||||
offset = align_offset(offset, s->cluster_size);
|
||||
end_offset = start_of_cluster(s, end_offset);
|
||||
end_offset &= ~(s->cluster_size - 1);
|
||||
|
||||
if (offset > end_offset) {
|
||||
return 0;
|
||||
@@ -1613,7 +1613,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
|
||||
}
|
||||
|
||||
ret = bdrv_write_zeroes(bs->file, offset / BDRV_SECTOR_SIZE,
|
||||
s->cluster_sectors, 0);
|
||||
s->cluster_sectors);
|
||||
if (ret < 0) {
|
||||
if (!preallocated) {
|
||||
qcow2_free_clusters(bs, offset, s->cluster_size,
|
||||
|
@@ -515,8 +515,8 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||
s->l2_table_cache);
|
||||
}
|
||||
|
||||
start = start_of_cluster(s, offset);
|
||||
last = start_of_cluster(s, offset + length - 1);
|
||||
start = offset & ~(s->cluster_size - 1);
|
||||
last = (offset + length - 1) & ~(s->cluster_size - 1);
|
||||
for(cluster_offset = start; cluster_offset <= last;
|
||||
cluster_offset += s->cluster_size)
|
||||
{
|
||||
@@ -724,7 +724,7 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
|
||||
}
|
||||
redo:
|
||||
free_in_cluster = s->cluster_size -
|
||||
offset_into_cluster(s, s->free_byte_offset);
|
||||
(s->free_byte_offset & (s->cluster_size - 1));
|
||||
if (size <= free_in_cluster) {
|
||||
/* enough space in current cluster */
|
||||
offset = s->free_byte_offset;
|
||||
@@ -732,7 +732,7 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
|
||||
free_in_cluster -= size;
|
||||
if (free_in_cluster == 0)
|
||||
s->free_byte_offset = 0;
|
||||
if (offset_into_cluster(s, offset) != 0)
|
||||
if ((offset & (s->cluster_size - 1)) != 0)
|
||||
qcow2_update_cluster_refcount(bs, offset >> s->cluster_bits, 1,
|
||||
QCOW2_DISCARD_NEVER);
|
||||
} else {
|
||||
@@ -740,7 +740,7 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
|
||||
if (offset < 0) {
|
||||
return offset;
|
||||
}
|
||||
cluster_offset = start_of_cluster(s, s->free_byte_offset);
|
||||
cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1);
|
||||
if ((cluster_offset + s->cluster_size) == offset) {
|
||||
/* we are lucky: contiguous data */
|
||||
offset = s->free_byte_offset;
|
||||
@@ -1010,8 +1010,8 @@ static void inc_refcounts(BlockDriverState *bs,
|
||||
if (size <= 0)
|
||||
return;
|
||||
|
||||
start = start_of_cluster(s, offset);
|
||||
last = start_of_cluster(s, offset + size - 1);
|
||||
start = offset & ~(s->cluster_size - 1);
|
||||
last = (offset + size - 1) & ~(s->cluster_size - 1);
|
||||
for(cluster_offset = start; cluster_offset <= last;
|
||||
cluster_offset += s->cluster_size) {
|
||||
k = cluster_offset >> s->cluster_bits;
|
||||
@@ -1122,7 +1122,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
offset, s->cluster_size);
|
||||
|
||||
/* Correct offsets are cluster aligned */
|
||||
if (offset_into_cluster(s, offset)) {
|
||||
if (offset & (s->cluster_size - 1)) {
|
||||
fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
|
||||
"properly aligned; L2 entry corrupted.\n", offset);
|
||||
res->corruptions++;
|
||||
@@ -1194,7 +1194,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
||||
l2_offset, s->cluster_size);
|
||||
|
||||
/* L2 tables are cluster aligned */
|
||||
if (offset_into_cluster(s, l2_offset)) {
|
||||
if (l2_offset & (s->cluster_size - 1)) {
|
||||
fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not "
|
||||
"cluster aligned; L1 entry corrupted\n", l2_offset);
|
||||
res->corruptions++;
|
||||
@@ -1423,7 +1423,7 @@ static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
|
||||
}
|
||||
|
||||
/* update refcount table */
|
||||
assert(!offset_into_cluster(s, new_offset));
|
||||
assert(!(new_offset & (s->cluster_size - 1)));
|
||||
s->refcount_table[reftable_index] = new_offset;
|
||||
ret = write_reftable_entry(bs, reftable_index);
|
||||
if (ret < 0) {
|
||||
@@ -1507,7 +1507,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
cluster = offset >> s->cluster_bits;
|
||||
|
||||
/* Refcount blocks are cluster aligned */
|
||||
if (offset_into_cluster(s, offset)) {
|
||||
if (offset & (s->cluster_size - 1)) {
|
||||
fprintf(stderr, "ERROR refcount block %" PRId64 " is not "
|
||||
"cluster aligned; refcount table entry corrupted\n", i);
|
||||
res->corruptions++;
|
||||
|
@@ -675,10 +675,7 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||
return s->nb_snapshots;
|
||||
}
|
||||
|
||||
int qcow2_snapshot_load_tmp(BlockDriverState *bs,
|
||||
const char *snapshot_id,
|
||||
const char *name,
|
||||
Error **errp)
|
||||
int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name)
|
||||
{
|
||||
int i, snapshot_index;
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
@@ -690,10 +687,8 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
|
||||
assert(bs->read_only);
|
||||
|
||||
/* Search the snapshot */
|
||||
snapshot_index = find_snapshot_by_id_and_name(bs, snapshot_id, name);
|
||||
snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_name);
|
||||
if (snapshot_index < 0) {
|
||||
error_setg(errp,
|
||||
"Can't find snapshot");
|
||||
return -ENOENT;
|
||||
}
|
||||
sn = &s->snapshots[snapshot_index];
|
||||
@@ -704,7 +699,6 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
|
||||
|
||||
ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Failed to read l1 table for snapshot");
|
||||
g_free(new_l1_table);
|
||||
return ret;
|
||||
}
|
||||
|
@@ -718,7 +718,6 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
qemu_opts_del(opts);
|
||||
bs->bl.write_zeroes_alignment = s->cluster_sectors;
|
||||
|
||||
if (s->use_lazy_refcounts && s->qcow_version < 3) {
|
||||
error_setg(errp, "Lazy refcounts require a qcow2 image with at least "
|
||||
@@ -1472,7 +1471,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
* size for any qcow2 image.
|
||||
*/
|
||||
BlockDriverState* bs;
|
||||
QCowHeader *header;
|
||||
QCowHeader header;
|
||||
uint8_t* refcount_table;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
@@ -1490,34 +1489,30 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
}
|
||||
|
||||
/* Write the header */
|
||||
QEMU_BUILD_BUG_ON((1 << MIN_CLUSTER_BITS) < sizeof(*header));
|
||||
header = g_malloc0(cluster_size);
|
||||
*header = (QCowHeader) {
|
||||
.magic = cpu_to_be32(QCOW_MAGIC),
|
||||
.version = cpu_to_be32(version),
|
||||
.cluster_bits = cpu_to_be32(cluster_bits),
|
||||
.size = cpu_to_be64(0),
|
||||
.l1_table_offset = cpu_to_be64(0),
|
||||
.l1_size = cpu_to_be32(0),
|
||||
.refcount_table_offset = cpu_to_be64(cluster_size),
|
||||
.refcount_table_clusters = cpu_to_be32(1),
|
||||
.refcount_order = cpu_to_be32(3 + REFCOUNT_SHIFT),
|
||||
.header_length = cpu_to_be32(sizeof(*header)),
|
||||
};
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.magic = cpu_to_be32(QCOW_MAGIC);
|
||||
header.version = cpu_to_be32(version);
|
||||
header.cluster_bits = cpu_to_be32(cluster_bits);
|
||||
header.size = cpu_to_be64(0);
|
||||
header.l1_table_offset = cpu_to_be64(0);
|
||||
header.l1_size = cpu_to_be32(0);
|
||||
header.refcount_table_offset = cpu_to_be64(cluster_size);
|
||||
header.refcount_table_clusters = cpu_to_be32(1);
|
||||
header.refcount_order = cpu_to_be32(3 + REFCOUNT_SHIFT);
|
||||
header.header_length = cpu_to_be32(sizeof(header));
|
||||
|
||||
if (flags & BLOCK_FLAG_ENCRYPT) {
|
||||
header->crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
|
||||
header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
|
||||
} else {
|
||||
header->crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
|
||||
header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
|
||||
}
|
||||
|
||||
if (flags & BLOCK_FLAG_LAZY_REFCOUNTS) {
|
||||
header->compatible_features |=
|
||||
header.compatible_features |=
|
||||
cpu_to_be64(QCOW2_COMPAT_LAZY_REFCOUNTS);
|
||||
}
|
||||
|
||||
ret = bdrv_pwrite(bs, 0, header, cluster_size);
|
||||
g_free(header);
|
||||
ret = bdrv_pwrite(bs, 0, &header, sizeof(header));
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not write qcow2 header");
|
||||
goto out;
|
||||
@@ -1593,8 +1588,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
|
||||
/* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning */
|
||||
ret = bdrv_open(bs, filename, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_BACKING,
|
||||
drv, &local_err);
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB, drv, &local_err);
|
||||
if (error_is_set(&local_err)) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
@@ -1702,7 +1696,7 @@ static int qcow2_make_empty(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
static coroutine_fn int qcow2_co_write_zeroes(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
|
||||
int64_t sector_num, int nb_sectors)
|
||||
{
|
||||
int ret;
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
@@ -1898,8 +1892,6 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
|
||||
static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
bdi->unallocated_blocks_are_zero = true;
|
||||
bdi->can_write_zeroes_with_unmap = (s->qcow_version >= 3);
|
||||
bdi->cluster_size = s->cluster_size;
|
||||
bdi->vm_state_offset = qcow2_vm_state_offset(s);
|
||||
return 0;
|
||||
|
@@ -488,10 +488,7 @@ int qcow2_snapshot_delete(BlockDriverState *bs,
|
||||
const char *name,
|
||||
Error **errp);
|
||||
int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
|
||||
int qcow2_snapshot_load_tmp(BlockDriverState *bs,
|
||||
const char *snapshot_id,
|
||||
const char *name,
|
||||
Error **errp);
|
||||
int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name);
|
||||
|
||||
void qcow2_free_snapshots(BlockDriverState *bs);
|
||||
int qcow2_read_snapshots(BlockDriverState *bs);
|
||||
|
@@ -495,7 +495,6 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
}
|
||||
|
||||
bs->bl.write_zeroes_alignment = s->header.cluster_size >> BDRV_SECTOR_BITS;
|
||||
s->need_check_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
qed_need_check_timer_cb, s);
|
||||
|
||||
@@ -1398,8 +1397,7 @@ static void coroutine_fn qed_co_write_zeroes_cb(void *opaque, int ret)
|
||||
|
||||
static int coroutine_fn bdrv_qed_co_write_zeroes(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors,
|
||||
BdrvRequestFlags flags)
|
||||
int nb_sectors)
|
||||
{
|
||||
BlockDriverAIOCB *blockacb;
|
||||
BDRVQEDState *s = bs->opaque;
|
||||
@@ -1476,8 +1474,6 @@ static int bdrv_qed_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
memset(bdi, 0, sizeof(*bdi));
|
||||
bdi->cluster_size = s->header.cluster_size;
|
||||
bdi->is_dirty = s->header.features & QED_F_NEED_CHECK;
|
||||
bdi->unallocated_blocks_are_zero = true;
|
||||
bdi->can_write_zeroes_with_unmap = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -21,10 +21,9 @@
|
||||
#define QEMU_AIO_IOCTL 0x0004
|
||||
#define QEMU_AIO_FLUSH 0x0008
|
||||
#define QEMU_AIO_DISCARD 0x0010
|
||||
#define QEMU_AIO_WRITE_ZEROES 0x0020
|
||||
#define QEMU_AIO_TYPE_MASK \
|
||||
(QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH| \
|
||||
QEMU_AIO_DISCARD|QEMU_AIO_WRITE_ZEROES)
|
||||
QEMU_AIO_DISCARD)
|
||||
|
||||
/* AIO flags */
|
||||
#define QEMU_AIO_MISALIGNED 0x1000
|
||||
|
@@ -139,11 +139,9 @@ typedef struct BDRVRawState {
|
||||
void *aio_ctx;
|
||||
#endif
|
||||
#ifdef CONFIG_XFS
|
||||
bool is_xfs:1;
|
||||
bool is_xfs : 1;
|
||||
#endif
|
||||
bool has_discard:1;
|
||||
bool has_write_zeroes:1;
|
||||
bool discard_zeroes:1;
|
||||
bool has_discard : 1;
|
||||
} BDRVRawState;
|
||||
|
||||
typedef struct BDRVRawReopenState {
|
||||
@@ -285,7 +283,6 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
Error *local_err = NULL;
|
||||
const char *filename;
|
||||
int fd, ret;
|
||||
struct stat st;
|
||||
|
||||
opts = qemu_opts_create_nofail(&raw_runtime_opts);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
@@ -326,38 +323,10 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
}
|
||||
#endif
|
||||
|
||||
s->has_discard = true;
|
||||
s->has_write_zeroes = true;
|
||||
|
||||
if (fstat(s->fd, &st) < 0) {
|
||||
error_setg_errno(errp, errno, "Could not stat file");
|
||||
goto fail;
|
||||
}
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
s->discard_zeroes = true;
|
||||
}
|
||||
if (S_ISBLK(st.st_mode)) {
|
||||
#ifdef BLKDISCARDZEROES
|
||||
unsigned int arg;
|
||||
if (ioctl(s->fd, BLKDISCARDZEROES, &arg) == 0 && arg) {
|
||||
s->discard_zeroes = true;
|
||||
}
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
/* On Linux 3.10, BLKDISCARD leaves stale data in the page cache. Do
|
||||
* not rely on the contents of discarded blocks unless using O_DIRECT.
|
||||
* Same for BLKZEROOUT.
|
||||
*/
|
||||
if (!(bs->open_flags & BDRV_O_NOCACHE)) {
|
||||
s->discard_zeroes = false;
|
||||
s->has_write_zeroes = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
s->has_discard = 1;
|
||||
#ifdef CONFIG_XFS
|
||||
if (platform_test_xfs_fd(s->fd)) {
|
||||
s->is_xfs = true;
|
||||
s->is_xfs = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -706,23 +675,6 @@ static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XFS
|
||||
static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes)
|
||||
{
|
||||
struct xfs_flock64 fl;
|
||||
|
||||
memset(&fl, 0, sizeof(fl));
|
||||
fl.l_whence = SEEK_SET;
|
||||
fl.l_start = offset;
|
||||
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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes)
|
||||
{
|
||||
struct xfs_flock64 fl;
|
||||
@@ -741,49 +693,13 @@ static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes)
|
||||
}
|
||||
#endif
|
||||
|
||||
static ssize_t handle_aiocb_write_zeroes(RawPosixAIOData *aiocb)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
BDRVRawState *s = aiocb->bs->opaque;
|
||||
|
||||
if (s->has_write_zeroes == 0) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (aiocb->aio_type & QEMU_AIO_BLKDEV) {
|
||||
#ifdef BLKZEROOUT
|
||||
do {
|
||||
uint64_t range[2] = { aiocb->aio_offset, aiocb->aio_nbytes };
|
||||
if (ioctl(aiocb->aio_fildes, BLKZEROOUT, range) == 0) {
|
||||
return 0;
|
||||
}
|
||||
} while (errno == EINTR);
|
||||
|
||||
ret = -errno;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef CONFIG_XFS
|
||||
if (s->is_xfs) {
|
||||
return xfs_write_zeroes(s, aiocb->aio_offset, aiocb->aio_nbytes);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ret == -ENODEV || ret == -ENOSYS || ret == -EOPNOTSUPP ||
|
||||
ret == -ENOTTY) {
|
||||
s->has_write_zeroes = false;
|
||||
ret = -ENOTSUP;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
BDRVRawState *s = aiocb->bs->opaque;
|
||||
|
||||
if (!s->has_discard) {
|
||||
return -ENOTSUP;
|
||||
if (s->has_discard == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (aiocb->aio_type & QEMU_AIO_BLKDEV) {
|
||||
@@ -818,8 +734,8 @@ static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb)
|
||||
|
||||
if (ret == -ENODEV || ret == -ENOSYS || ret == -EOPNOTSUPP ||
|
||||
ret == -ENOTTY) {
|
||||
s->has_discard = false;
|
||||
ret = -ENOTSUP;
|
||||
s->has_discard = 0;
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -861,9 +777,6 @@ static int aio_worker(void *arg)
|
||||
case QEMU_AIO_DISCARD:
|
||||
ret = handle_aiocb_discard(aiocb);
|
||||
break;
|
||||
case QEMU_AIO_WRITE_ZEROES:
|
||||
ret = handle_aiocb_write_zeroes(aiocb);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
|
||||
ret = -EINVAL;
|
||||
@@ -874,29 +787,6 @@ static int aio_worker(void *arg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int paio_submit_co(BlockDriverState *bs, int fd,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
int type)
|
||||
{
|
||||
RawPosixAIOData *acb = g_slice_new(RawPosixAIOData);
|
||||
ThreadPool *pool;
|
||||
|
||||
acb->bs = bs;
|
||||
acb->aio_type = type;
|
||||
acb->aio_fildes = fd;
|
||||
|
||||
if (qiov) {
|
||||
acb->aio_iov = qiov->iov;
|
||||
acb->aio_niov = qiov->niov;
|
||||
}
|
||||
acb->aio_nbytes = nb_sectors * 512;
|
||||
acb->aio_offset = sector_num * 512;
|
||||
|
||||
trace_paio_submit_co(sector_num, nb_sectors, type);
|
||||
pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
|
||||
return thread_pool_submit_co(pool, aio_worker, acb);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type)
|
||||
@@ -1309,31 +1199,6 @@ static coroutine_fn BlockDriverAIOCB *raw_aio_discard(BlockDriverState *bs,
|
||||
cb, opaque, QEMU_AIO_DISCARD);
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_write_zeroes(
|
||||
BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, BdrvRequestFlags flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
if (!(flags & BDRV_REQ_MAY_UNMAP)) {
|
||||
return paio_submit_co(bs, s->fd, sector_num, NULL, nb_sectors,
|
||||
QEMU_AIO_WRITE_ZEROES);
|
||||
} else if (s->discard_zeroes) {
|
||||
return paio_submit_co(bs, s->fd, sector_num, NULL, nb_sectors,
|
||||
QEMU_AIO_DISCARD);
|
||||
}
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
bdi->unallocated_blocks_are_zero = s->discard_zeroes;
|
||||
bdi->can_write_zeroes_with_unmap = s->discard_zeroes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static QEMUOptionParameter raw_create_options[] = {
|
||||
{
|
||||
.name = BLOCK_OPT_SIZE,
|
||||
@@ -1357,7 +1222,6 @@ static BlockDriver bdrv_file = {
|
||||
.bdrv_create = raw_create,
|
||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||
.bdrv_co_get_block_status = raw_co_get_block_status,
|
||||
.bdrv_co_write_zeroes = raw_co_write_zeroes,
|
||||
|
||||
.bdrv_aio_readv = raw_aio_readv,
|
||||
.bdrv_aio_writev = raw_aio_writev,
|
||||
@@ -1366,7 +1230,6 @@ static BlockDriver bdrv_file = {
|
||||
|
||||
.bdrv_truncate = raw_truncate,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
.bdrv_get_info = raw_get_info,
|
||||
.bdrv_get_allocated_file_size
|
||||
= raw_get_allocated_file_size,
|
||||
|
||||
@@ -1662,26 +1525,6 @@ static coroutine_fn BlockDriverAIOCB *hdev_aio_discard(BlockDriverState *bs,
|
||||
cb, opaque, QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV);
|
||||
}
|
||||
|
||||
static coroutine_fn int hdev_co_write_zeroes(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int rc;
|
||||
|
||||
rc = fd_open(bs);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
if (!(flags & BDRV_REQ_MAY_UNMAP)) {
|
||||
return paio_submit_co(bs, s->fd, sector_num, NULL, nb_sectors,
|
||||
QEMU_AIO_WRITE_ZEROES|QEMU_AIO_BLKDEV);
|
||||
} else if (s->discard_zeroes) {
|
||||
return paio_submit_co(bs, s->fd, sector_num, NULL, nb_sectors,
|
||||
QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV);
|
||||
}
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int hdev_create(const char *filename, QEMUOptionParameter *options,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -1734,7 +1577,6 @@ static BlockDriver bdrv_host_device = {
|
||||
.bdrv_reopen_abort = raw_reopen_abort,
|
||||
.bdrv_create = hdev_create,
|
||||
.create_options = raw_create_options,
|
||||
.bdrv_co_write_zeroes = hdev_co_write_zeroes,
|
||||
|
||||
.bdrv_aio_readv = raw_aio_readv,
|
||||
.bdrv_aio_writev = raw_aio_writev,
|
||||
@@ -1743,7 +1585,6 @@ static BlockDriver bdrv_host_device = {
|
||||
|
||||
.bdrv_truncate = raw_truncate,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
.bdrv_get_info = raw_get_info,
|
||||
.bdrv_get_allocated_file_size
|
||||
= raw_get_allocated_file_size,
|
||||
|
||||
|
@@ -68,10 +68,9 @@ static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_write_zeroes(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
BdrvRequestFlags flags)
|
||||
int64_t sector_num, int nb_sectors)
|
||||
{
|
||||
return bdrv_co_write_zeroes(bs->file, sector_num, nb_sectors, flags);
|
||||
return bdrv_co_write_zeroes(bs->file, sector_num, nb_sectors);
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_discard(BlockDriverState *bs,
|
||||
@@ -150,7 +149,6 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
bs->sg = bs->file->sg;
|
||||
bs->bl = bs->file->bl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
130
block/sheepdog.c
130
block/sheepdog.c
@@ -91,14 +91,6 @@
|
||||
#define SD_NR_VDIS (1U << 24)
|
||||
#define SD_DATA_OBJ_SIZE (UINT64_C(1) << 22)
|
||||
#define SD_MAX_VDI_SIZE (SD_DATA_OBJ_SIZE * MAX_DATA_OBJS)
|
||||
/*
|
||||
* For erasure coding, we use at most SD_EC_MAX_STRIP for data strips and
|
||||
* (SD_EC_MAX_STRIP - 1) for parity strips
|
||||
*
|
||||
* SD_MAX_COPIES is sum of number of data strips and parity strips.
|
||||
*/
|
||||
#define SD_EC_MAX_STRIP 16
|
||||
#define SD_MAX_COPIES (SD_EC_MAX_STRIP * 2 - 1)
|
||||
|
||||
#define SD_INODE_SIZE (sizeof(SheepdogInode))
|
||||
#define CURRENT_VDI_ID 0
|
||||
@@ -1472,7 +1464,9 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot)
|
||||
static int do_sd_create(BDRVSheepdogState *s, char *filename, int64_t vdi_size,
|
||||
uint32_t base_vid, uint32_t *vdi_id, int snapshot,
|
||||
uint8_t copy_policy)
|
||||
{
|
||||
SheepdogVdiReq hdr;
|
||||
SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
|
||||
@@ -1489,11 +1483,11 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot)
|
||||
* does not fit in buf? For now, just truncate and avoid buffer overrun.
|
||||
*/
|
||||
memset(buf, 0, sizeof(buf));
|
||||
pstrcpy(buf, sizeof(buf), s->name);
|
||||
pstrcpy(buf, sizeof(buf), filename);
|
||||
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
hdr.opcode = SD_OP_NEW_VDI;
|
||||
hdr.vdi_id = s->inode.vdi_id;
|
||||
hdr.vdi_id = base_vid;
|
||||
|
||||
wlen = SD_MAX_VDI_LEN;
|
||||
|
||||
@@ -1501,9 +1495,8 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot)
|
||||
hdr.snapid = snapshot;
|
||||
|
||||
hdr.data_length = wlen;
|
||||
hdr.vdi_size = s->inode.vdi_size;
|
||||
hdr.copy_policy = s->inode.copy_policy;
|
||||
hdr.copies = s->inode.nr_copies;
|
||||
hdr.vdi_size = vdi_size;
|
||||
hdr.copy_policy = copy_policy;
|
||||
|
||||
ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
|
||||
|
||||
@@ -1514,7 +1507,7 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot)
|
||||
}
|
||||
|
||||
if (rsp->result != SD_RES_SUCCESS) {
|
||||
error_report("%s, %s", sd_strerror(rsp->result), s->inode.name);
|
||||
error_report("%s, %s", sd_strerror(rsp->result), filename);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -1571,79 +1564,27 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sheepdog support two kinds of redundancy, full replication and erasure
|
||||
* coding.
|
||||
*
|
||||
* # create a fully replicated vdi with x copies
|
||||
* -o redundancy=x (1 <= x <= SD_MAX_COPIES)
|
||||
*
|
||||
* # create a erasure coded vdi with x data strips and y parity strips
|
||||
* -o redundancy=x:y (x must be one of {2,4,8,16} and 1 <= y < SD_EC_MAX_STRIP)
|
||||
*/
|
||||
static int parse_redundancy(BDRVSheepdogState *s, const char *opt)
|
||||
{
|
||||
struct SheepdogInode *inode = &s->inode;
|
||||
const char *n1, *n2;
|
||||
long copy, parity;
|
||||
char p[10];
|
||||
|
||||
pstrcpy(p, sizeof(p), opt);
|
||||
n1 = strtok(p, ":");
|
||||
n2 = strtok(NULL, ":");
|
||||
|
||||
if (!n1) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
copy = strtol(n1, NULL, 10);
|
||||
if (copy > SD_MAX_COPIES || copy < 1) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!n2) {
|
||||
inode->copy_policy = 0;
|
||||
inode->nr_copies = copy;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (copy != 2 && copy != 4 && copy != 8 && copy != 16) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
parity = strtol(n2, NULL, 10);
|
||||
if (parity >= SD_EC_MAX_STRIP || parity < 1) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 4 bits for parity and 4 bits for data.
|
||||
* We have to compress upper data bits because it can't represent 16
|
||||
*/
|
||||
inode->copy_policy = ((copy / 2) << 4) + parity;
|
||||
inode->nr_copies = copy + parity;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
Error **errp)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t vid = 0;
|
||||
uint32_t vid = 0, base_vid = 0;
|
||||
int64_t vdi_size = 0;
|
||||
char *backing_file = NULL;
|
||||
BDRVSheepdogState *s;
|
||||
char tag[SD_MAX_VDI_TAG_LEN];
|
||||
char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
|
||||
uint32_t snapid;
|
||||
bool prealloc = false;
|
||||
Error *local_err = NULL;
|
||||
|
||||
s = g_malloc0(sizeof(BDRVSheepdogState));
|
||||
|
||||
memset(vdi, 0, sizeof(vdi));
|
||||
memset(tag, 0, sizeof(tag));
|
||||
if (strstr(filename, "://")) {
|
||||
ret = sd_parse_uri(s, filename, s->name, &snapid, tag);
|
||||
ret = sd_parse_uri(s, filename, vdi, &snapid, tag);
|
||||
} else {
|
||||
ret = parse_vdiname(s, filename, s->name, &snapid, tag);
|
||||
ret = parse_vdiname(s, filename, vdi, &snapid, tag);
|
||||
}
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
@@ -1651,7 +1592,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
|
||||
while (options && options->name) {
|
||||
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
|
||||
s->inode.vdi_size = options->value.n;
|
||||
vdi_size = options->value.n;
|
||||
} else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
|
||||
backing_file = options->value.s;
|
||||
} else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
|
||||
@@ -1665,16 +1606,11 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
} else if (!strcmp(options->name, BLOCK_OPT_REDUNDANCY)) {
|
||||
ret = parse_redundancy(s, options->value.s);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
options++;
|
||||
}
|
||||
|
||||
if (s->inode.vdi_size > SD_MAX_VDI_SIZE) {
|
||||
if (vdi_size > SD_MAX_VDI_SIZE) {
|
||||
error_report("too big image size");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
@@ -1709,10 +1645,12 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
|
||||
goto out;
|
||||
}
|
||||
|
||||
base_vid = s->inode.vdi_id;
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
|
||||
ret = do_sd_create(s, &vid, 0);
|
||||
/* TODO: allow users to specify copy number */
|
||||
ret = do_sd_create(s, vdi, vdi_size, base_vid, &vid, 0, 0);
|
||||
if (!prealloc || ret) {
|
||||
goto out;
|
||||
}
|
||||
@@ -1895,7 +1833,8 @@ static int sd_create_branch(BDRVSheepdogState *s)
|
||||
* false bail out.
|
||||
*/
|
||||
deleted = sd_delete(s);
|
||||
ret = do_sd_create(s, &vid, !deleted);
|
||||
ret = do_sd_create(s, s->name, s->inode.vdi_size, s->inode.vdi_id, &vid,
|
||||
!deleted, s->inode.copy_policy);
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
@@ -2158,7 +2097,8 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = do_sd_create(s, &new_vid, 1);
|
||||
ret = do_sd_create(s, s->name, s->inode.vdi_size, s->inode.vdi_id, &new_vid,
|
||||
1, s->inode.copy_policy);
|
||||
if (ret < 0) {
|
||||
error_report("failed to create inode for snapshot. %s",
|
||||
strerror(errno));
|
||||
@@ -2467,22 +2407,6 @@ sd_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int64_t sd_get_allocated_file_size(BlockDriverState *bs)
|
||||
{
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
SheepdogInode *inode = &s->inode;
|
||||
unsigned long i, last = DIV_ROUND_UP(inode->vdi_size, SD_DATA_OBJ_SIZE);
|
||||
uint64_t size = 0;
|
||||
|
||||
for (i = 0; i < last; i++) {
|
||||
if (inode->data_vdi_id[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
size += SD_DATA_OBJ_SIZE;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static QEMUOptionParameter sd_create_options[] = {
|
||||
{
|
||||
.name = BLOCK_OPT_SIZE,
|
||||
@@ -2499,11 +2423,6 @@ static QEMUOptionParameter sd_create_options[] = {
|
||||
.type = OPT_STRING,
|
||||
.help = "Preallocation mode (allowed values: off, full)"
|
||||
},
|
||||
{
|
||||
.name = BLOCK_OPT_REDUNDANCY,
|
||||
.type = OPT_STRING,
|
||||
.help = "Redundancy of the image"
|
||||
},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@@ -2517,7 +2436,6 @@ static BlockDriver bdrv_sheepdog = {
|
||||
.bdrv_create = sd_create,
|
||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||
.bdrv_getlength = sd_getlength,
|
||||
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
|
||||
.bdrv_truncate = sd_truncate,
|
||||
|
||||
.bdrv_co_readv = sd_co_readv,
|
||||
@@ -2547,7 +2465,6 @@ static BlockDriver bdrv_sheepdog_tcp = {
|
||||
.bdrv_create = sd_create,
|
||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||
.bdrv_getlength = sd_getlength,
|
||||
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
|
||||
.bdrv_truncate = sd_truncate,
|
||||
|
||||
.bdrv_co_readv = sd_co_readv,
|
||||
@@ -2577,7 +2494,6 @@ static BlockDriver bdrv_sheepdog_unix = {
|
||||
.bdrv_create = sd_create,
|
||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||
.bdrv_getlength = sd_getlength,
|
||||
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
|
||||
.bdrv_truncate = sd_truncate,
|
||||
|
||||
.bdrv_co_readv = sd_co_readv,
|
||||
|
@@ -25,24 +25,6 @@
|
||||
#include "block/snapshot.h"
|
||||
#include "block/block_int.h"
|
||||
|
||||
QemuOptsList internal_snapshot_opts = {
|
||||
.name = "snapshot",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(internal_snapshot_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = SNAPSHOT_OPT_ID,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "snapshot id"
|
||||
},{
|
||||
.name = SNAPSHOT_OPT_NAME,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "snapshot name"
|
||||
},{
|
||||
/* end of list */
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
|
||||
const char *name)
|
||||
{
|
||||
@@ -212,7 +194,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
|
||||
* If only @snapshot_id is specified, delete the first one with id
|
||||
* @snapshot_id.
|
||||
* If only @name is specified, delete the first one with name @name.
|
||||
* if none is specified, return -EINVAL.
|
||||
* if none is specified, return -ENINVAL.
|
||||
*
|
||||
* Returns: 0 on success, -errno on failure. If @bs is not inserted, return
|
||||
* -ENOMEDIUM. If @snapshot_id and @name are both NULL, return -EINVAL. If @bs
|
||||
@@ -283,71 +265,18 @@ int bdrv_snapshot_list(BlockDriverState *bs,
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporarily load an internal snapshot by @snapshot_id and @name.
|
||||
* @bs: block device used in the operation
|
||||
* @snapshot_id: unique snapshot ID, or NULL
|
||||
* @name: snapshot name, or NULL
|
||||
* @errp: location to store error
|
||||
*
|
||||
* If both @snapshot_id and @name are specified, load the first one with
|
||||
* id @snapshot_id and name @name.
|
||||
* If only @snapshot_id is specified, load the first one with id
|
||||
* @snapshot_id.
|
||||
* If only @name is specified, load the first one with name @name.
|
||||
* if none is specified, return -EINVAL.
|
||||
*
|
||||
* Returns: 0 on success, -errno on fail. If @bs is not inserted, return
|
||||
* -ENOMEDIUM. If @bs is not readonly, return -EINVAL. If @bs did not support
|
||||
* internal snapshot, return -ENOTSUP. If qemu can't find a matching @id and
|
||||
* @name, return -ENOENT. If @errp != NULL, it will always be filled on
|
||||
* failure.
|
||||
*/
|
||||
int bdrv_snapshot_load_tmp(BlockDriverState *bs,
|
||||
const char *snapshot_id,
|
||||
const char *name,
|
||||
Error **errp)
|
||||
const char *snapshot_name)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
|
||||
if (!drv) {
|
||||
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs));
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
if (!snapshot_id && !name) {
|
||||
error_setg(errp, "snapshot_id and name are both NULL");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!bs->read_only) {
|
||||
error_setg(errp, "Device is not readonly");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (drv->bdrv_snapshot_load_tmp) {
|
||||
return drv->bdrv_snapshot_load_tmp(bs, snapshot_id, name, errp);
|
||||
return drv->bdrv_snapshot_load_tmp(bs, snapshot_name);
|
||||
}
|
||||
error_set(errp, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
drv->format_name, bdrv_get_device_name(bs),
|
||||
"temporarily load internal snapshot");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
|
||||
const char *id_or_name,
|
||||
Error **errp)
|
||||
{
|
||||
int ret;
|
||||
Error *local_err = NULL;
|
||||
|
||||
ret = bdrv_snapshot_load_tmp(bs, id_or_name, NULL, &local_err);
|
||||
if (ret == -ENOENT || ret == -EINVAL) {
|
||||
error_free(local_err);
|
||||
local_err = NULL;
|
||||
ret = bdrv_snapshot_load_tmp(bs, NULL, id_or_name, &local_err);
|
||||
}
|
||||
|
||||
if (error_is_set(&local_err)) {
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@@ -88,11 +88,6 @@ static void coroutine_fn stream_run(void *opaque)
|
||||
int n = 0;
|
||||
void *buf;
|
||||
|
||||
if (!bs->backing_hd) {
|
||||
block_job_completed(&s->common, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
s->common.len = bdrv_getlength(bs);
|
||||
if (s->common.len < 0) {
|
||||
block_job_completed(&s->common, s->common.len);
|
||||
|
@@ -331,7 +331,6 @@ static int vdi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
logout("\n");
|
||||
bdi->cluster_size = s->block_size;
|
||||
bdi->vm_state_offset = 0;
|
||||
bdi->unallocated_blocks_are_zero = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
13
block/vhdx.c
13
block/vhdx.c
@@ -1043,18 +1043,6 @@ static void vhdx_block_translate(BDRVVHDXState *s, int64_t sector_num,
|
||||
}
|
||||
|
||||
|
||||
static int vhdx_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
{
|
||||
BDRVVHDXState *s = bs->opaque;
|
||||
|
||||
bdi->cluster_size = s->block_size;
|
||||
|
||||
bdi->unallocated_blocks_are_zero =
|
||||
(s->params.data_bits & VHDX_PARAMS_HAS_PARENT) == 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static coroutine_fn int vhdx_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, QEMUIOVector *qiov)
|
||||
@@ -1897,7 +1885,6 @@ static BlockDriver bdrv_vhdx = {
|
||||
.bdrv_co_readv = vhdx_co_readv,
|
||||
.bdrv_co_writev = vhdx_co_writev,
|
||||
.bdrv_create = vhdx_create,
|
||||
.bdrv_get_info = vhdx_get_info,
|
||||
|
||||
.create_options = vhdx_create_options,
|
||||
};
|
||||
|
80
block/vmdk.c
80
block/vmdk.c
@@ -428,10 +428,6 @@ static int vmdk_add_extent(BlockDriverState *bs,
|
||||
extent->l2_size = l2_size;
|
||||
extent->cluster_sectors = flat ? sectors : cluster_sectors;
|
||||
|
||||
if (!flat) {
|
||||
bs->bl.write_zeroes_alignment =
|
||||
MAX(bs->bl.write_zeroes_alignment, cluster_sectors);
|
||||
}
|
||||
if (s->num_extents > 1) {
|
||||
extent->end_sector = (*(extent - 1)).end_sector + extent->sectors;
|
||||
} else {
|
||||
@@ -609,20 +605,13 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
header = footer.header;
|
||||
}
|
||||
|
||||
if (le32_to_cpu(header.version) > 3) {
|
||||
if (le32_to_cpu(header.version) >= 3) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "VMDK version %d",
|
||||
le32_to_cpu(header.version));
|
||||
qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bs->device_name, "vmdk", buf);
|
||||
return -ENOTSUP;
|
||||
} else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR)) {
|
||||
/* VMware KB 2064959 explains that version 3 added support for
|
||||
* persistent changed block tracking (CBT), and backup software can
|
||||
* read it as version=1 if it doesn't care about the changed area
|
||||
* information. So we are safe to enable read only. */
|
||||
error_setg(errp, "VMDK version 3 must be read only");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (le32_to_cpu(header.num_gtes_per_gt) > 512) {
|
||||
@@ -1430,8 +1419,7 @@ static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors,
|
||||
BdrvRequestFlags flags)
|
||||
int nb_sectors)
|
||||
{
|
||||
int ret;
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
@@ -1600,7 +1588,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
Error **errp)
|
||||
{
|
||||
int fd, idx = 0;
|
||||
char *desc = NULL;
|
||||
char desc[BUF_SIZE];
|
||||
int64_t total_size = 0, filesize;
|
||||
const char *adapter_type = NULL;
|
||||
const char *backing_file = NULL;
|
||||
@@ -1608,7 +1596,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
int flags = 0;
|
||||
int ret = 0;
|
||||
bool flat, split, compress;
|
||||
GString *ext_desc_lines;
|
||||
char ext_desc_lines[BUF_SIZE] = "";
|
||||
char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX];
|
||||
const int64_t split_size = 0x80000000; /* VMDK has constant split size */
|
||||
const char *desc_extent_line;
|
||||
@@ -1636,11 +1624,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
"ddb.geometry.sectors = \"63\"\n"
|
||||
"ddb.adapterType = \"%s\"\n";
|
||||
|
||||
ext_desc_lines = g_string_new(NULL);
|
||||
|
||||
if (filename_decompose(filename, path, prefix, postfix, PATH_MAX, errp)) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Read out options */
|
||||
while (options && options->name) {
|
||||
@@ -1666,8 +1651,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
strcmp(adapter_type, "lsilogic") &&
|
||||
strcmp(adapter_type, "legacyESX")) {
|
||||
error_setg(errp, "Unknown adapter type: '%s'", adapter_type);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (strcmp(adapter_type, "ide") != 0) {
|
||||
/* that's the number of heads with which vmware operates when
|
||||
@@ -1683,8 +1667,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
strcmp(fmt, "twoGbMaxExtentFlat") &&
|
||||
strcmp(fmt, "streamOptimized")) {
|
||||
error_setg(errp, "Unknown subformat: '%s'", fmt);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
return -EINVAL;
|
||||
}
|
||||
split = !(strcmp(fmt, "twoGbMaxExtentFlat") &&
|
||||
strcmp(fmt, "twoGbMaxExtentSparse"));
|
||||
@@ -1698,25 +1681,22 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
}
|
||||
if (flat && backing_file) {
|
||||
error_setg(errp, "Flat image can't have backing file");
|
||||
ret = -ENOTSUP;
|
||||
goto exit;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if (flat && zeroed_grain) {
|
||||
error_setg(errp, "Flat image can't enable zeroed grain");
|
||||
ret = -ENOTSUP;
|
||||
goto exit;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if (backing_file) {
|
||||
BlockDriverState *bs = bdrv_new("");
|
||||
ret = bdrv_open(bs, backing_file, NULL, BDRV_O_NO_BACKING, NULL, errp);
|
||||
ret = bdrv_open(bs, backing_file, NULL, 0, NULL, errp);
|
||||
if (ret != 0) {
|
||||
bdrv_unref(bs);
|
||||
goto exit;
|
||||
return ret;
|
||||
}
|
||||
if (strcmp(bs->drv->format_name, "vmdk")) {
|
||||
bdrv_unref(bs);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
return -EINVAL;
|
||||
}
|
||||
parent_cid = vmdk_read_cid(bs, 0);
|
||||
bdrv_unref(bs);
|
||||
@@ -1750,27 +1730,25 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
|
||||
if (vmdk_create_extent(ext_filename, size,
|
||||
flat, compress, zeroed_grain)) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
return -EINVAL;
|
||||
}
|
||||
filesize -= size;
|
||||
|
||||
/* Format description line */
|
||||
snprintf(desc_line, sizeof(desc_line),
|
||||
desc_extent_line, size / 512, desc_filename);
|
||||
g_string_append(ext_desc_lines, desc_line);
|
||||
pstrcat(ext_desc_lines, sizeof(ext_desc_lines), desc_line);
|
||||
}
|
||||
/* generate descriptor file */
|
||||
desc = g_strdup_printf(desc_template,
|
||||
(unsigned int)time(NULL),
|
||||
parent_cid,
|
||||
fmt,
|
||||
parent_desc_line,
|
||||
ext_desc_lines->str,
|
||||
(flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
|
||||
total_size / (int64_t)(63 * number_heads * 512),
|
||||
number_heads,
|
||||
adapter_type);
|
||||
snprintf(desc, sizeof(desc), desc_template,
|
||||
(unsigned int)time(NULL),
|
||||
parent_cid,
|
||||
fmt,
|
||||
parent_desc_line,
|
||||
ext_desc_lines,
|
||||
(flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
|
||||
total_size / (int64_t)(63 * number_heads * 512), number_heads,
|
||||
adapter_type);
|
||||
if (split || flat) {
|
||||
fd = qemu_open(filename,
|
||||
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
||||
@@ -1781,25 +1759,21 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
||||
0644);
|
||||
}
|
||||
if (fd < 0) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
return -errno;
|
||||
}
|
||||
/* the descriptor offset = 0x200 */
|
||||
if (!split && !flat && 0x200 != lseek(fd, 0x200, SEEK_SET)) {
|
||||
ret = -errno;
|
||||
goto close_exit;
|
||||
goto exit;
|
||||
}
|
||||
ret = qemu_write_full(fd, desc, strlen(desc));
|
||||
if (ret != strlen(desc)) {
|
||||
ret = -errno;
|
||||
goto close_exit;
|
||||
goto exit;
|
||||
}
|
||||
ret = 0;
|
||||
close_exit:
|
||||
qemu_close(fd);
|
||||
exit:
|
||||
g_free(desc);
|
||||
g_string_free(ext_desc_lines, true);
|
||||
qemu_close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
15
block/vpc.c
15
block/vpc.c
@@ -455,19 +455,6 @@ fail:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
{
|
||||
BDRVVPCState *s = (BDRVVPCState *)bs->opaque;
|
||||
VHDFooter *footer = (VHDFooter *) s->footer_buf;
|
||||
|
||||
if (cpu_to_be32(footer->type) != VHD_FIXED) {
|
||||
bdi->cluster_size = s->block_size;
|
||||
}
|
||||
|
||||
bdi->unallocated_blocks_are_zero = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vpc_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
@@ -870,8 +857,6 @@ static BlockDriver bdrv_vpc = {
|
||||
.bdrv_read = vpc_co_read,
|
||||
.bdrv_write = vpc_co_write,
|
||||
|
||||
.bdrv_get_info = vpc_get_info,
|
||||
|
||||
.create_options = vpc_create_options,
|
||||
.bdrv_has_zero_init = vpc_has_zero_init,
|
||||
};
|
||||
|
7
configure
vendored
7
configure
vendored
@@ -1357,6 +1357,11 @@ EOF
|
||||
pie="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
if compile_prog "-fno-pie" "-nopie"; then
|
||||
CFLAGS_NOPIE="-fno-pie"
|
||||
LDFLAGS_NOPIE="-nopie"
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
@@ -4288,6 +4293,7 @@ echo "LD=$ld" >> $config_host_mak
|
||||
echo "WINDRES=$windres" >> $config_host_mak
|
||||
echo "LIBTOOL=$libtool" >> $config_host_mak
|
||||
echo "CFLAGS=$CFLAGS" >> $config_host_mak
|
||||
echo "CFLAGS_NOPIE=$CFLAGS_NOPIE" >> $config_host_mak
|
||||
echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak
|
||||
echo "QEMU_INCLUDES=$QEMU_INCLUDES" >> $config_host_mak
|
||||
if test "$sparse" = "yes" ; then
|
||||
@@ -4301,6 +4307,7 @@ else
|
||||
echo "AUTOCONF_HOST := " >> $config_host_mak
|
||||
fi
|
||||
echo "LDFLAGS=$LDFLAGS" >> $config_host_mak
|
||||
echo "LDFLAGS_NOPIE=$LDFLAGS_NOPIE" >> $config_host_mak
|
||||
echo "LIBTOOLFLAGS=$LIBTOOLFLAGS" >> $config_host_mak
|
||||
echo "LIBS+=$LIBS" >> $config_host_mak
|
||||
echo "LIBS_TOOLS+=$libs_tools" >> $config_host_mak
|
||||
|
289
exec.c
289
exec.c
@@ -83,20 +83,37 @@ int use_icount;
|
||||
typedef struct PhysPageEntry PhysPageEntry;
|
||||
|
||||
struct PhysPageEntry {
|
||||
uint16_t is_leaf : 1;
|
||||
/* index into phys_sections (is_leaf) or phys_map_nodes (!is_leaf) */
|
||||
/* How many bits skip to next level (in units of L2_SIZE). 0 for a leaf. */
|
||||
uint16_t skip : 1;
|
||||
/* index into phys_sections (!skip) or phys_map_nodes (skip) */
|
||||
uint16_t ptr : 15;
|
||||
};
|
||||
|
||||
typedef PhysPageEntry Node[L2_SIZE];
|
||||
/* Size of the L2 (and L3, etc) page tables. */
|
||||
#define ADDR_SPACE_BITS TARGET_PHYS_ADDR_SPACE_BITS
|
||||
|
||||
#define P_L2_BITS 10
|
||||
#define P_L2_SIZE (1 << P_L2_BITS)
|
||||
|
||||
#define P_L2_LEVELS (((ADDR_SPACE_BITS - TARGET_PAGE_BITS - 1) / P_L2_BITS) + 1)
|
||||
|
||||
typedef PhysPageEntry Node[P_L2_SIZE];
|
||||
|
||||
typedef struct PhysPageMap {
|
||||
unsigned sections_nb;
|
||||
unsigned sections_nb_alloc;
|
||||
unsigned nodes_nb;
|
||||
unsigned nodes_nb_alloc;
|
||||
Node *nodes;
|
||||
MemoryRegionSection *sections;
|
||||
} PhysPageMap;
|
||||
|
||||
struct AddressSpaceDispatch {
|
||||
/* This is a multi-level map on the physical address space.
|
||||
* The bottom level has pointers to MemoryRegionSections.
|
||||
*/
|
||||
PhysPageEntry phys_map;
|
||||
Node *nodes;
|
||||
MemoryRegionSection *sections;
|
||||
PhysPageMap map;
|
||||
AddressSpace *as;
|
||||
};
|
||||
|
||||
@@ -113,18 +130,6 @@ typedef struct subpage_t {
|
||||
#define PHYS_SECTION_ROM 2
|
||||
#define PHYS_SECTION_WATCH 3
|
||||
|
||||
typedef struct PhysPageMap {
|
||||
unsigned sections_nb;
|
||||
unsigned sections_nb_alloc;
|
||||
unsigned nodes_nb;
|
||||
unsigned nodes_nb_alloc;
|
||||
Node *nodes;
|
||||
MemoryRegionSection *sections;
|
||||
} PhysPageMap;
|
||||
|
||||
static PhysPageMap *prev_map;
|
||||
static PhysPageMap next_map;
|
||||
|
||||
#define PHYS_MAP_NODE_NIL (((uint16_t)~0) >> 1)
|
||||
|
||||
static void io_mem_init(void);
|
||||
@@ -135,63 +140,60 @@ static MemoryRegion io_mem_watch;
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
static void phys_map_node_reserve(unsigned nodes)
|
||||
static void phys_map_node_reserve(PhysPageMap *map, unsigned nodes)
|
||||
{
|
||||
if (next_map.nodes_nb + nodes > next_map.nodes_nb_alloc) {
|
||||
next_map.nodes_nb_alloc = MAX(next_map.nodes_nb_alloc * 2,
|
||||
16);
|
||||
next_map.nodes_nb_alloc = MAX(next_map.nodes_nb_alloc,
|
||||
next_map.nodes_nb + nodes);
|
||||
next_map.nodes = g_renew(Node, next_map.nodes,
|
||||
next_map.nodes_nb_alloc);
|
||||
if (map->nodes_nb + nodes > map->nodes_nb_alloc) {
|
||||
map->nodes_nb_alloc = MAX(map->nodes_nb_alloc * 2, 16);
|
||||
map->nodes_nb_alloc = MAX(map->nodes_nb_alloc, map->nodes_nb + nodes);
|
||||
map->nodes = g_renew(Node, map->nodes, map->nodes_nb_alloc);
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t phys_map_node_alloc(void)
|
||||
static uint16_t phys_map_node_alloc(PhysPageMap *map)
|
||||
{
|
||||
unsigned i;
|
||||
uint16_t ret;
|
||||
|
||||
ret = next_map.nodes_nb++;
|
||||
ret = map->nodes_nb++;
|
||||
assert(ret != PHYS_MAP_NODE_NIL);
|
||||
assert(ret != next_map.nodes_nb_alloc);
|
||||
for (i = 0; i < L2_SIZE; ++i) {
|
||||
next_map.nodes[ret][i].is_leaf = 0;
|
||||
next_map.nodes[ret][i].ptr = PHYS_MAP_NODE_NIL;
|
||||
assert(ret != map->nodes_nb_alloc);
|
||||
for (i = 0; i < P_L2_SIZE; ++i) {
|
||||
map->nodes[ret][i].skip = 1;
|
||||
map->nodes[ret][i].ptr = PHYS_MAP_NODE_NIL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void phys_page_set_level(PhysPageEntry *lp, hwaddr *index,
|
||||
hwaddr *nb, uint16_t leaf,
|
||||
static void phys_page_set_level(PhysPageMap *map, PhysPageEntry *lp,
|
||||
hwaddr *index, hwaddr *nb, uint16_t leaf,
|
||||
int level)
|
||||
{
|
||||
PhysPageEntry *p;
|
||||
int i;
|
||||
hwaddr step = (hwaddr)1 << (level * L2_BITS);
|
||||
hwaddr step = (hwaddr)1 << (level * P_L2_BITS);
|
||||
|
||||
if (!lp->is_leaf && lp->ptr == PHYS_MAP_NODE_NIL) {
|
||||
lp->ptr = phys_map_node_alloc();
|
||||
p = next_map.nodes[lp->ptr];
|
||||
if (lp->skip && lp->ptr == PHYS_MAP_NODE_NIL) {
|
||||
lp->ptr = phys_map_node_alloc(map);
|
||||
p = map->nodes[lp->ptr];
|
||||
if (level == 0) {
|
||||
for (i = 0; i < L2_SIZE; i++) {
|
||||
p[i].is_leaf = 1;
|
||||
for (i = 0; i < P_L2_SIZE; i++) {
|
||||
p[i].skip = 0;
|
||||
p[i].ptr = PHYS_SECTION_UNASSIGNED;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p = next_map.nodes[lp->ptr];
|
||||
p = map->nodes[lp->ptr];
|
||||
}
|
||||
lp = &p[(*index >> (level * L2_BITS)) & (L2_SIZE - 1)];
|
||||
lp = &p[(*index >> (level * P_L2_BITS)) & (P_L2_SIZE - 1)];
|
||||
|
||||
while (*nb && lp < &p[L2_SIZE]) {
|
||||
while (*nb && lp < &p[P_L2_SIZE]) {
|
||||
if ((*index & (step - 1)) == 0 && *nb >= step) {
|
||||
lp->is_leaf = true;
|
||||
lp->skip = 0;
|
||||
lp->ptr = leaf;
|
||||
*index += step;
|
||||
*nb -= step;
|
||||
} else {
|
||||
phys_page_set_level(lp, index, nb, leaf, level - 1);
|
||||
phys_page_set_level(map, lp, index, nb, leaf, level - 1);
|
||||
}
|
||||
++lp;
|
||||
}
|
||||
@@ -202,23 +204,24 @@ static void phys_page_set(AddressSpaceDispatch *d,
|
||||
uint16_t leaf)
|
||||
{
|
||||
/* Wildly overreserve - it doesn't matter much. */
|
||||
phys_map_node_reserve(3 * P_L2_LEVELS);
|
||||
phys_map_node_reserve(&d->map, 3 * P_L2_LEVELS);
|
||||
|
||||
phys_page_set_level(&d->phys_map, &index, &nb, leaf, P_L2_LEVELS - 1);
|
||||
phys_page_set_level(&d->map, &d->phys_map, &index, &nb, leaf, P_L2_LEVELS - 1);
|
||||
}
|
||||
|
||||
static MemoryRegionSection *phys_page_find(PhysPageEntry lp, hwaddr index,
|
||||
static MemoryRegionSection *phys_page_find(PhysPageEntry lp, hwaddr addr,
|
||||
Node *nodes, MemoryRegionSection *sections)
|
||||
{
|
||||
PhysPageEntry *p;
|
||||
hwaddr index = addr >> TARGET_PAGE_BITS;
|
||||
int i;
|
||||
|
||||
for (i = P_L2_LEVELS - 1; i >= 0 && !lp.is_leaf; i--) {
|
||||
for (i = P_L2_LEVELS; lp.skip && (i -= lp.skip) >= 0;) {
|
||||
if (lp.ptr == PHYS_MAP_NODE_NIL) {
|
||||
return §ions[PHYS_SECTION_UNASSIGNED];
|
||||
}
|
||||
p = nodes[lp.ptr];
|
||||
lp = p[(index >> (i * L2_BITS)) & (L2_SIZE - 1)];
|
||||
lp = p[(index >> (i * P_L2_BITS)) & (P_L2_SIZE - 1)];
|
||||
}
|
||||
return §ions[lp.ptr];
|
||||
}
|
||||
@@ -236,11 +239,10 @@ static MemoryRegionSection *address_space_lookup_region(AddressSpaceDispatch *d,
|
||||
MemoryRegionSection *section;
|
||||
subpage_t *subpage;
|
||||
|
||||
section = phys_page_find(d->phys_map, addr >> TARGET_PAGE_BITS,
|
||||
d->nodes, d->sections);
|
||||
section = phys_page_find(d->phys_map, addr, d->map.nodes, d->map.sections);
|
||||
if (resolve_subpage && section->mr->subpage) {
|
||||
subpage = container_of(section->mr, subpage_t, iomem);
|
||||
section = &d->sections[subpage->sub_section[SUBPAGE_IDX(addr)]];
|
||||
section = &d->map.sections[subpage->sub_section[SUBPAGE_IDX(addr)]];
|
||||
}
|
||||
return section;
|
||||
}
|
||||
@@ -264,6 +266,18 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x
|
||||
return section;
|
||||
}
|
||||
|
||||
static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
|
||||
{
|
||||
if (memory_region_is_ram(mr)) {
|
||||
return !(is_write && mr->readonly);
|
||||
}
|
||||
if (memory_region_is_romd(mr)) {
|
||||
return !is_write;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
||||
hwaddr *xlat, hwaddr *plen,
|
||||
bool is_write)
|
||||
@@ -293,6 +307,11 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
||||
as = iotlb.target_as;
|
||||
}
|
||||
|
||||
if (memory_access_is_direct(mr, is_write)) {
|
||||
hwaddr page = ((addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE) - addr;
|
||||
len = MIN(page, len);
|
||||
}
|
||||
|
||||
*plen = len;
|
||||
*xlat = addr;
|
||||
return mr;
|
||||
@@ -708,7 +727,7 @@ hwaddr memory_region_section_get_iotlb(CPUArchState *env,
|
||||
iotlb |= PHYS_SECTION_ROM;
|
||||
}
|
||||
} else {
|
||||
iotlb = section - address_space_memory.dispatch->sections;
|
||||
iotlb = section - address_space_memory.dispatch->map.sections;
|
||||
iotlb += xlat;
|
||||
}
|
||||
|
||||
@@ -747,23 +766,23 @@ void phys_mem_set_alloc(void *(*alloc)(size_t))
|
||||
phys_mem_alloc = alloc;
|
||||
}
|
||||
|
||||
static uint16_t phys_section_add(MemoryRegionSection *section)
|
||||
static uint16_t phys_section_add(PhysPageMap *map,
|
||||
MemoryRegionSection *section)
|
||||
{
|
||||
/* The physical section number is ORed with a page-aligned
|
||||
* pointer to produce the iotlb entries. Thus it should
|
||||
* never overflow into the page-aligned value.
|
||||
*/
|
||||
assert(next_map.sections_nb < TARGET_PAGE_SIZE);
|
||||
assert(map->sections_nb < TARGET_PAGE_SIZE);
|
||||
|
||||
if (next_map.sections_nb == next_map.sections_nb_alloc) {
|
||||
next_map.sections_nb_alloc = MAX(next_map.sections_nb_alloc * 2,
|
||||
16);
|
||||
next_map.sections = g_renew(MemoryRegionSection, next_map.sections,
|
||||
next_map.sections_nb_alloc);
|
||||
if (map->sections_nb == map->sections_nb_alloc) {
|
||||
map->sections_nb_alloc = MAX(map->sections_nb_alloc * 2, 16);
|
||||
map->sections = g_renew(MemoryRegionSection, map->sections,
|
||||
map->sections_nb_alloc);
|
||||
}
|
||||
next_map.sections[next_map.sections_nb] = *section;
|
||||
map->sections[map->sections_nb] = *section;
|
||||
memory_region_ref(section->mr);
|
||||
return next_map.sections_nb++;
|
||||
return map->sections_nb++;
|
||||
}
|
||||
|
||||
static void phys_section_destroy(MemoryRegion *mr)
|
||||
@@ -785,7 +804,6 @@ static void phys_sections_free(PhysPageMap *map)
|
||||
}
|
||||
g_free(map->sections);
|
||||
g_free(map->nodes);
|
||||
g_free(map);
|
||||
}
|
||||
|
||||
static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *section)
|
||||
@@ -793,8 +811,8 @@ static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *secti
|
||||
subpage_t *subpage;
|
||||
hwaddr base = section->offset_within_address_space
|
||||
& TARGET_PAGE_MASK;
|
||||
MemoryRegionSection *existing = phys_page_find(d->phys_map, base >> TARGET_PAGE_BITS,
|
||||
next_map.nodes, next_map.sections);
|
||||
MemoryRegionSection *existing = phys_page_find(d->phys_map, base,
|
||||
d->map.nodes, d->map.sections);
|
||||
MemoryRegionSection subsection = {
|
||||
.offset_within_address_space = base,
|
||||
.size = int128_make64(TARGET_PAGE_SIZE),
|
||||
@@ -807,13 +825,14 @@ static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *secti
|
||||
subpage = subpage_init(d->as, base);
|
||||
subsection.mr = &subpage->iomem;
|
||||
phys_page_set(d, base >> TARGET_PAGE_BITS, 1,
|
||||
phys_section_add(&subsection));
|
||||
phys_section_add(&d->map, &subsection));
|
||||
} else {
|
||||
subpage = container_of(existing->mr, subpage_t, iomem);
|
||||
}
|
||||
start = section->offset_within_address_space & ~TARGET_PAGE_MASK;
|
||||
end = start + int128_get64(section->size) - 1;
|
||||
subpage_register(subpage, start, end, phys_section_add(section));
|
||||
subpage_register(subpage, start, end,
|
||||
phys_section_add(&d->map, section));
|
||||
}
|
||||
|
||||
|
||||
@@ -821,7 +840,7 @@ static void register_multipage(AddressSpaceDispatch *d,
|
||||
MemoryRegionSection *section)
|
||||
{
|
||||
hwaddr start_addr = section->offset_within_address_space;
|
||||
uint16_t section_index = phys_section_add(section);
|
||||
uint16_t section_index = phys_section_add(&d->map, section);
|
||||
uint64_t num_pages = int128_get64(int128_rshift(section->size,
|
||||
TARGET_PAGE_BITS));
|
||||
|
||||
@@ -904,13 +923,6 @@ static long gethugepagesize(const char *path)
|
||||
return fs.f_bsize;
|
||||
}
|
||||
|
||||
static sigjmp_buf sigjump;
|
||||
|
||||
static void sigbus_handler(int signal)
|
||||
{
|
||||
siglongjmp(sigjump, 1);
|
||||
}
|
||||
|
||||
static void *file_ram_alloc(RAMBlock *block,
|
||||
ram_addr_t memory,
|
||||
const char *path)
|
||||
@@ -920,6 +932,9 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
char *c;
|
||||
void *area;
|
||||
int fd;
|
||||
#ifdef MAP_POPULATE
|
||||
int flags;
|
||||
#endif
|
||||
unsigned long hpagesize;
|
||||
|
||||
hpagesize = gethugepagesize(path);
|
||||
@@ -967,52 +982,21 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
if (ftruncate(fd, memory))
|
||||
perror("ftruncate");
|
||||
|
||||
#ifdef MAP_POPULATE
|
||||
/* NB: MAP_POPULATE won't exhaustively alloc all phys pages in the case
|
||||
* MAP_PRIVATE is requested. For mem_prealloc we mmap as MAP_SHARED
|
||||
* to sidestep this quirk.
|
||||
*/
|
||||
flags = mem_prealloc ? MAP_POPULATE | MAP_SHARED : MAP_PRIVATE;
|
||||
area = mmap(0, memory, PROT_READ | PROT_WRITE, flags, fd, 0);
|
||||
#else
|
||||
area = mmap(0, memory, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
#endif
|
||||
if (area == MAP_FAILED) {
|
||||
perror("file_ram_alloc: can't mmap RAM pages");
|
||||
close(fd);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (mem_prealloc) {
|
||||
int ret, i;
|
||||
struct sigaction act, oldact;
|
||||
sigset_t set, oldset;
|
||||
|
||||
memset(&act, 0, sizeof(act));
|
||||
act.sa_handler = &sigbus_handler;
|
||||
act.sa_flags = 0;
|
||||
|
||||
ret = sigaction(SIGBUS, &act, &oldact);
|
||||
if (ret) {
|
||||
perror("file_ram_alloc: failed to install signal handler");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* unblock SIGBUS */
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGBUS);
|
||||
pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
|
||||
|
||||
if (sigsetjmp(sigjump, 1)) {
|
||||
fprintf(stderr, "file_ram_alloc: failed to preallocate pages\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* MAP_POPULATE silently ignores failures */
|
||||
for (i = 0; i < (memory/hpagesize)-1; i++) {
|
||||
memset(area + (hpagesize*i), 0, 1);
|
||||
}
|
||||
|
||||
ret = sigaction(SIGBUS, &oldact, NULL);
|
||||
if (ret) {
|
||||
perror("file_ram_alloc: failed to reinstall signal handler");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
||||
}
|
||||
|
||||
block->fd = fd;
|
||||
return area;
|
||||
}
|
||||
@@ -1640,7 +1624,7 @@ static subpage_t *subpage_init(AddressSpace *as, hwaddr base)
|
||||
return mmio;
|
||||
}
|
||||
|
||||
static uint16_t dummy_section(MemoryRegion *mr)
|
||||
static uint16_t dummy_section(PhysPageMap *map, MemoryRegion *mr)
|
||||
{
|
||||
MemoryRegionSection section = {
|
||||
.mr = mr,
|
||||
@@ -1649,12 +1633,13 @@ static uint16_t dummy_section(MemoryRegion *mr)
|
||||
.size = int128_2_64(),
|
||||
};
|
||||
|
||||
return phys_section_add(§ion);
|
||||
return phys_section_add(map, §ion);
|
||||
}
|
||||
|
||||
MemoryRegion *iotlb_to_region(hwaddr index)
|
||||
{
|
||||
return address_space_memory.dispatch->sections[index & ~TARGET_PAGE_MASK].mr;
|
||||
return address_space_memory.dispatch->map.sections[
|
||||
index & ~TARGET_PAGE_MASK].mr;
|
||||
}
|
||||
|
||||
static void io_mem_init(void)
|
||||
@@ -1671,9 +1656,19 @@ static void io_mem_init(void)
|
||||
static void mem_begin(MemoryListener *listener)
|
||||
{
|
||||
AddressSpace *as = container_of(listener, AddressSpace, dispatch_listener);
|
||||
AddressSpaceDispatch *d = g_new(AddressSpaceDispatch, 1);
|
||||
AddressSpaceDispatch *d = g_new0(AddressSpaceDispatch, 1);
|
||||
uint16_t n;
|
||||
|
||||
d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .is_leaf = 0 };
|
||||
n = dummy_section(&d->map, &io_mem_unassigned);
|
||||
assert(n == PHYS_SECTION_UNASSIGNED);
|
||||
n = dummy_section(&d->map, &io_mem_notdirty);
|
||||
assert(n == PHYS_SECTION_NOTDIRTY);
|
||||
n = dummy_section(&d->map, &io_mem_rom);
|
||||
assert(n == PHYS_SECTION_ROM);
|
||||
n = dummy_section(&d->map, &io_mem_watch);
|
||||
assert(n == PHYS_SECTION_WATCH);
|
||||
|
||||
d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .skip = 1 };
|
||||
d->as = as;
|
||||
as->next_dispatch = d;
|
||||
}
|
||||
@@ -1684,37 +1679,12 @@ static void mem_commit(MemoryListener *listener)
|
||||
AddressSpaceDispatch *cur = as->dispatch;
|
||||
AddressSpaceDispatch *next = as->next_dispatch;
|
||||
|
||||
next->nodes = next_map.nodes;
|
||||
next->sections = next_map.sections;
|
||||
|
||||
as->dispatch = next;
|
||||
g_free(cur);
|
||||
}
|
||||
|
||||
static void core_begin(MemoryListener *listener)
|
||||
{
|
||||
uint16_t n;
|
||||
|
||||
prev_map = g_new(PhysPageMap, 1);
|
||||
*prev_map = next_map;
|
||||
|
||||
memset(&next_map, 0, sizeof(next_map));
|
||||
n = dummy_section(&io_mem_unassigned);
|
||||
assert(n == PHYS_SECTION_UNASSIGNED);
|
||||
n = dummy_section(&io_mem_notdirty);
|
||||
assert(n == PHYS_SECTION_NOTDIRTY);
|
||||
n = dummy_section(&io_mem_rom);
|
||||
assert(n == PHYS_SECTION_ROM);
|
||||
n = dummy_section(&io_mem_watch);
|
||||
assert(n == PHYS_SECTION_WATCH);
|
||||
}
|
||||
|
||||
/* This listener's commit run after the other AddressSpaceDispatch listeners'.
|
||||
* All AddressSpaceDispatch instances have switched to the next map.
|
||||
*/
|
||||
static void core_commit(MemoryListener *listener)
|
||||
{
|
||||
phys_sections_free(prev_map);
|
||||
if (cur) {
|
||||
phys_sections_free(&cur->map);
|
||||
g_free(cur);
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_commit(MemoryListener *listener)
|
||||
@@ -1742,8 +1712,6 @@ static void core_log_global_stop(MemoryListener *listener)
|
||||
}
|
||||
|
||||
static MemoryListener core_memory_listener = {
|
||||
.begin = core_begin,
|
||||
.commit = core_commit,
|
||||
.log_global_start = core_log_global_start,
|
||||
.log_global_stop = core_log_global_stop,
|
||||
.priority = 1,
|
||||
@@ -1778,7 +1746,12 @@ void address_space_destroy_dispatch(AddressSpace *as)
|
||||
static void memory_map_init(void)
|
||||
{
|
||||
system_memory = g_malloc(sizeof(*system_memory));
|
||||
memory_region_init(system_memory, NULL, "system", INT64_MAX);
|
||||
|
||||
assert(ADDR_SPACE_BITS <= 64);
|
||||
|
||||
memory_region_init(system_memory, NULL, "system",
|
||||
ADDR_SPACE_BITS == 64 ?
|
||||
UINT64_MAX : (0x1ULL << ADDR_SPACE_BITS));
|
||||
address_space_init(&address_space_memory, system_memory, "memory");
|
||||
|
||||
system_io = g_malloc(sizeof(*system_io));
|
||||
@@ -1859,18 +1832,6 @@ static void invalidate_and_set_dirty(hwaddr addr,
|
||||
xen_modified_memory(addr, length);
|
||||
}
|
||||
|
||||
static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
|
||||
{
|
||||
if (memory_region_is_ram(mr)) {
|
||||
return !(is_write && mr->readonly);
|
||||
}
|
||||
if (memory_region_is_romd(mr)) {
|
||||
return !is_write;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
|
||||
{
|
||||
unsigned access_size_max = mr->ops->valid.max_access_size;
|
||||
|
@@ -75,9 +75,18 @@ static struct keymap map[0xE0] = {
|
||||
[0x2c] = {4,3}, /* z */
|
||||
[0xc7] = {5,0}, /* Home */
|
||||
[0x2a] = {5,1}, /* shift */
|
||||
[0x39] = {5,2}, /* space */
|
||||
/*
|
||||
* There are two matrix positions which map to space,
|
||||
* but QEMU can only use one of them for the reverse
|
||||
* mapping, so simply use the second one.
|
||||
*/
|
||||
/* [0x39] = {5,2}, space */
|
||||
[0x39] = {5,3}, /* space */
|
||||
[0x1c] = {5,5}, /* enter */
|
||||
/*
|
||||
* Matrix position {5,4} and other keys are missing here.
|
||||
* TODO: Compare with Linux code and test real hardware.
|
||||
*/
|
||||
[0x1c] = {5,5}, /* enter (TODO: might be wrong) */
|
||||
[0xc8] = {6,0}, /* up */
|
||||
[0xd0] = {6,1}, /* down */
|
||||
[0xcb] = {6,2}, /* left */
|
||||
|
@@ -92,8 +92,6 @@
|
||||
#define MP_ETH_CRDP3 0x4AC
|
||||
#define MP_ETH_CTDP0 0x4E0
|
||||
#define MP_ETH_CTDP1 0x4E4
|
||||
#define MP_ETH_CTDP2 0x4E8
|
||||
#define MP_ETH_CTDP3 0x4EC
|
||||
|
||||
/* MII PHY access */
|
||||
#define MP_ETH_SMIR_DATA 0x0000FFFF
|
||||
@@ -308,7 +306,7 @@ static uint64_t mv88w8618_eth_read(void *opaque, hwaddr offset,
|
||||
case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
|
||||
return s->rx_queue[(offset - MP_ETH_CRDP0)/4];
|
||||
|
||||
case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
|
||||
case MP_ETH_CTDP0 ... MP_ETH_CTDP1:
|
||||
return s->tx_queue[(offset - MP_ETH_CTDP0)/4];
|
||||
|
||||
default:
|
||||
@@ -362,7 +360,7 @@ static void mv88w8618_eth_write(void *opaque, hwaddr offset,
|
||||
s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value;
|
||||
break;
|
||||
|
||||
case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
|
||||
case MP_ETH_CTDP0 ... MP_ETH_CTDP1:
|
||||
s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value;
|
||||
break;
|
||||
}
|
||||
|
@@ -728,20 +728,18 @@ static int virtio_blk_device_init(VirtIODevice *vdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_blk_device_exit(DeviceState *dev)
|
||||
static void virtio_blk_device_exit(VirtIODevice *vdev)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VirtIOBlock *s = VIRTIO_BLK(dev);
|
||||
VirtIOBlock *s = VIRTIO_BLK(vdev);
|
||||
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
|
||||
remove_migration_state_change_notifier(&s->migration_state_notifier);
|
||||
virtio_blk_data_plane_destroy(s->dataplane);
|
||||
s->dataplane = NULL;
|
||||
#endif
|
||||
qemu_del_vm_change_state_handler(s->change);
|
||||
unregister_savevm(dev, "virtio-blk", s);
|
||||
unregister_savevm(DEVICE(vdev), "virtio-blk", s);
|
||||
blockdev_mark_auto_del(s->bs);
|
||||
virtio_cleanup(vdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Property virtio_blk_properties[] = {
|
||||
@@ -753,10 +751,10 @@ static void virtio_blk_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||
dc->exit = virtio_blk_device_exit;
|
||||
dc->props = virtio_blk_properties;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
vdc->init = virtio_blk_device_init;
|
||||
vdc->exit = virtio_blk_device_exit;
|
||||
vdc->get_config = virtio_blk_update_config;
|
||||
vdc->set_config = virtio_blk_set_config;
|
||||
vdc->get_features = virtio_blk_get_features;
|
||||
|
@@ -120,8 +120,8 @@ typedef struct {
|
||||
uint64_t char_tx_time;
|
||||
CharDriverState *chr;
|
||||
qemu_irq irq;
|
||||
QEMUTimer *fifo_trigger_handle;
|
||||
QEMUTimer *tx_time_handle;
|
||||
struct QEMUTimer *fifo_trigger_handle;
|
||||
struct QEMUTimer *tx_time_handle;
|
||||
} UartState;
|
||||
|
||||
static void uart_update_status(UartState *s)
|
||||
|
@@ -987,12 +987,11 @@ static const TypeInfo virtio_serial_port_type_info = {
|
||||
.class_init = virtio_serial_port_class_init,
|
||||
};
|
||||
|
||||
static int virtio_serial_device_exit(DeviceState *dev)
|
||||
static void virtio_serial_device_exit(VirtIODevice *vdev)
|
||||
{
|
||||
VirtIOSerial *vser = VIRTIO_SERIAL(dev);
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VirtIOSerial *vser = VIRTIO_SERIAL(vdev);
|
||||
|
||||
unregister_savevm(dev, "virtio-console", vser);
|
||||
unregister_savevm(DEVICE(vdev), "virtio-console", vser);
|
||||
|
||||
g_free(vser->ivqs);
|
||||
g_free(vser->ovqs);
|
||||
@@ -1004,7 +1003,6 @@ static int virtio_serial_device_exit(DeviceState *dev)
|
||||
g_free(vser->post_load);
|
||||
}
|
||||
virtio_cleanup(vdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Property virtio_serial_properties[] = {
|
||||
@@ -1016,10 +1014,10 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||
dc->exit = virtio_serial_device_exit;
|
||||
dc->props = virtio_serial_properties;
|
||||
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
||||
vdc->init = virtio_serial_device_init;
|
||||
vdc->exit = virtio_serial_device_exit;
|
||||
vdc->get_features = get_features;
|
||||
vdc->get_config = get_config;
|
||||
vdc->set_config = set_config;
|
||||
|
@@ -23,7 +23,6 @@
|
||||
*/
|
||||
#include "hw/hw.h"
|
||||
#include "hw/loader.h"
|
||||
#include "trace.h"
|
||||
#include "ui/console.h"
|
||||
#include "hw/pci/pci.h"
|
||||
|
||||
|
@@ -285,8 +285,7 @@ static inline void build_append_array(GArray *array, GArray *val)
|
||||
g_array_append_vals(array, val->data, val->len);
|
||||
}
|
||||
|
||||
static void GCC_FMT_ATTR(2, 3)
|
||||
build_append_nameseg(GArray *array, const char *format, ...)
|
||||
static void build_append_nameseg(GArray *array, const char *format, ...)
|
||||
{
|
||||
/* It would be nicer to use g_string_vprintf but it's only there in 2.22 */
|
||||
char s[] = "XXXX";
|
||||
@@ -631,7 +630,7 @@ build_append_notify(GArray *device, const char *name,
|
||||
GArray *method = build_alloc_array();
|
||||
uint8_t op = 0x14; /* MethodOp */
|
||||
|
||||
build_append_nameseg(method, "%s", name);
|
||||
build_append_nameseg(method, name);
|
||||
build_append_byte(method, 0x02); /* MethodFlags: ArgCount */
|
||||
for (i = skip; i < count; i++) {
|
||||
GArray *target = build_alloc_array();
|
||||
|
@@ -18,11 +18,10 @@
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "bios-linker-loader.h"
|
||||
#include "hw/nvram/fw_cfg.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "qemu/bswap.h"
|
||||
|
||||
#define BIOS_LINKER_LOADER_FILESZ FW_CFG_MAX_FILE_PATH
|
||||
|
20
hw/i386/pc.c
20
hw/i386/pc.c
@@ -1093,21 +1093,13 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
|
||||
return guest_info;
|
||||
}
|
||||
|
||||
void pc_init_pci64_hole(PcPciInfo *pci_info, uint64_t pci_hole64_start,
|
||||
uint64_t pci_hole64_size)
|
||||
/* setup pci memory address space mapping into system address space */
|
||||
void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory,
|
||||
MemoryRegion *pci_address_space)
|
||||
{
|
||||
if ((sizeof(hwaddr) == 4) || (!pci_hole64_size)) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* BIOS does not set MTRR entries for the 64 bit window, so no need to
|
||||
* align address to power of two. Align address at 1G, this makes sure
|
||||
* it can be exactly covered with a PAT entry even when using huge
|
||||
* pages.
|
||||
*/
|
||||
pci_info->w64.begin = ROUND_UP(pci_hole64_start, 0x1ULL << 30);
|
||||
pci_info->w64.end = pci_info->w64.begin + pci_hole64_size;
|
||||
assert(pci_info->w64.begin <= pci_info->w64.end);
|
||||
/* Set to lower priority than RAM */
|
||||
memory_region_add_subregion_overlap(system_memory, 0x0,
|
||||
pci_address_space, -1);
|
||||
}
|
||||
|
||||
void pc_acpi_init(const char *default_dsdt)
|
||||
|
@@ -150,7 +150,6 @@ static void pc_init1(QEMUMachineInitArgs *args,
|
||||
pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
|
||||
system_memory, system_io, args->ram_size,
|
||||
below_4g_mem_size,
|
||||
0x100000000ULL - below_4g_mem_size,
|
||||
above_4g_mem_size,
|
||||
pci_memory, ram_memory);
|
||||
} else {
|
||||
@@ -339,24 +338,13 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args)
|
||||
.desc = "Standard PC (i440FX + PIIX, 1996)", \
|
||||
.hot_add_cpu = pc_hot_add_cpu
|
||||
|
||||
#define PC_I440FX_2_0_MACHINE_OPTIONS \
|
||||
PC_I440FX_MACHINE_OPTIONS, \
|
||||
.default_machine_opts = "firmware=bios-256k.bin"
|
||||
|
||||
static QEMUMachine pc_i440fx_machine_v2_0 = {
|
||||
PC_I440FX_2_0_MACHINE_OPTIONS,
|
||||
.name = "pc-i440fx-2.0",
|
||||
.alias = "pc",
|
||||
.init = pc_init_pci,
|
||||
.is_default = 1,
|
||||
};
|
||||
|
||||
#define PC_I440FX_1_7_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
|
||||
|
||||
static QEMUMachine pc_i440fx_machine_v1_7 = {
|
||||
PC_I440FX_1_7_MACHINE_OPTIONS,
|
||||
.name = "pc-i440fx-1.7",
|
||||
.alias = "pc",
|
||||
.init = pc_init_pci,
|
||||
.is_default = 1,
|
||||
};
|
||||
|
||||
#define PC_I440FX_1_6_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
|
||||
@@ -758,7 +746,6 @@ static QEMUMachine xenfv_machine = {
|
||||
|
||||
static void pc_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&pc_i440fx_machine_v2_0);
|
||||
qemu_register_machine(&pc_i440fx_machine_v1_7);
|
||||
qemu_register_machine(&pc_i440fx_machine_v1_6);
|
||||
qemu_register_machine(&pc_i440fx_machine_v1_5);
|
||||
|
@@ -259,22 +259,12 @@ static void pc_q35_init_1_4(QEMUMachineInitArgs *args)
|
||||
.desc = "Standard PC (Q35 + ICH9, 2009)", \
|
||||
.hot_add_cpu = pc_hot_add_cpu
|
||||
|
||||
#define PC_Q35_2_0_MACHINE_OPTIONS \
|
||||
PC_Q35_MACHINE_OPTIONS, \
|
||||
.default_machine_opts = "firmware=bios-256k.bin"
|
||||
|
||||
static QEMUMachine pc_q35_machine_v2_0 = {
|
||||
PC_Q35_2_0_MACHINE_OPTIONS,
|
||||
.name = "pc-q35-2.0",
|
||||
.alias = "q35",
|
||||
.init = pc_q35_init,
|
||||
};
|
||||
|
||||
#define PC_Q35_1_7_MACHINE_OPTIONS PC_Q35_MACHINE_OPTIONS
|
||||
|
||||
static QEMUMachine pc_q35_machine_v1_7 = {
|
||||
PC_Q35_1_7_MACHINE_OPTIONS,
|
||||
.name = "pc-q35-1.7",
|
||||
.alias = "q35",
|
||||
.init = pc_q35_init,
|
||||
};
|
||||
|
||||
@@ -316,7 +306,6 @@ static QEMUMachine pc_q35_machine_v1_4 = {
|
||||
|
||||
static void pc_q35_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&pc_q35_machine_v2_0);
|
||||
qemu_register_machine(&pc_q35_machine_v1_7);
|
||||
qemu_register_machine(&pc_q35_machine_v1_6);
|
||||
qemu_register_machine(&pc_q35_machine_v1_5);
|
||||
|
@@ -418,7 +418,7 @@ static int exynos4210_combiner_init(SysBusDevice *sbd)
|
||||
qdev_init_gpio_in(dev, exynos4210_combiner_handler, IIC_NIRQ);
|
||||
|
||||
/* Connect SysBusDev irqs to device specific irqs */
|
||||
for (i = 0; i < IIC_NIRQ; i++) {
|
||||
for (i = 0; i < IIC_NGRP; i++) {
|
||||
sysbus_init_irq(sbd, &s->output_irq[i]);
|
||||
}
|
||||
|
||||
|
@@ -41,7 +41,7 @@
|
||||
#define GIC_SET_MODEL(irq) s->irq_state[irq].model = true
|
||||
#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = false
|
||||
#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
|
||||
#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)
|
||||
#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level |= (cm)
|
||||
#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
|
||||
#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
|
||||
#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = true
|
||||
|
@@ -276,7 +276,7 @@ static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc,
|
||||
}
|
||||
break;
|
||||
case SYS_CFG_OSC:
|
||||
if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) {
|
||||
if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) {
|
||||
/* motherboard clock */
|
||||
*val = s->mb_clock[device];
|
||||
return true;
|
||||
@@ -324,7 +324,7 @@ static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc,
|
||||
|
||||
switch (function) {
|
||||
case SYS_CFG_OSC:
|
||||
if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) {
|
||||
if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) {
|
||||
/* motherboard clock */
|
||||
s->mb_clock[device] = val;
|
||||
return true;
|
||||
|
121
hw/misc/vfio.c
121
hw/misc/vfio.c
@@ -52,8 +52,6 @@
|
||||
/* Extra debugging, trap acceleration paths for more logging */
|
||||
#define VFIO_ALLOW_MMAP 1
|
||||
#define VFIO_ALLOW_KVM_INTX 1
|
||||
#define VFIO_ALLOW_KVM_MSI 1
|
||||
#define VFIO_ALLOW_KVM_MSIX 1
|
||||
|
||||
struct VFIODevice;
|
||||
|
||||
@@ -210,17 +208,6 @@ static QLIST_HEAD(, VFIOContainer)
|
||||
static QLIST_HEAD(, VFIOGroup)
|
||||
group_list = QLIST_HEAD_INITIALIZER(group_list);
|
||||
|
||||
#ifdef CONFIG_KVM
|
||||
/*
|
||||
* We have a single VFIO pseudo device per KVM VM. Once created it lives
|
||||
* for the life of the VM. Closing the file descriptor only drops our
|
||||
* reference to it and the device's reference to kvm. Therefore once
|
||||
* initialized, this file descriptor is only released on QEMU exit and
|
||||
* we'll re-use it should another vfio device be attached before then.
|
||||
*/
|
||||
static int vfio_kvm_device_fd = -1;
|
||||
#endif
|
||||
|
||||
static void vfio_disable_interrupts(VFIODevice *vdev);
|
||||
static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len);
|
||||
static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
|
||||
@@ -592,21 +579,9 @@ static void vfio_msi_interrupt(void *opaque)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef VFIO_DEBUG
|
||||
MSIMessage msg;
|
||||
|
||||
if (vdev->interrupt == VFIO_INT_MSIX) {
|
||||
msg = msi_get_message(&vdev->pdev, nr);
|
||||
} else if (vdev->interrupt == VFIO_INT_MSI) {
|
||||
msg = msix_get_message(&vdev->pdev, nr);
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
|
||||
DPRINTF("%s(%04x:%02x:%02x.%x) vector %d 0x%"PRIx64"/0x%x\n", __func__,
|
||||
DPRINTF("%s(%04x:%02x:%02x.%x) vector %d\n", __func__,
|
||||
vdev->host.domain, vdev->host.bus, vdev->host.slot,
|
||||
vdev->host.function, nr, msg.address, msg.data);
|
||||
#endif
|
||||
vdev->host.function, nr);
|
||||
|
||||
if (vdev->interrupt == VFIO_INT_MSIX) {
|
||||
msix_notify(&vdev->pdev, nr);
|
||||
@@ -674,8 +649,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
|
||||
* Attempt to enable route through KVM irqchip,
|
||||
* default to userspace handling if unavailable.
|
||||
*/
|
||||
vector->virq = msg && VFIO_ALLOW_KVM_MSIX ?
|
||||
kvm_irqchip_add_msi_route(kvm_state, *msg) : -1;
|
||||
vector->virq = msg ? kvm_irqchip_add_msi_route(kvm_state, *msg) : -1;
|
||||
if (vector->virq < 0 ||
|
||||
kvm_irqchip_add_irqfd_notifier(kvm_state, &vector->interrupt,
|
||||
NULL, vector->virq) < 0) {
|
||||
@@ -842,8 +816,7 @@ retry:
|
||||
* Attempt to enable route through KVM irqchip,
|
||||
* default to userspace handling if unavailable.
|
||||
*/
|
||||
vector->virq = VFIO_ALLOW_KVM_MSI ?
|
||||
kvm_irqchip_add_msi_route(kvm_state, vector->msg) : -1;
|
||||
vector->virq = kvm_irqchip_add_msi_route(kvm_state, vector->msg);
|
||||
if (vector->virq < 0 ||
|
||||
kvm_irqchip_add_irqfd_notifier(kvm_state, &vector->interrupt,
|
||||
NULL, vector->virq) < 0) {
|
||||
@@ -1839,34 +1812,6 @@ static void vfio_probe_nvidia_bar5_window_quirk(VFIODevice *vdev, int nr)
|
||||
vdev->host.function);
|
||||
}
|
||||
|
||||
static void vfio_nvidia_88000_quirk_write(void *opaque, hwaddr addr,
|
||||
uint64_t data, unsigned size)
|
||||
{
|
||||
VFIOQuirk *quirk = opaque;
|
||||
VFIODevice *vdev = quirk->vdev;
|
||||
PCIDevice *pdev = &vdev->pdev;
|
||||
hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK;
|
||||
|
||||
vfio_generic_quirk_write(opaque, addr, data, size);
|
||||
|
||||
/*
|
||||
* Nvidia seems to acknowledge MSI interrupts by writing 0xff to the
|
||||
* MSI capability ID register. Both the ID and next register are
|
||||
* read-only, so we allow writes covering either of those to real hw.
|
||||
* NB - only fixed for the 0x88000 MMIO window.
|
||||
*/
|
||||
if ((pdev->cap_present & QEMU_PCI_CAP_MSI) &&
|
||||
vfio_range_contained(addr, size, pdev->msi_cap, PCI_MSI_FLAGS)) {
|
||||
vfio_bar_write(&vdev->bars[quirk->data.bar], addr + base, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps vfio_nvidia_88000_quirk = {
|
||||
.read = vfio_generic_quirk_read,
|
||||
.write = vfio_nvidia_88000_quirk_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
/*
|
||||
* Finally, BAR0 itself. We want to redirect any accesses to either
|
||||
* 0x1800 or 0x88000 through the PCI config space access functions.
|
||||
@@ -1893,7 +1838,7 @@ static void vfio_probe_nvidia_bar0_88000_quirk(VFIODevice *vdev, int nr)
|
||||
quirk->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1;
|
||||
quirk->data.bar = nr;
|
||||
|
||||
memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_nvidia_88000_quirk,
|
||||
memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_generic_quirk,
|
||||
quirk, "vfio-nvidia-bar0-88000-quirk",
|
||||
TARGET_PAGE_ALIGN(quirk->data.address_mask + 1));
|
||||
memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
|
||||
@@ -3108,59 +3053,6 @@ static void vfio_pci_reset_handler(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
static void vfio_kvm_device_add_group(VFIOGroup *group)
|
||||
{
|
||||
#ifdef CONFIG_KVM
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_VFIO_GROUP,
|
||||
.attr = KVM_DEV_VFIO_GROUP_ADD,
|
||||
.addr = (uint64_t)(unsigned long)&group->fd,
|
||||
};
|
||||
|
||||
if (!kvm_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (vfio_kvm_device_fd < 0) {
|
||||
struct kvm_create_device cd = {
|
||||
.type = KVM_DEV_TYPE_VFIO,
|
||||
};
|
||||
|
||||
if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
|
||||
DPRINTF("KVM_CREATE_DEVICE: %m\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vfio_kvm_device_fd = cd.fd;
|
||||
}
|
||||
|
||||
if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
|
||||
error_report("Failed to add group %d to KVM VFIO device: %m",
|
||||
group->groupid);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void vfio_kvm_device_del_group(VFIOGroup *group)
|
||||
{
|
||||
#ifdef CONFIG_KVM
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_DEV_VFIO_GROUP,
|
||||
.attr = KVM_DEV_VFIO_GROUP_DEL,
|
||||
.addr = (uint64_t)(unsigned long)&group->fd,
|
||||
};
|
||||
|
||||
if (vfio_kvm_device_fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
|
||||
error_report("Failed to remove group %d to KVM VFIO device: %m",
|
||||
group->groupid);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int vfio_connect_container(VFIOGroup *group)
|
||||
{
|
||||
VFIOContainer *container;
|
||||
@@ -3309,8 +3201,6 @@ static VFIOGroup *vfio_get_group(int groupid)
|
||||
|
||||
QLIST_INSERT_HEAD(&group_list, group, next);
|
||||
|
||||
vfio_kvm_device_add_group(group);
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
@@ -3320,7 +3210,6 @@ static void vfio_put_group(VFIOGroup *group)
|
||||
return;
|
||||
}
|
||||
|
||||
vfio_kvm_device_del_group(group);
|
||||
vfio_disconnect_container(group);
|
||||
QLIST_REMOVE(group, next);
|
||||
DPRINTF("vfio_put_group: close group->fd\n");
|
||||
|
@@ -1428,7 +1428,7 @@ static NetClientInfo net_virtio_info = {
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = virtio_net_can_receive,
|
||||
.receive = virtio_net_receive,
|
||||
.cleanup = virtio_net_cleanup,
|
||||
.cleanup = virtio_net_cleanup,
|
||||
.link_status_changed = virtio_net_set_link_status,
|
||||
.query_rx_filter = virtio_net_query_rxfilter,
|
||||
};
|
||||
@@ -1570,16 +1570,15 @@ static int virtio_net_device_init(VirtIODevice *vdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_net_device_exit(DeviceState *qdev)
|
||||
static void virtio_net_device_exit(VirtIODevice *vdev)
|
||||
{
|
||||
VirtIONet *n = VIRTIO_NET(qdev);
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
|
||||
VirtIONet *n = VIRTIO_NET(vdev);
|
||||
int i;
|
||||
|
||||
/* This will stop vhost backend if appropriate. */
|
||||
virtio_net_set_status(vdev, 0);
|
||||
|
||||
unregister_savevm(qdev, "virtio-net", n);
|
||||
unregister_savevm(DEVICE(vdev), "virtio-net", n);
|
||||
|
||||
if (n->netclient_name) {
|
||||
g_free(n->netclient_name);
|
||||
@@ -1610,8 +1609,6 @@ static int virtio_net_device_exit(DeviceState *qdev)
|
||||
g_free(n->vqs);
|
||||
qemu_del_nic(n->nic);
|
||||
virtio_cleanup(vdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void virtio_net_instance_init(Object *obj)
|
||||
@@ -1638,10 +1635,10 @@ static void virtio_net_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||
dc->exit = virtio_net_device_exit;
|
||||
dc->props = virtio_net_properties;
|
||||
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
|
||||
vdc->init = virtio_net_device_init;
|
||||
vdc->exit = virtio_net_device_exit;
|
||||
vdc->get_config = virtio_net_get_config;
|
||||
vdc->set_config = virtio_net_set_config;
|
||||
vdc->get_features = virtio_net_get_features;
|
||||
|
@@ -126,7 +126,7 @@ static const VMStateDescription vmstate_eeprom = {
|
||||
.version_id = EEPROM_VERSION,
|
||||
.minimum_version_id = OLD_EEPROM_VERSION,
|
||||
.minimum_version_id_old = OLD_EEPROM_VERSION,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_UINT8(tick, eeprom_t),
|
||||
VMSTATE_UINT8(address, eeprom_t),
|
||||
VMSTATE_UINT8(command, eeprom_t),
|
||||
@@ -157,13 +157,13 @@ void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi)
|
||||
logout("CS=%u SK=%u DI=%u DO=%u, tick = %u\n",
|
||||
eecs, eesk, eedi, eedo, tick);
|
||||
|
||||
if (!eeprom->eecs && eecs) {
|
||||
if (! eeprom->eecs && eecs) {
|
||||
/* Start chip select cycle. */
|
||||
logout("Cycle start, waiting for 1st start bit (0)\n");
|
||||
tick = 0;
|
||||
command = 0x0;
|
||||
address = 0x0;
|
||||
} else if (eeprom->eecs && !eecs) {
|
||||
} else if (eeprom->eecs && ! eecs) {
|
||||
/* End chip select cycle. This triggers write / erase. */
|
||||
if (eeprom->writable) {
|
||||
uint8_t subcommand = address >> (eeprom->addrbits - 2);
|
||||
@@ -189,7 +189,7 @@ void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi)
|
||||
}
|
||||
/* Output DO is tristate, read results in 1. */
|
||||
eedo = 1;
|
||||
} else if (eecs && !eeprom->eesk && eesk) {
|
||||
} else if (eecs && ! eeprom->eesk && eesk) {
|
||||
/* Raising edge of clock shifts data in. */
|
||||
if (tick == 0) {
|
||||
/* Wait for 1st start bit. */
|
||||
@@ -230,20 +230,20 @@ void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi)
|
||||
if (command == 0) {
|
||||
/* Command code in upper 2 bits of address. */
|
||||
switch (address >> (eeprom->addrbits - 2)) {
|
||||
case 0:
|
||||
logout("write disable command\n");
|
||||
eeprom->writable = 0;
|
||||
break;
|
||||
case 1:
|
||||
logout("write all command\n");
|
||||
break;
|
||||
case 2:
|
||||
logout("erase all command\n");
|
||||
break;
|
||||
case 3:
|
||||
logout("write enable command\n");
|
||||
eeprom->writable = 1;
|
||||
break;
|
||||
case 0:
|
||||
logout("write disable command\n");
|
||||
eeprom->writable = 0;
|
||||
break;
|
||||
case 1:
|
||||
logout("write all command\n");
|
||||
break;
|
||||
case 2:
|
||||
logout("erase all command\n");
|
||||
break;
|
||||
case 3:
|
||||
logout("write enable command\n");
|
||||
eeprom->writable = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Read, write or erase word. */
|
||||
@@ -276,7 +276,7 @@ uint16_t eeprom93xx_read(eeprom_t *eeprom)
|
||||
{
|
||||
/* Return status of pin DO (0 or 1). */
|
||||
logout("CS=%u DO=%u\n", eeprom->eecs, eeprom->eedo);
|
||||
return eeprom->eedo;
|
||||
return (eeprom->eedo);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -296,18 +296,18 @@ eeprom_t *eeprom93xx_new(DeviceState *dev, uint16_t nwords)
|
||||
uint8_t addrbits;
|
||||
|
||||
switch (nwords) {
|
||||
case 16:
|
||||
case 64:
|
||||
addrbits = 6;
|
||||
break;
|
||||
case 128:
|
||||
case 256:
|
||||
addrbits = 8;
|
||||
break;
|
||||
default:
|
||||
assert(!"Unsupported EEPROM size, fallback to 64 words!");
|
||||
nwords = 64;
|
||||
addrbits = 6;
|
||||
case 16:
|
||||
case 64:
|
||||
addrbits = 6;
|
||||
break;
|
||||
case 128:
|
||||
case 256:
|
||||
addrbits = 8;
|
||||
break;
|
||||
default:
|
||||
assert(!"Unsupported EEPROM size, fallback to 64 words!");
|
||||
nwords = 64;
|
||||
addrbits = 6;
|
||||
}
|
||||
|
||||
eeprom = (eeprom_t *)g_malloc0(sizeof(*eeprom) + nwords * 2);
|
||||
|
@@ -103,8 +103,6 @@ struct PCII440FXState {
|
||||
MemoryRegion *system_memory;
|
||||
MemoryRegion *pci_address_space;
|
||||
MemoryRegion *ram_memory;
|
||||
MemoryRegion pci_hole;
|
||||
MemoryRegion pci_hole_64bit;
|
||||
PAMMemoryRegion pam_regions[13];
|
||||
MemoryRegion smram_region;
|
||||
uint8_t smm_enabled;
|
||||
@@ -313,8 +311,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
|
||||
MemoryRegion *address_space_mem,
|
||||
MemoryRegion *address_space_io,
|
||||
ram_addr_t ram_size,
|
||||
hwaddr pci_hole_start,
|
||||
hwaddr pci_hole_size,
|
||||
ram_addr_t below_4g_mem_size,
|
||||
ram_addr_t above_4g_mem_size,
|
||||
MemoryRegion *pci_address_space,
|
||||
MemoryRegion *ram_memory)
|
||||
@@ -327,7 +324,6 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
|
||||
PCII440FXState *f;
|
||||
unsigned i;
|
||||
I440FXState *i440fx;
|
||||
uint64_t pci_hole64_size;
|
||||
|
||||
dev = qdev_create(NULL, TYPE_I440FX_PCI_HOST_BRIDGE);
|
||||
s = PCI_HOST_BRIDGE(dev);
|
||||
@@ -345,33 +341,12 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
|
||||
f->ram_memory = ram_memory;
|
||||
|
||||
i440fx = I440FX_PCI_HOST_BRIDGE(dev);
|
||||
/* Set PCI window size the way seabios has always done it. */
|
||||
/* Power of 2 so bios can cover it with a single MTRR */
|
||||
if (ram_size <= 0x80000000) {
|
||||
i440fx->pci_info.w32.begin = 0x80000000;
|
||||
} else if (ram_size <= 0xc0000000) {
|
||||
i440fx->pci_info.w32.begin = 0xc0000000;
|
||||
} else {
|
||||
i440fx->pci_info.w32.begin = 0xe0000000;
|
||||
}
|
||||
i440fx->pci_info.w32.begin = below_4g_mem_size;
|
||||
|
||||
memory_region_init_alias(&f->pci_hole, OBJECT(d), "pci-hole", f->pci_address_space,
|
||||
pci_hole_start, pci_hole_size);
|
||||
memory_region_add_subregion(f->system_memory, pci_hole_start, &f->pci_hole);
|
||||
/* setup pci memory mapping */
|
||||
pc_pci_as_mapping_init(OBJECT(f), f->system_memory,
|
||||
f->pci_address_space);
|
||||
|
||||
pci_hole64_size = pci_host_get_hole64_size(i440fx->pci_hole64_size);
|
||||
|
||||
pc_init_pci64_hole(&i440fx->pci_info, 0x100000000ULL + above_4g_mem_size,
|
||||
pci_hole64_size);
|
||||
memory_region_init_alias(&f->pci_hole_64bit, OBJECT(d), "pci-hole64",
|
||||
f->pci_address_space,
|
||||
i440fx->pci_info.w64.begin,
|
||||
pci_hole64_size);
|
||||
if (pci_hole64_size) {
|
||||
memory_region_add_subregion(f->system_memory,
|
||||
i440fx->pci_info.w64.begin,
|
||||
&f->pci_hole_64bit);
|
||||
}
|
||||
memory_region_init_alias(&f->smram_region, OBJECT(d), "smram-region",
|
||||
f->pci_address_space, 0xa0000, 0x20000);
|
||||
memory_region_add_subregion_overlap(f->system_memory, 0xa0000,
|
||||
|
@@ -356,28 +356,11 @@ static int mch_init(PCIDevice *d)
|
||||
{
|
||||
int i;
|
||||
MCHPCIState *mch = MCH_PCI_DEVICE(d);
|
||||
uint64_t pci_hole64_size;
|
||||
|
||||
/* setup pci memory regions */
|
||||
memory_region_init_alias(&mch->pci_hole, OBJECT(mch), "pci-hole",
|
||||
mch->pci_address_space,
|
||||
mch->below_4g_mem_size,
|
||||
0x100000000ULL - mch->below_4g_mem_size);
|
||||
memory_region_add_subregion(mch->system_memory, mch->below_4g_mem_size,
|
||||
&mch->pci_hole);
|
||||
/* setup pci memory mapping */
|
||||
pc_pci_as_mapping_init(OBJECT(mch), mch->system_memory,
|
||||
mch->pci_address_space);
|
||||
|
||||
pci_hole64_size = pci_host_get_hole64_size(mch->pci_hole64_size);
|
||||
pc_init_pci64_hole(&mch->pci_info, 0x100000000ULL + mch->above_4g_mem_size,
|
||||
pci_hole64_size);
|
||||
memory_region_init_alias(&mch->pci_hole_64bit, OBJECT(mch), "pci-hole64",
|
||||
mch->pci_address_space,
|
||||
mch->pci_info.w64.begin,
|
||||
pci_hole64_size);
|
||||
if (pci_hole64_size) {
|
||||
memory_region_add_subregion(mch->system_memory,
|
||||
mch->pci_info.w64.begin,
|
||||
&mch->pci_hole_64bit);
|
||||
}
|
||||
/* smram */
|
||||
cpu_smm_register(&mch_set_smm, mch);
|
||||
memory_region_init_alias(&mch->smram_region, OBJECT(mch), "smram-region",
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#define MAX_CPUS 1
|
||||
|
||||
#define BIOS_SIZE (1024 * 1024)
|
||||
#define BIOS_FILENAME "ppc_rom.bin"
|
||||
#define NVRAM_SIZE 0x2000
|
||||
#define PROM_FILENAME "openbios-ppc"
|
||||
#define PROM_ADDR 0xfff00000
|
||||
|
@@ -684,7 +684,7 @@ static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
|
||||
}
|
||||
|
||||
static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
|
||||
QEMUTimer *timer,
|
||||
struct QEMUTimer *timer,
|
||||
void (*raise_excp)(PowerPCCPU *),
|
||||
uint32_t decr, uint32_t value,
|
||||
int is_excp)
|
||||
@@ -856,9 +856,9 @@ typedef struct ppc40x_timer_t ppc40x_timer_t;
|
||||
struct ppc40x_timer_t {
|
||||
uint64_t pit_reload; /* PIT auto-reload value */
|
||||
uint64_t fit_next; /* Tick for next FIT interrupt */
|
||||
QEMUTimer *fit_timer;
|
||||
struct QEMUTimer *fit_timer;
|
||||
uint64_t wdt_next; /* Tick for next WDT interrupt */
|
||||
QEMUTimer *wdt_timer;
|
||||
struct QEMUTimer *wdt_timer;
|
||||
|
||||
/* 405 have the PIT, 440 have a DECR. */
|
||||
unsigned int decr_excp;
|
||||
|
@@ -1234,7 +1234,7 @@ struct ppc4xx_gpt_t {
|
||||
MemoryRegion iomem;
|
||||
int64_t tb_offset;
|
||||
uint32_t tb_freq;
|
||||
QEMUTimer *timer;
|
||||
struct QEMUTimer *timer;
|
||||
qemu_irq irqs[5];
|
||||
uint32_t oe;
|
||||
uint32_t ol;
|
||||
|
@@ -64,10 +64,10 @@ typedef struct booke_timer_t booke_timer_t;
|
||||
struct booke_timer_t {
|
||||
|
||||
uint64_t fit_next;
|
||||
QEMUTimer *fit_timer;
|
||||
struct QEMUTimer *fit_timer;
|
||||
|
||||
uint64_t wdt_next;
|
||||
QEMUTimer *wdt_timer;
|
||||
struct QEMUTimer *wdt_timer;
|
||||
|
||||
uint32_t flags;
|
||||
};
|
||||
|
@@ -57,9 +57,10 @@ static const TypeInfo virtual_css_bus_info = {
|
||||
VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch)
|
||||
{
|
||||
VirtIODevice *vdev = NULL;
|
||||
VirtioCcwDevice *dev = sch->driver_data;
|
||||
|
||||
if (sch->driver_data) {
|
||||
vdev = ((VirtioCcwDevice *)sch->driver_data)->vdev;
|
||||
if (dev) {
|
||||
vdev = virtio_bus_get_device(&dev->bus);
|
||||
}
|
||||
return vdev;
|
||||
}
|
||||
@@ -67,7 +68,8 @@ VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch)
|
||||
static int virtio_ccw_set_guest2host_notifier(VirtioCcwDevice *dev, int n,
|
||||
bool assign, bool set_handler)
|
||||
{
|
||||
VirtQueue *vq = virtio_get_queue(dev->vdev, n);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
|
||||
VirtQueue *vq = virtio_get_queue(vdev, n);
|
||||
EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
|
||||
int r = 0;
|
||||
SubchDev *sch = dev->sch;
|
||||
@@ -97,6 +99,7 @@ static int virtio_ccw_set_guest2host_notifier(VirtioCcwDevice *dev, int n,
|
||||
|
||||
static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev)
|
||||
{
|
||||
VirtIODevice *vdev;
|
||||
int n, r;
|
||||
|
||||
if (!(dev->flags & VIRTIO_CCW_FLAG_USE_IOEVENTFD) ||
|
||||
@@ -104,8 +107,9 @@ static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev)
|
||||
dev->ioeventfd_started) {
|
||||
return;
|
||||
}
|
||||
vdev = virtio_bus_get_device(&dev->bus);
|
||||
for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
|
||||
if (!virtio_queue_get_num(dev->vdev, n)) {
|
||||
if (!virtio_queue_get_num(vdev, n)) {
|
||||
continue;
|
||||
}
|
||||
r = virtio_ccw_set_guest2host_notifier(dev, n, true, true);
|
||||
@@ -118,7 +122,7 @@ static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev)
|
||||
|
||||
assign_error:
|
||||
while (--n >= 0) {
|
||||
if (!virtio_queue_get_num(dev->vdev, n)) {
|
||||
if (!virtio_queue_get_num(vdev, n)) {
|
||||
continue;
|
||||
}
|
||||
r = virtio_ccw_set_guest2host_notifier(dev, n, false, false);
|
||||
@@ -132,13 +136,15 @@ static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev)
|
||||
|
||||
static void virtio_ccw_stop_ioeventfd(VirtioCcwDevice *dev)
|
||||
{
|
||||
VirtIODevice *vdev;
|
||||
int n, r;
|
||||
|
||||
if (!dev->ioeventfd_started) {
|
||||
return;
|
||||
}
|
||||
vdev = virtio_bus_get_device(&dev->bus);
|
||||
for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
|
||||
if (!virtio_queue_get_num(dev->vdev, n)) {
|
||||
if (!virtio_queue_get_num(vdev, n)) {
|
||||
continue;
|
||||
}
|
||||
r = virtio_ccw_set_guest2host_notifier(dev, n, false, false);
|
||||
@@ -189,7 +195,7 @@ typedef struct VirtioFeatDesc {
|
||||
static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
|
||||
uint16_t index, uint16_t num)
|
||||
{
|
||||
VirtioCcwDevice *dev = sch->driver_data;
|
||||
VirtIODevice *vdev = virtio_ccw_get_vdev(sch);
|
||||
|
||||
if (index > VIRTIO_PCI_QUEUE_MAX) {
|
||||
return -EINVAL;
|
||||
@@ -200,23 +206,23 @@ static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!dev) {
|
||||
if (!vdev) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
virtio_queue_set_addr(dev->vdev, index, addr);
|
||||
virtio_queue_set_addr(vdev, index, addr);
|
||||
if (!addr) {
|
||||
virtio_queue_set_vector(dev->vdev, index, 0);
|
||||
virtio_queue_set_vector(vdev, index, 0);
|
||||
} else {
|
||||
/* Fail if we don't have a big enough queue. */
|
||||
/* TODO: Add interface to handle vring.num changing */
|
||||
if (virtio_queue_get_num(dev->vdev, index) > num) {
|
||||
if (virtio_queue_get_num(vdev, index) > num) {
|
||||
return -EINVAL;
|
||||
}
|
||||
virtio_queue_set_vector(dev->vdev, index, index);
|
||||
virtio_queue_set_vector(vdev, index, index);
|
||||
}
|
||||
/* tell notify handler in case of config change */
|
||||
dev->vdev->config_vector = VIRTIO_PCI_QUEUE_MAX;
|
||||
vdev->config_vector = VIRTIO_PCI_QUEUE_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -230,6 +236,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
hwaddr indicators;
|
||||
VqConfigBlock vq_config;
|
||||
VirtioCcwDevice *dev = sch->driver_data;
|
||||
VirtIODevice *vdev = virtio_ccw_get_vdev(sch);
|
||||
bool check_len;
|
||||
int len;
|
||||
hwaddr hw_len;
|
||||
@@ -272,7 +279,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
break;
|
||||
case CCW_CMD_VDEV_RESET:
|
||||
virtio_ccw_stop_ioeventfd(dev);
|
||||
virtio_reset(dev->vdev);
|
||||
virtio_reset(vdev);
|
||||
ret = 0;
|
||||
break;
|
||||
case CCW_CMD_READ_FEAT:
|
||||
@@ -319,7 +326,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
features.features = ldl_le_phys(ccw.cda);
|
||||
if (features.index < ARRAY_SIZE(dev->host_features)) {
|
||||
virtio_bus_set_vdev_features(&dev->bus, features.features);
|
||||
dev->vdev->guest_features = features.features;
|
||||
vdev->guest_features = features.features;
|
||||
} else {
|
||||
/*
|
||||
* If the guest supports more feature bits, assert that it
|
||||
@@ -337,30 +344,30 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
break;
|
||||
case CCW_CMD_READ_CONF:
|
||||
if (check_len) {
|
||||
if (ccw.count > dev->vdev->config_len) {
|
||||
if (ccw.count > vdev->config_len) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
len = MIN(ccw.count, dev->vdev->config_len);
|
||||
len = MIN(ccw.count, vdev->config_len);
|
||||
if (!ccw.cda) {
|
||||
ret = -EFAULT;
|
||||
} else {
|
||||
virtio_bus_get_vdev_config(&dev->bus, dev->vdev->config);
|
||||
virtio_bus_get_vdev_config(&dev->bus, vdev->config);
|
||||
/* XXX config space endianness */
|
||||
cpu_physical_memory_write(ccw.cda, dev->vdev->config, len);
|
||||
cpu_physical_memory_write(ccw.cda, vdev->config, len);
|
||||
sch->curr_status.scsw.count = ccw.count - len;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case CCW_CMD_WRITE_CONF:
|
||||
if (check_len) {
|
||||
if (ccw.count > dev->vdev->config_len) {
|
||||
if (ccw.count > vdev->config_len) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
len = MIN(ccw.count, dev->vdev->config_len);
|
||||
len = MIN(ccw.count, vdev->config_len);
|
||||
hw_len = len;
|
||||
if (!ccw.cda) {
|
||||
ret = -EFAULT;
|
||||
@@ -371,9 +378,9 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
} else {
|
||||
len = hw_len;
|
||||
/* XXX config space endianness */
|
||||
memcpy(dev->vdev->config, config, len);
|
||||
memcpy(vdev->config, config, len);
|
||||
cpu_physical_memory_unmap(config, hw_len, 0, hw_len);
|
||||
virtio_bus_set_vdev_config(&dev->bus, dev->vdev->config);
|
||||
virtio_bus_set_vdev_config(&dev->bus, vdev->config);
|
||||
sch->curr_status.scsw.count = ccw.count - len;
|
||||
ret = 0;
|
||||
}
|
||||
@@ -397,9 +404,9 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
|
||||
virtio_ccw_stop_ioeventfd(dev);
|
||||
}
|
||||
virtio_set_status(dev->vdev, status);
|
||||
if (dev->vdev->status == 0) {
|
||||
virtio_reset(dev->vdev);
|
||||
virtio_set_status(vdev, status);
|
||||
if (vdev->status == 0) {
|
||||
virtio_reset(vdev);
|
||||
}
|
||||
if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
|
||||
virtio_ccw_start_ioeventfd(dev);
|
||||
@@ -463,7 +470,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
ret = -EFAULT;
|
||||
} else {
|
||||
vq_config.index = lduw_phys(ccw.cda);
|
||||
vq_config.num_max = virtio_queue_get_num(dev->vdev,
|
||||
vq_config.num_max = virtio_queue_get_num(vdev,
|
||||
vq_config.index);
|
||||
stw_phys(ccw.cda + sizeof(vq_config.index), vq_config.num_max);
|
||||
sch->curr_status.scsw.count = ccw.count - sizeof(vq_config);
|
||||
@@ -495,7 +502,6 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
|
||||
sch->driver_data = dev;
|
||||
dev->sch = sch;
|
||||
|
||||
dev->vdev = vdev;
|
||||
dev->indicators = 0;
|
||||
|
||||
/* Initialize subchannel structure. */
|
||||
@@ -608,7 +614,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
|
||||
memset(&sch->id, 0, sizeof(SenseId));
|
||||
sch->id.reserved = 0xff;
|
||||
sch->id.cu_type = VIRTIO_CCW_CU_TYPE;
|
||||
sch->id.cu_model = dev->vdev->device_id;
|
||||
sch->id.cu_model = vdev->device_id;
|
||||
|
||||
/* Only the first 32 feature bits are used. */
|
||||
dev->host_features[0] = virtio_bus_get_vdev_features(&dev->bus,
|
||||
@@ -631,7 +637,6 @@ static int virtio_ccw_exit(VirtioCcwDevice *dev)
|
||||
{
|
||||
SubchDev *sch = dev->sch;
|
||||
|
||||
virtio_ccw_stop_ioeventfd(dev);
|
||||
if (sch) {
|
||||
css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
|
||||
g_free(sch);
|
||||
@@ -892,9 +897,10 @@ static unsigned virtio_ccw_get_features(DeviceState *d)
|
||||
static void virtio_ccw_reset(DeviceState *d)
|
||||
{
|
||||
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
|
||||
|
||||
virtio_ccw_stop_ioeventfd(dev);
|
||||
virtio_reset(dev->vdev);
|
||||
virtio_reset(vdev);
|
||||
css_reset_sch(dev->sch);
|
||||
dev->indicators = 0;
|
||||
dev->indicators2 = 0;
|
||||
@@ -934,9 +940,10 @@ static int virtio_ccw_set_host_notifier(DeviceState *d, int n, bool assign)
|
||||
static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n,
|
||||
bool assign, bool with_irqfd)
|
||||
{
|
||||
VirtQueue *vq = virtio_get_queue(dev->vdev, n);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
|
||||
VirtQueue *vq = virtio_get_queue(vdev, n);
|
||||
EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
|
||||
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(dev->vdev);
|
||||
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
|
||||
if (assign) {
|
||||
int r = event_notifier_init(notifier, 0);
|
||||
@@ -952,16 +959,16 @@ static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n,
|
||||
* land in qemu (and only the irq fd) in this code.
|
||||
*/
|
||||
if (k->guest_notifier_mask) {
|
||||
k->guest_notifier_mask(dev->vdev, n, false);
|
||||
k->guest_notifier_mask(vdev, n, false);
|
||||
}
|
||||
/* get lost events and re-inject */
|
||||
if (k->guest_notifier_pending &&
|
||||
k->guest_notifier_pending(dev->vdev, n)) {
|
||||
k->guest_notifier_pending(vdev, n)) {
|
||||
event_notifier_set(notifier);
|
||||
}
|
||||
} else {
|
||||
if (k->guest_notifier_mask) {
|
||||
k->guest_notifier_mask(dev->vdev, n, true);
|
||||
k->guest_notifier_mask(vdev, n, true);
|
||||
}
|
||||
virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
|
||||
event_notifier_cleanup(notifier);
|
||||
@@ -973,7 +980,7 @@ static int virtio_ccw_set_guest_notifiers(DeviceState *d, int nvqs,
|
||||
bool assigned)
|
||||
{
|
||||
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
|
||||
VirtIODevice *vdev = dev->vdev;
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
|
||||
int r, n;
|
||||
|
||||
for (n = 0; n < nvqs; n++) {
|
||||
@@ -1228,6 +1235,8 @@ static int virtio_ccw_busdev_unplug(DeviceState *dev)
|
||||
VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
|
||||
SubchDev *sch = _dev->sch;
|
||||
|
||||
virtio_ccw_stop_ioeventfd(_dev);
|
||||
|
||||
/*
|
||||
* We should arrive here only for device_del, since we don't support
|
||||
* direct hot(un)plug of channels, but only through virtio.
|
||||
|
@@ -77,7 +77,6 @@ typedef struct VirtIOCCWDeviceClass {
|
||||
struct VirtioCcwDevice {
|
||||
DeviceState parent_obj;
|
||||
SubchDev *sch;
|
||||
VirtIODevice *vdev;
|
||||
char *bus_id;
|
||||
uint32_t host_features[VIRTIO_CCW_FEATURE_SIZE];
|
||||
VirtioBusState bus;
|
||||
|
@@ -469,6 +469,8 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
|
||||
r->req.dev->sense_is_ua = false;
|
||||
}
|
||||
break;
|
||||
case TEST_UNIT_READY:
|
||||
break;
|
||||
default:
|
||||
scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED));
|
||||
scsi_req_complete(req, CHECK_CONDITION);
|
||||
@@ -886,7 +888,6 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
case RELEASE:
|
||||
case ERASE:
|
||||
case ALLOW_MEDIUM_REMOVAL:
|
||||
case VERIFY_10:
|
||||
case SEEK_10:
|
||||
case SYNCHRONIZE_CACHE:
|
||||
case SYNCHRONIZE_CACHE_16:
|
||||
@@ -903,6 +904,16 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
case ALLOW_OVERWRITE:
|
||||
cmd->xfer = 0;
|
||||
break;
|
||||
case VERIFY_10:
|
||||
case VERIFY_12:
|
||||
case VERIFY_16:
|
||||
if ((buf[1] & 2) == 0) {
|
||||
cmd->xfer = 0;
|
||||
} else if ((buf[1] & 4) == 1) {
|
||||
cmd->xfer = 1;
|
||||
}
|
||||
cmd->xfer *= dev->blocksize;
|
||||
break;
|
||||
case MODE_SENSE:
|
||||
break;
|
||||
case WRITE_SAME_10:
|
||||
@@ -1100,6 +1111,9 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd)
|
||||
case WRITE_VERIFY_12:
|
||||
case WRITE_16:
|
||||
case WRITE_VERIFY_16:
|
||||
case VERIFY_10:
|
||||
case VERIFY_12:
|
||||
case VERIFY_16:
|
||||
case COPY:
|
||||
case COPY_VERIFY:
|
||||
case COMPARE:
|
||||
@@ -1293,11 +1307,6 @@ const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
|
||||
.key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02
|
||||
};
|
||||
|
||||
/* Illegal request, Invalid Transfer Tag */
|
||||
const struct SCSISense sense_code_INVALID_TAG = {
|
||||
.key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01
|
||||
};
|
||||
|
||||
/* Command aborted, I/O process terminated */
|
||||
const struct SCSISense sense_code_IO_ERROR = {
|
||||
.key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
|
||||
@@ -1313,11 +1322,6 @@ const struct SCSISense sense_code_LUN_FAILURE = {
|
||||
.key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
|
||||
};
|
||||
|
||||
/* Command aborted, Overlapped Commands Attempted */
|
||||
const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
|
||||
.key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* Unit attention, Capacity data has changed */
|
||||
const struct SCSISense sense_code_CAPACITY_CHANGED = {
|
||||
.key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
|
||||
|
@@ -41,7 +41,6 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
|
||||
#include <scsi/sg.h>
|
||||
#endif
|
||||
|
||||
#define SCSI_WRITE_SAME_MAX 524288
|
||||
#define SCSI_DMA_BUF_SIZE 131072
|
||||
#define SCSI_MAX_INQUIRY_LEN 256
|
||||
#define SCSI_MAX_MODE_LEN 256
|
||||
@@ -635,8 +634,6 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
||||
buflen = 0x40;
|
||||
memset(outbuf + 4, 0, buflen - 4);
|
||||
|
||||
outbuf[4] = 0x1; /* wsnz */
|
||||
|
||||
/* optimal transfer length granularity */
|
||||
outbuf[6] = (min_io_size >> 8) & 0xff;
|
||||
outbuf[7] = min_io_size & 0xff;
|
||||
@@ -1546,16 +1543,10 @@ done:
|
||||
|
||||
static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
|
||||
{
|
||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||
uint8_t *p = inbuf;
|
||||
int len = r->req.cmd.xfer;
|
||||
UnmapCBData *data;
|
||||
|
||||
/* Reject ANCHOR=1. */
|
||||
if (r->req.cmd.buf[1] & 0x1) {
|
||||
goto invalid_field;
|
||||
}
|
||||
|
||||
if (len < 8) {
|
||||
goto invalid_param_len;
|
||||
}
|
||||
@@ -1569,11 +1560,6 @@ static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
|
||||
goto invalid_param_len;
|
||||
}
|
||||
|
||||
if (bdrv_is_read_only(s->qdev.conf.bs)) {
|
||||
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
|
||||
return;
|
||||
}
|
||||
|
||||
data = g_new0(UnmapCBData, 1);
|
||||
data->r = r;
|
||||
data->inbuf = &p[8];
|
||||
@@ -1586,115 +1572,6 @@ static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
|
||||
|
||||
invalid_param_len:
|
||||
scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
|
||||
return;
|
||||
|
||||
invalid_field:
|
||||
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
|
||||
}
|
||||
|
||||
typedef struct WriteSameCBData {
|
||||
SCSIDiskReq *r;
|
||||
int64_t sector;
|
||||
int nb_sectors;
|
||||
QEMUIOVector qiov;
|
||||
struct iovec iov;
|
||||
} WriteSameCBData;
|
||||
|
||||
static void scsi_write_same_complete(void *opaque, int ret)
|
||||
{
|
||||
WriteSameCBData *data = opaque;
|
||||
SCSIDiskReq *r = data->r;
|
||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||
|
||||
assert(r->req.aiocb != NULL);
|
||||
r->req.aiocb = NULL;
|
||||
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
|
||||
if (r->req.io_canceled) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (scsi_handle_rw_error(r, -ret)) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
data->nb_sectors -= data->iov.iov_len / 512;
|
||||
data->sector += data->iov.iov_len / 512;
|
||||
data->iov.iov_len = MIN(data->nb_sectors * 512, data->iov.iov_len);
|
||||
if (data->iov.iov_len) {
|
||||
bdrv_acct_start(s->qdev.conf.bs, &r->acct, data->iov.iov_len, BDRV_ACCT_WRITE);
|
||||
r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, data->sector,
|
||||
&data->qiov, data->iov.iov_len / 512,
|
||||
scsi_write_same_complete, r);
|
||||
return;
|
||||
}
|
||||
|
||||
scsi_req_complete(&r->req, GOOD);
|
||||
|
||||
done:
|
||||
if (!r->req.io_canceled) {
|
||||
scsi_req_unref(&r->req);
|
||||
}
|
||||
qemu_vfree(data->iov.iov_base);
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
|
||||
{
|
||||
SCSIRequest *req = &r->req;
|
||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
||||
uint32_t nb_sectors = scsi_data_cdb_length(r->req.cmd.buf);
|
||||
WriteSameCBData *data;
|
||||
uint8_t *buf;
|
||||
int i;
|
||||
|
||||
/* Fail if PBDATA=1 or LBDATA=1 or ANCHOR=1. */
|
||||
if (nb_sectors == 0 || (req->cmd.buf[1] & 0x16)) {
|
||||
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_is_read_only(s->qdev.conf.bs)) {
|
||||
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
|
||||
return;
|
||||
}
|
||||
if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) {
|
||||
scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer_is_zero(inbuf, s->qdev.blocksize)) {
|
||||
int flags = (req->cmd.buf[1] & 0x8) ? BDRV_REQ_MAY_UNMAP : 0;
|
||||
|
||||
/* The request is used as the AIO opaque value, so add a ref. */
|
||||
scsi_req_ref(&r->req);
|
||||
bdrv_acct_start(s->qdev.conf.bs, &r->acct, nb_sectors * s->qdev.blocksize,
|
||||
BDRV_ACCT_WRITE);
|
||||
r->req.aiocb = bdrv_aio_write_zeroes(s->qdev.conf.bs,
|
||||
r->req.cmd.lba * (s->qdev.blocksize / 512),
|
||||
nb_sectors * (s->qdev.blocksize / 512),
|
||||
flags, scsi_aio_complete, r);
|
||||
return;
|
||||
}
|
||||
|
||||
data = g_new0(WriteSameCBData, 1);
|
||||
data->r = r;
|
||||
data->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
|
||||
data->nb_sectors = nb_sectors * (s->qdev.blocksize / 512);
|
||||
data->iov.iov_len = MIN(data->nb_sectors * 512, SCSI_WRITE_SAME_MAX);
|
||||
data->iov.iov_base = buf = qemu_blockalign(s->qdev.conf.bs, data->iov.iov_len);
|
||||
qemu_iovec_init_external(&data->qiov, &data->iov, 1);
|
||||
|
||||
for (i = 0; i < data->iov.iov_len; i += s->qdev.blocksize) {
|
||||
memcpy(&buf[i], inbuf, s->qdev.blocksize);
|
||||
}
|
||||
|
||||
scsi_req_ref(&r->req);
|
||||
bdrv_acct_start(s->qdev.conf.bs, &r->acct, data->iov.iov_len, BDRV_ACCT_WRITE);
|
||||
r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, data->sector,
|
||||
&data->qiov, data->iov.iov_len / 512,
|
||||
scsi_write_same_complete, data);
|
||||
}
|
||||
|
||||
static void scsi_disk_emulate_write_data(SCSIRequest *req)
|
||||
@@ -1720,10 +1597,14 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req)
|
||||
scsi_disk_emulate_unmap(r, r->iov.iov_base);
|
||||
break;
|
||||
|
||||
case WRITE_SAME_10:
|
||||
case WRITE_SAME_16:
|
||||
scsi_disk_emulate_write_same(r, r->iov.iov_base);
|
||||
case VERIFY_10:
|
||||
case VERIFY_12:
|
||||
case VERIFY_16:
|
||||
if (r->req.status == -1) {
|
||||
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
@@ -1964,12 +1845,39 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
|
||||
case UNMAP:
|
||||
DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer);
|
||||
break;
|
||||
case VERIFY_10:
|
||||
case VERIFY_12:
|
||||
case VERIFY_16:
|
||||
DPRINTF("Verify (bytchk %lu)\n", (r->req.buf[1] >> 1) & 3);
|
||||
if (req->cmd.buf[1] & 6) {
|
||||
goto illegal_request;
|
||||
}
|
||||
break;
|
||||
case WRITE_SAME_10:
|
||||
case WRITE_SAME_16:
|
||||
DPRINTF("WRITE SAME %d (len %lu)\n",
|
||||
req->cmd.buf[0] == WRITE_SAME_10 ? 10 : 16,
|
||||
(long)r->req.cmd.xfer);
|
||||
break;
|
||||
nb_sectors = scsi_data_cdb_length(r->req.cmd.buf);
|
||||
if (bdrv_is_read_only(s->qdev.conf.bs)) {
|
||||
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
|
||||
return 0;
|
||||
}
|
||||
if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) {
|
||||
goto illegal_lba;
|
||||
}
|
||||
|
||||
/*
|
||||
* We only support WRITE SAME with the unmap bit set for now.
|
||||
*/
|
||||
if (!(req->cmd.buf[1] & 0x8)) {
|
||||
goto illegal_request;
|
||||
}
|
||||
|
||||
/* The request is used as the AIO opaque value, so add a ref. */
|
||||
scsi_req_ref(&r->req);
|
||||
r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs,
|
||||
r->req.cmd.lba * (s->qdev.blocksize / 512),
|
||||
nb_sectors * (s->qdev.blocksize / 512),
|
||||
scsi_aio_complete, r);
|
||||
return 0;
|
||||
default:
|
||||
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
|
||||
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
|
||||
@@ -2044,10 +1952,6 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
|
||||
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
|
||||
return 0;
|
||||
}
|
||||
/* fallthrough */
|
||||
case VERIFY_10:
|
||||
case VERIFY_12:
|
||||
case VERIFY_16:
|
||||
DPRINTF("Write %s(sector %" PRId64 ", count %u)\n",
|
||||
(command & 0xe) == 0xe ? "And Verify " : "",
|
||||
r->req.cmd.lba, len);
|
||||
@@ -2277,6 +2181,7 @@ static const SCSIReqOps scsi_disk_emulate_reqops = {
|
||||
.send_command = scsi_disk_emulate_command,
|
||||
.read_data = scsi_disk_emulate_read_data,
|
||||
.write_data = scsi_disk_emulate_write_data,
|
||||
.cancel_io = scsi_cancel_io,
|
||||
.get_buf = scsi_get_buf,
|
||||
};
|
||||
|
||||
@@ -2315,14 +2220,14 @@ static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
|
||||
[UNMAP] = &scsi_disk_emulate_reqops,
|
||||
[WRITE_SAME_10] = &scsi_disk_emulate_reqops,
|
||||
[WRITE_SAME_16] = &scsi_disk_emulate_reqops,
|
||||
[VERIFY_10] = &scsi_disk_emulate_reqops,
|
||||
[VERIFY_12] = &scsi_disk_emulate_reqops,
|
||||
[VERIFY_16] = &scsi_disk_emulate_reqops,
|
||||
|
||||
[READ_6] = &scsi_disk_dma_reqops,
|
||||
[READ_10] = &scsi_disk_dma_reqops,
|
||||
[READ_12] = &scsi_disk_dma_reqops,
|
||||
[READ_16] = &scsi_disk_dma_reqops,
|
||||
[VERIFY_10] = &scsi_disk_dma_reqops,
|
||||
[VERIFY_12] = &scsi_disk_dma_reqops,
|
||||
[VERIFY_16] = &scsi_disk_dma_reqops,
|
||||
[WRITE_6] = &scsi_disk_dma_reqops,
|
||||
[WRITE_10] = &scsi_disk_dma_reqops,
|
||||
[WRITE_12] = &scsi_disk_dma_reqops,
|
||||
|
@@ -240,11 +240,10 @@ static int vhost_scsi_init(VirtIODevice *vdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vhost_scsi_exit(DeviceState *qdev)
|
||||
static void vhost_scsi_exit(VirtIODevice *vdev)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
|
||||
VHostSCSI *s = VHOST_SCSI(qdev);
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(qdev);
|
||||
VHostSCSI *s = VHOST_SCSI(vdev);
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
|
||||
|
||||
migrate_del_blocker(s->migration_blocker);
|
||||
error_free(s->migration_blocker);
|
||||
@@ -253,7 +252,7 @@ static int vhost_scsi_exit(DeviceState *qdev)
|
||||
vhost_scsi_set_status(vdev, 0);
|
||||
|
||||
g_free(s->dev.vqs);
|
||||
return virtio_scsi_common_exit(vs);
|
||||
virtio_scsi_common_exit(vs);
|
||||
}
|
||||
|
||||
static Property vhost_scsi_properties[] = {
|
||||
@@ -265,10 +264,10 @@ static void vhost_scsi_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||
dc->exit = vhost_scsi_exit;
|
||||
dc->props = vhost_scsi_properties;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
vdc->init = vhost_scsi_init;
|
||||
vdc->exit = vhost_scsi_exit;
|
||||
vdc->get_features = vhost_scsi_get_features;
|
||||
vdc->set_config = vhost_scsi_set_config;
|
||||
vdc->set_status = vhost_scsi_set_status;
|
||||
|
@@ -306,6 +306,10 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
|
||||
VirtIOSCSIReq *req = r->hba_private;
|
||||
uint32_t sense_len;
|
||||
|
||||
if (r->io_canceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
req->resp.cmd->response = VIRTIO_SCSI_S_OK;
|
||||
req->resp.cmd->status = status;
|
||||
if (req->resp.cmd->status == GOOD) {
|
||||
@@ -516,7 +520,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
|
||||
evt->event = event;
|
||||
evt->reason = reason;
|
||||
if (!dev) {
|
||||
assert(event == VIRTIO_SCSI_T_NO_EVENT);
|
||||
assert(event == VIRTIO_SCSI_T_EVENTS_MISSED);
|
||||
} else {
|
||||
evt->lun[0] = 1;
|
||||
evt->lun[1] = dev->id;
|
||||
@@ -644,22 +648,21 @@ static int virtio_scsi_device_init(VirtIODevice *vdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int virtio_scsi_common_exit(VirtIOSCSICommon *vs)
|
||||
void virtio_scsi_common_exit(VirtIOSCSICommon *vs)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(vs);
|
||||
|
||||
g_free(vs->cmd_vqs);
|
||||
virtio_cleanup(vdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_scsi_device_exit(DeviceState *qdev)
|
||||
static void virtio_scsi_device_exit(VirtIODevice *vdev)
|
||||
{
|
||||
VirtIOSCSI *s = VIRTIO_SCSI(qdev);
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(qdev);
|
||||
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
|
||||
|
||||
unregister_savevm(qdev, "virtio-scsi", s);
|
||||
return virtio_scsi_common_exit(vs);
|
||||
unregister_savevm(DEVICE(vdev), "virtio-scsi", s);
|
||||
virtio_scsi_common_exit(vs);
|
||||
}
|
||||
|
||||
static Property virtio_scsi_properties[] = {
|
||||
@@ -680,10 +683,10 @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||
dc->exit = virtio_scsi_device_exit;
|
||||
dc->props = virtio_scsi_properties;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
vdc->init = virtio_scsi_device_init;
|
||||
vdc->exit = virtio_scsi_device_exit;
|
||||
vdc->set_config = virtio_scsi_set_config;
|
||||
vdc->get_features = virtio_scsi_get_features;
|
||||
vdc->reset = virtio_scsi_reset;
|
||||
|
@@ -320,6 +320,7 @@ static uint64_t icp_pit_read(void *opaque, hwaddr offset,
|
||||
n = offset >> 8;
|
||||
if (n > 2) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return arm_timer_read(s->timer[n], offset & 0xff);
|
||||
@@ -334,6 +335,7 @@ static void icp_pit_write(void *opaque, hwaddr offset,
|
||||
n = offset >> 8;
|
||||
if (n > 2) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
|
||||
return;
|
||||
}
|
||||
|
||||
arm_timer_write(s->timer[n], offset & 0xff, value);
|
||||
|
@@ -42,7 +42,6 @@
|
||||
|
||||
#define HPET_MSI_SUPPORT 0
|
||||
|
||||
#define TYPE_HPET "hpet"
|
||||
#define HPET(obj) OBJECT_CHECK(HPETState, (obj), TYPE_HPET)
|
||||
|
||||
struct HPETState;
|
||||
@@ -757,11 +756,6 @@ static void hpet_device_class_init(ObjectClass *klass, void *data)
|
||||
dc->props = hpet_device_properties;
|
||||
}
|
||||
|
||||
bool hpet_find(void)
|
||||
{
|
||||
return object_resolve_path_type("", TYPE_HPET, NULL);
|
||||
}
|
||||
|
||||
static const TypeInfo hpet_device_info = {
|
||||
.name = TYPE_HPET,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
|
@@ -61,8 +61,8 @@ struct M48t59State {
|
||||
time_t stop_time;
|
||||
/* Alarm & watchdog */
|
||||
struct tm alarm;
|
||||
QEMUTimer *alrm_timer;
|
||||
QEMUTimer *wd_timer;
|
||||
struct QEMUTimer *alrm_timer;
|
||||
struct QEMUTimer *wd_timer;
|
||||
/* NVRAM storage */
|
||||
uint8_t *buffer;
|
||||
/* Model parameters */
|
||||
|
18
hw/usb/bus.c
18
hw/usb/bus.c
@@ -203,24 +203,6 @@ void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep)
|
||||
}
|
||||
}
|
||||
|
||||
int usb_device_alloc_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps,
|
||||
int streams)
|
||||
{
|
||||
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->alloc_streams) {
|
||||
return klass->alloc_streams(dev, eps, nr_eps, streams);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usb_device_free_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps)
|
||||
{
|
||||
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->free_streams) {
|
||||
klass->free_streams(dev, eps, nr_eps);
|
||||
}
|
||||
}
|
||||
|
||||
static int usb_qdev_init(DeviceState *qdev)
|
||||
{
|
||||
USBDevice *dev = USB_DEVICE(qdev);
|
||||
|
@@ -623,7 +623,6 @@ void usb_ep_reset(USBDevice *dev)
|
||||
dev->ep_ctl.type = USB_ENDPOINT_XFER_CONTROL;
|
||||
dev->ep_ctl.ifnum = 0;
|
||||
dev->ep_ctl.max_packet_size = 64;
|
||||
dev->ep_ctl.max_streams = 0;
|
||||
dev->ep_ctl.dev = dev;
|
||||
dev->ep_ctl.pipeline = false;
|
||||
for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
|
||||
@@ -637,8 +636,6 @@ void usb_ep_reset(USBDevice *dev)
|
||||
dev->ep_out[ep].ifnum = USB_INTERFACE_INVALID;
|
||||
dev->ep_in[ep].max_packet_size = 0;
|
||||
dev->ep_out[ep].max_packet_size = 0;
|
||||
dev->ep_in[ep].max_streams = 0;
|
||||
dev->ep_out[ep].max_streams = 0;
|
||||
dev->ep_in[ep].dev = dev;
|
||||
dev->ep_out[ep].dev = dev;
|
||||
dev->ep_in[ep].pipeline = false;
|
||||
@@ -767,25 +764,6 @@ int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep)
|
||||
return uep->max_packet_size;
|
||||
}
|
||||
|
||||
void usb_ep_set_max_streams(USBDevice *dev, int pid, int ep, uint8_t raw)
|
||||
{
|
||||
struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
|
||||
int MaxStreams;
|
||||
|
||||
MaxStreams = raw & 0x1f;
|
||||
if (MaxStreams) {
|
||||
uep->max_streams = 1 << MaxStreams;
|
||||
} else {
|
||||
uep->max_streams = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int usb_ep_get_max_streams(USBDevice *dev, int pid, int ep)
|
||||
{
|
||||
struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
|
||||
return uep->max_streams;
|
||||
}
|
||||
|
||||
void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled)
|
||||
{
|
||||
struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
|
||||
|
@@ -6,6 +6,16 @@
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static uint8_t usb_lo(uint16_t val)
|
||||
{
|
||||
return val & 0xff;
|
||||
}
|
||||
|
||||
static uint8_t usb_hi(uint16_t val)
|
||||
{
|
||||
return (val >> 8) & 0xff;
|
||||
}
|
||||
|
||||
int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
|
||||
uint8_t *dest, size_t len)
|
||||
{
|
||||
@@ -375,8 +385,6 @@ static void usb_desc_ep_init(USBDevice *dev)
|
||||
usb_ep_set_ifnum(dev, pid, ep, iface->bInterfaceNumber);
|
||||
usb_ep_set_max_packet_size(dev, pid, ep,
|
||||
iface->eps[e].wMaxPacketSize);
|
||||
usb_ep_set_max_streams(dev, pid, ep,
|
||||
iface->eps[e].bmAttributes_super);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -194,17 +194,6 @@ struct USBDesc {
|
||||
|
||||
#define USB_DESC_FLAG_SUPER (1 << 1)
|
||||
|
||||
/* little helpers */
|
||||
static inline uint8_t usb_lo(uint16_t val)
|
||||
{
|
||||
return val & 0xff;
|
||||
}
|
||||
|
||||
static inline uint8_t usb_hi(uint16_t val)
|
||||
{
|
||||
return (val >> 8) & 0xff;
|
||||
}
|
||||
|
||||
/* generate usb packages from structs */
|
||||
int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
|
||||
uint8_t *dest, size_t len);
|
||||
|
@@ -236,7 +236,7 @@ static const USBDescDevice desc_device_tablet2 = {
|
||||
.bNumInterfaces = 1,
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = STR_CONFIG_TABLET,
|
||||
.bmAttributes = 0xa0,
|
||||
.bmAttributes = 0x80,
|
||||
.bMaxPower = 50,
|
||||
.nif = 1,
|
||||
.ifs = &desc_iface_tablet2,
|
||||
|
156
hw/usb/dev-uas.c
156
hw/usb/dev-uas.c
@@ -55,7 +55,7 @@ typedef struct {
|
||||
uint8_t id;
|
||||
uint8_t reserved;
|
||||
uint16_t tag;
|
||||
} QEMU_PACKED uas_iu_header;
|
||||
} QEMU_PACKED uas_ui_header;
|
||||
|
||||
typedef struct {
|
||||
uint8_t prio_taskattr; /* 6:3 priority, 2:0 task attribute */
|
||||
@@ -65,7 +65,7 @@ typedef struct {
|
||||
uint64_t lun;
|
||||
uint8_t cdb[16];
|
||||
uint8_t add_cdb[];
|
||||
} QEMU_PACKED uas_iu_command;
|
||||
} QEMU_PACKED uas_ui_command;
|
||||
|
||||
typedef struct {
|
||||
uint16_t status_qualifier;
|
||||
@@ -73,29 +73,29 @@ typedef struct {
|
||||
uint8_t reserved[7];
|
||||
uint16_t sense_length;
|
||||
uint8_t sense_data[18];
|
||||
} QEMU_PACKED uas_iu_sense;
|
||||
} QEMU_PACKED uas_ui_sense;
|
||||
|
||||
typedef struct {
|
||||
uint8_t add_response_info[3];
|
||||
uint16_t add_response_info;
|
||||
uint8_t response_code;
|
||||
} QEMU_PACKED uas_iu_response;
|
||||
} QEMU_PACKED uas_ui_response;
|
||||
|
||||
typedef struct {
|
||||
uint8_t function;
|
||||
uint8_t reserved;
|
||||
uint16_t task_tag;
|
||||
uint64_t lun;
|
||||
} QEMU_PACKED uas_iu_task_mgmt;
|
||||
} QEMU_PACKED uas_ui_task_mgmt;
|
||||
|
||||
typedef struct {
|
||||
uas_iu_header hdr;
|
||||
uas_ui_header hdr;
|
||||
union {
|
||||
uas_iu_command command;
|
||||
uas_iu_sense sense;
|
||||
uas_iu_task_mgmt task;
|
||||
uas_iu_response response;
|
||||
uas_ui_command command;
|
||||
uas_ui_sense sense;
|
||||
uas_ui_task_mgmt task;
|
||||
uas_ui_response response;
|
||||
};
|
||||
} QEMU_PACKED uas_iu;
|
||||
} QEMU_PACKED uas_ui;
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
@@ -122,8 +122,8 @@ struct UASDevice {
|
||||
UASRequest *dataout2;
|
||||
|
||||
/* usb 3.0 only */
|
||||
USBPacket *data3[UAS_MAX_STREAMS + 1];
|
||||
USBPacket *status3[UAS_MAX_STREAMS + 1];
|
||||
USBPacket *data3[UAS_MAX_STREAMS];
|
||||
USBPacket *status3[UAS_MAX_STREAMS];
|
||||
};
|
||||
|
||||
struct UASRequest {
|
||||
@@ -145,7 +145,7 @@ struct UASRequest {
|
||||
|
||||
struct UASStatus {
|
||||
uint32_t stream;
|
||||
uas_iu status;
|
||||
uas_ui status;
|
||||
uint32_t length;
|
||||
QTAILQ_ENTRY(UASStatus) next;
|
||||
};
|
||||
@@ -338,7 +338,7 @@ static UASStatus *usb_uas_alloc_status(UASDevice *uas, uint8_t id, uint16_t tag)
|
||||
|
||||
st->status.hdr.id = id;
|
||||
st->status.hdr.tag = cpu_to_be16(tag);
|
||||
st->length = sizeof(uas_iu_header);
|
||||
st->length = sizeof(uas_ui_header);
|
||||
if (uas_using_streams(uas)) {
|
||||
st->stream = tag;
|
||||
}
|
||||
@@ -392,13 +392,15 @@ static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length)
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_uas_queue_response(UASDevice *uas, uint16_t tag, uint8_t code)
|
||||
static void usb_uas_queue_response(UASDevice *uas, uint16_t tag,
|
||||
uint8_t code, uint16_t add_info)
|
||||
{
|
||||
UASStatus *st = usb_uas_alloc_status(uas, UAS_UI_RESPONSE, tag);
|
||||
|
||||
trace_usb_uas_response(uas->dev.addr, tag, code);
|
||||
st->status.response.response_code = code;
|
||||
usb_uas_queue_status(uas, st, sizeof(uas_iu_response));
|
||||
st->status.response.add_response_info = cpu_to_be16(add_info);
|
||||
usb_uas_queue_status(uas, st, sizeof(uas_ui_response));
|
||||
}
|
||||
|
||||
static void usb_uas_queue_sense(UASRequest *req, uint8_t status)
|
||||
@@ -414,28 +416,10 @@ static void usb_uas_queue_sense(UASRequest *req, uint8_t status)
|
||||
sizeof(st->status.sense.sense_data));
|
||||
st->status.sense.sense_length = cpu_to_be16(slen);
|
||||
}
|
||||
len = sizeof(uas_iu_sense) - sizeof(st->status.sense.sense_data) + slen;
|
||||
len = sizeof(uas_ui_sense) - sizeof(st->status.sense.sense_data) + slen;
|
||||
usb_uas_queue_status(req->uas, st, len);
|
||||
}
|
||||
|
||||
static void usb_uas_queue_fake_sense(UASDevice *uas, uint16_t tag,
|
||||
struct SCSISense sense)
|
||||
{
|
||||
UASStatus *st = usb_uas_alloc_status(uas, UAS_UI_SENSE, tag);
|
||||
int len, slen = 0;
|
||||
|
||||
st->status.sense.status = CHECK_CONDITION;
|
||||
st->status.sense.status_qualifier = cpu_to_be16(0);
|
||||
st->status.sense.sense_data[0] = 0x70;
|
||||
st->status.sense.sense_data[2] = sense.key;
|
||||
st->status.sense.sense_data[7] = 10;
|
||||
st->status.sense.sense_data[12] = sense.asc;
|
||||
st->status.sense.sense_data[13] = sense.ascq;
|
||||
slen = 18;
|
||||
len = sizeof(uas_iu_sense) - sizeof(st->status.sense.sense_data) + slen;
|
||||
usb_uas_queue_status(uas, st, len);
|
||||
}
|
||||
|
||||
static void usb_uas_queue_read_ready(UASRequest *req)
|
||||
{
|
||||
UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_READ_READY,
|
||||
@@ -534,14 +518,14 @@ static void usb_uas_start_next_transfer(UASDevice *uas)
|
||||
}
|
||||
}
|
||||
|
||||
static UASRequest *usb_uas_alloc_request(UASDevice *uas, uas_iu *iu)
|
||||
static UASRequest *usb_uas_alloc_request(UASDevice *uas, uas_ui *ui)
|
||||
{
|
||||
UASRequest *req;
|
||||
|
||||
req = g_new0(UASRequest, 1);
|
||||
req->uas = uas;
|
||||
req->tag = be16_to_cpu(iu->hdr.tag);
|
||||
req->lun = be64_to_cpu(iu->command.lun);
|
||||
req->tag = be16_to_cpu(ui->hdr.tag);
|
||||
req->lun = be64_to_cpu(ui->command.lun);
|
||||
req->dev = usb_uas_get_dev(req->uas, req->lun);
|
||||
return req;
|
||||
}
|
||||
@@ -664,7 +648,7 @@ static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p)
|
||||
return;
|
||||
}
|
||||
if (uas_using_streams(uas)) {
|
||||
for (i = 0; i <= UAS_MAX_STREAMS; i++) {
|
||||
for (i = 0; i < UAS_MAX_STREAMS; i++) {
|
||||
if (uas->status3[i] == p) {
|
||||
uas->status3[i] = NULL;
|
||||
return;
|
||||
@@ -684,20 +668,16 @@ static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p)
|
||||
assert(!"canceled usb packet not found");
|
||||
}
|
||||
|
||||
static void usb_uas_command(UASDevice *uas, uas_iu *iu)
|
||||
static void usb_uas_command(UASDevice *uas, uas_ui *ui)
|
||||
{
|
||||
UASRequest *req;
|
||||
uint32_t len;
|
||||
uint16_t tag = be16_to_cpu(iu->hdr.tag);
|
||||
|
||||
if (uas_using_streams(uas) && tag > UAS_MAX_STREAMS) {
|
||||
goto invalid_tag;
|
||||
}
|
||||
req = usb_uas_find_request(uas, tag);
|
||||
req = usb_uas_find_request(uas, be16_to_cpu(ui->hdr.tag));
|
||||
if (req) {
|
||||
goto overlapped_tag;
|
||||
}
|
||||
req = usb_uas_alloc_request(uas, iu);
|
||||
req = usb_uas_alloc_request(uas, ui);
|
||||
if (req->dev == NULL) {
|
||||
goto bad_target;
|
||||
}
|
||||
@@ -714,7 +694,7 @@ static void usb_uas_command(UASDevice *uas, uas_iu *iu)
|
||||
|
||||
req->req = scsi_req_new(req->dev, req->tag,
|
||||
usb_uas_get_lun(req->lun),
|
||||
iu->command.cdb, req);
|
||||
ui->command.cdb, req);
|
||||
if (uas->requestlog) {
|
||||
scsi_req_print(req->req);
|
||||
}
|
||||
@@ -725,97 +705,105 @@ static void usb_uas_command(UASDevice *uas, uas_iu *iu)
|
||||
}
|
||||
return;
|
||||
|
||||
invalid_tag:
|
||||
usb_uas_queue_fake_sense(uas, tag, sense_code_INVALID_TAG);
|
||||
return;
|
||||
|
||||
overlapped_tag:
|
||||
usb_uas_queue_fake_sense(uas, tag, sense_code_OVERLAPPED_COMMANDS);
|
||||
usb_uas_queue_response(uas, req->tag, UAS_RC_OVERLAPPED_TAG, 0);
|
||||
return;
|
||||
|
||||
bad_target:
|
||||
usb_uas_queue_fake_sense(uas, tag, sense_code_LUN_NOT_SUPPORTED);
|
||||
/*
|
||||
* FIXME: Seems to upset linux, is this wrong?
|
||||
* NOTE: Happens only with no scsi devices at the bus, not sure
|
||||
* this is a valid UAS setup in the first place.
|
||||
*/
|
||||
usb_uas_queue_response(uas, req->tag, UAS_RC_INVALID_INFO_UNIT, 0);
|
||||
g_free(req);
|
||||
}
|
||||
|
||||
static void usb_uas_task(UASDevice *uas, uas_iu *iu)
|
||||
static void usb_uas_task(UASDevice *uas, uas_ui *ui)
|
||||
{
|
||||
uint16_t tag = be16_to_cpu(iu->hdr.tag);
|
||||
uint64_t lun64 = be64_to_cpu(iu->task.lun);
|
||||
uint16_t tag = be16_to_cpu(ui->hdr.tag);
|
||||
uint64_t lun64 = be64_to_cpu(ui->task.lun);
|
||||
SCSIDevice *dev = usb_uas_get_dev(uas, lun64);
|
||||
int lun = usb_uas_get_lun(lun64);
|
||||
UASRequest *req;
|
||||
uint16_t task_tag;
|
||||
|
||||
if (uas_using_streams(uas) && tag > UAS_MAX_STREAMS) {
|
||||
goto invalid_tag;
|
||||
}
|
||||
req = usb_uas_find_request(uas, be16_to_cpu(iu->hdr.tag));
|
||||
req = usb_uas_find_request(uas, be16_to_cpu(ui->hdr.tag));
|
||||
if (req) {
|
||||
goto overlapped_tag;
|
||||
}
|
||||
if (dev == NULL) {
|
||||
goto incorrect_lun;
|
||||
}
|
||||
|
||||
switch (iu->task.function) {
|
||||
switch (ui->task.function) {
|
||||
case UAS_TMF_ABORT_TASK:
|
||||
task_tag = be16_to_cpu(iu->task.task_tag);
|
||||
task_tag = be16_to_cpu(ui->task.task_tag);
|
||||
trace_usb_uas_tmf_abort_task(uas->dev.addr, tag, task_tag);
|
||||
if (dev == NULL) {
|
||||
goto bad_target;
|
||||
}
|
||||
if (dev->lun != lun) {
|
||||
goto incorrect_lun;
|
||||
}
|
||||
req = usb_uas_find_request(uas, task_tag);
|
||||
if (req && req->dev == dev) {
|
||||
scsi_req_cancel(req->req);
|
||||
}
|
||||
usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE);
|
||||
usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE, 0);
|
||||
break;
|
||||
|
||||
case UAS_TMF_LOGICAL_UNIT_RESET:
|
||||
trace_usb_uas_tmf_logical_unit_reset(uas->dev.addr, tag, lun);
|
||||
if (dev == NULL) {
|
||||
goto bad_target;
|
||||
}
|
||||
if (dev->lun != lun) {
|
||||
goto incorrect_lun;
|
||||
}
|
||||
qdev_reset_all(&dev->qdev);
|
||||
usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE);
|
||||
usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
trace_usb_uas_tmf_unsupported(uas->dev.addr, tag, iu->task.function);
|
||||
usb_uas_queue_response(uas, tag, UAS_RC_TMF_NOT_SUPPORTED);
|
||||
trace_usb_uas_tmf_unsupported(uas->dev.addr, tag, ui->task.function);
|
||||
usb_uas_queue_response(uas, tag, UAS_RC_TMF_NOT_SUPPORTED, 0);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
|
||||
invalid_tag:
|
||||
usb_uas_queue_response(uas, tag, UAS_RC_INVALID_INFO_UNIT);
|
||||
overlapped_tag:
|
||||
usb_uas_queue_response(uas, req->tag, UAS_RC_OVERLAPPED_TAG, 0);
|
||||
return;
|
||||
|
||||
overlapped_tag:
|
||||
usb_uas_queue_response(uas, req->tag, UAS_RC_OVERLAPPED_TAG);
|
||||
bad_target:
|
||||
/* FIXME: correct? [see long comment in usb_uas_command()] */
|
||||
usb_uas_queue_response(uas, tag, UAS_RC_INVALID_INFO_UNIT, 0);
|
||||
return;
|
||||
|
||||
incorrect_lun:
|
||||
usb_uas_queue_response(uas, tag, UAS_RC_INCORRECT_LUN);
|
||||
usb_uas_queue_response(uas, tag, UAS_RC_INCORRECT_LUN, 0);
|
||||
}
|
||||
|
||||
static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
UASDevice *uas = DO_UPCAST(UASDevice, dev, dev);
|
||||
uas_iu iu;
|
||||
uas_ui ui;
|
||||
UASStatus *st;
|
||||
UASRequest *req;
|
||||
int length;
|
||||
|
||||
switch (p->ep->nr) {
|
||||
case UAS_PIPE_ID_COMMAND:
|
||||
length = MIN(sizeof(iu), p->iov.size);
|
||||
usb_packet_copy(p, &iu, length);
|
||||
switch (iu.hdr.id) {
|
||||
length = MIN(sizeof(ui), p->iov.size);
|
||||
usb_packet_copy(p, &ui, length);
|
||||
switch (ui.hdr.id) {
|
||||
case UAS_UI_COMMAND:
|
||||
usb_uas_command(uas, &iu);
|
||||
usb_uas_command(uas, &ui);
|
||||
break;
|
||||
case UAS_UI_TASK_MGMT:
|
||||
usb_uas_task(uas, &iu);
|
||||
usb_uas_task(uas, &ui);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: unknown command iu: id 0x%x\n",
|
||||
__func__, iu.hdr.id);
|
||||
fprintf(stderr, "%s: unknown command ui: id 0x%x\n",
|
||||
__func__, ui.hdr.id);
|
||||
p->status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
|
@@ -28,7 +28,6 @@
|
||||
*/
|
||||
|
||||
#include "hw/usb/hcd-ehci.h"
|
||||
#include "trace.h"
|
||||
|
||||
/* Capability Registers Base Address - section 2.2 */
|
||||
#define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */
|
||||
@@ -827,9 +826,9 @@ static void ehci_child_detach(USBPort *port, USBDevice *child)
|
||||
static void ehci_wakeup(USBPort *port)
|
||||
{
|
||||
EHCIState *s = port->opaque;
|
||||
uint32_t *portsc = &s->portsc[port->index];
|
||||
uint32_t portsc = s->portsc[port->index];
|
||||
|
||||
if (*portsc & PORTSC_POWNER) {
|
||||
if (portsc & PORTSC_POWNER) {
|
||||
USBPort *companion = s->companion_ports[port->index];
|
||||
if (companion->ops->wakeup) {
|
||||
companion->ops->wakeup(companion);
|
||||
@@ -837,12 +836,6 @@ static void ehci_wakeup(USBPort *port)
|
||||
return;
|
||||
}
|
||||
|
||||
if (*portsc & PORTSC_SUSPEND) {
|
||||
trace_usb_ehci_port_wakeup(port->index);
|
||||
*portsc |= PORTSC_FPRES;
|
||||
ehci_raise_irq(s, USBSTS_PCD);
|
||||
}
|
||||
|
||||
qemu_bh_schedule(s->async_bh);
|
||||
}
|
||||
|
||||
@@ -1074,14 +1067,6 @@ static void ehci_port_write(void *ptr, hwaddr addr,
|
||||
}
|
||||
}
|
||||
|
||||
if ((val & PORTSC_SUSPEND) && !(*portsc & PORTSC_SUSPEND)) {
|
||||
trace_usb_ehci_port_suspend(port);
|
||||
}
|
||||
if (!(val & PORTSC_FPRES) && (*portsc & PORTSC_FPRES)) {
|
||||
trace_usb_ehci_port_resume(port);
|
||||
val &= ~PORTSC_SUSPEND;
|
||||
}
|
||||
|
||||
*portsc &= ~PORTSC_RO_MASK;
|
||||
*portsc |= val;
|
||||
trace_usb_ehci_portsc_change(addr + s->portscbase, addr >> 2, *portsc, old);
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/usb.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "trace.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/pci/pci.h"
|
||||
|
@@ -1150,111 +1150,6 @@ static void xhci_free_streams(XHCIEPContext *epctx)
|
||||
epctx->nr_pstreams = 0;
|
||||
}
|
||||
|
||||
static int xhci_epmask_to_eps_with_streams(XHCIState *xhci,
|
||||
unsigned int slotid,
|
||||
uint32_t epmask,
|
||||
XHCIEPContext **epctxs,
|
||||
USBEndpoint **eps)
|
||||
{
|
||||
XHCISlot *slot;
|
||||
XHCIEPContext *epctx;
|
||||
USBEndpoint *ep;
|
||||
int i, j;
|
||||
|
||||
assert(slotid >= 1 && slotid <= xhci->numslots);
|
||||
|
||||
slot = &xhci->slots[slotid - 1];
|
||||
|
||||
for (i = 2, j = 0; i <= 31; i++) {
|
||||
if (!(epmask & (1 << i))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
epctx = slot->eps[i - 1];
|
||||
ep = xhci_epid_to_usbep(xhci, slotid, i);
|
||||
if (!epctx || !epctx->nr_pstreams || !ep) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (epctxs) {
|
||||
epctxs[j] = epctx;
|
||||
}
|
||||
eps[j++] = ep;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
static void xhci_free_device_streams(XHCIState *xhci, unsigned int slotid,
|
||||
uint32_t epmask)
|
||||
{
|
||||
USBEndpoint *eps[30];
|
||||
int nr_eps;
|
||||
|
||||
nr_eps = xhci_epmask_to_eps_with_streams(xhci, slotid, epmask, NULL, eps);
|
||||
if (nr_eps) {
|
||||
usb_device_free_streams(eps[0]->dev, eps, nr_eps);
|
||||
}
|
||||
}
|
||||
|
||||
static TRBCCode xhci_alloc_device_streams(XHCIState *xhci, unsigned int slotid,
|
||||
uint32_t epmask)
|
||||
{
|
||||
XHCIEPContext *epctxs[30];
|
||||
USBEndpoint *eps[30];
|
||||
int i, r, nr_eps, req_nr_streams, dev_max_streams;
|
||||
|
||||
nr_eps = xhci_epmask_to_eps_with_streams(xhci, slotid, epmask, epctxs,
|
||||
eps);
|
||||
if (nr_eps == 0) {
|
||||
return CC_SUCCESS;
|
||||
}
|
||||
|
||||
req_nr_streams = epctxs[0]->nr_pstreams;
|
||||
dev_max_streams = eps[0]->max_streams;
|
||||
|
||||
for (i = 1; i < nr_eps; i++) {
|
||||
/*
|
||||
* HdG: I don't expect these to ever trigger, but if they do we need
|
||||
* to come up with another solution, ie group identical endpoints
|
||||
* together and make an usb_device_alloc_streams call per group.
|
||||
*/
|
||||
if (epctxs[i]->nr_pstreams != req_nr_streams) {
|
||||
FIXME("guest streams config not identical for all eps");
|
||||
return CC_RESOURCE_ERROR;
|
||||
}
|
||||
if (eps[i]->max_streams != dev_max_streams) {
|
||||
FIXME("device streams config not identical for all eps");
|
||||
return CC_RESOURCE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* max-streams in both the device descriptor and in the controller is a
|
||||
* power of 2. But stream id 0 is reserved, so if a device can do up to 4
|
||||
* streams the guest will ask for 5 rounded up to the next power of 2 which
|
||||
* becomes 8. For emulated devices usb_device_alloc_streams is a nop.
|
||||
*
|
||||
* For redirected devices however this is an issue, as there we must ask
|
||||
* the real xhci controller to alloc streams, and the host driver for the
|
||||
* real xhci controller will likely disallow allocating more streams then
|
||||
* the device can handle.
|
||||
*
|
||||
* So we limit the requested nr_streams to the maximum number the device
|
||||
* can handle.
|
||||
*/
|
||||
if (req_nr_streams > dev_max_streams) {
|
||||
req_nr_streams = dev_max_streams;
|
||||
}
|
||||
|
||||
r = usb_device_alloc_streams(eps[0]->dev, eps, nr_eps, req_nr_streams);
|
||||
if (r != 0) {
|
||||
fprintf(stderr, "xhci: alloc streams failed\n");
|
||||
return CC_RESOURCE_ERROR;
|
||||
}
|
||||
|
||||
return CC_SUCCESS;
|
||||
}
|
||||
|
||||
static XHCIStreamContext *xhci_find_stream(XHCIEPContext *epctx,
|
||||
unsigned int streamid,
|
||||
uint32_t *cc_error)
|
||||
@@ -1600,8 +1495,7 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid,
|
||||
}
|
||||
|
||||
if (!xhci->slots[slotid-1].uport ||
|
||||
!xhci->slots[slotid-1].uport->dev ||
|
||||
!xhci->slots[slotid-1].uport->dev->attached) {
|
||||
!xhci->slots[slotid-1].uport->dev) {
|
||||
return CC_USB_TRANSACTION_ERROR;
|
||||
}
|
||||
|
||||
@@ -2088,14 +1982,6 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the device has been detached, but the guest has not noticed this
|
||||
yet the 2 above checks will succeed, but we must NOT continue */
|
||||
if (!xhci->slots[slotid - 1].uport ||
|
||||
!xhci->slots[slotid - 1].uport->dev ||
|
||||
!xhci->slots[slotid - 1].uport->dev->attached) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (epctx->retry) {
|
||||
XHCITransfer *xfer = epctx->retry;
|
||||
|
||||
@@ -2320,7 +2206,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
|
||||
trace_usb_xhci_slot_address(slotid, uport->path);
|
||||
|
||||
dev = uport->dev;
|
||||
if (!dev || !dev->attached) {
|
||||
if (!dev) {
|
||||
fprintf(stderr, "xhci: port %s not connected\n", uport->path);
|
||||
return CC_USB_TRANSACTION_ERROR;
|
||||
}
|
||||
@@ -2427,8 +2313,6 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
|
||||
return CC_CONTEXT_STATE_ERROR;
|
||||
}
|
||||
|
||||
xhci_free_device_streams(xhci, slotid, ictl_ctx[0] | ictl_ctx[1]);
|
||||
|
||||
for (i = 2; i <= 31; i++) {
|
||||
if (ictl_ctx[0] & (1<<i)) {
|
||||
xhci_disable_ep(xhci, slotid, i);
|
||||
@@ -2450,16 +2334,6 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
|
||||
}
|
||||
}
|
||||
|
||||
res = xhci_alloc_device_streams(xhci, slotid, ictl_ctx[1]);
|
||||
if (res != CC_SUCCESS) {
|
||||
for (i = 2; i <= 31; i++) {
|
||||
if (ictl_ctx[1] & (1 << i)) {
|
||||
xhci_disable_ep(xhci, slotid, i);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
|
||||
slot_ctx[3] |= SLOT_CONFIGURED << SLOT_STATE_SHIFT;
|
||||
slot_ctx[0] &= ~(SLOT_CONTEXT_ENTRIES_MASK << SLOT_CONTEXT_ENTRIES_SHIFT);
|
||||
@@ -3142,14 +3016,6 @@ static void xhci_oper_write(void *ptr, hwaddr reg,
|
||||
} else if (!(val & USBCMD_RS) && (xhci->usbcmd & USBCMD_RS)) {
|
||||
xhci_stop(xhci);
|
||||
}
|
||||
if (val & USBCMD_CSS) {
|
||||
/* save state */
|
||||
xhci->usbsts &= ~USBSTS_SRE;
|
||||
}
|
||||
if (val & USBCMD_CRS) {
|
||||
/* restore state */
|
||||
xhci->usbsts |= USBSTS_SRE;
|
||||
}
|
||||
xhci->usbcmd = val & 0xc0f;
|
||||
xhci_mfwrap_update(xhci);
|
||||
if (val & USBCMD_HCRST) {
|
||||
|
@@ -370,16 +370,14 @@ static int virtio_balloon_device_init(VirtIODevice *vdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_balloon_device_exit(DeviceState *qdev)
|
||||
static void virtio_balloon_device_exit(VirtIODevice *vdev)
|
||||
{
|
||||
VirtIOBalloon *s = VIRTIO_BALLOON(qdev);
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
|
||||
VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
|
||||
|
||||
balloon_stats_destroy_timer(s);
|
||||
qemu_remove_balloon_handler(s);
|
||||
unregister_savevm(qdev, "virtio-balloon", s);
|
||||
unregister_savevm(DEVICE(vdev), "virtio-balloon", s);
|
||||
virtio_cleanup(vdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Property virtio_balloon_properties[] = {
|
||||
@@ -390,10 +388,10 @@ static void virtio_balloon_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||
dc->exit = virtio_balloon_device_exit;
|
||||
dc->props = virtio_balloon_properties;
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
vdc->init = virtio_balloon_device_init;
|
||||
vdc->exit = virtio_balloon_device_exit;
|
||||
vdc->get_config = virtio_balloon_get_config;
|
||||
vdc->set_config = virtio_balloon_set_config;
|
||||
vdc->get_features = virtio_balloon_get_features;
|
||||
|
@@ -37,8 +37,8 @@ do { printf("virtio_bus: " fmt , ## __VA_ARGS__); } while (0)
|
||||
#define DPRINTF(fmt, ...) do { } while (0)
|
||||
#endif
|
||||
|
||||
/* Plug the VirtIODevice */
|
||||
int virtio_bus_plug_device(VirtIODevice *vdev)
|
||||
/* A VirtIODevice is being plugged */
|
||||
int virtio_bus_device_plugged(VirtIODevice *vdev)
|
||||
{
|
||||
DeviceState *qdev = DEVICE(vdev);
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(qdev));
|
||||
@@ -46,8 +46,6 @@ int virtio_bus_plug_device(VirtIODevice *vdev)
|
||||
VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
|
||||
DPRINTF("%s: plug device.\n", qbus->name);
|
||||
|
||||
bus->vdev = vdev;
|
||||
|
||||
if (klass->device_plugged != NULL) {
|
||||
klass->device_plugged(qbus->parent);
|
||||
}
|
||||
@@ -58,73 +56,83 @@ int virtio_bus_plug_device(VirtIODevice *vdev)
|
||||
/* Reset the virtio_bus */
|
||||
void virtio_bus_reset(VirtioBusState *bus)
|
||||
{
|
||||
VirtIODevice *vdev = virtio_bus_get_device(bus);
|
||||
|
||||
DPRINTF("%s: reset device.\n", qbus->name);
|
||||
if (bus->vdev != NULL) {
|
||||
virtio_reset(bus->vdev);
|
||||
if (vdev != NULL) {
|
||||
virtio_reset(vdev);
|
||||
}
|
||||
}
|
||||
|
||||
/* Destroy the VirtIODevice */
|
||||
void virtio_bus_destroy_device(VirtioBusState *bus)
|
||||
/* A VirtIODevice is being unplugged */
|
||||
void virtio_bus_device_unplugged(VirtIODevice *vdev)
|
||||
{
|
||||
BusState *qbus = BUS(bus);
|
||||
VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
|
||||
DeviceState *qdev = DEVICE(vdev);
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(qdev));
|
||||
VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
|
||||
DPRINTF("%s: remove device.\n", qbus->name);
|
||||
|
||||
if (bus->vdev != NULL) {
|
||||
if (klass->device_unplug != NULL) {
|
||||
klass->device_unplug(qbus->parent);
|
||||
if (vdev != NULL) {
|
||||
if (klass->device_unplugged != NULL) {
|
||||
klass->device_unplugged(qbus->parent);
|
||||
}
|
||||
object_unparent(OBJECT(bus->vdev));
|
||||
bus->vdev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the device id of the plugged device. */
|
||||
uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus)
|
||||
{
|
||||
assert(bus->vdev != NULL);
|
||||
return bus->vdev->device_id;
|
||||
VirtIODevice *vdev = virtio_bus_get_device(bus);
|
||||
assert(vdev != NULL);
|
||||
return vdev->device_id;
|
||||
}
|
||||
|
||||
/* Get the config_len field of the plugged device. */
|
||||
size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus)
|
||||
{
|
||||
assert(bus->vdev != NULL);
|
||||
return bus->vdev->config_len;
|
||||
VirtIODevice *vdev = virtio_bus_get_device(bus);
|
||||
assert(vdev != NULL);
|
||||
return vdev->config_len;
|
||||
}
|
||||
|
||||
/* Get the features of the plugged device. */
|
||||
uint32_t virtio_bus_get_vdev_features(VirtioBusState *bus,
|
||||
uint32_t requested_features)
|
||||
{
|
||||
VirtIODevice *vdev = virtio_bus_get_device(bus);
|
||||
VirtioDeviceClass *k;
|
||||
assert(bus->vdev != NULL);
|
||||
k = VIRTIO_DEVICE_GET_CLASS(bus->vdev);
|
||||
|
||||
assert(vdev != NULL);
|
||||
k = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
assert(k->get_features != NULL);
|
||||
return k->get_features(bus->vdev, requested_features);
|
||||
return k->get_features(vdev, requested_features);
|
||||
}
|
||||
|
||||
/* Set the features of the plugged device. */
|
||||
void virtio_bus_set_vdev_features(VirtioBusState *bus,
|
||||
uint32_t requested_features)
|
||||
{
|
||||
VirtIODevice *vdev = virtio_bus_get_device(bus);
|
||||
VirtioDeviceClass *k;
|
||||
assert(bus->vdev != NULL);
|
||||
k = VIRTIO_DEVICE_GET_CLASS(bus->vdev);
|
||||
|
||||
assert(vdev != NULL);
|
||||
k = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
if (k->set_features != NULL) {
|
||||
k->set_features(bus->vdev, requested_features);
|
||||
k->set_features(vdev, requested_features);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get bad features of the plugged device. */
|
||||
uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus)
|
||||
{
|
||||
VirtIODevice *vdev = virtio_bus_get_device(bus);
|
||||
VirtioDeviceClass *k;
|
||||
assert(bus->vdev != NULL);
|
||||
k = VIRTIO_DEVICE_GET_CLASS(bus->vdev);
|
||||
|
||||
assert(vdev != NULL);
|
||||
k = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
if (k->bad_features != NULL) {
|
||||
return k->bad_features(bus->vdev);
|
||||
return k->bad_features(vdev);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@@ -133,22 +141,26 @@ uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus)
|
||||
/* Get config of the plugged device. */
|
||||
void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config)
|
||||
{
|
||||
VirtIODevice *vdev = virtio_bus_get_device(bus);
|
||||
VirtioDeviceClass *k;
|
||||
assert(bus->vdev != NULL);
|
||||
k = VIRTIO_DEVICE_GET_CLASS(bus->vdev);
|
||||
|
||||
assert(vdev != NULL);
|
||||
k = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
if (k->get_config != NULL) {
|
||||
k->get_config(bus->vdev, config);
|
||||
k->get_config(vdev, config);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set config of the plugged device. */
|
||||
void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config)
|
||||
{
|
||||
VirtIODevice *vdev = virtio_bus_get_device(bus);
|
||||
VirtioDeviceClass *k;
|
||||
assert(bus->vdev != NULL);
|
||||
k = VIRTIO_DEVICE_GET_CLASS(bus->vdev);
|
||||
|
||||
assert(vdev != NULL);
|
||||
k = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
if (k->set_config != NULL) {
|
||||
k->set_config(bus->vdev, config);
|
||||
k->set_config(vdev, config);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -95,7 +95,7 @@ static void virtio_mmio_bus_new(VirtioBusState *bus, size_t bus_size,
|
||||
static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque;
|
||||
VirtIODevice *vdev = proxy->bus.vdev;
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
|
||||
DPRINTF("virtio_mmio_read offset 0x%x\n", (int)offset);
|
||||
|
||||
@@ -185,7 +185,7 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque;
|
||||
VirtIODevice *vdev = proxy->bus.vdev;
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
|
||||
DPRINTF("virtio_mmio_write offset 0x%x value 0x%" PRIx64 "\n",
|
||||
(int)offset, value);
|
||||
@@ -298,12 +298,13 @@ static const MemoryRegionOps virtio_mem_ops = {
|
||||
static void virtio_mmio_update_irq(DeviceState *opaque, uint16_t vector)
|
||||
{
|
||||
VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
int level;
|
||||
|
||||
if (!proxy->bus.vdev) {
|
||||
if (!vdev) {
|
||||
return;
|
||||
}
|
||||
level = (proxy->bus.vdev->isr != 0);
|
||||
level = (vdev->isr != 0);
|
||||
DPRINTF("virtio_mmio setting IRQ %d\n", level);
|
||||
qemu_set_irq(proxy->irq, level);
|
||||
}
|
||||
|
@@ -113,31 +113,40 @@ static inline VirtIOPCIProxy *to_virtio_pci_proxy_fast(DeviceState *d)
|
||||
static void virtio_pci_notify(DeviceState *d, uint16_t vector)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d);
|
||||
|
||||
if (msix_enabled(&proxy->pci_dev))
|
||||
msix_notify(&proxy->pci_dev, vector);
|
||||
else
|
||||
pci_set_irq(&proxy->pci_dev, proxy->vdev->isr & 1);
|
||||
else {
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
pci_set_irq(&proxy->pci_dev, vdev->isr & 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_pci_save_config(DeviceState *d, QEMUFile *f)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
|
||||
pci_device_save(&proxy->pci_dev, f);
|
||||
msix_save(&proxy->pci_dev, f);
|
||||
if (msix_present(&proxy->pci_dev))
|
||||
qemu_put_be16(f, proxy->vdev->config_vector);
|
||||
qemu_put_be16(f, vdev->config_vector);
|
||||
}
|
||||
|
||||
static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
|
||||
if (msix_present(&proxy->pci_dev))
|
||||
qemu_put_be16(f, virtio_queue_vector(proxy->vdev, n));
|
||||
qemu_put_be16(f, virtio_queue_vector(vdev, n));
|
||||
}
|
||||
|
||||
static int virtio_pci_load_config(DeviceState *d, QEMUFile *f)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
|
||||
int ret;
|
||||
ret = pci_device_load(&proxy->pci_dev, f);
|
||||
if (ret) {
|
||||
@@ -146,12 +155,12 @@ static int virtio_pci_load_config(DeviceState *d, QEMUFile *f)
|
||||
msix_unuse_all_vectors(&proxy->pci_dev);
|
||||
msix_load(&proxy->pci_dev, f);
|
||||
if (msix_present(&proxy->pci_dev)) {
|
||||
qemu_get_be16s(f, &proxy->vdev->config_vector);
|
||||
qemu_get_be16s(f, &vdev->config_vector);
|
||||
} else {
|
||||
proxy->vdev->config_vector = VIRTIO_NO_VECTOR;
|
||||
vdev->config_vector = VIRTIO_NO_VECTOR;
|
||||
}
|
||||
if (proxy->vdev->config_vector != VIRTIO_NO_VECTOR) {
|
||||
return msix_vector_use(&proxy->pci_dev, proxy->vdev->config_vector);
|
||||
if (vdev->config_vector != VIRTIO_NO_VECTOR) {
|
||||
return msix_vector_use(&proxy->pci_dev, vdev->config_vector);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -159,13 +168,15 @@ static int virtio_pci_load_config(DeviceState *d, QEMUFile *f)
|
||||
static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
|
||||
uint16_t vector;
|
||||
if (msix_present(&proxy->pci_dev)) {
|
||||
qemu_get_be16s(f, &vector);
|
||||
} else {
|
||||
vector = VIRTIO_NO_VECTOR;
|
||||
}
|
||||
virtio_queue_set_vector(proxy->vdev, n, vector);
|
||||
virtio_queue_set_vector(vdev, n, vector);
|
||||
if (vector != VIRTIO_NO_VECTOR) {
|
||||
return msix_vector_use(&proxy->pci_dev, vector);
|
||||
}
|
||||
@@ -175,7 +186,8 @@ static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f)
|
||||
static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
|
||||
int n, bool assign, bool set_handler)
|
||||
{
|
||||
VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
VirtQueue *vq = virtio_get_queue(vdev, n);
|
||||
EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
|
||||
int r = 0;
|
||||
|
||||
@@ -200,6 +212,7 @@ static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
|
||||
|
||||
static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
|
||||
{
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
int n, r;
|
||||
|
||||
if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) ||
|
||||
@@ -209,7 +222,7 @@ static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
|
||||
}
|
||||
|
||||
for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
|
||||
if (!virtio_queue_get_num(proxy->vdev, n)) {
|
||||
if (!virtio_queue_get_num(vdev, n)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -223,7 +236,7 @@ static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
|
||||
|
||||
assign_error:
|
||||
while (--n >= 0) {
|
||||
if (!virtio_queue_get_num(proxy->vdev, n)) {
|
||||
if (!virtio_queue_get_num(vdev, n)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -236,6 +249,7 @@ assign_error:
|
||||
|
||||
static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
|
||||
{
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
int r;
|
||||
int n;
|
||||
|
||||
@@ -244,7 +258,7 @@ static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
|
||||
}
|
||||
|
||||
for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
|
||||
if (!virtio_queue_get_num(proxy->vdev, n)) {
|
||||
if (!virtio_queue_get_num(vdev, n)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -257,7 +271,7 @@ static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
|
||||
static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = opaque;
|
||||
VirtIODevice *vdev = proxy->vdev;
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
hwaddr pa;
|
||||
|
||||
switch (addr) {
|
||||
@@ -272,7 +286,7 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
|
||||
if (pa == 0) {
|
||||
virtio_pci_stop_ioeventfd(proxy);
|
||||
virtio_reset(proxy->vdev);
|
||||
virtio_reset(vdev);
|
||||
msix_unuse_all_vectors(&proxy->pci_dev);
|
||||
}
|
||||
else
|
||||
@@ -299,7 +313,7 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
}
|
||||
|
||||
if (vdev->status == 0) {
|
||||
virtio_reset(proxy->vdev);
|
||||
virtio_reset(vdev);
|
||||
msix_unuse_all_vectors(&proxy->pci_dev);
|
||||
}
|
||||
|
||||
@@ -335,7 +349,7 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
|
||||
static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
|
||||
{
|
||||
VirtIODevice *vdev = proxy->vdev;
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
uint32_t ret = 0xFFFFFFFF;
|
||||
|
||||
switch (addr) {
|
||||
@@ -381,6 +395,7 @@ static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = opaque;
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
|
||||
uint64_t val = 0;
|
||||
if (addr < config) {
|
||||
@@ -390,16 +405,16 @@ static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr,
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
val = virtio_config_readb(proxy->vdev, addr);
|
||||
val = virtio_config_readb(vdev, addr);
|
||||
break;
|
||||
case 2:
|
||||
val = virtio_config_readw(proxy->vdev, addr);
|
||||
val = virtio_config_readw(vdev, addr);
|
||||
if (virtio_is_big_endian()) {
|
||||
val = bswap16(val);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
val = virtio_config_readl(proxy->vdev, addr);
|
||||
val = virtio_config_readl(vdev, addr);
|
||||
if (virtio_is_big_endian()) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
@@ -413,6 +428,7 @@ static void virtio_pci_config_write(void *opaque, hwaddr addr,
|
||||
{
|
||||
VirtIOPCIProxy *proxy = opaque;
|
||||
uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
if (addr < config) {
|
||||
virtio_ioport_write(proxy, addr, val);
|
||||
return;
|
||||
@@ -424,19 +440,19 @@ static void virtio_pci_config_write(void *opaque, hwaddr addr,
|
||||
*/
|
||||
switch (size) {
|
||||
case 1:
|
||||
virtio_config_writeb(proxy->vdev, addr, val);
|
||||
virtio_config_writeb(vdev, addr, val);
|
||||
break;
|
||||
case 2:
|
||||
if (virtio_is_big_endian()) {
|
||||
val = bswap16(val);
|
||||
}
|
||||
virtio_config_writew(proxy->vdev, addr, val);
|
||||
virtio_config_writew(vdev, addr, val);
|
||||
break;
|
||||
case 4:
|
||||
if (virtio_is_big_endian()) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
virtio_config_writel(proxy->vdev, addr, val);
|
||||
virtio_config_writel(vdev, addr, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -455,6 +471,7 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
|
||||
uint32_t val, int len)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
|
||||
pci_default_write_config(pci_dev, address, val, len);
|
||||
|
||||
@@ -462,8 +479,7 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
|
||||
!(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER) &&
|
||||
!(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) {
|
||||
virtio_pci_stop_ioeventfd(proxy);
|
||||
virtio_set_status(proxy->vdev,
|
||||
proxy->vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
|
||||
virtio_set_status(vdev, vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,7 +522,8 @@ static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy,
|
||||
unsigned int vector)
|
||||
{
|
||||
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
|
||||
VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
VirtQueue *vq = virtio_get_queue(vdev, queue_no);
|
||||
EventNotifier *n = virtio_queue_get_guest_notifier(vq);
|
||||
int ret;
|
||||
ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, NULL, irqfd->virq);
|
||||
@@ -517,7 +534,8 @@ static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
|
||||
unsigned int queue_no,
|
||||
unsigned int vector)
|
||||
{
|
||||
VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
VirtQueue *vq = virtio_get_queue(vdev, queue_no);
|
||||
EventNotifier *n = virtio_queue_get_guest_notifier(vq);
|
||||
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
|
||||
int ret;
|
||||
@@ -529,7 +547,7 @@ static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
|
||||
static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs)
|
||||
{
|
||||
PCIDevice *dev = &proxy->pci_dev;
|
||||
VirtIODevice *vdev = proxy->vdev;
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
unsigned int vector;
|
||||
int ret, queue_no;
|
||||
@@ -578,7 +596,7 @@ undo:
|
||||
static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
|
||||
{
|
||||
PCIDevice *dev = &proxy->pci_dev;
|
||||
VirtIODevice *vdev = proxy->vdev;
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
unsigned int vector;
|
||||
int queue_no;
|
||||
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
@@ -606,8 +624,9 @@ static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
|
||||
unsigned int vector,
|
||||
MSIMessage msg)
|
||||
{
|
||||
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(proxy->vdev);
|
||||
VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
VirtQueue *vq = virtio_get_queue(vdev, queue_no);
|
||||
EventNotifier *n = virtio_queue_get_guest_notifier(vq);
|
||||
VirtIOIRQFD *irqfd;
|
||||
int ret = 0;
|
||||
@@ -626,10 +645,10 @@ static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
|
||||
* Otherwise, set it up now.
|
||||
*/
|
||||
if (k->guest_notifier_mask) {
|
||||
k->guest_notifier_mask(proxy->vdev, queue_no, false);
|
||||
k->guest_notifier_mask(vdev, queue_no, false);
|
||||
/* Test after unmasking to avoid losing events. */
|
||||
if (k->guest_notifier_pending &&
|
||||
k->guest_notifier_pending(proxy->vdev, queue_no)) {
|
||||
k->guest_notifier_pending(vdev, queue_no)) {
|
||||
event_notifier_set(n);
|
||||
}
|
||||
} else {
|
||||
@@ -642,13 +661,14 @@ static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
|
||||
unsigned int queue_no,
|
||||
unsigned int vector)
|
||||
{
|
||||
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(proxy->vdev);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
|
||||
/* If guest supports masking, keep irqfd but mask it.
|
||||
* Otherwise, clean it up now.
|
||||
*/
|
||||
if (k->guest_notifier_mask) {
|
||||
k->guest_notifier_mask(proxy->vdev, queue_no, true);
|
||||
k->guest_notifier_mask(vdev, queue_no, true);
|
||||
} else {
|
||||
kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
|
||||
}
|
||||
@@ -658,7 +678,7 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
|
||||
MSIMessage msg)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
|
||||
VirtIODevice *vdev = proxy->vdev;
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
int ret, queue_no;
|
||||
|
||||
for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
|
||||
@@ -688,7 +708,7 @@ undo:
|
||||
static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
|
||||
VirtIODevice *vdev = proxy->vdev;
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
int queue_no;
|
||||
|
||||
for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
|
||||
@@ -707,7 +727,7 @@ static void virtio_pci_vector_poll(PCIDevice *dev,
|
||||
unsigned int vector_end)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
|
||||
VirtIODevice *vdev = proxy->vdev;
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
int queue_no;
|
||||
unsigned int vector;
|
||||
@@ -739,8 +759,9 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
|
||||
bool with_irqfd)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(proxy->vdev);
|
||||
VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
VirtQueue *vq = virtio_get_queue(vdev, n);
|
||||
EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
|
||||
|
||||
if (assign) {
|
||||
@@ -755,7 +776,7 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
|
||||
}
|
||||
|
||||
if (!msix_enabled(&proxy->pci_dev) && vdc->guest_notifier_mask) {
|
||||
vdc->guest_notifier_mask(proxy->vdev, n, !assign);
|
||||
vdc->guest_notifier_mask(vdev, n, !assign);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -770,7 +791,7 @@ static bool virtio_pci_query_guest_notifiers(DeviceState *d)
|
||||
static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
|
||||
VirtIODevice *vdev = proxy->vdev;
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
int r, n;
|
||||
bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
|
||||
@@ -864,11 +885,12 @@ static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign)
|
||||
static void virtio_pci_vmstate_change(DeviceState *d, bool running)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
|
||||
if (running) {
|
||||
/* Try to find out if the guest has bus master disabled, but is
|
||||
in ready state. Then we have a buggy guest OS. */
|
||||
if ((proxy->vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) &&
|
||||
if ((vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) &&
|
||||
!(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
|
||||
proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
|
||||
}
|
||||
@@ -943,8 +965,6 @@ static void virtio_pci_device_plugged(DeviceState *d)
|
||||
uint8_t *config;
|
||||
uint32_t size;
|
||||
|
||||
proxy->vdev = bus->vdev;
|
||||
|
||||
config = proxy->pci_dev.config;
|
||||
if (proxy->class_code) {
|
||||
pci_config_set_class(config, proxy->class_code);
|
||||
@@ -982,6 +1002,15 @@ static void virtio_pci_device_plugged(DeviceState *d)
|
||||
proxy->host_features);
|
||||
}
|
||||
|
||||
static void virtio_pci_device_unplugged(DeviceState *d)
|
||||
{
|
||||
PCIDevice *pci_dev = PCI_DEVICE(d);
|
||||
VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
|
||||
|
||||
virtio_pci_stop_ioeventfd(proxy);
|
||||
msix_uninit_exclusive_bar(pci_dev);
|
||||
}
|
||||
|
||||
static int virtio_pci_init(PCIDevice *pci_dev)
|
||||
{
|
||||
VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev);
|
||||
@@ -996,9 +1025,7 @@ static int virtio_pci_init(PCIDevice *pci_dev)
|
||||
static void virtio_pci_exit(PCIDevice *pci_dev)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
|
||||
virtio_pci_stop_ioeventfd(proxy);
|
||||
memory_region_destroy(&proxy->bar);
|
||||
msix_uninit_exclusive_bar(pci_dev);
|
||||
}
|
||||
|
||||
static void virtio_pci_reset(DeviceState *qdev)
|
||||
@@ -1533,6 +1560,7 @@ static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
|
||||
k->set_guest_notifiers = virtio_pci_set_guest_notifiers;
|
||||
k->vmstate_change = virtio_pci_vmstate_change;
|
||||
k->device_plugged = virtio_pci_device_plugged;
|
||||
k->device_unplugged = virtio_pci_device_unplugged;
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_pci_bus_info = {
|
||||
|
@@ -82,7 +82,6 @@ typedef struct VirtioPCIClass {
|
||||
|
||||
struct VirtIOPCIProxy {
|
||||
PCIDevice pci_dev;
|
||||
VirtIODevice *vdev;
|
||||
MemoryRegion bar;
|
||||
uint32_t flags;
|
||||
uint32_t class_code;
|
||||
|
@@ -190,16 +190,14 @@ static int virtio_rng_device_init(VirtIODevice *vdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_rng_device_exit(DeviceState *qdev)
|
||||
static void virtio_rng_device_exit(VirtIODevice *vdev)
|
||||
{
|
||||
VirtIORNG *vrng = VIRTIO_RNG(qdev);
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
|
||||
VirtIORNG *vrng = VIRTIO_RNG(vdev);
|
||||
|
||||
timer_del(vrng->rate_limit_timer);
|
||||
timer_free(vrng->rate_limit_timer);
|
||||
unregister_savevm(qdev, "virtio-rng", vrng);
|
||||
unregister_savevm(DEVICE(vdev), "virtio-rng", vrng);
|
||||
virtio_cleanup(vdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Property virtio_rng_properties[] = {
|
||||
@@ -211,10 +209,10 @@ static void virtio_rng_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||
dc->exit = virtio_rng_device_exit;
|
||||
dc->props = virtio_rng_properties;
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
vdc->init = virtio_rng_device_init;
|
||||
vdc->exit = virtio_rng_device_exit;
|
||||
vdc->get_features = get_features;
|
||||
}
|
||||
|
||||
|
@@ -1158,14 +1158,19 @@ static int virtio_device_init(DeviceState *qdev)
|
||||
if (k->init(vdev) < 0) {
|
||||
return -1;
|
||||
}
|
||||
virtio_bus_plug_device(vdev);
|
||||
virtio_bus_device_plugged(vdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_device_exit(DeviceState *qdev)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
|
||||
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(qdev);
|
||||
|
||||
virtio_bus_device_unplugged(vdev);
|
||||
if (k->exit) {
|
||||
k->exit(vdev);
|
||||
}
|
||||
if (vdev->bus_name) {
|
||||
g_free(vdev->bus_name);
|
||||
vdev->bus_name = NULL;
|
||||
|
@@ -570,8 +570,7 @@ static void xen_pt_region_update(XenPCIPassthroughState *s,
|
||||
if (args.rc) {
|
||||
XEN_PT_WARN(d, "Region: %d (addr: %#"FMT_PCIBUS
|
||||
", len: %#"FMT_PCIBUS") is overlapped.\n",
|
||||
bar, sec->offset_within_address_space,
|
||||
int128_get64(sec->size));
|
||||
bar, sec->offset_within_address_space, sec->size);
|
||||
}
|
||||
|
||||
if (d->io_regions[bar].type & PCI_BASE_ADDRESS_SPACE_IO) {
|
||||
|
@@ -74,10 +74,6 @@ static int xen_pv_init(PCIDevice *pci_dev)
|
||||
XenPVDevice *d = XEN_PV_DEVICE(pci_dev);
|
||||
uint8_t *pci_conf;
|
||||
|
||||
/* device-id property must always be supplied */
|
||||
if (d->device_id == 0xffff)
|
||||
return -1;
|
||||
|
||||
pci_conf = pci_dev->config;
|
||||
|
||||
pci_set_word(pci_conf + PCI_VENDOR_ID, d->vendor_id);
|
||||
@@ -103,7 +99,7 @@ static int xen_pv_init(PCIDevice *pci_dev)
|
||||
|
||||
static Property xen_pv_props[] = {
|
||||
DEFINE_PROP_UINT16("vendor-id", XenPVDevice, vendor_id, PCI_VENDOR_ID_XEN),
|
||||
DEFINE_PROP_UINT16("device-id", XenPVDevice, device_id, 0xffff),
|
||||
DEFINE_PROP_UINT16("device-id", XenPVDevice, device_id, PCI_DEVICE_ID_XEN_PVDEVICE),
|
||||
DEFINE_PROP_UINT8("revision", XenPVDevice, revision, 0x01),
|
||||
DEFINE_PROP_UINT32("size", XenPVDevice, size, 0x400000),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
|
@@ -18,22 +18,6 @@ typedef struct BlockDriverInfo {
|
||||
/* offset at which the VM state can be saved (0 if not possible) */
|
||||
int64_t vm_state_offset;
|
||||
bool is_dirty;
|
||||
/*
|
||||
* True if unallocated blocks read back as zeroes. This is equivalent
|
||||
* to the the LBPRZ flag in the SCSI logical block provisioning page.
|
||||
*/
|
||||
bool unallocated_blocks_are_zero;
|
||||
/*
|
||||
* True if the driver can optimize writing zeroes by unmapping
|
||||
* sectors. This is equivalent to the BLKDISCARDZEROES ioctl in Linux
|
||||
* with the difference that in qemu a discard is allowed to silently
|
||||
* fail. Therefore we have to use bdrv_write_zeroes with the
|
||||
* BDRV_REQ_MAY_UNMAP flag for an optimized zero write with unmapping.
|
||||
* After this call the driver has to guarantee that the contents read
|
||||
* back as zero. It is additionally required that the block device is
|
||||
* opened with BDRV_O_UNMAP flag for this to work.
|
||||
*/
|
||||
bool can_write_zeroes_with_unmap;
|
||||
} BlockDriverInfo;
|
||||
|
||||
typedef struct BlockFragInfo {
|
||||
@@ -78,18 +62,6 @@ typedef struct BlockDevOps {
|
||||
void (*resize_cb)(void *opaque);
|
||||
} BlockDevOps;
|
||||
|
||||
typedef enum {
|
||||
BDRV_REQ_COPY_ON_READ = 0x1,
|
||||
BDRV_REQ_ZERO_WRITE = 0x2,
|
||||
/* The BDRV_REQ_MAY_UNMAP flag is used to indicate that the block driver
|
||||
* is allowed to optimize a write zeroes request by unmapping (discarding)
|
||||
* blocks if it is guaranteed that the result will read back as
|
||||
* zeroes. The flag is only passed to the driver if the block device is
|
||||
* opened with BDRV_O_UNMAP.
|
||||
*/
|
||||
BDRV_REQ_MAY_UNMAP = 0x4,
|
||||
} BdrvRequestFlags;
|
||||
|
||||
#define BDRV_O_RDWR 0x0002
|
||||
#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */
|
||||
#define BDRV_O_NOCACHE 0x0020 /* do not use the host page cache */
|
||||
@@ -215,11 +187,7 @@ int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num,
|
||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors);
|
||||
int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, BdrvRequestFlags flags);
|
||||
BlockDriverAIOCB *bdrv_aio_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, BdrvRequestFlags flags,
|
||||
BlockDriverCompletionFunc *cb, void *opaque);
|
||||
int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags);
|
||||
int nb_sectors);
|
||||
int bdrv_writev(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov);
|
||||
int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
||||
void *buf, int count);
|
||||
@@ -241,7 +209,7 @@ int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
* because it may allocate memory for the entire region.
|
||||
*/
|
||||
int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, BdrvRequestFlags flags);
|
||||
int nb_sectors);
|
||||
BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
|
||||
const char *backing_file);
|
||||
int bdrv_get_backing_file_depth(BlockDriverState *bs);
|
||||
@@ -314,7 +282,6 @@ typedef struct BlockRequest {
|
||||
/* Fields to be filled by multiwrite caller */
|
||||
int64_t sector;
|
||||
int nb_sectors;
|
||||
int flags;
|
||||
QEMUIOVector *qiov;
|
||||
BlockDriverCompletionFunc *cb;
|
||||
void *opaque;
|
||||
@@ -349,8 +316,6 @@ int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors);
|
||||
int bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors);
|
||||
int bdrv_has_zero_init_1(BlockDriverState *bs);
|
||||
int bdrv_has_zero_init(BlockDriverState *bs);
|
||||
bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs);
|
||||
bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs);
|
||||
int64_t bdrv_get_block_status(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, int *pnum);
|
||||
int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
||||
@@ -423,16 +388,12 @@ void *qemu_blockalign(BlockDriverState *bs, size_t size);
|
||||
bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov);
|
||||
|
||||
struct HBitmapIter;
|
||||
typedef struct BdrvDirtyBitmap BdrvDirtyBitmap;
|
||||
BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity);
|
||||
void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
|
||||
BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
|
||||
int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
|
||||
void bdrv_set_dirty_tracking(BlockDriverState *bs, int granularity);
|
||||
int bdrv_get_dirty(BlockDriverState *bs, int64_t sector);
|
||||
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);
|
||||
void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);
|
||||
void bdrv_dirty_iter_init(BlockDriverState *bs,
|
||||
BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
|
||||
int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
|
||||
void bdrv_dirty_iter_init(BlockDriverState *bs, struct HBitmapIter *hbi);
|
||||
int64_t bdrv_get_dirty_count(BlockDriverState *bs);
|
||||
|
||||
void bdrv_enable_copy_on_read(BlockDriverState *bs);
|
||||
void bdrv_disable_copy_on_read(BlockDriverState *bs);
|
||||
@@ -523,7 +484,6 @@ void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event);
|
||||
|
||||
int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
|
||||
const char *tag);
|
||||
int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag);
|
||||
int bdrv_debug_resume(BlockDriverState *bs, const char *tag);
|
||||
bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag);
|
||||
|
||||
|
@@ -53,7 +53,6 @@
|
||||
#define BLOCK_OPT_COMPAT_LEVEL "compat"
|
||||
#define BLOCK_OPT_LAZY_REFCOUNTS "lazy_refcounts"
|
||||
#define BLOCK_OPT_ADAPTER_TYPE "adapter_type"
|
||||
#define BLOCK_OPT_REDUNDANCY "redundancy"
|
||||
|
||||
typedef struct BdrvTrackedRequest {
|
||||
BlockDriverState *bs;
|
||||
@@ -131,7 +130,7 @@ struct BlockDriver {
|
||||
* instead.
|
||||
*/
|
||||
int coroutine_fn (*bdrv_co_write_zeroes)(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags);
|
||||
int64_t sector_num, int nb_sectors);
|
||||
int coroutine_fn (*bdrv_co_discard)(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors);
|
||||
int64_t coroutine_fn (*bdrv_co_get_block_status)(BlockDriverState *bs,
|
||||
@@ -176,9 +175,7 @@ struct BlockDriver {
|
||||
int (*bdrv_snapshot_list)(BlockDriverState *bs,
|
||||
QEMUSnapshotInfo **psn_info);
|
||||
int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs,
|
||||
const char *snapshot_id,
|
||||
const char *name,
|
||||
Error **errp);
|
||||
const char *snapshot_name);
|
||||
int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
|
||||
ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs);
|
||||
|
||||
@@ -221,8 +218,6 @@ struct BlockDriver {
|
||||
/* TODO Better pass a option string/QDict/QemuOpts to add any rule? */
|
||||
int (*bdrv_debug_breakpoint)(BlockDriverState *bs, const char *event,
|
||||
const char *tag);
|
||||
int (*bdrv_debug_remove_breakpoint)(BlockDriverState *bs,
|
||||
const char *tag);
|
||||
int (*bdrv_debug_resume)(BlockDriverState *bs, const char *tag);
|
||||
bool (*bdrv_debug_is_suspended)(BlockDriverState *bs, const char *tag);
|
||||
|
||||
@@ -235,23 +230,6 @@ struct BlockDriver {
|
||||
QLIST_ENTRY(BlockDriver) list;
|
||||
};
|
||||
|
||||
typedef struct BlockLimits {
|
||||
/* maximum number of sectors that can be discarded at once */
|
||||
int max_discard;
|
||||
|
||||
/* optimal alignment for discard requests in sectors */
|
||||
int64_t discard_alignment;
|
||||
|
||||
/* maximum number of sectors that can zeroized at once */
|
||||
int max_write_zeroes;
|
||||
|
||||
/* optimal alignment for write zeroes requests in sectors */
|
||||
int64_t write_zeroes_alignment;
|
||||
|
||||
/* optimal transfer length in sectors */
|
||||
int opt_transfer_length;
|
||||
} BlockLimits;
|
||||
|
||||
/*
|
||||
* Note: the function bdrv_append() copies and swaps contents of
|
||||
* BlockDriverStates, so if you add new fields to this struct, please
|
||||
@@ -305,9 +283,6 @@ struct BlockDriverState {
|
||||
uint64_t total_time_ns[BDRV_MAX_IOTYPE];
|
||||
uint64_t wr_highest_sector;
|
||||
|
||||
/* I/O Limits */
|
||||
BlockLimits bl;
|
||||
|
||||
/* Whether the disk can expand beyond total_sectors */
|
||||
int growable;
|
||||
|
||||
@@ -326,7 +301,7 @@ struct BlockDriverState {
|
||||
bool iostatus_enabled;
|
||||
BlockDeviceIoStatus iostatus;
|
||||
char device_name[32];
|
||||
QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps;
|
||||
HBitmap *dirty_bitmap;
|
||||
int refcnt;
|
||||
int in_use; /* users other than guest access, eg. block migration */
|
||||
QTAILQ_ENTRY(BlockDriverState) list;
|
||||
|
@@ -105,6 +105,7 @@ bool qemu_in_coroutine(void);
|
||||
*/
|
||||
typedef struct CoQueue {
|
||||
QTAILQ_HEAD(, Coroutine) entries;
|
||||
AioContext *ctx;
|
||||
} CoQueue;
|
||||
|
||||
/**
|
||||
@@ -119,6 +120,12 @@ void qemu_co_queue_init(CoQueue *queue);
|
||||
*/
|
||||
void coroutine_fn qemu_co_queue_wait(CoQueue *queue);
|
||||
|
||||
/**
|
||||
* Adds the current coroutine to the head of the CoQueue and transfers control to the
|
||||
* caller of the coroutine.
|
||||
*/
|
||||
void coroutine_fn qemu_co_queue_wait_insert_head(CoQueue *queue);
|
||||
|
||||
/**
|
||||
* Restarts the next coroutine in the CoQueue and removes it from the queue.
|
||||
*
|
||||
|
@@ -27,14 +27,6 @@
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/option.h"
|
||||
|
||||
|
||||
#define SNAPSHOT_OPT_BASE "snapshot."
|
||||
#define SNAPSHOT_OPT_ID "snapshot.id"
|
||||
#define SNAPSHOT_OPT_NAME "snapshot.name"
|
||||
|
||||
extern QemuOptsList internal_snapshot_opts;
|
||||
|
||||
typedef struct QEMUSnapshotInfo {
|
||||
char id_str[128]; /* unique snapshot id */
|
||||
@@ -69,10 +61,5 @@ void bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs,
|
||||
int bdrv_snapshot_list(BlockDriverState *bs,
|
||||
QEMUSnapshotInfo **psn_info);
|
||||
int bdrv_snapshot_load_tmp(BlockDriverState *bs,
|
||||
const char *snapshot_id,
|
||||
const char *name,
|
||||
Error **errp);
|
||||
int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
|
||||
const char *id_or_name,
|
||||
Error **errp);
|
||||
const char *snapshot_name);
|
||||
#endif
|
||||
|
@@ -411,65 +411,6 @@ typedef struct {
|
||||
#define R_SPARC_5 44
|
||||
#define R_SPARC_6 45
|
||||
|
||||
/* Bits present in AT_HWCAP for ARM. */
|
||||
|
||||
#define HWCAP_ARM_SWP (1 << 0)
|
||||
#define HWCAP_ARM_HALF (1 << 1)
|
||||
#define HWCAP_ARM_THUMB (1 << 2)
|
||||
#define HWCAP_ARM_26BIT (1 << 3)
|
||||
#define HWCAP_ARM_FAST_MULT (1 << 4)
|
||||
#define HWCAP_ARM_FPA (1 << 5)
|
||||
#define HWCAP_ARM_VFP (1 << 6)
|
||||
#define HWCAP_ARM_EDSP (1 << 7)
|
||||
#define HWCAP_ARM_JAVA (1 << 8)
|
||||
#define HWCAP_ARM_IWMMXT (1 << 9)
|
||||
#define HWCAP_ARM_CRUNCH (1 << 10)
|
||||
#define HWCAP_ARM_THUMBEE (1 << 11)
|
||||
#define HWCAP_ARM_NEON (1 << 12)
|
||||
#define HWCAP_ARM_VFPv3 (1 << 13)
|
||||
#define HWCAP_ARM_VFPv3D16 (1 << 14) /* also set for VFPv4-D16 */
|
||||
#define HWCAP_ARM_TLS (1 << 15)
|
||||
#define HWCAP_ARM_VFPv4 (1 << 16)
|
||||
#define HWCAP_ARM_IDIVA (1 << 17)
|
||||
#define HWCAP_ARM_IDIVT (1 << 18)
|
||||
#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)
|
||||
#define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs */
|
||||
#define HWCAP_LPAE (1 << 20)
|
||||
|
||||
/* Bits present in AT_HWCAP for PowerPC. */
|
||||
|
||||
#define PPC_FEATURE_32 0x80000000
|
||||
#define PPC_FEATURE_64 0x40000000
|
||||
#define PPC_FEATURE_601_INSTR 0x20000000
|
||||
#define PPC_FEATURE_HAS_ALTIVEC 0x10000000
|
||||
#define PPC_FEATURE_HAS_FPU 0x08000000
|
||||
#define PPC_FEATURE_HAS_MMU 0x04000000
|
||||
#define PPC_FEATURE_HAS_4xxMAC 0x02000000
|
||||
#define PPC_FEATURE_UNIFIED_CACHE 0x01000000
|
||||
#define PPC_FEATURE_HAS_SPE 0x00800000
|
||||
#define PPC_FEATURE_HAS_EFP_SINGLE 0x00400000
|
||||
#define PPC_FEATURE_HAS_EFP_DOUBLE 0x00200000
|
||||
#define PPC_FEATURE_NO_TB 0x00100000
|
||||
#define PPC_FEATURE_POWER4 0x00080000
|
||||
#define PPC_FEATURE_POWER5 0x00040000
|
||||
#define PPC_FEATURE_POWER5_PLUS 0x00020000
|
||||
#define PPC_FEATURE_CELL 0x00010000
|
||||
#define PPC_FEATURE_BOOKE 0x00008000
|
||||
#define PPC_FEATURE_SMT 0x00004000
|
||||
#define PPC_FEATURE_ICACHE_SNOOP 0x00002000
|
||||
#define PPC_FEATURE_ARCH_2_05 0x00001000
|
||||
#define PPC_FEATURE_PA6T 0x00000800
|
||||
#define PPC_FEATURE_HAS_DFP 0x00000400
|
||||
#define PPC_FEATURE_POWER6_EXT 0x00000200
|
||||
#define PPC_FEATURE_ARCH_2_06 0x00000100
|
||||
#define PPC_FEATURE_HAS_VSX 0x00000080
|
||||
|
||||
#define PPC_FEATURE_PSERIES_PERFMON_COMPAT \
|
||||
0x00000040
|
||||
|
||||
#define PPC_FEATURE_TRUE_LE 0x00000002
|
||||
#define PPC_FEATURE_PPC_LE 0x00000001
|
||||
|
||||
/* Bits present in AT_HWCAP, primarily for Sparc32. */
|
||||
|
||||
#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */
|
||||
@@ -479,20 +420,6 @@ typedef struct {
|
||||
#define HWCAP_SPARC_V9 16
|
||||
#define HWCAP_SPARC_ULTRA3 32
|
||||
|
||||
/* Bits present in AT_HWCAP for s390. */
|
||||
|
||||
#define HWCAP_S390_ESAN3 1
|
||||
#define HWCAP_S390_ZARCH 2
|
||||
#define HWCAP_S390_STFLE 4
|
||||
#define HWCAP_S390_MSA 8
|
||||
#define HWCAP_S390_LDISP 16
|
||||
#define HWCAP_S390_EIMM 32
|
||||
#define HWCAP_S390_DFP 64
|
||||
#define HWCAP_S390_HPAGE 128
|
||||
#define HWCAP_S390_ETF3EH 256
|
||||
#define HWCAP_S390_HIGH_GPRS 512
|
||||
#define HWCAP_S390_TE 1024
|
||||
|
||||
/*
|
||||
* 68k ELF relocation types
|
||||
*/
|
||||
|
@@ -65,13 +65,13 @@ struct SerialState {
|
||||
/* Interrupt trigger level for recv_fifo */
|
||||
uint8_t recv_fifo_itl;
|
||||
|
||||
QEMUTimer *fifo_timeout_timer;
|
||||
struct QEMUTimer *fifo_timeout_timer;
|
||||
int timeout_ipending; /* timeout interrupt pending state */
|
||||
|
||||
uint64_t char_transmit_time; /* time to transmit a char in ticks */
|
||||
int poll_msl;
|
||||
|
||||
QEMUTimer *modem_status_poll;
|
||||
struct QEMUTimer *modem_status_poll;
|
||||
MemoryRegion io;
|
||||
};
|
||||
|
||||
|
@@ -128,17 +128,9 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
|
||||
#define PCI_HOST_PROP_PCI_HOLE64_SIZE "pci-hole64-size"
|
||||
#define DEFAULT_PCI_HOLE64_SIZE (~0x0ULL)
|
||||
|
||||
static inline uint64_t pci_host_get_hole64_size(uint64_t pci_hole64_size)
|
||||
{
|
||||
if (pci_hole64_size == DEFAULT_PCI_HOLE64_SIZE) {
|
||||
return 1ULL << 62;
|
||||
} else {
|
||||
return pci_hole64_size;
|
||||
}
|
||||
}
|
||||
|
||||
void pc_init_pci64_hole(PcPciInfo *pci_info, uint64_t pci_hole64_start,
|
||||
uint64_t pci_hole64_size);
|
||||
void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory,
|
||||
MemoryRegion *pci_address_space);
|
||||
|
||||
FWCfgState *pc_memory_init(MemoryRegion *system_memory,
|
||||
const char *kernel_filename,
|
||||
@@ -187,8 +179,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn,
|
||||
MemoryRegion *address_space_mem,
|
||||
MemoryRegion *address_space_io,
|
||||
ram_addr_t ram_size,
|
||||
hwaddr pci_hole_start,
|
||||
hwaddr pci_hole_size,
|
||||
ram_addr_t below_4g_mem_size,
|
||||
ram_addr_t above_4g_mem_size,
|
||||
MemoryRegion *pci_memory,
|
||||
MemoryRegion *ram_memory);
|
||||
|
@@ -53,8 +53,6 @@ typedef struct MCHPCIState {
|
||||
MemoryRegion *address_space_io;
|
||||
PAMMemoryRegion pam_regions[13];
|
||||
MemoryRegion smram_region;
|
||||
MemoryRegion pci_hole;
|
||||
MemoryRegion pci_hole_64bit;
|
||||
PcPciInfo pci_info;
|
||||
uint8_t smm_enabled;
|
||||
ram_addr_t below_4g_mem_size;
|
||||
|
@@ -146,6 +146,7 @@
|
||||
|
||||
#define PCI_VENDOR_ID_XEN 0x5853
|
||||
#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001
|
||||
#define PCI_DEVICE_ID_XEN_PVDEVICE 0x0002
|
||||
|
||||
#define PCI_VENDOR_ID_NEC 0x1033
|
||||
#define PCI_DEVICE_ID_NEC_UPD720200 0x0194
|
||||
|
@@ -24,10 +24,10 @@ struct ppc_tb_t {
|
||||
/* Decrementer management */
|
||||
uint64_t decr_next; /* Tick for next decr interrupt */
|
||||
uint32_t decr_freq; /* decrementer frequency */
|
||||
QEMUTimer *decr_timer;
|
||||
struct QEMUTimer *decr_timer;
|
||||
/* Hypervisor decrementer management */
|
||||
uint64_t hdecr_next; /* Tick for next hdecr interrupt */
|
||||
QEMUTimer *hdecr_timer;
|
||||
struct QEMUTimer *hdecr_timer;
|
||||
uint64_t purr_load;
|
||||
uint64_t purr_start;
|
||||
void *opaque;
|
||||
|
@@ -199,16 +199,12 @@ extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
|
||||
extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
|
||||
/* Illegal request, medium removal prevented */
|
||||
extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
|
||||
/* Illegal request, Invalid Transfer Tag */
|
||||
extern const struct SCSISense sense_code_INVALID_TAG;
|
||||
/* Command aborted, I/O process terminated */
|
||||
extern const struct SCSISense sense_code_IO_ERROR;
|
||||
/* Command aborted, I_T Nexus loss occurred */
|
||||
extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
|
||||
/* Command aborted, Logical Unit failure */
|
||||
extern const struct SCSISense sense_code_LUN_FAILURE;
|
||||
/* Command aborted, Overlapped Commands Attempted */
|
||||
extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS;
|
||||
/* LUN not ready, Capacity data has changed */
|
||||
extern const struct SCSISense sense_code_CAPACITY_CHANGED;
|
||||
/* LUN not ready, Medium not present */
|
||||
|
@@ -13,6 +13,8 @@
|
||||
#ifndef QEMU_HPET_EMUL_H
|
||||
#define QEMU_HPET_EMUL_H
|
||||
|
||||
#include "qom/object.h"
|
||||
|
||||
#define HPET_BASE 0xfed00000
|
||||
#define HPET_CLK_PERIOD 10000000ULL /* 10000000 femtoseconds == 10ns*/
|
||||
|
||||
@@ -72,5 +74,11 @@ struct hpet_fw_config
|
||||
|
||||
extern struct hpet_fw_config hpet_cfg;
|
||||
|
||||
bool hpet_find(void);
|
||||
#define TYPE_HPET "hpet"
|
||||
|
||||
static inline bool hpet_find(void)
|
||||
{
|
||||
return object_resolve_path_type("", TYPE_HPET, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -102,26 +102,17 @@
|
||||
|
||||
#define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
|
||||
#define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
|
||||
#define VendorDeviceRequest ((USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
|
||||
#define VendorDeviceOutRequest \
|
||||
((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
|
||||
|
||||
#define InterfaceRequest \
|
||||
#define InterfaceRequest \
|
||||
((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
|
||||
#define InterfaceOutRequest \
|
||||
((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
|
||||
#define EndpointRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
|
||||
#define EndpointOutRequest \
|
||||
((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
|
||||
#define ClassInterfaceRequest \
|
||||
((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)<<8)
|
||||
#define ClassInterfaceOutRequest \
|
||||
((USB_DIR_OUT|USB_TYPE_CLASS|USB_RECIP_INTERFACE)<<8)
|
||||
#define VendorInterfaceRequest \
|
||||
((USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE)<<8)
|
||||
#define VendorInterfaceOutRequest \
|
||||
((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE)<<8)
|
||||
|
||||
#define EndpointRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
|
||||
#define EndpointOutRequest \
|
||||
((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
|
||||
|
||||
#define USB_REQ_GET_STATUS 0x00
|
||||
#define USB_REQ_CLEAR_FEATURE 0x01
|
||||
@@ -198,7 +189,6 @@ struct USBEndpoint {
|
||||
uint8_t type;
|
||||
uint8_t ifnum;
|
||||
int max_packet_size;
|
||||
int max_streams;
|
||||
bool pipeline;
|
||||
bool halted;
|
||||
USBDevice *dev;
|
||||
@@ -324,14 +314,6 @@ typedef struct USBDeviceClass {
|
||||
*/
|
||||
void (*ep_stopped)(USBDevice *dev, USBEndpoint *ep);
|
||||
|
||||
/*
|
||||
* Called by the hcd to alloc / free streams on a bulk endpoint.
|
||||
* Optional may be NULL.
|
||||
*/
|
||||
int (*alloc_streams)(USBDevice *dev, USBEndpoint **eps, int nr_eps,
|
||||
int streams);
|
||||
void (*free_streams)(USBDevice *dev, USBEndpoint **eps, int nr_eps);
|
||||
|
||||
const char *product_desc;
|
||||
const USBDesc *usb_desc;
|
||||
} USBDeviceClass;
|
||||
@@ -439,8 +421,6 @@ void usb_ep_set_ifnum(USBDevice *dev, int pid, int ep, uint8_t ifnum);
|
||||
void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
|
||||
uint16_t raw);
|
||||
int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep);
|
||||
void usb_ep_set_max_streams(USBDevice *dev, int pid, int ep, uint8_t raw);
|
||||
int usb_ep_get_max_streams(USBDevice *dev, int pid, int ep);
|
||||
void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled);
|
||||
void usb_ep_set_halted(USBDevice *dev, int pid, int ep, bool halted);
|
||||
USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
|
||||
@@ -570,10 +550,6 @@ void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep);
|
||||
|
||||
void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep);
|
||||
|
||||
int usb_device_alloc_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps,
|
||||
int streams);
|
||||
void usb_device_free_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps);
|
||||
|
||||
const char *usb_device_get_product_desc(USBDevice *dev);
|
||||
|
||||
const USBDesc *usb_device_get_usb_desc(USBDevice *dev);
|
||||
|
@@ -61,7 +61,7 @@ typedef struct VirtioBusClass {
|
||||
* transport independent exit function.
|
||||
* This is called by virtio-bus just before the device is unplugged.
|
||||
*/
|
||||
void (*device_unplug)(DeviceState *d);
|
||||
void (*device_unplugged)(DeviceState *d);
|
||||
/*
|
||||
* Does the transport have variable vring alignment?
|
||||
* (ie can it ever call virtio_queue_set_align()?)
|
||||
@@ -72,15 +72,11 @@ typedef struct VirtioBusClass {
|
||||
|
||||
struct VirtioBusState {
|
||||
BusState parent_obj;
|
||||
/*
|
||||
* Only one VirtIODevice can be plugged on the bus.
|
||||
*/
|
||||
VirtIODevice *vdev;
|
||||
};
|
||||
|
||||
int virtio_bus_plug_device(VirtIODevice *vdev);
|
||||
int virtio_bus_device_plugged(VirtIODevice *vdev);
|
||||
void virtio_bus_reset(VirtioBusState *bus);
|
||||
void virtio_bus_destroy_device(VirtioBusState *bus);
|
||||
void virtio_bus_device_unplugged(VirtIODevice *bus);
|
||||
/* Get the device id of the plugged device. */
|
||||
uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus);
|
||||
/* Get the config_len field of the plugged device. */
|
||||
@@ -98,4 +94,16 @@ void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config);
|
||||
/* Set config of the plugged device. */
|
||||
void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config);
|
||||
|
||||
static inline VirtIODevice *virtio_bus_get_device(VirtioBusState *bus)
|
||||
{
|
||||
BusState *qbus = &bus->parent_obj;
|
||||
BusChild *kid = QTAILQ_FIRST(&qbus->children);
|
||||
DeviceState *qdev = kid ? kid->child : NULL;
|
||||
|
||||
/* This is used on the data path, the cast is guaranteed
|
||||
* to succeed by the qdev machinery.
|
||||
*/
|
||||
return (VirtIODevice *)qdev;
|
||||
}
|
||||
|
||||
#endif /* VIRTIO_BUS_H */
|
||||
|
@@ -187,6 +187,6 @@ typedef struct {
|
||||
VIRTIO_SCSI_F_CHANGE, true)
|
||||
|
||||
int virtio_scsi_common_init(VirtIOSCSICommon *vs);
|
||||
int virtio_scsi_common_exit(VirtIOSCSICommon *vs);
|
||||
void virtio_scsi_common_exit(VirtIOSCSICommon *vs);
|
||||
|
||||
#endif /* _QEMU_VIRTIO_SCSI_H */
|
||||
|
@@ -127,6 +127,7 @@ typedef struct VirtioDeviceClass {
|
||||
/* This is what a VirtioDevice must implement */
|
||||
DeviceClass parent;
|
||||
int (*init)(VirtIODevice *vdev);
|
||||
void (*exit)(VirtIODevice *vdev);
|
||||
uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features);
|
||||
uint32_t (*bad_features)(VirtIODevice *vdev);
|
||||
void (*set_features)(VirtIODevice *vdev, uint32_t val);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user