LINUX 2.6.37内存管理 SLAB分析之(2)SLAB缓冲创建与销毁

创建:

kmem_cache_create函数:

    if (!name || in_interrupt() || (size < BYTES_PER_WORD) ||
        size > KMALLOC_MAX_SIZE) {
        printk(KERN_ERR "%s: Early error in slab %s\n", __func__,
                name);
        BUG();
    }

检查传入的参数是否都正确。

    if (slab_is_available()) {
        get_online_cpus();
        mutex_lock(&cache_chain_mutex);
    }

根据g_cpucache_up来判断SLAB是否就绪,具体见cpuup_callback

    list_for_each_entry(pc, &cache_chain, next) {
        char tmp;
        int res;

        /*
         * This happens when the module gets unloaded and doesn't
         * destroy its slab cache and no-one else reuses the vmalloc
         * area of the module.  Print a warning.
         */
        res = probe_kernel_address(pc->name, tmp);
        if (res) {
            printk(KERN_ERR
                   "SLAB: cache with size %d has lost its name\n",
                   pc->buffer_size);
            continue;
        }

        if (!strcmp(pc->name, name)) {
            printk(KERN_ERR
                   "kmem_cache_create: duplicate cache %s\n", name);
            dump_stack();
            goto oops;
        }
    }

确定name是否存在,使用了安全的读函数,出错不会导致内核崩溃,并检查是否有相同的缓冲已经创建。

    if (size & (BYTES_PER_WORD - 1)) {
        size += (BYTES_PER_WORD - 1);
        size &= ~(BYTES_PER_WORD - 1);
    }

确保大小按BYTES_PER_WORD(4字节)对齐,最后部分不够BYTES_PER_WORD的则扩大到BYTES_PER_WORD。

    if (flags & SLAB_HWCACHE_ALIGN) {
        /*
         * Default alignment: as specified by the arch code.  Except if
         * an object is really small, then squeeze multiple objects into
         * one cacheline.
         */
        ralign = cache_line_size();
        while (size <= ralign / 2)
            ralign /= 2;
    } else {
        ralign = BYTES_PER_WORD;
    }

判断对齐方式。

    /*
     * Redzoning and user store require word alignment or possibly larger.
     * Note this will be overridden by architecture or caller mandated
     * alignment if either is greater than BYTES_PER_WORD.
     */
    if (flags & SLAB_STORE_USER)
        ralign = BYTES_PER_WORD;

    if (flags & SLAB_RED_ZONE) {
        ralign = REDZONE_ALIGN;
        /* If redzoning, ensure that the second redzone is suitably
         * aligned, by adjusting the object size accordingly. */
        size += REDZONE_ALIGN - 1;
        size &= ~(REDZONE_ALIGN - 1);
    }

    /* 2) arch mandated alignment */
    if (ralign < ARCH_SLAB_MINALIGN) {
        ralign = ARCH_SLAB_MINALIGN;
    }
    /* 3) caller mandated alignment */
    if (ralign < align) {
        ralign = align;
    }

对齐方式做些修正。

    cachep = kmem_cache_zalloc(&cache_cache, gfp);
    if (!cachep)
        goto oops;

分配kmem_cache对象,并zero。

    if ((size >= (PAGE_SIZE >> 3)) && !slab_early_init &&
        !(flags & SLAB_NOLEAKTRACE))
        /*
         * Size is large, assume best to place the slab management obj
         * off-slab (should allow better packing of objs).
         */
        flags |= CFLGS_OFF_SLAB;

对象大于(页size/8)则slab head存储在外面。

    size = ALIGN(size, align);

根据对齐值修正size.

    left_over = calculate_slab_order(cachep, size, align, flags);

    if (!cachep->num) {
        printk(KERN_ERR
               "kmem_cache_create: couldn't create cache %s.\n", name);
        kmem_cache_free(&cache_cache, cachep);
        cachep = NULL;
        goto oops;
    }

