Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into s…
Browse files Browse the repository at this point in the history
…taging

Block layer patches:

- qcow2: Fix data corruption bug that is triggered in partial cluster
  allocation with default options
- qapi: add support for blkreplay driver
- doc: Describe missing generic -blockdev options
- iotests: Fix 118 when run as root
- Minor code cleanups

# gpg: Signature made Fri 25 Oct 2019 14:19:04 BST
# gpg:                using RSA key 7F09B272C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full]
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74  56FE 7F09 B272 C88F 2FD6

* remotes/kevin/tags/for-upstream:
  qcow2: Fix corruption bug in qcow2_detect_metadata_preallocation()
  coroutine: Add qemu_co_mutex_assert_locked()
  doc: Describe missing generic -blockdev options
  block/backup: drop dead code from backup_job_create
  blockdev: Use error_report() in hmp_commit()
  iotests: Skip read-only cases in 118 when run as root
  qapi: add support for blkreplay driver

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Oct 25, 2019
2 parents bad76ac + 5e97855 commit 03bf012
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 12 deletions.
5 changes: 1 addition & 4 deletions block/backup.c
Expand Up @@ -474,10 +474,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
if (sync_bitmap) {
bdrv_reclaim_dirty_bitmap(sync_bitmap, NULL);
}
if (job) {
backup_clean(&job->common.job);
job_early_fail(&job->common.job);
} else if (backup_top) {
if (backup_top) {
bdrv_backup_top_drop(backup_top);
}

Expand Down
2 changes: 2 additions & 0 deletions block/qcow2-refcount.c
Expand Up @@ -3455,6 +3455,8 @@ int qcow2_detect_metadata_preallocation(BlockDriverState *bs)
int64_t i, end_cluster, cluster_count = 0, threshold;
int64_t file_length, real_allocation, real_clusters;

qemu_co_mutex_assert_locked(&s->lock);

file_length = bdrv_getlength(bs->file->bs);
if (file_length < 0) {
return file_length;
Expand Down
3 changes: 2 additions & 1 deletion block/qcow2.c
Expand Up @@ -1916,14 +1916,15 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
unsigned int bytes;
int status = 0;

qemu_co_mutex_lock(&s->lock);

if (!s->metadata_preallocation_checked) {
ret = qcow2_detect_metadata_preallocation(bs);
s->metadata_preallocation = (ret == 1);
s->metadata_preallocation_checked = true;
}

bytes = MIN(INT_MAX, count);
qemu_co_mutex_lock(&s->lock);
ret = qcow2_get_cluster_offset(bs, offset, &bytes, &cluster_offset);
qemu_co_mutex_unlock(&s->lock);
if (ret < 0) {
Expand Down
7 changes: 3 additions & 4 deletions blockdev.c
Expand Up @@ -1088,11 +1088,11 @@ void hmp_commit(Monitor *mon, const QDict *qdict)

blk = blk_by_name(device);
if (!blk) {
monitor_printf(mon, "Device '%s' not found\n", device);
error_report("Device '%s' not found", device);
return;
}
if (!blk_is_available(blk)) {
monitor_printf(mon, "Device '%s' has no medium\n", device);
error_report("Device '%s' has no medium", device);
return;
}

Expand All @@ -1105,8 +1105,7 @@ void hmp_commit(Monitor *mon, const QDict *qdict)
aio_context_release(aio_context);
}
if (ret < 0) {
monitor_printf(mon, "'commit' error for '%s': %s\n", device,
strerror(-ret));
error_report("'commit' error for '%s': %s", device, strerror(-ret));
}
}

Expand Down
15 changes: 15 additions & 0 deletions include/qemu/coroutine.h
Expand Up @@ -167,6 +167,21 @@ void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex);
*/
void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex);

/**
* Assert that the current coroutine holds @mutex.
*/
static inline coroutine_fn void qemu_co_mutex_assert_locked(CoMutex *mutex)
{
/*
* mutex->holder doesn't need any synchronisation if the assertion holds
* true because the mutex protects it. If it doesn't hold true, we still
* don't mind if another thread takes or releases mutex behind our back,
* because the condition will be false no matter whether we read NULL or
* the pointer for any other coroutine.
*/
assert(atomic_read(&mutex->locked) &&
mutex->holder == qemu_coroutine_self());
}

