本发明属于计算机技术领域,尤其是一种持久性内存文件读写方法、系统、装置及存储介质。
背景技术:
目前,随着社会产生的数据量不断增加,海量数据存储对现有的主存存储技术在容量上带来了巨大的挑战,同时也对系统的性能提出了更高的要求。在传统的存储体系结构中,一般使用dram(dynamicrandomaccessmemory,动态随机存取存储器)作为主存,使用磁盘或者固态盘作为外存。但是这种存储体系结构存在两个问题:(1)dram设备存储容量较小。因为其介质密度较低,在保存数据时需要持续动态刷新,制程工艺已很难再有提升;(2)dram介质是易失性的,其断电以后无法持久化保存数据,因此需要外存对数据进行持久化保存。但是系统需要频繁地在主存和外存之间迁移数据,成为了系统性能的瓶颈。
为缓解上述问题,将nvms(non-volatilememories,非易失性存储器)与传统dram一起放在处理器的内存总线上,从而形成易失性、非易失性内存混合的内存架构应运而生。随着近几年科学的发展,一些新型的非易失存储设备相继诞生,比较常见的包括相变存储器(phasechangerandom-accessmemory,pcram)、阻变存储器(resistiverandom-accessmemory,reram)和磁阻式存储器(magneticrandom-accessmemory,mram)等。新型非易失存储器nvm,也被称为持久性内存(persistentmemory,pm),具有高集成度、低功耗、非易失以及良好的可扩展性等优良特性。
在混合内存架构的应用直接模式下,现有技术中已经存在不少针对pm所设计的内存文件系统,与传统文件系统相比,针对pm的特性做了很多优化和调整,比如对其i/o操作栈进行精简,对读写两个方向采用不同的文件缓存策略等。但是用户层在使用这些文件系统进行读写操作时,只能消耗大量的cpu资源用于dram和pm之间数据的传输,而不能像传统文件系统那样,由直接存储器访问(directmemoryaccess,dma)设备分担大部分的i/o工作,所以上述文件系统都存在一个普遍的问题,就是它们进行读写操作的实质,都由传统的i/o操作转变为cpu资源密集型的内存拷贝工作,这种转变会导致各种问题,具体如下所述:
(1)在并发的场景下执行读写任务时,线程对cpu资源的竞争变得更加激烈。并发的实质是一个物理cpu(或者多个物理cpu)在若干道程序(或线程)之间多路复用,因此,存在较多个线程争抢较少cpu资源的场景。
(2)cpu在执行内存拷贝时,存在各种性能陷阱,在需要拷贝大量数据的场景下这种缺陷尤为明显。首先,当cpu执行拷贝任务时,只能以高速缓存行(cache)粒度(在大多数现代处理器中为64b或更大)将数据读入高速缓存,并且需要将数据读入32位或64位大小的寄存器来执行复制操作,所以cpu总是以寄存器大小的粒度拷贝数据,导致拷贝的效率较低。
(3)除了以上提到的这两点问题,文件系统的读写操作由i/o密集型操作转变为cpu密集型操作,还可能会导致一些隐性的问题。例如在通常情况下,程序员在并发的场景下对程序进行编写和优化时,会把读写操作误认为为传统的i/o操作,并针对其进行一些特别的处理,比如:在程序中使用更多的线程使cpu的资源得到充分的利用。但是,当读写操作的实质发生改变时,由于之前的这些程序在混合内存结构上的性能,不能匹配新型的pm存储结构,导致其不能得到很好的发挥,需要重新花费精力和物力对程序进行改写和优化。
技术实现要素:
有鉴于此,为至少部分解决上述技术问题之一,本发明实施例目的在于提供一种持久性内存文件读写方法,能够克服现有的读写接口只能通过耗费cpu资源,来执行dram和pm之间数据拷贝工作的缺陷,可以在并发的场景下更好的执行;方法执行时可以避免由于使用cpu拷贝的带来各种缺陷。同时本发明还提供能够对应实现该方法的系统、装置以及计算机可读存储介质。
第一方面,本发明实施例提供了一种持久性内存文件读写方法,其包括以下步骤:
获取数据读写指令,根据所述读写指令调用第一接口,根据所述第一接口的直接存储器访问通道进行数据拷贝传输;
完成所述数据拷贝传输后,解除对所述直接存储器访问通道的占用;
所述根据所述第一接口的直接存储器访问通道进行数据拷贝传输,其包括以下步骤:
获取所述直接存储器访问通道,为所述直接存储器访问通道分配拷贝任务;
根据所述直接存储器访问通道的传输地址映射得到总线地址,所述传输地址包括用户层地址和内核层地址;
对完成映射后的直接存储器访问通道填充第一描述符,所述第一描述符包括传输地址长度、源地址、目的地址以及标志位;
启动所述直接存储器访问通道,根据所述拷贝任务以及所述第一描述符进行数据拷贝传输。
在本发明的一些实施例中,所述读写方法还包括:根据所述读写指令关闭所述第一接口,通过中央处理器进行数据拷贝传输。
在本发明的一些实施例中,所述获取所述直接存储器访问通道,为所述直接存储器访问通道分配拷贝任务这一步骤,其包括:
初始化所述直接存储器访问通道,并获取所述直接存储器访问通道的设备号;
将所述设备号进行升序排列并进行遍历,确定第一访问通道;
为所述第一访问通道分配第二描述符,所述第二描述符包括所述拷贝任务。
在本发明的一些实施例中,所述根据所述直接存储器访问通道的传输地址映射得到总线地址这一步骤,其包括:
将所述传输地址进行预处理得到第一输入地址,所述第一输入地址为符合映射接口输入类型的地址;
通过所述映射接口将所述第一输入地址转换得到总线地址。
在本发明的一些实施例中,所述将所述传输地址进行预处理得到第一输入地址这一步骤,其包括:
根据所述拷贝任务的地址长度,确定所述用户层地址占用的页面;
固定所述页面,得到页面数组;对所述页面数组中的地址增加线性偏移,得到所述第一输入地址。
在本发明的一些实施例中,通过所述映射接口将所述第一输入地址转换得到总线地址这一步骤,其包括:
构建分散表,将增加线性偏移后的页面数组填充至所述分散表的表项;
将所述分散表中相邻的页面进行合并,对合并后的分散表进行映射,得到所述总线地址。
在本发明的一些实施例中,所述读写方法还包括以下步骤:
将所述拷贝任务的文件数据写入到持久性内存中;
将所述文件数据的元数据信息、日志记录的开始标记以及日志记录的结束标记写入到所述持久性内存中。
第二方面,本发明的技术方案还提供一种持久性内存文件读写系统,包括:
指令获取单元,用于获取数据读写指令,根据所述读写指令调用第一接口;
读写接口单元,用于通过的直接存储器访问通道进行数据拷贝传输;并在完成所述数据拷贝传输后,解除对所述直接存储器访问通道的占用;
其中,读写接口单元包括:
直接存储器访问通道,用于在易失性内存和持久性内存之间进行数据传输;
通道获取单元,用于获取所述直接存储器访问通道,为所述直接存储器访问通道分配拷贝任务;
地址映射单元,用于根据所述直接存储器访问通道的传输地址映射得到总线地址,所述传输地址包括用户层地址和内核层地址;
描述符填充单元,用于对完成映射后的直接存储器访问通道填充第一描述符,所述第一描述符包括传输地址长度、源地址、目的地址以及标志位;
通道启动单元,用于启动所述直接存储器访问通道,根据所述拷贝任务以及所述第一描述符进行数据拷贝传输。
第三方面,本发明的技术方案还提供一种持久性内存文件读写装置,其包括:
至少一个处理器;
至少一个存储器,用于存储至少一个程序;
当至少一个程序被至少一个处理器执行,使得至少一个处理器实现第一方面中的一种持久性内存文件读写方法。
第四方面,本发明的技术方案还提供了一种存储介质,其中存储有处理器可执行的程序,处理器可执行的程序在由处理器执行时用于实现如第一方面中的方法。
本发明的优点和有益效果将在下面的描述中部分给出,其他部分可以通过本发明的具体实施方式了解得到:
本发明所提供的一种持久性内存文件读写方法,方法将通过直接存储器访问通道设备进行数据拷贝的方式,融入到适用于持久性内存的读写方法中,基于持久性内存文件系统,构建了新的读写接口,使得当使用该接口执行读写任务时,可以利用支持在内存之间进行传输的dma设备来执行数据传输工作,克服了现有的读写接口只能通过耗费cpu资源,来执行dram和pm之间数据拷贝工作的缺陷,可以在并发的场景下更好的执行;方法执行时可以避免由于使用cpu拷贝的带来各种缺陷;可以在一定程度上避免因为读写操作的实质由传统认知中的i/o密集型操作,转变为cpu密集型操作而带来的一系列隐患。方法同时还兼容文件系统原本利用cpu来执行dram和pm之间的数据拷贝工作的方式,不会对原有文件系统造成破坏。
附图说明
为了更清楚地说明本申请实施例中的技术方案,下面将对实施例描述中所需要使用的附图作简单地介绍,显而易见地,下面描述中的附图仅仅是本申请的一些实施例,对于本领域普通技术人员来讲,在不付出创造性劳动的前提下,还可以根据这些附图获得其他的附图。
图1为本发明实施例所提供的混合内存架构的结构示意图;
图2为本发明持久性内存文件读写方法的步骤流程图;
图3为本发明实施例中读写操作的步骤流程图;
图4为本发明实施例的dma传输方法、传输接口函数以及文件读写接口实现的对应关系示意图。
具体实施方式
下面详细描述本发明的实施例,实施例的示例在附图中示出,其中自始至终相同或类似的标号表示相同或类似的元件或具有相同或类似功能的元件。下面通过参考附图描述的实施例是示例性的,仅用于解释本发明,而不能理解为对本发明的限制。对于以下实施例中的步骤编号,其仅为了便于阐述说明而设置,对步骤之间的顺序不做任何限定,实施例中的各步骤的执行顺序均可根据本领域技术人员的理解来进行适应性调整。
首先,针对本方案中所涉及主要技术名词进行解释,其他非主要技术名词将在文中首次出现进行解释并不在此处进行一一罗列:
动态随机存取存储器(dynamicrandomaccessmemory,dram),是一种半导体存储器,主要的作用原理是利用电容内存储电荷的多寡来代表一个二进制比特(bit)是1还是0。
持久性内存(persistentmemory,pm),具有高集成度、低功耗、非易失以及良好的可扩展性等优良特性。
非易失性存储器((non-volatilememories,nvms),是指当电流关掉后,所存储的数据不会消失的电脑存储器。
直接存储器访问(directmemoryaccess,dma),它允许不同速度的硬件装置来沟通,而不需要依赖于cpu的大量中断负载。
本申请的技术方案基于持久性内存文件系统,构建一套新的读写接口,使得当用户层使用该接口执行读写任务时,可以利用支持在内存之间进行传输的dma设备来执行,dram和pm之间数据,特指需要读取到用户层或从用户层写入的数据的传输工作。
intel的i/o加速技术(i/oat),在cpu中引入了一个dma引擎,即嵌入式dma控制器,用于内存之间的数据拷贝。该引擎在芯片组中以pci-e总线(peripheralcomponentinterconnect-express,pci-e)逻辑设备的形式出现,并且有多个独立的dma通道用于内存之间的数据传输。除了在intel平台上的i/oat,其他平台也会有类似的dma设备用于内存间的数据传输。本申请提出的技术方案同样适用于其他具备类似dma引擎的硬件平台。
第一方面,本申请的技术方案将利用上述的dma设备进行数据拷贝的方式,融入到适用于持久性内存的读写方法中,基于持久性内存文件系统,设计了一套新的读写接口。新的读写接口相比原来的接口多了一种新的拷贝模式——dma拷贝模式,即通过利用上述的特殊dma引擎实现。并且,可以在使用读写接口前,自由选择是否启用该模式,同时保留原有的cpu拷贝模式。应用了本技术方案的读写方法后,混合内存架构如图1所示,当用户层进行读写操作时,可以选择使用cpu或dma引擎在dram和pm之间,对需要读取到用户层或从用户层写入的数据进行传输。
另外,在硬件上,本申请的技术方案对于文件读写接口的实现,是在配置戴尔r740刀片服务器,使用ubuntuserver16.04.6x86_64操作系统,linux5.1.0版本内核的实验环境下进行的。本申请的技术方案将dma传输方式具体化为函数接口,并把这些函数接口整合到持久性内存文件系统“nova(5.1版本)”的代码中,在nova的基础上,构建一套新的读写接口。文件系统nova是目前被学术界普遍接受的文件系统之一,nova不仅充分利用了持久性内存设备的特性,还对读写操作提供强一致性和原子性的保证。此外,本申请的技术方案对于文件读写接口的实现方法同样也适用其他持久性内存文件系统比如“pmfs”,“ext4-dax”等。
第二方面,如图2所示,本申请的技术方案提出了基于第一方面中的混合内存架构以及nova文件系统,一种持久性内存文件的读写方法,其主要包括步骤s01-s02:
s01、获取数据读写指令,根据读写指令调用第一接口,根据第一接口的直接存储器访问通道进行数据拷贝传输。
其中,第一接口即为添加了dma拷贝模式的读写接口。具体地,如图3所示,可以利用系统调用open函数打开需要读写的文件,当打开文件成功时会返回一个文件描述符,之后用户层调用write和read读写接口,以及该文件描述符,对文件进行读写操作。open函数的主要功能,是创建一个新的文件对象,文件对象表示已打开的文件,用结构体file表示。当用户层调用系统调用close函数时,会对创建的文件对象进行撤销。以实施例中的nova文件系统为例,对该文件系统下的文件,进行“open”和“close”操作时,会分别在内核层调用nova_open和nova_release接口,实现“open”和“close”的具体功能。
如图4所示,实施例中,提供了一个用于i/oat传输的结构体ioat_inf,在函数nova_open中,加上分配一个ioat_inf结构体,并将其保存在file->private_data中的操作。在函数“nova_release”中,添加从file->private_data中取出结构体ioat_inf,并将其空间释放掉的操作。对于结构体ioat_inf的描述如表1所示:
表1
在实施例中,可以通过系统调用ioctl来给文件发送命令,文件系统在接受到正确的命令后,会执行一定的操作。在本实施例中利用ioctl接口来实现dma读写模式的开启和关闭。当用户层调用ioctl接口时,内核层会调用文件系统nova中的函数nova_ioctl。实施例给nova_ioctl函数添加两条命令:ioat_open和ioat_close。
需要补充的是,在一些可行的实施例中,本申请所提供的读写方法还包括步骤s03:根据读写指令关闭第一接口,通过中央处理器进行数据拷贝传输。
具体地,在用户层不调用ioctl接口的情况下,文件系统在执行读写操作时,默认使用cpu来执行dram和pm之间拷贝操作。若用户层对打开的文件,调用ioctl接口时,并使用ioat_open命令,在之后读写操作的过程中,dram和pm之间的数据传输操作由dma通道来执行;若使用命令ioat_close,则dram和pm之间的数据拷贝操作依然由cpu来执行。
进一步地,当用户层调用ioctl接口,并使用ioat_open命令时,文件系统会调用本发明设计的函数接口ioat_dma_open。接口ioat_dma_open通过dma进行进行数据拷贝传输。“ioat_dma_open”和“ioat_dma_close”两个接口的伪代码,如下所示,
a)算法1、ioat_dma_open接口:
输入:structfile*filp
输出:
fori<numdo/*num为系统所有的设备数量*/
/*sdevice为系统所有的dma设备的集合*/
pdev=pci_get_device(sdevice[i]);/*获取dma设备pdev*/
ifpdev!=null/*发现可用设备*/
thenbreak
endif
endfor
ifpdev==null/*没有发现可用设备*/
returnerror
endif
ioatdma_device=pci_get_drvdata(pdev)
利用ioatdma_device结构体获取通道dma_chan
ifioat_dma->dma_dev->device_alloc_chan_resources(dma_chan)<1/*为dma_chan分配通道传输的描述符*/
pci_dev_put(pdev)/*分配失败,增加对设备引用,释放设备*/
returnerror
endif
将flag标志改为ioat_moad
将修改后的dma_chan,ioatdma_device,pdev,flag保存到filp->private_data中
return0
b)算法2、ioat_dma_close接口:
输入:structfile*filp
输出:
/*对filp->private_data中保存的数据进行相关操作*/
ioat_dma->dma_dev->device_free_chan_resources(dma_chan)/*释放用于通道传输的描述符*/
pci_dev_put(pdev)/*解除对设备的占用*/
将flag标志改为cpu_mode
return0
实施例修改系统调用read和write在nova中具体实现的接口do_dax_mapping_read以及do_nova_inplace_file_write。将两个接口中用于dram和pm之间的进行拷贝的函数copy_to_user和memcpy_to_pmem_nocache,分别替换为本发明设计的函数ioat_dma_to_user和ioat_dma_from_user,形成新的读写接口。当用户层每次调用read和write调用时,内核层会调用nova中的接口nova_dax_file_read和nova_dax_file_write。实施例在nova的这两个接口中添加一个判断,根据file->private_data中的flag,来判断是调用文件系统原本的读写接口do_dax_mapping_read和do_nova_inplace_file_write,还是调用替换后的读写接口。
在本实施例中,步骤s01中根据第一接口的直接存储器访问通道进行数据拷贝传输,其具体包括步骤s011-s014:
s011、获取直接存储器访问通道,为直接存储器访问通道分配拷贝任务;
s012、根据直接存储器访问通道的传输地址映射得到总线地址,其中,传输地址包括用户层地址和内核层地址;
s013、对完成映射后的直接存储器访问通道填充第一描述符,其中,第一描述符包括传输地址长度、源地址、目的地址以及标志位;
s014、启动直接存储器访问通道,根据拷贝任务以及第一描述符进行数据拷贝传输。
在实施例的步骤s01中,接口ioat_dma_open先获取用于之后读写操作的dma通道设备,并分配和初始化好用于通道传输的描述符,最后改变标志位为i/oat读写模式。函数接口ioat_dma_close释放用于通道传输的描述符并解除对dma通道的占用,最后改变标志位为cpu读写模式。
在一些可行的实施例中,步骤s011还可以进一步细分为步骤s0111-s0113:
s0111、初始化直接存储器访问通道,并获取直接存储器访问通道的设备号;
s0112、将设备号进行升序排列并进行遍历,确定第一访问通道,其中,第一访问通道为可用的直接存储器访问通道;
s0113、为第一访问通道分配第二描述符,第二描述符包括拷贝任务,其中,区别于第一描述符,第二描述符为环状描述符。
具体地,系统启动时,会自动加载i/oat驱动模块,并调用探测接口ioat_pci_probe,对整个系统的dma通道进行检测,并对检测到的通道进行初始化设置和测试。系统在在i/oat驱动模块加载之后,首先根据dma通道的设备号,利用接口pci_get_device,获取在i/oat驱动加载时初始化好的dma通道。为了保证dma通道的成功获取,会对系统所有dma通道按照设备号升序进行遍历,直到找到可用设备为止。获取到通道后,调用i/oat驱动代码中的ioat_alloc_chan_resources接口,给dma通道分配用于传输的环状描述符ioat_ring_ent,并对环状描述符进行初始化。环状描述符ioat_ring_ent的主要成员变量如表2所示:
表2
步骤s012主要进行传输地址的处理,在使用dma通道进行数据传输的时候,对源内存地址和目的内存地址的使用存在一定的标准:必须使用在物理地址上连续的地址,且需要将地址进行映射,得到地址类型为dma_addr_t的总线地址用于传输。
在一些可行的实施例中,步骤s012可以进一步细分为步骤s0121-s0122:
s0121、将传输地址进行预处理得到第一输入地址,其中,第一输入地址为符合映射接口输入类型的地址;
s0122、通过映射接口将第一输入地址转换得到总线地址。
具体地,实施例方法中对内存地址的处理总共分为两步:第一步,将需要传输的地址通过页面分割和增加线性偏移进行预处理,转换为符合映射接口输入地址类型的地址;第二步,将预处理后的地址利用相应的映射接口dma_map_sg和dma_map_single进行映射,转换为总线地址。由于dma传输方法需要应用在文件系统的读写中,所以需要考虑两种类型的地址处理,一个是用户层地址,即dram逻辑地址,一个是内核层地址,即pm的物理地址。
实施例中,针对用户层地址和内核层地址进行分开处理,在步骤s0121中,可进以步细分为步骤s0121a和s0121b:
s0121a、根据拷贝任务的地址长度,确定用户层地址占用的页面;
s0121b、固定页面,得到页面数组;对页面数组中的地址增加线性偏移,得到第一输入地址,其中,第一输入地址为符合映射接口输入类型的地址。
具体地,首先得到符合映射接口输入地址类型的地址。由于用户层地址只是在虚拟的页面上连续,而在物理地址上最多只能保证4kb的连续,所以需要将地址按照页面进行分割,然后按页面分别进行映射。在实施例中,首先根据需要拷贝的地址长度,计算出用户层地址占用的页面总数量。然后,将需要拷贝的用户层地址的页面,利用get_user_pages函数将其固定防止被置换到磁盘上。得到一个固定后的页面数组后,则用于后续的地址映射。内核层中提供的用于dma映射的接口,是针对内核虚拟地址所设计的,其在映射之前,为了得到真实的物理地址,会将输入地址先减掉一个固定的线性偏移。所以,对于内核层地址的处理,直接将pm的物理地址加上这个固定的线性偏移,得到用于后续映射的地址。
在步骤s0122中,可进以步细分为步骤s0122a和s0122b:
s0122a、构建分散表,将增加线性偏移后的页面数组填充至分散表的表项;
s0122b、将分散表中相邻的页面进行合并,对合并后的分散表进行映射,得到总线地址。
具体的,将之前处理好的地址进行映射,得到总线地址,用于dma传输。实施例方法将之前固定好的页面数组,利用用于分散/聚集映射的接口dma_map_sg进行映射。具体步骤为:先新建一个分散表,将固定好的页面数组,利用接口sg_set_page,将页面依次填充进分散表的各表项,然后对分散表进行映射,映射后的分散表中保存的地址可用于后续的传输。在映射过程中会将相邻的页面进行合并,所以映射后的分散表的表项会减少。对于加上线性偏移后的内核层地址,直接利用流映射接口dma_map_single对整个地址段进行流映射,映射完成后函数会返回一个总线地址用于后续传输。
本实施例在进行dma地址映射的时候,选择了使用“流式dma映射”。在使用流映射接口时,需要指定映射地址的方向是dma_to_device或dma_from_device。当流映射接口dma_map_sg或dma_map_single,指定方向为dma_from_device时,会无效掉被映射地址在cpu中的cache,之后访问该段地址时,必须从内存中重新获取;当流映射接口指定方向为dma_to_device时,则写回被映射地址在cpu中的cache,保证被映射地址,传输到其他设备中的数据是最新的。当使用流映射取消接口dma_unmap_sg和dma_unmap_single,指定方向为dma_from_device时,会再次无效掉被映射地址在cpu中的cache;当流取消映射接口指定方向为dma_to_device时,不进行任何操作。为了保证dma传输的cpu缓存一致性,实施例在执行读操作时,设置用户层地址映射或取消映射)时的方向为dma_from_device,内核层地址映射或取消映射时的方向为dma_to_device,在进行写操作时,两者映射或取消映射的方向互换。
执行本实施例的步骤s013,在利用dma通道进行数据传输前,需要将传输的源内存地址和目的内存地址,以及传输的地址长度等传输信息填充到描述符ioat_dma_descriptor中。在进行dma传输时会根据描述符中的信息,去完成相应的传输任务。描述符ioat_dma_descriptor的主要成员变量,如表3所示:
表3
对描述符进行填充时需要考虑描述符的总数量,以及每个dma通道的所能传输的最大地址容量(后文简称max)。每个dma通道里面有固定数量的描述符,步骤s011在进行dma通道资源分配的时候,已经为这些描述符分配好了空间,所以实施例执行一个循环,将需要传输的地址信息依次填充到这些描述符里面。在步骤s012中已经得到了用于映射的内核层地址以及用户层地址;映射后的内核层地址在物理地址上整段连续,而映射后的用户层地址,只在分散表的表项中连续。考虑到用户层地址的特殊性,实施例在描述符的填充过程中,将分散表中保存的地址,按表项分开并分别填充进描述符,作为其中的目的地址或源地址。描述符中的另一个传输方向的内存地址,则由同样长度和位置的映射后的内核层地址充当,这样可以保证每一个描述符中的传输地址都是连续的。
为了充分利用每个描述符的数据容量,即每次可以最多传输的数据大小,本实施例还提供一种描述符填充算法,其描述如下:算法利用函数接口for_each_sg,循环访问每个表项。每循环到一个表项先判断表项中保存的地址长度是不是大于max。如果大于的话就给描述符填充max字节长度的地址,然后将表项中保存的地址向前移动max个单位,并获取下一个描述符继续填充该表项中的地址,直到该表项中保存的地址全部填充完毕;如果该表项中保存的地址长度小于或者等于max,那么直接将其中的地址全部填充进该描述符;当一个表项中的地址全部填充完毕后,循环至下一个表项,直至分散表中所有的数据填充完毕。描述符填充算法的伪代码如下所示,
算法3、描述符填充算法:
输入:sg,ioat_chan,dma_dest
输出:
其中,sg为用户层地址填充并映射后的分散表,ioat_chan为dma传输通道,dma_dest为映射后的内核层地址,在这里用做传输目的地址。
当需要传输的地址信息,全部填充进描述符后,执行步骤s014,启动dma通道进行传输。i/oat技术会在dma传输完毕的时候调用一个回调函数,该回调函数的函数指针在i/oat的驱动代码为callback,回调函数传入的参数为callback_result。实施例采用了nova内核中提供的completion机制,通过接口init_completion初始化一个completion变量,并将callback_result设为该变量。然后采用一个函数赋值给指针callback,当dma传输完成的时候就会调用该函数,该函数的功能是调用接口complete,去唤醒传入callback_result变量的进程。完成赋值等操作之后,利用i/oat驱动代码中提供的接口ioat_issue_pending,启动dma传输通道去完成之前填充在描述符中的传输任务。然后利用接口wait_for_completion_timeout,将当前进程提交至等待队列,并利用该接口的设置一个等待时间。在等待的过程中,当前进程休眠,不占用cpu的资源。当dma通道传输完成后,调用回调函数callback对当前进程进行唤醒,或者当设置的等待时间到了的时候,当前进程会自动取消等待。
实施例的ioat_dma_to_user和ioat_dma_from_user两个函数,使用dma通道完成dram和pm之间的数据拷贝。两个接口输入参数中的ioat_dma以及dam_chan,在使用ioctl接口的ioat_open命令时,已经保存在file->private_data中,直接从结构体file中获取。其中src和dest参数一个是用户层地址,即dram地址,可以直接使用原本读写接口中的用户层地址指针,在代码里体现为constchar__user*buf;而另一个地址是内核层的虚拟地址,由pm的物理地址映射得来,需要利用接口nova_get_pfn得到pm设备上真实的物理地址,然后再将利用接口phys_to_virt转化为内核虚拟地址,用于接口的传输。ioat_dma_from_user接口的伪代码如下:
算法4、ioat_dma_from_user接口:
根据传输地址的长度count,计算出需要固定的页面数量n_page;
根据页面数量n_page分配好页面数组page和分散表数组sg的地址空间;
将地址src的页面固定到页面数组page中;
通过循环调用sg_set_page函数将page中保存的页面的值赋值给sg的表项;
res=dma_map_sg(dev,sg,n_page,dma_to_device);/*对sg进行映射,res保存映射后的分散表sg总项数*/
dma_dest=dma_map_single(dev,dest,op_size,dma_from_device);/*对地址dest进行映射*/
检测通道ioat_chan的状态,以及能否传输count字节的数据;
利用描述符填充算法对传输的描述符进行填充;
填充最后一个描述符desc传输标志位,以及其他的相关信息;
将传输任务设置为completion事件;
提交传输通道dma_chan;
将当前进程添加至等待队列;
等待传输完成,当传输完成或超过设定的等待时间时,对当前线程进行唤醒;
取消sg的映射;
将固定page数组固定的页面全部放回;
释放page数组的空间;
释放sg数组的空间;
returnerr/*err如果上述步骤均没有问题则err的值为0,否则返回不同的错误类型的值,如-enodev*/
本实施例的ioat_dma_to_user接口和ioat_dma_from_user的代码内容基本相同,只是将ioat_dma_from_user代码中的src和dest的含义互换即可。
s02、完成数据拷贝传输后,解除对直接存储器访问通道的占用。
具体地,在传输完成后,需要对之前分配的资源进行一些处理工作,防止占用系统不必要的内存空间和影响后续的读写工作。首先利用接口dma_unmap_single和dma_unmap_sg取消内核层地址和分散表的映射。然后将固定的用户层页面利用接口put_page进行放回,再利用kfree接口释放掉之前给页面数组和分散表分配的地址空间。
上述是完成一次dma传输任务后的处理工作,如果不再使用dma通道进行传输,还需要将dma通道和给其分配的环状描述符给释放掉。首先调用i/oat驱动代码中的接口ioat_free_chan_resources释放给dma设备的分配的环状描述符,然后调用接口pci_dev_put解除对dma设备的占用。
在一些可选的实施例中,实施例的读写方法还包括步骤s03-s04:
s03、将拷贝任务的文件数据写入到持久性内存中;
s04、将文件数据的元数据信息、日志记录的开始标记以及日志记录的结束标记写入到持久性内存中。
具体地,在持久性内存设备上进行读写时,需要保证在读写过程中,如果系统发生崩溃,重启系统后文件系统能够保持一致性。实施例系统中的读写接口,采用metadatajournaling(元数据日志记录)的方法,来保证文件系统的崩溃恢复一致性。在对文件进行读操作的过程中,由于是将数据从pm拷贝到dram中,而dram本身是易失的,重启后不会保存任何的数据,所以不需要考虑崩溃恢复后出现不一致的情况。在对文件进行写操作的过程中,本发明采用如下步骤保证崩溃恢复后文件系统的一致性:
(1)先将文件需要写入的数据写入到pm上;
(2)将被写入文件的元数据信息和txb(txb标记一条新的日志记录的开始)形成的日志记录写入到pm上;
(3)进一步写入txe(txe标记着日志记录的结束)。
在步骤(1)传输数据的过程中,系统出现崩溃时,由于文件的元数据信息还没有写入到pm设备,所以不会导致造成了文件系统后续读到垃圾数据。而在步骤(2)和(3)这种二阶段提交式的日志写入,确保了整条日志记录写入的原子性。
若在步骤(2)执行的过程中,系统发生崩溃,那么日志记录是不完整的,在文件系统重启执行崩溃恢复时,会将此条日志记录视为非法,因此不会导致任何不一致的状态。
而步骤(3)的执行,由于txe本身的所占字节较少,而pm设备最多支持64个字节的原子写入,因此txe可以原子写入到pm设备上。所以步骤(1)(2)(3),不管在哪个过程中发生崩溃,都不会导致文件系统出现不一致的状态。
第三方面,本申请的实施例还提供一种持久性内存文件读写系统,包括:
指令获取单元,用于获取数据读写指令,根据读写指令调用第一接口;
读写接口单元,用于通过的直接存储器访问通道进行数据拷贝传输;并在完成数据拷贝传输后,解除对直接存储器访问通道的占用;
其中,读写接口单元包括:
直接存储器访问通道,用于在易失性内存和持久性内存之间进行数据传输;
通道获取单元,用于获取直接存储器访问通道,为直接存储器访问通道分配拷贝任务;
地址映射单元,用于根据直接存储器访问通道的传输地址映射得到总线地址,传输地址包括用户层地址和内核层地址;
描述符填充单元,用于对完成映射后的直接存储器访问通道填充第一描述符,第一描述符包括传输地址长度、源地址、目的地址以及标志位;
通道启动单元,用于启动直接存储器访问通道,根据拷贝任务以及第一描述符进行数据拷贝传输。
第四方面,本申请的实施例还提供一种持久性内存文件读写装置,其包括至少一个处理器;至少一个存储器,用于存储至少一个程序;当至少一个程序被至少一个处理器执行,使得至少一个处理器实现如第以方面中的一种持久性内存文件读写方法。
本发明实施例还提供了一种存储介质,其中存储有程序,程序被处理器执行如第二方面中的方法。
从上述具体的实施过程,可以总结出,本发明所提供的技术方案相较于现有技术存在以下优点或优势:
1.本申请的技术方案可以缓和在并发的场景下执行读写任务时,线程对cpu资源的竞争。
2.本申请的技术方案可以避免使用cpu进行内存拷贝时带来的各种缺陷,提升拷贝大量数据时的带宽。
3.本申请的技术方案避免读写操作的实质由传统认知中的i/o密集型操作,转变为cpu密集型操作而带来的一系列隐患。
4.本申请的技术方案可以灵活选择使用cpu或dma设备来完成dram和pm之间的数据拷贝工作。
在一些可选择的实施例中,在方框图中提到的功能/操作可以不按照操作示图提到的顺序发生。例如,取决于所涉及的功能/操作,连续示出的两个方框实际上可以被大体上同时地执行或所述方框有时能以相反顺序被执行。此外,在本发明的流程图中所呈现和描述的实施例以示例的方式被提供,目的在于提供对技术更全面的理解。所公开的方法不限于本文所呈现的操作和逻辑流程。可选择的实施例是可预期的,其中各种操作的顺序被改变以及其中被描述为较大操作的一部分的子操作被独立地执行。
此外,虽然在功能性模块的背景下描述了本发明,但应当理解的是,除非另有相反说明,功能和/或特征中的一个或多个可以被集成在单个物理装置和/或软件模块中,或者一个或多个功能和/或特征可以在单独的物理装置或软件模块中被实现。还可以理解的是,有关每个模块的实际实现的详细讨论对于理解本发明是不必要的。更确切地说,考虑到在本文中公开的装置中各种功能模块的属性、功能和内部关系的情况下,在工程师的常规技术内将会了解该模块的实际实现。因此,本领域技术人员运用普通技术就能够在无需过度试验的情况下实现在权利要求书中所阐明的本发明。还可以理解的是,所公开的特定概念仅仅是说明性的,并不意在限制本发明的范围,本发明的范围由所附权利要求书及其等同方案的全部范围来决定。
其中,功能如果以软件功能单元的形式实现并作为独立的产品销售或使用时,可以存储在一个计算机可读取存储介质中。基于这样的理解,本发明的技术方案本质上或者说对现有技术做出贡献的部分或者该技术方案的部分可以以软件产品的形式体现出来,该计算机软件产品存储在一个存储介质中,包括若干指令用以使得一台计算机设备(可以是个人计算机,服务器,或者网络设备等)执行本发明各个实施例方法的全部或部分步骤。而前述的存储介质包括:u盘、移动硬盘、只读存储器(rom,read-onlymemory)、随机存取存储器(ram,randomaccessmemory)、磁碟或者光盘等各种可以存储程序代码的介质。
在流程图中表示或在此以其他方式描述的逻辑和/或步骤,例如,可以被认为是用于实现逻辑功能的可执行指令的定序列表,可以具体实现在任何计算机可读介质中,以供指令执行系统、装置或设备(如基于计算机的系统、包括处理器的系统或其他可以从指令执行系统、装置或设备取指令并执行指令的系统)使用,或结合这些指令执行系统、装置或设备而使用。就本说明书而言,“计算机可读介质”可以是任何可以包含、存储、通信、传播或传输程序以供指令执行系统、装置或设备或结合这些指令执行系统、装置或设备而使用的装置。
计算机可读介质的更具体的示例(非穷尽性列表)包括以下:具有一个或多个布线的电连接部(电子装置),便携式计算机盘盒(磁装置),随机存取存储器(ram),只读存储器(rom),可擦除可编辑只读存储器(eprom或闪速存储器),光纤装置,以及便携式光盘只读存储器(cdrom)。另外,计算机可读介质甚至可以是可在其上打印程序的纸或其他合适的介质,因为可以例如通过对纸或其他介质进行光学扫描,接着进行编辑、解译或必要时以其他合适方式进行处理来以电子方式获得程序,然后将其存储在计算机存储器中。
应当理解,本发明的各部分可以用硬件、软件、固件或它们的组合来实现。在上述实施方式中,多个步骤或方法可以用存储在存储器中且由合适的指令执行系统执行的软件或固件来实现。例如,如果用硬件来实现,和在另一实施方式中一样,可用本领域公知的下列技术中的任一项或他们的组合来实现:具有用于对数据信号实现逻辑功能的逻辑门电路的离散逻辑电路,具有合适的组合逻辑门电路的专用集成电路,可编程门阵列(pga),现场可编程门阵列(fpga)等。
在本说明书的描述中,参考术语“一个实施例”、“一些实施例”、“示例”、“具体示例”、或“一些示例”等的描述意指结合该实施例或示例描述的具体特征、结构、材料或者特点包含于本发明的至少一个实施例或示例中。在本说明书中,对上述术语的示意性表述不一定指的是相同的实施例或示例。而且,描述的具体特征、结构、材料或者特点可以在任何的一个或多个实施例或示例中以合适的方式结合。
尽管已经示出和描述了本发明的实施例,本领域的普通技术人员可以理解:在不脱离本发明的原理和宗旨的情况下可以对这些实施例进行多种变化、修改、替换和变型,本发明的范围由权利要求及其等同物限定。
以上是对本发明的较佳实施进行了具体说明,但本发明并不限于上述实施例,熟悉本领域的技术人员在不违背本发明精神的前提下还可做作出种种的等同变形或替换,这些等同的变形或替换均包含在本申请权利要求所限定的范围内。
1.一种持久性内存文件读写方法,其特征在于,包括以下步骤:
获取数据读写指令,根据所述读写指令调用第一接口,根据所述第一接口的直接存储器访问通道进行数据拷贝传输;
完成所述数据拷贝传输后,解除对所述直接存储器访问通道的占用;
所述根据所述第一接口的直接存储器访问通道进行数据拷贝传输,其包括以下步骤:
获取所述直接存储器访问通道,为所述直接存储器访问通道分配拷贝任务;
根据所述直接存储器访问通道的传输地址映射得到总线地址,所述传输地址包括用户层地址和内核层地址;
对完成映射后的直接存储器访问通道填充第一描述符,所述第一描述符包括传输地址长度、源地址、目的地址以及标志位;
启动所述直接存储器访问通道,根据所述拷贝任务以及所述第一描述符进行数据拷贝传输。
2.根据权利要求1所述的一种持久性内存文件读写方法,其特征在于,所述读写方法还包括:
根据所述读写指令关闭所述第一接口,通过中央处理器进行数据拷贝传输。
3.根据权利要求1所述的一种持久性内存文件读写方法,其特征在于,所述获取所述直接存储器访问通道,为所述直接存储器访问通道分配拷贝任务这一步骤,其包括:
初始化所述直接存储器访问通道,并获取所述直接存储器访问通道的设备号;
将所述设备号进行升序排列并进行遍历,确定第一访问通道;
为所述第一访问通道分配第二描述符,所述第二描述符包括所述拷贝任务。
4.根据权利要求1所述的一种持久性内存文件读写方法,其特征在于,所述根据所述直接存储器访问通道的传输地址映射得到总线地址这一步骤,其包括:
将所述传输地址进行预处理得到第一输入地址,所述第一输入地址为符合映射接口输入类型的地址;
通过所述映射接口将所述第一输入地址转换得到总线地址。
5.根据权利要求4所述的一种持久性内存文件读写方法,其特征在于,所述将所述传输地址进行预处理得到第一输入地址这一步骤,其包括:
根据所述拷贝任务的地址长度,确定所述用户层地址占用的页面;
固定所述页面,得到页面数组;对所述页面数组中的地址增加线性偏移,得到所述第一输入地址。
6.根据权利要求5所述的一种持久性内存文件读写方法,其特征在于,所述通过所述映射接口将所述第一输入地址转换得到总线地址这一步骤,其包括:
构建分散表,将增加线性偏移后的页面数组填充至所述分散表的表项;
将所述分散表中相邻的页面进行合并,对合并后的分散表进行映射,得到所述总线地址。
7.根据权利要求1-6任一项所述的一种持久性内存文件读写方法,其特征在于,所述读写方法还包括以下步骤:
将所述拷贝任务的文件数据写入到持久性内存中;
将所述文件数据的元数据信息、日志记录的开始标记以及日志记录的结束标记写入到所述持久性内存中。
8.一种持久性内存文件读写系统,其特征在于,包括:
指令获取单元,用于获取数据读写指令,根据所述读写指令调用第一接口;
读写接口单元,用于通过的直接存储器访问通道进行数据拷贝传输;并在完成所述数据拷贝传输后,解除对所述直接存储器访问通道的占用;
其中,读写接口单元包括:
直接存储器访问通道,用于在易失性内存和持久性内存之间进行数据传输;
通道获取单元,用于获取所述直接存储器访问通道,为所述直接存储器访问通道分配拷贝任务;
地址映射单元,用于根据所述直接存储器访问通道的传输地址映射得到总线地址,所述传输地址包括用户层地址和内核层地址;
描述符填充单元,用于对完成映射后的直接存储器访问通道填充第一描述符,所述第一描述符包括传输地址长度、源地址、目的地址以及标志位;
通道启动单元,用于启动所述直接存储器访问通道,根据所述拷贝任务以及所述第一描述符进行数据拷贝传输。
9.一种持久性内存文件读写装置,其特征在于,包括:
至少一个处理器;
至少一个存储器,用于存储至少一个程序;
当所述至少一个程序被所述至少一个处理器执行,使得所述至少一个处理器实现如权利要求1-7任一项所述的一种持久性内存文件读写方法。
10.一种存储介质,其中存储有处理器可执行的程序,其特征在于:所述处理器可执行的程序在由处理器执行时用于实现如权利要求1-7中任一项所述的一种持久性内存文件读写方法。
技术总结