diff options
author | dfr <dfr@FreeBSD.org> | 2008-06-26 10:21:54 +0000 |
---|---|---|
committer | dfr <dfr@FreeBSD.org> | 2008-06-26 10:21:54 +0000 |
commit | 41cea6d5ca71b8cf057f9face8055b218b30e18e (patch) | |
tree | 994a214037913bc4e44eaee5070c65aeadf53485 /usr.sbin | |
parent | ca3c788812715a263f83dcec4bdabaf6c10eb922 (diff) | |
download | FreeBSD-src-41cea6d5ca71b8cf057f9face8055b218b30e18e.zip FreeBSD-src-41cea6d5ca71b8cf057f9face8055b218b30e18e.tar.gz |
Re-implement the client side of rpc.lockd in the kernel. This implementation
provides the correct semantics for flock(2) style locks which are used by the
lockf(1) command line tool and the pidfile(3) library. It also implements
recovery from server restarts and ensures that dirty cache blocks are written
to the server before obtaining locks (allowing multiple clients to use file
locking to safely share data).
Sponsored by: Isilon Systems
PR: 94256
MFC after: 2 weeks
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/rpc.lockd/lockd.c | 107 | ||||
-rw-r--r-- | usr.sbin/rpc.statd/file.c | 30 |
2 files changed, 92 insertions, 45 deletions
diff --git a/usr.sbin/rpc.lockd/lockd.c b/usr.sbin/rpc.lockd/lockd.c index f2fedce..c111b58 100644 --- a/usr.sbin/rpc.lockd/lockd.c +++ b/usr.sbin/rpc.lockd/lockd.c @@ -80,6 +80,7 @@ int _rpcsvcdirty = 0; int grace_expired; int nsm_state; int kernel_lockd; +int kernel_lockd_client; pid_t client_pid; struct mon mon_host; char **hosts, *svcport_str = NULL; @@ -175,6 +176,7 @@ main(int argc, char **argv) } kernel_lockd = FALSE; + kernel_lockd_client = FALSE; if (modfind("nfslockd") < 0) { if (kldload("nfslockd") < 0) { fprintf(stderr, "Can't find or load kernel support for rpc.lockd - using non-kernel implementation\n"); @@ -184,6 +186,10 @@ main(int argc, char **argv) } else { kernel_lockd = TRUE; } + if (kernel_lockd) { + if (getosreldate() >= 800040) + kernel_lockd_client = TRUE; + } (void)rpcb_unset(NLM_PROG, NLM_SM, NULL); (void)rpcb_unset(NLM_PROG, NLM_VERS, NULL); @@ -245,41 +251,42 @@ main(int argc, char **argv) } if (kernel_lockd) { - /* - * For the kernel lockd case, we run a cut-down RPC - * service on a local-domain socket. The kernel's RPC - * server will pass what it can't handle (mainly - * client replies) down to us. This can go away - * entirely if/when we move the client side of NFS - * locking into the kernel. - */ - struct sockaddr_un sun; - int fd, oldmask; - SVCXPRT *xprt; - - memset(&sun, 0, sizeof sun); - sun.sun_family = AF_LOCAL; - unlink(_PATH_RPCLOCKDSOCK); - strcpy(sun.sun_path, _PATH_RPCLOCKDSOCK); - sun.sun_len = SUN_LEN(&sun); - fd = socket(AF_LOCAL, SOCK_STREAM, 0); - if (!fd) { - err(1, "Can't create local lockd socket"); - } - oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO); - if (bind(fd, (struct sockaddr *) &sun, sun.sun_len) < 0) { - err(1, "Can't bind local lockd socket"); - } - umask(oldmask); - if (listen(fd, SOMAXCONN) < 0) { - err(1, "Can't listen on local lockd socket"); - } - xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE); - if (!xprt) { - err(1, "Can't create transport for local lockd socket"); - } - if (!svc_reg(xprt, NLM_PROG, NLM_VERS4, nlm_prog_4, NULL)) { - err(1, "Can't register service for local lockd socket"); + if (!kernel_lockd_client) { + /* + * For the case where we have a kernel lockd but it + * doesn't provide client locking, we run a cut-down + * RPC service on a local-domain socket. The kernel's + * RPC server will pass what it can't handle (mainly + * client replies) down to us. + */ + struct sockaddr_un sun; + int fd, oldmask; + SVCXPRT *xprt; + + memset(&sun, 0, sizeof sun); + sun.sun_family = AF_LOCAL; + unlink(_PATH_RPCLOCKDSOCK); + strcpy(sun.sun_path, _PATH_RPCLOCKDSOCK); + sun.sun_len = SUN_LEN(&sun); + fd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (!fd) { + err(1, "Can't create local lockd socket"); + } + oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO); + if (bind(fd, (struct sockaddr *) &sun, sun.sun_len) < 0) { + err(1, "Can't bind local lockd socket"); + } + umask(oldmask); + if (listen(fd, SOMAXCONN) < 0) { + err(1, "Can't listen on local lockd socket"); + } + xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE); + if (!xprt) { + err(1, "Can't create transport for local lockd socket"); + } + if (!svc_reg(xprt, NLM_PROG, NLM_VERS4, nlm_prog_4, NULL)) { + err(1, "Can't register service for local lockd socket"); + } } /* @@ -342,17 +349,27 @@ main(int argc, char **argv) } if (kernel_lockd) { - init_nsm(); - client_pid = client_request(); - - /* - * Create a child process to enter the kernel and then - * wait for RPCs on our local domain socket. - */ - if (!fork()) + if (!kernel_lockd_client) { + init_nsm(); + client_pid = client_request(); + + /* + * Create a child process to enter the kernel and then + * wait for RPCs on our local domain socket. + */ + if (!fork()) + nlm_syscall(debug_level, grace_period, + naddrs, addrs); + else + svc_run(); + } else { + /* + * The kernel lockd implementation provides + * both client and server so we don't need to + * do anything else. + */ nlm_syscall(debug_level, grace_period, naddrs, addrs); - else - svc_run(); + } } else { grace_expired = 0; alarm(grace_period); diff --git a/usr.sbin/rpc.statd/file.c b/usr.sbin/rpc.statd/file.c index efcaaaf..0625e30 100644 --- a/usr.sbin/rpc.statd/file.c +++ b/usr.sbin/rpc.statd/file.c @@ -36,6 +36,7 @@ #include <err.h> #include <errno.h> #include <fcntl.h> +#include <netdb.h> #include <stdio.h> #include <string.h> #include <unistd.h> @@ -78,8 +79,11 @@ HostInfo *find_host(char *hostname, int create) HostInfo *hp; HostInfo *spare_slot = NULL; HostInfo *result = NULL; + struct addrinfo *ai1, *ai2; int i; + if (getaddrinfo(hostname, NULL, NULL, &ai1) != 0) + ai1 = NULL; for (i = 0, hp = status_info->hosts; i < status_info->noOfHosts; i++, hp++) { if (!strncasecmp(hostname, hp->hostname, SM_MAXSTRLEN)) @@ -87,9 +91,35 @@ HostInfo *find_host(char *hostname, int create) result = hp; break; } + if (hp->hostname[0] && + getaddrinfo(hp->hostname, NULL, NULL, &ai2) != 0) + ai2 = NULL; + if (ai1 && ai2) + { + struct addrinfo *p1, *p2; + for (p1 = ai1; !result && p1; p1 = p1->ai_next) + { + for (p2 = ai2; !result && p2; p2 = p2->ai_next) + { + if (p1->ai_family == p2->ai_family + && p1->ai_addrlen == p2->ai_addrlen + && !memcmp(p1->ai_addr, p2->ai_addr, p1->ai_addrlen)) + { + result = hp; + break; + } + } + } + if (result) + break; + } + if (ai2) + freeaddrinfo(ai2); if (!spare_slot && !hp->monList && !hp->notifyReqd) spare_slot = hp; } + if (ai1) + freeaddrinfo(ai1); /* Return if entry found, or if not asked to create one. */ if (result || !create) return (result); |