Compare commits
78 Commits
pull-ui-20
...
pull-vga-2
Author | SHA1 | Date | |
---|---|---|---|
|
321c9adba5 | ||
|
0c55a1cfd3 | ||
|
3eb769fd1c | ||
|
8d94c1ca53 | ||
|
bba19b88a6 | ||
|
cb9ab7caae | ||
|
c65db7705b | ||
|
8983b670f6 | ||
|
f8aa905a4f | ||
|
3bb1e822ca | ||
|
c7fc50d376 | ||
|
16b0d55586 | ||
|
9e43034008 | ||
|
ac987b30d0 | ||
|
e0f100f57c | ||
|
d0a18f1025 | ||
|
7429e20788 | ||
|
8bfb137152 | ||
|
d234c92931 | ||
|
53f1dfd1ff | ||
|
ddf4987d76 | ||
|
3399833f14 | ||
|
02650acbc6 | ||
|
178b4db7e5 | ||
|
3064bf6fff | ||
|
67a0fd2a9b | ||
|
1963f8d52e | ||
|
c78dc18295 | ||
|
15a2b18fe5 | ||
|
ca9bd24cf1 | ||
|
d8da3cef3b | ||
|
9c4218e957 | ||
|
2c1d04e002 | ||
|
64dff52019 | ||
|
938abd4325 | ||
|
13855c6b9f | ||
|
033cb5659a | ||
|
741cc43133 | ||
|
5b9e0e4693 | ||
|
1b1e0659a4 | ||
|
3301f6c6e9 | ||
|
16dee4183a | ||
|
c5acdc9ab4 | ||
|
e43f7f6f46 | ||
|
34250395fe | ||
|
15cfba693b | ||
|
4a940d14b3 | ||
|
dd170c0677 | ||
|
60d446881d | ||
|
d1f9cd7084 | ||
|
05d0fce497 | ||
|
d3780c2dce | ||
|
cc8c46b7c5 | ||
|
3db1d98a20 | ||
|
327032ce74 | ||
|
abb3e55b5b | ||
|
12c7ec87a7 | ||
|
8f3a73bc57 | ||
|
d2ea854c38 | ||
|
baa3f63827 | ||
|
958e369360 | ||
|
dce0238c74 | ||
|
074d1ccb42 | ||
|
5a8660741a | ||
|
49d925ce50 | ||
|
c0377a7cc6 | ||
|
6086a565b0 | ||
|
6db2625572 | ||
|
9940c3236f | ||
|
fd47bfe5ad | ||
|
00ffc3c166 | ||
|
ea53854a54 | ||
|
1760048a5d | ||
|
47213eb110 | ||
|
2c64846972 | ||
|
a907ec52cc | ||
|
9884abee8f | ||
|
07982d2ee9 |
@@ -21,6 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include <alsa/asoundlib.h>
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/main-loop.h"
|
||||
|
@@ -21,6 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "audio.h"
|
||||
#include "monitor/monitor.h"
|
||||
|
@@ -1,3 +1,4 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
/* public domain */
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
|
||||
#define AUDIO_CAP "win-int"
|
||||
|
@@ -22,8 +22,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
#include <string.h> /* strerror */
|
||||
#include <pthread.h> /* pthread_X */
|
||||
|
||||
#include "qemu-common.h"
|
||||
|
@@ -26,6 +26,7 @@
|
||||
* SEAL 1.07 by Carlos 'pel' Hasan was used as documentation
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
|
||||
|
@@ -22,6 +22,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
|
||||
|
@@ -21,6 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
#include "qemu/timer.h"
|
||||
|
@@ -21,9 +21,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include "qemu/osdep.h"
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/soundcard.h>
|
||||
#include "qemu-common.h"
|
||||
|
@@ -1,4 +1,5 @@
|
||||
/* public domain */
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
|
||||
|
@@ -21,6 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include <SDL.h>
|
||||
#include <SDL_thread.h>
|
||||
#include "qemu-common.h"
|
||||
|
@@ -17,6 +17,7 @@
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/timer.h"
|
||||
|
@@ -21,6 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "audio.h"
|
||||
|
@@ -1,3 +1,4 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
114
block.c
114
block.c
@@ -79,6 +79,9 @@ struct BdrvStates bdrv_states = QTAILQ_HEAD_INITIALIZER(bdrv_states);
|
||||
static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states =
|
||||
QTAILQ_HEAD_INITIALIZER(graph_bdrv_states);
|
||||
|
||||
static QTAILQ_HEAD(, BlockDriverState) all_bdrv_states =
|
||||
QTAILQ_HEAD_INITIALIZER(all_bdrv_states);
|
||||
|
||||
static QLIST_HEAD(, BlockDriver) bdrv_drivers =
|
||||
QLIST_HEAD_INITIALIZER(bdrv_drivers);
|
||||
|
||||
@@ -88,9 +91,13 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
|
||||
const BdrvChildRole *child_role, Error **errp);
|
||||
|
||||
static void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
|
||||
static void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs);
|
||||
|
||||
/* If non-zero, use only whitelisted block drivers */
|
||||
static int use_bdrv_whitelist;
|
||||
|
||||
static void bdrv_close(BlockDriverState *bs);
|
||||
|
||||
#ifdef _WIN32
|
||||
static int is_windows_drive_prefix(const char *filename)
|
||||
{
|
||||
@@ -257,19 +264,15 @@ BlockDriverState *bdrv_new(void)
|
||||
for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
|
||||
QLIST_INIT(&bs->op_blockers[i]);
|
||||
}
|
||||
notifier_list_init(&bs->close_notifiers);
|
||||
notifier_with_return_list_init(&bs->before_write_notifiers);
|
||||
qemu_co_queue_init(&bs->throttled_reqs[0]);
|
||||
qemu_co_queue_init(&bs->throttled_reqs[1]);
|
||||
bs->refcnt = 1;
|
||||
bs->aio_context = qemu_get_aio_context();
|
||||
|
||||
return bs;
|
||||
}
|
||||
QTAILQ_INSERT_TAIL(&all_bdrv_states, bs, bs_list);
|
||||
|
||||
void bdrv_add_close_notifier(BlockDriverState *bs, Notifier *notify)
|
||||
{
|
||||
notifier_list_add(&bs->close_notifiers, notify);
|
||||
return bs;
|
||||
}
|
||||
|
||||
BlockDriver *bdrv_find_format(const char *format_name)
|
||||
@@ -2138,13 +2141,11 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state)
|
||||
}
|
||||
|
||||
|
||||
void bdrv_close(BlockDriverState *bs)
|
||||
static void bdrv_close(BlockDriverState *bs)
|
||||
{
|
||||
BdrvAioNotifier *ban, *ban_next;
|
||||
|
||||
if (bs->job) {
|
||||
block_job_cancel_sync(bs->job);
|
||||
}
|
||||
assert(!bs->job);
|
||||
|
||||
/* Disable I/O limits and drain all pending throttled requests */
|
||||
if (bs->throttle_state) {
|
||||
@@ -2155,7 +2156,8 @@ void bdrv_close(BlockDriverState *bs)
|
||||
bdrv_flush(bs);
|
||||
bdrv_drain(bs); /* in case flush left pending I/O */
|
||||
|
||||
notifier_list_notify(&bs->close_notifiers, bs);
|
||||
bdrv_release_named_dirty_bitmaps(bs);
|
||||
assert(QLIST_EMPTY(&bs->dirty_bitmaps));
|
||||
|
||||
if (bs->blk) {
|
||||
blk_dev_change_media_cb(bs->blk, false);
|
||||
@@ -2210,31 +2212,55 @@ void bdrv_close(BlockDriverState *bs)
|
||||
void bdrv_close_all(void)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
AioContext *aio_context;
|
||||
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
/* Drop references from requests still in flight, such as canceled block
|
||||
* jobs whose AIO context has not been polled yet */
|
||||
bdrv_drain_all();
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
bdrv_close(bs);
|
||||
aio_context_release(aio_context);
|
||||
blk_remove_all_bs();
|
||||
blockdev_close_all_bdrv_states();
|
||||
|
||||
/* Cancel all block jobs */
|
||||
while (!QTAILQ_EMPTY(&all_bdrv_states)) {
|
||||
QTAILQ_FOREACH(bs, &all_bdrv_states, bs_list) {
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
if (bs->job) {
|
||||
block_job_cancel_sync(bs->job);
|
||||
aio_context_release(aio_context);
|
||||
break;
|
||||
}
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
/* All the remaining BlockDriverStates are referenced directly or
|
||||
* indirectly from block jobs, so there needs to be at least one BDS
|
||||
* directly used by a block job */
|
||||
assert(bs);
|
||||
}
|
||||
}
|
||||
|
||||
/* Note that bs->device_list.tqe_prev is initially null,
|
||||
* and gets set to non-null by QTAILQ_INSERT_TAIL(). Establish
|
||||
* the useful invariant "bs in bdrv_states iff bs->tqe_prev" by
|
||||
* resetting it to null on remove. */
|
||||
void bdrv_device_remove(BlockDriverState *bs)
|
||||
{
|
||||
QTAILQ_REMOVE(&bdrv_states, bs, device_list);
|
||||
bs->device_list.tqe_prev = NULL;
|
||||
}
|
||||
|
||||
/* make a BlockDriverState anonymous by removing from bdrv_state and
|
||||
* graph_bdrv_state list.
|
||||
Also, NULL terminate the device_name to prevent double remove */
|
||||
void bdrv_make_anon(BlockDriverState *bs)
|
||||
{
|
||||
/*
|
||||
* Take care to remove bs from bdrv_states only when it's actually
|
||||
* in it. Note that bs->device_list.tqe_prev is initially null,
|
||||
* and gets set to non-null by QTAILQ_INSERT_TAIL(). Establish
|
||||
* the useful invariant "bs in bdrv_states iff bs->tqe_prev" by
|
||||
* resetting it to null on remove.
|
||||
*/
|
||||
/* Take care to remove bs from bdrv_states only when it's actually
|
||||
* in it. */
|
||||
if (bs->device_list.tqe_prev) {
|
||||
QTAILQ_REMOVE(&bdrv_states, bs, device_list);
|
||||
bs->device_list.tqe_prev = NULL;
|
||||
bdrv_device_remove(bs);
|
||||
}
|
||||
if (bs->node_name[0] != '\0') {
|
||||
QTAILQ_REMOVE(&graph_bdrv_states, bs, node_list);
|
||||
@@ -2275,7 +2301,7 @@ static void change_parent_backing_link(BlockDriverState *from,
|
||||
if (!to->device_list.tqe_prev) {
|
||||
QTAILQ_INSERT_BEFORE(from, to, device_list);
|
||||
}
|
||||
QTAILQ_REMOVE(&bdrv_states, from, device_list);
|
||||
bdrv_device_remove(from);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2366,13 +2392,14 @@ static void bdrv_delete(BlockDriverState *bs)
|
||||
assert(!bs->job);
|
||||
assert(bdrv_op_blocker_is_empty(bs));
|
||||
assert(!bs->refcnt);
|
||||
assert(QLIST_EMPTY(&bs->dirty_bitmaps));
|
||||
|
||||
bdrv_close(bs);
|
||||
|
||||
/* remove from list, if necessary */
|
||||
bdrv_make_anon(bs);
|
||||
|
||||
QTAILQ_REMOVE(&all_bdrv_states, bs, bs_list);
|
||||
|
||||
g_free(bs);
|
||||
}
|
||||
|
||||
@@ -3582,21 +3609,40 @@ static void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
|
||||
static void bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs,
|
||||
BdrvDirtyBitmap *bitmap,
|
||||
bool only_named)
|
||||
{
|
||||
BdrvDirtyBitmap *bm, *next;
|
||||
QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
|
||||
if (bm == bitmap) {
|
||||
if ((!bitmap || bm == bitmap) && (!only_named || bm->name)) {
|
||||
assert(!bdrv_dirty_bitmap_frozen(bm));
|
||||
QLIST_REMOVE(bitmap, list);
|
||||
hbitmap_free(bitmap->bitmap);
|
||||
g_free(bitmap->name);
|
||||
g_free(bitmap);
|
||||
return;
|
||||
QLIST_REMOVE(bm, list);
|
||||
hbitmap_free(bm->bitmap);
|
||||
g_free(bm->name);
|
||||
g_free(bm);
|
||||
|
||||
if (bitmap) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
bdrv_do_release_matching_dirty_bitmap(bs, bitmap, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()).
|
||||
* There must not be any frozen bitmaps attached.
|
||||
*/
|
||||
static void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs)
|
||||
{
|
||||
bdrv_do_release_matching_dirty_bitmap(bs, NULL, true);
|
||||
}
|
||||
|
||||
void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
assert(!bdrv_dirty_bitmap_frozen(bitmap));
|
||||
|
@@ -49,6 +49,8 @@ struct BlockBackend {
|
||||
BlockdevOnError on_read_error, on_write_error;
|
||||
bool iostatus_enabled;
|
||||
BlockDeviceIoStatus iostatus;
|
||||
|
||||
NotifierList remove_bs_notifiers, insert_bs_notifiers;
|
||||
};
|
||||
|
||||
typedef struct BlockBackendAIOCB {
|
||||
@@ -99,6 +101,8 @@ BlockBackend *blk_new(const char *name, Error **errp)
|
||||
blk = g_new0(BlockBackend, 1);
|
||||
blk->name = g_strdup(name);
|
||||
blk->refcnt = 1;
|
||||
notifier_list_init(&blk->remove_bs_notifiers);
|
||||
notifier_list_init(&blk->insert_bs_notifiers);
|
||||
QTAILQ_INSERT_TAIL(&blk_backends, blk, link);
|
||||
return blk;
|
||||
}
|
||||
@@ -162,11 +166,10 @@ static void blk_delete(BlockBackend *blk)
|
||||
assert(!blk->refcnt);
|
||||
assert(!blk->dev);
|
||||
if (blk->bs) {
|
||||
assert(blk->bs->blk == blk);
|
||||
blk->bs->blk = NULL;
|
||||
bdrv_unref(blk->bs);
|
||||
blk->bs = NULL;
|
||||
blk_remove_bs(blk);
|
||||
}
|
||||
assert(QLIST_EMPTY(&blk->remove_bs_notifiers.notifiers));
|
||||
assert(QLIST_EMPTY(&blk->insert_bs_notifiers.notifiers));
|
||||
if (blk->root_state.throttle_state) {
|
||||
g_free(blk->root_state.throttle_group);
|
||||
throttle_group_unref(blk->root_state.throttle_state);
|
||||
@@ -220,6 +223,21 @@ void blk_unref(BlockBackend *blk)
|
||||
}
|
||||
}
|
||||
|
||||
void blk_remove_all_bs(void)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
|
||||
QTAILQ_FOREACH(blk, &blk_backends, link) {
|
||||
AioContext *ctx = blk_get_aio_context(blk);
|
||||
|
||||
aio_context_acquire(ctx);
|
||||
if (blk->bs) {
|
||||
blk_remove_bs(blk);
|
||||
}
|
||||
aio_context_release(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the BlockBackend after @blk.
|
||||
* If @blk is null, return the first one.
|
||||
@@ -345,6 +363,10 @@ void blk_hide_on_behalf_of_hmp_drive_del(BlockBackend *blk)
|
||||
*/
|
||||
void blk_remove_bs(BlockBackend *blk)
|
||||
{
|
||||
assert(blk->bs->blk == blk);
|
||||
|
||||
notifier_list_notify(&blk->remove_bs_notifiers, blk);
|
||||
|
||||
blk_update_root_state(blk);
|
||||
|
||||
blk->bs->blk = NULL;
|
||||
@@ -361,6 +383,8 @@ void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
|
||||
bdrv_ref(bs);
|
||||
blk->bs = bs;
|
||||
bs->blk = blk;
|
||||
|
||||
notifier_list_notify(&blk->insert_bs_notifiers, blk);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -458,6 +482,14 @@ bool blk_dev_has_removable_media(BlockBackend *blk)
|
||||
return !blk->dev || (blk->dev_ops && blk->dev_ops->change_media_cb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Does @blk's attached device model have a tray?
|
||||
*/
|
||||
bool blk_dev_has_tray(BlockBackend *blk)
|
||||
{
|
||||
return blk->dev_ops && blk->dev_ops->is_tray_open;
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify @blk's attached device model of a media eject request.
|
||||
* If @force is true, the medium is about to be yanked out forcefully.
|
||||
@@ -474,7 +506,7 @@ void blk_dev_eject_request(BlockBackend *blk, bool force)
|
||||
*/
|
||||
bool blk_dev_is_tray_open(BlockBackend *blk)
|
||||
{
|
||||
if (blk->dev_ops && blk->dev_ops->is_tray_open) {
|
||||
if (blk_dev_has_tray(blk)) {
|
||||
return blk->dev_ops->is_tray_open(blk->dev_opaque);
|
||||
}
|
||||
return false;
|
||||
@@ -1118,11 +1150,14 @@ void blk_remove_aio_context_notifier(BlockBackend *blk,
|
||||
}
|
||||
}
|
||||
|
||||
void blk_add_close_notifier(BlockBackend *blk, Notifier *notify)
|
||||
void blk_add_remove_bs_notifier(BlockBackend *blk, Notifier *notify)
|
||||
{
|
||||
if (blk->bs) {
|
||||
bdrv_add_close_notifier(blk->bs, notify);
|
||||
}
|
||||
notifier_list_add(&blk->remove_bs_notifiers, notify);
|
||||
}
|
||||
|
||||
void blk_add_insert_bs_notifier(BlockBackend *blk, Notifier *notify)
|
||||
{
|
||||
notifier_list_add(&blk->insert_bs_notifiers, notify);
|
||||
}
|
||||
|
||||
void blk_io_plug(BlockBackend *blk)
|
||||
|
44
block/io.c
44
block/io.c
@@ -664,6 +664,7 @@ int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||
int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
|
||||
{
|
||||
int64_t target_sectors, ret, nb_sectors, sector_num = 0;
|
||||
BlockDriverState *file;
|
||||
int n;
|
||||
|
||||
target_sectors = bdrv_nb_sectors(bs);
|
||||
@@ -676,7 +677,7 @@ int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
|
||||
if (nb_sectors <= 0) {
|
||||
return 0;
|
||||
}
|
||||
ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n);
|
||||
ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n, &file);
|
||||
if (ret < 0) {
|
||||
error_report("error getting block status at sector %" PRId64 ": %s",
|
||||
sector_num, strerror(-ret));
|
||||
@@ -1466,6 +1467,7 @@ int bdrv_flush_all(void)
|
||||
typedef struct BdrvCoGetBlockStatusData {
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *base;
|
||||
BlockDriverState **file;
|
||||
int64_t sector_num;
|
||||
int nb_sectors;
|
||||
int *pnum;
|
||||
@@ -1487,10 +1489,14 @@ typedef struct BdrvCoGetBlockStatusData {
|
||||
*
|
||||
* 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes
|
||||
* beyond the end of the disk image it will be clamped.
|
||||
*
|
||||
* If returned value is positive and BDRV_BLOCK_OFFSET_VALID bit is set, 'file'
|
||||
* points to the BDS which the sector range is allocated in.
|
||||
*/
|
||||
static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
int nb_sectors, int *pnum,
|
||||
BlockDriverState **file)
|
||||
{
|
||||
int64_t total_sectors;
|
||||
int64_t n;
|
||||
@@ -1520,7 +1526,9 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum);
|
||||
*file = NULL;
|
||||
ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum,
|
||||
file);
|
||||
if (ret < 0) {
|
||||
*pnum = 0;
|
||||
return ret;
|
||||
@@ -1529,7 +1537,7 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
||||
if (ret & BDRV_BLOCK_RAW) {
|
||||
assert(ret & BDRV_BLOCK_OFFSET_VALID);
|
||||
return bdrv_get_block_status(bs->file->bs, ret >> BDRV_SECTOR_BITS,
|
||||
*pnum, pnum);
|
||||
*pnum, pnum, file);
|
||||
}
|
||||
|
||||
if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
|
||||
@@ -1546,13 +1554,14 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
||||
}
|
||||
}
|
||||
|
||||
if (bs->file &&
|
||||
if (*file && *file != bs &&
|
||||
(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) &&
|
||||
(ret & BDRV_BLOCK_OFFSET_VALID)) {
|
||||
BlockDriverState *file2;
|
||||
int file_pnum;
|
||||
|
||||
ret2 = bdrv_co_get_block_status(bs->file->bs, ret >> BDRV_SECTOR_BITS,
|
||||
*pnum, &file_pnum);
|
||||
ret2 = bdrv_co_get_block_status(*file, ret >> BDRV_SECTOR_BITS,
|
||||
*pnum, &file_pnum, &file2);
|
||||
if (ret2 >= 0) {
|
||||
/* Ignore errors. This is just providing extra information, it
|
||||
* is useful but not necessary.
|
||||
@@ -1577,14 +1586,15 @@ static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs,
|
||||
BlockDriverState *base,
|
||||
int64_t sector_num,
|
||||
int nb_sectors,
|
||||
int *pnum)
|
||||
int *pnum,
|
||||
BlockDriverState **file)
|
||||
{
|
||||
BlockDriverState *p;
|
||||
int64_t ret = 0;
|
||||
|
||||
assert(bs != base);
|
||||
for (p = bs; p != base; p = backing_bs(p)) {
|
||||
ret = bdrv_co_get_block_status(p, sector_num, nb_sectors, pnum);
|
||||
ret = bdrv_co_get_block_status(p, sector_num, nb_sectors, pnum, file);
|
||||
if (ret < 0 || ret & BDRV_BLOCK_ALLOCATED) {
|
||||
break;
|
||||
}
|
||||
@@ -1603,7 +1613,8 @@ static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
|
||||
data->ret = bdrv_co_get_block_status_above(data->bs, data->base,
|
||||
data->sector_num,
|
||||
data->nb_sectors,
|
||||
data->pnum);
|
||||
data->pnum,
|
||||
data->file);
|
||||
data->done = true;
|
||||
}
|
||||
|
||||
@@ -1615,12 +1626,14 @@ static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
|
||||
int64_t bdrv_get_block_status_above(BlockDriverState *bs,
|
||||
BlockDriverState *base,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
int nb_sectors, int *pnum,
|
||||
BlockDriverState **file)
|
||||
{
|
||||
Coroutine *co;
|
||||
BdrvCoGetBlockStatusData data = {
|
||||
.bs = bs,
|
||||
.base = base,
|
||||
.file = file,
|
||||
.sector_num = sector_num,
|
||||
.nb_sectors = nb_sectors,
|
||||
.pnum = pnum,
|
||||
@@ -1644,16 +1657,19 @@ int64_t bdrv_get_block_status_above(BlockDriverState *bs,
|
||||
|
||||
int64_t bdrv_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
int nb_sectors, int *pnum,
|
||||
BlockDriverState **file)
|
||||
{
|
||||
return bdrv_get_block_status_above(bs, backing_bs(bs),
|
||||
sector_num, nb_sectors, pnum);
|
||||
sector_num, nb_sectors, pnum, file);
|
||||
}
|
||||
|
||||
int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
int64_t ret = bdrv_get_block_status(bs, sector_num, nb_sectors, pnum);
|
||||
BlockDriverState *file;
|
||||
int64_t ret = bdrv_get_block_status(bs, sector_num, nb_sectors, pnum,
|
||||
&file);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
@@ -532,7 +532,8 @@ static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun,
|
||||
|
||||
static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
int nb_sectors, int *pnum,
|
||||
BlockDriverState **file)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct scsi_get_lba_status *lbas = NULL;
|
||||
@@ -624,6 +625,9 @@ out:
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
}
|
||||
if (ret > 0 && ret & BDRV_BLOCK_OFFSET_VALID) {
|
||||
*file = bs;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -650,7 +654,8 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
||||
!iscsi_allocationmap_is_allocated(iscsilun, sector_num, nb_sectors)) {
|
||||
int64_t ret;
|
||||
int pnum;
|
||||
ret = iscsi_co_get_block_status(bs, sector_num, INT_MAX, &pnum);
|
||||
BlockDriverState *file;
|
||||
ret = iscsi_co_get_block_status(bs, sector_num, INT_MAX, &pnum, &file);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
@@ -168,6 +168,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
MirrorOp *op;
|
||||
int pnum;
|
||||
int64_t ret;
|
||||
BlockDriverState *file;
|
||||
|
||||
max_iov = MIN(source->bl.max_iov, s->target->bl.max_iov);
|
||||
|
||||
@@ -306,7 +307,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
trace_mirror_one_iteration(s, sector_num, nb_sectors);
|
||||
|
||||
ret = bdrv_get_block_status_above(source, NULL, sector_num,
|
||||
nb_sectors, &pnum);
|
||||
nb_sectors, &pnum, &file);
|
||||
if (ret < 0 || pnum < nb_sectors ||
|
||||
(ret & BDRV_BLOCK_DATA && !(ret & BDRV_BLOCK_ZERO))) {
|
||||
bdrv_aio_readv(source, sector_num, &op->qiov, nb_sectors,
|
||||
|
@@ -261,7 +261,7 @@ static coroutine_fn int parallels_co_flush_to_os(BlockDriverState *bs)
|
||||
|
||||
|
||||
static int64_t coroutine_fn parallels_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, int *pnum)
|
||||
int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
|
||||
{
|
||||
BDRVParallelsState *s = bs->opaque;
|
||||
int64_t offset;
|
||||
@@ -274,6 +274,7 @@ static int64_t coroutine_fn parallels_co_get_block_status(BlockDriverState *bs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
*file = bs->file->bs;
|
||||
return (offset << BDRV_SECTOR_BITS) |
|
||||
BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
|
||||
}
|
||||
|
11
block/qapi.c
11
block/qapi.c
@@ -211,11 +211,13 @@ void bdrv_query_image_info(BlockDriverState *bs,
|
||||
Error *err = NULL;
|
||||
ImageInfo *info;
|
||||
|
||||
aio_context_acquire(bdrv_get_aio_context(bs));
|
||||
|
||||
size = bdrv_getlength(bs);
|
||||
if (size < 0) {
|
||||
error_setg_errno(errp, -size, "Can't get size of device '%s'",
|
||||
bdrv_get_device_name(bs));
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
info = g_new0(ImageInfo, 1);
|
||||
@@ -283,10 +285,13 @@ void bdrv_query_image_info(BlockDriverState *bs,
|
||||
default:
|
||||
error_propagate(errp, err);
|
||||
qapi_free_ImageInfo(info);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*p_info = info;
|
||||
|
||||
out:
|
||||
aio_context_release(bdrv_get_aio_context(bs));
|
||||
}
|
||||
|
||||
/* @p_info will be set only on success. */
|
||||
@@ -300,7 +305,7 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
|
||||
info->locked = blk_dev_is_medium_locked(blk);
|
||||
info->removable = blk_dev_has_removable_media(blk);
|
||||
|
||||
if (blk_dev_has_removable_media(blk)) {
|
||||
if (blk_dev_has_tray(blk)) {
|
||||
info->has_tray_open = true;
|
||||
info->tray_open = blk_dev_is_tray_open(blk);
|
||||
}
|
||||
|
@@ -489,7 +489,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
static int64_t coroutine_fn qcow_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, int *pnum)
|
||||
int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int index_in_cluster, n;
|
||||
@@ -510,6 +510,7 @@ static int64_t coroutine_fn qcow_co_get_block_status(BlockDriverState *bs,
|
||||
return BDRV_BLOCK_DATA;
|
||||
}
|
||||
cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS);
|
||||
*file = bs->file->bs;
|
||||
return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | cluster_offset;
|
||||
}
|
||||
|
||||
|
@@ -1330,7 +1330,7 @@ static void qcow2_join_options(QDict *options, QDict *old_options)
|
||||
}
|
||||
|
||||
static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, int *pnum)
|
||||
int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
uint64_t cluster_offset;
|
||||
@@ -1349,6 +1349,7 @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
|
||||
!s->cipher) {
|
||||
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
||||
cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS);
|
||||
*file = bs->file->bs;
|
||||
status |= BDRV_BLOCK_OFFSET_VALID | cluster_offset;
|
||||
}
|
||||
if (ret == QCOW2_CLUSTER_ZERO) {
|
||||
|
@@ -693,6 +693,7 @@ typedef struct {
|
||||
uint64_t pos;
|
||||
int64_t status;
|
||||
int *pnum;
|
||||
BlockDriverState **file;
|
||||
} QEDIsAllocatedCB;
|
||||
|
||||
static void qed_is_allocated_cb(void *opaque, int ret, uint64_t offset, size_t len)
|
||||
@@ -704,6 +705,7 @@ static void qed_is_allocated_cb(void *opaque, int ret, uint64_t offset, size_t l
|
||||
case QED_CLUSTER_FOUND:
|
||||
offset |= qed_offset_into_cluster(s, cb->pos);
|
||||
cb->status = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | offset;
|
||||
*cb->file = cb->bs->file->bs;
|
||||
break;
|
||||
case QED_CLUSTER_ZERO:
|
||||
cb->status = BDRV_BLOCK_ZERO;
|
||||
@@ -725,7 +727,8 @@ static void qed_is_allocated_cb(void *opaque, int ret, uint64_t offset, size_t l
|
||||
|
||||
static int64_t coroutine_fn bdrv_qed_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
int nb_sectors, int *pnum,
|
||||
BlockDriverState **file)
|
||||
{
|
||||
BDRVQEDState *s = bs->opaque;
|
||||
size_t len = (size_t)nb_sectors * BDRV_SECTOR_SIZE;
|
||||
@@ -734,6 +737,7 @@ static int64_t coroutine_fn bdrv_qed_co_get_block_status(BlockDriverState *bs,
|
||||
.pos = (uint64_t)sector_num * BDRV_SECTOR_SIZE,
|
||||
.status = BDRV_BLOCK_OFFSET_MASK,
|
||||
.pnum = pnum,
|
||||
.file = file,
|
||||
};
|
||||
QEDRequest request = { .l2_table = NULL };
|
||||
|
||||
|
@@ -1818,7 +1818,8 @@ static int find_allocation(BlockDriverState *bs, off_t start,
|
||||
*/
|
||||
static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
int nb_sectors, int *pnum,
|
||||
BlockDriverState **file)
|
||||
{
|
||||
off_t start, data = 0, hole = 0;
|
||||
int64_t total_size;
|
||||
@@ -1860,6 +1861,7 @@ static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
||||
*pnum = MIN(nb_sectors, (data - start) / BDRV_SECTOR_SIZE);
|
||||
ret = BDRV_BLOCK_ZERO;
|
||||
}
|
||||
*file = bs;
|
||||
return ret | BDRV_BLOCK_OFFSET_VALID | start;
|
||||
}
|
||||
|
||||
|
@@ -115,9 +115,11 @@ fail:
|
||||
|
||||
static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
int nb_sectors, int *pnum,
|
||||
BlockDriverState **file)
|
||||
{
|
||||
*pnum = nb_sectors;
|
||||
*file = bs->file->bs;
|
||||
return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | BDRV_BLOCK_DATA |
|
||||
(sector_num << BDRV_SECTOR_BITS);
|
||||
}
|
||||
|
@@ -2708,7 +2708,7 @@ retry:
|
||||
|
||||
static coroutine_fn int64_t
|
||||
sd_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
||||
int *pnum)
|
||||
int *pnum, BlockDriverState **file)
|
||||
{
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
SheepdogInode *inode = &s->inode;
|
||||
@@ -2739,6 +2739,9 @@ sd_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
||||
if (*pnum > nb_sectors) {
|
||||
*pnum = nb_sectors;
|
||||
}
|
||||
if (ret > 0 && ret & BDRV_BLOCK_OFFSET_VALID) {
|
||||
*file = bs;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@@ -527,7 +527,7 @@ static int vdi_reopen_prepare(BDRVReopenState *state,
|
||||
}
|
||||
|
||||
static int64_t coroutine_fn vdi_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, int *pnum)
|
||||
int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
|
||||
{
|
||||
/* TODO: Check for too large sector_num (in bdrv_is_allocated or here). */
|
||||
BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
|
||||
@@ -551,6 +551,7 @@ static int64_t coroutine_fn vdi_co_get_block_status(BlockDriverState *bs,
|
||||
offset = s->header.offset_data +
|
||||
(uint64_t)bmap_entry * s->block_size +
|
||||
sector_in_block * SECTOR_SIZE;
|
||||
*file = bs->file->bs;
|
||||
return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | offset;
|
||||
}
|
||||
|
||||
|
18
block/vmdk.c
18
block/vmdk.c
@@ -571,6 +571,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
VmdkExtent *extent;
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
int64_t l1_backup_offset = 0;
|
||||
bool compressed;
|
||||
|
||||
ret = bdrv_pread(file->bs, sizeof(magic), &header, sizeof(header));
|
||||
if (ret < 0) {
|
||||
@@ -645,6 +646,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
header = footer.header;
|
||||
}
|
||||
|
||||
compressed =
|
||||
le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE;
|
||||
if (le32_to_cpu(header.version) > 3) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "VMDK version %" PRId32,
|
||||
@@ -652,7 +655,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
error_setg(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bdrv_get_device_or_node_name(bs), "vmdk", buf);
|
||||
return -ENOTSUP;
|
||||
} else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR)) {
|
||||
} else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR) &&
|
||||
!compressed) {
|
||||
/* 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
|
||||
@@ -1257,7 +1261,7 @@ static inline uint64_t vmdk_find_index_in_cluster(VmdkExtent *extent,
|
||||
}
|
||||
|
||||
static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, int *pnum)
|
||||
int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
int64_t index_in_cluster, n, ret;
|
||||
@@ -1274,6 +1278,7 @@ static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
|
||||
0, 0);
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
|
||||
index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num);
|
||||
switch (ret) {
|
||||
case VMDK_ERROR:
|
||||
ret = -EIO;
|
||||
@@ -1286,14 +1291,15 @@ static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
|
||||
break;
|
||||
case VMDK_OK:
|
||||
ret = BDRV_BLOCK_DATA;
|
||||
if (extent->file == bs->file && !extent->compressed) {
|
||||
ret |= BDRV_BLOCK_OFFSET_VALID | offset;
|
||||
if (!extent->compressed) {
|
||||
ret |= BDRV_BLOCK_OFFSET_VALID;
|
||||
ret |= (offset + (index_in_cluster << BDRV_SECTOR_BITS))
|
||||
& BDRV_BLOCK_OFFSET_MASK;
|
||||
}
|
||||
|
||||
*file = extent->file->bs;
|
||||
break;
|
||||
}
|
||||
|
||||
index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num);
|
||||
n = extent->cluster_sectors - index_in_cluster;
|
||||
if (n > nb_sectors) {
|
||||
n = nb_sectors;
|
||||
|
@@ -579,7 +579,7 @@ static coroutine_fn int vpc_co_write(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
|
||||
static int64_t coroutine_fn vpc_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, int *pnum)
|
||||
int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
|
||||
{
|
||||
BDRVVPCState *s = bs->opaque;
|
||||
VHDFooter *footer = (VHDFooter*) s->footer_buf;
|
||||
@@ -589,6 +589,7 @@ static int64_t coroutine_fn vpc_co_get_block_status(BlockDriverState *bs,
|
||||
|
||||
if (be32_to_cpu(footer->type) == VHD_FIXED) {
|
||||
*pnum = nb_sectors;
|
||||
*file = bs->file->bs;
|
||||
return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | BDRV_BLOCK_DATA |
|
||||
(sector_num << BDRV_SECTOR_BITS);
|
||||
}
|
||||
@@ -610,6 +611,7 @@ static int64_t coroutine_fn vpc_co_get_block_status(BlockDriverState *bs,
|
||||
/* *pnum can't be greater than one block for allocated
|
||||
* sectors since there is always a bitmap in between. */
|
||||
if (allocated) {
|
||||
*file = bs->file->bs;
|
||||
return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
|
||||
}
|
||||
if (nb_sectors == 0) {
|
||||
|
@@ -2884,7 +2884,7 @@ static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
|
||||
static int64_t coroutine_fn vvfat_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, int* n)
|
||||
int64_t sector_num, int nb_sectors, int *n, BlockDriverState **file)
|
||||
{
|
||||
BDRVVVFATState* s = bs->opaque;
|
||||
*n = s->sector_count - sector_num;
|
||||
|
@@ -45,37 +45,11 @@ void qmp_nbd_server_start(SocketAddress *addr, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Hook into the BlockBackend notifiers to close the export when the
|
||||
* backend is closed.
|
||||
*/
|
||||
typedef struct NBDCloseNotifier {
|
||||
Notifier n;
|
||||
NBDExport *exp;
|
||||
QTAILQ_ENTRY(NBDCloseNotifier) next;
|
||||
} NBDCloseNotifier;
|
||||
|
||||
static QTAILQ_HEAD(, NBDCloseNotifier) close_notifiers =
|
||||
QTAILQ_HEAD_INITIALIZER(close_notifiers);
|
||||
|
||||
static void nbd_close_notifier(Notifier *n, void *data)
|
||||
{
|
||||
NBDCloseNotifier *cn = DO_UPCAST(NBDCloseNotifier, n, n);
|
||||
|
||||
notifier_remove(&cn->n);
|
||||
QTAILQ_REMOVE(&close_notifiers, cn, next);
|
||||
|
||||
nbd_export_close(cn->exp);
|
||||
nbd_export_put(cn->exp);
|
||||
g_free(cn);
|
||||
}
|
||||
|
||||
void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
|
||||
Error **errp)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
NBDExport *exp;
|
||||
NBDCloseNotifier *n;
|
||||
|
||||
if (server_fd == -1) {
|
||||
error_setg(errp, "NBD server not running");
|
||||
@@ -113,19 +87,15 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
|
||||
|
||||
nbd_export_set_name(exp, device);
|
||||
|
||||
n = g_new0(NBDCloseNotifier, 1);
|
||||
n->n.notify = nbd_close_notifier;
|
||||
n->exp = exp;
|
||||
blk_add_close_notifier(blk, &n->n);
|
||||
QTAILQ_INSERT_TAIL(&close_notifiers, n, next);
|
||||
/* The list of named exports has a strong reference to this export now and
|
||||
* our only way of accessing it is through nbd_export_find(), so we can drop
|
||||
* the strong reference that is @exp. */
|
||||
nbd_export_put(exp);
|
||||
}
|
||||
|
||||
void qmp_nbd_server_stop(Error **errp)
|
||||
{
|
||||
while (!QTAILQ_EMPTY(&close_notifiers)) {
|
||||
NBDCloseNotifier *cn = QTAILQ_FIRST(&close_notifiers);
|
||||
nbd_close_notifier(&cn->n, nbd_export_get_blockdev(cn->exp));
|
||||
}
|
||||
nbd_export_close_all();
|
||||
|
||||
if (server_fd != -1) {
|
||||
qemu_set_fd_handler(server_fd, NULL, NULL, NULL);
|
||||
|
64
blockdev.c
64
blockdev.c
@@ -50,6 +50,9 @@
|
||||
#include "trace.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
|
||||
static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states =
|
||||
QTAILQ_HEAD_INITIALIZER(monitor_bdrv_states);
|
||||
|
||||
static const char *const if_name[IF_COUNT] = {
|
||||
[IF_NONE] = "none",
|
||||
[IF_IDE] = "ide",
|
||||
@@ -702,6 +705,19 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void blockdev_close_all_bdrv_states(void)
|
||||
{
|
||||
BlockDriverState *bs, *next_bs;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(bs, &monitor_bdrv_states, monitor_list, next_bs) {
|
||||
AioContext *ctx = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_context_acquire(ctx);
|
||||
bdrv_unref(bs);
|
||||
aio_context_release(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -2304,6 +2320,11 @@ void qmp_blockdev_open_tray(const char *device, bool has_force, bool force,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blk_dev_has_tray(blk)) {
|
||||
/* Ignore this command on tray-less devices */
|
||||
return;
|
||||
}
|
||||
|
||||
if (blk_dev_is_tray_open(blk)) {
|
||||
return;
|
||||
}
|
||||
@@ -2334,6 +2355,11 @@ void qmp_blockdev_close_tray(const char *device, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blk_dev_has_tray(blk)) {
|
||||
/* Ignore this command on tray-less devices */
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blk_dev_is_tray_open(blk)) {
|
||||
return;
|
||||
}
|
||||
@@ -2363,7 +2389,7 @@ void qmp_x_blockdev_remove_medium(const char *device, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_device && !blk_dev_is_tray_open(blk)) {
|
||||
if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
|
||||
error_setg(errp, "Tray of device '%s' is not open", device);
|
||||
return;
|
||||
}
|
||||
@@ -2382,12 +2408,19 @@ void qmp_x_blockdev_remove_medium(const char *device, Error **errp)
|
||||
|
||||
/* This follows the convention established by bdrv_make_anon() */
|
||||
if (bs->device_list.tqe_prev) {
|
||||
QTAILQ_REMOVE(&bdrv_states, bs, device_list);
|
||||
bs->device_list.tqe_prev = NULL;
|
||||
bdrv_device_remove(bs);
|
||||
}
|
||||
|
||||
blk_remove_bs(blk);
|
||||
|
||||
if (!blk_dev_has_tray(blk)) {
|
||||
/* For tray-less devices, blockdev-open-tray is a no-op (or may not be
|
||||
* called at all); therefore, the medium needs to be ejected here.
|
||||
* Do it after blk_remove_bs() so blk_is_inserted(blk) returns the @load
|
||||
* value passed here (i.e. false). */
|
||||
blk_dev_change_media_cb(blk, false);
|
||||
}
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
@@ -2413,7 +2446,7 @@ static void qmp_blockdev_insert_anon_medium(const char *device,
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_device && !blk_dev_is_tray_open(blk)) {
|
||||
if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
|
||||
error_setg(errp, "Tray of device '%s' is not open", device);
|
||||
return;
|
||||
}
|
||||
@@ -2426,6 +2459,15 @@ static void qmp_blockdev_insert_anon_medium(const char *device,
|
||||
blk_insert_bs(blk, bs);
|
||||
|
||||
QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list);
|
||||
|
||||
if (!blk_dev_has_tray(blk)) {
|
||||
/* For tray-less devices, blockdev-close-tray is a no-op (or may not be
|
||||
* called at all); therefore, the medium needs to be pushed into the
|
||||
* slot here.
|
||||
* Do it after blk_insert_bs() so blk_is_inserted(blk) returns the @load
|
||||
* value passed here (i.e. true). */
|
||||
blk_dev_change_media_cb(blk, true);
|
||||
}
|
||||
}
|
||||
|
||||
void qmp_x_blockdev_insert_medium(const char *device, const char *node_name,
|
||||
@@ -2765,7 +2807,7 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_close(bs);
|
||||
blk_remove_bs(blk);
|
||||
}
|
||||
|
||||
/* if we have a device attached to this BlockDriverState
|
||||
@@ -3848,12 +3890,15 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
||||
if (!bs) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
QTAILQ_INSERT_TAIL(&monitor_bdrv_states, bs, monitor_list);
|
||||
}
|
||||
|
||||
if (bs && bdrv_key_required(bs)) {
|
||||
if (blk) {
|
||||
blk_unref(blk);
|
||||
} else {
|
||||
QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list);
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
error_setg(errp, "blockdev-add doesn't support encrypted devices");
|
||||
@@ -3913,7 +3958,13 @@ void qmp_x_blockdev_del(bool has_id, const char *id,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bs->refcnt > 1 || !QLIST_EMPTY(&bs->parents)) {
|
||||
if (!blk && !bs->monitor_list.tqe_prev) {
|
||||
error_setg(errp, "Node %s is not owned by the monitor",
|
||||
bs->node_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bs->refcnt > 1) {
|
||||
error_setg(errp, "Block device %s is in use",
|
||||
bdrv_get_device_or_node_name(bs));
|
||||
goto out;
|
||||
@@ -3923,6 +3974,7 @@ void qmp_x_blockdev_del(bool has_id, const char *id,
|
||||
if (blk) {
|
||||
blk_unref(blk);
|
||||
} else {
|
||||
QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list);
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
|
||||
|
@@ -278,14 +278,6 @@ void block_job_iostatus_reset(BlockJob *job)
|
||||
}
|
||||
}
|
||||
|
||||
struct BlockFinishData {
|
||||
BlockJob *job;
|
||||
BlockCompletionFunc *cb;
|
||||
void *opaque;
|
||||
bool cancelled;
|
||||
int ret;
|
||||
};
|
||||
|
||||
static int block_job_finish_sync(BlockJob *job,
|
||||
void (*finish)(BlockJob *, Error **errp),
|
||||
Error **errp)
|
||||
|
@@ -24,12 +24,8 @@
|
||||
#ifdef CONFIG_GNUTLS_HASH
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <gnutls/crypto.h>
|
||||
#endif
|
||||
|
||||
static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG__MAX] = {
|
||||
[QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5,
|
||||
[QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1,
|
||||
[QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256,
|
||||
};
|
||||
|
||||
static size_t qcrypto_hash_alg_size[QCRYPTO_HASH_ALG__MAX] = {
|
||||
[QCRYPTO_HASH_ALG_MD5] = 16,
|
||||
@@ -37,6 +33,22 @@ static size_t qcrypto_hash_alg_size[QCRYPTO_HASH_ALG__MAX] = {
|
||||
[QCRYPTO_HASH_ALG_SHA256] = 32,
|
||||
};
|
||||
|
||||
size_t qcrypto_hash_digest_len(QCryptoHashAlgorithm alg)
|
||||
{
|
||||
if (alg >= G_N_ELEMENTS(qcrypto_hash_alg_size)) {
|
||||
return 0;
|
||||
}
|
||||
return qcrypto_hash_alg_size[alg];
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_GNUTLS_HASH
|
||||
static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG__MAX] = {
|
||||
[QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5,
|
||||
[QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1,
|
||||
[QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256,
|
||||
};
|
||||
|
||||
gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
|
||||
{
|
||||
if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map)) {
|
||||
@@ -45,14 +57,6 @@ gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t qcrypto_hash_digest_len(QCryptoHashAlgorithm alg)
|
||||
{
|
||||
if (alg >= G_N_ELEMENTS(qcrypto_hash_alg_size)) {
|
||||
return 0;
|
||||
}
|
||||
return qcrypto_hash_alg_size[alg];
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
|
||||
const struct iovec *iov,
|
||||
|
@@ -352,38 +352,6 @@ qcrypto_secret_complete(UserCreatable *uc, Error **errp)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_secret_init(Object *obj)
|
||||
{
|
||||
object_property_add_bool(obj, "loaded",
|
||||
qcrypto_secret_prop_get_loaded,
|
||||
qcrypto_secret_prop_set_loaded,
|
||||
NULL);
|
||||
object_property_add_enum(obj, "format",
|
||||
"QCryptoSecretFormat",
|
||||
QCryptoSecretFormat_lookup,
|
||||
qcrypto_secret_prop_get_format,
|
||||
qcrypto_secret_prop_set_format,
|
||||
NULL);
|
||||
object_property_add_str(obj, "data",
|
||||
qcrypto_secret_prop_get_data,
|
||||
qcrypto_secret_prop_set_data,
|
||||
NULL);
|
||||
object_property_add_str(obj, "file",
|
||||
qcrypto_secret_prop_get_file,
|
||||
qcrypto_secret_prop_set_file,
|
||||
NULL);
|
||||
object_property_add_str(obj, "keyid",
|
||||
qcrypto_secret_prop_get_keyid,
|
||||
qcrypto_secret_prop_set_keyid,
|
||||
NULL);
|
||||
object_property_add_str(obj, "iv",
|
||||
qcrypto_secret_prop_get_iv,
|
||||
qcrypto_secret_prop_set_iv,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_secret_finalize(Object *obj)
|
||||
{
|
||||
@@ -402,6 +370,33 @@ qcrypto_secret_class_init(ObjectClass *oc, void *data)
|
||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||
|
||||
ucc->complete = qcrypto_secret_complete;
|
||||
|
||||
object_class_property_add_bool(oc, "loaded",
|
||||
qcrypto_secret_prop_get_loaded,
|
||||
qcrypto_secret_prop_set_loaded,
|
||||
NULL);
|
||||
object_class_property_add_enum(oc, "format",
|
||||
"QCryptoSecretFormat",
|
||||
QCryptoSecretFormat_lookup,
|
||||
qcrypto_secret_prop_get_format,
|
||||
qcrypto_secret_prop_set_format,
|
||||
NULL);
|
||||
object_class_property_add_str(oc, "data",
|
||||
qcrypto_secret_prop_get_data,
|
||||
qcrypto_secret_prop_set_data,
|
||||
NULL);
|
||||
object_class_property_add_str(oc, "file",
|
||||
qcrypto_secret_prop_get_file,
|
||||
qcrypto_secret_prop_set_file,
|
||||
NULL);
|
||||
object_class_property_add_str(oc, "keyid",
|
||||
qcrypto_secret_prop_get_keyid,
|
||||
qcrypto_secret_prop_set_keyid,
|
||||
NULL);
|
||||
object_class_property_add_str(oc, "iv",
|
||||
qcrypto_secret_prop_get_iv,
|
||||
qcrypto_secret_prop_set_iv,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -493,7 +488,6 @@ static const TypeInfo qcrypto_secret_info = {
|
||||
.parent = TYPE_OBJECT,
|
||||
.name = TYPE_QCRYPTO_SECRET,
|
||||
.instance_size = sizeof(QCryptoSecret),
|
||||
.instance_init = qcrypto_secret_init,
|
||||
.instance_finalize = qcrypto_secret_finalize,
|
||||
.class_size = sizeof(QCryptoSecretClass),
|
||||
.class_init = qcrypto_secret_class_init,
|
||||
|
@@ -198,27 +198,32 @@ qcrypto_tls_creds_prop_get_endpoint(Object *obj,
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_tls_creds_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
object_class_property_add_bool(oc, "verify-peer",
|
||||
qcrypto_tls_creds_prop_get_verify,
|
||||
qcrypto_tls_creds_prop_set_verify,
|
||||
NULL);
|
||||
object_class_property_add_str(oc, "dir",
|
||||
qcrypto_tls_creds_prop_get_dir,
|
||||
qcrypto_tls_creds_prop_set_dir,
|
||||
NULL);
|
||||
object_class_property_add_enum(oc, "endpoint",
|
||||
"QCryptoTLSCredsEndpoint",
|
||||
QCryptoTLSCredsEndpoint_lookup,
|
||||
qcrypto_tls_creds_prop_get_endpoint,
|
||||
qcrypto_tls_creds_prop_set_endpoint,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_tls_creds_init(Object *obj)
|
||||
{
|
||||
QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
|
||||
|
||||
creds->verifyPeer = true;
|
||||
|
||||
object_property_add_bool(obj, "verify-peer",
|
||||
qcrypto_tls_creds_prop_get_verify,
|
||||
qcrypto_tls_creds_prop_set_verify,
|
||||
NULL);
|
||||
object_property_add_str(obj, "dir",
|
||||
qcrypto_tls_creds_prop_get_dir,
|
||||
qcrypto_tls_creds_prop_set_dir,
|
||||
NULL);
|
||||
object_property_add_enum(obj, "endpoint",
|
||||
"QCryptoTLSCredsEndpoint",
|
||||
QCryptoTLSCredsEndpoint_lookup,
|
||||
qcrypto_tls_creds_prop_get_endpoint,
|
||||
qcrypto_tls_creds_prop_set_endpoint,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -237,6 +242,7 @@ static const TypeInfo qcrypto_tls_creds_info = {
|
||||
.instance_size = sizeof(QCryptoTLSCreds),
|
||||
.instance_init = qcrypto_tls_creds_init,
|
||||
.instance_finalize = qcrypto_tls_creds_finalize,
|
||||
.class_init = qcrypto_tls_creds_class_init,
|
||||
.class_size = sizeof(QCryptoTLSCredsClass),
|
||||
.abstract = true,
|
||||
};
|
||||
|
@@ -171,16 +171,6 @@ qcrypto_tls_creds_anon_complete(UserCreatable *uc, Error **errp)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_tls_creds_anon_init(Object *obj)
|
||||
{
|
||||
object_property_add_bool(obj, "loaded",
|
||||
qcrypto_tls_creds_anon_prop_get_loaded,
|
||||
qcrypto_tls_creds_anon_prop_set_loaded,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_tls_creds_anon_finalize(Object *obj)
|
||||
{
|
||||
@@ -196,6 +186,11 @@ qcrypto_tls_creds_anon_class_init(ObjectClass *oc, void *data)
|
||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||
|
||||
ucc->complete = qcrypto_tls_creds_anon_complete;
|
||||
|
||||
object_class_property_add_bool(oc, "loaded",
|
||||
qcrypto_tls_creds_anon_prop_get_loaded,
|
||||
qcrypto_tls_creds_anon_prop_set_loaded,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -203,7 +198,6 @@ static const TypeInfo qcrypto_tls_creds_anon_info = {
|
||||
.parent = TYPE_QCRYPTO_TLS_CREDS,
|
||||
.name = TYPE_QCRYPTO_TLS_CREDS_ANON,
|
||||
.instance_size = sizeof(QCryptoTLSCredsAnon),
|
||||
.instance_init = qcrypto_tls_creds_anon_init,
|
||||
.instance_finalize = qcrypto_tls_creds_anon_finalize,
|
||||
.class_size = sizeof(QCryptoTLSCredsAnonClass),
|
||||
.class_init = qcrypto_tls_creds_anon_class_init,
|
||||
|
@@ -804,19 +804,6 @@ qcrypto_tls_creds_x509_init(Object *obj)
|
||||
QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
|
||||
|
||||
creds->sanityCheck = true;
|
||||
|
||||
object_property_add_bool(obj, "loaded",
|
||||
qcrypto_tls_creds_x509_prop_get_loaded,
|
||||
qcrypto_tls_creds_x509_prop_set_loaded,
|
||||
NULL);
|
||||
object_property_add_bool(obj, "sanity-check",
|
||||
qcrypto_tls_creds_x509_prop_get_sanity,
|
||||
qcrypto_tls_creds_x509_prop_set_sanity,
|
||||
NULL);
|
||||
object_property_add_str(obj, "passwordid",
|
||||
qcrypto_tls_creds_x509_prop_get_passwordid,
|
||||
qcrypto_tls_creds_x509_prop_set_passwordid,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -836,6 +823,19 @@ qcrypto_tls_creds_x509_class_init(ObjectClass *oc, void *data)
|
||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||
|
||||
ucc->complete = qcrypto_tls_creds_x509_complete;
|
||||
|
||||
object_class_property_add_bool(oc, "loaded",
|
||||
qcrypto_tls_creds_x509_prop_get_loaded,
|
||||
qcrypto_tls_creds_x509_prop_set_loaded,
|
||||
NULL);
|
||||
object_class_property_add_bool(oc, "sanity-check",
|
||||
qcrypto_tls_creds_x509_prop_get_sanity,
|
||||
qcrypto_tls_creds_x509_prop_set_sanity,
|
||||
NULL);
|
||||
object_class_property_add_str(oc, "passwordid",
|
||||
qcrypto_tls_creds_x509_prop_get_passwordid,
|
||||
qcrypto_tls_creds_x509_prop_set_passwordid,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/audio/audio.h"
|
||||
#include "audio/audio.h"
|
||||
|
@@ -22,6 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/audio/audio.h"
|
||||
#include "audio/audio.h"
|
||||
|
@@ -22,6 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
@@ -21,6 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/audio/audio.h"
|
||||
#include "audio/audio.h"
|
||||
|
@@ -26,6 +26,7 @@
|
||||
/* #define VERBOSE_ES1370 */
|
||||
#define SILENT_ES1370
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/audio/audio.h"
|
||||
#include "audio/audio.h"
|
||||
|
@@ -32,10 +32,7 @@
|
||||
|
||||
#define HAS_YM3812 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "qemu/osdep.h"
|
||||
#include <math.h>
|
||||
//#include "driver.h" /* use M.A.M.E. */
|
||||
#include "fmopl.h"
|
||||
|
@@ -21,6 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/audio/audio.h"
|
||||
#include "audio/audio.h"
|
||||
|
@@ -26,6 +26,7 @@
|
||||
* TODO: check mixer: see 7.20 of sdk for panning pos (applies to all gus models?)?
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "gustate.h"
|
||||
#include "gusemu.h"
|
||||
|
||||
|
@@ -22,6 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "gusemu.h"
|
||||
#include "gustate.h"
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "intel-hda.h"
|
||||
|
@@ -17,6 +17,7 @@
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/msi.h"
|
||||
|
@@ -13,6 +13,7 @@
|
||||
* It supports only one playback voice and no record voice.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "audio/audio.h"
|
||||
#include "lm4549.h"
|
||||
@@ -33,7 +34,6 @@ do { printf("lm4549: " fmt , ## __VA_ARGS__); } while (0)
|
||||
#endif
|
||||
|
||||
#if defined(LM4549_DUMP_DAC_INPUT)
|
||||
#include <stdio.h>
|
||||
static FILE *fp_dac_input;
|
||||
#endif
|
||||
|
||||
|
@@ -9,6 +9,7 @@
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
|
@@ -21,6 +21,7 @@
|
||||
* http://www.milkymist.org/socdoc/ac97.pdf
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "trace.h"
|
||||
|
@@ -22,6 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/isa/isa.h"
|
||||
|
@@ -20,6 +20,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
#include "pl041.h"
|
||||
|
@@ -21,6 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/audio/audio.h"
|
||||
#include "audio/audio.h"
|
||||
|
@@ -7,6 +7,7 @@
|
||||
* This file is licensed under GNU GPL.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "audio/audio.h"
|
||||
|
@@ -40,6 +40,8 @@ struct VirtIOBlockDataPlane {
|
||||
EventNotifier *guest_notifier; /* irq */
|
||||
QEMUBH *bh; /* bh for guest notification */
|
||||
|
||||
Notifier insert_notifier, remove_notifier;
|
||||
|
||||
/* Note that these EventNotifiers are assigned by value. This is
|
||||
* fine as long as you do not call event_notifier_cleanup on them
|
||||
* (because you don't own the file descriptor or handle; you just
|
||||
@@ -137,6 +139,54 @@ static void handle_notify(EventNotifier *e)
|
||||
blk_io_unplug(s->conf->conf.blk);
|
||||
}
|
||||
|
||||
static void data_plane_set_up_op_blockers(VirtIOBlockDataPlane *s)
|
||||
{
|
||||
assert(!s->blocker);
|
||||
error_setg(&s->blocker, "block device is in use by data plane");
|
||||
blk_op_block_all(s->conf->conf.blk, s->blocker);
|
||||
blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_RESIZE, s->blocker);
|
||||
blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker);
|
||||
blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_BACKUP_SOURCE, s->blocker);
|
||||
blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_CHANGE, s->blocker);
|
||||
blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_COMMIT_SOURCE, s->blocker);
|
||||
blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_COMMIT_TARGET, s->blocker);
|
||||
blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_EJECT, s->blocker);
|
||||
blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT,
|
||||
s->blocker);
|
||||
blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT,
|
||||
s->blocker);
|
||||
blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
|
||||
s->blocker);
|
||||
blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_MIRROR_SOURCE, s->blocker);
|
||||
blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_STREAM, s->blocker);
|
||||
blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_REPLACE, s->blocker);
|
||||
}
|
||||
|
||||
static void data_plane_remove_op_blockers(VirtIOBlockDataPlane *s)
|
||||
{
|
||||
if (s->blocker) {
|
||||
blk_op_unblock_all(s->conf->conf.blk, s->blocker);
|
||||
error_free(s->blocker);
|
||||
s->blocker = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void data_plane_blk_insert_notifier(Notifier *n, void *data)
|
||||
{
|
||||
VirtIOBlockDataPlane *s = container_of(n, VirtIOBlockDataPlane,
|
||||
insert_notifier);
|
||||
assert(s->conf->conf.blk == data);
|
||||
data_plane_set_up_op_blockers(s);
|
||||
}
|
||||
|
||||
static void data_plane_blk_remove_notifier(Notifier *n, void *data)
|
||||
{
|
||||
VirtIOBlockDataPlane *s = container_of(n, VirtIOBlockDataPlane,
|
||||
remove_notifier);
|
||||
assert(s->conf->conf.blk == data);
|
||||
data_plane_remove_op_blockers(s);
|
||||
}
|
||||
|
||||
/* Context: QEMU global mutex held */
|
||||
void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
|
||||
VirtIOBlockDataPlane **dataplane,
|
||||
@@ -179,22 +229,12 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
|
||||
s->ctx = iothread_get_aio_context(s->iothread);
|
||||
s->bh = aio_bh_new(s->ctx, notify_guest_bh, s);
|
||||
|
||||
error_setg(&s->blocker, "block device is in use by data plane");
|
||||
blk_op_block_all(conf->conf.blk, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_RESIZE, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_BACKUP_SOURCE, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_CHANGE, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT_SOURCE, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT_TARGET, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_EJECT, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
|
||||
s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_MIRROR_SOURCE, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_STREAM, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_REPLACE, s->blocker);
|
||||
s->insert_notifier.notify = data_plane_blk_insert_notifier;
|
||||
s->remove_notifier.notify = data_plane_blk_remove_notifier;
|
||||
blk_add_insert_bs_notifier(conf->conf.blk, &s->insert_notifier);
|
||||
blk_add_remove_bs_notifier(conf->conf.blk, &s->remove_notifier);
|
||||
|
||||
data_plane_set_up_op_blockers(s);
|
||||
|
||||
*dataplane = s;
|
||||
}
|
||||
@@ -207,8 +247,9 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
|
||||
}
|
||||
|
||||
virtio_blk_data_plane_stop(s);
|
||||
blk_op_unblock_all(s->conf->conf.blk, s->blocker);
|
||||
error_free(s->blocker);
|
||||
data_plane_remove_op_blockers(s);
|
||||
notifier_remove(&s->insert_notifier);
|
||||
notifier_remove(&s->remove_notifier);
|
||||
qemu_bh_delete(s->bh);
|
||||
object_unref(OBJECT(s->iothread));
|
||||
g_free(s);
|
||||
|
@@ -173,7 +173,6 @@ typedef struct FDrive {
|
||||
uint8_t media_changed; /* Is media changed */
|
||||
uint8_t media_rate; /* Data rate of medium */
|
||||
|
||||
bool media_inserted; /* Is there a medium in the tray */
|
||||
bool media_validated; /* Have we validated the media? */
|
||||
} FDrive;
|
||||
|
||||
@@ -249,7 +248,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
|
||||
#endif
|
||||
drv->head = head;
|
||||
if (drv->track != track) {
|
||||
if (drv->media_inserted) {
|
||||
if (drv->blk != NULL && blk_is_inserted(drv->blk)) {
|
||||
drv->media_changed = 0;
|
||||
}
|
||||
ret = 1;
|
||||
@@ -258,7 +257,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
|
||||
drv->sect = sect;
|
||||
}
|
||||
|
||||
if (!drv->media_inserted) {
|
||||
if (drv->blk == NULL || !blk_is_inserted(drv->blk)) {
|
||||
ret = 2;
|
||||
}
|
||||
|
||||
@@ -288,7 +287,9 @@ static int pick_geometry(FDrive *drv)
|
||||
bool magic = drv->drive == FLOPPY_DRIVE_TYPE_AUTO;
|
||||
|
||||
/* We can only pick a geometry if we have a diskette. */
|
||||
if (!drv->media_inserted || drv->drive == FLOPPY_DRIVE_TYPE_NONE) {
|
||||
if (!drv->blk || !blk_is_inserted(drv->blk) ||
|
||||
drv->drive == FLOPPY_DRIVE_TYPE_NONE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -390,7 +391,7 @@ static void fd_revalidate(FDrive *drv)
|
||||
FLOPPY_DPRINTF("revalidate\n");
|
||||
if (drv->blk != NULL) {
|
||||
drv->ro = blk_is_read_only(drv->blk);
|
||||
if (!drv->media_inserted) {
|
||||
if (!blk_is_inserted(drv->blk)) {
|
||||
FLOPPY_DPRINTF("No disk in drive\n");
|
||||
drv->disk = FLOPPY_DRIVE_TYPE_NONE;
|
||||
} else if (!drv->media_validated) {
|
||||
@@ -793,7 +794,7 @@ static bool fdrive_media_changed_needed(void *opaque)
|
||||
{
|
||||
FDrive *drive = opaque;
|
||||
|
||||
return (drive->media_inserted && drive->media_changed != 1);
|
||||
return (drive->blk != NULL && drive->media_changed != 1);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_fdrive_media_changed = {
|
||||
@@ -2285,22 +2286,13 @@ static void fdctrl_change_cb(void *opaque, bool load)
|
||||
{
|
||||
FDrive *drive = opaque;
|
||||
|
||||
drive->media_inserted = load && drive->blk && blk_is_inserted(drive->blk);
|
||||
|
||||
drive->media_changed = 1;
|
||||
drive->media_validated = false;
|
||||
fd_revalidate(drive);
|
||||
}
|
||||
|
||||
static bool fdctrl_is_tray_open(void *opaque)
|
||||
{
|
||||
FDrive *drive = opaque;
|
||||
return !drive->media_inserted;
|
||||
}
|
||||
|
||||
static const BlockDevOps fdctrl_block_ops = {
|
||||
.change_media_cb = fdctrl_change_cb,
|
||||
.is_tray_open = fdctrl_is_tray_open,
|
||||
};
|
||||
|
||||
/* Init functions */
|
||||
@@ -2327,7 +2319,6 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, Error **errp)
|
||||
fd_init(drive);
|
||||
if (drive->blk) {
|
||||
blk_set_dev_ops(drive->blk, &fdctrl_block_ops, drive);
|
||||
drive->media_inserted = blk_is_inserted(drive->blk);
|
||||
pick_drive_type(drive);
|
||||
}
|
||||
fd_revalidate(drive);
|
||||
|
@@ -916,45 +916,13 @@ static void nvme_class_init(ObjectClass *oc, void *data)
|
||||
dc->vmsd = &nvme_vmstate;
|
||||
}
|
||||
|
||||
static void nvme_get_bootindex(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
NvmeCtrl *s = NVME(obj);
|
||||
|
||||
visit_type_int32(v, &s->conf.bootindex, name, errp);
|
||||
}
|
||||
|
||||
static void nvme_set_bootindex(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
NvmeCtrl *s = NVME(obj);
|
||||
int32_t boot_index;
|
||||
Error *local_err = NULL;
|
||||
|
||||
visit_type_int32(v, &boot_index, name, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
/* check whether bootindex is present in fw_boot_order list */
|
||||
check_boot_index(boot_index, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
/* change bootindex to a new one */
|
||||
s->conf.bootindex = boot_index;
|
||||
|
||||
out:
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
}
|
||||
|
||||
static void nvme_instance_init(Object *obj)
|
||||
{
|
||||
object_property_add(obj, "bootindex", "int32",
|
||||
nvme_get_bootindex,
|
||||
nvme_set_bootindex, NULL, NULL, NULL);
|
||||
object_property_set_int(obj, -1, "bootindex", NULL);
|
||||
NvmeCtrl *s = NVME(obj);
|
||||
|
||||
device_add_bootindex_property(obj, &s->conf.bootindex,
|
||||
"bootindex", "/namespace@1,0",
|
||||
DEVICE(obj), &error_abort);
|
||||
}
|
||||
|
||||
static const TypeInfo nvme_info = {
|
||||
|
@@ -198,7 +198,7 @@ static void virgl_cmd_submit_3d(VirtIOGPU *g,
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: size mismatch (%zd/%d)",
|
||||
__func__, s, cs.size);
|
||||
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (virtio_gpu_stats_enabled(g->conf)) {
|
||||
@@ -208,6 +208,7 @@ static void virgl_cmd_submit_3d(VirtIOGPU *g,
|
||||
|
||||
virgl_renderer_submit_cmd(buf, cs.hdr.ctx_id, cs.size / 4);
|
||||
|
||||
out:
|
||||
g_free(buf);
|
||||
}
|
||||
|
||||
@@ -382,6 +383,11 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
|
||||
{
|
||||
VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
|
||||
|
||||
cmd->waiting = g->renderer_blocked;
|
||||
if (cmd->waiting) {
|
||||
return;
|
||||
}
|
||||
|
||||
virgl_renderer_force_ctx_0();
|
||||
switch (cmd->cmd_hdr.type) {
|
||||
case VIRTIO_GPU_CMD_CTX_CREATE:
|
||||
@@ -553,7 +559,8 @@ static void virtio_gpu_fence_poll(void *opaque)
|
||||
VirtIOGPU *g = opaque;
|
||||
|
||||
virgl_renderer_poll();
|
||||
if (g->inflight) {
|
||||
virtio_gpu_process_cmdq(g);
|
||||
if (!QTAILQ_EMPTY(&g->cmdq) || !QTAILQ_EMPTY(&g->fenceq)) {
|
||||
timer_mod(g->fence_poll, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 10);
|
||||
}
|
||||
}
|
||||
|
@@ -755,6 +755,39 @@ static void virtio_gpu_handle_cursor_cb(VirtIODevice *vdev, VirtQueue *vq)
|
||||
qemu_bh_schedule(g->cursor_bh);
|
||||
}
|
||||
|
||||
void virtio_gpu_process_cmdq(VirtIOGPU *g)
|
||||
{
|
||||
struct virtio_gpu_ctrl_command *cmd;
|
||||
|
||||
while (!QTAILQ_EMPTY(&g->cmdq)) {
|
||||
cmd = QTAILQ_FIRST(&g->cmdq);
|
||||
|
||||
/* process command */
|
||||
VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_cmd,
|
||||
g, cmd);
|
||||
if (cmd->waiting) {
|
||||
break;
|
||||
}
|
||||
QTAILQ_REMOVE(&g->cmdq, cmd, next);
|
||||
if (virtio_gpu_stats_enabled(g->conf)) {
|
||||
g->stats.requests++;
|
||||
}
|
||||
|
||||
if (!cmd->finished) {
|
||||
QTAILQ_INSERT_TAIL(&g->fenceq, cmd, next);
|
||||
g->inflight++;
|
||||
if (virtio_gpu_stats_enabled(g->conf)) {
|
||||
if (g->stats.max_inflight < g->inflight) {
|
||||
g->stats.max_inflight = g->inflight;
|
||||
}
|
||||
fprintf(stderr, "inflight: %3d (+)\r", g->inflight);
|
||||
}
|
||||
} else {
|
||||
g_free(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
||||
@@ -776,26 +809,14 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
||||
cmd->vq = vq;
|
||||
cmd->error = 0;
|
||||
cmd->finished = false;
|
||||
if (virtio_gpu_stats_enabled(g->conf)) {
|
||||
g->stats.requests++;
|
||||
}
|
||||
|
||||
VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_cmd,
|
||||
g, cmd);
|
||||
if (!cmd->finished) {
|
||||
QTAILQ_INSERT_TAIL(&g->fenceq, cmd, next);
|
||||
g->inflight++;
|
||||
if (virtio_gpu_stats_enabled(g->conf)) {
|
||||
if (g->stats.max_inflight < g->inflight) {
|
||||
g->stats.max_inflight = g->inflight;
|
||||
}
|
||||
fprintf(stderr, "inflight: %3d (+)\r", g->inflight);
|
||||
}
|
||||
cmd = g_new(struct virtio_gpu_ctrl_command, 1);
|
||||
}
|
||||
cmd->waiting = false;
|
||||
QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next);
|
||||
cmd = g_new(struct virtio_gpu_ctrl_command, 1);
|
||||
}
|
||||
g_free(cmd);
|
||||
|
||||
virtio_gpu_process_cmdq(g);
|
||||
|
||||
#ifdef CONFIG_VIRGL
|
||||
if (g->use_virgl_renderer) {
|
||||
virtio_gpu_virgl_fence_poll(g);
|
||||
@@ -876,11 +897,22 @@ static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void virtio_gpu_gl_block(void *opaque, bool block)
|
||||
{
|
||||
VirtIOGPU *g = opaque;
|
||||
|
||||
g->renderer_blocked = block;
|
||||
if (!block) {
|
||||
virtio_gpu_process_cmdq(g);
|
||||
}
|
||||
}
|
||||
|
||||
const GraphicHwOps virtio_gpu_ops = {
|
||||
.invalidate = virtio_gpu_invalidate_display,
|
||||
.gfx_update = virtio_gpu_update_display,
|
||||
.text_update = virtio_gpu_text_update,
|
||||
.ui_info = virtio_gpu_ui_info,
|
||||
.gl_block = virtio_gpu_gl_block,
|
||||
};
|
||||
|
||||
static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
|
||||
@@ -921,6 +953,7 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
|
||||
g->ctrl_bh = qemu_bh_new(virtio_gpu_ctrl_bh, g);
|
||||
g->cursor_bh = qemu_bh_new(virtio_gpu_cursor_bh, g);
|
||||
QTAILQ_INIT(&g->reslist);
|
||||
QTAILQ_INIT(&g->cmdq);
|
||||
QTAILQ_INIT(&g->fenceq);
|
||||
|
||||
g->enabled_output_bitmask = 1;
|
||||
|
@@ -66,11 +66,21 @@ static int virtio_vga_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void virtio_vga_gl_block(void *opaque, bool block)
|
||||
{
|
||||
VirtIOVGA *vvga = opaque;
|
||||
|
||||
if (virtio_gpu_ops.gl_block) {
|
||||
virtio_gpu_ops.gl_block(&vvga->vdev, block);
|
||||
}
|
||||
}
|
||||
|
||||
static const GraphicHwOps virtio_vga_ops = {
|
||||
.invalidate = virtio_vga_invalidate_display,
|
||||
.gfx_update = virtio_vga_update_display,
|
||||
.text_update = virtio_vga_text_update,
|
||||
.ui_info = virtio_vga_ui_info,
|
||||
.gl_block = virtio_vga_gl_block,
|
||||
};
|
||||
|
||||
/* VGA device wrapper around PCI device around virtio GPU */
|
||||
|
@@ -263,15 +263,6 @@ static const MemoryRegionOps ivshmem_mmio_ops = {
|
||||
},
|
||||
};
|
||||
|
||||
static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
|
||||
{
|
||||
IVShmemState *s = opaque;
|
||||
|
||||
IVSHMEM_DPRINTF("ivshmem_receive 0x%02x size: %d\n", *buf, size);
|
||||
|
||||
ivshmem_IntrStatus_write(s, *buf);
|
||||
}
|
||||
|
||||
static int ivshmem_can_receive(void * opaque)
|
||||
{
|
||||
return sizeof(int64_t);
|
||||
@@ -282,15 +273,24 @@ static void ivshmem_event(void *opaque, int event)
|
||||
IVSHMEM_DPRINTF("ivshmem_event %d\n", event);
|
||||
}
|
||||
|
||||
static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
|
||||
|
||||
static void ivshmem_vector_notify(void *opaque)
|
||||
{
|
||||
MSIVector *entry = opaque;
|
||||
PCIDevice *pdev = entry->pdev;
|
||||
IVShmemState *s = IVSHMEM(pdev);
|
||||
int vector = entry - s->msi_vectors;
|
||||
EventNotifier *n = &s->peers[s->vm_id].eventfds[vector];
|
||||
|
||||
if (!event_notifier_test_and_clear(n)) {
|
||||
return;
|
||||
}
|
||||
|
||||
IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, vector);
|
||||
msix_notify(pdev, vector);
|
||||
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
|
||||
msix_notify(pdev, vector);
|
||||
} else {
|
||||
ivshmem_IntrStatus_write(s, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int ivshmem_vector_unmask(PCIDevice *dev, unsigned vector,
|
||||
@@ -350,38 +350,16 @@ static void ivshmem_vector_poll(PCIDevice *dev,
|
||||
}
|
||||
}
|
||||
|
||||
static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *n,
|
||||
int vector)
|
||||
static void watch_vector_notifier(IVShmemState *s, EventNotifier *n,
|
||||
int vector)
|
||||
{
|
||||
/* create a event character device based on the passed eventfd */
|
||||
IVShmemState *s = opaque;
|
||||
PCIDevice *pdev = PCI_DEVICE(s);
|
||||
int eventfd = event_notifier_get_fd(n);
|
||||
CharDriverState *chr;
|
||||
|
||||
s->msi_vectors[vector].pdev = pdev;
|
||||
|
||||
chr = qemu_chr_open_eventfd(eventfd);
|
||||
|
||||
if (chr == NULL) {
|
||||
error_report("creating chardriver for eventfd %d failed", eventfd);
|
||||
return NULL;
|
||||
}
|
||||
qemu_chr_fe_claim_no_fail(chr);
|
||||
|
||||
/* if MSI is supported we need multiple interrupts */
|
||||
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
|
||||
s->msi_vectors[vector].pdev = PCI_DEVICE(s);
|
||||
|
||||
qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd,
|
||||
ivshmem_event, &s->msi_vectors[vector]);
|
||||
} else {
|
||||
qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive,
|
||||
ivshmem_event, s);
|
||||
}
|
||||
|
||||
return chr;
|
||||
s->msi_vectors[vector].pdev = PCI_DEVICE(s);
|
||||
|
||||
qemu_set_fd_handler(eventfd, ivshmem_vector_notify,
|
||||
NULL, &s->msi_vectors[vector]);
|
||||
}
|
||||
|
||||
static int check_shm_size(IVShmemState *s, int fd, Error **errp)
|
||||
@@ -591,7 +569,7 @@ static void setup_interrupt(IVShmemState *s, int vector)
|
||||
|
||||
if (!with_irqfd) {
|
||||
IVSHMEM_DPRINTF("with eventfd");
|
||||
s->eventfd_chr[vector] = create_eventfd_chr_device(s, n, vector);
|
||||
watch_vector_notifier(s, n, vector);
|
||||
} else if (msix_enabled(pdev)) {
|
||||
IVSHMEM_DPRINTF("with irqfd");
|
||||
if (ivshmem_add_kvm_msi_virq(s, vector) < 0) {
|
||||
@@ -772,18 +750,20 @@ static void ivshmem_reset(DeviceState *d)
|
||||
ivshmem_use_msix(s);
|
||||
}
|
||||
|
||||
static int ivshmem_setup_msi(IVShmemState * s)
|
||||
static int ivshmem_setup_interrupts(IVShmemState *s)
|
||||
{
|
||||
if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
|
||||
|
||||
/* allocate QEMU char devices for receiving interrupts */
|
||||
/* allocate QEMU callback data for receiving interrupts */
|
||||
s->msi_vectors = g_malloc0(s->vectors * sizeof(MSIVector));
|
||||
|
||||
ivshmem_use_msix(s);
|
||||
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
|
||||
if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
|
||||
ivshmem_use_msix(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -950,9 +930,8 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
|
||||
IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
|
||||
s->server_chr->filename);
|
||||
|
||||
if (ivshmem_has_feature(s, IVSHMEM_MSI) &&
|
||||
ivshmem_setup_msi(s)) {
|
||||
error_setg(errp, "msix initialization failed");
|
||||
if (ivshmem_setup_interrupts(s) < 0) {
|
||||
error_setg(errp, "failed to initialize interrupts");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -758,6 +758,22 @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_scsi_blk_insert_notifier(Notifier *n, void *data)
|
||||
{
|
||||
VirtIOSCSIBlkChangeNotifier *cn = DO_UPCAST(VirtIOSCSIBlkChangeNotifier,
|
||||
n, n);
|
||||
assert(cn->sd->conf.blk == data);
|
||||
blk_op_block_all(cn->sd->conf.blk, cn->s->blocker);
|
||||
}
|
||||
|
||||
static void virtio_scsi_blk_remove_notifier(Notifier *n, void *data)
|
||||
{
|
||||
VirtIOSCSIBlkChangeNotifier *cn = DO_UPCAST(VirtIOSCSIBlkChangeNotifier,
|
||||
n, n);
|
||||
assert(cn->sd->conf.blk == data);
|
||||
blk_op_unblock_all(cn->sd->conf.blk, cn->s->blocker);
|
||||
}
|
||||
|
||||
static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -766,6 +782,8 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
SCSIDevice *sd = SCSI_DEVICE(dev);
|
||||
|
||||
if (s->ctx && !s->dataplane_disabled) {
|
||||
VirtIOSCSIBlkChangeNotifier *insert_notifier, *remove_notifier;
|
||||
|
||||
if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
|
||||
return;
|
||||
}
|
||||
@@ -773,6 +791,20 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
aio_context_acquire(s->ctx);
|
||||
blk_set_aio_context(sd->conf.blk, s->ctx);
|
||||
aio_context_release(s->ctx);
|
||||
|
||||
insert_notifier = g_new0(VirtIOSCSIBlkChangeNotifier, 1);
|
||||
insert_notifier->n.notify = virtio_scsi_blk_insert_notifier;
|
||||
insert_notifier->s = s;
|
||||
insert_notifier->sd = sd;
|
||||
blk_add_insert_bs_notifier(sd->conf.blk, &insert_notifier->n);
|
||||
QTAILQ_INSERT_TAIL(&s->insert_notifiers, insert_notifier, next);
|
||||
|
||||
remove_notifier = g_new0(VirtIOSCSIBlkChangeNotifier, 1);
|
||||
remove_notifier->n.notify = virtio_scsi_blk_remove_notifier;
|
||||
remove_notifier->s = s;
|
||||
remove_notifier->sd = sd;
|
||||
blk_add_remove_bs_notifier(sd->conf.blk, &remove_notifier->n);
|
||||
QTAILQ_INSERT_TAIL(&s->remove_notifiers, remove_notifier, next);
|
||||
}
|
||||
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
|
||||
@@ -788,6 +820,7 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
|
||||
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
|
||||
SCSIDevice *sd = SCSI_DEVICE(dev);
|
||||
VirtIOSCSIBlkChangeNotifier *insert_notifier, *remove_notifier;
|
||||
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
|
||||
virtio_scsi_push_event(s, sd,
|
||||
@@ -798,6 +831,25 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
if (s->ctx) {
|
||||
blk_op_unblock_all(sd->conf.blk, s->blocker);
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(insert_notifier, &s->insert_notifiers, next) {
|
||||
if (insert_notifier->sd == sd) {
|
||||
notifier_remove(&insert_notifier->n);
|
||||
QTAILQ_REMOVE(&s->insert_notifiers, insert_notifier, next);
|
||||
g_free(insert_notifier);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(remove_notifier, &s->remove_notifiers, next) {
|
||||
if (remove_notifier->sd == sd) {
|
||||
notifier_remove(&remove_notifier->n);
|
||||
QTAILQ_REMOVE(&s->remove_notifiers, remove_notifier, next);
|
||||
g_free(remove_notifier);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qdev_simple_device_unplug_cb(hotplug_dev, dev, errp);
|
||||
}
|
||||
|
||||
@@ -912,6 +964,9 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
|
||||
add_migration_state_change_notifier(&s->migration_state_notifier);
|
||||
|
||||
error_setg(&s->blocker, "block device is in use by data plane");
|
||||
|
||||
QTAILQ_INIT(&s->insert_notifiers);
|
||||
QTAILQ_INIT(&s->remove_notifiers);
|
||||
}
|
||||
|
||||
static void virtio_scsi_instance_init(Object *obj)
|
||||
|
@@ -866,6 +866,7 @@ void ehci_reset(void *opaque)
|
||||
s->usbsts = USBSTS_HALT;
|
||||
s->usbsts_pending = 0;
|
||||
s->usbsts_frindex = 0;
|
||||
ehci_update_irq(s);
|
||||
|
||||
s->astate = EST_INACTIVE;
|
||||
s->pstate = EST_INACTIVE;
|
||||
@@ -1405,21 +1406,23 @@ static int ehci_process_itd(EHCIState *ehci,
|
||||
if (itd->transact[i] & ITD_XACT_ACTIVE) {
|
||||
pg = get_field(itd->transact[i], ITD_XACT_PGSEL);
|
||||
off = itd->transact[i] & ITD_XACT_OFFSET_MASK;
|
||||
ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK);
|
||||
ptr2 = (itd->bufptr[pg+1] & ITD_BUFPTR_MASK);
|
||||
len = get_field(itd->transact[i], ITD_XACT_LENGTH);
|
||||
|
||||
if (len > max * mult) {
|
||||
len = max * mult;
|
||||
}
|
||||
|
||||
if (len > BUFF_SIZE) {
|
||||
if (len > BUFF_SIZE || pg > 6) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK);
|
||||
qemu_sglist_init(&ehci->isgl, ehci->device, 2, ehci->as);
|
||||
if (off + len > 4096) {
|
||||
/* transfer crosses page border */
|
||||
if (pg == 6) {
|
||||
return -1; /* avoid page pg + 1 */
|
||||
}
|
||||
ptr2 = (itd->bufptr[pg + 1] & ITD_BUFPTR_MASK);
|
||||
uint32_t len2 = off + len - 4096;
|
||||
uint32_t len1 = len - len2;
|
||||
qemu_sglist_add(&ehci->isgl, ptr1 + off, len1);
|
||||
|
@@ -111,9 +111,10 @@ typedef struct HDGeometry {
|
||||
|
||||
/*
|
||||
* Allocation status flags
|
||||
* BDRV_BLOCK_DATA: data is read from bs->file or another file
|
||||
* BDRV_BLOCK_DATA: data is read from a file returned by bdrv_get_block_status.
|
||||
* BDRV_BLOCK_ZERO: sectors read as zero
|
||||
* BDRV_BLOCK_OFFSET_VALID: sector stored in bs->file as raw data
|
||||
* BDRV_BLOCK_OFFSET_VALID: sector stored as raw data in a file returned by
|
||||
* bdrv_get_block_status.
|
||||
* BDRV_BLOCK_ALLOCATED: the content of the block is determined by this
|
||||
* layer (as opposed to the backing file)
|
||||
* BDRV_BLOCK_RAW: used internally to indicate that the request
|
||||
@@ -198,6 +199,7 @@ int bdrv_create(BlockDriver *drv, const char* filename,
|
||||
int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp);
|
||||
BlockDriverState *bdrv_new_root(void);
|
||||
BlockDriverState *bdrv_new(void);
|
||||
void bdrv_device_remove(BlockDriverState *bs);
|
||||
void bdrv_make_anon(BlockDriverState *bs);
|
||||
void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
|
||||
void bdrv_replace_in_backing_chain(BlockDriverState *old,
|
||||
@@ -225,8 +227,6 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
|
||||
BlockReopenQueue *queue, Error **errp);
|
||||
void bdrv_reopen_commit(BDRVReopenState *reopen_state);
|
||||
void bdrv_reopen_abort(BDRVReopenState *reopen_state);
|
||||
void bdrv_close(BlockDriverState *bs);
|
||||
void bdrv_add_close_notifier(BlockDriverState *bs, Notifier *notify);
|
||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors);
|
||||
int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num,
|
||||
@@ -386,11 +386,13 @@ 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 nb_sectors, int *pnum,
|
||||
BlockDriverState **file);
|
||||
int64_t bdrv_get_block_status_above(BlockDriverState *bs,
|
||||
BlockDriverState *base,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum);
|
||||
int nb_sectors, int *pnum,
|
||||
BlockDriverState **file);
|
||||
int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
||||
int *pnum);
|
||||
int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
|
||||
|
@@ -166,7 +166,8 @@ struct BlockDriver {
|
||||
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,
|
||||
int64_t sector_num, int nb_sectors, int *pnum);
|
||||
int64_t sector_num, int nb_sectors, int *pnum,
|
||||
BlockDriverState **file);
|
||||
|
||||
/*
|
||||
* Invalidate any cached meta-data.
|
||||
@@ -403,8 +404,6 @@ struct BlockDriverState {
|
||||
BdrvChild *backing;
|
||||
BdrvChild *file;
|
||||
|
||||
NotifierList close_notifiers;
|
||||
|
||||
/* Callback before write request is processed */
|
||||
NotifierWithReturnList before_write_notifiers;
|
||||
|
||||
@@ -445,6 +444,10 @@ struct BlockDriverState {
|
||||
QTAILQ_ENTRY(BlockDriverState) node_list;
|
||||
/* element of the list of "drives" the guest sees */
|
||||
QTAILQ_ENTRY(BlockDriverState) device_list;
|
||||
/* element of the list of all BlockDriverStates (all_bdrv_states) */
|
||||
QTAILQ_ENTRY(BlockDriverState) bs_list;
|
||||
/* element of the list of monitor-owned BDS */
|
||||
QTAILQ_ENTRY(BlockDriverState) monitor_list;
|
||||
QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps;
|
||||
int refcnt;
|
||||
|
||||
@@ -695,6 +698,7 @@ void blk_set_bs(BlockBackend *blk, BlockDriverState *bs);
|
||||
|
||||
void blk_dev_change_media_cb(BlockBackend *blk, bool load);
|
||||
bool blk_dev_has_removable_media(BlockBackend *blk);
|
||||
bool blk_dev_has_tray(BlockBackend *blk);
|
||||
void blk_dev_eject_request(BlockBackend *blk, bool force);
|
||||
bool blk_dev_is_tray_open(BlockBackend *blk);
|
||||
bool blk_dev_is_medium_locked(BlockBackend *blk);
|
||||
@@ -706,4 +710,6 @@ bool bdrv_requests_pending(BlockDriverState *bs);
|
||||
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
|
||||
void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in);
|
||||
|
||||
void blockdev_close_all_bdrv_states(void);
|
||||
|
||||
#endif /* BLOCK_INT_H */
|
||||
|
@@ -138,7 +138,7 @@ size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgorithm alg,
|
||||
* @mode: the cipher usage mode
|
||||
* @key: the private key bytes
|
||||
* @nkey: the length of @key
|
||||
* @errp: pointer to an uninitialized error object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Creates a new cipher object for encrypting/decrypting
|
||||
* data with the algorithm @alg in the usage mode @mode.
|
||||
@@ -174,7 +174,7 @@ void qcrypto_cipher_free(QCryptoCipher *cipher);
|
||||
* @in: buffer holding the plain text input data
|
||||
* @out: buffer to fill with the cipher text output data
|
||||
* @len: the length of @in and @out buffers
|
||||
* @errp: pointer to an uninitialized error object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Encrypts the plain text stored in @in, filling
|
||||
* @out with the resulting ciphered text. Both the
|
||||
@@ -196,7 +196,7 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
||||
* @in: buffer holding the cipher text input data
|
||||
* @out: buffer to fill with the plain text output data
|
||||
* @len: the length of @in and @out buffers
|
||||
* @errp: pointer to an uninitialized error object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Decrypts the cipher text stored in @in, filling
|
||||
* @out with the resulting plain text. Both the
|
||||
@@ -216,7 +216,7 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
||||
* @cipher: the cipher object
|
||||
* @iv: the initialization vector bytes
|
||||
* @niv: the length of @iv
|
||||
* @errpr: pointer to an uninitialized error object
|
||||
* @errpr: pointer to a NULL-initialized error object
|
||||
*
|
||||
* If the @cipher object is setup to use a mode that requires
|
||||
* initialization vectors, this sets the initialization vector
|
||||
|
@@ -55,7 +55,7 @@ size_t qcrypto_hash_digest_len(QCryptoHashAlgorithm alg);
|
||||
* @niov: the length of @iov
|
||||
* @result: pointer to hold output hash
|
||||
* @resultlen: pointer to hold length of @result
|
||||
* @errp: pointer to uninitialized error object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Computes the hash across all the memory regions
|
||||
* present in @iov. The @result pointer will be
|
||||
@@ -80,7 +80,7 @@ int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
|
||||
* @len: the length of @buf
|
||||
* @result: pointer to hold output hash
|
||||
* @resultlen: pointer to hold length of @result
|
||||
* @errp: pointer to uninitialized error object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Computes the hash across all the memory region
|
||||
* @buf of length @len. The @result pointer will be
|
||||
@@ -104,7 +104,7 @@ int qcrypto_hash_bytes(QCryptoHashAlgorithm alg,
|
||||
* @iov: the array of memory regions to hash
|
||||
* @niov: the length of @iov
|
||||
* @digest: pointer to hold output hash
|
||||
* @errp: pointer to uninitialized error object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Computes the hash across all the memory regions
|
||||
* present in @iov. The @digest pointer will be
|
||||
@@ -127,7 +127,7 @@ int qcrypto_hash_digestv(QCryptoHashAlgorithm alg,
|
||||
* @buf: the memory region to hash
|
||||
* @len: the length of @buf
|
||||
* @digest: pointer to hold output hash
|
||||
* @errp: pointer to uninitialized error object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Computes the hash across all the memory region
|
||||
* @buf of length @len. The @digest pointer will be
|
||||
@@ -150,7 +150,7 @@ int qcrypto_hash_digest(QCryptoHashAlgorithm alg,
|
||||
* @iov: the array of memory regions to hash
|
||||
* @niov: the length of @iov
|
||||
* @base64: pointer to hold output hash
|
||||
* @errp: pointer to uninitialized error object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Computes the hash across all the memory regions
|
||||
* present in @iov. The @base64 pointer will be
|
||||
@@ -173,7 +173,7 @@ int qcrypto_hash_base64v(QCryptoHashAlgorithm alg,
|
||||
* @buf: the memory region to hash
|
||||
* @len: the length of @buf
|
||||
* @base64: pointer to hold output hash
|
||||
* @errp: pointer to uninitialized error object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Computes the hash across all the memory region
|
||||
* @buf of length @len. The @base64 pointer will be
|
||||
|
@@ -114,7 +114,7 @@ typedef struct QCryptoTLSSession QCryptoTLSSession;
|
||||
* @hostname: optional hostname to validate
|
||||
* @aclname: optional ACL to validate peer credentials against
|
||||
* @endpoint: role of the TLS session, client or server
|
||||
* @errp: pointer to an uninitialized error object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Create a new TLS session object that will be used to
|
||||
* negotiate a TLS session over an arbitrary data channel.
|
||||
@@ -163,7 +163,7 @@ void qcrypto_tls_session_free(QCryptoTLSSession *sess);
|
||||
/**
|
||||
* qcrypto_tls_session_check_credentials:
|
||||
* @sess: the TLS session object
|
||||
* @errp: pointer to an uninitialized error object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Validate the peer's credentials after a successful
|
||||
* TLS handshake. It is an error to call this before
|
||||
@@ -249,7 +249,7 @@ ssize_t qcrypto_tls_session_read(QCryptoTLSSession *sess,
|
||||
/**
|
||||
* qcrypto_tls_session_handshake:
|
||||
* @sess: the TLS session object
|
||||
* @errp: pointer to an uninitialized error object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Start, or continue, a TLS handshake sequence. If
|
||||
* the underlying data channel is non-blocking, then
|
||||
@@ -292,7 +292,7 @@ qcrypto_tls_session_get_handshake_status(QCryptoTLSSession *sess);
|
||||
/**
|
||||
* qcrypto_tls_session_get_key_size:
|
||||
* @sess: the TLS session object
|
||||
* @errp: pointer to an uninitialized error object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Check the size of the data channel encryption key
|
||||
*
|
||||
|
@@ -76,6 +76,7 @@ struct virtio_gpu_ctrl_command {
|
||||
VirtQueue *vq;
|
||||
struct virtio_gpu_ctrl_hdr cmd_hdr;
|
||||
uint32_t error;
|
||||
bool waiting;
|
||||
bool finished;
|
||||
QTAILQ_ENTRY(virtio_gpu_ctrl_command) next;
|
||||
};
|
||||
@@ -94,6 +95,7 @@ typedef struct VirtIOGPU {
|
||||
DeviceState *qdev;
|
||||
|
||||
QTAILQ_HEAD(, virtio_gpu_simple_resource) reslist;
|
||||
QTAILQ_HEAD(, virtio_gpu_ctrl_command) cmdq;
|
||||
QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq;
|
||||
|
||||
struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUT];
|
||||
@@ -105,6 +107,7 @@ typedef struct VirtIOGPU {
|
||||
|
||||
bool use_virgl_renderer;
|
||||
bool renderer_inited;
|
||||
bool renderer_blocked;
|
||||
QEMUTimer *fence_poll;
|
||||
QEMUTimer *print_stats;
|
||||
|
||||
@@ -151,6 +154,7 @@ int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab,
|
||||
struct virtio_gpu_ctrl_command *cmd,
|
||||
struct iovec **iov);
|
||||
void virtio_gpu_cleanup_mapping_iov(struct iovec *iov, uint32_t count);
|
||||
void virtio_gpu_process_cmdq(VirtIOGPU *g);
|
||||
|
||||
/* virtio-gpu-3d.c */
|
||||
void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
|
||||
|
@@ -76,6 +76,13 @@ typedef struct VirtIOSCSICommon {
|
||||
VirtQueue **cmd_vqs;
|
||||
} VirtIOSCSICommon;
|
||||
|
||||
typedef struct VirtIOSCSIBlkChangeNotifier {
|
||||
Notifier n;
|
||||
struct VirtIOSCSI *s;
|
||||
SCSIDevice *sd;
|
||||
QTAILQ_ENTRY(VirtIOSCSIBlkChangeNotifier) next;
|
||||
} VirtIOSCSIBlkChangeNotifier;
|
||||
|
||||
typedef struct VirtIOSCSI {
|
||||
VirtIOSCSICommon parent_obj;
|
||||
|
||||
@@ -86,6 +93,9 @@ typedef struct VirtIOSCSI {
|
||||
/* Fields for dataplane below */
|
||||
AioContext *ctx; /* one iothread per virtio-scsi-pci for now */
|
||||
|
||||
QTAILQ_HEAD(, VirtIOSCSIBlkChangeNotifier) insert_notifiers;
|
||||
QTAILQ_HEAD(, VirtIOSCSIBlkChangeNotifier) remove_notifiers;
|
||||
|
||||
/* Vring is used instead of vq in dataplane code, because of the underlying
|
||||
* memory layer thread safety */
|
||||
VirtIOSCSIVring *ctrl_vring;
|
||||
|
@@ -68,6 +68,7 @@ BlockBackend *blk_new_open(const char *name, const char *filename,
|
||||
int blk_get_refcnt(BlockBackend *blk);
|
||||
void blk_ref(BlockBackend *blk);
|
||||
void blk_unref(BlockBackend *blk);
|
||||
void blk_remove_all_bs(void);
|
||||
const char *blk_name(BlockBackend *blk);
|
||||
BlockBackend *blk_by_name(const char *name);
|
||||
BlockBackend *blk_next(BlockBackend *blk);
|
||||
@@ -164,7 +165,8 @@ void blk_remove_aio_context_notifier(BlockBackend *blk,
|
||||
void *),
|
||||
void (*detach_aio_context)(void *),
|
||||
void *opaque);
|
||||
void blk_add_close_notifier(BlockBackend *blk, Notifier *notify);
|
||||
void blk_add_remove_bs_notifier(BlockBackend *blk, Notifier *notify);
|
||||
void blk_add_insert_bs_notifier(BlockBackend *blk, Notifier *notify);
|
||||
void blk_io_plug(BlockBackend *blk);
|
||||
void blk_io_unplug(BlockBackend *blk);
|
||||
BlockAcctStats *blk_get_stats(BlockBackend *blk);
|
||||
|
@@ -360,9 +360,6 @@ void register_char_driver(const char *name, ChardevBackendKind kind,
|
||||
CharDriverState *(*create)(const char *id, ChardevBackend *backend,
|
||||
ChardevReturn *ret, Error **errp));
|
||||
|
||||
/* add an eventfd to the qemu devices that are polled */
|
||||
CharDriverState *qemu_chr_open_eventfd(int eventfd);
|
||||
|
||||
extern int term_escape_char;
|
||||
|
||||
CharDriverState *qemu_char_get_next_serial(void);
|
||||
|
@@ -362,6 +362,7 @@ typedef struct GraphicHwOps {
|
||||
void (*text_update)(void *opaque, console_ch_t *text);
|
||||
void (*update_interval)(void *opaque, uint64_t interval);
|
||||
int (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info);
|
||||
void (*gl_block)(void *opaque, bool block);
|
||||
} GraphicHwOps;
|
||||
|
||||
QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
|
||||
@@ -374,6 +375,7 @@ void graphic_console_set_hwops(QemuConsole *con,
|
||||
void graphic_hw_update(QemuConsole *con);
|
||||
void graphic_hw_invalidate(QemuConsole *con);
|
||||
void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
|
||||
void graphic_hw_gl_block(QemuConsole *con, bool block);
|
||||
|
||||
QemuConsole *qemu_console_lookup_by_index(unsigned int index);
|
||||
QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head);
|
||||
|
@@ -11,6 +11,5 @@ EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win);
|
||||
|
||||
int qemu_egl_init_dpy(EGLNativeDisplayType dpy, bool gles, bool debug);
|
||||
EGLContext qemu_egl_init_ctx(void);
|
||||
bool qemu_egl_has_ext(const char *haystack, const char *needle);
|
||||
|
||||
#endif /* EGL_HELPERS_H */
|
||||
|
16
nbd/server.c
16
nbd/server.c
@@ -64,6 +64,8 @@ struct NBDExport {
|
||||
QTAILQ_ENTRY(NBDExport) next;
|
||||
|
||||
AioContext *ctx;
|
||||
|
||||
Notifier eject_notifier;
|
||||
};
|
||||
|
||||
static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports);
|
||||
@@ -644,6 +646,12 @@ static void blk_aio_detach(void *opaque)
|
||||
exp->ctx = NULL;
|
||||
}
|
||||
|
||||
static void nbd_eject_notifier(Notifier *n, void *data)
|
||||
{
|
||||
NBDExport *exp = container_of(n, NBDExport, eject_notifier);
|
||||
nbd_export_close(exp);
|
||||
}
|
||||
|
||||
NBDExport *nbd_export_new(BlockBackend *blk, off_t dev_offset, off_t size,
|
||||
uint32_t nbdflags, void (*close)(NBDExport *),
|
||||
Error **errp)
|
||||
@@ -666,6 +674,10 @@ NBDExport *nbd_export_new(BlockBackend *blk, off_t dev_offset, off_t size,
|
||||
exp->ctx = blk_get_aio_context(blk);
|
||||
blk_ref(blk);
|
||||
blk_add_aio_context_notifier(blk, blk_aio_attached, blk_aio_detach, exp);
|
||||
|
||||
exp->eject_notifier.notify = nbd_eject_notifier;
|
||||
blk_add_remove_bs_notifier(blk, &exp->eject_notifier);
|
||||
|
||||
/*
|
||||
* NBD exports are used for non-shared storage migration. Make sure
|
||||
* that BDRV_O_INACTIVE is cleared and the image is ready for write
|
||||
@@ -747,6 +759,7 @@ void nbd_export_put(NBDExport *exp)
|
||||
}
|
||||
|
||||
if (exp->blk) {
|
||||
notifier_remove(&exp->eject_notifier);
|
||||
blk_remove_aio_context_notifier(exp->blk, blk_aio_attached,
|
||||
blk_aio_detach, exp);
|
||||
blk_unref(exp->blk);
|
||||
@@ -1082,8 +1095,7 @@ static coroutine_fn void nbd_co_client_start(void *opaque)
|
||||
nbd_export_get(exp);
|
||||
}
|
||||
if (nbd_negotiate(data)) {
|
||||
shutdown(client->sock, 2);
|
||||
client->close(client);
|
||||
client_close(client);
|
||||
goto out;
|
||||
}
|
||||
qemu_co_mutex_init(&client->send_lock);
|
||||
|
@@ -185,6 +185,33 @@
|
||||
'*total-clusters': 'int', '*allocated-clusters': 'int',
|
||||
'*fragmented-clusters': 'int', '*compressed-clusters': 'int' } }
|
||||
|
||||
##
|
||||
# @MapEntry:
|
||||
#
|
||||
# Mapping information from a virtual block range to a host file range
|
||||
#
|
||||
# @start: the start byte of the mapped virtual range
|
||||
#
|
||||
# @length: the number of bytes of the mapped virtual range
|
||||
#
|
||||
# @data: whether the mapped range has data
|
||||
#
|
||||
# @zero: whether the virtual blocks are zeroed
|
||||
#
|
||||
# @depth: the depth of the mapping
|
||||
#
|
||||
# @offset: #optional the offset in file that the virtual sectors are mapped to
|
||||
#
|
||||
# @filename: #optional filename that is referred to by @offset
|
||||
#
|
||||
# Since: 2.6
|
||||
#
|
||||
##
|
||||
{ 'struct': 'MapEntry',
|
||||
'data': {'start': 'int', 'length': 'int', 'data': 'bool',
|
||||
'zero': 'bool', 'depth': 'int', '*offset': 'int',
|
||||
'*filename': 'str' } }
|
||||
|
||||
##
|
||||
# @BlockdevCacheInfo
|
||||
#
|
||||
@@ -382,8 +409,8 @@
|
||||
# @locked: True if the guest has locked this device from having its media
|
||||
# removed
|
||||
#
|
||||
# @tray_open: #optional True if the device has a tray and it is open
|
||||
# (only present if removable is true)
|
||||
# @tray_open: #optional True if the device's tray is open
|
||||
# (only present if it has a tray)
|
||||
#
|
||||
# @dirty-bitmaps: #optional dirty bitmaps information (only present if the
|
||||
# driver has one or more dirty bitmaps) (Since 2.0)
|
||||
@@ -2098,8 +2125,7 @@
|
||||
# respond to the eject request
|
||||
# - if the BlockBackend denoted by @device does not have a guest device attached
|
||||
# to it
|
||||
# - if the guest device does not have an actual tray and is empty, for instance
|
||||
# for floppy disk drives
|
||||
# - if the guest device does not have an actual tray
|
||||
#
|
||||
# @device: block device name
|
||||
#
|
||||
|
13
qemu-char.c
13
qemu-char.c
@@ -2838,19 +2838,6 @@ static int tcp_chr_sync_read(CharDriverState *chr, const uint8_t *buf, int len)
|
||||
return size;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
CharDriverState *qemu_chr_open_eventfd(int eventfd)
|
||||
{
|
||||
CharDriverState *chr = qemu_chr_open_fd(eventfd, eventfd, NULL, NULL);
|
||||
|
||||
if (chr) {
|
||||
chr->avail_connections = 1;
|
||||
}
|
||||
|
||||
return chr;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void tcp_chr_connect(void *opaque)
|
||||
{
|
||||
CharDriverState *chr = opaque;
|
||||
|
84
qemu-img.c
84
qemu-img.c
@@ -1072,13 +1072,15 @@ static int img_compare(int argc, char **argv)
|
||||
|
||||
for (;;) {
|
||||
int64_t status1, status2;
|
||||
BlockDriverState *file;
|
||||
|
||||
nb_sectors = sectors_to_process(total_sectors, sector_num);
|
||||
if (nb_sectors <= 0) {
|
||||
break;
|
||||
}
|
||||
status1 = bdrv_get_block_status_above(bs1, NULL, sector_num,
|
||||
total_sectors1 - sector_num,
|
||||
&pnum1);
|
||||
&pnum1, &file);
|
||||
if (status1 < 0) {
|
||||
ret = 3;
|
||||
error_report("Sector allocation test failed for %s", filename1);
|
||||
@@ -1088,7 +1090,7 @@ static int img_compare(int argc, char **argv)
|
||||
|
||||
status2 = bdrv_get_block_status_above(bs2, NULL, sector_num,
|
||||
total_sectors2 - sector_num,
|
||||
&pnum2);
|
||||
&pnum2, &file);
|
||||
if (status2 < 0) {
|
||||
ret = 3;
|
||||
error_report("Sector allocation test failed for %s", filename2);
|
||||
@@ -1271,9 +1273,10 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
|
||||
n = MIN(s->total_sectors - sector_num, BDRV_REQUEST_MAX_SECTORS);
|
||||
|
||||
if (s->sector_next_status <= sector_num) {
|
||||
BlockDriverState *file;
|
||||
ret = bdrv_get_block_status(blk_bs(s->src[s->src_cur]),
|
||||
sector_num - s->src_cur_offset,
|
||||
n, &n);
|
||||
n, &n, &file);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -2144,47 +2147,37 @@ static int img_info(int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
typedef struct MapEntry {
|
||||
int flags;
|
||||
int depth;
|
||||
int64_t start;
|
||||
int64_t length;
|
||||
int64_t offset;
|
||||
BlockDriverState *bs;
|
||||
} MapEntry;
|
||||
|
||||
static void dump_map_entry(OutputFormat output_format, MapEntry *e,
|
||||
MapEntry *next)
|
||||
{
|
||||
switch (output_format) {
|
||||
case OFORMAT_HUMAN:
|
||||
if ((e->flags & BDRV_BLOCK_DATA) &&
|
||||
!(e->flags & BDRV_BLOCK_OFFSET_VALID)) {
|
||||
if (e->data && !e->has_offset) {
|
||||
error_report("File contains external, encrypted or compressed clusters.");
|
||||
exit(1);
|
||||
}
|
||||
if ((e->flags & (BDRV_BLOCK_DATA|BDRV_BLOCK_ZERO)) == BDRV_BLOCK_DATA) {
|
||||
if (e->data && !e->zero) {
|
||||
printf("%#-16"PRIx64"%#-16"PRIx64"%#-16"PRIx64"%s\n",
|
||||
e->start, e->length, e->offset, e->bs->filename);
|
||||
e->start, e->length,
|
||||
e->has_offset ? e->offset : 0,
|
||||
e->has_filename ? e->filename : "");
|
||||
}
|
||||
/* This format ignores the distinction between 0, ZERO and ZERO|DATA.
|
||||
* Modify the flags here to allow more coalescing.
|
||||
*/
|
||||
if (next &&
|
||||
(next->flags & (BDRV_BLOCK_DATA|BDRV_BLOCK_ZERO)) != BDRV_BLOCK_DATA) {
|
||||
next->flags &= ~BDRV_BLOCK_DATA;
|
||||
next->flags |= BDRV_BLOCK_ZERO;
|
||||
if (next && (!next->data || next->zero)) {
|
||||
next->data = false;
|
||||
next->zero = true;
|
||||
}
|
||||
break;
|
||||
case OFORMAT_JSON:
|
||||
printf("%s{ \"start\": %"PRId64", \"length\": %"PRId64", \"depth\": %d,"
|
||||
" \"zero\": %s, \"data\": %s",
|
||||
printf("%s{ \"start\": %"PRId64", \"length\": %"PRId64","
|
||||
" \"depth\": %"PRId64", \"zero\": %s, \"data\": %s",
|
||||
(e->start == 0 ? "[" : ",\n"),
|
||||
e->start, e->length, e->depth,
|
||||
(e->flags & BDRV_BLOCK_ZERO) ? "true" : "false",
|
||||
(e->flags & BDRV_BLOCK_DATA) ? "true" : "false");
|
||||
if (e->flags & BDRV_BLOCK_OFFSET_VALID) {
|
||||
e->zero ? "true" : "false",
|
||||
e->data ? "true" : "false");
|
||||
if (e->has_offset) {
|
||||
printf(", \"offset\": %"PRId64"", e->offset);
|
||||
}
|
||||
putchar('}');
|
||||
@@ -2201,6 +2194,7 @@ static int get_block_status(BlockDriverState *bs, int64_t sector_num,
|
||||
{
|
||||
int64_t ret;
|
||||
int depth;
|
||||
BlockDriverState *file;
|
||||
|
||||
/* As an optimization, we could cache the current range of unallocated
|
||||
* clusters in each file of the chain, and avoid querying the same
|
||||
@@ -2209,7 +2203,8 @@ static int get_block_status(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
depth = 0;
|
||||
for (;;) {
|
||||
ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &nb_sectors);
|
||||
ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &nb_sectors,
|
||||
&file);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -2228,13 +2223,39 @@ static int get_block_status(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
e->start = sector_num * BDRV_SECTOR_SIZE;
|
||||
e->length = nb_sectors * BDRV_SECTOR_SIZE;
|
||||
e->flags = ret & ~BDRV_BLOCK_OFFSET_MASK;
|
||||
e->data = !!(ret & BDRV_BLOCK_DATA);
|
||||
e->zero = !!(ret & BDRV_BLOCK_ZERO);
|
||||
e->offset = ret & BDRV_BLOCK_OFFSET_MASK;
|
||||
e->has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID);
|
||||
e->depth = depth;
|
||||
e->bs = bs;
|
||||
if (file && e->has_offset) {
|
||||
e->has_filename = true;
|
||||
e->filename = file->filename;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool entry_mergeable(const MapEntry *curr, const MapEntry *next)
|
||||
{
|
||||
if (curr->length == 0) {
|
||||
return false;
|
||||
}
|
||||
if (curr->zero != next->zero ||
|
||||
curr->data != next->data ||
|
||||
curr->depth != next->depth ||
|
||||
curr->has_filename != next->has_filename ||
|
||||
curr->has_offset != next->has_offset) {
|
||||
return false;
|
||||
}
|
||||
if (curr->has_filename && strcmp(curr->filename, next->filename)) {
|
||||
return false;
|
||||
}
|
||||
if (curr->has_offset && curr->offset + curr->length != next->offset) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int img_map(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
@@ -2316,10 +2337,7 @@ static int img_map(int argc, char **argv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (curr.length != 0 && curr.flags == next.flags &&
|
||||
curr.depth == next.depth &&
|
||||
((curr.flags & BDRV_BLOCK_OFFSET_VALID) == 0 ||
|
||||
curr.offset + curr.length == next.offset)) {
|
||||
if (entry_mergeable(&curr, &next)) {
|
||||
curr.length += next.length;
|
||||
continue;
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
stub-obj-y += arch-query-cpu-def.o
|
||||
stub-obj-y += bdrv-commit-all.o
|
||||
stub-obj-y += blockdev-close-all-bdrv-states.o
|
||||
stub-obj-y += clock-warp.o
|
||||
stub-obj-y += cpu-get-clock.o
|
||||
stub-obj-y += cpu-get-icount.o
|
||||
|
5
stubs/blockdev-close-all-bdrv-states.c
Normal file
5
stubs/blockdev-close-all-bdrv-states.c
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "block/block_int.h"
|
||||
|
||||
void blockdev_close_all_bdrv_states(void)
|
||||
{
|
||||
}
|
@@ -304,7 +304,6 @@ static void test_media_insert(void)
|
||||
qmp_discard_response("{'execute':'change', 'arguments':{"
|
||||
" 'device':'floppy0', 'target': %s, 'arg': 'raw' }}",
|
||||
test_image);
|
||||
qmp_discard_response(""); /* ignore event (open -> close) */
|
||||
|
||||
dir = inb(FLOPPY_BASE + reg_dir);
|
||||
assert_bit_set(dir, DSKCHG);
|
||||
@@ -335,7 +334,6 @@ static void test_media_change(void)
|
||||
* reset the bit. */
|
||||
qmp_discard_response("{'execute':'eject', 'arguments':{"
|
||||
" 'device':'floppy0' }}");
|
||||
qmp_discard_response(""); /* ignore event */
|
||||
|
||||
dir = inb(FLOPPY_BASE + reg_dir);
|
||||
assert_bit_set(dir, DSKCHG);
|
||||
|
@@ -34,12 +34,10 @@ static void save_fn(QPCIDevice *dev, int devfn, void *data)
|
||||
*pdev = dev;
|
||||
}
|
||||
|
||||
static QPCIDevice *get_device(void)
|
||||
static QPCIDevice *get_device(QPCIBus *pcibus)
|
||||
{
|
||||
QPCIDevice *dev;
|
||||
QPCIBus *pcibus;
|
||||
|
||||
pcibus = qpci_init_pc();
|
||||
dev = NULL;
|
||||
qpci_device_foreach(pcibus, 0x1af4, 0x1110, save_fn, &dev);
|
||||
g_assert(dev != NULL);
|
||||
@@ -50,6 +48,7 @@ static QPCIDevice *get_device(void)
|
||||
typedef struct _IVState {
|
||||
QTestState *qtest;
|
||||
void *reg_base, *mem_base;
|
||||
QPCIBus *pcibus;
|
||||
QPCIDevice *dev;
|
||||
} IVState;
|
||||
|
||||
@@ -100,13 +99,20 @@ static inline void out_reg(IVState *s, enum Reg reg, unsigned v)
|
||||
global_qtest = qtest;
|
||||
}
|
||||
|
||||
static void cleanup_vm(IVState *s)
|
||||
{
|
||||
g_free(s->dev);
|
||||
qpci_free_pc(s->pcibus);
|
||||
qtest_quit(s->qtest);
|
||||
}
|
||||
|
||||
static void setup_vm_cmd(IVState *s, const char *cmd, bool msix)
|
||||
{
|
||||
uint64_t barsize;
|
||||
|
||||
s->qtest = qtest_start(cmd);
|
||||
|
||||
s->dev = get_device();
|
||||
s->pcibus = qpci_init_pc();
|
||||
s->dev = get_device(s->pcibus);
|
||||
|
||||
/* FIXME: other bar order fails, mappings changes */
|
||||
s->mem_base = qpci_iomap(s->dev, 2, &barsize);
|
||||
@@ -173,7 +179,7 @@ static void test_ivshmem_single(void)
|
||||
g_assert_cmpuint(data[i], ==, i);
|
||||
}
|
||||
|
||||
qtest_quit(s->qtest);
|
||||
cleanup_vm(s);
|
||||
}
|
||||
|
||||
static void test_ivshmem_pair(void)
|
||||
@@ -218,8 +224,8 @@ static void test_ivshmem_pair(void)
|
||||
g_assert_cmpuint(data[i], ==, 0x44);
|
||||
}
|
||||
|
||||
qtest_quit(s1->qtest);
|
||||
qtest_quit(s2->qtest);
|
||||
cleanup_vm(s1);
|
||||
cleanup_vm(s2);
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
@@ -271,18 +277,18 @@ static void *server_thread(void *data)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void setup_vm_with_server(IVState *s, int nvectors)
|
||||
static void setup_vm_with_server(IVState *s, int nvectors, bool msi)
|
||||
{
|
||||
char *cmd = g_strdup_printf("-chardev socket,id=chr0,path=%s,nowait "
|
||||
"-device ivshmem,size=1M,chardev=chr0,vectors=%d",
|
||||
tmpserver, nvectors);
|
||||
"-device ivshmem,size=1M,chardev=chr0,vectors=%d,msi=%s",
|
||||
tmpserver, nvectors, msi ? "true" : "false");
|
||||
|
||||
setup_vm_cmd(s, cmd, true);
|
||||
setup_vm_cmd(s, cmd, msi);
|
||||
|
||||
g_free(cmd);
|
||||
}
|
||||
|
||||
static void test_ivshmem_server(void)
|
||||
static void test_ivshmem_server(bool msi)
|
||||
{
|
||||
IVState state1, state2, *s1, *s2;
|
||||
ServerThread thread;
|
||||
@@ -300,9 +306,9 @@ static void test_ivshmem_server(void)
|
||||
ret = ivshmem_server_start(&server);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
|
||||
setup_vm_with_server(&state1, nvectors);
|
||||
setup_vm_with_server(&state1, nvectors, msi);
|
||||
s1 = &state1;
|
||||
setup_vm_with_server(&state2, nvectors);
|
||||
setup_vm_with_server(&state2, nvectors, msi);
|
||||
s2 = &state2;
|
||||
|
||||
g_assert_cmpuint(in_reg(s1, IVPOSITION), ==, 0xffffffff);
|
||||
@@ -332,32 +338,42 @@ static void test_ivshmem_server(void)
|
||||
g_assert_cmpuint(vm1, !=, vm2);
|
||||
|
||||
global_qtest = s1->qtest;
|
||||
ret = qpci_msix_table_size(s1->dev);
|
||||
g_assert_cmpuint(ret, ==, nvectors);
|
||||
if (msi) {
|
||||
ret = qpci_msix_table_size(s1->dev);
|
||||
g_assert_cmpuint(ret, ==, nvectors);
|
||||
}
|
||||
|
||||
/* ping vm2 -> vm1 */
|
||||
ret = qpci_msix_pending(s1->dev, 0);
|
||||
g_assert_cmpuint(ret, ==, 0);
|
||||
if (msi) {
|
||||
ret = qpci_msix_pending(s1->dev, 0);
|
||||
g_assert_cmpuint(ret, ==, 0);
|
||||
} else {
|
||||
out_reg(s1, INTRSTATUS, 0);
|
||||
}
|
||||
out_reg(s2, DOORBELL, vm1 << 16);
|
||||
do {
|
||||
g_usleep(10000);
|
||||
ret = qpci_msix_pending(s1->dev, 0);
|
||||
ret = msi ? qpci_msix_pending(s1->dev, 0) : in_reg(s1, INTRSTATUS);
|
||||
} while (ret == 0 && g_get_monotonic_time() < end_time);
|
||||
g_assert_cmpuint(ret, !=, 0);
|
||||
|
||||
/* ping vm1 -> vm2 */
|
||||
global_qtest = s2->qtest;
|
||||
ret = qpci_msix_pending(s2->dev, 0);
|
||||
g_assert_cmpuint(ret, ==, 0);
|
||||
if (msi) {
|
||||
ret = qpci_msix_pending(s2->dev, 0);
|
||||
g_assert_cmpuint(ret, ==, 0);
|
||||
} else {
|
||||
out_reg(s2, INTRSTATUS, 0);
|
||||
}
|
||||
out_reg(s1, DOORBELL, vm2 << 16);
|
||||
do {
|
||||
g_usleep(10000);
|
||||
ret = qpci_msix_pending(s2->dev, 0);
|
||||
ret = msi ? qpci_msix_pending(s2->dev, 0) : in_reg(s2, INTRSTATUS);
|
||||
} while (ret == 0 && g_get_monotonic_time() < end_time);
|
||||
g_assert_cmpuint(ret, !=, 0);
|
||||
|
||||
qtest_quit(s2->qtest);
|
||||
qtest_quit(s1->qtest);
|
||||
cleanup_vm(s2);
|
||||
cleanup_vm(s1);
|
||||
|
||||
if (qemu_write_full(thread.pipe[1], "q", 1) != 1) {
|
||||
g_error("qemu_write_full: %s", g_strerror(errno));
|
||||
@@ -370,6 +386,16 @@ static void test_ivshmem_server(void)
|
||||
close(thread.pipe[0]);
|
||||
}
|
||||
|
||||
static void test_ivshmem_server_msi(void)
|
||||
{
|
||||
test_ivshmem_server(true);
|
||||
}
|
||||
|
||||
static void test_ivshmem_server_irq(void)
|
||||
{
|
||||
test_ivshmem_server(false);
|
||||
}
|
||||
|
||||
#define PCI_SLOT_HP 0x06
|
||||
|
||||
static void test_ivshmem_hotplug(void)
|
||||
@@ -395,7 +421,7 @@ static void test_ivshmem_memdev(void)
|
||||
setup_vm_cmd(&state, "-object memory-backend-ram,size=1M,id=mb1"
|
||||
" -device ivshmem,x-memdev=mb1", false);
|
||||
|
||||
qtest_quit(state.qtest);
|
||||
cleanup_vm(&state);
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
@@ -483,7 +509,8 @@ int main(int argc, char **argv)
|
||||
qtest_add_func("/ivshmem/memdev", test_ivshmem_memdev);
|
||||
if (g_test_slow()) {
|
||||
qtest_add_func("/ivshmem/pair", test_ivshmem_pair);
|
||||
qtest_add_func("/ivshmem/server", test_ivshmem_server);
|
||||
qtest_add_func("/ivshmem/server-msi", test_ivshmem_server_msi);
|
||||
qtest_add_func("/ivshmem/server-irq", test_ivshmem_server_irq);
|
||||
}
|
||||
|
||||
ret = g_test_run();
|
||||
|
@@ -34,11 +34,13 @@ void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
|
||||
|
||||
if (vendor_id != -1 &&
|
||||
qpci_config_readw(dev, PCI_VENDOR_ID) != vendor_id) {
|
||||
g_free(dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (device_id != -1 &&
|
||||
qpci_config_readw(dev, PCI_DEVICE_ID) != device_id) {
|
||||
g_free(dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@@ -132,6 +132,16 @@ _img_info
|
||||
$QEMU_IO -c "write -P 0xa 900G 512" "$TEST_IMG" | _filter_qemu_io
|
||||
$QEMU_IO -c "read -v 900G 1024" "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
echo
|
||||
echo "=== Testing qemu-img map on extents ==="
|
||||
for fmt in monolithicSparse twoGbMaxExtentSparse; do
|
||||
IMGOPTS="subformat=$fmt" _make_test_img 31G
|
||||
$QEMU_IO -c "write 65024 1k" "$TEST_IMG" | _filter_qemu_io
|
||||
$QEMU_IO -c "write 2147483136 1k" "$TEST_IMG" | _filter_qemu_io
|
||||
$QEMU_IO -c "write 5G 1k" "$TEST_IMG" | _filter_qemu_io
|
||||
$QEMU_IMG map "$TEST_IMG" | _filter_testdir
|
||||
done
|
||||
|
||||
echo
|
||||
echo "=== Testing afl image with a very large capacity ==="
|
||||
_use_sample_img afl9.vmdk.bz2
|
||||
|
@@ -2335,6 +2335,31 @@ e1000003f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
read 1024/1024 bytes at offset 966367641600
|
||||
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
=== Testing qemu-img map on extents ===
|
||||
Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=33285996544 subformat=monolithicSparse
|
||||
wrote 1024/1024 bytes at offset 65024
|
||||
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 1024/1024 bytes at offset 2147483136
|
||||
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 1024/1024 bytes at offset 5368709120
|
||||
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Offset Length Mapped to File
|
||||
0 0x20000 0x3f0000 TEST_DIR/iotest-version3.vmdk
|
||||
0x7fff0000 0x20000 0x410000 TEST_DIR/iotest-version3.vmdk
|
||||
0x140000000 0x10000 0x430000 TEST_DIR/iotest-version3.vmdk
|
||||
Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=33285996544 subformat=twoGbMaxExtentSparse
|
||||
wrote 1024/1024 bytes at offset 65024
|
||||
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 1024/1024 bytes at offset 2147483136
|
||||
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 1024/1024 bytes at offset 5368709120
|
||||
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Offset Length Mapped to File
|
||||
0 0x20000 0x50000 TEST_DIR/iotest-version3-s001.vmdk
|
||||
0x7fff0000 0x10000 0x70000 TEST_DIR/iotest-version3-s001.vmdk
|
||||
0x80000000 0x10000 0x50000 TEST_DIR/iotest-version3-s002.vmdk
|
||||
0x140000000 0x10000 0x50000 TEST_DIR/iotest-version3-s003.vmdk
|
||||
|
||||
=== Testing afl image with a very large capacity ===
|
||||
qemu-img: Can't get size of device 'image': File too large
|
||||
*** done
|
||||
|
@@ -169,7 +169,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
|
||||
"file": "TEST_DIR/t.qcow2",
|
||||
"encryption_key_missing": false
|
||||
},
|
||||
"tray_open": false,
|
||||
"type": "unknown"
|
||||
}
|
||||
]
|
||||
@@ -289,7 +288,6 @@ Testing:
|
||||
"file": "TEST_DIR/t.qcow2",
|
||||
"encryption_key_missing": false
|
||||
},
|
||||
"tray_open": false,
|
||||
"type": "unknown"
|
||||
}
|
||||
]
|
||||
@@ -410,7 +408,6 @@ Testing:
|
||||
"file": "TEST_DIR/t.qcow2",
|
||||
"encryption_key_missing": false
|
||||
},
|
||||
"tray_open": false,
|
||||
"type": "unknown"
|
||||
}
|
||||
]
|
||||
@@ -501,7 +498,6 @@ Testing:
|
||||
"file": "TEST_DIR/t.qcow2",
|
||||
"encryption_key_missing": false
|
||||
},
|
||||
"tray_open": false,
|
||||
"type": "unknown"
|
||||
}
|
||||
]
|
||||
|
@@ -49,17 +49,6 @@ wait_for_tcp_port() {
|
||||
done
|
||||
}
|
||||
|
||||
filter_nbd() {
|
||||
# nbd.c error messages contain function names and line numbers that are prone
|
||||
# to change. Message ordering depends on timing between send and receive
|
||||
# callbacks sometimes, making them unreliable.
|
||||
#
|
||||
# Filter out the TCP port number since this changes between runs.
|
||||
sed -e 's#^.*nbd/.*\.c:.*##g' \
|
||||
-e 's#nbd:127\.0\.0\.1:[^:]*:#nbd:127\.0\.0\.1:PORT:#g' \
|
||||
-e 's#\(exportname=foo\|PORT\): Failed to .*$#\1#'
|
||||
}
|
||||
|
||||
check_disconnect() {
|
||||
event=$1
|
||||
when=$2
|
||||
@@ -84,7 +73,7 @@ EOF
|
||||
|
||||
$PYTHON nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" 2>&1 >/dev/null &
|
||||
wait_for_tcp_port "127\\.0\\.0\\.1:$port"
|
||||
$QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | filter_nbd
|
||||
$QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | _filter_nbd
|
||||
|
||||
echo
|
||||
}
|
||||
|
@@ -51,7 +51,6 @@ no file open, try 'help open'
|
||||
|
||||
=== Check disconnect after neg2 ===
|
||||
|
||||
|
||||
read failed: Input/output error
|
||||
|
||||
=== Check disconnect 8 neg2 ===
|
||||
@@ -66,42 +65,34 @@ no file open, try 'help open'
|
||||
|
||||
=== Check disconnect before request ===
|
||||
|
||||
|
||||
read failed: Input/output error
|
||||
|
||||
=== Check disconnect after request ===
|
||||
|
||||
|
||||
read failed: Input/output error
|
||||
|
||||
=== Check disconnect before reply ===
|
||||
|
||||
|
||||
read failed: Input/output error
|
||||
|
||||
=== Check disconnect after reply ===
|
||||
|
||||
|
||||
read failed: Input/output error
|
||||
|
||||
=== Check disconnect 4 reply ===
|
||||
|
||||
|
||||
read failed: Input/output error
|
||||
|
||||
=== Check disconnect 8 reply ===
|
||||
|
||||
|
||||
read failed: Input/output error
|
||||
|
||||
=== Check disconnect before data ===
|
||||
|
||||
|
||||
read failed: Input/output error
|
||||
|
||||
=== Check disconnect after data ===
|
||||
|
||||
|
||||
read 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
@@ -132,7 +123,6 @@ no file open, try 'help open'
|
||||
|
||||
=== Check disconnect after neg-classic ===
|
||||
|
||||
|
||||
read failed: Input/output error
|
||||
|
||||
*** done
|
||||
|
86
tests/qemu-iotests/117
Executable file
86
tests/qemu-iotests/117
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test case for shared BDS between backend trees
|
||||
#
|
||||
# Copyright (C) 2016 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# creator
|
||||
owner=mreitz@redhat.com
|
||||
|
||||
seq="$(basename $0)"
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here="$PWD"
|
||||
tmp=/tmp/$$
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
_cleanup_test_img
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
. ./common.qemu
|
||||
|
||||
_supported_fmt qcow2
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
_make_test_img 64k
|
||||
|
||||
_launch_qemu
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{ 'execute': 'qmp_capabilities' }" \
|
||||
'return'
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{ 'execute': 'blockdev-add',
|
||||
'arguments': { 'options': { 'id': 'protocol',
|
||||
'driver': 'file',
|
||||
'filename': '$TEST_IMG' } } }" \
|
||||
'return'
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{ 'execute': 'blockdev-add',
|
||||
'arguments': { 'options': { 'id': 'format',
|
||||
'driver': '$IMGFMT',
|
||||
'file': 'protocol' } } }" \
|
||||
'return'
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{ 'execute': 'human-monitor-command',
|
||||
'arguments': { 'command-line': 'qemu-io format \"write -P 42 0 64k\"' } }" \
|
||||
'return'
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{ 'execute': 'quit' }" \
|
||||
'return'
|
||||
|
||||
wait=1 _cleanup_qemu
|
||||
|
||||
_check_test_img
|
||||
|
||||
$QEMU_IO -c 'read -P 42 0 64k' "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
# success, all done
|
||||
echo '*** done'
|
||||
rm -f $seq.full
|
||||
status=0
|
14
tests/qemu-iotests/117.out
Normal file
14
tests/qemu-iotests/117.out
Normal file
@@ -0,0 +1,14 @@
|
||||
QA output created by 117
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
wrote 65536/65536 bytes at offset 0
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
{"return": ""}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
|
||||
No errors were found on the image.
|
||||
read 65536/65536 bytes at offset 0
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
*** done
|
@@ -42,6 +42,9 @@ class ChangeBaseClass(iotests.QMPTestCase):
|
||||
self.has_opened = True
|
||||
|
||||
def wait_for_open(self):
|
||||
if not self.has_real_tray:
|
||||
return
|
||||
|
||||
timeout = time.clock() + 3
|
||||
while not self.has_opened and time.clock() < timeout:
|
||||
self.process_events()
|
||||
@@ -49,6 +52,9 @@ class ChangeBaseClass(iotests.QMPTestCase):
|
||||
self.fail('Timeout while waiting for the tray to open')
|
||||
|
||||
def wait_for_close(self):
|
||||
if not self.has_real_tray:
|
||||
return
|
||||
|
||||
timeout = time.clock() + 3
|
||||
while not self.has_closed and time.clock() < timeout:
|
||||
self.process_events()
|
||||
@@ -65,7 +71,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
|
||||
self.wait_for_close()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
if self.has_real_tray:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
||||
|
||||
def test_blockdev_change_medium(self):
|
||||
@@ -78,7 +85,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
|
||||
self.wait_for_close()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
if self.has_real_tray:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
||||
|
||||
def test_eject(self):
|
||||
@@ -88,7 +96,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
|
||||
self.wait_for_open()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
if self.has_real_tray:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
self.assert_qmp_absent(result, 'return[0]/inserted')
|
||||
|
||||
def test_tray_eject_change(self):
|
||||
@@ -98,7 +107,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
|
||||
self.wait_for_open()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
if self.has_real_tray:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
self.assert_qmp_absent(result, 'return[0]/inserted')
|
||||
|
||||
result = self.vm.qmp('blockdev-change-medium', device='drive0',
|
||||
@@ -109,7 +119,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
|
||||
self.wait_for_close()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
if self.has_real_tray:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
||||
|
||||
def test_tray_open_close(self):
|
||||
@@ -119,7 +130,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
|
||||
self.wait_for_open()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
if self.has_real_tray:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
if self.was_empty == True:
|
||||
self.assert_qmp_absent(result, 'return[0]/inserted')
|
||||
else:
|
||||
@@ -132,10 +144,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
|
||||
self.wait_for_close()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
if self.has_real_tray or not self.was_empty:
|
||||
if self.has_real_tray:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
else:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
if self.was_empty == True:
|
||||
self.assert_qmp_absent(result, 'return[0]/inserted')
|
||||
else:
|
||||
@@ -148,20 +158,18 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
|
||||
self.wait_for_open()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
if self.has_real_tray:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
self.assert_qmp_absent(result, 'return[0]/inserted')
|
||||
|
||||
result = self.vm.qmp('blockdev-close-tray', device='drive0')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
if self.has_real_tray:
|
||||
self.wait_for_close()
|
||||
self.wait_for_close()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
if self.has_real_tray:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
else:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
self.assert_qmp_absent(result, 'return[0]/inserted')
|
||||
|
||||
def test_tray_open_change(self):
|
||||
@@ -171,7 +179,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
|
||||
self.wait_for_open()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
if self.has_real_tray:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
if self.was_empty == True:
|
||||
self.assert_qmp_absent(result, 'return[0]/inserted')
|
||||
else:
|
||||
@@ -185,7 +194,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
|
||||
self.wait_for_close()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
if self.has_real_tray:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
||||
|
||||
def test_cycle(self):
|
||||
@@ -202,7 +212,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
|
||||
self.wait_for_open()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
if self.has_real_tray:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
if self.was_empty == True:
|
||||
self.assert_qmp_absent(result, 'return[0]/inserted')
|
||||
else:
|
||||
@@ -212,7 +223,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
if self.has_real_tray:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
self.assert_qmp_absent(result, 'return[0]/inserted')
|
||||
|
||||
result = self.vm.qmp('x-blockdev-insert-medium', device='drive0',
|
||||
@@ -220,7 +232,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
if self.has_real_tray:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
||||
|
||||
result = self.vm.qmp('blockdev-close-tray', device='drive0')
|
||||
@@ -229,7 +242,8 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
|
||||
self.wait_for_close()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
if self.has_real_tray:
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
||||
|
||||
def test_close_on_closed(self):
|
||||
@@ -239,16 +253,14 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass):
|
||||
self.assertEquals(self.vm.get_qmp_events(wait=False), [])
|
||||
|
||||
def test_remove_on_closed(self):
|
||||
if self.has_opened:
|
||||
# Empty floppy drive
|
||||
if not self.has_real_tray:
|
||||
return
|
||||
|
||||
result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
|
||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||
|
||||
def test_insert_on_closed(self):
|
||||
if self.has_opened:
|
||||
# Empty floppy drive
|
||||
if not self.has_real_tray:
|
||||
return
|
||||
|
||||
result = self.vm.qmp('blockdev-add',
|
||||
@@ -366,7 +378,6 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
self.vm.launch()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
|
||||
|
||||
@@ -376,11 +387,7 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
read_only_mode='retain')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
self.wait_for_open()
|
||||
self.wait_for_close()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
||||
|
||||
@@ -390,7 +397,6 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
self.vm.launch()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
|
||||
|
||||
@@ -400,11 +406,7 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
read_only_mode='retain')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
self.wait_for_open()
|
||||
self.wait_for_close()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
||||
|
||||
@@ -414,7 +416,6 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
self.vm.launch()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
|
||||
|
||||
@@ -427,7 +428,6 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
self.assertEquals(self.vm.get_qmp_events(wait=False), [])
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
|
||||
|
||||
@@ -437,7 +437,6 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
self.vm.launch()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
|
||||
|
||||
@@ -448,11 +447,7 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
read_only_mode='read-write')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
self.wait_for_open()
|
||||
self.wait_for_close()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
||||
|
||||
@@ -462,7 +457,6 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
self.vm.launch()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
|
||||
|
||||
@@ -473,11 +467,7 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
read_only_mode='read-only')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
self.wait_for_open()
|
||||
self.wait_for_close()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
||||
|
||||
@@ -486,7 +476,6 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
self.vm.launch()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
|
||||
|
||||
@@ -497,11 +486,7 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
read_only_mode='read-only')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
self.wait_for_open()
|
||||
self.wait_for_close()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
||||
|
||||
@@ -511,7 +496,6 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
self.vm.launch()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
|
||||
|
||||
@@ -522,10 +506,7 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
read_only_mode='read-write')
|
||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||
|
||||
self.assertEquals(self.vm.get_qmp_events(wait=False), [])
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
|
||||
|
||||
@@ -535,7 +516,6 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
self.vm.launch()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
|
||||
|
||||
@@ -545,11 +525,7 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
read_only_mode='retain')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
self.wait_for_open()
|
||||
self.wait_for_close()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
||||
|
||||
@@ -559,7 +535,6 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
self.vm.launch()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
|
||||
|
||||
@@ -569,10 +544,7 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
read_only_mode='retain')
|
||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||
|
||||
self.assertEquals(self.vm.get_qmp_events(wait=False), [])
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
|
||||
|
||||
@@ -582,7 +554,6 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
self.vm.launch()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
|
||||
|
||||
@@ -594,13 +565,7 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
'driver': 'file'}})
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
self.wait_for_open()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
|
||||
|
||||
@@ -608,7 +573,6 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
self.assert_qmp_absent(result, 'return[0]/inserted')
|
||||
|
||||
result = self.vm.qmp('x-blockdev-insert-medium', device='drive0',
|
||||
@@ -616,17 +580,10 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', True)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
||||
|
||||
result = self.vm.qmp('blockdev-close-tray', device='drive0')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
self.wait_for_close()
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
||||
|
||||
@@ -648,7 +605,6 @@ class TestBlockJobsAfterCycle(ChangeBaseClass):
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/format', 'null-co')
|
||||
|
||||
# For device-less BBs, calling blockdev-open-tray or blockdev-close-tray
|
||||
@@ -671,7 +627,6 @@ class TestBlockJobsAfterCycle(ChangeBaseClass):
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/tray_open', False)
|
||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
|
||||
|
||||
def tearDown(self):
|
||||
@@ -717,4 +672,6 @@ if __name__ == '__main__':
|
||||
# We need floppy and IDE CD-ROM
|
||||
iotests.notrun('not suitable for this machine type: %s' %
|
||||
iotests.qemu_default_machine)
|
||||
iotests.main()
|
||||
# Need to support image creation
|
||||
iotests.main(supported_fmts=['vpc', 'parallels', 'qcow', 'vdi', 'qcow2',
|
||||
'vmdk', 'raw', 'vhdx', 'qed'])
|
||||
|
92
tests/qemu-iotests/140
Executable file
92
tests/qemu-iotests/140
Executable file
@@ -0,0 +1,92 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test case for ejecting a BB with an NBD server attached to it
|
||||
#
|
||||
# Copyright (C) 2016 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# creator
|
||||
owner=mreitz@redhat.com
|
||||
|
||||
seq="$(basename $0)"
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here="$PWD"
|
||||
tmp=/tmp/$$
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
_cleanup_test_img
|
||||
rm -f "$TEST_DIR/nbd"
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
. ./common.qemu
|
||||
|
||||
_supported_fmt generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
_make_test_img 64k
|
||||
|
||||
$QEMU_IO -c 'write -P 42 0 64k' "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
keep_stderr=y \
|
||||
_launch_qemu -drive if=ide,media=cdrom,id=drv,file="$TEST_IMG",format=$IMGFMT \
|
||||
2> >(_filter_nbd)
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{ 'execute': 'qmp_capabilities' }" \
|
||||
'return'
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{ 'execute': 'nbd-server-start',
|
||||
'arguments': { 'addr': { 'type': 'unix',
|
||||
'data': { 'path': '$TEST_DIR/nbd' }}}}" \
|
||||
'return'
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{ 'execute': 'nbd-server-add',
|
||||
'arguments': { 'device': 'drv' }}" \
|
||||
'return'
|
||||
|
||||
$QEMU_IO_PROG -f raw -c 'read -P 42 0 64k' \
|
||||
"nbd+unix:///drv?socket=$TEST_DIR/nbd" 2>&1 \
|
||||
| _filter_qemu_io | _filter_nbd
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{ 'execute': 'eject',
|
||||
'arguments': { 'device': 'drv' }}" \
|
||||
'return'
|
||||
|
||||
$QEMU_IO_PROG -f raw -c close \
|
||||
"nbd+unix:///drv?socket=$TEST_DIR/nbd" 2>&1 \
|
||||
| _filter_qemu_io | _filter_nbd
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{ 'execute': 'quit' }" \
|
||||
'return'
|
||||
|
||||
wait=1 _cleanup_qemu
|
||||
|
||||
# success, all done
|
||||
echo '*** done'
|
||||
rm -f $seq.full
|
||||
status=0
|
16
tests/qemu-iotests/140.out
Normal file
16
tests/qemu-iotests/140.out
Normal file
@@ -0,0 +1,16 @@
|
||||
QA output created by 140
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536
|
||||
wrote 65536/65536 bytes at offset 0
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
read 65536/65536 bytes at offset 0
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "drv", "tray-open": true}}
|
||||
{"return": {}}
|
||||
can't open device nbd+unix:///drv?socket=TEST_DIR/nbd: Failed to read export length
|
||||
no file open, try 'help open'
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
|
||||
*** done
|
186
tests/qemu-iotests/141
Executable file
186
tests/qemu-iotests/141
Executable file
@@ -0,0 +1,186 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test case for ejecting BDSs with block jobs still running on them
|
||||
#
|
||||
# Copyright (C) 2016 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# creator
|
||||
owner=mreitz@redhat.com
|
||||
|
||||
seq="$(basename $0)"
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here="$PWD"
|
||||
tmp=/tmp/$$
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
_cleanup_test_img
|
||||
rm -f "$TEST_DIR/{b,m,o}.$IMGFMT"
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
. ./common.qemu
|
||||
|
||||
# Needs backing file and backing format support
|
||||
_supported_fmt qcow2 qed
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
|
||||
test_blockjob()
|
||||
{
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{'execute': 'blockdev-add',
|
||||
'arguments': {
|
||||
'options': {
|
||||
'id': 'drv0',
|
||||
'driver': '$IMGFMT',
|
||||
'file': {
|
||||
'driver': 'file',
|
||||
'filename': '$TEST_IMG'
|
||||
}}}}" \
|
||||
'return'
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"$1" \
|
||||
"$2" \
|
||||
| _filter_img_create
|
||||
|
||||
# We want this to return an error because the block job is still running
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{'execute': 'x-blockdev-remove-medium',
|
||||
'arguments': {'device': 'drv0'}}" \
|
||||
'error'
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{'execute': 'block-job-cancel',
|
||||
'arguments': {'device': 'drv0'}}" \
|
||||
"$3"
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{'execute': 'x-blockdev-del',
|
||||
'arguments': {'id': 'drv0'}}" \
|
||||
'return'
|
||||
}
|
||||
|
||||
|
||||
TEST_IMG="$TEST_DIR/b.$IMGFMT" _make_test_img 1M
|
||||
TEST_IMG="$TEST_DIR/m.$IMGFMT" _make_test_img -b "$TEST_DIR/b.$IMGFMT" 1M
|
||||
_make_test_img -b "$TEST_DIR/m.$IMGFMT" 1M
|
||||
|
||||
_launch_qemu -nodefaults
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{'execute': 'qmp_capabilities'}" \
|
||||
'return'
|
||||
|
||||
echo
|
||||
echo '=== Testing drive-backup ==='
|
||||
echo
|
||||
|
||||
# drive-backup will not send BLOCK_JOB_READY by itself, and cancelling the job
|
||||
# will consequently result in BLOCK_JOB_CANCELLED being emitted.
|
||||
|
||||
test_blockjob \
|
||||
"{'execute': 'drive-backup',
|
||||
'arguments': {'device': 'drv0',
|
||||
'target': '$TEST_DIR/o.$IMGFMT',
|
||||
'format': '$IMGFMT',
|
||||
'sync': 'none'}}" \
|
||||
'return' \
|
||||
'BLOCK_JOB_CANCELLED'
|
||||
|
||||
echo
|
||||
echo '=== Testing drive-mirror ==='
|
||||
echo
|
||||
|
||||
# drive-mirror will send BLOCK_JOB_READY basically immediately, and cancelling
|
||||
# the job will consequently result in BLOCK_JOB_COMPLETED being emitted.
|
||||
|
||||
test_blockjob \
|
||||
"{'execute': 'drive-mirror',
|
||||
'arguments': {'device': 'drv0',
|
||||
'target': '$TEST_DIR/o.$IMGFMT',
|
||||
'format': '$IMGFMT',
|
||||
'sync': 'none'}}" \
|
||||
'BLOCK_JOB_READY' \
|
||||
'BLOCK_JOB_COMPLETED'
|
||||
|
||||
echo
|
||||
echo '=== Testing active block-commit ==='
|
||||
echo
|
||||
|
||||
# An active block-commit will send BLOCK_JOB_READY basically immediately, and
|
||||
# cancelling the job will consequently result in BLOCK_JOB_COMPLETED being
|
||||
# emitted.
|
||||
|
||||
test_blockjob \
|
||||
"{'execute': 'block-commit',
|
||||
'arguments': {'device': 'drv0'}}" \
|
||||
'BLOCK_JOB_READY' \
|
||||
'BLOCK_JOB_COMPLETED'
|
||||
|
||||
echo
|
||||
echo '=== Testing non-active block-commit ==='
|
||||
echo
|
||||
|
||||
# Give block-commit something to work on, otherwise it would be done
|
||||
# immediately, send a BLOCK_JOB_COMPLETED and ejecting the BDS would work just
|
||||
# fine without the block job still running.
|
||||
|
||||
$QEMU_IO -c 'write 0 1M' "$TEST_DIR/m.$IMGFMT" | _filter_qemu_io
|
||||
|
||||
test_blockjob \
|
||||
"{'execute': 'block-commit',
|
||||
'arguments': {'device': 'drv0',
|
||||
'top': '$TEST_DIR/m.$IMGFMT',
|
||||
'speed': 1}}" \
|
||||
'return' \
|
||||
'BLOCK_JOB_CANCELLED'
|
||||
|
||||
echo
|
||||
echo '=== Testing block-stream ==='
|
||||
echo
|
||||
|
||||
# Give block-stream something to work on, otherwise it would be done
|
||||
# immediately, send a BLOCK_JOB_COMPLETED and ejecting the BDS would work just
|
||||
# fine without the block job still running.
|
||||
|
||||
$QEMU_IO -c 'write 0 1M' "$TEST_DIR/b.$IMGFMT" | _filter_qemu_io
|
||||
|
||||
# With some data to stream (and @speed set to 1), block-stream will not complete
|
||||
# until we send the block-job-cancel command. Therefore, no event other than
|
||||
# BLOCK_JOB_CANCELLED will be emitted.
|
||||
|
||||
test_blockjob \
|
||||
"{'execute': 'block-stream',
|
||||
'arguments': {'device': 'drv0',
|
||||
'speed': 1}}" \
|
||||
'return' \
|
||||
'BLOCK_JOB_CANCELLED'
|
||||
|
||||
_cleanup_qemu
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
59
tests/qemu-iotests/141.out
Normal file
59
tests/qemu-iotests/141.out
Normal file
@@ -0,0 +1,59 @@
|
||||
QA output created by 141
|
||||
Formatting 'TEST_DIR/b.IMGFMT', fmt=IMGFMT size=1048576
|
||||
Formatting 'TEST_DIR/m.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/b.IMGFMT
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/m.IMGFMT
|
||||
{"return": {}}
|
||||
|
||||
=== Testing drive-backup ===
|
||||
|
||||
{"return": {}}
|
||||
Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
|
||||
{"return": {}}
|
||||
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: backup"}}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "drv0", "len": 1048576, "offset": 0, "speed": 0, "type": "backup"}}
|
||||
{"return": {}}
|
||||
|
||||
=== Testing drive-mirror ===
|
||||
|
||||
{"return": {}}
|
||||
Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "drv0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}}
|
||||
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: mirror"}}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "drv0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}}
|
||||
{"return": {}}
|
||||
|
||||
=== Testing active block-commit ===
|
||||
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "drv0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
|
||||
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "drv0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
|
||||
{"return": {}}
|
||||
|
||||
=== Testing non-active block-commit ===
|
||||
|
||||
wrote 1048576/1048576 bytes at offset 0
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "drv0", "len": 1048576, "offset": 524288, "speed": 1, "type": "commit"}}
|
||||
{"return": {}}
|
||||
|
||||
=== Testing block-stream ===
|
||||
|
||||
wrote 1048576/1048576 bytes at offset 0
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: stream"}}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "drv0", "len": 1048576, "offset": 524288, "speed": 1, "type": "stream"}}
|
||||
{"return": {}}
|
||||
*** done
|
73
tests/qemu-iotests/143
Executable file
73
tests/qemu-iotests/143
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test case for connecting to a non-existing NBD export name
|
||||
#
|
||||
# Copyright (C) 2016 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# creator
|
||||
owner=mreitz@redhat.com
|
||||
|
||||
seq="$(basename $0)"
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here="$PWD"
|
||||
tmp=/tmp/$$
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
rm -f "$TEST_DIR/nbd"
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
. ./common.qemu
|
||||
|
||||
_supported_fmt generic
|
||||
_supported_proto generic
|
||||
_supported_os Linux
|
||||
|
||||
keep_stderr=y \
|
||||
_launch_qemu 2> >(_filter_nbd)
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{ 'execute': 'qmp_capabilities' }" \
|
||||
'return'
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{ 'execute': 'nbd-server-start',
|
||||
'arguments': { 'addr': { 'type': 'unix',
|
||||
'data': { 'path': '$TEST_DIR/nbd' }}}}" \
|
||||
'return'
|
||||
|
||||
# This should just result in a client error, not in the server crashing
|
||||
$QEMU_IO_PROG -f raw -c quit \
|
||||
"nbd+unix:///no_such_export?socket=$TEST_DIR/nbd" 2>&1 \
|
||||
| _filter_qemu_io | _filter_nbd
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{ 'execute': 'quit' }" \
|
||||
'return'
|
||||
|
||||
wait=1 _cleanup_qemu
|
||||
|
||||
# success, all done
|
||||
echo '*** done'
|
||||
rm -f $seq.full
|
||||
status=0
|
7
tests/qemu-iotests/143.out
Normal file
7
tests/qemu-iotests/143.out
Normal file
@@ -0,0 +1,7 @@
|
||||
QA output created by 143
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
can't open device nbd+unix:///no_such_export?socket=TEST_DIR/nbd: Failed to read export length
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
|
||||
*** done
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user