From mboxrd@z Thu Jan 1 00:00:00 1970 From: Changli Gao Subject: Re: [RFC] mm: generic adaptive large memory allocation APIs Date: Fri, 7 May 2010 12:32:30 +0800 Message-ID: References: <1273105838-4441-1-git-send-email-xiaosuo@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: Eric Dumazet , Jiri Slaby , Changli Gao , Alexander Viro , "Paul E. McKenney" , Alexey Dobriyan , Ingo Molnar , Peter Zijlstra , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, Avi Kivity , Tetsuo Handa To: akpm@linux-foundation.org Return-path: In-Reply-To: <1273105838-4441-1-git-send-email-xiaosuo@gmail.com> Sender: linux-kernel-owner@vger.kernel.org List-Id: linux-fsdevel.vger.kernel.org On Thu, May 6, 2010 at 8:30 AM, Changli Gao wrote: > void kvfree(void *ptr, size_t size) > { > =C2=A0 =C2=A0 =C2=A0 =C2=A0if (size < PAGE_SIZE) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0kfree(ptr); > =C2=A0 =C2=A0 =C2=A0 =C2=A0else if (is_vmalloc_addr(ptr)) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0vfree(ptr); > =C2=A0 =C2=A0 =C2=A0 =C2=A0else > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0free_pages_exa= ct(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 =3D 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 =3D alloc_pages_exact(size, GFP_KERNEL | __GFP_NOWARN); if (ptr !=3D NULL) { virt_to_head_page(ptr)->private =3D size; return ptr; } here is the test code: #include #include #include #include #include #include #include #define kmalloc(size, gfp) ({ \ void *ptr =3D kmalloc(size, gfp); \ if (ptr !=3D NULL) \ printk("kmalloc: %p(%u)\n", ptr, size); \ ptr; }) #define alloc_pages_exact(size, gfp) ({ \ void *ptr =3D alloc_pages_exact(size, gfp); \ if (ptr !=3D NULL) \ printk("alloc_pages_exact: %p(%u)\n", ptr, size); \ ptr; }) #define vmalloc(size) ({ \ void *ptr =3D vmalloc(size); \ if (ptr !=3D 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 =3D alloc_pages_exact(size, GFP_KERNEL | __GFP_NOWARN); if (ptr !=3D NULL) { virt_to_head_page(ptr)->private =3D 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 =3D 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 =3D 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 =3D 1; size < (1<<30); size <<=3D 1) { ptr =3D kvmalloc(size); if (ptr =3D=3D NULL) return -1; if (is_vmalloc_addr(ptr)) { kvfree(ptr); break; } kvfree(ptr); } ptr =3D kvmalloc(size); if (ptr =3D=3D NULL) return -1; kvfree_inatomic(ptr); return 0; } module_init(test_init); static void test_exit(void) { } module_exit(test_exit); MODULE_LICENSE("GPL"); --=20 Regards=EF=BC=8C Changli Gao(xiaosuo@gmail.com)