Message ID | 1524670052-28373-3-git-send-email-minyard@acm.org |
---|---|
State | New |
Headers | show |
Series | [v3,1/3] vmstate: Add a VSTRUCT type | expand |
Hi Corey On Wed, Apr 25, 2018 at 5:27 PM, <minyard@acm.org> wrote: > From: Corey Minyard <cminyard@mvista.com> > > The vmstate for isa_ipmi_kcs was referencing into the kcs structure, > instead create a kcs structure separate and use that. > > There were also some issues in the state transfer. The inlen field > was not being transferred, so if a transaction was in process during > the transfer it would be messed up. And the use_irq field was > transferred, but that should come from the configuration. > > To fix this, the new VMS_VSTRUCT macros are used so the exact > version of the structure can be specified, depending on what > version was being received. So an upgrade should work for KCS. Looks good overall, You could easily split this patch further to help review/bisecting etc. Introduce VMSTATE_STRUCT, unuse use_irq, introduce version 2, add the postload checks. You could also help reviewers by giving your test setup, so we can more easily reproduce the fix and/or try variants. I also wonder if you could have used subsections, but the VSTRUCT type seems a good approach to me, David would have to review it though. > Signed-off-by: Corey Minyard <cminyard@mvista.com> > Cc: Dr. David Alan Gilbert <dgilbert@redhat.com> > --- > hw/ipmi/isa_ipmi_kcs.c | 81 ++++++++++++++++++++++++++++++++++++++++---------- > 1 file changed, 66 insertions(+), 15 deletions(-) > > diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c > index 689587b..a794315 100644 > --- a/hw/ipmi/isa_ipmi_kcs.c > +++ b/hw/ipmi/isa_ipmi_kcs.c > @@ -22,6 +22,7 @@ > * THE SOFTWARE. > */ > #include "qemu/osdep.h" > +#include "qemu/log.h" > #include "qapi/error.h" > #include "hw/hw.h" > #include "hw/ipmi/ipmi.h" > @@ -422,24 +423,69 @@ static void ipmi_isa_realize(DeviceState *dev, Error **errp) > isa_register_ioport(isadev, &iik->kcs.io, iik->kcs.io_base); > } > > -const VMStateDescription vmstate_ISAIPMIKCSDevice = { > +static int ipmi_kcs_vmstate_post_load(void *opaque, int version) > +{ > + IPMIKCS *ik = opaque; > + > + /* Make sure all the values are sane. */ > + if (ik->outpos >= MAX_IPMI_MSG_SIZE || ik->outlen >= MAX_IPMI_MSG_SIZE || > + ik->outpos >= ik->outlen) { > + qemu_log_mask(LOG_GUEST_ERROR, > + "ipmi:kcs: vmstate transfer received bad out values: %d %d\n", > + ik->outpos, ik->outlen); > + ik->outpos = 0; > + ik->outlen = 0; > + } > + > + if (ik->inlen >= MAX_IPMI_MSG_SIZE) { > + qemu_log_mask(LOG_GUEST_ERROR, > + "ipmi:kcs: vmstate transfer received bad in value: %d\n", > + ik->inlen); > + ik->inlen = 0; > + } > + > + return 0; > +} > + > +static bool vmstate_kcs_before_version2(void *opaque, int version) > +{ > + return version <= 1; > +} > + > +static const VMStateDescription vmstate_IPMIKCS = { > + .name = TYPE_IPMI_INTERFACE_PREFIX "kcs", > + .version_id = 2, > + .minimum_version_id = 1, > + .post_load = ipmi_kcs_vmstate_post_load, > + .fields = (VMStateField[]) { > + VMSTATE_BOOL(obf_irq_set, IPMIKCS), > + VMSTATE_BOOL(atn_irq_set, IPMIKCS), > + VMSTATE_UNUSED_TEST(vmstate_kcs_before_version2, 1), /* Was use_irq */ > + VMSTATE_BOOL(irqs_enabled, IPMIKCS), > + VMSTATE_UINT32(outpos, IPMIKCS), > + VMSTATE_UINT32_V(outlen, IPMIKCS, 2), > + VMSTATE_UINT8_ARRAY(outmsg, IPMIKCS, MAX_IPMI_MSG_SIZE), > + VMSTATE_UINT32_V(inlen, IPMIKCS, 2), > + VMSTATE_UINT8_ARRAY(inmsg, IPMIKCS, MAX_IPMI_MSG_SIZE), > + VMSTATE_BOOL(write_end, IPMIKCS), > + VMSTATE_UINT8(status_reg, IPMIKCS), > + VMSTATE_UINT8(data_out_reg, IPMIKCS), > + VMSTATE_INT16(data_in_reg, IPMIKCS), > + VMSTATE_INT16(cmd_reg, IPMIKCS), > + VMSTATE_UINT8(waiting_rsp, IPMIKCS), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static const VMStateDescription vmstate_ISAIPMIKCSDevice = { > .name = TYPE_IPMI_INTERFACE, > - .version_id = 1, > + .version_id = 2, > .minimum_version_id = 1, > .fields = (VMStateField[]) { > - VMSTATE_BOOL(kcs.obf_irq_set, ISAIPMIKCSDevice), > - VMSTATE_BOOL(kcs.atn_irq_set, ISAIPMIKCSDevice), > - VMSTATE_BOOL(kcs.use_irq, ISAIPMIKCSDevice), > - VMSTATE_BOOL(kcs.irqs_enabled, ISAIPMIKCSDevice), > - VMSTATE_UINT32(kcs.outpos, ISAIPMIKCSDevice), > - VMSTATE_UINT8_ARRAY(kcs.outmsg, ISAIPMIKCSDevice, MAX_IPMI_MSG_SIZE), > - VMSTATE_UINT8_ARRAY(kcs.inmsg, ISAIPMIKCSDevice, MAX_IPMI_MSG_SIZE), > - VMSTATE_BOOL(kcs.write_end, ISAIPMIKCSDevice), > - VMSTATE_UINT8(kcs.status_reg, ISAIPMIKCSDevice), > - VMSTATE_UINT8(kcs.data_out_reg, ISAIPMIKCSDevice), > - VMSTATE_INT16(kcs.data_in_reg, ISAIPMIKCSDevice), > - VMSTATE_INT16(kcs.cmd_reg, ISAIPMIKCSDevice), > - VMSTATE_UINT8(kcs.waiting_rsp, ISAIPMIKCSDevice), > + VMSTATE_VSTRUCT_TEST(kcs, ISAIPMIKCSDevice, vmstate_kcs_before_version2, > + 0, vmstate_IPMIKCS, IPMIKCS, 1), > + VMSTATE_VSTRUCT_V(kcs, ISAIPMIKCSDevice, 2, vmstate_IPMIKCS, > + IPMIKCS, 2), > VMSTATE_END_OF_LIST() > } > }; > @@ -450,6 +496,11 @@ static void isa_ipmi_kcs_init(Object *obj) > > ipmi_bmc_find_and_link(obj, (Object **) &iik->kcs.bmc); > > + /* > + * Version 1 had an incorrect name, it clashed with the BT > + * IPMI device, so receive it, but transmit a different > + * version. > + */ > vmstate_register(NULL, 0, &vmstate_ISAIPMIKCSDevice, iik); > } > > -- > 2.7.4 > > -- Marc-André Lureau
On 05/18/2018 10:45 AM, Marc-André Lureau wrote: > Hi Corey > > On Wed, Apr 25, 2018 at 5:27 PM, <minyard@acm.org> wrote: >> From: Corey Minyard <cminyard@mvista.com> >> >> The vmstate for isa_ipmi_kcs was referencing into the kcs structure, >> instead create a kcs structure separate and use that. >> >> There were also some issues in the state transfer. The inlen field >> was not being transferred, so if a transaction was in process during >> the transfer it would be messed up. And the use_irq field was >> transferred, but that should come from the configuration. >> >> To fix this, the new VMS_VSTRUCT macros are used so the exact >> version of the structure can be specified, depending on what >> version was being received. So an upgrade should work for KCS. > Looks good overall, > > You could easily split this patch further to help review/bisecting etc. > > Introduce VMSTATE_STRUCT, unuse use_irq, introduce version 2, add the > postload checks. That's probably fair. I'll do that for v4. > You could also help reviewers by giving your test setup, so we can > more easily reproduce the fix and/or try variants. Hmm. That's a little hard. I'll see what I can do. Maybe it's not too bad, most distros should have the openipmi library available. > > I also wonder if you could have used subsections, but the VSTRUCT type > seems a good approach to me, David would have to review it though. Yeah, I think we talked about subsections at one point, but this seemed better. That will have to wait for David. Thanks, -corey > >> Signed-off-by: Corey Minyard <cminyard@mvista.com> >> Cc: Dr. David Alan Gilbert <dgilbert@redhat.com> >> --- >> hw/ipmi/isa_ipmi_kcs.c | 81 ++++++++++++++++++++++++++++++++++++++++---------- >> 1 file changed, 66 insertions(+), 15 deletions(-) >> >> diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c >> index 689587b..a794315 100644 >> --- a/hw/ipmi/isa_ipmi_kcs.c >> +++ b/hw/ipmi/isa_ipmi_kcs.c >> @@ -22,6 +22,7 @@ >> * THE SOFTWARE. >> */ >> #include "qemu/osdep.h" >> +#include "qemu/log.h" >> #include "qapi/error.h" >> #include "hw/hw.h" >> #include "hw/ipmi/ipmi.h" >> @@ -422,24 +423,69 @@ static void ipmi_isa_realize(DeviceState *dev, Error **errp) >> isa_register_ioport(isadev, &iik->kcs.io, iik->kcs.io_base); >> } >> >> -const VMStateDescription vmstate_ISAIPMIKCSDevice = { >> +static int ipmi_kcs_vmstate_post_load(void *opaque, int version) >> +{ >> + IPMIKCS *ik = opaque; >> + >> + /* Make sure all the values are sane. */ >> + if (ik->outpos >= MAX_IPMI_MSG_SIZE || ik->outlen >= MAX_IPMI_MSG_SIZE || >> + ik->outpos >= ik->outlen) { >> + qemu_log_mask(LOG_GUEST_ERROR, >> + "ipmi:kcs: vmstate transfer received bad out values: %d %d\n", >> + ik->outpos, ik->outlen); >> + ik->outpos = 0; >> + ik->outlen = 0; >> + } >> + >> + if (ik->inlen >= MAX_IPMI_MSG_SIZE) { >> + qemu_log_mask(LOG_GUEST_ERROR, >> + "ipmi:kcs: vmstate transfer received bad in value: %d\n", >> + ik->inlen); >> + ik->inlen = 0; >> + } >> + >> + return 0; >> +} >> + >> +static bool vmstate_kcs_before_version2(void *opaque, int version) >> +{ >> + return version <= 1; >> +} >> + >> +static const VMStateDescription vmstate_IPMIKCS = { >> + .name = TYPE_IPMI_INTERFACE_PREFIX "kcs", >> + .version_id = 2, >> + .minimum_version_id = 1, >> + .post_load = ipmi_kcs_vmstate_post_load, >> + .fields = (VMStateField[]) { >> + VMSTATE_BOOL(obf_irq_set, IPMIKCS), >> + VMSTATE_BOOL(atn_irq_set, IPMIKCS), >> + VMSTATE_UNUSED_TEST(vmstate_kcs_before_version2, 1), /* Was use_irq */ >> + VMSTATE_BOOL(irqs_enabled, IPMIKCS), >> + VMSTATE_UINT32(outpos, IPMIKCS), >> + VMSTATE_UINT32_V(outlen, IPMIKCS, 2), >> + VMSTATE_UINT8_ARRAY(outmsg, IPMIKCS, MAX_IPMI_MSG_SIZE), >> + VMSTATE_UINT32_V(inlen, IPMIKCS, 2), >> + VMSTATE_UINT8_ARRAY(inmsg, IPMIKCS, MAX_IPMI_MSG_SIZE), >> + VMSTATE_BOOL(write_end, IPMIKCS), >> + VMSTATE_UINT8(status_reg, IPMIKCS), >> + VMSTATE_UINT8(data_out_reg, IPMIKCS), >> + VMSTATE_INT16(data_in_reg, IPMIKCS), >> + VMSTATE_INT16(cmd_reg, IPMIKCS), >> + VMSTATE_UINT8(waiting_rsp, IPMIKCS), >> + VMSTATE_END_OF_LIST() >> + } >> +}; >> + >> +static const VMStateDescription vmstate_ISAIPMIKCSDevice = { >> .name = TYPE_IPMI_INTERFACE, >> - .version_id = 1, >> + .version_id = 2, >> .minimum_version_id = 1, >> .fields = (VMStateField[]) { >> - VMSTATE_BOOL(kcs.obf_irq_set, ISAIPMIKCSDevice), >> - VMSTATE_BOOL(kcs.atn_irq_set, ISAIPMIKCSDevice), >> - VMSTATE_BOOL(kcs.use_irq, ISAIPMIKCSDevice), >> - VMSTATE_BOOL(kcs.irqs_enabled, ISAIPMIKCSDevice), >> - VMSTATE_UINT32(kcs.outpos, ISAIPMIKCSDevice), >> - VMSTATE_UINT8_ARRAY(kcs.outmsg, ISAIPMIKCSDevice, MAX_IPMI_MSG_SIZE), >> - VMSTATE_UINT8_ARRAY(kcs.inmsg, ISAIPMIKCSDevice, MAX_IPMI_MSG_SIZE), >> - VMSTATE_BOOL(kcs.write_end, ISAIPMIKCSDevice), >> - VMSTATE_UINT8(kcs.status_reg, ISAIPMIKCSDevice), >> - VMSTATE_UINT8(kcs.data_out_reg, ISAIPMIKCSDevice), >> - VMSTATE_INT16(kcs.data_in_reg, ISAIPMIKCSDevice), >> - VMSTATE_INT16(kcs.cmd_reg, ISAIPMIKCSDevice), >> - VMSTATE_UINT8(kcs.waiting_rsp, ISAIPMIKCSDevice), >> + VMSTATE_VSTRUCT_TEST(kcs, ISAIPMIKCSDevice, vmstate_kcs_before_version2, >> + 0, vmstate_IPMIKCS, IPMIKCS, 1), >> + VMSTATE_VSTRUCT_V(kcs, ISAIPMIKCSDevice, 2, vmstate_IPMIKCS, >> + IPMIKCS, 2), >> VMSTATE_END_OF_LIST() >> } >> }; >> @@ -450,6 +496,11 @@ static void isa_ipmi_kcs_init(Object *obj) >> >> ipmi_bmc_find_and_link(obj, (Object **) &iik->kcs.bmc); >> >> + /* >> + * Version 1 had an incorrect name, it clashed with the BT >> + * IPMI device, so receive it, but transmit a different >> + * version. >> + */ >> vmstate_register(NULL, 0, &vmstate_ISAIPMIKCSDevice, iik); >> } >> >> -- >> 2.7.4 >> >> > >
diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c index 689587b..a794315 100644 --- a/hw/ipmi/isa_ipmi_kcs.c +++ b/hw/ipmi/isa_ipmi_kcs.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "qapi/error.h" #include "hw/hw.h" #include "hw/ipmi/ipmi.h" @@ -422,24 +423,69 @@ static void ipmi_isa_realize(DeviceState *dev, Error **errp) isa_register_ioport(isadev, &iik->kcs.io, iik->kcs.io_base); } -const VMStateDescription vmstate_ISAIPMIKCSDevice = { +static int ipmi_kcs_vmstate_post_load(void *opaque, int version) +{ + IPMIKCS *ik = opaque; + + /* Make sure all the values are sane. */ + if (ik->outpos >= MAX_IPMI_MSG_SIZE || ik->outlen >= MAX_IPMI_MSG_SIZE || + ik->outpos >= ik->outlen) { + qemu_log_mask(LOG_GUEST_ERROR, + "ipmi:kcs: vmstate transfer received bad out values: %d %d\n", + ik->outpos, ik->outlen); + ik->outpos = 0; + ik->outlen = 0; + } + + if (ik->inlen >= MAX_IPMI_MSG_SIZE) { + qemu_log_mask(LOG_GUEST_ERROR, + "ipmi:kcs: vmstate transfer received bad in value: %d\n", + ik->inlen); + ik->inlen = 0; + } + + return 0; +} + +static bool vmstate_kcs_before_version2(void *opaque, int version) +{ + return version <= 1; +} + +static const VMStateDescription vmstate_IPMIKCS = { + .name = TYPE_IPMI_INTERFACE_PREFIX "kcs", + .version_id = 2, + .minimum_version_id = 1, + .post_load = ipmi_kcs_vmstate_post_load, + .fields = (VMStateField[]) { + VMSTATE_BOOL(obf_irq_set, IPMIKCS), + VMSTATE_BOOL(atn_irq_set, IPMIKCS), + VMSTATE_UNUSED_TEST(vmstate_kcs_before_version2, 1), /* Was use_irq */ + VMSTATE_BOOL(irqs_enabled, IPMIKCS), + VMSTATE_UINT32(outpos, IPMIKCS), + VMSTATE_UINT32_V(outlen, IPMIKCS, 2), + VMSTATE_UINT8_ARRAY(outmsg, IPMIKCS, MAX_IPMI_MSG_SIZE), + VMSTATE_UINT32_V(inlen, IPMIKCS, 2), + VMSTATE_UINT8_ARRAY(inmsg, IPMIKCS, MAX_IPMI_MSG_SIZE), + VMSTATE_BOOL(write_end, IPMIKCS), + VMSTATE_UINT8(status_reg, IPMIKCS), + VMSTATE_UINT8(data_out_reg, IPMIKCS), + VMSTATE_INT16(data_in_reg, IPMIKCS), + VMSTATE_INT16(cmd_reg, IPMIKCS), + VMSTATE_UINT8(waiting_rsp, IPMIKCS), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_ISAIPMIKCSDevice = { .name = TYPE_IPMI_INTERFACE, - .version_id = 1, + .version_id = 2, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_BOOL(kcs.obf_irq_set, ISAIPMIKCSDevice), - VMSTATE_BOOL(kcs.atn_irq_set, ISAIPMIKCSDevice), - VMSTATE_BOOL(kcs.use_irq, ISAIPMIKCSDevice), - VMSTATE_BOOL(kcs.irqs_enabled, ISAIPMIKCSDevice), - VMSTATE_UINT32(kcs.outpos, ISAIPMIKCSDevice), - VMSTATE_UINT8_ARRAY(kcs.outmsg, ISAIPMIKCSDevice, MAX_IPMI_MSG_SIZE), - VMSTATE_UINT8_ARRAY(kcs.inmsg, ISAIPMIKCSDevice, MAX_IPMI_MSG_SIZE), - VMSTATE_BOOL(kcs.write_end, ISAIPMIKCSDevice), - VMSTATE_UINT8(kcs.status_reg, ISAIPMIKCSDevice), - VMSTATE_UINT8(kcs.data_out_reg, ISAIPMIKCSDevice), - VMSTATE_INT16(kcs.data_in_reg, ISAIPMIKCSDevice), - VMSTATE_INT16(kcs.cmd_reg, ISAIPMIKCSDevice), - VMSTATE_UINT8(kcs.waiting_rsp, ISAIPMIKCSDevice), + VMSTATE_VSTRUCT_TEST(kcs, ISAIPMIKCSDevice, vmstate_kcs_before_version2, + 0, vmstate_IPMIKCS, IPMIKCS, 1), + VMSTATE_VSTRUCT_V(kcs, ISAIPMIKCSDevice, 2, vmstate_IPMIKCS, + IPMIKCS, 2), VMSTATE_END_OF_LIST() } }; @@ -450,6 +496,11 @@ static void isa_ipmi_kcs_init(Object *obj) ipmi_bmc_find_and_link(obj, (Object **) &iik->kcs.bmc); + /* + * Version 1 had an incorrect name, it clashed with the BT + * IPMI device, so receive it, but transmit a different + * version. + */ vmstate_register(NULL, 0, &vmstate_ISAIPMIKCSDevice, iik); }