Cosmos OpenSSD--greedy_ftl1.2.0(三)


我們來假設模擬一個小型的模型來分析寫和垃圾回收的過程

假設只有一個die,4個block,每個block4個page,每個page8KB

那么PageMap就是Page[0][0]到Page[0][15]

BlockMap就是Block[0][0]到Block[0][3]

GcMap就是GC[0][0]到GC[0][4]

那么最初就會如下圖:第零塊用來保留元數據,最后一塊保留作為垃圾回收合並塊

 


 接下來從上層來了數據,黃色部分表示更改的數據,紅色部分表示更新的數據,最左側是流程

在這里,lpn0的內容作為page緩存留在SDRAM里面,只把lpn1的內容存入flash

 


接下來更改的數據緩存命中了,所以lpn0的內容直接在SDRAM里面修改,此時數據末尾剛好占據了一個頁,所以直接存入flash,並把之前的保存頁無效,此時GC表開始變化

 


接下來依舊緩存命中,但是請求最后一頁並不是完整的一頁,於是先預讀出其中的內容,修改之后尋找新頁再保存進flash

 


這一次的緩存並沒有命中,所以先把SDRAM里面的內容flush進SDRAM里面,因為請求並不滿足一頁,所以執行read-modify-write,此時lpn1作為新的page緩存,並不直接存進flash而是保留在SDRAM中

 


緩存依舊不命中,此時block1已經沒有頁面可用了,於是找到了下一個空閑block,先flush,然后更新page緩存,將lpn1的內容存入flash

 


接下來緩存不命中,並且消耗掉了所有的頁面,於是lpn3的內容無處存取,引發垃圾回收操作

 


