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