]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
mm: allow PF_MEMALLOC from softirq context
authorMel Gorman <mgorman@suse.de>
Sat, 21 Jul 2012 00:54:21 +0000 (10:54 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Wed, 25 Jul 2012 03:02:35 +0000 (13:02 +1000)
This is needed to allow network softirq packet processing to make use of
PF_MEMALLOC.

Currently softirq context cannot use PF_MEMALLOC due to it not being
associated with a task, and therefore not having task flags to fiddle with
- thus the gfp to alloc flag mapping ignores the task flags when in
interrupts (hard or soft) context.

Allowing softirqs to make use of PF_MEMALLOC therefore requires some
trickery.  This patch borrows the task flags from whatever process happens
to be preempted by the softirq.  It then modifies the gfp to alloc flags
mapping to not exclude task flags in softirq context, and modify the
softirq code to save, clear and restore the PF_MEMALLOC flag.

The save and clear, ensures the preempted task's PF_MEMALLOC flag doesn't
leak into the softirq.  The restore ensures a softirq's PF_MEMALLOC flag
cannot leak back into the preempted process.  This should be safe due to
the following reasons

Softirqs can run on multiple CPUs sure but the same task should not be
executing the same softirq code. Neither should the softirq
handler be preempted by any other softirq handler so the flags
should not leak to an unrelated softirq.

Softirqs re-enable hardware interrupts in __do_softirq() so can be
preempted by hardware interrupts so PF_MEMALLOC is inherited
by the hard IRQ. However, this is similar to a process in
reclaim being preempted by a hardirq. While PF_MEMALLOC is
set, gfp_to_alloc_flags() distinguishes between hard and
soft irqs and avoids giving a hardirq the ALLOC_NO_WATERMARKS
flag.

If the softirq is deferred to ksoftirq then its flags may be used
        instead of a normal tasks but as the softirq cannot be preempted,
        the PF_MEMALLOC flag does not leak to other code by accident.

[davem@davemloft.net: Document why PF_MEMALLOC is safe]
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Mel Gorman <mgorman@suse.de>
Cc: David Miller <davem@davemloft.net>
Cc: Neil Brown <neilb@suse.de>
Cc: Mike Christie <michaelc@cs.wisc.edu>
Cc: Eric B Munson <emunson@mgebm.net>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Christoph Lameter <cl@linux.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
include/linux/sched.h
kernel/softirq.c
mm/page_alloc.c

index 3c40e4406468cf0c42e7730a5f6be2b0f33c8e0c..b8c86648a2f95dc6f83aab668fd9a7e07f277b4e 100644 (file)
@@ -1886,6 +1886,13 @@ static inline void rcu_copy_process(struct task_struct *p)
 
 #endif
 
+static inline void tsk_restore_flags(struct task_struct *task,
+                               unsigned long orig_flags, unsigned long flags)
+{
+       task->flags &= ~flags;
+       task->flags |= orig_flags & flags;
+}
+
 #ifdef CONFIG_SMP
 extern void do_set_cpus_allowed(struct task_struct *p,
                               const struct cpumask *new_mask);
index 671f9594e3681e028c18b3e7456b1e58de2930c2..b73e681df09ea23e951b04672ca41227e9e0787f 100644 (file)
@@ -210,6 +210,14 @@ asmlinkage void __do_softirq(void)
        __u32 pending;
        int max_restart = MAX_SOFTIRQ_RESTART;
        int cpu;
+       unsigned long old_flags = current->flags;
+
+       /*
+        * Mask out PF_MEMALLOC s current task context is borrowed for the
+        * softirq. A softirq handled such as network RX might set PF_MEMALLOC
+        * again if the socket is related to swap
+        */
+       current->flags &= ~PF_MEMALLOC;
 
        pending = local_softirq_pending();
        account_system_vtime(current);
@@ -265,6 +273,7 @@ restart:
 
        account_system_vtime(current);
        __local_bh_enable(SOFTIRQ_OFFSET);
+       tsk_restore_flags(current, old_flags, PF_MEMALLOC);
 }
 
 #ifndef __ARCH_HAS_DO_SOFTIRQ
index 7aaf96c74f47eb249c2f641cb8bc6866dd4aea74..f4e9fe33fae99843662bf7531efa493db6556c67 100644 (file)
@@ -2295,7 +2295,11 @@ gfp_to_alloc_flags(gfp_t gfp_mask)
        if (likely(!(gfp_mask & __GFP_NOMEMALLOC))) {
                if (gfp_mask & __GFP_MEMALLOC)
                        alloc_flags |= ALLOC_NO_WATERMARKS;
-               else if (likely(!(gfp_mask & __GFP_NOMEMALLOC)) && !in_interrupt())
+               else if (in_serving_softirq() && (current->flags & PF_MEMALLOC))
+                       alloc_flags |= ALLOC_NO_WATERMARKS;
+               else if (!in_interrupt() &&
+                               ((current->flags & PF_MEMALLOC) ||
+                                unlikely(test_thread_flag(TIF_MEMDIE))))
                        alloc_flags |= ALLOC_NO_WATERMARKS;
        }