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

Commit 396c9df2 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull locking fixes from Ingo Molnar:
 "Two fixes: an smp-call fix and a lockdep fix"

* 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  smp: Fix smp_call_function_single_async() locking
  lockdep: Make print_lock() robust against concurrent release
parents 8f502d5b 8053871d
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -551,7 +551,21 @@ static void print_lockdep_cache(struct lockdep_map *lock)

static void print_lock(struct held_lock *hlock)
{
	print_lock_name(hlock_class(hlock));
	/*
	 * We can be called locklessly through debug_show_all_locks() so be
	 * extra careful, the hlock might have been released and cleared.
	 */
	unsigned int class_idx = hlock->class_idx;

	/* Don't re-read hlock->class_idx, can't use READ_ONCE() on bitfields: */
	barrier();

	if (!class_idx || (class_idx - 1) >= MAX_LOCKDEP_KEYS) {
		printk("<RELEASED>\n");
		return;
	}

	print_lock_name(lock_classes + class_idx - 1);
	printk(", at: ");
	print_ip_sym(hlock->acquire_ip);
}
+47 −31
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@

enum {
	CSD_FLAG_LOCK		= 0x01,
	CSD_FLAG_WAIT		= 0x02,
	CSD_FLAG_SYNCHRONOUS	= 0x02,
};

struct call_function_data {
@@ -107,7 +107,7 @@ void __init call_function_init(void)
 */
static void csd_lock_wait(struct call_single_data *csd)
{
	while (csd->flags & CSD_FLAG_LOCK)
	while (smp_load_acquire(&csd->flags) & CSD_FLAG_LOCK)
		cpu_relax();
}

@@ -121,19 +121,17 @@ static void csd_lock(struct call_single_data *csd)
	 * to ->flags with any subsequent assignments to other
	 * fields of the specified call_single_data structure:
	 */
	smp_mb();
	smp_wmb();
}

static void csd_unlock(struct call_single_data *csd)
{
	WARN_ON((csd->flags & CSD_FLAG_WAIT) && !(csd->flags & CSD_FLAG_LOCK));
	WARN_ON(!(csd->flags & CSD_FLAG_LOCK));

	/*
	 * ensure we're all done before releasing data:
	 */
	smp_mb();

	csd->flags &= ~CSD_FLAG_LOCK;
	smp_store_release(&csd->flags, 0);
}

static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_single_data, csd_data);
@@ -144,13 +142,16 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_single_data, csd_data);
 * ->func, ->info, and ->flags set.
 */
static int generic_exec_single(int cpu, struct call_single_data *csd,
			       smp_call_func_t func, void *info, int wait)
			       smp_call_func_t func, void *info)
{
	struct call_single_data csd_stack = { .flags = 0 };
	if (cpu == smp_processor_id()) {
		unsigned long flags;


	if (cpu == smp_processor_id()) {
		/*
		 * We can unlock early even for the synchronous on-stack case,
		 * since we're doing this from the same CPU..
		 */
		csd_unlock(csd);
		local_irq_save(flags);
		func(info);
		local_irq_restore(flags);
@@ -161,21 +162,9 @@ static int generic_exec_single(int cpu, struct call_single_data *csd,
	if ((unsigned)cpu >= nr_cpu_ids || !cpu_online(cpu))
		return -ENXIO;


	if (!csd) {
		csd = &csd_stack;
		if (!wait)
			csd = this_cpu_ptr(&csd_data);
	}

	csd_lock(csd);

	csd->func = func;
	csd->info = info;

	if (wait)
		csd->flags |= CSD_FLAG_WAIT;

	/*
	 * The list addition should be visible before sending the IPI
	 * handler locks the list to pull the entry off it because of
@@ -190,9 +179,6 @@ static int generic_exec_single(int cpu, struct call_single_data *csd,
	if (llist_add(&csd->llist, &per_cpu(call_single_queue, cpu)))
		arch_send_call_function_single_ipi(cpu);

	if (wait)
		csd_lock_wait(csd);

	return 0;
}

@@ -250,8 +236,17 @@ static void flush_smp_call_function_queue(bool warn_cpu_offline)
	}

	llist_for_each_entry_safe(csd, csd_next, entry, llist) {
		csd->func(csd->info);
		smp_call_func_t func = csd->func;
		void *info = csd->info;

		/* Do we wait until *after* callback? */
		if (csd->flags & CSD_FLAG_SYNCHRONOUS) {
			func(info);
			csd_unlock(csd);
		} else {
			csd_unlock(csd);
			func(info);
		}
	}

	/*
@@ -274,6 +269,8 @@ static void flush_smp_call_function_queue(bool warn_cpu_offline)
int smp_call_function_single(int cpu, smp_call_func_t func, void *info,
			     int wait)
{
	struct call_single_data *csd;
	struct call_single_data csd_stack = { .flags = CSD_FLAG_LOCK | CSD_FLAG_SYNCHRONOUS };
	int this_cpu;
	int err;

@@ -292,7 +289,16 @@ int smp_call_function_single(int cpu, smp_call_func_t func, void *info,
	WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
		     && !oops_in_progress);

	err = generic_exec_single(cpu, NULL, func, info, wait);
	csd = &csd_stack;
	if (!wait) {
		csd = this_cpu_ptr(&csd_data);
		csd_lock(csd);
	}

	err = generic_exec_single(cpu, csd, func, info);

	if (wait)
		csd_lock_wait(csd);

	put_cpu();

@@ -321,7 +327,15 @@ int smp_call_function_single_async(int cpu, struct call_single_data *csd)
	int err = 0;

	preempt_disable();
	err = generic_exec_single(cpu, csd, csd->func, csd->info, 0);

	/* We could deadlock if we have to wait here with interrupts disabled! */
	if (WARN_ON_ONCE(csd->flags & CSD_FLAG_LOCK))
		csd_lock_wait(csd);

	csd->flags = CSD_FLAG_LOCK;
	smp_wmb();

	err = generic_exec_single(cpu, csd, csd->func, csd->info);
	preempt_enable();

	return err;
@@ -433,6 +447,8 @@ void smp_call_function_many(const struct cpumask *mask,
		struct call_single_data *csd = per_cpu_ptr(cfd->csd, cpu);

		csd_lock(csd);
		if (wait)
			csd->flags |= CSD_FLAG_SYNCHRONOUS;
		csd->func = func;
		csd->info = info;
		llist_add(&csd->llist, &per_cpu(call_single_queue, cpu));