Docs/RCU: Correct sample code of qatomic_rcu_set
[qemu/ar7.git] / tests / qemu-iotests / 219
blobdb272c524948159a208b7b4740137c091a415606
1 #!/usr/bin/env python3
3 # Copyright (C) 2018 Red Hat, Inc.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 # Creator/Owner: Kevin Wolf <kwolf@redhat.com>
20 # Check using the job-* QMP commands with block jobs
22 import iotests
24 iotests.script_initialize(supported_fmts=['qcow2'])
26 img_size = 4 * 1024 * 1024
28 def pause_wait(vm, job_id):
29     with iotests.Timeout(3, "Timeout waiting for job to pause"):
30         while True:
31             result = vm.qmp('query-jobs')
32             for job in result['return']:
33                 if job['id'] == job_id and job['status'] in ['paused', 'standby']:
34                     return job
36 # Test that block-job-pause/resume and job-pause/resume can be mixed
37 def test_pause_resume(vm):
38     for pause_cmd, pause_arg in [('block-job-pause', 'device'),
39                                  ('job-pause', 'id')]:
40         for resume_cmd, resume_arg in [('block-job-resume', 'device'),
41                                        ('job-resume', 'id')]:
42             iotests.log('=== Testing %s/%s ===' % (pause_cmd, resume_cmd))
44             iotests.log(vm.qmp(pause_cmd, **{pause_arg: 'job0'}))
45             pause_wait(vm, 'job0')
46             iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
47             result = vm.qmp('query-jobs')
48             iotests.log(result)
50             old_progress = result['return'][0]['current-progress']
51             total_progress = result['return'][0]['total-progress']
53             iotests.log(vm.qmp(resume_cmd, **{resume_arg: 'job0'}))
54             iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
55             if old_progress < total_progress:
56                 # Wait for the job to advance
57                 while result['return'][0]['current-progress'] == old_progress:
58                     result = vm.qmp('query-jobs')
59                 iotests.log(result)
60             else:
61                 # Already reached the end, so the job cannot advance
62                 # any further; therefore, the query-jobs result can be
63                 # logged immediately
64                 iotests.log(vm.qmp('query-jobs'))
66 def test_job_lifecycle(vm, job, job_args, has_ready=False, is_mirror=False):
67     global img_size
69     iotests.log('')
70     iotests.log('')
71     iotests.log('Starting block job: %s (auto-finalize: %s; auto-dismiss: %s)' %
72                 (job,
73                  job_args.get('auto-finalize', True),
74                  job_args.get('auto-dismiss', True)))
75     iotests.log(vm.qmp(job, job_id='job0', **job_args))
77     # Depending on the storage, the first request may or may not have completed
78     # yet (and the total progress may not have been fully determined yet), so
79     # filter out the progress. Later query-job calls don't need the filtering
80     # because the progress is made deterministic by the block job speed
81     result = vm.qmp('query-jobs')
82     for j in result['return']:
83         j['current-progress'] = 'FILTERED'
84         j['total-progress'] = 'FILTERED'
85     iotests.log(result)
87     # undefined -> created -> running
88     iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
89     iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
91     # Wait for total-progress to stabilize
92     while vm.qmp('query-jobs')['return'][0]['total-progress'] < img_size:
93         pass
95     # RUNNING state:
96     # pause/resume should work, complete/finalize/dismiss should error out
97     iotests.log('')
98     iotests.log('Pause/resume in RUNNING')
99     test_pause_resume(vm)
101     iotests.log(vm.qmp('job-complete', id='job0'))
102     iotests.log(vm.qmp('job-finalize', id='job0'))
103     iotests.log(vm.qmp('job-dismiss', id='job0'))
105     iotests.log(vm.qmp('block-job-complete', device='job0'))
106     iotests.log(vm.qmp('block-job-finalize', id='job0'))
107     iotests.log(vm.qmp('block-job-dismiss', id='job0'))
109     # Let the job complete (or transition to READY if it supports that)
110     iotests.log(vm.qmp('block-job-set-speed', device='job0', speed=0))
111     if has_ready:
112         iotests.log('')
113         iotests.log('Waiting for READY state...')
114         vm.event_wait('BLOCK_JOB_READY')
115         iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
116         iotests.log(vm.qmp('query-jobs'))
118         # READY state:
119         # pause/resume/complete should work, finalize/dismiss should error out
120         iotests.log('')
121         iotests.log('Pause/resume in READY')
122         test_pause_resume(vm)
124         iotests.log(vm.qmp('job-finalize', id='job0'))
125         iotests.log(vm.qmp('job-dismiss', id='job0'))
127         iotests.log(vm.qmp('block-job-finalize', id='job0'))
128         iotests.log(vm.qmp('block-job-dismiss', id='job0'))
130         # Transition to WAITING
131         iotests.log(vm.qmp('job-complete', id='job0'))
133     # Move to WAITING and PENDING state
134     iotests.log('')
135     iotests.log('Waiting for PENDING state...')
136     iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
137     iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
138     if is_mirror:
139         iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
140         iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
142     if not job_args.get('auto-finalize', True):
143         # PENDING state:
144         # finalize should work, pause/complete/dismiss should error out
145         iotests.log(vm.qmp('query-jobs'))
147         iotests.log(vm.qmp('job-pause', id='job0'))
148         iotests.log(vm.qmp('job-complete', id='job0'))
149         iotests.log(vm.qmp('job-dismiss', id='job0'))
151         iotests.log(vm.qmp('block-job-pause', device='job0'))
152         iotests.log(vm.qmp('block-job-complete', device='job0'))
153         iotests.log(vm.qmp('block-job-dismiss', id='job0'))
155         # Transition to CONCLUDED
156         iotests.log(vm.qmp('job-finalize', id='job0'))
159     # Move to CONCLUDED state
160     iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
162     if not job_args.get('auto-dismiss', True):
163         # CONCLUDED state:
164         # dismiss should work, pause/complete/finalize should error out
165         iotests.log(vm.qmp('query-jobs'))
167         iotests.log(vm.qmp('job-pause', id='job0'))
168         iotests.log(vm.qmp('job-complete', id='job0'))
169         iotests.log(vm.qmp('job-finalize', id='job0'))
171         iotests.log(vm.qmp('block-job-pause', device='job0'))
172         iotests.log(vm.qmp('block-job-complete', device='job0'))
173         iotests.log(vm.qmp('block-job-finalize', id='job0'))
175         # Transition to NULL
176         iotests.log(vm.qmp('job-dismiss', id='job0'))
178     # Move to NULL state
179     iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
180     iotests.log(vm.qmp('query-jobs'))
183 with iotests.FilePath('disk.img') as disk_path, \
184      iotests.FilePath('copy.img') as copy_path, \
185      iotests.VM() as vm:
187     iotests.qemu_img_create('-f', iotests.imgfmt, disk_path, str(img_size))
188     iotests.qemu_io('-c', 'write 0 %i' % (img_size),
189                     '-f', iotests.imgfmt, disk_path)
191     iotests.log('Launching VM...')
192     vm.add_blockdev(vm.qmp_to_opts({
193         'driver': iotests.imgfmt,
194         'node-name': 'drive0-node',
195         'file': {
196             'driver': 'file',
197             'filename': disk_path,
198         },
199     }))
200     vm.launch()
202     # In order to keep things deterministic (especially progress in query-job,
203     # but related to this also automatic state transitions like job
204     # completion), but still get pause points often enough to avoid making this
205     # test very slow, it's important to have the right ratio between speed and
206     # buf_size.
207     #
208     # For backup, buf_size is hard-coded to the source image cluster size (64k),
209     # so we'll pick the same for mirror. The slice time, i.e. the granularity
210     # of the rate limiting is 100ms. With a speed of 256k per second, we can
211     # get four pause points per second. This gives us 250ms per iteration,
212     # which should be enough to stay deterministic.
214     test_job_lifecycle(vm, 'drive-mirror', has_ready=True, job_args={
215         'device': 'drive0-node',
216         'target': copy_path,
217         'sync': 'full',
218         'speed': 262144,
219         'buf_size': 65536,
220     })
222     for auto_finalize in [True, False]:
223         for auto_dismiss in [True, False]:
224             test_job_lifecycle(vm, 'drive-backup', is_mirror=True, job_args={
225                 'device': 'drive0-node',
226                 'target': copy_path,
227                 'sync': 'full',
228                 'speed': 262144,
229                 'auto-finalize': auto_finalize,
230                 'auto-dismiss': auto_dismiss,
231             })
233     vm.shutdown()