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