⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clnt.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	case -ETIMEDOUT:		task->tk_action = call_timeout;		return;	}	rpc_exit(task, -EIO);}/* * 5.	Transmit the RPC request, and wait for reply */static voidcall_transmit(struct rpc_task *task){	dprint_status(task);	task->tk_action = call_status;	if (task->tk_status < 0)		return;	task->tk_status = xprt_prepare_transmit(task);	if (task->tk_status != 0)		return;	task->tk_action = call_transmit_status;	/* Encode here so that rpcsec_gss can use correct sequence number. */	if (rpc_task_need_encode(task)) {		BUG_ON(task->tk_rqstp->rq_bytes_sent != 0);		call_encode(task);		/* Did the encode result in an error condition? */		if (task->tk_status != 0)			return;	}	xprt_transmit(task);	if (task->tk_status < 0)		return;	/*	 * On success, ensure that we call xprt_end_transmit() before sleeping	 * in order to allow access to the socket to other RPC requests.	 */	call_transmit_status(task);	if (task->tk_msg.rpc_proc->p_decode != NULL)		return;	task->tk_action = rpc_exit_task;	rpc_wake_up_task(task);}/* * 5a.	Handle cleanup after a transmission */static voidcall_transmit_status(struct rpc_task *task){	task->tk_action = call_status;	/*	 * Special case: if we've been waiting on the socket's write_space()	 * callback, then don't call xprt_end_transmit().	 */	if (task->tk_status == -EAGAIN)		return;	xprt_end_transmit(task);	rpc_task_force_reencode(task);}/* * 6.	Sort out the RPC call status */static voidcall_status(struct rpc_task *task){	struct rpc_clnt	*clnt = task->tk_client;	struct rpc_rqst	*req = task->tk_rqstp;	int		status;	if (req->rq_received > 0 && !req->rq_bytes_sent)		task->tk_status = req->rq_received;	dprint_status(task);	status = task->tk_status;	if (status >= 0) {		task->tk_action = call_decode;		return;	}	task->tk_status = 0;	switch(status) {	case -EHOSTDOWN:	case -EHOSTUNREACH:	case -ENETUNREACH:		/*		 * Delay any retries for 3 seconds, then handle as if it		 * were a timeout.		 */		rpc_delay(task, 3*HZ);	case -ETIMEDOUT:		task->tk_action = call_timeout;		if (task->tk_client->cl_discrtry)			xprt_disconnect(task->tk_xprt);		break;	case -ECONNREFUSED:	case -ENOTCONN:		rpc_force_rebind(clnt);		task->tk_action = call_bind;		break;	case -EAGAIN:		task->tk_action = call_transmit;		break;	case -EIO:		/* shutdown or soft timeout */		rpc_exit(task, status);		break;	default:		printk("%s: RPC call returned error %d\n",			       clnt->cl_protname, -status);		rpc_exit(task, status);	}}/* * 6a.	Handle RPC timeout * 	We do not release the request slot, so we keep using the *	same XID for all retransmits. */static voidcall_timeout(struct rpc_task *task){	struct rpc_clnt	*clnt = task->tk_client;	if (xprt_adjust_timeout(task->tk_rqstp) == 0) {		dprintk("RPC: %5u call_timeout (minor)\n", task->tk_pid);		goto retry;	}	dprintk("RPC: %5u call_timeout (major)\n", task->tk_pid);	task->tk_timeouts++;	if (RPC_IS_SOFT(task)) {		printk(KERN_NOTICE "%s: server %s not responding, timed out\n",				clnt->cl_protname, clnt->cl_server);		rpc_exit(task, -EIO);		return;	}	if (!(task->tk_flags & RPC_CALL_MAJORSEEN)) {		task->tk_flags |= RPC_CALL_MAJORSEEN;		printk(KERN_NOTICE "%s: server %s not responding, still trying\n",			clnt->cl_protname, clnt->cl_server);	}	rpc_force_rebind(clnt);retry:	clnt->cl_stats->rpcretrans++;	task->tk_action = call_bind;	task->tk_status = 0;}/* * 7.	Decode the RPC reply */static voidcall_decode(struct rpc_task *task){	struct rpc_clnt	*clnt = task->tk_client;	struct rpc_rqst	*req = task->tk_rqstp;	kxdrproc_t	decode = task->tk_msg.rpc_proc->p_decode;	__be32		*p;	dprintk("RPC: %5u call_decode (status %d)\n",			task->tk_pid, task->tk_status);	if (task->tk_flags & RPC_CALL_MAJORSEEN) {		printk(KERN_NOTICE "%s: server %s OK\n",			clnt->cl_protname, clnt->cl_server);		task->tk_flags &= ~RPC_CALL_MAJORSEEN;	}	if (task->tk_status < 12) {		if (!RPC_IS_SOFT(task)) {			task->tk_action = call_bind;			clnt->cl_stats->rpcretrans++;			goto out_retry;		}		dprintk("RPC:       %s: too small RPC reply size (%d bytes)\n",				clnt->cl_protname, task->tk_status);		task->tk_action = call_timeout;		goto out_retry;	}	/*	 * Ensure that we see all writes made by xprt_complete_rqst()	 * before it changed req->rq_received.	 */	smp_rmb();	req->rq_rcv_buf.len = req->rq_private_buf.len;	/* Check that the softirq receive buffer is valid */	WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,				sizeof(req->rq_rcv_buf)) != 0);	/* Verify the RPC header */	p = call_verify(task);	if (IS_ERR(p)) {		if (p == ERR_PTR(-EAGAIN))			goto out_retry;		return;	}	task->tk_action = rpc_exit_task;	if (decode) {		task->tk_status = rpcauth_unwrap_resp(task, decode, req, p,						      task->tk_msg.rpc_resp);	}	dprintk("RPC: %5u call_decode result %d\n", task->tk_pid,			task->tk_status);	return;out_retry:	req->rq_received = req->rq_private_buf.len = 0;	task->tk_status = 0;	if (task->tk_client->cl_discrtry)		xprt_disconnect(task->tk_xprt);}/* * 8.	Refresh the credentials if rejected by the server */static voidcall_refresh(struct rpc_task *task){	dprint_status(task);	task->tk_action = call_refreshresult;	task->tk_status = 0;	task->tk_client->cl_stats->rpcauthrefresh++;	rpcauth_refreshcred(task);}/* * 8a.	Process the results of a credential refresh */static voidcall_refreshresult(struct rpc_task *task){	int status = task->tk_status;	dprint_status(task);	task->tk_status = 0;	task->tk_action = call_reserve;	if (status >= 0 && rpcauth_uptodatecred(task))		return;	if (status == -EACCES) {		rpc_exit(task, -EACCES);		return;	}	task->tk_action = call_refresh;	if (status != -ETIMEDOUT)		rpc_delay(task, 3*HZ);	return;}/* * Call header serialization */static __be32 *call_header(struct rpc_task *task){	struct rpc_clnt *clnt = task->tk_client;	struct rpc_rqst	*req = task->tk_rqstp;	__be32		*p = req->rq_svec[0].iov_base;	/* FIXME: check buffer size? */	p = xprt_skip_transport_header(task->tk_xprt, p);	*p++ = req->rq_xid;		/* XID */	*p++ = htonl(RPC_CALL);		/* CALL */	*p++ = htonl(RPC_VERSION);	/* RPC version */	*p++ = htonl(clnt->cl_prog);	/* program number */	*p++ = htonl(clnt->cl_vers);	/* program version */	*p++ = htonl(task->tk_msg.rpc_proc->p_proc);	/* procedure */	p = rpcauth_marshcred(task, p);	req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p);	return p;}/* * Reply header verification */static __be32 *call_verify(struct rpc_task *task){	struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];	int len = task->tk_rqstp->rq_rcv_buf.len >> 2;	__be32	*p = iov->iov_base;	u32 n;	int error = -EACCES;	if ((task->tk_rqstp->rq_rcv_buf.len & 3) != 0) {		/* RFC-1014 says that the representation of XDR data must be a		 * multiple of four bytes		 * - if it isn't pointer subtraction in the NFS client may give		 *   undefined results		 */		dprintk("RPC: %5u %s: XDR representation not a multiple of"		       " 4 bytes: 0x%x\n", task->tk_pid, __FUNCTION__,		       task->tk_rqstp->rq_rcv_buf.len);		goto out_eio;	}	if ((len -= 3) < 0)		goto out_overflow;	p += 1;	/* skip XID */	if ((n = ntohl(*p++)) != RPC_REPLY) {		dprintk("RPC: %5u %s: not an RPC reply: %x\n",				task->tk_pid, __FUNCTION__, n);		goto out_garbage;	}	if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {		if (--len < 0)			goto out_overflow;		switch ((n = ntohl(*p++))) {			case RPC_AUTH_ERROR:				break;			case RPC_MISMATCH:				dprintk("RPC: %5u %s: RPC call version "						"mismatch!\n",						task->tk_pid, __FUNCTION__);				error = -EPROTONOSUPPORT;				goto out_err;			default:				dprintk("RPC: %5u %s: RPC call rejected, "						"unknown error: %x\n",						task->tk_pid, __FUNCTION__, n);				goto out_eio;		}		if (--len < 0)			goto out_overflow;		switch ((n = ntohl(*p++))) {		case RPC_AUTH_REJECTEDCRED:		case RPC_AUTH_REJECTEDVERF:		case RPCSEC_GSS_CREDPROBLEM:		case RPCSEC_GSS_CTXPROBLEM:			if (!task->tk_cred_retry)				break;			task->tk_cred_retry--;			dprintk("RPC: %5u %s: retry stale creds\n",					task->tk_pid, __FUNCTION__);			rpcauth_invalcred(task);			/* Ensure we obtain a new XID! */			xprt_release(task);			task->tk_action = call_refresh;			goto out_retry;		case RPC_AUTH_BADCRED:		case RPC_AUTH_BADVERF:			/* possibly garbled cred/verf? */			if (!task->tk_garb_retry)				break;			task->tk_garb_retry--;			dprintk("RPC: %5u %s: retry garbled creds\n",					task->tk_pid, __FUNCTION__);			task->tk_action = call_bind;			goto out_retry;		case RPC_AUTH_TOOWEAK:			printk(KERN_NOTICE "call_verify: server %s requires stronger "			       "authentication.\n", task->tk_client->cl_server);			break;		default:			dprintk("RPC: %5u %s: unknown auth error: %x\n",					task->tk_pid, __FUNCTION__, n);			error = -EIO;		}		dprintk("RPC: %5u %s: call rejected %d\n",				task->tk_pid, __FUNCTION__, n);		goto out_err;	}	if (!(p = rpcauth_checkverf(task, p))) {		dprintk("RPC: %5u %s: auth check failed\n",				task->tk_pid, __FUNCTION__);		goto out_garbage;		/* bad verifier, retry */	}	len = p - (__be32 *)iov->iov_base - 1;	if (len < 0)		goto out_overflow;	switch ((n = ntohl(*p++))) {	case RPC_SUCCESS:		return p;	case RPC_PROG_UNAVAIL:		dprintk("RPC: %5u %s: program %u is unsupported by server %s\n",				task->tk_pid, __FUNCTION__,				(unsigned int)task->tk_client->cl_prog,				task->tk_client->cl_server);		error = -EPFNOSUPPORT;		goto out_err;	case RPC_PROG_MISMATCH:		dprintk("RPC: %5u %s: program %u, version %u unsupported by "				"server %s\n", task->tk_pid, __FUNCTION__,				(unsigned int)task->tk_client->cl_prog,				(unsigned int)task->tk_client->cl_vers,				task->tk_client->cl_server);		error = -EPROTONOSUPPORT;		goto out_err;	case RPC_PROC_UNAVAIL:		dprintk("RPC: %5u %s: proc %p unsupported by program %u, "				"version %u on server %s\n",				task->tk_pid, __FUNCTION__,				task->tk_msg.rpc_proc,				task->tk_client->cl_prog,				task->tk_client->cl_vers,				task->tk_client->cl_server);		error = -EOPNOTSUPP;		goto out_err;	case RPC_GARBAGE_ARGS:		dprintk("RPC: %5u %s: server saw garbage\n",				task->tk_pid, __FUNCTION__);		break;			/* retry */	default:		dprintk("RPC: %5u %s: server accept status: %x\n",				task->tk_pid, __FUNCTION__, n);		/* Also retry */	}out_garbage:	task->tk_client->cl_stats->rpcgarbage++;	if (task->tk_garb_retry) {		task->tk_garb_retry--;		dprintk("RPC: %5u %s: retrying\n",				task->tk_pid, __FUNCTION__);		task->tk_action = call_bind;out_retry:		return ERR_PTR(-EAGAIN);	}out_eio:	error = -EIO;out_err:	rpc_exit(task, error);	dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid,			__FUNCTION__, error);	return ERR_PTR(error);out_overflow:	dprintk("RPC: %5u %s: server reply was truncated.\n", task->tk_pid,			__FUNCTION__);	goto out_garbage;}static int rpcproc_encode_null(void *rqstp, __be32 *data, void *obj){	return 0;}static int rpcproc_decode_null(void *rqstp, __be32 *data, void *obj){	return 0;}static struct rpc_procinfo rpcproc_null = {	.p_encode = rpcproc_encode_null,	.p_decode = rpcproc_decode_null,};static int rpc_ping(struct rpc_clnt *clnt, int flags){	struct rpc_message msg = {		.rpc_proc = &rpcproc_null,	};	int err;	msg.rpc_cred = authnull_ops.lookup_cred(NULL, NULL, 0);	err = rpc_call_sync(clnt, &msg, flags);	put_rpccred(msg.rpc_cred);	return err;}struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int flags){	struct rpc_message msg = {		.rpc_proc = &rpcproc_null,		.rpc_cred = cred,	};	return rpc_do_run_task(clnt, &msg, flags, &rpc_default_ops, NULL);}EXPORT_SYMBOL(rpc_call_null);#ifdef RPC_DEBUGvoid rpc_show_tasks(void){	struct rpc_clnt *clnt;	struct rpc_task *t;	spin_lock(&rpc_client_lock);	if (list_empty(&all_clients))		goto out;	printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout "		"-rpcwait -action- ---ops--\n");	list_for_each_entry(clnt, &all_clients, cl_clients) {		if (list_empty(&clnt->cl_tasks))			continue;		spin_lock(&clnt->cl_lock);		list_for_each_entry(t, &clnt->cl_tasks, tk_task) {			const char *rpc_waitq = "none";			int proc;			if (t->tk_msg.rpc_proc)				proc = t->tk_msg.rpc_proc->p_proc;			else				proc = -1;			if (RPC_IS_QUEUED(t))				rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq);			printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n",				t->tk_pid, proc,				t->tk_flags, t->tk_status,				t->tk_client,				(t->tk_client ? t->tk_client->cl_prog : 0),				t->tk_rqstp, t->tk_timeout,				rpc_waitq,				t->tk_action, t->tk_ops);		}		spin_unlock(&clnt->cl_lock);	}out:	spin_unlock(&rpc_client_lock);}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -