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