zoukankan      html  css  js  c++  java
  • 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
    ", 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!
    ");
     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 }
  • 相关阅读:
    凸优化-凸函数
    hadoop平台-Hbase安装
    非常实用的python字符串处理方法
    中心极限定理
    线性回归-误差项分析
    nginx为什么性能这么优越?
    Redis为什么单线程还那么快?线程安全吗?
    nginx负载均衡配置
    Dubbo的超时重试机制
    java类加载过程
  • 原文地址:https://www.cnblogs.com/losing-1216/p/4936021.html
Copyright © 2011-2022 走看看