从layout到extent的演变史(二)
交流了一下,发现了理解这个过程的好流程。pnfs中读写操作的流程是,client先发送open的RPC,server返回open的结果(应该和fh相关),client再发送getlayout的RPC,client拿到layout后,直接从磁盘上读文件内容。我们做的优化是在发送open RPC时同时将layout也获取过来,这样可以节省一次getlayout的RPC的时间。
pnfs_open_layout
pnfs中读文件过程,到函数_nfs4_do_open,如果inode->size不为0,文件不空,则调用pnfs_open_layout预取该文件的layout保存在nfs_inode里面中。下面开始讲解pnfs_open_layout的函数。
根据inode获取到pnfs_layout_type(下文用变量名称lo代替),如果为空,则分配初始化锁上;如果非空,则引用计数加1,直接锁上。先根据inode获取到nfs_inode,nfs_inode中有pnfs_layout_type,每个文件对应一个lo。重点介绍一下分配并初始化lo的过程。
lo的初始化过程
如果lo为空,会分配并初始化lo。那都初始化lo的什么内容呢?
lo结构体中有void *ld_data指针,这个是指向layout driver的私有数据,那这个私有数据就是指pnfs_block_layout。初始化struct layoutdriver_io_operations *io_ops,调用bl_alloc_layout分配和初始化pnfs_block_layout,这个结构体还是值得一看的。
struct pnfs_block_layout {
struct pnfs_inval_markings bl_inval; /* tracks INVAL->RW transition */
spinlock_t bl_ext_lock; /* Protects list manipulation */
struct list_head bl_extents[EXTENT_LISTS]; /* R and RW extents */
struct list_head bl_commit; /* Needs layout commit */
unsigned int bl_count; /* entries in bl_commit */
sector_t bl_blocksize; /* Server blocksize in sectors */
};
看到了吧,日思夜想的extent终于出现了,你会不会突然的出现,在街角的咖啡店。出现了,这里仅仅是初始化,初始化bl_extents[0]和bl_extent[1]两个list_head链表,初始化bl_commit链表,这是需要提交layout的链表,设置bl_count是0,设置bl_blocksize,再看它是什么作用。初始化结束后,返回这个pnfs_block_layout。lo->ld_data指向返回的pnfs_block_layout。
给lo分配lseg。和struct pnfs_layoutdriver_type初始化相关。
/* Per-layout driver specific registration structure */
struct pnfs_layoutdriver_type {
const u32 id;
const char *name;
struct layoutdriver_io_operations *ld_io_ops;
struct layoutdriver_policy_operations *ld_policy_ops;
};
lo是有了,再分配struct pnfs_layout_segment *lseg。先看sruct layoutdriver_io_operations,真正的从磁盘上读写文件的函数(我的理解)。调用bl_alloc_lseg分配lseg。
static struct layoutdriver_io_operations blocklayout_io_operations = {
.commit = bl_commit,
.read_pagelist = bl_read_pagelist,
.write_pagelist = bl_write_pagelist,
.write_begin = bl_write_begin,
.write_end = bl_write_end,
.write_end_cleanup = bl_write_end_cleanup,
.alloc_layout = bl_alloc_layout,
.free_layout = bl_free_layout,
.alloc_lseg = bl_alloc_lseg,
.free_lseg = bl_free_lseg,
.setup_layoutcommit = bl_setup_layoutcommit,
.encode_layoutcommit = bl_encode_layoutcommit,
.cleanup_layoutcommit = bl_cleanup_layoutcommit,
};
bl_alloc_lseg()
原型:static struct pnfs_layout_segment *bl_alloc_lseg(struct pnfs_layout_type *lo, struct nfs4_pnfs_layoutget_res *lgr)
功能:根据server返回的lgr内容来初始化lseg。
实际上起作用的函数是nfs4_blk_process_layoutget。