flashcache中内存与磁盘,磁盘与磁盘的io

flashcache中跟磁盘相关的读写分为以下两类:

1)磁盘跟内存的交互

2)磁盘跟磁盘之前的交互

比如说读不命中时就是直接从磁盘读,属于第1种情况,那读命中呢?也是属于第1种情况,不过这时候是从SSD读。磁盘跟磁盘之间交互是用于写脏数据,将SSD中脏cache块拷贝到磁盘上去。现在介绍下两种情况使用的接口函数,这样后面在看读写流程时看到这两个函数就十分亲切了,并且清楚地知道数据是从哪里流向哪里。

对于情况1,主要是两个函数dm_io_async_bvec和flashcache_dm_io_async_vm。

int dm_io_async_bvec(unsigned int num_regions,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
                struct dm_io_region *where,
#else
                struct io_region *where,
#endif
                int rw,
                struct bio_vec *bvec, io_notify_fn fn,
                void *context)
{
    struct dm_io_request iorq;

    iorq.bi_rw = rw;
    iorq.mem.type = DM_IO_BVEC;
    iorq.mem.ptr.bvec = bvec;
    iorq.notify.fn = fn;
    iorq.notify.context = context;
    iorq.client = flashcache_io_client;
    return dm_io(&iorq, num_regions, where, NULL);
}
#endif
int
flashcache_dm_io_async_vm(struct cache_c *dmc, unsigned int num_regions,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
              struct io_region *where,
#else
              struct dm_io_region *where,
#endif
              int rw,
              void *data, io_notify_fn fn, void *context)
{
    unsigned long error_bits = 0;
    int error;
    struct dm_io_request io_req = {
        .bi_rw = rw,
        .mem.type = DM_IO_VMA,
        .mem.ptr.vma = data,
        .mem.offset = 0,
        .notify.fn = fn,
        .notify.context = context,
        .client = flashcache_io_client,
    };

    error = dm_io(&io_req, 1, where, &error_bits);
    if (error)
        return error;
    if (error_bits)
        return error_bits;
    return 0;
}
#endif

上面两个函数都使用struct dm_io_request 来包装了请求,其中的只有两种请求的类型是不一样的,第一个函数对应的是DM_IO_BVEC,第二个函数是DM_IO_VMA。

其实我开始一直不明白,为什么要使用这两个函数让硬盘与内存打交道,不过后来看了dm_io发现其中的io服务类型有多种不同类型,这两个函数的调用分别对应不同的io类型。下面先看一下dm_io相关的数据结构。

 dm_io

dm-io为device mapper提供同步或者异步的io服务。

使用dm-io必须设置dm_io_region结构(2.6.26版本以前叫io_region),该结构定义了io操作的区域,读一般针对一个dm_io_region区,而写可以针对一组dm_io_region区。

struct dm_io_region {
    struct block_device *bdev;
    sector_t sector;
    sector_t count;         /* If this is zero the region is ignored. */
};

老版本的内核,用户必须设置一个io_region结构来描述预期的I/O所在地。每个io_region说明了一个在区域上的有起始位置和长度的块设备。

struct io_region {
      struct block_device *bdev;
      sector_t sector;
      sector_t count;
   };

Dm-io 可以从一个io_region中读取或者写入到一个或者多个io_region中去。一个io_region结构数组指定了写入到多个区域。

dm-io一共有四种dm_io_mem_type类型(老一点的内核版本只有前面三种,Flashcache主要使用DM_IO_BVEC):

enum dm_io_mem_type {
    DM_IO_PAGE_LIST,/* Page list */
    DM_IO_BVEC,     /* Bio vector */
    DM_IO_VMA,      /* Virtual memory area */
    DM_IO_KMEM,     /* Kernel memory */
};

struct dm_io_memory {
    enum dm_io_mem_type type;
    union {
            struct page_list *pl;
            struct bio_vec *bvec;
            void *vma;
            void *addr;
    } ptr;

    unsigned offset;
};

Dm-io 提供同步和异步I/O服务。老一点的内核它提供了3种I/O服务,每种服务都有一个同步和一个异步的版本。

DM_IO_PAGE_LIST

第一个I/O服务类型使用了一串内存页作为缓冲区,伴随着一个首页面的偏移。

   struct page_list {
      struct page_list *next;
      struct page *page;
   };
 int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw,
                  struct page_list *pl, unsigned int offset,
                  unsigned long *error_bits);
   int dm_io_async(unsigned int num_regions, struct io_region *where, int rw,
                   struct page_list *pl, unsigned int offset,
                   io_notify_fn fn, void *context);

DM_IO_BVEC

