patch-2.4.22 linux-2.4.22/mm/vmalloc.c

Next file: linux-2.4.22/net/802/llc_sendpdu.c
Previous file: linux-2.4.22/mm/swapfile.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.21/mm/vmalloc.c linux-2.4.22/mm/vmalloc.c
@@ -93,7 +93,8 @@
 }
 
 static inline int alloc_area_pte (pte_t * pte, unsigned long address,
-			unsigned long size, int gfp_mask, pgprot_t prot)
+			unsigned long size, int gfp_mask,
+			pgprot_t prot, struct page ***pages)
 {
 	unsigned long end;
 
@@ -103,9 +104,20 @@
 		end = PMD_SIZE;
 	do {
 		struct page * page;
-		spin_unlock(&init_mm.page_table_lock);
-		page = alloc_page(gfp_mask);
-		spin_lock(&init_mm.page_table_lock);
+
+		if (!pages) {
+			spin_unlock(&init_mm.page_table_lock);
+			page = alloc_page(gfp_mask);
+			spin_lock(&init_mm.page_table_lock);
+		} else {
+			page = (**pages);
+			(*pages)++;
+
+			/* Add a reference to the page so we can free later */
+			if (page)
+				atomic_inc(&page->count);
+
+		}
 		if (!pte_none(*pte))
 			printk(KERN_ERR "alloc_area_pte: page already exists\n");
 		if (!page)
@@ -117,7 +129,9 @@
 	return 0;
 }
 
-static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, int gfp_mask, pgprot_t prot)
+static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address,
+			unsigned long size, int gfp_mask,
+			pgprot_t prot, struct page ***pages)
 {
 	unsigned long end;
 
@@ -129,7 +143,8 @@
 		pte_t * pte = pte_alloc(&init_mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
-		if (alloc_area_pte(pte, address, end - address, gfp_mask, prot))
+		if (alloc_area_pte(pte, address, end - address,
+					gfp_mask, prot, pages))
 			return -ENOMEM;
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
@@ -137,8 +152,11 @@
 	return 0;
 }
 
-inline int vmalloc_area_pages (unsigned long address, unsigned long size,
-                               int gfp_mask, pgprot_t prot)
+static inline int __vmalloc_area_pages (unsigned long address,
+					unsigned long size,
+					int gfp_mask,
+					pgprot_t prot,
+					struct page ***pages)
 {
 	pgd_t * dir;
 	unsigned long end = address + size;
@@ -155,7 +173,7 @@
 			break;
 
 		ret = -ENOMEM;
-		if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot))
+		if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot, pages))
 			break;
 
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
@@ -168,6 +186,12 @@
 	return ret;
 }
 
+int vmalloc_area_pages(unsigned long address, unsigned long size,
+		       int gfp_mask, pgprot_t prot)
+{
+	return __vmalloc_area_pages(address, size, gfp_mask, prot, NULL);
+}
+
 struct vm_struct * get_vm_area(unsigned long size, unsigned long flags)
 {
 	unsigned long addr, next;
@@ -246,7 +270,30 @@
 	if (!area)
 		return NULL;
 	addr = area->addr;
-	if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, gfp_mask, prot)) {
+	if (__vmalloc_area_pages(VMALLOC_VMADDR(addr), size, gfp_mask,
+				 prot, NULL)) {
+		vfree(addr);
+		return NULL;
+	}
+	return addr;
+}
+
+void * vmap(struct page **pages, int count,
+	    unsigned long flags, pgprot_t prot)
+{
+	void * addr;
+	struct vm_struct *area;
+	unsigned long size = count << PAGE_SHIFT;
+
+	if (!size || size > (max_mapnr << PAGE_SHIFT))
+		return NULL;
+	area = get_vm_area(size, flags);
+	if (!area) {
+		return NULL;
+	}
+	addr = area->addr;
+	if (__vmalloc_area_pages(VMALLOC_VMADDR(addr), size, 0,
+				 prot, &pages)) {
 		vfree(addr);
 		return NULL;
 	}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)