磁盘高速传输

更新时间:
2024-01-09
下载文档

磁盘高速传输

SylixOS 管线模型分析

SyilxOS 在 CAHCE 回写的过程采取了两种传输方式,即直接回写和多管线并发回写。并发写管线通过多线程并发处理 CACHE 提交的写请求,实现一定意义上的磁盘高速传输。SylixOS 中通过 LW_DISKCACHE_WP 结构体管理并发写管线,该结构体的具体内容如下:

typedef struct {
    BOOL                    DISKCWP_bExit;                                          /*  是否需要退出              */
    BOOL                    DISKCWP_bCacheCoherence;                                /*  CACHE 一致性标志          */
    BOOL                    DISKCWP_bParallel;                                      /*  并行化读写支持            */
    INT                     DISKCWP_iPipeline;                                      /*  写管线线程数              */
    INT                     DISKCWP_iMsgCount;                                      /*  写消息缓冲个数            */
    PVOID                   DISKCWP_pvRBurstBuffer;                                 /*  管线缓存                 */
    PVOID                   DISKCWP_pvWBurstBuffer;                                    /*  管线缓存                 */
    LW_OBJECT_HANDLE        DISKCWP_hMsgQueue;                                      /*  管线刷新队列              */
    LW_OBJECT_HANDLE        DISKCWP_hCounter;                                       /*  计数信号量               */
    LW_OBJECT_HANDLE        DISKCWP_hPart;                                          /*  管线缓存管理              */
    LW_OBJECT_HANDLE        DISKCWP_hSync;                                          /*  排空信号                 */
    LW_OBJECT_HANDLE        DISKCWP_hDev;                                           /*  非并发设备锁              */
    LW_OBJECT_HANDLE        DISKCWP_hWThread[LW_CFG_DISKCACHE_MAX_PIPELINE];         /*  管线写任务表              */
} LW_DISKCACHE_WP;
typedef LW_DISKCACHE_WP    *PLW_DISKCACHE_WP;
  • DISKCWP_bExit :为 LW_TRUE 时,写管线线程将会退出。
  • DISKCWP_bCacheCoherence :为 LW_TRUE 时,管线缓存将使用非缓冲的内存。
  • DISKCWP_bParallel :并行化读写支持,如果不支持则需要在操作设备前调用设备锁,防止并发操作。
  • DISKCWP_iPipeline :写管线线程数,为 0 时表示不使用并发写管线。
  • DISKCWP_iMsgCount :写消息缓冲个数,最小为 DCATTR_iPipeline,可以为 DCATTR_iPipeline 的 2 ~ 8 倍。
  • DISKCWP_hMsgQueue :管线刷新队列,上层通过发送一个消息,发起一个写请求。
  • DISKCWP_hCounter :计数信号量,用于计数当前缓冲块,发起写请求时申请,完成回写时释放。
  • DISKCWP_hPart :通过定长内存管理管线缓存。
  • DISKCWP_hDev :非并发设备锁。
  • DISKCWP_hWThread :管线写任务表。
  • DISKCWP_hSync :排空信号,用于回写完成后同步。

写管线的创建通过调用 __diskCacheWpCreate 函数来完成,其函数原型如下:

#include <SylixOS.h>
INT   __diskCacheWpCreate(PLW_DISKCACHE_CB     pdiskc,
                          PLW_DISKCACHE_WP     pwp, 
                          BOOL                 bCacheCoherence,
                          BOOL                 bParallel,
                          INT                  iPipeline, 
                          INT                  iMsgCount,
                          INT                  iMaxRBurstSector,
                          INT                  iMaxWBurstSector,
                          ULONG                ulBytesPerSector);

函数 __diskCacheWpCreate 原型分析:

  • 此函数成功返回 ERROR_NONE ,失败返回 PX_ERROR
  • 参数 pdiskc 是磁盘缓冲控制块。
  • 参数 pwb 是并发写管线控制块。
  • 参数 bCacheCoherence 是 CACHE 一致性需求。
  • 参数 bParallel 是表明并发读写支持。
  • 参数 iPipeline 是写管线线程数。
  • 参数 iMsgCount 是管线总消息个数。
  • 参数 iMaxRBurstSector 是读猝发长度。
  • 参数 iMaxWBurstSector 是写猝发长度。
  • 参数 ulBytesPerSector 是每扇区大小。