第二种I/O服务类型把一组bio载体当着I/O的数据缓冲。如果调用者提前拼装了bio,这个服务可以很顺利地完成。但是需要将不同的bio页指向不同的设备。

   int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where,
                       int rw, struct bio_vec *bvec,
                       unsigned long *error_bits);
   int dm_io_async_bvec(unsigned int num_regions, struct io_region *where,
                        int rw, struct bio_vec *bvec,
                        io_notify_fn fn, void *context);
 

DM_IO_VMA

第三种I/O服务类型把一个指向虚拟动态内存缓冲区的的指针当作I/O的数据缓冲。如果调用者需要在很大的块设备上进行I/O操作又不想分配大量的个人内存页,那么这种服务可以胜任。

 int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw,
                     void *data, unsigned long *error_bits);
   int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw,
                      void *data, io_notify_fn fn, void *context);

异步I/O服务的调用者必须包含一个完成的回调函数和一个指向一些这个I/O内容数据的指针。

typedef void (*io_notify_fn)(unsigned long error, void *context);

这个"error"参数,就像这个"*error"参数在任何同步版本中一样,在这个回调函数中就象一个位集合(而不是一个简单的错误值)。

在写I/O到多个目标区域的情况下,这个位集合允许dm-io说明在每个单独的区域上的成功或者失败。

在使用任何dm-io服务之前,用户必须调用dm_io_get()、同时指定他们想要的页数来执行I/O.

DM-io将尝试着更改自己的内存池的大小来确认在执行i/o时为了避免不必要的等待而有足够的页面来供给。
当用户完成了使用I/O服务,他们将调用dm_io_put(),并指定和给dm_io_get()的相同数量的页面。

dm-io通过dm_io_request结构来封装请求的类型,如果设置了dm_io_notify.fn则是异步IO,否则是同步IO。

struct dm_io_request {
    int bi_rw;                      /* READ|WRITE - not READA */
    struct dm_io_memory mem;        /* Memory to use for io */
    struct dm_io_notify notify;     /* Synchronous if notify.fn is NULL */
    struct dm_io_client *client;    /* Client memory handler */
};

使用dm_io服务前前需要通过dm_io_client_create函数(在2.6.22版本前是dm_io_get)先创建dm_io_client结构,为dm-io的执行过程中分配内存池。使用dm-io服务完毕后,则需要调用dm_io_client_destroy函数(在2.6.22版本前是dm_io_put)释放内存池。

struct dm_io_client {
    mempool_t *pool;
    struct bio_set *bios;
};

dm-io函数执行具体的io请求。

int dm_io(struct dm_io_request *io_req, unsigned num_regions,
      struct dm_io_region *where, unsigned long *sync_error_bits)
{
    int r;
    struct dpages dp;

    r = dp_init(io_req, &dp);
    if (r)
            return r;

    if (!io_req->notify.fn)
            return sync_io(io_req->client, num_regions, where,
                           io_req->bi_rw, &dp, sync_error_bits);

    return async_io(io_req->client, num_regions, where, io_req->bi_rw,
                    &dp, io_req->notify.fn, io_req->notify.context);
}

对于第二种情况,磁盘跟磁盘之前的交互。这种情况只用于将ssd中脏块写入disk中。

int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
                   unsigned int num_dests, struct dm_io_region *dests,
                   unsigned int flags, dm_kcopyd_notify_fn fn, void *context)

第一个参数dm_kcopyd_client,在使用kcopyd异步拷贝服务时,必须先创建一个对应的client,首先要分配“kcopyd客户端”结构,调用函数如下:

kcopyd_client_create(FLASHCACHE_COPY_PAGES, &flashcache_kcp_client);

创建dm_kcopyd_client结构。

第二个参数dm_io_region是源地址,第四个参数是目的地址,定义如下

struct dm_io_region {
     struct block_device *bdev;
     sector_t sector;
     sector_t count;          /* If this is zero the region is ignored. */
};

dm_kcopyd_notify_fn fn是kcopyd处理完请求的回调函数

context 是回调函数参数,在flashcache都设置对应的kcached_job。

flashcache中内存与磁盘,磁盘与磁盘的io

时间: 2024-10-06 04:56:05

flashcache中内存与磁盘,磁盘与磁盘的io的相关文章

CentOS查看CPU、内存、网络流量和磁盘 I/O

