Revision 1d809098
b/block/stream.c | ||
---|---|---|
31 | 31 |
BlockJob common; |
32 | 32 |
RateLimit limit; |
33 | 33 |
BlockDriverState *base; |
34 |
BlockdevOnError on_error; |
|
34 | 35 |
char backing_file_id[1024]; |
35 | 36 |
} StreamBlockJob; |
36 | 37 |
|
... | ... | |
78 | 79 |
BlockDriverState *bs = s->common.bs; |
79 | 80 |
BlockDriverState *base = s->base; |
80 | 81 |
int64_t sector_num, end; |
82 |
int error = 0; |
|
81 | 83 |
int ret = 0; |
82 | 84 |
int n = 0; |
83 | 85 |
void *buf; |
... | ... | |
142 | 144 |
ret = stream_populate(bs, sector_num, n, buf); |
143 | 145 |
} |
144 | 146 |
if (ret < 0) { |
145 |
break; |
|
147 |
BlockErrorAction action = |
|
148 |
block_job_error_action(&s->common, s->common.bs, s->on_error, |
|
149 |
true, -ret); |
|
150 |
if (action == BDRV_ACTION_STOP) { |
|
151 |
n = 0; |
|
152 |
continue; |
|
153 |
} |
|
154 |
if (error == 0) { |
|
155 |
error = ret; |
|
156 |
} |
|
157 |
if (action == BDRV_ACTION_REPORT) { |
|
158 |
break; |
|
159 |
} |
|
146 | 160 |
} |
147 | 161 |
ret = 0; |
148 | 162 |
|
... | ... | |
154 | 168 |
bdrv_disable_copy_on_read(bs); |
155 | 169 |
} |
156 | 170 |
|
171 |
/* Do not remove the backing file if an error was there but ignored. */ |
|
172 |
ret = error; |
|
173 |
|
|
157 | 174 |
if (!block_job_is_cancelled(&s->common) && sector_num == end && ret == 0) { |
158 | 175 |
const char *base_id = NULL, *base_fmt = NULL; |
159 | 176 |
if (base) { |
... | ... | |
189 | 206 |
|
190 | 207 |
void stream_start(BlockDriverState *bs, BlockDriverState *base, |
191 | 208 |
const char *base_id, int64_t speed, |
209 |
BlockdevOnError on_error, |
|
192 | 210 |
BlockDriverCompletionFunc *cb, |
193 | 211 |
void *opaque, Error **errp) |
194 | 212 |
{ |
195 | 213 |
StreamBlockJob *s; |
196 | 214 |
|
215 |
if ((on_error == BLOCKDEV_ON_ERROR_STOP || |
|
216 |
on_error == BLOCKDEV_ON_ERROR_ENOSPC) && |
|
217 |
!bdrv_iostatus_is_enabled(bs)) { |
|
218 |
error_set(errp, QERR_INVALID_PARAMETER, "on-error"); |
|
219 |
return; |
|
220 |
} |
|
221 |
|
|
197 | 222 |
s = block_job_create(&stream_job_type, bs, speed, cb, opaque, errp); |
198 | 223 |
if (!s) { |
199 | 224 |
return; |
... | ... | |
204 | 229 |
pstrcpy(s->backing_file_id, sizeof(s->backing_file_id), base_id); |
205 | 230 |
} |
206 | 231 |
|
232 |
s->on_error = on_error; |
|
207 | 233 |
s->common.co = qemu_coroutine_create(stream_run); |
208 | 234 |
trace_stream_start(bs, base, s, s->common.co, opaque); |
209 | 235 |
qemu_coroutine_enter(s->common.co, s); |
b/block_int.h | ||
---|---|---|
299 | 299 |
* @base_id: The file name that will be written to @bs as the new |
300 | 300 |
* backing file if the job completes. Ignored if @base is %NULL. |
301 | 301 |
* @speed: The maximum speed, in bytes per second, or 0 for unlimited. |
302 |
* @on_error: The action to take upon error. |
|
302 | 303 |
* @cb: Completion function for the job. |
303 | 304 |
* @opaque: Opaque pointer value passed to @cb. |
304 | 305 |
* @errp: Error object. |
... | ... | |
310 | 311 |
* @base_id in the written image and to @base in the live BlockDriverState. |
311 | 312 |
*/ |
312 | 313 |
void stream_start(BlockDriverState *bs, BlockDriverState *base, |
313 |
const char *base_id, int64_t speed, |
|
314 |
const char *base_id, int64_t speed, BlockdevOnError on_error,
|
|
314 | 315 |
BlockDriverCompletionFunc *cb, |
315 | 316 |
void *opaque, Error **errp); |
316 | 317 |
|
b/blockdev.c | ||
---|---|---|
1096 | 1096 |
} |
1097 | 1097 |
|
1098 | 1098 |
void qmp_block_stream(const char *device, bool has_base, |
1099 |
const char *base, bool has_speed, |
|
1100 |
int64_t speed, Error **errp) |
|
1099 |
const char *base, bool has_speed, int64_t speed, |
|
1100 |
bool has_on_error, BlockdevOnError on_error, |
|
1101 |
Error **errp) |
|
1101 | 1102 |
{ |
1102 | 1103 |
BlockDriverState *bs; |
1103 | 1104 |
BlockDriverState *base_bs = NULL; |
1104 | 1105 |
Error *local_err = NULL; |
1105 | 1106 |
|
1107 |
if (!has_on_error) { |
|
1108 |
on_error = BLOCKDEV_ON_ERROR_REPORT; |
|
1109 |
} |
|
1110 |
|
|
1106 | 1111 |
bs = bdrv_find(device); |
1107 | 1112 |
if (!bs) { |
1108 | 1113 |
error_set(errp, QERR_DEVICE_NOT_FOUND, device); |
... | ... | |
1118 | 1123 |
} |
1119 | 1124 |
|
1120 | 1125 |
stream_start(bs, base_bs, base, has_speed ? speed : 0, |
1121 |
block_job_cb, bs, &local_err); |
|
1126 |
on_error, block_job_cb, bs, &local_err);
|
|
1122 | 1127 |
if (error_is_set(&local_err)) { |
1123 | 1128 |
error_propagate(errp, local_err); |
1124 | 1129 |
return; |
b/hmp.c | ||
---|---|---|
930 | 930 |
int64_t speed = qdict_get_try_int(qdict, "speed", 0); |
931 | 931 |
|
932 | 932 |
qmp_block_stream(device, base != NULL, base, |
933 |
qdict_haskey(qdict, "speed"), speed, &error); |
|
933 |
qdict_haskey(qdict, "speed"), speed, |
|
934 |
BLOCKDEV_ON_ERROR_REPORT, true, &error); |
|
934 | 935 |
|
935 | 936 |
hmp_handle_error(mon, &error); |
936 | 937 |
} |
b/qapi-schema.json | ||
---|---|---|
1869 | 1869 |
# |
1870 | 1870 |
# @speed: #optional the maximum speed, in bytes per second |
1871 | 1871 |
# |
1872 |
# @on-error: #optional the action to take on an error (default report). |
|
1873 |
# 'stop' and 'enospc' can only be used if the block device |
|
1874 |
# supports io-status (see BlockInfo). Since 1.3. |
|
1875 |
# |
|
1872 | 1876 |
# Returns: Nothing on success |
1873 | 1877 |
# If @device does not exist, DeviceNotFound |
1874 | 1878 |
# |
1875 | 1879 |
# Since: 1.1 |
1876 | 1880 |
## |
1877 |
{ 'command': 'block-stream', 'data': { 'device': 'str', '*base': 'str', |
|
1878 |
'*speed': 'int' } } |
|
1881 |
{ 'command': 'block-stream', |
|
1882 |
'data': { 'device': 'str', '*base': 'str', '*speed': 'int', |
|
1883 |
'*on-error': 'BlockdevOnError' } } |
|
1879 | 1884 |
|
1880 | 1885 |
## |
1881 | 1886 |
# @block-job-set-speed: |
b/qmp-commands.hx | ||
---|---|---|
787 | 787 |
|
788 | 788 |
{ |
789 | 789 |
.name = "block-stream", |
790 |
.args_type = "device:B,base:s?,speed:o?", |
|
790 |
.args_type = "device:B,base:s?,speed:o?,on-error:s?",
|
|
791 | 791 |
.mhandler.cmd_new = qmp_marshal_input_block_stream, |
792 | 792 |
}, |
793 | 793 |
|
Also available in: Unified diff