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