垃圾回收操作的依據是元數據的更新,因此我們來看元數據更新的代碼

 1 void UpdateMetaForOverwrite(u32 lpn)
 2 {
 3     pageMap = (struct pmArray*)(PAGE_MAP_ADDR);
 4     blockMap = (struct bmArray*)(BLOCK_MAP_ADDR);
 5     gcMap = (struct gcArray*)(GC_MAP_ADDR);
 6 
 7     u32 dieNo = lpn % DIE_NUM;
 8     u32 dieLpn = lpn / DIE_NUM;
 9 
10     if(pageMap->pmEntry[dieNo][dieLpn].ppn != 0xffffffff)
11     {
12         // GC victim block list management
13         u32 diePbn = pageMap->pmEntry[dieNo][dieLpn].ppn / PAGE_NUM_PER_BLOCK;
14 
15         // unlink
16         if((blockMap->bmEntry[dieNo][diePbn].nextBlock != 0xffffffff) && (blockMap->bmEntry[dieNo][diePbn].prevBlock != 0xffffffff))
17         {
18             blockMap->bmEntry[dieNo][blockMap->bmEntry[dieNo][diePbn].prevBlock].nextBlock = blockMap->bmEntry[dieNo][diePbn].nextBlock;
19             blockMap->bmEntry[dieNo][blockMap->bmEntry[dieNo][diePbn].nextBlock].prevBlock = blockMap->bmEntry[dieNo][diePbn].prevBlock;
20         }
21         else if((blockMap->bmEntry[dieNo][diePbn].nextBlock == 0xffffffff) && (blockMap->bmEntry[dieNo][diePbn].prevBlock != 0xffffffff))
22         {
23             blockMap->bmEntry[dieNo][blockMap->bmEntry[dieNo][diePbn].prevBlock].nextBlock = 0xffffffff;
24             gcMap->gcEntry[dieNo][blockMap->bmEntry[dieNo][diePbn].invalidPageCnt].tail = blockMap->bmEntry[dieNo][diePbn].prevBlock;
25         }
26         else if((blockMap->bmEntry[dieNo][diePbn].nextBlock != 0xffffffff) && (blockMap->bmEntry[dieNo][diePbn].prevBlock == 0xffffffff))
27         {
28             blockMap->bmEntry[dieNo][blockMap->bmEntry[dieNo][diePbn].nextBlock].prevBlock = 0xffffffff;
29             gcMap->gcEntry[dieNo][blockMap->bmEntry[dieNo][diePbn].invalidPageCnt].head = blockMap->bmEntry[dieNo][diePbn].nextBlock;
30         }
31         else
32         {
33             gcMap->gcEntry[dieNo][blockMap->bmEntry[dieNo][diePbn].invalidPageCnt].head = 0xffffffff;
34             gcMap->gcEntry[dieNo][blockMap->bmEntry[dieNo][diePbn].invalidPageCnt].tail = 0xffffffff;
35         }
36 
37 //            xil_printf("[unlink] dieNo = %d, invalidPageCnt= %d, diePbn= %d, blockMap.prevBlock= %d, blockMap.nextBlock= %d, gcMap.head= %d, gcMap.tail= %d\r\n", dieNo, blockMap->bmEntry[dieNo][diePbn].invalidPageCnt, diePbn, blockMap->bmEntry[dieNo][diePbn].prevBlock, blockMap->bmEntry[dieNo][diePbn].nextBlock, gcMap->gcEntry[dieNo][blockMap->bmEntry[dieNo][diePbn].invalidPageCnt].head, gcMap->gcEntry[dieNo][blockMap->bmEntry[dieNo][diePbn].invalidPageCnt].tail);
38 
39         // invalidation update
40         pageMap->pmEntry[dieNo][pageMap->pmEntry[dieNo][dieLpn].ppn].valid = 0;
41         blockMap->bmEntry[dieNo][diePbn].invalidPageCnt++;
42 
43         // insertion
44         if(gcMap->gcEntry[dieNo][blockMap->bmEntry[dieNo][diePbn].invalidPageCnt].tail != 0xffffffff)
45         {
46             blockMap->bmEntry[dieNo][diePbn].prevBlock = gcMap->gcEntry[dieNo][blockMap->bmEntry[dieNo][diePbn].invalidPageCnt].tail;
47             blockMap->bmEntry[dieNo][diePbn].nextBlock = 0xffffffff;
48             blockMap->bmEntry[dieNo][gcMap->gcEntry[dieNo][blockMap->bmEntry[dieNo][diePbn].invalidPageCnt].tail].nextBlock = diePbn;
49             gcMap->gcEntry[dieNo][blockMap->bmEntry[dieNo][diePbn].invalidPageCnt].tail = diePbn;
50         }
51         else
52         {
53             blockMap->bmEntry[dieNo][diePbn].prevBlock = 0xffffffff;
54             blockMap->bmEntry[dieNo][diePbn].nextBlock = 0xffffffff;
55             gcMap->gcEntry[dieNo][blockMap->bmEntry[dieNo][diePbn].invalidPageCnt].head = diePbn;
56             gcMap->gcEntry[dieNo][blockMap->bmEntry[dieNo][diePbn].invalidPageCnt].tail = diePbn;
57         }
58     }
59 }

其實從上面的寫過程分析,我們可以大概了解到GC表其實就是把有相同無效頁的block串聯在一起

我們假設從block1到block7,其中無效頁最終分別為100,120,110,100,110,120,100

當block1進行完之后,GC[0][100].head=1  GC[0][100].tail=1

當block2的無效頁也到達100的時候,分析代碼可知,GC[0][100].head=1  GC[0][100].tail=2,而且block1和block2會鏈接起來,但是block2的無效頁會繼續增加,於是當他的無效頁增加的時候,block1和block2又會斷開,指向無效的0xffffffff,而block2執行完畢之后GC[0][120].head=2  GC[0][120].tail=2.

