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