Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3e34131a authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'stable/for-linus-3.11-rc0-tag-two' of...

Merge tag 'stable/for-linus-3.11-rc0-tag-two' of git://git.kernel.org/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()
parents f3acb96f 0b0c002c
Loading
Loading
Loading
Loading
+59 −32
Original line number Diff line number Diff line
@@ -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);
@@ -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,
@@ -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,
@@ -124,7 +166,8 @@ 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,
@@ -132,7 +175,8 @@ static int xen_smp_intr_init(unsigned int cpu)
				     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,
@@ -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
@@ -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;
}

@@ -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);
}
+6 −1
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#include <linux/debugfs.h>
#include <linux/log2.h>
#include <linux/gfp.h>
#include <linux/slab.h>

#include <asm/paravirt.h>

@@ -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);

@@ -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));
@@ -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);
@@ -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)
+30 −28
Original line number Diff line number Diff line
@@ -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>
@@ -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)
@@ -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);
@@ -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];

@@ -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 */
@@ -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;
@@ -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);

@@ -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)
+3 −4
Original line number Diff line number Diff line
@@ -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()) {
@@ -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;
+4 −2
Original line number Diff line number Diff line
@@ -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>
@@ -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;
	}

@@ -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)
Loading