Changeset 745 for trunk/server/lib/tdb/common/open.c
- Timestamp:
- Nov 27, 2012, 4:43:17 PM (13 years ago)
- Location:
- trunk/server
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/server
- Property svn:mergeinfo changed
/vendor/current merged: 581,587,591,594,597,600,615,618,740
- Property svn:mergeinfo changed
-
trunk/server/lib/tdb/common/open.c
r456 r745 7 7 Copyright (C) Paul `Rusty' Russell 2000 8 8 Copyright (C) Jeremy Allison 2000-2003 9 9 10 10 ** NOTE! The following LGPL license applies to the tdb 11 11 ** library. This does NOT imply that all of Samba is released 12 12 ** under the LGPL 13 13 14 14 This library is free software; you can redistribute it and/or 15 15 modify it under the terms of the GNU Lesser General Public … … 36 36 static struct tdb_context *tdbs = NULL; 37 37 38 39 /* This is based on the hash algorithm from gdbm */ 40 static unsigned int default_tdb_hash(TDB_DATA *key) 41 { 42 uint32_t value; /* Used to compute the hash value. */ 43 uint32_t i; /* Used to cycle through random values. */ 44 45 /* Set the initial value from the key size. */ 46 for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++) 47 value = (value + (key->dptr[i] << (i*5 % 24))); 48 49 return (1103515243 * value + 12345); 50 } 51 38 /* We use two hashes to double-check they're using the right hash function. */ 39 void tdb_header_hash(struct tdb_context *tdb, 40 uint32_t *magic1_hash, uint32_t *magic2_hash) 41 { 42 TDB_DATA hash_key; 43 uint32_t tdb_magic = TDB_MAGIC; 44 45 hash_key.dptr = discard_const_p(unsigned char, TDB_MAGIC_FOOD); 46 hash_key.dsize = sizeof(TDB_MAGIC_FOOD); 47 *magic1_hash = tdb->hash_fn(&hash_key); 48 49 hash_key.dptr = (unsigned char *)CONVERT(tdb_magic); 50 hash_key.dsize = sizeof(tdb_magic); 51 *magic2_hash = tdb->hash_fn(&hash_key); 52 53 /* Make sure at least one hash is non-zero! */ 54 if (*magic1_hash == 0 && *magic2_hash == 0) 55 *magic1_hash = 1; 56 } 52 57 53 58 /* initialise a new database with a specified hash size */ … … 57 62 size_t size; 58 63 int ret = -1; 59 ssize_t written;60 64 61 65 /* We make it up in memory, then write it out if not internal */ … … 69 73 newdb->version = TDB_VERSION; 70 74 newdb->hash_size = hash_size; 75 76 tdb_header_hash(tdb, &newdb->magic1_hash, &newdb->magic2_hash); 77 78 /* Make sure older tdbs (which don't check the magic hash fields) 79 * will refuse to open this TDB. */ 80 if (tdb->flags & TDB_INCOMPATIBLE_HASH) 81 newdb->rwlocks = TDB_HASH_RWLOCK_MAGIC; 82 71 83 if (tdb->flags & TDB_INTERNAL) { 72 84 tdb->map_size = size; … … 89 101 memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1); 90 102 /* we still have "ret == -1" here */ 91 written = write(tdb->fd, newdb, size); 92 if (written == size) { 103 if (tdb_write_all(tdb->fd, newdb, size)) 93 104 ret = 0; 94 } else if (written != -1) {95 /* call write once again, this usually should return -1 and96 * set errno appropriately */97 size -= written;98 written = write(tdb->fd, newdb+written, size);99 if (written == size) {100 ret = 0;101 } else if (written >= 0) {102 /* a second incomplete write - we give up.103 * guessing the errno... */104 errno = ENOSPC;105 }106 }107 105 108 106 fail: … … 117 115 { 118 116 struct tdb_context *i; 119 117 120 118 for (i = tdbs; i; i = i->next) { 121 119 if (i->device == device && i->inode == ino) { … … 137 135 138 136 @param name may be NULL for internal databases. */ 139 struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,137 _PUBLIC_ struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags, 140 138 int open_flags, mode_t mode) 141 139 { … … 149 147 } 150 148 151 152 struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, 149 static bool check_header_hash(struct tdb_context *tdb, 150 bool default_hash, uint32_t *m1, uint32_t *m2) 151 { 152 tdb_header_hash(tdb, m1, m2); 153 if (tdb->header.magic1_hash == *m1 && 154 tdb->header.magic2_hash == *m2) { 155 return true; 156 } 157 158 /* If they explicitly set a hash, always respect it. */ 159 if (!default_hash) 160 return false; 161 162 /* Otherwise, try the other inbuilt hash. */ 163 if (tdb->hash_fn == tdb_old_hash) 164 tdb->hash_fn = tdb_jenkins_hash; 165 else 166 tdb->hash_fn = tdb_old_hash; 167 return check_header_hash(tdb, false, m1, m2); 168 } 169 170 _PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, 153 171 int open_flags, mode_t mode, 154 172 const struct tdb_logging_context *log_ctx, … … 161 179 uint32_t vertest; 162 180 unsigned v; 181 const char *hash_alg; 182 uint32_t magic1, magic2; 163 183 164 184 if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) { … … 182 202 tdb->log.log_private = NULL; 183 203 } 184 tdb->hash_fn = hash_fn ? hash_fn : default_tdb_hash; 204 205 if (name == NULL && (tdb_flags & TDB_INTERNAL)) { 206 name = "__TDB_INTERNAL__"; 207 } 208 209 if (name == NULL) { 210 tdb->name = discard_const_p(char, "__NULL__"); 211 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: called with name == NULL\n")); 212 tdb->name = NULL; 213 errno = EINVAL; 214 goto fail; 215 } 216 217 /* now make a copy of the name, as the caller memory might went away */ 218 if (!(tdb->name = (char *)strdup(name))) { 219 /* 220 * set the name as the given string, so that tdb_name() will 221 * work in case of an error. 222 */ 223 tdb->name = discard_const_p(char, name); 224 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't strdup(%s)\n", 225 name)); 226 tdb->name = NULL; 227 errno = ENOMEM; 228 goto fail; 229 } 230 231 if (hash_fn) { 232 tdb->hash_fn = hash_fn; 233 hash_alg = "the user defined"; 234 } else { 235 /* This controls what we use when creating a tdb. */ 236 if (tdb->flags & TDB_INCOMPATIBLE_HASH) { 237 tdb->hash_fn = tdb_jenkins_hash; 238 } else { 239 tdb->hash_fn = tdb_old_hash; 240 } 241 hash_alg = "either default"; 242 } 185 243 186 244 #ifdef __OS2__ … … 189 247 } 190 248 #endif 191 192 249 /* cache the page size */ 193 250 tdb->page_size = getpagesize(); … … 204 261 goto fail; 205 262 } 206 263 207 264 if (hash_size == 0) 208 265 hash_size = DEFAULT_HASH_SIZE; … … 223 280 } 224 281 282 if (getenv("TDB_NO_FSYNC")) { 283 tdb->flags |= TDB_NOSYNC; 284 } 285 225 286 /* 226 287 * TDB_ALLOW_NESTING is the default behavior. … … 253 314 254 315 /* ensure there is only one process initialising at once */ 255 if (tdb ->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {256 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get globallock on %s: %s\n",316 if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) { 317 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get open lock on %s: %s\n", 257 318 name, strerror(errno))); 258 319 goto fail; /* errno set by tdb_brlock */ … … 261 322 /* we need to zero database if we are the only one with it open */ 262 323 if ((tdb_flags & TDB_CLEAR_IF_FIRST) && 263 (!tdb->read_only)264 324 #ifndef __OS2__ 265 && (locked = (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0, 1) == 0)) 266 #endif 267 ) { 325 (!tdb->read_only) && 326 (locked = (tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE) == 0))) { 327 #else 328 (!tdb->read_only) ) { 329 #endif 268 330 open_flags |= O_CREAT; 269 331 if (ftruncate(tdb->fd, 0) == -1) { … … 304 366 goto fail; 305 367 306 if (tdb->header.rwlocks != 0) { 368 if (tdb->header.rwlocks != 0 && 369 tdb->header.rwlocks != TDB_HASH_RWLOCK_MAGIC) { 307 370 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n")); 371 goto fail; 372 } 373 374 if ((tdb->header.magic1_hash == 0) && (tdb->header.magic2_hash == 0)) { 375 /* older TDB without magic hash references */ 376 tdb->hash_fn = tdb_old_hash; 377 } else if (!check_header_hash(tdb, !hash_fn, &magic1, &magic2)) { 378 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: " 379 "%s was not created with %s hash function we are using\n" 380 "magic1_hash[0x%08X %s 0x%08X] " 381 "magic2_hash[0x%08X %s 0x%08X]\n", 382 name, hash_alg, 383 tdb->header.magic1_hash, 384 (tdb->header.magic1_hash == magic1) ? "==" : "!=", 385 magic1, 386 tdb->header.magic2_hash, 387 (tdb->header.magic2_hash == magic2) ? "==" : "!=", 388 magic2)); 389 errno = EINVAL; 308 390 goto fail; 309 391 } … … 318 400 } 319 401 320 if (!(tdb->name = (char *)strdup(name))) {321 errno = ENOMEM;322 goto fail;323 }324 325 402 tdb->map_size = st.st_size; 326 403 tdb->device = st.st_dev; … … 329 406 if (locked) { 330 407 #ifndef __OS2__ 331 if (tdb ->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0, 1) == -1) {408 if (tdb_nest_unlock(tdb, ACTIVE_LOCK, F_WRLCK, false) == -1) { 332 409 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: " 333 "failed to take ACTIVE_LOCK on %s: %s\n",410 "failed to release ACTIVE_LOCK on %s: %s\n", 334 411 name, strerror(errno))); 335 412 goto fail; 336 413 } 337 338 414 #endif 339 415 } … … 346 422 if (tdb_flags & TDB_CLEAR_IF_FIRST) { 347 423 /* leave this lock in place to indicate it's in use */ 348 if (tdb ->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)424 if (tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) { 349 425 goto fail; 426 } 350 427 } 351 428 #endif … … 358 435 #ifdef __OS2__ 359 436 // YD internal databases do not get global lock! 360 if (tdb ->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1) == -1)437 if (tdb_nest_unlock(tdb, OPEN_LOCK, F_WRLCK, false) == -1) 361 438 goto fail; 362 439 #endif … … 381 458 /* Internal (memory-only) databases skip all the code above to 382 459 * do with disk files, and resume here by releasing their 383 * globallock and hooking into the active list. */460 * open lock and hooking into the active list. */ 384 461 #ifndef __OS2__ 385 if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1) == -1) 386 goto fail; 462 if (tdb_nest_unlock(tdb, OPEN_LOCK, F_WRLCK, false) == -1) { 463 goto fail; 464 } 387 465 #endif 388 466 tdb->next = tdbs; 389 467 tdbs = tdb; 390 468 return tdb; 391 469 … … 405 483 tdb_munmap(tdb); 406 484 } 407 SAFE_FREE(tdb->name); 485 if (tdb->fd != -1) 486 if (close(tdb->fd) != 0) 487 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n")); 408 488 #ifdef __OS2__ 409 489 DosCloseMutexSem( tdb->hGlobalLock); … … 414 494 tdb->hTransactionLock = 0; 415 495 #endif 416 if (tdb->fd != -1) 417 if (close(tdb->fd) != 0) 418 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n")); 496 SAFE_FREE(tdb->lockrecs); 497 SAFE_FREE(tdb->name); 419 498 SAFE_FREE(tdb); 420 499 errno = save_errno; … … 427 506 */ 428 507 429 void tdb_set_max_dead(struct tdb_context *tdb, int max_dead)508 _PUBLIC_ void tdb_set_max_dead(struct tdb_context *tdb, int max_dead) 430 509 { 431 510 tdb->max_dead_records = max_dead; … … 437 516 * @returns -1 for error; 0 for success. 438 517 **/ 439 int tdb_close(struct tdb_context *tdb)518 _PUBLIC_ int tdb_close(struct tdb_context *tdb) 440 519 { 441 520 struct tdb_context **i; 442 521 int ret = 0; 443 522 523 if (tdb->transaction) { 524 tdb_transaction_cancel(tdb); 525 } 444 526 tdb_trace(tdb, "tdb_close"); 445 if (tdb->transaction) {446 _tdb_transaction_cancel(tdb);447 }448 527 449 528 if (tdb->map_ptr) { … … 457 536 // YD internal databases do not have a global lock 458 537 if (!(tdb->flags & TDB_INTERNAL)) 459 tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLK, 0, 1);538 tdb_nest_unlock(tdb, OPEN_LOCK, F_WRLCK, false); 460 539 #endif 461 540 if (tdb->fd != -1) { … … 491 570 492 571 /* register a loging function */ 493 void tdb_set_logging_function(struct tdb_context *tdb,494 const struct tdb_logging_context *log_ctx)572 _PUBLIC_ void tdb_set_logging_function(struct tdb_context *tdb, 573 const struct tdb_logging_context *log_ctx) 495 574 { 496 575 tdb->log = *log_ctx; 497 576 } 498 577 499 void *tdb_get_logging_private(struct tdb_context *tdb)578 _PUBLIC_ void *tdb_get_logging_private(struct tdb_context *tdb) 500 579 { 501 580 return tdb->log.log_private; … … 526 605 #endif 527 606 528 if (tdb ->num_locks != 0 || tdb->global_lock.count) {607 if (tdb_have_extra_locks(tdb)) { 529 608 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed with locks held\n")); 530 609 goto fail; … … 561 640 #endif /* fake pread or pwrite */ 562 641 563 if (active_lock && 564 (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)) { 642 /* We may still think we hold the active lock. */ 643 tdb->num_lockrecs = 0; 644 SAFE_FREE(tdb->lockrecs); 645 646 if (active_lock && tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) { 565 647 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n")); 566 648 goto fail; … … 576 658 /* reopen a tdb - this can be used after a fork to ensure that we have an independent 577 659 seek pointer from our parent and to re-establish locks */ 578 int tdb_reopen(struct tdb_context *tdb)660 _PUBLIC_ int tdb_reopen(struct tdb_context *tdb) 579 661 { 580 662 return tdb_reopen_internal(tdb, tdb->flags & TDB_CLEAR_IF_FIRST); … … 582 664 583 665 /* reopen all tdb's */ 584 int tdb_reopen_all(int parent_longlived)666 _PUBLIC_ int tdb_reopen_all(int parent_longlived) 585 667 { 586 668 struct tdb_context *tdb; … … 623 705 // extract path info 624 706 _splitpath( name, drive, dir, fname, ext); 625 sprintf( szSem, "\\SEM32\\TDB_ GL_%s%s%s%i", dir, fname, ext, global_Sem32Add);707 sprintf( szSem, "\\SEM32\\TDB_OL_%s%s%s%i", dir, fname, ext, global_Sem32Add); 626 708 rc = DosCreateMutexSem( szSem, &tdb->hGlobalLock, 0, FALSE); 627 709 if (rc == ERROR_DUPLICATE_NAME) … … 632 714 return -1; 633 715 } 634 TDB_LOG((tdb, TDB_DEBUG_TRACE,"%s pid %d globalhandle %d\n", caller, getpid(), tdb->hGlobalLock));716 TDB_LOG((tdb, TDB_DEBUG_TRACE,"%s pid %d open handle %d\n", caller, getpid(), tdb->hGlobalLock)); 635 717 636 718 sprintf( szSem, "\\SEM32\\TDB_AL_%s%s%s%i", dir, fname, ext, global_Sem32Add); … … 659 741 } 660 742 #endif 661
Note:
See TracChangeset
for help on using the changeset viewer.