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