k/v/malloc

  看以前的驱动hook代码,发现分配20Bytes的内存竟然使用vmalooc;这些人当时写代码太随意了,再次记录一下vmalloc kmalloc  kmem_cache_alloc  alloc_page 等的区别

Kmalloc: kmalloc是基于kmem_cache_alloc、 slab实现的,但是kmalloc 可以分配非固定大小的内存,kmem_cache_alloc 只能是固定的!!kmalloc 分配95Bytes时 虽然调用的是cache_alloc(96)从而对外提供了分配非固定大小的内存;kmem_cache_alloc大小都是 32 64 96 128 等Bytes

/**
 * kmalloc - allocate memory
 * @size: how many bytes of memory are required.
 * @flags: the type of memory to allocate.
 *
 * kmalloc is the normal method of allocating memory
 * for objects smaller than page size in the kernel.
 *
 * The @flags argument may be one of:
 *
 * %GFP_USER - Allocate memory on behalf of user.  May sleep.
 *
 * %GFP_KERNEL - Allocate normal kernel ram.  May sleep.
 *
 * %GFP_ATOMIC - Allocation will not sleep.  May use emergency pools.
 *   For example, use this inside interrupt handlers.
 *
 * %GFP_HIGHUSER - Allocate pages from high memory.
 *
 * %GFP_NOIO - Do not do any I/O at all while trying to get memory.
 *
 * %GFP_NOFS - Do not make any fs calls while trying to get memory.
 *
 * %GFP_NOWAIT - Allocation will not sleep.
 *
 * %__GFP_THISNODE - Allocate node-local memory only.
 *
 * %GFP_DMA - Allocation suitable for DMA.
 *   Should only be used for kmalloc() caches. Otherwise, use a
 *   slab created with SLAB_DMA.
 *
 * Also it is possible to set different flags by OR'ing
 * in one or more of the following additional @flags:
 *
 * %__GFP_COLD - Request cache-cold pages instead of
 *   trying to return cache-warm pages.
 *
 * %__GFP_HIGH - This allocation has high priority and may use emergency pools.
 *
 * %__GFP_NOFAIL - Indicate that this allocation is in no way allowed to fail
 *   (think twice before using).
 *
 * %__GFP_NORETRY - If memory is not immediately available,
 *   then give up at once.
 *
 * %__GFP_NOWARN - If allocation fails, don't issue any warnings.
 *
 * %__GFP_REPEAT - If allocation fails initially, try once more before failing.
 *
 * There are other flags available as well, but these are not intended
 * for general use, and so are not documented here. For a full list of
 * potential flags, always refer to linux/gfp.h.
 */
 /*__builtin_constant_p  判断是否为常量  believe that this asks the compiler whether its argument evaluates
to a constant value. For instance, __builtin_constant_p(1234) has a
value of 1, whereas __builtin_constant_p(x), where `x` is a variable,
has a value of 0.This is sometimes useful when writing highly-optimized code.*/
static __always_inline void *kmalloc(size_t size, gfp_t flags)
{
    if (__builtin_constant_p(size)) {//是否为常量

        if (size > KMALLOC_MAX_CACHE_SIZE)// 大于 kmalloc cache size,就通过 alloc_pages 分配page 然后映射出虚拟内核地址
            return kmalloc_large(size, flags);
#ifndef CONFIG_SLOB
        if (!(flags & GFP_DMA)) {
            int index = kmalloc_index(size);

            if (!index)
                return ZERO_SIZE_PTR;

            return kmem_cache_alloc_trace(kmalloc_caches[index],
                    flags, size);//通过 kmem_cache_alloc  分配除内存 比如kmalloc-32 kmalloc-64
        }
#endif
    }
    //动态数值:通过slab 等
    return __kmalloc(size, flags);
}

/**
 * __do_kmalloc - allocate memory
 * @size: how many bytes of memory are required.
 * @flags: the type of memory to allocate (see kmalloc).
 * @caller: function caller for debug tracking of the caller
 */
static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
                      unsigned long caller)
{
    struct kmem_cache *cachep;
    void *ret;

    cachep = kmalloc_slab(size, flags);// 也会校验 size的大小,超过kmalloc的大小,认为是错误的,通过size 返回kmalloc_cache的index
    if (unlikely(ZERO_OR_NULL_PTR(cachep)))
        return cachep;
    ret = slab_alloc(cachep, flags, caller);

    kasan_kmalloc(cachep, ret, size, flags);
    trace_kmalloc(caller, ret,
              size, cachep->size, flags);

    return ret;
}

/*
 * Find the kmem_cache structure that serves a given size of
 * allocation
 */
struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags)
{
    int index;

    if (unlikely(size > KMALLOC_MAX_SIZE)) {
        WARN_ON_ONCE(!(flags & __GFP_NOWARN));
        return NULL;
    }

    if (size <= 192) {
        if (!size)
            return ZERO_SIZE_PTR;

        index = size_index[size_index_elem(size)];
    } else
        index = fls(size - 1);

#ifdef CONFIG_ZONE_DMA
    if (unlikely((flags & GFP_DMA)))
        return kmalloc_dma_caches[index];

#endif
    return kmalloc_caches[index];
}

 

 

Vmalloc:可以看奔跑吧linux 内核这本书:

  1,vmalloc分配的一般为高端内存,只有当内存不够的时候才分配低端内存;kmallco从低端内存分配。

  2,vmalloc分配的物理地址一般不连续,而kmalloc分配的地址连续,两者分配的虚拟地址都是连续的;

  3,vmalloc分配的一般为大块内存,而kmaooc一般分配的为小块内存,(一般不超过128k);

   

/*
 *    vmalloc  -  allocate virtually contiguous memory
 *
 *    @size:        allocation size
 *
 *    Allocate enough pages to cover @size from the page level
 *    allocator and map them into contiguous kernel virtual space.
 *
 *    For tight control over page level allocator and protection flags
 *    use __vmalloc() instead.
 */
void *vmalloc(unsigned long size)
{
       return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);
}

 

 

 

 

 

 

 

 

void *__vmalloc_node_range(unsigned long size, unsigned long align,
            unsigned long start, unsigned long end, gfp_t gfp_mask,
            pgprot_t prot, unsigned long vm_flags, int node,
            const void *caller)
{
    struct vm_struct *area;
    void *addr;
    unsigned long real_size = size;

    size = PAGE_ALIGN(size);//page 对其,也就是size 是10Bytes,结果还是分配一个页 注意效率啊
    if (!size || (size >> PAGE_SHIFT) > totalram_pages)
        goto fail;
------------------
    area = __get_vm_area_node(size, align, VM_ALLOC | VM_UNINITIALIZED |
                vm_flags, start, end, node, gfp_mask, caller);
-----
    addr = __vmalloc_area_node(area, gfp_mask, prot, node);
----------------------------return addr;
----------
}

 

 

 

 

 

 

 

 

posted @ 2022-01-27 13:17  codestacklinuxer  阅读(48)  评论(0编辑  收藏  举报