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