--- /dev/null
+From stable-bounces@linux.kernel.org Mon May 22 18:00:14 2006
+Date: Mon, 22 May 2006 17:56:07 -0700
+From: Paul Jackson <pj@sgi.com>
+To: stable@kernel.org
+Cc: Paul Jackson <pj@sgi.com>, David Chinner <dgc@sgi.com>, Simon.Derr@bull.net
+Subject: Cpuset: might sleep checking zones allowed fix
+
+From: Paul Jackson <pj@sgi.com>
+
+Fix an infrequently encountered 'sleeping function called
+from invalid context' in the cpuset hooks in __alloc_pages.
+Could sleep while interrupts disabled.
+
+The routine cpuset_zone_allowed() is called by code in
+mm/page_alloc.c __alloc_pages() to determine if a zone is
+allowed in the current tasks cpuset. This routine can sleep,
+for certain GFP_KERNEL allocations, if the zone is on a memory
+node not allowed in the current cpuset, but might be allowed
+in a parent cpuset.
+
+But we can't sleep in __alloc_pages() if in interrupt, nor
+if called for a GFP_ATOMIC request (__GFP_WAIT not set in
+gfp_flags).
+
+The rule was intended to be:
+ Don't call cpuset_zone_allowed() if you can't sleep, unless you
+ pass in the __GFP_HARDWALL flag set in gfp_flag, which disables
+ the code that might scan up ancestor cpusets and sleep.
+
+This rule was being violated due to a bogus change made (by myself,
+pj) to __alloc_pages() as part of the November 2005 effort to
+cleanup its logic.
+
+The bogus change can be seen at:
+ http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-11/4691.html
+ [PATCH 01/05] mm fix __alloc_pages cpuset ALLOC_* flags
+
+This was first noticed on a tight memory system, in code that
+was disabling interrupts and doing allocation requests with
+__GFP_WAIT not set, which resulted in __might_sleep() writing
+complaints to the log "Debug: sleeping function called ...",
+when the code in cpuset_zone_allowed() tried to take the
+callback_sem cpuset semaphore.
+
+Special thanks to Dave Chinner, for figuring this out,
+and a tip of the hat to Nick Piggin who warned me of this
+back in Nov 2005, before I was ready to listen.
+
+Signed-off-by: Paul Jackson <pj@sgi.com>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+---
+
+ mm/page_alloc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- linux-2.6.16.18.orig/mm/page_alloc.c
++++ linux-2.6.16.18/mm/page_alloc.c
+@@ -949,7 +949,8 @@ restart:
+ alloc_flags |= ALLOC_HARDER;
+ if (gfp_mask & __GFP_HIGH)
+ alloc_flags |= ALLOC_HIGH;
+- alloc_flags |= ALLOC_CPUSET;
++ if (wait)
++ alloc_flags |= ALLOC_CPUSET;
+
+ /*
+ * Go through the zonelist again. Let __GFP_HIGH and allocations