From c6207348dfef098226d946a179061f0ba0fdcf7d Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Tue, 28 Oct 2014 09:55:15 -0400 Subject: [PATCH] Linux v3.18-rc2-43-gf7e87a44ef60 - Add two RCU patches to fix a deadlock and a hang - Reenable debugging options. --- config-generic | 6 +- config-nodebug | 112 +++++------ config-x86-generic | 2 +- kernel.spec | 15 +- ...rier-understand-about-missing-rcuo-k.patch | 177 ++++++++++++++++++ ...lock-between-CPU-hotplug-and-expedit.patch | 67 +++++++ sources | 1 + 7 files changed, 318 insertions(+), 62 deletions(-) create mode 100644 rcu-Make-rcu_barrier-understand-about-missing-rcuo-k.patch create mode 100644 rcu-More-on-deadlock-between-CPU-hotplug-and-expedit.patch diff --git a/config-generic b/config-generic index acd9cc340..487fd7cb0 100644 --- a/config-generic +++ b/config-generic @@ -1699,13 +1699,13 @@ CONFIG_B43_PCMCIA=y CONFIG_B43_SDIO=y CONFIG_B43_BCMA=y CONFIG_B43_BCMA_PIO=y -# CONFIG_B43_DEBUG is not set +CONFIG_B43_DEBUG=y CONFIG_B43_PHY_LP=y CONFIG_B43_PHY_N=y CONFIG_B43_PHY_HT=y CONFIG_B43_PHY_G=y CONFIG_B43LEGACY=m -# CONFIG_B43LEGACY_DEBUG is not set +CONFIG_B43LEGACY_DEBUG=y CONFIG_B43LEGACY_DMA=y CONFIG_B43LEGACY_PIO=y CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y @@ -4694,7 +4694,7 @@ CONFIG_PM_DEBUG=y # CONFIG_DPM_WATCHDOG is not set # revisit this in debug CONFIG_PM_TRACE=y CONFIG_PM_TRACE_RTC=y -# CONFIG_PM_TEST_SUSPEND is not set +CONFIG_PM_TEST_SUSPEND=y CONFIG_PM_RUNTIME=y # CONFIG_PM_OPP is not set # CONFIG_PM_AUTOSLEEP is not set diff --git a/config-nodebug b/config-nodebug index ed6913376..143433bf8 100644 --- a/config-nodebug +++ b/config-nodebug @@ -2,115 +2,115 @@ CONFIG_SND_VERBOSE_PRINTK=y CONFIG_SND_DEBUG=y CONFIG_SND_PCM_XRUN_DEBUG=y -# CONFIG_DEBUG_ATOMIC_SLEEP is not set +CONFIG_DEBUG_ATOMIC_SLEEP=y -# CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_RT_MUTEXES is not set -# CONFIG_DEBUG_LOCK_ALLOC is not set -# CONFIG_LOCK_TORTURE_TEST is not set -# CONFIG_PROVE_LOCKING is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_PROVE_RCU is not set +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_LOCK_ALLOC=y +CONFIG_LOCK_TORTURE_TEST=m +CONFIG_PROVE_LOCKING=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_PROVE_RCU=y # CONFIG_PROVE_RCU_REPEATEDLY is not set -# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_DEBUG_PER_CPU_MAPS=y CONFIG_CPUMASK_OFFSTACK=y -# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set +CONFIG_CPU_NOTIFIER_ERROR_INJECT=m -# CONFIG_FAULT_INJECTION is not set -# CONFIG_FAILSLAB is not set -# CONFIG_FAIL_PAGE_ALLOC is not set -# CONFIG_FAIL_MAKE_REQUEST is not set -# CONFIG_FAULT_INJECTION_DEBUG_FS is not set -# CONFIG_FAULT_INJECTION_STACKTRACE_FILTER is not set -# CONFIG_FAIL_IO_TIMEOUT is not set -# CONFIG_FAIL_MMC_REQUEST is not set +CONFIG_FAULT_INJECTION=y +CONFIG_FAILSLAB=y +CONFIG_FAIL_PAGE_ALLOC=y +CONFIG_FAIL_MAKE_REQUEST=y +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y +CONFIG_FAIL_IO_TIMEOUT=y +CONFIG_FAIL_MMC_REQUEST=y -# CONFIG_LOCK_STAT is not set +CONFIG_LOCK_STAT=y -# CONFIG_DEBUG_STACK_USAGE is not set +CONFIG_DEBUG_STACK_USAGE=y -# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_DEBUG=y -# CONFIG_DEBUG_SG is not set -# CONFIG_DEBUG_PI_LIST is not set +CONFIG_DEBUG_SG=y +CONFIG_DEBUG_PI_LIST=y # CONFIG_DEBUG_PAGEALLOC is not set -# CONFIG_DEBUG_OBJECTS is not set +CONFIG_DEBUG_OBJECTS=y # CONFIG_DEBUG_OBJECTS_SELFTEST is not set -# CONFIG_DEBUG_OBJECTS_FREE is not set -# CONFIG_DEBUG_OBJECTS_TIMERS is not set -# CONFIG_DEBUG_OBJECTS_RCU_HEAD is not set +CONFIG_DEBUG_OBJECTS_FREE=y +CONFIG_DEBUG_OBJECTS_TIMERS=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1 -# CONFIG_X86_PTDUMP is not set -# CONFIG_EFI_PGT_DUMP is not set +CONFIG_X86_PTDUMP=y +CONFIG_EFI_PGT_DUMP=y -# CONFIG_CAN_DEBUG_DEVICES is not set +CONFIG_CAN_DEBUG_DEVICES=y -# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODULE_FORCE_UNLOAD=y -# CONFIG_DEBUG_NOTIFIERS is not set +CONFIG_DEBUG_NOTIFIERS=y -# CONFIG_DMA_API_DEBUG is not set +CONFIG_DMA_API_DEBUG=y -# CONFIG_MMIOTRACE is not set +CONFIG_MMIOTRACE=y -# CONFIG_DEBUG_CREDENTIALS is not set +CONFIG_DEBUG_CREDENTIALS=y # off in both production debug and nodebug builds, # on in rawhide nodebug builds -# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y -# CONFIG_EXT4_DEBUG is not set +CONFIG_EXT4_DEBUG=y # CONFIG_XFS_WARN is not set -# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_DEBUG_PERF_USE_VMALLOC=y -# CONFIG_JBD2_DEBUG is not set +CONFIG_JBD2_DEBUG=y -# CONFIG_NFSD_FAULT_INJECTION is not set +CONFIG_NFSD_FAULT_INJECTION=y -# CONFIG_DEBUG_BLK_CGROUP is not set +CONFIG_DEBUG_BLK_CGROUP=y -# CONFIG_DRBD_FAULT_INJECTION is not set +CONFIG_DRBD_FAULT_INJECTION=y -# CONFIG_ATH_DEBUG is not set -# CONFIG_CARL9170_DEBUGFS is not set -# CONFIG_IWLWIFI_DEVICE_TRACING is not set +CONFIG_ATH_DEBUG=y +CONFIG_CARL9170_DEBUGFS=y +CONFIG_IWLWIFI_DEVICE_TRACING=y # CONFIG_RTLWIFI_DEBUG is not set -# CONFIG_DEBUG_OBJECTS_WORK is not set +CONFIG_DEBUG_OBJECTS_WORK=y -# CONFIG_DMADEVICES_DEBUG is not set -# CONFIG_DMADEVICES_VDEBUG is not set +CONFIG_DMADEVICES_DEBUG=y +CONFIG_DMADEVICES_VDEBUG=y CONFIG_PM_ADVANCED_DEBUG=y -# CONFIG_CEPH_LIB_PRETTYDEBUG is not set -# CONFIG_QUOTA_DEBUG is not set +CONFIG_CEPH_LIB_PRETTYDEBUG=y +CONFIG_QUOTA_DEBUG=y CONFIG_KGDB_KDB=y CONFIG_KDB_KEYBOARD=y CONFIG_KDB_CONTINUE_CATASTROPHIC=0 -# CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER is not set +CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y # CONFIG_PERCPU_TEST is not set -# CONFIG_TEST_LIST_SORT is not set +CONFIG_TEST_LIST_SORT=y # CONFIG_TEST_STRING_HELPERS is not set -# CONFIG_DETECT_HUNG_TASK is not set +CONFIG_DETECT_HUNG_TASK=y CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 # CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set -# CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set +CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y -# CONFIG_DEBUG_KMEMLEAK is not set +CONFIG_DEBUG_KMEMLEAK=y CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=1024 # CONFIG_DEBUG_KMEMLEAK_TEST is not set CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y @@ -121,7 +121,7 @@ CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y # CONFIG_SPI_DEBUG is not set -# CONFIG_X86_DEBUG_STATIC_CPU_HAS is not set +CONFIG_X86_DEBUG_STATIC_CPU_HAS=y # CONFIG_SCHEDSTATS is not set # CONFIG_LATENCYTOP is not set diff --git a/config-x86-generic b/config-x86-generic index 59217f12b..2a12307ea 100644 --- a/config-x86-generic +++ b/config-x86-generic @@ -337,7 +337,7 @@ CONFIG_SP5100_TCO=m # CONFIG_MEMTEST is not set # CONFIG_DEBUG_TLBFLUSH is not set -# CONFIG_MAXSMP is not set +CONFIG_MAXSMP=y CONFIG_HP_ILO=m diff --git a/kernel.spec b/kernel.spec index eceb18a2e..f5a45f24d 100644 --- a/kernel.spec +++ b/kernel.spec @@ -69,7 +69,7 @@ Summary: The Linux kernel # The rc snapshot level %define rcrev 2 # The git snapshot level -%define gitrev 0 +%define gitrev 1 # Set rpm version accordingly %define rpmversion 3.%{upstream_sublevel}.0 %endif @@ -124,7 +124,7 @@ Summary: The Linux kernel # Set debugbuildsenabled to 1 for production (build separate debug kernels) # and 0 for rawhide (all kernels are debug kernels). # See also 'make debug' and 'make release'. -%define debugbuildsenabled 1 +%define debugbuildsenabled 0 # Want to build a vanilla kernel build without any non-upstream patches? %define with_vanilla %{?_with_vanilla: 1} %{?!_with_vanilla: 0} @@ -620,6 +620,9 @@ Patch26058: asus-nb-wmi-Add-wapf4-quirk-for-the-X550VB.patch #rhbz 1111138 Patch26059: i8042-Add-notimeout-quirk-for-Fujitsu-Lifebook-A544-.patch +Patch26060: rcu-More-on-deadlock-between-CPU-hotplug-and-expedit.patch +Patch26061: rcu-Make-rcu_barrier-understand-about-missing-rcuo-k.patch + # git clone ssh://git.fedorahosted.org/git/kernel-arm64.git, git diff master...devel Patch30000: kernel-arm64.patch @@ -1349,6 +1352,9 @@ ApplyPatch asus-nb-wmi-Add-wapf4-quirk-for-the-X550VB.patch #rhbz 1111138 ApplyPatch i8042-Add-notimeout-quirk-for-Fujitsu-Lifebook-A544-.patch +ApplyPatch rcu-More-on-deadlock-between-CPU-hotplug-and-expedit.patch +ApplyPatch rcu-Make-rcu_barrier-understand-about-missing-rcuo-k.patch + %if 0%{?aarch64patches} ApplyPatch kernel-arm64.patch %ifnarch aarch64 # this is stupid, but i want to notice before secondary koji does. @@ -2217,6 +2223,11 @@ fi # ||----w | # || || %changelog +* Tue Oct 28 2014 Josh Boyer - 3.18.0-0.rc2.git1.1 +- Linux v3.18-rc2-43-gf7e87a44ef60 +- Add two RCU patches to fix a deadlock and a hang +- Reenable debugging options. + * Mon Oct 27 2014 Josh Boyer - 3.18.0-0.rc2.git0.1 - Linux v3.18-rc2 - Disable debugging options. diff --git a/rcu-Make-rcu_barrier-understand-about-missing-rcuo-k.patch b/rcu-Make-rcu_barrier-understand-about-missing-rcuo-k.patch new file mode 100644 index 000000000..ca3592e53 --- /dev/null +++ b/rcu-Make-rcu_barrier-understand-about-missing-rcuo-k.patch @@ -0,0 +1,177 @@ +From: "Paul E. McKenney" +Date: Mon, 27 Oct 2014 09:15:54 -0700 +Subject: [PATCH] rcu: Make rcu_barrier() understand about missing rcuo + kthreads + +Commit 35ce7f29a44a (rcu: Create rcuo kthreads only for onlined CPUs) +avoids creating rcuo kthreads for CPUs that never come online. This +fixes a bug in many instances of firmware: Instead of lying about their +age, these systems instead lie about the number of CPUs that they have. +Before commit 35ce7f29a44a, this could result in huge numbers of useless +rcuo kthreads being created. + +It appears that experience indicates that I should have told the +people suffering from this problem to fix their broken firmware, but +I instead produced what turned out to be a partial fix. The missing +piece supplied by this commit makes sure that rcu_barrier() knows not to +post callbacks for no-CBs CPUs that have not yet come online, because +otherwise rcu_barrier() will hang on systems having firmware that lies +about the number of CPUs. + +It is tempting to simply have rcu_barrier() refuse to post a callback on +any no-CBs CPU that does not have an rcuo kthread. This unfortunately +does not work because rcu_barrier() is required to wait for all pending +callbacks. It is therefore required to wait even for those callbacks +that cannot possibly be invoked. Even if doing so hangs the system. + +Given that posting a callback to a no-CBs CPU that does not yet have an +rcuo kthread can hang rcu_barrier(), It is tempting to report an error +in this case. Unfortunately, this will result in false positives at +boot time, when it is perfectly legal to post callbacks to the boot CPU +before the scheduler has started, in other words, before it is legal +to invoke rcu_barrier(). + +So this commit instead has rcu_barrier() avoid posting callbacks to +CPUs having neither rcuo kthread nor pending callbacks, and has it +complain bitterly if it finds CPUs having no rcuo kthread but some +pending callbacks. And when rcu_barrier() does find CPUs having no rcuo +kthread but pending callbacks, as noted earlier, it has no choice but +to hang indefinitely. + +Reported-by: Yanko Kaneti +Reported-by: Jay Vosburgh +Reported-by: Meelis Roos +Reported-by: Eric B Munson +Signed-off-by: Paul E. McKenney +Tested-by: Eric B Munson +--- + include/trace/events/rcu.h | 18 +++++++++--------- + kernel/rcu/tree.c | 15 ++++++++++----- + kernel/rcu/tree.h | 1 + + kernel/rcu/tree_plugin.h | 33 +++++++++++++++++++++++++++++++++ + 4 files changed, 53 insertions(+), 14 deletions(-) + +diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h +index 9b56f37148cf..e335e7d8c6c2 100644 +--- a/include/trace/events/rcu.h ++++ b/include/trace/events/rcu.h +@@ -660,18 +660,18 @@ TRACE_EVENT(rcu_torture_read, + /* + * Tracepoint for _rcu_barrier() execution. The string "s" describes + * the _rcu_barrier phase: +- * "Begin": rcu_barrier_callback() started. +- * "Check": rcu_barrier_callback() checking for piggybacking. +- * "EarlyExit": rcu_barrier_callback() piggybacked, thus early exit. +- * "Inc1": rcu_barrier_callback() piggyback check counter incremented. +- * "Offline": rcu_barrier_callback() found offline CPU +- * "OnlineNoCB": rcu_barrier_callback() found online no-CBs CPU. +- * "OnlineQ": rcu_barrier_callback() found online CPU with callbacks. +- * "OnlineNQ": rcu_barrier_callback() found online CPU, no callbacks. ++ * "Begin": _rcu_barrier() started. ++ * "Check": _rcu_barrier() checking for piggybacking. ++ * "EarlyExit": _rcu_barrier() piggybacked, thus early exit. ++ * "Inc1": _rcu_barrier() piggyback check counter incremented. ++ * "OfflineNoCB": _rcu_barrier() found callback on never-online CPU ++ * "OnlineNoCB": _rcu_barrier() found online no-CBs CPU. ++ * "OnlineQ": _rcu_barrier() found online CPU with callbacks. ++ * "OnlineNQ": _rcu_barrier() found online CPU, no callbacks. + * "IRQ": An rcu_barrier_callback() callback posted on remote CPU. + * "CB": An rcu_barrier_callback() invoked a callback, not the last. + * "LastCB": An rcu_barrier_callback() invoked the last callback. +- * "Inc2": rcu_barrier_callback() piggyback check counter incremented. ++ * "Inc2": _rcu_barrier() piggyback check counter incremented. + * The "cpu" argument is the CPU or -1 if meaningless, the "cnt" argument + * is the count of remaining callbacks, and "done" is the piggybacking count. + */ +diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c +index 133e47223095..9815447d22e0 100644 +--- a/kernel/rcu/tree.c ++++ b/kernel/rcu/tree.c +@@ -3299,11 +3299,16 @@ static void _rcu_barrier(struct rcu_state *rsp) + continue; + rdp = per_cpu_ptr(rsp->rda, cpu); + if (rcu_is_nocb_cpu(cpu)) { +- _rcu_barrier_trace(rsp, "OnlineNoCB", cpu, +- rsp->n_barrier_done); +- atomic_inc(&rsp->barrier_cpu_count); +- __call_rcu(&rdp->barrier_head, rcu_barrier_callback, +- rsp, cpu, 0); ++ if (!rcu_nocb_cpu_needs_barrier(rsp, cpu)) { ++ _rcu_barrier_trace(rsp, "OfflineNoCB", cpu, ++ rsp->n_barrier_done); ++ } else { ++ _rcu_barrier_trace(rsp, "OnlineNoCB", cpu, ++ rsp->n_barrier_done); ++ atomic_inc(&rsp->barrier_cpu_count); ++ __call_rcu(&rdp->barrier_head, ++ rcu_barrier_callback, rsp, cpu, 0); ++ } + } else if (ACCESS_ONCE(rdp->qlen)) { + _rcu_barrier_trace(rsp, "OnlineQ", cpu, + rsp->n_barrier_done); +diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h +index d03764652d91..bbdc45d8d74f 100644 +--- a/kernel/rcu/tree.h ++++ b/kernel/rcu/tree.h +@@ -587,6 +587,7 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu); + static void print_cpu_stall_info_end(void); + static void zero_cpu_stall_ticks(struct rcu_data *rdp); + static void increment_cpu_stall_ticks(void); ++static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu); + static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq); + static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp); + static void rcu_init_one_nocb(struct rcu_node *rnp); +diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h +index 387dd4599344..c1d7f27bd38f 100644 +--- a/kernel/rcu/tree_plugin.h ++++ b/kernel/rcu/tree_plugin.h +@@ -2050,6 +2050,33 @@ static void wake_nocb_leader(struct rcu_data *rdp, bool force) + } + + /* ++ * Does the specified CPU need an RCU callback for the specified flavor ++ * of rcu_barrier()? ++ */ ++static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu) ++{ ++ struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu); ++ struct rcu_head *rhp; ++ ++ /* No-CBs CPUs might have callbacks on any of three lists. */ ++ rhp = ACCESS_ONCE(rdp->nocb_head); ++ if (!rhp) ++ rhp = ACCESS_ONCE(rdp->nocb_gp_head); ++ if (!rhp) ++ rhp = ACCESS_ONCE(rdp->nocb_follower_head); ++ ++ /* Having no rcuo kthread but CBs after scheduler starts is bad! */ ++ if (!ACCESS_ONCE(rdp->nocb_kthread) && rhp) { ++ /* RCU callback enqueued before CPU first came online??? */ ++ pr_err("RCU: Never-onlined no-CBs CPU %d has CB %p\n", ++ cpu, rhp->func); ++ WARN_ON_ONCE(1); ++ } ++ ++ return !!rhp; ++} ++ ++/* + * Enqueue the specified string of rcu_head structures onto the specified + * CPU's no-CBs lists. The CPU is specified by rdp, the head of the + * string by rhp, and the tail of the string by rhtp. The non-lazy/lazy +@@ -2642,6 +2669,12 @@ static bool init_nocb_callback_list(struct rcu_data *rdp) + + #else /* #ifdef CONFIG_RCU_NOCB_CPU */ + ++static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu) ++{ ++ WARN_ON_ONCE(1); /* Should be dead code. */ ++ return false; ++} ++ + static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp) + { + } +-- +1.9.3 + diff --git a/rcu-More-on-deadlock-between-CPU-hotplug-and-expedit.patch b/rcu-More-on-deadlock-between-CPU-hotplug-and-expedit.patch new file mode 100644 index 000000000..77770ff12 --- /dev/null +++ b/rcu-More-on-deadlock-between-CPU-hotplug-and-expedit.patch @@ -0,0 +1,67 @@ +From: "Paul E. McKenney" +Date: Wed, 22 Oct 2014 10:00:05 -0700 +Subject: [PATCH] rcu: More on deadlock between CPU hotplug and expedited grace + periods + +Commit dd56af42bd82 (rcu: Eliminate deadlock between CPU hotplug and +expedited grace periods) was incomplete. Although it did eliminate +deadlocks involving synchronize_sched_expedited()'s acquisition of +cpu_hotplug.lock via get_online_cpus(), it did nothing about the similar +deadlock involving acquisition of this same lock via put_online_cpus(). +This deadlock became apparent with testing involving hibernation. + +This commit therefore changes put_online_cpus() acquisition of this lock +to be conditional, and increments a new cpu_hotplug.puts_pending field +in case of acquisition failure. Then cpu_hotplug_begin() checks for this +new field being non-zero, and applies any changes to cpu_hotplug.refcount. + +Reported-by: Jiri Kosina +Signed-off-by: Paul E. McKenney +Tested-by: Jiri Kosina +Tested-by: Borislav Petkov +--- + kernel/cpu.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/kernel/cpu.c b/kernel/cpu.c +index 356450f09c1f..90a3d017b90c 100644 +--- a/kernel/cpu.c ++++ b/kernel/cpu.c +@@ -64,6 +64,8 @@ static struct { + * an ongoing cpu hotplug operation. + */ + int refcount; ++ /* And allows lockless put_online_cpus(). */ ++ atomic_t puts_pending; + + #ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; +@@ -113,7 +115,11 @@ void put_online_cpus(void) + { + if (cpu_hotplug.active_writer == current) + return; +- mutex_lock(&cpu_hotplug.lock); ++ if (!mutex_trylock(&cpu_hotplug.lock)) { ++ atomic_inc(&cpu_hotplug.puts_pending); ++ cpuhp_lock_release(); ++ return; ++ } + + if (WARN_ON(!cpu_hotplug.refcount)) + cpu_hotplug.refcount++; /* try to fix things up */ +@@ -155,6 +161,12 @@ void cpu_hotplug_begin(void) + cpuhp_lock_acquire(); + for (;;) { + mutex_lock(&cpu_hotplug.lock); ++ if (atomic_read(&cpu_hotplug.puts_pending)) { ++ int delta; ++ ++ delta = atomic_xchg(&cpu_hotplug.puts_pending, 0); ++ cpu_hotplug.refcount -= delta; ++ } + if (likely(!cpu_hotplug.refcount)) + break; + __set_current_state(TASK_UNINTERRUPTIBLE); +-- +1.9.3 + diff --git a/sources b/sources index 2ae36ec2d..d3a573fce 100644 --- a/sources +++ b/sources @@ -1,3 +1,4 @@ fb30d0f29214d75cddd2faa94f73d5cf linux-3.17.tar.xz 159e969cbc27201d8e2fa0f609dc722f perf-man-3.17.tar.gz cdc96388a5c70f5f385925caab06db12 patch-3.18-rc2.xz +49299760d7aedcae41033aec7d7b61a0 patch-3.18-rc2-git1.xz