安装 yum install -y sysstat sar -d 1 1 rrqm/s: 每秒进行 merge 的读操作数目.即 delta(rmerge)/swrqm/s: 每秒进行 merge 的写操作数目.即 delta(wmerge)/sr/s: 每秒完成的读 I/O 设备次数.即 delta(rio)/sw/s: 每秒完成的写 I/O 设备次数.即 delta(wio)/srsec/s: 每秒读扇区数.即 delta(rsect)/swsec/s: 每秒写扇区数.即 delta(wse

升级CUDA版本导致VS2010错误:未找到导入的项目XXX,请确认&lt;Import&gt;声明中的路径正确,且磁盘上存在该文件。。。。

VS2010错误:未找到导入的项目XXX,请确认<Import>声明中的路径正确,且磁盘上存在该文件. E:\IGSNRR\dev\PhDThesisCode_CUDA\gtcg\gtcg.vcxproj : error : 未找到导入的项目“C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\BuildCustomizations\CUDA 5.5.props”.请确认 <Import> 声明中的路径正确,且磁盘上存在该文件. E:

请确认 &lt;Import&gt; 声明中的路径正确,且磁盘上存在该文件。

在网上下了个源码打开报错. 一查,原来是路径错误. 解决办法:将项目文件(.csproj)用记事本打开,然后找到<Import >节点,作如下操作: <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />  //也可能是别的,自己试试哪种符合自己的. 替换为: <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targ

在Mac中如何通过命令对NTFS磁盘格式化

在使用电脑的时候,很多的用户朋友们都会遇到磁盘爆满,或者病毒侵入的情况,面对这种情况我们不得不格式化磁盘.那么在Mac中如何通过命令对NTFS磁盘格式化呢? 1. 首先下载NTFS For Mac. 下载之后就可以读取NTFS磁盘. 2. 插入要格式化的NTFS磁盘. 您可以在Mac OS X下通过命令行格式化NTFS磁盘.按照以下步骤进行操作: 启动命令行:应用程序 > 工具 > 终端; 输入diskutil获取帮助. 图一:格式化命令图 使用diskutil eraseVolume UFS

[Win32] 直接读写磁盘扇区(磁盘绝对读写)

??本博文由CSDN博主zuishikonghuan所作,版权归zuishikonghuan全部.转载请注明出处:http://blog.csdn.net/zuishikonghuan/article/details/50380313 正讲着驱动开发呢,这里突然插一篇Win32的博文.事实上.还是做引子,上一篇博文"IRP与派遣函数"中,我们知道了驱动程序须要处理I/O请求.我们先来看看怎么发出一个I/O请求. 一般的程序不会直接去訪问磁盘,毕竟有文件系统(FileSystem)帮助我

(转)GPT磁盘与MBR磁盘区别

摘要:   Windows 2008磁盘管理器中,在磁盘标签处右击鼠标,随磁盘属性的不同会出现“转换到动态磁盘”,“转换到基本磁盘”“转换成GPT磁盘”,“转换成MBR磁盘”等选项,在此做简单介绍.部分资料参照网络上的资源. 基本磁盘与动态磁盘    磁盘的使用方式可以分为两类:一类是“基本磁盘”.基本磁盘非常常见,我们平时使用的磁盘类型基本上都是“基本磁盘”.“基本磁盘”受26个英文字母的限制,也就是说磁盘的盘符只能是26个英文字母中的一个.因为A.B已经被软驱占用,实际上磁盘可用的盘符只有C

磁盘管理之磁盘分区

磁盘管理之磁盘分区 磁盘分区表 磁盘分区表位置:0磁头0磁道1扇区(前446字节表示mbr主引导记录,中单64字节表示分区表,最后2字节55AA标识表示结束标记) 主分区(primary):一般一定要有,用来存放数据(最多四个主分区) 扩展分区(extend):只能有一个扩展分区,无法直接使用 逻辑分区(logical):在扩展分区下新建,用来存放数据 磁盘分区的设备名 磁盘: SAS/SATA/SCSI表示/dev/sd(a-z)如第一块硬盘表示/dev/sda,第三块/dev/sdc 分区:

Linux磁盘系统——管理磁盘的命令

Linux磁盘系统——管理磁盘的命令 摘要:本文主要学习了Linux系统中管理磁盘的命令,包括查看磁盘使用情况.磁盘挂载相关.磁盘分区相关.磁盘格式化等操作. df命令 df命令用于显示Linux系统中各文件系统的硬盘使用情况,包括文件系统所在硬盘分区的总容量.已使用的容量.剩余容量等. /dev/shm为内存挂载点,如果你想把文件放到内存里,就可以放到/dev/shm/目录下. 基本语法 1 [[email protected] ~]# df [选项] 目录或文件 选项说明 1 -a:显示所有

VMware Workstation 集群仲裁磁盘和数据共享磁盘的创建

最近项目需要对SQL Server建立集群服务,多个SQL Server数据库建立集群服务,对外提供唯一的URL访问地址.当主节点断电.断网后,通过心跳线将消息传递到备用节点,备用节点在3秒内接管数据库访问任务,实现双机热备. 由于台式机过2天才能到位,所以就先在虚拟机上装了2套windows Server 2008 R2系统,模拟集群创建过程.关于SQL Server建立集群的文章,网上是众说纷纭,对于一个新手来说,可谓是不知所措.但集群中仲裁磁盘和共享磁盘的创建是每个集群所必须的,在此我把虚