Skip to content

Commit

Permalink
Merge tag 'stable/for-linus-3.11-rc0-tag-two' of git://git.kernel.org…
Browse files Browse the repository at this point in the history
…/pub/scm/linux/kernel/git/konrad/xen

Pull Xen bugfixes from Konrad Rzeszutek Wilk:
 - Fix memory leak when CPU hotplugging.
 - Compile bugs with various #ifdefs
 - Fix state changes in Xen PCI front not dealing well with new
   toolstack.
 - Cleanups in code (use pr_*, fix 80 characters splits, etc)
 - Long standing bug in double-reporting the steal time

* tag 'stable/for-linus-3.11-rc0-tag-two' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen:
  xen/time: remove blocked time accounting from xen "clockchip"
  xen: Convert printks to pr_<level>
  xen: ifdef CONFIG_HIBERNATE_CALLBACKS xen_*_suspend
  xen/pcifront: Deal with toolstack missing 'XenbusStateClosing' state.
  xen/time: Free onlined per-cpu data structure if we want to online it again.
  xen/time: Check that the per_cpu data structure has data before freeing.
  xen/time: Don't leak interrupt name when offlining.
  xen/time: Encapsulate the struct clock_event_device in another structure.
  xen/spinlock: Don't leak interrupt name when offlining.
  xen/smp: Don't leak interrupt name when offlining.
  xen/smp: Set the per-cpu IRQ number to a valid default.
  xen/smp: Introduce a common structure to contain the IRQ name and interrupt line.
  xen/smp: Coalesce the free_irq calls in one function.
  xen-pciback: fix error return code in pcistub_irq_handler_switch()
  • Loading branch information
Linus Torvalds committed Jul 3, 2013
2 parents f3acb96 + 0b0c002 commit 3e34131
Show file tree
Hide file tree
Showing 38 changed files with 321 additions and 265 deletions.
91 changes: 59 additions & 32 deletions arch/x86/xen/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,15 @@

cpumask_var_t xen_cpu_initialized_map;

static DEFINE_PER_CPU(int, xen_resched_irq);
static DEFINE_PER_CPU(int, xen_callfunc_irq);
static DEFINE_PER_CPU(int, xen_callfuncsingle_irq);
static DEFINE_PER_CPU(int, xen_irq_work);
static DEFINE_PER_CPU(int, xen_debug_irq) = -1;
struct xen_common_irq {
int irq;
char *name;
};
static DEFINE_PER_CPU(struct xen_common_irq, xen_resched_irq) = { .irq = -1 };
static DEFINE_PER_CPU(struct xen_common_irq, xen_callfunc_irq) = { .irq = -1 };
static DEFINE_PER_CPU(struct xen_common_irq, xen_callfuncsingle_irq) = { .irq = -1 };
static DEFINE_PER_CPU(struct xen_common_irq, xen_irq_work) = { .irq = -1 };
static DEFINE_PER_CPU(struct xen_common_irq, xen_debug_irq) = { .irq = -1 };

static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id);
static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id);
Expand Down Expand Up @@ -99,10 +103,47 @@ static void __cpuinit cpu_bringup_and_idle(void)
cpu_startup_entry(CPUHP_ONLINE);
}

static void xen_smp_intr_free(unsigned int cpu)
{
if (per_cpu(xen_resched_irq, cpu).irq >= 0) {
unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu).irq, NULL);
per_cpu(xen_resched_irq, cpu).irq = -1;
kfree(per_cpu(xen_resched_irq, cpu).name);
per_cpu(xen_resched_irq, cpu).name = NULL;
}
if (per_cpu(xen_callfunc_irq, cpu).irq >= 0) {
unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu).irq, NULL);
per_cpu(xen_callfunc_irq, cpu).irq = -1;
kfree(per_cpu(xen_callfunc_irq, cpu).name);
per_cpu(xen_callfunc_irq, cpu).name = NULL;
}
if (per_cpu(xen_debug_irq, cpu).irq >= 0) {
unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu).irq, NULL);
per_cpu(xen_debug_irq, cpu).irq = -1;
kfree(per_cpu(xen_debug_irq, cpu).name);
per_cpu(xen_debug_irq, cpu).name = NULL;
}
if (per_cpu(xen_callfuncsingle_irq, cpu).irq >= 0) {
unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu).irq,
NULL);
per_cpu(xen_callfuncsingle_irq, cpu).irq = -1;
kfree(per_cpu(xen_callfuncsingle_irq, cpu).name);
per_cpu(xen_callfuncsingle_irq, cpu).name = NULL;
}
if (xen_hvm_domain())
return;

