1
The following changes since commit 5ec2eca83dc478ddf24077e02a8b34dd26cd3ff9:
1
The following changes since commit 9cf289af47bcfae5c75de37d8e5d6fd23705322c:
2
2
3
Merge remote-tracking branch 'remotes/awilliam/tags/vfio-updates-20190613.0' into staging (2019-06-14 09:33:55 +0100)
3
Merge tag 'qga-pull-request' of gitlab.com:marcandre.lureau/qemu into staging (2022-05-04 03:42:49 -0700)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://github.com/XanClic/qemu.git tags/pull-block-2019-06-14
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to 21c1ce592a144188dfe59b9e156a97da412a59a2:
9
for you to fetch changes up to bef2e050d6a7feb865854c65570c496ac5a8cf53:
10
10
11
iotests: Test qemu-img convert -C --salvage (2019-06-14 15:09:42 +0200)
11
util/event-loop-base: Introduce options to set the thread pool size (2022-05-04 17:02:19 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches:
14
Pull request
15
- Allow blockdev-backup from nodes that are not in qemu's main AIO
15
16
context to newly added nodes
16
Add new thread-pool-min/thread-pool-max parameters to control the thread pool
17
- Add salvaging mode to qemu-img convert
17
used for async I/O.
18
- Minor fixes to tests, documentation, and for less Valgrind annoyance
19
18
20
----------------------------------------------------------------
19
----------------------------------------------------------------
21
Andrey Shinkevich (1):
22
hw/block/fdc: floppy command FIFO memory initialization
23
20
24
John Snow (6):
21
Nicolas Saenz Julienne (3):
25
blockdev-backup: don't check aio_context too early
22
Introduce event-loop-base abstract class
26
iotests.py: do not use infinite waits
23
util/main-loop: Introduce the main loop into QOM
27
QEMUMachine: add events_wait method
24
util/event-loop-base: Introduce options to set the thread pool size
28
iotests.py: rewrite run_job to be pickier
29
iotests: add iotest 256 for testing blockdev-backup across iothread
30
contexts
31
event_match: always match on None value
32
25
33
Max Reitz (12):
26
qapi/qom.json | 43 ++++++++--
34
iotests: Filter 175's allocation information
27
meson.build | 26 +++---
35
iotests: Fix intermittent failure in 219
28
include/block/aio.h | 10 +++
36
qemu-img: Fix options leakage in img_rebase()
29
include/block/thread-pool.h | 3 +
37
qapi/block-core: Overlays are not snapshots
30
include/qemu/main-loop.h | 10 +++
38
blockdev: Overlays are not snapshots
31
include/sysemu/event-loop-base.h | 41 +++++++++
39
qemu-img: Move quiet into ImgConvertState
32
include/sysemu/iothread.h | 6 +-
40
qemu-img: Add salvaging mode to convert
33
event-loop-base.c | 140 +++++++++++++++++++++++++++++++
41
blkdebug: Add @iotype error option
34
iothread.c | 68 +++++----------
42
blkdebug: Add "none" event
35
util/aio-posix.c | 1 +
43
blkdebug: Inject errors on .bdrv_co_block_status()
36
util/async.c | 20 +++++
44
iotests: Test qemu-img convert --salvage
37
util/main-loop.c | 65 ++++++++++++++
45
iotests: Test qemu-img convert -C --salvage
38
util/thread-pool.c | 55 +++++++++++-
46
39
13 files changed, 419 insertions(+), 69 deletions(-)
47
Vladimir Sementsov-Ogievskiy (1):
40
create mode 100644 include/sysemu/event-loop-base.h
48
iotests: restrict 254 to support only qcow2
41
create mode 100644 event-loop-base.c
49
50
qapi/block-core.json | 53 ++++++++---
51
block/blkdebug.c | 60 ++++++++++--
52
blockdev.c | 14 +--
53
hw/block/fdc.c | 1 +
54
qemu-img.c | 106 +++++++++++++++------
55
python/qemu/__init__.py | 67 ++++++++++----
56
qemu-img-cmds.hx | 4 +-
57
qemu-img.texi | 4 +
58
tests/qemu-iotests/082 | 1 +
59
tests/qemu-iotests/082.out | 3 +
60
tests/qemu-iotests/085.out | 10 +-
61
tests/qemu-iotests/175 | 26 +++++-
62
tests/qemu-iotests/175.out | 8 +-
63
tests/qemu-iotests/219 | 13 ++-
64
tests/qemu-iotests/251 | 170 ++++++++++++++++++++++++++++++++++
65
tests/qemu-iotests/251.out | 43 +++++++++
66
tests/qemu-iotests/254 | 2 +
67
tests/qemu-iotests/256 | 122 ++++++++++++++++++++++++
68
tests/qemu-iotests/256.out | 119 ++++++++++++++++++++++++
69
tests/qemu-iotests/group | 2 +
70
tests/qemu-iotests/iotests.py | 60 +++++++-----
71
21 files changed, 772 insertions(+), 116 deletions(-)
72
create mode 100755 tests/qemu-iotests/251
73
create mode 100644 tests/qemu-iotests/251.out
74
create mode 100755 tests/qemu-iotests/256
75
create mode 100644 tests/qemu-iotests/256.out
76
42
77
--
43
--
78
2.21.0
44
2.35.1
79
80
diff view generated by jsdifflib
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
3
in blockdev_backup_prepare, we check to make sure that the target is
4
associated with a compatible aio context. However, do_blockdev_backup is
5
called later and has some logic to move the target to a compatible
6
aio_context. The transaction version will fail certain commands
7
needlessly early as a result.
8
9
Allow blockdev_backup_prepare to simply call do_blockdev_backup, which
10
will ultimately decide if the contexts are compatible or not.
11
12
Note: the transaction version has always disallowed this operation since
13
its initial commit bd8baecd (2014), whereas the version of
14
qmp_blockdev_backup at the time, from commit c29c1dd312f, tried to
15
enforce the aio_context switch instead. It's not clear, and I can't see
16
from the mailing list archives at the time, why the two functions take a
17
different approach. It wasn't until later in efd7556708b (2016) that the
18
standalone version tried to determine if it could set the context or
19
not.
20
21
Reported-by: aihua liang <aliang@redhat.com>
22
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1683498
23
Signed-off-by: John Snow <jsnow@redhat.com>
24
Message-id: 20190523170643.20794-2-jsnow@redhat.com
25
Reviewed-by: Max Reitz <mreitz@redhat.com>
26
Signed-off-by: Max Reitz <mreitz@redhat.com>
27
---
28
blockdev.c | 4 ----
29
1 file changed, 4 deletions(-)
30
31
diff --git a/blockdev.c b/blockdev.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/blockdev.c
34
+++ b/blockdev.c
35
@@ -XXX,XX +XXX,XX @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
36
}
37
38
aio_context = bdrv_get_aio_context(bs);
39
- if (aio_context != bdrv_get_aio_context(target)) {
40
- error_setg(errp, "Backup between two IO threads is not implemented");
41
- return;
42
- }
43
aio_context_acquire(aio_context);
44
state->bs = bs;
45
46
--
47
2.21.0
48
49
diff view generated by jsdifflib
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
3
Cap waits to 60 seconds so that iotests can fail gracefully if something
4
goes wrong.
5
6
Signed-off-by: John Snow <jsnow@redhat.com>
7
Message-id: 20190523170643.20794-3-jsnow@redhat.com
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
tests/qemu-iotests/iotests.py | 14 +++++++-------
12
1 file changed, 7 insertions(+), 7 deletions(-)
13
14
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/iotests.py
17
+++ b/tests/qemu-iotests/iotests.py
18
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
19
output_list += [key + '=' + obj[key]]
20
return ','.join(output_list)
21
22
- def get_qmp_events_filtered(self, wait=True):
23
+ def get_qmp_events_filtered(self, wait=60.0):
24
result = []
25
for ev in self.get_qmp_events(wait=wait):
26
result.append(filter_qmp_event(ev))
27
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
28
29
# Returns None on success, and an error string on failure
30
def run_job(self, job, auto_finalize=True, auto_dismiss=False,
31
- pre_finalize=None):
32
+ pre_finalize=None, wait=60.0):
33
error = None
34
while True:
35
- for ev in self.get_qmp_events_filtered(wait=True):
36
+ for ev in self.get_qmp_events_filtered(wait=wait):
37
if ev['event'] == 'JOB_STATUS_CHANGE':
38
status = ev['data']['status']
39
if status == 'aborting':
40
@@ -XXX,XX +XXX,XX @@ class QMPTestCase(unittest.TestCase):
41
self.assertEqual(self.vm.flatten_qmp_object(json.loads(json_filename[5:])),
42
self.vm.flatten_qmp_object(reference))
43
44
- def cancel_and_wait(self, drive='drive0', force=False, resume=False):
45
+ def cancel_and_wait(self, drive='drive0', force=False, resume=False, wait=60.0):
46
'''Cancel a block job and wait for it to finish, returning the event'''
47
result = self.vm.qmp('block-job-cancel', device=drive, force=force)
48
self.assert_qmp(result, 'return', {})
49
@@ -XXX,XX +XXX,XX @@ class QMPTestCase(unittest.TestCase):
50
cancelled = False
51
result = None
52
while not cancelled:
53
- for event in self.vm.get_qmp_events(wait=True):
54
+ for event in self.vm.get_qmp_events(wait=wait):
55
if event['event'] == 'BLOCK_JOB_COMPLETED' or \
56
event['event'] == 'BLOCK_JOB_CANCELLED':
57
self.assert_qmp(event, 'data/device', drive)
58
@@ -XXX,XX +XXX,XX @@ class QMPTestCase(unittest.TestCase):
59
self.assert_no_active_block_jobs()
60
return result
61
62
- def wait_until_completed(self, drive='drive0', check_offset=True):
63
+ def wait_until_completed(self, drive='drive0', check_offset=True, wait=60.0):
64
'''Wait for a block job to finish, returning the event'''
65
while True:
66
- for event in self.vm.get_qmp_events(wait=True):
67
+ for event in self.vm.get_qmp_events(wait=wait):
68
if event['event'] == 'BLOCK_JOB_COMPLETED':
69
self.assert_qmp(event, 'data/device', drive)
70
self.assert_qmp_absent(event, 'data/error')
71
--
72
2.21.0
73
74
diff view generated by jsdifflib
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
3
Instead of event_wait which looks for a single event, add an events_wait
4
which can look for any number of events simultaneously. However, it
5
will still only return one at a time, whichever happens first.
6
7
Signed-off-by: John Snow <jsnow@redhat.com>
8
Message-id: 20190523170643.20794-4-jsnow@redhat.com
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
python/qemu/__init__.py | 69 +++++++++++++++++++++++++++++------------
13
1 file changed, 49 insertions(+), 20 deletions(-)
14
15
diff --git a/python/qemu/__init__.py b/python/qemu/__init__.py
16
index XXXXXXX..XXXXXXX 100644
17
--- a/python/qemu/__init__.py
18
+++ b/python/qemu/__init__.py
19
@@ -XXX,XX +XXX,XX @@ class QEMUMachine(object):
20
self._qmp.clear_events()
21
return events
22
23
- def event_wait(self, name, timeout=60.0, match=None):
24
+ @staticmethod
25
+ def event_match(event, match=None):
26
"""
27
- Wait for specified timeout on named event in QMP; optionally filter
28
- results by match.
29
+ Check if an event matches optional match criteria.
30
31
- The 'match' is checked to be a recursive subset of the 'event'; skips
32
- branch processing on match's value None
33
- {"foo": {"bar": 1}} matches {"foo": None}
34
- {"foo": {"bar": 1}} does not matches {"foo": {"baz": None}}
35
+ The match criteria takes the form of a matching subdict. The event is
36
+ checked to be a superset of the subdict, recursively, with matching
37
+ values whenever those values are not None.
38
+
39
+ Examples, with the subdict queries on the left:
40
+ - None matches any object.
41
+ - {"foo": None} matches {"foo": {"bar": 1}}
42
+ - {"foo": {"baz": None}} does not match {"foo": {"bar": 1}}
43
+ - {"foo": {"baz": 2}} matches {"foo": {"bar": 1, "baz": 2}}
44
"""
45
- def event_match(event, match=None):
46
- if match is None:
47
- return True
48
+ if match is None:
49
+ return True
50
51
- for key in match:
52
- if key in event:
53
- if isinstance(event[key], dict):
54
- if not event_match(event[key], match[key]):
55
- return False
56
- elif event[key] != match[key]:
57
+ for key in match:
58
+ if key in event:
59
+ if isinstance(event[key], dict):
60
+ if not QEMUMachine.event_match(event[key], match[key]):
61
return False
62
- else:
63
+ elif event[key] != match[key]:
64
return False
65
+ else:
66
+ return False
67
+ return True
68
69
- return True
70
+ def event_wait(self, name, timeout=60.0, match=None):
71
+ """
72
+ event_wait waits for and returns a named event from QMP with a timeout.
73
+
74
+ name: The event to wait for.
75
+ timeout: QEMUMonitorProtocol.pull_event timeout parameter.
76
+ match: Optional match criteria. See event_match for details.
77
+ """
78
+ return self.events_wait([(name, match)], timeout)
79
+
80
+ def events_wait(self, events, timeout=60.0):
81
+ """
82
+ events_wait waits for and returns a named event from QMP with a timeout.
83
+
84
+ events: a sequence of (name, match_criteria) tuples.
85
+ The match criteria are optional and may be None.
86
+ See event_match for details.
87
+ timeout: QEMUMonitorProtocol.pull_event timeout parameter.
88
+ """
89
+ def _match(event):
90
+ for name, match in events:
91
+ if (event['event'] == name and
92
+ self.event_match(event, match)):
93
+ return True
94
+ return False
95
96
# Search cached events
97
for event in self._events:
98
- if (event['event'] == name) and event_match(event, match):
99
+ if _match(event):
100
self._events.remove(event)
101
return event
102
103
# Poll for new events
104
while True:
105
event = self._qmp.pull_event(wait=timeout)
106
- if (event['event'] == name) and event_match(event, match):
107
+ if _match(event):
108
return event
109
self._events.append(event)
110
111
--
112
2.21.0
113
114
diff view generated by jsdifflib
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
3
Don't pull events out of the queue that don't belong to us;
4
be choosier so that we can use this method to drive jobs that
5
were launched by transactions that may have more jobs.
6
7
Signed-off-by: John Snow <jsnow@redhat.com>
8
Message-id: 20190523170643.20794-5-jsnow@redhat.com
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
tests/qemu-iotests/iotests.py | 48 +++++++++++++++++++++--------------
13
1 file changed, 29 insertions(+), 19 deletions(-)
14
15
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
16
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/qemu-iotests/iotests.py
18
+++ b/tests/qemu-iotests/iotests.py
19
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
20
# Returns None on success, and an error string on failure
21
def run_job(self, job, auto_finalize=True, auto_dismiss=False,
22
pre_finalize=None, wait=60.0):
23
+ match_device = {'data': {'device': job}}
24
+ match_id = {'data': {'id': job}}
25
+ events = [
26
+ ('BLOCK_JOB_COMPLETED', match_device),
27
+ ('BLOCK_JOB_CANCELLED', match_device),
28
+ ('BLOCK_JOB_ERROR', match_device),
29
+ ('BLOCK_JOB_READY', match_device),
30
+ ('BLOCK_JOB_PENDING', match_id),
31
+ ('JOB_STATUS_CHANGE', match_id)
32
+ ]
33
error = None
34
while True:
35
- for ev in self.get_qmp_events_filtered(wait=wait):
36
- if ev['event'] == 'JOB_STATUS_CHANGE':
37
- status = ev['data']['status']
38
- if status == 'aborting':
39
- result = self.qmp('query-jobs')
40
- for j in result['return']:
41
- if j['id'] == job:
42
- error = j['error']
43
- log('Job failed: %s' % (j['error']))
44
- elif status == 'pending' and not auto_finalize:
45
- if pre_finalize:
46
- pre_finalize()
47
- self.qmp_log('job-finalize', id=job)
48
- elif status == 'concluded' and not auto_dismiss:
49
- self.qmp_log('job-dismiss', id=job)
50
- elif status == 'null':
51
- return error
52
- else:
53
- log(ev)
54
+ ev = filter_qmp_event(self.events_wait(events))
55
+ if ev['event'] != 'JOB_STATUS_CHANGE':
56
+ log(ev)
57
+ continue
58
+ status = ev['data']['status']
59
+ if status == 'aborting':
60
+ result = self.qmp('query-jobs')
61
+ for j in result['return']:
62
+ if j['id'] == job:
63
+ error = j['error']
64
+ log('Job failed: %s' % (j['error']))
65
+ elif status == 'pending' and not auto_finalize:
66
+ if pre_finalize:
67
+ pre_finalize()
68
+ self.qmp_log('job-finalize', id=job)
69
+ elif status == 'concluded' and not auto_dismiss:
70
+ self.qmp_log('job-dismiss', id=job)
71
+ elif status == 'null':
72
+ return error
73
74
def node_info(self, node_name):
75
nodes = self.qmp('query-named-block-nodes')
76
--
77
2.21.0
78
79
diff view generated by jsdifflib
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
3
Signed-off-by: John Snow <jsnow@redhat.com>
4
Message-id: 20190523170643.20794-6-jsnow@redhat.com
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
[mreitz: Moved from 250 to 256]
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
9
tests/qemu-iotests/256 | 122 +++++++++++++++++++++++++++++++++++++
10
tests/qemu-iotests/256.out | 119 ++++++++++++++++++++++++++++++++++++
11
tests/qemu-iotests/group | 1 +
12
3 files changed, 242 insertions(+)
13
create mode 100755 tests/qemu-iotests/256
14
create mode 100644 tests/qemu-iotests/256.out
15
16
diff --git a/tests/qemu-iotests/256 b/tests/qemu-iotests/256
17
new file mode 100755
18
index XXXXXXX..XXXXXXX
19
--- /dev/null
20
+++ b/tests/qemu-iotests/256
21
@@ -XXX,XX +XXX,XX @@
22
+#!/usr/bin/env python
23
+#
24
+# Test incremental/backup across iothread contexts
25
+#
26
+# Copyright (c) 2019 John Snow for Red Hat, Inc.
27
+#
28
+# This program is free software; you can redistribute it and/or modify
29
+# it under the terms of the GNU General Public License as published by
30
+# the Free Software Foundation; either version 2 of the License, or
31
+# (at your option) any later version.
32
+#
33
+# This program is distributed in the hope that it will be useful,
34
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
35
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36
+# GNU General Public License for more details.
37
+#
38
+# You should have received a copy of the GNU General Public License
39
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
40
+#
41
+# owner=jsnow@redhat.com
42
+
43
+import os
44
+import iotests
45
+from iotests import log
46
+
47
+iotests.verify_image_format(supported_fmts=['qcow2'])
48
+size = 64 * 1024 * 1024
49
+
50
+with iotests.FilePath('img0') as img0_path, \
51
+ iotests.FilePath('img1') as img1_path, \
52
+ iotests.FilePath('img0-full') as img0_full_path, \
53
+ iotests.FilePath('img1-full') as img1_full_path, \
54
+ iotests.FilePath('img0-incr') as img0_incr_path, \
55
+ iotests.FilePath('img1-incr') as img1_incr_path, \
56
+ iotests.VM() as vm:
57
+
58
+ def create_target(filepath, name, size):
59
+ basename = os.path.basename(filepath)
60
+ nodename = "file_{}".format(basename)
61
+ log(vm.command('blockdev-create', job_id='job1',
62
+ options={
63
+ 'driver': 'file',
64
+ 'filename': filepath,
65
+ 'size': 0,
66
+ }))
67
+ vm.run_job('job1')
68
+ log(vm.command('blockdev-add', driver='file',
69
+ node_name=nodename, filename=filepath))
70
+ log(vm.command('blockdev-create', job_id='job2',
71
+ options={
72
+ 'driver': iotests.imgfmt,
73
+ 'file': nodename,
74
+ 'size': size,
75
+ }))
76
+ vm.run_job('job2')
77
+ log(vm.command('blockdev-add', driver=iotests.imgfmt,
78
+ node_name=name,
79
+ file=nodename))
80
+
81
+ log('--- Preparing images & VM ---\n')
82
+ vm.add_object('iothread,id=iothread0')
83
+ vm.add_object('iothread,id=iothread1')
84
+ vm.add_device('virtio-scsi-pci,id=scsi0,iothread=iothread0')
85
+ vm.add_device('virtio-scsi-pci,id=scsi1,iothread=iothread1')
86
+ iotests.qemu_img_create('-f', iotests.imgfmt, img0_path, str(size))
87
+ iotests.qemu_img_create('-f', iotests.imgfmt, img1_path, str(size))
88
+ vm.add_drive(img0_path, interface='none')
89
+ vm.add_device('scsi-hd,id=device0,drive=drive0,bus=scsi0.0')
90
+ vm.add_drive(img1_path, interface='none')
91
+ vm.add_device('scsi-hd,id=device1,drive=drive1,bus=scsi1.0')
92
+
93
+ log('--- Starting VM ---\n')
94
+ vm.launch()
95
+
96
+ log('--- Create Targets & Full Backups ---\n')
97
+ create_target(img0_full_path, 'img0-full', size)
98
+ create_target(img1_full_path, 'img1-full', size)
99
+ ret = vm.qmp_log('transaction', indent=2, actions=[
100
+ { 'type': 'block-dirty-bitmap-add',
101
+ 'data': { 'node': 'drive0', 'name': 'bitmap0' }},
102
+ { 'type': 'block-dirty-bitmap-add',
103
+ 'data': { 'node': 'drive1', 'name': 'bitmap1' }},
104
+ { 'type': 'blockdev-backup',
105
+ 'data': { 'device': 'drive0',
106
+ 'target': 'img0-full',
107
+ 'sync': 'full',
108
+ 'job-id': 'j0' }},
109
+ { 'type': 'blockdev-backup',
110
+ 'data': { 'device': 'drive1',
111
+ 'target': 'img1-full',
112
+ 'sync': 'full',
113
+ 'job-id': 'j1' }}
114
+ ])
115
+ if "error" in ret:
116
+ raise Exception(ret['error']['desc'])
117
+ vm.run_job('j0', auto_dismiss=True)
118
+ vm.run_job('j1', auto_dismiss=True)
119
+
120
+ log('\n--- Create Targets & Incremental Backups ---\n')
121
+ create_target(img0_incr_path, 'img0-incr', size)
122
+ create_target(img1_incr_path, 'img1-incr', size)
123
+ ret = vm.qmp_log('transaction', indent=2, actions=[
124
+ { 'type': 'blockdev-backup',
125
+ 'data': { 'device': 'drive0',
126
+ 'target': 'img0-incr',
127
+ 'sync': 'incremental',
128
+ 'bitmap': 'bitmap0',
129
+ 'job-id': 'j2' }},
130
+ { 'type': 'blockdev-backup',
131
+ 'data': { 'device': 'drive1',
132
+ 'target': 'img1-incr',
133
+ 'sync': 'incremental',
134
+ 'bitmap': 'bitmap1',
135
+ 'job-id': 'j3' }}
136
+ ])
137
+ if "error" in ret:
138
+ raise Exception(ret['error']['desc'])
139
+ vm.run_job('j2', auto_dismiss=True)
140
+ vm.run_job('j3', auto_dismiss=True)
141
+
142
+ log('\n--- Done ---')
143
+ vm.shutdown()
144
diff --git a/tests/qemu-iotests/256.out b/tests/qemu-iotests/256.out
145
new file mode 100644
146
index XXXXXXX..XXXXXXX
147
--- /dev/null
148
+++ b/tests/qemu-iotests/256.out
149
@@ -XXX,XX +XXX,XX @@
150
+--- Preparing images & VM ---
151
+
152
+--- Starting VM ---
153
+
154
+--- Create Targets & Full Backups ---
155
+
156
+{}
157
+{"execute": "job-dismiss", "arguments": {"id": "job1"}}
158
+{"return": {}}
159
+{}
160
+{}
161
+{"execute": "job-dismiss", "arguments": {"id": "job2"}}
162
+{"return": {}}
163
+{}
164
+{}
165
+{"execute": "job-dismiss", "arguments": {"id": "job1"}}
166
+{"return": {}}
167
+{}
168
+{}
169
+{"execute": "job-dismiss", "arguments": {"id": "job2"}}
170
+{"return": {}}
171
+{}
172
+{
173
+ "execute": "transaction",
174
+ "arguments": {
175
+ "actions": [
176
+ {
177
+ "data": {
178
+ "name": "bitmap0",
179
+ "node": "drive0"
180
+ },
181
+ "type": "block-dirty-bitmap-add"
182
+ },
183
+ {
184
+ "data": {
185
+ "name": "bitmap1",
186
+ "node": "drive1"
187
+ },
188
+ "type": "block-dirty-bitmap-add"
189
+ },
190
+ {
191
+ "data": {
192
+ "device": "drive0",
193
+ "job-id": "j0",
194
+ "sync": "full",
195
+ "target": "img0-full"
196
+ },
197
+ "type": "blockdev-backup"
198
+ },
199
+ {
200
+ "data": {
201
+ "device": "drive1",
202
+ "job-id": "j1",
203
+ "sync": "full",
204
+ "target": "img1-full"
205
+ },
206
+ "type": "blockdev-backup"
207
+ }
208
+ ]
209
+ }
210
+}
211
+{
212
+ "return": {}
213
+}
214
+{"data": {"device": "j0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
215
+{"data": {"device": "j1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
216
+
217
+--- Create Targets & Incremental Backups ---
218
+
219
+{}
220
+{"execute": "job-dismiss", "arguments": {"id": "job1"}}
221
+{"return": {}}
222
+{}
223
+{}
224
+{"execute": "job-dismiss", "arguments": {"id": "job2"}}
225
+{"return": {}}
226
+{}
227
+{}
228
+{"execute": "job-dismiss", "arguments": {"id": "job1"}}
229
+{"return": {}}
230
+{}
231
+{}
232
+{"execute": "job-dismiss", "arguments": {"id": "job2"}}
233
+{"return": {}}
234
+{}
235
+{
236
+ "execute": "transaction",
237
+ "arguments": {
238
+ "actions": [
239
+ {
240
+ "data": {
241
+ "bitmap": "bitmap0",
242
+ "device": "drive0",
243
+ "job-id": "j2",
244
+ "sync": "incremental",
245
+ "target": "img0-incr"
246
+ },
247
+ "type": "blockdev-backup"
248
+ },
249
+ {
250
+ "data": {
251
+ "bitmap": "bitmap1",
252
+ "device": "drive1",
253
+ "job-id": "j3",
254
+ "sync": "incremental",
255
+ "target": "img1-incr"
256
+ },
257
+ "type": "blockdev-backup"
258
+ }
259
+ ]
260
+ }
261
+}
262
+{
263
+ "return": {}
264
+}
265
+{"data": {"device": "j2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
266
+{"data": {"device": "j3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
267
+
268
+--- Done ---
269
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
270
index XXXXXXX..XXXXXXX 100644
271
--- a/tests/qemu-iotests/group
272
+++ b/tests/qemu-iotests/group
273
@@ -XXX,XX +XXX,XX @@
274
253 rw auto quick
275
254 rw auto backing quick
276
255 rw auto quick
277
+256 rw auto quick
278
--
279
2.21.0
280
281
diff view generated by jsdifflib
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
3
Before, event_match didn't always recurse if the event value was not a
4
dictionary, and would instead check for equality immediately.
5
6
By delaying equality checking to post-recursion, we can allow leaf
7
values like "5" to match "None" and take advantage of the generic
8
None-returns-True clause.
9
10
This makes the matching a little more obviously consistent at the
11
expense of being able to check for explicit None values, which is
12
probably not that important given what this function is used for.
13
14
Signed-off-by: John Snow <jsnow@redhat.com>
15
Message-id: 20190528183857.26167-1-jsnow@redhat.com
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
18
python/qemu/__init__.py | 24 ++++++++++++++----------
19
1 file changed, 14 insertions(+), 10 deletions(-)
20
21
diff --git a/python/qemu/__init__.py b/python/qemu/__init__.py
22
index XXXXXXX..XXXXXXX 100644
23
--- a/python/qemu/__init__.py
24
+++ b/python/qemu/__init__.py
25
@@ -XXX,XX +XXX,XX @@ class QEMUMachine(object):
26
27
The match criteria takes the form of a matching subdict. The event is
28
checked to be a superset of the subdict, recursively, with matching
29
- values whenever those values are not None.
30
+ values whenever the subdict values are not None.
31
+
32
+ This has a limitation that you cannot explicitly check for None values.
33
34
Examples, with the subdict queries on the left:
35
- None matches any object.
36
- {"foo": None} matches {"foo": {"bar": 1}}
37
- - {"foo": {"baz": None}} does not match {"foo": {"bar": 1}}
38
- - {"foo": {"baz": 2}} matches {"foo": {"bar": 1, "baz": 2}}
39
+ - {"foo": None} matches {"foo": 5}
40
+ - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
41
+ - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
42
"""
43
if match is None:
44
return True
45
46
- for key in match:
47
- if key in event:
48
- if isinstance(event[key], dict):
49
+ try:
50
+ for key in match:
51
+ if key in event:
52
if not QEMUMachine.event_match(event[key], match[key]):
53
return False
54
- elif event[key] != match[key]:
55
+ else:
56
return False
57
- else:
58
- return False
59
- return True
60
+ return True
61
+ except TypeError:
62
+ # either match or event wasn't iterable (not a dict)
63
+ return match == event
64
65
def event_wait(self, name, timeout=60.0, match=None):
66
"""
67
--
68
2.21.0
69
70
diff view generated by jsdifflib
Deleted patch
1
It is possible for an empty file to take up blocks on a filesystem, for
2
example:
3
1
4
$ qemu-img create -f raw test.img 1G
5
Formatting 'test.img', fmt=raw size=1073741824
6
$ mkfs.ext4 -I 128 -q test.img
7
$ mkdir test-mount
8
$ sudo mount -o loop test.img test-mount
9
$ sudo touch test-mount/test-file
10
$ stat -c 'blocks=%b' test-mount/test-file
11
blocks=8
12
13
These extra blocks (one cluster) are apparently used for metadata,
14
because they are always there, on top of blocks used for data:
15
16
$ sudo dd if=/dev/zero of=test-mount/test-file bs=1M count=1
17
1+0 records in
18
1+0 records out
19
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.00135339 s, 775 MB/s
20
$ stat -c 'blocks=%b' test-mount/test-file
21
blocks=2056
22
23
Make iotest 175 take this into account.
24
25
Reported-by: Thomas Huth <thuth@redhat.com>
26
Signed-off-by: Max Reitz <mreitz@redhat.com>
27
Reviewed-by: Eric Blake <eblake@redhat.com>
28
Reviewed-by: Nir Soffer <nsoffer@redhat.com>
29
Message-id: 20190516144319.12570-1-mreitz@redhat.com
30
Signed-off-by: Max Reitz <mreitz@redhat.com>
31
---
32
tests/qemu-iotests/175 | 26 ++++++++++++++++++++++----
33
tests/qemu-iotests/175.out | 8 ++++----
34
2 files changed, 26 insertions(+), 8 deletions(-)
35
36
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
37
index XXXXXXX..XXXXXXX 100755
38
--- a/tests/qemu-iotests/175
39
+++ b/tests/qemu-iotests/175
40
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
41
42
_cleanup()
43
{
44
-    _cleanup_test_img
45
+ _cleanup_test_img
46
+ rm -f "$TEST_DIR/empty"
47
}
48
trap "_cleanup; exit \$status" 0 1 2 3 15
49
50
+# Some file systems sometimes allocate extra blocks independently of
51
+# the file size. This function hides the resulting difference in the
52
+# stat -c '%b' output.
53
+# Parameter 1: Number of blocks an empty file occupies
54
+# Parameter 2: Image size in bytes
55
+_filter_blocks()
56
+{
57
+ extra_blocks=$1
58
+ img_size=$2
59
+
60
+ sed -e "s/blocks=$extra_blocks\\(\$\\|[^0-9]\\)/nothing allocated/" \
61
+ -e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/everything allocated/"
62
+}
63
+
64
# get standard environment, filters and checks
65
. ./common.rc
66
. ./common.filter
67
@@ -XXX,XX +XXX,XX @@ _supported_fmt raw
68
_supported_proto file
69
_supported_os Linux
70
71
-size=1m
72
+size=$((1 * 1024 * 1024))
73
+
74
+touch "$TEST_DIR/empty"
75
+extra_blocks=$(stat -c '%b' "$TEST_DIR/empty")
76
77
echo
78
echo "== creating image with default preallocation =="
79
_make_test_img $size | _filter_imgfmt
80
-stat -c "size=%s, blocks=%b" $TEST_IMG
81
+stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size
82
83
for mode in off full falloc; do
84
echo
85
echo "== creating image with preallocation $mode =="
86
IMGOPTS=preallocation=$mode _make_test_img $size | _filter_imgfmt
87
- stat -c "size=%s, blocks=%b" $TEST_IMG
88
+ stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size
89
done
90
91
# success, all done
92
diff --git a/tests/qemu-iotests/175.out b/tests/qemu-iotests/175.out
93
index XXXXXXX..XXXXXXX 100644
94
--- a/tests/qemu-iotests/175.out
95
+++ b/tests/qemu-iotests/175.out
96
@@ -XXX,XX +XXX,XX @@ QA output created by 175
97
98
== creating image with default preallocation ==
99
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
100
-size=1048576, blocks=0
101
+size=1048576, nothing allocated
102
103
== creating image with preallocation off ==
104
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=off
105
-size=1048576, blocks=0
106
+size=1048576, nothing allocated
107
108
== creating image with preallocation full ==
109
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=full
110
-size=1048576, blocks=2048
111
+size=1048576, everything allocated
112
113
== creating image with preallocation falloc ==
114
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=falloc
115
-size=1048576, blocks=2048
116
+size=1048576, everything allocated
117
*** done
118
--
119
2.21.0
120
121
diff view generated by jsdifflib
Deleted patch
1
In 219, we wait for the job to make progress before we emit its status.
2
This makes the output reliable. We do not wait for any more progress if
3
the job's current-progress already matches its total-progress.
4
1
5
Unfortunately, there is a bug: Right after the job has been started,
6
it's possible that total-progress is still 0. In that case, we may skip
7
the first progress-making step and keep ending up 64 kB short.
8
9
To fix that bug, we can simply wait for total-progress to reach 4 MB
10
(the image size) after starting the job.
11
12
Reported-by: Karen Mezick <kmezick@redhat.com>
13
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1686651
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
Message-id: 20190516161114.27596-1-mreitz@redhat.com
16
Reviewed-by: John Snow <jsnow@redhat.com>
17
[mreitz: Adjusted commit message as per John's proposal]
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
---
20
tests/qemu-iotests/219 | 13 ++++++++++---
21
1 file changed, 10 insertions(+), 3 deletions(-)
22
23
diff --git a/tests/qemu-iotests/219 b/tests/qemu-iotests/219
24
index XXXXXXX..XXXXXXX 100755
25
--- a/tests/qemu-iotests/219
26
+++ b/tests/qemu-iotests/219
27
@@ -XXX,XX +XXX,XX @@ import iotests
28
29
iotests.verify_image_format(supported_fmts=['qcow2'])
30
31
+img_size = 4 * 1024 * 1024
32
+
33
def pause_wait(vm, job_id):
34
with iotests.Timeout(3, "Timeout waiting for job to pause"):
35
while True:
36
@@ -XXX,XX +XXX,XX @@ def test_pause_resume(vm):
37
iotests.log(vm.qmp('query-jobs'))
38
39
def test_job_lifecycle(vm, job, job_args, has_ready=False):
40
+ global img_size
41
+
42
iotests.log('')
43
iotests.log('')
44
iotests.log('Starting block job: %s (auto-finalize: %s; auto-dismiss: %s)' %
45
@@ -XXX,XX +XXX,XX @@ def test_job_lifecycle(vm, job, job_args, has_ready=False):
46
iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
47
iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
48
49
+ # Wait for total-progress to stabilize
50
+ while vm.qmp('query-jobs')['return'][0]['total-progress'] < img_size:
51
+ pass
52
+
53
# RUNNING state:
54
# pause/resume should work, complete/finalize/dismiss should error out
55
iotests.log('')
56
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('disk.img') as disk_path, \
57
iotests.FilePath('copy.img') as copy_path, \
58
iotests.VM() as vm:
59
60
- img_size = '4M'
61
- iotests.qemu_img_create('-f', iotests.imgfmt, disk_path, img_size)
62
- iotests.qemu_io('-c', 'write 0 %s' % (img_size),
63
+ iotests.qemu_img_create('-f', iotests.imgfmt, disk_path, str(img_size))
64
+ iotests.qemu_io('-c', 'write 0 %i' % (img_size),
65
'-f', iotests.imgfmt, disk_path)
66
67
iotests.log('Launching VM...')
68
--
69
2.21.0
70
71
diff view generated by jsdifflib
Deleted patch
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
2
1
3
The uninitialized memory allocated for the command FIFO of the
4
floppy controller during the VM hardware initialization incurs
5
many unwanted reports by Valgrind when VM state is being saved.
6
That verbosity hardens a search for the real memory issues when
7
the iotests run. Particularly, the patch eliminates 20 unnecessary
8
reports of the Valgrind tool in the iotest #169.
9
10
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
11
Message-id: 1559154027-282547-1-git-send-email-andrey.shinkevich@virtuozzo.com
12
Reviewed-by: John Snow <jsnow@redhat.com>
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
hw/block/fdc.c | 1 +
16
1 file changed, 1 insertion(+)
17
18
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/hw/block/fdc.c
21
+++ b/hw/block/fdc.c
22
@@ -XXX,XX +XXX,XX @@ static void fdctrl_realize_common(DeviceState *dev, FDCtrl *fdctrl,
23
24
FLOPPY_DPRINTF("init controller\n");
25
fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN);
26
+ memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
27
fdctrl->fifo_size = 512;
28
fdctrl->result_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
29
fdctrl_result_timer, fdctrl);
30
--
31
2.21.0
32
33
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
Test fails at least for qcow, because of different cluster sizes in
4
base and top (and therefore different granularities of bitmaps we are
5
trying to merge).
6
7
The test aim is to check block-dirty-bitmap-merge between different
8
nodes functionality, no needs to check all formats. So, let's just drop
9
support for anything except qcow2.
10
11
Reported-by: Max Reitz <mreitz@redhat.com>
12
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Message-id: 20190605155405.104384-1-vsementsov@virtuozzo.com
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
tests/qemu-iotests/254 | 2 ++
17
1 file changed, 2 insertions(+)
18
19
diff --git a/tests/qemu-iotests/254 b/tests/qemu-iotests/254
20
index XXXXXXX..XXXXXXX 100755
21
--- a/tests/qemu-iotests/254
22
+++ b/tests/qemu-iotests/254
23
@@ -XXX,XX +XXX,XX @@
24
import iotests
25
from iotests import qemu_img_create, file_path, log
26
27
+iotests.verify_image_format(supported_fmts=['qcow2'])
28
+
29
disk, top = file_path('disk', 'top')
30
size = 1024 * 1024
31
32
--
33
2.21.0
34
35
diff view generated by jsdifflib
Deleted patch
1
img_rebase() can leak a QDict in two occasions. Fix it.
2
1
3
Coverity: CID 1401416
4
Fixes: d16699b64671466b42079c45b89127aeea1ca565
5
Fixes: 330c72957196e0ae382abcaa97ebf4eb9bc8574f
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Message-id: 20190528195338.12376-1-mreitz@redhat.com
8
Reviewed-by: John Snow <jsnow@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
qemu-img.c | 3 +++
12
1 file changed, 3 insertions(+)
13
14
diff --git a/qemu-img.c b/qemu-img.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/qemu-img.c
17
+++ b/qemu-img.c
18
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
19
out_baseimg,
20
&local_err);
21
if (local_err) {
22
+ qobject_unref(options);
23
error_reportf_err(local_err,
24
"Could not resolve backing filename: ");
25
ret = -1;
26
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
27
*/
28
prefix_chain_bs = bdrv_find_backing_image(bs, out_real_path);
29
if (prefix_chain_bs) {
30
+ qobject_unref(options);
31
g_free(out_real_path);
32
+
33
blk_new_backing = blk_new(qemu_get_aio_context(),
34
BLK_PERM_CONSISTENT_READ,
35
BLK_PERM_ALL);
36
--
37
2.21.0
38
39
diff view generated by jsdifflib
Deleted patch
1
A snapshot is something that reflects the state of something at a
2
certain point in time. It does not change.
3
1
4
The file our snapshot commands create (or the node they install) is not
5
a snapshot, as it does change over time. It is an overlay. We cannot
6
do anything about the parameter names, but we can at least adjust the
7
descriptions to reflect that fact.
8
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Message-id: 20190603202236.1342-2-mreitz@redhat.com
12
Reviewed-by: John Snow <jsnow@redhat.com>
13
Reviewed-by: Alberto Garcia <berto@igalia.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
qapi/block-core.json | 20 ++++++++++----------
17
1 file changed, 10 insertions(+), 10 deletions(-)
18
19
diff --git a/qapi/block-core.json b/qapi/block-core.json
20
index XXXXXXX..XXXXXXX 100644
21
--- a/qapi/block-core.json
22
+++ b/qapi/block-core.json
23
@@ -XXX,XX +XXX,XX @@
24
#
25
# Either @device or @node-name must be set but not both.
26
#
27
-# @device: the name of the device to generate the snapshot from.
28
+# @device: the name of the device to take a snapshot of.
29
#
30
# @node-name: graph node name to generate the snapshot from (Since 2.0)
31
#
32
-# @snapshot-file: the target of the new image. If the file exists, or
33
-# if it is a device, the snapshot will be created in the existing
34
-# file/device. Otherwise, a new file will be created.
35
+# @snapshot-file: the target of the new overlay image. If the file
36
+# exists, or if it is a device, the overlay will be created in the
37
+# existing file/device. Otherwise, a new file will be created.
38
#
39
# @snapshot-node-name: the graph node name of the new image (Since 2.0)
40
#
41
-# @format: the format of the snapshot image, default is 'qcow2'.
42
+# @format: the format of the overlay image, default is 'qcow2'.
43
#
44
# @mode: whether and how QEMU should create a new image, default is
45
# 'absolute-paths'.
46
@@ -XXX,XX +XXX,XX @@
47
##
48
# @BlockdevSnapshot:
49
#
50
-# @node: device or node name that will have a snapshot created.
51
+# @node: device or node name that will have a snapshot taken.
52
#
53
# @overlay: reference to the existing block device that will become
54
-# the overlay of @node, as part of creating the snapshot.
55
+# the overlay of @node, as part of taking the snapshot.
56
# It must not have a current backing file (this can be
57
# achieved by passing "backing": null to blockdev-add).
58
#
59
@@ -XXX,XX +XXX,XX @@
60
##
61
# @blockdev-snapshot-sync:
62
#
63
-# Generates a synchronous snapshot of a block device.
64
+# Takes a synchronous snapshot of a block device.
65
#
66
# For the arguments, see the documentation of BlockdevSnapshotSync.
67
#
68
@@ -XXX,XX +XXX,XX @@
69
##
70
# @blockdev-snapshot:
71
#
72
-# Generates a snapshot of a block device.
73
+# Takes a snapshot of a block device.
74
#
75
-# Create a snapshot, by installing 'node' as the backing image of
76
+# Take a snapshot, by installing 'node' as the backing image of
77
# 'overlay'. Additionally, if 'node' is associated with a block
78
# device, the block device changes to using 'overlay' as its new active
79
# image.
80
--
81
2.21.0
82
83
diff view generated by jsdifflib
Deleted patch
1
There are error messages which refer to an overlay node as the snapshot.
2
That is wrong, those are two different things.
3
1
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Message-id: 20190603202236.1342-3-mreitz@redhat.com
7
Reviewed-by: John Snow <jsnow@redhat.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
blockdev.c | 10 +++++-----
12
tests/qemu-iotests/085.out | 10 +++++-----
13
2 files changed, 10 insertions(+), 10 deletions(-)
14
15
diff --git a/blockdev.c b/blockdev.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/blockdev.c
18
+++ b/blockdev.c
19
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
20
s->has_snapshot_node_name ? s->snapshot_node_name : NULL;
21
22
if (node_name && !snapshot_node_name) {
23
- error_setg(errp, "New snapshot node name missing");
24
+ error_setg(errp, "New overlay node name missing");
25
goto out;
26
}
27
28
if (snapshot_node_name &&
29
bdrv_lookup_bs(snapshot_node_name, snapshot_node_name, NULL)) {
30
- error_setg(errp, "New snapshot node name already in use");
31
+ error_setg(errp, "New overlay node name already in use");
32
goto out;
33
}
34
35
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
36
}
37
38
if (bdrv_has_blk(state->new_bs)) {
39
- error_setg(errp, "The snapshot is already in use");
40
+ error_setg(errp, "The overlay is already in use");
41
goto out;
42
}
43
44
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
45
}
46
47
if (state->new_bs->backing != NULL) {
48
- error_setg(errp, "The snapshot already has a backing image");
49
+ error_setg(errp, "The overlay already has a backing image");
50
goto out;
51
}
52
53
if (!state->new_bs->drv->supports_backing) {
54
- error_setg(errp, "The snapshot does not support backing images");
55
+ error_setg(errp, "The overlay does not support backing images");
56
goto out;
57
}
58
59
diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out
60
index XXXXXXX..XXXXXXX 100644
61
--- a/tests/qemu-iotests/085.out
62
+++ b/tests/qemu-iotests/085.out
63
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/
64
65
=== Invalid command - cannot create a snapshot using a file BDS ===
66
67
-{"error": {"class": "GenericError", "desc": "The snapshot does not support backing images"}}
68
+{"error": {"class": "GenericError", "desc": "The overlay does not support backing images"}}
69
70
=== Invalid command - snapshot node used as active layer ===
71
72
-{"error": {"class": "GenericError", "desc": "The snapshot is already in use"}}
73
-{"error": {"class": "GenericError", "desc": "The snapshot is already in use"}}
74
-{"error": {"class": "GenericError", "desc": "The snapshot is already in use"}}
75
+{"error": {"class": "GenericError", "desc": "The overlay is already in use"}}
76
+{"error": {"class": "GenericError", "desc": "The overlay is already in use"}}
77
+{"error": {"class": "GenericError", "desc": "The overlay is already in use"}}
78
79
=== Invalid command - snapshot node used as backing hd ===
80
81
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/
82
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
83
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base
84
{"return": {}}
85
-{"error": {"class": "GenericError", "desc": "The snapshot already has a backing image"}}
86
+{"error": {"class": "GenericError", "desc": "The overlay already has a backing image"}}
87
88
=== Invalid command - The node does not exist ===
89
90
--
91
2.21.0
92
93
diff view generated by jsdifflib
Deleted patch
1
Move img_convert()'s quiet flag into the ImgConvertState so it is
2
accessible by nested functions. -q dictates that it suppresses anything
3
but errors, so if those functions want to emit warnings, they need to
4
query this flag first. (There currently are no such warnings, but there
5
will be as of the next patch.)
6
1
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Message-id: 20190507203508.18026-2-mreitz@redhat.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
qemu-img.c | 13 +++++++------
14
1 file changed, 7 insertions(+), 6 deletions(-)
15
16
diff --git a/qemu-img.c b/qemu-img.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/qemu-img.c
19
+++ b/qemu-img.c
20
@@ -XXX,XX +XXX,XX @@ typedef struct ImgConvertState {
21
int64_t target_backing_sectors; /* negative if unknown */
22
bool wr_in_order;
23
bool copy_range;
24
+ bool quiet;
25
int min_sparse;
26
int alignment;
27
size_t cluster_sectors;
28
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
29
QDict *open_opts = NULL;
30
char *options = NULL;
31
Error *local_err = NULL;
32
- bool writethrough, src_writethrough, quiet = false, image_opts = false,
33
+ bool writethrough, src_writethrough, image_opts = false,
34
skip_create = false, progress = false, tgt_image_opts = false;
35
int64_t ret = -EINVAL;
36
bool force_share = false;
37
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
38
src_cache = optarg;
39
break;
40
case 'q':
41
- quiet = true;
42
+ s.quiet = true;
43
break;
44
case 'n':
45
skip_create = true;
46
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
47
}
48
49
/* Initialize before goto out */
50
- if (quiet) {
51
+ if (s.quiet) {
52
progress = false;
53
}
54
qemu_progress_init(progress, 1.0);
55
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
56
57
for (bs_i = 0; bs_i < s.src_num; bs_i++) {
58
s.src[bs_i] = img_open(image_opts, argv[optind + bs_i],
59
- fmt, src_flags, src_writethrough, quiet,
60
+ fmt, src_flags, src_writethrough, s.quiet,
61
force_share);
62
if (!s.src[bs_i]) {
63
ret = -1;
64
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
65
66
if (skip_create) {
67
s.target = img_open(tgt_image_opts, out_filename, out_fmt,
68
- flags, writethrough, quiet, false);
69
+ flags, writethrough, s.quiet, false);
70
} else {
71
/* TODO ultimately we should allow --target-image-opts
72
* to be used even when -n is not given.
73
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
74
* to allow filenames in option syntax
75
*/
76
s.target = img_open_file(out_filename, open_opts, out_fmt,
77
- flags, writethrough, quiet, false);
78
+ flags, writethrough, s.quiet, false);
79
open_opts = NULL; /* blk_new_open will have freed it */
80
}
81
if (!s.target) {
82
--
83
2.21.0
84
85
diff view generated by jsdifflib
1
This new error option allows users of blkdebug to inject errors only on
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
2
certain kinds of I/O operations. Users usually want to make a very
2
3
specific operation fail, not just any; but right now they simply hope
3
Introduce the 'event-loop-base' abstract class, it'll hold the
4
that the event that triggers the error injection is followed up with
4
properties common to all event loops and provide the necessary hooks for
5
that very operation. That may not be true, however, because the block
5
their creation and maintenance. Then have iothread inherit from it.
6
layer is changing (including blkdebug, which may increase the number of
6
7
types of I/O operations on which to inject errors).
7
EventLoopBaseClass is defined as user creatable and provides a hook for
8
8
its children to attach themselves to the user creatable class 'complete'
9
The new option's default has been chosen to keep backwards
9
function. It also provides an update_params() callback to propagate
10
compatibility.
10
property changes onto its children.
11
11
12
Note that similar to the internal representation, we could choose to
12
The new 'event-loop-base' class will live in the root directory. It is
13
expose this option as a list of I/O types. But there is no practical
13
built on its own using the 'link_whole' option (there are no direct
14
use for this, because as described above, users usually know exactly
14
function dependencies between the class and its children, it all happens
15
which kind of operation they want to make fail, so there is no need to
15
trough 'constructor' magic). And also imposes new compilation
16
specify multiple I/O types at once. In addition, exposing this option
16
dependencies:
17
as a list would require non-trivial changes to qemu_opts_absorb_qdict().
17
18
18
qom <- event-loop-base <- blockdev (iothread.c)
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
20
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
20
And in subsequent patches:
21
Message-id: 20190507203508.18026-4-mreitz@redhat.com
21
22
Signed-off-by: Max Reitz <mreitz@redhat.com>
22
qom <- event-loop-base <- qemuutil (util/main-loop.c)
23
24
All this forced some amount of reordering in meson.build:
25
26
- Moved qom build definition before qemuutil. Doing it the other way
27
around (i.e. moving qemuutil after qom) isn't possible as a lot of
28
core libraries that live in between the two depend on it.
29
30
- Process the 'hw' subdir earlier, as it introduces files into the
31
'qom' source set.
32
33
No functional changes intended.
34
35
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
36
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
37
Acked-by: Markus Armbruster <armbru@redhat.com>
38
Message-id: 20220425075723.20019-2-nsaenzju@redhat.com
39
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
23
---
40
---
24
qapi/block-core.json | 26 +++++++++++++++++++++++
41
qapi/qom.json | 22 +++++--
25
block/blkdebug.c | 50 ++++++++++++++++++++++++++++++++++++--------
42
meson.build | 23 ++++---
26
2 files changed, 67 insertions(+), 9 deletions(-)
43
include/sysemu/event-loop-base.h | 36 +++++++++++
27
44
include/sysemu/iothread.h | 6 +-
28
diff --git a/qapi/block-core.json b/qapi/block-core.json
45
event-loop-base.c | 104 +++++++++++++++++++++++++++++++
46
iothread.c | 65 ++++++-------------
47
6 files changed, 192 insertions(+), 64 deletions(-)
48
create mode 100644 include/sysemu/event-loop-base.h
49
create mode 100644 event-loop-base.c
50
51
diff --git a/qapi/qom.json b/qapi/qom.json
29
index XXXXXXX..XXXXXXX 100644
52
index XXXXXXX..XXXXXXX 100644
30
--- a/qapi/block-core.json
53
--- a/qapi/qom.json
31
+++ b/qapi/block-core.json
54
+++ b/qapi/qom.json
32
@@ -XXX,XX +XXX,XX @@
55
@@ -XXX,XX +XXX,XX @@
33
'l1_shrink_write_table', 'l1_shrink_free_l2_clusters',
56
'*repeat': 'bool',
34
'cor_write', 'cluster_alloc_space'] }
57
'*grab-toggle': 'GrabToggleKeys' } }
35
58
36
+##
59
+##
37
+# @BlkdebugIOType:
60
+# @EventLoopBaseProperties:
38
+#
61
+#
39
+# Kinds of I/O that blkdebug can inject errors in.
62
+# Common properties for event loops
40
+#
63
+#
41
+# @read: .bdrv_co_preadv()
64
+# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
65
+# 0 means that the engine will use its default.
66
+# (default: 0)
42
+#
67
+#
43
+# @write: .bdrv_co_pwritev()
68
+# Since: 7.1
44
+#
45
+# @write-zeroes: .bdrv_co_pwrite_zeroes()
46
+#
47
+# @discard: .bdrv_co_pdiscard()
48
+#
49
+# @flush: .bdrv_co_flush_to_disk()
50
+#
51
+# Since: 4.1
52
+##
69
+##
53
+{ 'enum': 'BlkdebugIOType', 'prefix': 'BLKDEBUG_IO_TYPE',
70
+{ 'struct': 'EventLoopBaseProperties',
54
+ 'data': [ 'read', 'write', 'write-zeroes', 'discard', 'flush' ] }
71
+ 'data': { '*aio-max-batch': 'int' } }
55
+
72
+
56
##
73
##
57
# @BlkdebugInjectErrorOptions:
74
# @IothreadProperties:
58
#
75
#
59
@@ -XXX,XX +XXX,XX @@
76
@@ -XXX,XX +XXX,XX @@
60
# @state: the state identifier blkdebug needs to be in to
77
# algorithm detects it is spending too long polling without
61
# actually trigger the event; defaults to "any"
78
# encountering events. 0 selects a default behaviour (default: 0)
62
#
79
#
63
+# @iotype: the type of I/O operations on which this error should
80
-# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
64
+# be injected; defaults to "all read, write,
81
-# 0 means that the engine will use its default
65
+# write-zeroes, discard, and flush operations"
82
-# (default:0, since 6.1)
66
+# (since: 4.1)
83
+# The @aio-max-batch option is available since 6.1.
67
+#
68
# @errno: error identifier (errno) to be returned; defaults to
69
# EIO
70
#
84
#
71
@@ -XXX,XX +XXX,XX @@
85
# Since: 2.0
72
{ 'struct': 'BlkdebugInjectErrorOptions',
86
##
73
'data': { 'event': 'BlkdebugEvent',
87
{ 'struct': 'IothreadProperties',
74
'*state': 'int',
88
+ 'base': 'EventLoopBaseProperties',
75
+ '*iotype': 'BlkdebugIOType',
89
'data': { '*poll-max-ns': 'int',
76
'*errno': 'int',
90
'*poll-grow': 'int',
77
'*sector': 'int',
91
- '*poll-shrink': 'int',
78
'*once': 'bool',
92
- '*aio-max-batch': 'int' } }
79
diff --git a/block/blkdebug.c b/block/blkdebug.c
93
+ '*poll-shrink': 'int' } }
94
95
##
96
# @MemoryBackendProperties:
97
diff --git a/meson.build b/meson.build
80
index XXXXXXX..XXXXXXX 100644
98
index XXXXXXX..XXXXXXX 100644
81
--- a/block/blkdebug.c
99
--- a/meson.build
82
+++ b/block/blkdebug.c
100
+++ b/meson.build
83
@@ -XXX,XX +XXX,XX @@ typedef struct BlkdebugRule {
101
@@ -XXX,XX +XXX,XX @@ subdir('qom')
84
int state;
102
subdir('authz')
85
union {
103
subdir('crypto')
86
struct {
104
subdir('ui')
87
+ uint64_t iotype_mask;
105
+subdir('hw')
88
int error;
106
89
int immediately;
107
90
int once;
108
if enable_modules
91
@@ -XXX,XX +XXX,XX @@ typedef struct BlkdebugRule {
109
@@ -XXX,XX +XXX,XX @@ if enable_modules
92
QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
110
modulecommon = declare_dependency(link_whole: libmodulecommon, compile_args: '-DBUILD_DSO')
93
} BlkdebugRule;
111
endif
94
112
95
+QEMU_BUILD_BUG_MSG(BLKDEBUG_IO_TYPE__MAX > 64,
113
+qom_ss = qom_ss.apply(config_host, strict: false)
96
+ "BlkdebugIOType mask does not fit into an uint64_t");
114
+libqom = static_library('qom', qom_ss.sources() + genh,
97
+
115
+ dependencies: [qom_ss.dependencies()],
98
static QemuOptsList inject_error_opts = {
116
+ name_suffix: 'fa')
99
.name = "inject-error",
117
+qom = declare_dependency(link_whole: libqom)
100
.head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
118
+
101
@@ -XXX,XX +XXX,XX @@ static QemuOptsList inject_error_opts = {
119
+event_loop_base = files('event-loop-base.c')
102
.name = "state",
120
+event_loop_base = static_library('event-loop-base', sources: event_loop_base + genh,
103
.type = QEMU_OPT_NUMBER,
121
+ build_by_default: true)
104
},
122
+event_loop_base = declare_dependency(link_whole: event_loop_base,
105
+ {
123
+ dependencies: [qom])
106
+ .name = "iotype",
124
+
107
+ .type = QEMU_OPT_STRING,
125
stub_ss = stub_ss.apply(config_all, strict: false)
108
+ },
126
109
{
127
util_ss.add_all(trace_ss)
110
.name = "errno",
128
@@ -XXX,XX +XXX,XX @@ subdir('monitor')
111
.type = QEMU_OPT_NUMBER,
129
subdir('net')
112
@@ -XXX,XX +XXX,XX @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
130
subdir('replay')
113
int event;
131
subdir('semihosting')
114
struct BlkdebugRule *rule;
132
-subdir('hw')
115
int64_t sector;
133
subdir('tcg')
116
+ BlkdebugIOType iotype;
134
subdir('fpu')
117
+ Error *local_error = NULL;
135
subdir('accel')
118
136
@@ -XXX,XX +XXX,XX @@ qemu_syms = custom_target('qemu.syms', output: 'qemu.syms',
119
/* Find the right event for the rule */
137
capture: true,
120
event_name = qemu_opt_get(opts, "event");
138
command: [undefsym, nm, '@INPUT@'])
121
@@ -XXX,XX +XXX,XX @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
139
122
sector = qemu_opt_get_number(opts, "sector", -1);
140
-qom_ss = qom_ss.apply(config_host, strict: false)
123
rule->options.inject.offset =
141
-libqom = static_library('qom', qom_ss.sources() + genh,
124
sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE;
142
- dependencies: [qom_ss.dependencies()],
125
+
143
- name_suffix: 'fa')
126
+ iotype = qapi_enum_parse(&BlkdebugIOType_lookup,
144
-
127
+ qemu_opt_get(opts, "iotype"),
145
-qom = declare_dependency(link_whole: libqom)
128
+ BLKDEBUG_IO_TYPE__MAX, &local_error);
146
-
129
+ if (local_error) {
147
authz_ss = authz_ss.apply(config_host, strict: false)
130
+ error_propagate(errp, local_error);
148
libauthz = static_library('authz', authz_ss.sources() + genh,
131
+ return -1;
149
dependencies: [authz_ss.dependencies()],
132
+ }
150
@@ -XXX,XX +XXX,XX @@ libblockdev = static_library('blockdev', blockdev_ss.sources() + genh,
133
+ if (iotype != BLKDEBUG_IO_TYPE__MAX) {
151
build_by_default: false)
134
+ rule->options.inject.iotype_mask = (1ull << iotype);
152
135
+ } else {
153
blockdev = declare_dependency(link_whole: [libblockdev],
136
+ /* Apply the default */
154
- dependencies: [block])
137
+ rule->options.inject.iotype_mask =
155
+ dependencies: [block, event_loop_base])
138
+ (1ull << BLKDEBUG_IO_TYPE_READ)
156
139
+ | (1ull << BLKDEBUG_IO_TYPE_WRITE)
157
qmp_ss = qmp_ss.apply(config_host, strict: false)
140
+ | (1ull << BLKDEBUG_IO_TYPE_WRITE_ZEROES)
158
libqmp = static_library('qmp', qmp_ss.sources() + genh,
141
+ | (1ull << BLKDEBUG_IO_TYPE_DISCARD)
159
diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h
142
+ | (1ull << BLKDEBUG_IO_TYPE_FLUSH);
160
new file mode 100644
143
+ }
161
index XXXXXXX..XXXXXXX
144
+
162
--- /dev/null
145
break;
163
+++ b/include/sysemu/event-loop-base.h
146
164
@@ -XXX,XX +XXX,XX @@
147
case ACTION_SET_STATE:
165
+/*
148
@@ -XXX,XX +XXX,XX @@ out:
166
+ * QEMU event-loop backend
149
return ret;
167
+ *
168
+ * Copyright (C) 2022 Red Hat Inc
169
+ *
170
+ * Authors:
171
+ * Nicolas Saenz Julienne <nsaenzju@redhat.com>
172
+ *
173
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
174
+ * See the COPYING file in the top-level directory.
175
+ */
176
+#ifndef QEMU_EVENT_LOOP_BASE_H
177
+#define QEMU_EVENT_LOOP_BASE_H
178
+
179
+#include "qom/object.h"
180
+#include "block/aio.h"
181
+#include "qemu/typedefs.h"
182
+
183
+#define TYPE_EVENT_LOOP_BASE "event-loop-base"
184
+OBJECT_DECLARE_TYPE(EventLoopBase, EventLoopBaseClass,
185
+ EVENT_LOOP_BASE)
186
+
187
+struct EventLoopBaseClass {
188
+ ObjectClass parent_class;
189
+
190
+ void (*init)(EventLoopBase *base, Error **errp);
191
+ void (*update_params)(EventLoopBase *base, Error **errp);
192
+};
193
+
194
+struct EventLoopBase {
195
+ Object parent;
196
+
197
+ /* AioContext AIO engine parameters */
198
+ int64_t aio_max_batch;
199
+};
200
+#endif
201
diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h
202
index XXXXXXX..XXXXXXX 100644
203
--- a/include/sysemu/iothread.h
204
+++ b/include/sysemu/iothread.h
205
@@ -XXX,XX +XXX,XX @@
206
#include "block/aio.h"
207
#include "qemu/thread.h"
208
#include "qom/object.h"
209
+#include "sysemu/event-loop-base.h"
210
211
#define TYPE_IOTHREAD "iothread"
212
213
struct IOThread {
214
- Object parent_obj;
215
+ EventLoopBase parent_obj;
216
217
QemuThread thread;
218
AioContext *ctx;
219
@@ -XXX,XX +XXX,XX @@ struct IOThread {
220
int64_t poll_max_ns;
221
int64_t poll_grow;
222
int64_t poll_shrink;
223
-
224
- /* AioContext AIO engine parameters */
225
- int64_t aio_max_batch;
226
};
227
typedef struct IOThread IOThread;
228
229
diff --git a/event-loop-base.c b/event-loop-base.c
230
new file mode 100644
231
index XXXXXXX..XXXXXXX
232
--- /dev/null
233
+++ b/event-loop-base.c
234
@@ -XXX,XX +XXX,XX @@
235
+/*
236
+ * QEMU event-loop base
237
+ *
238
+ * Copyright (C) 2022 Red Hat Inc
239
+ *
240
+ * Authors:
241
+ * Stefan Hajnoczi <stefanha@redhat.com>
242
+ * Nicolas Saenz Julienne <nsaenzju@redhat.com>
243
+ *
244
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
245
+ * See the COPYING file in the top-level directory.
246
+ */
247
+
248
+#include "qemu/osdep.h"
249
+#include "qom/object_interfaces.h"
250
+#include "qapi/error.h"
251
+#include "sysemu/event-loop-base.h"
252
+
253
+typedef struct {
254
+ const char *name;
255
+ ptrdiff_t offset; /* field's byte offset in EventLoopBase struct */
256
+} EventLoopBaseParamInfo;
257
+
258
+static EventLoopBaseParamInfo aio_max_batch_info = {
259
+ "aio-max-batch", offsetof(EventLoopBase, aio_max_batch),
260
+};
261
+
262
+static void event_loop_base_get_param(Object *obj, Visitor *v,
263
+ const char *name, void *opaque, Error **errp)
264
+{
265
+ EventLoopBase *event_loop_base = EVENT_LOOP_BASE(obj);
266
+ EventLoopBaseParamInfo *info = opaque;
267
+ int64_t *field = (void *)event_loop_base + info->offset;
268
+
269
+ visit_type_int64(v, name, field, errp);
270
+}
271
+
272
+static void event_loop_base_set_param(Object *obj, Visitor *v,
273
+ const char *name, void *opaque, Error **errp)
274
+{
275
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(obj);
276
+ EventLoopBase *base = EVENT_LOOP_BASE(obj);
277
+ EventLoopBaseParamInfo *info = opaque;
278
+ int64_t *field = (void *)base + info->offset;
279
+ int64_t value;
280
+
281
+ if (!visit_type_int64(v, name, &value, errp)) {
282
+ return;
283
+ }
284
+
285
+ if (value < 0) {
286
+ error_setg(errp, "%s value must be in range [0, %" PRId64 "]",
287
+ info->name, INT64_MAX);
288
+ return;
289
+ }
290
+
291
+ *field = value;
292
+
293
+ if (bc->update_params) {
294
+ bc->update_params(base, errp);
295
+ }
296
+
297
+ return;
298
+}
299
+
300
+static void event_loop_base_complete(UserCreatable *uc, Error **errp)
301
+{
302
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc);
303
+ EventLoopBase *base = EVENT_LOOP_BASE(uc);
304
+
305
+ if (bc->init) {
306
+ bc->init(base, errp);
307
+ }
308
+}
309
+
310
+static void event_loop_base_class_init(ObjectClass *klass, void *class_data)
311
+{
312
+ UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
313
+ ucc->complete = event_loop_base_complete;
314
+
315
+ object_class_property_add(klass, "aio-max-batch", "int",
316
+ event_loop_base_get_param,
317
+ event_loop_base_set_param,
318
+ NULL, &aio_max_batch_info);
319
+}
320
+
321
+static const TypeInfo event_loop_base_info = {
322
+ .name = TYPE_EVENT_LOOP_BASE,
323
+ .parent = TYPE_OBJECT,
324
+ .instance_size = sizeof(EventLoopBase),
325
+ .class_size = sizeof(EventLoopBaseClass),
326
+ .class_init = event_loop_base_class_init,
327
+ .abstract = true,
328
+ .interfaces = (InterfaceInfo[]) {
329
+ { TYPE_USER_CREATABLE },
330
+ { }
331
+ }
332
+};
333
+
334
+static void register_types(void)
335
+{
336
+ type_register_static(&event_loop_base_info);
337
+}
338
+type_init(register_types);
339
diff --git a/iothread.c b/iothread.c
340
index XXXXXXX..XXXXXXX 100644
341
--- a/iothread.c
342
+++ b/iothread.c
343
@@ -XXX,XX +XXX,XX @@
344
#include "qemu/module.h"
345
#include "block/aio.h"
346
#include "block/block.h"
347
+#include "sysemu/event-loop-base.h"
348
#include "sysemu/iothread.h"
349
#include "qapi/error.h"
350
#include "qapi/qapi-commands-misc.h"
351
@@ -XXX,XX +XXX,XX @@ static void iothread_init_gcontext(IOThread *iothread)
352
iothread->main_loop = g_main_loop_new(iothread->worker_context, TRUE);
150
}
353
}
151
354
152
-static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes)
355
-static void iothread_set_aio_context_params(IOThread *iothread, Error **errp)
153
+static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
356
+static void iothread_set_aio_context_params(EventLoopBase *base, Error **errp)
154
+ BlkdebugIOType iotype)
155
{
357
{
156
BDRVBlkdebugState *s = bs->opaque;
358
+ IOThread *iothread = IOTHREAD(base);
157
BlkdebugRule *rule = NULL;
359
ERRP_GUARD();
158
@@ -XXX,XX +XXX,XX @@ static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes)
360
159
QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
361
+ if (!iothread->ctx) {
160
uint64_t inject_offset = rule->options.inject.offset;
362
+ return;
161
363
+ }
162
- if (inject_offset == -1 ||
364
+
163
- (bytes && inject_offset >= offset &&
365
aio_context_set_poll_params(iothread->ctx,
164
- inject_offset < offset + bytes))
366
iothread->poll_max_ns,
165
+ if ((inject_offset == -1 ||
367
iothread->poll_grow,
166
+ (bytes && inject_offset >= offset &&
368
@@ -XXX,XX +XXX,XX @@ static void iothread_set_aio_context_params(IOThread *iothread, Error **errp)
167
+ inject_offset < offset + bytes)) &&
168
+ (rule->options.inject.iotype_mask & (1ull << iotype)))
169
{
170
break;
171
}
172
@@ -XXX,XX +XXX,XX @@ blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
173
assert(bytes <= bs->bl.max_transfer);
174
}
369
}
175
370
176
- err = rule_check(bs, offset, bytes);
371
aio_context_set_aio_params(iothread->ctx,
177
+ err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_READ);
372
- iothread->aio_max_batch,
178
if (err) {
373
+ iothread->parent_obj.aio_max_batch,
179
return err;
374
errp);
375
}
376
377
-static void iothread_complete(UserCreatable *obj, Error **errp)
378
+
379
+static void iothread_init(EventLoopBase *base, Error **errp)
380
{
381
Error *local_error = NULL;
382
- IOThread *iothread = IOTHREAD(obj);
383
+ IOThread *iothread = IOTHREAD(base);
384
char *thread_name;
385
386
iothread->stopping = false;
387
@@ -XXX,XX +XXX,XX @@ static void iothread_complete(UserCreatable *obj, Error **errp)
388
*/
389
iothread_init_gcontext(iothread);
390
391
- iothread_set_aio_context_params(iothread, &local_error);
392
+ iothread_set_aio_context_params(base, &local_error);
393
if (local_error) {
394
error_propagate(errp, local_error);
395
aio_context_unref(iothread->ctx);
396
@@ -XXX,XX +XXX,XX @@ static void iothread_complete(UserCreatable *obj, Error **errp)
397
* to inherit.
398
*/
399
thread_name = g_strdup_printf("IO %s",
400
- object_get_canonical_path_component(OBJECT(obj)));
401
+ object_get_canonical_path_component(OBJECT(base)));
402
qemu_thread_create(&iothread->thread, thread_name, iothread_run,
403
iothread, QEMU_THREAD_JOINABLE);
404
g_free(thread_name);
405
@@ -XXX,XX +XXX,XX @@ static IOThreadParamInfo poll_grow_info = {
406
static IOThreadParamInfo poll_shrink_info = {
407
"poll-shrink", offsetof(IOThread, poll_shrink),
408
};
409
-static IOThreadParamInfo aio_max_batch_info = {
410
- "aio-max-batch", offsetof(IOThread, aio_max_batch),
411
-};
412
413
static void iothread_get_param(Object *obj, Visitor *v,
414
const char *name, IOThreadParamInfo *info, Error **errp)
415
@@ -XXX,XX +XXX,XX @@ static void iothread_set_poll_param(Object *obj, Visitor *v,
180
}
416
}
181
@@ -XXX,XX +XXX,XX @@ blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
417
}
182
assert(bytes <= bs->bl.max_transfer);
418
183
}
419
-static void iothread_get_aio_param(Object *obj, Visitor *v,
184
420
- const char *name, void *opaque, Error **errp)
185
- err = rule_check(bs, offset, bytes);
421
-{
186
+ err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_WRITE);
422
- IOThreadParamInfo *info = opaque;
187
if (err) {
423
-
188
return err;
424
- iothread_get_param(obj, v, name, info, errp);
189
}
425
-}
190
@@ -XXX,XX +XXX,XX @@ blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
426
-
191
427
-static void iothread_set_aio_param(Object *obj, Visitor *v,
192
static int blkdebug_co_flush(BlockDriverState *bs)
428
- const char *name, void *opaque, Error **errp)
429
-{
430
- IOThread *iothread = IOTHREAD(obj);
431
- IOThreadParamInfo *info = opaque;
432
-
433
- if (!iothread_set_param(obj, v, name, info, errp)) {
434
- return;
435
- }
436
-
437
- if (iothread->ctx) {
438
- aio_context_set_aio_params(iothread->ctx,
439
- iothread->aio_max_batch,
440
- errp);
441
- }
442
-}
443
-
444
static void iothread_class_init(ObjectClass *klass, void *class_data)
193
{
445
{
194
- int err = rule_check(bs, 0, 0);
446
- UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
195
+ int err = rule_check(bs, 0, 0, BLKDEBUG_IO_TYPE_FLUSH);
447
- ucc->complete = iothread_complete;
196
448
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(klass);
197
if (err) {
449
+
198
return err;
450
+ bc->init = iothread_init;
199
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs,
451
+ bc->update_params = iothread_set_aio_context_params;
200
assert(bytes <= bs->bl.max_pwrite_zeroes);
452
201
}
453
object_class_property_add(klass, "poll-max-ns", "int",
202
454
iothread_get_poll_param,
203
- err = rule_check(bs, offset, bytes);
455
@@ -XXX,XX +XXX,XX @@ static void iothread_class_init(ObjectClass *klass, void *class_data)
204
+ err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_WRITE_ZEROES);
456
iothread_get_poll_param,
205
if (err) {
457
iothread_set_poll_param,
206
return err;
458
NULL, &poll_shrink_info);
207
}
459
- object_class_property_add(klass, "aio-max-batch", "int",
208
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
460
- iothread_get_aio_param,
209
assert(bytes <= bs->bl.max_pdiscard);
461
- iothread_set_aio_param,
210
}
462
- NULL, &aio_max_batch_info);
211
463
}
212
- err = rule_check(bs, offset, bytes);
464
213
+ err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_DISCARD);
465
static const TypeInfo iothread_info = {
214
if (err) {
466
.name = TYPE_IOTHREAD,
215
return err;
467
- .parent = TYPE_OBJECT,
216
}
468
+ .parent = TYPE_EVENT_LOOP_BASE,
469
.class_init = iothread_class_init,
470
.instance_size = sizeof(IOThread),
471
.instance_init = iothread_instance_init,
472
.instance_finalize = iothread_instance_finalize,
473
- .interfaces = (InterfaceInfo[]) {
474
- {TYPE_USER_CREATABLE},
475
- {}
476
- },
477
};
478
479
static void iothread_register_types(void)
480
@@ -XXX,XX +XXX,XX @@ static int query_one_iothread(Object *object, void *opaque)
481
info->poll_max_ns = iothread->poll_max_ns;
482
info->poll_grow = iothread->poll_grow;
483
info->poll_shrink = iothread->poll_shrink;
484
- info->aio_max_batch = iothread->aio_max_batch;
485
+ info->aio_max_batch = iothread->parent_obj.aio_max_batch;
486
487
QAPI_LIST_APPEND(*tail, info);
488
return 0;
217
--
489
--
218
2.21.0
490
2.35.1
219
220
diff view generated by jsdifflib
1
This adds a salvaging mode (--salvage) to qemu-img convert which ignores
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
2
read errors and treats the respective areas as containing only zeroes.
2
3
This can be used for instance to at least partially recover the data
3
'event-loop-base' provides basic property handling for all 'AioContext'
4
from terminally corrupted qcow2 images.
4
based event loops. So let's define a new 'MainLoopClass' that inherits
5
5
from it. This will permit tweaking the main loop's properties through
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
qapi as well as through the command line using the '-object' keyword[1].
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Only one instance of 'MainLoopClass' might be created at any time.
8
Message-id: 20190507203508.18026-3-mreitz@redhat.com
8
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
'EventLoopBaseClass' learns a new callback, 'can_be_deleted()' so as to
10
mark 'MainLoop' as non-deletable.
11
12
[1] For example:
13
-object main-loop,id=main-loop,aio-max-batch=<value>
14
15
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
16
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Acked-by: Markus Armbruster <armbru@redhat.com>
18
Message-id: 20220425075723.20019-3-nsaenzju@redhat.com
19
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
20
---
11
qemu-img.c | 90 +++++++++++++++++++++++++++++++++++++-----------
21
qapi/qom.json | 13 ++++++++
12
qemu-img-cmds.hx | 4 +--
22
meson.build | 3 +-
13
qemu-img.texi | 4 +++
23
include/qemu/main-loop.h | 10 ++++++
14
3 files changed, 75 insertions(+), 23 deletions(-)
24
include/sysemu/event-loop-base.h | 1 +
15
25
event-loop-base.c | 13 ++++++++
16
diff --git a/qemu-img.c b/qemu-img.c
26
util/main-loop.c | 56 ++++++++++++++++++++++++++++++++
17
index XXXXXXX..XXXXXXX 100644
27
6 files changed, 95 insertions(+), 1 deletion(-)
18
--- a/qemu-img.c
28
19
+++ b/qemu-img.c
29
diff --git a/qapi/qom.json b/qapi/qom.json
20
@@ -XXX,XX +XXX,XX @@ enum {
30
index XXXXXXX..XXXXXXX 100644
21
OPTION_SIZE = 264,
31
--- a/qapi/qom.json
22
OPTION_PREALLOCATION = 265,
32
+++ b/qapi/qom.json
23
OPTION_SHRINK = 266,
33
@@ -XXX,XX +XXX,XX @@
24
+ OPTION_SALVAGE = 267,
34
'*poll-grow': 'int',
35
'*poll-shrink': 'int' } }
36
37
+##
38
+# @MainLoopProperties:
39
+#
40
+# Properties for the main-loop object.
41
+#
42
+# Since: 7.1
43
+##
44
+{ 'struct': 'MainLoopProperties',
45
+ 'base': 'EventLoopBaseProperties',
46
+ 'data': {} }
47
+
48
##
49
# @MemoryBackendProperties:
50
#
51
@@ -XXX,XX +XXX,XX @@
52
{ 'name': 'input-linux',
53
'if': 'CONFIG_LINUX' },
54
'iothread',
55
+ 'main-loop',
56
{ 'name': 'memory-backend-epc',
57
'if': 'CONFIG_LINUX' },
58
'memory-backend-file',
59
@@ -XXX,XX +XXX,XX @@
60
'input-linux': { 'type': 'InputLinuxProperties',
61
'if': 'CONFIG_LINUX' },
62
'iothread': 'IothreadProperties',
63
+ 'main-loop': 'MainLoopProperties',
64
'memory-backend-epc': { 'type': 'MemoryBackendEpcProperties',
65
'if': 'CONFIG_LINUX' },
66
'memory-backend-file': 'MemoryBackendFileProperties',
67
diff --git a/meson.build b/meson.build
68
index XXXXXXX..XXXXXXX 100644
69
--- a/meson.build
70
+++ b/meson.build
71
@@ -XXX,XX +XXX,XX @@ libqemuutil = static_library('qemuutil',
72
sources: util_ss.sources() + stub_ss.sources() + genh,
73
dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman])
74
qemuutil = declare_dependency(link_with: libqemuutil,
75
- sources: genh + version_res)
76
+ sources: genh + version_res,
77
+ dependencies: [event_loop_base])
78
79
if have_system or have_user
80
decodetree = generator(find_program('scripts/decodetree.py'),
81
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
82
index XXXXXXX..XXXXXXX 100644
83
--- a/include/qemu/main-loop.h
84
+++ b/include/qemu/main-loop.h
85
@@ -XXX,XX +XXX,XX @@
86
#define QEMU_MAIN_LOOP_H
87
88
#include "block/aio.h"
89
+#include "qom/object.h"
90
+#include "sysemu/event-loop-base.h"
91
92
#define SIG_IPI SIGUSR1
93
94
+#define TYPE_MAIN_LOOP "main-loop"
95
+OBJECT_DECLARE_TYPE(MainLoop, MainLoopClass, MAIN_LOOP)
96
+
97
+struct MainLoop {
98
+ EventLoopBase parent_obj;
99
+};
100
+typedef struct MainLoop MainLoop;
101
+
102
/**
103
* qemu_init_main_loop: Set up the process so that it can run the main loop.
104
*
105
diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h
106
index XXXXXXX..XXXXXXX 100644
107
--- a/include/sysemu/event-loop-base.h
108
+++ b/include/sysemu/event-loop-base.h
109
@@ -XXX,XX +XXX,XX @@ struct EventLoopBaseClass {
110
111
void (*init)(EventLoopBase *base, Error **errp);
112
void (*update_params)(EventLoopBase *base, Error **errp);
113
+ bool (*can_be_deleted)(EventLoopBase *base);
25
};
114
};
26
115
27
typedef enum OutputFormat {
116
struct EventLoopBase {
28
@@ -XXX,XX +XXX,XX @@ typedef struct ImgConvertState {
117
diff --git a/event-loop-base.c b/event-loop-base.c
29
int64_t target_backing_sectors; /* negative if unknown */
118
index XXXXXXX..XXXXXXX 100644
30
bool wr_in_order;
119
--- a/event-loop-base.c
31
bool copy_range;
120
+++ b/event-loop-base.c
32
+ bool salvage;
121
@@ -XXX,XX +XXX,XX @@ static void event_loop_base_complete(UserCreatable *uc, Error **errp)
33
bool quiet;
34
int min_sparse;
35
int alignment;
36
@@ -XXX,XX +XXX,XX @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
37
}
122
}
38
123
}
39
if (s->sector_next_status <= sector_num) {
124
40
- int64_t count = n * BDRV_SECTOR_SIZE;
125
+static bool event_loop_base_can_be_deleted(UserCreatable *uc)
41
+ uint64_t offset = (sector_num - src_cur_offset) * BDRV_SECTOR_SIZE;
126
+{
42
+ int64_t count;
127
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc);
43
128
+ EventLoopBase *backend = EVENT_LOOP_BASE(uc);
44
- if (s->target_has_backing) {
129
+
45
+ do {
130
+ if (bc->can_be_deleted) {
46
+ count = n * BDRV_SECTOR_SIZE;
131
+ return bc->can_be_deleted(backend);
47
+
132
+ }
48
+ if (s->target_has_backing) {
133
+
49
+ ret = bdrv_block_status(blk_bs(s->src[src_cur]), offset,
134
+ return true;
50
+ count, &count, NULL, NULL);
135
+}
51
+ } else {
136
+
52
+ ret = bdrv_block_status_above(blk_bs(s->src[src_cur]), NULL,
137
static void event_loop_base_class_init(ObjectClass *klass, void *class_data)
53
+ offset, count, &count, NULL,
54
+ NULL);
55
+ }
56
+
57
+ if (ret < 0) {
58
+ if (s->salvage) {
59
+ if (n == 1) {
60
+ if (!s->quiet) {
61
+ warn_report("error while reading block status at "
62
+ "offset %" PRIu64 ": %s", offset,
63
+ strerror(-ret));
64
+ }
65
+ /* Just try to read the data, then */
66
+ ret = BDRV_BLOCK_DATA;
67
+ count = BDRV_SECTOR_SIZE;
68
+ } else {
69
+ /* Retry on a shorter range */
70
+ n = DIV_ROUND_UP(n, 4);
71
+ }
72
+ } else {
73
+ error_report("error while reading block status at offset "
74
+ "%" PRIu64 ": %s", offset, strerror(-ret));
75
+ return ret;
76
+ }
77
+ }
78
+ } while (ret < 0);
79
80
- ret = bdrv_block_status(blk_bs(s->src[src_cur]),
81
- (sector_num - src_cur_offset) *
82
- BDRV_SECTOR_SIZE,
83
- count, &count, NULL, NULL);
84
- } else {
85
- ret = bdrv_block_status_above(blk_bs(s->src[src_cur]), NULL,
86
- (sector_num - src_cur_offset) *
87
- BDRV_SECTOR_SIZE,
88
- count, &count, NULL, NULL);
89
- }
90
- if (ret < 0) {
91
- error_report("error while reading block status of sector %" PRId64
92
- ": %s", sector_num, strerror(-ret));
93
- return ret;
94
- }
95
n = DIV_ROUND_UP(count, BDRV_SECTOR_SIZE);
96
97
if (ret & BDRV_BLOCK_ZERO) {
98
@@ -XXX,XX +XXX,XX @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
99
static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num,
100
int nb_sectors, uint8_t *buf)
101
{
138
{
102
+ uint64_t single_read_until = 0;
139
UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
103
int n, ret;
140
ucc->complete = event_loop_base_complete;
104
141
+ ucc->can_be_deleted = event_loop_base_can_be_deleted;
105
assert(nb_sectors <= s->buf_sectors);
142
106
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num,
143
object_class_property_add(klass, "aio-max-batch", "int",
107
BlockBackend *blk;
144
event_loop_base_get_param,
108
int src_cur;
145
diff --git a/util/main-loop.c b/util/main-loop.c
109
int64_t bs_sectors, src_cur_offset;
146
index XXXXXXX..XXXXXXX 100644
110
+ uint64_t offset;
147
--- a/util/main-loop.c
111
148
+++ b/util/main-loop.c
112
/* In the case of compression with multiple source files, we can get a
149
@@ -XXX,XX +XXX,XX @@
113
* nb_sectors that spreads into the next part. So we must be able to
150
#include "qemu/error-report.h"
114
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num,
151
#include "qemu/queue.h"
115
blk = s->src[src_cur];
152
#include "qemu/compiler.h"
116
bs_sectors = s->src_sectors[src_cur];
153
+#include "qom/object.h"
117
154
118
+ offset = (sector_num - src_cur_offset) << BDRV_SECTOR_BITS;
155
#ifndef _WIN32
119
+
156
#include <sys/wait.h>
120
n = MIN(nb_sectors, bs_sectors - (sector_num - src_cur_offset));
157
@@ -XXX,XX +XXX,XX @@ int qemu_init_main_loop(Error **errp)
121
+ if (single_read_until > offset) {
158
return 0;
122
+ n = 1;
159
}
123
+ }
160
124
161
+static void main_loop_update_params(EventLoopBase *base, Error **errp)
125
- ret = blk_co_pread(
162
+{
126
- blk, (sector_num - src_cur_offset) << BDRV_SECTOR_BITS,
163
+ if (!qemu_aio_context) {
127
- n << BDRV_SECTOR_BITS, buf, 0);
164
+ error_setg(errp, "qemu aio context not ready");
128
+ ret = blk_co_pread(blk, offset, n << BDRV_SECTOR_BITS, buf, 0);
165
+ return;
129
if (ret < 0) {
130
- return ret;
131
+ if (s->salvage) {
132
+ if (n > 1) {
133
+ single_read_until = offset + (n << BDRV_SECTOR_BITS);
134
+ continue;
135
+ } else {
136
+ if (!s->quiet) {
137
+ warn_report("error while reading offset %" PRIu64
138
+ ": %s", offset, strerror(-ret));
139
+ }
140
+ memset(buf, 0, BDRV_SECTOR_SIZE);
141
+ }
142
+ } else {
143
+ return ret;
144
+ }
145
}
146
147
sector_num += n;
148
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
149
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
150
{"force-share", no_argument, 0, 'U'},
151
{"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS},
152
+ {"salvage", no_argument, 0, OPTION_SALVAGE},
153
{0, 0, 0, 0}
154
};
155
c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WU",
156
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
157
case OPTION_IMAGE_OPTS:
158
image_opts = true;
159
break;
160
+ case OPTION_SALVAGE:
161
+ s.salvage = true;
162
+ break;
163
case OPTION_TARGET_IMAGE_OPTS:
164
tgt_image_opts = true;
165
break;
166
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
167
goto fail_getopt;
168
}
169
170
+ if (s.copy_range && s.salvage) {
171
+ error_report("Cannot use copy offloading in salvaging mode");
172
+ goto fail_getopt;
173
+ }
166
+ }
174
+
167
+
175
if (tgt_image_opts && !skip_create) {
168
+ aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp);
176
error_report("--target-image-opts requires use of -n flag");
169
+}
177
goto fail_getopt;
170
+
178
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
171
+MainLoop *mloop;
179
index XXXXXXX..XXXXXXX 100644
172
+
180
--- a/qemu-img-cmds.hx
173
+static void main_loop_init(EventLoopBase *base, Error **errp)
181
+++ b/qemu-img-cmds.hx
174
+{
182
@@ -XXX,XX +XXX,XX @@ STEXI
175
+ MainLoop *m = MAIN_LOOP(base);
183
ETEXI
176
+
184
177
+ if (mloop) {
185
DEF("convert", img_convert,
178
+ error_setg(errp, "only one main-loop instance allowed");
186
- "convert [--object objectdef] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] filename [filename2 [...]] output_filename")
179
+ return;
187
+ "convert [--object objectdef] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename")
180
+ }
188
STEXI
181
+
189
-@item convert [--object @var{objectdef}] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] @var{filename} [@var{filename2} [...]] @var{output_filename}
182
+ main_loop_update_params(base, errp);
190
+@item convert [--object @var{objectdef}] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] [--salvage] @var{filename} [@var{filename2} [...]] @var{output_filename}
183
+
191
ETEXI
184
+ mloop = m;
192
185
+ return;
193
DEF("create", img_create,
186
+}
194
diff --git a/qemu-img.texi b/qemu-img.texi
187
+
195
index XXXXXXX..XXXXXXX 100644
188
+static bool main_loop_can_be_deleted(EventLoopBase *base)
196
--- a/qemu-img.texi
189
+{
197
+++ b/qemu-img.texi
190
+ return false;
198
@@ -XXX,XX +XXX,XX @@ improve performance if the data is remote, such as with NFS or iSCSI backends,
191
+}
199
but will not automatically sparsify zero sectors, and may result in a fully
192
+
200
allocated target image depending on the host support for getting allocation
193
+static void main_loop_class_init(ObjectClass *oc, void *class_data)
201
information.
194
+{
202
+@item --salvage
195
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(oc);
203
+Try to ignore I/O errors when reading. Unless in quiet mode (@code{-q}), errors
196
+
204
+will still be printed. Areas that cannot be read from the source will be
197
+ bc->init = main_loop_init;
205
+treated as containing only zeroes.
198
+ bc->update_params = main_loop_update_params;
206
@end table
199
+ bc->can_be_deleted = main_loop_can_be_deleted;
207
200
+}
208
Parameters to dd subcommand:
201
+
202
+static const TypeInfo main_loop_info = {
203
+ .name = TYPE_MAIN_LOOP,
204
+ .parent = TYPE_EVENT_LOOP_BASE,
205
+ .class_init = main_loop_class_init,
206
+ .instance_size = sizeof(MainLoop),
207
+};
208
+
209
+static void main_loop_register_types(void)
210
+{
211
+ type_register_static(&main_loop_info);
212
+}
213
+
214
+type_init(main_loop_register_types)
215
+
216
static int max_priority;
217
218
#ifndef _WIN32
209
--
219
--
210
2.21.0
220
2.35.1
211
212
diff view generated by jsdifflib
1
Together with @iotypes and @sector, this can be used to trap e.g. the
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
2
first read or write access to a certain sector without having to know
3
what happens internally in the block layer, i.e. which "real" events
4
happen right before such an access.
5
2
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
The thread pool regulates itself: when idle, it kills threads until
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
empty, when in demand, it creates new threads until full. This behaviour
8
Message-id: 20190507203508.18026-5-mreitz@redhat.com
5
doesn't play well with latency sensitive workloads where the price of
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
creating a new thread is too high. For example, when paired with qemu's
7
'-mlock', or using safety features like SafeStack, creating a new thread
8
has been measured take multiple milliseconds.
9
10
In order to mitigate this let's introduce a new 'EventLoopBase'
11
property to set the thread pool size. The threads will be created during
12
the pool's initialization or upon updating the property's value, remain
13
available during its lifetime regardless of demand, and destroyed upon
14
freeing it. A properly characterized workload will then be able to
15
configure the pool to avoid any latency spikes.
16
17
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Acked-by: Markus Armbruster <armbru@redhat.com>
20
Message-id: 20220425075723.20019-4-nsaenzju@redhat.com
21
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
22
---
11
qapi/block-core.json | 4 +++-
23
qapi/qom.json | 10 +++++-
12
block/blkdebug.c | 2 ++
24
include/block/aio.h | 10 ++++++
13
2 files changed, 5 insertions(+), 1 deletion(-)
25
include/block/thread-pool.h | 3 ++
26
include/sysemu/event-loop-base.h | 4 +++
27
event-loop-base.c | 23 +++++++++++++
28
iothread.c | 3 ++
29
util/aio-posix.c | 1 +
30
util/async.c | 20 ++++++++++++
31
util/main-loop.c | 9 ++++++
32
util/thread-pool.c | 55 +++++++++++++++++++++++++++++---
33
10 files changed, 133 insertions(+), 5 deletions(-)
14
34
15
diff --git a/qapi/block-core.json b/qapi/block-core.json
35
diff --git a/qapi/qom.json b/qapi/qom.json
16
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
17
--- a/qapi/block-core.json
37
--- a/qapi/qom.json
18
+++ b/qapi/block-core.json
38
+++ b/qapi/qom.json
19
@@ -XXX,XX +XXX,XX @@
39
@@ -XXX,XX +XXX,XX @@
40
# 0 means that the engine will use its default.
41
# (default: 0)
20
#
42
#
21
# @cluster_alloc_space: an allocation of file space for a cluster (since 4.1)
43
+# @thread-pool-min: minimum number of threads reserved in the thread pool
22
#
44
+# (default:0)
23
+# @none: triggers once at creation of the blkdebug node (since 4.1)
24
+#
45
+#
25
# Since: 2.9
46
+# @thread-pool-max: maximum number of threads the thread pool can contain
47
+# (default:64)
48
+#
49
# Since: 7.1
26
##
50
##
27
{ 'enum': 'BlkdebugEvent', 'prefix': 'BLKDBG',
51
{ 'struct': 'EventLoopBaseProperties',
28
@@ -XXX,XX +XXX,XX @@
52
- 'data': { '*aio-max-batch': 'int' } }
29
'pwritev_rmw_tail', 'pwritev_rmw_after_tail', 'pwritev',
53
+ 'data': { '*aio-max-batch': 'int',
30
'pwritev_zero', 'pwritev_done', 'empty_image_prepare',
54
+ '*thread-pool-min': 'int',
31
'l1_shrink_write_table', 'l1_shrink_free_l2_clusters',
55
+ '*thread-pool-max': 'int' } }
32
- 'cor_write', 'cluster_alloc_space'] }
33
+ 'cor_write', 'cluster_alloc_space', 'none'] }
34
56
35
##
57
##
36
# @BlkdebugIOType:
58
# @IothreadProperties:
37
diff --git a/block/blkdebug.c b/block/blkdebug.c
59
diff --git a/include/block/aio.h b/include/block/aio.h
38
index XXXXXXX..XXXXXXX 100644
60
index XXXXXXX..XXXXXXX 100644
39
--- a/block/blkdebug.c
61
--- a/include/block/aio.h
40
+++ b/block/blkdebug.c
62
+++ b/include/block/aio.h
41
@@ -XXX,XX +XXX,XX @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
63
@@ -XXX,XX +XXX,XX @@ struct AioContext {
42
goto out;
64
QSLIST_HEAD(, Coroutine) scheduled_coroutines;
65
QEMUBH *co_schedule_bh;
66
67
+ int thread_pool_min;
68
+ int thread_pool_max;
69
/* Thread pool for performing work and receiving completion callbacks.
70
* Has its own locking.
71
*/
72
@@ -XXX,XX +XXX,XX @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
73
void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch,
74
Error **errp);
75
76
+/**
77
+ * aio_context_set_thread_pool_params:
78
+ * @ctx: the aio context
79
+ * @min: min number of threads to have readily available in the thread pool
80
+ * @min: max number of threads the thread pool can contain
81
+ */
82
+void aio_context_set_thread_pool_params(AioContext *ctx, int64_t min,
83
+ int64_t max, Error **errp);
84
#endif
85
diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h
86
index XXXXXXX..XXXXXXX 100644
87
--- a/include/block/thread-pool.h
88
+++ b/include/block/thread-pool.h
89
@@ -XXX,XX +XXX,XX @@
90
91
#include "block/block.h"
92
93
+#define THREAD_POOL_MAX_THREADS_DEFAULT 64
94
+
95
typedef int ThreadPoolFunc(void *opaque);
96
97
typedef struct ThreadPool ThreadPool;
98
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool,
99
int coroutine_fn thread_pool_submit_co(ThreadPool *pool,
100
ThreadPoolFunc *func, void *arg);
101
void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg);
102
+void thread_pool_update_params(ThreadPool *pool, struct AioContext *ctx);
103
104
#endif
105
diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h
106
index XXXXXXX..XXXXXXX 100644
107
--- a/include/sysemu/event-loop-base.h
108
+++ b/include/sysemu/event-loop-base.h
109
@@ -XXX,XX +XXX,XX @@ struct EventLoopBase {
110
111
/* AioContext AIO engine parameters */
112
int64_t aio_max_batch;
113
+
114
+ /* AioContext thread pool parameters */
115
+ int64_t thread_pool_min;
116
+ int64_t thread_pool_max;
117
};
118
#endif
119
diff --git a/event-loop-base.c b/event-loop-base.c
120
index XXXXXXX..XXXXXXX 100644
121
--- a/event-loop-base.c
122
+++ b/event-loop-base.c
123
@@ -XXX,XX +XXX,XX @@
124
#include "qemu/osdep.h"
125
#include "qom/object_interfaces.h"
126
#include "qapi/error.h"
127
+#include "block/thread-pool.h"
128
#include "sysemu/event-loop-base.h"
129
130
typedef struct {
131
@@ -XXX,XX +XXX,XX @@ typedef struct {
132
ptrdiff_t offset; /* field's byte offset in EventLoopBase struct */
133
} EventLoopBaseParamInfo;
134
135
+static void event_loop_base_instance_init(Object *obj)
136
+{
137
+ EventLoopBase *base = EVENT_LOOP_BASE(obj);
138
+
139
+ base->thread_pool_max = THREAD_POOL_MAX_THREADS_DEFAULT;
140
+}
141
+
142
static EventLoopBaseParamInfo aio_max_batch_info = {
143
"aio-max-batch", offsetof(EventLoopBase, aio_max_batch),
144
};
145
+static EventLoopBaseParamInfo thread_pool_min_info = {
146
+ "thread-pool-min", offsetof(EventLoopBase, thread_pool_min),
147
+};
148
+static EventLoopBaseParamInfo thread_pool_max_info = {
149
+ "thread-pool-max", offsetof(EventLoopBase, thread_pool_max),
150
+};
151
152
static void event_loop_base_get_param(Object *obj, Visitor *v,
153
const char *name, void *opaque, Error **errp)
154
@@ -XXX,XX +XXX,XX @@ static void event_loop_base_class_init(ObjectClass *klass, void *class_data)
155
event_loop_base_get_param,
156
event_loop_base_set_param,
157
NULL, &aio_max_batch_info);
158
+ object_class_property_add(klass, "thread-pool-min", "int",
159
+ event_loop_base_get_param,
160
+ event_loop_base_set_param,
161
+ NULL, &thread_pool_min_info);
162
+ object_class_property_add(klass, "thread-pool-max", "int",
163
+ event_loop_base_get_param,
164
+ event_loop_base_set_param,
165
+ NULL, &thread_pool_max_info);
166
}
167
168
static const TypeInfo event_loop_base_info = {
169
.name = TYPE_EVENT_LOOP_BASE,
170
.parent = TYPE_OBJECT,
171
.instance_size = sizeof(EventLoopBase),
172
+ .instance_init = event_loop_base_instance_init,
173
.class_size = sizeof(EventLoopBaseClass),
174
.class_init = event_loop_base_class_init,
175
.abstract = true,
176
diff --git a/iothread.c b/iothread.c
177
index XXXXXXX..XXXXXXX 100644
178
--- a/iothread.c
179
+++ b/iothread.c
180
@@ -XXX,XX +XXX,XX @@ static void iothread_set_aio_context_params(EventLoopBase *base, Error **errp)
181
aio_context_set_aio_params(iothread->ctx,
182
iothread->parent_obj.aio_max_batch,
183
errp);
184
+
185
+ aio_context_set_thread_pool_params(iothread->ctx, base->thread_pool_min,
186
+ base->thread_pool_max, errp);
187
}
188
189
190
diff --git a/util/aio-posix.c b/util/aio-posix.c
191
index XXXXXXX..XXXXXXX 100644
192
--- a/util/aio-posix.c
193
+++ b/util/aio-posix.c
194
@@ -XXX,XX +XXX,XX @@
195
196
#include "qemu/osdep.h"
197
#include "block/block.h"
198
+#include "block/thread-pool.h"
199
#include "qemu/main-loop.h"
200
#include "qemu/rcu.h"
201
#include "qemu/rcu_queue.h"
202
diff --git a/util/async.c b/util/async.c
203
index XXXXXXX..XXXXXXX 100644
204
--- a/util/async.c
205
+++ b/util/async.c
206
@@ -XXX,XX +XXX,XX @@ AioContext *aio_context_new(Error **errp)
207
208
ctx->aio_max_batch = 0;
209
210
+ ctx->thread_pool_min = 0;
211
+ ctx->thread_pool_max = THREAD_POOL_MAX_THREADS_DEFAULT;
212
+
213
return ctx;
214
fail:
215
g_source_destroy(&ctx->source);
216
@@ -XXX,XX +XXX,XX @@ void qemu_set_current_aio_context(AioContext *ctx)
217
assert(!get_my_aiocontext());
218
set_my_aiocontext(ctx);
219
}
220
+
221
+void aio_context_set_thread_pool_params(AioContext *ctx, int64_t min,
222
+ int64_t max, Error **errp)
223
+{
224
+
225
+ if (min > max || !max || min > INT_MAX || max > INT_MAX) {
226
+ error_setg(errp, "bad thread-pool-min/thread-pool-max values");
227
+ return;
228
+ }
229
+
230
+ ctx->thread_pool_min = min;
231
+ ctx->thread_pool_max = max;
232
+
233
+ if (ctx->thread_pool) {
234
+ thread_pool_update_params(ctx->thread_pool, ctx);
235
+ }
236
+}
237
diff --git a/util/main-loop.c b/util/main-loop.c
238
index XXXXXXX..XXXXXXX 100644
239
--- a/util/main-loop.c
240
+++ b/util/main-loop.c
241
@@ -XXX,XX +XXX,XX @@
242
#include "sysemu/replay.h"
243
#include "qemu/main-loop.h"
244
#include "block/aio.h"
245
+#include "block/thread-pool.h"
246
#include "qemu/error-report.h"
247
#include "qemu/queue.h"
248
#include "qemu/compiler.h"
249
@@ -XXX,XX +XXX,XX @@ int qemu_init_main_loop(Error **errp)
250
251
static void main_loop_update_params(EventLoopBase *base, Error **errp)
252
{
253
+ ERRP_GUARD();
254
+
255
if (!qemu_aio_context) {
256
error_setg(errp, "qemu aio context not ready");
257
return;
43
}
258
}
44
259
45
+ bdrv_debug_event(bs, BLKDBG_NONE);
260
aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp);
46
+
261
+ if (*errp) {
47
ret = 0;
262
+ return;
48
out:
263
+ }
49
if (ret < 0) {
264
+
265
+ aio_context_set_thread_pool_params(qemu_aio_context, base->thread_pool_min,
266
+ base->thread_pool_max, errp);
267
}
268
269
MainLoop *mloop;
270
diff --git a/util/thread-pool.c b/util/thread-pool.c
271
index XXXXXXX..XXXXXXX 100644
272
--- a/util/thread-pool.c
273
+++ b/util/thread-pool.c
274
@@ -XXX,XX +XXX,XX @@ struct ThreadPool {
275
QemuMutex lock;
276
QemuCond worker_stopped;
277
QemuSemaphore sem;
278
- int max_threads;
279
QEMUBH *new_thread_bh;
280
281
/* The following variables are only accessed from one AioContext. */
282
@@ -XXX,XX +XXX,XX @@ struct ThreadPool {
283
int new_threads; /* backlog of threads we need to create */
284
int pending_threads; /* threads created but not running yet */
285
bool stopping;
286
+ int min_threads;
287
+ int max_threads;
288
};
289
290
+static inline bool back_to_sleep(ThreadPool *pool, int ret)
291
+{
292
+ /*
293
+ * The semaphore timed out, we should exit the loop except when:
294
+ * - There is work to do, we raced with the signal.
295
+ * - The max threads threshold just changed, we raced with the signal.
296
+ * - The thread pool forces a minimum number of readily available threads.
297
+ */
298
+ if (ret == -1 && (!QTAILQ_EMPTY(&pool->request_list) ||
299
+ pool->cur_threads > pool->max_threads ||
300
+ pool->cur_threads <= pool->min_threads)) {
301
+ return true;
302
+ }
303
+
304
+ return false;
305
+}
306
+
307
static void *worker_thread(void *opaque)
308
{
309
ThreadPool *pool = opaque;
310
@@ -XXX,XX +XXX,XX @@ static void *worker_thread(void *opaque)
311
ret = qemu_sem_timedwait(&pool->sem, 10000);
312
qemu_mutex_lock(&pool->lock);
313
pool->idle_threads--;
314
- } while (ret == -1 && !QTAILQ_EMPTY(&pool->request_list));
315
- if (ret == -1 || pool->stopping) {
316
+ } while (back_to_sleep(pool, ret));
317
+ if (ret == -1 || pool->stopping ||
318
+ pool->cur_threads > pool->max_threads) {
319
break;
320
}
321
322
@@ -XXX,XX +XXX,XX @@ void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg)
323
thread_pool_submit_aio(pool, func, arg, NULL, NULL);
324
}
325
326
+void thread_pool_update_params(ThreadPool *pool, AioContext *ctx)
327
+{
328
+ qemu_mutex_lock(&pool->lock);
329
+
330
+ pool->min_threads = ctx->thread_pool_min;
331
+ pool->max_threads = ctx->thread_pool_max;
332
+
333
+ /*
334
+ * We either have to:
335
+ * - Increase the number available of threads until over the min_threads
336
+ * threshold.
337
+ * - Decrease the number of available threads until under the max_threads
338
+ * threshold.
339
+ * - Do nothing. The current number of threads fall in between the min and
340
+ * max thresholds. We'll let the pool manage itself.
341
+ */
342
+ for (int i = pool->cur_threads; i < pool->min_threads; i++) {
343
+ spawn_thread(pool);
344
+ }
345
+
346
+ for (int i = pool->cur_threads; i > pool->max_threads; i--) {
347
+ qemu_sem_post(&pool->sem);
348
+ }
349
+
350
+ qemu_mutex_unlock(&pool->lock);
351
+}
352
+
353
static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
354
{
355
if (!ctx) {
356
@@ -XXX,XX +XXX,XX @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
357
qemu_mutex_init(&pool->lock);
358
qemu_cond_init(&pool->worker_stopped);
359
qemu_sem_init(&pool->sem, 0);
360
- pool->max_threads = 64;
361
pool->new_thread_bh = aio_bh_new(ctx, spawn_thread_bh_fn, pool);
362
363
QLIST_INIT(&pool->head);
364
QTAILQ_INIT(&pool->request_list);
365
+
366
+ thread_pool_update_params(pool, ctx);
367
}
368
369
ThreadPool *thread_pool_new(AioContext *ctx)
50
--
370
--
51
2.21.0
371
2.35.1
52
53
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Max Reitz <mreitz@redhat.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
3
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
Message-id: 20190507203508.18026-6-mreitz@redhat.com
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
---
7
qapi/block-core.json | 5 ++++-
8
block/blkdebug.c | 8 ++++++++
9
2 files changed, 12 insertions(+), 1 deletion(-)
10
1
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
12
index XXXXXXX..XXXXXXX 100644
13
--- a/qapi/block-core.json
14
+++ b/qapi/block-core.json
15
@@ -XXX,XX +XXX,XX @@
16
#
17
# @flush: .bdrv_co_flush_to_disk()
18
#
19
+# @block-status: .bdrv_co_block_status()
20
+#
21
# Since: 4.1
22
##
23
{ 'enum': 'BlkdebugIOType', 'prefix': 'BLKDEBUG_IO_TYPE',
24
- 'data': [ 'read', 'write', 'write-zeroes', 'discard', 'flush' ] }
25
+ 'data': [ 'read', 'write', 'write-zeroes', 'discard', 'flush',
26
+ 'block-status' ] }
27
28
##
29
# @BlkdebugInjectErrorOptions:
30
diff --git a/block/blkdebug.c b/block/blkdebug.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/block/blkdebug.c
33
+++ b/block/blkdebug.c
34
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkdebug_co_block_status(BlockDriverState *bs,
35
int64_t *map,
36
BlockDriverState **file)
37
{
38
+ int err;
39
+
40
assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment));
41
+
42
+ err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_BLOCK_STATUS);
43
+ if (err) {
44
+ return err;
45
+ }
46
+
47
return bdrv_co_block_status_from_file(bs, want_zero, offset, bytes,
48
pnum, map, file);
49
}
50
--
51
2.21.0
52
53
diff view generated by jsdifflib
Deleted patch
1
This test converts a simple image to another, but blkdebug injects
2
block_status and read faults at some offsets. The resulting image
3
should be the same as the input image, except that sectors that could
4
not be read have to be 0.
5
1
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Message-id: 20190507203508.18026-7-mreitz@redhat.com
8
Tested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
[mreitz: Dropped superfluous printf from _filter_offsets, as suggested
11
by Vladimir; disable test for VDI and IMGOPTSSYNTAX]
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
tests/qemu-iotests/251 | 170 +++++++++++++++++++++++++++++++++++++
15
tests/qemu-iotests/251.out | 43 ++++++++++
16
tests/qemu-iotests/group | 1 +
17
3 files changed, 214 insertions(+)
18
create mode 100755 tests/qemu-iotests/251
19
create mode 100644 tests/qemu-iotests/251.out
20
21
diff --git a/tests/qemu-iotests/251 b/tests/qemu-iotests/251
22
new file mode 100755
23
index XXXXXXX..XXXXXXX
24
--- /dev/null
25
+++ b/tests/qemu-iotests/251
26
@@ -XXX,XX +XXX,XX @@
27
+#!/usr/bin/env bash
28
+#
29
+# Test qemu-img convert --salvage
30
+#
31
+# Copyright (C) 2019 Red Hat, Inc.
32
+#
33
+# This program is free software; you can redistribute it and/or modify
34
+# it under the terms of the GNU General Public License as published by
35
+# the Free Software Foundation; either version 2 of the License, or
36
+# (at your option) any later version.
37
+#
38
+# This program is distributed in the hope that it will be useful,
39
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
40
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41
+# GNU General Public License for more details.
42
+#
43
+# You should have received a copy of the GNU General Public License
44
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
45
+#
46
+
47
+# creator
48
+owner=mreitz@redhat.com
49
+
50
+seq=$(basename $0)
51
+echo "QA output created by $seq"
52
+
53
+status=1    # failure is the default!
54
+
55
+_cleanup()
56
+{
57
+ _cleanup_test_img
58
+}
59
+trap "_cleanup; exit \$status" 0 1 2 3 15
60
+
61
+# get standard environment, filters and checks
62
+. ./common.rc
63
+. ./common.filter
64
+. ./common.qemu
65
+
66
+_supported_fmt generic
67
+_supported_proto file
68
+_supported_os Linux
69
+
70
+if [ "$IMGOPTSSYNTAX" = "true" ]; then
71
+ # We use json:{} filenames here, so we cannot work with additional options.
72
+ _unsupported_fmt $IMGFMT
73
+else
74
+ # With VDI, the output is ordered differently. Just disable it.
75
+ _unsupported_fmt vdi
76
+fi
77
+
78
+
79
+TEST_IMG="$TEST_IMG.orig" _make_test_img 64M
80
+
81
+$QEMU_IO -c 'write -P 42 0 64M' "$TEST_IMG.orig" | _filter_qemu_io
82
+
83
+
84
+sector_size=512
85
+
86
+# Offsets on which to fail block-status. Keep in ascending order so
87
+# the indexing done by _filter_offsets will appear in ascending order
88
+# in the output as well.
89
+status_fail_offsets="$((16 * 1024 * 1024 + 8192))
90
+ $((33 * 1024 * 1024 + 512))"
91
+
92
+# Offsets on which to fail reads. Keep in ascending order for the
93
+# same reason.
94
+# The second element is shared with $status_fail_offsets on purpose.
95
+# Starting with the third element, we test what happens when a
96
+# continuous range of sectors is inaccessible.
97
+read_fail_offsets="$((32 * 1024 * 1024 - 65536))
98
+ $((33 * 1024 * 1024 + 512))
99
+ $(seq $((34 * 1024 * 1024)) $sector_size \
100
+ $((34 * 1024 * 1024 + 4096 - $sector_size)))"
101
+
102
+
103
+# blkdebug must be above the format layer so it can intercept all
104
+# block-status events
105
+source_img="json:{'driver': 'blkdebug',
106
+ 'image': {
107
+ 'driver': '$IMGFMT',
108
+ 'file': {
109
+ 'driver': 'file',
110
+ 'filename': '$TEST_IMG.orig'
111
+ }
112
+ },
113
+ 'inject-error': ["
114
+
115
+for ofs in $status_fail_offsets
116
+do
117
+ source_img+="{ 'event': 'none',
118
+ 'iotype': 'block-status',
119
+ 'errno': 5,
120
+ 'sector': $((ofs / sector_size)) },"
121
+done
122
+
123
+for ofs in $read_fail_offsets
124
+do
125
+ source_img+="{ 'event': 'none',
126
+ 'iotype': 'read',
127
+ 'errno': 5,
128
+ 'sector': $((ofs / sector_size)) },"
129
+done
130
+
131
+# Remove the trailing comma and terminate @inject-error and json:{}
132
+source_img="${source_img%,} ] }"
133
+
134
+
135
+echo
136
+
137
+
138
+_filter_offsets() {
139
+ filters=
140
+
141
+ index=0
142
+ for ofs in $1
143
+ do
144
+ filters+=" -e s/$ofs/status_fail_offset_$index/"
145
+ index=$((index + 1))
146
+ done
147
+
148
+ index=0
149
+ for ofs in $2
150
+ do
151
+ filters+=" -e s/$ofs/read_fail_offset_$index/"
152
+ index=$((index + 1))
153
+ done
154
+
155
+ sed $filters
156
+}
157
+
158
+# While determining the number of allocated sectors in the input
159
+# image, we should see one block status warning per element of
160
+# $status_fail_offsets.
161
+#
162
+# Then, the image is read. Since the block status is queried in
163
+# basically the same way, the same warnings as in the previous step
164
+# should reappear. Interleaved with those we should see a read
165
+# warning per element of $read_fail_offsets.
166
+# Note that $read_fail_offsets and $status_fail_offsets share an
167
+# element (read_fail_offset_1 == status_fail_offset_1), so
168
+# "status_fail_offset_1" in the output is the same as
169
+# "read_fail_offset_1".
170
+$QEMU_IMG convert --salvage "$source_img" "$TEST_IMG" 2>&1 \
171
+ | _filter_offsets "$status_fail_offsets" "$read_fail_offsets"
172
+
173
+echo
174
+
175
+# The offsets where the block status could not be determined should
176
+# have been treated as containing data and thus should be correct in
177
+# the output image.
178
+# The offsets where reading failed altogether should be 0. Make them
179
+# 0 in the input image, too, so we can compare both images.
180
+for ofs in $read_fail_offsets
181
+do
182
+ $QEMU_IO -c "write -z $ofs $sector_size" "$TEST_IMG.orig" \
183
+ | _filter_qemu_io \
184
+ | _filter_offsets '' "$read_fail_offsets"
185
+done
186
+
187
+echo
188
+
189
+# These should be equal now.
190
+$QEMU_IMG compare "$TEST_IMG.orig" "$TEST_IMG"
191
+
192
+
193
+# success, all done
194
+echo "*** done"
195
+rm -f $seq.full
196
+status=0
197
diff --git a/tests/qemu-iotests/251.out b/tests/qemu-iotests/251.out
198
new file mode 100644
199
index XXXXXXX..XXXXXXX
200
--- /dev/null
201
+++ b/tests/qemu-iotests/251.out
202
@@ -XXX,XX +XXX,XX @@
203
+QA output created by 251
204
+Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864
205
+wrote 67108864/67108864 bytes at offset 0
206
+64 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
207
+
208
+qemu-img: warning: error while reading block status at offset status_fail_offset_0: Input/output error
209
+qemu-img: warning: error while reading block status at offset status_fail_offset_1: Input/output error
210
+qemu-img: warning: error while reading block status at offset status_fail_offset_0: Input/output error
211
+qemu-img: warning: error while reading offset read_fail_offset_0: Input/output error
212
+qemu-img: warning: error while reading block status at offset status_fail_offset_1: Input/output error
213
+qemu-img: warning: error while reading offset status_fail_offset_1: Input/output error
214
+qemu-img: warning: error while reading offset read_fail_offset_2: Input/output error
215
+qemu-img: warning: error while reading offset read_fail_offset_3: Input/output error
216
+qemu-img: warning: error while reading offset read_fail_offset_4: Input/output error
217
+qemu-img: warning: error while reading offset read_fail_offset_5: Input/output error
218
+qemu-img: warning: error while reading offset read_fail_offset_6: Input/output error
219
+qemu-img: warning: error while reading offset read_fail_offset_7: Input/output error
220
+qemu-img: warning: error while reading offset read_fail_offset_8: Input/output error
221
+qemu-img: warning: error while reading offset read_fail_offset_9: Input/output error
222
+
223
+wrote 512/512 bytes at offset read_fail_offset_0
224
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
225
+wrote 512/512 bytes at offset read_fail_offset_1
226
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
227
+wrote 512/512 bytes at offset read_fail_offset_2
228
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
229
+wrote 512/512 bytes at offset read_fail_offset_3
230
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
231
+wrote 512/512 bytes at offset read_fail_offset_4
232
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
233
+wrote 512/512 bytes at offset read_fail_offset_5
234
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
235
+wrote 512/512 bytes at offset read_fail_offset_6
236
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
237
+wrote 512/512 bytes at offset read_fail_offset_7
238
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
239
+wrote 512/512 bytes at offset read_fail_offset_8
240
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
241
+wrote 512/512 bytes at offset read_fail_offset_9
242
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
243
+
244
+Images are identical.
245
+*** done
246
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
247
index XXXXXXX..XXXXXXX 100644
248
--- a/tests/qemu-iotests/group
249
+++ b/tests/qemu-iotests/group
250
@@ -XXX,XX +XXX,XX @@
251
248 rw quick
252
249 rw auto quick
253
250 rw auto quick
254
+251 rw auto quick
255
252 rw auto backing quick
256
253 rw auto quick
257
254 rw auto backing quick
258
--
259
2.21.0
260
261
diff view generated by jsdifflib
Deleted patch
1
We do not support this combination (yet), so this should yield an error
2
message.
3
1
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
Tested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Message-id: 20190507203508.18026-8-mreitz@redhat.com
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
tests/qemu-iotests/082 | 1 +
11
tests/qemu-iotests/082.out | 3 +++
12
2 files changed, 4 insertions(+)
13
14
diff --git a/tests/qemu-iotests/082 b/tests/qemu-iotests/082
15
index XXXXXXX..XXXXXXX 100755
16
--- a/tests/qemu-iotests/082
17
+++ b/tests/qemu-iotests/082
18
@@ -XXX,XX +XXX,XX @@ echo === convert: -C and other options ===
19
run_qemu_img convert -C -S 4k -O $IMGFMT "$TEST_IMG" "$TEST_IMG".target
20
run_qemu_img convert -C -S 8k -O $IMGFMT "$TEST_IMG" "$TEST_IMG".target
21
run_qemu_img convert -C -c -O $IMGFMT "$TEST_IMG" "$TEST_IMG".target
22
+run_qemu_img convert -C --salvage -O $IMGFMT "$TEST_IMG" "$TEST_IMG".target
23
24
echo
25
echo === amend: Options specified more than once ===
26
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
27
index XXXXXXX..XXXXXXX 100644
28
--- a/tests/qemu-iotests/082.out
29
+++ b/tests/qemu-iotests/082.out
30
@@ -XXX,XX +XXX,XX @@ qemu-img: Cannot enable copy offloading when -S is used
31
Testing: convert -C -c -O qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.target
32
qemu-img: Cannot enable copy offloading when -c is used
33
34
+Testing: convert -C --salvage -O qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.target
35
+qemu-img: Cannot use copy offloading in salvaging mode
36
+
37
=== amend: Options specified more than once ===
38
39
Testing: amend -f foo -f qcow2 -o lazy_refcounts=on TEST_DIR/t.qcow2
40
--
41
2.21.0
42
43
diff view generated by jsdifflib