实例说明RPC的使用
上一篇介绍了一下RPC的原理,这篇通过实例来说明RPC的使用。以pnfs中client端往磁盘上写文件后,向server端提交layout过程为例。(client端写文件前,需要先向server端获取到layout,才能写文件)
layout和extent的概念
一直没有把我们的layout和extent弄清楚,所以决心弄清楚他们。
client端向server端申请layout,server端返回的layout是什么?又怎样从layout分配extent的过程。
layout是文件逻辑位置到磁盘物理位置的映射。
client端提交layout
做法是在向server端提交在客户端本地缓存中创建的fake inode时,提交layout。是否是只有文件写入磁盘后,才可以提交layout?
向server端提交,信息保存在struct nfs4_entry_createdata,在对这个结构体初始化时,有如下代码,对lseg初始化:
data->arg.args.lseg.iomode = IOMODE_RW;
data->arg.args.lseg.offset = write_begin_pos;
data->arg.args.lseg.length = write_end_pos - write_begin_pos + 1;
lseg是struct nfs4_pnfs_layout_segment ,write_begin_pos、write_end_pos在nfs_inode结构体中保存,
struct nfs4_pnfs_layout_segment {
u32 iomode; /* 访问模式 */
u64 offset; /* layout在文件中的起始位置 */
u64 length; /* layout的长度 */
};
初始化struct nfs4_entry_createdata,调用bl_setup_layoutcommit初始化struct bl_layoutupdate_data,再调用nfs4_entry_deleg_commit_rpc(data),向server端发送RPC。
函数nfs4_entry_deleg_commit_rpc
初始化了两个结构体:
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ENTRYCOMMIT],
.rpc_argp = e_arg,
.rpc_resp = e_res,
.rpc_cred = cred,
};
rpc_pro是指向结构体struct rpc_procinfo的指针,
struct rpc_task_setup task_setup_data = {
.rpc_client = server->client,
.rpc_message = &msg,
.callback_ops = &nfs4_entrycommit_ops, /* 回调函数 */
.callback_data = data,
.workqueue = nfsiod_workqueue,
.flags = RPC_TASK_ASYNC,
};
回调函数是在RPC具体执行时调用的。
const struct rpc_call_ops nfs4_entrycommit_ops = {
.rpc_call_prepare = nfs4_entrycommit_prepare,
.rpc_call_done = nfs4_entrycommit_done,
.rpc_release = nfs4_entrycommit_release,
};
执行rpc_run_task(&task_setup_data),rpc_run_task是通用函数,先是分配一个新的RPC task,然后rpc_execute开始执行。
rpc_execute是一个很重要的函数,它将rpc的执行过程表示为一个状态机,rpc的不同执行过程表示不同的状态,另外rpc_task结构体封装了一个rpc任务,里面有表示rpc任务当前状态的字段,控制字段。
在上述的状态机中,并没有设置所谓的状态,而是通过回调函数的形式,在状态要改变的时候更新回调函数,这样就免去了一个大的switch-case了,不过这只是编程上的技巧。
下一篇写一下,RPC状态机的执行过程。
参考:
http://blog.youkuaiyun.com/dog250/article/details/5303423