Board logo

标题: Linux SLUB 分配器详解(3)SLUB 分配器的实现 [打印本页]

作者: look_w    时间: 2018-5-23 16:28     标题: Linux SLUB 分配器详解(3)SLUB 分配器的实现

为了保证内核其它模块能够无缝迁移到 SLUB 分配器,SLUB保留了原有 SLAB 分配器所有的接口 API 函数。表 4 列出主要的 API 函数:
表 4. SLUB API 函数函数描述kmem_cache_create创建新的缓冲区。kmem_cache_destroy销毁缓冲区。因为存在重用缓冲区的情况,只有当 kmem_cache 结构的 refcount 字段为 0时才真正销毁。kmem_cache_alloc从处理器本地的活动 slab 中分配对象。kmem_cache_alloc_node如果指定的 NUMA 节点与本处理器所在节点不一致,则先从指定节点上获取 slab,替换处理器活动 slab,然后分配对象。kmem_cache_free释放对象。如果对象属于某 Partial slab 且释放操作使这个 slab转变成Empty 状态,则释放该 slab。kmem_ptr_validate检查给定对象的指针是否合法。kmem_cache_size返回对象实际大小。kmem_cache_shrink检查各个节点的 Partial 队列,回收实际处于 Empty 状态的 slab,并将剩余的 slab 按已分配对象的数目排序。kmalloc从通用缓冲区中分配一个对象。kmalloc_node从通用缓冲区中分配一个属于指定 NUMA 节点的对象。kfree释放一个通用对象。ksize返回分配给对象的内存大小(可能大于对象的实际大小)
下面介绍 kmem_cache_alloc,kmem_cache_alloc_node 和 kmem_cache_free 三个函数的实现细节。kmem_cache_alloc 和 kmem_cache_alloc_node 函数都是直接调用 slab_alloc 函数,只是 kmem_cache_alloc 传入的 node 参数为 -1;kmem_cache_free 则调用 slab_free 函数。
清单 1. slab_alloc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
static __always_inline void *slab_alloc(struct kmem_cache *s,
        gfp_t gfpflags, int node, void *addr)
{
    void **object;
    struct kmem_cache_cpu *c;
    unsigned long flags;

    local_irq_save(flags);
    c = get_cpu_slab(s, smp_processor_id());                         (a)
    if (unlikely(!c->freelist || !node_match(c, node)))
        object = __slab_alloc(s, gfpflags, node, addr, c);         (b)
    else {
        object = c->freelist;                                            (c)
        c->freelist = object[c->offset];
        stat(c, ALLOC_FASTPATH);
    }
    local_irq_restore(flags);

    if (unlikely((gfpflags & __GFP_ZERO) && object))
        memset(object, 0, c->objsize);

    return object;                                                         (d)
}




清单 2. __slab_alloc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
static void *__slab_alloc(struct kmem_cache *s,
        gfp_t gfpflags, int node, void *addr, struct kmem_cache_cpu *c)
{
    void **object;
    struct page *new;

    gfpflags &= ~__GFP_ZERO;

    if (!c->page)                                                          (a)
        goto new_slab;

    slab_lock(c->page);
    if (unlikely(!node_match(c, node)))                                (b)
        goto another_slab;

    stat(c, ALLOC_REFILL);

load_freelist:
    object = c->page->freelist;
    if (unlikely(!object))                                                (c)
        goto another_slab;
    if (unlikely(SlabDebug(c->page)))
        goto debug;

    c->freelist = object[c->offset];                                    (d)
    c->page->inuse = s->objects;
    c->page->freelist = NULL;
    c->node = page_to_nid(c->page);
unlock_out:
    slab_unlock(c->page);
    stat(c, ALLOC_SLOWPATH);
    return object;

another_slab:
    deactivate_slab(s, c);                                                (e)

new_slab:
    new = get_partial(s, gfpflags, node);                              (f)
    if (new) {
        c->page = new;
        stat(c, ALLOC_FROM_PARTIAL);
        goto load_freelist;
    }

    if (gfpflags & __GFP_WAIT)                                           (g)
        local_irq_enable();

    new = new_slab(s, gfpflags, node);                                 (h)

    if (gfpflags & __GFP_WAIT)
        local_irq_disable();

    if (new) {
        c = get_cpu_slab(s, smp_processor_id());
        stat(c, ALLOC_SLAB);
        if (c->page)
            flush_slab(s, c);
        slab_lock(new);
        SetSlabFrozen(new);
        c->page = new;
        goto load_freelist;
    }
    if (!(gfpflags & __GFP_NORETRY) &&
                (s->flags & __PAGE_ALLOC_FALLBACK)) {
        if (gfpflags & __GFP_WAIT)
            local_irq_enable();
        object = kmalloc_large(s->objsize, gfpflags);                (i)
        if (gfpflags & __GFP_WAIT)
            local_irq_disable();
        return object;
    }
    return NULL;
debug:
    if (!alloc_debug_processing(s, c->page, object, addr))
        goto another_slab;

    c->page->inuse++;
    c->page->freelist = object[c->offset];
    c->node = -1;
    goto unlock_out;
}




清单 3. slab_free
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static __always_inline void slab_free(struct kmem_cache *s,
            struct page *page, void *x, void *addr)
{
    void **object = (void *)x;
    struct kmem_cache_cpu *c;
    unsigned long flags;

    local_irq_save(flags);
    c = get_cpu_slab(s, smp_processor_id());
    debug_check_no_locks_freed(object, c->objsize);
    if (likely(page == c->page && c->node >= 0)) {                   (a)
        object[c->offset] = c->freelist;
        c->freelist = object;
        stat(c, FREE_FASTPATH);
    } else
        __slab_free(s, page, x, addr, c->offset);                     (b)

    local_irq_restore(flags);
}




清单 4. __slab_free
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
static void __slab_free(struct kmem_cache *s, struct page *page,
                void *x, void *addr, unsigned int offset)
{
    void *prior;
    void **object = (void *)x;
    struct kmem_cache_cpu *c;

    c = get_cpu_slab(s, raw_smp_processor_id());
    stat(c, FREE_SLOWPATH);
    slab_lock(page);

    if (unlikely(SlabDebug(page)))
        goto debug;

checks_ok:
    prior = object[offset] = page->freelist;                          (a)
    page->freelist = object;
    page->inuse--;

    if (unlikely(SlabFrozen(page))) {
        stat(c, FREE_FROZEN);
        goto out_unlock;
    }

    if (unlikely(!page->inuse))                                          (b)
        goto slab_empty;

    if (unlikely(!prior)) {                                               (c)
        add_partial(get_node(s, page_to_nid(page)), page, 1);
        stat(c, FREE_ADD_PARTIAL);
    }

out_unlock:
    slab_unlock(page);
    return;

slab_empty:
    if (prior) {                                                            (d)
        remove_partial(s, page);
        stat(c, FREE_REMOVE_PARTIAL);
    }
    slab_unlock(page);
    stat(c, FREE_SLAB);
    discard_slab(s, page);
    return;

debug:
    if (!free_debug_processing(s, page, x, addr))
        goto out_unlock;
    goto checks_ok;
}









欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0