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

📄 svcsock.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * linux/net/sunrpc/svcsock.c * * These are the RPC server socket internals. * * The server scheduling algorithm does not always distribute the load * evenly when servicing a single client. May need to modify the * svc_sock_enqueue procedure... * * TCP support is largely untested and may be a little slow. The problem * is that we currently do two separate recvfrom's, one for the 4-byte * record length, and the second for the actual record. This could possibly * be improved by always reading a minimum size of around 100 bytes and * tucking any superfluous bytes away in a temporary store. Still, that * leaves write requests out in the rain. An alternative may be to peek at * the first skb in the queue, and if it matches the next TCP sequence * number, to extract the record marker. Yuck. * * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */#include <linux/sched.h>#include <linux/errno.h>#include <linux/fcntl.h>#include <linux/net.h>#include <linux/in.h>#include <linux/inet.h>#include <linux/udp.h>#include <linux/tcp.h>#include <linux/unistd.h>#include <linux/slab.h>#include <linux/netdevice.h>#include <linux/skbuff.h>#include <linux/suspend.h>#include <net/sock.h>#include <net/checksum.h>#include <net/ip.h>#include <net/tcp.h>#include <asm/uaccess.h>#include <asm/ioctls.h>#include <linux/sunrpc/types.h>#include <linux/sunrpc/xdr.h>#include <linux/sunrpc/svcsock.h>#include <linux/sunrpc/stats.h>/* SMP locking strategy: * * 	svc_serv->sv_lock protects most stuff for that service. * *	Some flags can be set to certain values at any time *	providing that certain rules are followed: * *	SK_BUSY  can be set to 0 at any time.   *		svc_sock_enqueue must be called afterwards *	SK_CONN, SK_DATA, can be set or cleared at any time. *		after a set, svc_sock_enqueue must be called.	 *		after a clear, the socket must be read/accepted *		 if this succeeds, it must be set again. *	SK_CLOSE can set at any time. It is never cleared. * */#define RPCDBG_FACILITY	RPCDBG_SVCSOCKstatic struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *,					 int *errp, int pmap_reg);static void		svc_udp_data_ready(struct sock *, int);static int		svc_udp_recvfrom(struct svc_rqst *);static int		svc_udp_sendto(struct svc_rqst *);static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk);static int svc_deferred_recv(struct svc_rqst *rqstp);static struct cache_deferred_req *svc_defer(struct cache_req *req);/* * Queue up an idle server thread.  Must have serv->sv_lock held. * Note: this is really a stack rather than a queue, so that we only * use as many different threads as we need, and the rest don't polute * the cache. */static inline voidsvc_serv_enqueue(struct svc_serv *serv, struct svc_rqst *rqstp){	list_add(&rqstp->rq_list, &serv->sv_threads);}/* * Dequeue an nfsd thread.  Must have serv->sv_lock held. */static inline voidsvc_serv_dequeue(struct svc_serv *serv, struct svc_rqst *rqstp){	list_del(&rqstp->rq_list);}/* * Release an skbuff after use */static inline voidsvc_release_skb(struct svc_rqst *rqstp){	struct sk_buff *skb = rqstp->rq_skbuff;	struct svc_deferred_req *dr = rqstp->rq_deferred;	if (skb) {		rqstp->rq_skbuff = NULL;		dprintk("svc: service %p, releasing skb %p\n", rqstp, skb);		skb_free_datagram(rqstp->rq_sock->sk_sk, skb);	}	if (dr) {		rqstp->rq_deferred = NULL;		kfree(dr);	}}/* * Any space to write? */static inline unsigned longsvc_sock_wspace(struct svc_sock *svsk){	int wspace;	if (svsk->sk_sock->type == SOCK_STREAM)		wspace = sk_stream_wspace(svsk->sk_sk);	else		wspace = sock_wspace(svsk->sk_sk);	return wspace;}/* * Queue up a socket with data pending. If there are idle nfsd * processes, wake 'em up. * */static voidsvc_sock_enqueue(struct svc_sock *svsk){	struct svc_serv	*serv = svsk->sk_server;	struct svc_rqst	*rqstp;	if (!(svsk->sk_flags &	      ( (1<<SK_CONN)|(1<<SK_DATA)|(1<<SK_CLOSE)|(1<<SK_DEFERRED)) ))		return;	if (test_bit(SK_DEAD, &svsk->sk_flags))		return;	spin_lock_bh(&serv->sv_lock);	if (!list_empty(&serv->sv_threads) && 	    !list_empty(&serv->sv_sockets))		printk(KERN_ERR			"svc_sock_enqueue: threads and sockets both waiting??\n");	if (test_bit(SK_DEAD, &svsk->sk_flags)) {		/* Don't enqueue dead sockets */		dprintk("svc: socket %p is dead, not enqueued\n", svsk->sk_sk);		goto out_unlock;	}	if (test_bit(SK_BUSY, &svsk->sk_flags)) {		/* Don't enqueue socket while daemon is receiving */		dprintk("svc: socket %p busy, not enqueued\n", svsk->sk_sk);		goto out_unlock;	}	set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);	if (((svsk->sk_reserved + serv->sv_bufsz)*2	     > svc_sock_wspace(svsk))	    && !test_bit(SK_CLOSE, &svsk->sk_flags)	    && !test_bit(SK_CONN, &svsk->sk_flags)) {		/* Don't enqueue while not enough space for reply */		dprintk("svc: socket %p  no space, %d*2 > %ld, not enqueued\n",			svsk->sk_sk, svsk->sk_reserved+serv->sv_bufsz,			svc_sock_wspace(svsk));		goto out_unlock;	}	clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);	/* Mark socket as busy. It will remain in this state until the	 * server has processed all pending data and put the socket back	 * on the idle list.	 */	set_bit(SK_BUSY, &svsk->sk_flags);	if (!list_empty(&serv->sv_threads)) {		rqstp = list_entry(serv->sv_threads.next,				   struct svc_rqst,				   rq_list);		dprintk("svc: socket %p served by daemon %p\n",			svsk->sk_sk, rqstp);		svc_serv_dequeue(serv, rqstp);		if (rqstp->rq_sock)			printk(KERN_ERR 				"svc_sock_enqueue: server %p, rq_sock=%p!\n",				rqstp, rqstp->rq_sock);		rqstp->rq_sock = svsk;		svsk->sk_inuse++;		rqstp->rq_reserved = serv->sv_bufsz;		svsk->sk_reserved += rqstp->rq_reserved;		wake_up(&rqstp->rq_wait);	} else {		dprintk("svc: socket %p put into queue\n", svsk->sk_sk);		list_add_tail(&svsk->sk_ready, &serv->sv_sockets);	}out_unlock:	spin_unlock_bh(&serv->sv_lock);}/* * Dequeue the first socket.  Must be called with the serv->sv_lock held. */static inline struct svc_sock *svc_sock_dequeue(struct svc_serv *serv){	struct svc_sock	*svsk;	if (list_empty(&serv->sv_sockets))		return NULL;	svsk = list_entry(serv->sv_sockets.next,			  struct svc_sock, sk_ready);	list_del_init(&svsk->sk_ready);	dprintk("svc: socket %p dequeued, inuse=%d\n",		svsk->sk_sk, svsk->sk_inuse);	return svsk;}/* * Having read something from a socket, check whether it * needs to be re-enqueued. * Note: SK_DATA only gets cleared when a read-attempt finds * no (or insufficient) data. */static inline voidsvc_sock_received(struct svc_sock *svsk){	clear_bit(SK_BUSY, &svsk->sk_flags);	svc_sock_enqueue(svsk);}/** * svc_reserve - change the space reserved for the reply to a request. * @rqstp:  The request in question * @space: new max space to reserve * * Each request reserves some space on the output queue of the socket * to make sure the reply fits.  This function reduces that reserved * space to be the amount of space used already, plus @space. * */void svc_reserve(struct svc_rqst *rqstp, int space){	space += rqstp->rq_res.head[0].iov_len;	if (space < rqstp->rq_reserved) {		struct svc_sock *svsk = rqstp->rq_sock;		spin_lock_bh(&svsk->sk_server->sv_lock);		svsk->sk_reserved -= (rqstp->rq_reserved - space);		rqstp->rq_reserved = space;		spin_unlock_bh(&svsk->sk_server->sv_lock);		svc_sock_enqueue(svsk);	}}/* * Release a socket after use. */static inline voidsvc_sock_put(struct svc_sock *svsk){	struct svc_serv *serv = svsk->sk_server;	spin_lock_bh(&serv->sv_lock);	if (!--(svsk->sk_inuse) && test_bit(SK_DEAD, &svsk->sk_flags)) {		spin_unlock_bh(&serv->sv_lock);		dprintk("svc: releasing dead socket\n");		sock_release(svsk->sk_sock);		kfree(svsk);	}	else		spin_unlock_bh(&serv->sv_lock);}static voidsvc_sock_release(struct svc_rqst *rqstp){	struct svc_sock	*svsk = rqstp->rq_sock;	svc_release_skb(rqstp);	svc_free_allpages(rqstp);	rqstp->rq_res.page_len = 0;	rqstp->rq_res.page_base = 0;	/* Reset response buffer and release	 * the reservation.	 * But first, check that enough space was reserved	 * for the reply, otherwise we have a bug!	 */	if ((rqstp->rq_res.len) >  rqstp->rq_reserved)		printk(KERN_ERR "RPC request reserved %d but used %d\n",		       rqstp->rq_reserved,		       rqstp->rq_res.len);	rqstp->rq_res.head[0].iov_len = 0;	svc_reserve(rqstp, 0);	rqstp->rq_sock = NULL;	svc_sock_put(svsk);}/* * External function to wake up a server waiting for data */voidsvc_wake_up(struct svc_serv *serv){	struct svc_rqst	*rqstp;	spin_lock_bh(&serv->sv_lock);	if (!list_empty(&serv->sv_threads)) {		rqstp = list_entry(serv->sv_threads.next,				   struct svc_rqst,				   rq_list);		dprintk("svc: daemon %p woken up.\n", rqstp);		/*		svc_serv_dequeue(serv, rqstp);		rqstp->rq_sock = NULL;		 */		wake_up(&rqstp->rq_wait);	}	spin_unlock_bh(&serv->sv_lock);}/* * Generic sendto routine */static intsvc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr){	struct svc_sock	*svsk = rqstp->rq_sock;	struct socket	*sock = svsk->sk_sock;	int		slen;	char 		buffer[CMSG_SPACE(sizeof(struct in_pktinfo))];	struct cmsghdr *cmh = (struct cmsghdr *)buffer;	struct in_pktinfo *pki = (struct in_pktinfo *)CMSG_DATA(cmh);	int		len = 0;	int		result;	int		size;	struct page	**ppage = xdr->pages;	size_t		base = xdr->page_base;	unsigned int	pglen = xdr->page_len;	unsigned int	flags = MSG_MORE;	slen = xdr->len;	if (rqstp->rq_prot == IPPROTO_UDP) {		/* set the source and destination */		struct msghdr	msg;		msg.msg_name    = &rqstp->rq_addr;		msg.msg_namelen = sizeof(rqstp->rq_addr);		msg.msg_iov     = NULL;		msg.msg_iovlen  = 0;		msg.msg_flags	= MSG_MORE;		msg.msg_control = cmh;		msg.msg_controllen = sizeof(buffer);		cmh->cmsg_len = CMSG_LEN(sizeof(*pki));		cmh->cmsg_level = SOL_IP;		cmh->cmsg_type = IP_PKTINFO;		pki->ipi_ifindex = 0;		pki->ipi_spec_dst.s_addr = rqstp->rq_daddr;		if (sock_sendmsg(sock, &msg, 0) < 0)			goto out;	}	/* send head */	if (slen == xdr->head[0].iov_len)		flags = 0;	len = sock->ops->sendpage(sock, rqstp->rq_respages[0], 0, xdr->head[0].iov_len, flags);	if (len != xdr->head[0].iov_len)		goto out;	slen -= xdr->head[0].iov_len;	if (slen == 0)		goto out;	/* send page data */	size = PAGE_SIZE - base < pglen ? PAGE_SIZE - base : pglen;	while (pglen > 0) {		if (slen == size)			flags = 0;		result = sock->ops->sendpage(sock, *ppage, base, size, flags);		if (result > 0)			len += result;		if (result != size)			goto out;		slen -= size;		pglen -= size;		size = PAGE_SIZE < pglen ? PAGE_SIZE : pglen;		base = 0;		ppage++;	}	/* send tail */	if (xdr->tail[0].iov_len) {		result = sock->ops->sendpage(sock, rqstp->rq_respages[rqstp->rq_restailpage], 					     ((unsigned long)xdr->tail[0].iov_base)& (PAGE_SIZE-1),					     xdr->tail[0].iov_len, 0);		if (result > 0)			len += result;	}out:	dprintk("svc: socket %p sendto([%p %Zu... ], %d) = %d (addr %x)\n",			rqstp->rq_sock, xdr->head[0].iov_base, xdr->head[0].iov_len, xdr->len, len,		rqstp->rq_addr.sin_addr.s_addr);	return len;}/* * Check input queue length */static intsvc_recv_available(struct svc_sock *svsk){	mm_segment_t	oldfs;	struct socket	*sock = svsk->sk_sock;	int		avail, err;	oldfs = get_fs(); set_fs(KERNEL_DS);	err = sock->ops->ioctl(sock, TIOCINQ, (unsigned long) &avail);	set_fs(oldfs);	return (err >= 0)? avail : err;}/* * Generic recvfrom routine. */static intsvc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr, int buflen){	struct msghdr	msg;	struct socket	*sock;	int		len, alen;	rqstp->rq_addrlen = sizeof(rqstp->rq_addr);	sock = rqstp->rq_sock->sk_sock;	msg.msg_name    = &rqstp->rq_addr;	msg.msg_namelen = sizeof(rqstp->rq_addr);	msg.msg_control = NULL;	msg.msg_controllen = 0;	msg.msg_flags	= MSG_DONTWAIT;	len = kernel_recvmsg(sock, &msg, iov, nr, buflen, MSG_DONTWAIT);	/* sock_recvmsg doesn't fill in the name/namelen, so we must..	 * possibly we should cache this in the svc_sock structure	 * at accept time. FIXME	 */	alen = sizeof(rqstp->rq_addr);	sock->ops->getname(sock, (struct sockaddr *)&rqstp->rq_addr, &alen, 1);	dprintk("svc: socket %p recvfrom(%p, %Zu) = %d\n",		rqstp->rq_sock, iov[0].iov_base, iov[0].iov_len, len);	return len;}/* * Set socket snd and rcv buffer lengths */static inline voidsvc_sock_setbufsize(struct socket *sock, unsigned int snd, unsigned int rcv){#if 0	mm_segment_t	oldfs;	oldfs = get_fs(); set_fs(KERNEL_DS);	sock_setsockopt(sock, SOL_SOCKET, SO_SNDBUF,			(char*)&snd, sizeof(snd));	sock_setsockopt(sock, SOL_SOCKET, SO_RCVBUF,			(char*)&rcv, sizeof(rcv));#else	/* sock_setsockopt limits use to sysctl_?mem_max,	 * which isn't acceptable.  Until that is made conditional	 * on not having CAP_SYS_RESOURCE or similar, we go direct...	 * DaveM said I could!	 */	lock_sock(sock->sk);	sock->sk->sk_sndbuf = snd * 2;	sock->sk->sk_rcvbuf = rcv * 2;	sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK;	release_sock(sock->sk);#endif}/* * INET callback when data has been received on the socket. */static voidsvc_udp_data_ready(struct sock *sk, int count){	struct svc_sock	*svsk = (struct svc_sock *)(sk->sk_user_data);	if (!svsk)		goto out;	dprintk("svc: socket %p(inet %p), count=%d, busy=%d\n",		svsk, sk, count, test_bit(SK_BUSY, &svsk->sk_flags));	set_bit(SK_DATA, &svsk->sk_flags);	svc_sock_enqueue(svsk); out:	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))		wake_up_interruptible(sk->sk_sleep);}/*

⌨️ 快捷键说明

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