linux kernel中
memory可以分成3種類型的ZONE
1. ZONE_DMA: 有些Device需要用DMA (direct memory access) 用途的memory
2. ZONE_NORMAL: 一般memory
3. ZONE_HIGHMEM: high memory, 不是永久都會是kernel space address的那些memory

在linux kernel中allocate page or memory的function
1. struct page * alloc_pages(gfp_t gfp_mask, unsigned int order)
gfp_mask 待會再說 先感受一下page要怎樣allocate
要注意的是,這裡的order指的是 2^order (1 << order)
例如
page = alloc_pages(GFP_KERNEL, 2);
要的是4個page
另 page_address(struct page *page) 可以回傳page的logical address

2. unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
這個function的動作和alloc_pages()一樣,只是他是直接回傳page的logical address

3. struct page * alloc_page(gfp_t gfp_mask)
等同於
alloc_pages(gfp_mask, 0);

4. unsigned long __get_free_page(gfp_t gfp_mask)
等同於
__get_free_pages(gfp_mask, 0);

5. unsigned long get_zeroed_page(unsigned int gfp_mask)
這個function比較特別,回傳的是page 的logical address
但是內容已經被清為0

注意 以上function回傳的都是連續的physical space (連續的physical pages)!!

對應的free functions
void __free_pages(struct page *page, unsigned int order)
void free_pages(unsigned long addr, unsigned int order)
void free_page(unsigned long addr)

記住!
在alloc memory的時候必須加入錯誤偵測
因為並不一定每一次alloc memory 都會成功
sample code.
unsigned long page;
page = __get_free_pages(GFP_KERNEL, 3)
if (!page) {
/* 記憶體不足 */
return -ENOMEM;
}

/* 不需要用 請記得釋放它 */
free_pages(page, 3)

以上所說 都為page為單位
以下是以byte為單位
1. void * kmalloc(size_t size, gfp_t flags);
void kfree(const void *ptr);
回傳一個連續的physical space
Sample code.
struct dog *p;
p = kmalloc(sizeof(struct dog), GFP_KERNEL);
if (!p)
/* handling error... */
kfree(p);

很明顯的 這個function所回傳的資料
最小一定會比size大 這是因為kernel的最底層
會是以page為單位allocate
所以回傳的大小會是page size的倍數
注意!!
不用要kfree()去釋放不是由kmalloc()所配置的memory

剛剛用了這麼多gfp_mask
現在深入的談談gfp_mask 有哪些flag 和 要怎麼用
是可以分成action modifier, zone modifier, 和type flag
不過一般來說只會用到type flag
type flag是由action modifier和zone modifier組成
但是在這裡只會紀錄常用的type flag

Type Flags
1. GFP_ATOMIC
一看見atomic 然後去查字典 會發現是原子的意思
原子跟kernel 有甚麼關係 ??
其實應該是取他不可分割的意思
意思就是這個動作不會被中斷 一次做到完的意思
在alloc memory的時候 為了要回收memory可能會reschedule
會造成這個process sleep
所以這個flag就是確保在allocate memory的時候不會做以上的動作
這個特性 就是要用在
interrupt handles 之類,不能sleep的routine中

2. GFP_KERNEL
可以進入sleep,最常用的應該就是這個flag
如果沒有特殊需求 用這個就對了

3. GFP_NOIO, GFP_NOFS
NOIO 沒有初始化disk I/O
NOFS 沒有初始化filesystem I/O
為什麼需要用??
I/O只有一個
假設沒有使用這些flag
第一個allocator 配置memory 做了I/O的操作
另一個allocator 配置memory的時候也做了I/O的動作
allocator必需確認沒有人在使用I/O
會造成deadlock

4. GFP_DMA
通常使用在device drivers 而且和GFP_ATOMIC 或 GFP_KERNEL
其中之一連用

以下是一些情況和對應的flags
-------------------------------------------------------------
情況 flags
process context, can sleep            Use GFP_KERNEL
process context, cannot sleep       Use GFP_ATOMIC
interrupt handler                           Use GFP_ATOMIC
softirq                                            Use GFP_ATOMIC
tasklet                                           Use GFP_ATOMIC
need DMA memory, can sleep        Use (GFP_DMA | GFP_KERNEL)
need DMA memory, cannot sleep   Use (GFP_DMA | GFP_ATOMIC)

另外 virtual address的配置是使用
vmalloc vfree
vmalloc()只保證回傳連續的virtual pages
在virtual address 是連續的!
在kernel中為了效能
通常都會使用kmalloc

Reference

1. Linux Kernel Development 3rd-博客來

2. Linux Kernel Development 3rd-天瓏

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 jpsix 的頭像
    jpsix

    地瓜粥在讀書

    jpsix 發表在 痞客邦 留言(0) 人氣()