HFILES = ifconfig.h
-CFILES = ifconfig.c ifmedia.c
+CFILES = ifconfig.c ifmedia.c ifvlan.c
OTHERSRCS = Makefile.preamble Makefile Makefile.dist ifconfig.8\
Makefile.postamble
PROF_LIBS = $(LIBS)
+HEADER_PATHS = -I$(NEXT_ROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders
NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
-include Makefile.postamble
-include Makefile.dependencies
+
OTHER_GENERATED_OFILES = $(VERS_OFILE)
-include ../Makefile.include
-OTHER_CFLAGS += -DUSE_IF_MEDIA -DINET6 -DNO_IPX
+OTHER_CFLAGS += -DUSE_IF_MEDIA -DINET6 -DNO_IPX -DUSE_VLANS
H_FILES = (ifconfig.h);
M_FILES = ();
OTHER_LIBS = ();
- OTHER_LINKED = (ifconfig.c, ifmedia.c);
+ OTHER_LINKED = (ifconfig.c, ifmedia.c, ifvlan.c);
OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.dist, ifconfig.8, Makefile.postamble);
PRECOMPILED_HEADERS = ();
PROJECT_HEADERS = ();
Create the specified network pseudo-device.
If the interface is given without a unit number, try to create a new
device with an arbitrary unit number.
-If creation of an arbitrary device is sucessful, the new device name is
+If creation of an arbitrary device is successful, the new device name is
printed to standard output.
.It Cm destroy
Destroy the specified network pseudo-device.
Included for
.Tn Solaris
compatibility.
+.It Cm vlan Ar vlan_tag
+If the interface is a vlan pseudo interface, set the vlan tag value
+to
+.Ar vlan_tag .
+This value is a 16-bit number which is used to create an 802.1Q
+vlan header for packets sent from the vlan interface.
+Note that
+.Cm vlan
+and
+.Cm vlandev
+must both be set at the same time.
+.It Cm vlandev Ar iface
+If the interface is a vlan pseudo device, associate physical interface
+.Ar iface
+with it.
+Packets transmitted through the vlan interface will be
+diverted to the specified physical interface
+.Ar iface
+with 802.1Q vlan encapsulation.
+Packets with 802.1Q encapsulation received
+by the parent interface with the correct vlan tag will be diverted to
+the associated vlan pseudo-interface.
+The vlan interface is assigned a
+copy of the parent interface's flags and the parent's ethernet address.
+The
+.Cm vlandev
+and
+.Cm vlan
+must both be set at the same time.
+If the vlan interface already has
+a physical interface associated with it, this command will fail.
+To
+change the association to another physical interface, the existing
+association must be cleared first.
+.Pp
+Note: if the hardware tagging capability
+is set on the vlan interface, the vlan pseudo
+interface's behavior changes:
+the vlan interface recognizes that the
+parent interface supports insertion and extraction of vlan tags on its
+own (usually in firmware) and that it should pass packets to and from
+the parent unaltered.
+.It Fl vlandev Ar iface
+If the driver is a vlan pseudo device, disassociate the physical interface
+.Ar iface
+from it.
+This breaks the link between the vlan interface and its parent,
+clears its vlan tag, flags and its link address and shuts the interface down.
.It Cm metric Ar n
Set the routing metric of the interface to
.Ar n ,
static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94";
#endif
static const char rcsid[] =
- "$Id: ifconfig.c,v 1.5 2003/07/02 01:22:29 lindak Exp $";
+ "$Id: ifconfig.c,v 1.5.28.1 2004/04/14 00:27:17 lindak Exp $";
#endif /* not lint */
#include <sys/param.h>
+#define KERNEL_PRIVATE
#include <sys/ioctl.h>
+#undef KERNEL_PRIVATE
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <string.h>
#include <unistd.h>
+struct ether_addr *ether_aton __P((const char *));
+
#include "ifconfig.h"
/* wrapper for KAME-special getnameinfo() */
#endif
c_func setifipdst;
c_func setifflags, setifmetric, setifmtu, setiflladdr;
+c_func clone_destroy;
+void clone_create(void);
#define NEXTARG 0xffffff
#define NEXTARG2 0xfffffe
{"create", 0, clone_create },
{"plumb", 0, clone_create },
#endif
-#ifndef __APPLE__
{"destroy", 0, clone_destroy },
{"unplumb", 0, clone_destroy },
-#endif
#ifdef USE_IEEE80211
{ "ssid", NEXTARG, set80211ssid },
{ "nwid", NEXTARG, set80211ssid },
usage()
{
#ifndef INET6
- fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
- "usage: ifconfig interface address_family [address [dest_address]]",
- " [parameters]",
- " ifconfig interface create",
- " ifconfig -a [-d] [-m] [-u] [address_family]",
- " ifconfig -l [-d] [-u] [address_family]",
- " ifconfig [-d] [-m] [-u]");
+ fprintf(stderr, "%s",
+ "usage: ifconfig interface address_family [address [dest_address]]\n"
+ " [parameters]\n"
+ " ifconfig interface create\n"
+ " ifconfig -a [-d] [-m] [-u] [address_family]\n"
+ " ifconfig -l [-d] [-u] [address_family]\n"
+ " ifconfig [-d] [-m] [-u]\n");
#else
- fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
- "usage: ifconfig [-L] interface address_family [address [dest_address]]",
- " [parameters]",
- " ifconfig interface create",
- " ifconfig -a [-L] [-d] [-m] [-u] [address_family]",
- " ifconfig -l [-d] [-u] [address_family]",
- " ifconfig [-L] [-d] [-m] [-u]");
+ fprintf(stderr, "%s",
+ "usage: ifconfig [-L] interface address_family [address [dest_address]]\n"
+ " [parameters]\n"
+ " ifconfig interface create\n"
+ " ifconfig -a [-L] [-d] [-m] [-u] [address_family]\n"
+ " ifconfig -l [-d] [-u] [address_family]\n"
+ " ifconfig [-L] [-d] [-m] [-u]\n");
#endif
exit(1);
}
*/
if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
strcmp(argv[0], "plumb") == 0)) {
-#ifndef __APPLE__
clone_create();
-#endif
argc--, argv++;
if (argc == 0)
exit(0);
}
#define RIDADDR 0
#define ADDR 1
-#define MASK 2
+#define NMASK 2
#define DSTADDR 3
/*ARGSUSED*/
if (*afp->af_getaddr == NULL)
return;
setmask++;
- (*afp->af_getaddr)(addr, MASK);
+ (*afp->af_getaddr)(addr, NMASK);
}
#ifdef INET6
const struct afswtch *afp;
{
if (*afp->af_getprefix)
- (*afp->af_getprefix)(addr, MASK);
+ (*afp->af_getprefix)(addr, NMASK);
explicit_prefix = 1;
}
struct netent *np;
sin->sin_len = sizeof(*sin);
- if (which != MASK)
+ if (which != NMASK)
sin->sin_family = AF_INET;
if (which == ADDR) {
/* address is `name/masklen' */
int masklen;
int ret;
- struct sockaddr_in *min = sintab[MASK];
+ struct sockaddr_in *min = sintab[NMASK];
*p = '\0';
ret = sscanf(p+1, "%u", &masklen);
if(ret != 1 || (masklen < 0 || masklen > 32)) {
newaddr &= 1;
sin->sin6_len = sizeof(*sin);
- if (which != MASK)
+ if (which != NMASK)
sin->sin6_family = AF_INET6;
if (which == ADDR) {
char *p = NULL;
if((p = strrchr(s, '/')) != NULL) {
*p = '\0';
- in6_getprefix(p + 1, MASK);
+ in6_getprefix(p + 1, NMASK);
explicit_prefix = 1;
}
}
if ((len < 0) || (len > 128))
errx(1, "%s: bad value", plen);
sin->sin6_len = sizeof(*sin);
- if (which != MASK)
+ if (which != NMASK)
sin->sin6_family = AF_INET6;
if ((len == 0) || (len == 128)) {
memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
ea = ether_aton(addr);
if (ea == NULL)
errx(1, "malformed ether address");
- if (which == MASK)
+ if (which == NMASK)
errx(1, "Ethernet does not use netmasks");
sea->sa_family = AF_LINK;
sea->sa_len = ETHER_ADDR_LEN;
}
#endif /*INET6*/
+void
+clone_create(void)
+{
+ int s;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s == -1)
+ err(1, "socket");
+
+ memset(&ifr, 0, sizeof(ifr));
+ (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCIFCREATE, &ifr) < 0)
+ err(1, "SIOCIFCREATE");
+
+ if (strcmp(name, ifr.ifr_name) != 0) {
+ printf("%s\n", ifr.ifr_name);
+ strlcpy(name, ifr.ifr_name, sizeof(name));
+ }
+
+ close(s);
+}
+
+void
+clone_destroy(const char *val, int d, int s, const struct afswtch *rafp)
+{
+
+ (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
+ err(1, "SIOCIFDESTROY");
+}
*
* so there!
*
- * $Id: ifconfig.h,v 1.1.1.1 2000/01/11 01:48:49 wsanchez Exp $
+ * $Id: ifconfig.h,v 1.1.1.1.140.1 2004/04/14 00:27:17 lindak Exp $
*/
extern struct ifreq ifr;
extern void setmediaopt(const char *, int, int, const struct afswtch *rafp);
extern void unsetmediaopt(const char *, int, int, const struct afswtch *rafp);
extern void media_status(int s, struct rt_addrinfo *);
+
+extern void setvlantag(const char *, int, int, const struct afswtch *rafp);
+extern void setvlandev(const char *, int, int, const struct afswtch *rafp);
+extern void unsetvlandev(const char *, int, int, const struct afswtch *rafp);
+extern void vlan_status(int s, struct rt_addrinfo *);
+
--- /dev/null
+/*
+ * Copyright (c) 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``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 Bill Paul OR THE VOICES IN HIS HEAD
+ * 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.
+ */
+
+#include <sys/param.h>
+#define KERNEL_PRIVATE
+#include <sys/ioctl.h>
+#undef KERNEL_PRIVATE
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_vlan_var.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+static int __tag = 0;
+static int __have_tag = 0;
+
+void
+vlan_status(int s, struct rt_addrinfo *info __unused)
+{
+ struct vlanreq vreq;
+
+ bzero((char *)&vreq, sizeof(struct vlanreq));
+ ifr.ifr_data = (caddr_t)&vreq;
+
+ if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
+ return;
+
+ printf("\tvlan: %d parent interface: %s\n",
+ vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ?
+ "<none>" : vreq.vlr_parent);
+
+ return;
+}
+
+void
+setvlantag(const char *val, int d, int s, const struct afswtch *afp)
+{
+ u_int16_t tag;
+ struct vlanreq vreq;
+
+ __tag = tag = atoi(val);
+ __have_tag = 1;
+
+ bzero((char *)&vreq, sizeof(struct vlanreq));
+ ifr.ifr_data = (caddr_t)&vreq;
+
+ if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGETVLAN");
+
+ vreq.vlr_tag = tag;
+
+ if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETVLAN");
+
+ return;
+}
+
+void
+setvlandev(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct vlanreq vreq;
+
+ if (!__have_tag)
+ errx(1, "must specify both vlan tag and device");
+
+ bzero((char *)&vreq, sizeof(struct vlanreq));
+ ifr.ifr_data = (caddr_t)&vreq;
+
+ if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGETVLAN");
+
+ strncpy(vreq.vlr_parent, val, sizeof(vreq.vlr_parent));
+ vreq.vlr_tag = __tag;
+
+ if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETVLAN");
+
+ return;
+}
+
+void
+unsetvlandev(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct vlanreq vreq;
+
+ bzero((char *)&vreq, sizeof(struct vlanreq));
+ ifr.ifr_data = (caddr_t)&vreq;
+
+ if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGETVLAN");
+
+ bzero((char *)&vreq.vlr_parent, sizeof(vreq.vlr_parent));
+ vreq.vlr_tag = 0;
+
+ if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETVLAN");
+
+ return;
+}
{
X509 *x509;
u_char *bp;
- vchar_t pubkey;
+ EVP_PKEY *evp;
bp = cert->v;
return -1;
}
- pubkey.v = x509->cert_info->key->public_key->data;
- pubkey.l = x509->cert_info->key->public_key->length;
-
- return eay_rsa_verify(source, sig, &pubkey);
+ evp = X509_get_pubkey(x509);
+ if (!evp) {
+ plog(LLV_ERROR, LOCATION, NULL, "X509_get_pubkey: %s\n", eay_strerror());
+ return -1;
+ }
+
+ return eay_rsa_verify(source, sig, evp);
}
/*
}
int
-eay_rsa_verify(src, sig, pubkey)
- vchar_t *src, *sig, *pubkey;
-{
+eay_rsa_verify(src, sig, evp)
+ vchar_t *src, *sig;
EVP_PKEY *evp;
- u_char *bp = pubkey->v;
+{
vchar_t *xbuf = NULL;
int pad = RSA_PKCS1_PADDING;
int len = 0;
int error;
- evp = d2i_PUBKEY(NULL, &bp, pubkey->l);
- if (evp == NULL)
-#ifndef EAYDEBUG
- return NULL;
-#endif
-
len = RSA_size(evp->pkey.rsa);
xbuf = vmalloc(len);
* SUCH DAMAGE.
*/
+#ifdef HAVE_OPENSSL_EVP_H
+#include <openssl/evp.h>
+#endif
+
#ifdef HAVE_SIGNING_C
/* X509 Certificate */
#define GENT_OTHERNAME 0
/* RSA */
extern vchar_t *eay_rsa_sign __P((vchar_t *, vchar_t *));
-extern int eay_rsa_verify __P((vchar_t *, vchar_t *, vchar_t *));
+extern int eay_rsa_verify __P((vchar_t *, vchar_t *, EVP_PKEY *));
/* ASN.1 */
extern vchar_t *eay_get_pkcs1privkey __P((char *));
plog(LLV_ERROR, LOCATION, (struct sockaddr *)&remote,
"packet shorter than isakmp header size.\n");
/* dummy receive */
+ if ((len = recvfrom(so_isakmp, (char *)&isakmp, sizeof(isakmp),
+ 0, (struct sockaddr *)&remote, &remote_len)) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to receive isakmp packet\n");
+ }
+ goto end;
+ }
+
+ /* reject if the size is toooo big */
+ if (ntohl(isakmp.len) > 0xffff) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "the length of the isakmp header is too big.\n");
if ((len = recvfrom(so_isakmp, (char *)&isakmp, sizeof(isakmp),
0, (struct sockaddr *)&remote, &remote_len)) < 0) {
plog(LLV_ERROR, LOCATION, NULL,
#include "lockd.h"
#include "lockd_lock.h"
-#define DAEMON_USERNAME "daemon"
-
#define nfslockdans(_v, _ansp) \
- ((_ansp)->la_vers = (_v), \
+ ((_ansp)->la_version = (_v), \
nfsclnt(NFSCLNT_LOCKDANS, (_ansp)))
static void client_cleanup(void);
static void set_auth(CLIENT *cl, struct xucred *ucred);
int lock_request(LOCKD_MSG *);
+int cancel_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
- */
-#define lockd_seteuid(uid) seteuid(uid)
-
#define d_calls (debug_level > 1)
#define d_args (debug_level > 2)
void
client_cleanup(void)
{
- (void)lockd_seteuid(0);
(void) nfsclnt(NFSCLNT_LOCKDFD, (struct lockd_ans *)-1);
exit(-1);
}
#endif
int fd, nr, ret;
pid_t child;
- uid_t daemon_uid;
mode_t old_umask;
- struct passwd *pw;
/* Recreate the NLM fifo. */
(void)unlink(_PATH_LCKFIFO);
/* Open the fifo for reading. */
if ((fd = open(_PATH_LCKFIFO, O_RDONLY | O_NONBLOCK)) == -1) {
syslog(LOG_ERR, "open: %s: %m", _PATH_LCKFIFO);
- goto err;
+ _exit (1);
}
(void)unlink(_PATH_LCKFIFO);
if (nfsclnt(NFSCLNT_LOCKDFD, (struct lockd_ans *)fd)) {
syslog(LOG_ERR, "nfsclnt_fd: %d: %m", fd);
- goto err;
+ _exit (1);
}
- pw = getpwnam(DAEMON_USERNAME);
- if (pw == NULL) {
- syslog(LOG_ERR, "getpwnam: %s: %m", DAEMON_USERNAME);
- goto err;
- }
- daemon_uid = pw->pw_uid;
- /* drop our root priviledges */
- (void)lockd_seteuid(daemon_uid);
for (;;) {
#ifndef USE_NFSLOCKDWAIT_INSTEAD_OF_SELECT
switch (msg.lm_fl.l_type) {
case F_RDLCK:
case F_WRLCK:
- if (msg.lm_getlk)
+ if (msg.lm_flags & LOCKD_MSG_TEST)
ret = test_request(&msg);
+ else if (msg.lm_flags & LOCKD_MSG_CANCEL)
+ ret = cancel_request(&msg);
else
ret = lock_request(&msg);
break;
if (ret) {
struct lockd_ans ans;
- ans.la_msg_ident = msg.lm_msg_ident;
+ ans.la_xid = msg.lm_xid;
ans.la_errno = ENOTSUP;
if (nfslockdans(LOCKD_ANS_VERSION, &ans)) {
syslog(LOG_DEBUG, "process %lu: %m",
- (u_long)msg.lm_msg_ident.pid);
+ (u_long)msg.lm_fl.l_pid);
}
}
} else if (nr == -1) {
/* Reached only on error. */
err:
- (void)lockd_seteuid(0);
(void) nfsclnt(NFSCLNT_LOCKDFD, (struct lockd_ans *)-1);
_exit (1);
return 0;
if (d_calls)
syslog(LOG_DEBUG, "test request: %s: %s to %s",
- msg->lm_nfsv3 ? "V4" : "V1/3",
+ (msg->lm_flags & LOCKD_MSG_NFSV3) ? "V4" : "V1/3",
msg->lm_fl.l_type == F_WRLCK ? "write" : "read",
from_addr((struct sockaddr *)&msg->lm_addr));
- if (msg->lm_nfsv3) {
+ if (msg->lm_flags & LOCKD_MSG_NFSV3) {
struct nlm4_testargs arg4;
- arg4.cookie.n_bytes = (char *)&msg->lm_msg_ident;
- arg4.cookie.n_len = sizeof(msg->lm_msg_ident);
+ arg4.cookie.n_bytes = (char *)&msg->lm_xid;
+ arg4.cookie.n_len = sizeof(msg->lm_xid);
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.svid = msg->lm_fl.l_pid;
arg4.alock.l_offset = msg->lm_fl.l_start;
arg4.alock.l_len = msg->lm_fl.l_len;
return (1);
set_auth(cli, &msg->lm_cred);
- (void)clnt_call(cli, NLM_TEST_MSG,
+ (void)clnt_call(cli, NLM4_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.cookie.n_bytes = (char *)&msg->lm_xid;
+ arg.cookie.n_len = sizeof(msg->lm_xid);
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.svid = msg->lm_fl.l_pid;
arg.alock.l_offset = msg->lm_fl.l_start;
arg.alock.l_len = msg->lm_fl.l_len;
if (d_calls)
syslog(LOG_DEBUG, "lock request: %s: %s to %s",
- msg->lm_nfsv3 ? "V4" : "V1/3",
+ (msg->lm_flags & LOCKD_MSG_NFSV3) ? "V4" : "V1/3",
msg->lm_fl.l_type == F_WRLCK ? "write" : "read",
from_addr((struct sockaddr *)&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;
+ if (msg->lm_flags & LOCKD_MSG_NFSV3) {
+ arg4.cookie.n_bytes = (char *)&msg->lm_xid;
+ arg4.cookie.n_len = sizeof(msg->lm_xid);
+ arg4.block = (msg->lm_flags & LOCKD_MSG_BLOCK) ? 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.svid = msg->lm_fl.l_pid;
arg4.alock.l_offset = msg->lm_fl.l_start;
arg4.alock.l_len = msg->lm_fl.l_len;
arg4.reclaim = 0;
return (1);
set_auth(cli, &msg->lm_cred);
- (void)clnt_call(cli, NLM_LOCK_MSG,
+ (void)clnt_call(cli, NLM4_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.cookie.n_bytes = (char *)&msg->lm_xid;
+ arg.cookie.n_len = sizeof(msg->lm_xid);
+ arg.block = (msg->lm_flags & LOCKD_MSG_BLOCK) ? 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.svid = msg->lm_fl.l_pid;
arg.alock.l_offset = msg->lm_fl.l_start;
arg.alock.l_len = msg->lm_fl.l_len;
arg.reclaim = 0;
return (0);
}
+/*
+ * cancel_request --
+ * Convert a lock LOCKD_MSG into an NLM request, and send it off.
+ */
+int
+cancel_request(LOCKD_MSG *msg)
+{
+ CLIENT *cli;
+ struct nlm4_cancargs arg4;
+ struct nlm_cancargs arg;
+ struct timeval timeout = {0, 0}; /* No timeout, no response. */
+ char dummy;
+
+ if (d_calls)
+ syslog(LOG_DEBUG, "cancel request: %s: %s to %s",
+ (msg->lm_flags & LOCKD_MSG_NFSV3) ? "V4" : "V1/3",
+ msg->lm_fl.l_type == F_WRLCK ? "write" : "read",
+ from_addr((struct sockaddr *)&msg->lm_addr));
+
+ if (msg->lm_flags & LOCKD_MSG_NFSV3) {
+ arg4.cookie.n_bytes = (char *)&msg->lm_xid;
+ arg4.cookie.n_len = sizeof(msg->lm_xid);
+ arg4.block = (msg->lm_flags & LOCKD_MSG_BLOCK) ? 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_fl.l_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, NLM4_CANCEL_MSG,
+ xdr_nlm4_cancargs, &arg4, xdr_void, &dummy, timeout);
+ } else {
+ arg.cookie.n_bytes = (char *)&msg->lm_xid;
+ arg.cookie.n_len = sizeof(msg->lm_xid);
+ arg.block = (msg->lm_flags & LOCKD_MSG_BLOCK) ? 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_fl.l_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_CANCEL_MSG,
+ xdr_nlm_cancargs, &arg, xdr_void, &dummy, timeout);
+ }
+ return (0);
+}
+
/*
* unlock_request --
* Convert an unlock LOCKD_MSG into an NLM request, and send it off.
if (d_calls)
syslog(LOG_DEBUG, "unlock request: %s: to %s",
- msg->lm_nfsv3 ? "V4" : "V1/3",
+ (msg->lm_flags & LOCKD_MSG_NFSV3) ? "V4" : "V1/3",
from_addr((struct sockaddr *)&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);
+ if (msg->lm_flags & LOCKD_MSG_NFSV3) {
+ arg4.cookie.n_bytes = (char *)&msg->lm_xid;
+ arg4.cookie.n_len = sizeof(msg->lm_xid);
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.svid = msg->lm_fl.l_pid;
arg4.alock.l_offset = msg->lm_fl.l_start;
arg4.alock.l_len = msg->lm_fl.l_len;
return (1);
set_auth(cli, &msg->lm_cred);
- (void)clnt_call(cli, NLM_UNLOCK_MSG,
+ (void)clnt_call(cli, NLM4_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.cookie.n_bytes = (char *)&msg->lm_xid;
+ arg.cookie.n_len = sizeof(msg->lm_xid);
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.svid = msg->lm_fl.l_pid;
arg.alock.l_offset = msg->lm_fl.l_start;
arg.alock.l_len = msg->lm_fl.l_len;
}
int
-lock_answer(int pid, netobj *netcookie, int result, int version,
- int *pid_p, off_t l_start, off_t l_len)
+lock_answer(int version, netobj *netcookie, nlm4_lock *lock, int flags, int result)
{
struct lockd_ans ans;
- if (netcookie->n_len != sizeof(ans.la_msg_ident)) {
- if (pid == -1) { /* we're screwed */
+ ans.la_flags = 0;
+ if (flags & LOCK_ANSWER_GRANTED)
+ ans.la_flags |= LOCKD_ANS_GRANTED;
+
+ if (netcookie->n_len != sizeof(ans.la_xid)) {
+ if (lock == NULL) { /* we're screwed */
syslog(LOG_ERR, "inedible nlm cookie");
return -1;
}
- ans.la_msg_ident.pid = pid;
- ans.la_msg_ident.msg_seq = -1;
+ /* no/bad cookie - need to copy lock info to identify request */
+ ans.la_xid = 0;
+ /* copy lock info */
+ ans.la_fh_len = lock->fh.n_len;
+ if (!lock->fh.n_len || (lock->fh.n_len > NFS_SMALLFH)) {
+ syslog(LOG_ERR, "bogus filehandle size %d in answer", lock->fh.n_len);
+ return -1;
+ }
+ memcpy(ans.la_fh, lock->fh.n_bytes, ans.la_fh_len);
+ ans.la_pid = lock->svid;
+ ans.la_start = lock->l_offset;
+ ans.la_len = lock->l_len;
+ ans.la_flags |= LOCKD_ANS_LOCK_INFO;
+ if (flags & LOCK_ANSWER_LOCK_EXCL)
+ ans.la_flags |= LOCKD_ANS_LOCK_EXCL;
} else {
- memcpy(&ans.la_msg_ident, netcookie->n_bytes,
- sizeof(ans.la_msg_ident));
+ memcpy(&ans.la_xid, netcookie->n_bytes, sizeof(ans.la_xid));
+ ans.la_fh_len = 0;
}
if (d_calls)
syslog(LOG_DEBUG, "lock answer: pid %lu: %s %d",
- (unsigned long)ans.la_msg_ident.pid,
+ (unsigned long)ans.la_pid,
version == NLM_VERS4 ? "nlmv4" : "nlmv3",
result);
- ans.la_getlk_set = 0;
if (version == NLM_VERS4)
switch (result) {
case nlm4_granted:
ans.la_errno = 0;
+ if ((flags & LOCK_ANSWER_GRANTED) && lock &&
+ !(ans.la_flags & LOCKD_ANS_LOCK_INFO)) {
+ /* copy lock info */
+ ans.la_fh_len = lock->fh.n_len;
+ if (!lock->fh.n_len || (lock->fh.n_len > NFS_SMALLFH)) {
+ syslog(LOG_ERR, "bogus filehandle size %d in answer", lock->fh.n_len);
+ return -1;
+ }
+ memcpy(ans.la_fh, lock->fh.n_bytes, ans.la_fh_len);
+ ans.la_pid = lock->svid;
+ ans.la_start = lock->l_offset;
+ ans.la_len = lock->l_len;
+ ans.la_flags |= LOCKD_ANS_LOCK_INFO;
+ if (flags & LOCK_ANSWER_LOCK_EXCL)
+ ans.la_flags |= LOCKD_ANS_LOCK_EXCL;
+ }
break;
default:
ans.la_errno = EACCES;
break;
case nlm4_denied:
- if (pid_p == NULL)
+ if (lock == NULL)
ans.la_errno = EACCES;
else {
/* this is an answer to a nlm_test msg */
- ans.la_getlk_set = 1;
- ans.la_getlk_pid = *pid_p;
- ans.la_getlk_start = l_start;
- ans.la_getlk_len = l_len;
+ ans.la_pid = lock->svid;
+ ans.la_start = lock->l_offset;
+ ans.la_len = lock->l_len;
+ ans.la_flags |= LOCKD_ANS_LOCK_INFO;
+ if (flags & LOCK_ANSWER_LOCK_EXCL)
+ ans.la_flags |= LOCKD_ANS_LOCK_EXCL;
ans.la_errno = 0;
}
break;
ans.la_errno = ENOLCK;
break;
case nlm4_blocked:
- return -1;
- /* NOTREACHED */
+ ans.la_errno = EINPROGRESS;
+ break;
case nlm4_denied_grace_period:
ans.la_errno = EAGAIN;
break;
switch (result) {
case nlm_granted:
ans.la_errno = 0;
+ if ((flags & LOCK_ANSWER_GRANTED) && lock &&
+ !(ans.la_flags & LOCKD_ANS_LOCK_INFO)) {
+ /* copy lock info */
+ ans.la_fh_len = lock->fh.n_len;
+ if (!lock->fh.n_len || (lock->fh.n_len > NFS_SMALLFH)) {
+ syslog(LOG_ERR, "bogus filehandle size %d in answer", lock->fh.n_len);
+ return -1;
+ }
+ memcpy(ans.la_fh, lock->fh.n_bytes, ans.la_fh_len);
+ ans.la_pid = lock->svid;
+ ans.la_start = lock->l_offset;
+ ans.la_len = lock->l_len;
+ ans.la_flags |= LOCKD_ANS_LOCK_INFO;
+ if (flags & LOCK_ANSWER_LOCK_EXCL)
+ ans.la_flags |= LOCKD_ANS_LOCK_EXCL;
+ }
break;
default:
ans.la_errno = EACCES;
break;
case nlm_denied:
- if (pid_p == NULL)
+ if (lock == NULL)
ans.la_errno = EACCES;
else {
/* this is an answer to a nlm_test msg */
- ans.la_getlk_set = 1;
- ans.la_getlk_pid = *pid_p;
- ans.la_getlk_start = l_start;
- ans.la_getlk_len = l_len;
+ ans.la_pid = lock->svid;
+ ans.la_start = lock->l_offset;
+ ans.la_len = lock->l_len;
+ ans.la_flags |= LOCKD_ANS_LOCK_INFO;
+ if (flags & LOCK_ANSWER_LOCK_EXCL)
+ ans.la_flags |= LOCKD_ANS_LOCK_EXCL;
ans.la_errno = 0;
}
break;
ans.la_errno = ENOLCK;
break;
case nlm_blocked:
- return -1;
- /* NOTREACHED */
+ ans.la_errno = EINPROGRESS;
+ break;
case nlm_denied_grace_period:
ans.la_errno = EAGAIN;
break;
if (nfslockdans(LOCKD_ANS_VERSION, &ans)) {
syslog(LOG_DEBUG, "lock_answer(%d): process %lu: %m",
- result, (u_long)ans.la_msg_ident.pid);
+ result, (u_long)ans.la_pid);
return -1;
}
return 0;
size_t len;
u_int8_t *p, *t, buf[NFS_SMALLFH*3+1];
- syslog(LOG_DEBUG, "process ID: %lu\n", (long)mp->lm_msg_ident.pid);
+ syslog(LOG_DEBUG, "process ID: %lu\n", (long)mp->lm_fl.l_pid);
fsidp = (fsid_t *)&mp->lm_fh;
fidp = (struct fid *)((u_int8_t *)&mp->lm_fh + sizeof(fsid_t));
mp->lm_fl.l_type, mp->lm_fl.l_whence);
/* Show wait flag. */
- syslog(LOG_DEBUG, "wait was %s\n", mp->lm_wait ? "set" : "not set");
+ syslog(LOG_DEBUG, "wait was %s\n", (mp->lm_flags & LOCKD_MSG_BLOCK) ? "set" : "not set");
}
struct timeval retry_time, time_now;
int i;
int sock_no;
- char host[NI_MAXHOST];
gettimeofday(&time_now, NULL);
clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time);
if (debug_level > 3)
- syslog(LOG_DEBUG, "Created CLIENT* for %s", host);
+ syslog(LOG_DEBUG, "Created CLIENT* for %s",
+ inet_ntoa(((struct sockaddr_in *)host_addr)->sin_addr));
return client;
}
struct svc_req *rqstp;
{
static nlm_res res;
- struct nlm4_lock arg4;
+ struct nlm4_cancargs arg4;
- nlmtonlm4(&arg->alock, &arg4);
+ arg4.cookie = arg->cookie;
+ arg4.block = arg->block;
+ arg4.exclusive = arg->exclusive;
+ nlmtonlm4(&arg->alock, &arg4.alock);
if (debug_level)
log_from_addr("nlm_cancel", rqstp);
/* copy cookie from arg to result. See comment in nlm_test_1() */
res.cookie = arg->cookie;
- /*
- * Since at present we never return 'nlm_blocked', there can never be
- * a lock to cancel, so this call always fails.
- */
- res.stat.stat = unlock(&arg4, LOCK_CANCEL);
+ res.stat.stat = cancellock(&arg4, 0);
return (&res);
}
struct svc_req *rqstp;
{
static nlm_res res;
- struct nlm4_lock arg4;
+ struct nlm4_cancargs arg4;
- nlmtonlm4(&arg->alock, &arg4);
+ arg4.cookie = arg->cookie;
+ arg4.block = arg->block;
+ arg4.exclusive = arg->exclusive;
+ nlmtonlm4(&arg->alock, &arg4.alock);
if (debug_level)
log_from_addr("nlm_cancel_msg", rqstp);
res.cookie = arg->cookie;
- /*
- * Since at present we never return 'nlm_blocked', there can never be
- * a lock to cancel, so this call always fails.
- */
- res.stat.stat = unlock(&arg4, LOCK_CANCEL);
+ res.stat.stat = cancellock(&arg4, 0);
transmit_result(NLM_CANCEL_RES, &res,
(struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
return (NULL);
struct svc_req *rqstp;
{
static nlm_res res;
+ nlm4_lock lock4;
+ int flags;
if (debug_level)
log_from_addr("nlm_granted", rqstp);
- res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
- nlm_granted, NLM_VERS, NULL, 0, 0) == 0 ?
- nlm_granted : nlm_denied;
+ lock4.fh = arg->alock.fh;
+ lock4.svid = arg->alock.svid;
+ lock4.l_offset = arg->alock.l_offset;
+ lock4.l_len = arg->alock.l_len;
+
+ flags = LOCK_ANSWER_GRANTED;
+ if (arg->exclusive)
+ flags |= LOCK_ANSWER_LOCK_EXCL;
+
+ if (lock_answer(NLM_VERS, &arg->cookie, &lock4, flags, nlm_granted))
+ res.stat.stat = nlm_denied;
+ else
+ res.stat.stat = nlm_granted;
/* copy cookie from arg to result. See comment in nlm_test_1() */
res.cookie = arg->cookie;
struct svc_req *rqstp;
{
static nlm_res res;
+ nlm4_lock lock4;
+ int flags;
if (debug_level)
log_from_addr("nlm_granted_msg", rqstp);
- res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
- nlm_granted, NLM_VERS, NULL, 0, 0) == 0 ?
- nlm_granted : nlm_denied;
+ lock4.fh = arg->alock.fh;
+ lock4.svid = arg->alock.svid;
+ lock4.l_offset = arg->alock.l_offset;
+ lock4.l_len = arg->alock.l_len;
+
+ flags = LOCK_ANSWER_GRANTED;
+ if (arg->exclusive)
+ flags |= LOCK_ANSWER_LOCK_EXCL;
+
+ if (lock_answer(NLM_VERS, &arg->cookie, &lock4, flags, nlm_granted))
+ res.stat.stat = nlm_denied;
+ else
+ res.stat.stat = nlm_granted;
res.cookie = arg->cookie;
nlm_testres *arg;
struct svc_req *rqstp;
{
+ nlm4_lock lock4;
+ int flags = 0;
+
if (debug_level)
log_from_addr("nlm_test_res", rqstp);
- (void)lock_answer(-1, &arg->cookie, arg->stat.stat, NLM_VERS,
- &arg->stat.nlm_testrply_u.holder.svid,
- arg->stat.nlm_testrply_u.holder.l_offset,
- arg->stat.nlm_testrply_u.holder.l_len);
+
+ if (arg->stat.stat == nlm_denied) {
+ lock4.fh.n_len = 0;
+ lock4.svid = arg->stat.nlm_testrply_u.holder.svid;
+ lock4.l_offset = arg->stat.nlm_testrply_u.holder.l_offset;
+ lock4.l_len = arg->stat.nlm_testrply_u.holder.l_len;
+ if (arg->stat.nlm_testrply_u.holder.exclusive)
+ flags |= LOCK_ANSWER_LOCK_EXCL;
+ lock_answer(NLM_VERS, &arg->cookie, &lock4, flags, arg->stat.stat);
+ } else
+ lock_answer(NLM_VERS, &arg->cookie, NULL, 0, arg->stat.stat);
+
return (NULL);
}
if (debug_level)
log_from_addr("nlm_lock_res", rqstp);
- (void)lock_answer(-1, &arg->cookie, arg->stat.stat, NLM_VERS, NULL, 0, 0);
+ lock_answer(NLM_VERS, &arg->cookie, NULL, 0, arg->stat.stat);
return (NULL);
}
*/
void *
nlm_cancel_res_1_svc(arg, rqstp)
- nlm_res *arg __unused;
+ nlm_res *arg;
struct svc_req *rqstp;
{
if (debug_level)
log_from_addr("nlm_cancel_res", rqstp);
+
+ lock_answer(NLM_VERS, &arg->cookie, NULL, 0, arg->stat.stat);
+
return (NULL);
}
if (debug_level)
log_from_addr("nlm_unlock_res", rqstp);
- lock_answer(-1, &arg->cookie, arg->stat.stat, NLM_VERS, NULL, 0, 0);
+ lock_answer(NLM_VERS, &arg->cookie, NULL, 0, arg->stat.stat);
return (NULL);
}
*/
void *
nlm_granted_res_1_svc(arg, rqstp)
- nlm_res *arg __unused;
+ nlm_res *arg;
struct svc_req *rqstp;
{
if (debug_level)
log_from_addr("nlm_granted_res", rqstp);
- /* XXX should undo lock if granted msg wasn't accepted! */
+ /* need to undo lock if granted msg wasn't accepted! */
+ if (arg->stat.stat != nlm_granted) {
+ nlm4_res arg4;
+ arg4.cookie = arg->cookie;
+ arg4.stat.stat = arg->stat.stat;
+ granted_failed(&arg4);
+ }
return (NULL);
}
/* copy cookie from arg to result. See comment in nlm_test_1() */
res.cookie = arg->cookie;
- /*
- * Since at present we never return 'nlm_blocked', there can never be
- * a lock to cancel, so this call always fails.
- */
- res.stat.stat = unlock(&arg->alock, LOCK_CANCEL);
+ res.stat.stat = cancellock(arg, LOCK_V4);
return (&res);
}
log_from_addr("nlm4_cancel_msg", rqstp);
res.cookie = arg->cookie;
- /*
- * Since at present we never return 'nlm_blocked', there can never be
- * a lock to cancel, so this call always fails.
- */
- res.stat.stat = unlock(&arg->alock, LOCK_CANCEL | LOCK_V4);
+ res.stat.stat = cancellock(arg, LOCK_V4);
transmit4_result(NLM4_CANCEL_RES, &res,
(struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
return (NULL);
struct svc_req *rqstp;
{
static nlm4_res res;
+ int flags;
if (debug_level)
log_from_addr("nlm4_granted", rqstp);
- res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
- nlm4_granted, NLM_VERS4, NULL, 0, 0) == 0 ?
- nlm4_granted : nlm4_denied;
+ flags = LOCK_ANSWER_GRANTED;
+ if (arg->exclusive)
+ flags |= LOCK_ANSWER_LOCK_EXCL;
+
+ if (lock_answer(NLM_VERS4, &arg->cookie, &arg->alock, flags, nlm4_granted))
+ res.stat.stat = nlm4_denied;
+ else
+ res.stat.stat = nlm4_granted;
/* copy cookie from arg to result. See comment in nlm_test_1() */
res.cookie = arg->cookie;
struct svc_req *rqstp;
{
static nlm4_res res;
+ int flags;
if (debug_level)
log_from_addr("nlm4_granted_msg", rqstp);
- res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
- nlm4_granted, NLM_VERS4, NULL, 0, 0) == 0 ?
- nlm4_granted : nlm4_denied;
+ flags = LOCK_ANSWER_GRANTED;
+ if (arg->exclusive)
+ flags |= LOCK_ANSWER_LOCK_EXCL;
+
+ if (lock_answer(NLM_VERS4, &arg->cookie, &arg->alock, flags, nlm4_granted))
+ res.stat.stat = nlm4_denied;
+ else
+ res.stat.stat = nlm4_granted;
res.cookie = arg->cookie;
nlm4_testres *arg;
struct svc_req *rqstp;
{
+ nlm4_lock lock4;
+ int flags = 0;
+
if (debug_level)
log_from_addr("nlm4_test_res", rqstp);
- (void)lock_answer(-1, &arg->cookie, arg->stat.stat, NLM_VERS4,
- (int *)&arg->stat.nlm4_testrply_u.holder.svid,
- arg->stat.nlm4_testrply_u.holder.l_offset,
- arg->stat.nlm4_testrply_u.holder.l_len);
+ if (arg->stat.stat == nlm4_denied) {
+ lock4.fh.n_len = 0;
+ lock4.svid = arg->stat.nlm4_testrply_u.holder.svid;
+ lock4.l_offset = arg->stat.nlm4_testrply_u.holder.l_offset;
+ lock4.l_len = arg->stat.nlm4_testrply_u.holder.l_len;
+ if (arg->stat.nlm4_testrply_u.holder.exclusive)
+ flags |= LOCK_ANSWER_LOCK_EXCL;
+ lock_answer(NLM_VERS4, &arg->cookie, &lock4, flags, arg->stat.stat);
+ } else
+ lock_answer(NLM_VERS4, &arg->cookie, NULL, 0, arg->stat.stat);
+
return (NULL);
}
if (debug_level)
log_from_addr("nlm4_lock_res", rqstp);
- (void)lock_answer(-1, &arg->cookie, arg->stat.stat, NLM_VERS4, NULL, 0, 0);
+ lock_answer(NLM_VERS4, &arg->cookie, NULL, 0, arg->stat.stat);
return (NULL);
}
*/
void *
nlm4_cancel_res_4_svc(arg, rqstp)
- nlm4_res *arg __unused;
+ nlm4_res *arg;
struct svc_req *rqstp;
{
if (debug_level)
log_from_addr("nlm4_cancel_res", rqstp);
+
+ lock_answer(NLM_VERS4, &arg->cookie, NULL, 0, arg->stat.stat);
+
return (NULL);
}
{
if (debug_level)
log_from_addr("nlm4_unlock_res", rqstp);
+
+ lock_answer(NLM_VERS4, &arg->cookie, NULL, 0, arg->stat.stat);
+
return (NULL);
}
{
if (debug_level)
log_from_addr("nlm4_granted_res", rqstp);
- /* XXX should undo lock if granted msg wasn't accepted! */
+ /* need to undo lock if granted msg wasn't accepted! */
+ if (arg->stat.stat != nlm4_granted)
+ granted_failed(arg);
return (NULL);
}
void handle_sig_cleanup(int);
void sigalarm_handler(void);
+void my_svc_run(void);
const char *transports[] = { "udp", "tcp", "udp6", "tcp6" };
struct sigaction sigalarm;
int grace_period = 30;
- while ((ch = getopt(argc, argv, "d:g:w")) != (-1)) {
+ while ((ch = getopt(argc, argv, "d:g:wx:")) != (-1)) {
switch (ch) {
case 'd':
debug_level = atoi(optarg);
case 'w':
waitkern = 1;
break;
+ case 'x':
+ host_expire = atoi(optarg);
+ break;
default:
case '?':
usage();
nanosleep(&ts, NULL);
}
- openlog("rpc.lockd", 0, LOG_DAEMON);
+ openlog("rpc.lockd", debug_level == 99 ? LOG_PERROR : 0, LOG_DAEMON);
if (debug_level)
syslog(LOG_INFO, "Starting, debug level %d", debug_level);
else
client_pid = client_request();
- svc_run(); /* Should never return */
+ my_svc_run(); /* Should never return */
exit(1);
}
void
usage()
{
- errx(1, "usage: rpc.lockd [-d <debuglevel>] [-g <grace period>] [-w]");
+ errx(1, "usage: rpc.lockd [-d <debuglevel>] [-g <grace period>] "
+ " [-x <statd cache timeout>] [-w]");
}
/*
exit(1);
}
+void
+my_svc_run(void)
+{
+ fd_set readfds;
+ struct timeval timeout;
+ struct timeval now;
+ int error;
+ int hashosts = 0;
+ int tsize = 0;
+ struct timeval *top;
+
+
+ for( ;; ) {
+ timeout.tv_sec = host_expire + 1;
+ timeout.tv_usec = 0;
+
+ tsize = getdtablesize();
+ bcopy(&svc_fdset, &readfds, sizeof(svc_fdset));
+ /*
+ * If there are any expired hosts then sleep with a
+ * timeout to expire them.
+ */
+ if (hashosts && (timeout.tv_sec >= 0))
+ top = &timeout;
+ else
+ top = NULL;
+ error = select(tsize, &readfds, NULL, NULL, top);
+ if (error == -1) {
+ if (errno == EINTR)
+ continue;
+ perror("rpc.lockd: my_svc_run: select failed");
+ return;
+ }
+ gettimeofday(&now, NULL);
+ currsec = now.tv_sec;
+ if (error > 0)
+ svc_getreqset(&readfds);
+ if (debug_level > 3 && error == 0)
+ fprintf(stderr, "my_svc_run: select timeout\n");
+ hashosts = expire_lock_hosts();
+ }
+}
pid_t client_request(void);
extern int nsm_state;
extern pid_t client_pid;
+extern time_t currsec;
+extern int host_expire;
/* XXX these should be in some system headers */
typedef u_int32_t rpcvers_t;
int nfsclnt(int, void *);
extern int callrpc(const char *, int, int, int, xdrproc_t, void *, xdrproc_t , void *);
+int expire_lock_hosts(void);
+
netobj filehandle; /* NFS filehandle */
struct sockaddr *addr;
struct nlm4_holder client; /* lock holder */
- /* XXX: client_cookie used *only* in send_granted */
- netobj client_cookie; /* cookie sent by the client */
+ u_int64_t granted_cookie;
char client_name[SM_MAXSTRLEN];
int nsm_status; /* status from the remote lock manager */
int status; /* lock status, see below */
/* struct describing a monitored host */
struct host {
- LIST_ENTRY(host) hostlst;
+ TAILQ_ENTRY(host) hostlst;
char name[SM_MAXSTRLEN];
int refcnt;
+ time_t lastuse;
};
/* list of hosts we monitor */
-LIST_HEAD(hostlst_head, host);
-struct hostlst_head hostlst_head = LIST_HEAD_INITIALIZER(hostlst_head);
+TAILQ_HEAD(hostlst_head, host);
+struct hostlst_head hostlst_head = TAILQ_HEAD_INITIALIZER(hostlst_head);
+struct hostlst_head hostlst_unref = TAILQ_HEAD_INITIALIZER(hostlst_unref);
+
+int host_expire = 60; /* seconds */
+time_t currsec;
+u_int64_t send_granted_cookie = 0;
/*
* File monitoring handlers
enum partialfilelock_status lock_partialfilelock(struct file_lock *fl);
-void send_granted(struct file_lock *fl, int opcode);
+int send_granted(struct file_lock *fl, int opcode);
void siglock(void);
void sigunlock(void);
+void destroy_lock_host(struct host *ihp);
void monitor_lock_host(const char *hostname);
void unmonitor_lock_host(const char *hostname);
void copy_nlm4_lock_to_nlm4_holder(const struct nlm4_lock *src,
const bool_t exclusive, struct nlm4_holder *dest);
struct file_lock * allocate_file_lock(const netobj *lockowner,
- const netobj *matchcookie, const netobj *filehandle);
+ const netobj *filehandle);
void deallocate_file_lock(struct file_lock *fl);
void fill_file_lock(struct file_lock *fl,
struct sockaddr *addr, const bool_t exclusive, const int32_t svid,
struct file_lock **conflicting_fl);
void remove_blockingfilelock(struct file_lock *fl);
void clear_blockingfilelock(const char *hostname);
-void retry_blockingfilelocklist(void);
+void retry_blockingfilelocklist(netobj *fh);
enum partialfilelock_status unlock_partialfilelock(
const struct file_lock *fl);
void clear_partialfilelock(const char *hostname);
debuglog("Dumping client identity:\n");
dump_netobj(&fl->client.oh);
- debuglog("Dumping client cookie:\n");
- dump_netobj(&fl->client_cookie);
-
debuglog("nsm: %d status: %d flags: %d locker: %d"
" fd: %d\n", fl->nsm_status, fl->status,
fl->flags, fl->locker, fl->fd);
*/
struct file_lock *
-allocate_file_lock(const netobj *lockowner, const netobj *matchcookie, const netobj *filehandle)
+allocate_file_lock(const netobj *lockowner, const netobj *filehandle)
{
struct file_lock *newfl;
newfl->client.oh.n_len = lockowner->n_len;
bcopy(lockowner->n_bytes, newfl->client.oh.n_bytes, lockowner->n_len);
- newfl->client_cookie.n_bytes = malloc(matchcookie->n_len);
- if (newfl->client_cookie.n_bytes == NULL) {
- free(newfl->client.oh.n_bytes);
- free(newfl);
- return NULL;
- }
- newfl->client_cookie.n_len = matchcookie->n_len;
- bcopy(matchcookie->n_bytes, newfl->client_cookie.n_bytes, matchcookie->n_len);
-
newfl->filehandle.n_bytes = malloc(filehandle->n_len);
if (newfl->filehandle.n_bytes == NULL) {
- free(newfl->client_cookie.n_bytes);
free(newfl->client.oh.n_bytes);
free(newfl);
return NULL;
deallocate_file_lock(struct file_lock *fl)
{
free(fl->client.oh.n_bytes);
- free(fl->client_cookie.n_bytes);
free(fl->filehandle.n_bytes);
free(fl);
}
/*
* get_lock_matching_unlock: Return a lock which matches the given unlock lock
- * or NULL otehrwise
+ * or NULL otherwise
* XXX: It is a shame that this duplicates so much code from test_nfslock.
*/
struct file_lock *
&start1, &len1, &start2, &len2);
if ((spstatus & SPL_LOCK1) != 0) {
- *left_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->client_cookie,
- &exist_lock->filehandle);
+ *left_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->filehandle);
if (*left_lock == NULL) {
debuglog("Unable to allocate resource for split 1\n");
return SPL_RESERR;
}
if ((spstatus & SPL_LOCK2) != 0) {
- *right_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->client_cookie,
- &exist_lock->filehandle);
+ *right_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->filehandle);
if (*right_lock == NULL) {
debuglog("Unable to allocate resource for split 1\n");
if (*left_lock != NULL) {
void
add_blockingfilelock(struct file_lock *fl)
{
+ struct file_lock *ifl, *nfl;
debuglog("Entering add_blockingfilelock\n");
+ /*
+ * Check for a duplicate lock request.
+ * If found, deallocate the older request.
+ */
+ ifl = LIST_FIRST(&blockedlocklist_head);
+ for (; ifl != NULL; ifl = nfl) {
+ debuglog("Pointer to file lock: %p\n",ifl);
+ debuglog("****Dump of ifl****\n");
+ dump_filelock(ifl);
+ debuglog("*******************\n");
+
+ nfl = LIST_NEXT(ifl, nfslocklist);
+
+ if (fl->filehandle.n_len != ifl->filehandle.n_len)
+ continue;
+ if (bcmp(fl->filehandle.n_bytes, ifl->filehandle.n_bytes,
+ fl->filehandle.n_len))
+ continue;
+
+ /* Filehandles match, check region */
+ if ((fl->client.l_offset != ifl->client.l_offset) ||
+ (fl->client.l_len != ifl->client.l_len))
+ continue;
+
+ /* Regions match, check the identity */
+ if (!same_filelock_identity(fl,ifl))
+ continue;
+
+ debuglog("add_blockingfilelock: removing duplicate lock request.\n");
+ remove_blockingfilelock(ifl);
+ deallocate_file_lock(ifl);
+ break;
+ }
+
/*
* Clear the blocking flag so that it can be reused without
* adding it to the blocking queue a second time
}
}
+int need_retry_blocked_locks = 0; /* need to call retry_blockingfilelocklist() */
+
void
-retry_blockingfilelocklist(void)
+retry_blockingfilelocklist(netobj *fh)
{
- /* Retry all locks in the blocked list */
+ /*
+ * If fh is given, then retry just the locks with the
+ * same filehandle in the blocked list.
+ * Otherwise, simply retry all locks in the blocked list.
+ */
struct file_lock *ifl, *nfl, *pfl; /* Iterator */
enum partialfilelock_status pflstatus;
+ int rv;
debuglog("Entering retry_blockingfilelocklist\n");
+ need_retry_blocked_locks = 0;
+
pfl = NULL;
ifl = LIST_FIRST(&blockedlocklist_head);
debuglog("Iterator choice %p\n",ifl);
debuglog("Prev iterator choice %p\n",pfl);
debuglog("Next iterator choice %p\n",nfl);
+ /* if given a filehandle, only retry locks for the same filehandle */
+ if (fh && !same_netobj(fh, &ifl->filehandle)) {
+ ifl = nfl;
+ continue;
+ }
+
/*
* SUBTLE BUG: The file_lock must be removed from the
* old list so that it's list pointers get disconnected
if (pflstatus == PFL_GRANTED || pflstatus == PFL_GRANTED_DUPLICATE) {
debuglog("Granted blocked lock\n");
/* lock granted and is now being used */
- send_granted(ifl,0);
- /* XXX should undo lock if send_granted fails */
+ rv = send_granted(ifl, 0);
+ if (rv) {
+ /*
+ * Uh oh... the NLM_GRANTED message failed.
+ * About the only thing we can do is drop the lock.
+ * Note: this could be bad if the error was only
+ * transient. Hopefully, if the client is still
+ * waiting for the lock, they will resend the request.
+ */
+ do_unlock(ifl);
+ /* ifl is NO LONGER VALID AT THIS POINT */
+ }
} else {
/* Reinsert lock back into same place in blocked list */
debuglog("Replacing blocked lock\n");
LIST_INSERT_HEAD(&blockedlocklist_head, ifl, nfslocklist);
}
+ if (pflstatus == PFL_GRANTED || pflstatus == PFL_GRANTED_DUPLICATE) {
+ /* If ifl was permanently removed from the list, (e.g the */
+ /* lock was granted), pfl should remain where it's at. */
+ } else {
+ /* If ifl was left in the list, (e.g it was reinserted back */
+ /* in place), pfl should simply be moved forward to be ifl */
+ pfl = ifl;
+ }
/* Valid increment behavior regardless of state of ifl */
ifl = nfl;
- /* if a lock was granted incrementing pfl would make it nfl */
- if (pfl != NULL && (LIST_NEXT(pfl, nfslocklist) != nfl))
- pfl = LIST_NEXT(pfl, nfslocklist);
- else
- pfl = LIST_FIRST(&blockedlocklist_head);
}
debuglog("Exiting retry_blockingfilelocklist\n");
// XXX Workaround is to move this to nlm_prot_svc.c
// XXX after the unlock response is sent.
// retry_blockingfilelocklist();
+ need_retry_blocked_locks = 1;
break;
case NFS_DENIED_NOLOCK:
retval = PFL_GRANTED;
nlm4_denied_grace_period : nlm_denied_grace_period;
/* allocate new file_lock for this request */
- newfl = allocate_file_lock(&lckarg->alock.oh, &lckarg->cookie, &lckarg->alock.fh);
+ newfl = allocate_file_lock(&lckarg->alock.oh, &lckarg->alock.fh);
if (newfl == NULL) {
syslog(LOG_NOTICE, "lock allocate failed: %s", strerror(errno));
/* failed */
return err;
}
+/* cancel a blocked lock request */
+enum nlm_stats
+cancellock(nlm4_cancargs *args, const int flags __unused)
+{
+ struct file_lock *ifl, *nfl;
+ enum nlm_stats err;
+
+ siglock();
+
+ debuglog("Entering cancellock...\n");
+
+ err = nlm_denied;
+
+ /*
+ * scan blocked lock list for matching request and remove/destroy
+ */
+ ifl = LIST_FIRST(&blockedlocklist_head);
+ for ( ; ifl != NULL; ifl = nfl) {
+ nfl = LIST_NEXT(ifl, nfslocklist);
+
+ /* compare lock fh - filehandle */
+ if (!same_netobj(&args->alock.fh, &ifl->filehandle))
+ continue;
+
+ /* compare lock caller_name - client_name */
+ if (strncmp(args->alock.caller_name, ifl->client_name, SM_MAXSTRLEN))
+ continue;
+
+ /* Note: done't compare cookie - client_cookie */
+ /* The cookie may be specific to the cancel request */
+ /* and not be the same as the one in the original lock request. */
+
+ /* compare lock oh - client.oh */
+ if (!same_netobj(&args->alock.oh, &ifl->client.oh))
+ continue;
+
+ /* compare lock svid - client.svid */
+ if (args->alock.svid != ifl->client.svid)
+ continue;
+
+ /* compare lock l_offset - client.l_offset */
+ if (args->alock.l_offset != ifl->client.l_offset)
+ continue;
+
+ /* compare lock l_len - client.l_len */
+ if (args->alock.l_len != ifl->client.l_len)
+ continue;
+
+ /* compare exclusive - client.exclusive */
+ if (args->exclusive != ifl->client.exclusive)
+ continue;
+
+ /* got it */
+ remove_blockingfilelock(ifl);
+ deallocate_file_lock(ifl);
+ err = nlm_granted;
+ break;
+ }
+
+ sigunlock();
+
+ debuglog("Exiting cancellock...\n");
+
+ return err;
+}
+
+
/*
* XXX: The following monitor/unmonitor routines
* have not been extensively tested (ie. no regression
* script exists like for the locking sections
*/
+/*
+ * Find a lock host on a queue. If found:
+ * bump the ref,
+ * bump the access time,
+ * dequeue it from the queue it was found on,
+ * enqueue it at the front of the "in use" queue.
+ */
+struct host *
+get_lock_host(struct hostlst_head *hd, const char *hostname)
+{
+ struct host *ihp;
+
+ debuglog("get_lock_host %s\n", hostname);
+ TAILQ_FOREACH(ihp, hd, hostlst) {
+ if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) {
+ TAILQ_REMOVE(hd, ihp, hostlst);
+ /* Host is already monitored, bump refcount */
+ ++ihp->refcnt;
+ ihp->lastuse = currsec;
+ /* Host should only be in the monitor list once */
+ TAILQ_INSERT_HEAD(&hostlst_head, ihp, hostlst);
+ break;
+ }
+ }
+ debuglog("get_lock_host %s %s\n",
+ ihp == NULL ? "did not find" : "found", hostname);
+ return (ihp);
+}
+
/*
* monitor_lock_host: monitor lock hosts locally with a ref count and
* inform statd
struct mon smon;
struct sm_stat_res sres;
int rpcret, statflag;
-
+
rpcret = 0;
statflag = 0;
- LIST_FOREACH(ihp, &hostlst_head, hostlst) {
- if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) {
- /* Host is already monitored, bump refcount */
- ++ihp->refcnt;
- /* Host should only be in the monitor list once */
- return;
- }
+ debuglog("monitor_lock_host: %s\n", hostname);
+ ihp = get_lock_host(&hostlst_head, hostname);
+ if (ihp == NULL)
+ ihp = get_lock_host(&hostlst_unref, hostname);
+ if (ihp != NULL) {
+ debuglog("Monitor_lock_host: %s (cached)\n", hostname);
+ return;
}
+ debuglog("Monitor_lock_host: %s (not found, creating)\n", hostname);
/* Host is not yet monitored, add it */
nhp = malloc(sizeof(struct host));
-
+
if (nhp == NULL) {
debuglog("Unable to allocate entry for statd mon\n");
return;
/* Allocated new host entry, now fill the fields */
strncpy(nhp->name, hostname, SM_MAXSTRLEN);
nhp->refcnt = 1;
+ nhp->lastuse = currsec;
debuglog("Locally Monitoring host %16s\n",hostname);
-
+
debuglog("Attempting to tell statd\n");
-
+
bzero(&smon,sizeof(smon));
-
+
smon.mon_id.mon_name = nhp->name;
smon.mon_id.my_id.my_name = "localhost\0";
smon.mon_id.my_id.my_prog = NLM_PROG;
smon.mon_id.my_id.my_vers = NLM_SM;
smon.mon_id.my_id.my_proc = NLM_SM_NOTIFY;
-
+
rpcret = callrpc("localhost", SM_PROG, SM_VERS, SM_MON, xdr_mon,
&smon, xdr_sm_stat_res, &sres);
-
+
if (rpcret == 0) {
if (sres.res_stat == stat_fail) {
debuglog("Statd call failed\n");
rpcret);
statflag = 0;
}
-
+
if (statflag == 1) {
- LIST_INSERT_HEAD(&hostlst_head, nhp, hostlst);
+ TAILQ_INSERT_HEAD(&hostlst_head, nhp, hostlst);
} else {
free(nhp);
}
-
}
/*
unmonitor_lock_host(const char *hostname)
{
struct host *ihp;
- struct mon_id smon_id;
- struct sm_stat smstat;
- int rpcret;
-
- rpcret = 0;
- for( ihp=LIST_FIRST(&hostlst_head); ihp != NULL;
- ihp=LIST_NEXT(ihp, hostlst)) {
+ TAILQ_FOREACH(ihp, &hostlst_head, hostlst) {
if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) {
/* Host is monitored, bump refcount */
--ihp->refcnt;
return;
if (ihp->refcnt < 0) {
- debuglog("Negative refcount!: %d\n",
- ihp->refcnt);
+ debuglog("Negative refcount!: %d\n", ihp->refcnt);
}
- debuglog("Attempting to unmonitor host %16s\n", hostname);
+ TAILQ_REMOVE(&hostlst_head, ihp, hostlst);
+ TAILQ_INSERT_HEAD(&hostlst_unref, ihp, hostlst);
+ if (host_expire <= 0)
+ destroy_lock_host(ihp);
+}
+
+void
+destroy_lock_host(struct host *ihp)
+{
+ struct mon_id smon_id;
+ struct sm_stat smstat;
+ int rpcret;
+
+ debuglog("Attempting to unmonitor host %16s\n", ihp->name);
bzero(&smon_id,sizeof(smon_id));
- smon_id.mon_name = (char *)hostname;
+ smon_id.mon_name = (char *)ihp->name;
smon_id.my_id.my_name = "localhost";
smon_id.my_id.my_prog = NLM_PROG;
smon_id.my_id.my_vers = NLM_SM;
smon_id.my_id.my_proc = NLM_SM_NOTIFY;
- rpcret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON, xdr_mon,
- &smon_id, xdr_sm_stat_res, &smstat);
+ rpcret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON, xdr_mon_id,
+ &smon_id, xdr_sm_stat, &smstat);
if (rpcret != 0) {
debuglog("Rpc call to unmonitor statd failed with "
- " return value: %d\n", rpcret);
+ " return value: %d: %s", rpcret, clnt_sperrno(rpcret));
+ } else {
+ debuglog("Succeeded unmonitoring %16s\n", ihp->name);
}
- LIST_REMOVE(ihp, hostlst);
+ TAILQ_REMOVE(&hostlst_unref, ihp, hostlst);
free(ihp);
}
+/*
+ * returns 1 if there are hosts to expire or 0 if there are none.
+ */
+int
+expire_lock_hosts(void)
+{
+ struct host *ihp;
+
+ debuglog("expire_lock_hosts: called\n");
+ for ( ;; ) {
+ ihp = TAILQ_LAST(&hostlst_unref, hostlst_head);
+ if (ihp == NULL)
+ break;
+ if (host_expire > 0 && ihp->lastuse >= currsec - host_expire)
+ break;
+ debuglog("expire_lock_hosts: expiring %s %d %d %d\n",
+ ihp->name, (int)ihp->lastuse,
+ (int)currsec, (int)currsec - host_expire);
+ destroy_lock_host(ihp);
+ }
+ return (TAILQ_LAST(&hostlst_unref, hostlst_head) != NULL);
+}
+
/*
* notify: Clear all locks from a host if statd complains
*
debuglog("Leaving notify\n");
}
-void
+int
send_granted(fl, opcode)
struct file_lock *fl;
int opcode __unused;
CLIENT *cli;
static char dummy;
struct timeval timeo;
- int success;
+ enum clnt_stat rv;
static struct nlm_res retval;
static struct nlm4_res retval4;
debuglog("About to send granted on blocked lock\n");
- //sleep(1);
- debuglog("Blowing off return send\n");
cli = get_client(fl->addr,
(fl->flags & LOCK_V4) ? NLM_VERS4 : NLM_VERS);
* The client will timeout and retry, the lock will be
* granted at this time.
*/
- return;
+ return -1;
}
timeo.tv_sec = 0;
timeo.tv_usec = (fl->flags & LOCK_ASYNC) ? 0 : 500000; /* 0.5s */
+ fl->granted_cookie = ++send_granted_cookie;
+ if (!send_granted_cookie)
+ send_granted_cookie++;
+
if (fl->flags & LOCK_V4) {
static nlm4_testargs res;
- res.cookie = fl->client_cookie;
+ res.cookie.n_len = sizeof(fl->granted_cookie);
+ res.cookie.n_bytes = (char*)&fl->granted_cookie;
res.exclusive = fl->client.exclusive;
res.alock.caller_name = fl->client_name;
res.alock.fh.n_len = fl->filehandle.n_len;
debuglog("sending v4 reply%s",
(fl->flags & LOCK_ASYNC) ? " (async)":"");
if (fl->flags & LOCK_ASYNC) {
- success = clnt_call(cli, NLM4_GRANTED_MSG,
+ rv = clnt_call(cli, NLM4_GRANTED_MSG,
xdr_nlm4_testargs, &res, xdr_void, &dummy, timeo);
} else {
- success = clnt_call(cli, NLM4_GRANTED,
+ rv = clnt_call(cli, NLM4_GRANTED,
xdr_nlm4_testargs, &res, xdr_nlm4_res,
&retval4, timeo);
}
} else {
static nlm_testargs res;
- res.cookie = fl->client_cookie;
+ res.cookie.n_len = sizeof(fl->granted_cookie);
+ res.cookie.n_bytes = (char*)&fl->granted_cookie;
res.exclusive = fl->client.exclusive;
res.alock.caller_name = fl->client_name;
res.alock.fh.n_len = fl->filehandle.n_len;
debuglog("sending v1 reply%s",
(fl->flags & LOCK_ASYNC) ? " (async)":"");
if (fl->flags & LOCK_ASYNC) {
- success = clnt_call(cli, NLM_GRANTED_MSG,
+ rv = clnt_call(cli, NLM_GRANTED_MSG,
xdr_nlm_testargs, &res, xdr_void, &dummy, timeo);
} else {
- success = clnt_call(cli, NLM_GRANTED,
+ rv = clnt_call(cli, NLM_GRANTED,
xdr_nlm_testargs, &res, xdr_nlm_res,
&retval, timeo);
}
}
if (debug_level > 2)
debuglog("clnt_call returns %d(%s) for granted",
- success, clnt_sperrno(success));
+ rv, clnt_sperrno(rv));
+
+ if ((rv != RPC_SUCCESS) &&
+ !((fl->flags & LOCK_ASYNC) && (rv == RPC_TIMEDOUT)))
+ return -1;
+ return 0;
+}
+
+/*
+ * granted_failed: remove a granted lock that wasn't successfully
+ * accepted by the client
+ */
+void
+granted_failed(nlm4_res *arg)
+{
+ u_int64_t cookie;
+ struct file_lock *ifl;
+
+ debuglog("Entering granted_failed, status %d\n", arg->stat.stat);
+
+ if (arg->cookie.n_len != sizeof(cookie)) {
+ debuglog("Exiting granted_failed: bogus cookie size %d\n",
+ arg->cookie.n_len);
+ return;
+ }
+ bcopy(arg->cookie.n_bytes, &cookie, sizeof(cookie));
+ debuglog("granted_failed, cookie 0x%llx\n", cookie);
+
+ LIST_FOREACH(ifl, &nfslocklist_head, nfslocklist) {
+ debuglog("Pointer to file lock: %p\n",ifl);
+
+ debuglog("****Dump of ifl****\n");
+ dump_filelock(ifl);
+
+ if (ifl->granted_cookie != cookie)
+ continue;
+
+ debuglog("granted_failed: cookie found\n");
+ break;
+ }
+
+ if (ifl) {
+ do_unlock(ifl);
+ /* ifl is NO LONGER VALID AT THIS POINT */
+ } else {
+ debuglog("granted_failed: cookie NOT FOUND\n");
+ }
+ debuglog("Exiting granted_failed\n");
}
/*
/* Headers and function declarations for file-locking utilities */
+#ifndef LOCKD_LOCK_H
+#define LOCKD_LOCK_H
struct nlm4_holder * testlock(struct nlm4_lock *lock, bool_t exclusive, int flags);
enum nlm_stats getlock(nlm4_lockargs *lckarg, struct svc_req *rqstp, const int flags);
enum nlm_stats unlock(nlm4_lock *lock, const int flags);
-int lock_answer(int pid, netobj *netcookie, int result, int version,
- int *pid_p, off_t l_start, off_t l_len);
+enum nlm_stats cancellock(nlm4_cancargs *args, const int flags);
+int lock_answer(int version, netobj *netcookie, nlm4_lock *lock, int flags, int result);
enum nlm_stats getshare(nlm_shareargs *shrarg, struct svc_req *rqstp, const int flags);
enum nlm_stats unshare(nlm_shareargs *shrarg, struct svc_req *rqstp);
void do_free_all(const char *hostname);
+void granted_failed(nlm4_res *arg);
void notify(const char *hostname, const int state);
#define LOCK_ASYNC 0x01 /* async version (getlock only) */
#define LOCK_V4 0x02 /* v4 version */
#define LOCK_MON 0x04 /* monitored lock (getlock only) */
-#define LOCK_CANCEL 0x08 /* cancel, not unlock request (unlock only) */
+
+/* flags for lock_answer */
+#define LOCK_ANSWER_GRANTED 0x0001 /* NLM_GRANTED request */
+#define LOCK_ANSWER_LOCK_EXCL 0x0004 /* lock is exclusive */
/* callbacks from lock_proc.c */
void transmit_result(int, nlm_res *, struct sockaddr *);
void transmit4_result(int, nlm4_res *, struct sockaddr *);
CLIENT *get_client(struct sockaddr *, rpcvers_t);
+
+extern time_t currsec;
+
+#endif /* !LOCKD_LOCK_H */
#endif
// XXX
-void retry_blockingfilelocklist(void);
+void retry_blockingfilelocklist(netobj *fh);
+extern int need_retry_blocked_locks; /* need to call retry_blockingfilelocklist() */
#define _RPCSVC_CLOSEDOWN 120
#ifndef lint
/*static char sccsid[] = "from: @(#)nlm_prot.x 1.8 87/09/21 Copyr 1987 Sun Micro";*/
/*static char sccsid[] = "from: * @(#)nlm_prot.x 2.1 88/08/01 4.0 RPCSRC";*/
-static char rcsid[] = "$Id: nlm_prot_svc.c,v 1.4 2003/07/24 05:11:22 lindak Exp $";
+static char rcsid[] = "$Id: nlm_prot_svc.c,v 1.4.36.1 2004/04/16 15:50:05 lindak Exp $";
#endif /* not lint */
extern int _rpcpmstart; /* Started by a port monitor ? */
extern int _rpcfdtype; /* Whether Stream or Datagram ? */
if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
svcerr_systemerr(transp);
}
+ if (need_retry_blocked_locks) {
+ // XXX sending granted messages before unlock response
+ // XXX causes unlock response to be corrupted?
+ // XXX so do this after we send any response
+ netobj *fh = NULL;
+ if ((local == (char *(*)(char *, struct svc_req *)) nlm_unlock_1_svc) ||
+ (local == (char *(*)(char *, struct svc_req *)) nlm_unlock_msg_1_svc))
+ fh = &argument.nlm_unlock_1_arg.alock.fh;
+ retry_blockingfilelocklist(fh);
+ }
if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) {
syslog(LOG_ERR, "unable to free arguments");
exit(1);
}
_rpcsvcdirty = 0;
- if ((local == (char *(*)(char *, struct svc_req *)) nlm_unlock_1_svc) ||
- (local == (char *(*)(char *, struct svc_req *)) nlm_unlock_msg_1_svc)) {
- // XXX sending granted messages before unlock response
- // XXX causes unlock response to be corrupted?
- // XXX so do this after we send any response
- retry_blockingfilelocklist();
- }
return;
}
if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
svcerr_systemerr(transp);
}
+ if (need_retry_blocked_locks) {
+ // XXX sending granted messages before unlock response
+ // XXX causes unlock response to be corrupted?
+ // XXX so do this after we send any response
+ netobj *fh = NULL;
+ if ((local == (char *(*)(char *, struct svc_req *)) nlm_unlock_1_svc) ||
+ (local == (char *(*)(char *, struct svc_req *)) nlm_unlock_msg_1_svc))
+ fh = &argument.nlm_unlock_3_arg.alock.fh;
+ retry_blockingfilelocklist(fh);
+ }
if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) {
syslog(LOG_ERR, "unable to free arguments");
exit(1);
}
_rpcsvcdirty = 0;
- if ((local == (char *(*)(char *, struct svc_req *)) nlm_unlock_1_svc) ||
- (local == (char *(*)(char *, struct svc_req *)) nlm_unlock_msg_1_svc) ||
- (local == (char *(*)(char *, struct svc_req *)) nlm_free_all_3_svc)) {
- // XXX sending granted messages before unlock response
- // XXX causes unlock response to be corrupted?
- // XXX so do this after we send any response
- retry_blockingfilelocklist();
- }
return;
}
if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
svcerr_systemerr(transp);
}
+ if (need_retry_blocked_locks) {
+ // XXX sending granted messages before unlock response
+ // XXX causes unlock response to be corrupted?
+ // XXX so do this after we send any response
+ netobj *fh = NULL;
+ if ((local == (char *(*)(char *, struct svc_req *)) nlm4_unlock_4_svc) ||
+ (local == (char *(*)(char *, struct svc_req *)) nlm4_unlock_msg_4_svc))
+ fh = &argument.nlm4_unlock_4_arg.alock.fh;
+ retry_blockingfilelocklist(fh);
+ }
if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) {
syslog(LOG_ERR, "unable to free arguments");
exit(1);
}
_rpcsvcdirty = 0;
- if ((local == (char *(*)(char *, struct svc_req *)) nlm4_unlock_4_svc) ||
- (local == (char *(*)(char *, struct svc_req *)) nlm4_unlock_msg_4_svc) ||
- (local == (char *(*)(char *, struct svc_req *)) nlm4_free_all_4_svc)) {
- // XXX sending granted messages before unlock response
- // XXX causes unlock response to be corrupted?
- // XXX so do this after we send any response
- retry_blockingfilelocklist();
- }
return;
}
.Nm
.Op Fl d Ar debug_level
.Op Fl g Ar grace period
+.Op Fl x Ar statd cache period
.Sh DESCRIPTION
The
.Nm
NFS locking daemons until it is known that they will be needed. (Note:
.Xr rpc.statd 8
will also be started if it isn't already running)
+.It Fl x
+The
+.Fl x
+option tells rpc.lockd how long to cache state records for contacting
+client
+.Xr rpc.statd 8
+implementations. Setting it to zero will disable the cache which will
+make lock and unlock requests from a single client more expensive because
+of additional interaction with the client's statd. The default cache time
+is 60 seconds.
.El
.Pp
Error conditions are logged to syslog, irrespective of the debug level,