从layout到extent的演变史(一)

从layout到extent的演变史

client端在读/写文件时,先从server端申请layout,才能向磁盘读/写文件,写文件时又有extent,这又是如何一个演变过程,余决心把这个过程搞得清清楚楚,不知不止。
Clients和Storage Devices传输数据时需要使用专门的存储协议,因为client直接从storage device读取数据。RFC定义了三种存储协议:file layout(RFC5661)、block layout(RFC5663)、object layout(RFC5664)。
我们的pnfs是block layout类型。

layout

什么是layout

layout翻译过来是布局,那布局是什么。
在rfc5663文档中是这样写的:
A pNFS layout for this block/volume class of storage is responsible for mapping from an NFS file (or portion of a file) to the blocks of storage volumes that contain the file.
layout是文件内指定区域的数据是如何分布到存储设备上的。可以这样理解,client要从存储设备上读取文件,client首先要找到在哪个存储设备上哪个位置分布,client向server发送请求,server管理layout信息,server将layout信息给client,client拿到layout信息后去读文件内容。client不需要理解layout信息内容,而是把layout信息传递给布局驱动layout driver来解释和处理,由layout driver根据layout完成文件数据到物理设备的读写。这里就到了我想知道的extent。
布局也可以理解为一种授权,拿到布局信息,才能读取文件内容。

layout的相关操作

LAYOUTGET:从元数据服务器MDS那里请求一个布局,用于读写文件指定区域。请求中会给定所请求的文件的文件句柄,要读写的逻辑区域的偏移和长度,以及请求的类型(读请求或者写请求);
LAYOUTCOMMIT:客户端将布局修改提交到元数据服务器。客户端需要保证在布局提交之前,数据已经写入到存储设备之中;
LAYOUTRETURN:客户端用此操作来归还已经获得的布局信息。归还完毕后,客户端不得再使用此布局信息来访问存储设备。归还的布局信息可能是之前获得的布局信息的一个子集。LAYOUTGET操作的返回值中有一个标志,叫做关闭时归还,用于指示客户端在文件关闭时即归还所得布局;
CB_LAYOUTRECALL:服务器用此操作来召回已经授权给客户端的布局,当数据发生改变,server阻止client使用旧的布局来从存储设备上访问文件。

client用layout读取文件过程

涉及文件读写的操作分为两部分,一部分是元数据服务器的,另一部分是客户端的。元数据服务器上主要包括分配资源和更新文件映射;客户端上的操作主要包括:获取布局、进行读写IO和提交布局修改。
当客户端需要读写文件时,它先以pNFS协议将请求发送到元数据服务器,然后元数据服务器上的pNFS服务进程会向底层存储系统(负责管理元数据的文件系统)请求文件的布局信息。底层存储系统将布局信息返回给pNFS服务进程,然后pNFS服务进程将结果按pNFS协议的标准回复给客户端。客户端将收到的布局信息传给layout driver,最后layout driver根据布局信息完成数据读写。
server的底层文件系统负责管理文件布局?
那么server端底层的文件系统是如何管理的呢?
NFS是一种网络文件系统,它必须依附于一种实际的文件系统之上(比如EXT3、JFS等)。如果底层的文件系统支持pNFS,则这种文件系统必须实现struct pnfs_export_operations中定义的方法。

struct pnfs_export_operations {
    /* Returns the supported pnfs_layouttype4. */
    int (*layout_type) (struct super_block *);

    /* Encode device info onto the xdr stream. */
    int (*get_device_info) (struct super_block *,
                struct exp_xdr_stream *,
                u32 layout_type,
                const struct nfsd4_pnfs_deviceid *);
    int (*layout_get) (struct inode *,
               struct exp_xdr_stream *xdr,
               const struct nfsd4_pnfs_layoutget_arg *,
               struct nfsd4_pnfs_layoutget_res *);
    /* Commit changes to layout */
    int (*layout_commit) (struct inode *,
                  const struct nfsd4_pnfs_layoutcommit_arg *,
                  struct nfsd4_pnfs_layoutcommit_res *);

