[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 3/3] piix4acpi, xen, hotplug: Fix race with ACPI AML code and hotplug.
On Mon, 13 May 2013, Konrad Rzeszutek Wilk wrote: > >From 950424a5e6a481dd1b2b4fb2645e7a852c199b7f Mon Sep 17 00:00:00 2001 > From: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx> > Date: Mon, 13 May 2013 11:55:42 -0400 > Subject: [PATCH] piix4acpi, xen, hotplug: Fix race with ACPI AML code and > hotplug. > > This is a race so the amount varies but on a 4PCPU box > I seem to get only ~14 out of 16 vCPUs I want to online. > > The issue at hand is that QEMU xenstore.c hotplug code changes > the vCPU array and triggers an ACPI SCI for each vCPU > online/offline change. That means we modify the array of vCPUs > as the guests ACPI AML code is reading it - resulting in > the guest reading the data only once and not changing the > CPU states appropiately. > > The fix is to seperate the vCPU array changes from the ACPI SCI > notification. The code now will enumerate all of the vCPUs > and change the vCPU array if there is a need for a change. > If a change did occur then only _one_ ACPI SCI pulse is sent > to the guest. The vCPU array at that point has the online/offline > modified to what the user wanted to have. > > Specifically, if a user provided this command: > xl vcpu-set latest 16 > > (guest config has vcpus=1, maxvcpus=32) QEMU and the guest > (in this case Linux) would do: > > QEMU: Guest OS: > -xenstore_process_vcpu_set_event > -> Gets an XenBus notification for CPU1 > -> Updates the gpe_state.cpus_state bitfield. > -> Pulses the ACPI SCI > - ACPI SCI kicks in > > -> Gets an XenBus notification for CPU2 > -> Updates the gpe_state.cpus_state bitfield. > -> Pulses the ACPI SCI > > -> Gets an XenBus notification for CPU3 > -> Updates the gpe_state.cpus_state bitfield. > -> Pulses the ACPI SCI > ... > - Method(PRST) invoked > > -> Gets an XenBus notification for CPU12 > -> Updates the gpe_state.cpus_state bitfield. > -> Pulses the ACPI SCI > - reads AF00 for CPU state > [gets 0xff] > - reads AF02 [gets 0x7f] > > -> Gets an XenBus notification for CPU13 > -> Updates the gpe_state.cpus_state bitfield. > -> Pulses the ACPI SCI > > .. until VCPU 16 > - Method PRST updates > PR01 through 13 FLG > entry. > - PR01->PR13 _MAD > invoked. > > - Brings up 13 CPUs. > > While QEMU updates the rest of the cpus_state bitfields the ACPI AML > only does the CPU hotplug on those it had read. > > [v1: Use stack for the 'attr' instead of malloc/free] > Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx> Acked-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx> > xenstore.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- > 1 files changed, 59 insertions(+), 6 deletions(-) > > diff --git a/xenstore.c b/xenstore.c > index c861d36..b0d6f77 100644 > --- a/xenstore.c > +++ b/xenstore.c > @@ -22,6 +22,7 @@ > #include "pci.h" > #include "qemu-timer.h" > #include "qemu-xen.h" > +#include "xen_backend.h" > > struct xs_handle *xsh = NULL; > static char *media_filename[MAX_DRIVES+1]; > @@ -999,25 +1000,24 @@ void xenstore_record_dm_state(const char *state) > { > xenstore_record_dm("state", state); > } > - > -static void xenstore_process_vcpu_set_event(char **vec) > +static int xenstore_process_one_vcpu_set_event(char *node) > { > char *act = NULL; > - char *vcpustr, *node = vec[XS_WATCH_PATH]; > + char *vcpustr; > unsigned int vcpu, len; > int changed = -EINVAL; > > vcpustr = strstr(node, "cpu/"); > if (!vcpustr) { > fprintf(stderr, "vcpu-set: watch node error.\n"); > - return; > + return changed; > } > sscanf(vcpustr, "cpu/%u", &vcpu); > > act = xs_read(xsh, XBT_NULL, node, &len); > if (!act) { > fprintf(stderr, "vcpu-set: no command yet.\n"); > - return; > + return changed; > } > > if (!strncmp(act, "online", len)) > @@ -1028,8 +1028,61 @@ static void xenstore_process_vcpu_set_event(char **vec) > fprintf(stderr, "vcpu-set: command error.\n"); > > free(act); > - if (changed > 0) > + return changed; > +} > +static void xenstore_process_vcpu_set_event(char **vec) > +{ > + int changed = 0, rc, i, num = 0; > + char *vcpu, **dir; > + char *path = vec[XS_WATCH_PATH]; > + > + /* > + * Process the event right away in case the loop below fails > + * to get to vCPU that is in the event. > + */ > + rc = xenstore_process_one_vcpu_set_event(path); > + if (rc > 0) > + changed = 1; > + /* > + * We get: /local/domain/<domid>/cpu/<vcpu>/availability or > + * (at init) /local/domain/<domid>/cpu [ignore it] and need to > + * iterate over /local/domain/<domid>/cpu/ directory. > + */ > + vcpu = strstr(path, "cpu/"); > + if (!vcpu) { > + fprintf(stderr,"[%s]: %s has no CPU!\n", __func__, path); > + return; > + } > + /* Eliminate '/availability' */ > + vcpu[3] = '\0'; > + dir = xs_directory(xsh, XBT_NULL, path, &num); > + > + if (!dir) { > + fprintf(stderr, "[%s]: directory %s has no dirs!\n", __func__, path); > + return; > + } > + if (num != vcpus) > + fprintf(stderr, "[%s]: %d (number of vcpu entries) != %d (maxvcpus)! > "\ > + "Continuing on..\n", __func__, num, vcpus); > + > + for (i = 0; i < num; i++) { > + char attr[XEN_BUFSIZE]; > + > + /* Construct "/local/domain/<domid>/cpu" (path) with <vcpu> (attr), > + * and "availability" with '/' sprinkled around. */ > + snprintf(attr, XEN_BUFSIZE, "%s/%s/%s", path, dir[i], > "availability"); > + rc = xenstore_process_one_vcpu_set_event(attr); > + > + if (rc > 0) > + changed = 1; > + if (rc < 0) /* say xs_read failed */ > + break; > + } > + free (dir); > + if (changed > 0) { > + fprintf(stderr, "Notifying OS about CPU hotplug changes.\n"); > qemu_cpu_notify(); > + } > return; > } _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |