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

📄 clnt.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (task->tk_rqstp) {		printk(KERN_ERR "%s: status=%d, request allocated anyway\n",				__FUNCTION__, status);		xprt_release(task);	}	switch (status) {	case -EAGAIN:	/* woken up; retry */		task->tk_action = call_reserve;		return;	case -EIO:	/* probably a shutdown */		break;	default:		printk(KERN_ERR "%s: unrecognized error %d, exiting\n",				__FUNCTION__, status);		break;	}	rpc_exit(task, status);}/* * 2.	Allocate the buffer. For details, see sched.c:rpc_malloc. *	(Note: buffer memory is freed in rpc_task_release). */static voidcall_allocate(struct rpc_task *task){	unsigned int	bufsiz;	dprintk("RPC: %4d call_allocate (status %d)\n", 				task->tk_pid, task->tk_status);	task->tk_action = call_bind;	if (task->tk_buffer)		return;	/* FIXME: compute buffer requirements more exactly using	 * auth->au_wslack */	bufsiz = task->tk_msg.rpc_proc->p_bufsiz + RPC_SLACK_SPACE;	if (rpc_malloc(task, bufsiz << 1) != NULL)		return;	printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task); 	if (RPC_IS_ASYNC(task) || !(task->tk_client->cl_intr && signalled())) {		xprt_release(task);		task->tk_action = call_reserve;		rpc_delay(task, HZ>>4);		return;	}	rpc_exit(task, -ERESTARTSYS);}/* * 3.	Encode arguments of an RPC call */static voidcall_encode(struct rpc_task *task){	struct rpc_clnt	*clnt = task->tk_client;	struct rpc_rqst	*req = task->tk_rqstp;	struct xdr_buf *sndbuf = &req->rq_snd_buf;	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;	unsigned int	bufsiz;	kxdrproc_t	encode;	int		status;	u32		*p;	dprintk("RPC: %4d call_encode (status %d)\n", 				task->tk_pid, task->tk_status);	/* Default buffer setup */	bufsiz = task->tk_bufsize >> 1;	sndbuf->head[0].iov_base = (void *)task->tk_buffer;	sndbuf->head[0].iov_len  = bufsiz;	sndbuf->tail[0].iov_len  = 0;	sndbuf->page_len	 = 0;	sndbuf->len		 = 0;	sndbuf->buflen		 = bufsiz;	rcvbuf->head[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz);	rcvbuf->head[0].iov_len  = bufsiz;	rcvbuf->tail[0].iov_len  = 0;	rcvbuf->page_len	 = 0;	rcvbuf->len		 = 0;	rcvbuf->buflen		 = bufsiz;	/* Encode header and provided arguments */	encode = task->tk_msg.rpc_proc->p_encode;	if (!(p = call_header(task))) {		printk(KERN_INFO "RPC: call_header failed, exit EIO\n");		rpc_exit(task, -EIO);		return;	}	if (encode && (status = rpcauth_wrap_req(task, encode, req, p,						 task->tk_msg.rpc_argp)) < 0) {		printk(KERN_WARNING "%s: can't encode arguments: %d\n",				clnt->cl_protname, -status);		rpc_exit(task, status);	}}/* * 4.	Get the server port number if not yet set */static voidcall_bind(struct rpc_task *task){	struct rpc_clnt	*clnt = task->tk_client;	struct rpc_xprt *xprt = clnt->cl_xprt;	dprintk("RPC: %4d call_bind xprt %p %s connected\n", task->tk_pid,			xprt, (xprt_connected(xprt) ? "is" : "is not"));	task->tk_action = (xprt_connected(xprt)) ? call_transmit : call_connect;	if (!clnt->cl_port) {		task->tk_action = call_connect;		task->tk_timeout = RPC_CONNECT_TIMEOUT;		rpc_getport(task, clnt);	}}/* * 4a.	Connect to the RPC server (TCP case) */static voidcall_connect(struct rpc_task *task){	struct rpc_clnt *clnt = task->tk_client;	dprintk("RPC: %4d call_connect status %d\n",				task->tk_pid, task->tk_status);	if (xprt_connected(clnt->cl_xprt)) {		task->tk_action = call_transmit;		return;	}	task->tk_action = call_connect_status;	if (task->tk_status < 0)		return;	xprt_connect(task);}/* * 4b. Sort out connect result */static voidcall_connect_status(struct rpc_task *task){	struct rpc_clnt *clnt = task->tk_client;	int status = task->tk_status;	task->tk_status = 0;	if (status >= 0) {		clnt->cl_stats->netreconn++;		task->tk_action = call_transmit;		return;	}	/* Something failed: we may have to rebind */	if (clnt->cl_autobind)		clnt->cl_port = 0;	switch (status) {	case -ENOTCONN:	case -ETIMEDOUT:	case -EAGAIN:		task->tk_action = (clnt->cl_port == 0) ? call_bind : call_connect;		break;	default:		rpc_exit(task, -EIO);	}}/* * 5.	Transmit the RPC request, and wait for reply */static voidcall_transmit(struct rpc_task *task){	dprintk("RPC: %4d call_transmit (status %d)\n", 				task->tk_pid, task->tk_status);	task->tk_action = call_status;	if (task->tk_status < 0)		return;	task->tk_status = xprt_prepare_transmit(task);	if (task->tk_status != 0)		return;	/* Encode here so that rpcsec_gss can use correct sequence number. */	if (!task->tk_rqstp->rq_bytes_sent)		call_encode(task);	if (task->tk_status < 0)		return;	xprt_transmit(task);	if (task->tk_status < 0)		return;	if (!task->tk_msg.rpc_proc->p_decode) {		task->tk_action = NULL;		rpc_wake_up_task(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;	dprintk("RPC: %4d call_status (status %d)\n", 				task->tk_pid, task->tk_status);	status = task->tk_status;	if (status >= 0) {		task->tk_action = call_decode;		return;	}	task->tk_status = 0;	switch(status) {	case -ETIMEDOUT:		task->tk_action = call_timeout;		break;	case -ECONNREFUSED:	case -ENOTCONN:		req->rq_bytes_sent = 0;		if (clnt->cl_autobind)			clnt->cl_port = 0;		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:		if (clnt->cl_chatty)			printk("%s: RPC call returned error %d\n",			       clnt->cl_protname, -status);		rpc_exit(task, status);		break;	}}/* * 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: %4d call_timeout (minor)\n", task->tk_pid);		goto retry;	}	dprintk("RPC: %4d call_timeout (major)\n", task->tk_pid);	if (RPC_IS_SOFT(task)) {		if (clnt->cl_chatty)			printk(KERN_NOTICE "%s: server %s not responding, timed out\n",				clnt->cl_protname, clnt->cl_server);		rpc_exit(task, -EIO);		return;	}	if (clnt->cl_chatty && !(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);	}	if (clnt->cl_autobind)		clnt->cl_port = 0;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;	u32		*p;	dprintk("RPC: %4d call_decode (status %d)\n", 				task->tk_pid, task->tk_status);	if (clnt->cl_chatty && (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;		}		printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n",			clnt->cl_protname, task->tk_status);		rpc_exit(task, -EIO);		return;	}	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 */	if (!(p = call_verify(task))) {		if (task->tk_action == NULL)			return;		goto out_retry;	}	/*	 * The following is an NFS-specific hack to cater for setuid	 * processes whose uid is mapped to nobody on the server.	 */	if (task->tk_client->cl_droppriv &&             (ntohl(*p) == NFSERR_ACCES || ntohl(*p) == NFSERR_PERM)) {		if (RPC_IS_SETUID(task) && task->tk_suid_retry) {			dprintk("RPC: %4d retry squashed uid\n", task->tk_pid);			task->tk_flags ^= RPC_CALL_REALUID;			task->tk_action = call_bind;			task->tk_suid_retry--;			goto out_retry;		}	}	task->tk_action = NULL;	if (decode)		task->tk_status = rpcauth_unwrap_resp(task, decode, req, p,						      task->tk_msg.rpc_resp);	dprintk("RPC: %4d 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;}/* * 8.	Refresh the credentials if rejected by the server */static voidcall_refresh(struct rpc_task *task){	dprintk("RPC: %4d call_refresh\n", task->tk_pid);	xprt_release(task);	/* Must do to obtain new XID */	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;	dprintk("RPC: %4d call_refreshresult (status %d)\n", 				task->tk_pid, task->tk_status);	task->tk_status = 0;	task->tk_action = call_reserve;	if (status >= 0 && rpcauth_uptodatecred(task))		return;	if (rpcauth_deadcred(task)) {		rpc_exit(task, -EACCES);		return;	}	task->tk_action = call_refresh;	if (status != -ETIMEDOUT)		rpc_delay(task, 3*HZ);	return;}/* * Call header serialization */static u32 *call_header(struct rpc_task *task){	struct rpc_clnt *clnt = task->tk_client;	struct rpc_xprt *xprt = clnt->cl_xprt;	struct rpc_rqst	*req = task->tk_rqstp;	u32		*p = req->rq_svec[0].iov_base;	/* FIXME: check buffer size? */	if (xprt->stream)		*p++ = 0;		/* fill in later */	*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 */	return rpcauth_marshcred(task, p);}/* * Reply header verification */static u32 *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;	u32	*p = iov->iov_base, n;	if ((len -= 3) < 0)		goto garbage;	p += 1;	/* skip XID */	if ((n = ntohl(*p++)) != RPC_REPLY) {		printk(KERN_WARNING "call_verify: not an RPC reply: %x\n", n);		goto garbage;	}	if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {		int	error = -EACCES;		if (--len < 0)			goto garbage;		if ((n = ntohl(*p++)) != RPC_AUTH_ERROR) {			printk(KERN_WARNING "call_verify: RPC call rejected: %x\n", n);		} else if (--len < 0)		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: %4d call_verify: retry stale creds\n",							task->tk_pid);			rpcauth_invalcred(task);			task->tk_action = call_refresh;			return NULL;		case RPC_AUTH_BADCRED:		case RPC_AUTH_BADVERF:			/* possibly garbled cred/verf? */			if (!task->tk_garb_retry)				break;			task->tk_garb_retry--;			dprintk("RPC: %4d call_verify: retry garbled creds\n",							task->tk_pid);			task->tk_action = call_bind;			return NULL;		case RPC_AUTH_TOOWEAK:			printk(KERN_NOTICE "call_verify: server requires stronger "			       "authentication.\n");			break;		default:			printk(KERN_WARNING "call_verify: unknown auth error: %x\n", n);			error = -EIO;		} else			goto garbage;		dprintk("RPC: %4d call_verify: call rejected %d\n",						task->tk_pid, n);		rpc_exit(task, error);		return NULL;	}	if (!(p = rpcauth_checkverf(task, p))) {		printk(KERN_WARNING "call_verify: auth check failed\n");		goto garbage;		/* bad verifier, retry */	}	len = p - (u32 *)iov->iov_base - 1;	if (len < 0)		goto garbage;	switch ((n = ntohl(*p++))) {	case RPC_SUCCESS:		return p;	case RPC_PROG_UNAVAIL:		printk(KERN_WARNING "RPC: call_verify: program %u is unsupported by server %s\n",				(unsigned int)task->tk_client->cl_prog,				task->tk_client->cl_server);		goto out_eio;	case RPC_PROG_MISMATCH:		printk(KERN_WARNING "RPC: call_verify: program %u, version %u unsupported by server %s\n",				(unsigned int)task->tk_client->cl_prog,				(unsigned int)task->tk_client->cl_vers,				task->tk_client->cl_server);		goto out_eio;	case RPC_PROC_UNAVAIL:		printk(KERN_WARNING "RPC: call_verify: proc %p unsupported by program %u, version %u on server %s\n",				task->tk_msg.rpc_proc,				task->tk_client->cl_prog,				task->tk_client->cl_vers,				task->tk_client->cl_server);		goto out_eio;	case RPC_GARBAGE_ARGS:		break;			/* retry */	default:		printk(KERN_WARNING "call_verify: server accept status: %x\n", n);		/* Also retry */	}garbage:	dprintk("RPC: %4d call_verify: server saw garbage\n", task->tk_pid);	task->tk_client->cl_stats->rpcgarbage++;	if (task->tk_garb_retry) {		task->tk_garb_retry--;		dprintk(KERN_WARNING "RPC: garbage, retrying %4d\n", task->tk_pid);		task->tk_action = call_bind;		return NULL;	}	printk(KERN_WARNING "RPC: garbage, exit EIO\n");out_eio:	rpc_exit(task, -EIO);	return NULL;}

⌨️ 快捷键说明

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