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