函数 __diskCacheWpCreate 根据入参创建对应的写管线,并填充相关信息到并发写管线控制结构体。写管线线程运行后,循环等待接收管线刷新消息。当线程接收到消息后,根据消息中的信息调用具体的硬件接口进行写操作,释放相关资源后进入下一次循环等待接收消息。其中消息类型如下:

typedef struct {
    ULONG                 DISKCWPM_ulStartSector;         /*  起始扇区             */
    ULONG                 DISKCWPM_ulNSector;             /*  扇区数量             */
    PVOID                 DISKCWPM_pvBuffer;              /*  扇区缓冲             */
} LW_DISKCACHE_WPMSG;
typedef LW_DISKCACHE_WPMSG *PLW_DISKCACHE_WPMSG;

其中的扇区缓冲通过定长内存分区管理,分区总大小为:最大写猝发大小 × 消息个数,每个内存块的大小为最大写猝发的大小。上层发起写请求时,需要从定长分区中申请内存块,将要处理的数据填入缓冲区。为了实现互斥,系统还创建了初始值与消息个数相等的计数信号量,每次申请内存块前,都需要先申请信号量。所以管线线程完成写操作后,同时要释放消息中的内存块以及计数信号量和同步信号。

SylixOS 管线使用

SylixOS 管线使用主要在 CACHE 回写时,即调用 diskCacheFlushList 函数将链表内的 CACHE 节点扇区全部回写磁盘。由于链表以扇区号升序排列,所以能够方便的查找连续扇区,进行多扇区猝发写操作。此时,需要调用 diskCacheWpGetBuffer 函数在已初始化后的内存分区中申请一个内存块,该函数的具体实现如下:

PVOID  __diskCacheWpGetBuffer (PLW_DISKCACHE_WP  pwp, BOOL bRead)
{
    PVOID  pvRet;
    if (bRead) {
        return  (pwp->DISKCWP_pvRBurstBuffer);
    }
    if (pwp->DISKCWP_iPipeline == 0) {
        return  (pwp->DISKCWP_pvWBurstBuffer);
    }
    if (API_SemaphoreCPend(pwp->DISKCWP_hCounter, LW_OPTION_WAIT_INFINITE)) {
        _BugHandle(LW_TRUE, LW_TRUE, "diskcache pipeline error!\r\n");
    }
    pvRet = API_PartitionGet(pwp->DISKCWP_hPart);
    _BugHandle((pvRet == LW_NULL), LW_TRUE, "diskcache pipeline error!\r\n");
    return  (pvRet);
}

在申请内存块前,需要先请求计数信号量,计数信号量与内存块数量相等。当内存分区中已没有剩余的内存块时,线程无法获得计数信号量进入休眠。当管线线程完成写操作后会释放接收到的内存块,并释放计数信号量,此时休眠线程成功申请信号量进入就绪态,并顺利获得内存块。

接着需要将 CACHE 中的缓冲数据拷贝到内存块中,并提交一个写请求。管线线程接收到消息后进行具体的写操作和资源释放。写请求函数具体实现如下:

INT  __diskCacheWpWrite (PLW_DISKCACHE_CB     pdiskc,
                         PLW_BLK_DEV          pblkdDisk,
                         PVOID                pvBuffer,
                         ULONG                ulStartSector,
                         ULONG                ulNSector)
{
    LW_DISKCACHE_WPMSG  diskcwpm;
    PLW_DISKCACHE_WP    pwp = &pdiskc->DISKC_wpWrite;
    if (pwp->DISKCWP_iPipeline == 0) {
        return  (pdiskc->DISKC_pblkdDisk->BLKD_pfuncBlkWrt(pblkdDisk, 
                                                           pvBuffer,
                                                           ulStartSector,
                                                           ulNSector));
    }
    diskcwpm.DISKCWPM_ulStartSector  = ulStartSector;
    diskcwpm.DISKCWPM_ulNSector      = ulNSector;
    diskcwpm.DISKCWPM_pvBuffer       = pvBuffer;
    API_MsgQueueSend2(pwp->DISKCWP_hMsgQueue, &diskcwpm, 
                          sizeof(LW_DISKCACHE_WPMSG), LW_OPTION_WAIT_INFINITE);
    return  (ERROR_NONE);
}

发起写请求后可通过调用 __diskCacheWpSync 函数进行写同步,该函数通过写管线控制块中的 DISKCWP_hSync 信号量实现同步功能。

文档内容是否对您有所帮助?
有帮助
没帮助