天天看點

【存儲管理】核心緩沖區的管理

專用緩沖區隊列

(1)在kmem_cache_s中,slabs維持一個slab隊列,firstnotfull指向隊列中第一個含有空閑對象的slab,當firstnotfull== slabs表示隊列中已不存在空閑對象slab,next用來cache_cache建立專用緩沖區slab隊列的隊列,及slab隊列控制結構的隊列,當slab的slabt與對象不再同一個slab上時即大對象,指針slabp_cache指向對方隊列中的控制結構,num表示slab上有幾個緩沖區,gfporder表示每一個slab的大小,objsize表示原始對象的大小(如node);

(2)在使用kmem_cache_create()時,參數offset為0表示對第一個緩沖區在slab中的位移并無要求,但flags是SLAB_HWCACHE_ALIGN表示要求與高速緩存中的緩沖行邊界對齊,指明構造函數和拆除函數;具體功能是經過一系列的運算,以确定每一個slab有幾個頁面組成,劃分成多少個對象緩沖區,slab的控制結構kmem_slab_t應該在slab上外面集中存儲,還是與相應的緩沖區緊挨着放在一起,還有“顔色”數量等等,最後要将kmem_cache_t鍊入cache_cahe的next隊列中;它隻是建立了所需的專用緩沖區隊列的基礎設施,所形成的slab隊列是個空隊列,具體的建立等需要配置設定緩沖區時,卻發現隊列中無空閑的緩沖區可供配置設定,使用kmem_cache_grow來進行的;

(3)在_kmem_cache_alloc()中,kem_cache_alloc_one()通過隊列頭的指針firstnotfull,找到第一個含有空閑對象的slab,如果它與slabs相同,說明還未建立好slab隊列,是個空隊列或沒有空閑對象的slab,應該進一步擴充;如果找到了空的slab,就使用kmem_cache_alloc_one_tail,return slab->smem+slab->free*cache->objsize,更新slabt,kmem_cache_t裡的相關資訊;如果slab隊列中已經不存在包含空閑對象的slab,是以到标号alloc_new_slab中,使用kmem_cache_grow來配置設定一塊新的slab,使緩沖區隊列生長起來;

(4)在kmem_cache_grow中,首先對一些參數進行了一些檢查以後,計算出下一塊slab的着色區大小,通過kmem_getpages()配置設定用于具體對象緩沖區的頁面,這個函數最終調用alloc_pages()配置設定空閑頁面,然後使用kmem_cache_slabmgme建立起slab的管理資訊,及更新inuse=0,以及更新colouroff着色區的大小s_mem=objp+colour_off;使用宏操作SET_PAGE_CACHE,SET_PAGE_SLAB設定page的prev和next,分别使他們屬于所屬的slab和slab隊列,PageSetSlab設定page的PG_slab設定為1,以表明頁面的用途;緩沖區隊列增長以後, 在_kmem_cache_alloc()中try_again重試;

(5)其實在_kmem_cache_alloc()在之前,我們會調用skb_from_poll(),先從已配置設定的slab塊中配置設定,如果失敗的話再試_kmem_cache_alloc();緩沖區隊列的縮小是通過kswapd定時地調用kmem_cache_reap()來收割,依次檢查若幹專用緩沖區slab隊列,看是否有完全空閑的slab存在,有的話就将這些slab占用的記憶體頁面釋放;

(6)kmem_cache_free()中的kmem_cache_free_one()通過slab的連結數組釋放給定對象,還要遞減所屬slab隊列控制結構中的非空閑對象的計數即inuse,分為三種情況(原slab沒有空閑對象後現在有了,原slab有空閑對象後現在所有的都空閑了,原slab有空閑對象後現在就多一個);

通用緩沖區隊列

(1)kmalloc就是使用使用通用緩沖區隊列的一個例子,它首先在cache_sizes結構數組中從小到大掃描,找到第一個能滿足要求的隊列,然後調用_kmem_cache_alloc()從該隊列中配置設定一個緩沖區;