On Thu, May 6, 2010 at 8:30 AM, Changli Gao <xiaosuo@xxxxxxxxx> wrote: > void kvfree(void *ptr, size_t size) > { > if (size < PAGE_SIZE) > kfree(ptr); > else if (is_vmalloc_addr(ptr)) > vfree(ptr); > else > free_pages_exact(ptr, size); > } I found a way to eliminate the size argument of kvfree() and kvfree_inatomic(). We can check where the page_head is slab or compound, as pages owned by slab subsystem always have Slab flag set or are compound. page = virt_to_head_page(ptr); if (PageSlab(page) || PageCompound(page)) kfree(ptr); else free_pages_exact(ptr, page->private); And we can save the size argument in page->private after alloc_pages_eact() returns. ptr = alloc_pages_exact(size, GFP_KERNEL | __GFP_NOWARN); if (ptr != NULL) { virt_to_head_page(ptr)->private = size; return ptr; } here is the test code: #include <linux/kernel.h> #include <linux/module.h> #include <linux/mm.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/interrupt.h> #define kmalloc(size, gfp) ({ \ void *ptr = kmalloc(size, gfp); \ if (ptr != NULL) \ printk("kmalloc: %p(%u)\n", ptr, size); \ ptr; }) #define alloc_pages_exact(size, gfp) ({ \ void *ptr = alloc_pages_exact(size, gfp); \ if (ptr != NULL) \ printk("alloc_pages_exact: %p(%u)\n", ptr, size); \ ptr; }) #define vmalloc(size) ({ \ void *ptr = vmalloc(size); \ if (ptr != NULL) \ printk("vmalloc: %p(%u)\n", ptr, size); \ ptr; }) #define kfree(ptr) do { printk("kfree: %p\n", ptr); kfree(ptr); } while (0) #define vfree(ptr) do { printk("vfree: %p\n", ptr); vfree(ptr); } while (0) #define free_pages_exact(ptr, size) do { \ printk("free_pages_exact: %p(%u)\n", ptr, size); \ free_pages_exact(ptr, size); \ } while (0) void *kvmalloc(size_t size) { void *ptr; if (size < PAGE_SIZE) return kmalloc(size, GFP_KERNEL); ptr = alloc_pages_exact(size, GFP_KERNEL | __GFP_NOWARN); if (ptr != NULL) { virt_to_head_page(ptr)->private = size; return ptr; } return vmalloc(size); } EXPORT_SYMBOL(kvmalloc); static void kvfree_work(struct work_struct *work) { vfree(work); } static void __kvfree(void *ptr, bool inatomic) { if (unlikely(ZERO_OR_NULL_PTR(ptr))) return; if (is_vmalloc_addr(ptr)) { if (inatomic) { struct work_struct *work; work = ptr; BUILD_BUG_ON(sizeof(struct work_struct) > PAGE_SIZE); INIT_WORK(work, kvfree_work); schedule_work(work); } else { vfree(ptr); } } else { struct page *page; page = virt_to_head_page(ptr); if (PageSlab(page) || PageCompound(page)) kfree(ptr); else free_pages_exact(ptr, page->private); } } void kvfree(void *ptr) { __kvfree(ptr, false); } EXPORT_SYMBOL(kvfree); void kvfree_inatomic(void *ptr) { __kvfree(ptr, true); } EXPORT_SYMBOL(kvfree_inatomic); //-------------------- // for testing static int test_init(void) { int size; void *ptr; for (size = 1; size < (1<<30); size <<= 1) { ptr = kvmalloc(size); if (ptr == NULL) return -1; if (is_vmalloc_addr(ptr)) { kvfree(ptr); break; } kvfree(ptr); } ptr = kvmalloc(size); if (ptr == NULL) return -1; kvfree_inatomic(ptr); return 0; } module_init(test_init); static void test_exit(void) { } module_exit(test_exit); MODULE_LICENSE("GPL"); -- Regards, Changli Gao(xiaosuo@xxxxxxxxx) -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html