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