只有當block4和block7的無效頁最終停在100的時候,block1↔block4↔block7

 


 既然已經了解GC表表示的什么意思,那么再看垃圾回收操作的代碼就簡單多了

 1 u32 GarbageCollection(u32 dieNo)
 2 {
 3     xil_printf("GC occurs!\r\n");
 4 
 5     pageMap = (struct pmArray*)(PAGE_MAP_ADDR);
 6     blockMap = (struct bmArray*)(BLOCK_MAP_ADDR);
 7     dieBlock = (struct dieArray*)(DIE_MAP_ADDR);
 8     gcMap = (struct gcArray*)(GC_MAP_ADDR);
 9 
10     int i;
11     for(i=PAGE_NUM_PER_BLOCK ; i>0 ; i--)      //從無效頁大的開始回收 12     {
13         if(gcMap->gcEntry[dieNo][i].head != 0xffffffff)  //擁有這么多無效頁的塊存在的話,取出一塊進行回收 14         {
15             u32 victimBlock = gcMap->gcEntry[dieNo][i].head;    // GC victim block
16 
17             // link setting
18             if(blockMap->bmEntry[dieNo][victimBlock].nextBlock != 0xffffffff)  //更新GC鏈表 19             {
20                 gcMap->gcEntry[dieNo][i].head = blockMap->bmEntry[dieNo][victimBlock].nextBlock;
21                 blockMap->bmEntry[dieNo][blockMap->bmEntry[dieNo][victimBlock].nextBlock].prevBlock = 0xffffffff;
22             }
23             else
24             {
25                 gcMap->gcEntry[dieNo][i].head = 0xffffffff;
26                 gcMap->gcEntry[dieNo][i].tail = 0xffffffff;
27             }
28 
29             // copy valid pages from the victim block to the free block
30             if(i != PAGE_NUM_PER_BLOCK)    //如果整個塊都是無效頁就直接擦除就行了 31             {
32                 int j;
33                 for(j=0 ; j<PAGE_NUM_PER_BLOCK ; j++)  //
34                 {
35                     if(pageMap->pmEntry[dieNo][(victimBlock * PAGE_NUM_PER_BLOCK) + j].valid)
36                     {
37                         // page copy process
38                         u32 validPage = victimBlock*PAGE_NUM_PER_BLOCK + j;
39                         u32 freeBlock = dieBlock->dieEntry[dieNo].freeBlock;  //最開始有預留一個塊 40                         u32 freePage = freeBlock*PAGE_NUM_PER_BLOCK + blockMap->bmEntry[dieNo][freeBlock].currentPage;
41 
42                         WaitWayFree(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM);
43                         SsdRead(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM, validPage, GC_BUFFER_ADDR);    //將一個塊里面的有效頁讀取到BUFFER里面 44                         WaitWayFree(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM);
45                         SsdProgram(dieNo % CHANNEL_NUM, dieNo / CHANNEL_NUM, freePage, GC_BUFFER_ADDR);  //有效數據寫入 46 
47                         // pageMap, blockMap update
48                         u32 lpn = pageMap->pmEntry[dieNo][validPage].lpn;
49 
50                         pageMap->pmEntry[dieNo][lpn].ppn = freePage;      //更新頁映射信息 51                         pageMap->pmEntry[dieNo][freePage].lpn = lpn;
52                         blockMap->bmEntry[dieNo][freeBlock].currentPage++;
53                     }
54                 }
55             }
56 
57             // erased victim block becomes the free block for GC migration
58             EraseBlock(dieNo, victimBlock);
59             blockMap->bmEntry[dieNo][victimBlock].free = 0;
60 
61             u32 currentBlock = dieBlock->dieEntry[dieNo].freeBlock;
62             dieBlock->dieEntry[dieNo].freeBlock = victimBlock;      //將剛擦出的塊作為新的freeblock 63 
64             return currentBlock;    // atomic GC completion
65         }
66     }
67 
68     // no free space anymore
69     assert(!"[WARNING] There are no free blocks. Abort terminate this ssd. [WARNING]");
70     return 1;
71 }

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com