/**
* CoQueues are a mechanism to queue coroutines in order to continue executing
Expand Down
18 changes: 16 additions & 2 deletions qapi/block-core.json
Expand Up @@ -2883,12 +2883,13 @@
# @nvme: Since 2.12
# @copy-on-read: Since 3.0
# @blklogwrites: Since 3.0
# @blkreplay: Since 4.2
#
# Since: 2.9
##
{ 'enum': 'BlockdevDriver',
'data': [ 'blkdebug', 'blklogwrites', 'blkverify', 'bochs', 'cloop',
'copy-on-read', 'dmg', 'file', 'ftp', 'ftps', 'gluster',
'data': [ 'blkdebug', 'blklogwrites', 'blkreplay', 'blkverify', 'bochs',
'cloop', 'copy-on-read', 'dmg', 'file', 'ftp', 'ftps', 'gluster',
'host_cdrom', 'host_device', 'http', 'https', 'iscsi', 'luks',
'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels', 'qcow',
'qcow2', 'qed', 'quorum', 'raw', 'rbd',
Expand Down Expand Up @@ -3501,6 +3502,18 @@
'data': { 'test': 'BlockdevRef',
'raw': 'BlockdevRef' } }

##
# @BlockdevOptionsBlkreplay:
#
# Driver specific block device options for blkreplay.
#
# @image: disk image which should be controlled with blkreplay
#
# Since: 4.2
##
{ 'struct': 'BlockdevOptionsBlkreplay',
'data': { 'image': 'BlockdevRef' } }

##
# @QuorumReadPattern:
#
Expand Down Expand Up @@ -4028,6 +4041,7 @@
'blkdebug': 'BlockdevOptionsBlkdebug',
'blklogwrites':'BlockdevOptionsBlklogwrites',
'blkverify': 'BlockdevOptionsBlkverify',
'blkreplay': 'BlockdevOptionsBlkreplay',
'bochs': 'BlockdevOptionsGenericFormat',
'cloop': 'BlockdevOptionsGenericFormat',
'copy-on-read':'BlockdevOptionsGenericFormat',
Expand Down
22 changes: 21 additions & 1 deletion qemu-options.hx
Expand Up @@ -864,7 +864,8 @@ ETEXI
DEF("blockdev", HAS_ARG, QEMU_OPTION_blockdev,
"-blockdev [driver=]driver[,node-name=N][,discard=ignore|unmap]\n"
" [,cache.direct=on|off][,cache.no-flush=on|off]\n"
" [,read-only=on|off][,detect-zeroes=on|off|unmap]\n"
" [,read-only=on|off][,auto-read-only=on|off]\n"
" [,force-share=on|off][,detect-zeroes=on|off|unmap]\n"
" [,driver specific parameters...]\n"
" configure a block backend\n", QEMU_ARCH_ALL)
STEXI
Expand Down Expand Up @@ -900,6 +901,25 @@ name is not intended to be predictable and changes between QEMU invocations.
For the top level, an explicit node name must be specified.
@item read-only
Open the node read-only. Guest write attempts will fail.

Note that some block drivers support only read-only access, either generally or
in certain configurations. In this case, the default value
@option{read-only=off} does not work and the option must be specified
explicitly.
@item auto-read-only
If @option{auto-read-only=on} is set, QEMU may fall back to read-only usage
even when @option{read-only=off} is requested, or even switch between modes as
needed, e.g. depending on whether the image file is writable or whether a
writing user is attached to the node.
@item force-share
Override the image locking system of QEMU by forcing the node to utilize
weaker shared access for permissions where it would normally request exclusive
access. When there is the potential for multiple instances to have the same
file open (whether this invocation of QEMU is the first or the second
instance), both instances must permit shared access for the second instance to
succeed at opening the file.

Enabling @option{force-share=on} requires @option{read-only=on}.
@item cache.direct
The host page cache can be avoided with @option{cache.direct=on}. This will
attempt to do disk IO directly to the guest's memory. QEMU may still perform an
Expand Down
3 changes: 3 additions & 0 deletions tests/qemu-iotests/118
Expand Up @@ -446,6 +446,7 @@ class TestChangeReadOnly(ChangeBaseClass):
self.assert_qmp(result, 'return[0]/inserted/ro', True)
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)

@iotests.skip_if_user_is_root
def test_rw_ro_retain(self):
os.chmod(new_img, 0o444)
self.vm.add_drive(old_img, 'media=disk', 'none')
Expand Down Expand Up @@ -530,6 +531,7 @@ class TestChangeReadOnly(ChangeBaseClass):
self.assert_qmp(result, 'return[0]/inserted/ro', True)
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)

@iotests.skip_if_user_is_root
def test_make_ro_rw(self):
os.chmod(new_img, 0o444)
self.vm.add_drive(old_img, 'media=disk', 'none')
Expand Down Expand Up @@ -571,6 +573,7 @@ class TestChangeReadOnly(ChangeBaseClass):
self.assert_qmp(result, 'return[0]/inserted/ro', True)
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)

@iotests.skip_if_user_is_root
def test_make_ro_rw_by_retain(self):
os.chmod(new_img, 0o444)
self.vm.add_drive(old_img, 'media=disk', 'none')
Expand Down
10 changes: 10 additions & 0 deletions tests/qemu-iotests/iotests.py
Expand Up @@ -931,6 +931,16 @@ def func_wrapper(*args, **kwargs):
return func_wrapper
return skip_test_decorator

def skip_if_user_is_root(func):
'''Skip Test Decorator
Runs the test only without root permissions'''
def func_wrapper(*args, **kwargs):
if os.getuid() == 0:
case_notrun('{}: cannot be run as root'.format(args[0]))
else:
return func(*args, **kwargs)
return func_wrapper

def execute_unittest(output, verbosity, debug):
runner = unittest.TextTestRunner(stream=output, descriptions=True,
verbosity=verbosity)
Expand Down

0 comments on commit 03bf012

Please sign in to comment.