Commit 75df529b authored by Andrew Jones's avatar Andrew Jones Committed by Catalin Marinas
Browse files

arm64: paravirt: Initialize steal time when cpu is online



Steal time initialization requires mapping a memory region which
invokes a memory allocation. Doing this at CPU starting time results
in the following trace when CONFIG_DEBUG_ATOMIC_SLEEP is enabled:

BUG: sleeping function called from invalid context at mm/slab.h:498
in_atomic(): 1, irqs_disabled(): 128, non_block: 0, pid: 0, name: swapper/1
CPU: 1 PID: 0 Comm: swapper/1 Not tainted 5.9.0-rc5+ #1
Call trace:
 dump_backtrace+0x0/0x208
 show_stack+0x1c/0x28
 dump_stack+0xc4/0x11c
 ___might_sleep+0xf8/0x130
 __might_sleep+0x58/0x90
 slab_pre_alloc_hook.constprop.101+0xd0/0x118
 kmem_cache_alloc_node_trace+0x84/0x270
 __get_vm_area_node+0x88/0x210
 get_vm_area_caller+0x38/0x40
 __ioremap_caller+0x70/0xf8
 ioremap_cache+0x78/0xb0
 memremap+0x9c/0x1a8
 init_stolen_time_cpu+0x54/0xf0
 cpuhp_invoke_callback+0xa8/0x720
 notify_cpu_starting+0xc8/0xd8
 secondary_start_kernel+0x114/0x180
CPU1: Booted secondary processor 0x0000000001 [0x431f0a11]

However we don't need to initialize steal time at CPU starting time.
We can simply wait until CPU online time, just sacrificing a bit of
accuracy by returning zero for steal time until we know better.

While at it, add __init to the functions that are only called by
pv_time_init() which is __init.

Signed-off-by: default avatarAndrew Jones <drjones@redhat.com>
Fixes: e0685fa2 ("arm64: Retrieve stolen time as paravirtualized guest")
Cc: stable@vger.kernel.org
Reviewed-by: default avatarSteven Price <steven.price@arm.com>
Link: https://lore.kernel.org/r/20200916154530.40809-1-drjones@redhat.com


Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 32f6865c
Loading
Loading
Loading
Loading
+15 −11
Original line number Diff line number Diff line
@@ -50,16 +50,19 @@ static u64 pv_steal_clock(int cpu)
	struct pv_time_stolen_time_region *reg;

	reg = per_cpu_ptr(&stolen_time_region, cpu);
	if (!reg->kaddr) {
		pr_warn_once("stolen time enabled but not configured for cpu %d\n",
			     cpu);

	/*
	 * paravirt_steal_clock() may be called before the CPU
	 * online notification callback runs. Until the callback
	 * has run we just return zero.
	 */
	if (!reg->kaddr)
		return 0;
	}

	return le64_to_cpu(READ_ONCE(reg->kaddr->stolen_time));
}

static int stolen_time_dying_cpu(unsigned int cpu)
static int stolen_time_cpu_down_prepare(unsigned int cpu)
{
	struct pv_time_stolen_time_region *reg;

@@ -73,7 +76,7 @@ static int stolen_time_dying_cpu(unsigned int cpu)
	return 0;
}

static int init_stolen_time_cpu(unsigned int cpu)
static int stolen_time_cpu_online(unsigned int cpu)
{
	struct pv_time_stolen_time_region *reg;
	struct arm_smccc_res res;
@@ -103,19 +106,20 @@ static int init_stolen_time_cpu(unsigned int cpu)
	return 0;
}

static int pv_time_init_stolen_time(void)
static int __init pv_time_init_stolen_time(void)
{
	int ret;

	ret = cpuhp_setup_state(CPUHP_AP_ARM_KVMPV_STARTING,
				"hypervisor/arm/pvtime:starting",
				init_stolen_time_cpu, stolen_time_dying_cpu);
	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
				"hypervisor/arm/pvtime:online",
				stolen_time_cpu_online,
				stolen_time_cpu_down_prepare);
	if (ret < 0)
		return ret;
	return 0;
}

static bool has_pv_steal_clock(void)
static bool __init has_pv_steal_clock(void)
{
	struct arm_smccc_res res;

+0 −1
Original line number Diff line number Diff line
@@ -142,7 +142,6 @@ enum cpuhp_state {
	/* Must be the last timer callback */
	CPUHP_AP_DUMMY_TIMER_STARTING,
	CPUHP_AP_ARM_XEN_STARTING,
	CPUHP_AP_ARM_KVMPV_STARTING,
	CPUHP_AP_ARM_CORESIGHT_STARTING,
	CPUHP_AP_ARM_CORESIGHT_CTI_STARTING,
	CPUHP_AP_ARM64_ISNDEP_STARTING,