Linux rpc_create_client RPC客户端与xprt传输绑定
rpc_create_client是SUNRPC层创建RPC客户端实例的核心函数,位于net/sunrpc/clnt.c。它完成struct rpc_clnt的分配与初始化,并将客户端绑定到一个已创建的传输通道(xprt)上。NFS客户端在挂载时通过rpc_create调用间接调用此函数。
函数原型:
```c
struct 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);
else
return 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的核心实现:
```c
static 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.c:
```c
struct 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_xprt:
```c
static 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并设置连接参数:
```c
static 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_UNIX(AUTH_SYS)和RPC_AUTH_GSS(Kerberos)。认证句柄保存在cl_auth中,在每次RPC调用时通过rpcauth_refreshcred更新凭证。