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