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