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