xref: /openbsd/usr.sbin/rpc.lockd/lockd_lock.c (revision 5b133f3f)
1*5b133f3fSguenther /*	$OpenBSD: lockd_lock.c,v 1.12 2023/03/08 04:43:15 guenther Exp $	*/
25507b659Ssturm 
35507b659Ssturm /*
45507b659Ssturm  * Copyright (c) 2000 Manuel Bouyer.
55507b659Ssturm  *
65507b659Ssturm  * Redistribution and use in source and binary forms, with or without
75507b659Ssturm  * modification, are permitted provided that the following conditions
85507b659Ssturm  * are met:
95507b659Ssturm  * 1. Redistributions of source code must retain the above copyright
105507b659Ssturm  *    notice, this list of conditions and the following disclaimer.
115507b659Ssturm  * 2. Redistributions in binary form must reproduce the above copyright
125507b659Ssturm  *    notice, this list of conditions and the following disclaimer in the
135507b659Ssturm  *    documentation and/or other materials provided with the distribution.
145507b659Ssturm  *
155507b659Ssturm  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
165507b659Ssturm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
175507b659Ssturm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
185507b659Ssturm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
195507b659Ssturm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
205507b659Ssturm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
215507b659Ssturm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
225507b659Ssturm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
235507b659Ssturm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
245507b659Ssturm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
255507b659Ssturm  * SUCH DAMAGE.
265507b659Ssturm  *
275507b659Ssturm  */
285507b659Ssturm 
29b9fc9a72Sderaadt #include <sys/socket.h>
30b9fc9a72Sderaadt #include <sys/stat.h>
31b9fc9a72Sderaadt #include <sys/mount.h>
32b9fc9a72Sderaadt #include <sys/wait.h>
335507b659Ssturm #include <stdio.h>
345507b659Ssturm #include <stdlib.h>
355507b659Ssturm #include <unistd.h>
365507b659Ssturm #include <fcntl.h>
375507b659Ssturm #include <inttypes.h>
385507b659Ssturm #include <syslog.h>
395507b659Ssturm #include <errno.h>
405507b659Ssturm #include <string.h>
415507b659Ssturm #include <signal.h>
425507b659Ssturm #include <rpc/rpc.h>
435507b659Ssturm #include <rpcsvc/sm_inter.h>
445507b659Ssturm #include <rpcsvc/nlm_prot.h>
455507b659Ssturm #include "lockd_lock.h"
465507b659Ssturm #include "lockd.h"
475507b659Ssturm 
485507b659Ssturm /* A set of utilities for managing file locking */
495507b659Ssturm LIST_HEAD(lcklst_head, file_lock);
505507b659Ssturm struct lcklst_head lcklst_head = LIST_HEAD_INITIALIZER(lcklst_head);
515507b659Ssturm 
525507b659Ssturm #define	FHANDLE_SIZE_MAX	1024	/* arbitrary big enough value */
535507b659Ssturm typedef struct {
545507b659Ssturm 	size_t fhsize;
555507b659Ssturm 	char *fhdata;
565507b659Ssturm } nfs_fhandle_t;
575507b659Ssturm 
585507b659Ssturm static int
fhcmp(const nfs_fhandle_t * fh1,const nfs_fhandle_t * fh2)595507b659Ssturm fhcmp(const nfs_fhandle_t *fh1, const nfs_fhandle_t *fh2)
605507b659Ssturm {
61d2a74e6aSsturm 	return memcmp(fh1->fhdata, fh2->fhdata, sizeof(fhandle_t));
625507b659Ssturm }
635507b659Ssturm 
645507b659Ssturm static int
fhconv(nfs_fhandle_t * fh,const netobj * rfh)655507b659Ssturm fhconv(nfs_fhandle_t *fh, const netobj *rfh)
665507b659Ssturm {
675507b659Ssturm 	size_t sz;
685507b659Ssturm 
695507b659Ssturm 	sz = rfh->n_len;
705507b659Ssturm 	if (sz > FHANDLE_SIZE_MAX) {
715507b659Ssturm 		syslog(LOG_DEBUG,
725507b659Ssturm 		    "received fhandle size %zd, max supported size %d",
735507b659Ssturm 		    sz, FHANDLE_SIZE_MAX);
745507b659Ssturm 		errno = EINVAL;
755507b659Ssturm 		return -1;
765507b659Ssturm 	}
775507b659Ssturm 	fh->fhdata = malloc(sz);
785507b659Ssturm 	if (fh->fhdata == NULL) {
795507b659Ssturm 		return -1;
805507b659Ssturm 	}
815507b659Ssturm 	fh->fhsize = sz;
825507b659Ssturm 	memcpy(fh->fhdata, rfh->n_bytes, sz);
835507b659Ssturm 	return 0;
845507b659Ssturm }
855507b659Ssturm 
865507b659Ssturm static void
fhfree(nfs_fhandle_t * fh)875507b659Ssturm fhfree(nfs_fhandle_t *fh)
885507b659Ssturm {
895507b659Ssturm 
905507b659Ssturm 	free(fh->fhdata);
915507b659Ssturm }
925507b659Ssturm 
935507b659Ssturm /* struct describing a lock */
945507b659Ssturm struct file_lock {
955507b659Ssturm 	LIST_ENTRY(file_lock) lcklst;
965507b659Ssturm 	nfs_fhandle_t filehandle; /* NFS filehandle */
975507b659Ssturm 	struct sockaddr_in *addr;
985507b659Ssturm 	struct nlm4_holder client; /* lock holder */
995507b659Ssturm 	netobj client_cookie; /* cookie sent by the client */
1005507b659Ssturm 	char client_name[128];
1015507b659Ssturm 	int nsm_status; /* status from the remote lock manager */
1025507b659Ssturm 	int status; /* lock status, see below */
1035507b659Ssturm 	int flags; /* lock flags, see lockd_lock.h */
1045507b659Ssturm 	pid_t locker; /* pid of the child process trying to get the lock */
1055507b659Ssturm 	int fd;	/* file descriptor for this lock */
1065507b659Ssturm };
1075507b659Ssturm 
1085507b659Ssturm /* lock status */
1095507b659Ssturm #define LKST_LOCKED	1 /* lock is locked */
1105507b659Ssturm #define LKST_WAITING	2 /* file is already locked by another host */
1115507b659Ssturm #define LKST_PROCESSING	3 /* child is trying to acquire the lock */
112d595756bSjmc #define LKST_DYING	4 /* must die when we get news from the child */
1135507b659Ssturm 
1145507b659Ssturm static struct file_lock *lalloc(void);
1155507b659Ssturm void lfree(struct file_lock *);
1165507b659Ssturm enum nlm_stats do_lock(struct file_lock *, int);
1175507b659Ssturm enum nlm_stats do_unlock(struct file_lock *);
1185507b659Ssturm void send_granted(struct file_lock *, int);
1195507b659Ssturm void siglock(void);
1205507b659Ssturm void sigunlock(void);
1215507b659Ssturm 
12275a10426Ssturm /* list of hosts we monitor */
12375a10426Ssturm LIST_HEAD(hostlst_head, host);
12475a10426Ssturm struct hostlst_head hostlst_head = LIST_HEAD_INITIALIZER(hostlst_head);
12575a10426Ssturm 
12675a10426Ssturm /* struct describing a lock */
12775a10426Ssturm struct host {
12875a10426Ssturm 	LIST_ENTRY(host) hostlst;
12975a10426Ssturm 	char name[SM_MAXSTRLEN+1];
13075a10426Ssturm 	int refcnt;
13175a10426Ssturm };
13275a10426Ssturm 
13375a10426Ssturm void do_mon(const char *);
13475a10426Ssturm 
1355507b659Ssturm #define	LL_FH	0x01
1365507b659Ssturm #define	LL_NAME	0x02
1375507b659Ssturm #define	LL_SVID	0x04
1385507b659Ssturm 
1395507b659Ssturm static struct file_lock *lock_lookup(struct file_lock *, int);
1405507b659Ssturm 
1415507b659Ssturm /*
1425507b659Ssturm  * lock_lookup: lookup a matching lock.
1435507b659Ssturm  * called with siglock held.
1445507b659Ssturm  */
1455507b659Ssturm static struct file_lock *
lock_lookup(struct file_lock * newfl,int flags)1465507b659Ssturm lock_lookup(struct file_lock *newfl, int flags)
1475507b659Ssturm {
1485507b659Ssturm 	struct file_lock *fl;
1495507b659Ssturm 
1505507b659Ssturm 	LIST_FOREACH(fl, &lcklst_head, lcklst) {
1515507b659Ssturm 		if ((flags & LL_SVID) != 0 &&
1525507b659Ssturm 		    newfl->client.svid != fl->client.svid)
1535507b659Ssturm 			continue;
1545507b659Ssturm 		if ((flags & LL_NAME) != 0 &&
1555507b659Ssturm 		    strcmp(newfl->client_name, fl->client_name) != 0)
1565507b659Ssturm 			continue;
1575507b659Ssturm 		if ((flags & LL_FH) != 0 &&
1585507b659Ssturm 		    fhcmp(&newfl->filehandle, &fl->filehandle) != 0)
1595507b659Ssturm 			continue;
1605507b659Ssturm 		/* found */
1615507b659Ssturm 		break;
1625507b659Ssturm 	}
1635507b659Ssturm 
1645507b659Ssturm 	return fl;
1655507b659Ssturm }
1665507b659Ssturm 
1675507b659Ssturm /*
1685507b659Ssturm  * testlock(): inform the caller if the requested lock would be granted or not
1695507b659Ssturm  * returns NULL if lock would granted, or pointer to the current nlm4_holder
1705507b659Ssturm  * otherwise.
1715507b659Ssturm  */
1725507b659Ssturm 
1735507b659Ssturm struct nlm4_holder *
testlock(struct nlm4_lock * lock,int flags)1745507b659Ssturm testlock(struct nlm4_lock *lock, int flags)
1755507b659Ssturm {
1765507b659Ssturm 	struct file_lock *fl;
1775507b659Ssturm 	nfs_fhandle_t filehandle;
1785507b659Ssturm 
1795507b659Ssturm 	/* convert lock to a local filehandle */
1805507b659Ssturm 	if (fhconv(&filehandle, &lock->fh)) {
1815507b659Ssturm 		syslog(LOG_NOTICE, "fhconv failed (%m)");
1825507b659Ssturm 		return NULL; /* XXX */
1835507b659Ssturm 	}
1845507b659Ssturm 
1855507b659Ssturm 	siglock();
1865507b659Ssturm 	/* search through the list for lock holder */
1875507b659Ssturm 	LIST_FOREACH(fl, &lcklst_head, lcklst) {
1885507b659Ssturm 		if (fl->status != LKST_LOCKED)
1895507b659Ssturm 			continue;
1905507b659Ssturm 		if (fhcmp(&fl->filehandle, &filehandle) != 0)
1915507b659Ssturm 			continue;
1925507b659Ssturm 		/* got it ! */
1935507b659Ssturm 		syslog(LOG_DEBUG, "test for %s: found lock held by %s",
1945507b659Ssturm 		    lock->caller_name, fl->client_name);
1955507b659Ssturm 		sigunlock();
1965507b659Ssturm 		fhfree(&filehandle);
1975507b659Ssturm 		return (&fl->client);
1985507b659Ssturm 	}
1995507b659Ssturm 	/* not found */
2005507b659Ssturm 	sigunlock();
2015507b659Ssturm 	fhfree(&filehandle);
2025507b659Ssturm 	syslog(LOG_DEBUG, "test for %s: no lock found", lock->caller_name);
2035507b659Ssturm 	return NULL;
2045507b659Ssturm }
2055507b659Ssturm 
2065507b659Ssturm /*
2075507b659Ssturm  * getlock: try to acquire the lock.
2085507b659Ssturm  * If file is already locked and we can sleep, put the lock in the list with
2095507b659Ssturm  * status LKST_WAITING; it'll be processed later.
2105507b659Ssturm  * Otherwise try to lock. If we're allowed to block, fork a child which
2115507b659Ssturm  * will do the blocking lock.
2125507b659Ssturm  */
2135507b659Ssturm enum nlm_stats
getlock(nlm4_lockargs * lckarg,struct svc_req * rqstp,int flags)2145507b659Ssturm getlock(nlm4_lockargs * lckarg, struct svc_req *rqstp, int flags)
2155507b659Ssturm {
2165507b659Ssturm 	struct file_lock *fl, *newfl;
2175507b659Ssturm 	enum nlm_stats retval;
2185507b659Ssturm 	struct sockaddr_in *addr;
2195507b659Ssturm 
2205507b659Ssturm 	if (grace_expired == 0 && lckarg->reclaim == 0)
2215507b659Ssturm 		return (flags & LOCK_V4) ?
2225507b659Ssturm 		    nlm4_denied_grace_period : nlm_denied_grace_period;
2235507b659Ssturm 
2245507b659Ssturm 	/* allocate new file_lock for this request */
2255507b659Ssturm 	newfl = lalloc();
2265507b659Ssturm 	if (newfl == NULL) {
2275507b659Ssturm 		syslog(LOG_NOTICE, "malloc failed (%m)");
2285507b659Ssturm 		/* failed */
2295507b659Ssturm 		return (flags & LOCK_V4) ?
2305507b659Ssturm 		    nlm4_denied_nolock : nlm_denied_nolocks;
2315507b659Ssturm 	}
2325507b659Ssturm 	if (fhconv(&newfl->filehandle, &lckarg->alock.fh)) {
2335507b659Ssturm 		syslog(LOG_NOTICE, "fhconv failed (%m)");
2345507b659Ssturm 		lfree(newfl);
2355507b659Ssturm 		/* failed */
2365507b659Ssturm 		return (flags & LOCK_V4) ?
2375507b659Ssturm 		    nlm4_denied_nolock : nlm_denied_nolocks;
2385507b659Ssturm 	}
2395507b659Ssturm 	addr = svc_getcaller(rqstp->rq_xprt);
2405507b659Ssturm 	newfl->addr = malloc(addr->sin_len);
2415507b659Ssturm 	if (newfl->addr == NULL) {
2425507b659Ssturm 		syslog(LOG_NOTICE, "malloc failed (%m)");
2435507b659Ssturm 		lfree(newfl);
2445507b659Ssturm 		/* failed */
2455507b659Ssturm 		return (flags & LOCK_V4) ?
2465507b659Ssturm 		    nlm4_denied_nolock : nlm_denied_nolocks;
2475507b659Ssturm 	}
2485507b659Ssturm 	memcpy(newfl->addr, addr, addr->sin_len);
2495507b659Ssturm 	newfl->client.exclusive = lckarg->exclusive;
2505507b659Ssturm 	newfl->client.svid = lckarg->alock.svid;
2515507b659Ssturm 	newfl->client.oh.n_bytes = malloc(lckarg->alock.oh.n_len);
2525507b659Ssturm 	if (newfl->client.oh.n_bytes == NULL) {
2535507b659Ssturm 		syslog(LOG_NOTICE, "malloc failed (%m)");
2545507b659Ssturm 		lfree(newfl);
2555507b659Ssturm 		return (flags & LOCK_V4) ?
2565507b659Ssturm 		    nlm4_denied_nolock : nlm_denied_nolocks;
2575507b659Ssturm 	}
2585507b659Ssturm 	newfl->client.oh.n_len = lckarg->alock.oh.n_len;
2595507b659Ssturm 	memcpy(newfl->client.oh.n_bytes, lckarg->alock.oh.n_bytes,
2605507b659Ssturm 	    lckarg->alock.oh.n_len);
2615507b659Ssturm 	newfl->client.l_offset = lckarg->alock.l_offset;
2625507b659Ssturm 	newfl->client.l_len = lckarg->alock.l_len;
2635507b659Ssturm 	newfl->client_cookie.n_len = lckarg->cookie.n_len;
2645507b659Ssturm 	newfl->client_cookie.n_bytes = malloc(lckarg->cookie.n_len);
2655507b659Ssturm 	if (newfl->client_cookie.n_bytes == NULL) {
2665507b659Ssturm 		syslog(LOG_NOTICE, "malloc failed (%m)");
2675507b659Ssturm 		lfree(newfl);
2685507b659Ssturm 		return (flags & LOCK_V4) ?
2695507b659Ssturm 		    nlm4_denied_nolock : nlm_denied_nolocks;
2705507b659Ssturm 	}
2715507b659Ssturm 	memcpy(newfl->client_cookie.n_bytes, lckarg->cookie.n_bytes,
2725507b659Ssturm 	    lckarg->cookie.n_len);
2735507b659Ssturm 	strlcpy(newfl->client_name, lckarg->alock.caller_name,
2745507b659Ssturm 	    sizeof(newfl->client_name));
2755507b659Ssturm 	newfl->nsm_status = lckarg->state;
2765507b659Ssturm 	newfl->status = 0;
2775507b659Ssturm 	newfl->flags = flags;
2785507b659Ssturm 	siglock();
2795507b659Ssturm 	/* look for a lock rq from this host for this fh */
2805507b659Ssturm 	fl = lock_lookup(newfl, LL_FH|LL_NAME|LL_SVID);
2815507b659Ssturm 	if (fl) {
2825507b659Ssturm 		/* already locked by this host ??? */
2835507b659Ssturm 		sigunlock();
2845507b659Ssturm 		syslog(LOG_NOTICE, "duplicate lock from %s.%"
2855507b659Ssturm 		    PRIu32,
2865507b659Ssturm 		    newfl->client_name, newfl->client.svid);
2875507b659Ssturm 		lfree(newfl);
2885507b659Ssturm 		switch(fl->status) {
2895507b659Ssturm 		case LKST_LOCKED:
2905507b659Ssturm 			return (flags & LOCK_V4) ?
2915507b659Ssturm 			    nlm4_granted : nlm_granted;
2925507b659Ssturm 		case LKST_WAITING:
2935507b659Ssturm 		case LKST_PROCESSING:
2945507b659Ssturm 			return (flags & LOCK_V4) ?
2955507b659Ssturm 			    nlm4_blocked : nlm_blocked;
2965507b659Ssturm 		case LKST_DYING:
2975507b659Ssturm 			return (flags & LOCK_V4) ?
2985507b659Ssturm 			    nlm4_denied : nlm_denied;
2995507b659Ssturm 		default:
3005507b659Ssturm 			syslog(LOG_NOTICE, "bad status %d",
3015507b659Ssturm 			    fl->status);
3025507b659Ssturm 			return (flags & LOCK_V4) ?
3035507b659Ssturm 			    nlm4_failed : nlm_denied;
3045507b659Ssturm 		}
3055507b659Ssturm 		/* NOTREACHED */
3065507b659Ssturm 	}
3075507b659Ssturm 	fl = lock_lookup(newfl, LL_FH);
3085507b659Ssturm 	if (fl) {
3095507b659Ssturm 		/*
3105507b659Ssturm 		 * We already have a lock for this file.
3115507b659Ssturm 		 * Put this one in waiting state if allowed to block
3125507b659Ssturm 		 */
3135507b659Ssturm 		if (lckarg->block) {
3145507b659Ssturm 			syslog(LOG_DEBUG, "lock from %s.%" PRIu32 ": "
3155507b659Ssturm 			    "already locked, waiting",
3165507b659Ssturm 			    lckarg->alock.caller_name,
3175507b659Ssturm 			    lckarg->alock.svid);
3185507b659Ssturm 			newfl->status = LKST_WAITING;
3195507b659Ssturm 			LIST_INSERT_HEAD(&lcklst_head, newfl, lcklst);
32075a10426Ssturm 			do_mon(lckarg->alock.caller_name);
3215507b659Ssturm 			sigunlock();
3225507b659Ssturm 			return (flags & LOCK_V4) ?
3235507b659Ssturm 			    nlm4_blocked : nlm_blocked;
3245507b659Ssturm 		} else {
3255507b659Ssturm 			sigunlock();
3265507b659Ssturm 			syslog(LOG_DEBUG, "lock from %s.%" PRIu32 ": "
3275507b659Ssturm 			    "already locked, failed",
3285507b659Ssturm 			    lckarg->alock.caller_name,
3295507b659Ssturm 			    lckarg->alock.svid);
3305507b659Ssturm 			lfree(newfl);
3315507b659Ssturm 			return (flags & LOCK_V4) ?
3325507b659Ssturm 			    nlm4_denied : nlm_denied;
3335507b659Ssturm 		}
3345507b659Ssturm 		/* NOTREACHED */
3355507b659Ssturm 	}
3365507b659Ssturm 
3375507b659Ssturm 	/* no entry for this file yet; add to list */
3385507b659Ssturm 	LIST_INSERT_HEAD(&lcklst_head, newfl, lcklst);
3395507b659Ssturm 	/* do the lock */
3405507b659Ssturm 	retval = do_lock(newfl, lckarg->block);
3415507b659Ssturm 	switch (retval) {
3425507b659Ssturm 	case nlm4_granted:
3435507b659Ssturm 	/* case nlm_granted: is the same as nlm4_granted */
3445507b659Ssturm 	case nlm4_blocked:
3455507b659Ssturm 	/* case nlm_blocked: is the same as nlm4_blocked */
34675a10426Ssturm 		do_mon(lckarg->alock.caller_name);
3475507b659Ssturm 		break;
3485507b659Ssturm 	default:
3495507b659Ssturm 		lfree(newfl);
3505507b659Ssturm 		break;
3515507b659Ssturm 	}
3525507b659Ssturm 	sigunlock();
3535507b659Ssturm 	return retval;
3545507b659Ssturm }
3555507b659Ssturm 
3565507b659Ssturm /* unlock a filehandle */
3575507b659Ssturm enum nlm_stats
unlock(nlm4_lock * lck,int flags)3585507b659Ssturm unlock(nlm4_lock *lck, int flags)
3595507b659Ssturm {
3605507b659Ssturm 	struct file_lock *fl;
3615507b659Ssturm 	nfs_fhandle_t filehandle;
3625507b659Ssturm 	int err = (flags & LOCK_V4) ? nlm4_granted : nlm_granted;
3635507b659Ssturm 
3645507b659Ssturm 	if (fhconv(&filehandle, &lck->fh)) {
3655507b659Ssturm 		syslog(LOG_NOTICE, "fhconv failed (%m)");
3665507b659Ssturm 		return (flags & LOCK_V4) ? nlm4_denied : nlm_denied;
3675507b659Ssturm 	}
3685507b659Ssturm 	siglock();
3695507b659Ssturm 	LIST_FOREACH(fl, &lcklst_head, lcklst) {
3705507b659Ssturm 		if (strcmp(fl->client_name, lck->caller_name) ||
3715507b659Ssturm 		    fhcmp(&filehandle, &fl->filehandle) != 0 ||
3725507b659Ssturm 		    fl->client.oh.n_len != lck->oh.n_len ||
3735507b659Ssturm 		    memcmp(fl->client.oh.n_bytes, lck->oh.n_bytes,
3745507b659Ssturm 			fl->client.oh.n_len) != 0 ||
3755507b659Ssturm 		    fl->client.svid != lck->svid)
3765507b659Ssturm 			continue;
3775507b659Ssturm 		/* Got it, unlock and remove from the queue */
3785507b659Ssturm 		syslog(LOG_DEBUG, "unlock from %s.%" PRIu32 ": found struct, "
3795507b659Ssturm 		    "status %d", lck->caller_name, lck->svid, fl->status);
3805507b659Ssturm 		switch (fl->status) {
3815507b659Ssturm 		case LKST_LOCKED:
3825507b659Ssturm 			err = do_unlock(fl);
3835507b659Ssturm 			break;
3845507b659Ssturm 		case LKST_WAITING:
3855507b659Ssturm 			/* remove from the list */
3865507b659Ssturm 			LIST_REMOVE(fl, lcklst);
3875507b659Ssturm 			lfree(fl);
3885507b659Ssturm 			break;
3895507b659Ssturm 		case LKST_PROCESSING:
3905507b659Ssturm 			/*
3915507b659Ssturm 			 * being handled by a child; will clean up
3925507b659Ssturm 			 * when the child exits
3935507b659Ssturm 			 */
3945507b659Ssturm 			fl->status = LKST_DYING;
3955507b659Ssturm 			break;
3965507b659Ssturm 		case LKST_DYING:
3975507b659Ssturm 			/* nothing to do */
3985507b659Ssturm 			break;
3995507b659Ssturm 		default:
4003a50f0a9Sjmc 			syslog(LOG_NOTICE, "unknown status %d for %s",
4015507b659Ssturm 			    fl->status, fl->client_name);
4025507b659Ssturm 		}
4035507b659Ssturm 		sigunlock();
4045507b659Ssturm 		fhfree(&filehandle);
4055507b659Ssturm 		return err;
4065507b659Ssturm 	}
4075507b659Ssturm 	sigunlock();
4085507b659Ssturm 	/* didn't find a matching entry; log anyway */
4095507b659Ssturm 	syslog(LOG_NOTICE, "no matching entry for %s",
4105507b659Ssturm 	    lck->caller_name);
4115507b659Ssturm 	fhfree(&filehandle);
4125507b659Ssturm 	return (flags & LOCK_V4) ? nlm4_granted : nlm_granted;
4135507b659Ssturm }
4145507b659Ssturm 
4155507b659Ssturm static struct file_lock *
lalloc(void)4165507b659Ssturm lalloc(void)
4175507b659Ssturm {
4185507b659Ssturm 	return calloc(1, sizeof(struct file_lock));
4195507b659Ssturm }
4205507b659Ssturm 
4215507b659Ssturm void
lfree(struct file_lock * fl)4225507b659Ssturm lfree(struct file_lock *fl)
4235507b659Ssturm {
4245507b659Ssturm 	free(fl->addr);
4255507b659Ssturm 	free(fl->client.oh.n_bytes);
4265507b659Ssturm 	free(fl->client_cookie.n_bytes);
4275507b659Ssturm 	fhfree(&fl->filehandle);
4285507b659Ssturm 	free(fl);
4295507b659Ssturm }
4305507b659Ssturm 
4315507b659Ssturm void
sigchild_handler(int sig)4325507b659Ssturm sigchild_handler(int sig)
4335507b659Ssturm {
4345507b659Ssturm 	int sstatus;
4355507b659Ssturm 	pid_t pid;
4365507b659Ssturm 	struct file_lock *fl;
4375507b659Ssturm 
4385507b659Ssturm 	for (;;) {
4395507b659Ssturm 		pid = wait4(-1, &sstatus, WNOHANG, NULL);
4405507b659Ssturm 		if (pid == -1) {
4415507b659Ssturm 			if (errno != ECHILD)
4425507b659Ssturm 				syslog(LOG_NOTICE, "wait failed (%m)");
4435507b659Ssturm 			else
4445507b659Ssturm 				syslog(LOG_DEBUG, "wait failed (%m)");
4455507b659Ssturm 			return;
4465507b659Ssturm 		}
4475507b659Ssturm 		if (pid == 0) {
4485507b659Ssturm 			/* no more child to handle yet */
4495507b659Ssturm 			return;
4505507b659Ssturm 		}
4515507b659Ssturm 		/*
4525507b659Ssturm 		 * if we're here we have a child that exited
4535507b659Ssturm 		 * Find the associated file_lock.
4545507b659Ssturm 		 */
4555507b659Ssturm 		LIST_FOREACH(fl, &lcklst_head, lcklst) {
4565507b659Ssturm 			if (pid == fl->locker)
4575507b659Ssturm 				break;
4585507b659Ssturm 		}
4595507b659Ssturm 		if (fl == NULL) {
4605507b659Ssturm 			syslog(LOG_NOTICE, "unknown child %d", pid);
4615507b659Ssturm 		} else {
4625507b659Ssturm 			/* protect from pid reusing. */
4635507b659Ssturm 			fl->locker = 0;
4645507b659Ssturm 			if (!WIFEXITED(sstatus) || WEXITSTATUS(sstatus) != 0) {
4655507b659Ssturm 				syslog(LOG_NOTICE, "child %d failed", pid);
4665507b659Ssturm 				/*
4675507b659Ssturm 				 * can't do much here; we can't reply
4685507b659Ssturm 				 * anything but OK for blocked locks
4695507b659Ssturm 				 * Eventually the client will time out
4705507b659Ssturm 				 * and retry.
4715507b659Ssturm 				 */
4725507b659Ssturm 				do_unlock(fl);
4735507b659Ssturm 				return;
4745507b659Ssturm 			}
4755507b659Ssturm 
4765507b659Ssturm 			/* check lock status */
4775507b659Ssturm 			syslog(LOG_DEBUG, "processing child %d, status %d",
4785507b659Ssturm 			    pid, fl->status);
4795507b659Ssturm 			switch(fl->status) {
4805507b659Ssturm 			case LKST_PROCESSING:
4815507b659Ssturm 				fl->status = LKST_LOCKED;
4825507b659Ssturm 				send_granted(fl, (fl->flags & LOCK_V4) ?
4835507b659Ssturm 				    nlm4_granted : nlm_granted);
4845507b659Ssturm 				break;
4855507b659Ssturm 			case LKST_DYING:
4865507b659Ssturm 				do_unlock(fl);
4875507b659Ssturm 				break;
4885507b659Ssturm 			default:
4895507b659Ssturm 				syslog(LOG_NOTICE, "bad lock status (%d) for"
4905507b659Ssturm 				   " child %d", fl->status, pid);
4915507b659Ssturm 			}
4925507b659Ssturm 		}
4935507b659Ssturm 	}
4945507b659Ssturm }
4955507b659Ssturm 
4965507b659Ssturm /*
4975507b659Ssturm  *
498d5a3b0c4Sjmc  * try to acquire the lock described by fl. Eventually fork a child to do a
4995507b659Ssturm  * blocking lock if allowed and required.
5005507b659Ssturm  */
5015507b659Ssturm 
5025507b659Ssturm enum nlm_stats
do_lock(struct file_lock * fl,int block)5035507b659Ssturm do_lock(struct file_lock *fl, int block)
5045507b659Ssturm {
5055507b659Ssturm 	int lflags, error;
5065507b659Ssturm 	struct stat st;
5075507b659Ssturm 
5085507b659Ssturm 	fl->fd = fhopen((fhandle_t *)fl->filehandle.fhdata, O_RDWR);
509df69c215Sderaadt 	if (fl->fd == -1) {
5105507b659Ssturm 		switch (errno) {
5115507b659Ssturm 		case ESTALE:
5125507b659Ssturm 			error = nlm4_stale_fh;
5135507b659Ssturm 			break;
5145507b659Ssturm 		case EROFS:
5155507b659Ssturm 			error = nlm4_rofs;
5165507b659Ssturm 			break;
5175507b659Ssturm 		default:
5185507b659Ssturm 			error = nlm4_failed;
5195507b659Ssturm 		}
5205507b659Ssturm 		if ((fl->flags & LOCK_V4) == 0)
5215507b659Ssturm 			error = nlm_denied;
5225507b659Ssturm 		syslog(LOG_NOTICE, "fhopen failed (from %s) (%m)",
5235507b659Ssturm 		    fl->client_name);
5245507b659Ssturm 		LIST_REMOVE(fl, lcklst);
5255507b659Ssturm 		return error;
5265507b659Ssturm 	}
527df69c215Sderaadt 	if (fstat(fl->fd, &st) == -1) {
5285507b659Ssturm 		syslog(LOG_NOTICE, "fstat failed (from %s) (%m)",
5295507b659Ssturm 		    fl->client_name);
5305507b659Ssturm 	}
5315507b659Ssturm 	syslog(LOG_DEBUG, "lock from %s.%" PRIu32 " for file%s%s: "
53279d31f91Sderaadt 	    "dev %u ino %llu (uid %d), flags %d",
5335507b659Ssturm 	    fl->client_name, fl->client.svid,
5345507b659Ssturm 	    fl->client.exclusive ? " (exclusive)":"", block ? " (block)":"",
53579d31f91Sderaadt 	    st.st_dev, (unsigned long long)st.st_ino, st.st_uid, fl->flags);
5365507b659Ssturm 	lflags = LOCK_NB;
5375507b659Ssturm 	if (fl->client.exclusive == 0)
5385507b659Ssturm 		lflags |= LOCK_SH;
5395507b659Ssturm 	else
5405507b659Ssturm 		lflags |= LOCK_EX;
5415507b659Ssturm 	error = flock(fl->fd, lflags);
5425507b659Ssturm 	if (error != 0 && errno == EAGAIN && block) {
5435507b659Ssturm 		switch (fl->locker = fork()) {
5445507b659Ssturm 		case -1: /* fork failed */
5455507b659Ssturm 			syslog(LOG_NOTICE, "fork failed (%m)");
5465507b659Ssturm 			LIST_REMOVE(fl, lcklst);
5475507b659Ssturm 			close(fl->fd);
5485507b659Ssturm 			return (fl->flags & LOCK_V4) ?
5495507b659Ssturm 			    nlm4_denied_nolock : nlm_denied_nolocks;
5505507b659Ssturm 		case 0:
5515507b659Ssturm 			/*
5525507b659Ssturm 			 * Attempt a blocking lock. Will have to call
5535507b659Ssturm 			 * NLM_GRANTED later.
5545507b659Ssturm 			 */
5555507b659Ssturm 			setproctitle("%s.%" PRIu32,
5565507b659Ssturm 			    fl->client_name, fl->client.svid);
5575507b659Ssturm 			lflags &= ~LOCK_NB;
5585507b659Ssturm 			if(flock(fl->fd, lflags) != 0) {
5595507b659Ssturm 				syslog(LOG_NOTICE, "flock failed (%m)");
5605507b659Ssturm 				_exit(1);
5615507b659Ssturm 			}
5625507b659Ssturm 			/* lock granted */
5635507b659Ssturm 			_exit(0);
5645507b659Ssturm 			/*NOTREACHED*/
5655507b659Ssturm 		default:
5665507b659Ssturm 			syslog(LOG_DEBUG, "lock request from %s.%" PRIu32 ": "
5675507b659Ssturm 			    "forked %d",
5685507b659Ssturm 			    fl->client_name, fl->client.svid, fl->locker);
5695507b659Ssturm 			fl->status = LKST_PROCESSING;
5705507b659Ssturm 			return (fl->flags & LOCK_V4) ?
5715507b659Ssturm 			    nlm4_blocked : nlm_blocked;
5725507b659Ssturm 		}
5735507b659Ssturm 	}
5745507b659Ssturm 	/* non block case */
5755507b659Ssturm 	if (error != 0) {
5765507b659Ssturm 		switch (errno) {
5775507b659Ssturm 		case EAGAIN:
5785507b659Ssturm 			error = nlm4_denied;
5795507b659Ssturm 			break;
5805507b659Ssturm 		case ESTALE:
5815507b659Ssturm 			error = nlm4_stale_fh;
5825507b659Ssturm 			break;
5835507b659Ssturm 		case EROFS:
5845507b659Ssturm 			error = nlm4_rofs;
5855507b659Ssturm 			break;
5865507b659Ssturm 		default:
5875507b659Ssturm 			error = nlm4_failed;
5885507b659Ssturm 		}
5895507b659Ssturm 		if ((fl->flags & LOCK_V4) == 0)
5905507b659Ssturm 			error = nlm_denied;
5915507b659Ssturm 		if (errno != EAGAIN)
5925507b659Ssturm 			syslog(LOG_NOTICE, "flock for %s failed (%m)",
5935507b659Ssturm 			    fl->client_name);
5945507b659Ssturm 		else syslog(LOG_DEBUG, "flock for %s failed (%m)",
5955507b659Ssturm 			    fl->client_name);
5965507b659Ssturm 		LIST_REMOVE(fl, lcklst);
5975507b659Ssturm 		close(fl->fd);
5985507b659Ssturm 		return error;
5995507b659Ssturm 	}
6005507b659Ssturm 	fl->status = LKST_LOCKED;
6015507b659Ssturm 	return (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted;
6025507b659Ssturm }
6035507b659Ssturm 
6045507b659Ssturm void
send_granted(struct file_lock * fl,int opcode)6055507b659Ssturm send_granted(struct file_lock *fl, int opcode)
6065507b659Ssturm {
6075507b659Ssturm 	CLIENT *cli;
6085507b659Ssturm 	static char dummy;
6095507b659Ssturm 	struct timeval timeo;
6105507b659Ssturm 	int success;
6115507b659Ssturm 	static struct nlm_res retval;
6125507b659Ssturm 	static struct nlm4_res retval4;
6135507b659Ssturm 
6145507b659Ssturm 	cli = get_client(fl->addr,
6155507b659Ssturm 	    (fl->flags & LOCK_V4) ? NLM_VERS4 : NLM_VERS);
6165507b659Ssturm 	if (cli == NULL) {
6175507b659Ssturm 		syslog(LOG_NOTICE, "failed to get CLIENT for %s.%" PRIu32,
6185507b659Ssturm 		    fl->client_name, fl->client.svid);
6195507b659Ssturm 		/*
6205507b659Ssturm 		 * We fail to notify remote that the lock has been granted.
6215507b659Ssturm 		 * The client will timeout and retry, the lock will be
6225507b659Ssturm 		 * granted at this time.
6235507b659Ssturm 		 */
6245507b659Ssturm 		return;
6255507b659Ssturm 	}
6265507b659Ssturm 	timeo.tv_sec = 0;
6275507b659Ssturm 	timeo.tv_usec = (fl->flags & LOCK_ASYNC) ? 0 : 500000; /* 0.5s */
6285507b659Ssturm 
6295507b659Ssturm 	if (fl->flags & LOCK_V4) {
6305507b659Ssturm 		static nlm4_testargs result;
6315507b659Ssturm 		result.cookie = fl->client_cookie;
6325507b659Ssturm 		result.exclusive = fl->client.exclusive;
6335507b659Ssturm 		result.alock.caller_name = fl->client_name;
6345507b659Ssturm 		result.alock.fh.n_len = fl->filehandle.fhsize;
6355507b659Ssturm 		result.alock.fh.n_bytes = fl->filehandle.fhdata;
6365507b659Ssturm 		result.alock.oh = fl->client.oh;
6375507b659Ssturm 		result.alock.svid = fl->client.svid;
6385507b659Ssturm 		result.alock.l_offset = fl->client.l_offset;
6395507b659Ssturm 		result.alock.l_len = fl->client.l_len;
6405507b659Ssturm 		syslog(LOG_DEBUG, "sending v4 reply%s",
6415507b659Ssturm 		    (fl->flags & LOCK_ASYNC) ? " (async)":"");
6425507b659Ssturm 		if (fl->flags & LOCK_ASYNC) {
6435507b659Ssturm 			success = clnt_call(cli, NLM4_GRANTED_MSG,
6445507b659Ssturm 			    xdr_nlm4_testargs, &result, xdr_void, &dummy, timeo);
6455507b659Ssturm 		} else {
6465507b659Ssturm 			success = clnt_call(cli, NLM4_GRANTED,
6475507b659Ssturm 			    xdr_nlm4_testargs, &result, xdr_nlm4_res,
6485507b659Ssturm 			    &retval4, timeo);
6495507b659Ssturm 		}
6505507b659Ssturm 	} else {
6515507b659Ssturm 		static nlm_testargs result;
6525507b659Ssturm 
6535507b659Ssturm 		result.cookie = fl->client_cookie;
6545507b659Ssturm 		result.exclusive = fl->client.exclusive;
6555507b659Ssturm 		result.alock.caller_name = fl->client_name;
6565507b659Ssturm 		result.alock.fh.n_len = fl->filehandle.fhsize;
6575507b659Ssturm 		result.alock.fh.n_bytes = fl->filehandle.fhdata;
6585507b659Ssturm 		result.alock.oh = fl->client.oh;
6595507b659Ssturm 		result.alock.svid = fl->client.svid;
6605507b659Ssturm 		result.alock.l_offset =
6615507b659Ssturm 		    (unsigned int)fl->client.l_offset;
6625507b659Ssturm 		result.alock.l_len =
6635507b659Ssturm 		    (unsigned int)fl->client.l_len;
6645507b659Ssturm 		syslog(LOG_DEBUG, "sending v1 reply%s",
6655507b659Ssturm 		    (fl->flags & LOCK_ASYNC) ? " (async)":"");
6665507b659Ssturm 		if (fl->flags & LOCK_ASYNC) {
6675507b659Ssturm 			success = clnt_call(cli, NLM_GRANTED_MSG,
6685507b659Ssturm 			    xdr_nlm_testargs, &result, xdr_void, &dummy, timeo);
6695507b659Ssturm 		} else {
6705507b659Ssturm 			success = clnt_call(cli, NLM_GRANTED,
6715507b659Ssturm 			    xdr_nlm_testargs, &result, xdr_nlm_res,
6725507b659Ssturm 			    &retval, timeo);
6735507b659Ssturm 		}
6745507b659Ssturm 	}
6755507b659Ssturm 	if (debug_level > 2)
6765507b659Ssturm 		syslog(LOG_DEBUG, "clnt_call returns %d(%s) for granted",
6775507b659Ssturm 		    success, clnt_sperrno(success));
6785507b659Ssturm 
6795507b659Ssturm }
6805507b659Ssturm 
6815507b659Ssturm enum nlm_stats
do_unlock(struct file_lock * rfl)6825507b659Ssturm do_unlock(struct file_lock *rfl)
6835507b659Ssturm {
6845507b659Ssturm 	struct file_lock *fl;
6855507b659Ssturm 	int error;
6865507b659Ssturm 	int lockst;
6875507b659Ssturm 
6885507b659Ssturm 	/* unlock the file: closing is enough ! */
6895507b659Ssturm 	if (close(rfl->fd) == -1) {
6905507b659Ssturm 		if (errno == ESTALE)
6915507b659Ssturm 			error = nlm4_stale_fh;
6925507b659Ssturm 		else
6935507b659Ssturm 			error = nlm4_failed;
6945507b659Ssturm 		if ((rfl->flags & LOCK_V4) == 0)
6955507b659Ssturm 			error = nlm_denied;
6965507b659Ssturm 		syslog(LOG_NOTICE, "close failed (from %s) (%m)",
6975507b659Ssturm 		    rfl->client_name);
6985507b659Ssturm 	} else {
6995507b659Ssturm 		error = (rfl->flags & LOCK_V4) ?
7005507b659Ssturm 		    nlm4_granted : nlm_granted;
7015507b659Ssturm 	}
7025507b659Ssturm 	LIST_REMOVE(rfl, lcklst);
7035507b659Ssturm 
7045507b659Ssturm 	/* process the next LKST_WAITING lock request for this fh */
7055507b659Ssturm 	LIST_FOREACH(fl, &lcklst_head, lcklst) {
7065507b659Ssturm 		if (fl->status != LKST_WAITING ||
7075507b659Ssturm 		    fhcmp(&rfl->filehandle, &fl->filehandle) != 0)
7085507b659Ssturm 			continue;
7095507b659Ssturm 
7105507b659Ssturm 		lockst = do_lock(fl, 1); /* If it's LKST_WAITING we can block */
7115507b659Ssturm 		switch (lockst) {
7125507b659Ssturm 		case nlm4_granted:
7135507b659Ssturm 		/* case nlm_granted: same as nlm4_granted */
7145507b659Ssturm 			send_granted(fl, (fl->flags & LOCK_V4) ?
7155507b659Ssturm 			    nlm4_granted : nlm_granted);
7165507b659Ssturm 			break;
7175507b659Ssturm 		case nlm4_blocked:
7185507b659Ssturm 		/* case nlm_blocked: same as nlm4_blocked */
7195507b659Ssturm 			break;
7205507b659Ssturm 		default:
7215507b659Ssturm 			lfree(fl);
7225507b659Ssturm 			break;
7235507b659Ssturm 		}
7245507b659Ssturm 		break;
7255507b659Ssturm 	}
7265507b659Ssturm 	lfree(rfl);
7275507b659Ssturm 	return error;
7285507b659Ssturm }
7295507b659Ssturm 
7305507b659Ssturm void
siglock(void)7315507b659Ssturm siglock(void)
7325507b659Ssturm {
7335507b659Ssturm 	sigset_t block;
7345507b659Ssturm 
7355507b659Ssturm 	sigemptyset(&block);
7365507b659Ssturm 	sigaddset(&block, SIGCHLD);
7375507b659Ssturm 
738df69c215Sderaadt 	if (sigprocmask(SIG_BLOCK, &block, NULL) == -1) {
7395507b659Ssturm 		syslog(LOG_WARNING, "siglock failed (%m)");
7405507b659Ssturm 	}
7415507b659Ssturm }
7425507b659Ssturm 
7435507b659Ssturm void
sigunlock(void)7445507b659Ssturm sigunlock(void)
7455507b659Ssturm {
7465507b659Ssturm 	sigset_t block;
7475507b659Ssturm 
7485507b659Ssturm 	sigemptyset(&block);
7495507b659Ssturm 	sigaddset(&block, SIGCHLD);
7505507b659Ssturm 
751df69c215Sderaadt 	if (sigprocmask(SIG_UNBLOCK, &block, NULL) == -1) {
7525507b659Ssturm 		syslog(LOG_WARNING, "sigunlock failed (%m)");
7535507b659Ssturm 	}
7545507b659Ssturm }
7555507b659Ssturm 
75675a10426Ssturm /* monitor a host through rpc.statd, and keep a ref count */
75775a10426Ssturm void
do_mon(const char * hostname)75875a10426Ssturm do_mon(const char *hostname)
75975a10426Ssturm {
76075a10426Ssturm 	static char localhost[] = "localhost";
76175a10426Ssturm 	struct host *hp;
76275a10426Ssturm 	struct mon my_mon;
76375a10426Ssturm 	struct sm_stat_res result;
76475a10426Ssturm 	int retval;
76575a10426Ssturm 
76675a10426Ssturm 	LIST_FOREACH(hp, &hostlst_head, hostlst) {
76775a10426Ssturm 		if (strcmp(hostname, hp->name) == 0) {
76875a10426Ssturm 			/* already monitored, just bump refcnt */
76975a10426Ssturm 			hp->refcnt++;
77075a10426Ssturm 			return;
77175a10426Ssturm 		}
77275a10426Ssturm 	}
77375a10426Ssturm 	/* not found, have to create an entry for it */
77475a10426Ssturm 	hp = malloc(sizeof(struct host));
77575a10426Ssturm 	if (hp == NULL) {
77675a10426Ssturm 		syslog(LOG_WARNING, "can't monitor host %s (%m)", hostname);
77775a10426Ssturm 		return;
77875a10426Ssturm 	}
77975a10426Ssturm 	strlcpy(hp->name, hostname, sizeof(hp->name));
78075a10426Ssturm 	hp->refcnt = 1;
78175a10426Ssturm 	syslog(LOG_DEBUG, "monitoring host %s", hostname);
78275a10426Ssturm 	memset(&my_mon, 0, sizeof(my_mon));
78375a10426Ssturm 	my_mon.mon_id.mon_name = hp->name;
78475a10426Ssturm 	my_mon.mon_id.my_id.my_name = localhost;
78575a10426Ssturm 	my_mon.mon_id.my_id.my_prog = NLM_PROG;
78675a10426Ssturm 	my_mon.mon_id.my_id.my_vers = NLM_SM;
78775a10426Ssturm 	my_mon.mon_id.my_id.my_proc = NLM_SM_NOTIFY;
78875a10426Ssturm 	if ((retval = callrpc(localhost, SM_PROG, SM_VERS, SM_MON, xdr_mon,
78975a10426Ssturm 	    (void *)&my_mon, xdr_sm_stat_res, (void *)&result)) != 0) {
79075a10426Ssturm 		syslog(LOG_WARNING, "rpc to statd failed (%s)",
79175a10426Ssturm 		    clnt_sperrno((enum clnt_stat)retval));
79275a10426Ssturm 		free(hp);
79375a10426Ssturm 		return;
79475a10426Ssturm 	}
79575a10426Ssturm 	if (result.res_stat == stat_fail) {
79675a10426Ssturm 		syslog(LOG_WARNING, "statd failed");
79775a10426Ssturm 		free(hp);
79875a10426Ssturm 		return;
79975a10426Ssturm 	}
80075a10426Ssturm 	LIST_INSERT_HEAD(&hostlst_head, hp, hostlst);
80175a10426Ssturm }
80275a10426Ssturm 
8035507b659Ssturm void
notify(const char * hostname,int state)8045507b659Ssturm notify(const char *hostname, int state)
8055507b659Ssturm {
8065507b659Ssturm 	struct file_lock *fl, *next_fl;
8075507b659Ssturm 	int err;
8085507b659Ssturm 	syslog(LOG_DEBUG, "notify from %s, new state %d", hostname, state);
8095507b659Ssturm 	/* search all lock for this host; if status changed, release the lock */
8105507b659Ssturm 	siglock();
8115507b659Ssturm 	for (fl = LIST_FIRST(&lcklst_head); fl != NULL; fl = next_fl) {
8125507b659Ssturm 		next_fl = LIST_NEXT(fl, lcklst);
8135507b659Ssturm 		if (strcmp(hostname, fl->client_name) == 0 &&
8145507b659Ssturm 		    fl->nsm_status != state) {
8155507b659Ssturm 			syslog(LOG_DEBUG, "state %d, nsm_state %d, unlocking",
8165507b659Ssturm 			    fl->status, fl->nsm_status);
8175507b659Ssturm 			switch(fl->status) {
8185507b659Ssturm 			case LKST_LOCKED:
8195507b659Ssturm 				err = do_unlock(fl);
8205507b659Ssturm 				if (err != nlm_granted)
8215507b659Ssturm 					syslog(LOG_DEBUG,
8225507b659Ssturm 					    "notify: unlock failed for %s (%d)",
8235507b659Ssturm 			    		    hostname, err);
8245507b659Ssturm 				break;
8255507b659Ssturm 			case LKST_WAITING:
8265507b659Ssturm 				LIST_REMOVE(fl, lcklst);
8275507b659Ssturm 				lfree(fl);
8285507b659Ssturm 				break;
8295507b659Ssturm 			case LKST_PROCESSING:
8305507b659Ssturm 				fl->status = LKST_DYING;
8315507b659Ssturm 				break;
8325507b659Ssturm 			case LKST_DYING:
8335507b659Ssturm 				break;
8345507b659Ssturm 			default:
8353a50f0a9Sjmc 				syslog(LOG_NOTICE, "unknown status %d for %s",
8365507b659Ssturm 				    fl->status, fl->client_name);
8375507b659Ssturm 			}
8385507b659Ssturm 		}
8395507b659Ssturm 	}
8405507b659Ssturm 	sigunlock();
8415507b659Ssturm }
842