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