Linux rpc_create_client RPC客户端与xprt传输绑定rpc_create_client是SUNRPC层创建RPC客户端实例的核心函数位于net/sunrpc/clnt.c。它完成struct rpc_clnt的分配与初始化并将客户端绑定到一个已创建的传输通道xprt上。NFS客户端在挂载时通过rpc_create调用间接调用此函数。函数原型cstruct rpc_clnt *rpc_create(struct rpc_create_args *args){struct rpc_xprt *xprt;struct rpc_clnt *clnt ERR_PTR(-EIO);if (args-protocol XPRT_TRANSPORT_TCP)xprt xprt_create_transport(XPRT_TRANSPORT_TCP, args-address,args-addrsize, args-servername,args-xprtsec);else if (args-protocol XPRT_TRANSPORT_UDP)xprt xprt_create_transport(XPRT_TRANSPORT_UDP, args-address,args-addrsize, args-servername,args-xprtsec);elsereturn ERR_PTR(-EPROTONOSUPPORT);if (IS_ERR(xprt))return ERR_CAST(xprt);clnt rpc_create_client(xprt, args-program, args-version,args-prognumber, args-authflavor);...return clnt;}rpc_create_client的核心实现cstatic struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt,const struct rpc_program *program,u32 version, u32 prognumber,rpc_authflavor_t authflavor){struct rpc_clnt *clnt NULL;const struct rpc_version *vers;int err;vers rpc_verify_header(program, version);if (IS_ERR(vers))goto out_err;clnt kzalloc(sizeof(*clnt), GFP_KERNEL);if (!clnt)goto out_err;clnt-cl_program program;clnt-cl_vers vers;clnt-cl_prog prognumber;clnt-cl_xprt xprt;clnt-cl_autobind 1;clnt-cl_timeout xprt-timeout;clnt-cl_metrics alloc_percpu(struct rpc_clnt_metrics);INIT_LIST_HEAD(clnt-cl_tasks);spin_lock_init(clnt-cl_lock);refcount_set(clnt-cl_count, 1);rpc_init_rtt(clnt-cl_rtt_default, HZ);err rpc_register_client(clnt);if (err)goto out_err;if (authflavor ! RPC_AUTH_NULL) {clnt-cl_auth rpcauth_create(authflavor, clnt);if (IS_ERR(clnt-cl_auth))goto out_err;}return clnt;out_err:if (!IS_ERR_OR_NULL(clnt))rpc_destroy_client(clnt);return ERR_PTR(err);}xprt_create_transport是传输层创建函数定义在net/sunrpc/xprt.ccstruct rpc_xprt *xprt_create_transport(int xprt_type,struct sockaddr *addr,size_t addrlen,const char *servername,struct xprtsec_parms *xprtsec){struct rpc_xprt *xprt;const struct rpc_xprt_ops *ops;int err;ops rpc_xprt_find_transport_owner(xprt_type);if (!ops)return ERR_PTR(-EPROTONOSUPPORT);xprt ops-alloc_xprt(xprt_sec);if (!xprt)return ERR_PTR(-ENOMEM);xprt-ops ops;xprt-addr *addr;xprt-addrlen addrlen;xprt-servername kstrdup(servername, GFP_KERNEL);xprt-max_reqs RPC_MAX_SLOT_TABLE;xprt-min_reqs 0;xprt-num_reqs 0;xprt-cwnd RPC_INITIAL_CWND;xprt-timeout NULL;xprt-bind_timeout RPC_BIND_TIMEOUT_DEF;xprt-reestablish_timeout RPC_REESTABLISH_TIMEOUT_DEF;xprt-idle_timeout RPC_MAX_IDLE_TIMEOUT_DEF;xprt-cong 0;err xprt-ops-xprt_setup(xprt, addr, addrlen);if (err)goto out_destroy;return xprt;out_destroy:xprt-ops-destroy_xprt(xprt);return ERR_PTR(err);}对于TCP传输alloc_xprt指向xs_tcp_alloc_xprtcstatic struct rpc_xprt *xs_tcp_alloc_xprt(struct xprt_sec *xprtsec){struct rpc_xprt *xprt kzalloc(sizeof(*xprt), GFP_KERNEL);if (!xprt)return NULL;xprt-ops xs_tcp_ops;xprt-xprtsec *xprtsec;return xprt;}xprt_setup对应xs_tcp_setup_xprt它创建内核socket并设置连接参数cstatic int xs_tcp_setup_xprt(struct rpc_xprt *xprt,struct sockaddr *addr, size_t addrlen){struct socket *sock;int err, type SOCK_STREAM;err __sock_create(xprt-xprt_net, addr-sa_family, type, IPPROTO_TCP,sock, 1);if (err 0)return err;sock-sk-sk_allocation GFP_NOIO;sock-sk-sk_use_task_frag false;xprt-inet sock-sk;err kernel_connect(sock, addr, addrlen, O_NONBLOCK);if (err 0 err ! -EINPROGRESS)goto out;xprt-sock sock;xs_set_memalloc(xprt);return 0;out:sock_release(sock);return err;}客户端创建完成后xprt与clnt之间的绑定通过cl_xprt字段维系。当RPC任务通过rpc_run_task启动时任务通过task-tk_client-cl_xprt找到传输通道调用xprt-ops-send_request发送RPC消息。接收路径则通过xprt-recv函数对于TCP为xs_tcp_data_ready完成数据到达后调用xprt_complete_rqst完成请求-响应匹配。绑定后的auth创建过程通过rpcauth_create初始化认证机制常用的有RPC_AUTH_UNIXAUTH_SYS和RPC_AUTH_GSSKerberos。认证句柄保存在cl_auth中在每次RPC调用时通过rpcauth_refreshcred更新凭证。
Linux rpc_create_client RPC客户端与xprt传输绑定
发布时间:2026/6/21 5:08:37
Linux rpc_create_client RPC客户端与xprt传输绑定rpc_create_client是SUNRPC层创建RPC客户端实例的核心函数位于net/sunrpc/clnt.c。它完成struct rpc_clnt的分配与初始化并将客户端绑定到一个已创建的传输通道xprt上。NFS客户端在挂载时通过rpc_create调用间接调用此函数。函数原型cstruct rpc_clnt *rpc_create(struct rpc_create_args *args){struct rpc_xprt *xprt;struct rpc_clnt *clnt ERR_PTR(-EIO);if (args-protocol XPRT_TRANSPORT_TCP)xprt xprt_create_transport(XPRT_TRANSPORT_TCP, args-address,args-addrsize, args-servername,args-xprtsec);else if (args-protocol XPRT_TRANSPORT_UDP)xprt xprt_create_transport(XPRT_TRANSPORT_UDP, args-address,args-addrsize, args-servername,args-xprtsec);elsereturn ERR_PTR(-EPROTONOSUPPORT);if (IS_ERR(xprt))return ERR_CAST(xprt);clnt rpc_create_client(xprt, args-program, args-version,args-prognumber, args-authflavor);...return clnt;}rpc_create_client的核心实现cstatic struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt,const struct rpc_program *program,u32 version, u32 prognumber,rpc_authflavor_t authflavor){struct rpc_clnt *clnt NULL;const struct rpc_version *vers;int err;vers rpc_verify_header(program, version);if (IS_ERR(vers))goto out_err;clnt kzalloc(sizeof(*clnt), GFP_KERNEL);if (!clnt)goto out_err;clnt-cl_program program;clnt-cl_vers vers;clnt-cl_prog prognumber;clnt-cl_xprt xprt;clnt-cl_autobind 1;clnt-cl_timeout xprt-timeout;clnt-cl_metrics alloc_percpu(struct rpc_clnt_metrics);INIT_LIST_HEAD(clnt-cl_tasks);spin_lock_init(clnt-cl_lock);refcount_set(clnt-cl_count, 1);rpc_init_rtt(clnt-cl_rtt_default, HZ);err rpc_register_client(clnt);if (err)goto out_err;if (authflavor ! RPC_AUTH_NULL) {clnt-cl_auth rpcauth_create(authflavor, clnt);if (IS_ERR(clnt-cl_auth))goto out_err;}return clnt;out_err:if (!IS_ERR_OR_NULL(clnt))rpc_destroy_client(clnt);return ERR_PTR(err);}xprt_create_transport是传输层创建函数定义在net/sunrpc/xprt.ccstruct rpc_xprt *xprt_create_transport(int xprt_type,struct sockaddr *addr,size_t addrlen,const char *servername,struct xprtsec_parms *xprtsec){struct rpc_xprt *xprt;const struct rpc_xprt_ops *ops;int err;ops rpc_xprt_find_transport_owner(xprt_type);if (!ops)return ERR_PTR(-EPROTONOSUPPORT);xprt ops-alloc_xprt(xprt_sec);if (!xprt)return ERR_PTR(-ENOMEM);xprt-ops ops;xprt-addr *addr;xprt-addrlen addrlen;xprt-servername kstrdup(servername, GFP_KERNEL);xprt-max_reqs RPC_MAX_SLOT_TABLE;xprt-min_reqs 0;xprt-num_reqs 0;xprt-cwnd RPC_INITIAL_CWND;xprt-timeout NULL;xprt-bind_timeout RPC_BIND_TIMEOUT_DEF;xprt-reestablish_timeout RPC_REESTABLISH_TIMEOUT_DEF;xprt-idle_timeout RPC_MAX_IDLE_TIMEOUT_DEF;xprt-cong 0;err xprt-ops-xprt_setup(xprt, addr, addrlen);if (err)goto out_destroy;return xprt;out_destroy:xprt-ops-destroy_xprt(xprt);return ERR_PTR(err);}对于TCP传输alloc_xprt指向xs_tcp_alloc_xprtcstatic struct rpc_xprt *xs_tcp_alloc_xprt(struct xprt_sec *xprtsec){struct rpc_xprt *xprt kzalloc(sizeof(*xprt), GFP_KERNEL);if (!xprt)return NULL;xprt-ops xs_tcp_ops;xprt-xprtsec *xprtsec;return xprt;}xprt_setup对应xs_tcp_setup_xprt它创建内核socket并设置连接参数cstatic int xs_tcp_setup_xprt(struct rpc_xprt *xprt,struct sockaddr *addr, size_t addrlen){struct socket *sock;int err, type SOCK_STREAM;err __sock_create(xprt-xprt_net, addr-sa_family, type, IPPROTO_TCP,sock, 1);if (err 0)return err;sock-sk-sk_allocation GFP_NOIO;sock-sk-sk_use_task_frag false;xprt-inet sock-sk;err kernel_connect(sock, addr, addrlen, O_NONBLOCK);if (err 0 err ! -EINPROGRESS)goto out;xprt-sock sock;xs_set_memalloc(xprt);return 0;out:sock_release(sock);return err;}客户端创建完成后xprt与clnt之间的绑定通过cl_xprt字段维系。当RPC任务通过rpc_run_task启动时任务通过task-tk_client-cl_xprt找到传输通道调用xprt-ops-send_request发送RPC消息。接收路径则通过xprt-recv函数对于TCP为xs_tcp_data_ready完成数据到达后调用xprt_complete_rqst完成请求-响应匹配。绑定后的auth创建过程通过rpcauth_create初始化认证机制常用的有RPC_AUTH_UNIXAUTH_SYS和RPC_AUTH_GSSKerberos。认证句柄保存在cl_auth中在每次RPC调用时通过rpcauth_refreshcred更新凭证。