RPC代码位于net/sunrpc/
几个概念
以下信息可以在/sys/kernel/debug/sunrpc中查看
xprt (transport)
struct rpc_xprt描述,代表一个连接(可以是TCP,UDP和RDMA)。由xprt_create_transport创建。
rpc client
struct rpc_clnt描述,代表一个client handle。由rpc_create创建,它会创建transport,并发送ping,判断是否对方支持这个RPC
rpc message
struct rpc_message描述,代表一个rpc message,在创建task时候需要描述rpc message,里面包括传输的参数,返回的参数地址,发生/接收时候用到编码/解码函数等。
rpc task
struct rpc_task描述,代表一个task,内部是一个有限状态机。
RPC 除调度之外的其它接口
rpc_create //返回rpc_clnt
xprt_create_transport //返回rpc_xprt,代表一个TCP连接
rpc_create_xprt //根据rpc_xprt,返回一个rpc_clnt
RPC task数据结构
每个Task(struct rpc_task)就是一个有限状态机,状态机运行完毕表示这个task运行完毕。
RPC Task 调度函数
rpc_execute //运行状态机
rpc_run_task //用rpc_task_setup描述task,对rpc_execute的封装
rpc_call_sync //用rpc_message描述task,对rpc_run_task的封装
rpc_call_async //用rpc_message描述task,对rpc_run_task的封装
rpc_call_start //将task->tk_action设置为call_start
rpc_execute()中,如果task需要prepare,状态机从rpc_prepare_task()开始运行,否则从call_start开始。
NFS Client构造RPC request
NFS Client是sunrpc重要客户,NFS的RPC请求本质上都是构造struct rpc_task,然后调用rpc_run_task完成的。
调用rpc_call_sync()
=>rpc_call_sync() => rpc_run_task() => rpc_execute()
参见nfs4_proc_exchange_id的实现
调用rpc_call_async()
=>rpc_call_async() => rpc_run_task() => rpc_execute()
参见nfs4_proc_async_renew的实现
直接调用rpc_run_task()
参见nfs41_proc_reclaim_complete的实现。
需要注意的是,rpc_task状态机还提供了一些callback,允许在运行之前和之后会被调用。例如:
static const struct rpc_call_ops nfs4_reclaim_complete_call_ops = {
.rpc_call_prepare = nfs4_reclaim_complete_prepare,
.rpc_call_done = nfs4_reclaim_complete_done,
.rpc_release = nfs4_free_reclaim_complete_data,
};
RPC Task 状态机 状态转移
__rpc_execute是RPC的处理函数,本质上是一个有限状态机FSM。如果是同步RPC,由rpc_execute调用。如果是异步RPC,由rpc_execute插入到work queue中调用。
__rpc_execute(struct rpc_task *task)
{
for(;;)
{
task->tk_callback(); //如call_start,call_reserve等。在这里修改tk_callback
}
}
rpc_call_start() => call_start => call_reserve => call_refresh => ... => call_connect => 等等
call_start //0. Initial state
call_reserve //1. Reserve an RPC call slot
call_refresh //2. Bind and/or refresh the credentials
rpc_xdr_encode //3. Encode arguments of an RPC call
call_bind //4. Get the server port number if not yet set
call_transmit //5. Transmit the RPC request, and wait for reply
call_status //6. Sort out the RPC call status
call_decode //7. Decode the RPC reply
work queue
sun rpc里边会使用三个workqueue,分别是rpciod_workqueue,xprtiod_workqueue,nfsiod_workqueue。
rpciod_workqueue:调用__rpc_execute运行rpc task状态机。同步RPC调用运行在调用者的运行上下文,异步RPC在这个work queue执行__rpc_execute。
xprtiod_workqueue:处理网络收发(在Linux 4.4中还没有这个)
nfsiod_workqueue:rpc task使用结束后,需要调用rpc_free_task进行回收。回收可以同步,也可以异步。异步回收时在这个work queue中。这是nfs的RPC请求时提供的。
统计参数
/proc/net/rpc/