void kfree(const void *x)
{
struct page *page;
if (unlikely(ZERO_OR_NULL_PTR(x)))
return;
page = virt_to_head_page(x);/* 注意,对于 SLAB 而言,假设这个 SLAB 有多个 Page, 则除首 Page 之外的其它的所有 Page 都通过其 first_page 成员指向首 Page (见 Page 数据结构) ,故而这里就得到该 SLAB 的首 Page 了 */
if (unlikely(!PageSlab(page))) {
put_page(page);
return;
}
slab_free(page->slab, page, (void *)x, __builtin_return_address(0));
}
static void __always_inline slab_free(struct kmem_cache *s,
struct page *page, void *x, void *addr)
{
void **object = (void *)x;
unsigned long flags;
struct kmem_cache_cpu *c;
local_irq_save(flags);
debug_check_no_locks_freed(object, s->objsize);
c = get_cpu_slab(s, smp_processor_id());
if (likely(page == c->page && c->node >= 0)) {/* 如果释放的对象在当前的 SLAB 上,就直接放到 kmem_cache-> cpu_slab->freelist 里 */
object[c->offset] = c->freelist;
c->freelist = object;
} else
__slab_free(s, page, x, addr, c->offset);
local_irq_restore(flags);
}
static void __slab_free(struct kmem_cache *s, struct page *page,
void *x, void *addr, unsigned int offset)
{
void *prior;
void **object = (void *)x;
slab_lock(page);
if (unlikely(SlabDebug(page)))
goto debug;
checks_ok:
prior = object[offset] = page->freelist;/* 这里请注意, page 为该 object 所在的 SLAB 的首 Page ,同时,此 SLAB 不是当前的 SLAB ,故而释放的对象不能放到 kmem_cache-> cpu_slab->freelist 里,而需要放到该首 Page 的 freelist 结构里,见 3.2 节的分析;同时,另一点很重要,如果这里 prior 为 NULL ,则说明此前此 SLAB 上的对象已经被分配光了,即此 SLAB 杯 deactivate 了,故而后面要把该 SLAB 加入到 Partial 链表里 */
page->freelist = object;
page->inuse--;/* 因为是放到了 Page 的 freelist 里,故而在使用的对象计数要减 1*/
if (unlikely(SlabFrozen(page)))
goto out_unlock;
if (unlikely(!page->inuse))/* 该 SLAB 上的对象已经都被释放了,即都是空闲对象了,且该 SLAB 不是当前 SLAB ,这样,这个 SLAB 所占用的空间就可以释放给系统了 */
goto slab_empty;
/*
* Objects left in the slab. If it
* was not on the partial list before
* then add it.
*/
if (unlikely(!prior))
add_partial_tail(get_node(s, page_to_nid(page)), page);/* 此前此 SLAB 上的对象已经被分配光了,即此 SLAB 杯 deactivate 了,故而后面要把该 SLAB 加入到 Partial 链表里 */
out_unlock:
slab_unlock(page);
return;
slab_empty:
if (prior)
/*
* Slab still on the partial list.
*/
remove_partial(s, page);
slab_unlock(page);
discard_slab(s, page);/* 释放给系统 */
return;
debug:
if (!free_debug_processing(s, page, x, addr))
goto out_unlock;
goto checks_ok;
}