diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 6e18a06aaabe..684996c8a3a4 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c @@ -116,8 +116,6 @@ void __jbd2_log_wait_for_space(journal_t *journal) nblocks = jbd2_space_needed(journal); while (jbd2_log_space_left(journal) < nblocks) { write_unlock(&journal->j_state_lock); - if (current->plug) - io_schedule(); mutex_lock(&journal->j_checkpoint_mutex); /* diff --git a/include/linux/locallock.h b/include/linux/locallock.h index e572a3971631..0baaf28dc4ee 100644 --- a/include/linux/locallock.h +++ b/include/linux/locallock.h @@ -77,6 +77,9 @@ static inline int __local_trylock(struct local_irq_lock *lv) lv->owner = current; lv->nestcnt = 1; return 1; + } else if (lv->owner == current) { + lv->nestcnt++; + return 1; } return 0; } @@ -250,6 +253,12 @@ static inline int __local_unlock_irqrestore(struct local_irq_lock *lv, static inline void local_irq_lock_init(int lvar) { } +#define local_trylock(lvar) \ + ({ \ + preempt_disable(); \ + 1; \ + }) + #define local_lock(lvar) preempt_disable() #define local_unlock(lvar) preempt_enable() #define local_lock_irq(lvar) local_irq_disable() diff --git a/kernel/cpu_pm.c b/kernel/cpu_pm.c index 009cc9a17d95..10f4640f991e 100644 --- a/kernel/cpu_pm.c +++ b/kernel/cpu_pm.c @@ -22,14 +22,13 @@ #include #include -static DEFINE_RWLOCK(cpu_pm_notifier_lock); -static RAW_NOTIFIER_HEAD(cpu_pm_notifier_chain); +static ATOMIC_NOTIFIER_HEAD(cpu_pm_notifier_chain); static int cpu_pm_notify(enum cpu_pm_event event, int nr_to_call, int *nr_calls) { int ret; - ret = __raw_notifier_call_chain(&cpu_pm_notifier_chain, event, NULL, + ret = __atomic_notifier_call_chain(&cpu_pm_notifier_chain, event, NULL, nr_to_call, nr_calls); return notifier_to_errno(ret); @@ -47,14 +46,7 @@ static int cpu_pm_notify(enum cpu_pm_event event, int nr_to_call, int *nr_calls) */ int cpu_pm_register_notifier(struct notifier_block *nb) { - unsigned long flags; - int ret; - - write_lock_irqsave(&cpu_pm_notifier_lock, flags); - ret = raw_notifier_chain_register(&cpu_pm_notifier_chain, nb); - write_unlock_irqrestore(&cpu_pm_notifier_lock, flags); - - return ret; + return atomic_notifier_chain_register(&cpu_pm_notifier_chain, nb); } EXPORT_SYMBOL_GPL(cpu_pm_register_notifier); @@ -69,14 +61,7 @@ EXPORT_SYMBOL_GPL(cpu_pm_register_notifier); */ int cpu_pm_unregister_notifier(struct notifier_block *nb) { - unsigned long flags; - int ret; - - write_lock_irqsave(&cpu_pm_notifier_lock, flags); - ret = raw_notifier_chain_unregister(&cpu_pm_notifier_chain, nb); - write_unlock_irqrestore(&cpu_pm_notifier_lock, flags); - - return ret; + return atomic_notifier_chain_unregister(&cpu_pm_notifier_chain, nb); } EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier); @@ -100,7 +85,6 @@ int cpu_pm_enter(void) int nr_calls; int ret = 0; - read_lock(&cpu_pm_notifier_lock); ret = cpu_pm_notify(CPU_PM_ENTER, -1, &nr_calls); if (ret) /* @@ -108,7 +92,6 @@ int cpu_pm_enter(void) * PM entry who are notified earlier to prepare for it. */ cpu_pm_notify(CPU_PM_ENTER_FAILED, nr_calls - 1, NULL); - read_unlock(&cpu_pm_notifier_lock); return ret; } @@ -128,13 +111,7 @@ EXPORT_SYMBOL_GPL(cpu_pm_enter); */ int cpu_pm_exit(void) { - int ret; - - read_lock(&cpu_pm_notifier_lock); - ret = cpu_pm_notify(CPU_PM_EXIT, -1, NULL); - read_unlock(&cpu_pm_notifier_lock); - - return ret; + return cpu_pm_notify(CPU_PM_EXIT, -1, NULL); } EXPORT_SYMBOL_GPL(cpu_pm_exit); @@ -159,7 +136,6 @@ int cpu_cluster_pm_enter(void) int nr_calls; int ret = 0; - read_lock(&cpu_pm_notifier_lock); ret = cpu_pm_notify(CPU_CLUSTER_PM_ENTER, -1, &nr_calls); if (ret) /* @@ -167,7 +143,6 @@ int cpu_cluster_pm_enter(void) * PM entry who are notified earlier to prepare for it. */ cpu_pm_notify(CPU_CLUSTER_PM_ENTER_FAILED, nr_calls - 1, NULL); - read_unlock(&cpu_pm_notifier_lock); return ret; } @@ -190,13 +165,7 @@ EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter); */ int cpu_cluster_pm_exit(void) { - int ret; - - read_lock(&cpu_pm_notifier_lock); - ret = cpu_pm_notify(CPU_CLUSTER_PM_EXIT, -1, NULL); - read_unlock(&cpu_pm_notifier_lock); - - return ret; + return cpu_pm_notify(CPU_CLUSTER_PM_EXIT, -1, NULL); } EXPORT_SYMBOL_GPL(cpu_cluster_pm_exit); diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index b5b89c51f27e..bb42267257ad 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "rtmutex_common.h" @@ -1998,9 +1999,19 @@ rt_mutex_fastlock(struct rt_mutex *lock, int state, if (likely(rt_mutex_cmpxchg_acquire(lock, NULL, current))) { rt_mutex_deadlock_account_lock(lock, current); return 0; - } else - return slowfn(lock, state, NULL, RT_MUTEX_MIN_CHAINWALK, - ww_ctx); + } + + /* + * If rt_mutex blocks, the function sched_submit_work will not call + * blk_schedule_flush_plug (because tsk_is_pi_blocked would be true). + * We must call blk_schedule_flush_plug here, if we don't call it, + * a deadlock in device mapper may happen. + */ + if (unlikely(blk_needs_flush_plug(current))) + blk_schedule_flush_plug(current); + + return slowfn(lock, state, NULL, RT_MUTEX_MIN_CHAINWALK, + ww_ctx); } static inline int @@ -2017,8 +2028,12 @@ rt_mutex_timed_fastlock(struct rt_mutex *lock, int state, likely(rt_mutex_cmpxchg_acquire(lock, NULL, current))) { rt_mutex_deadlock_account_lock(lock, current); return 0; - } else - return slowfn(lock, state, timeout, chwalk, ww_ctx); + } + + if (unlikely(blk_needs_flush_plug(current))) + blk_schedule_flush_plug(current); + + return slowfn(lock, state, timeout, chwalk, ww_ctx); } static inline int diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index ba3d60144838..120fc8932165 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -1461,7 +1461,7 @@ static inline int hrtimer_rt_defer(struct hrtimer *timer) { return 0; } static enum hrtimer_restart hrtimer_wakeup(struct hrtimer *timer); -static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now) +static int __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now) { struct hrtimer_clock_base *base = cpu_base->clock_base; unsigned int active = cpu_base->active_bases; @@ -1511,8 +1511,7 @@ static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now) raise = 1; } } - if (raise) - raise_softirq_irqoff(HRTIMER_SOFTIRQ); + return raise; } #ifdef CONFIG_HIGH_RES_TIMERS @@ -1526,6 +1525,7 @@ void hrtimer_interrupt(struct clock_event_device *dev) struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); ktime_t expires_next, now, entry_time, delta; int retries = 0; + int raise; BUG_ON(!cpu_base->hres_active); cpu_base->nr_events++; @@ -1544,7 +1544,7 @@ retry: */ cpu_base->expires_next.tv64 = KTIME_MAX; - __hrtimer_run_queues(cpu_base, now); + raise = __hrtimer_run_queues(cpu_base, now); /* Reevaluate the clock bases for the next expiry */ expires_next = __hrtimer_get_next_event(cpu_base); @@ -1555,6 +1555,8 @@ retry: cpu_base->expires_next = expires_next; cpu_base->in_hrtirq = 0; raw_spin_unlock(&cpu_base->lock); + if (raise) + raise_softirq_irqoff(HRTIMER_SOFTIRQ); /* Reprogramming necessary ? */ if (!tick_program_event(expires_next, 0)) { @@ -1634,6 +1636,7 @@ void hrtimer_run_queues(void) { struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); ktime_t now; + int raise; if (__hrtimer_hres_active(cpu_base)) return; @@ -1652,8 +1655,10 @@ void hrtimer_run_queues(void) raw_spin_lock(&cpu_base->lock); now = hrtimer_update_base(cpu_base); - __hrtimer_run_queues(cpu_base, now); + raise = __hrtimer_run_queues(cpu_base, now); raw_spin_unlock(&cpu_base->lock); + if (raise) + raise_softirq_irqoff(HRTIMER_SOFTIRQ); } /* @@ -1852,7 +1857,7 @@ static void init_hrtimers_cpu(int cpu) #ifdef CONFIG_HOTPLUG_CPU -static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, +static int migrate_hrtimer_list(struct hrtimer_clock_base *old_base, struct hrtimer_clock_base *new_base) { struct hrtimer *timer; @@ -1880,12 +1885,21 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, */ enqueue_hrtimer(timer, new_base); } +#ifdef CONFIG_PREEMPT_RT_BASE + list_splice_tail(&old_base->expired, &new_base->expired); + /* + * Tell the caller to raise HRTIMER_SOFTIRQ. We can't safely + * acquire ktimersoftd->pi_lock while the base lock is held. + */ + return !list_empty(&new_base->expired); +#endif + return 0; } static void migrate_hrtimers(int scpu) { struct hrtimer_cpu_base *old_base, *new_base; - int i; + int i, raise = 0; BUG_ON(cpu_online(scpu)); tick_cancel_sched_timer(scpu); @@ -1901,13 +1915,16 @@ static void migrate_hrtimers(int scpu) raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING); for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { - migrate_hrtimer_list(&old_base->clock_base[i], - &new_base->clock_base[i]); + raise |= migrate_hrtimer_list(&old_base->clock_base[i], + &new_base->clock_base[i]); } raw_spin_unlock(&old_base->lock); raw_spin_unlock(&new_base->lock); + if (raise) + raise_softirq_irqoff(HRTIMER_SOFTIRQ); + /* Check, if we got expired work to do */ __hrtimer_peek_ahead_timers(); local_irq_enable(); diff --git a/localversion-rt b/localversion-rt index 34eca4e89203..9788245dd428 100644 --- a/localversion-rt +++ b/localversion-rt @@ -1 +1 @@ --rt116 +-rt117 diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index c842f40c1173..035a5f6e3de9 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -213,15 +213,13 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) } /* Send frame to sockets with specific channel */ -void hci_send_to_channel(unsigned short channel, struct sk_buff *skb, - int flag, struct sock *skip_sk) +static void __hci_send_to_channel(unsigned short channel, struct sk_buff *skb, + int flag, struct sock *skip_sk) { struct sock *sk; BT_DBG("channel %u len %d", channel, skb->len); - read_lock(&hci_sk_list.lock); - sk_for_each(sk, &hci_sk_list.head) { struct sk_buff *nskb; @@ -247,6 +245,13 @@ void hci_send_to_channel(unsigned short channel, struct sk_buff *skb, kfree_skb(nskb); } +} + +void hci_send_to_channel(unsigned short channel, struct sk_buff *skb, + int flag, struct sock *skip_sk) +{ + read_lock(&hci_sk_list.lock); + __hci_send_to_channel(channel, skb, flag, skip_sk); read_unlock(&hci_sk_list.lock); } @@ -299,8 +304,8 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb) hdr->index = cpu_to_le16(hdev->id); hdr->len = cpu_to_le16(skb->len); - hci_send_to_channel(HCI_CHANNEL_MONITOR, skb_copy, - HCI_SOCK_TRUSTED, NULL); + __hci_send_to_channel(HCI_CHANNEL_MONITOR, skb_copy, + HCI_SOCK_TRUSTED, NULL); kfree_skb(skb_copy); } diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index ff2593269089..2c1ce3e80ee4 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -219,7 +219,11 @@ static inline struct sock *icmp_xmit_lock(struct net *net) local_bh_disable(); - local_lock(icmp_sk_lock); + if (!local_trylock(icmp_sk_lock)) { + local_bh_enable(); + return NULL; + } + sk = icmp_sk(net); if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {