config_no_bootmem

来源:互联网 发布:ar3d什么软件 编辑:程序博客网 时间:2024/04/27 21:47
在uboot 传递给kernel memory bank相关信息后,kernel这边会以memblcok的方式保存这些信息,当buddy system 没有起来之前,在kernel中也是要有一套机制来管理memory的申请和释放.
source/mm/Makefile
 44 ifdef CONFIG_NO_BOOTMEM
 45         obj-y           += nobootmem.o
 46 else
 47         obj-y           += bootmem.o
 48 endif
如上所示kernel 可以选择nobootmem 或者bootmem 来在buddy system起来之前管理memory.
这两种机制对提供的API是一致的,因此对用户是透明的。我们以alloc_bootmem 为例来分析一下这两种机制的差别.
可以看到alloc_bootmem 在下面两个文件中都有实现。
mm/nobootmem.c, line 309
mm/bootmem.c, line 700


700 void * __init __alloc_bootmem(unsigned long size, unsigned long align,
701                               unsigned long goal)
702 {
703         unsigned long limit = 0;
704 
705         return ___alloc_bootmem(size, align, goal, limit);
706 }
两种机制继续调用___alloc_bootmem
672 static void * __init ___alloc_bootmem(unsigned long size, unsigned long align,
673                                         unsigned long goal, unsigned long limit)
674 {
675         void *mem = ___alloc_bootmem_nopanic(size, align, goal, limit);
676 
677         if (mem)
678                 return mem;
679         /*
680          * Whoops, we cannot satisfy the allocation request.
681          */
682         pr_alert("bootmem alloc of %lu bytes failed!\n", size);
683         panic("Out of memory");
684         return NULL;
685 }
两种机制继续调用___alloc_bootmem_nopanic
632 static void * __init ___alloc_bootmem_nopanic(unsigned long size,
633                                               unsigned long align,
634                                               unsigned long goal,
635                                               unsigned long limit)
636 {
637         void *ptr;
638 
639 restart:
640         ptr = alloc_bootmem_core(size, align, goal, limit);
641         if (ptr)
642                 return ptr;
643         if (goal) {
644                 goal = 0;
645                 goto restart;
646         }
647 
648         return NULL;
649 }
从___alloc_bootmem_nopanic 两种机制走的flow就不一样了我们先看bootmem 调用alloc_bootmem_core


 static void * __init alloc_bootmem_core(unsigned long size,
608                                         unsigned long align,
609                                         unsigned long goal,
610                                         unsigned long limit)
611 {
612         bootmem_data_t *bdata;
613         void *region;
614 
615         if (WARN_ON_ONCE(slab_is_available()))
616                 return kzalloc(size, GFP_NOWAIT);
617 
618         list_for_each_entry(bdata, &bdata_list, list) {
619                 if (goal && bdata->node_low_pfn <= PFN_DOWN(goal))
620                         continue;
621                 if (limit && bdata->node_min_pfn >= PFN_DOWN(limit))
622                         break;
623 
624                 region = alloc_bootmem_bdata(bdata, size, align, goal, limit);
625                 if (region)
626                         return region;
627         }
628 
629         return NULL;
630 }
这个时候就去bdata 中的bitmap中找是否有足够的memory 进行,是page来计算的。


而noboomem的___alloc_bootmem_nopanic的实现如下:
235 static void * __init ___alloc_bootmem_nopanic(unsigned long size,
236                                         unsigned long align,
237                                         unsigned long goal,
238                                         unsigned long limit)
239 {
240         void *ptr;
241 
242         if (WARN_ON_ONCE(slab_is_available()))
243                 return kzalloc(size, GFP_NOWAIT);
244 
245 restart:
246 
247         ptr = __alloc_memory_core_early(NUMA_NO_NODE, size, align, goal, limit);
248 
249         if (ptr)
250                 return ptr;
251 
252         if (goal != 0) {
253                 goal = 0;
254                 goto restart;
255         }
256 
257         return NULL;
258 }
调用__alloc_memory_core_early 来分配memory
static void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
 37                                         u64 goal, u64 limit)
 38 {
 39         void *ptr;
 40         u64 addr;
 41         ulong flags = choose_memblock_flags();
 42 
 43         if (limit > memblock.current_limit)
 44                 limit = memblock.current_limit;
 45 
 46 again:
 47         addr = memblock_find_in_range_node(size, align, goal, limit, nid,
 48                                            flags);
 49         if (!addr && (flags & MEMBLOCK_MIRROR)) {
 50                 flags &= ~MEMBLOCK_MIRROR;
 51                 pr_warn("Could not allocate %pap bytes of mirrored memory\n",
 52                         &size);
 53                 goto again;
 54         }
 55         if (!addr)
 56                 return NULL;
 57 
 58         if (memblock_reserve(addr, size))
 59                 return NULL;
 60 
 61         ptr = phys_to_virt(addr);
 62         memset(ptr, 0, size);
 63         /*
 64          * The min_count is set to 0 so that bootmem allocated blocks
 65          * are never reported as leaks.
 66          */
 67         kmemleak_alloc(ptr, size, 0, 0);
 68         return ptr;
 69 }
最终的是47行直接调用memblcok 来分配.
可见两种机制提供的API是一致的。但是实现的细节不同。bootmem是通过bitmap,按page来申请的。而nobootmem 直接通过memblock来实现。个人还是比较喜欢nobootmem 去繁就简的实现。
0 0