lockd_lock.c revision 1.27 1 /* $NetBSD: lockd_lock.c,v 1.27 2007/10/27 18:41:54 christos 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 return calloc(1, sizeof(struct file_lock));
436 }
437
438 void
439 lfree(fl)
440 struct file_lock *fl;
441 {
442 free(fl->addr);
443 free(fl->client.oh.n_bytes);
444 free(fl->client_cookie.n_bytes);
445 fhfree(&fl->filehandle);
446 free(fl);
447 }
448
449 void
450 sigchild_handler(sig)
451 int sig;
452 {
453 int status;
454 pid_t pid;
455 struct file_lock *fl;
456
457 while (1) {
458 pid = wait4(-1, &status, WNOHANG, NULL);
459 if (pid == -1) {
460 if (errno != ECHILD)
461 syslog(LOG_NOTICE, "wait failed: %s",
462 strerror(errno));
463 else
464 syslog(LOG_DEBUG, "wait failed: %s",
465 strerror(errno));
466 return;
467 }
468 if (pid == 0) {
469 /* no more child to handle yet */
470 return;
471 }
472 /*
473 * if we're here we have a child that exited
474 * Find the associated file_lock.
475 */
476 LIST_FOREACH(fl, &lcklst_head, lcklst) {
477 if (pid == fl->locker)
478 break;
479 }
480 if (fl == NULL) {
481 syslog(LOG_NOTICE, "unknow child %d", pid);
482 } else {
483 /*
484 * protect from pid reusing.
485 */
486 fl->locker = 0;
487 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
488 syslog(LOG_NOTICE, "child %d failed", pid);
489 /*
490 * can't do much here; we can't reply
491 * anything but OK for blocked locks
492 * Eventually the client will time out
493 * and retry.
494 */
495 do_unlock(fl);
496 return;
497 }
498
499 /* check lock status */
500 syslog(LOG_DEBUG, "processing child %d, status %d",
501 pid, fl->status);
502 switch(fl->status) {
503 case LKST_PROCESSING:
504 fl->status = LKST_LOCKED;
505 send_granted(fl, (fl->flags & LOCK_V4) ?
506 nlm4_granted : nlm_granted);
507 break;
508 case LKST_DYING:
509 do_unlock(fl);
510 break;
511 default:
512 syslog(LOG_NOTICE, "bad lock status (%d) for"
513 " child %d", fl->status, pid);
514 }
515 }
516 }
517 }
518
519 /*
520 *
521 * try to acquire the lock described by fl. Eventually fork a child to do a
522 * blocking lock if allowed and required.
523 */
524
525 enum nlm_stats
526 do_lock(fl, block)
527 struct file_lock *fl;
528 int block;
529 {
530 int lflags, error;
531 struct stat st;
532
533 fl->fd = fhopen(fl->filehandle.fhdata, fl->filehandle.fhsize, O_RDWR);
534 if (fl->fd < 0) {
535 switch (errno) {
536 case ESTALE:
537 error = nlm4_stale_fh;
538 break;
539 case EROFS:
540 error = nlm4_rofs;
541 break;
542 default:
543 error = nlm4_failed;
544 }
545 if ((fl->flags & LOCK_V4) == 0)
546 error = nlm_denied;
547 syslog(LOG_NOTICE, "fhopen failed (from %s): %s",
548 fl->client_name, strerror(errno));
549 LIST_REMOVE(fl, lcklst);
550 return error;
551 }
552 if (fstat(fl->fd, &st) < 0) {
553 syslog(LOG_NOTICE, "fstat failed (from %s): %s",
554 fl->client_name, strerror(errno));
555 }
556 syslog(LOG_DEBUG, "lock from %s.%" PRIu32 " for file%s%s: "
557 "dev %u ino %llu (uid %d), flags %d",
558 fl->client_name, fl->client.svid,
559 fl->client.exclusive ? " (exclusive)":"", block ? " (block)":"",
560 st.st_dev, (unsigned long long)st.st_ino, st.st_uid, fl->flags);
561 lflags = LOCK_NB;
562 if (fl->client.exclusive == 0)
563 lflags |= LOCK_SH;
564 else
565 lflags |= LOCK_EX;
566 error = flock(fl->fd, lflags);
567 if (error != 0 && errno == EAGAIN && block) {
568 switch (fl->locker = fork()) {
569 case -1: /* fork failed */
570 syslog(LOG_NOTICE, "fork failed: %s", strerror(errno));
571 LIST_REMOVE(fl, lcklst);
572 close(fl->fd);
573 return (fl->flags & LOCK_V4) ?
574 nlm4_denied_nolock : nlm_denied_nolocks;
575 case 0:
576 /*
577 * Attempt a blocking lock. Will have to call
578 * NLM_GRANTED later.
579 */
580 setproctitle("%s.%" PRIu32,
581 fl->client_name, fl->client.svid);
582 lflags &= ~LOCK_NB;
583 if(flock(fl->fd, lflags) != 0) {
584 syslog(LOG_NOTICE, "flock failed: %s",
585 strerror(errno));
586 _exit(1);
587 }
588 /* lock granted */
589 _exit(0);
590 default:
591 syslog(LOG_DEBUG, "lock request from %s.%" PRIu32 ": "
592 "forked %d",
593 fl->client_name, fl->client.svid, fl->locker);
594 fl->status = LKST_PROCESSING;
595 return (fl->flags & LOCK_V4) ?
596 nlm4_blocked : nlm_blocked;
597 }
598 }
599 /* non block case */
600 if (error != 0) {
601 switch (errno) {
602 case EAGAIN:
603 error = nlm4_denied;
604 break;
605 case ESTALE:
606 error = nlm4_stale_fh;
607 break;
608 case EROFS:
609 error = nlm4_rofs;
610 break;
611 default:
612 error = nlm4_failed;
613 }
614 if ((fl->flags & LOCK_V4) == 0)
615 error = nlm_denied;
616 if (errno != EAGAIN)
617 syslog(LOG_NOTICE, "flock for %s failed: %s",
618 fl->client_name, strerror(errno));
619 else syslog(LOG_DEBUG, "flock for %s failed: %s",
620 fl->client_name, strerror(errno));
621 LIST_REMOVE(fl, lcklst);
622 close(fl->fd);
623 return error;
624 }
625 fl->status = LKST_LOCKED;
626 return (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted;
627 }
628
629 void
630 send_granted(fl, opcode)
631 struct file_lock *fl;
632 int opcode;
633 {
634 CLIENT *cli;
635 static char dummy;
636 struct timeval timeo;
637 int success;
638 static struct nlm_res retval;
639 static struct nlm4_res retval4;
640
641 cli = get_client(fl->addr,
642 (fl->flags & LOCK_V4) ? NLM_VERS4 : NLM_VERS);
643 if (cli == NULL) {
644 syslog(LOG_NOTICE, "failed to get CLIENT for %s.%" PRIu32,
645 fl->client_name, fl->client.svid);
646 /*
647 * We fail to notify remote that the lock has been granted.
648 * The client will timeout and retry, the lock will be
649 * granted at this time.
650 */
651 return;
652 }
653 timeo.tv_sec = 0;
654 timeo.tv_usec = (fl->flags & LOCK_ASYNC) ? 0 : 500000; /* 0.5s */
655
656 if (fl->flags & LOCK_V4) {
657 static nlm4_testargs res;
658 res.cookie = fl->client_cookie;
659 res.exclusive = fl->client.exclusive;
660 res.alock.caller_name = fl->client_name;
661 res.alock.fh.n_len = fl->filehandle.fhsize;
662 res.alock.fh.n_bytes = fl->filehandle.fhdata;
663 res.alock.oh = fl->client.oh;
664 res.alock.svid = fl->client.svid;
665 res.alock.l_offset = fl->client.l_offset;
666 res.alock.l_len = fl->client.l_len;
667 syslog(LOG_DEBUG, "sending v4 reply%s",
668 (fl->flags & LOCK_ASYNC) ? " (async)":"");
669 if (fl->flags & LOCK_ASYNC) {
670 success = clnt_call(cli, NLM4_GRANTED_MSG,
671 xdr_nlm4_testargs, &res, xdr_void, &dummy, timeo);
672 } else {
673 success = clnt_call(cli, NLM4_GRANTED,
674 xdr_nlm4_testargs, &res, xdr_nlm4_res,
675 &retval4, timeo);
676 }
677 } else {
678 static nlm_testargs res;
679
680 res.cookie = fl->client_cookie;
681 res.exclusive = fl->client.exclusive;
682 res.alock.caller_name = fl->client_name;
683 res.alock.fh.n_len = fl->filehandle.fhsize;
684 res.alock.fh.n_bytes = fl->filehandle.fhdata;
685 res.alock.oh = fl->client.oh;
686 res.alock.svid = fl->client.svid;
687 res.alock.l_offset = fl->client.l_offset;
688 res.alock.l_len = fl->client.l_len;
689 syslog(LOG_DEBUG, "sending v1 reply%s",
690 (fl->flags & LOCK_ASYNC) ? " (async)":"");
691 if (fl->flags & LOCK_ASYNC) {
692 success = clnt_call(cli, NLM_GRANTED_MSG,
693 xdr_nlm_testargs, &res, xdr_void, &dummy, timeo);
694 } else {
695 success = clnt_call(cli, NLM_GRANTED,
696 xdr_nlm_testargs, &res, xdr_nlm_res,
697 &retval, timeo);
698 }
699 }
700 if (debug_level > 2)
701 syslog(LOG_DEBUG, "clnt_call returns %d(%s) for granted",
702 success, clnt_sperrno(success));
703
704 }
705
706 enum nlm_stats
707 do_unlock(rfl)
708 struct file_lock *rfl;
709 {
710 struct file_lock *fl;
711 int error;
712 int lockst;
713
714 /* unlock the file: closing is enough ! */
715 if (close(rfl->fd) < 0) {
716 if (errno == ESTALE)
717 error = nlm4_stale_fh;
718 else
719 error = nlm4_failed;
720 if ((rfl->flags & LOCK_V4) == 0)
721 error = nlm_denied;
722 syslog(LOG_NOTICE,
723 "close failed (from %s): %s",
724 rfl->client_name, strerror(errno));
725 } else {
726 error = (rfl->flags & LOCK_V4) ?
727 nlm4_granted : nlm_granted;
728 }
729 LIST_REMOVE(rfl, lcklst);
730
731 /* process the next LKST_WAITING lock request for this fh */
732 LIST_FOREACH(fl, &lcklst_head, lcklst) {
733 if (fl->status != LKST_WAITING ||
734 fhcmp(&rfl->filehandle, &fl->filehandle) != 0)
735 continue;
736
737 lockst = do_lock(fl, 1); /* If it's LKST_WAITING we can block */
738 switch (lockst) {
739 case nlm4_granted:
740 /* case nlm_granted: same as nlm4_granted */
741 send_granted(fl, (fl->flags & LOCK_V4) ?
742 nlm4_granted : nlm_granted);
743 break;
744 case nlm4_blocked:
745 /* case nlm_blocked: same as nlm4_blocked */
746 break;
747 default:
748 lfree(fl);
749 break;
750 }
751 break;
752 }
753 lfree(rfl);
754 return error;
755 }
756
757 void
758 siglock()
759 {
760 sigset_t block;
761
762 sigemptyset(&block);
763 sigaddset(&block, SIGCHLD);
764
765 if (sigprocmask(SIG_BLOCK, &block, NULL) < 0) {
766 syslog(LOG_WARNING, "siglock failed: %s", strerror(errno));
767 }
768 }
769
770 void
771 sigunlock()
772 {
773 sigset_t block;
774
775 sigemptyset(&block);
776 sigaddset(&block, SIGCHLD);
777
778 if (sigprocmask(SIG_UNBLOCK, &block, NULL) < 0) {
779 syslog(LOG_WARNING, "sigunlock failed: %s", strerror(errno));
780 }
781 }
782
783 /* monitor a host through rpc.statd, and keep a ref count */
784 void
785 do_mon(hostname)
786 char *hostname;
787 {
788 struct host *hp;
789 struct mon my_mon;
790 struct sm_stat_res res;
791 int retval;
792
793 LIST_FOREACH(hp, &hostlst_head, hostlst) {
794 if (strcmp(hostname, hp->name) == 0) {
795 /* already monitored, just bump refcnt */
796 hp->refcnt++;
797 return;
798 }
799 }
800 /* not found, have to create an entry for it */
801 hp = malloc(sizeof(struct host));
802 if (hp == NULL) {
803 syslog(LOG_WARNING, "can't monitor host %s: malloc failed\n",
804 hostname);
805 return;
806 }
807 strlcpy(hp->name, hostname, sizeof(hp->name));
808 hp->refcnt = 1;
809 syslog(LOG_DEBUG, "monitoring host %s",
810 hostname);
811 memset(&my_mon, 0, sizeof(my_mon));
812 my_mon.mon_id.mon_name = hp->name;
813 my_mon.mon_id.my_id.my_name = "localhost";
814 my_mon.mon_id.my_id.my_prog = NLM_PROG;
815 my_mon.mon_id.my_id.my_vers = NLM_SM;
816 my_mon.mon_id.my_id.my_proc = NLM_SM_NOTIFY;
817 if ((retval =
818 callrpc("localhost", SM_PROG, SM_VERS, SM_MON, xdr_mon,
819 (char*)&my_mon, xdr_sm_stat_res, (char*)&res)) != 0) {
820 syslog(LOG_WARNING, "rpc to statd failed: %s",
821 clnt_sperrno((enum clnt_stat)retval));
822 free(hp);
823 return;
824 }
825 if (res.res_stat == stat_fail) {
826 syslog(LOG_WARNING, "statd failed");
827 free(hp);
828 return;
829 }
830 LIST_INSERT_HEAD(&hostlst_head, hp, hostlst);
831 }
832
833 void
834 notify(hostname, state)
835 char *hostname;
836 int state;
837 {
838 struct file_lock *fl, *next_fl;
839 int err;
840 syslog(LOG_DEBUG, "notify from %s, new state %d", hostname, state);
841 /* search all lock for this host; if status changed, release the lock */
842 siglock();
843 for (fl = LIST_FIRST(&lcklst_head); fl != NULL; fl = next_fl) {
844 next_fl = LIST_NEXT(fl, lcklst);
845 if (strcmp(hostname, fl->client_name) == 0 &&
846 fl->nsm_status != state) {
847 syslog(LOG_DEBUG, "state %d, nsm_state %d, unlocking",
848 fl->status, fl->nsm_status);
849 switch(fl->status) {
850 case LKST_LOCKED:
851 err = do_unlock(fl);
852 if (err != nlm_granted)
853 syslog(LOG_DEBUG,
854 "notify: unlock failed for %s (%d)",
855 hostname, err);
856 break;
857 case LKST_WAITING:
858 LIST_REMOVE(fl, lcklst);
859 lfree(fl);
860 break;
861 case LKST_PROCESSING:
862 fl->status = LKST_DYING;
863 break;
864 case LKST_DYING:
865 break;
866 default:
867 syslog(LOG_NOTICE, "unknow status %d for %s",
868 fl->status, fl->client_name);
869 }
870 }
871 }
872 sigunlock();
873 }
874