1 /* $NetBSD: lockd_lock.c,v 1.30 2009/10/19 18:41:17 bouyer Exp $ */
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
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
38 #include <sys/socket.h>
39 #include <sys/param.h>
40 #include <sys/mount.h>
42 #include <rpcsvc/sm_inter.h>
43 #include <rpcsvc/nlm_prot.h>
44 #include "lockd_lock.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 */
58 fhcmp(const nfs_fhandle_t
*fh1
, const nfs_fhandle_t
*fh2
)
60 return memcmp(fh1
->fhdata
, fh2
->fhdata
, MIN(fh1
->fhsize
, fh2
->fhsize
));
64 fhconv(nfs_fhandle_t
*fh
, const netobj
*rfh
)
69 if (sz
> FHANDLE_SIZE_MAX
) {
71 "received fhandle size %zd, max supported size %d",
72 sz
, FHANDLE_SIZE_MAX
);
76 fh
->fhdata
= malloc(sz
);
77 if (fh
->fhdata
== NULL
) {
81 (void)memcpy(fh
->fhdata
, rfh
->n_bytes
, sz
);
86 fhfree(nfs_fhandle_t
*fh
)
92 /* struct describing a 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 */
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);
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 */
127 LIST_ENTRY(host
) hostlst
;
128 char name
[SM_MAXSTRLEN
+1];
132 void do_mon(const char *);
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
)
153 if ((flags
& LL_NAME
) != 0 &&
154 strcmp(newfl
->client_name
, fl
->client_name
) != 0)
156 if ((flags
& LL_FH
) != 0 &&
157 fhcmp(&newfl
->filehandle
, &fl
->filehandle
) != 0)
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
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 */
186 /* search through the list for lock holder */
187 LIST_FOREACH(fl
, &lcklst_head
, lcklst
) {
188 if (fl
->status
!= LKST_LOCKED
)
190 if (fhcmp(&fl
->filehandle
, &filehandle
) != 0)
193 syslog(LOG_DEBUG
, "test for %s: found lock held by %s",
194 lock
->caller_name
, fl
->client_name
);
197 return (&fl
->client
);
202 syslog(LOG_DEBUG
, "test for %s: no lock found", lock
->caller_name
);
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.
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 */
227 syslog(LOG_NOTICE
, "malloc failed (%m)");
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)");
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)");
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)");
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)");
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
;
277 newfl
->flags
= flags
;
279 /* look for a lock rq from this host for this fh */
280 fl
= lock_lookup(newfl
, LL_FH
|LL_NAME
|LL_SVID
);
282 /* already locked by this host ??? */
284 syslog(LOG_NOTICE
, "duplicate lock from %s.%"
286 newfl
->client_name
, newfl
->client
.svid
);
290 return (flags
& LOCK_V4
) ?
291 (enum nlm_stats
)nlm4_granted
: nlm_granted
;
293 case LKST_PROCESSING
:
294 return (flags
& LOCK_V4
) ?
295 (enum nlm_stats
)nlm4_blocked
: nlm_blocked
;
297 return (flags
& LOCK_V4
) ?
298 (enum nlm_stats
)nlm4_denied
: nlm_denied
;
300 syslog(LOG_NOTICE
, "bad status %d",
302 return (flags
& LOCK_V4
) ?
303 (enum nlm_stats
)nlm4_failed
: nlm_denied
;
307 fl
= lock_lookup(newfl
, LL_FH
);
310 * We already have a lock for this file.
311 * Put this one in waiting state if allowed to block
314 syslog(LOG_DEBUG
, "lock from %s.%" PRIu32
": "
315 "already locked, waiting",
316 lckarg
->alock
.caller_name
,
318 newfl
->status
= LKST_WAITING
;
319 LIST_INSERT_HEAD(&lcklst_head
, newfl
, lcklst
);
320 do_mon(lckarg
->alock
.caller_name
);
322 return (flags
& LOCK_V4
) ?
323 (enum nlm_stats
)nlm4_blocked
: nlm_blocked
;
326 syslog(LOG_DEBUG
, "lock from %s.%" PRIu32
": "
327 "already locked, failed",
328 lckarg
->alock
.caller_name
,
331 return (flags
& LOCK_V4
) ?
332 (enum nlm_stats
)nlm4_denied
: nlm_denied
;
337 /* no entry for this file yet; add to list */
338 LIST_INSERT_HEAD(&lcklst_head
, newfl
, lcklst
);
340 retval
= do_lock(newfl
, lckarg
->block
);
343 /* case nlm_granted: is the same as nlm4_granted */
345 /* case nlm_blocked: is the same as nlm4_blocked */
346 do_mon(lckarg
->alock
.caller_name
);
356 /* unlock a filehandle */
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
;
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
)
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
) {
385 /* remove from the list */
386 LIST_REMOVE(fl
, lcklst
);
389 case LKST_PROCESSING
:
391 * being handled by a child; will clean up
392 * when the child exits
394 fl
->status
= LKST_DYING
;
400 syslog(LOG_NOTICE
, "unknow status %d for %s",
401 fl
->status
, fl
->client_name
);
408 /* didn't find a matching entry; log anyway */
409 syslog(LOG_NOTICE
, "no matching entry for %s",
412 return (flags
& LOCK_V4
) ? (enum nlm_stats
)nlm4_granted
: nlm_granted
;
415 static struct file_lock
*
418 return calloc(1, sizeof(struct file_lock
));
422 lfree(struct file_lock
*fl
)
425 free(fl
->client
.oh
.n_bytes
);
426 free(fl
->client_cookie
.n_bytes
);
427 fhfree(&fl
->filehandle
);
433 sigchild_handler(int sig
)
437 struct file_lock
*fl
;
440 pid
= wait4(-1, &sstatus
, WNOHANG
, NULL
);
443 syslog(LOG_NOTICE
, "wait failed (%m)");
445 syslog(LOG_DEBUG
, "wait failed (%m)");
449 /* no more child to handle yet */
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
)
461 syslog(LOG_NOTICE
, "unknow child %d", pid
);
464 * protect from pid reusing.
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
479 /* check lock status */
480 syslog(LOG_DEBUG
, "processing child %d, status %d",
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
);
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.
506 do_lock(struct file_lock
*fl
, int block
)
511 fl
->fd
= fhopen(fl
->filehandle
.fhdata
, fl
->filehandle
.fhsize
, O_RDWR
);
515 error
= nlm4_stale_fh
;
523 if ((fl
->flags
& LOCK_V4
) == 0)
525 syslog(LOG_NOTICE
, "fhopen failed (from %s) (%m)",
527 LIST_REMOVE(fl
, lcklst
);
530 if (fstat(fl
->fd
, &st
) < 0) {
531 syslog(LOG_NOTICE
, "fstat failed (from %s) (%m)",
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
);
541 if (fl
->client
.exclusive
== 0)
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
);
552 return (fl
->flags
& LOCK_V4
) ?
553 (enum nlm_stats
)nlm4_denied_nolock
: nlm_denied_nolocks
;
556 * Attempt a blocking lock. Will have to call
559 setproctitle("%s.%" PRIu32
,
560 fl
->client_name
, fl
->client
.svid
);
562 if(flock(fl
->fd
, lflags
) != 0) {
563 syslog(LOG_NOTICE
, "flock failed (%m)");
570 syslog(LOG_DEBUG
, "lock request from %s.%" PRIu32
": "
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
;
585 error
= nlm4_stale_fh
;
593 if ((fl
->flags
& LOCK_V4
) == 0)
596 syslog(LOG_NOTICE
, "flock for %s failed (%m)",
598 else syslog(LOG_DEBUG
, "flock for %s failed (%m)",
600 LIST_REMOVE(fl
, lcklst
);
604 fl
->status
= LKST_LOCKED
;
605 return (fl
->flags
& LOCK_V4
) ? (enum nlm_stats
)nlm4_granted
: nlm_granted
;
610 send_granted(struct file_lock
*fl
, int opcode
)
614 struct timeval timeo
;
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
));
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.
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
);
651 success
= clnt_call(cli
, NLM4_GRANTED
,
652 xdr_nlm4_testargs
, &result
, xdr_nlm4_res
,
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
;
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
);
675 success
= clnt_call(cli
, NLM_GRANTED
,
676 xdr_nlm_testargs
, &result
, xdr_nlm_res
,
681 syslog(LOG_DEBUG
, "clnt_call returns %d(%s) for granted",
682 success
, clnt_sperrno(success
));
687 do_unlock(struct file_lock
*rfl
)
689 struct file_lock
*fl
;
693 /* unlock the file: closing is enough ! */
694 if (close(rfl
->fd
) == -1) {
696 error
= nlm4_stale_fh
;
699 if ((rfl
->flags
& LOCK_V4
) == 0)
701 syslog(LOG_NOTICE
, "close failed (from %s) (%m)",
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)
715 lockst
= do_lock(fl
, 1); /* If it's LKST_WAITING we can block */
718 /* case nlm_granted: same as nlm4_granted */
719 send_granted(fl
, (fl
->flags
& LOCK_V4
) ?
720 (enum nlm_stats
)nlm4_granted
: nlm_granted
);
723 /* case nlm_blocked: same as nlm4_blocked */
740 (void)sigemptyset(&block
);
741 (void)sigaddset(&block
, SIGCHLD
);
743 if (sigprocmask(SIG_BLOCK
, &block
, NULL
) < 0) {
744 syslog(LOG_WARNING
, "siglock failed (%m)");
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 */
763 do_mon(const char *hostname
)
765 static char localhost
[] = "localhost";
768 struct sm_stat_res result
;
771 LIST_FOREACH(hp
, &hostlst_head
, hostlst
) {
772 if (strcmp(hostname
, hp
->name
) == 0) {
773 /* already monitored, just bump refcnt */
778 /* not found, have to create an entry for it */
779 hp
= malloc(sizeof(struct host
));
781 syslog(LOG_WARNING
, "can't monitor host %s (%m)",
785 (void)strlcpy(hp
->name
, hostname
, sizeof(hp
->name
));
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
));
801 if (result
.res_stat
== stat_fail
) {
802 syslog(LOG_WARNING
, "statd failed");
806 LIST_INSERT_HEAD(&hostlst_head
, hp
, hostlst
);
810 notify(const char *hostname
, int state
)
812 struct file_lock
*fl
, *next_fl
;
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 */
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
);
826 if (err
!= nlm_granted
)
828 "notify: unlock failed for %s (%d)",
832 LIST_REMOVE(fl
, lcklst
);
835 case LKST_PROCESSING
:
836 fl
->status
= LKST_DYING
;
841 syslog(LOG_NOTICE
, "unknow status %d for %s",
842 fl
->status
, fl
->client_name
);