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 | ... | ... |