patch-2.3.99-pre9 linux/mm/vmalloc.c
Next file: linux/mm/vmscan.c
Previous file: linux/mm/swapfile.c
Back to the patch index
Back to the overall index
- Lines: 160
- Date:
Sun May 21 20:18:08 2000
- Orig file:
v2.3.99-pre8/linux/mm/vmalloc.c
- Orig date:
Mon Mar 27 08:08:33 2000
diff -u --recursive --new-file v2.3.99-pre8/linux/mm/vmalloc.c linux/mm/vmalloc.c
@@ -3,14 +3,17 @@
*
* Copyright (C) 1993 Linus Torvalds
* Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
+ * SMP-safe vmalloc/vfree/ioremap, Tigran Aivazian <tigran@veritas.com>, May 2000
*/
#include <linux/malloc.h>
#include <linux/vmalloc.h>
+#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <asm/pgalloc.h>
+rwlock_t vmlist_lock = RW_LOCK_UNLOCKED;
struct vm_struct * vmlist = NULL;
static inline void free_area_pte(pmd_t * pmd, unsigned long address, unsigned long size)
@@ -87,7 +90,8 @@
flush_tlb_all();
}
-static inline int alloc_area_pte(pte_t * pte, unsigned long address, unsigned long size)
+static inline int alloc_area_pte (pte_t * pte, unsigned long address,
+ unsigned long size, int gfp_mask)
{
unsigned long end;
@@ -99,7 +103,7 @@
struct page * page;
if (!pte_none(*pte))
printk(KERN_ERR "alloc_area_pte: page already exists\n");
- page = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
+ page = alloc_page(gfp_mask);
if (!page)
return -ENOMEM;
set_pte(pte, mk_pte(page, PAGE_KERNEL));
@@ -109,7 +113,7 @@
return 0;
}
-static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size)
+static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, int gfp_mask)
{
unsigned long end;
@@ -121,7 +125,7 @@
pte_t * pte = pte_alloc_kernel(pmd, address);
if (!pte)
return -ENOMEM;
- if (alloc_area_pte(pte, address, end - address))
+ if (alloc_area_pte(pte, address, end - address, gfp_mask))
return -ENOMEM;
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
@@ -129,7 +133,8 @@
return 0;
}
-int vmalloc_area_pages(unsigned long address, unsigned long size)
+inline int vmalloc_area_pages (unsigned long address,
+ unsigned long size, int gfp_mask)
{
pgd_t * dir;
unsigned long end = address + size;
@@ -143,7 +148,7 @@
pmd = pmd_alloc_kernel(dir, address);
if (!pmd)
return -ENOMEM;
- if (alloc_area_pmd(pmd, address, end - address))
+ if (alloc_area_pmd(pmd, address, end - address, gfp_mask))
return -ENOMEM;
if (pgd_val(olddir) != pgd_val(*dir))
set_pgdir(address, *dir);
@@ -163,11 +168,13 @@
if (!area)
return NULL;
addr = VMALLOC_START;
+ write_lock(&vmlist_lock);
for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
if (size + addr < (unsigned long) tmp->addr)
break;
addr = tmp->size + (unsigned long) tmp->addr;
if (addr > VMALLOC_END-size) {
+ write_unlock(&vmlist_lock);
kfree(area);
return NULL;
}
@@ -177,6 +184,7 @@
area->size = size + PAGE_SIZE;
area->next = *p;
*p = area;
+ write_unlock(&vmlist_lock);
return area;
}
@@ -190,18 +198,21 @@
printk(KERN_ERR "Trying to vfree() bad address (%p)\n", addr);
return;
}
+ write_lock(&vmlist_lock);
for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
if (tmp->addr == addr) {
*p = tmp->next;
vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size);
kfree(tmp);
+ write_unlock(&vmlist_lock);
return;
}
}
+ write_unlock(&vmlist_lock);
printk(KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n", addr);
}
-void * vmalloc(unsigned long size)
+void * __vmalloc (unsigned long size, int gfp_mask)
{
void * addr;
struct vm_struct *area;
@@ -217,7 +228,7 @@
return NULL;
}
addr = area->addr;
- if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size)) {
+ if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, gfp_mask)) {
vfree(addr);
BUG();
return NULL;
@@ -235,6 +246,7 @@
if ((unsigned long) addr + count < count)
count = -(unsigned long) addr;
+ read_lock(&vmlist_lock);
for (tmp = vmlist; tmp; tmp = tmp->next) {
vaddr = (char *) tmp->addr;
if (addr >= vaddr + tmp->size - PAGE_SIZE)
@@ -242,7 +254,7 @@
while (addr < vaddr) {
if (count == 0)
goto finished;
- put_user('\0', buf);
+ *buf = '\0';
buf++;
addr++;
count--;
@@ -251,12 +263,13 @@
do {
if (count == 0)
goto finished;
- put_user(*addr, buf);
+ *buf = *addr;
buf++;
addr++;
count--;
} while (--n > 0);
}
finished:
+ read_unlock(&vmlist_lock);
return buf - buf_start;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)