Commit 428c570512c1d9298b52dc9fc1a541b542a5c117

Authored by aliguori
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  
... ...
... ... @@ -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  
... ...