日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

周六早上读核感悟

發(fā)布時間:2024/4/15 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 周六早上读核感悟 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

今天周六,因為老婆還要早起備課,我也就跟著早早起來了,九點半就起床了,閑來無事就看了一會代碼,懶得寫代碼看代碼總可以了吧,主要看了兩塊,都是關(guān)于內(nèi)存的,一個是內(nèi)核高端臨時映射,一個是伙伴系統(tǒng)的per_cpu_pages中的冷熱頁面隊列,一個一個說。

關(guān)于高端映射的原理我就不多說了,內(nèi)核代碼很清晰,基本就是在虛擬內(nèi)存的高端為每個cpu都預(yù)留了一片區(qū)域:

enum fixed_addresses {

...

#ifdef CONFIG_HIGHMEM

FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */

FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, //為每一個cpu都留一片區(qū)域

...

__end_of_fixed_addresses

};

enum km_type {

KM_BOUNCE_READ,

KM_SKB_SUNRPC_DATA,

KM_SKB_DATA_SOFTIRQ,

KM_USER0, //操作用戶數(shù)據(jù)時用

KM_USER1,

KM_BIO_SRC_IRQ,

KM_BIO_DST_IRQ,

KM_PTE0,

KM_PTE1,

KM_IRQ0, //中斷用

KM_IRQ1,

KM_SOFTIRQ0, //軟中斷用

KM_SOFTIRQ1,

KM_TYPE_NR //類型的數(shù)量

};

static void __init kmap_init(void)

{

unsigned long kmap_vstart;

kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);

kmap_pte = kmap_get_fixmap_pte(kmap_vstart);

kmap_prot = PAGE_KERNEL;

}

void *kmap_atomic(struct page *page, enum km_type type)

{

enum fixed_addresses idx;

unsigned long vaddr;

inc_preempt_count();

if (!PageHighMem(page))

return page_address(page);

idx = type + KM_TYPE_NR*smp_processor_id(); //找到屬于本cpu的那一片臨時映射區(qū)域

vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);

set_pte(kmap_pte-idx, mk_pte(page, kmap_prot));

__flush_tlb_one(vaddr);

return (void*) vaddr;

}

上面的過程簡單而又清晰,在內(nèi)核代碼中很多地方用到了KM_USER0/1的地方,說不能在中斷上下文調(diào)用,這到底是為什么?而且在上面的代碼可以看出來,映射的時候,根本不管這個地址是否已經(jīng)有了映射,而是直接映射進去,那么可想而知,如果原來有映射的話,那么數(shù)據(jù)肯定就被破壞了,其實也不是破壞,而是訪問者的頁面被默默更換了,這可能會釀成事故,我們一般要求虛擬地址是頁面獨占的,也就是說一個虛擬地址必須對應(yīng)僅一個頁面,除了這個臨時映射,別的映射都可以保證這一點,對于用戶映射,如果不是因為缺頁,那是不會映射新頁面的,因此問題解決,對于內(nèi)核一一映射,初始化時就映射好了,以后也不會改變,對于vmalloc動態(tài)映射,vm_struct鏈表可以保證一個地址如果已經(jīng)被映射就不再會有別的映射,對于kmap映射的永久映射,last_pkmap_nr也會保證這一點,但是對于高端臨時映射卻沒有任何保證,這該如何是好,這難道是內(nèi)核的不周嗎?如果這樣想的話就錯了,前面幾種映射是有保證,但是這種保證的代價就是沒有話你就必須等,對于不允許等待的操作或者快速操作,有必要提供一個特殊通道給它們用,就好比大型超市結(jié)賬的地方都有快速區(qū),你如果就買一瓶純凈水,那么就不必排隊了,內(nèi)核也是這樣。快速通道就是專門為一些快速操作提供的,但是內(nèi)核是不允許出錯的,為了防止意外,比如不能保證沒有兩個快速操作同時需要映射,那么就要進行排隊,而排隊就意味著等待,這好像又回到了前面的那些映射方式,這似乎是一個怪圈,如果按照這種線性的思路考慮的話,就不可能找到一種截然不同的又不用等待又不會出錯的解決方案,那么內(nèi)核可以講排隊的縱向過程鋪開成橫向的多個窗口,也就有了上面的臨時映射的設(shè)計方式,km_type中的就是這些窗口,用戶當(dāng)然可以隨便使用,但是出了問題內(nèi)核概不負(fù)責(zé),因此把規(guī)則交給用戶自覺遵守而不是靠內(nèi)核來扶正,這就是最好的解決方案,這個方案不用等待,來了一個用戶頁面的映射,那么由于一個cpu一個時間只能有一個用戶進程陷入內(nèi)核,那么為每個cpu都提供一個km_type窗口的話所有問題就解決了,臨時映射用戶頁面的時候,內(nèi)核執(zhí)行緒十分了解自己的行為,它將該頁面映射到自己cpu的KM_USER0,或者KM_USER1,然后就可以安心的操作了,因為內(nèi)核固定了只有操作用戶頁面的才可以映射到這兩個窗口,這個進程之所以安心是因為它相信別的執(zhí)行緒會遵守這個規(guī)定的,另外對它本身的限制就是它的操作必須快速而且不許睡眠,當(dāng)然內(nèi)核也不能搶占,這是靠遞增搶占標(biāo)志做到的。km_type窗口中的每一個都有自己的用途,用戶只要按照規(guī)定使用就沒有問題,這個特殊的快速通道確實起到了快速操作的作用。

關(guān)于伙伴系統(tǒng)的per_cpu_pages中的冷熱頁面隊列前面我就研究過一段時間,如果是進程的頁面釋放,那么就釋放到熱隊列中,如果是設(shè)備的頁面,那么就釋放到冷隊列中,因為設(shè)備使用的僅僅是頁面,比如DMA,它是不經(jīng)過cpu的,因此頁面數(shù)據(jù)就不會被cpu的cache緩存,其實很多硬件外設(shè)沒有MMU,因此要求為硬件外設(shè)分配內(nèi)存的時候必須為它指定物理地址,并且地址必須連續(xù),把它想成實模式cpu就可以了。外設(shè)不被cpu緩存,那么外設(shè)的頁面置入冷隊列,這樣在釋放頁面的時候,伙伴系統(tǒng)的熱隊列頁面數(shù)量肯定比全部數(shù)量少,這樣當(dāng)有頁面分配需要的時候,如果是cpu需要頁面,那么直接從熱隊列分配,此時很可能數(shù)據(jù)還在cpu緩存中,效率會大大提高,即使你不用老頁面的數(shù)據(jù)而是使用一個零頁面,那么在memset(addr,0,PAGE_SIZE)的時候也會提高效率,因為cpu操作的是虛擬地址,總線上才是物理地址。頁面總是順序排列的,不同的是它的虛擬地址可能每次都不同,然而cpu最終訪問的頁面,此時已經(jīng)過了mmu,cpu是以物理地址操作cache的而不是虛擬地址,因此緩存熱頁面才有意義。

轉(zhuǎn)載于:https://blog.51cto.com/dog250/1273506

總結(jié)

以上是生活随笔為你收集整理的周六早上读核感悟的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。