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