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