我们在上篇文章分析cache_grow()函数的时候涉及两个函数,我们没有细说。一个就是kmem_getpages()和kmem_freepages()函数,这两个函数有3个参数。kmem_cahce_t:主要是把申请到的对象加到这个高速缓存内
flags:表示你申请时候的一些控制标志。nodeid:主要是要求在那个内存节点号申请内存。我们先来说下kmem_getpages()函数吧。
static void *kmem_getpages(kmem_cache_t *cachep, int flags, int nodeid)
{
struct page *page;
void *addr;
int i;
flags |= cachep->gfpflags;//设置flags,如果此高速缓存内存位于dma时,gfpflags就不为0.反而是在标志的某一位设置为1.
if (likely(nodeid == -1)) {//如果nodeid为-1,说明没有指定在哪个节点号申请内存。
addr = (void*)__get_free_pages(flags, cachep->gfporder);//申请2的gfporder页的内存空间,函数返回是内存空间起始的线性地址。
if (!addr)
return NULL;
page = virt_to_page(addr);//由线性地址找到对应的struct page结构体。
} else {//如果指定了内存节点号。
page = alloc_pages_node(nodeid, flags, cachep->gfporder);//在指定的内存节点号申请内存空间。
if (!page)
return NULL;
addr = page_address(page);//把返回的struct page结构体转换为对应的线性地址。
}
i = (1 << cachep->gfporder);//这里是统计申请到的页数。
if (cachep->flags & SLAB_RECLAIM_ACCOUNT)
atomic_add(i, &slab_reclaim_pages);//如果设置了可跟踪slab回收标志,我们将slab_reclaim_pages加上i。这里主要表示我们有多少页可以被回收的。
add_page_state(nr_slab, i);//将当前处理器的页状态的slab计数器加i。这里主要是统计内存页的状态,主要是为了表明我们的系统内有多少内存页已经交给了slab管理了。
while (i--) {
SetPageSlab(page);//将每页对应的struct page结构体的flags成员设置属于slab管理的标志位置1.
page++;
}
return addr;
}
下面我们来说说它的相对函数kmem_freepages()函数。
static void kmem_freepages(kmem_cache_t *cachep, void *addr)
{
unsigned long i = (1<<cachep->gfporder);
struct page *page = virt_to_page(addr);
const unsigned long nr_freed = i;
while (i--) {
if (!TestClearPageSlab(page))
BUG();//由于这里是要释放申请用做slab管理的页,所以他们对应的struct page结构体的flags标志的PG_slab标志位必须被置1了,发现不为1时则系统就崩溃了。如果为1时,我们还要把这位清0.
page++;
}
sub_page_state(nr_slab, nr_freed);//这里和上面相反,把当前处理器内存页状态的slab计数器减去nr_freed,表明系统现有的由slab管理的内存页数量。
if (current->recl