Implement client side NFS locks.
Obtained from: BSD/os Import Ok'd by: mckusick, jkh, motd on builder.freebsd.org
This commit is contained in:
parent
0dfba3cef1
commit
603c86672c
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
269
sys/nfs/nfs_lock.c
Normal file
269
sys/nfs/nfs_lock.c
Normal file
@ -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);
|
||||
}
|
112
sys/nfs/nfs_lock.h
Normal file
112
sys/nfs/nfs_lock.h
Normal file
@ -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
|
@ -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
|
||||
*/
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/*
|
||||
|
45
sys/nfs/nlminfo.h
Normal file
45
sys/nfs/nlminfo.h
Normal file
@ -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));
|
||||
|
@ -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
|
||||
|
269
sys/nfsclient/nfs_lock.c
Normal file
269
sys/nfsclient/nfs_lock.c
Normal file
@ -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);
|
||||
}
|
112
sys/nfsclient/nfs_lock.h
Normal file
112
sys/nfsclient/nfs_lock.h
Normal file
@ -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
|
@ -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
|
||||
*/
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
45
sys/nfsclient/nlminfo.h
Normal file
45
sys/nfsclient/nlminfo.h
Normal file
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
586
usr.sbin/rpc.lockd/kern.c
Normal file
586
usr.sbin/rpc.lockd/kern.c
Normal file
@ -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");
|
||||
}
|
@ -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;
|
||||
|
@ -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 */
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user