1 /* $NetBSD: lockd_lock.c,v 1.5 2000/11/21 03:47:41 enami Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-4-Clause 5 * 6 * Copyright (c) 2001 Andrew P. Lentvorski, Jr. 7 * Copyright (c) 2000 Manuel Bouyer. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 */ 38 39 #include <sys/cdefs.h> 40 #define LOCKD_DEBUG 41 42 #include <stdio.h> 43 #ifdef LOCKD_DEBUG 44 #include <stdarg.h> 45 #endif 46 #include <stdlib.h> 47 #include <unistd.h> 48 #include <fcntl.h> 49 #include <syslog.h> 50 #include <errno.h> 51 #include <string.h> 52 #include <signal.h> 53 #include <rpc/rpc.h> 54 #include <sys/types.h> 55 #include <sys/stat.h> 56 #include <sys/socket.h> 57 #include <sys/param.h> 58 #include <sys/mount.h> 59 #include <sys/wait.h> 60 #include <rpcsvc/sm_inter.h> 61 #include <rpcsvc/nlm_prot.h> 62 #include "lockd_lock.h" 63 #include "lockd.h" 64 65 #define MAXOBJECTSIZE 64 66 #define MAXBUFFERSIZE 1024 67 68 /* 69 * A set of utilities for managing file locking 70 * 71 * XXX: All locks are in a linked list, a better structure should be used 72 * to improve search/access efficiency. 73 */ 74 75 /* struct describing a lock */ 76 struct file_lock { 77 LIST_ENTRY(file_lock) nfslocklist; 78 fhandle_t filehandle; /* NFS filehandle */ 79 struct sockaddr *addr; 80 struct nlm4_holder client; /* lock holder */ 81 /* XXX: client_cookie used *only* in send_granted */ 82 netobj client_cookie; /* cookie sent by the client */ 83 int nsm_status; /* status from the remote lock manager */ 84 int status; /* lock status, see below */ 85 int flags; /* lock flags, see lockd_lock.h */ 86 int blocking; /* blocking lock or not */ 87 char client_name[SM_MAXSTRLEN]; /* client_name is really variable 88 length and must be last! */ 89 }; 90 91 LIST_HEAD(nfslocklist_head, file_lock); 92 struct nfslocklist_head nfslocklist_head = LIST_HEAD_INITIALIZER(nfslocklist_head); 93 94 LIST_HEAD(blockedlocklist_head, file_lock); 95 struct blockedlocklist_head blockedlocklist_head = LIST_HEAD_INITIALIZER(blockedlocklist_head); 96 97 /* lock status */ 98 #define LKST_LOCKED 1 /* lock is locked */ 99 /* XXX: Is this flag file specific or lock specific? */ 100 #define LKST_WAITING 2 /* file is already locked by another host */ 101 #define LKST_PROCESSING 3 /* child is trying to acquire the lock */ 102 #define LKST_DYING 4 /* must dies when we get news from the child */ 103 104 /* struct describing a monitored host */ 105 struct host { 106 LIST_ENTRY(host) hostlst; 107 int refcnt; 108 char name[SM_MAXSTRLEN]; /* name is really variable length and 109 must be last! */ 110 }; 111 /* list of hosts we monitor */ 112 LIST_HEAD(hostlst_head, host); 113 struct hostlst_head hostlst_head = LIST_HEAD_INITIALIZER(hostlst_head); 114 115 /* 116 * File monitoring handlers 117 * XXX: These might be able to be removed when kevent support 118 * is placed into the hardware lock/unlock routines. (ie. 119 * let the kernel do all the file monitoring) 120 */ 121 122 /* Struct describing a monitored file */ 123 struct monfile { 124 LIST_ENTRY(monfile) monfilelist; 125 fhandle_t filehandle; /* Local access filehandle */ 126 int fd; /* file descriptor: remains open until unlock! */ 127 int refcount; 128 int exclusive; 129 }; 130 131 /* List of files we monitor */ 132 LIST_HEAD(monfilelist_head, monfile); 133 struct monfilelist_head monfilelist_head = LIST_HEAD_INITIALIZER(monfilelist_head); 134 135 static int debugdelay = 0; 136 137 enum nfslock_status { NFS_GRANTED = 0, NFS_GRANTED_DUPLICATE, 138 NFS_DENIED, NFS_DENIED_NOLOCK, 139 NFS_RESERR }; 140 141 enum hwlock_status { HW_GRANTED = 0, HW_GRANTED_DUPLICATE, 142 HW_DENIED, HW_DENIED_NOLOCK, 143 HW_STALEFH, HW_READONLY, HW_RESERR }; 144 145 enum partialfilelock_status { PFL_GRANTED=0, PFL_GRANTED_DUPLICATE, PFL_DENIED, 146 PFL_NFSDENIED, PFL_NFSBLOCKED, PFL_NFSDENIED_NOLOCK, PFL_NFSRESERR, 147 PFL_HWDENIED, PFL_HWBLOCKED, PFL_HWDENIED_NOLOCK, PFL_HWRESERR}; 148 149 enum LFLAGS {LEDGE_LEFT, LEDGE_LBOUNDARY, LEDGE_INSIDE, LEDGE_RBOUNDARY, LEDGE_RIGHT}; 150 enum RFLAGS {REDGE_LEFT, REDGE_LBOUNDARY, REDGE_INSIDE, REDGE_RBOUNDARY, REDGE_RIGHT}; 151 /* XXX: WARNING! I HAVE OVERLOADED THIS STATUS ENUM! SPLIT IT APART INTO TWO */ 152 enum split_status {SPL_DISJOINT=0, SPL_LOCK1=1, SPL_LOCK2=2, SPL_CONTAINED=4, SPL_RESERR=8}; 153 154 enum partialfilelock_status lock_partialfilelock(struct file_lock *fl); 155 156 void send_granted(struct file_lock *fl, int opcode); 157 void siglock(void); 158 void sigunlock(void); 159 void monitor_lock_host(const char *hostname); 160 void unmonitor_lock_host(char *hostname); 161 162 void copy_nlm4_lock_to_nlm4_holder(const struct nlm4_lock *src, 163 const bool_t exclusive, struct nlm4_holder *dest); 164 struct file_lock * allocate_file_lock(const netobj *lockowner, 165 const netobj *matchcookie, 166 const struct sockaddr *addr, 167 const char *caller_name); 168 void deallocate_file_lock(struct file_lock *fl); 169 void fill_file_lock(struct file_lock *fl, const fhandle_t *fh, 170 const bool_t exclusive, const int32_t svid, 171 const u_int64_t offset, const u_int64_t len, 172 const int state, const int status, const int flags, const int blocking); 173 int regions_overlap(const u_int64_t start1, const u_int64_t len1, 174 const u_int64_t start2, const u_int64_t len2); 175 enum split_status region_compare(const u_int64_t starte, const u_int64_t lene, 176 const u_int64_t startu, const u_int64_t lenu, 177 u_int64_t *start1, u_int64_t *len1, u_int64_t *start2, u_int64_t *len2); 178 int same_netobj(const netobj *n0, const netobj *n1); 179 int same_filelock_identity(const struct file_lock *fl0, 180 const struct file_lock *fl2); 181 182 static void debuglog(char const *fmt, ...); 183 void dump_static_object(const unsigned char* object, const int sizeof_object, 184 unsigned char* hbuff, const int sizeof_hbuff, 185 unsigned char* cbuff, const int sizeof_cbuff); 186 void dump_netobj(const struct netobj *nobj); 187 void dump_filelock(const struct file_lock *fl); 188 struct file_lock * get_lock_matching_unlock(const struct file_lock *fl); 189 enum nfslock_status test_nfslock(const struct file_lock *fl, 190 struct file_lock **conflicting_fl); 191 enum nfslock_status lock_nfslock(struct file_lock *fl); 192 enum nfslock_status delete_nfslock(struct file_lock *fl); 193 enum nfslock_status unlock_nfslock(const struct file_lock *fl, 194 struct file_lock **released_lock, struct file_lock **left_lock, 195 struct file_lock **right_lock); 196 enum hwlock_status lock_hwlock(struct file_lock *fl); 197 enum split_status split_nfslock(const struct file_lock *exist_lock, 198 const struct file_lock *unlock_lock, struct file_lock **left_lock, 199 struct file_lock **right_lock); 200 int duplicate_block(struct file_lock *fl); 201 void add_blockingfilelock(struct file_lock *fl); 202 enum hwlock_status unlock_hwlock(const struct file_lock *fl); 203 enum hwlock_status test_hwlock(const struct file_lock *fl, 204 struct file_lock **conflicting_fl); 205 void remove_blockingfilelock(struct file_lock *fl); 206 void clear_blockingfilelock(const char *hostname); 207 void retry_blockingfilelocklist(void); 208 enum partialfilelock_status unlock_partialfilelock( 209 const struct file_lock *fl); 210 void clear_partialfilelock(const char *hostname); 211 enum partialfilelock_status test_partialfilelock( 212 const struct file_lock *fl, struct file_lock **conflicting_fl); 213 enum nlm_stats do_test(struct file_lock *fl, 214 struct file_lock **conflicting_fl); 215 enum nlm_stats do_unlock(struct file_lock *fl); 216 enum nlm_stats do_lock(struct file_lock *fl); 217 void do_clear(const char *hostname); 218 219 void 220 debuglog(char const *fmt, ...) 221 { 222 va_list ap; 223 224 if (debug_level < 1) { 225 return; 226 } 227 228 sleep(debugdelay); 229 230 va_start(ap, fmt); 231 vsyslog(LOG_DEBUG, fmt, ap); 232 va_end(ap); 233 } 234 235 void 236 dump_static_object(const unsigned char *object, const int size_object, 237 unsigned char *hbuff, const int size_hbuff, unsigned char *cbuff, 238 const int size_cbuff) 239 { 240 int i, objectsize; 241 242 if (debug_level < 2) { 243 return; 244 } 245 246 objectsize = size_object; 247 248 if (objectsize == 0) { 249 debuglog("object is size 0\n"); 250 } else { 251 if (objectsize > MAXOBJECTSIZE) { 252 debuglog("Object of size %d being clamped" 253 "to size %d\n", objectsize, MAXOBJECTSIZE); 254 objectsize = MAXOBJECTSIZE; 255 } 256 257 if (hbuff != NULL) { 258 if (size_hbuff < objectsize*2+1) { 259 debuglog("Hbuff not large enough." 260 " Increase size\n"); 261 } else { 262 for(i=0;i<objectsize;i++) { 263 sprintf(hbuff+i*2,"%02x",*(object+i)); 264 } 265 *(hbuff+i*2) = '\0'; 266 } 267 } 268 269 if (cbuff != NULL) { 270 if (size_cbuff < objectsize+1) { 271 debuglog("Cbuff not large enough." 272 " Increase Size\n"); 273 } 274 275 for(i=0;i<objectsize;i++) { 276 if (*(object+i) >= 32 && *(object+i) <= 127) { 277 *(cbuff+i) = *(object+i); 278 } else { 279 *(cbuff+i) = '.'; 280 } 281 } 282 *(cbuff+i) = '\0'; 283 } 284 } 285 } 286 287 void 288 dump_netobj(const struct netobj *nobj) 289 { 290 char hbuff[MAXBUFFERSIZE*2]; 291 char cbuff[MAXBUFFERSIZE]; 292 293 if (debug_level < 2) { 294 return; 295 } 296 297 if (nobj == NULL) { 298 debuglog("Null netobj pointer\n"); 299 } 300 else if (nobj->n_len == 0) { 301 debuglog("Size zero netobj\n"); 302 } else { 303 dump_static_object(nobj->n_bytes, nobj->n_len, 304 hbuff, sizeof(hbuff), cbuff, sizeof(cbuff)); 305 debuglog("netobj: len: %d data: %s ::: %s\n", 306 nobj->n_len, hbuff, cbuff); 307 } 308 } 309 310 /* #define DUMP_FILELOCK_VERBOSE */ 311 void 312 dump_filelock(const struct file_lock *fl) 313 { 314 #ifdef DUMP_FILELOCK_VERBOSE 315 char hbuff[MAXBUFFERSIZE*2]; 316 char cbuff[MAXBUFFERSIZE]; 317 #endif 318 319 if (debug_level < 2) { 320 return; 321 } 322 323 if (fl != NULL) { 324 debuglog("Dumping file lock structure @ %p\n", fl); 325 326 #ifdef DUMP_FILELOCK_VERBOSE 327 dump_static_object((unsigned char *)&fl->filehandle, 328 sizeof(fl->filehandle), hbuff, sizeof(hbuff), 329 cbuff, sizeof(cbuff)); 330 debuglog("Filehandle: %8s ::: %8s\n", hbuff, cbuff); 331 #endif 332 333 debuglog("Dumping nlm4_holder:\n" 334 "exc: %x svid: %x offset:len %llx:%llx\n", 335 fl->client.exclusive, fl->client.svid, 336 fl->client.l_offset, fl->client.l_len); 337 338 #ifdef DUMP_FILELOCK_VERBOSE 339 debuglog("Dumping client identity:\n"); 340 dump_netobj(&fl->client.oh); 341 342 debuglog("Dumping client cookie:\n"); 343 dump_netobj(&fl->client_cookie); 344 345 debuglog("nsm: %d status: %d flags: %d svid: %x" 346 " client_name: %s\n", fl->nsm_status, fl->status, 347 fl->flags, fl->client.svid, fl->client_name); 348 #endif 349 } else { 350 debuglog("NULL file lock structure\n"); 351 } 352 } 353 354 void 355 copy_nlm4_lock_to_nlm4_holder(const struct nlm4_lock *src, 356 const bool_t exclusive, struct nlm4_holder *dest) 357 { 358 359 dest->exclusive = exclusive; 360 dest->oh.n_len = src->oh.n_len; 361 dest->oh.n_bytes = src->oh.n_bytes; 362 dest->svid = src->svid; 363 dest->l_offset = src->l_offset; 364 dest->l_len = src->l_len; 365 } 366 367 /* 368 * allocate_file_lock: Create a lock with the given parameters 369 */ 370 371 struct file_lock * 372 allocate_file_lock(const netobj *lockowner, const netobj *matchcookie, 373 const struct sockaddr *addr, const char *caller_name) 374 { 375 struct file_lock *newfl; 376 size_t n; 377 378 /* Beware of rubbish input! */ 379 n = strnlen(caller_name, SM_MAXSTRLEN); 380 if (n == SM_MAXSTRLEN) { 381 return NULL; 382 } 383 384 newfl = malloc(sizeof(*newfl) - sizeof(newfl->client_name) + n + 1); 385 if (newfl == NULL) { 386 return NULL; 387 } 388 bzero(newfl, sizeof(*newfl) - sizeof(newfl->client_name)); 389 memcpy(newfl->client_name, caller_name, n); 390 newfl->client_name[n] = 0; 391 392 newfl->client.oh.n_bytes = malloc(lockowner->n_len); 393 if (newfl->client.oh.n_bytes == NULL) { 394 free(newfl); 395 return NULL; 396 } 397 newfl->client.oh.n_len = lockowner->n_len; 398 bcopy(lockowner->n_bytes, newfl->client.oh.n_bytes, lockowner->n_len); 399 400 newfl->client_cookie.n_bytes = malloc(matchcookie->n_len); 401 if (newfl->client_cookie.n_bytes == NULL) { 402 free(newfl->client.oh.n_bytes); 403 free(newfl); 404 return NULL; 405 } 406 newfl->client_cookie.n_len = matchcookie->n_len; 407 bcopy(matchcookie->n_bytes, newfl->client_cookie.n_bytes, matchcookie->n_len); 408 409 newfl->addr = malloc(addr->sa_len); 410 if (newfl->addr == NULL) { 411 free(newfl->client_cookie.n_bytes); 412 free(newfl->client.oh.n_bytes); 413 free(newfl); 414 return NULL; 415 } 416 memcpy(newfl->addr, addr, addr->sa_len); 417 418 return newfl; 419 } 420 421 /* 422 * file_file_lock: Force creation of a valid file lock 423 */ 424 void 425 fill_file_lock(struct file_lock *fl, const fhandle_t *fh, 426 const bool_t exclusive, const int32_t svid, 427 const u_int64_t offset, const u_int64_t len, 428 const int state, const int status, const int flags, const int blocking) 429 { 430 bcopy(fh, &fl->filehandle, sizeof(fhandle_t)); 431 432 fl->client.exclusive = exclusive; 433 fl->client.svid = svid; 434 fl->client.l_offset = offset; 435 fl->client.l_len = len; 436 437 fl->nsm_status = state; 438 fl->status = status; 439 fl->flags = flags; 440 fl->blocking = blocking; 441 } 442 443 /* 444 * deallocate_file_lock: Free all storage associated with a file lock 445 */ 446 void 447 deallocate_file_lock(struct file_lock *fl) 448 { 449 free(fl->addr); 450 free(fl->client.oh.n_bytes); 451 free(fl->client_cookie.n_bytes); 452 free(fl); 453 } 454 455 /* 456 * regions_overlap(): This function examines the two provided regions for 457 * overlap. 458 */ 459 int 460 regions_overlap(const u_int64_t start1, const u_int64_t len1, 461 const u_int64_t start2, const u_int64_t len2) 462 { 463 u_int64_t d1,d2,d3,d4; 464 enum split_status result; 465 466 debuglog("Entering region overlap with vals: %llu:%llu--%llu:%llu\n", 467 start1, len1, start2, len2); 468 469 result = region_compare(start1, len1, start2, len2, 470 &d1, &d2, &d3, &d4); 471 472 debuglog("Exiting region overlap with val: %d\n",result); 473 474 if (result == SPL_DISJOINT) { 475 return 0; 476 } else { 477 return 1; 478 } 479 } 480 481 /* 482 * region_compare(): Examine lock regions and split appropriately 483 * 484 * XXX: Fix 64 bit overflow problems 485 * XXX: Check to make sure I got *ALL* the cases. 486 * XXX: This DESPERATELY needs a regression test. 487 */ 488 enum split_status 489 region_compare(const u_int64_t starte, const u_int64_t lene, 490 const u_int64_t startu, const u_int64_t lenu, u_int64_t *start1, 491 u_int64_t *len1, u_int64_t *start2, u_int64_t *len2) 492 { 493 /* 494 * Please pay attention to the sequential exclusions 495 * of the if statements!!! 496 */ 497 enum LFLAGS lflags; 498 enum RFLAGS rflags; 499 enum split_status retval; 500 501 retval = SPL_DISJOINT; 502 503 if (lene == 0 && lenu == 0) { 504 /* Examine left edge of locker */ 505 lflags = LEDGE_INSIDE; 506 if (startu < starte) { 507 lflags = LEDGE_LEFT; 508 } else if (startu == starte) { 509 lflags = LEDGE_LBOUNDARY; 510 } 511 512 rflags = REDGE_RBOUNDARY; /* Both are infiinite */ 513 514 if (lflags == LEDGE_INSIDE) { 515 *start1 = starte; 516 *len1 = startu - starte; 517 } 518 519 if (lflags == LEDGE_LEFT || lflags == LEDGE_LBOUNDARY) { 520 retval = SPL_CONTAINED; 521 } else { 522 retval = SPL_LOCK1; 523 } 524 } else if (lene == 0 && lenu != 0) { 525 /* Established lock is infinite */ 526 /* Examine left edge of unlocker */ 527 lflags = LEDGE_INSIDE; 528 if (startu < starte) { 529 lflags = LEDGE_LEFT; 530 } else if (startu == starte) { 531 lflags = LEDGE_LBOUNDARY; 532 } 533 534 /* Examine right edge of unlocker */ 535 if (startu + lenu < starte) { 536 /* Right edge of unlocker left of established lock */ 537 rflags = REDGE_LEFT; 538 return SPL_DISJOINT; 539 } else if (startu + lenu == starte) { 540 /* Right edge of unlocker on start of established lock */ 541 rflags = REDGE_LBOUNDARY; 542 return SPL_DISJOINT; 543 } else { /* Infinifty is right of finity */ 544 /* Right edge of unlocker inside established lock */ 545 rflags = REDGE_INSIDE; 546 } 547 548 if (lflags == LEDGE_INSIDE) { 549 *start1 = starte; 550 *len1 = startu - starte; 551 retval |= SPL_LOCK1; 552 } 553 554 if (rflags == REDGE_INSIDE) { 555 /* Create right lock */ 556 *start2 = startu+lenu; 557 *len2 = 0; 558 retval |= SPL_LOCK2; 559 } 560 } else if (lene != 0 && lenu == 0) { 561 /* Unlocker is infinite */ 562 /* Examine left edge of unlocker */ 563 lflags = LEDGE_RIGHT; 564 if (startu < starte) { 565 lflags = LEDGE_LEFT; 566 retval = SPL_CONTAINED; 567 return retval; 568 } else if (startu == starte) { 569 lflags = LEDGE_LBOUNDARY; 570 retval = SPL_CONTAINED; 571 return retval; 572 } else if ((startu > starte) && (startu < starte + lene - 1)) { 573 lflags = LEDGE_INSIDE; 574 } else if (startu == starte + lene - 1) { 575 lflags = LEDGE_RBOUNDARY; 576 } else { /* startu > starte + lene -1 */ 577 lflags = LEDGE_RIGHT; 578 return SPL_DISJOINT; 579 } 580 581 rflags = REDGE_RIGHT; /* Infinity is right of finity */ 582 583 if (lflags == LEDGE_INSIDE || lflags == LEDGE_RBOUNDARY) { 584 *start1 = starte; 585 *len1 = startu - starte; 586 retval |= SPL_LOCK1; 587 return retval; 588 } 589 } else { 590 /* Both locks are finite */ 591 592 /* Examine left edge of unlocker */ 593 lflags = LEDGE_RIGHT; 594 if (startu < starte) { 595 lflags = LEDGE_LEFT; 596 } else if (startu == starte) { 597 lflags = LEDGE_LBOUNDARY; 598 } else if ((startu > starte) && (startu < starte + lene - 1)) { 599 lflags = LEDGE_INSIDE; 600 } else if (startu == starte + lene - 1) { 601 lflags = LEDGE_RBOUNDARY; 602 } else { /* startu > starte + lene -1 */ 603 lflags = LEDGE_RIGHT; 604 return SPL_DISJOINT; 605 } 606 607 /* Examine right edge of unlocker */ 608 if (startu + lenu < starte) { 609 /* Right edge of unlocker left of established lock */ 610 rflags = REDGE_LEFT; 611 return SPL_DISJOINT; 612 } else if (startu + lenu == starte) { 613 /* Right edge of unlocker on start of established lock */ 614 rflags = REDGE_LBOUNDARY; 615 return SPL_DISJOINT; 616 } else if (startu + lenu < starte + lene) { 617 /* Right edge of unlocker inside established lock */ 618 rflags = REDGE_INSIDE; 619 } else if (startu + lenu == starte + lene) { 620 /* Right edge of unlocker on right edge of established lock */ 621 rflags = REDGE_RBOUNDARY; 622 } else { /* startu + lenu > starte + lene */ 623 /* Right edge of unlocker is right of established lock */ 624 rflags = REDGE_RIGHT; 625 } 626 627 if (lflags == LEDGE_INSIDE || lflags == LEDGE_RBOUNDARY) { 628 /* Create left lock */ 629 *start1 = starte; 630 *len1 = (startu - starte); 631 retval |= SPL_LOCK1; 632 } 633 634 if (rflags == REDGE_INSIDE) { 635 /* Create right lock */ 636 *start2 = startu+lenu; 637 *len2 = starte+lene-(startu+lenu); 638 retval |= SPL_LOCK2; 639 } 640 641 if ((lflags == LEDGE_LEFT || lflags == LEDGE_LBOUNDARY) && 642 (rflags == REDGE_RBOUNDARY || rflags == REDGE_RIGHT)) { 643 retval = SPL_CONTAINED; 644 } 645 } 646 return retval; 647 } 648 649 /* 650 * same_netobj: Compares the apprpriate bits of a netobj for identity 651 */ 652 int 653 same_netobj(const netobj *n0, const netobj *n1) 654 { 655 int retval; 656 657 retval = 0; 658 659 debuglog("Entering netobj identity check\n"); 660 661 if (n0->n_len == n1->n_len) { 662 debuglog("Preliminary length check passed\n"); 663 retval = !bcmp(n0->n_bytes, n1->n_bytes, n0->n_len); 664 debuglog("netobj %smatch\n", retval ? "" : "mis"); 665 } 666 667 return (retval); 668 } 669 670 /* 671 * same_filelock_identity: Compares the appropriate bits of a file_lock 672 */ 673 int 674 same_filelock_identity(const struct file_lock *fl0, const struct file_lock *fl1) 675 { 676 int retval; 677 678 retval = 0; 679 680 debuglog("Checking filelock identity\n"); 681 682 /* 683 * Check process ids and host information. 684 */ 685 retval = (fl0->client.svid == fl1->client.svid && 686 same_netobj(&(fl0->client.oh), &(fl1->client.oh))); 687 688 debuglog("Exiting checking filelock identity: retval: %d\n",retval); 689 690 return (retval); 691 } 692 693 /* 694 * Below here are routines associated with manipulating the NFS 695 * lock list. 696 */ 697 698 /* 699 * get_lock_matching_unlock: Return a lock which matches the given unlock lock 700 * or NULL otehrwise 701 * XXX: It is a shame that this duplicates so much code from test_nfslock. 702 */ 703 struct file_lock * 704 get_lock_matching_unlock(const struct file_lock *fl) 705 { 706 struct file_lock *ifl; /* Iterator */ 707 708 debuglog("Entering get_lock_matching_unlock\n"); 709 debuglog("********Dump of fl*****************\n"); 710 dump_filelock(fl); 711 712 LIST_FOREACH(ifl, &nfslocklist_head, nfslocklist) { 713 debuglog("Pointer to file lock: %p\n",ifl); 714 715 debuglog("****Dump of ifl****\n"); 716 dump_filelock(ifl); 717 debuglog("*******************\n"); 718 719 /* 720 * XXX: It is conceivable that someone could use the NLM RPC 721 * system to directly access filehandles. This may be a 722 * security hazard as the filehandle code may bypass normal 723 * file access controls 724 */ 725 if (bcmp(&fl->filehandle, &ifl->filehandle, sizeof(fhandle_t))) 726 continue; 727 728 debuglog("get_lock_matching_unlock: Filehandles match, " 729 "checking regions\n"); 730 731 /* Filehandles match, check for region overlap */ 732 if (!regions_overlap(fl->client.l_offset, fl->client.l_len, 733 ifl->client.l_offset, ifl->client.l_len)) 734 continue; 735 736 debuglog("get_lock_matching_unlock: Region overlap" 737 " found %llu : %llu -- %llu : %llu\n", 738 fl->client.l_offset,fl->client.l_len, 739 ifl->client.l_offset,ifl->client.l_len); 740 741 /* Regions overlap, check the identity */ 742 if (!same_filelock_identity(fl,ifl)) 743 continue; 744 745 debuglog("get_lock_matching_unlock: Duplicate lock id. Granting\n"); 746 return (ifl); 747 } 748 749 debuglog("Exiting bet_lock_matching_unlock\n"); 750 751 return (NULL); 752 } 753 754 /* 755 * test_nfslock: check for NFS lock in lock list 756 * 757 * This routine makes the following assumptions: 758 * 1) Nothing will adjust the lock list during a lookup 759 * 760 * This routine has an interesting quirk which bit me hard. 761 * The conflicting_fl is the pointer to the conflicting lock. 762 * However, to modify the "*pointer* to the conflicting lock" rather 763 * that the "conflicting lock itself" one must pass in a "pointer to 764 * the pointer of the conflicting lock". Gross. 765 */ 766 767 enum nfslock_status 768 test_nfslock(const struct file_lock *fl, struct file_lock **conflicting_fl) 769 { 770 struct file_lock *ifl; /* Iterator */ 771 enum nfslock_status retval; 772 773 debuglog("Entering test_nfslock\n"); 774 775 retval = NFS_GRANTED; 776 (*conflicting_fl) = NULL; 777 778 debuglog("Entering lock search loop\n"); 779 780 debuglog("***********************************\n"); 781 debuglog("Dumping match filelock\n"); 782 debuglog("***********************************\n"); 783 dump_filelock(fl); 784 debuglog("***********************************\n"); 785 786 LIST_FOREACH(ifl, &nfslocklist_head, nfslocklist) { 787 if (retval == NFS_DENIED) 788 break; 789 790 debuglog("Top of lock loop\n"); 791 debuglog("Pointer to file lock: %p\n",ifl); 792 793 debuglog("***********************************\n"); 794 debuglog("Dumping test filelock\n"); 795 debuglog("***********************************\n"); 796 dump_filelock(ifl); 797 debuglog("***********************************\n"); 798 799 /* 800 * XXX: It is conceivable that someone could use the NLM RPC 801 * system to directly access filehandles. This may be a 802 * security hazard as the filehandle code may bypass normal 803 * file access controls 804 */ 805 if (bcmp(&fl->filehandle, &ifl->filehandle, sizeof(fhandle_t))) 806 continue; 807 808 debuglog("test_nfslock: filehandle match found\n"); 809 810 /* Filehandles match, check for region overlap */ 811 if (!regions_overlap(fl->client.l_offset, fl->client.l_len, 812 ifl->client.l_offset, ifl->client.l_len)) 813 continue; 814 815 debuglog("test_nfslock: Region overlap found" 816 " %llu : %llu -- %llu : %llu\n", 817 fl->client.l_offset,fl->client.l_len, 818 ifl->client.l_offset,ifl->client.l_len); 819 820 /* Regions overlap, check the exclusivity */ 821 if (!(fl->client.exclusive || ifl->client.exclusive)) 822 continue; 823 824 debuglog("test_nfslock: Exclusivity failure: %d %d\n", 825 fl->client.exclusive, 826 ifl->client.exclusive); 827 828 if (same_filelock_identity(fl,ifl)) { 829 debuglog("test_nfslock: Duplicate id. Granting\n"); 830 (*conflicting_fl) = ifl; 831 retval = NFS_GRANTED_DUPLICATE; 832 } else { 833 /* locking attempt fails */ 834 debuglog("test_nfslock: Lock attempt failed\n"); 835 debuglog("Desired lock\n"); 836 dump_filelock(fl); 837 debuglog("Conflicting lock\n"); 838 dump_filelock(ifl); 839 (*conflicting_fl) = ifl; 840 retval = NFS_DENIED; 841 } 842 } 843 844 debuglog("Dumping file locks\n"); 845 debuglog("Exiting test_nfslock\n"); 846 847 return (retval); 848 } 849 850 /* 851 * lock_nfslock: attempt to create a lock in the NFS lock list 852 * 853 * This routine tests whether the lock will be granted and then adds 854 * the entry to the lock list if so. 855 * 856 * Argument fl gets modified as its list housekeeping entries get modified 857 * upon insertion into the NFS lock list 858 * 859 * This routine makes several assumptions: 860 * 1) It is perfectly happy to grant a duplicate lock from the same pid. 861 * While this seems to be intuitively wrong, it is required for proper 862 * Posix semantics during unlock. It is absolutely imperative to not 863 * unlock the main lock before the two child locks are established. Thus, 864 * one has to be able to create duplicate locks over an existing lock 865 * 2) It currently accepts duplicate locks from the same id,pid 866 */ 867 868 enum nfslock_status 869 lock_nfslock(struct file_lock *fl) 870 { 871 enum nfslock_status retval; 872 struct file_lock *dummy_fl; 873 874 dummy_fl = NULL; 875 876 debuglog("Entering lock_nfslock...\n"); 877 878 retval = test_nfslock(fl,&dummy_fl); 879 880 if (retval == NFS_GRANTED || retval == NFS_GRANTED_DUPLICATE) { 881 debuglog("Inserting lock...\n"); 882 dump_filelock(fl); 883 LIST_INSERT_HEAD(&nfslocklist_head, fl, nfslocklist); 884 } 885 886 debuglog("Exiting lock_nfslock...\n"); 887 888 return (retval); 889 } 890 891 /* 892 * delete_nfslock: delete an NFS lock list entry 893 * 894 * This routine is used to delete a lock out of the NFS lock list 895 * without regard to status, underlying locks, regions or anything else 896 * 897 * Note that this routine *does not deallocate memory* of the lock. 898 * It just disconnects it from the list. The lock can then be used 899 * by other routines without fear of trashing the list. 900 */ 901 902 enum nfslock_status 903 delete_nfslock(struct file_lock *fl) 904 { 905 906 LIST_REMOVE(fl, nfslocklist); 907 908 return (NFS_GRANTED); 909 } 910 911 enum split_status 912 split_nfslock(const struct file_lock *exist_lock, 913 const struct file_lock *unlock_lock, struct file_lock **left_lock, 914 struct file_lock **right_lock) 915 { 916 u_int64_t start1, len1, start2, len2; 917 enum split_status spstatus; 918 919 spstatus = region_compare(exist_lock->client.l_offset, exist_lock->client.l_len, 920 unlock_lock->client.l_offset, unlock_lock->client.l_len, 921 &start1, &len1, &start2, &len2); 922 923 if ((spstatus & SPL_LOCK1) != 0) { 924 *left_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->client_cookie, exist_lock->addr, exist_lock->client_name); 925 if (*left_lock == NULL) { 926 debuglog("Unable to allocate resource for split 1\n"); 927 return SPL_RESERR; 928 } 929 930 fill_file_lock(*left_lock, &exist_lock->filehandle, 931 exist_lock->client.exclusive, exist_lock->client.svid, 932 start1, len1, 933 exist_lock->nsm_status, 934 exist_lock->status, exist_lock->flags, exist_lock->blocking); 935 } 936 937 if ((spstatus & SPL_LOCK2) != 0) { 938 *right_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->client_cookie, exist_lock->addr, exist_lock->client_name); 939 if (*right_lock == NULL) { 940 debuglog("Unable to allocate resource for split 1\n"); 941 if (*left_lock != NULL) { 942 deallocate_file_lock(*left_lock); 943 } 944 return SPL_RESERR; 945 } 946 947 fill_file_lock(*right_lock, &exist_lock->filehandle, 948 exist_lock->client.exclusive, exist_lock->client.svid, 949 start2, len2, 950 exist_lock->nsm_status, 951 exist_lock->status, exist_lock->flags, exist_lock->blocking); 952 } 953 954 return spstatus; 955 } 956 957 enum nfslock_status 958 unlock_nfslock(const struct file_lock *fl, struct file_lock **released_lock, 959 struct file_lock **left_lock, struct file_lock **right_lock) 960 { 961 struct file_lock *mfl; /* Matching file lock */ 962 enum nfslock_status retval; 963 enum split_status spstatus; 964 965 debuglog("Entering unlock_nfslock\n"); 966 967 *released_lock = NULL; 968 *left_lock = NULL; 969 *right_lock = NULL; 970 971 retval = NFS_DENIED_NOLOCK; 972 973 debuglog("Attempting to match lock...\n"); 974 mfl = get_lock_matching_unlock(fl); 975 976 if (mfl != NULL) { 977 debuglog("Unlock matched. Querying for split\n"); 978 979 spstatus = split_nfslock(mfl, fl, left_lock, right_lock); 980 981 debuglog("Split returned %d %p %p %p %p\n",spstatus,mfl,fl,*left_lock,*right_lock); 982 debuglog("********Split dumps********"); 983 dump_filelock(mfl); 984 dump_filelock(fl); 985 dump_filelock(*left_lock); 986 dump_filelock(*right_lock); 987 debuglog("********End Split dumps********"); 988 989 if (spstatus == SPL_RESERR) { 990 if (*left_lock != NULL) { 991 deallocate_file_lock(*left_lock); 992 *left_lock = NULL; 993 } 994 995 if (*right_lock != NULL) { 996 deallocate_file_lock(*right_lock); 997 *right_lock = NULL; 998 } 999 1000 return NFS_RESERR; 1001 } 1002 1003 /* Insert new locks from split if required */ 1004 if (*left_lock != NULL) { 1005 debuglog("Split left activated\n"); 1006 LIST_INSERT_HEAD(&nfslocklist_head, *left_lock, nfslocklist); 1007 } 1008 1009 if (*right_lock != NULL) { 1010 debuglog("Split right activated\n"); 1011 LIST_INSERT_HEAD(&nfslocklist_head, *right_lock, nfslocklist); 1012 } 1013 1014 /* Unlock the lock since it matches identity */ 1015 LIST_REMOVE(mfl, nfslocklist); 1016 *released_lock = mfl; 1017 retval = NFS_GRANTED; 1018 } 1019 1020 debuglog("Exiting unlock_nfslock\n"); 1021 1022 return retval; 1023 } 1024 1025 /* 1026 * Below here are the routines for manipulating the file lock directly 1027 * on the disk hardware itself 1028 */ 1029 enum hwlock_status 1030 lock_hwlock(struct file_lock *fl) 1031 { 1032 struct monfile *imf,*nmf; 1033 int lflags, flerror; 1034 1035 /* Scan to see if filehandle already present */ 1036 LIST_FOREACH(imf, &monfilelist_head, monfilelist) { 1037 if (bcmp(&fl->filehandle, &imf->filehandle, 1038 sizeof(fl->filehandle)) == 0) { 1039 /* imf is the correct filehandle */ 1040 break; 1041 } 1042 } 1043 1044 /* 1045 * Filehandle already exists (we control the file) 1046 * *AND* NFS has already cleared the lock for availability 1047 * Grant it and bump the refcount. 1048 */ 1049 if (imf != NULL) { 1050 ++(imf->refcount); 1051 return (HW_GRANTED); 1052 } 1053 1054 /* No filehandle found, create and go */ 1055 nmf = malloc(sizeof(struct monfile)); 1056 if (nmf == NULL) { 1057 debuglog("hwlock resource allocation failure\n"); 1058 return (HW_RESERR); 1059 } 1060 1061 /* XXX: Is O_RDWR always the correct mode? */ 1062 nmf->fd = fhopen(&fl->filehandle, O_RDWR); 1063 if (nmf->fd < 0) { 1064 debuglog("fhopen failed (from %16s): %32s\n", 1065 fl->client_name, strerror(errno)); 1066 free(nmf); 1067 switch (errno) { 1068 case ESTALE: 1069 return (HW_STALEFH); 1070 case EROFS: 1071 return (HW_READONLY); 1072 default: 1073 return (HW_RESERR); 1074 } 1075 } 1076 1077 /* File opened correctly, fill the monitor struct */ 1078 bcopy(&fl->filehandle, &nmf->filehandle, sizeof(fl->filehandle)); 1079 nmf->refcount = 1; 1080 nmf->exclusive = fl->client.exclusive; 1081 1082 lflags = (nmf->exclusive == 1) ? 1083 (LOCK_EX | LOCK_NB) : (LOCK_SH | LOCK_NB); 1084 1085 flerror = flock(nmf->fd, lflags); 1086 1087 if (flerror != 0) { 1088 debuglog("flock failed (from %16s): %32s\n", 1089 fl->client_name, strerror(errno)); 1090 close(nmf->fd); 1091 free(nmf); 1092 switch (errno) { 1093 case EAGAIN: 1094 return (HW_DENIED); 1095 case ESTALE: 1096 return (HW_STALEFH); 1097 case EROFS: 1098 return (HW_READONLY); 1099 default: 1100 return (HW_RESERR); 1101 break; 1102 } 1103 } 1104 1105 /* File opened and locked */ 1106 LIST_INSERT_HEAD(&monfilelist_head, nmf, monfilelist); 1107 1108 debuglog("flock succeeded (from %16s)\n", fl->client_name); 1109 return (HW_GRANTED); 1110 } 1111 1112 enum hwlock_status 1113 unlock_hwlock(const struct file_lock *fl) 1114 { 1115 struct monfile *imf; 1116 1117 debuglog("Entering unlock_hwlock\n"); 1118 debuglog("Entering loop interation\n"); 1119 1120 /* Scan to see if filehandle already present */ 1121 LIST_FOREACH(imf, &monfilelist_head, monfilelist) { 1122 if (bcmp(&fl->filehandle, &imf->filehandle, 1123 sizeof(fl->filehandle)) == 0) { 1124 /* imf is the correct filehandle */ 1125 break; 1126 } 1127 } 1128 1129 debuglog("Completed iteration. Proceeding\n"); 1130 1131 if (imf == NULL) { 1132 /* No lock found */ 1133 debuglog("Exiting unlock_hwlock (HW_DENIED_NOLOCK)\n"); 1134 return (HW_DENIED_NOLOCK); 1135 } 1136 1137 /* Lock found */ 1138 --imf->refcount; 1139 1140 if (imf->refcount < 0) { 1141 debuglog("Negative hardware reference count\n"); 1142 } 1143 1144 if (imf->refcount <= 0) { 1145 close(imf->fd); 1146 LIST_REMOVE(imf, monfilelist); 1147 free(imf); 1148 } 1149 debuglog("Exiting unlock_hwlock (HW_GRANTED)\n"); 1150 return (HW_GRANTED); 1151 } 1152 1153 enum hwlock_status 1154 test_hwlock(const struct file_lock *fl __unused, 1155 struct file_lock **conflicting_fl __unused) 1156 { 1157 1158 /* 1159 * XXX: lock tests on hardware are not required until 1160 * true partial file testing is done on the underlying file 1161 */ 1162 return (HW_RESERR); 1163 } 1164 1165 1166 1167 /* 1168 * Below here are routines for manipulating blocked lock requests 1169 * They should only be called from the XXX_partialfilelock routines 1170 * if at all possible 1171 */ 1172 1173 int 1174 duplicate_block(struct file_lock *fl) 1175 { 1176 struct file_lock *ifl; 1177 int retval = 0; 1178 1179 debuglog("Entering duplicate_block"); 1180 1181 /* 1182 * Is this lock request already on the blocking list? 1183 * Consider it a dupe if the file handles, offset, length, 1184 * exclusivity and client match. 1185 */ 1186 LIST_FOREACH(ifl, &blockedlocklist_head, nfslocklist) { 1187 if (!bcmp(&fl->filehandle, &ifl->filehandle, 1188 sizeof(fhandle_t)) && 1189 fl->client.exclusive == ifl->client.exclusive && 1190 fl->client.l_offset == ifl->client.l_offset && 1191 fl->client.l_len == ifl->client.l_len && 1192 same_filelock_identity(fl, ifl)) { 1193 retval = 1; 1194 break; 1195 } 1196 } 1197 1198 debuglog("Exiting duplicate_block: %s\n", retval ? "already blocked" 1199 : "not already blocked"); 1200 return retval; 1201 } 1202 1203 void 1204 add_blockingfilelock(struct file_lock *fl) 1205 { 1206 debuglog("Entering add_blockingfilelock\n"); 1207 1208 /* 1209 * A blocking lock request _should_ never be duplicated as a client 1210 * that is already blocked shouldn't be able to request another 1211 * lock. Alas, there are some buggy clients that do request the same 1212 * lock repeatedly. Make sure only unique locks are on the blocked 1213 * lock list. 1214 */ 1215 if (duplicate_block(fl)) { 1216 debuglog("Exiting add_blockingfilelock: already blocked\n"); 1217 return; 1218 } 1219 1220 /* 1221 * Clear the blocking flag so that it can be reused without 1222 * adding it to the blocking queue a second time 1223 */ 1224 1225 fl->blocking = 0; 1226 LIST_INSERT_HEAD(&blockedlocklist_head, fl, nfslocklist); 1227 1228 debuglog("Exiting add_blockingfilelock: added blocked lock\n"); 1229 } 1230 1231 void 1232 remove_blockingfilelock(struct file_lock *fl) 1233 { 1234 1235 debuglog("Entering remove_blockingfilelock\n"); 1236 1237 LIST_REMOVE(fl, nfslocklist); 1238 1239 debuglog("Exiting remove_blockingfilelock\n"); 1240 } 1241 1242 void 1243 clear_blockingfilelock(const char *hostname) 1244 { 1245 struct file_lock *ifl,*nfl; 1246 1247 /* 1248 * Normally, LIST_FOREACH is called for, but since 1249 * the current element *is* the iterator, deleting it 1250 * would mess up the iteration. Thus, a next element 1251 * must be used explicitly 1252 */ 1253 1254 ifl = LIST_FIRST(&blockedlocklist_head); 1255 1256 while (ifl != NULL) { 1257 nfl = LIST_NEXT(ifl, nfslocklist); 1258 1259 if (strncmp(hostname, ifl->client_name, SM_MAXSTRLEN) == 0) { 1260 remove_blockingfilelock(ifl); 1261 deallocate_file_lock(ifl); 1262 } 1263 1264 ifl = nfl; 1265 } 1266 } 1267 1268 void 1269 retry_blockingfilelocklist(void) 1270 { 1271 /* Retry all locks in the blocked list */ 1272 struct file_lock *ifl, *nfl; /* Iterator */ 1273 enum partialfilelock_status pflstatus; 1274 1275 debuglog("Entering retry_blockingfilelocklist\n"); 1276 1277 LIST_FOREACH_SAFE(ifl, &blockedlocklist_head, nfslocklist, nfl) { 1278 debuglog("Iterator choice %p\n",ifl); 1279 debuglog("Next iterator choice %p\n",nfl); 1280 1281 /* 1282 * SUBTLE BUG: The file_lock must be removed from the 1283 * old list so that it's list pointers get disconnected 1284 * before being allowed to participate in the new list 1285 * which will automatically add it in if necessary. 1286 */ 1287 1288 LIST_REMOVE(ifl, nfslocklist); 1289 pflstatus = lock_partialfilelock(ifl); 1290 1291 if (pflstatus == PFL_GRANTED || pflstatus == PFL_GRANTED_DUPLICATE) { 1292 debuglog("Granted blocked lock\n"); 1293 /* lock granted and is now being used */ 1294 send_granted(ifl,0); 1295 } else { 1296 /* Reinsert lock back into blocked list */ 1297 debuglog("Replacing blocked lock\n"); 1298 LIST_INSERT_HEAD(&blockedlocklist_head, ifl, nfslocklist); 1299 } 1300 } 1301 1302 debuglog("Exiting retry_blockingfilelocklist\n"); 1303 } 1304 1305 /* 1306 * Below here are routines associated with manipulating all 1307 * aspects of the partial file locking system (list, hardware, etc.) 1308 */ 1309 1310 /* 1311 * Please note that lock monitoring must be done at this level which 1312 * keeps track of *individual* lock requests on lock and unlock 1313 * 1314 * XXX: Split unlocking is going to make the unlock code miserable 1315 */ 1316 1317 /* 1318 * lock_partialfilelock: 1319 * 1320 * Argument fl gets modified as its list housekeeping entries get modified 1321 * upon insertion into the NFS lock list 1322 * 1323 * This routine makes several assumptions: 1324 * 1) It (will) pass locks through to flock to lock the entire underlying file 1325 * and then parcel out NFS locks if it gets control of the file. 1326 * This matches the old rpc.lockd file semantics (except where it 1327 * is now more correct). It is the safe solution, but will cause 1328 * overly restrictive blocking if someone is trying to use the 1329 * underlying files without using NFS. This appears to be an 1330 * acceptable tradeoff since most people use standalone NFS servers. 1331 * XXX: The right solution is probably kevent combined with fcntl 1332 * 1333 * 2) Nothing modifies the lock lists between testing and granting 1334 * I have no idea whether this is a useful assumption or not 1335 */ 1336 1337 enum partialfilelock_status 1338 lock_partialfilelock(struct file_lock *fl) 1339 { 1340 enum partialfilelock_status retval; 1341 enum nfslock_status lnlstatus; 1342 enum hwlock_status hwstatus; 1343 1344 debuglog("Entering lock_partialfilelock\n"); 1345 1346 retval = PFL_DENIED; 1347 1348 /* 1349 * Execute the NFS lock first, if possible, as it is significantly 1350 * easier and less expensive to undo than the filesystem lock 1351 */ 1352 1353 lnlstatus = lock_nfslock(fl); 1354 1355 switch (lnlstatus) { 1356 case NFS_GRANTED: 1357 case NFS_GRANTED_DUPLICATE: 1358 /* 1359 * At this point, the NFS lock is allocated and active. 1360 * Remember to clean it up if the hardware lock fails 1361 */ 1362 hwstatus = lock_hwlock(fl); 1363 1364 switch (hwstatus) { 1365 case HW_GRANTED: 1366 case HW_GRANTED_DUPLICATE: 1367 debuglog("HW GRANTED\n"); 1368 /* 1369 * XXX: Fixme: Check hwstatus for duplicate when 1370 * true partial file locking and accounting is 1371 * done on the hardware. 1372 */ 1373 if (lnlstatus == NFS_GRANTED_DUPLICATE) { 1374 retval = PFL_GRANTED_DUPLICATE; 1375 } else { 1376 retval = PFL_GRANTED; 1377 } 1378 monitor_lock_host(fl->client_name); 1379 break; 1380 case HW_RESERR: 1381 debuglog("HW RESERR\n"); 1382 retval = PFL_HWRESERR; 1383 break; 1384 case HW_DENIED: 1385 debuglog("HW DENIED\n"); 1386 retval = PFL_HWDENIED; 1387 break; 1388 default: 1389 debuglog("Unmatched hwstatus %d\n",hwstatus); 1390 break; 1391 } 1392 1393 if (retval != PFL_GRANTED && 1394 retval != PFL_GRANTED_DUPLICATE) { 1395 /* Clean up the NFS lock */ 1396 debuglog("Deleting trial NFS lock\n"); 1397 delete_nfslock(fl); 1398 } 1399 break; 1400 case NFS_DENIED: 1401 retval = PFL_NFSDENIED; 1402 break; 1403 case NFS_RESERR: 1404 retval = PFL_NFSRESERR; 1405 break; 1406 default: 1407 debuglog("Unmatched lnlstatus %d\n"); 1408 retval = PFL_NFSDENIED_NOLOCK; 1409 break; 1410 } 1411 1412 /* 1413 * By the time fl reaches here, it is completely free again on 1414 * failure. The NFS lock done before attempting the 1415 * hardware lock has been backed out 1416 */ 1417 1418 if (retval == PFL_NFSDENIED || retval == PFL_HWDENIED) { 1419 /* Once last chance to check the lock */ 1420 if (fl->blocking == 1) { 1421 if (retval == PFL_NFSDENIED) { 1422 /* Queue the lock */ 1423 debuglog("BLOCKING LOCK RECEIVED\n"); 1424 retval = PFL_NFSBLOCKED; 1425 add_blockingfilelock(fl); 1426 dump_filelock(fl); 1427 } else { 1428 /* retval is okay as PFL_HWDENIED */ 1429 debuglog("BLOCKING LOCK DENIED IN HARDWARE\n"); 1430 dump_filelock(fl); 1431 } 1432 } else { 1433 /* Leave retval alone, it's already correct */ 1434 debuglog("Lock denied. Non-blocking failure\n"); 1435 dump_filelock(fl); 1436 } 1437 } 1438 1439 debuglog("Exiting lock_partialfilelock\n"); 1440 1441 return retval; 1442 } 1443 1444 /* 1445 * unlock_partialfilelock: 1446 * 1447 * Given a file_lock, unlock all locks which match. 1448 * 1449 * Note that a given lock might have to unlock ITSELF! See 1450 * clear_partialfilelock for example. 1451 */ 1452 1453 enum partialfilelock_status 1454 unlock_partialfilelock(const struct file_lock *fl) 1455 { 1456 struct file_lock *lfl,*rfl,*releasedfl,*selffl; 1457 enum partialfilelock_status retval; 1458 enum nfslock_status unlstatus; 1459 enum hwlock_status unlhwstatus, lhwstatus; 1460 1461 debuglog("Entering unlock_partialfilelock\n"); 1462 1463 selffl = NULL; 1464 lfl = NULL; 1465 rfl = NULL; 1466 releasedfl = NULL; 1467 retval = PFL_DENIED; 1468 1469 /* 1470 * There are significant overlap and atomicity issues 1471 * with partially releasing a lock. For example, releasing 1472 * part of an NFS shared lock does *not* always release the 1473 * corresponding part of the file since there is only one 1474 * rpc.lockd UID but multiple users could be requesting it 1475 * from NFS. Also, an unlock request should never allow 1476 * another process to gain a lock on the remaining parts. 1477 * ie. Always apply the new locks before releasing the 1478 * old one 1479 */ 1480 1481 /* 1482 * Loop is required since multiple little locks 1483 * can be allocated and then deallocated with one 1484 * big unlock. 1485 * 1486 * The loop is required to be here so that the nfs & 1487 * hw subsystems do not need to communicate with one 1488 * one another 1489 */ 1490 1491 do { 1492 debuglog("Value of releasedfl: %p\n",releasedfl); 1493 /* lfl&rfl are created *AND* placed into the NFS lock list if required */ 1494 unlstatus = unlock_nfslock(fl, &releasedfl, &lfl, &rfl); 1495 debuglog("Value of releasedfl: %p\n",releasedfl); 1496 1497 1498 /* XXX: This is grungy. It should be refactored to be cleaner */ 1499 if (lfl != NULL) { 1500 lhwstatus = lock_hwlock(lfl); 1501 if (lhwstatus != HW_GRANTED && 1502 lhwstatus != HW_GRANTED_DUPLICATE) { 1503 debuglog("HW duplicate lock failure for left split\n"); 1504 } 1505 monitor_lock_host(lfl->client_name); 1506 } 1507 1508 if (rfl != NULL) { 1509 lhwstatus = lock_hwlock(rfl); 1510 if (lhwstatus != HW_GRANTED && 1511 lhwstatus != HW_GRANTED_DUPLICATE) { 1512 debuglog("HW duplicate lock failure for right split\n"); 1513 } 1514 monitor_lock_host(rfl->client_name); 1515 } 1516 1517 switch (unlstatus) { 1518 case NFS_GRANTED: 1519 /* Attempt to unlock on the hardware */ 1520 debuglog("NFS unlock granted. Attempting hardware unlock\n"); 1521 1522 /* This call *MUST NOT* unlock the two newly allocated locks */ 1523 unlhwstatus = unlock_hwlock(fl); 1524 debuglog("HW unlock returned with code %d\n",unlhwstatus); 1525 1526 switch (unlhwstatus) { 1527 case HW_GRANTED: 1528 debuglog("HW unlock granted\n"); 1529 unmonitor_lock_host(releasedfl->client_name); 1530 retval = PFL_GRANTED; 1531 break; 1532 case HW_DENIED_NOLOCK: 1533 /* Huh?!?! This shouldn't happen */ 1534 debuglog("HW unlock denied no lock\n"); 1535 retval = PFL_HWRESERR; 1536 /* Break out of do-while */ 1537 unlstatus = NFS_RESERR; 1538 break; 1539 default: 1540 debuglog("HW unlock failed\n"); 1541 retval = PFL_HWRESERR; 1542 /* Break out of do-while */ 1543 unlstatus = NFS_RESERR; 1544 break; 1545 } 1546 1547 debuglog("Exiting with status retval: %d\n",retval); 1548 1549 retry_blockingfilelocklist(); 1550 break; 1551 case NFS_DENIED_NOLOCK: 1552 retval = PFL_GRANTED; 1553 debuglog("All locks cleaned out\n"); 1554 break; 1555 default: 1556 retval = PFL_NFSRESERR; 1557 debuglog("NFS unlock failure\n"); 1558 dump_filelock(fl); 1559 break; 1560 } 1561 1562 if (releasedfl != NULL) { 1563 if (fl == releasedfl) { 1564 /* 1565 * XXX: YECHHH!!! Attempt to unlock self succeeded 1566 * but we can't deallocate the space yet. This is what 1567 * happens when you don't write malloc and free together 1568 */ 1569 debuglog("Attempt to unlock self\n"); 1570 selffl = releasedfl; 1571 } else { 1572 /* 1573 * XXX: this deallocation *still* needs to migrate closer 1574 * to the allocation code way up in get_lock or the allocation 1575 * code needs to migrate down (violation of "When you write 1576 * malloc you must write free") 1577 */ 1578 1579 deallocate_file_lock(releasedfl); 1580 releasedfl = NULL; 1581 } 1582 } 1583 1584 } while (unlstatus == NFS_GRANTED); 1585 1586 if (selffl != NULL) { 1587 /* 1588 * This statement wipes out the incoming file lock (fl) 1589 * in spite of the fact that it is declared const 1590 */ 1591 debuglog("WARNING! Destroying incoming lock pointer\n"); 1592 deallocate_file_lock(selffl); 1593 } 1594 1595 debuglog("Exiting unlock_partialfilelock\n"); 1596 1597 return retval; 1598 } 1599 1600 /* 1601 * clear_partialfilelock 1602 * 1603 * Normally called in response to statd state number change. 1604 * Wipe out all locks held by a host. As a bonus, the act of 1605 * doing so should automatically clear their statd entries and 1606 * unmonitor the host. 1607 */ 1608 1609 void 1610 clear_partialfilelock(const char *hostname) 1611 { 1612 struct file_lock *ifl, *nfl; 1613 1614 /* Clear blocking file lock list */ 1615 clear_blockingfilelock(hostname); 1616 1617 /* do all required unlocks */ 1618 /* Note that unlock can smash the current pointer to a lock */ 1619 1620 /* 1621 * Normally, LIST_FOREACH is called for, but since 1622 * the current element *is* the iterator, deleting it 1623 * would mess up the iteration. Thus, a next element 1624 * must be used explicitly 1625 */ 1626 1627 ifl = LIST_FIRST(&nfslocklist_head); 1628 1629 while (ifl != NULL) { 1630 nfl = LIST_NEXT(ifl, nfslocklist); 1631 1632 if (strncmp(hostname, ifl->client_name, SM_MAXSTRLEN) == 0) { 1633 /* Unlock destroys ifl out from underneath */ 1634 unlock_partialfilelock(ifl); 1635 /* ifl is NO LONGER VALID AT THIS POINT */ 1636 } 1637 ifl = nfl; 1638 } 1639 } 1640 1641 /* 1642 * test_partialfilelock: 1643 */ 1644 enum partialfilelock_status 1645 test_partialfilelock(const struct file_lock *fl, 1646 struct file_lock **conflicting_fl) 1647 { 1648 enum partialfilelock_status retval; 1649 enum nfslock_status teststatus; 1650 1651 debuglog("Entering testpartialfilelock...\n"); 1652 1653 retval = PFL_DENIED; 1654 1655 teststatus = test_nfslock(fl, conflicting_fl); 1656 debuglog("test_partialfilelock: teststatus %d\n",teststatus); 1657 1658 if (teststatus == NFS_GRANTED || teststatus == NFS_GRANTED_DUPLICATE) { 1659 /* XXX: Add the underlying filesystem locking code */ 1660 retval = (teststatus == NFS_GRANTED) ? 1661 PFL_GRANTED : PFL_GRANTED_DUPLICATE; 1662 debuglog("Dumping locks...\n"); 1663 dump_filelock(fl); 1664 dump_filelock(*conflicting_fl); 1665 debuglog("Done dumping locks...\n"); 1666 } else { 1667 retval = PFL_NFSDENIED; 1668 debuglog("NFS test denied.\n"); 1669 dump_filelock(fl); 1670 debuglog("Conflicting.\n"); 1671 dump_filelock(*conflicting_fl); 1672 } 1673 1674 debuglog("Exiting testpartialfilelock...\n"); 1675 1676 return retval; 1677 } 1678 1679 /* 1680 * Below here are routines associated with translating the partial file locking 1681 * codes into useful codes to send back to the NFS RPC messaging system 1682 */ 1683 1684 /* 1685 * These routines translate the (relatively) useful return codes back onto 1686 * the few return codes which the nlm subsystems wishes to trasmit 1687 */ 1688 1689 enum nlm_stats 1690 do_test(struct file_lock *fl, struct file_lock **conflicting_fl) 1691 { 1692 enum partialfilelock_status pfsret; 1693 enum nlm_stats retval; 1694 1695 debuglog("Entering do_test...\n"); 1696 1697 pfsret = test_partialfilelock(fl,conflicting_fl); 1698 1699 switch (pfsret) { 1700 case PFL_GRANTED: 1701 debuglog("PFL test lock granted\n"); 1702 dump_filelock(fl); 1703 dump_filelock(*conflicting_fl); 1704 retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 1705 break; 1706 case PFL_GRANTED_DUPLICATE: 1707 debuglog("PFL test lock granted--duplicate id detected\n"); 1708 dump_filelock(fl); 1709 dump_filelock(*conflicting_fl); 1710 debuglog("Clearing conflicting_fl for call semantics\n"); 1711 *conflicting_fl = NULL; 1712 retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 1713 break; 1714 case PFL_NFSDENIED: 1715 case PFL_HWDENIED: 1716 debuglog("PFL test lock denied\n"); 1717 dump_filelock(fl); 1718 dump_filelock(*conflicting_fl); 1719 retval = (fl->flags & LOCK_V4) ? nlm4_denied : nlm_denied; 1720 break; 1721 case PFL_NFSRESERR: 1722 case PFL_HWRESERR: 1723 debuglog("PFL test lock resource fail\n"); 1724 dump_filelock(fl); 1725 dump_filelock(*conflicting_fl); 1726 retval = (fl->flags & LOCK_V4) ? nlm4_denied_nolocks : nlm_denied_nolocks; 1727 break; 1728 default: 1729 debuglog("PFL test lock *FAILED*\n"); 1730 dump_filelock(fl); 1731 dump_filelock(*conflicting_fl); 1732 retval = (fl->flags & LOCK_V4) ? nlm4_failed : nlm_denied; 1733 break; 1734 } 1735 1736 debuglog("Exiting do_test...\n"); 1737 1738 return retval; 1739 } 1740 1741 /* 1742 * do_lock: Try to acquire a lock 1743 * 1744 * This routine makes a distinction between NLM versions. I am pretty 1745 * convinced that this should be abstracted out and bounced up a level 1746 */ 1747 1748 enum nlm_stats 1749 do_lock(struct file_lock *fl) 1750 { 1751 enum partialfilelock_status pfsret; 1752 enum nlm_stats retval; 1753 1754 debuglog("Entering do_lock...\n"); 1755 1756 pfsret = lock_partialfilelock(fl); 1757 1758 switch (pfsret) { 1759 case PFL_GRANTED: 1760 debuglog("PFL lock granted"); 1761 dump_filelock(fl); 1762 retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 1763 break; 1764 case PFL_GRANTED_DUPLICATE: 1765 debuglog("PFL lock granted--duplicate id detected"); 1766 dump_filelock(fl); 1767 retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 1768 break; 1769 case PFL_NFSDENIED: 1770 case PFL_HWDENIED: 1771 debuglog("PFL_NFS lock denied"); 1772 dump_filelock(fl); 1773 retval = (fl->flags & LOCK_V4) ? nlm4_denied : nlm_denied; 1774 break; 1775 case PFL_NFSBLOCKED: 1776 case PFL_HWBLOCKED: 1777 debuglog("PFL_NFS blocking lock denied. Queued.\n"); 1778 dump_filelock(fl); 1779 retval = (fl->flags & LOCK_V4) ? nlm4_blocked : nlm_blocked; 1780 break; 1781 case PFL_NFSRESERR: 1782 case PFL_HWRESERR: 1783 debuglog("PFL lock resource alocation fail\n"); 1784 dump_filelock(fl); 1785 retval = (fl->flags & LOCK_V4) ? nlm4_denied_nolocks : nlm_denied_nolocks; 1786 break; 1787 default: 1788 debuglog("PFL lock *FAILED*"); 1789 dump_filelock(fl); 1790 retval = (fl->flags & LOCK_V4) ? nlm4_failed : nlm_denied; 1791 break; 1792 } 1793 1794 debuglog("Exiting do_lock...\n"); 1795 1796 return retval; 1797 } 1798 1799 enum nlm_stats 1800 do_unlock(struct file_lock *fl) 1801 { 1802 enum partialfilelock_status pfsret; 1803 enum nlm_stats retval; 1804 1805 debuglog("Entering do_unlock...\n"); 1806 pfsret = unlock_partialfilelock(fl); 1807 1808 switch (pfsret) { 1809 case PFL_GRANTED: 1810 debuglog("PFL unlock granted"); 1811 dump_filelock(fl); 1812 retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 1813 break; 1814 case PFL_NFSDENIED: 1815 case PFL_HWDENIED: 1816 debuglog("PFL_NFS unlock denied"); 1817 dump_filelock(fl); 1818 retval = (fl->flags & LOCK_V4) ? nlm4_denied : nlm_denied; 1819 break; 1820 case PFL_NFSDENIED_NOLOCK: 1821 case PFL_HWDENIED_NOLOCK: 1822 debuglog("PFL_NFS no lock found\n"); 1823 retval = (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted; 1824 break; 1825 case PFL_NFSRESERR: 1826 case PFL_HWRESERR: 1827 debuglog("PFL unlock resource failure"); 1828 dump_filelock(fl); 1829 retval = (fl->flags & LOCK_V4) ? nlm4_denied_nolocks : nlm_denied_nolocks; 1830 break; 1831 default: 1832 debuglog("PFL unlock *FAILED*"); 1833 dump_filelock(fl); 1834 retval = (fl->flags & LOCK_V4) ? nlm4_failed : nlm_denied; 1835 break; 1836 } 1837 1838 debuglog("Exiting do_unlock...\n"); 1839 1840 return retval; 1841 } 1842 1843 /* 1844 * do_clear 1845 * 1846 * This routine is non-existent because it doesn't have a return code. 1847 * It is here for completeness in case someone *does* need to do return 1848 * codes later. A decent compiler should optimize this away. 1849 */ 1850 1851 void 1852 do_clear(const char *hostname) 1853 { 1854 1855 clear_partialfilelock(hostname); 1856 } 1857 1858 /* 1859 * The following routines are all called from the code which the 1860 * RPC layer invokes 1861 */ 1862 1863 /* 1864 * testlock(): inform the caller if the requested lock would be granted 1865 * 1866 * returns NULL if lock would granted 1867 * returns pointer to a conflicting nlm4_holder if not 1868 */ 1869 1870 struct nlm4_holder * 1871 testlock(struct nlm4_lock *lock, bool_t exclusive, int flags __unused) 1872 { 1873 struct file_lock test_fl, *conflicting_fl; 1874 1875 bzero(&test_fl, sizeof(test_fl)); 1876 1877 bcopy(lock->fh.n_bytes, &(test_fl.filehandle), sizeof(fhandle_t)); 1878 copy_nlm4_lock_to_nlm4_holder(lock, exclusive, &test_fl.client); 1879 1880 siglock(); 1881 do_test(&test_fl, &conflicting_fl); 1882 1883 if (conflicting_fl == NULL) { 1884 debuglog("No conflicting lock found\n"); 1885 sigunlock(); 1886 return NULL; 1887 } else { 1888 debuglog("Found conflicting lock\n"); 1889 dump_filelock(conflicting_fl); 1890 sigunlock(); 1891 return (&conflicting_fl->client); 1892 } 1893 } 1894 1895 /* 1896 * getlock: try to acquire the lock. 1897 * If file is already locked and we can sleep, put the lock in the list with 1898 * status LKST_WAITING; it'll be processed later. 1899 * Otherwise try to lock. If we're allowed to block, fork a child which 1900 * will do the blocking lock. 1901 */ 1902 1903 enum nlm_stats 1904 getlock(nlm4_lockargs *lckarg, struct svc_req *rqstp, const int flags) 1905 { 1906 struct file_lock *newfl; 1907 enum nlm_stats retval; 1908 1909 debuglog("Entering getlock...\n"); 1910 1911 if (grace_expired == 0 && lckarg->reclaim == 0) 1912 return (flags & LOCK_V4) ? 1913 nlm4_denied_grace_period : nlm_denied_grace_period; 1914 1915 /* allocate new file_lock for this request */ 1916 newfl = allocate_file_lock(&lckarg->alock.oh, &lckarg->cookie, 1917 (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf, lckarg->alock.caller_name); 1918 if (newfl == NULL) { 1919 syslog(LOG_NOTICE, "lock allocate failed: %s", strerror(errno)); 1920 /* failed */ 1921 return (flags & LOCK_V4) ? 1922 nlm4_denied_nolocks : nlm_denied_nolocks; 1923 } 1924 1925 if (lckarg->alock.fh.n_len != sizeof(fhandle_t)) { 1926 debuglog("received fhandle size %d, local size %d", 1927 lckarg->alock.fh.n_len, (int)sizeof(fhandle_t)); 1928 } 1929 1930 fill_file_lock(newfl, (fhandle_t *)lckarg->alock.fh.n_bytes, 1931 lckarg->exclusive, lckarg->alock.svid, lckarg->alock.l_offset, 1932 lckarg->alock.l_len, 1933 lckarg->state, 0, flags, lckarg->block); 1934 1935 /* 1936 * newfl is now fully constructed and deallocate_file_lock 1937 * can now be used to delete it 1938 */ 1939 1940 siglock(); 1941 debuglog("Pointer to new lock is %p\n",newfl); 1942 1943 retval = do_lock(newfl); 1944 1945 debuglog("Pointer to new lock is %p\n",newfl); 1946 sigunlock(); 1947 1948 switch (retval) 1949 { 1950 case nlm4_granted: 1951 /* case nlm_granted: is the same as nlm4_granted */ 1952 /* do_mon(lckarg->alock.caller_name); */ 1953 break; 1954 case nlm4_blocked: 1955 /* case nlm_blocked: is the same as nlm4_blocked */ 1956 /* do_mon(lckarg->alock.caller_name); */ 1957 break; 1958 default: 1959 deallocate_file_lock(newfl); 1960 break; 1961 } 1962 1963 debuglog("Exiting getlock...\n"); 1964 1965 return retval; 1966 } 1967 1968 1969 /* unlock a filehandle */ 1970 enum nlm_stats 1971 unlock(nlm4_lock *lock, const int flags __unused) 1972 { 1973 struct file_lock fl; 1974 enum nlm_stats err; 1975 1976 siglock(); 1977 1978 debuglog("Entering unlock...\n"); 1979 1980 bzero(&fl,sizeof(struct file_lock)); 1981 bcopy(lock->fh.n_bytes, &fl.filehandle, sizeof(fhandle_t)); 1982 1983 copy_nlm4_lock_to_nlm4_holder(lock, 0, &fl.client); 1984 1985 err = do_unlock(&fl); 1986 1987 sigunlock(); 1988 1989 debuglog("Exiting unlock...\n"); 1990 1991 return err; 1992 } 1993 1994 /* 1995 * XXX: The following monitor/unmonitor routines 1996 * have not been extensively tested (ie. no regression 1997 * script exists like for the locking sections 1998 */ 1999 2000 /* 2001 * monitor_lock_host: monitor lock hosts locally with a ref count and 2002 * inform statd 2003 */ 2004 void 2005 monitor_lock_host(const char *hostname) 2006 { 2007 struct host *ihp, *nhp; 2008 struct mon smon; 2009 struct sm_stat_res sres; 2010 int rpcret, statflag; 2011 size_t n; 2012 2013 rpcret = 0; 2014 statflag = 0; 2015 2016 LIST_FOREACH(ihp, &hostlst_head, hostlst) { 2017 if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) { 2018 /* Host is already monitored, bump refcount */ 2019 ++ihp->refcnt; 2020 /* Host should only be in the monitor list once */ 2021 return; 2022 } 2023 } 2024 2025 /* Host is not yet monitored, add it */ 2026 n = strnlen(hostname, SM_MAXSTRLEN); 2027 if (n == SM_MAXSTRLEN) { 2028 return; 2029 } 2030 nhp = malloc(sizeof(*nhp) - sizeof(nhp->name) + n + 1); 2031 if (nhp == NULL) { 2032 debuglog("Unable to allocate entry for statd mon\n"); 2033 return; 2034 } 2035 2036 /* Allocated new host entry, now fill the fields */ 2037 memcpy(nhp->name, hostname, n); 2038 nhp->name[n] = 0; 2039 nhp->refcnt = 1; 2040 debuglog("Locally Monitoring host %16s\n",hostname); 2041 2042 debuglog("Attempting to tell statd\n"); 2043 2044 bzero(&smon,sizeof(smon)); 2045 2046 smon.mon_id.mon_name = nhp->name; 2047 smon.mon_id.my_id.my_name = "localhost"; 2048 smon.mon_id.my_id.my_prog = NLM_PROG; 2049 smon.mon_id.my_id.my_vers = NLM_SM; 2050 smon.mon_id.my_id.my_proc = NLM_SM_NOTIFY; 2051 2052 rpcret = callrpc("localhost", SM_PROG, SM_VERS, SM_MON, 2053 (xdrproc_t)xdr_mon, &smon, 2054 (xdrproc_t)xdr_sm_stat_res, &sres); 2055 2056 if (rpcret == 0) { 2057 if (sres.res_stat == stat_fail) { 2058 debuglog("Statd call failed\n"); 2059 statflag = 0; 2060 } else { 2061 statflag = 1; 2062 } 2063 } else { 2064 debuglog("Rpc call to statd failed with return value: %d\n", 2065 rpcret); 2066 statflag = 0; 2067 } 2068 2069 if (statflag == 1) { 2070 LIST_INSERT_HEAD(&hostlst_head, nhp, hostlst); 2071 } else { 2072 free(nhp); 2073 } 2074 2075 } 2076 2077 /* 2078 * unmonitor_lock_host: clear monitor ref counts and inform statd when gone 2079 */ 2080 void 2081 unmonitor_lock_host(char *hostname) 2082 { 2083 struct host *ihp; 2084 struct mon_id smon_id; 2085 struct sm_stat smstat; 2086 int rpcret; 2087 2088 rpcret = 0; 2089 2090 for( ihp=LIST_FIRST(&hostlst_head); ihp != NULL; 2091 ihp=LIST_NEXT(ihp, hostlst)) { 2092 if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) { 2093 /* Host is monitored, bump refcount */ 2094 --ihp->refcnt; 2095 /* Host should only be in the monitor list once */ 2096 break; 2097 } 2098 } 2099 2100 if (ihp == NULL) { 2101 debuglog("Could not find host %16s in mon list\n", hostname); 2102 return; 2103 } 2104 2105 if (ihp->refcnt > 0) 2106 return; 2107 2108 if (ihp->refcnt < 0) { 2109 debuglog("Negative refcount!: %d\n", 2110 ihp->refcnt); 2111 } 2112 2113 debuglog("Attempting to unmonitor host %16s\n", hostname); 2114 2115 bzero(&smon_id,sizeof(smon_id)); 2116 2117 smon_id.mon_name = hostname; 2118 smon_id.my_id.my_name = "localhost"; 2119 smon_id.my_id.my_prog = NLM_PROG; 2120 smon_id.my_id.my_vers = NLM_SM; 2121 smon_id.my_id.my_proc = NLM_SM_NOTIFY; 2122 2123 rpcret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON, 2124 (xdrproc_t)xdr_mon_id, &smon_id, 2125 (xdrproc_t)xdr_sm_stat, &smstat); 2126 2127 if (rpcret != 0) { 2128 debuglog("Rpc call to unmonitor statd failed with " 2129 " return value: %d\n", rpcret); 2130 } 2131 2132 LIST_REMOVE(ihp, hostlst); 2133 free(ihp); 2134 } 2135 2136 /* 2137 * notify: Clear all locks from a host if statd complains 2138 * 2139 * XXX: This routine has not been thoroughly tested. However, neither 2140 * had the old one been. It used to compare the statd crash state counter 2141 * to the current lock state. The upshot of this was that it basically 2142 * cleared all locks from the specified host 99% of the time (with the 2143 * other 1% being a bug). Consequently, the assumption is that clearing 2144 * all locks from a host when notified by statd is acceptable. 2145 * 2146 * Please note that this routine skips the usual level of redirection 2147 * through a do_* type routine. This introduces a possible level of 2148 * error and might better be written as do_notify and take this one out. 2149 2150 */ 2151 2152 void 2153 notify(const char *hostname, const int state) 2154 { 2155 debuglog("notify from %s, new state %d", hostname, state); 2156 2157 siglock(); 2158 do_clear(hostname); 2159 sigunlock(); 2160 2161 debuglog("Leaving notify\n"); 2162 } 2163 2164 void 2165 send_granted(struct file_lock *fl, int opcode __unused) 2166 { 2167 CLIENT *cli; 2168 static char dummy; 2169 struct timeval timeo; 2170 int success; 2171 static struct nlm_res retval; 2172 static struct nlm4_res retval4; 2173 2174 debuglog("About to send granted on blocked lock\n"); 2175 2176 cli = get_client(fl->addr, 2177 (fl->flags & LOCK_V4) ? NLM_VERS4 : NLM_VERS); 2178 if (cli == NULL) { 2179 syslog(LOG_NOTICE, "failed to get CLIENT for %s", 2180 fl->client_name); 2181 /* 2182 * We fail to notify remote that the lock has been granted. 2183 * The client will timeout and retry, the lock will be 2184 * granted at this time. 2185 */ 2186 return; 2187 } 2188 timeo.tv_sec = 0; 2189 timeo.tv_usec = (fl->flags & LOCK_ASYNC) ? 0 : 500000; /* 0.5s */ 2190 2191 if (fl->flags & LOCK_V4) { 2192 static nlm4_testargs res; 2193 res.cookie = fl->client_cookie; 2194 res.exclusive = fl->client.exclusive; 2195 res.alock.caller_name = fl->client_name; 2196 res.alock.fh.n_len = sizeof(fhandle_t); 2197 res.alock.fh.n_bytes = (char*)&fl->filehandle; 2198 res.alock.oh = fl->client.oh; 2199 res.alock.svid = fl->client.svid; 2200 res.alock.l_offset = fl->client.l_offset; 2201 res.alock.l_len = fl->client.l_len; 2202 debuglog("sending v4 reply%s", 2203 (fl->flags & LOCK_ASYNC) ? " (async)":""); 2204 if (fl->flags & LOCK_ASYNC) { 2205 success = clnt_call(cli, NLM4_GRANTED_MSG, 2206 (xdrproc_t)xdr_nlm4_testargs, &res, 2207 (xdrproc_t)xdr_void, &dummy, timeo); 2208 } else { 2209 success = clnt_call(cli, NLM4_GRANTED, 2210 (xdrproc_t)xdr_nlm4_testargs, &res, 2211 (xdrproc_t)xdr_nlm4_res, &retval4, timeo); 2212 } 2213 } else { 2214 static nlm_testargs res; 2215 2216 res.cookie = fl->client_cookie; 2217 res.exclusive = fl->client.exclusive; 2218 res.alock.caller_name = fl->client_name; 2219 res.alock.fh.n_len = sizeof(fhandle_t); 2220 res.alock.fh.n_bytes = (char*)&fl->filehandle; 2221 res.alock.oh = fl->client.oh; 2222 res.alock.svid = fl->client.svid; 2223 res.alock.l_offset = fl->client.l_offset; 2224 res.alock.l_len = fl->client.l_len; 2225 debuglog("sending v1 reply%s", 2226 (fl->flags & LOCK_ASYNC) ? " (async)":""); 2227 if (fl->flags & LOCK_ASYNC) { 2228 success = clnt_call(cli, NLM_GRANTED_MSG, 2229 (xdrproc_t)xdr_nlm_testargs, &res, 2230 (xdrproc_t)xdr_void, &dummy, timeo); 2231 } else { 2232 success = clnt_call(cli, NLM_GRANTED, 2233 (xdrproc_t)xdr_nlm_testargs, &res, 2234 (xdrproc_t)xdr_nlm_res, &retval, timeo); 2235 } 2236 } 2237 if (debug_level > 2) 2238 debuglog("clnt_call returns %d(%s) for granted", 2239 success, clnt_sperrno(success)); 2240 2241 } 2242 2243 /* 2244 * Routines below here have not been modified in the overhaul 2245 */ 2246 2247 /* 2248 * Are these two routines still required since lockd is not spawning off 2249 * children to service locks anymore? Presumably they were originally 2250 * put in place to prevent a one child from changing the lock list out 2251 * from under another one. 2252 */ 2253 2254 void 2255 siglock(void) 2256 { 2257 sigset_t block; 2258 2259 sigemptyset(&block); 2260 sigaddset(&block, SIGCHLD); 2261 2262 if (sigprocmask(SIG_BLOCK, &block, NULL) < 0) { 2263 syslog(LOG_WARNING, "siglock failed: %s", strerror(errno)); 2264 } 2265 } 2266 2267 void 2268 sigunlock(void) 2269 { 2270 sigset_t block; 2271 2272 sigemptyset(&block); 2273 sigaddset(&block, SIGCHLD); 2274 2275 if (sigprocmask(SIG_UNBLOCK, &block, NULL) < 0) { 2276 syslog(LOG_WARNING, "sigunlock failed: %s", strerror(errno)); 2277 } 2278 } 2279