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