Skip to content

Commit 8bcbde5

Browse files
David HildenbrandIngo Molnar
authored andcommitted
sched/preempt, mm/fault: Count pagefault_disable() levels in pagefault_disabled
Until now, pagefault_disable()/pagefault_enabled() used the preempt count to track whether in an environment with pagefaults disabled (can be queried via in_atomic()). This patch introduces a separate counter in task_struct to count the level of pagefault_disable() calls. We'll keep manipulating the preempt count to retain compatibility to existing pagefault handlers. It is now possible to verify whether in a pagefault_disable() envionment by calling pagefault_disabled(). In contrast to in_atomic() it will not be influenced by preempt_enable()/preempt_disable(). This patch is based on a patch from Ingo Molnar. Reviewed-and-tested-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: David.Laight@ACULAB.COM Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: airlied@linux.ie Cc: akpm@linux-foundation.org Cc: benh@kernel.crashing.org Cc: bigeasy@linutronix.de Cc: borntraeger@de.ibm.com Cc: daniel.vetter@intel.com Cc: heiko.carstens@de.ibm.com Cc: herbert@gondor.apana.org.au Cc: hocko@suse.cz Cc: hughd@google.com Cc: mst@redhat.com Cc: paulus@samba.org Cc: ralf@linux-mips.org Cc: schwidefsky@de.ibm.com Cc: yang.shi@windriver.com Link: http://lkml.kernel.org/r/1431359540-32227-2-git-send-email-dahi@linux.vnet.ibm.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent 3e51f3c commit 8bcbde5

File tree

3 files changed

+33
-7
lines changed

3 files changed

+33
-7
lines changed

include/linux/sched.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,6 +1788,7 @@ struct task_struct {
17881788
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
17891789
unsigned long task_state_change;
17901790
#endif
1791+
int pagefault_disabled;
17911792
};
17921793

17931794
/* Future-safe accessor for struct task_struct's cpus_allowed. */

include/linux/uaccess.h

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,36 @@
22
#define __LINUX_UACCESS_H__
33

44
#include <linux/preempt.h>
5+
#include <linux/sched.h>
56
#include <asm/uaccess.h>
67

8+
static __always_inline void pagefault_disabled_inc(void)
9+
{
10+
current->pagefault_disabled++;
11+
}
12+
13+
static __always_inline void pagefault_disabled_dec(void)
14+
{
15+
current->pagefault_disabled--;
16+
WARN_ON(current->pagefault_disabled < 0);
17+
}
18+
719
/*
8-
* These routines enable/disable the pagefault handler in that
9-
* it will not take any locks and go straight to the fixup table.
20+
* These routines enable/disable the pagefault handler. If disabled, it will
21+
* not take any locks and go straight to the fixup table.
22+
*
23+
* We increase the preempt and the pagefault count, to be able to distinguish
24+
* whether we run in simple atomic context or in a real pagefault_disable()
25+
* context.
26+
*
27+
* For now, after pagefault_disabled() has been called, we run in atomic
28+
* context. User access methods will not sleep.
1029
*
11-
* They have great resemblance to the preempt_disable/enable calls
12-
* and in fact they are identical; this is because currently there is
13-
* no other way to make the pagefault handlers do this. So we do
14-
* disable preemption but we don't necessarily care about that.
1530
*/
1631
static inline void pagefault_disable(void)
1732
{
1833
preempt_count_inc();
34+
pagefault_disabled_inc();
1935
/*
2036
* make sure to have issued the store before a pagefault
2137
* can hit.
@@ -25,18 +41,24 @@ static inline void pagefault_disable(void)
2541

2642
static inline void pagefault_enable(void)
2743
{
28-
#ifndef CONFIG_PREEMPT
2944
/*
3045
* make sure to issue those last loads/stores before enabling
3146
* the pagefault handler again.
3247
*/
3348
barrier();
49+
pagefault_disabled_dec();
50+
#ifndef CONFIG_PREEMPT
3451
preempt_count_dec();
3552
#else
3653
preempt_enable();
3754
#endif
3855
}
3956

57+
/*
58+
* Is the pagefault handler disabled? If so, user access methods will not sleep.
59+
*/
60+
#define pagefault_disabled() (current->pagefault_disabled != 0)
61+
4062
#ifndef ARCH_HAS_NOCACHE_UACCESS
4163

4264
static inline unsigned long __copy_from_user_inatomic_nocache(void *to,

kernel/fork.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,6 +1393,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
13931393
p->hardirq_context = 0;
13941394
p->softirq_context = 0;
13951395
#endif
1396+
1397+
p->pagefault_disabled = 0;
1398+
13961399
#ifdef CONFIG_LOCKDEP
13971400
p->lockdep_depth = 0; /* no locks held yet */
13981401
p->curr_chain_key = 0;

0 commit comments

Comments
 (0)