From 8d780f43921feb7fd8d0b58f779a22d1265f2378 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 17 Nov 2015 17:05:49 +0100 Subject: error: Document how to accumulate multiple errors Suggested-by: Eric Blake Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1447776349-2344-1-git-send-email-armbru@redhat.com> --- include/qapi/error.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'include') diff --git a/include/qapi/error.h b/include/qapi/error.h index 6285cf50d1..1480f59ec5 100644 --- a/include/qapi/error.h +++ b/include/qapi/error.h @@ -76,6 +76,23 @@ * But when all you do with the error is pass it on, please use * foo(arg, errp); * for readability. + * + * Receive and accumulate multiple errors (first one wins): + * Error *err = NULL, *local_err = NULL; + * foo(arg, &err); + * bar(arg, &local_err); + * error_propagate(&err, local_err); + * if (err) { + * handle the error... + * } + * + * Do *not* "optimize" this to + * foo(arg, &err); + * bar(arg, &err); // WRONG! + * if (err) { + * handle the error... + * } + * because this may pass a non-null err to bar(). */ #ifndef ERROR_H -- cgit v1.2.3-55-g7522 From 6231a6da9f40c3a33589402c9c57557e3a4f05ad Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 10 Dec 2015 17:29:15 +0100 Subject: hw: Inline the qdev_prop_set_drive_nofail() wrapper Signed-off-by: Markus Armbruster Message-Id: <1449764955-10741-3-git-send-email-armbru@redhat.com> Reviewed-by: Peter Maydell --- hw/arm/nseries.c | 4 ++-- hw/block/fdc.c | 15 ++++++++++----- hw/block/nand.c | 2 +- hw/core/qdev-properties-system.c | 6 ------ hw/ide/qdev.c | 3 ++- hw/isa/pc87312.c | 8 ++++---- hw/ppc/spapr.c | 3 ++- include/hw/qdev-properties.h | 2 -- 8 files changed, 21 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index 2a8835ec01..57170aea8b 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -172,8 +172,8 @@ static void n8x0_nand_setup(struct n800_s *s) qdev_prop_set_int32(s->nand, "shift", 1); dinfo = drive_get(IF_MTD, 0, 0); if (dinfo) { - qdev_prop_set_drive_nofail(s->nand, "drive", - blk_by_legacy_dinfo(dinfo)); + qdev_prop_set_drive(s->nand, "drive", blk_by_legacy_dinfo(dinfo), + &error_fatal); } qdev_init_nofail(s->nand); sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0, diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 4292eced32..858f5f7ce7 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2245,10 +2245,12 @@ ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds) dev = DEVICE(isadev); if (fds[0]) { - qdev_prop_set_drive_nofail(dev, "driveA", blk_by_legacy_dinfo(fds[0])); + qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fds[0]), + &error_fatal); } if (fds[1]) { - qdev_prop_set_drive_nofail(dev, "driveB", blk_by_legacy_dinfo(fds[1])); + qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fds[1]), + &error_fatal); } qdev_init_nofail(dev); @@ -2268,10 +2270,12 @@ void fdctrl_init_sysbus(qemu_irq irq, int dma_chann, fdctrl = &sys->state; fdctrl->dma_chann = dma_chann; /* FIXME */ if (fds[0]) { - qdev_prop_set_drive_nofail(dev, "driveA", blk_by_legacy_dinfo(fds[0])); + qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fds[0]), + &error_fatal); } if (fds[1]) { - qdev_prop_set_drive_nofail(dev, "driveB", blk_by_legacy_dinfo(fds[1])); + qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fds[1]), + &error_fatal); } qdev_init_nofail(dev); sbd = SYS_BUS_DEVICE(dev); @@ -2287,7 +2291,8 @@ void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base, dev = qdev_create(NULL, "SUNW,fdtwo"); if (fds[0]) { - qdev_prop_set_drive_nofail(dev, "drive", blk_by_legacy_dinfo(fds[0])); + qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(fds[0]), + &error_fatal); } qdev_init_nofail(dev); sys = SYSBUS_FDC(dev); diff --git a/hw/block/nand.c b/hw/block/nand.c index f0e34139fe..478e1a6b3f 100644 --- a/hw/block/nand.c +++ b/hw/block/nand.c @@ -635,7 +635,7 @@ DeviceState *nand_init(BlockBackend *blk, int manf_id, int chip_id) qdev_prop_set_uint8(dev, "manufacturer_id", manf_id); qdev_prop_set_uint8(dev, "chip_id", chip_id); if (blk) { - qdev_prop_set_drive_nofail(dev, "drive", blk); + qdev_prop_set_drive(dev, "drive", blk, &error_fatal); } qdev_init_nofail(dev); diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index d515e99f98..1589abaf60 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -364,12 +364,6 @@ void qdev_prop_set_drive(DeviceState *dev, const char *name, name, errp); } -void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, - BlockBackend *value) -{ - qdev_prop_set_drive(dev, name, value, &error_fatal); -} - void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value) { diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 788b36133c..1f831098c7 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -118,7 +118,8 @@ IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive) dev = qdev_create(&bus->qbus, drive->media_cd ? "ide-cd" : "ide-hd"); qdev_prop_set_uint32(dev, "unit", unit); - qdev_prop_set_drive_nofail(dev, "drive", blk_by_legacy_dinfo(drive)); + qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(drive), + &error_fatal); qdev_init_nofail(dev); return DO_UPCAST(IDEDevice, qdev, dev); } diff --git a/hw/isa/pc87312.c b/hw/isa/pc87312.c index 3b1fcec537..38030655f4 100644 --- a/hw/isa/pc87312.c +++ b/hw/isa/pc87312.c @@ -324,14 +324,14 @@ static void pc87312_realize(DeviceState *dev, Error **errp) /* FIXME use a qdev drive property instead of drive_get() */ drive = drive_get(IF_FLOPPY, 0, 0); if (drive != NULL) { - qdev_prop_set_drive_nofail(d, "driveA", - blk_by_legacy_dinfo(drive)); + qdev_prop_set_drive(d, "driveA", blk_by_legacy_dinfo(drive), + &error_fatal); } /* FIXME use a qdev drive property instead of drive_get() */ drive = drive_get(IF_FLOPPY, 0, 1); if (drive != NULL) { - qdev_prop_set_drive_nofail(d, "driveB", - blk_by_legacy_dinfo(drive)); + qdev_prop_set_drive(d, "driveB", blk_by_legacy_dinfo(drive), + &error_fatal); } qdev_init_nofail(d); s->fdc.dev = isa; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 414e0f9b7a..0ca01767e5 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1216,7 +1216,8 @@ static void spapr_create_nvram(sPAPRMachineState *spapr) DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0); if (dinfo) { - qdev_prop_set_drive_nofail(dev, "drive", blk_by_legacy_dinfo(dinfo)); + qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo), + &error_fatal); } qdev_init_nofail(dev); diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index 77538a8ca2..254afd8859 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -180,8 +180,6 @@ void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *valu void qdev_prop_set_netdev(DeviceState *dev, const char *name, NetClientState *value); void qdev_prop_set_drive(DeviceState *dev, const char *name, BlockBackend *value, Error **errp); -void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, - BlockBackend *value); void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value); void qdev_prop_set_enum(DeviceState *dev, const char *name, int value); /* FIXME: Remove opaque pointer properties. */ -- cgit v1.2.3-55-g7522 From d10e54329bbfe6bfacf75eb33caead39eef9f3c8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 17 Dec 2015 17:35:18 +0100 Subject: isa: Clean up error handling around isa_bus_new() We can have at most one ISA bus. If you try to create another one, isa_bus_new() complains to stderr and returns null. isa_bus_new() is called in two contexts, machine's init() and device's realize() methods. Since complaining to stderr is not proper in the latter context, convert isa_bus_new() to Error. Machine's init(): * mips_jazz_init(), called from the init() methods of machines "magnum" and "pica" * mips_r4k_init(), the init() method of machine "mips" * pc_init1() called from the init() methods of non-q35 PC machines * typhoon_init(), called from clipper_init(), the init() method of machine "clipper" These callers always create the first ISA bus, hence isa_bus_new() can't fail. Simply pass &error_abort. Device's realize(): * i82378_realize(), of PCI device "i82378" * ich9_lpc_realize(), of PCI device "ICH9-LPC" * pci_ebus_realize(), of PCI device "ebus" * piix3_realize(), of PCI device "pci-piix3", abstract parent of "PIIX3" and "PIIX3-xen" * piix4_realize(), of PCI device "PIIX4" * vt82c686b_realize(), of PCI device "VT82C686B" Propagate the error. Note that these devices are typically created only by machine init() methods with qdev_init_nofail() or similar. If we screwed up and created an ISA bus before that call, we now give up right away. Before, we'd hobble on, and typically die in isa_bus_irqs(). Similar if someone finds a way to hot-plug one of these critters. Cc: Richard Henderson Cc: "Michael S. Tsirkin" Cc: "Hervé Poussineau" Cc: Aurelien Jarno Cc: Mark Cave-Ayland Signed-off-by: Markus Armbruster Reviewed-by: Marcel Apfelbaum Reviewed-by: Hervé Poussineau Reviewed-by: Michael S. Tsirkin Message-Id: <1450370121-5768-11-git-send-email-armbru@redhat.com> --- hw/alpha/typhoon.c | 3 ++- hw/i386/pc_piix.c | 3 ++- hw/isa/i82378.c | 5 ++++- hw/isa/isa-bus.c | 4 ++-- hw/isa/lpc_ich9.c | 6 +++++- hw/isa/piix4.c | 6 ++++-- hw/isa/vt82c686.c | 5 ++++- hw/mips/mips_jazz.c | 2 +- hw/mips/mips_r4k.c | 2 +- hw/pci-host/piix.c | 6 ++++-- hw/sparc64/sun4u.c | 6 ++++-- include/hw/isa/isa.h | 2 +- 12 files changed, 34 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c index 421162e1d4..35dc8a5b47 100644 --- a/hw/alpha/typhoon.c +++ b/hw/alpha/typhoon.c @@ -920,7 +920,8 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, { qemu_irq *isa_irqs; - *isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io); + *isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io, + &error_abort); isa_irqs = i8259_init(*isa_bus, qemu_allocate_irq(typhoon_set_isa_irq, s, 0)); isa_bus_irqs(*isa_bus, isa_irqs); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 438cdae99e..df2b824385 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -189,7 +189,8 @@ static void pc_init1(MachineState *machine, } else { pci_bus = NULL; i440fx_state = NULL; - isa_bus = isa_bus_new(NULL, get_system_memory(), system_io); + isa_bus = isa_bus_new(NULL, get_system_memory(), system_io, + &error_abort); no_hpet = 1; } isa_bus_irqs(isa_bus, gsi); diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c index d4c830684b..3793c6fe7a 100644 --- a/hw/isa/i82378.c +++ b/hw/isa/i82378.c @@ -75,7 +75,10 @@ static void i82378_realize(PCIDevice *pci, Error **errp) pci_config_set_interrupt_pin(pci_conf, 1); /* interrupt pin 0 */ isabus = isa_bus_new(dev, get_system_memory(), - pci_address_space_io(pci)); + pci_address_space_io(pci), errp); + if (!isabus) { + return; + } /* This device has: 2 82C59 (irq) diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 43e0cd8ddd..af6ffd6461 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -44,10 +44,10 @@ static const TypeInfo isa_bus_info = { }; ISABus *isa_bus_new(DeviceState *dev, MemoryRegion* address_space, - MemoryRegion *address_space_io) + MemoryRegion *address_space_io, Error **errp) { if (isabus) { - fprintf(stderr, "Can't create a second ISA bus\n"); + error_setg(errp, "Can't create a second ISA bus"); return NULL; } if (!dev) { diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index 8e5844906c..ed9907d29a 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -607,7 +607,11 @@ static void ich9_lpc_realize(PCIDevice *d, Error **errp) ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); ISABus *isa_bus; - isa_bus = isa_bus_new(DEVICE(d), get_system_memory(), get_system_io()); + isa_bus = isa_bus_new(DEVICE(d), get_system_memory(), get_system_io(), + errp); + if (!isa_bus) { + return; + } pci_set_long(d->wmask + ICH9_LPC_PMBASE, ICH9_LPC_PMBASE_BASE_ADDRESS_MASK); diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index 2c59e91fff..644cfd9536 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -90,8 +90,10 @@ static void piix4_realize(PCIDevice *dev, Error **errp) { PIIX4State *d = PIIX4_PCI_DEVICE(dev); - isa_bus_new(DEVICE(d), pci_address_space(dev), - pci_address_space_io(dev)); + if (!isa_bus_new(DEVICE(d), pci_address_space(dev), + pci_address_space_io(dev), errp)) { + return; + } piix4_dev = &d->dev; qemu_register_reset(piix4_reset, d); } diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index 252e1d7145..6c2190b46c 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -440,7 +440,10 @@ static void vt82c686b_realize(PCIDevice *d, Error **errp) int i; isa_bus = isa_bus_new(DEVICE(d), get_system_memory(), - pci_address_space_io(d)); + pci_address_space_io(d), errp); + if (!isa_bus) { + return; + } pci_conf = d->config; pci_config_set_prog_interface(pci_conf, 0x0); diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 1ab885bb3f..1cfbaa605a 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -219,7 +219,7 @@ static void mips_jazz_init(MachineState *machine, memory_region_init(isa_mem, NULL, "isa-mem", 0x01000000); memory_region_add_subregion(address_space, 0x90000000, isa_io); memory_region_add_subregion(address_space, 0x91000000, isa_mem); - isa_bus = isa_bus_new(NULL, isa_mem, isa_io); + isa_bus = isa_bus_new(NULL, isa_mem, isa_io, &error_abort); /* ISA devices */ i8259 = i8259_init(isa_bus, env->irq[4]); diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c index af10da1c57..2d4e038673 100644 --- a/hw/mips/mips_r4k.c +++ b/hw/mips/mips_r4k.c @@ -272,7 +272,7 @@ void mips_r4k_init(MachineState *machine) memory_region_init(isa_mem, NULL, "isa-mem", 0x01000000); memory_region_add_subregion(get_system_memory(), 0x14000000, isa_io); memory_region_add_subregion(get_system_memory(), 0x10000000, isa_mem); - isa_bus = isa_bus_new(NULL, isa_mem, get_system_io()); + isa_bus = isa_bus_new(NULL, isa_mem, get_system_io(), &error_abort); /* The PIC is attached to the MIPS CPU INT0 pin */ i8259 = i8259_init(isa_bus, env->irq[2]); diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index 924f0fa82b..b0d7e31607 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -651,8 +651,10 @@ static void piix3_realize(PCIDevice *dev, Error **errp) { PIIX3State *d = PIIX3_PCI_DEVICE(dev); - isa_bus_new(DEVICE(d), get_system_memory(), - pci_address_space_io(dev)); + if (!isa_bus_new(DEVICE(d), get_system_memory(), + pci_address_space_io(dev), errp)) { + return; + } memory_region_init_io(&d->rcr_mem, OBJECT(dev), &rcr_ops, d, "piix3-reset-control", 1); diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 8058aac5d7..1925a1cef9 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -604,8 +604,10 @@ static void pci_ebus_realize(PCIDevice *pci_dev, Error **errp) { EbusState *s = DO_UPCAST(EbusState, pci_dev, pci_dev); - isa_bus_new(DEVICE(pci_dev), get_system_memory(), - pci_address_space_io(pci_dev)); + if (!isa_bus_new(DEVICE(pci_dev), get_system_memory(), + pci_address_space_io(pci_dev), errp)) { + return; + } pci_dev->config[0x04] = 0x06; // command = bus master, pci mem pci_dev->config[0x05] = 0x00; diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index d758b39a2e..de3cd3d38a 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -59,7 +59,7 @@ struct ISADevice { }; ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space, - MemoryRegion *address_space_io); + MemoryRegion *address_space_io, Error **errp); void isa_bus_irqs(ISABus *bus, qemu_irq *irqs); qemu_irq isa_get_irq(ISADevice *dev, int isairq); void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq); -- cgit v1.2.3-55-g7522 From f4d0064afcff4c38b379800674938cde8f069dcd Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 18 Dec 2015 16:35:08 +0100 Subject: error: Improve documentation While there, tighten error_append_hint()'s assertion. Signed-off-by: Markus Armbruster Message-Id: <1450452927-8346-6-git-send-email-armbru@redhat.com> Reviewed-by: Eric Blake --- include/qapi/error.h | 20 ++++++++++++++++++-- util/error.c | 2 +- util/qemu-error.c | 8 ++++---- 3 files changed, 23 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/qapi/error.h b/include/qapi/error.h index 1480f59ec5..b18a608c6d 100644 --- a/include/qapi/error.h +++ b/include/qapi/error.h @@ -18,6 +18,15 @@ * Create an error: * error_setg(&err, "situation normal, all fouled up"); * + * Create an error and add additional explanation: + * error_setg(&err, "invalid quark"); + * error_append_hint(&err, "Valid quarks are up, down, strange, " + * "charm, top, bottom.\n"); + * + * Do *not* contract this to + * error_setg(&err, "invalid quark\n" + * "Valid quarks are up, down, strange, charm, top, bottom."); + * * Report an error to stderr: * error_report_err(err); * This frees the error object. @@ -26,6 +35,7 @@ * const char *msg = error_get_pretty(err); * do with msg what needs to be done... * error_free(err); + * Note that this loses hints added with error_append_hint(). * * Handle an error without reporting it (just for completeness): * error_free(err); @@ -142,6 +152,8 @@ ErrorClass error_get_class(const Error *err); * If @errp is anything else, *@errp must be NULL. * The new error's class is ERROR_CLASS_GENERIC_ERROR, and its * human-readable error message is made from printf-style @fmt, ... + * The resulting message should be a single phrase, with no newline or + * trailing punctuation. */ #define error_setg(errp, fmt, ...) \ error_setg_internal((errp), __FILE__, __LINE__, __func__, \ @@ -198,7 +210,11 @@ void error_propagate(Error **dst_errp, Error *local_err); /** * Append a printf-style human-readable explanation to an existing error. - * May be called multiple times, and safe if @errp is NULL. + * @errp may be NULL, but not &error_fatal or &error_abort. + * Trivially the case if you call it only after error_setg() or + * error_propagate(). + * May be called multiple times. The resulting hint should end with a + * newline. */ void error_append_hint(Error **errp, const char *fmt, ...) GCC_FMT_ATTR(2, 3); @@ -232,7 +248,7 @@ void error_free_or_abort(Error **errp); /* * Convenience function to error_report() and free @err. */ -void error_report_err(Error *); +void error_report_err(Error *err); /* * Just like error_setg(), except you get to specify the error class. diff --git a/util/error.c b/util/error.c index 9b27c4508e..ebfb74b02e 100644 --- a/util/error.c +++ b/util/error.c @@ -132,7 +132,7 @@ void error_append_hint(Error **errp, const char *fmt, ...) return; } err = *errp; - assert(err && errp != &error_abort); + assert(err && errp != &error_abort && errp != &error_fatal); if (!err->hint) { err->hint = g_string_new(NULL); diff --git a/util/qemu-error.c b/util/qemu-error.c index c1574bb348..ecf5708478 100644 --- a/util/qemu-error.c +++ b/util/qemu-error.c @@ -200,8 +200,8 @@ static void error_print_loc(void) bool enable_timestamp_msg; /* * Print an error message to current monitor if we have one, else to stderr. - * Format arguments like vsprintf(). The result should not contain - * newlines. + * Format arguments like vsprintf(). The resulting message should be + * a single phrase, with no newline or trailing punctuation. * Prepend the current location and append a newline. * It's wrong to call this in a QMP monitor. Use error_setg() there. */ @@ -224,8 +224,8 @@ void error_vreport(const char *fmt, va_list ap) /* * Print an error message to current monitor if we have one, else to stderr. - * Format arguments like sprintf(). The result should not contain - * newlines. + * Format arguments like sprintf(). The resulting message should be a + * single phrase, with no newline or trailing punctuation. * Prepend the current location and append a newline. * It's wrong to call this in a QMP monitor. Use error_setg() there. */ -- cgit v1.2.3-55-g7522 From 8277d2aa58fe4f8f3ee394ea647ea652faf822a4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 18 Dec 2015 16:35:12 +0100 Subject: error: New error_prepend(), error_reportf_err() Instead of simply propagating an error verbatim, we sometimes want to add to its message, like this: frobnicate(arg, &err); error_setg(errp, "Can't frobnicate %s: %s", arg, error_get_pretty(err)); error_free(err); This is suboptimal, because it loses err's hint (if any). Moreover, when errp is &error_abort or is subsequently propagated to &error_abort, the abort message points to the place where we last added to the error, not to the place where it originated. To avoid these issues, provide means to add to an error's message in place: frobnicate(arg, errp); error_prepend(errp, "Can't frobnicate %s: ", arg); Likewise, reporting an error like frobnicate(arg, &err); error_report("Can't frobnicate %s: %s", arg, error_get_pretty(err)); can lose err's hint. To avoid: error_reportf_err(err, "Can't frobnicate %s: ", arg); The next commits will put these functions to use. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1450452927-8346-10-git-send-email-armbru@redhat.com> --- include/qapi/error.h | 31 +++++++++++++++++++++++++++++-- util/error.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/qapi/error.h b/include/qapi/error.h index b18a608c6d..45d6c72dee 100644 --- a/include/qapi/error.h +++ b/include/qapi/error.h @@ -31,6 +31,9 @@ * error_report_err(err); * This frees the error object. * + * Report an error to stderr with additional text prepended: + * error_reportf_err(err, "Could not frobnicate '%s': ", name); + * * Report an error somewhere else: * const char *msg = error_get_pretty(err); * do with msg what needs to be done... @@ -48,6 +51,10 @@ * error_propagate(errp, err); * where Error **errp is a parameter, by convention the last one. * + * Pass an existing error to the caller with the message modified: + * error_propagate(errp, err); + * error_prepend(errp, "Could not frobnicate '%s': ", name); + * * Create a new error and pass it to the caller: * error_setg(errp, "situation normal, all fouled up"); * @@ -108,9 +115,10 @@ #ifndef ERROR_H #define ERROR_H +#include +#include #include "qemu/compiler.h" #include "qapi-types.h" -#include /* * Opaque error object. @@ -208,7 +216,20 @@ void error_setg_win32_internal(Error **errp, */ void error_propagate(Error **dst_errp, Error *local_err); -/** +/* + * Prepend some text to @errp's human-readable error message. + * The text is made by formatting @fmt, @ap like vprintf(). + */ +void error_vprepend(Error **errp, const char *fmt, va_list ap); + +/* + * Prepend some text to @errp's human-readable error message. + * The text is made by formatting @fmt, ... like printf(). + */ +void error_prepend(Error **errp, const char *fmt, ...) + GCC_FMT_ATTR(2, 3); + +/* * Append a printf-style human-readable explanation to an existing error. * @errp may be NULL, but not &error_fatal or &error_abort. * Trivially the case if you call it only after error_setg() or @@ -250,6 +271,12 @@ void error_free_or_abort(Error **errp); */ void error_report_err(Error *err); +/* + * Convenience function to error_prepend(), error_report() and free @err. + */ +void error_reportf_err(Error *err, const char *fmt, ...) + GCC_FMT_ATTR(2, 3); + /* * Just like error_setg(), except you get to specify the error class. * Note: use of error classes other than ERROR_CLASS_GENERIC_ERROR is diff --git a/util/error.c b/util/error.c index ebfb74b02e..57303fd05c 100644 --- a/util/error.c +++ b/util/error.c @@ -122,6 +122,29 @@ void error_setg_file_open_internal(Error **errp, "Could not open '%s'", filename); } +void error_vprepend(Error **errp, const char *fmt, va_list ap) +{ + GString *newmsg; + + if (!errp) { + return; + } + + newmsg = g_string_new(NULL); + g_string_vprintf(newmsg, fmt, ap); + g_string_append(newmsg, (*errp)->msg); + (*errp)->msg = g_string_free(newmsg, 0); +} + +void error_prepend(Error **errp, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + error_vprepend(errp, fmt, ap); + va_end(ap); +} + void error_append_hint(Error **errp, const char *fmt, ...) { va_list ap; @@ -209,6 +232,16 @@ void error_report_err(Error *err) error_free(err); } +void error_reportf_err(Error *err, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + error_vprepend(&err, fmt, ap); + va_end(ap); + error_report_err(err); +} + void error_free(Error *err) { if (err) { -- cgit v1.2.3-55-g7522 From 533fdaedeb7f7ae90866312f57249ebbb7e3c97f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 18 Dec 2015 16:35:27 +0100 Subject: error: Consistently name Error * objects err, and not errp Signed-off-by: Markus Armbruster Message-Id: <1450452927-8346-25-git-send-email-armbru@redhat.com> Reviewed-by: Eric Blake --- contrib/ivshmem-server/main.c | 8 ++++---- hmp.c | 32 ++++++++++++++++---------------- hw/core/nmi.c | 10 +++++----- include/qemu/sockets.h | 2 +- tests/test-string-output-visitor.c | 6 +++--- 5 files changed, 29 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/contrib/ivshmem-server/main.c b/contrib/ivshmem-server/main.c index 00508b5edd..9b0d6e2319 100644 --- a/contrib/ivshmem-server/main.c +++ b/contrib/ivshmem-server/main.c @@ -65,7 +65,7 @@ ivshmem_server_parse_args(IvshmemServerArgs *args, int argc, char *argv[]) { int c; unsigned long long v; - Error *errp = NULL; + Error *err = NULL; while ((c = getopt(argc, argv, "h" /* help */ @@ -104,9 +104,9 @@ ivshmem_server_parse_args(IvshmemServerArgs *args, int argc, char *argv[]) break; case 'l': /* shm_size */ - parse_option_size("shm_size", optarg, &args->shm_size, &errp); - if (errp) { - error_report_err(errp); + parse_option_size("shm_size", optarg, &args->shm_size, &err); + if (err) { + error_report_err(err); ivshmem_server_usage(argv[0], 1); } break; diff --git a/hmp.c b/hmp.c index 9723397b8b..54f2620690 100644 --- a/hmp.c +++ b/hmp.c @@ -2078,11 +2078,11 @@ void hmp_rocker(Monitor *mon, const QDict *qdict) { const char *name = qdict_get_str(qdict, "name"); RockerSwitch *rocker; - Error *errp = NULL; + Error *err = NULL; - rocker = qmp_query_rocker(name, &errp); - if (errp != NULL) { - hmp_handle_error(mon, &errp); + rocker = qmp_query_rocker(name, &err); + if (err != NULL) { + hmp_handle_error(mon, &err); return; } @@ -2097,11 +2097,11 @@ void hmp_rocker_ports(Monitor *mon, const QDict *qdict) { RockerPortList *list, *port; const char *name = qdict_get_str(qdict, "name"); - Error *errp = NULL; + Error *err = NULL; - list = qmp_query_rocker_ports(name, &errp); - if (errp != NULL) { - hmp_handle_error(mon, &errp); + list = qmp_query_rocker_ports(name, &err); + if (err != NULL) { + hmp_handle_error(mon, &err); return; } @@ -2126,11 +2126,11 @@ void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict) RockerOfDpaFlowList *list, *info; const char *name = qdict_get_str(qdict, "name"); uint32_t tbl_id = qdict_get_try_int(qdict, "tbl_id", -1); - Error *errp = NULL; + Error *err = NULL; - list = qmp_query_rocker_of_dpa_flows(name, tbl_id != -1, tbl_id, &errp); - if (errp != NULL) { - hmp_handle_error(mon, &errp); + list = qmp_query_rocker_of_dpa_flows(name, tbl_id != -1, tbl_id, &err); + if (err != NULL) { + hmp_handle_error(mon, &err); return; } @@ -2276,12 +2276,12 @@ void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict) RockerOfDpaGroupList *list, *g; const char *name = qdict_get_str(qdict, "name"); uint8_t type = qdict_get_try_int(qdict, "type", 9); - Error *errp = NULL; + Error *err = NULL; bool set = false; - list = qmp_query_rocker_of_dpa_groups(name, type != 9, type, &errp); - if (errp != NULL) { - hmp_handle_error(mon, &errp); + list = qmp_query_rocker_of_dpa_groups(name, type != 9, type, &err); + if (err != NULL) { + hmp_handle_error(mon, &err); return; } diff --git a/hw/core/nmi.c b/hw/core/nmi.c index de1d1f8cb1..4057cdd6a2 100644 --- a/hw/core/nmi.c +++ b/hw/core/nmi.c @@ -25,7 +25,7 @@ struct do_nmi_s { int cpu_index; - Error *errp; + Error *err; bool handled; }; @@ -40,8 +40,8 @@ static int do_nmi(Object *o, void *opaque) NMIClass *nc = NMI_GET_CLASS(n); ns->handled = true; - nc->nmi_monitor_handler(n, ns->cpu_index, &ns->errp); - if (ns->errp) { + nc->nmi_monitor_handler(n, ns->cpu_index, &ns->err); + if (ns->err) { return -1; } } @@ -59,13 +59,13 @@ void nmi_monitor_handle(int cpu_index, Error **errp) { struct do_nmi_s ns = { .cpu_index = cpu_index, - .errp = NULL, + .err = NULL, .handled = false }; nmi_children(object_get_root(), &ns); if (ns.handled) { - error_propagate(errp, ns.errp); + error_propagate(errp, ns.err); } else { error_setg(errp, QERR_UNSUPPORTED); } diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index 74c692d432..2e7f98518e 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -53,7 +53,7 @@ int recv_all(int fd, void *buf, int len1, bool single_read); /* callback function for nonblocking connect * valid fd on success, negative error code on failure */ -typedef void NonBlockingConnectHandler(int fd, Error *errp, void *opaque); +typedef void NonBlockingConnectHandler(int fd, Error *err, void *opaque); InetSocketAddress *inet_parse(const char *str, Error **errp); int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp); diff --git a/tests/test-string-output-visitor.c b/tests/test-string-output-visitor.c index 95852523b4..7aecdfcefb 100644 --- a/tests/test-string-output-visitor.c +++ b/tests/test-string-output-visitor.c @@ -81,7 +81,7 @@ static void test_visitor_out_intList(TestOutputVisitorData *data, 3, 4, 5, 6, 11, 12, 13, 21, 22, INT64_MAX - 1, INT64_MAX}; intList *list = NULL, **tmp = &list; int i; - Error *errp = NULL; + Error *err = NULL; char *str; for (i = 0; i < sizeof(value) / sizeof(value[0]); i++) { @@ -90,8 +90,8 @@ static void test_visitor_out_intList(TestOutputVisitorData *data, tmp = &(*tmp)->next; } - visit_type_intList(data->ov, &list, NULL, &errp); - g_assert(errp == NULL); + visit_type_intList(data->ov, &list, NULL, &err); + g_assert(err == NULL); str = string_output_get_string(data->sov); g_assert(str != NULL); -- cgit v1.2.3-55-g7522