设为首页 加入收藏

TOP

Linux内核最新的连续内存分配器(CMA)——避免预留大块内存【转】(二)
2019-09-01 23:09:14 】 浏览:155
Tags:Linux 内核 最新 连续 内存 分配器 CMA 避免 预留 大块
p;     */         r->start = base;         r->size = size;         r->dev = dev;         cma_reserved_count++;         pr_info("CMA: reserved %ld MiB at %08lx\n", size / SZ_1M,                 (unsigned long)base);         /* Architecture specific contiguous memory fixup. */         dma_contiguous_early_fixup(base, size);         return 0; err:         pr_err("CMA: failed to reserve %ld MiB\n", size / SZ_1M);         return base; }

由此可见,连续内存区域也是在内核启动的早期,通过__memblock_alloc_base()拿到的。

另外:

drivers/base/dma-contiguous.c里面的core_initcall()会导致cma_init_reserved_areas()被调用:

cma_create_area()会调用cma_activate_area(),cma_activate_area()函数则会针对每个page调用:

init_cma_reserved_pageblock(pfn_to_page(base_pfn));

这个函数则会通过set_pageblock_migratetype(page, MIGRATE_CMA)将页设置为MIGRATE_CMA类型的:

#ifdef CONFIG_CMA
/* Free whole pageblock and set it's migration type to MIGRATE_CMA. */
void __init init_cma_reserved_pageblock(struct page *page)
{                                    
        unsigned i = pageblock_nr_pages;
        struct page *p = page;
        
        do {
                __ClearPageReserved(p);
                set_page_count(p, 0);
        } while (++p, --i);
        
        set_page_refcounted(page);
        set_pageblock_migratetype(page, MIGRATE_CMA);
        __free_pages(page, pageblock_order);
        totalram_pages += pageblock_nr_pages;
}       
#endif

同时其中调用的__free_pages(page, pageblock_order);最终会调用到__free_one_page(page, zone, order, migratetype);

相关的page会被加到MIGRATE_CMA的free_list上面去:

list_add(&page->lru, &zone->free_area[order].free_list[migratetype]);

2. 申请连续内存

申请连续内存仍然使用标准的arch/arm/mm/dma-mapping.c中定义的dma_alloc_coherent()和dma_alloc_writecombine(),这二者会间接调用drivers/base/dma-contiguous.c中的

struct page *dma_alloc_from_contiguous(struct device *dev, int count,
                                       unsigned int align)

->

struct page *dma_alloc_from_contiguous(struct device *dev, int count,
                                       unsigned int align)
{
       ...
 
       for (;;) {
                pageno = bitmap_find_next_zero_area(cma->bitmap, cma->count,
                                                    start, count, mask);
                if (pageno >= cma->count) {
                        ret = -ENOMEM;
                        goto error;
                }
 
                pfn = cma->base_pfn + pageno;
                ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA);
                if (ret == 0) {
                        bitmap_set(cma->bitmap, pageno, count);
                        break;
                } else if (ret != -EBUSY) {
                        goto error;
                }
                pr_debug("%s(): memory range at %p is busy, retrying\n",
                         __func__, pfn_to_page(pfn));
                /* try again with a bit different memory target */
                start = pageno + mask + 1;
        }
       ...
 
}

--》

int alloc_contig_range(unsigned long start, unsigned long end,

                       unsigned migratetype)

需要隔离page,隔离page的作用通过代码的注释可以体现:

 /*
         * What we do here is we mark all pageblocks in range as
         * MIGRATE_ISOLATE.  Because of the way page allocator work, we
         * align the range to MAX_ORDER pages so that page allocator
         * won't try to merge buddies from different pageblocks and
         * change MIGRATE_ISOLATE to some other migration type.
         *
         * Once the pageblocks
首页 上一页 1 2 3 4 5 6 下一页 尾页 2/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇微处理器功耗来源 下一篇a simple game based on RT-Thread

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目