xref: /netbsd-src/usr.sbin/rpc.lockd/lockd_lock.c (revision d710132b4b8ce7f7cccaaf660cb16aa16b4077a0)
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