1/* 2 Unix SMB/CIFS implementation. 3 byte range locking code 4 Updated to handle range splits/merges. 5 6 Copyright (C) Andrew Tridgell 1992-2000 7 Copyright (C) Jeremy Allison 1992-2000 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22*/ 23 24/* This module implements a tdb based byte range locking service, 25 replacing the fcntl() based byte range locking previously 26 used. This allows us to provide the same semantics as NT */ 27 28#include "includes.h" 29 30#define ZERO_ZERO 0 31 32/* This contains elements that differentiate locks. The smbpid is a 33 client supplied pid, and is essentially the locking context for 34 this client */ 35 36struct lock_context { 37 uint16 smbpid; 38 uint16 tid; 39 pid_t pid; 40}; 41 42/* The data in brlock records is an unsorted linear array of these 43 records. It is unnecessary to store the count as tdb provides the 44 size of the record */ 45 46struct lock_struct { 47 struct lock_context context; 48 br_off start; 49 br_off size; 50 int fnum; 51 enum brl_type lock_type; 52}; 53 54/* The key used in the brlock database. */ 55 56struct lock_key { 57 SMB_DEV_T device; 58 SMB_INO_T inode; 59}; 60 61/* The open brlock.tdb database. */ 62 63static TDB_CONTEXT *tdb; 64 65/**************************************************************************** 66 Create a locking key - ensuring zero filled for pad purposes. 67****************************************************************************/ 68 69static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode) 70{ 71 static struct lock_key key; 72 TDB_DATA kbuf; 73 74 memset(&key, '\0', sizeof(key)); 75 key.device = dev; 76 key.inode = inode; 77 kbuf.dptr = (char *)&key; 78 kbuf.dsize = sizeof(key); 79 return kbuf; 80} 81 82/**************************************************************************** 83 See if two locking contexts are equal. 84****************************************************************************/ 85 86static BOOL brl_same_context(struct lock_context *ctx1, 87 struct lock_context *ctx2) 88{ 89 return (ctx1->pid == ctx2->pid) && 90 (ctx1->smbpid == ctx2->smbpid) && 91 (ctx1->tid == ctx2->tid); 92} 93 94/**************************************************************************** 95 See if lck1 and lck2 overlap. 96****************************************************************************/ 97 98static BOOL brl_overlap(struct lock_struct *lck1, 99 struct lock_struct *lck2) 100{ 101 /* this extra check is not redundent - it copes with locks 102 that go beyond the end of 64 bit file space */ 103 if (lck1->size != 0 && 104 lck1->start == lck2->start && 105 lck1->size == lck2->size) { 106 return True; 107 } 108 109 if (lck1->start >= (lck2->start+lck2->size) || 110 lck2->start >= (lck1->start+lck1->size)) { 111 return False; 112 } 113 return True; 114} 115 116/**************************************************************************** 117 See if lock2 can be added when lock1 is in place. 118****************************************************************************/ 119 120static BOOL brl_conflict(struct lock_struct *lck1, 121 struct lock_struct *lck2) 122{ 123 if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK ) 124 return False; 125 126 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) { 127 return False; 128 } 129 130 if (brl_same_context(&lck1->context, &lck2->context) && 131 lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) { 132 return False; 133 } 134 135 return brl_overlap(lck1, lck2); 136} 137 138#if ZERO_ZERO 139static BOOL brl_conflict1(struct lock_struct *lck1, 140 struct lock_struct *lck2) 141{ 142 if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK ) 143 return False; 144 145 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) { 146 return False; 147 } 148 149 if (brl_same_context(&lck1->context, &lck2->context) && 150 lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) { 151 return False; 152 } 153 154 if (lck2->start == 0 && lck2->size == 0 && lck1->size != 0) { 155 return True; 156 } 157 158 if (lck1->start >= (lck2->start + lck2->size) || 159 lck2->start >= (lck1->start + lck1->size)) { 160 return False; 161 } 162 163 return True; 164} 165#endif 166 167/**************************************************************************** 168 Check to see if this lock conflicts, but ignore our own locks on the 169 same fnum only. 170****************************************************************************/ 171 172static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck2) 173{ 174 if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK ) 175 return False; 176 177 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) 178 return False; 179 180 /* 181 * Incoming WRITE locks conflict with existing READ locks even 182 * if the context is the same. JRA. See LOCKTEST7 in smbtorture. 183 */ 184 185 if (!(lck2->lock_type == WRITE_LOCK && lck1->lock_type == READ_LOCK)) { 186 if (brl_same_context(&lck1->context, &lck2->context) && 187 lck1->fnum == lck2->fnum) 188 return False; 189 } 190 191 return brl_overlap(lck1, lck2); 192} 193 194/**************************************************************************** 195 Amazingly enough, w2k3 "remembers" whether the last lock failure 196 is the same as this one and changes its error code. I wonder if any 197 app depends on this ? 198****************************************************************************/ 199 200static NTSTATUS brl_lock_failed(struct lock_struct *lock) 201{ 202 static struct lock_struct last_lock_failure; 203 204 if (brl_same_context(&lock->context, &last_lock_failure.context) && 205 lock->fnum == last_lock_failure.fnum && 206 lock->start == last_lock_failure.start && 207 lock->size == last_lock_failure.size) { 208 return NT_STATUS_FILE_LOCK_CONFLICT; 209 } 210 last_lock_failure = *lock; 211 if (lock->start >= 0xEF000000 && 212 (lock->start >> 63) == 0) { 213 /* amazing the little things you learn with a test 214 suite. Locks beyond this offset (as a 64 bit 215 number!) always generate the conflict error code, 216 unless the top bit is set */ 217 return NT_STATUS_FILE_LOCK_CONFLICT; 218 } 219 return NT_STATUS_LOCK_NOT_GRANTED; 220} 221 222#if DONT_DO_THIS 223 /* doing this traversal could kill solaris machines under high load (tridge) */ 224 /* delete any dead locks */ 225 226/**************************************************************************** 227 Delete a record if it is for a dead process, if check_self is true, then 228 delete any records belonging to this pid also (there shouldn't be any). 229****************************************************************************/ 230 231static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state) 232{ 233 struct lock_struct *locks; 234 int count, i; 235 BOOL check_self = *(BOOL *)state; 236 pid_t mypid = sys_getpid(); 237 238 tdb_chainlock(tdb, kbuf); 239 240 locks = (struct lock_struct *)dbuf.dptr; 241 242 count = dbuf.dsize / sizeof(*locks); 243 for (i=0; i<count; i++) { 244 struct lock_struct *lock = &locks[i]; 245 246 /* If check_self is true we want to remove our own records. */ 247 if (check_self && (mypid == lock->context.pid)) { 248 249 DEBUG(0,("brlock : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n", 250 (unsigned int)lock->context.pid )); 251 252 } else if (process_exists(lock->context.pid)) { 253 254 DEBUG(10,("brlock : delete_fn. pid %u exists.\n", (unsigned int)lock->context.pid )); 255 continue; 256 } 257 258 DEBUG(10,("brlock : delete_fn. Deleting record for process %u\n", 259 (unsigned int)lock->context.pid )); 260 261 if (count > 1 && i < count-1) { 262 memmove(&locks[i], &locks[i+1], 263 sizeof(*locks)*((count-1) - i)); 264 } 265 count--; 266 i--; 267 } 268 269 if (count == 0) { 270 tdb_delete(tdb, kbuf); 271 } else if (count < (dbuf.dsize / sizeof(*locks))) { 272 dbuf.dsize = count * sizeof(*locks); 273 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); 274 } 275 276 tdb_chainunlock(tdb, kbuf); 277 return 0; 278} 279#endif 280 281/**************************************************************************** 282 Open up the brlock.tdb database. 283****************************************************************************/ 284 285void brl_init(int read_only) 286{ 287 if (tdb) 288 return; 289 tdb = tdb_open_log(lock_path("brlock.tdb"), 0, TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST), 290 read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644 ); 291 if (!tdb) { 292 DEBUG(0,("Failed to open byte range locking database\n")); 293 return; 294 } 295 296#if DONT_DO_THIS 297 /* doing this traversal could kill solaris machines under high load (tridge) */ 298 /* delete any dead locks */ 299 if (!read_only) { 300 BOOL check_self = False; 301 tdb_traverse(tdb, delete_fn, &check_self); 302 } 303#endif 304} 305 306/**************************************************************************** 307 Close down the brlock.tdb database. 308****************************************************************************/ 309 310void brl_shutdown(int read_only) 311{ 312 if (!tdb) 313 return; 314 315#if DONT_DO_THIS 316 /* doing this traversal could kill solaris machines under high load (tridge) */ 317 /* delete any dead locks */ 318 if (!read_only) { 319 BOOL check_self = True; 320 tdb_traverse(tdb, delete_fn, &check_self); 321 } 322#endif 323 324 tdb_close(tdb); 325} 326 327#if ZERO_ZERO 328/**************************************************************************** 329compare two locks for sorting 330****************************************************************************/ 331static int lock_compare(struct lock_struct *lck1, 332 struct lock_struct *lck2) 333{ 334 if (lck1->start != lck2->start) return (lck1->start - lck2->start); 335 if (lck2->size != lck1->size) { 336 return ((int)lck1->size - (int)lck2->size); 337 } 338 return 0; 339} 340#endif 341 342/**************************************************************************** 343 Lock a range of bytes. 344****************************************************************************/ 345 346NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum, 347 uint16 smbpid, pid_t pid, uint16 tid, 348 br_off start, br_off size, 349 enum brl_type lock_type, BOOL *my_lock_ctx) 350{ 351 TDB_DATA kbuf, dbuf; 352 int count, i; 353 struct lock_struct lock, *locks; 354 char *tp; 355 NTSTATUS status = NT_STATUS_OK; 356 357 *my_lock_ctx = False; 358 kbuf = locking_key(dev,ino); 359 360 dbuf.dptr = NULL; 361 362#if !ZERO_ZERO 363 if (start == 0 && size == 0) { 364 DEBUG(0,("client sent 0/0 lock - please report this\n")); 365 } 366#endif 367 368 tdb_chainlock(tdb, kbuf); 369 dbuf = tdb_fetch(tdb, kbuf); 370 371 lock.context.smbpid = smbpid; 372 lock.context.pid = pid; 373 lock.context.tid = tid; 374 lock.start = start; 375 lock.size = size; 376 lock.fnum = fnum; 377 lock.lock_type = lock_type; 378 379 if (dbuf.dptr) { 380 /* there are existing locks - make sure they don't conflict */ 381 locks = (struct lock_struct *)dbuf.dptr; 382 count = dbuf.dsize / sizeof(*locks); 383 for (i=0; i<count; i++) { 384 if (brl_conflict(&locks[i], &lock)) { 385 status = brl_lock_failed(&lock);; 386 /* Did we block ourselves ? */ 387 if (brl_same_context(&locks[i].context, &lock.context)) 388 *my_lock_ctx = True; 389 goto fail; 390 } 391#if ZERO_ZERO 392 if (lock.start == 0 && lock.size == 0 && 393 locks[i].size == 0) { 394 break; 395 } 396#endif 397 } 398 } 399 400 /* no conflicts - add it to the list of locks */ 401 tp = SMB_REALLOC(dbuf.dptr, dbuf.dsize + sizeof(*locks)); 402 if (!tp) { 403 status = NT_STATUS_NO_MEMORY; 404 goto fail; 405 } else { 406 dbuf.dptr = tp; 407 } 408 memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock)); 409 dbuf.dsize += sizeof(lock); 410 411#if ZERO_ZERO 412 /* sort the lock list */ 413 qsort(dbuf.dptr, dbuf.dsize/sizeof(lock), sizeof(lock), lock_compare); 414#endif 415 416 if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) { 417 status = NT_STATUS_INTERNAL_DB_CORRUPTION; 418 goto fail; 419 } 420 421 SAFE_FREE(dbuf.dptr); 422 tdb_chainunlock(tdb, kbuf); 423 return NT_STATUS_OK; 424 425 fail: 426 427 SAFE_FREE(dbuf.dptr); 428 tdb_chainunlock(tdb, kbuf); 429 return status; 430} 431 432/**************************************************************************** 433 Check if an unlock overlaps a pending lock. 434****************************************************************************/ 435 436static BOOL brl_pending_overlap(struct lock_struct *lock, struct lock_struct *pend_lock) 437{ 438 if ((lock->start <= pend_lock->start) && (lock->start + lock->size > pend_lock->start)) 439 return True; 440 if ((lock->start >= pend_lock->start) && (lock->start <= pend_lock->start + pend_lock->size)) 441 return True; 442 return False; 443} 444 445/**************************************************************************** 446 Unlock a range of bytes. 447****************************************************************************/ 448 449BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum, 450 uint16 smbpid, pid_t pid, uint16 tid, 451 br_off start, br_off size, 452 BOOL remove_pending_locks_only, 453 void (*pre_unlock_fn)(void *), 454 void *pre_unlock_data) 455{ 456 TDB_DATA kbuf, dbuf; 457 int count, i, j; 458 struct lock_struct *locks; 459 struct lock_context context; 460 461 kbuf = locking_key(dev,ino); 462 463 dbuf.dptr = NULL; 464 465 tdb_chainlock(tdb, kbuf); 466 dbuf = tdb_fetch(tdb, kbuf); 467 468 if (!dbuf.dptr) { 469 DEBUG(10,("brl_unlock: tdb_fetch failed !\n")); 470 goto fail; 471 } 472 473 context.smbpid = smbpid; 474 context.pid = pid; 475 context.tid = tid; 476 477 /* there are existing locks - find a match */ 478 locks = (struct lock_struct *)dbuf.dptr; 479 count = dbuf.dsize / sizeof(*locks); 480 481#if ZERO_ZERO 482 for (i=0; i<count; i++) { 483 struct lock_struct *lock = &locks[i]; 484 485 if (lock->lock_type == WRITE_LOCK && 486 brl_same_context(&lock->context, &context) && 487 lock->fnum == fnum && 488 lock->start == start && 489 lock->size == size) { 490 491 if (pre_unlock_fn) 492 (*pre_unlock_fn)(pre_unlock_data); 493 494 /* found it - delete it */ 495 if (count == 1) { 496 tdb_delete(tdb, kbuf); 497 } else { 498 if (i < count-1) { 499 memmove(&locks[i], &locks[i+1], 500 sizeof(*locks)*((count-1) - i)); 501 } 502 dbuf.dsize -= sizeof(*locks); 503 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); 504 } 505 506 SAFE_FREE(dbuf.dptr); 507 tdb_chainunlock(tdb, kbuf); 508 return True; 509 } 510 } 511#endif 512 513 locks = (struct lock_struct *)dbuf.dptr; 514 count = dbuf.dsize / sizeof(*locks); 515 for (i=0; i<count; i++) { 516 struct lock_struct *lock = &locks[i]; 517 518 if (brl_same_context(&lock->context, &context) && 519 lock->fnum == fnum && 520 lock->start == start && 521 lock->size == size) { 522 523 if (remove_pending_locks_only && lock->lock_type != PENDING_LOCK) 524 continue; 525 526 if (lock->lock_type != PENDING_LOCK) { 527 528 /* Do any POSIX unlocks needed. */ 529 if (pre_unlock_fn) 530 (*pre_unlock_fn)(pre_unlock_data); 531 532 /* Send unlock messages to any pending waiters that overlap. */ 533 for (j=0; j<count; j++) { 534 struct lock_struct *pend_lock = &locks[j]; 535 536 /* Ignore non-pending locks. */ 537 if (pend_lock->lock_type != PENDING_LOCK) 538 continue; 539 540 /* We could send specific lock info here... */ 541 if (brl_pending_overlap(lock, pend_lock)) { 542 DEBUG(10,("brl_unlock: sending unlock message to pid %u\n", 543 (unsigned int)pend_lock->context.pid )); 544 545 message_send_pid(pend_lock->context.pid, 546 MSG_SMB_UNLOCK, 547 NULL, 0, True); 548 } 549 } 550 } 551 552 /* found it - delete it */ 553 if (count == 1) { 554 tdb_delete(tdb, kbuf); 555 } else { 556 if (i < count-1) { 557 memmove(&locks[i], &locks[i+1], 558 sizeof(*locks)*((count-1) - i)); 559 } 560 dbuf.dsize -= sizeof(*locks); 561 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); 562 } 563 564 SAFE_FREE(dbuf.dptr); 565 tdb_chainunlock(tdb, kbuf); 566 return True; 567 } 568 } 569 570 /* we didn't find it */ 571 572 fail: 573 SAFE_FREE(dbuf.dptr); 574 tdb_chainunlock(tdb, kbuf); 575 return False; 576} 577 578 579/**************************************************************************** 580 Test if we could add a lock if we wanted to. 581****************************************************************************/ 582 583BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum, 584 uint16 smbpid, pid_t pid, uint16 tid, 585 br_off start, br_off size, 586 enum brl_type lock_type) 587{ 588 TDB_DATA kbuf, dbuf; 589 int count, i; 590 struct lock_struct lock, *locks; 591 592 kbuf = locking_key(dev,ino); 593 594 dbuf.dptr = NULL; 595 596 dbuf = tdb_fetch(tdb, kbuf); 597 598 lock.context.smbpid = smbpid; 599 lock.context.pid = pid; 600 lock.context.tid = tid; 601 lock.start = start; 602 lock.size = size; 603 lock.fnum = fnum; 604 lock.lock_type = lock_type; 605 606 if (dbuf.dptr) { 607 /* there are existing locks - make sure they don't conflict */ 608 locks = (struct lock_struct *)dbuf.dptr; 609 count = dbuf.dsize / sizeof(*locks); 610 for (i=0; i<count; i++) { 611 /* 612 * Our own locks don't conflict. 613 */ 614 if (brl_conflict_other(&locks[i], &lock)) 615 goto fail; 616 } 617 } 618 619 /* no conflicts - we could have added it */ 620 SAFE_FREE(dbuf.dptr); 621 return True; 622 623 fail: 624 SAFE_FREE(dbuf.dptr); 625 return False; 626} 627 628/**************************************************************************** 629 Remove any locks associated with a open file. 630****************************************************************************/ 631 632void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum) 633{ 634 TDB_DATA kbuf, dbuf; 635 int count, i, j, dcount=0; 636 struct lock_struct *locks; 637 638 kbuf = locking_key(dev,ino); 639 640 dbuf.dptr = NULL; 641 642 tdb_chainlock(tdb, kbuf); 643 dbuf = tdb_fetch(tdb, kbuf); 644 645 if (!dbuf.dptr) goto fail; 646 647 /* there are existing locks - remove any for this fnum */ 648 locks = (struct lock_struct *)dbuf.dptr; 649 count = dbuf.dsize / sizeof(*locks); 650 651 for (i=0; i<count; i++) { 652 struct lock_struct *lock = &locks[i]; 653 654 if (lock->context.tid == tid && 655 lock->context.pid == pid && 656 lock->fnum == fnum) { 657 658 /* Send unlock messages to any pending waiters that overlap. */ 659 for (j=0; j<count; j++) { 660 struct lock_struct *pend_lock = &locks[j]; 661 662 /* Ignore our own or non-pending locks. */ 663 if (pend_lock->lock_type != PENDING_LOCK) 664 continue; 665 666 if (pend_lock->context.tid == tid && 667 pend_lock->context.pid == pid && 668 pend_lock->fnum == fnum) 669 continue; 670 671 /* We could send specific lock info here... */ 672 if (brl_pending_overlap(lock, pend_lock)) 673 message_send_pid(pend_lock->context.pid, 674 MSG_SMB_UNLOCK, 675 NULL, 0, True); 676 } 677 678 /* found it - delete it */ 679 if (count > 1 && i < count-1) { 680 memmove(&locks[i], &locks[i+1], 681 sizeof(*locks)*((count-1) - i)); 682 } 683 count--; 684 i--; 685 dcount++; 686 } 687 } 688 689 if (count == 0) { 690 tdb_delete(tdb, kbuf); 691 } else if (count < (dbuf.dsize / sizeof(*locks))) { 692 dbuf.dsize -= dcount * sizeof(*locks); 693 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); 694 } 695 696 /* we didn't find it */ 697 fail: 698 SAFE_FREE(dbuf.dptr); 699 tdb_chainunlock(tdb, kbuf); 700} 701 702/**************************************************************************** 703 Traverse the whole database with this function, calling traverse_callback 704 on each lock. 705****************************************************************************/ 706 707static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state) 708{ 709 struct lock_struct *locks; 710 struct lock_key *key; 711 int i; 712 713 BRLOCK_FN(traverse_callback) = (BRLOCK_FN_CAST())state; 714 715 locks = (struct lock_struct *)dbuf.dptr; 716 key = (struct lock_key *)kbuf.dptr; 717 718 for (i=0;i<dbuf.dsize/sizeof(*locks);i++) { 719 traverse_callback(key->device, key->inode, 720 locks[i].context.pid, 721 locks[i].lock_type, 722 locks[i].start, 723 locks[i].size); 724 } 725 return 0; 726} 727 728/******************************************************************* 729 Call the specified function on each lock in the database. 730********************************************************************/ 731 732int brl_forall(BRLOCK_FN(fn)) 733{ 734 if (!tdb) return 0; 735 return tdb_traverse(tdb, traverse_fn, (void *)fn); 736} 737