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 -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJdsvZIAAoJEH8JsnLIjy/W14oP/1vcfFbet4tOzFU8Wx1rOwR6 1sCWN41Wwj60wNIS4npDTj1iKVXFXShkOOZyufQ/1AE5yEnP+Qod03rURqQTZKeS UT11Cwqx6hyqCJRgNMFBmdlQiGXW3rJWlSM0E5zV10hPwDGEK3c9rjox0b7MdTjD h7oOXk26hILV4ig6OFXsUghNP6jAuRLsWWeMd2/0xl6PcniU4XHLuMvmdwxMHoDU q3CEAxJe0xG2M6Fu7oEnJss+C/18lk7vlQ/3g93jUe54NVlme6r9FNErdBBDr/MF Jo8u4GTS2lp3uNaNmKL+yECkiigRxIBGoPeRGHQRk0rMl2KR3/NwbMXYFFer8jsi aRzVziNC0L+LWyU0I1Taf9IlyyHVhZkhoU6NU5c0fqs9mOBy1E/5LxoP7zUWqbUC 7ZZg8Hhv+9gZJdk62/vqm4y/tEQmYmUxA6/GSb3Yn5aogCiGBsMsTsq9zge3Fkrq wl/CwmtcngZzENUreGTMv/MbPbRx+A8QWA/TRVdg0AGcvosQfqR1a1i421X4AGuB 9bx0wSfnrnRS43BPTkY2Wqhq4GMfHWxf80S9a0xlZxnZZLt2vef+vDhgV/d2yd56 RRTUC5jqBPtxPT98frgjGRdr74DqEInSrtOf/9DpJ79SgoLFNylp31kqJRQ/qNJN iSKyGWA7nn+8VQi+1ufh =JZpU -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging 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>
This commit is contained in:
commit
03bf012e52
|
@ -474,10 +474,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||||
if (sync_bitmap) {
|
if (sync_bitmap) {
|
||||||
bdrv_reclaim_dirty_bitmap(sync_bitmap, NULL);
|
bdrv_reclaim_dirty_bitmap(sync_bitmap, NULL);
|
||||||
}
|
}
|
||||||
if (job) {
|
if (backup_top) {
|
||||||
backup_clean(&job->common.job);
|
|
||||||
job_early_fail(&job->common.job);
|
|
||||||
} else if (backup_top) {
|
|
||||||
bdrv_backup_top_drop(backup_top);
|
bdrv_backup_top_drop(backup_top);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3455,6 +3455,8 @@ int qcow2_detect_metadata_preallocation(BlockDriverState *bs)
|
||||||
int64_t i, end_cluster, cluster_count = 0, threshold;
|
int64_t i, end_cluster, cluster_count = 0, threshold;
|
||||||
int64_t file_length, real_allocation, real_clusters;
|
int64_t file_length, real_allocation, real_clusters;
|
||||||
|
|
||||||
|
qemu_co_mutex_assert_locked(&s->lock);
|
||||||
|
|
||||||
file_length = bdrv_getlength(bs->file->bs);
|
file_length = bdrv_getlength(bs->file->bs);
|
||||||
if (file_length < 0) {
|
if (file_length < 0) {
|
||||||
return file_length;
|
return file_length;
|
||||||
|
|
|
@ -1916,6 +1916,8 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
|
||||||
unsigned int bytes;
|
unsigned int bytes;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
|
qemu_co_mutex_lock(&s->lock);
|
||||||
|
|
||||||
if (!s->metadata_preallocation_checked) {
|
if (!s->metadata_preallocation_checked) {
|
||||||
ret = qcow2_detect_metadata_preallocation(bs);
|
ret = qcow2_detect_metadata_preallocation(bs);
|
||||||
s->metadata_preallocation = (ret == 1);
|
s->metadata_preallocation = (ret == 1);
|
||||||
|
@ -1923,7 +1925,6 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes = MIN(INT_MAX, count);
|
bytes = MIN(INT_MAX, count);
|
||||||
qemu_co_mutex_lock(&s->lock);
|
|
||||||
ret = qcow2_get_cluster_offset(bs, offset, &bytes, &cluster_offset);
|
ret = qcow2_get_cluster_offset(bs, offset, &bytes, &cluster_offset);
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
qemu_co_mutex_unlock(&s->lock);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|
|
@ -1088,11 +1088,11 @@ void hmp_commit(Monitor *mon, const QDict *qdict)
|
||||||
|
|
||||||
blk = blk_by_name(device);
|
blk = blk_by_name(device);
|
||||||
if (!blk) {
|
if (!blk) {
|
||||||
monitor_printf(mon, "Device '%s' not found\n", device);
|
error_report("Device '%s' not found", device);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!blk_is_available(blk)) {
|
if (!blk_is_available(blk)) {
|
||||||
monitor_printf(mon, "Device '%s' has no medium\n", device);
|
error_report("Device '%s' has no medium", device);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1105,8 +1105,7 @@ void hmp_commit(Monitor *mon, const QDict *qdict)
|
||||||
aio_context_release(aio_context);
|
aio_context_release(aio_context);
|
||||||
}
|
}
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
monitor_printf(mon, "'commit' error for '%s': %s\n", device,
|
error_report("'commit' error for '%s': %s", device, strerror(-ret));
|
||||||
strerror(-ret));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -167,6 +167,21 @@ void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex);
|
||||||
*/
|
*/
|
||||||
void coroutine_fn qemu_co_mutex_unlock(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
|
* CoQueues are a mechanism to queue coroutines in order to continue executing
|
||||||
|
|
|
@ -2883,12 +2883,13 @@
|
||||||
# @nvme: Since 2.12
|
# @nvme: Since 2.12
|
||||||
# @copy-on-read: Since 3.0
|
# @copy-on-read: Since 3.0
|
||||||
# @blklogwrites: Since 3.0
|
# @blklogwrites: Since 3.0
|
||||||
|
# @blkreplay: Since 4.2
|
||||||
#
|
#
|
||||||
# Since: 2.9
|
# Since: 2.9
|
||||||
##
|
##
|
||||||
{ 'enum': 'BlockdevDriver',
|
{ 'enum': 'BlockdevDriver',
|
||||||
'data': [ 'blkdebug', 'blklogwrites', 'blkverify', 'bochs', 'cloop',
|
'data': [ 'blkdebug', 'blklogwrites', 'blkreplay', 'blkverify', 'bochs',
|
||||||
'copy-on-read', 'dmg', 'file', 'ftp', 'ftps', 'gluster',
|
'cloop', 'copy-on-read', 'dmg', 'file', 'ftp', 'ftps', 'gluster',
|
||||||
'host_cdrom', 'host_device', 'http', 'https', 'iscsi', 'luks',
|
'host_cdrom', 'host_device', 'http', 'https', 'iscsi', 'luks',
|
||||||
'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels', 'qcow',
|
'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels', 'qcow',
|
||||||
'qcow2', 'qed', 'quorum', 'raw', 'rbd',
|
'qcow2', 'qed', 'quorum', 'raw', 'rbd',
|
||||||
|
@ -3501,6 +3502,18 @@
|
||||||
'data': { 'test': 'BlockdevRef',
|
'data': { 'test': 'BlockdevRef',
|
||||||
'raw': '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:
|
# @QuorumReadPattern:
|
||||||
#
|
#
|
||||||
|
@ -4028,6 +4041,7 @@
|
||||||
'blkdebug': 'BlockdevOptionsBlkdebug',
|
'blkdebug': 'BlockdevOptionsBlkdebug',
|
||||||
'blklogwrites':'BlockdevOptionsBlklogwrites',
|
'blklogwrites':'BlockdevOptionsBlklogwrites',
|
||||||
'blkverify': 'BlockdevOptionsBlkverify',
|
'blkverify': 'BlockdevOptionsBlkverify',
|
||||||
|
'blkreplay': 'BlockdevOptionsBlkreplay',
|
||||||
'bochs': 'BlockdevOptionsGenericFormat',
|
'bochs': 'BlockdevOptionsGenericFormat',
|
||||||
'cloop': 'BlockdevOptionsGenericFormat',
|
'cloop': 'BlockdevOptionsGenericFormat',
|
||||||
'copy-on-read':'BlockdevOptionsGenericFormat',
|
'copy-on-read':'BlockdevOptionsGenericFormat',
|
||||||
|
|
|
@ -864,7 +864,8 @@ ETEXI
|
||||||
DEF("blockdev", HAS_ARG, QEMU_OPTION_blockdev,
|
DEF("blockdev", HAS_ARG, QEMU_OPTION_blockdev,
|
||||||
"-blockdev [driver=]driver[,node-name=N][,discard=ignore|unmap]\n"
|
"-blockdev [driver=]driver[,node-name=N][,discard=ignore|unmap]\n"
|
||||||
" [,cache.direct=on|off][,cache.no-flush=on|off]\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"
|
" [,driver specific parameters...]\n"
|
||||||
" configure a block backend\n", QEMU_ARCH_ALL)
|
" configure a block backend\n", QEMU_ARCH_ALL)
|
||||||
STEXI
|
STEXI
|
||||||
|
@ -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.
|
For the top level, an explicit node name must be specified.
|
||||||
@item read-only
|
@item read-only
|
||||||
Open the node read-only. Guest write attempts will fail.
|
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
|
@item cache.direct
|
||||||
The host page cache can be avoided with @option{cache.direct=on}. This will
|
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
|
attempt to do disk IO directly to the guest's memory. QEMU may still perform an
|
||||||
|
|
|
@ -446,6 +446,7 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||||
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
||||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
||||||
|
|
||||||
|
@iotests.skip_if_user_is_root
|
||||||
def test_rw_ro_retain(self):
|
def test_rw_ro_retain(self):
|
||||||
os.chmod(new_img, 0o444)
|
os.chmod(new_img, 0o444)
|
||||||
self.vm.add_drive(old_img, 'media=disk', 'none')
|
self.vm.add_drive(old_img, 'media=disk', 'none')
|
||||||
|
@ -530,6 +531,7 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||||
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
||||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
||||||
|
|
||||||
|
@iotests.skip_if_user_is_root
|
||||||
def test_make_ro_rw(self):
|
def test_make_ro_rw(self):
|
||||||
os.chmod(new_img, 0o444)
|
os.chmod(new_img, 0o444)
|
||||||
self.vm.add_drive(old_img, 'media=disk', 'none')
|
self.vm.add_drive(old_img, 'media=disk', 'none')
|
||||||
|
@ -571,6 +573,7 @@ class TestChangeReadOnly(ChangeBaseClass):
|
||||||
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
self.assert_qmp(result, 'return[0]/inserted/ro', True)
|
||||||
self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
|
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):
|
def test_make_ro_rw_by_retain(self):
|
||||||
os.chmod(new_img, 0o444)
|
os.chmod(new_img, 0o444)
|
||||||
self.vm.add_drive(old_img, 'media=disk', 'none')
|
self.vm.add_drive(old_img, 'media=disk', 'none')
|
||||||
|
|
|
@ -931,6 +931,16 @@ def skip_if_unsupported(required_formats=[], read_only=False):
|
||||||
return func_wrapper
|
return func_wrapper
|
||||||
return skip_test_decorator
|
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):
|
def execute_unittest(output, verbosity, debug):
|
||||||
runner = unittest.TextTestRunner(stream=output, descriptions=True,
|
runner = unittest.TextTestRunner(stream=output, descriptions=True,
|
||||||
verbosity=verbosity)
|
verbosity=verbosity)
|
||||||
|
|
Loading…
Reference in New Issue