if (per_cpu(xen_irq_work, cpu).irq >= 0) {
unbind_from_irqhandler(per_cpu(xen_irq_work, cpu).irq, NULL);
per_cpu(xen_irq_work, cpu).irq = -1;
kfree(per_cpu(xen_irq_work, cpu).name);
per_cpu(xen_irq_work, cpu).name = NULL;
}
};
static int xen_smp_intr_init(unsigned int cpu)
{
int rc;
const char *resched_name, *callfunc_name, *debug_name;
char *resched_name, *callfunc_name, *debug_name;

resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu);
rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR,
Expand All @@ -113,7 +154,8 @@ static int xen_smp_intr_init(unsigned int cpu)
NULL);
if (rc < 0)
goto fail;
per_cpu(xen_resched_irq, cpu) = rc;
per_cpu(xen_resched_irq, cpu).irq = rc;
per_cpu(xen_resched_irq, cpu).name = resched_name;

callfunc_name = kasprintf(GFP_KERNEL, "callfunc%d", cpu);
rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_VECTOR,
Expand All @@ -124,15 +166,17 @@ static int xen_smp_intr_init(unsigned int cpu)
NULL);
if (rc < 0)
goto fail;
per_cpu(xen_callfunc_irq, cpu) = rc;
per_cpu(xen_callfunc_irq, cpu).irq = rc;
per_cpu(xen_callfunc_irq, cpu).name = callfunc_name;

debug_name = kasprintf(GFP_KERNEL, "debug%d", cpu);
rc = bind_virq_to_irqhandler(VIRQ_DEBUG, cpu, xen_debug_interrupt,
IRQF_DISABLED | IRQF_PERCPU | IRQF_NOBALANCING,
debug_name, NULL);
if (rc < 0)
goto fail;
per_cpu(xen_debug_irq, cpu) = rc;
per_cpu(xen_debug_irq, cpu).irq = rc;
per_cpu(xen_debug_irq, cpu).name = debug_name;

callfunc_name = kasprintf(GFP_KERNEL, "callfuncsingle%d", cpu);
rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_SINGLE_VECTOR,
Expand All @@ -143,7 +187,8 @@ static int xen_smp_intr_init(unsigned int cpu)
NULL);
if (rc < 0)
goto fail;
per_cpu(xen_callfuncsingle_irq, cpu) = rc;
per_cpu(xen_callfuncsingle_irq, cpu).irq = rc;
per_cpu(xen_callfuncsingle_irq, cpu).name = callfunc_name;

/*
* The IRQ worker on PVHVM goes through the native path and uses the
Expand All @@ -161,26 +206,13 @@ static int xen_smp_intr_init(unsigned int cpu)
NULL);
if (rc < 0)
goto fail;
per_cpu(xen_irq_work, cpu) = rc;
per_cpu(xen_irq_work, cpu).irq = rc;
per_cpu(xen_irq_work, cpu).name = callfunc_name;

return 0;

fail:
if (per_cpu(xen_resched_irq, cpu) >= 0)
unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu), NULL);
if (per_cpu(xen_callfunc_irq, cpu) >= 0)
unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu), NULL);
if (per_cpu(xen_debug_irq, cpu) >= 0)
unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu), NULL);
if (per_cpu(xen_callfuncsingle_irq, cpu) >= 0)
unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu),
NULL);
if (xen_hvm_domain())
return rc;

if (per_cpu(xen_irq_work, cpu) >= 0)
unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL);

xen_smp_intr_free(cpu);
return rc;
}

Expand Down Expand Up @@ -433,12 +465,7 @@ static void xen_cpu_die(unsigned int cpu)
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(HZ/10);
}
unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu), NULL);
unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu), NULL);
unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu), NULL);
unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu), NULL);
if (!xen_hvm_domain())
unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL);
xen_smp_intr_free(cpu);
xen_uninit_lock_cpu(cpu);
xen_teardown_timer(cpu);
}
Expand Down
7 changes: 6 additions & 1 deletion arch/x86/xen/spinlock.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <linux/debugfs.h>
#include <linux/log2.h>
#include <linux/gfp.h>
#include <linux/slab.h>

#include <asm/paravirt.h>

Expand Down Expand Up @@ -165,6 +166,7 @@ static int xen_spin_trylock(struct arch_spinlock *lock)
return old == 0;
}

static DEFINE_PER_CPU(char *, irq_name);
static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
static DEFINE_PER_CPU(struct xen_spinlock *, lock_spinners);

Expand Down Expand Up @@ -362,7 +364,7 @@ static irqreturn_t dummy_handler(int irq, void *dev_id)
void __cpuinit xen_init_lock_cpu(int cpu)
{
int irq;
const char *name;
char *name;

WARN(per_cpu(lock_kicker_irq, cpu) >= 0, "spinlock on CPU%d exists on IRQ%d!\n",
cpu, per_cpu(lock_kicker_irq, cpu));
Expand All @@ -385,6 +387,7 @@ void __cpuinit xen_init_lock_cpu(int cpu)
if (irq >= 0) {
disable_irq(irq); /* make sure it's never delivered */
per_cpu(lock_kicker_irq, cpu) = irq;
per_cpu(irq_name, cpu) = name;
}

