Commit 272c5ac4 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] ppc64: Fix a sleeping with spinlock bug in ioremap

From: Benjamin Herrenschmidt <benh@kernel.crashing.org>

ppc64 uses its own range allocator for ioremap (in order to allocate
things in a different space than normal vmalloc).  This is historic stuff,
we may get rid of it, but in the meantime, here's a patch turning the
spinlock in there into a semaphore so it doesn't blow up when doing
kmallocs.
parent b9f47731
...@@ -9,13 +9,13 @@ ...@@ -9,13 +9,13 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/semaphore.h>
rwlock_t imlist_lock = RW_LOCK_UNLOCKED; static DECLARE_MUTEX(imlist_sem);
struct vm_struct * imlist = NULL; struct vm_struct * imlist = NULL;
static int get_free_im_addr(unsigned long size, unsigned long *im_addr) static int get_free_im_addr(unsigned long size, unsigned long *im_addr)
...@@ -223,7 +223,7 @@ struct vm_struct * im_get_free_area(unsigned long size) ...@@ -223,7 +223,7 @@ struct vm_struct * im_get_free_area(unsigned long size)
struct vm_struct *area; struct vm_struct *area;
unsigned long addr; unsigned long addr;
write_lock(&imlist_lock); down(&imlist_sem);
if (get_free_im_addr(size, &addr)) { if (get_free_im_addr(size, &addr)) {
printk(KERN_ERR "%s() cannot obtain addr for size 0x%lx\n", printk(KERN_ERR "%s() cannot obtain addr for size 0x%lx\n",
__FUNCTION__, size); __FUNCTION__, size);
...@@ -238,7 +238,7 @@ struct vm_struct * im_get_free_area(unsigned long size) ...@@ -238,7 +238,7 @@ struct vm_struct * im_get_free_area(unsigned long size)
__FUNCTION__, addr, size); __FUNCTION__, addr, size);
} }
next_im_done: next_im_done:
write_unlock(&imlist_lock); up(&imlist_sem);
return area; return area;
} }
...@@ -247,9 +247,9 @@ struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size, ...@@ -247,9 +247,9 @@ struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size,
{ {
struct vm_struct *area; struct vm_struct *area;
write_lock(&imlist_lock); down(&imlist_sem);
area = __im_get_area(v_addr, size, criteria); area = __im_get_area(v_addr, size, criteria);
write_unlock(&imlist_lock); up(&imlist_sem);
return area; return area;
} }
...@@ -264,17 +264,17 @@ unsigned long im_free(void * addr) ...@@ -264,17 +264,17 @@ unsigned long im_free(void * addr)
printk(KERN_ERR "Trying to %s bad address (%p)\n", __FUNCTION__, addr); printk(KERN_ERR "Trying to %s bad address (%p)\n", __FUNCTION__, addr);
return ret_size; return ret_size;
} }
write_lock(&imlist_lock); down(&imlist_sem);
for (p = &imlist ; (tmp = *p) ; p = &tmp->next) { for (p = &imlist ; (tmp = *p) ; p = &tmp->next) {
if (tmp->addr == addr) { if (tmp->addr == addr) {
ret_size = tmp->size; ret_size = tmp->size;
*p = tmp->next; *p = tmp->next;
kfree(tmp); kfree(tmp);
write_unlock(&imlist_lock); up(&imlist_sem);
return ret_size; return ret_size;
} }
} }
write_unlock(&imlist_lock); up(&imlist_sem);
printk(KERN_ERR "Trying to %s nonexistent area (%p)\n", __FUNCTION__, printk(KERN_ERR "Trying to %s nonexistent area (%p)\n", __FUNCTION__,
addr); addr);
return ret_size; return ret_size;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment