Re: [patch] fix statd -n

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, Apr 20, 2008 at 8:02 PM, J. Bruce Fields <bfields@xxxxxxxxxxxx> wrote:

>  > >  Right, that's what would make the most sense to me.  Janne, is there any
>  > >  reason that wouldn't solve your problem?
>  >
>  > I didn't get the idea. So the idea is to use multiple sockets,
>  > one bound to LOOPBACK and one to external interface?
>
>  I suppose so.  One socket would be for communication for the local
>  kernel nfsd, one for communication with statd peers.

Finally got around to it again. Attached patch takes a
shot at the two socket approach. Patch is a draft to
see what you guys would really think about this
approach.


-- 
// Janne
diff -Naurp nfs-utils-1.1.2.orig/utils/statd/rmtcall.c nfs-utils-1.1.2/utils/statd/rmtcall.c
--- nfs-utils-1.1.2.orig/utils/statd/rmtcall.c	2008-03-14 11:46:29.000000000 -0400
+++ nfs-utils-1.1.2/utils/statd/rmtcall.c	2008-04-28 16:16:02.000000000 -0400
@@ -54,35 +54,34 @@
 
 static unsigned long	xid = 0;	/* RPC XID counter */
 static int		sockfd = -1;	/* notify socket */
+static int              nlmfd = -1;     /* lockd socket */
 
 /*
- * Initialize callback socket
+ * Initialize callback socket and bind it to addr
  */
 int
-statd_get_socket(void)
+statd_reserve_socket(struct in_addr *addr)
 {
-	struct sockaddr_in	sin;
+	struct sockaddr_in      sin;
 	struct servent *se;
 	int loopcnt = 100;
+	int fd = -1;
 
-	if (sockfd >= 0)
-		return sockfd;
-
-	while (loopcnt-- > 0) {
+	memset(&sin, 0, sizeof(sin));
+	sin.sin_family = AF_INET;
+	memcpy(&sin.sin_addr, addr, sizeof(struct in_addr));
 
-		if (sockfd >= 0) close(sockfd);
+	while (loopcnt-- > 0)
+	{
+		if (fd >= 0)
+			close(fd);
 
-		if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+		if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
 			note(N_CRIT, "Can't create socket: %m");
 			return -1;
 		}
 
-
-		memset(&sin, 0, sizeof(sin));
-		sin.sin_family = AF_INET;
-		sin.sin_addr.s_addr = INADDR_ANY;
-
-		if (bindresvport(sockfd, &sin) < 0) {
+		if (bindresvport(fd, &sin) < 0) {
 			dprintf(N_WARNING,
 				"process_hosts: can't bind to reserved port\n");
 			break;
@@ -92,12 +91,75 @@ statd_get_socket(void)
 			break;
 		/* rather not use that port, try again */
 	}
-	FD_SET(sockfd, &SVC_FDSET);
-	return sockfd;
+	FD_SET(fd, &SVC_FDSET);
+	return fd;
+}
+
+/*
+ * Check required sockets and init
+ */
+int
+statd_init_sockets(void)
+{
+	struct hostent *hp = 0;
+	struct in_addr addr;
+
+	if (MY_NAME)
+		hp = gethostbyname(MY_NAME);
+
+	if (hp) {
+		memcpy (&addr,hp->h_addr,sizeof(struct in_addr));
+		sockfd = statd_reserve_socket(&addr);
+
+		addr.s_addr = htonl(INADDR_LOOPBACK);
+		nlmfd  = statd_reserve_socket(&addr);
+	} else {
+		addr.s_addr = INADDR_ANY;
+		sockfd = statd_reserve_socket(&addr);
+		nlmfd  = sockfd;
+	}
+	if (sockfd < 0 || nlmfd < 0) {
+		close(sockfd);
+		close(nlmfd);
+		sockfd = 0;
+		nlmfd  = 0;
+		return -1;
+	}
+	return 1;
+}
+
+/*
+ *  Get socket to destination. Local communications should
+ *  use specific socket bound to loopback if we're running
+ *  with -n.
+ */
+int
+statd_get_socket(struct in_addr *dest)
+{
+	struct in_addr addr;
+	int res;
+
+	if (!dest)
+		return -1;
+
+	addr.s_addr = ntohl(dest->s_addr);
+
+	if ((nlmfd > 0) && (addr.s_addr == INADDR_LOOPBACK))
+		return nlmfd;
+
+	if ((sockfd > 0) && (addr.s_addr != INADDR_LOOPBACK))
+		return sockfd;
+
+	res = statd_init_sockets();
+	if (res < 0) {
+		note(N_WARNING, "statd_get_socket: could not initilize sockets\n");
+		return -1;
+	}
+	return (addr.s_addr == INADDR_LOOPBACK) ? nlmfd : sockfd;
 }
 
 static unsigned long
-xmit_call(int sockfd, struct sockaddr_in *sin,
+xmit_call(int fd, struct sockaddr_in *sin,
 	  u_int32_t prog, u_int32_t vers, u_int32_t proc,
 	  xdrproc_t func, void *obj)
 /* 		__u32 prog, __u32 vers, __u32 proc, xdrproc_t func, void *obj) */
@@ -150,7 +212,7 @@ xmit_call(int sockfd, struct sockaddr_in
 	/* Get overall length of datagram */
 	msglen = xdr_getpos(xdrs);
 
-	if ((err = sendto(sockfd, msgbuf, msglen, 0,
+	if ((err = sendto(fd, msgbuf, msglen, 0,
 			(struct sockaddr *) sin, sizeof(*sin))) < 0) {
 		dprintf(N_WARNING, "xmit_mesg: sendto failed: %m");
 	} else if (err != msglen) {
@@ -163,7 +225,7 @@ xmit_call(int sockfd, struct sockaddr_in
 }
 
 static notify_list *
-recv_rply(int sockfd, struct sockaddr_in *sin, u_long *portp)
+recv_rply(int fd, struct sockaddr_in *sin, u_long *portp)
 {
 	unsigned int		msgbuf[MAXMSGSIZE], msglen;
 	struct rpc_msg		mesg;
@@ -172,7 +234,7 @@ recv_rply(int sockfd, struct sockaddr_in
 	socklen_t		alen = sizeof(*sin);
 
 	/* Receive message */
-	if ((msglen = recvfrom(sockfd, msgbuf, sizeof(msgbuf), 0,
+	if ((msglen = recvfrom(fd, msgbuf, sizeof(msgbuf), 0,
 			(struct sockaddr *) sin, &alen)) < 0) {
 		dprintf(N_WARNING, "recv_rply: recvfrom failed: %m");
 		return NULL;
@@ -239,7 +301,7 @@ done:
  * Notify operation for a single list entry
  */
 static int
-process_entry(int sockfd, notify_list *lp)
+process_entry(int fd, notify_list *lp)
 {
 	struct sockaddr_in	sin;
 	struct status		new_status;
@@ -273,7 +335,7 @@ process_entry(int sockfd, notify_list *l
 	new_status.state    = NL_STATE(lp);
 	memcpy(new_status.priv, NL_PRIV(lp), SM_PRIV_SIZE);
 
-	lp->xid = xmit_call(sockfd, &sin, prog, vers, proc, func, objp);
+	lp->xid = xmit_call(fd, &sin, prog, vers, proc, func, objp);
 	if (!lp->xid) {
 		note(N_WARNING, "notify_host: failed to notify port %d\n",
 				ntohs(lp->port));
@@ -283,26 +345,20 @@ process_entry(int sockfd, notify_list *l
 	return 1;
 }
 
-/*
- * Process a datagram received on the notify socket
- */
 int
-process_reply(FD_SET_TYPE *rfds)
+process_sock(int fd)
 {
-	struct sockaddr_in	sin;
-	notify_list		*lp;
-	u_long			port;
+	struct sockaddr_in      sin;
+	notify_list             *lp;
+	u_long                  port;
 
-	if (sockfd == -1 || !FD_ISSET(sockfd, rfds))
-		return 0;
-
-	if (!(lp = recv_rply(sockfd, &sin, &port)))
+	if (!(lp = recv_rply(fd, &sin, &port)))
 		return 1;
 
 	if (lp->port == 0) {
 		if (port != 0) {
 			lp->port = htons((unsigned short) port);
-			process_entry(sockfd, lp);
+			process_entry(fd, lp);
 			NL_WHEN(lp) = time(NULL) + NOTIFY_TIMEOUT;
 			nlist_remove(&notify, lp);
 			nlist_insert_timer(&notify, lp);
@@ -319,6 +375,23 @@ process_reply(FD_SET_TYPE *rfds)
 }
 
 /*
+ * Process a datagram received on the notify socket
+ */
+int
+process_reply(FD_SET_TYPE *rfds)
+{
+	int ret1 = 0, ret2 = 0;
+
+	if (FD_ISSET(sockfd,rfds)) {
+		ret1 = process_sock(sockfd);
+	}
+	if ((nlmfd != sockfd) && (FD_ISSET(nlmfd,rfds))) {
+		ret2 = process_sock(nlmfd);
+	}
+	return ret1+ret2;
+}
+
+/*
  * Process a notify list, either for notifying remote hosts after reboot
  * or for calling back (local) statd clients when the remote has notified
  * us of a crash. 
@@ -330,10 +403,9 @@ process_notify_list(void)
 	time_t		now;
 	int		fd;
 
-	if ((fd = statd_get_socket()) < 0)
-		return 0;
-
 	while ((entry = notify) != NULL && NL_WHEN(entry) < time(&now)) {
+		fd = statd_get_socket(&entry->addr);
+
 		if (process_entry(fd, entry)) {
 			NL_WHEN(entry) = time(NULL) + NOTIFY_TIMEOUT;
 			nlist_remove(&notify, entry);
diff -Naurp nfs-utils-1.1.2.orig/utils/statd/statd.c nfs-utils-1.1.2/utils/statd/statd.c
--- nfs-utils-1.1.2.orig/utils/statd/statd.c	2008-03-14 11:46:29.000000000 -0400
+++ nfs-utils-1.1.2/utils/statd/statd.c	2008-04-28 14:47:15.000000000 -0400
@@ -75,7 +75,7 @@ static struct option longopts[] =
 };
 
 extern void sm_prog_1 (struct svc_req *, register SVCXPRT *);
-extern int statd_get_socket(void);
+extern int  statd_init_sockets(void);
 static void load_state_number(void);
 
 #ifdef SIMULATIONS
@@ -477,7 +477,7 @@ int main (int argc, char **argv)
 		}
 
 	/* Make sure we have a privilege port for calling into the kernel */
-	statd_get_socket();
+	statd_init_sockets();
 
 	/* If sm-notify didn't take all the state files, load
 	 * state information into our notify-list so we can

[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux