summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoralfred <alfred@FreeBSD.org>2001-04-17 20:45:23 +0000
committeralfred <alfred@FreeBSD.org>2001-04-17 20:45:23 +0000
commitf0669d6c9e71dffa3f4104a202e3e1046c64021c (patch)
tree397489679b0ebce3143827e9a1702a14829f93a7
parent676302e684a39f23d1e6c16f7fea4855deb723a4 (diff)
downloadFreeBSD-src-f0669d6c9e71dffa3f4104a202e3e1046c64021c.zip
FreeBSD-src-f0669d6c9e71dffa3f4104a202e3e1046c64021c.tar.gz
Implement client side NFS locks.
Obtained from: BSD/os Import Ok'd by: mckusick, jkh, motd on builder.freebsd.org
-rw-r--r--include/rpcsvc/nlm_prot.x13
-rw-r--r--sys/conf/files1
-rw-r--r--sys/kern/kern_lockf.c2
-rw-r--r--sys/nfs/nfs.h1
-rw-r--r--sys/nfs/nfs_lock.c269
-rw-r--r--sys/nfs/nfs_lock.h112
-rw-r--r--sys/nfs/nfs_syscalls.c9
-rw-r--r--sys/nfs/nfs_vnops.c9
-rw-r--r--sys/nfs/nlminfo.h45
-rw-r--r--sys/nfsclient/nfs.h1
-rw-r--r--sys/nfsclient/nfs_lock.c269
-rw-r--r--sys/nfsclient/nfs_lock.h112
-rw-r--r--sys/nfsclient/nfs_nfsiod.c9
-rw-r--r--sys/nfsclient/nfs_vnops.c9
-rw-r--r--sys/nfsclient/nfsargs.h1
-rw-r--r--sys/nfsclient/nfsstats.h1
-rw-r--r--sys/nfsclient/nlminfo.h45
-rw-r--r--sys/nfsserver/nfs.h1
-rw-r--r--sys/nfsserver/nfs_syscalls.c9
-rw-r--r--sys/nfsserver/nfsrvstats.h1
-rw-r--r--sys/sys/lockf.h2
-rw-r--r--sys/sys/proc.h3
-rw-r--r--usr.sbin/rpc.lockd/Makefile4
-rw-r--r--usr.sbin/rpc.lockd/kern.c586
-rw-r--r--usr.sbin/rpc.lockd/lock_proc.c25
-rw-r--r--usr.sbin/rpc.lockd/lockd.c55
-rw-r--r--usr.sbin/rpc.lockd/lockd.h3
-rw-r--r--usr.sbin/rpc.lockd/lockd_lock.c8
28 files changed, 1578 insertions, 27 deletions
diff --git a/include/rpcsvc/nlm_prot.x b/include/rpcsvc/nlm_prot.x
index ba0ccf3..1f5722e 100644
--- a/include/rpcsvc/nlm_prot.x
+++ b/include/rpcsvc/nlm_prot.x
@@ -27,7 +27,8 @@ enum nlm_stats {
nlm_denied = 1,
nlm_denied_nolocks = 2,
nlm_blocked = 3,
- nlm_denied_grace_period = 4
+ nlm_denied_grace_period = 4,
+ nlm_deadlck = 5
};
struct nlm_holder {
@@ -147,7 +148,7 @@ struct nlm_notify {
enum nlm4_stats {
nlm4_granted = 0,
nlm4_denied = 1,
- nlm4_denied_nolock = 2,
+ nlm4_denied_nolocks = 2,
nlm4_blocked = 3,
nlm4_denied_grace_period = 4,
nlm4_deadlck = 5,
@@ -253,11 +254,17 @@ struct nlm_sm_status {
opaque priv[16]; /* private data */
};
+struct nlm4_notify {
+ string name<MAXNAMELEN>;
+ int32_t state;
+};
+
/*
* Over-the-wire protocol used between the network lock managers
*/
program NLM_PROG {
+
version NLM_SM {
void NLM_SM_NOTIFY(struct nlm_sm_status) = 1;
} = 0;
@@ -316,6 +323,6 @@ program NLM_PROG {
nlm4_shareres NLM4_SHARE(nlm4_shareargs) = 20;
nlm4_shareres NLM4_UNSHARE(nlm4_shareargs) = 21;
nlm4_res NLM4_NM_LOCK(nlm4_lockargs) = 22;
- void NLM4_FREE_ALL(nlm_notify) = 23;
+ void NLM4_FREE_ALL(nlm4_notify) = 23;
} = 4;
} = 100021;
diff --git a/sys/conf/files b/sys/conf/files
index abc0ef8..3d6e793 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1101,6 +1101,7 @@ nfs/bootp_subr.c optional bootp
nfs/krpc_subr.c optional bootp
nfs/nfs_bio.c optional nfs
nfs/nfs_node.c optional nfs
+nfs/nfs_lock.c optional nfs
nfs/nfs_nqlease.c optional nfs
nfs/nfs_serv.c optional nfs
nfs/nfs_socket.c optional nfs
diff --git a/sys/kern/kern_lockf.c b/sys/kern/kern_lockf.c
index 6c96c9c..8f210b2 100644
--- a/sys/kern/kern_lockf.c
+++ b/sys/kern/kern_lockf.c
@@ -69,7 +69,7 @@ static int lockf_debug = 0;
SYSCTL_INT(_debug, OID_AUTO, lockf_debug, CTLFLAG_RW, &lockf_debug, 0, "");
#endif
-static MALLOC_DEFINE(M_LOCKF, "lockf", "Byte-range locking structures");
+MALLOC_DEFINE(M_LOCKF, "lockf", "Byte-range locking structures");
#define NOLOCKF (struct lockf *)0
#define SELF 0x1
diff --git a/sys/nfs/nfs.h b/sys/nfs/nfs.h
index 259ec20..2b0f664 100644
--- a/sys/nfs/nfs.h
+++ b/sys/nfs/nfs.h
@@ -274,6 +274,7 @@ struct nfsstats {
#define NFSSVC_GOTAUTH 0x040
#define NFSSVC_AUTHINFAIL 0x080
#define NFSSVC_MNTD 0x100
+#define NFSSVC_LOCKDANS 0x200
/*
* fs.nfs sysctl(3) identifiers
diff --git a/sys/nfs/nfs_lock.c b/sys/nfs/nfs_lock.c
new file mode 100644
index 0000000..aaac361
--- /dev/null
+++ b/sys/nfs/nfs_lock.c
@@ -0,0 +1,269 @@
+/*-
+ * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Berkeley Software Design Inc's name may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from BSDI nfs_lock.c,v 2.4 1998/12/14 23:49:56 jch Exp
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/fcntl.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/unistd.h>
+#include <sys/vnode.h>
+#include <sys/resourcevar.h>
+#include <sys/kernel.h> /* for hz */
+#include <sys/lockf.h> /* for hz */
+
+#include <net/if.h>
+
+#include <nfs/rpcv2.h>
+#include <nfs/nfsproto.h>
+#include <nfs/nfs.h>
+#include <nfs/nfsmount.h>
+#include <nfs/nfsnode.h>
+#include <nfs/nfs_lock.h>
+#include <nfs/nlminfo.h>
+
+#define NFSOWNER_1ST_LEVEL_START 1 /* initial entries */
+#define NFSOWNER_2ND_LEVEL 256 /* some power of 2 */
+
+#define NFSOWNER(tbl, i) \
+ (tbl)[(i) / NFSOWNER_2ND_LEVEL][(i) % NFSOWNER_2ND_LEVEL]
+
+/*
+ * XXX
+ * We have to let the process know if the call succeeded. I'm using an extra
+ * field in the p_nlminfo field in the proc structure, as it is already for
+ * lockd stuff.
+ */
+
+/*
+ * nfs_advlock --
+ * NFS advisory byte-level locks.
+ */
+int
+nfs_dolock(ap)
+ struct vop_advlock_args /* {
+ struct vnode *a_vp;
+ caddr_t a_id;
+ int a_op;
+ struct flock *a_fl;
+ int a_flags;
+ } */ *ap;
+{
+ LOCKD_MSG msg;
+ struct nameidata nd;
+ struct proc *p;
+ uid_t saved_uid;
+ struct vnode *vp, *wvp;
+ int error, error1;
+ struct flock *fl;
+ int fmode, ioflg;
+
+ p = curproc;
+ vp = ap->a_vp;
+ fl = ap->a_fl;
+
+ /*
+ * the NLM protocol doesn't allow the server to return an error
+ * on ranges, so we do it. Note that we should be returning
+ * EOVERFLOW in some cases, but we don't have it.
+ */
+ if (fl->l_start < 0 || fl->l_len < 0 ||
+ ((fl->l_len != 0 &&
+ (fl->l_start + fl->l_len - 1) < 0)))
+ return (EINVAL);
+
+ /*
+ * Fill in the information structure.
+ */
+ msg.lm_version = LOCKD_MSG_VERSION;
+ msg.lm_msg_ident.pid = p->p_pid;
+ /*
+ * if there is no nfsowner table yet, allocate one.
+ */
+ if (p->p_nlminfo == NULL) {
+ MALLOC(p->p_nlminfo, struct nlminfo *,
+ sizeof(struct nlminfo), M_LOCKF, M_WAITOK | M_ZERO);
+ p->p_nlminfo->pid_start = p->p_stats->p_start;
+ }
+ msg.lm_msg_ident.pid_start = p->p_nlminfo->pid_start;
+ msg.lm_msg_ident.msg_seq = ++(p->p_nlminfo->msg_seq);
+
+ msg.lm_fl = *fl;
+ msg.lm_wait = ap->a_flags & F_WAIT;
+ msg.lm_getlk = ap->a_op == F_GETLK;
+ /*
+ * XXX -- I think this is wrong for anything other AF_INET.
+ */
+ msg.lm_addr = *(VFSTONFS(vp->v_mount)->nm_nam);
+ msg.lm_fh_len = NFS_ISV3(vp) ? VTONFS(vp)->n_fhsize : NFSX_V2FH;
+ bcopy(VTONFS(vp)->n_fhp, msg.lm_fh, msg.lm_fh_len);
+ msg.lm_nfsv3 = NFS_ISV3(vp);
+ msg.lm_cred = *(p->p_ucred);
+
+ /*
+ * Open the lock fifo. If for any reason we don't find the fifo, it
+ * means that the lock daemon isn't running. Translate any missing
+ * file error message for the user, otherwise the application will
+ * complain that the user's file is missing, which isn't the case.
+ * Note that we use proc0's cred, so the fifo is opened as root.
+ */
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, _PATH_LCKFIFO, p);
+
+ /*
+ * XXX Hack to temporarily allow this process (regardless of it's creds)
+ * to open the fifo we need to write to. vn_open() really should
+ * take a ucred (and once it does, this code should be fixed to use
+ * proc0's ucred.
+ */
+ saved_uid = p->p_ucred->cr_uid;
+ p->p_ucred->cr_uid = 0; /* temporarly run the vn_open as root */
+
+ fmode = FFLAGS(O_WRONLY);
+ error = vn_open(&nd, &fmode, 0);
+ p->p_ucred->cr_uid = saved_uid;
+ if (error != 0) {
+ return (error == ENOENT ? EOPNOTSUPP : error);
+ }
+ wvp = nd.ni_vp;
+ VOP_UNLOCK(wvp, 0, p); /* vn_open leaves it locked */
+
+
+ ioflg = IO_UNIT;
+ for (;;) {
+ VOP_LEASE(wvp, p, proc0.p_ucred, LEASE_WRITE);
+
+ error = vn_rdwr(UIO_WRITE, wvp, (caddr_t)&msg, sizeof(msg), 0,
+ UIO_SYSSPACE, ioflg, proc0.p_ucred, NULL, p);
+
+ if (error && (((ioflg & IO_NDELAY) == 0) || error != EAGAIN)) {
+ break;
+ }
+ /*
+ * If we're locking a file, wait for an answer. Unlocks succeed
+ * immediately.
+ */
+ if (fl->l_type == F_UNLCK)
+ /*
+ * XXX this isn't exactly correct. The client side
+ * needs to continue sending it's unlock until
+ * it gets a responce back.
+ */
+ break;
+
+ /*
+ * retry after 20 seconds if we haven't gotten a responce yet.
+ * This number was picked out of thin air... but is longer
+ * then even a reasonably loaded system should take (at least
+ * on a local network). XXX Probably should use a back-off
+ * scheme.
+ */
+ if ((error = tsleep((void *)p->p_nlminfo,
+ PCATCH | PUSER, "lockd", 20*hz)) != 0) {
+ if (error == EWOULDBLOCK) {
+ /*
+ * We timed out, so we rewrite the request
+ * to the fifo, but only if it isn't already
+ * full.
+ */
+ ioflg |= IO_NDELAY;
+ continue;
+ }
+
+ break;
+ }
+
+ if (msg.lm_getlk && p->p_nlminfo->retcode == 0) {
+ if (p->p_nlminfo->set_getlk_pid) {
+ fl->l_pid = p->p_nlminfo->getlk_pid;
+ } else {
+ fl->l_type = F_UNLCK;
+ }
+ }
+ error = p->p_nlminfo->retcode;
+ break;
+ }
+
+ if ((error1 = vn_close(wvp, FWRITE, proc0.p_ucred, p)) && error == 0)
+ return (error1);
+
+ return (error);
+}
+
+/*
+ * nfslockdans --
+ * NFS advisory byte-level locks answer from the lock daemon.
+ */
+int
+nfslockdans(p, ansp)
+ struct proc *p;
+ struct lockd_ans *ansp;
+{
+ int error;
+
+ /* Let root, or someone who once was root (lockd generally
+ * switches to the daemon uid once it is done setting up) make
+ * this call
+ */
+ if ((error = suser(p)) != 0 && p->p_cred->p_svuid != 0)
+ return (error);
+
+ /* the version should match, or we're out of sync */
+ if (ansp->la_vers != LOCKD_ANS_VERSION)
+ return (EINVAL);
+
+ /* Find the process, set its return errno and wake it up. */
+ if ((p = pfind(ansp->la_msg_ident.pid)) == NULL)
+ return (ESRCH);
+
+ /* verify the pid hasn't been reused (if we can), and it isn't waiting
+ * for an answer from a more recent request. We return an EPIPE if
+ * the match fails, because we've already used ESRCH above, and this
+ * is sort of like writing on a pipe after the reader has closed it.
+ */
+ if (p->p_nlminfo == NULL ||
+ ((ansp->la_msg_ident.msg_seq != -1) &&
+ (timevalcmp(&p->p_nlminfo->pid_start,
+ &ansp->la_msg_ident.pid_start, !=) ||
+ p->p_nlminfo->msg_seq != ansp->la_msg_ident.msg_seq)))
+ return (EPIPE);
+
+ p->p_nlminfo->retcode = ansp->la_errno;
+ p->p_nlminfo->set_getlk_pid = ansp->la_set_getlk_pid;
+ p->p_nlminfo->getlk_pid = ansp->la_getlk_pid;
+
+ (void)wakeup((void *)p->p_nlminfo);
+
+ return (0);
+}
diff --git a/sys/nfs/nfs_lock.h b/sys/nfs/nfs_lock.h
new file mode 100644
index 0000000..64b6c70
--- /dev/null
+++ b/sys/nfs/nfs_lock.h
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 1998 Berkeley Software Design, Inc. All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Berkeley Software Design Inc's name may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from nfs_lock.h,v 2.2 1998/04/28 19:38:41 don Exp
+ * $FreeBSD$
+ */
+
+/*
+ * lockd uses the nfssvc system call to get the unique kernel services it needs.
+ * It passes in a request structure with a version number at the start.
+ * This prevents libc from needing to change if the information passed
+ * between lockd and the kernel needs to change.
+ *
+ * If a structure changes, you must bump the version number.
+ */
+
+#include <nfs/nfsproto.h>
+
+
+#define LOCKD_REQ_VERSION 1
+
+struct lockd_req {
+ int vers; /* keep in sync with kernel please */
+ int op; /* F_GETLK | F_SETLK | F_UNLCK */
+ int owner; /* owner of lock, -1 to allocate one */
+ int owner_rel_ok; /* release owner if no locks left ? */
+ int *owner_ret; /* owner alloc/free result target */
+ void *fh; /* NFS file handle */
+ size_t fh_len; /* NFS file handle length */
+ u_quad_t offset; /* offset of where to start lock */
+ u_quad_t len; /* length of range to lock */
+ int type; /* F_RDLCK | F_WRLCK | F_UNLCK */
+ struct ucred cred; /* user credentials to use for lock */
+ struct sockaddr saddr; /* XXX how about non AF_INET ?? */
+ int pid; /* pid of lock requester */
+};
+
+/*
+ * The fifo where the kernel writes requests for locks on remote NFS files,
+ * and where lockd reads these requests.
+ *
+ */
+#define _PATH_LCKFIFO "/var/run/lock"
+
+/*
+ * This structure is used to uniquely identify the process which originated
+ * a particular message to lockd. A sequence number is used to differentiate
+ * multiple messages from the same process. A process start time is used to
+ * detect the unlikely, but possible, event of the recycling of a pid.
+ */
+struct lockd_msg_ident {
+ pid_t pid; /* The process ID. */
+ struct timeval pid_start; /* Start time of process id */
+ int msg_seq; /* Sequence number of message */
+};
+
+#define LOCKD_MSG_VERSION 1
+
+/*
+ * The structure that the kernel hands us for each lock request.
+ */
+typedef struct __lock_msg {
+ int lm_version; /* which version is this */
+ struct lockd_msg_ident lm_msg_ident; /* originator of the message */
+ struct flock lm_fl; /* The lock request. */
+ int lm_wait; /* The F_WAIT flag. */
+ int lm_getlk; /* is this a F_GETLK request */
+ struct sockaddr lm_addr; /* The address. */
+ int lm_nfsv3; /* If NFS version 3. */
+ size_t lm_fh_len; /* The file handle length. */
+ struct ucred lm_cred; /* user cred for lock req */
+ u_int8_t lm_fh[NFS_SMALLFH];/* The file handle. */
+} LOCKD_MSG;
+
+#define LOCKD_ANS_VERSION 1
+
+struct lockd_ans {
+ int la_vers;
+ struct lockd_msg_ident la_msg_ident; /* originator of the message */
+ int la_errno;
+ int la_set_getlk_pid; /* use returned pid */
+ int la_getlk_pid; /* returned pid for F_GETLK */
+};
+
+#ifdef _KERNEL
+int nfs_dolock(struct vop_advlock_args *ap);
+int nfslockdans(struct proc *p, struct lockd_ans *ansp);
+int nfslockdreq(struct proc *p, struct lockd_req *reqp);
+#endif
diff --git a/sys/nfs/nfs_syscalls.c b/sys/nfs/nfs_syscalls.c
index 2d46568..a47d5a8 100644
--- a/sys/nfs/nfs_syscalls.c
+++ b/sys/nfs/nfs_syscalls.c
@@ -56,6 +56,8 @@
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/namei.h>
+#include <sys/fcntl.h>
+#include <sys/lockf.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
@@ -69,6 +71,7 @@
#include <nfs/nfsnode.h>
#include <nfs/nqnfs.h>
#include <nfs/nfsrtt.h>
+#include <nfs/nfs_lock.h>
static MALLOC_DEFINE(M_NFSSVC, "NFS srvsock", "Nfs server structure");
@@ -152,6 +155,12 @@ nfssvc(p, uap)
#endif /* NFS_NOSERVER */
int error;
+ if ((uap->flag & NFSSVC_LOCKDANS) != 0) {
+ struct lockd_ans la;
+
+ error = copyin(uap->argp, &la, sizeof(la));
+ return (error != 0 ? error : nfslockdans(p, &la));
+ }
/*
* Must be super user
*/
diff --git a/sys/nfs/nfs_vnops.c b/sys/nfs/nfs_vnops.c
index 2a5564e..b37f6da 100644
--- a/sys/nfs/nfs_vnops.c
+++ b/sys/nfs/nfs_vnops.c
@@ -76,6 +76,7 @@
#include <nfs/xdr_subs.h>
#include <nfs/nfsm_subs.h>
#include <nfs/nqnfs.h>
+#include <nfs/nfs_lock.h>
#include <net/if.h>
#include <netinet/in.h>
@@ -3057,14 +3058,8 @@ nfs_advlock(ap)
int a_flags;
} */ *ap;
{
- register struct nfsnode *np = VTONFS(ap->a_vp);
- /*
- * The following kludge is to allow diskless support to work
- * until a real NFS lockd is implemented. Basically, just pretend
- * that this is a local lock.
- */
- return (lf_advlock(ap, &(np->n_lockf), np->n_size));
+ return (nfs_dolock(ap));
}
/*
diff --git a/sys/nfs/nlminfo.h b/sys/nfs/nlminfo.h
new file mode 100644
index 0000000..79c6e17
--- /dev/null
+++ b/sys/nfs/nlminfo.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 1998 Berkeley Software Design, Inc. All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Berkeley Software Design Inc's name may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from BSDI nlminfo.h,v 2.1 1998/03/18 01:30:38 don Exp
+ * $FreeBSD$
+ */
+
+/*
+ * Misc NLM informationi, some needed for the master lockd process, and some
+ * needed by every process doing nlm based locking.
+ */
+struct nlminfo {
+ /* these are used by any process doing nlm locking */
+ int msg_seq; /* sequence counter for lock requests */
+ int retcode; /* return code for lock requests */
+ int set_getlk_pid;
+ int getlk_pid;
+ struct timeval pid_start; /* process starting time */
+};
+
+extern void nlminfo_release __P((struct proc *p));
+
diff --git a/sys/nfsclient/nfs.h b/sys/nfsclient/nfs.h
index 259ec20..2b0f664 100644
--- a/sys/nfsclient/nfs.h
+++ b/sys/nfsclient/nfs.h
@@ -274,6 +274,7 @@ struct nfsstats {
#define NFSSVC_GOTAUTH 0x040
#define NFSSVC_AUTHINFAIL 0x080
#define NFSSVC_MNTD 0x100
+#define NFSSVC_LOCKDANS 0x200
/*
* fs.nfs sysctl(3) identifiers
diff --git a/sys/nfsclient/nfs_lock.c b/sys/nfsclient/nfs_lock.c
new file mode 100644
index 0000000..aaac361
--- /dev/null
+++ b/sys/nfsclient/nfs_lock.c
@@ -0,0 +1,269 @@
+/*-
+ * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Berkeley Software Design Inc's name may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from BSDI nfs_lock.c,v 2.4 1998/12/14 23:49:56 jch Exp
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/fcntl.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/unistd.h>
+#include <sys/vnode.h>
+#include <sys/resourcevar.h>
+#include <sys/kernel.h> /* for hz */
+#include <sys/lockf.h> /* for hz */
+
+#include <net/if.h>
+
+#include <nfs/rpcv2.h>
+#include <nfs/nfsproto.h>
+#include <nfs/nfs.h>
+#include <nfs/nfsmount.h>
+#include <nfs/nfsnode.h>
+#include <nfs/nfs_lock.h>
+#include <nfs/nlminfo.h>
+
+#define NFSOWNER_1ST_LEVEL_START 1 /* initial entries */
+#define NFSOWNER_2ND_LEVEL 256 /* some power of 2 */
+
+#define NFSOWNER(tbl, i) \
+ (tbl)[(i) / NFSOWNER_2ND_LEVEL][(i) % NFSOWNER_2ND_LEVEL]
+
+/*
+ * XXX
+ * We have to let the process know if the call succeeded. I'm using an extra
+ * field in the p_nlminfo field in the proc structure, as it is already for
+ * lockd stuff.
+ */
+
+/*
+ * nfs_advlock --
+ * NFS advisory byte-level locks.
+ */
+int
+nfs_dolock(ap)
+ struct vop_advlock_args /* {
+ struct vnode *a_vp;
+ caddr_t a_id;
+ int a_op;
+ struct flock *a_fl;
+ int a_flags;
+ } */ *ap;
+{
+ LOCKD_MSG msg;
+ struct nameidata nd;
+ struct proc *p;
+ uid_t saved_uid;
+ struct vnode *vp, *wvp;
+ int error, error1;
+ struct flock *fl;
+ int fmode, ioflg;
+
+ p = curproc;
+ vp = ap->a_vp;
+ fl = ap->a_fl;
+
+ /*
+ * the NLM protocol doesn't allow the server to return an error
+ * on ranges, so we do it. Note that we should be returning
+ * EOVERFLOW in some cases, but we don't have it.
+ */
+ if (fl->l_start < 0 || fl->l_len < 0 ||
+ ((fl->l_len != 0 &&
+ (fl->l_start + fl->l_len - 1) < 0)))
+ return (EINVAL);
+
+ /*
+ * Fill in the information structure.
+ */
+ msg.lm_version = LOCKD_MSG_VERSION;
+ msg.lm_msg_ident.pid = p->p_pid;
+ /*
+ * if there is no nfsowner table yet, allocate one.
+ */
+ if (p->p_nlminfo == NULL) {
+ MALLOC(p->p_nlminfo, struct nlminfo *,
+ sizeof(struct nlminfo), M_LOCKF, M_WAITOK | M_ZERO);
+ p->p_nlminfo->pid_start = p->p_stats->p_start;
+ }
+ msg.lm_msg_ident.pid_start = p->p_nlminfo->pid_start;
+ msg.lm_msg_ident.msg_seq = ++(p->p_nlminfo->msg_seq);
+
+ msg.lm_fl = *fl;
+ msg.lm_wait = ap->a_flags & F_WAIT;
+ msg.lm_getlk = ap->a_op == F_GETLK;
+ /*
+ * XXX -- I think this is wrong for anything other AF_INET.
+ */
+ msg.lm_addr = *(VFSTONFS(vp->v_mount)->nm_nam);
+ msg.lm_fh_len = NFS_ISV3(vp) ? VTONFS(vp)->n_fhsize : NFSX_V2FH;
+ bcopy(VTONFS(vp)->n_fhp, msg.lm_fh, msg.lm_fh_len);
+ msg.lm_nfsv3 = NFS_ISV3(vp);
+ msg.lm_cred = *(p->p_ucred);
+
+ /*
+ * Open the lock fifo. If for any reason we don't find the fifo, it
+ * means that the lock daemon isn't running. Translate any missing
+ * file error message for the user, otherwise the application will
+ * complain that the user's file is missing, which isn't the case.
+ * Note that we use proc0's cred, so the fifo is opened as root.
+ */
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, _PATH_LCKFIFO, p);
+
+ /*
+ * XXX Hack to temporarily allow this process (regardless of it's creds)
+ * to open the fifo we need to write to. vn_open() really should
+ * take a ucred (and once it does, this code should be fixed to use
+ * proc0's ucred.
+ */
+ saved_uid = p->p_ucred->cr_uid;
+ p->p_ucred->cr_uid = 0; /* temporarly run the vn_open as root */
+
+ fmode = FFLAGS(O_WRONLY);
+ error = vn_open(&nd, &fmode, 0);
+ p->p_ucred->cr_uid = saved_uid;
+ if (error != 0) {
+ return (error == ENOENT ? EOPNOTSUPP : error);
+ }
+ wvp = nd.ni_vp;
+ VOP_UNLOCK(wvp, 0, p); /* vn_open leaves it locked */
+
+
+ ioflg = IO_UNIT;
+ for (;;) {
+ VOP_LEASE(wvp, p, proc0.p_ucred, LEASE_WRITE);
+
+ error = vn_rdwr(UIO_WRITE, wvp, (caddr_t)&msg, sizeof(msg), 0,
+ UIO_SYSSPACE, ioflg, proc0.p_ucred, NULL, p);
+
+ if (error && (((ioflg & IO_NDELAY) == 0) || error != EAGAIN)) {
+ break;
+ }
+ /*
+ * If we're locking a file, wait for an answer. Unlocks succeed
+ * immediately.
+ */
+ if (fl->l_type == F_UNLCK)
+ /*
+ * XXX this isn't exactly correct. The client side
+ * needs to continue sending it's unlock until
+ * it gets a responce back.
+ */
+ break;
+
+ /*
+ * retry after 20 seconds if we haven't gotten a responce yet.
+ * This number was picked out of thin air... but is longer
+ * then even a reasonably loaded system should take (at least
+ * on a local network). XXX Probably should use a back-off
+ * scheme.
+ */
+ if ((error = tsleep((void *)p->p_nlminfo,
+ PCATCH | PUSER, "lockd", 20*hz)) != 0) {
+ if (error == EWOULDBLOCK) {
+ /*
+ * We timed out, so we rewrite the request
+ * to the fifo, but only if it isn't already
+ * full.
+ */
+ ioflg |= IO_NDELAY;
+ continue;
+ }
+
+ break;
+ }
+
+ if (msg.lm_getlk && p->p_nlminfo->retcode == 0) {
+ if (p->p_nlminfo->set_getlk_pid) {
+ fl->l_pid = p->p_nlminfo->getlk_pid;
+ } else {
+ fl->l_type = F_UNLCK;
+ }
+ }
+ error = p->p_nlminfo->retcode;
+ break;
+ }
+
+ if ((error1 = vn_close(wvp, FWRITE, proc0.p_ucred, p)) && error == 0)
+ return (error1);
+
+ return (error);
+}
+
+/*
+ * nfslockdans --
+ * NFS advisory byte-level locks answer from the lock daemon.
+ */
+int
+nfslockdans(p, ansp)
+ struct proc *p;
+ struct lockd_ans *ansp;
+{
+ int error;
+
+ /* Let root, or someone who once was root (lockd generally
+ * switches to the daemon uid once it is done setting up) make
+ * this call
+ */
+ if ((error = suser(p)) != 0 && p->p_cred->p_svuid != 0)
+ return (error);
+
+ /* the version should match, or we're out of sync */
+ if (ansp->la_vers != LOCKD_ANS_VERSION)
+ return (EINVAL);
+
+ /* Find the process, set its return errno and wake it up. */
+ if ((p = pfind(ansp->la_msg_ident.pid)) == NULL)
+ return (ESRCH);
+
+ /* verify the pid hasn't been reused (if we can), and it isn't waiting
+ * for an answer from a more recent request. We return an EPIPE if
+ * the match fails, because we've already used ESRCH above, and this
+ * is sort of like writing on a pipe after the reader has closed it.
+ */
+ if (p->p_nlminfo == NULL ||
+ ((ansp->la_msg_ident.msg_seq != -1) &&
+ (timevalcmp(&p->p_nlminfo->pid_start,
+ &ansp->la_msg_ident.pid_start, !=) ||
+ p->p_nlminfo->msg_seq != ansp->la_msg_ident.msg_seq)))
+ return (EPIPE);
+
+ p->p_nlminfo->retcode = ansp->la_errno;
+ p->p_nlminfo->set_getlk_pid = ansp->la_set_getlk_pid;
+ p->p_nlminfo->getlk_pid = ansp->la_getlk_pid;
+
+ (void)wakeup((void *)p->p_nlminfo);
+
+ return (0);
+}
diff --git a/sys/nfsclient/nfs_lock.h b/sys/nfsclient/nfs_lock.h
new file mode 100644
index 0000000..64b6c70
--- /dev/null
+++ b/sys/nfsclient/nfs_lock.h
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 1998 Berkeley Software Design, Inc. All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Berkeley Software Design Inc's name may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from nfs_lock.h,v 2.2 1998/04/28 19:38:41 don Exp
+ * $FreeBSD$
+ */
+
+/*
+ * lockd uses the nfssvc system call to get the unique kernel services it needs.
+ * It passes in a request structure with a version number at the start.
+ * This prevents libc from needing to change if the information passed
+ * between lockd and the kernel needs to change.
+ *
+ * If a structure changes, you must bump the version number.
+ */
+
+#include <nfs/nfsproto.h>
+
+
+#define LOCKD_REQ_VERSION 1
+
+struct lockd_req {
+ int vers; /* keep in sync with kernel please */
+ int op; /* F_GETLK | F_SETLK | F_UNLCK */
+ int owner; /* owner of lock, -1 to allocate one */
+ int owner_rel_ok; /* release owner if no locks left ? */
+ int *owner_ret; /* owner alloc/free result target */
+ void *fh; /* NFS file handle */
+ size_t fh_len; /* NFS file handle length */
+ u_quad_t offset; /* offset of where to start lock */
+ u_quad_t len; /* length of range to lock */
+ int type; /* F_RDLCK | F_WRLCK | F_UNLCK */
+ struct ucred cred; /* user credentials to use for lock */
+ struct sockaddr saddr; /* XXX how about non AF_INET ?? */
+ int pid; /* pid of lock requester */
+};
+
+/*
+ * The fifo where the kernel writes requests for locks on remote NFS files,
+ * and where lockd reads these requests.
+ *
+ */
+#define _PATH_LCKFIFO "/var/run/lock"
+
+/*
+ * This structure is used to uniquely identify the process which originated
+ * a particular message to lockd. A sequence number is used to differentiate
+ * multiple messages from the same process. A process start time is used to
+ * detect the unlikely, but possible, event of the recycling of a pid.
+ */
+struct lockd_msg_ident {
+ pid_t pid; /* The process ID. */
+ struct timeval pid_start; /* Start time of process id */
+ int msg_seq; /* Sequence number of message */
+};
+
+#define LOCKD_MSG_VERSION 1
+
+/*
+ * The structure that the kernel hands us for each lock request.
+ */
+typedef struct __lock_msg {
+ int lm_version; /* which version is this */
+ struct lockd_msg_ident lm_msg_ident; /* originator of the message */
+ struct flock lm_fl; /* The lock request. */
+ int lm_wait; /* The F_WAIT flag. */
+ int lm_getlk; /* is this a F_GETLK request */
+ struct sockaddr lm_addr; /* The address. */
+ int lm_nfsv3; /* If NFS version 3. */
+ size_t lm_fh_len; /* The file handle length. */
+ struct ucred lm_cred; /* user cred for lock req */
+ u_int8_t lm_fh[NFS_SMALLFH];/* The file handle. */
+} LOCKD_MSG;
+
+#define LOCKD_ANS_VERSION 1
+
+struct lockd_ans {
+ int la_vers;
+ struct lockd_msg_ident la_msg_ident; /* originator of the message */
+ int la_errno;
+ int la_set_getlk_pid; /* use returned pid */
+ int la_getlk_pid; /* returned pid for F_GETLK */
+};
+
+#ifdef _KERNEL
+int nfs_dolock(struct vop_advlock_args *ap);
+int nfslockdans(struct proc *p, struct lockd_ans *ansp);
+int nfslockdreq(struct proc *p, struct lockd_req *reqp);
+#endif
diff --git a/sys/nfsclient/nfs_nfsiod.c b/sys/nfsclient/nfs_nfsiod.c
index 2d46568..a47d5a8 100644
--- a/sys/nfsclient/nfs_nfsiod.c
+++ b/sys/nfsclient/nfs_nfsiod.c
@@ -56,6 +56,8 @@
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/namei.h>
+#include <sys/fcntl.h>
+#include <sys/lockf.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
@@ -69,6 +71,7 @@
#include <nfs/nfsnode.h>
#include <nfs/nqnfs.h>
#include <nfs/nfsrtt.h>
+#include <nfs/nfs_lock.h>
static MALLOC_DEFINE(M_NFSSVC, "NFS srvsock", "Nfs server structure");
@@ -152,6 +155,12 @@ nfssvc(p, uap)
#endif /* NFS_NOSERVER */
int error;
+ if ((uap->flag & NFSSVC_LOCKDANS) != 0) {
+ struct lockd_ans la;
+
+ error = copyin(uap->argp, &la, sizeof(la));
+ return (error != 0 ? error : nfslockdans(p, &la));
+ }
/*
* Must be super user
*/
diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c
index 2a5564e..b37f6da 100644
--- a/sys/nfsclient/nfs_vnops.c
+++ b/sys/nfsclient/nfs_vnops.c
@@ -76,6 +76,7 @@
#include <nfs/xdr_subs.h>
#include <nfs/nfsm_subs.h>
#include <nfs/nqnfs.h>
+#include <nfs/nfs_lock.h>
#include <net/if.h>
#include <netinet/in.h>
@@ -3057,14 +3058,8 @@ nfs_advlock(ap)
int a_flags;
} */ *ap;
{
- register struct nfsnode *np = VTONFS(ap->a_vp);
- /*
- * The following kludge is to allow diskless support to work
- * until a real NFS lockd is implemented. Basically, just pretend
- * that this is a local lock.
- */
- return (lf_advlock(ap, &(np->n_lockf), np->n_size));
+ return (nfs_dolock(ap));
}
/*
diff --git a/sys/nfsclient/nfsargs.h b/sys/nfsclient/nfsargs.h
index 259ec20..2b0f664 100644
--- a/sys/nfsclient/nfsargs.h
+++ b/sys/nfsclient/nfsargs.h
@@ -274,6 +274,7 @@ struct nfsstats {
#define NFSSVC_GOTAUTH 0x040
#define NFSSVC_AUTHINFAIL 0x080
#define NFSSVC_MNTD 0x100
+#define NFSSVC_LOCKDANS 0x200
/*
* fs.nfs sysctl(3) identifiers
diff --git a/sys/nfsclient/nfsstats.h b/sys/nfsclient/nfsstats.h
index 259ec20..2b0f664 100644
--- a/sys/nfsclient/nfsstats.h
+++ b/sys/nfsclient/nfsstats.h
@@ -274,6 +274,7 @@ struct nfsstats {
#define NFSSVC_GOTAUTH 0x040
#define NFSSVC_AUTHINFAIL 0x080
#define NFSSVC_MNTD 0x100
+#define NFSSVC_LOCKDANS 0x200
/*
* fs.nfs sysctl(3) identifiers
diff --git a/sys/nfsclient/nlminfo.h b/sys/nfsclient/nlminfo.h
new file mode 100644
index 0000000..79c6e17
--- /dev/null
+++ b/sys/nfsclient/nlminfo.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 1998 Berkeley Software Design, Inc. All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Berkeley Software Design Inc's name may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from BSDI nlminfo.h,v 2.1 1998/03/18 01:30:38 don Exp
+ * $FreeBSD$
+ */
+
+/*
+ * Misc NLM informationi, some needed for the master lockd process, and some
+ * needed by every process doing nlm based locking.
+ */
+struct nlminfo {
+ /* these are used by any process doing nlm locking */
+ int msg_seq; /* sequence counter for lock requests */
+ int retcode; /* return code for lock requests */
+ int set_getlk_pid;
+ int getlk_pid;
+ struct timeval pid_start; /* process starting time */
+};
+
+extern void nlminfo_release __P((struct proc *p));
+
diff --git a/sys/nfsserver/nfs.h b/sys/nfsserver/nfs.h
index 259ec20..2b0f664 100644
--- a/sys/nfsserver/nfs.h
+++ b/sys/nfsserver/nfs.h
@@ -274,6 +274,7 @@ struct nfsstats {
#define NFSSVC_GOTAUTH 0x040
#define NFSSVC_AUTHINFAIL 0x080
#define NFSSVC_MNTD 0x100
+#define NFSSVC_LOCKDANS 0x200
/*
* fs.nfs sysctl(3) identifiers
diff --git a/sys/nfsserver/nfs_syscalls.c b/sys/nfsserver/nfs_syscalls.c
index 2d46568..a47d5a8 100644
--- a/sys/nfsserver/nfs_syscalls.c
+++ b/sys/nfsserver/nfs_syscalls.c
@@ -56,6 +56,8 @@
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/namei.h>
+#include <sys/fcntl.h>
+#include <sys/lockf.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
@@ -69,6 +71,7 @@
#include <nfs/nfsnode.h>
#include <nfs/nqnfs.h>
#include <nfs/nfsrtt.h>
+#include <nfs/nfs_lock.h>
static MALLOC_DEFINE(M_NFSSVC, "NFS srvsock", "Nfs server structure");
@@ -152,6 +155,12 @@ nfssvc(p, uap)
#endif /* NFS_NOSERVER */
int error;
+ if ((uap->flag & NFSSVC_LOCKDANS) != 0) {
+ struct lockd_ans la;
+
+ error = copyin(uap->argp, &la, sizeof(la));
+ return (error != 0 ? error : nfslockdans(p, &la));
+ }
/*
* Must be super user
*/
diff --git a/sys/nfsserver/nfsrvstats.h b/sys/nfsserver/nfsrvstats.h
index 259ec20..2b0f664 100644
--- a/sys/nfsserver/nfsrvstats.h
+++ b/sys/nfsserver/nfsrvstats.h
@@ -274,6 +274,7 @@ struct nfsstats {
#define NFSSVC_GOTAUTH 0x040
#define NFSSVC_AUTHINFAIL 0x080
#define NFSSVC_MNTD 0x100
+#define NFSSVC_LOCKDANS 0x200
/*
* fs.nfs sysctl(3) identifiers
diff --git a/sys/sys/lockf.h b/sys/sys/lockf.h
index 17980f6..cded00f 100644
--- a/sys/sys/lockf.h
+++ b/sys/sys/lockf.h
@@ -44,6 +44,8 @@
struct vop_advlock_args;
+MALLOC_DECLARE(M_LOCKF);
+
/*
* The lockf structure is a kernel structure which contains the information
* associated with a byte range lock. The lockf structures are linked into
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 7ddd621..f824c57 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -146,6 +146,7 @@ struct pargs {
* for write access.
*/
struct ithd;
+struct nlminfo;
struct proc {
TAILQ_ENTRY(proc) p_procq; /* (j) Run/mutex queue. */
@@ -235,6 +236,8 @@ struct proc {
struct mtx *p_blocked; /* (j) Mutex process is blocked on. */
const char *p_mtxname; /* (j) Name of mutex blocked on. */
LIST_HEAD(, mtx) p_contested; /* (j) Contested locks. */
+
+ struct nlminfo *p_nlminfo; /* (?) only used by/for lockd */
void *p_aioinfo; /* (c) ASYNC I/O info. */
struct ithd *p_ithd; /* (b) For interrupt threads only. */
int p_intr_nesting_level; /* (k) Interrupt recursion. */
diff --git a/usr.sbin/rpc.lockd/Makefile b/usr.sbin/rpc.lockd/Makefile
index 6f089b4..2e8aa47 100644
--- a/usr.sbin/rpc.lockd/Makefile
+++ b/usr.sbin/rpc.lockd/Makefile
@@ -2,11 +2,11 @@
# $NetBSD: Makefile,v 1.12 2000/08/07 16:23:31 thorpej Exp $
PROG= rpc.lockd
-SRCS= nlm_prot_svc.c lockd.c lock_proc.c lockd_lock.c
+SRCS= kern.c nlm_prot_svc.c lockd.c lock_proc.c lockd_lock.c
MAN= rpc.lockd.8
MLINKS= rpc.lockd.8 lockd.8
-CFLAGS+= -I. -I${DESTDIR}/usr/include/rpcsvc
+CFLAGS+= -I. -I${DESTDIR}/usr/include/rpcsvc -g
DPADD= ${LIBRPCSVC} ${LIBUTIL}
LDADD= -lrpcsvc -lutil
diff --git a/usr.sbin/rpc.lockd/kern.c b/usr.sbin/rpc.lockd/kern.c
new file mode 100644
index 0000000..59f035d
--- /dev/null
+++ b/usr.sbin/rpc.lockd/kern.c
@@ -0,0 +1,586 @@
+/*-
+ * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Berkeley Software Design Inc's name may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from BSDI kern.c,v 1.2 1998/11/25 22:38:27 don Exp
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "nlm_prot.h"
+#include "nfs/nfs_lock.h"
+
+#include "lockd.h"
+#include "lockd_lock.h"
+#include <nfs/rpcv2.h>
+#include <nfs/nfsproto.h>
+#include <nfs/nfs.h>
+
+#define nfslockdans(_v, _ansp) \
+ ((_ansp)->la_vers = _v, \
+ nfssvc(NFSSVC_LOCKDANS, _ansp))
+
+/* Lock request owner. */
+typedef struct __owner {
+ pid_t pid; /* Process ID. */
+ time_t tod; /* Time-of-day. */
+} OWNER;
+static OWNER owner;
+
+static char hostname[MAXHOSTNAMELEN + 1]; /* Hostname. */
+
+int lock_request(LOCKD_MSG *);
+int test_request(LOCKD_MSG *);
+void show(LOCKD_MSG *);
+int unlock_request(LOCKD_MSG *);
+
+/*
+ * will break because fifo needs to be repopened when EOF'd
+ */
+#ifdef SETUID_DAEMON
+#define lockd_seteuid(uid) seteuid(uid)
+#else
+#define lockd_seteuid(uid) (1)
+#endif
+
+#define d_calls 0
+#define d_args 0
+
+void
+client_cleanup(sig, code)
+ int sig;
+ int code;
+{
+ (void)lockd_seteuid(0);
+ (void)unlink(_PATH_LCKFIFO);
+ exit(-1);
+}
+
+/*
+ * client_request --
+ * Loop around messages from the kernel, forwarding them off to
+ * NLM servers.
+ */
+pid_t
+client_request(void)
+{
+ LOCKD_MSG msg;
+ fd_set rdset;
+ int fd, nr, ret;
+ pid_t child;
+
+ /* Recreate the NLM fifo. */
+ (void)unlink(_PATH_LCKFIFO);
+ (void)umask(S_IXGRP|S_IXOTH);
+ if (mkfifo(_PATH_LCKFIFO, S_IWUSR | S_IRUSR)) {
+ syslog(LOG_ERR, "mkfifo: %s: %m", _PATH_LCKFIFO);
+ exit (1);
+ }
+#define linebug syslog(LOG_ERR, "lockd: %d", __LINE__);
+linebug
+
+ /*
+ * Create a separate process, the client code is really a separate
+ * daemon that shares a lot of code.
+ */
+ switch (child = fork()) {
+ case -1:
+ err(1, "fork");
+ case 0:
+ break;
+ default:
+ return (child);
+ }
+
+linebug
+ signal(SIGHUP, client_cleanup);
+ signal(SIGTERM, client_cleanup);
+
+ /* Setup. */
+ (void)time(&owner.tod);
+ owner.pid = getpid();
+ (void)gethostname(hostname, sizeof(hostname) - 1);
+
+linebug
+reopen:
+ /* Open the fifo for reading. */
+ if ((fd = open(_PATH_LCKFIFO, O_RDONLY /* | O_NONBLOCK */)) < 0)
+ syslog(LOG_ERR, "open: %s: %m", _PATH_LCKFIFO);
+
+ /* drop our root priviledges */
+ (void)lockd_seteuid(daemon_uid);
+
+ /* Set up the select. */
+ FD_ZERO(&rdset);
+
+ for (;;) {
+linebug
+ /* Wait for contact... fifo's return EAGAIN when read with
+ * no data
+ */
+ FD_SET(fd, &rdset);
+ (void)select(fd + 1, &rdset, NULL, NULL, NULL);
+
+linebug
+ /* Read the fixed length message. */
+ if ((nr = read(fd, &msg, sizeof(msg))) == sizeof(msg)) {
+ if (d_args)
+ show(&msg);
+
+ if (msg.lm_version != LOCKD_MSG_VERSION) {
+ syslog(LOG_ERR,
+ "unknown msg type: %d", msg.lm_version);
+ }
+ /*
+ * Send it to the NLM server and don't grant the lock
+ * if we fail for any reason.
+ */
+ switch (msg.lm_fl.l_type) {
+ case F_RDLCK:
+ case F_WRLCK:
+ if (msg.lm_getlk)
+ ret = test_request(&msg);
+ else
+ ret = lock_request(&msg);
+ break;
+ case F_UNLCK:
+ ret = unlock_request(&msg);
+ break;
+ default:
+ ret = 1;
+ syslog(LOG_ERR,
+ "unknown lock type: %d", msg.lm_fl.l_type);
+ break;
+ }
+ if (ret) {
+ struct lockd_ans ans;
+
+ ans.la_msg_ident = msg.lm_msg_ident;
+ ans.la_errno = EHOSTUNREACH;
+
+ if (nfslockdans(LOCKD_ANS_VERSION, &ans)) {
+ syslog((errno == EPIPE ? LOG_INFO :
+ LOG_ERR), "process %lu: %m",
+ (u_long)msg.lm_msg_ident.pid);
+ }
+ }
+ } else if (nr == -1) {
+linebug
+ if (errno != EAGAIN) {
+ syslog(LOG_ERR, "read: %s: %m", _PATH_LCKFIFO);
+ goto err;
+ }
+ } else if (nr != 0) {
+ syslog(LOG_ERR,
+ "%s: discard %d bytes", _PATH_LCKFIFO, nr);
+ } if (nr == 0) {
+ close (fd);
+ goto reopen;
+ }
+ }
+
+ /* Reached only on error. */
+err:
+ (void)lockd_seteuid(0);
+ (void)unlink(_PATH_LCKFIFO);
+ _exit (1);
+}
+
+void
+set_auth(
+ CLIENT *cl,
+ struct ucred *ucred
+)
+{
+ if (cl->cl_auth != NULL)
+ cl->cl_auth->ah_ops->ah_destroy(cl->cl_auth);
+ cl->cl_auth = authunix_create(hostname,
+ ucred->cr_uid,
+ ucred->cr_groups[0],
+ ucred->cr_ngroups-1,
+ &ucred->cr_groups[1]);
+}
+
+
+/*
+ * test_request --
+ * Convert a lock LOCKD_MSG into an NLM request, and send it off.
+ */
+int
+test_request(LOCKD_MSG *msg)
+{
+ CLIENT *cli;
+ struct timeval timeout = {0, 0}; /* No timeout, no response. */
+ char dummy;
+
+ if (d_calls)
+ syslog(LOG_DEBUG, "test request: %s: %s to %s",
+ msg->lm_nfsv3 ? "V4" : "V1/3",
+ msg->lm_fl.l_type == F_WRLCK ? "write" : "read",
+ from_addr((struct sockaddr_in *)&msg->lm_addr));
+
+ if (msg->lm_nfsv3) {
+ struct nlm4_testargs arg4;
+
+ arg4.cookie.n_bytes = (char *)&msg->lm_msg_ident;
+ arg4.cookie.n_len = sizeof(msg->lm_msg_ident);
+ arg4.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0;
+ arg4.alock.caller_name = hostname;
+ arg4.alock.fh.n_bytes = (char *)&msg->lm_fh;
+ arg4.alock.fh.n_len = msg->lm_fh_len;
+ arg4.alock.oh.n_bytes = (char *)&owner;
+ arg4.alock.oh.n_len = sizeof(owner);
+ arg4.alock.svid = msg->lm_msg_ident.pid;
+ arg4.alock.l_offset = msg->lm_fl.l_start;
+ arg4.alock.l_len = msg->lm_fl.l_len;
+
+ if ((cli = get_client(
+ (struct sockaddr *)&msg->lm_addr,
+ NLM_VERS4)) == NULL)
+ return (1);
+
+ set_auth(cli, &msg->lm_cred);
+ (void)clnt_call(cli, NLM_TEST_MSG,
+ xdr_nlm4_testargs, &arg4, xdr_void, &dummy, timeout);
+ } else {
+ struct nlm_testargs arg;
+
+ arg.cookie.n_bytes = (char *)&msg->lm_msg_ident;
+ arg.cookie.n_len = sizeof(msg->lm_msg_ident);
+ arg.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0;
+ arg.alock.caller_name = hostname;
+ arg.alock.fh.n_bytes = (char *)&msg->lm_fh;
+ arg.alock.fh.n_len = msg->lm_fh_len;
+ arg.alock.oh.n_bytes = (char *)&owner;
+ arg.alock.oh.n_len = sizeof(owner);
+ arg.alock.svid = msg->lm_msg_ident.pid;
+ arg.alock.l_offset = msg->lm_fl.l_start;
+ arg.alock.l_len = msg->lm_fl.l_len;
+
+ if ((cli = get_client(
+ (struct sockaddr *)&msg->lm_addr,
+ NLM_VERS)) == NULL)
+ return (1);
+
+ set_auth(cli, &msg->lm_cred);
+ (void)clnt_call(cli, NLM_TEST_MSG,
+ xdr_nlm_testargs, &arg, xdr_void, &dummy, timeout);
+ }
+ return (0);
+}
+
+/*
+ * lock_request --
+ * Convert a lock LOCKD_MSG into an NLM request, and send it off.
+ */
+int
+lock_request(LOCKD_MSG *msg)
+{
+ CLIENT *cli;
+ struct nlm4_lockargs arg4;
+ struct nlm_lockargs arg;
+ struct timeval timeout = {0, 0}; /* No timeout, no response. */
+ char dummy;
+
+ if (d_calls)
+ syslog(LOG_DEBUG, "lock request: %s: %s to %s",
+ msg->lm_nfsv3 ? "V4" : "V1/3",
+ msg->lm_fl.l_type == F_WRLCK ? "write" : "read",
+ from_addr((struct sockaddr_in *)&msg->lm_addr));
+
+ if (msg->lm_nfsv3) {
+ arg4.cookie.n_bytes = (char *)&msg->lm_msg_ident;
+ arg4.cookie.n_len = sizeof(msg->lm_msg_ident);
+ arg4.block = msg->lm_wait ? 1 : 0;
+ arg4.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0;
+ arg4.alock.caller_name = hostname;
+ arg4.alock.fh.n_bytes = (char *)&msg->lm_fh;
+ arg4.alock.fh.n_len = msg->lm_fh_len;
+ arg4.alock.oh.n_bytes = (char *)&owner;
+ arg4.alock.oh.n_len = sizeof(owner);
+ arg4.alock.svid = msg->lm_msg_ident.pid;
+ arg4.alock.l_offset = msg->lm_fl.l_start;
+ arg4.alock.l_len = msg->lm_fl.l_len;
+ arg4.reclaim = 0;
+ arg4.state = nsm_state;
+
+ if ((cli = get_client(
+ (struct sockaddr *)&msg->lm_addr,
+ NLM_VERS4)) == NULL)
+ return (1);
+
+ set_auth(cli, &msg->lm_cred);
+ (void)clnt_call(cli, NLM_LOCK_MSG,
+ xdr_nlm4_lockargs, &arg4, xdr_void, &dummy, timeout);
+ } else {
+ arg.cookie.n_bytes = (char *)&msg->lm_msg_ident;
+ arg.cookie.n_len = sizeof(msg->lm_msg_ident);
+ arg.block = msg->lm_wait ? 1 : 0;
+ arg.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0;
+ arg.alock.caller_name = hostname;
+ arg.alock.fh.n_bytes = (char *)&msg->lm_fh;
+ arg.alock.fh.n_len = msg->lm_fh_len;
+ arg.alock.oh.n_bytes = (char *)&owner;
+ arg.alock.oh.n_len = sizeof(owner);
+ arg.alock.svid = msg->lm_msg_ident.pid;
+ arg.alock.l_offset = msg->lm_fl.l_start;
+ arg.alock.l_len = msg->lm_fl.l_len;
+ arg.reclaim = 0;
+ arg.state = nsm_state;
+
+ if ((cli = get_client(
+ (struct sockaddr *)&msg->lm_addr,
+ NLM_VERS)) == NULL)
+ return (1);
+
+ set_auth(cli, &msg->lm_cred);
+ (void)clnt_call(cli, NLM_LOCK_MSG,
+ xdr_nlm_lockargs, &arg, xdr_void, &dummy, timeout);
+ }
+ return (0);
+}
+
+/*
+ * unlock_request --
+ * Convert an unlock LOCKD_MSG into an NLM request, and send it off.
+ */
+int
+unlock_request(LOCKD_MSG *msg)
+{
+ CLIENT *cli;
+ struct nlm4_unlockargs arg4;
+ struct nlm_unlockargs arg;
+ struct timeval timeout = {0, 0}; /* No timeout, no response. */
+ char dummy;
+
+ if (d_calls)
+ syslog(LOG_DEBUG, "unlock request: %s: to %s",
+ msg->lm_nfsv3 ? "V4" : "V1/3",
+ from_addr((struct sockaddr_in *)&msg->lm_addr));
+
+ if (msg->lm_nfsv3) {
+ arg4.cookie.n_bytes = (char *)&msg->lm_msg_ident;
+ arg4.cookie.n_len = sizeof(msg->lm_msg_ident);
+ arg4.alock.caller_name = hostname;
+ arg4.alock.fh.n_bytes = (char *)&msg->lm_fh;
+ arg4.alock.fh.n_len = msg->lm_fh_len;
+ arg4.alock.oh.n_bytes = (char *)&owner;
+ arg4.alock.oh.n_len = sizeof(owner);
+ arg4.alock.svid = msg->lm_msg_ident.pid;
+ arg4.alock.l_offset = msg->lm_fl.l_start;
+ arg4.alock.l_len = msg->lm_fl.l_len;
+
+ if ((cli = get_client(
+ (struct sockaddr *)&msg->lm_addr,
+ NLM_VERS4)) == NULL)
+ return (1);
+
+ set_auth(cli, &msg->lm_cred);
+ (void)clnt_call(cli, NLM_UNLOCK_MSG,
+ xdr_nlm4_unlockargs, &arg4, xdr_void, &dummy, timeout);
+ } else {
+ arg.cookie.n_bytes = (char *)&msg->lm_msg_ident;
+ arg.cookie.n_len = sizeof(msg->lm_msg_ident);
+ arg.alock.caller_name = hostname;
+ arg.alock.fh.n_bytes = (char *)&msg->lm_fh;
+ arg.alock.fh.n_len = msg->lm_fh_len;
+ arg.alock.oh.n_bytes = (char *)&owner;
+ arg.alock.oh.n_len = sizeof(owner);
+ arg.alock.svid = msg->lm_msg_ident.pid;
+ arg.alock.l_offset = msg->lm_fl.l_start;
+ arg.alock.l_len = msg->lm_fl.l_len;
+
+ if ((cli = get_client(
+ (struct sockaddr *)&msg->lm_addr,
+ NLM_VERS)) == NULL)
+ return (1);
+
+ set_auth(cli, &msg->lm_cred);
+ (void)clnt_call(cli, NLM_UNLOCK_MSG,
+ xdr_nlm_unlockargs, &arg, xdr_void, &dummy, timeout);
+ }
+
+ return (0);
+}
+
+int
+lock_answer(int pid, netobj *netcookie, int result, int *pid_p, int version)
+{
+ struct lockd_ans ans;
+
+ if (netcookie->n_len != sizeof(ans.la_msg_ident)) {
+ if (pid == -1) { /* we're screwed */
+ syslog(LOG_ERR, "inedible nlm cookie");
+ return -1;
+ }
+ ans.la_msg_ident.pid = pid;
+ ans.la_msg_ident.msg_seq = -1;
+ } else {
+ memcpy(&ans.la_msg_ident, netcookie->n_bytes,
+ sizeof(ans.la_msg_ident));
+ }
+
+ if (d_calls)
+ syslog(LOG_DEBUG, "lock answer: pid %lu: %s",
+ ans.la_msg_ident.pid, version == NLM_VERS4 ?
+ show_4state(result) : show_state(result));
+
+ ans.la_set_getlk_pid = 0;
+ if (version == NLM_VERS4)
+ switch (result) {
+ case nlm4_granted:
+ ans.la_errno = 0;
+ break;
+ default:
+ ans.la_errno = EACCES;
+ break;
+ case nlm4_denied:
+ if (pid_p == NULL)
+ ans.la_errno = EACCES;
+ else {
+ /* this is an answer to a nlm_test msg */
+ ans.la_set_getlk_pid = 1;
+ ans.la_getlk_pid = *pid_p;
+ ans.la_errno = 0;
+ }
+ break;
+ case nlm4_denied_nolocks:
+ ans.la_errno = EAGAIN;
+ break;
+ case nlm4_blocked:
+ return -1;
+ /* NOTREACHED */
+ case nlm4_denied_grace_period:
+ ans.la_errno = EAGAIN;
+ break;
+ case nlm4_deadlck:
+ ans.la_errno = EDEADLK;
+ break;
+ case nlm4_rofs:
+ ans.la_errno = EROFS;
+ break;
+ case nlm4_stale_fh:
+ ans.la_errno = ESTALE;
+ break;
+ case nlm4_fbig:
+ ans.la_errno = EFBIG;
+ break;
+ case nlm4_failed:
+ ans.la_errno = EACCES;
+ break;
+ }
+ else
+ switch (result) {
+ case nlm_granted:
+ ans.la_errno = 0;
+ break;
+ default:
+ ans.la_errno = EACCES;
+ break;
+ case nlm_denied:
+ if (pid_p == NULL)
+ ans.la_errno = EACCES;
+ else {
+ /* this is an answer to a nlm_test msg */
+ ans.la_set_getlk_pid = 1;
+ ans.la_getlk_pid = *pid_p;
+ ans.la_errno = 0;
+ }
+ break;
+ case nlm_denied_nolocks:
+ ans.la_errno = EAGAIN;
+ break;
+ case nlm_blocked:
+ return -1;
+ /* NOTREACHED */
+ case nlm_denied_grace_period:
+ ans.la_errno = EAGAIN;
+ break;
+ case nlm_deadlck:
+ ans.la_errno = EDEADLK;
+ break;
+ }
+
+ if (nfslockdans(LOCKD_ANS_VERSION, &ans)) {
+ syslog(((errno == EPIPE || errno == ESRCH) ?
+ LOG_INFO : LOG_ERR),
+ "process %lu: %m", (u_long)ans.la_msg_ident.pid);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * show --
+ * Display the contents of a kernel LOCKD_MSG structure.
+ */
+void
+show(LOCKD_MSG *mp)
+{
+ static char hex[] = "0123456789abcdef";
+ struct fid *fidp;
+ fsid_t *fsidp;
+ size_t len;
+ u_int8_t *p, *t, buf[NFS_SMALLFH*3+1];
+
+ printf("process ID: %lu\n", (long)mp->lm_msg_ident.pid);
+
+ fsidp = (fsid_t *)&mp->lm_fh;
+ fidp = (struct fid *)((u_int8_t *)&mp->lm_fh + sizeof(fsid_t));
+
+ for (t = buf, p = (u_int8_t *)mp->lm_fh,
+ len = mp->lm_fh_len;
+ len > 0; ++p, --len) {
+ *t++ = '\\';
+ *t++ = hex[(*p & 0xf0) >> 4];
+ *t++ = hex[*p & 0x0f];
+ }
+ *t = '\0';
+
+ printf("fh_len %d, fh %s\n", mp->lm_fh_len, buf);
+
+ /* Show flock structure. */
+ printf("start %qu; len %qu; pid %lu; type %d; whence %d\n",
+ mp->lm_fl.l_start, mp->lm_fl.l_len, (u_long)mp->lm_fl.l_pid,
+ mp->lm_fl.l_type, mp->lm_fl.l_whence);
+
+ /* Show wait flag. */
+ printf("wait was %s\n", mp->lm_wait ? "set" : "not set");
+}
diff --git a/usr.sbin/rpc.lockd/lock_proc.c b/usr.sbin/rpc.lockd/lock_proc.c
index 8b08fd0..4dbb6dc 100644
--- a/usr.sbin/rpc.lockd/lock_proc.c
+++ b/usr.sbin/rpc.lockd/lock_proc.c
@@ -634,10 +634,13 @@ nlm_granted_1_svc(arg, rqstp)
if (debug_level)
log_from_addr("nlm_granted", rqstp);
+ res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
+ nlm_granted, NULL, NLM_VERS) == 0 ?
+ nlm_granted : nlm_denied;
+
/* copy cookie from arg to result. See comment in nlm_test_1() */
res.cookie = arg->cookie;
- res.stat.stat = nlm_granted;
return (&res);
}
@@ -670,6 +673,8 @@ nlm_test_res_1_svc(arg, rqstp)
{
if (debug_level)
log_from_addr("nlm_test_res", rqstp);
+ (void)lock_answer(-1, &arg->cookie, arg->stat.stat,
+ &arg->stat.nlm_testrply_u.holder.svid, NLM_VERS);
return (NULL);
}
@@ -686,6 +691,8 @@ nlm_lock_res_1_svc(arg, rqstp)
if (debug_level)
log_from_addr("nlm_lock_res", rqstp);
+ (void)lock_answer(-1, &arg->cookie, arg->stat.stat, NULL, NLM_VERS);
+
return (NULL);
}
@@ -716,6 +723,9 @@ nlm_unlock_res_1_svc(arg, rqstp)
{
if (debug_level)
log_from_addr("nlm_unlock_res", rqstp);
+
+ lock_answer(&arg->cookie, arg->stat.stat, NLM_VERS);
+
return (NULL);
}
@@ -1077,10 +1087,13 @@ nlm4_granted_4_svc(arg, rqstp)
if (debug_level)
log_from_addr("nlm4_granted", rqstp);
+ res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
+ nlm4_granted, NULL, NLM_VERS4) == 0 ?
+ nlm4_granted : nlm4_denied;
+
/* copy cookie from arg to result. See comment in nlm_test_1() */
res.cookie = arg->cookie;
- res.stat.stat = nlm4_granted;
return (&res);
}
@@ -1113,6 +1126,10 @@ nlm4_test_res_4_svc(arg, rqstp)
{
if (debug_level)
log_from_addr("nlm4_test_res", rqstp);
+
+ (void)lock_answer(-1, &arg->cookie, arg->stat.stat,
+ (int *)&arg->stat.nlm4_testrply_u.holder.svid,
+ NLM_VERS4);
return (NULL);
}
@@ -1129,6 +1146,8 @@ nlm4_lock_res_4_svc(arg, rqstp)
if (debug_level)
log_from_addr("nlm4_lock_res", rqstp);
+ (void)lock_answer(-1, &arg->cookie, arg->stat.stat, NULL, NLM_VERS4);
+
return (NULL);
}
@@ -1268,7 +1287,7 @@ nlm4_nm_lock_4_svc(arg, rqstp)
*/
void *
nlm4_free_all_4_svc(arg, rqstp)
- nlm_notify *arg;
+ struct nlm4_notify *arg;
struct svc_req *rqstp;
{
static char dummy;
diff --git a/usr.sbin/rpc.lockd/lockd.c b/usr.sbin/rpc.lockd/lockd.c
index e0ac5cf..cd08f55 100644
--- a/usr.sbin/rpc.lockd/lockd.c
+++ b/usr.sbin/rpc.lockd/lockd.c
@@ -70,7 +70,11 @@ int debug_level = 0; /* 0 = no debugging syslog() calls */
int _rpcsvcdirty = 0;
int grace_expired;
+int nsm_state;
+pid_t client_pid;
+struct mon mon_host;
+void init_nsm(void);
int main __P((int, char **));
void nlm_prog_0 __P((struct svc_req *, SVCXPRT *));
void nlm_prog_1 __P((struct svc_req *, SVCXPRT *));
@@ -208,6 +212,10 @@ main(argc, argv)
exit(1);
}
+ init_nsm();
+
+ client_pid = client_request();
+
svc_run(); /* Should never return */
exit(1);
}
@@ -224,3 +232,50 @@ usage()
{
errx(1, "usage: rpc.lockd [-d <debuglevel>] [-g <grace period>]");
}
+
+/*
+ * init_nsm --
+ * Reset the NSM state-of-the-world and acquire its state.
+ */
+void
+init_nsm(void)
+{
+ enum clnt_stat ret;
+ my_id id;
+ sm_stat stat;
+
+ /*
+ * !!!
+ * The my_id structure isn't used by the SM_UNMON_ALL call, as far
+ * as I know. Leave it empty for now.
+ */
+ memset(&id, 0, sizeof(id));
+ id.my_name = "NFS NLM";
+
+ /*
+ * !!!
+ * The statd program must already be registered when lockd runs.
+ */
+ do {
+ ret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON_ALL,
+ xdr_my_id, &id, xdr_sm_stat, &stat);
+ if (ret == RPC_PROGUNAVAIL) {
+ warnx("%lu %s", SM_PROG, clnt_sperrno(ret));
+ sleep(2);
+ continue;
+ }
+ break;
+ } while (0);
+
+ if (ret != 0) {
+ errx(1, "%lu %s", SM_PROG, clnt_sperrno(ret));
+ }
+
+ nsm_state = stat.state;
+
+ /* setup constant data for SM_MON calls */
+ mon_host.mon_id.my_id.my_name = "localhost";
+ mon_host.mon_id.my_id.my_prog = NLM_PROG;
+ mon_host.mon_id.my_id.my_vers = NLM_SM;
+ mon_host.mon_id.my_id.my_proc = NLM_SM_NOTIFY; /* bsdi addition */
+}
diff --git a/usr.sbin/rpc.lockd/lockd.h b/usr.sbin/rpc.lockd/lockd.h
index 42f14f1..464ac3a 100644
--- a/usr.sbin/rpc.lockd/lockd.h
+++ b/usr.sbin/rpc.lockd/lockd.h
@@ -37,3 +37,6 @@
extern int debug_level;
extern int grace_expired;
void sigchild_handler __P((int));
+pid_t client_request(void);
+extern int nsm_state;
+extern pid_t client_pid;
diff --git a/usr.sbin/rpc.lockd/lockd_lock.c b/usr.sbin/rpc.lockd/lockd_lock.c
index 998a200..7a6c00d 100644
--- a/usr.sbin/rpc.lockd/lockd_lock.c
+++ b/usr.sbin/rpc.lockd/lockd_lock.c
@@ -162,7 +162,7 @@ getlock(lckarg, rqstp, flags)
syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno));
/* failed */
return (flags & LOCK_V4) ?
- nlm4_denied_nolock : nlm_denied_nolocks;
+ nlm4_denied_nolocks : nlm_denied_nolocks;
}
if (lckarg->alock.fh.n_len != sizeof(fhandle_t)) {
syslog(LOG_DEBUG, "recieved fhandle size %d, local size %d",
@@ -177,7 +177,7 @@ getlock(lckarg, rqstp, flags)
syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno));
free(newfl);
return (flags & LOCK_V4) ?
- nlm4_denied_nolock : nlm_denied_nolocks;
+ nlm4_denied_nolocks : nlm_denied_nolocks;
}
newfl->client.oh.n_len = lckarg->alock.oh.n_len;
memcpy(newfl->client.oh.n_bytes, lckarg->alock.oh.n_bytes,
@@ -191,7 +191,7 @@ getlock(lckarg, rqstp, flags)
free(newfl->client.oh.n_bytes);
free(newfl);
return (flags & LOCK_V4) ?
- nlm4_denied_nolock : nlm_denied_nolocks;
+ nlm4_denied_nolocks : nlm_denied_nolocks;
}
memcpy(newfl->client_cookie.n_bytes, lckarg->cookie.n_bytes,
lckarg->cookie.n_len);
@@ -462,7 +462,7 @@ do_lock(fl, block)
LIST_REMOVE(fl, lcklst);
close(fl->fd);
return (fl->flags & LOCK_V4) ?
- nlm4_denied_nolock : nlm_denied_nolocks;
+ nlm4_denied_nolocks : nlm_denied_nolocks;
case 0:
/*
* Attempt a blocking lock. Will have to call
OpenPOWER on IntegriCloud