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 | 457 | #define BM_STATUS_DMAING 0x01 |
458 | 458 | #define BM_STATUS_ERROR 0x02 |
459 | 459 | #define BM_STATUS_INT 0x04 |
460 | +#define BM_STATUS_DMA_RETRY 0x08 | |
461 | +#define BM_STATUS_PIO_RETRY 0x10 | |
460 | 462 | |
461 | 463 | #define BM_CMD_START 0x01 |
462 | 464 | #define BM_CMD_READ 0x08 |
... | ... | @@ -488,6 +490,8 @@ typedef struct BMDMAState { |
488 | 490 | IDEState *ide_if; |
489 | 491 | BlockDriverCompletionFunc *dma_cb; |
490 | 492 | BlockDriverAIOCB *aiocb; |
493 | + int64_t sector_num; | |
494 | + uint32_t nsector; | |
491 | 495 | } BMDMAState; |
492 | 496 | |
493 | 497 | typedef struct PCIIDEState { |
... | ... | @@ -498,6 +502,7 @@ typedef struct PCIIDEState { |
498 | 502 | } PCIIDEState; |
499 | 503 | |
500 | 504 | static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb); |
505 | +static void ide_dma_restart(IDEState *s); | |
501 | 506 | static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret); |
502 | 507 | |
503 | 508 | static void padstr(char *str, const char *src, int len) |
... | ... | @@ -865,6 +870,28 @@ static void ide_dma_error(IDEState *s) |
865 | 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 | 895 | /* return 0 if buffer completed */ |
869 | 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 | 1017 | if (n > s->req_nb_sectors) |
991 | 1018 | n = s->req_nb_sectors; |
992 | 1019 | ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); |
1020 | + | |
993 | 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 | 1026 | s->nsector -= n; |
... | ... | @@ -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 | 1069 | static void ide_write_dma_cb(void *opaque, int ret) |
1028 | 1070 | { |
1029 | 1071 | BMDMAState *bm = opaque; |
... | ... | @@ -1032,8 +1074,8 @@ static void ide_write_dma_cb(void *opaque, int ret) |
1032 | 1074 | int64_t sector_num; |
1033 | 1075 | |
1034 | 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 | 1081 | n = s->io_buffer_size >> 9; |
... | ... | @@ -2849,11 +2891,25 @@ static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb) |
2849 | 2891 | bm->cur_prd_last = 0; |
2850 | 2892 | bm->cur_prd_addr = 0; |
2851 | 2893 | bm->cur_prd_len = 0; |
2894 | + bm->sector_num = ide_get_sector(s); | |
2895 | + bm->nsector = s->nsector; | |
2852 | 2896 | if (bm->status & BM_STATUS_DMAING) { |
2853 | 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 | 2913 | static void ide_dma_cancel(BMDMAState *bm) |
2858 | 2914 | { |
2859 | 2915 | if (bm->status & BM_STATUS_DMAING) { |
... | ... | @@ -3043,6 +3099,7 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num, |
3043 | 3099 | d->ide_if[2 * i].bmdma = bm; |
3044 | 3100 | d->ide_if[2 * i + 1].bmdma = bm; |
3045 | 3101 | bm->pci_dev = (PCIIDEState *)pci_dev; |
3102 | + qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm); | |
3046 | 3103 | |
3047 | 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 | 3125 | |
3069 | 3126 | for(i = 0; i < 2; i++) { |
3070 | 3127 | BMDMAState *bm = &d->bmdma[i]; |
3128 | + uint8_t ifidx; | |
3071 | 3129 | qemu_put_8s(f, &bm->cmd); |
3072 | 3130 | qemu_put_8s(f, &bm->status); |
3073 | 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 | 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 | 3156 | PCIIDEState *d = opaque; |
3095 | 3157 | int ret, i; |
3096 | 3158 | |
3097 | - if (version_id != 1) | |
3159 | + if (version_id != 2) | |
3098 | 3160 | return -EINVAL; |
3099 | 3161 | ret = pci_device_load(&d->dev, f); |
3100 | 3162 | if (ret < 0) |
... | ... | @@ -3102,9 +3164,14 @@ static int pci_ide_load(QEMUFile* f, void *opaque, int version_id) |
3102 | 3164 | |
3103 | 3165 | for(i = 0; i < 2; i++) { |
3104 | 3166 | BMDMAState *bm = &d->bmdma[i]; |
3167 | + uint8_t ifidx; | |
3105 | 3168 | qemu_get_8s(f, &bm->cmd); |
3106 | 3169 | qemu_get_8s(f, &bm->status); |
3107 | 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 | 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 | 3279 | ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], irq[0]); |
3213 | 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 | 3283 | qemu_register_reset(cmd646_reset, d); |
3217 | 3284 | cmd646_reset(d); |
3218 | 3285 | } |
... | ... | @@ -3269,7 +3336,7 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, |
3269 | 3336 | ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); |
3270 | 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 | 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 | 3375 | ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); |
3309 | 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 | 128 | IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO |
129 | 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 | 136 | typedef struct DriveInfo { |
132 | 137 | BlockDriverState *bdrv; |
133 | 138 | BlockInterfaceType type; |
134 | 139 | int bus; |
135 | 140 | int unit; |
141 | + BlockInterfaceErrorAction onerror; | |
136 | 142 | char serial[21]; |
137 | 143 | } DriveInfo; |
138 | 144 | |
... | ... | @@ -146,6 +152,7 @@ extern DriveInfo drives_table[MAX_DRIVES+1]; |
146 | 152 | extern int drive_get_index(BlockInterfaceType type, int bus, int unit); |
147 | 153 | extern int drive_get_max_bus(BlockInterfaceType type); |
148 | 154 | extern const char *drive_get_serial(BlockDriverState *bdrv); |
155 | +extern BlockInterfaceErrorAction drive_get_onerror(BlockDriverState *bdrv); | |
149 | 156 | |
150 | 157 | /* serial ports */ |
151 | 158 | ... | ... |
vl.c
... | ... | @@ -2200,6 +2200,17 @@ const char *drive_get_serial(BlockDriverState *bdrv) |
2200 | 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 | 2214 | static void bdrv_format_print(void *opaque, const char *name) |
2204 | 2215 | { |
2205 | 2216 | fprintf(stderr, " %s", name); |
... | ... | @@ -2222,12 +2233,13 @@ static int drive_init(struct drive_opt *arg, int snapshot, |
2222 | 2233 | int max_devs; |
2223 | 2234 | int index; |
2224 | 2235 | int cache; |
2225 | - int bdrv_flags; | |
2236 | + int bdrv_flags, onerror; | |
2226 | 2237 | char *str = arg->opt; |
2227 | 2238 | static const char * const params[] = { "bus", "unit", "if", "index", |
2228 | 2239 | "cyls", "heads", "secs", "trans", |
2229 | 2240 | "media", "snapshot", "file", |
2230 | - "cache", "format", "serial", NULL }; | |
2241 | + "cache", "format", "serial", "werror", | |
2242 | + NULL }; | |
2231 | 2243 | |
2232 | 2244 | if (check_params(buf, sizeof(buf), params, str) < 0) { |
2233 | 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 | 2429 | if (!get_param_value(serial, sizeof(serial), "serial", str)) |
2418 | 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 | 2452 | /* compute bus and unit according index */ |
2421 | 2453 | |
2422 | 2454 | if (index != -1) { |
... | ... | @@ -2480,6 +2512,7 @@ static int drive_init(struct drive_opt *arg, int snapshot, |
2480 | 2512 | drives_table[nb_drives].type = type; |
2481 | 2513 | drives_table[nb_drives].bus = bus_id; |
2482 | 2514 | drives_table[nb_drives].unit = unit_id; |
2515 | + drives_table[nb_drives].onerror = onerror; | |
2483 | 2516 | strncpy(drives_table[nb_drives].serial, serial, sizeof(serial)); |
2484 | 2517 | nb_drives++; |
2485 | 2518 | ... | ... |