No empty .Rs/.Re
[netbsd-mini2440.git] / usr.sbin / rpc.lockd / lockd_lock.c
blobc775b22c83f87449e9c2e5d6482e9ad8884e1232
1 /* $NetBSD: lockd_lock.c,v 1.30 2009/10/19 18:41:17 bouyer Exp $ */
3 /*
4 * Copyright (c) 2000 Manuel Bouyer.
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.
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.
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"
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);
51 #define FHANDLE_SIZE_MAX 1024 /* arbitrary big enough value */
52 typedef struct {
53 size_t fhsize;
54 char *fhdata;
55 } nfs_fhandle_t;
57 static int
58 fhcmp(const nfs_fhandle_t *fh1, const nfs_fhandle_t *fh2)
60 return memcmp(fh1->fhdata, fh2->fhdata, MIN(fh1->fhsize, fh2->fhsize));
63 static int
64 fhconv(nfs_fhandle_t *fh, const netobj *rfh)
66 size_t sz;
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;
76 fh->fhdata = malloc(sz);
77 if (fh->fhdata == NULL) {
78 return -1;
80 fh->fhsize = sz;
81 (void)memcpy(fh->fhdata, rfh->n_bytes, sz);
82 return 0;
85 static void
86 fhfree(nfs_fhandle_t *fh)
89 free(fh->fhdata);
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 */
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 */
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);
121 /* list of hosts we monitor */
122 LIST_HEAD(hostlst_head, host);
123 struct hostlst_head hostlst_head = LIST_HEAD_INITIALIZER(hostlst_head);
125 /* struct describing a lock */
126 struct host {
127 LIST_ENTRY(host) hostlst;
128 char name[SM_MAXSTRLEN+1];
129 int refcnt;
132 void do_mon(const char *);
134 #define LL_FH 0x01
135 #define LL_NAME 0x02
136 #define LL_SVID 0x04
138 static struct file_lock *lock_lookup(struct file_lock *, int);
141 * lock_lookup: lookup a matching lock.
142 * called with siglock held.
144 static struct file_lock *
145 lock_lookup(struct file_lock *newfl, int flags)
147 struct file_lock *fl;
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;
163 return fl;
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.
172 struct nlm4_holder *
173 /*ARGSUSED*/
174 testlock(struct nlm4_lock *lock, int flags)
176 struct file_lock *fl;
177 nfs_fhandle_t filehandle;
179 /* convert lock to a local filehandle */
180 if (fhconv(&filehandle, &lock->fh)) {
181 syslog(LOG_NOTICE, "fhconv failed (%m)");
182 return NULL; /* XXX */
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);
199 /* not found */
200 sigunlock();
201 fhfree(&filehandle);
202 syslog(LOG_DEBUG, "test for %s: no lock found", lock->caller_name);
203 return NULL;
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.
213 enum nlm_stats
214 getlock(nlm4_lockargs * lckarg, struct svc_req *rqstp, int flags)
216 struct file_lock *fl, *newfl;
217 enum nlm_stats retval;
218 struct sockaddr *addr;
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;
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;
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;
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;
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;
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;
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;
305 /* NOTREACHED */
307 fl = lock_lookup(newfl, LL_FH);
308 if (fl) {
310 * We already have a lock for this file.
311 * Put this one in waiting state if allowed to block
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;
334 /* NOTREACHED */
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;
352 sigunlock();
353 return retval;
356 /* unlock a filehandle */
357 enum nlm_stats
358 unlock(nlm4_lock *lck, int flags)
360 struct file_lock *fl;
361 nfs_fhandle_t filehandle;
362 int err = (flags & LOCK_V4) ? (enum nlm_stats)nlm4_granted : nlm_granted;
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;
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:
391 * being handled by a child; will clean up
392 * when the child exits
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);
403 sigunlock();
404 fhfree(&filehandle);
405 return err;
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;
415 static struct file_lock *
416 lalloc(void)
418 return calloc(1, sizeof(struct file_lock));
421 void
422 lfree(struct file_lock *fl)
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);
431 void
432 /*ARGSUSED*/
433 sigchild_handler(int sig)
435 int sstatus;
436 pid_t pid;
437 struct file_lock *fl;
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;
448 if (pid == 0) {
449 /* no more child to handle yet */
450 return;
453 * if we're here we have a child that exited
454 * Find the associated file_lock.
456 LIST_FOREACH(fl, &lcklst_head, lcklst) {
457 if (pid == fl->locker)
458 break;
460 if (fl == NULL) {
461 syslog(LOG_NOTICE, "unknow child %d", pid);
462 } else {
464 * protect from pid reusing.
466 fl->locker = 0;
467 if (!WIFEXITED(sstatus) || WEXITSTATUS(sstatus) != 0) {
468 syslog(LOG_NOTICE, "child %d failed", pid);
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.
475 (void)do_unlock(fl);
476 return;
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);
501 * try to acquire the lock described by fl. Eventually fork a child to do a
502 * blocking lock if allowed and required.
505 enum nlm_stats
506 do_lock(struct file_lock *fl, int block)
508 int lflags, error;
509 struct stat st;
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;
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;
530 if (fstat(fl->fd, &st) < 0) {
531 syslog(LOG_NOTICE, "fstat failed (from %s) (%m)",
532 fl->client_name);
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:
556 * Attempt a blocking lock. Will have to call
557 * NLM_GRANTED later.
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);
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;
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;
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;
604 fl->status = LKST_LOCKED;
605 return (fl->flags & LOCK_V4) ? (enum nlm_stats)nlm4_granted : nlm_granted;
608 void
609 /*ARGSUSED*/
610 send_granted(struct file_lock *fl, int opcode)
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;
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);
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.
629 return;
631 timeo.tv_sec = 0;
632 timeo.tv_usec = (fl->flags & LOCK_ASYNC) ? 0 : 500000; /* 0.5s */
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);
655 } else {
656 static nlm_testargs result;
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);
680 if (debug_level > 2)
681 syslog(LOG_DEBUG, "clnt_call returns %d(%s) for granted",
682 success, clnt_sperrno(success));
686 enum nlm_stats
687 do_unlock(struct file_lock *rfl)
689 struct file_lock *fl;
690 int error;
691 int lockst;
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;
707 LIST_REMOVE(rfl, lcklst);
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;
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;
729 break;
731 lfree(rfl);
732 return error;
735 void
736 siglock(void)
738 sigset_t block;
740 (void)sigemptyset(&block);
741 (void)sigaddset(&block, SIGCHLD);
743 if (sigprocmask(SIG_BLOCK, &block, NULL) < 0) {
744 syslog(LOG_WARNING, "siglock failed (%m)");
748 void
749 sigunlock(void)
751 sigset_t block;
753 (void)sigemptyset(&block);
754 (void)sigaddset(&block, SIGCHLD);
756 if (sigprocmask(SIG_UNBLOCK, &block, NULL) < 0) {
757 syslog(LOG_WARNING, "sigunlock failed (%m)");
761 /* monitor a host through rpc.statd, and keep a ref count */
762 void
763 do_mon(const char *hostname)
765 static char localhost[] = "localhost";
766 struct host *hp;
767 struct mon my_mon;
768 struct sm_stat_res result;
769 int retval;
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;
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;
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;
801 if (result.res_stat == stat_fail) {
802 syslog(LOG_WARNING, "statd failed");
803 free(hp);
804 return;
806 LIST_INSERT_HEAD(&hostlst_head, hp, hostlst);
809 void
810 notify(const char *hostname, int state)
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);
846 sigunlock();