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

📄 rpcsock.c

📁 elinux jffs初始版本 具体了解JFFS的文件系统!
💻 C
字号:
/* *  linux/fs/nfs/rpcsock.c * *  This is a generic RPC call interface for datagram sockets that is able *  to place several concurrent RPC requests at the same time. It works like *  this: * *  -	When a process places a call, it allocates a request slot if *	one is available. Otherwise, it sleeps on the backlog queue *	(rpc_reserve). *  -	Then, the message is transmitted via rpc_send (exported by name of *	rpc_transmit). *  -	Finally, the process waits for the call to complete (rpc_doio): *	The first process on the receive queue waits for the next RPC packet, *	and peeks at the XID. If it finds a matching request, it receives *	the datagram on behalf of that process and wakes it up. Otherwise, *	the datagram is discarded. *  -	If the process having received the datagram was the first one on *	the receive queue, it wakes up the next one to listen for replies. *  -	It then removes itself from the request queue (rpc_release). *	If there are more callers waiting on the backlog queue, they are *	woken up, too. * * Mar 1996: *  -	Split up large functions into smaller chunks as per Linus' coding *	style. Found an interesting bug this way, too. *  -	Added entry points for nfsiod. * *  Copyright (C) 1995, 1996, Olaf Kirch <okir@monad.swb.de> */#include <linux/types.h>#include <linux/malloc.h>#include <linux/sched.h>#include <linux/nfs_fs.h>#include <linux/errno.h>#include <linux/socket.h>#include <linux/fcntl.h>#include <linux/in.h>#include <linux/net.h>#include <linux/mm.h>#include <linux/rpcsock.h>#include <linux/udp.h>#include <net/sock.h>#include <asm/segment.h>#define msleep(sec)	{ current->timeout = sec * HZ / 1000; \			  current->state = TASK_INTERRUPTIBLE; \			  schedule(); \			}#undef DEBUG_RPC#ifdef DEBUG_RPC			#define dprintk(args...)	printk(## args)#else#define	dprintk(args...)#endif/* * Insert new request into wait list. We make sure list is sorted by * increasing timeout value. */static inline voidrpc_insque(struct rpc_sock *rsock, struct rpc_wait *slot){	struct rpc_wait	*next = rsock->pending;	slot->w_next = next;	slot->w_prev = NULL;	if (next)		next->w_prev = slot;	rsock->pending = slot;	slot->w_queued = 1;	dprintk("RPC: inserted %p into queue\n", slot);}/* * Remove request from request queue */static inline voidrpc_remque(struct rpc_sock *rsock, struct rpc_wait *slot){	struct rpc_wait	*prev = slot->w_prev,			*next = slot->w_next;	if (prev != NULL)		prev->w_next = next;	else		rsock->pending = next;	if (next != NULL)		next->w_prev = prev;	slot->w_queued = 0;	dprintk("RPC: removed %p from queue, head now %p.\n",			slot, rsock->pending);}/* * Write data to socket. */static inline intrpc_sendmsg(struct rpc_sock *rsock, struct iovec *iov, int nr, int len,				struct sockaddr *sap, int salen){	struct socket	*sock = rsock->sock;	struct msghdr	msg;	unsigned long	oldfs;	int		result;	msg.msg_iov	= iov;	msg.msg_iovlen	= nr;	msg.msg_name	= sap;	msg.msg_namelen = salen;	msg.msg_control = NULL;	oldfs = get_fs();	set_fs(get_ds());	result = sock->ops->sendmsg(sock, &msg, len, 0, 0);	set_fs(oldfs);	dprintk("RPC: rpc_sendmsg(iov %p, len %d) = %d\n", iov, len, result);	return result;}/* * Read data from socket */static inline intrpc_recvmsg(struct rpc_sock *rsock, struct iovec *iov,			int nr, int len, int flags){	struct socket	*sock = rsock->sock;	struct sockaddr	sa;	struct msghdr	msg;	unsigned long	oldfs;	int		result, alen;	msg.msg_iov	= iov;	msg.msg_iovlen	= nr;	msg.msg_name	= &sa;	msg.msg_namelen = sizeof(sa);	msg.msg_control = NULL;	oldfs = get_fs();	set_fs(get_ds());	result = sock->ops->recvmsg(sock, &msg, len, 1, flags, &alen);	set_fs(oldfs);	dprintk("RPC: rpc_recvmsg(iov %p, len %d) = %d\n", iov, len, result);	return result;}/* * This code is slightly complicated. Since the networking code does not * honor the current->timeout value, we have to select on the socket. */static inline intrpc_select(struct rpc_sock *rsock){	struct select_table_entry entry;	struct file	*file = rsock->file;	select_table	wait_table;	dprintk("RPC: selecting on socket...\n");	wait_table.nr = 0;	wait_table.entry = &entry;	current->state = TASK_INTERRUPTIBLE;	if (!file->f_op->select(file->f_inode, file, SEL_IN, &wait_table)	 && !file->f_op->select(file->f_inode, file, SEL_IN, NULL)) {		schedule();		remove_wait_queue(entry.wait_address, &entry.wait);		current->state = TASK_RUNNING;		if (current->signal & ~current->blocked)			return -ERESTARTSYS;		if (current->timeout == 0)			return -ETIMEDOUT;	} else if (wait_table.nr)		remove_wait_queue(entry.wait_address, &entry.wait);	current->state = TASK_RUNNING;	dprintk("RPC: ...Okay, there appears to be some data.\n");	return 0;}/* * Reserve an RPC call slot. nocwait determines whether we wait in case * of congestion or not. */intrpc_reserve(struct rpc_sock *rsock, struct rpc_ioreq *req, int nocwait){	struct rpc_wait	*slot;	req->rq_slot = NULL;	while (!(slot = rsock->free) || rsock->cong >= rsock->cwnd) {		if (nocwait) {			current->timeout = 0;			return -ENOBUFS;		}		dprintk("RPC: rpc_reserve waiting on backlog\n");		interruptible_sleep_on(&rsock->backlog);		if (current->timeout == 0)			return -ETIMEDOUT;		if (current->signal & ~current->blocked)			return -ERESTARTSYS;		if (rsock->shutdown)			return -EIO;	}	rsock->free = slot->w_next;	rsock->cong += RPC_CWNDSCALE;	/* bump congestion value */	slot->w_queued = 0;	slot->w_gotit = 0;	slot->w_req = req;	dprintk("RPC: reserved slot %p\n", slot);	req->rq_slot = slot;	return 0;}/* * Release an RPC call slot */voidrpc_release(struct rpc_sock *rsock, struct rpc_ioreq *req){	struct rpc_wait	*slot = req->rq_slot;	if (slot != NULL) {		dprintk("RPC: release slot %p\n", slot);		/* Wake up the next receiver */		if (slot == rsock->pending && slot->w_next != NULL)			wake_up(&slot->w_next->w_wait);		/* remove slot from queue of pending */		if (slot->w_queued)			rpc_remque(rsock, slot);		slot->w_next = rsock->free;		rsock->free = slot;		/* decrease congestion value */		rsock->cong -= RPC_CWNDSCALE;		if (rsock->cong < rsock->cwnd && rsock->backlog)			wake_up(&rsock->backlog);		if (rsock->shutdown)			wake_up(&rsock->shutwait);		req->rq_slot = NULL;	}}/* * Adjust RPC congestion window */static voidrpc_cwnd_adjust(struct rpc_sock *rsock, int timeout){	unsigned long	cwnd = rsock->cwnd;	if (!timeout) {		if (rsock->cong >= cwnd) {			/* The (cwnd >> 1) term makes sure			 * the result gets rounded properly. */			cwnd += (RPC_CWNDSCALE * RPC_CWNDSCALE +					(cwnd >> 1)) / cwnd;			if (cwnd > RPC_MAXCWND)				cwnd = RPC_MAXCWND;		}	} else {		if ((cwnd >>= 1) < RPC_CWNDSCALE)			cwnd = RPC_CWNDSCALE;		dprintk("RPC: cwnd decrease %08lx\n", cwnd);	}	dprintk("RPC: cong %08lx, cwnd was %08lx, now %08lx\n",			rsock->cong, rsock->cwnd, cwnd);	rsock->cwnd = cwnd;}static inline voidrpc_send_check(char *where, u32 *ptr){	if (ptr[1] != htonl(RPC_CALL) || ptr[2] != htonl(RPC_VERSION)) {		printk("RPC: %s sending evil packet:\n"		       "     %08x %08x %08x %08x %08x %08x %08x %08x\n",		       where,		       ptr[0], ptr[1], ptr[2], ptr[3],		       ptr[4], ptr[5], ptr[6], ptr[7]);	}}/* * Place the actual RPC call. * We have to copy the iovec because sendmsg fiddles with its contents. */static inline intrpc_send(struct rpc_sock *rsock, struct rpc_wait *slot){	struct rpc_ioreq *req = slot->w_req;	struct iovec	iov[UIO_MAXIOV];	if (rsock->shutdown)		return -EIO;	memcpy(iov, req->rq_svec, req->rq_snr * sizeof(iov[0]));	slot->w_xid = *(u32 *)(iov[0].iov_base);	if (!slot->w_queued)		rpc_insque(rsock, slot);	dprintk("rpc_send(%p, %x)\n", slot, slot->w_xid);	rpc_send_check("rpc_send", (u32 *) req->rq_svec[0].iov_base);	return rpc_sendmsg(rsock, iov, req->rq_snr, req->rq_slen,				req->rq_addr, req->rq_alen);}/* * This is the same as rpc_send but for the functions exported to nfsiod */intrpc_transmit(struct rpc_sock *rsock, struct rpc_ioreq *req){	rpc_send_check("rpc_transmit", (u32 *) req->rq_svec[0].iov_base);	return rpc_send(rsock, req->rq_slot);}/* * Receive and dispatch a single reply */static inline intrpc_grok(struct rpc_sock *rsock){	struct rpc_wait	*rovr;	struct rpc_ioreq *req;	struct iovec	iov[UIO_MAXIOV];	u32		xid;	int		safe, result;	iov[0].iov_base = (void *) &xid;	iov[0].iov_len  = sizeof(xid);	result = rpc_recvmsg(rsock, iov, 1, sizeof(xid), MSG_PEEK);	if (result < 0) {		switch (-result) {		case EAGAIN: case ECONNREFUSED:			return 0;		case ERESTARTSYS:			return result;		default:			dprintk("rpc_grok: recv error = %d\n", result);		}	}	if (result < 4) {		printk(KERN_WARNING "RPC: impossible RPC reply size %d\n",						result);		iov[0].iov_base=(void*)&xid;	/* xid=32bits, which is large enough */		iov[0].iov_len=result;		rpc_recvmsg(rsock, iov, 1, result, 0);		return 0;	}	dprintk("RPC: rpc_grok: got xid %08lx\n", (unsigned long) xid);	/* Look for the caller */	safe = 0;	for (rovr = rsock->pending; rovr; rovr = rovr->w_next) {		if (rovr->w_xid == xid)			break;		if (safe++ > RPC_MAXREQS) {			printk(KERN_WARNING "RPC: loop in request Q!!\n");			rovr = NULL;			break;		}	}	if (!rovr || rovr->w_gotit) {		/* discard dgram */		dprintk("RPC: rpc_grok: %s.\n",			rovr? "duplicate reply" : "bad XID");		iov[0].iov_base = (void *) &xid;		iov[0].iov_len  = sizeof(xid);		rpc_recvmsg(rsock, iov, 1, sizeof(xid), 0);		return 0;	}	req = rovr->w_req;	/* Now receive the reply... Copy the iovec first because of 	 * memcpy_fromiovec fiddling. */	memcpy(iov, req->rq_rvec, req->rq_rnr * sizeof(iov[0]));	result = rpc_recvmsg(rsock, iov, req->rq_rnr, req->rq_rlen, 0);	rovr->w_result = result;	rovr->w_gotit = 1;	/* ... and wake up the process */	wake_up(&rovr->w_wait);	return result;}/* * Wait for the reply to our call. */static intrpc_recv(struct rpc_sock *rsock, struct rpc_wait *slot){	int	result;	do {		/* If we are not the receiver, wait on the sidelines */		dprintk("RPC: rpc_recv TP1\n");		while (rsock->pending != slot) {			if (!slot->w_gotit)				interruptible_sleep_on(&slot->w_wait);			if (slot->w_gotit)				return slot->w_result; /* quite important */			if (current->signal & ~current->blocked)				return -ERESTARTSYS;			if (rsock->shutdown)				return -EIO;			if (current->timeout == 0)				return -ETIMEDOUT;		}		/* Wait for data to arrive */		if ((result = rpc_select(rsock)) < 0) {			dprintk("RPC: select error = %d\n", result);			return result;		}		/* Receive and dispatch */		if ((result = rpc_grok(rsock)) < 0)			return result;	} while (current->timeout && !slot->w_gotit);	return slot->w_gotit? slot->w_result : -ETIMEDOUT;}/* * Generic RPC call routine. This handles retries and timeouts etc pp. * * If sent is non-null, it assumes the called has already sent out the * message, so it won't need to do so unless a timeout occurs. */intrpc_doio(struct rpc_sock *rsock, struct rpc_ioreq *req,			struct rpc_timeout *strategy, int sent){	struct rpc_wait	*slot;	int		result, retries;	unsigned long	timeout;	timeout = strategy->to_initval;	retries = 0;	slot = req->rq_slot;	do {		dprintk("RPC: rpc_doio: TP1 (req %p)\n", req);		current->timeout = jiffies + timeout;		if (slot == NULL) {			result = rpc_reserve(rsock, req, 0);			if (result == -ETIMEDOUT)				goto timedout;			if (result < 0)				break;			slot = req->rq_slot;			rpc_send_check("rpc_doio",				(u32 *) req->rq_svec[0].iov_base);			rpc_insque(rsock, slot);		}		/* This check is for loopback NFS. Sometimes replies come		 * in before biod has called rpc_doio... */		if (slot->w_gotit) {			result = slot->w_result;			break;		}		dprintk("RPC: rpc_doio: TP2\n");		if (sent || (result = rpc_send(rsock, slot)) >= 0) {			result = rpc_recv(rsock, slot);			sent = 0;		}		if (result != -ETIMEDOUT) {			/* dprintk("RPC: rpc_recv returned %d\n", result); */			rpc_cwnd_adjust(rsock, 0);			break;		}		rpc_cwnd_adjust(rsock, 1);timedout:		dprintk("RPC: rpc_recv returned timeout.\n");		if (strategy->to_exponential)			timeout <<= 1;		else			timeout += strategy->to_increment;		if (strategy->to_maxval && timeout >= strategy->to_maxval)			timeout = strategy->to_maxval;		if (strategy->to_retries && ++retries >= strategy->to_retries)			break;	} while (1);	dprintk("RPC: rpc_doio: TP3\n");	current->timeout = 0;	return result;}/* */intrpc_call(struct rpc_sock *rsock, struct rpc_ioreq *req,			struct rpc_timeout *strategy){	int	result;	result = rpc_doio(rsock, req, strategy, 0);	if (req->rq_slot == NULL)		printk(KERN_WARNING "RPC: bad: rq_slot == NULL\n");	rpc_release(rsock, req);	return result;}struct rpc_sock *rpc_makesock(struct file *file){	struct rpc_sock	*rsock;	struct socket	*sock;	struct sock	*sk;	struct rpc_wait	*slot;	int		i;	dprintk("RPC: make RPC socket...\n");	sock = &file->f_inode->u.socket_i;	if (sock->type != SOCK_DGRAM || sock->ops->family != AF_INET) {		printk(KERN_WARNING "RPC: only UDP sockets supported\n");		return NULL;	}	sk = (struct sock *) sock->data;	if ((rsock = kmalloc(sizeof(struct rpc_sock), GFP_KERNEL)) == NULL)		return NULL;	memset(rsock, 0, sizeof(*rsock)); /* Nnnngh! */	rsock->sock = sock;	rsock->inet = sk;	rsock->file = file;	rsock->cwnd = RPC_INITCWND;	dprintk("RPC: slots %p, %p, ...\n", rsock->waiting, rsock->waiting + 1);	rsock->free = rsock->waiting;	for (i = 0, slot = rsock->waiting; i < RPC_MAXREQS-1; i++, slot++)		slot->w_next = slot + 1;	slot->w_next = NULL;	dprintk("RPC: made socket %p\n", rsock);	return rsock;}intrpc_closesock(struct rpc_sock *rsock){	unsigned long	t0 = jiffies;	rsock->shutdown = 1;	while (rsock->pending || waitqueue_active(&rsock->backlog)) {		interruptible_sleep_on(&rsock->shutwait);		if (current->signal & ~current->blocked)			return -EINTR;#if 1		if (t0 && t0 - jiffies > 60 * HZ) {			printk(KERN_WARNING "RPC: hanging in rpc_closesock.\n");			t0 = 0;		}#endif	}	kfree(rsock);	return 0;}

⌨️ 快捷键说明

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