    /* Returns the layout */
    int (*layout_return) (struct inode *,
                  const struct nfsd4_pnfs_layoutreturn_arg *);
};

这个数据结构定义了MDS中layout相关的函数。

代码中的layout

layout相关的数据结构

Pnfs支持三种类型中的哪一种layout类型。三种类型layout编号如下:

enum pnfs_layouttype {
    LAYOUT_NFSV4_FILES  = 1,
    LAYOUT_OSD2_OBJECTS = 2,
    LAYOUT_BLOCK_VOLUME = 3,
};

layout编号从1开始,0是一个保留序号,不允许出现编号为0的layout类型。
和pnfs_layouttype相关的数据结构是pnfs_layoutdriver_type

/* Per-layout driver specific registration structure */
struct pnfs_layoutdriver_type {
    const u32 id;       /* id取值1、2、3三种layouttype */
    const char *name;
    struct layoutdriver_io_operations *ld_io_ops;
    struct layoutdriver_policy_operations *ld_policy_ops;
};

client端调用set_pnfs_layoutdriver函数,根据id设置pnfs支持的layout类型。当前每个pnfs只支持一种类型的layout。设置server->pnfs_curr_ld,pnfs当前使用的layout类型。
我们这个是支持block layout,对函数set_pnfs_layoutdriver做了一些修改,设置pnfs支持的layout类型时block layout,调用bl_initialize_mountpoint,为挂载点遍历可用的设备链表(发现只是修改了原pnfs的函数bl_set_layoutdriver)。
初始化结构体block_mount_id

struct block_mount_id {
    struct super_block      *bm_sb;     /* back pointer */
    spinlock_t          bm_lock;    /* protects list */
    struct list_head        bm_devlist; /* holds pnfs_block_dev */
};

bm_sb为传递的超级快,初始化链表等,这个应该是mount时调用的,mount时会指出挂载点,为挂载点找到设备,后面在挂载点的操作创建文件、删除文件等读写,都是需要设备的,挂载点只是个名称,最后写还是要写入到设备上。
跑偏了回来,layout在client端是如何存放的?
client端,每个layout用数据结构struct pnfs_layout_segment表示,每个layout表示文件中的一段数据。用户可能申请了文件中多个数据段的layout,因此同一个文件中所有的layout构成了一个链表,这个链表是在数据结构struct pnfs_layout_type的segs链表中。用户还可能访问了多个文件,每个文件对应一个struct pnfs_layout_type结构,struct pnfs_layout_type又在struct nfs_inode结构中,client端会有多个pnfs_layout_type结构,在nfs_inode结构中有链表lo_inodes,表示有layout的的nfs_inode链表,链表头在struct nfs_client有cl_lo_inodes链表。

struct pnfs_layout_type {
    int refcount;
    atomic_t lretcount;     /* Layoutreturns outstanding */
    atomic_t lgetcount;     /* Layoutgets outstanding */
    struct list_head segs;      /* layout segments list */
    int roc_iomode;         /* iomode to return on close, 0=none */
    seqlock_t seqlock;      /* Protects the stateid */
    nfs4_stateid stateid;
    void *ld_data;          /* layout driver private data */
};
struct nfs_inode {
    /* Inodes having layouts */
    struct list_head    lo_inodes;
    struct pnfs_layout_type layout;
};
struct pnfs_layout_segment {
    struct list_head fi_list;
    /* layout在文件中的数据范围和访问方式 */
    struct nfs4_pnfs_layout_segment range;
    struct kref kref;
    bool valid;
    struct pnfs_layout_type *layout;
    u8 ld_data[];           /* layout driver private data */
};
struct nfs4_pnfs_layout_segment {
    u32 iomode; /* 访问模式 */
    u64 offset; /* layout在文件中的起始位置 */
    u64 length; /* layout的长度 */
};

这样仅仅是把代码中layout的数据结构清晰化了,但函数实际执行时时什么情况并不清晰,下面通过具体函数来看layout。
先写到这里。
参考:
[1] http://www.rfc-editor.org/rfc/rfc5663.txt rfc5663主要针对块存储
[2] http://blog.csdn.net/ycnian/article/details/8732856

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值