]> rtime.felk.cvut.cz Git - hercules2020/nv-tegra/linux-4.4.git/blob - rt-patches/0162-rt-Introduce-cpu_chill.patch
Fix memguard and related syscalls
[hercules2020/nv-tegra/linux-4.4.git] / rt-patches / 0162-rt-Introduce-cpu_chill.patch
1 From db0e1630e6e25a6ab9d485a7984c0303b1c5adbc Mon Sep 17 00:00:00 2001
2 From: Thomas Gleixner <tglx@linutronix.de>
3 Date: Wed, 7 Mar 2012 20:51:03 +0100
4 Subject: [PATCH 162/366] rt: Introduce cpu_chill()
5
6 Retry loops on RT might loop forever when the modifying side was
7 preempted. Add cpu_chill() to replace cpu_relax(). cpu_chill()
8 defaults to cpu_relax() for non RT. On RT it puts the looping task to
9 sleep for a tick so the preempted task can make progress.
10
11 Steven Rostedt changed it to use a hrtimer instead of msleep():
12 |
13 |Ulrich Obergfell pointed out that cpu_chill() calls msleep() which is woken
14 |up by the ksoftirqd running the TIMER softirq. But as the cpu_chill() is
15 |called from softirq context, it may block the ksoftirqd() from running, in
16 |which case, it may never wake up the msleep() causing the deadlock.
17 |
18 |I checked the vmcore, and irq/74-qla2xxx is stuck in the msleep() call,
19 |running on CPU 8. The one ksoftirqd that is stuck, happens to be the one that
20 |runs on CPU 8, and it is blocked on a lock held by irq/74-qla2xxx. As that
21 |ksoftirqd is the one that will wake up irq/74-qla2xxx, and it happens to be
22 |blocked on a lock that irq/74-qla2xxx holds, we have our deadlock.
23 |
24 |The solution is not to convert the cpu_chill() back to a cpu_relax() as that
25 |will re-create a possible live lock that the cpu_chill() fixed earlier, and may
26 |also leave this bug open on other softirqs. The fix is to remove the
27 |dependency on ksoftirqd from cpu_chill(). That is, instead of calling
28 |msleep() that requires ksoftirqd to wake it up, use the
29 |hrtimer_nanosleep() code that does the wakeup from hard irq context.
30 |
31 ||Looks to be the lock of the block softirq. I don't have the core dump
32 ||anymore, but from what I could tell the ksoftirqd was blocked on the
33 ||block softirq lock, where the block softirq handler did a msleep
34 ||(called by the qla2xxx interrupt handler).
35 ||
36 ||Looking at trigger_softirq() in block/blk-softirq.c, it can do a
37 ||smp_callfunction() to another cpu to run the block softirq. If that
38 ||happens to be the cpu where the qla2xx irq handler is doing the block
39 ||softirq and is in a middle of a msleep(), I believe the ksoftirqd will
40 ||try to run the softirq. If it does that, then BOOM, it's deadlocked
41 ||because the ksoftirqd will never run the timer softirq either.
42 |
43 ||I should have also stated that it was only one lock that was involved.
44 ||But the lock owner was doing a msleep() that requires a wakeup by
45 ||ksoftirqd to continue. If ksoftirqd happens to be blocked on a lock
46 ||held by the msleep() caller, then you have your deadlock.
47 ||
48 ||It's best not to have any softirqs going to sleep requiring another
49 ||softirq to wake it up. Note, if we ever require a timer softirq to do a
50 ||cpu_chill() it will most definitely hit this deadlock.
51
52 + bigeasy: add PF_NOFREEZE:
53 | [....] Waiting for /dev to be fully populated...
54 | =====================================
55 | [ BUG: udevd/229 still has locks held! ]
56 | 3.12.11-rt17 #23 Not tainted
57 | -------------------------------------
58 | 1 lock held by udevd/229:
59 |  #0:  (&type->i_mutex_dir_key#2){+.+.+.}, at: lookup_slow+0x28/0x98
60 |
61 | stack backtrace:
62 | CPU: 0 PID: 229 Comm: udevd Not tainted 3.12.11-rt17 #23
63 | (unwind_backtrace+0x0/0xf8) from (show_stack+0x10/0x14)
64 | (show_stack+0x10/0x14) from (dump_stack+0x74/0xbc)
65 | (dump_stack+0x74/0xbc) from (do_nanosleep+0x120/0x160)
66 | (do_nanosleep+0x120/0x160) from (hrtimer_nanosleep+0x90/0x110)
67 | (hrtimer_nanosleep+0x90/0x110) from (cpu_chill+0x30/0x38)
68 | (cpu_chill+0x30/0x38) from (dentry_kill+0x158/0x1ec)
69 | (dentry_kill+0x158/0x1ec) from (dput+0x74/0x15c)
70 | (dput+0x74/0x15c) from (lookup_real+0x4c/0x50)
71 | (lookup_real+0x4c/0x50) from (__lookup_hash+0x34/0x44)
72 | (__lookup_hash+0x34/0x44) from (lookup_slow+0x38/0x98)
73 | (lookup_slow+0x38/0x98) from (path_lookupat+0x208/0x7fc)
74 | (path_lookupat+0x208/0x7fc) from (filename_lookup+0x20/0x60)
75 | (filename_lookup+0x20/0x60) from (user_path_at_empty+0x50/0x7c)
76 | (user_path_at_empty+0x50/0x7c) from (user_path_at+0x14/0x1c)
77 | (user_path_at+0x14/0x1c) from (vfs_fstatat+0x48/0x94)
78 | (vfs_fstatat+0x48/0x94) from (SyS_stat64+0x14/0x30)
79 | (SyS_stat64+0x14/0x30) from (ret_fast_syscall+0x0/0x48)
80
81 Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
82 Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
83 Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
84 ---
85  include/linux/delay.h |  6 ++++++
86  kernel/time/hrtimer.c | 19 +++++++++++++++++++
87  2 files changed, 25 insertions(+)
88
89 diff --git a/include/linux/delay.h b/include/linux/delay.h
90 index a6ecb34..37caab3 100644
91 --- a/include/linux/delay.h
92 +++ b/include/linux/delay.h
93 @@ -52,4 +52,10 @@ static inline void ssleep(unsigned int seconds)
94         msleep(seconds * 1000);
95  }
96  
97 +#ifdef CONFIG_PREEMPT_RT_FULL
98 +extern void cpu_chill(void);
99 +#else
100 +# define cpu_chill()   cpu_relax()
101 +#endif
102 +
103  #endif /* defined(_LINUX_DELAY_H) */
104 diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
105 index 6255e3d..2fc2569 100644
106 --- a/kernel/time/hrtimer.c
107 +++ b/kernel/time/hrtimer.c
108 @@ -1800,6 +1800,25 @@ SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp,
109         return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
110  }
111  
112 +#ifdef CONFIG_PREEMPT_RT_FULL
113 +/*
114 + * Sleep for 1 ms in hope whoever holds what we want will let it go.
115 + */
116 +void cpu_chill(void)
117 +{
118 +       struct timespec tu = {
119 +               .tv_nsec = NSEC_PER_MSEC,
120 +       };
121 +       unsigned int freeze_flag = current->flags & PF_NOFREEZE;
122 +
123 +       current->flags |= PF_NOFREEZE;
124 +       hrtimer_nanosleep(&tu, NULL, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
125 +       if (!freeze_flag)
126 +               current->flags &= ~PF_NOFREEZE;
127 +}
128 +EXPORT_SYMBOL(cpu_chill);
129 +#endif
130 +
131  /*
132   * Functions related to boot-time initialization:
133   */
134 -- 
135 1.9.1
136