printk("cpu %d spinlock event irq %d\n", cpu, irq);
Expand All @@ -401,6 +404,8 @@ void xen_uninit_lock_cpu(int cpu)

unbind_from_irqhandler(per_cpu(lock_kicker_irq, cpu), NULL);
per_cpu(lock_kicker_irq, cpu) = -1;
kfree(per_cpu(irq_name, cpu));
per_cpu(irq_name, cpu) = NULL;
}

void __init xen_init_spinlocks(void)
Expand Down
58 changes: 30 additions & 28 deletions arch/x86/xen/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <linux/kernel_stat.h>
#include <linux/math64.h>
#include <linux/gfp.h>
#include <linux/slab.h>

#include <asm/pvclock.h>
#include <asm/xen/hypervisor.h>
Expand All @@ -36,9 +37,8 @@ static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate);
/* snapshots of runstate info */
static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate_snapshot);

/* unused ns of stolen and blocked time */
/* unused ns of stolen time */
static DEFINE_PER_CPU(u64, xen_residual_stolen);
static DEFINE_PER_CPU(u64, xen_residual_blocked);

/* return an consistent snapshot of 64-bit time/counter value */
static u64 get64(const u64 *p)
Expand Down Expand Up @@ -115,7 +115,7 @@ static void do_stolen_accounting(void)
{
struct vcpu_runstate_info state;
struct vcpu_runstate_info *snap;
s64 blocked, runnable, offline, stolen;
s64 runnable, offline, stolen;
cputime_t ticks;

get_runstate_snapshot(&state);
Expand All @@ -125,7 +125,6 @@ static void do_stolen_accounting(void)
snap = &__get_cpu_var(xen_runstate_snapshot);

/* work out how much time the VCPU has not been runn*ing* */
blocked = state.time[RUNSTATE_blocked] - snap->time[RUNSTATE_blocked];
runnable = state.time[RUNSTATE_runnable] - snap->time[RUNSTATE_runnable];
offline = state.time[RUNSTATE_offline] - snap->time[RUNSTATE_offline];

Expand All @@ -141,17 +140,6 @@ static void do_stolen_accounting(void)
ticks = iter_div_u64_rem(stolen, NS_PER_TICK, &stolen);
__this_cpu_write(xen_residual_stolen, stolen);
account_steal_ticks(ticks);

/* Add the appropriate number of ticks of blocked time,
including any left-overs from last time. */
blocked += __this_cpu_read(xen_residual_blocked);

if (blocked < 0)
blocked = 0;

ticks = iter_div_u64_rem(blocked, NS_PER_TICK, &blocked);
__this_cpu_write(xen_residual_blocked, blocked);
account_idle_ticks(ticks);
}

/* Get the TSC speed from Xen */
Expand Down Expand Up @@ -377,11 +365,16 @@ static const struct clock_event_device xen_vcpuop_clockevent = {

static const struct clock_event_device *xen_clockevent =
&xen_timerop_clockevent;
static DEFINE_PER_CPU(struct clock_event_device, xen_clock_events) = { .irq = -1 };

struct xen_clock_event_device {
struct clock_event_device evt;
char *name;
};
static DEFINE_PER_CPU(struct xen_clock_event_device, xen_clock_events) = { .evt.irq = -1 };

static irqreturn_t xen_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = &__get_cpu_var(xen_clock_events);
struct clock_event_device *evt = &__get_cpu_var(xen_clock_events).evt;
irqreturn_t ret;

ret = IRQ_NONE;
Expand All @@ -395,14 +388,30 @@ static irqreturn_t xen_timer_interrupt(int irq, void *dev_id)
return ret;
}

void xen_teardown_timer(int cpu)
{
struct clock_event_device *evt;
BUG_ON(cpu == 0);
evt = &per_cpu(xen_clock_events, cpu).evt;

if (evt->irq >= 0) {
unbind_from_irqhandler(evt->irq, NULL);
evt->irq = -1;
kfree(per_cpu(xen_clock_events, cpu).name);
per_cpu(xen_clock_events, cpu).name = NULL;
}
}

void xen_setup_timer(int cpu)
{
const char *name;
char *name;
struct clock_event_device *evt;
int irq;

evt = &per_cpu(xen_clock_events, cpu);
evt = &per_cpu(xen_clock_events, cpu).evt;
WARN(evt->irq >= 0, "IRQ%d for CPU%d is already allocated\n", evt->irq, cpu);
if (evt->irq >= 0)
xen_teardown_timer(cpu);

printk(KERN_INFO "installing Xen timer for CPU %d\n", cpu);

Expand All @@ -420,22 +429,15 @@ void xen_setup_timer(int cpu)

evt->cpumask = cpumask_of(cpu);
evt->irq = irq;
per_cpu(xen_clock_events, cpu).name = name;
}

void xen_teardown_timer(int cpu)
{
struct clock_event_device *evt;
BUG_ON(cpu == 0);
evt = &per_cpu(xen_clock_events, cpu);
unbind_from_irqhandler(evt->irq, NULL);
evt->irq = -1;
}

void xen_setup_cpu_clockevents(void)
{
BUG_ON(preemptible());

clockevents_register_device(&__get_cpu_var(xen_clock_events));
clockevents_register_device(&__get_cpu_var(xen_clock_events).evt);
}

void xen_timer_resume(void)
Expand Down
7 changes: 3 additions & 4 deletions drivers/pci/xen-pcifront.c
Original file line number Diff line number Diff line change
Expand Up @@ -678,10 +678,9 @@ static int pcifront_connect_and_init_dma(struct pcifront_device *pdev)
if (!pcifront_dev) {
dev_info(&pdev->xdev->dev, "Installing PCI frontend\n");
pcifront_dev = pdev;
} else {
dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
} else
err = -EEXIST;
}

spin_unlock(&pcifront_dev_lock);

if (!err && !swiotlb_nr_tbl()) {
Expand Down Expand Up @@ -848,7 +847,7 @@ static int pcifront_try_connect(struct pcifront_device *pdev)
goto out;

err = pcifront_connect_and_init_dma(pdev);
if (err) {
if (err && err != -EEXIST) {
xenbus_dev_fatal(pdev->xdev, err,
"Error setting up PCI Frontend");
goto out;
Expand Down
6 changes: 4 additions & 2 deletions drivers/xen/balloon.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
* IN THE SOFTWARE.
*/

#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt

#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
Expand Down Expand Up @@ -242,7 +244,7 @@ static enum bp_state reserve_additional_memory(long credit)
rc = add_memory(nid, hotplug_start_paddr, balloon_hotplug << PAGE_SHIFT);

if (rc) {
pr_info("xen_balloon: %s: add_memory() failed: %i\n", __func__, rc);
pr_info("%s: add_memory() failed: %i\n", __func__, rc);
return BP_EAGAIN;
}

Expand Down Expand Up @@ -591,7 +593,7 @@ static int __init balloon_init(void)
if (!xen_domain())
return -ENODEV;

pr_info("xen/balloon: Initialising balloon driver.\n");
pr_info("Initialising balloon driver\n");

balloon_stats.current_pages = xen_pv_domain()
? min(xen_start_info->nr_pages - xen_released_pages, max_pfn)
Expand Down
6 changes: 4 additions & 2 deletions drivers/xen/cpu_hotplug.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt

#include <linux/notifier.h>

#include <xen/xen.h>
Expand Down Expand Up @@ -31,7 +33,7 @@ static int vcpu_online(unsigned int cpu)
err = xenbus_scanf(XBT_NIL, dir, "availability", "%15s", state);
if (err != 1) {
if (!xen_initial_domain())
printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
pr_err("Unable to read cpu state\n");
return err;
}

Expand All @@ -40,7 +42,7 @@ static int vcpu_online(unsigned int cpu)
else if (strcmp(state, "offline") == 0)
return 0;

printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n", state, cpu);
pr_err("unknown state(%s) on CPU%d\n", state, cpu);
return -EINVAL;
}
static void vcpu_hotplug(unsigned int cpu)
Expand Down
Loading

0 comments on commit 3e34131

Please sign in to comment.