Commit 428c570512c1d9298b52dc9fc1a541b542a5c117
1 parent
7da03b1d
Stop VM on ENOSPC error. (Gleb Natapov)
This version of the patch adds new option "werror" to -drive flag.
Possible values are:
report - report errors to a guest as IO errors
ignore - continue as if nothing happened
stop - stop VM on any error and retry last command on resume
enospc - stop vm on ENOSPC error and retry last command on resume
all other errors are reported to a guest.
Default is "report" to maintain current behaviour.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6388 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
117 additions
and
10 deletions
hw/ide.c
| @@ -457,6 +457,8 @@ static inline int media_is_cd(IDEState *s) | @@ -457,6 +457,8 @@ static inline int media_is_cd(IDEState *s) | ||
| 457 | #define BM_STATUS_DMAING 0x01 | 457 | #define BM_STATUS_DMAING 0x01 |
| 458 | #define BM_STATUS_ERROR 0x02 | 458 | #define BM_STATUS_ERROR 0x02 |
| 459 | #define BM_STATUS_INT 0x04 | 459 | #define BM_STATUS_INT 0x04 |
| 460 | +#define BM_STATUS_DMA_RETRY 0x08 | ||
| 461 | +#define BM_STATUS_PIO_RETRY 0x10 | ||
| 460 | 462 | ||
| 461 | #define BM_CMD_START 0x01 | 463 | #define BM_CMD_START 0x01 |
| 462 | #define BM_CMD_READ 0x08 | 464 | #define BM_CMD_READ 0x08 |
| @@ -488,6 +490,8 @@ typedef struct BMDMAState { | @@ -488,6 +490,8 @@ typedef struct BMDMAState { | ||
| 488 | IDEState *ide_if; | 490 | IDEState *ide_if; |
| 489 | BlockDriverCompletionFunc *dma_cb; | 491 | BlockDriverCompletionFunc *dma_cb; |
| 490 | BlockDriverAIOCB *aiocb; | 492 | BlockDriverAIOCB *aiocb; |
| 493 | + int64_t sector_num; | ||
| 494 | + uint32_t nsector; | ||
| 491 | } BMDMAState; | 495 | } BMDMAState; |
| 492 | 496 | ||
| 493 | typedef struct PCIIDEState { | 497 | typedef struct PCIIDEState { |
| @@ -498,6 +502,7 @@ typedef struct PCIIDEState { | @@ -498,6 +502,7 @@ typedef struct PCIIDEState { | ||
| 498 | } PCIIDEState; | 502 | } PCIIDEState; |
| 499 | 503 | ||
| 500 | static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb); | 504 | static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb); |
| 505 | +static void ide_dma_restart(IDEState *s); | ||
| 501 | static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret); | 506 | static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret); |
| 502 | 507 | ||
| 503 | static void padstr(char *str, const char *src, int len) | 508 | static void padstr(char *str, const char *src, int len) |
| @@ -865,6 +870,28 @@ static void ide_dma_error(IDEState *s) | @@ -865,6 +870,28 @@ static void ide_dma_error(IDEState *s) | ||
| 865 | ide_set_irq(s); | 870 | ide_set_irq(s); |
| 866 | } | 871 | } |
| 867 | 872 | ||
| 873 | +static int ide_handle_write_error(IDEState *s, int error, int op) | ||
| 874 | +{ | ||
| 875 | + BlockInterfaceErrorAction action = drive_get_onerror(s->bs); | ||
| 876 | + | ||
| 877 | + if (action == BLOCK_ERR_IGNORE) | ||
| 878 | + return 0; | ||
| 879 | + | ||
| 880 | + if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC) | ||
| 881 | + || action == BLOCK_ERR_STOP_ANY) { | ||
| 882 | + s->bmdma->ide_if = s; | ||
| 883 | + s->bmdma->status |= op; | ||
| 884 | + vm_stop(0); | ||
| 885 | + } else { | ||
| 886 | + if (op == BM_STATUS_DMA_RETRY) | ||
| 887 | + ide_dma_error(s); | ||
| 888 | + else | ||
| 889 | + ide_rw_error(s); | ||
| 890 | + } | ||
| 891 | + | ||
| 892 | + return 1; | ||
| 893 | +} | ||
| 894 | + | ||
| 868 | /* return 0 if buffer completed */ | 895 | /* return 0 if buffer completed */ |
| 869 | static int dma_buf_rw(BMDMAState *bm, int is_write) | 896 | static int dma_buf_rw(BMDMAState *bm, int is_write) |
| 870 | { | 897 | { |
| @@ -990,9 +1017,10 @@ static void ide_sector_write(IDEState *s) | @@ -990,9 +1017,10 @@ static void ide_sector_write(IDEState *s) | ||
| 990 | if (n > s->req_nb_sectors) | 1017 | if (n > s->req_nb_sectors) |
| 991 | n = s->req_nb_sectors; | 1018 | n = s->req_nb_sectors; |
| 992 | ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); | 1019 | ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); |
| 1020 | + | ||
| 993 | if (ret != 0) { | 1021 | if (ret != 0) { |
| 994 | - ide_rw_error(s); | ||
| 995 | - return; | 1022 | + if (ide_handle_write_error(s, -ret, BM_STATUS_PIO_RETRY)) |
| 1023 | + return; | ||
| 996 | } | 1024 | } |
| 997 | 1025 | ||
| 998 | s->nsector -= n; | 1026 | s->nsector -= n; |
| @@ -1024,6 +1052,20 @@ static void ide_sector_write(IDEState *s) | @@ -1024,6 +1052,20 @@ static void ide_sector_write(IDEState *s) | ||
| 1024 | } | 1052 | } |
| 1025 | } | 1053 | } |
| 1026 | 1054 | ||
| 1055 | +static void ide_dma_restart_cb(void *opaque, int running) | ||
| 1056 | +{ | ||
| 1057 | + BMDMAState *bm = opaque; | ||
| 1058 | + if (!running) | ||
| 1059 | + return; | ||
| 1060 | + if (bm->status & BM_STATUS_DMA_RETRY) { | ||
| 1061 | + bm->status &= ~BM_STATUS_DMA_RETRY; | ||
| 1062 | + ide_dma_restart(bm->ide_if); | ||
| 1063 | + } else if (bm->status & BM_STATUS_PIO_RETRY) { | ||
| 1064 | + bm->status &= ~BM_STATUS_PIO_RETRY; | ||
| 1065 | + ide_sector_write(bm->ide_if); | ||
| 1066 | + } | ||
| 1067 | +} | ||
| 1068 | + | ||
| 1027 | static void ide_write_dma_cb(void *opaque, int ret) | 1069 | static void ide_write_dma_cb(void *opaque, int ret) |
| 1028 | { | 1070 | { |
| 1029 | BMDMAState *bm = opaque; | 1071 | BMDMAState *bm = opaque; |
| @@ -1032,8 +1074,8 @@ static void ide_write_dma_cb(void *opaque, int ret) | @@ -1032,8 +1074,8 @@ static void ide_write_dma_cb(void *opaque, int ret) | ||
| 1032 | int64_t sector_num; | 1074 | int64_t sector_num; |
| 1033 | 1075 | ||
| 1034 | if (ret < 0) { | 1076 | if (ret < 0) { |
| 1035 | - ide_dma_error(s); | ||
| 1036 | - return; | 1077 | + if (ide_handle_write_error(s, -ret, BM_STATUS_DMA_RETRY)) |
| 1078 | + return; | ||
| 1037 | } | 1079 | } |
| 1038 | 1080 | ||
| 1039 | n = s->io_buffer_size >> 9; | 1081 | n = s->io_buffer_size >> 9; |
| @@ -2849,11 +2891,25 @@ static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb) | @@ -2849,11 +2891,25 @@ static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb) | ||
| 2849 | bm->cur_prd_last = 0; | 2891 | bm->cur_prd_last = 0; |
| 2850 | bm->cur_prd_addr = 0; | 2892 | bm->cur_prd_addr = 0; |
| 2851 | bm->cur_prd_len = 0; | 2893 | bm->cur_prd_len = 0; |
| 2894 | + bm->sector_num = ide_get_sector(s); | ||
| 2895 | + bm->nsector = s->nsector; | ||
| 2852 | if (bm->status & BM_STATUS_DMAING) { | 2896 | if (bm->status & BM_STATUS_DMAING) { |
| 2853 | bm->dma_cb(bm, 0); | 2897 | bm->dma_cb(bm, 0); |
| 2854 | } | 2898 | } |
| 2855 | } | 2899 | } |
| 2856 | 2900 | ||
| 2901 | +static void ide_dma_restart(IDEState *s) | ||
| 2902 | +{ | ||
| 2903 | + BMDMAState *bm = s->bmdma; | ||
| 2904 | + ide_set_sector(s, bm->sector_num); | ||
| 2905 | + s->io_buffer_index = 0; | ||
| 2906 | + s->io_buffer_size = 0; | ||
| 2907 | + s->nsector = bm->nsector; | ||
| 2908 | + bm->cur_addr = bm->addr; | ||
| 2909 | + bm->dma_cb = ide_write_dma_cb; | ||
| 2910 | + ide_dma_start(s, bm->dma_cb); | ||
| 2911 | +} | ||
| 2912 | + | ||
| 2857 | static void ide_dma_cancel(BMDMAState *bm) | 2913 | static void ide_dma_cancel(BMDMAState *bm) |
| 2858 | { | 2914 | { |
| 2859 | if (bm->status & BM_STATUS_DMAING) { | 2915 | if (bm->status & BM_STATUS_DMAING) { |
| @@ -3043,6 +3099,7 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num, | @@ -3043,6 +3099,7 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num, | ||
| 3043 | d->ide_if[2 * i].bmdma = bm; | 3099 | d->ide_if[2 * i].bmdma = bm; |
| 3044 | d->ide_if[2 * i + 1].bmdma = bm; | 3100 | d->ide_if[2 * i + 1].bmdma = bm; |
| 3045 | bm->pci_dev = (PCIIDEState *)pci_dev; | 3101 | bm->pci_dev = (PCIIDEState *)pci_dev; |
| 3102 | + qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm); | ||
| 3046 | 3103 | ||
| 3047 | register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm); | 3104 | register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm); |
| 3048 | 3105 | ||
| @@ -3068,9 +3125,14 @@ static void pci_ide_save(QEMUFile* f, void *opaque) | @@ -3068,9 +3125,14 @@ static void pci_ide_save(QEMUFile* f, void *opaque) | ||
| 3068 | 3125 | ||
| 3069 | for(i = 0; i < 2; i++) { | 3126 | for(i = 0; i < 2; i++) { |
| 3070 | BMDMAState *bm = &d->bmdma[i]; | 3127 | BMDMAState *bm = &d->bmdma[i]; |
| 3128 | + uint8_t ifidx; | ||
| 3071 | qemu_put_8s(f, &bm->cmd); | 3129 | qemu_put_8s(f, &bm->cmd); |
| 3072 | qemu_put_8s(f, &bm->status); | 3130 | qemu_put_8s(f, &bm->status); |
| 3073 | qemu_put_be32s(f, &bm->addr); | 3131 | qemu_put_be32s(f, &bm->addr); |
| 3132 | + qemu_put_sbe64s(f, &bm->sector_num); | ||
| 3133 | + qemu_put_be32s(f, &bm->nsector); | ||
| 3134 | + ifidx = bm->ide_if ? bm->ide_if - d->ide_if : 0; | ||
| 3135 | + qemu_put_8s(f, &ifidx); | ||
| 3074 | /* XXX: if a transfer is pending, we do not save it yet */ | 3136 | /* XXX: if a transfer is pending, we do not save it yet */ |
| 3075 | } | 3137 | } |
| 3076 | 3138 | ||
| @@ -3094,7 +3156,7 @@ static int pci_ide_load(QEMUFile* f, void *opaque, int version_id) | @@ -3094,7 +3156,7 @@ static int pci_ide_load(QEMUFile* f, void *opaque, int version_id) | ||
| 3094 | PCIIDEState *d = opaque; | 3156 | PCIIDEState *d = opaque; |
| 3095 | int ret, i; | 3157 | int ret, i; |
| 3096 | 3158 | ||
| 3097 | - if (version_id != 1) | 3159 | + if (version_id != 2) |
| 3098 | return -EINVAL; | 3160 | return -EINVAL; |
| 3099 | ret = pci_device_load(&d->dev, f); | 3161 | ret = pci_device_load(&d->dev, f); |
| 3100 | if (ret < 0) | 3162 | if (ret < 0) |
| @@ -3102,9 +3164,14 @@ static int pci_ide_load(QEMUFile* f, void *opaque, int version_id) | @@ -3102,9 +3164,14 @@ static int pci_ide_load(QEMUFile* f, void *opaque, int version_id) | ||
| 3102 | 3164 | ||
| 3103 | for(i = 0; i < 2; i++) { | 3165 | for(i = 0; i < 2; i++) { |
| 3104 | BMDMAState *bm = &d->bmdma[i]; | 3166 | BMDMAState *bm = &d->bmdma[i]; |
| 3167 | + uint8_t ifidx; | ||
| 3105 | qemu_get_8s(f, &bm->cmd); | 3168 | qemu_get_8s(f, &bm->cmd); |
| 3106 | qemu_get_8s(f, &bm->status); | 3169 | qemu_get_8s(f, &bm->status); |
| 3107 | qemu_get_be32s(f, &bm->addr); | 3170 | qemu_get_be32s(f, &bm->addr); |
| 3171 | + qemu_get_sbe64s(f, &bm->sector_num); | ||
| 3172 | + qemu_get_be32s(f, &bm->nsector); | ||
| 3173 | + qemu_get_8s(f, &ifidx); | ||
| 3174 | + bm->ide_if = &d->ide_if[ifidx]; | ||
| 3108 | /* XXX: if a transfer is pending, we do not save it yet */ | 3175 | /* XXX: if a transfer is pending, we do not save it yet */ |
| 3109 | } | 3176 | } |
| 3110 | 3177 | ||
| @@ -3212,7 +3279,7 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, | @@ -3212,7 +3279,7 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, | ||
| 3212 | ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], irq[0]); | 3279 | ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], irq[0]); |
| 3213 | ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], irq[1]); | 3280 | ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], irq[1]); |
| 3214 | 3281 | ||
| 3215 | - register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d); | 3282 | + register_savevm("ide", 0, 2, pci_ide_save, pci_ide_load, d); |
| 3216 | qemu_register_reset(cmd646_reset, d); | 3283 | qemu_register_reset(cmd646_reset, d); |
| 3217 | cmd646_reset(d); | 3284 | cmd646_reset(d); |
| 3218 | } | 3285 | } |
| @@ -3269,7 +3336,7 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, | @@ -3269,7 +3336,7 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, | ||
| 3269 | ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); | 3336 | ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); |
| 3270 | ide_init_ioport(&d->ide_if[2], 0x170, 0x376); | 3337 | ide_init_ioport(&d->ide_if[2], 0x170, 0x376); |
| 3271 | 3338 | ||
| 3272 | - register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d); | 3339 | + register_savevm("ide", 0, 2, pci_ide_save, pci_ide_load, d); |
| 3273 | } | 3340 | } |
| 3274 | 3341 | ||
| 3275 | /* hd_table must contain 4 block drivers */ | 3342 | /* hd_table must contain 4 block drivers */ |
| @@ -3308,7 +3375,7 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, | @@ -3308,7 +3375,7 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, | ||
| 3308 | ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); | 3375 | ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); |
| 3309 | ide_init_ioport(&d->ide_if[2], 0x170, 0x376); | 3376 | ide_init_ioport(&d->ide_if[2], 0x170, 0x376); |
| 3310 | 3377 | ||
| 3311 | - register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d); | 3378 | + register_savevm("ide", 0, 2, pci_ide_save, pci_ide_load, d); |
| 3312 | } | 3379 | } |
| 3313 | 3380 | ||
| 3314 | /***********************************************************/ | 3381 | /***********************************************************/ |
sysemu.h
| @@ -128,11 +128,17 @@ typedef enum { | @@ -128,11 +128,17 @@ typedef enum { | ||
| 128 | IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO | 128 | IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO |
| 129 | } BlockInterfaceType; | 129 | } BlockInterfaceType; |
| 130 | 130 | ||
| 131 | +typedef enum { | ||
| 132 | + BLOCK_ERR_REPORT, BLOCK_ERR_IGNORE, BLOCK_ERR_STOP_ENOSPC, | ||
| 133 | + BLOCK_ERR_STOP_ANY | ||
| 134 | +} BlockInterfaceErrorAction; | ||
| 135 | + | ||
| 131 | typedef struct DriveInfo { | 136 | typedef struct DriveInfo { |
| 132 | BlockDriverState *bdrv; | 137 | BlockDriverState *bdrv; |
| 133 | BlockInterfaceType type; | 138 | BlockInterfaceType type; |
| 134 | int bus; | 139 | int bus; |
| 135 | int unit; | 140 | int unit; |
| 141 | + BlockInterfaceErrorAction onerror; | ||
| 136 | char serial[21]; | 142 | char serial[21]; |
| 137 | } DriveInfo; | 143 | } DriveInfo; |
| 138 | 144 | ||
| @@ -146,6 +152,7 @@ extern DriveInfo drives_table[MAX_DRIVES+1]; | @@ -146,6 +152,7 @@ extern DriveInfo drives_table[MAX_DRIVES+1]; | ||
| 146 | extern int drive_get_index(BlockInterfaceType type, int bus, int unit); | 152 | extern int drive_get_index(BlockInterfaceType type, int bus, int unit); |
| 147 | extern int drive_get_max_bus(BlockInterfaceType type); | 153 | extern int drive_get_max_bus(BlockInterfaceType type); |
| 148 | extern const char *drive_get_serial(BlockDriverState *bdrv); | 154 | extern const char *drive_get_serial(BlockDriverState *bdrv); |
| 155 | +extern BlockInterfaceErrorAction drive_get_onerror(BlockDriverState *bdrv); | ||
| 149 | 156 | ||
| 150 | /* serial ports */ | 157 | /* serial ports */ |
| 151 | 158 |
vl.c
| @@ -2200,6 +2200,17 @@ const char *drive_get_serial(BlockDriverState *bdrv) | @@ -2200,6 +2200,17 @@ const char *drive_get_serial(BlockDriverState *bdrv) | ||
| 2200 | return "\0"; | 2200 | return "\0"; |
| 2201 | } | 2201 | } |
| 2202 | 2202 | ||
| 2203 | +BlockInterfaceErrorAction drive_get_onerror(BlockDriverState *bdrv) | ||
| 2204 | +{ | ||
| 2205 | + int index; | ||
| 2206 | + | ||
| 2207 | + for (index = 0; index < nb_drives; index++) | ||
| 2208 | + if (drives_table[index].bdrv == bdrv) | ||
| 2209 | + return drives_table[index].onerror; | ||
| 2210 | + | ||
| 2211 | + return BLOCK_ERR_REPORT; | ||
| 2212 | +} | ||
| 2213 | + | ||
| 2203 | static void bdrv_format_print(void *opaque, const char *name) | 2214 | static void bdrv_format_print(void *opaque, const char *name) |
| 2204 | { | 2215 | { |
| 2205 | fprintf(stderr, " %s", name); | 2216 | fprintf(stderr, " %s", name); |
| @@ -2222,12 +2233,13 @@ static int drive_init(struct drive_opt *arg, int snapshot, | @@ -2222,12 +2233,13 @@ static int drive_init(struct drive_opt *arg, int snapshot, | ||
| 2222 | int max_devs; | 2233 | int max_devs; |
| 2223 | int index; | 2234 | int index; |
| 2224 | int cache; | 2235 | int cache; |
| 2225 | - int bdrv_flags; | 2236 | + int bdrv_flags, onerror; |
| 2226 | char *str = arg->opt; | 2237 | char *str = arg->opt; |
| 2227 | static const char * const params[] = { "bus", "unit", "if", "index", | 2238 | static const char * const params[] = { "bus", "unit", "if", "index", |
| 2228 | "cyls", "heads", "secs", "trans", | 2239 | "cyls", "heads", "secs", "trans", |
| 2229 | "media", "snapshot", "file", | 2240 | "media", "snapshot", "file", |
| 2230 | - "cache", "format", "serial", NULL }; | 2241 | + "cache", "format", "serial", "werror", |
| 2242 | + NULL }; | ||
| 2231 | 2243 | ||
| 2232 | if (check_params(buf, sizeof(buf), params, str) < 0) { | 2244 | if (check_params(buf, sizeof(buf), params, str) < 0) { |
| 2233 | fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n", | 2245 | fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n", |
| @@ -2417,6 +2429,26 @@ static int drive_init(struct drive_opt *arg, int snapshot, | @@ -2417,6 +2429,26 @@ static int drive_init(struct drive_opt *arg, int snapshot, | ||
| 2417 | if (!get_param_value(serial, sizeof(serial), "serial", str)) | 2429 | if (!get_param_value(serial, sizeof(serial), "serial", str)) |
| 2418 | memset(serial, 0, sizeof(serial)); | 2430 | memset(serial, 0, sizeof(serial)); |
| 2419 | 2431 | ||
| 2432 | + onerror = BLOCK_ERR_REPORT; | ||
| 2433 | + if (get_param_value(buf, sizeof(serial), "werror", str)) { | ||
| 2434 | + if (type != IF_IDE) { | ||
| 2435 | + fprintf(stderr, "werror is supported only by IDE\n"); | ||
| 2436 | + return -1; | ||
| 2437 | + } | ||
| 2438 | + if (!strcmp(buf, "ignore")) | ||
| 2439 | + onerror = BLOCK_ERR_IGNORE; | ||
| 2440 | + else if (!strcmp(buf, "enospc")) | ||
| 2441 | + onerror = BLOCK_ERR_STOP_ENOSPC; | ||
| 2442 | + else if (!strcmp(buf, "stop")) | ||
| 2443 | + onerror = BLOCK_ERR_STOP_ANY; | ||
| 2444 | + else if (!strcmp(buf, "report")) | ||
| 2445 | + onerror = BLOCK_ERR_REPORT; | ||
| 2446 | + else { | ||
| 2447 | + fprintf(stderr, "qemu: '%s' invalid write error action\n", buf); | ||
| 2448 | + return -1; | ||
| 2449 | + } | ||
| 2450 | + } | ||
| 2451 | + | ||
| 2420 | /* compute bus and unit according index */ | 2452 | /* compute bus and unit according index */ |
| 2421 | 2453 | ||
| 2422 | if (index != -1) { | 2454 | if (index != -1) { |
| @@ -2480,6 +2512,7 @@ static int drive_init(struct drive_opt *arg, int snapshot, | @@ -2480,6 +2512,7 @@ static int drive_init(struct drive_opt *arg, int snapshot, | ||
| 2480 | drives_table[nb_drives].type = type; | 2512 | drives_table[nb_drives].type = type; |
| 2481 | drives_table[nb_drives].bus = bus_id; | 2513 | drives_table[nb_drives].bus = bus_id; |
| 2482 | drives_table[nb_drives].unit = unit_id; | 2514 | drives_table[nb_drives].unit = unit_id; |
| 2515 | + drives_table[nb_drives].onerror = onerror; | ||
| 2483 | strncpy(drives_table[nb_drives].serial, serial, sizeof(serial)); | 2516 | strncpy(drives_table[nb_drives].serial, serial, sizeof(serial)); |
| 2484 | nb_drives++; | 2517 | nb_drives++; |
| 2485 | 2518 |