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