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