History

sched: stop the unbound recursion in preempt_schedule_context()

preempt_schedule_context() does preempt_enable_notrace() at the end and this can call the same function again; exception_exit() is heavy and it is quite possible that need-resched is true again. 1. Change this code to dec preempt_count() and check need_resched() by hand. 2. As Linus suggested, we can use the PREEMPT_ACTIVE bit and avoid the enable/disable dance around __schedule(). But in this case we need to move into sched/core.c. 3. Cosmetic, but x86 forgets to declare this function. This doesn't really matter because it is only called by asm helpers, still it make sense to add the declaration into asm/preempt.h to match preempt_schedule().

Oleg Nesterov committed 12 years ago

Commit 009f60e1 parent 64192653 files · +42 −40Browse files

Unified · Split

3 files
  1. arch/x86/include/asm/preempt.h +1 −0
  2. kernel/context_tracking.c +0 −40
  3. kernel/sched/core.c +41 −0
arch/x86/include/asm/preempt.h+1−0
@@ -105,6 +105,7 @@ static __always_inline bool should_resched(void) · 104 unmodified lines
105105 # ifdef CONFIG_CONTEXT_TRACKING
106106 extern asmlinkage void ___preempt_schedule_context(void);
107107 # define __preempt_schedule_context() asm ("call ___preempt_schedule_context")
108+ extern asmlinkage void preempt_schedule_context(void);
108109 # endif
109110 #endif
110111
kernel/context_tracking.c+0−40
@@ -107,46 +107,6 @@ void context_tracking_user_enter(void) · 106 unmodified lines
107107 }
108108 NOKPROBE_SYMBOL(context_tracking_user_enter);
109109
110−#ifdef CONFIG_PREEMPT
111−/**
112− * preempt_schedule_context - preempt_schedule called by tracing
113− *
114− * The tracing infrastructure uses preempt_enable_notrace to prevent
115− * recursion and tracing preempt enabling caused by the tracing
116− * infrastructure itself. But as tracing can happen in areas coming
117− * from userspace or just about to enter userspace, a preempt enable
118− * can occur before user_exit() is called. This will cause the scheduler
119− * to be called when the system is still in usermode.
120− *
121− * To prevent this, the preempt_enable_notrace will use this function
122− * instead of preempt_schedule() to exit user context if needed before
123− * calling the scheduler.
124− */
125−asmlinkage __visible void __sched notrace preempt_schedule_context(void)
126−{
127− enum ctx_state prev_ctx;
128−
129− if (likely(!preemptible()))
130− return;
131−
132− /*
133− * Need to disable preemption in case user_exit() is traced
134− * and the tracer calls preempt_enable_notrace() causing
135− * an infinite recursion.
136− */
137− preempt_disable_notrace();
138− prev_ctx = exception_enter();
139− preempt_enable_no_resched_notrace();
140−
141− preempt_schedule();
142−
143− preempt_disable_notrace();
144− exception_exit(prev_ctx);
145− preempt_enable_notrace();
146−}
147−EXPORT_SYMBOL_GPL(preempt_schedule_context);
148−#endif /* CONFIG_PREEMPT */
149−
150110 /**
151111 * context_tracking_user_exit - Inform the context tracking that the CPU is
152112 * exiting userspace mode and entering the kernel.
kernel/sched/core.c+41−0
@@ -2951,6 +2951,47 @@ asmlinkage __visible void __sched notrace preempt_schedule(void) · 2950 unmodified lines
29512951 }
29522952 NOKPROBE_SYMBOL(preempt_schedule);
29532953 EXPORT_SYMBOL(preempt_schedule);
2954+
2955+#ifdef CONFIG_CONTEXT_TRACKING
2956+/**
2957+ * preempt_schedule_context - preempt_schedule called by tracing
2958+ *
2959+ * The tracing infrastructure uses preempt_enable_notrace to prevent
2960+ * recursion and tracing preempt enabling caused by the tracing
2961+ * infrastructure itself. But as tracing can happen in areas coming
2962+ * from userspace or just about to enter userspace, a preempt enable
2963+ * can occur before user_exit() is called. This will cause the scheduler
2964+ * to be called when the system is still in usermode.
2965+ *
2966+ * To prevent this, the preempt_enable_notrace will use this function
2967+ * instead of preempt_schedule() to exit user context if needed before
2968+ * calling the scheduler.
2969+ */
2970+asmlinkage __visible void __sched notrace preempt_schedule_context(void)
2971+{
2972+ enum ctx_state prev_ctx;
2973+
2974+ if (likely(!preemptible()))
2975+ return;
2976+
2977+ do {
2978+ __preempt_count_add(PREEMPT_ACTIVE);
2979+ /*
2980+ * Needs preempt disabled in case user_exit() is traced
2981+ * and the tracer calls preempt_enable_notrace() causing
2982+ * an infinite recursion.
2983+ */
2984+ prev_ctx = exception_enter();
2985+ __schedule();
2986+ exception_exit(prev_ctx);
2987+
2988+ __preempt_count_sub(PREEMPT_ACTIVE);
2989+ barrier();
2990+ } while (need_resched());
2991+}
2992+EXPORT_SYMBOL_GPL(preempt_schedule_context);
2993+#endif /* CONFIG_CONTEXT_TRACKING */
2994+
29542995 #endif /* CONFIG_PREEMPT */
29552996
29562997 /*

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t