请求分拆
以nfs4 direct_read过程为例,过程中的几个控制结构
- dreq,每个io过程的上下文,记录所有io的参数,及中间产生的状态值
- nfs_pageio_descriptor, 内核中操作内存都是以page为单位,内存buf最终会转换为多个page组成的list,该类型中,包含list指针,由于dio请求的长度是由系统调用者指定的,所以不可能一次性将数据全部发送,会按照指定的bsize(挂载时指定的每次IO大小进行分拆),每次拆分之后调用一次该描述符的pg_doio(nfs_generic_pg_readpages)接口,这个pg_doio过程也只是再次进行分拆,不会阻塞调用。doio之后,会再次设置nfs_pageio_descriptor的page_count和pg_list,直到将整个dreq中的buff都处理完
- nfs_read_header和nfs_pgio_header
nfs_read_header包含了nfs_pgio_header的结构,并包括nfs_read_data结构,每次调用pg_doio就会生成一个nfs_pgio_header结构,一个nfs_pgio_header初始包括descpg_list中的第一个req,如果指定的bsize(传输大小的限制) - nfs_read_data,如果一个bsize小于一个page的大小,那么需要再次进行拆分,拆分成多个nfs_read_data结构,否则只创建一个nfs_read_data结构,最终使用每个nfs_read_data构建一个rpc_task
rpc的状态机
- call_start
- call_reserve->xprt_reserve
- call_reserveresult
- call_refresh->rpcauth_refreshcred
- call_refreshresult
- call_allocate->xprt->ops->buf_alloc 此处只是申请缓冲区用来存放消息的控制结构,数据部分是使用page指针
- call_bind->xprt->ops->rpcbind(task) 此处有标记为检查,已经bound,直接跳过
- call_connect->xprt_connect 此处也有标记检查,已经连接直接跳过
- call_connect_status 如果执行了xprt_connect操作,那么下一步需要检查连接状态,已经建立连接跳过该步
- call_transmit->xprt_prepare_transmit->xprt->ops->reserve_xprt 此处会设置xprt的锁标记->rpc_xdr_encode->xprt_transmit->xprt->ops->send_request ,此处可能会因为发送缓冲区满而无法继续发送,但是会记录已经发送的长度,不会全部从头开始->rpc_sleep_on 在call_transimit,将task在等待队列上,此处不是立即挂起,而是在call_transmi调结束之后,不在调用其他action->call_transmit_status->xprt_end_transmit->xprt_release_write ,此处会释放xprt
- call_transmit_status 如果在执行call_transmit过程中出现错误,则task不会挂起,而是执行该步骤
- call_status
- call_decode
未完待续
声明:转载本博文章须在文章明显处注明作者及附上原文链接,便于读者找到原文的更新版。