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