[PATCH] uml: avoid malloc to sleep in atomic sections
authorPaolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Thu, 19 Jan 2006 01:42:58 +0000 (17:42 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Thu, 19 Jan 2006 03:20:21 +0000 (19:20 -0800)
Ugly trick to help make malloc not sleeping - we can't do anything else.  But
this is not yet optimal, since spinlock don't trigger in_atomic() when
preemption is disabled.

Also, even if ugly, this was already used in one place, and was even more
bogus.  Fix it.

Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Cc: Jeff Dike <jdike@addtoit.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/um/include/kern_util.h
arch/um/include/user.h
arch/um/kernel/process_kern.c
arch/um/os-Linux/helper.c

index 8f4e46d677ab08cb4305b85cc384a9e173d36bc0..c649108a9e9f298c4266c568ce88627bd8e2eab9 100644 (file)
@@ -120,8 +120,10 @@ extern void machine_halt(void);
 extern int is_syscall(unsigned long addr);
 extern void arch_switch(void);
 extern void free_irq(unsigned int, void *);
-extern int um_in_interrupt(void);
 extern int cpu(void);
+
+/* Are we disallowed to sleep? Used to choose between GFP_KERNEL and GFP_ATOMIC. */
+extern int __cant_sleep(void);
 extern void segv_handler(int sig, union uml_pt_regs *regs);
 extern void sigio_handler(int sig, union uml_pt_regs *regs);
 
index 0f865ef46918190d528f556506ca9439d75da175..91b0ac4ad88cceb8b9961c6ba667f4d16133a197 100644 (file)
@@ -18,6 +18,7 @@ extern int open_gdb_chan(void);
 extern unsigned long strlcpy(char *, const char *, unsigned long);
 extern unsigned long strlcat(char *, const char *, unsigned long);
 extern void *um_vmalloc(int size);
+extern void *um_vmalloc_atomic(int size);
 extern void vfree(void *ptr);
 
 #endif
index e167cf0a71f4657d7bd0e52d7144fab1a839f147..3113cab8675e6358c6909201ebbb3ae90beacf60 100644 (file)
@@ -287,17 +287,27 @@ EXPORT_SYMBOL(disable_hlt);
 
 void *um_kmalloc(int size)
 {
-       return(kmalloc(size, GFP_KERNEL));
+       return kmalloc(size, GFP_KERNEL);
 }
 
 void *um_kmalloc_atomic(int size)
 {
-       return(kmalloc(size, GFP_ATOMIC));
+       return kmalloc(size, GFP_ATOMIC);
 }
 
 void *um_vmalloc(int size)
 {
-       return(vmalloc(size));
+       return vmalloc(size);
+}
+
+void *um_vmalloc_atomic(int size)
+{
+       return __vmalloc(size, GFP_ATOMIC | __GFP_HIGHMEM, PAGE_KERNEL);
+}
+
+int __cant_sleep(void) {
+       return in_atomic() || irqs_disabled() || in_interrupt();
+       /* Is in_interrupt() really needed? */
 }
 
 unsigned long get_fault_addr(void)
@@ -369,11 +379,6 @@ int smp_sigio_handler(void)
        return(0);
 }
 
-int um_in_interrupt(void)
-{
-       return(in_interrupt());
-}
-
 int cpu(void)
 {
        return(current_thread->cpu);
index 36cc8475bcdacc76aba1d932a7d2a41eff6392d8..6490a4ff40ac458cdd96ee61128aeefb81303a43 100644 (file)
@@ -60,7 +60,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
 
        if((stack_out != NULL) && (*stack_out != 0))
                stack = *stack_out;
-       else stack = alloc_stack(0, um_in_interrupt());
+       else stack = alloc_stack(0, __cant_sleep());
        if(stack == 0)
                return(-ENOMEM);
 
@@ -124,7 +124,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
        unsigned long stack, sp;
        int pid, status, err;
 
-       stack = alloc_stack(stack_order, um_in_interrupt());
+       stack = alloc_stack(stack_order, __cant_sleep());
        if(stack == 0) return(-ENOMEM);
 
        sp = stack + (page_size() << stack_order) - sizeof(void *);