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