计算所需的空间大小,以及可以分配的对象数目,保存在cachep指向的kmem_cache结构中,并返回剩余的空间大小。

    slab_size = ALIGN(cachep->num * sizeof(kmem_bufctl_t)
              + sizeof(struct slab), align);

    /*
     * If the slab has been placed off-slab, and we have enough space then
     * move it on-slab. This is at the expense of any extra colouring.
     */
    if (flags & CFLGS_OFF_SLAB && left_over >= slab_size) {
        flags &= ~CFLGS_OFF_SLAB;
        left_over -= slab_size;
    }

    if (flags & CFLGS_OFF_SLAB) {
        /* really off slab. No need for manual alignment */
        slab_size =
            cachep->num * sizeof(kmem_bufctl_t) + sizeof(struct slab);

计算SLAB头的大小,如果剩余空间能够放的下SLAB头的话则去掉CFLGS_OFF_SLAB标志,SLAB头不保存在外面。

否则重新计算SLAB头,不考虑对齐。

    cachep->colour_off = cache_line_size();
    /* Offset must be a multiple of the alignment. */
    if (cachep->colour_off < align)
        cachep->colour_off = align;
    cachep->colour = left_over / cachep->colour_off;
    cachep->slab_size = slab_size;
    cachep->flags = flags;
    cachep->gfpflags = 0;
    if (CONFIG_ZONE_DMA_FLAG && (flags & SLAB_CACHE_DMA))
        cachep->gfpflags |= GFP_DMA;
    cachep->buffer_size = size;
    cachep->reciprocal_buffer_size = reciprocal_value(size);

初始化kmem_cache结构,  cachep->colour = left_over / cachep->colour_off, 计算颜色数量。

    if (flags & CFLGS_OFF_SLAB) {
        cachep->slabp_cache = kmem_find_general_cachep(slab_size, 0u);
        /*
         * This is a possibility for one of the malloc_sizes caches.
         * But since we go off slab only for object size greater than
         * PAGE_SIZE/8, and malloc_sizes gets created in ascending order,
         * this should not happen at all.
         * But leave a BUG_ON for some lucky dude.
         */
        BUG_ON(ZERO_OR_NULL_PTR(cachep->slabp_cache));
    }

如果需要将SLAB头保存在外面 则返回合适大小的通用缓冲kmem_cache结构。

    cachep->ctor = ctor;
    cachep->name = name;

设置构造函数和名字。

    if (setup_cpu_cache(cachep, gfp)) {
        __kmem_cache_destroy(cachep);
        cachep = NULL;
        goto oops;
    }

根据对象的size设置CPU一次操作的对象的最大数量,size越大,数量越少。

    list_add(&cachep->next, &cache_chain);

将该缓冲加如链表。

 

kmem_cache_destroy销毁缓冲

    BUG_ON(!cachep || in_interrupt());

    /* Find the cache in the chain of caches. */
    get_online_cpus();
    mutex_lock(&cache_chain_mutex);
    /*
     * the chain is never empty, cache_cache is never destroyed
     */
    list_del(&cachep->next);
    if (__cache_shrink(cachep)) {
        slab_error(cachep, "Can't free all objects");
        list_add(&cachep->next, &cache_chain);
        mutex_unlock(&cache_chain_mutex);
        put_online_cpus();
        return;
    }

    if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU))
        rcu_barrier();

    __kmem_cache_destroy(cachep);
    mutex_unlock(&cache_chain_mutex);
    put_online_cpus();

 

 

    for_each_online_cpu(i)
        kfree(cachep->array[i]);

    /* NUMA: free the list3 structures */
    for_each_online_node(i) {
        l3 = cachep->nodelists[i];
        if (l3) {
            kfree(l3->shared);
            free_alien_cache(l3->alien);
            kfree(l3);
        }
    }
    kmem_cache_free(&cache_cache, cachep);

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值