Home | History | Annotate | Line # | Download | only in rpc.lockd
      1  1.34       chs /*	$NetBSD: lockd_lock.c,v 1.34 2017/06/08 03:25:03 chs Exp $	*/
      2   1.1    bouyer 
      3   1.1    bouyer /*
      4   1.1    bouyer  * Copyright (c) 2000 Manuel Bouyer.
      5   1.1    bouyer  *
      6   1.1    bouyer  * Redistribution and use in source and binary forms, with or without
      7   1.1    bouyer  * modification, are permitted provided that the following conditions
      8   1.1    bouyer  * are met:
      9   1.1    bouyer  * 1. Redistributions of source code must retain the above copyright
     10   1.1    bouyer  *    notice, this list of conditions and the following disclaimer.
     11   1.1    bouyer  * 2. Redistributions in binary form must reproduce the above copyright
     12   1.1    bouyer  *    notice, this list of conditions and the following disclaimer in the
     13   1.1    bouyer  *    documentation and/or other materials provided with the distribution.
     14   1.1    bouyer  *
     15   1.1    bouyer  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     16   1.1    bouyer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17   1.1    bouyer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18   1.1    bouyer  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     19   1.1    bouyer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20   1.1    bouyer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21   1.1    bouyer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22   1.1    bouyer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23   1.1    bouyer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24   1.1    bouyer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25   1.1    bouyer  * SUCH DAMAGE.
     26   1.1    bouyer  *
     27   1.1    bouyer  */
     28   1.1    bouyer 
     29   1.1    bouyer #include <stdio.h>
     30   1.1    bouyer #include <stdlib.h>
     31   1.1    bouyer #include <unistd.h>
     32   1.1    bouyer #include <fcntl.h>
     33   1.1    bouyer #include <syslog.h>
     34   1.1    bouyer #include <errno.h>
     35   1.1    bouyer #include <string.h>
     36   1.1    bouyer #include <signal.h>
     37   1.1    bouyer #include <rpc/rpc.h>
     38   1.1    bouyer #include <sys/socket.h>
     39   1.1    bouyer #include <sys/param.h>
     40   1.1    bouyer #include <sys/mount.h>
     41  1.34       chs #include <sys/queue.h>
     42   1.1    bouyer #include <sys/wait.h>
     43   1.1    bouyer #include <rpcsvc/sm_inter.h>
     44   1.4   thorpej #include <rpcsvc/nlm_prot.h>
     45   1.1    bouyer #include "lockd_lock.h"
     46   1.1    bouyer #include "lockd.h"
     47   1.1    bouyer 
     48   1.1    bouyer /* A set of utilities for managing file locking */
     49   1.1    bouyer LIST_HEAD(lcklst_head, file_lock);
     50   1.1    bouyer struct lcklst_head lcklst_head = LIST_HEAD_INITIALIZER(lcklst_head);
     51   1.1    bouyer 
     52  1.25      yamt #define	FHANDLE_SIZE_MAX	1024	/* arbitrary big enough value */
     53  1.25      yamt typedef struct {
     54  1.25      yamt 	size_t fhsize;
     55  1.25      yamt 	char *fhdata;
     56  1.23    martin } nfs_fhandle_t;
     57  1.23    martin 
     58  1.25      yamt static int
     59  1.25      yamt fhcmp(const nfs_fhandle_t *fh1, const nfs_fhandle_t *fh2)
     60  1.25      yamt {
     61  1.31  christos 	return memcmp(fh1->fhdata, fh2->fhdata, MIN(fh1->fhsize, fh2->fhsize));
     62  1.25      yamt }
     63  1.25      yamt 
     64  1.25      yamt static int
     65  1.25      yamt fhconv(nfs_fhandle_t *fh, const netobj *rfh)
     66  1.25      yamt {
     67  1.25      yamt 	size_t sz;
     68  1.25      yamt 
     69  1.25      yamt 	sz = rfh->n_len;
     70  1.25      yamt 	if (sz > FHANDLE_SIZE_MAX) {
     71  1.25      yamt 		syslog(LOG_DEBUG,
     72  1.26    martin 		    "received fhandle size %zd, max supported size %d",
     73  1.25      yamt 		    sz, FHANDLE_SIZE_MAX);
     74  1.25      yamt 		errno = EINVAL;
     75  1.25      yamt 		return -1;
     76  1.25      yamt 	}
     77  1.25      yamt 	fh->fhdata = malloc(sz);
     78  1.25      yamt 	if (fh->fhdata == NULL) {
     79  1.25      yamt 		return -1;
     80  1.25      yamt 	}
     81  1.25      yamt 	fh->fhsize = sz;
     82  1.28  christos 	(void)memcpy(fh->fhdata, rfh->n_bytes, sz);
     83  1.25      yamt 	return 0;
     84  1.25      yamt }
     85  1.25      yamt 
     86  1.25      yamt static void
     87  1.25      yamt fhfree(nfs_fhandle_t *fh)
     88  1.25      yamt {
     89  1.25      yamt 
     90  1.25      yamt 	free(fh->fhdata);
     91  1.25      yamt }
     92  1.25      yamt 
     93   1.1    bouyer /* struct describing a lock */
     94   1.1    bouyer struct file_lock {
     95   1.1    bouyer 	LIST_ENTRY(file_lock) lcklst;
     96  1.23    martin 	nfs_fhandle_t filehandle; /* NFS filehandle */
     97   1.1    bouyer 	struct sockaddr *addr;
     98   1.1    bouyer 	struct nlm4_holder client; /* lock holder */
     99   1.1    bouyer 	netobj client_cookie; /* cookie sent by the client */
    100   1.1    bouyer 	char client_name[128];
    101   1.1    bouyer 	int nsm_status; /* status from the remote lock manager */
    102   1.1    bouyer 	int status; /* lock status, see below */
    103   1.1    bouyer 	int flags; /* lock flags, see lockd_lock.h */
    104   1.1    bouyer 	pid_t locker; /* pid of the child process trying to get the lock */
    105   1.1    bouyer 	int fd;	/* file descriptor for this lock */
    106   1.1    bouyer };
    107   1.1    bouyer 
    108   1.1    bouyer /* lock status */
    109   1.1    bouyer #define LKST_LOCKED	1 /* lock is locked */
    110   1.1    bouyer #define LKST_WAITING	2 /* file is already locked by another host */
    111   1.9       wiz #define LKST_PROCESSING	3 /* child is trying to acquire the lock */
    112   1.1    bouyer #define LKST_DYING	4 /* must dies when we get news from the child */
    113   1.1    bouyer 
    114  1.25      yamt static struct file_lock *lalloc(void);
    115  1.28  christos void lfree(struct file_lock *);
    116  1.28  christos enum nlm_stats do_lock(struct file_lock *, int);
    117  1.28  christos enum nlm_stats do_unlock(struct file_lock *);
    118  1.28  christos void send_granted(struct file_lock *, int);
    119  1.28  christos void siglock(void);
    120  1.28  christos void sigunlock(void);
    121   1.1    bouyer 
    122   1.1    bouyer /* list of hosts we monitor */
    123   1.1    bouyer LIST_HEAD(hostlst_head, host);
    124   1.1    bouyer struct hostlst_head hostlst_head = LIST_HEAD_INITIALIZER(hostlst_head);
    125   1.1    bouyer 
    126   1.1    bouyer /* struct describing a lock */
    127   1.1    bouyer struct host {
    128   1.1    bouyer 	LIST_ENTRY(host) hostlst;
    129  1.15      yamt 	char name[SM_MAXSTRLEN+1];
    130   1.1    bouyer 	int refcnt;
    131   1.1    bouyer };
    132   1.1    bouyer 
    133  1.28  christos void do_mon(const char *);
    134   1.1    bouyer 
    135  1.18      yamt #define	LL_FH	0x01
    136  1.18      yamt #define	LL_NAME	0x02
    137  1.18      yamt #define	LL_SVID	0x04
    138  1.18      yamt 
    139  1.28  christos static struct file_lock *lock_lookup(struct file_lock *, int);
    140  1.18      yamt 
    141  1.18      yamt /*
    142  1.18      yamt  * lock_lookup: lookup a matching lock.
    143  1.18      yamt  * called with siglock held.
    144  1.18      yamt  */
    145  1.18      yamt static struct file_lock *
    146  1.28  christos lock_lookup(struct file_lock *newfl, int flags)
    147  1.18      yamt {
    148  1.18      yamt 	struct file_lock *fl;
    149  1.18      yamt 
    150  1.18      yamt 	LIST_FOREACH(fl, &lcklst_head, lcklst) {
    151  1.18      yamt 		if ((flags & LL_SVID) != 0 &&
    152  1.18      yamt 		    newfl->client.svid != fl->client.svid)
    153  1.18      yamt 			continue;
    154  1.18      yamt 		if ((flags & LL_NAME) != 0 &&
    155  1.18      yamt 		    strcmp(newfl->client_name, fl->client_name) != 0)
    156  1.18      yamt 			continue;
    157  1.18      yamt 		if ((flags & LL_FH) != 0 &&
    158  1.25      yamt 		    fhcmp(&newfl->filehandle, &fl->filehandle) != 0)
    159  1.18      yamt 			continue;
    160  1.18      yamt 		/* found */
    161  1.18      yamt 		break;
    162  1.18      yamt 	}
    163  1.18      yamt 
    164  1.18      yamt 	return fl;
    165  1.18      yamt }
    166  1.18      yamt 
    167   1.1    bouyer /*
    168   1.1    bouyer  * testlock(): inform the caller if the requested lock would be granted or not
    169   1.1    bouyer  * returns NULL if lock would granted, or pointer to the current nlm4_holder
    170   1.1    bouyer  * otherwise.
    171   1.1    bouyer  */
    172   1.1    bouyer 
    173   1.1    bouyer struct nlm4_holder *
    174  1.28  christos /*ARGSUSED*/
    175  1.28  christos testlock(struct nlm4_lock *lock, int flags)
    176   1.1    bouyer {
    177   1.1    bouyer 	struct file_lock *fl;
    178  1.23    martin 	nfs_fhandle_t filehandle;
    179   1.1    bouyer 
    180   1.1    bouyer 	/* convert lock to a local filehandle */
    181  1.25      yamt 	if (fhconv(&filehandle, &lock->fh)) {
    182  1.28  christos 		syslog(LOG_NOTICE, "fhconv failed (%m)");
    183  1.25      yamt 		return NULL; /* XXX */
    184  1.25      yamt 	}
    185   1.1    bouyer 
    186   1.1    bouyer 	siglock();
    187   1.1    bouyer 	/* search through the list for lock holder */
    188  1.14      yamt 	LIST_FOREACH(fl, &lcklst_head, lcklst) {
    189   1.1    bouyer 		if (fl->status != LKST_LOCKED)
    190   1.1    bouyer 			continue;
    191  1.25      yamt 		if (fhcmp(&fl->filehandle, &filehandle) != 0)
    192   1.1    bouyer 			continue;
    193   1.1    bouyer 		/* got it ! */
    194   1.1    bouyer 		syslog(LOG_DEBUG, "test for %s: found lock held by %s",
    195   1.1    bouyer 		    lock->caller_name, fl->client_name);
    196   1.1    bouyer 		sigunlock();
    197  1.25      yamt 		fhfree(&filehandle);
    198   1.1    bouyer 		return (&fl->client);
    199   1.1    bouyer 	}
    200   1.1    bouyer 	/* not found */
    201   1.1    bouyer 	sigunlock();
    202  1.25      yamt 	fhfree(&filehandle);
    203   1.1    bouyer 	syslog(LOG_DEBUG, "test for %s: no lock found", lock->caller_name);
    204   1.1    bouyer 	return NULL;
    205   1.1    bouyer }
    206   1.1    bouyer 
    207   1.1    bouyer /*
    208   1.9       wiz  * getlock: try to acquire the lock.
    209   1.1    bouyer  * If file is already locked and we can sleep, put the lock in the list with
    210   1.1    bouyer  * status LKST_WAITING; it'll be processed later.
    211   1.1    bouyer  * Otherwise try to lock. If we're allowed to block, fork a child which
    212   1.1    bouyer  * will do the blocking lock.
    213   1.1    bouyer  */
    214   1.1    bouyer enum nlm_stats
    215  1.28  christos getlock(nlm4_lockargs * lckarg, struct svc_req *rqstp, int flags)
    216   1.1    bouyer {
    217   1.1    bouyer 	struct file_lock *fl, *newfl;
    218   1.1    bouyer 	enum nlm_stats retval;
    219  1.19    bouyer 	struct sockaddr *addr;
    220   1.1    bouyer 
    221   1.1    bouyer 	if (grace_expired == 0 && lckarg->reclaim == 0)
    222   1.1    bouyer 		return (flags & LOCK_V4) ?
    223  1.28  christos 		    (enum nlm_stats)nlm4_denied_grace_period : nlm_denied_grace_period;
    224   1.1    bouyer 
    225   1.1    bouyer 	/* allocate new file_lock for this request */
    226  1.25      yamt 	newfl = lalloc();
    227   1.1    bouyer 	if (newfl == NULL) {
    228  1.28  christos 		syslog(LOG_NOTICE, "malloc failed (%m)");
    229   1.1    bouyer 		/* failed */
    230   1.1    bouyer 		return (flags & LOCK_V4) ?
    231  1.28  christos 		    (enum nlm_stats)nlm4_denied_nolock : nlm_denied_nolocks;
    232   1.1    bouyer 	}
    233  1.25      yamt 	if (fhconv(&newfl->filehandle, &lckarg->alock.fh)) {
    234  1.28  christos 		syslog(LOG_NOTICE, "fhconv failed (%m)");
    235  1.25      yamt 		lfree(newfl);
    236  1.25      yamt 		/* failed */
    237  1.25      yamt 		return (flags & LOCK_V4) ?
    238  1.28  christos 		    (enum nlm_stats)nlm4_denied_nolock : nlm_denied_nolocks;
    239   1.1    bouyer 	}
    240  1.19    bouyer 	addr = (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf;
    241  1.28  christos 	newfl->addr = malloc((size_t)addr->sa_len);
    242  1.19    bouyer 	if (newfl->addr == NULL) {
    243  1.28  christos 		syslog(LOG_NOTICE, "malloc failed (%m)");
    244  1.25      yamt 		lfree(newfl);
    245  1.19    bouyer 		/* failed */
    246  1.19    bouyer 		return (flags & LOCK_V4) ?
    247  1.28  christos 		    (enum nlm_stats)nlm4_denied_nolock : nlm_denied_nolocks;
    248  1.19    bouyer 	}
    249  1.28  christos 	(void)memcpy(newfl->addr, addr, (size_t)addr->sa_len);
    250   1.1    bouyer 	newfl->client.exclusive = lckarg->exclusive;
    251   1.1    bouyer 	newfl->client.svid = lckarg->alock.svid;
    252   1.1    bouyer 	newfl->client.oh.n_bytes = malloc(lckarg->alock.oh.n_len);
    253   1.1    bouyer 	if (newfl->client.oh.n_bytes == NULL) {
    254  1.28  christos 		syslog(LOG_NOTICE, "malloc failed (%m)");
    255  1.25      yamt 		lfree(newfl);
    256   1.1    bouyer 		return (flags & LOCK_V4) ?
    257  1.28  christos 		    (enum nlm_stats)nlm4_denied_nolock : nlm_denied_nolocks;
    258   1.1    bouyer 	}
    259   1.1    bouyer 	newfl->client.oh.n_len = lckarg->alock.oh.n_len;
    260  1.28  christos 	(void)memcpy(newfl->client.oh.n_bytes, lckarg->alock.oh.n_bytes,
    261   1.1    bouyer 	    lckarg->alock.oh.n_len);
    262   1.1    bouyer 	newfl->client.l_offset = lckarg->alock.l_offset;
    263   1.1    bouyer 	newfl->client.l_len = lckarg->alock.l_len;
    264   1.1    bouyer 	newfl->client_cookie.n_len = lckarg->cookie.n_len;
    265   1.1    bouyer 	newfl->client_cookie.n_bytes = malloc(lckarg->cookie.n_len);
    266   1.1    bouyer 	if (newfl->client_cookie.n_bytes == NULL) {
    267  1.28  christos 		syslog(LOG_NOTICE, "malloc failed (%m)");
    268  1.25      yamt 		lfree(newfl);
    269   1.1    bouyer 		return (flags & LOCK_V4) ?
    270  1.28  christos 		    (enum nlm_stats)nlm4_denied_nolock : nlm_denied_nolocks;
    271   1.1    bouyer 	}
    272  1.28  christos 	(void)memcpy(newfl->client_cookie.n_bytes, lckarg->cookie.n_bytes,
    273   1.1    bouyer 	    lckarg->cookie.n_len);
    274  1.28  christos 	(void)strlcpy(newfl->client_name, lckarg->alock.caller_name,
    275  1.16      yamt 	    sizeof(newfl->client_name));
    276   1.1    bouyer 	newfl->nsm_status = lckarg->state;
    277   1.1    bouyer 	newfl->status = 0;
    278   1.1    bouyer 	newfl->flags = flags;
    279   1.1    bouyer 	siglock();
    280   1.1    bouyer 	/* look for a lock rq from this host for this fh */
    281  1.18      yamt 	fl = lock_lookup(newfl, LL_FH|LL_NAME|LL_SVID);
    282  1.18      yamt 	if (fl) {
    283  1.18      yamt 		/* already locked by this host ??? */
    284  1.18      yamt 		sigunlock();
    285  1.18      yamt 		syslog(LOG_NOTICE, "duplicate lock from %s.%"
    286  1.18      yamt 		    PRIu32,
    287  1.18      yamt 		    newfl->client_name, newfl->client.svid);
    288  1.18      yamt 		lfree(newfl);
    289  1.18      yamt 		switch(fl->status) {
    290  1.18      yamt 		case LKST_LOCKED:
    291  1.18      yamt 			return (flags & LOCK_V4) ?
    292  1.28  christos 			    (enum nlm_stats)nlm4_granted : nlm_granted;
    293  1.18      yamt 		case LKST_WAITING:
    294  1.18      yamt 		case LKST_PROCESSING:
    295  1.18      yamt 			return (flags & LOCK_V4) ?
    296  1.28  christos 			    (enum nlm_stats)nlm4_blocked : nlm_blocked;
    297  1.18      yamt 		case LKST_DYING:
    298  1.18      yamt 			return (flags & LOCK_V4) ?
    299  1.28  christos 			    (enum nlm_stats)nlm4_denied : nlm_denied;
    300  1.18      yamt 		default:
    301  1.18      yamt 			syslog(LOG_NOTICE, "bad status %d",
    302  1.18      yamt 			    fl->status);
    303  1.18      yamt 			return (flags & LOCK_V4) ?
    304  1.28  christos 			    (enum nlm_stats)nlm4_failed : nlm_denied;
    305  1.18      yamt 		}
    306  1.18      yamt 		/* NOTREACHED */
    307  1.18      yamt 	}
    308  1.18      yamt 	fl = lock_lookup(newfl, LL_FH);
    309  1.18      yamt 	if (fl) {
    310  1.18      yamt 		/*
    311  1.18      yamt 		 * We already have a lock for this file.
    312  1.18      yamt 		 * Put this one in waiting state if allowed to block
    313  1.18      yamt 		 */
    314  1.18      yamt 		if (lckarg->block) {
    315  1.18      yamt 			syslog(LOG_DEBUG, "lock from %s.%" PRIu32 ": "
    316  1.18      yamt 			    "already locked, waiting",
    317  1.18      yamt 			    lckarg->alock.caller_name,
    318  1.18      yamt 			    lckarg->alock.svid);
    319  1.18      yamt 			newfl->status = LKST_WAITING;
    320  1.18      yamt 			LIST_INSERT_HEAD(&lcklst_head, newfl, lcklst);
    321  1.18      yamt 			do_mon(lckarg->alock.caller_name);
    322  1.18      yamt 			sigunlock();
    323  1.18      yamt 			return (flags & LOCK_V4) ?
    324  1.28  christos 			    (enum nlm_stats)nlm4_blocked : nlm_blocked;
    325  1.18      yamt 		} else {
    326  1.18      yamt 			sigunlock();
    327  1.18      yamt 			syslog(LOG_DEBUG, "lock from %s.%" PRIu32 ": "
    328  1.18      yamt 			    "already locked, failed",
    329  1.18      yamt 			    lckarg->alock.caller_name,
    330  1.18      yamt 			    lckarg->alock.svid);
    331  1.18      yamt 			lfree(newfl);
    332  1.18      yamt 			return (flags & LOCK_V4) ?
    333  1.28  christos 			    (enum nlm_stats)nlm4_denied : nlm_denied;
    334   1.1    bouyer 		}
    335  1.18      yamt 		/* NOTREACHED */
    336   1.1    bouyer 	}
    337  1.18      yamt 
    338   1.1    bouyer 	/* no entry for this file yet; add to list */
    339   1.1    bouyer 	LIST_INSERT_HEAD(&lcklst_head, newfl, lcklst);
    340   1.1    bouyer 	/* do the lock */
    341   1.1    bouyer 	retval = do_lock(newfl, lckarg->block);
    342   1.1    bouyer 	switch (retval) {
    343   1.1    bouyer 	case nlm4_granted:
    344   1.1    bouyer 	/* case nlm_granted: is the same as nlm4_granted */
    345   1.1    bouyer 	case nlm4_blocked:
    346   1.1    bouyer 	/* case nlm_blocked: is the same as nlm4_blocked */
    347   1.1    bouyer 		do_mon(lckarg->alock.caller_name);
    348   1.1    bouyer 		break;
    349   1.1    bouyer 	default:
    350   1.5     enami 		lfree(newfl);
    351   1.1    bouyer 		break;
    352   1.1    bouyer 	}
    353   1.1    bouyer 	sigunlock();
    354   1.1    bouyer 	return retval;
    355   1.1    bouyer }
    356   1.1    bouyer 
    357   1.1    bouyer /* unlock a filehandle */
    358   1.1    bouyer enum nlm_stats
    359  1.28  christos unlock(nlm4_lock *lck, int flags)
    360   1.1    bouyer {
    361   1.1    bouyer 	struct file_lock *fl;
    362  1.23    martin 	nfs_fhandle_t filehandle;
    363  1.28  christos 	int err = (flags & LOCK_V4) ? (enum nlm_stats)nlm4_granted : nlm_granted;
    364   1.1    bouyer 
    365  1.25      yamt 	if (fhconv(&filehandle, &lck->fh)) {
    366  1.28  christos 		syslog(LOG_NOTICE, "fhconv failed (%m)");
    367  1.28  christos 		return (flags & LOCK_V4) ? (enum nlm_stats)nlm4_denied : nlm_denied;
    368  1.25      yamt 	}
    369   1.1    bouyer 	siglock();
    370  1.14      yamt 	LIST_FOREACH(fl, &lcklst_head, lcklst) {
    371   1.1    bouyer 		if (strcmp(fl->client_name, lck->caller_name) ||
    372  1.25      yamt 		    fhcmp(&filehandle, &fl->filehandle) != 0 ||
    373   1.1    bouyer 		    fl->client.oh.n_len != lck->oh.n_len ||
    374   1.1    bouyer 		    memcmp(fl->client.oh.n_bytes, lck->oh.n_bytes,
    375   1.1    bouyer 			fl->client.oh.n_len) != 0 ||
    376   1.1    bouyer 		    fl->client.svid != lck->svid)
    377   1.1    bouyer 			continue;
    378   1.1    bouyer 		/* Got it, unlock and remove from the queue */
    379  1.17      yamt 		syslog(LOG_DEBUG, "unlock from %s.%" PRIu32 ": found struct, "
    380  1.17      yamt 		    "status %d", lck->caller_name, lck->svid, fl->status);
    381   1.1    bouyer 		switch (fl->status) {
    382   1.1    bouyer 		case LKST_LOCKED:
    383   1.1    bouyer 			err = do_unlock(fl);
    384   1.1    bouyer 			break;
    385   1.1    bouyer 		case LKST_WAITING:
    386   1.1    bouyer 			/* remove from the list */
    387   1.1    bouyer 			LIST_REMOVE(fl, lcklst);
    388   1.1    bouyer 			lfree(fl);
    389   1.1    bouyer 			break;
    390   1.1    bouyer 		case LKST_PROCESSING:
    391   1.1    bouyer 			/*
    392   1.1    bouyer 			 * being handled by a child; will clean up
    393   1.1    bouyer 			 * when the child exits
    394   1.1    bouyer 			 */
    395   1.1    bouyer 			fl->status = LKST_DYING;
    396   1.1    bouyer 			break;
    397   1.1    bouyer 		case LKST_DYING:
    398   1.1    bouyer 			/* nothing to do */
    399   1.1    bouyer 			break;
    400   1.1    bouyer 		default:
    401  1.33       wiz 			syslog(LOG_NOTICE, "unknown status %d for %s",
    402   1.1    bouyer 			    fl->status, fl->client_name);
    403   1.1    bouyer 		}
    404   1.1    bouyer 		sigunlock();
    405  1.25      yamt 		fhfree(&filehandle);
    406   1.1    bouyer 		return err;
    407   1.1    bouyer 	}
    408   1.1    bouyer 	sigunlock();
    409   1.1    bouyer 	/* didn't find a matching entry; log anyway */
    410   1.1    bouyer 	syslog(LOG_NOTICE, "no matching entry for %s",
    411   1.1    bouyer 	    lck->caller_name);
    412  1.25      yamt 	fhfree(&filehandle);
    413  1.28  christos 	return (flags & LOCK_V4) ? (enum nlm_stats)nlm4_granted : nlm_granted;
    414   1.1    bouyer }
    415   1.1    bouyer 
    416  1.25      yamt static struct file_lock *
    417  1.25      yamt lalloc(void)
    418  1.25      yamt {
    419  1.27  christos 	return calloc(1, sizeof(struct file_lock));
    420  1.25      yamt }
    421  1.25      yamt 
    422   1.1    bouyer void
    423  1.28  christos lfree(struct file_lock *fl)
    424   1.1    bouyer {
    425  1.19    bouyer 	free(fl->addr);
    426   1.1    bouyer 	free(fl->client.oh.n_bytes);
    427   1.1    bouyer 	free(fl->client_cookie.n_bytes);
    428  1.25      yamt 	fhfree(&fl->filehandle);
    429   1.1    bouyer 	free(fl);
    430   1.1    bouyer }
    431   1.1    bouyer 
    432   1.1    bouyer void
    433  1.28  christos /*ARGSUSED*/
    434  1.28  christos sigchild_handler(int sig)
    435   1.1    bouyer {
    436  1.28  christos 	int sstatus;
    437   1.1    bouyer 	pid_t pid;
    438   1.1    bouyer 	struct file_lock *fl;
    439   1.1    bouyer 
    440  1.28  christos 	for (;;) {
    441  1.28  christos 		pid = wait4(-1, &sstatus, WNOHANG, NULL);
    442   1.1    bouyer 		if (pid == -1) {
    443   1.1    bouyer 			if (errno != ECHILD)
    444  1.28  christos 				syslog(LOG_NOTICE, "wait failed (%m)");
    445   1.1    bouyer 			else
    446  1.28  christos 				syslog(LOG_DEBUG, "wait failed (%m)");
    447   1.1    bouyer 			return;
    448   1.1    bouyer 		}
    449   1.1    bouyer 		if (pid == 0) {
    450   1.1    bouyer 			/* no more child to handle yet */
    451   1.1    bouyer 			return;
    452   1.1    bouyer 		}
    453   1.1    bouyer 		/*
    454   1.1    bouyer 		 * if we're here we have a child that exited
    455   1.1    bouyer 		 * Find the associated file_lock.
    456   1.1    bouyer 		 */
    457  1.14      yamt 		LIST_FOREACH(fl, &lcklst_head, lcklst) {
    458   1.1    bouyer 			if (pid == fl->locker)
    459   1.1    bouyer 				break;
    460   1.1    bouyer 		}
    461  1.12      yamt 		if (fl == NULL) {
    462  1.33       wiz 			syslog(LOG_NOTICE, "unknown child %d", pid);
    463   1.1    bouyer 		} else {
    464  1.12      yamt 			/*
    465  1.12      yamt 			 * protect from pid reusing.
    466  1.12      yamt 			 */
    467  1.12      yamt 			fl->locker = 0;
    468  1.28  christos 			if (!WIFEXITED(sstatus) || WEXITSTATUS(sstatus) != 0) {
    469   1.1    bouyer 				syslog(LOG_NOTICE, "child %d failed", pid);
    470   1.1    bouyer 				/*
    471   1.1    bouyer 				 * can't do much here; we can't reply
    472   1.1    bouyer 				 * anything but OK for blocked locks
    473   1.1    bouyer 				 * Eventually the client will time out
    474   1.1    bouyer 				 * and retry.
    475   1.1    bouyer 				 */
    476  1.28  christos 				(void)do_unlock(fl);
    477   1.1    bouyer 				return;
    478   1.1    bouyer 			}
    479   1.1    bouyer 
    480   1.1    bouyer 			/* check lock status */
    481   1.1    bouyer 			syslog(LOG_DEBUG, "processing child %d, status %d",
    482   1.1    bouyer 			    pid, fl->status);
    483   1.1    bouyer 			switch(fl->status) {
    484   1.1    bouyer 			case LKST_PROCESSING:
    485   1.1    bouyer 				fl->status = LKST_LOCKED;
    486   1.1    bouyer 				send_granted(fl, (fl->flags & LOCK_V4) ?
    487  1.28  christos 				    (enum nlm_stats)nlm4_granted : nlm_granted);
    488   1.1    bouyer 				break;
    489   1.1    bouyer 			case LKST_DYING:
    490  1.28  christos 				(void)do_unlock(fl);
    491   1.1    bouyer 				break;
    492   1.1    bouyer 			default:
    493   1.1    bouyer 				syslog(LOG_NOTICE, "bad lock status (%d) for"
    494   1.1    bouyer 				   " child %d", fl->status, pid);
    495   1.1    bouyer 			}
    496   1.1    bouyer 		}
    497   1.1    bouyer 	}
    498   1.1    bouyer }
    499   1.1    bouyer 
    500   1.1    bouyer /*
    501   1.1    bouyer  *
    502   1.9       wiz  * try to acquire the lock described by fl. Eventually fork a child to do a
    503   1.1    bouyer  * blocking lock if allowed and required.
    504   1.1    bouyer  */
    505   1.1    bouyer 
    506   1.1    bouyer enum nlm_stats
    507  1.28  christos do_lock(struct file_lock *fl, int block)
    508   1.1    bouyer {
    509   1.1    bouyer 	int lflags, error;
    510   1.1    bouyer 	struct stat st;
    511   1.1    bouyer 
    512  1.25      yamt 	fl->fd = fhopen(fl->filehandle.fhdata, fl->filehandle.fhsize, O_RDWR);
    513   1.1    bouyer 	if (fl->fd < 0) {
    514   1.1    bouyer 		switch (errno) {
    515   1.1    bouyer 		case ESTALE:
    516   1.1    bouyer 			error = nlm4_stale_fh;
    517   1.1    bouyer 			break;
    518   1.1    bouyer 		case EROFS:
    519   1.1    bouyer 			error = nlm4_rofs;
    520   1.1    bouyer 			break;
    521   1.1    bouyer 		default:
    522   1.1    bouyer 			error = nlm4_failed;
    523   1.1    bouyer 		}
    524   1.1    bouyer 		if ((fl->flags & LOCK_V4) == 0)
    525   1.1    bouyer 			error = nlm_denied;
    526  1.28  christos 		syslog(LOG_NOTICE, "fhopen failed (from %s) (%m)",
    527  1.28  christos 		    fl->client_name);
    528   1.1    bouyer 		LIST_REMOVE(fl, lcklst);
    529  1.11    simonb 		return error;
    530   1.1    bouyer 	}
    531   1.1    bouyer 	if (fstat(fl->fd, &st) < 0) {
    532  1.28  christos 		syslog(LOG_NOTICE, "fstat failed (from %s) (%m)",
    533  1.28  christos 		    fl->client_name);
    534   1.1    bouyer 	}
    535  1.17      yamt 	syslog(LOG_DEBUG, "lock from %s.%" PRIu32 " for file%s%s: "
    536  1.29  christos 	    "dev %llu ino %llu (uid %d), flags %d",
    537  1.17      yamt 	    fl->client_name, fl->client.svid,
    538  1.17      yamt 	    fl->client.exclusive ? " (exclusive)":"", block ? " (block)":"",
    539  1.29  christos 	    (unsigned long long)st.st_dev,
    540  1.29  christos 	    (unsigned long long)st.st_ino, st.st_uid, fl->flags);
    541   1.1    bouyer 	lflags = LOCK_NB;
    542   1.1    bouyer 	if (fl->client.exclusive == 0)
    543   1.1    bouyer 		lflags |= LOCK_SH;
    544   1.1    bouyer 	else
    545   1.1    bouyer 		lflags |= LOCK_EX;
    546   1.1    bouyer 	error = flock(fl->fd, lflags);
    547   1.1    bouyer 	if (error != 0 && errno == EAGAIN && block) {
    548   1.1    bouyer 		switch (fl->locker = fork()) {
    549   1.1    bouyer 		case -1: /* fork failed */
    550  1.28  christos 			syslog(LOG_NOTICE, "fork failed (%m)");
    551   1.1    bouyer 			LIST_REMOVE(fl, lcklst);
    552  1.28  christos 			(void)close(fl->fd);
    553   1.1    bouyer 			return (fl->flags & LOCK_V4) ?
    554  1.28  christos 			    (enum nlm_stats)nlm4_denied_nolock : nlm_denied_nolocks;
    555   1.1    bouyer 		case 0:
    556   1.1    bouyer 			/*
    557   1.1    bouyer 			 * Attempt a blocking lock. Will have to call
    558   1.1    bouyer 			 * NLM_GRANTED later.
    559   1.1    bouyer 			 */
    560  1.17      yamt 			setproctitle("%s.%" PRIu32,
    561  1.17      yamt 			    fl->client_name, fl->client.svid);
    562   1.1    bouyer 			lflags &= ~LOCK_NB;
    563   1.1    bouyer 			if(flock(fl->fd, lflags) != 0) {
    564  1.28  christos 				syslog(LOG_NOTICE, "flock failed (%m)");
    565  1.13      yamt 				_exit(1);
    566   1.1    bouyer 			}
    567   1.1    bouyer 			/* lock granted */
    568  1.13      yamt 			_exit(0);
    569  1.28  christos 			/*NOTREACHED*/
    570   1.1    bouyer 		default:
    571  1.17      yamt 			syslog(LOG_DEBUG, "lock request from %s.%" PRIu32 ": "
    572  1.17      yamt 			    "forked %d",
    573  1.17      yamt 			    fl->client_name, fl->client.svid, fl->locker);
    574   1.1    bouyer 			fl->status = LKST_PROCESSING;
    575   1.1    bouyer 			return (fl->flags & LOCK_V4) ?
    576  1.28  christos 			    (enum nlm_stats)nlm4_blocked : nlm_blocked;
    577   1.1    bouyer 		}
    578   1.1    bouyer 	}
    579   1.1    bouyer 	/* non block case */
    580   1.1    bouyer 	if (error != 0) {
    581   1.1    bouyer 		switch (errno) {
    582   1.1    bouyer 		case EAGAIN:
    583   1.1    bouyer 			error = nlm4_denied;
    584   1.1    bouyer 			break;
    585   1.1    bouyer 		case ESTALE:
    586   1.1    bouyer 			error = nlm4_stale_fh;
    587   1.1    bouyer 			break;
    588   1.1    bouyer 		case EROFS:
    589   1.1    bouyer 			error = nlm4_rofs;
    590   1.1    bouyer 			break;
    591   1.1    bouyer 		default:
    592   1.1    bouyer 			error = nlm4_failed;
    593   1.1    bouyer 		}
    594   1.1    bouyer 		if ((fl->flags & LOCK_V4) == 0)
    595   1.1    bouyer 			error = nlm_denied;
    596   1.1    bouyer 		if (errno != EAGAIN)
    597  1.28  christos 			syslog(LOG_NOTICE, "flock for %s failed (%m)",
    598  1.28  christos 			    fl->client_name);
    599  1.28  christos 		else syslog(LOG_DEBUG, "flock for %s failed (%m)",
    600  1.28  christos 			    fl->client_name);
    601   1.1    bouyer 		LIST_REMOVE(fl, lcklst);
    602  1.28  christos 		(void)close(fl->fd);
    603   1.1    bouyer 		return error;
    604   1.1    bouyer 	}
    605   1.1    bouyer 	fl->status = LKST_LOCKED;
    606  1.28  christos 	return (fl->flags & LOCK_V4) ? (enum nlm_stats)nlm4_granted : nlm_granted;
    607   1.1    bouyer }
    608   1.1    bouyer 
    609   1.1    bouyer void
    610  1.28  christos /*ARGSUSED*/
    611  1.28  christos send_granted(struct file_lock *fl, int opcode)
    612   1.1    bouyer {
    613   1.1    bouyer 	CLIENT *cli;
    614   1.1    bouyer 	static char dummy;
    615   1.1    bouyer 	struct timeval timeo;
    616   1.1    bouyer 	int success;
    617   1.1    bouyer 	static struct nlm_res retval;
    618   1.1    bouyer 	static struct nlm4_res retval4;
    619   1.1    bouyer 
    620  1.28  christos 	cli = get_client(fl->addr, (rpcvers_t)
    621  1.28  christos 	    ((fl->flags & LOCK_V4) ? NLM_VERS4 : NLM_VERS));
    622   1.1    bouyer 	if (cli == NULL) {
    623  1.17      yamt 		syslog(LOG_NOTICE, "failed to get CLIENT for %s.%" PRIu32,
    624  1.17      yamt 		    fl->client_name, fl->client.svid);
    625   1.1    bouyer 		/*
    626   1.1    bouyer 		 * We fail to notify remote that the lock has been granted.
    627   1.1    bouyer 		 * The client will timeout and retry, the lock will be
    628   1.1    bouyer 		 * granted at this time.
    629   1.1    bouyer 		 */
    630   1.1    bouyer 		return;
    631   1.1    bouyer 	}
    632   1.1    bouyer 	timeo.tv_sec = 0;
    633   1.1    bouyer 	timeo.tv_usec = (fl->flags & LOCK_ASYNC) ? 0 : 500000; /* 0.5s */
    634   1.1    bouyer 
    635   1.1    bouyer 	if (fl->flags & LOCK_V4) {
    636  1.28  christos 		static nlm4_testargs result;
    637  1.28  christos 		result.cookie = fl->client_cookie;
    638  1.28  christos 		result.exclusive = fl->client.exclusive;
    639  1.28  christos 		result.alock.caller_name = fl->client_name;
    640  1.28  christos 		result.alock.fh.n_len = fl->filehandle.fhsize;
    641  1.28  christos 		result.alock.fh.n_bytes = fl->filehandle.fhdata;
    642  1.28  christos 		result.alock.oh = fl->client.oh;
    643  1.28  christos 		result.alock.svid = fl->client.svid;
    644  1.28  christos 		result.alock.l_offset = fl->client.l_offset;
    645  1.28  christos 		result.alock.l_len = fl->client.l_len;
    646   1.1    bouyer 		syslog(LOG_DEBUG, "sending v4 reply%s",
    647   1.1    bouyer 		    (fl->flags & LOCK_ASYNC) ? " (async)":"");
    648   1.1    bouyer 		if (fl->flags & LOCK_ASYNC) {
    649   1.1    bouyer 			success = clnt_call(cli, NLM4_GRANTED_MSG,
    650  1.28  christos 			    xdr_nlm4_testargs, &result, xdr_void, &dummy, timeo);
    651   1.1    bouyer 		} else {
    652   1.1    bouyer 			success = clnt_call(cli, NLM4_GRANTED,
    653  1.28  christos 			    xdr_nlm4_testargs, &result, xdr_nlm4_res,
    654   1.1    bouyer 			    &retval4, timeo);
    655   1.1    bouyer 		}
    656   1.1    bouyer 	} else {
    657  1.28  christos 		static nlm_testargs result;
    658   1.1    bouyer 
    659  1.28  christos 		result.cookie = fl->client_cookie;
    660  1.28  christos 		result.exclusive = fl->client.exclusive;
    661  1.28  christos 		result.alock.caller_name = fl->client_name;
    662  1.28  christos 		result.alock.fh.n_len = fl->filehandle.fhsize;
    663  1.28  christos 		result.alock.fh.n_bytes = fl->filehandle.fhdata;
    664  1.28  christos 		result.alock.oh = fl->client.oh;
    665  1.28  christos 		result.alock.svid = fl->client.svid;
    666  1.28  christos 		result.alock.l_offset =
    667  1.28  christos 		    (unsigned int)fl->client.l_offset;
    668  1.28  christos 		result.alock.l_len =
    669  1.28  christos 		    (unsigned int)fl->client.l_len;
    670   1.1    bouyer 		syslog(LOG_DEBUG, "sending v1 reply%s",
    671   1.1    bouyer 		    (fl->flags & LOCK_ASYNC) ? " (async)":"");
    672   1.1    bouyer 		if (fl->flags & LOCK_ASYNC) {
    673   1.1    bouyer 			success = clnt_call(cli, NLM_GRANTED_MSG,
    674  1.28  christos 			    xdr_nlm_testargs, &result, xdr_void, &dummy, timeo);
    675   1.1    bouyer 		} else {
    676   1.1    bouyer 			success = clnt_call(cli, NLM_GRANTED,
    677  1.28  christos 			    xdr_nlm_testargs, &result, xdr_nlm_res,
    678   1.1    bouyer 			    &retval, timeo);
    679   1.1    bouyer 		}
    680   1.1    bouyer 	}
    681   1.1    bouyer 	if (debug_level > 2)
    682   1.1    bouyer 		syslog(LOG_DEBUG, "clnt_call returns %d(%s) for granted",
    683   1.1    bouyer 		    success, clnt_sperrno(success));
    684   1.1    bouyer 
    685   1.1    bouyer }
    686   1.1    bouyer 
    687   1.1    bouyer enum nlm_stats
    688  1.28  christos do_unlock(struct file_lock *rfl)
    689   1.1    bouyer {
    690   1.1    bouyer 	struct file_lock *fl;
    691   1.1    bouyer 	int error;
    692   1.1    bouyer 	int lockst;
    693   1.1    bouyer 
    694  1.10       wiz 	/* unlock the file: closing is enough ! */
    695  1.28  christos 	if (close(rfl->fd) == -1) {
    696   1.1    bouyer 		if (errno == ESTALE)
    697   1.1    bouyer 			error = nlm4_stale_fh;
    698   1.1    bouyer 		else
    699   1.1    bouyer 			error = nlm4_failed;
    700  1.21     lukem 		if ((rfl->flags & LOCK_V4) == 0)
    701   1.1    bouyer 			error = nlm_denied;
    702  1.28  christos 		syslog(LOG_NOTICE, "close failed (from %s) (%m)",
    703  1.28  christos 		    rfl->client_name);
    704   1.1    bouyer 	} else {
    705  1.21     lukem 		error = (rfl->flags & LOCK_V4) ?
    706  1.28  christos 		    (enum nlm_stats)nlm4_granted : nlm_granted;
    707   1.1    bouyer 	}
    708   1.1    bouyer 	LIST_REMOVE(rfl, lcklst);
    709   1.1    bouyer 
    710   1.1    bouyer 	/* process the next LKST_WAITING lock request for this fh */
    711  1.14      yamt 	LIST_FOREACH(fl, &lcklst_head, lcklst) {
    712   1.1    bouyer 		if (fl->status != LKST_WAITING ||
    713  1.25      yamt 		    fhcmp(&rfl->filehandle, &fl->filehandle) != 0)
    714   1.1    bouyer 			continue;
    715   1.1    bouyer 
    716   1.1    bouyer 		lockst = do_lock(fl, 1); /* If it's LKST_WAITING we can block */
    717   1.1    bouyer 		switch (lockst) {
    718   1.1    bouyer 		case nlm4_granted:
    719   1.1    bouyer 		/* case nlm_granted: same as nlm4_granted */
    720   1.1    bouyer 			send_granted(fl, (fl->flags & LOCK_V4) ?
    721  1.28  christos 			    (enum nlm_stats)nlm4_granted : nlm_granted);
    722   1.1    bouyer 			break;
    723   1.1    bouyer 		case nlm4_blocked:
    724   1.1    bouyer 		/* case nlm_blocked: same as nlm4_blocked */
    725   1.1    bouyer 			break;
    726   1.1    bouyer 		default:
    727   1.1    bouyer 			lfree(fl);
    728   1.1    bouyer 			break;
    729   1.1    bouyer 		}
    730   1.1    bouyer 		break;
    731   1.1    bouyer 	}
    732   1.8     oster 	lfree(rfl);
    733   1.1    bouyer 	return error;
    734   1.1    bouyer }
    735   1.1    bouyer 
    736   1.1    bouyer void
    737  1.28  christos siglock(void)
    738   1.1    bouyer {
    739   1.1    bouyer 	sigset_t block;
    740   1.1    bouyer 
    741  1.28  christos 	(void)sigemptyset(&block);
    742  1.28  christos 	(void)sigaddset(&block, SIGCHLD);
    743   1.1    bouyer 
    744   1.1    bouyer 	if (sigprocmask(SIG_BLOCK, &block, NULL) < 0) {
    745  1.28  christos 		syslog(LOG_WARNING, "siglock failed (%m)");
    746   1.1    bouyer 	}
    747   1.1    bouyer }
    748   1.1    bouyer 
    749   1.1    bouyer void
    750  1.28  christos sigunlock(void)
    751   1.1    bouyer {
    752   1.1    bouyer 	sigset_t block;
    753   1.1    bouyer 
    754  1.28  christos 	(void)sigemptyset(&block);
    755  1.28  christos 	(void)sigaddset(&block, SIGCHLD);
    756   1.1    bouyer 
    757   1.1    bouyer 	if (sigprocmask(SIG_UNBLOCK, &block, NULL) < 0) {
    758  1.28  christos 		syslog(LOG_WARNING, "sigunlock failed (%m)");
    759   1.1    bouyer 	}
    760   1.1    bouyer }
    761   1.1    bouyer 
    762   1.1    bouyer /* monitor a host through rpc.statd, and keep a ref count */
    763   1.1    bouyer void
    764  1.28  christos do_mon(const char *hostname)
    765   1.1    bouyer {
    766  1.28  christos 	static char localhost[] = "localhost";
    767   1.1    bouyer 	struct host *hp;
    768   1.1    bouyer 	struct mon my_mon;
    769  1.28  christos 	struct sm_stat_res result;
    770   1.1    bouyer 	int retval;
    771   1.1    bouyer 
    772  1.14      yamt 	LIST_FOREACH(hp, &hostlst_head, hostlst) {
    773   1.1    bouyer 		if (strcmp(hostname, hp->name) == 0) {
    774   1.1    bouyer 			/* already monitored, just bump refcnt */
    775   1.1    bouyer 			hp->refcnt++;
    776   1.1    bouyer 			return;
    777   1.1    bouyer 		}
    778   1.1    bouyer 	}
    779   1.1    bouyer 	/* not found, have to create an entry for it */
    780   1.1    bouyer 	hp = malloc(sizeof(struct host));
    781  1.19    bouyer  	if (hp == NULL) {
    782  1.28  christos  		syslog(LOG_WARNING, "can't monitor host %s (%m)",
    783  1.19    bouyer  		    hostname);
    784  1.19    bouyer  		return;
    785  1.19    bouyer 	}
    786  1.28  christos 	(void)strlcpy(hp->name, hostname, sizeof(hp->name));
    787   1.1    bouyer 	hp->refcnt = 1;
    788  1.28  christos 	syslog(LOG_DEBUG, "monitoring host %s", hostname);
    789  1.28  christos 	(void)memset(&my_mon, 0, sizeof(my_mon));
    790   1.1    bouyer 	my_mon.mon_id.mon_name = hp->name;
    791  1.28  christos 	my_mon.mon_id.my_id.my_name = localhost;
    792   1.1    bouyer 	my_mon.mon_id.my_id.my_prog = NLM_PROG;
    793   1.1    bouyer 	my_mon.mon_id.my_id.my_vers = NLM_SM;
    794   1.1    bouyer 	my_mon.mon_id.my_id.my_proc = NLM_SM_NOTIFY;
    795  1.32    plunky 	if ((retval = callrpc(localhost, SM_PROG, SM_VERS, SM_MON,
    796  1.32    plunky 	    (xdrproc_t)xdr_mon, (void *)&my_mon,
    797  1.32    plunky 	    (xdrproc_t)xdr_sm_stat_res, (void *)&result)) != 0) {
    798  1.28  christos 		syslog(LOG_WARNING, "rpc to statd failed (%s)",
    799   1.1    bouyer 		    clnt_sperrno((enum clnt_stat)retval));
    800   1.1    bouyer 		free(hp);
    801   1.1    bouyer 		return;
    802   1.1    bouyer 	}
    803  1.28  christos 	if (result.res_stat == stat_fail) {
    804   1.1    bouyer 		syslog(LOG_WARNING, "statd failed");
    805   1.1    bouyer 		free(hp);
    806   1.1    bouyer 		return;
    807   1.1    bouyer 	}
    808   1.1    bouyer 	LIST_INSERT_HEAD(&hostlst_head, hp, hostlst);
    809   1.1    bouyer }
    810   1.1    bouyer 
    811   1.1    bouyer void
    812  1.28  christos notify(const char *hostname, int state)
    813   1.1    bouyer {
    814   1.1    bouyer 	struct file_lock *fl, *next_fl;
    815   1.1    bouyer 	int err;
    816   1.1    bouyer 	syslog(LOG_DEBUG, "notify from %s, new state %d", hostname, state);
    817   1.1    bouyer 	/* search all lock for this host; if status changed, release the lock */
    818   1.1    bouyer 	siglock();
    819   1.1    bouyer 	for (fl = LIST_FIRST(&lcklst_head); fl != NULL; fl = next_fl) {
    820   1.1    bouyer 		next_fl = LIST_NEXT(fl, lcklst);
    821   1.1    bouyer 		if (strcmp(hostname, fl->client_name) == 0 &&
    822   1.1    bouyer 		    fl->nsm_status != state) {
    823   1.1    bouyer 			syslog(LOG_DEBUG, "state %d, nsm_state %d, unlocking",
    824   1.1    bouyer 			    fl->status, fl->nsm_status);
    825   1.1    bouyer 			switch(fl->status) {
    826   1.1    bouyer 			case LKST_LOCKED:
    827   1.1    bouyer 				err = do_unlock(fl);
    828   1.1    bouyer 				if (err != nlm_granted)
    829   1.1    bouyer 					syslog(LOG_DEBUG,
    830   1.1    bouyer 					    "notify: unlock failed for %s (%d)",
    831   1.1    bouyer 			    		    hostname, err);
    832   1.1    bouyer 				break;
    833   1.1    bouyer 			case LKST_WAITING:
    834   1.1    bouyer 				LIST_REMOVE(fl, lcklst);
    835   1.1    bouyer 				lfree(fl);
    836   1.1    bouyer 				break;
    837   1.1    bouyer 			case LKST_PROCESSING:
    838   1.1    bouyer 				fl->status = LKST_DYING;
    839   1.1    bouyer 				break;
    840   1.1    bouyer 			case LKST_DYING:
    841   1.1    bouyer 				break;
    842   1.1    bouyer 			default:
    843  1.33       wiz 				syslog(LOG_NOTICE, "unknown status %d for %s",
    844   1.1    bouyer 				    fl->status, fl->client_name);
    845   1.1    bouyer 			}
    846   1.1    bouyer 		}
    847   1.1    bouyer 	}
    848   1.1    bouyer 	sigunlock();
    849   1.1    bouyer }
    850