Changeset 740 for vendor/current/lib/tdb/common
- Timestamp:
- Nov 14, 2012, 12:59:34 PM (13 years ago)
- Location:
- vendor/current/lib/tdb/common
- Files:
-
- 2 added
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/lib/tdb/common/check.c
r414 r740 29 29 { 30 30 struct tdb_header hdr; 31 32 if (tdb->methods->tdb_read(tdb, 0, &hdr, sizeof(hdr), DOCONV()) == -1) 31 uint32_t h1, h2; 32 33 if (tdb->methods->tdb_read(tdb, 0, &hdr, sizeof(hdr), 0) == -1) 33 34 return false; 34 35 if (strcmp(hdr.magic_food, TDB_MAGIC_FOOD) != 0) … … 39 40 goto corrupt; 40 41 41 if (hdr.rwlocks != 0) 42 if (hdr.rwlocks != 0 && hdr.rwlocks != TDB_HASH_RWLOCK_MAGIC) 43 goto corrupt; 44 45 tdb_header_hash(tdb, &h1, &h2); 46 if (hdr.magic1_hash && hdr.magic2_hash && 47 (hdr.magic1_hash != h1 || hdr.magic2_hash != h2)) 42 48 goto corrupt; 43 49 … … 302 308 } 303 309 304 int tdb_check(struct tdb_context *tdb, 310 /* Slow, but should be very rare. */ 311 size_t tdb_dead_space(struct tdb_context *tdb, tdb_off_t off) 312 { 313 size_t len; 314 315 for (len = 0; off + len < tdb->map_size; len++) { 316 char c; 317 if (tdb->methods->tdb_read(tdb, off, &c, 1, 0)) 318 return 0; 319 if (c != 0 && c != 0x42) 320 break; 321 } 322 return len; 323 } 324 325 _PUBLIC_ int tdb_check(struct tdb_context *tdb, 305 326 int (*check)(TDB_DATA key, TDB_DATA data, void *private_data), 306 327 void *private_data) … … 311 332 struct tdb_record rec; 312 333 bool found_recovery = false; 313 314 if (tdb_lockall(tdb) == -1) 315 return -1; 334 tdb_len_t dead; 335 bool locked; 336 337 /* Read-only databases use no locking at all: it's best-effort. 338 * We may have a write lock already, so skip that case too. */ 339 if (tdb->read_only || tdb->allrecord_lock.count != 0) { 340 locked = false; 341 } else { 342 if (tdb_lockall_read(tdb) == -1) 343 return -1; 344 locked = true; 345 } 316 346 317 347 /* Make sure we know true size of the underlying file. */ … … 370 400 goto free; 371 401 break; 402 /* If we crash after ftruncate, we can get zeroes or fill. */ 403 case TDB_RECOVERY_INVALID_MAGIC: 404 case 0x42424242: 405 if (recovery_start == off) { 406 found_recovery = true; 407 break; 408 } 409 dead = tdb_dead_space(tdb, off); 410 if (dead < sizeof(rec)) 411 goto corrupt; 412 413 TDB_LOG((tdb, TDB_DEBUG_ERROR, 414 "Dead space at %d-%d (of %u)\n", 415 off, off + dead, tdb->map_size)); 416 rec.rec_len = dead - sizeof(rec); 417 break; 372 418 case TDB_RECOVERY_MAGIC: 373 case 0: /* Used for invalid (or in-progress) recovery area. */374 419 if (recovery_start != off) { 375 420 TDB_LOG((tdb, TDB_DEBUG_ERROR, … … 380 425 found_recovery = true; 381 426 break; 382 default: 427 default: ; 428 corrupt: 383 429 tdb->ecode = TDB_ERR_CORRUPT; 384 430 TDB_LOG((tdb, TDB_DEBUG_ERROR, … … 406 452 if (recovery_start != 0 && !found_recovery) { 407 453 TDB_LOG((tdb, TDB_DEBUG_ERROR, 408 "Expected %s recovery area, got %s\n", 409 recovery_start ? "a" : "no", 410 found_recovery ? "one" : "none")); 454 "Expected a recovery area at %u\n", 455 recovery_start)); 411 456 goto free; 412 457 } 413 458 414 459 free(hashes); 415 tdb_unlockall(tdb); 460 if (locked) { 461 tdb_unlockall_read(tdb); 462 } 416 463 return 0; 417 464 … … 419 466 free(hashes); 420 467 unlock: 421 tdb_unlockall(tdb); 468 if (locked) { 469 tdb_unlockall_read(tdb); 470 } 422 471 return -1; 423 472 } -
vendor/current/lib/tdb/common/dump.c
r414 r740 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 … … 81 81 } 82 82 83 void tdb_dump_all(struct tdb_context *tdb)83 _PUBLIC_ void tdb_dump_all(struct tdb_context *tdb) 84 84 { 85 85 int i; … … 91 91 } 92 92 93 int tdb_printfreelist(struct tdb_context *tdb)93 _PUBLIC_ int tdb_printfreelist(struct tdb_context *tdb) 94 94 { 95 95 int ret; -
vendor/current/lib/tdb/common/error.c
r414 r740 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 … … 28 28 #include "tdb_private.h" 29 29 30 enum TDB_ERROR tdb_error(struct tdb_context *tdb)30 _PUBLIC_ enum TDB_ERROR tdb_error(struct tdb_context *tdb) 31 31 { 32 32 return tdb->ecode; … … 47 47 48 48 /* Error string for the last tdb error */ 49 const char *tdb_errorstr(struct tdb_context *tdb)49 _PUBLIC_ const char *tdb_errorstr(struct tdb_context *tdb) 50 50 { 51 51 uint32_t i; -
vendor/current/lib/tdb/common/freelist.c
r414 r740 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 … … 99 99 100 100 /* Add an element into the freelist. Merge adjacent records if 101 nec cessary. */101 necessary. */ 102 102 int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec) 103 103 { … … 144 144 struct tdb_record l; 145 145 tdb_off_t leftsize; 146 146 147 147 /* Read in tailer and jump back to header */ 148 148 if (tdb_ofs_read(tdb, left, &leftsize) == -1) { … … 335 335 break; 336 336 } 337 337 338 338 /* this multiplier means we only extremely rarely 339 339 search more than 50 or so records. At 50 records we … … 368 368 return the size of the freelist - used to decide if we should repack 369 369 */ 370 int tdb_freelist_size(struct tdb_context *tdb)370 _PUBLIC_ int tdb_freelist_size(struct tdb_context *tdb) 371 371 { 372 372 tdb_off_t ptr; -
vendor/current/lib/tdb/common/freelistcheck.c
r414 r740 44 44 } 45 45 46 int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries)46 _PUBLIC_ int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries) 47 47 { 48 48 struct tdb_context *mem_tdb = NULL; -
vendor/current/lib/tdb/common/io.c
r597 r740 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 … … 477 477 tdb_oob, 478 478 tdb_expand_file, 479 tdb_brlock480 479 }; 481 480 -
vendor/current/lib/tdb/common/lock.c
r414 r740 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 … … 28 28 #include "tdb_private.h" 29 29 30 #define TDB_MARK_LOCK 0x80000000 31 32 void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *ptr) 30 _PUBLIC_ void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *ptr) 33 31 { 34 32 tdb->interrupt_sig_ptr = ptr; 33 } 34 35 static int fcntl_lock(struct tdb_context *tdb, 36 int rw, off_t off, off_t len, bool waitflag) 37 { 38 struct flock fl; 39 40 fl.l_type = rw; 41 fl.l_whence = SEEK_SET; 42 fl.l_start = off; 43 fl.l_len = len; 44 fl.l_pid = 0; 45 46 if (waitflag) 47 return fcntl(tdb->fd, F_SETLKW, &fl); 48 else 49 return fcntl(tdb->fd, F_SETLK, &fl); 50 } 51 52 static int fcntl_unlock(struct tdb_context *tdb, int rw, off_t off, off_t len) 53 { 54 struct flock fl; 55 #if 0 /* Check they matched up locks and unlocks correctly. */ 56 char line[80]; 57 FILE *locks; 58 bool found = false; 59 60 locks = fopen("/proc/locks", "r"); 61 62 while (fgets(line, 80, locks)) { 63 char *p; 64 int type, start, l; 65 66 /* eg. 1: FLOCK ADVISORY WRITE 2440 08:01:2180826 0 EOF */ 67 p = strchr(line, ':') + 1; 68 if (strncmp(p, " POSIX ADVISORY ", strlen(" POSIX ADVISORY "))) 69 continue; 70 p += strlen(" FLOCK ADVISORY "); 71 if (strncmp(p, "READ ", strlen("READ ")) == 0) 72 type = F_RDLCK; 73 else if (strncmp(p, "WRITE ", strlen("WRITE ")) == 0) 74 type = F_WRLCK; 75 else 76 abort(); 77 p += 6; 78 if (atoi(p) != getpid()) 79 continue; 80 p = strchr(strchr(p, ' ') + 1, ' ') + 1; 81 start = atoi(p); 82 p = strchr(p, ' ') + 1; 83 if (strncmp(p, "EOF", 3) == 0) 84 l = 0; 85 else 86 l = atoi(p) - start + 1; 87 88 if (off == start) { 89 if (len != l) { 90 fprintf(stderr, "Len %u should be %u: %s", 91 (int)len, l, line); 92 abort(); 93 } 94 if (type != rw) { 95 fprintf(stderr, "Type %s wrong: %s", 96 rw == F_RDLCK ? "READ" : "WRITE", line); 97 abort(); 98 } 99 found = true; 100 break; 101 } 102 } 103 104 if (!found) { 105 fprintf(stderr, "Unlock on %u@%u not found!\n", 106 (int)off, (int)len); 107 abort(); 108 } 109 110 fclose(locks); 111 #endif 112 113 fl.l_type = F_UNLCK; 114 fl.l_whence = SEEK_SET; 115 fl.l_start = off; 116 fl.l_len = len; 117 fl.l_pid = 0; 118 119 return fcntl(tdb->fd, F_SETLKW, &fl); 120 } 121 122 /* list -1 is the alloc list, otherwise a hash chain. */ 123 static tdb_off_t lock_offset(int list) 124 { 125 return FREELIST_TOP + 4*list; 35 126 } 36 127 … … 43 134 note that a len of zero means lock to end of file 44 135 */ 45 int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset,46 int rw_type, int lck_type, int probe, size_t len)47 { 48 struct flock fl; 136 int tdb_brlock(struct tdb_context *tdb, 137 int rw_type, tdb_off_t offset, size_t len, 138 enum tdb_lock_flags flags) 139 { 49 140 int ret; 50 141 51 142 if (tdb->flags & TDB_NOLOCK) { 143 return 0; 144 } 145 146 if (flags & TDB_LOCK_MARK_ONLY) { 52 147 return 0; 53 148 } … … 58 153 } 59 154 60 fl.l_type = rw_type;61 fl.l_whence = SEEK_SET;62 fl.l_start = offset;63 fl.l_len = len;64 fl.l_pid = 0;65 66 155 do { 67 ret = fcntl (tdb->fd,lck_type,&fl);68 156 ret = fcntl_lock(tdb, rw_type, offset, len, 157 flags & TDB_LOCK_WAIT); 69 158 /* Check for a sigalarm break. */ 70 159 if (ret == -1 && errno == EINTR && … … 80 169 * EAGAIN is an expected return from non-blocking 81 170 * locks. */ 82 if (! probe && lck_type != F_SETLK) {83 TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d len=%d\n",84 tdb->fd, offset, rw_type, lck_type, (int)len));171 if (!(flags & TDB_LOCK_PROBE) && errno != EAGAIN) { 172 TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d flags=%d len=%d\n", 173 tdb->fd, offset, rw_type, flags, (int)len)); 85 174 } 86 175 return -1; … … 89 178 } 90 179 180 int tdb_brunlock(struct tdb_context *tdb, 181 int rw_type, tdb_off_t offset, size_t len) 182 { 183 int ret; 184 185 if (tdb->flags & TDB_NOLOCK) { 186 return 0; 187 } 188 189 do { 190 ret = fcntl_unlock(tdb, rw_type, offset, len); 191 } while (ret == -1 && errno == EINTR); 192 193 if (ret == -1) { 194 TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brunlock failed (fd=%d) at offset %d rw_type=%d len=%d\n", 195 tdb->fd, offset, rw_type, (int)len)); 196 } 197 return ret; 198 } 91 199 92 200 /* … … 96 204 made. For those OSes we may loop for a while. 97 205 */ 98 int tdb_ brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len)206 int tdb_allrecord_upgrade(struct tdb_context *tdb) 99 207 { 100 208 int count = 1000; 209 210 if (tdb->allrecord_lock.count != 1) { 211 TDB_LOG((tdb, TDB_DEBUG_ERROR, 212 "tdb_allrecord_upgrade failed: count %u too high\n", 213 tdb->allrecord_lock.count)); 214 return -1; 215 } 216 217 if (tdb->allrecord_lock.off != 1) { 218 TDB_LOG((tdb, TDB_DEBUG_ERROR, 219 "tdb_allrecord_upgrade failed: already upgraded?\n")); 220 return -1; 221 } 222 101 223 while (count--) { 102 224 struct timeval tv; 103 if (tdb_brlock(tdb, offset, F_WRLCK, F_SETLKW, 1, len) == 0) { 225 if (tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0, 226 TDB_LOCK_WAIT|TDB_LOCK_PROBE) == 0) { 227 tdb->allrecord_lock.ltype = F_WRLCK; 228 tdb->allrecord_lock.off = 0; 104 229 return 0; 105 230 } … … 112 237 select(0, NULL, NULL, NULL, &tv); 113 238 } 114 TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_ brlock_upgrade failed at offset %d\n", offset));239 TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_allrecord_upgrade failed\n")); 115 240 return -1; 116 241 } 117 242 118 119 /* lock a list in the database. list -1 is the alloc list */ 120 static int _tdb_lock(struct tdb_context *tdb, int list, int ltype, int op) 243 static struct tdb_lock_type *find_nestlock(struct tdb_context *tdb, 244 tdb_off_t offset) 245 { 246 unsigned int i; 247 248 for (i=0; i<tdb->num_lockrecs; i++) { 249 if (tdb->lockrecs[i].off == offset) { 250 return &tdb->lockrecs[i]; 251 } 252 } 253 return NULL; 254 } 255 256 /* lock an offset in the database. */ 257 int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype, 258 enum tdb_lock_flags flags) 121 259 { 122 260 struct tdb_lock_type *new_lck; 123 int i; 124 bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK); 125 126 ltype &= ~TDB_MARK_LOCK; 127 128 /* a global lock allows us to avoid per chain locks */ 129 if (tdb->global_lock.count && 130 (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) { 131 return 0; 132 } 133 134 if (tdb->global_lock.count) { 135 tdb->ecode = TDB_ERR_LOCK; 136 return -1; 137 } 138 139 if (list < -1 || list >= (int)tdb->header.hash_size) { 140 tdb->ecode = TDB_ERR_LOCK; 141 TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid list %d for ltype=%d\n", 142 list, ltype)); 261 262 if (offset >= lock_offset(tdb->header.hash_size)) { 263 tdb->ecode = TDB_ERR_LOCK; 264 TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid offset %u for ltype=%d\n", 265 offset, ltype)); 143 266 return -1; 144 267 } … … 146 269 return 0; 147 270 148 for (i=0; i<tdb->num_lockrecs; i++) { 149 if (tdb->lockrecs[i].list == list) { 150 if (tdb->lockrecs[i].count == 0) { 151 /* 152 * Can't happen, see tdb_unlock(). It should 153 * be an assert. 154 */ 155 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock: " 156 "lck->count == 0 for list %d", list)); 157 } 158 /* 159 * Just increment the in-memory struct, posix locks 160 * don't stack. 161 */ 162 tdb->lockrecs[i].count++; 163 return 0; 164 } 271 new_lck = find_nestlock(tdb, offset); 272 if (new_lck) { 273 /* 274 * Just increment the in-memory struct, posix locks 275 * don't stack. 276 */ 277 new_lck->count++; 278 return 0; 165 279 } 166 280 … … 176 290 /* Since fcntl locks don't nest, we do a lock for the first one, 177 291 and simply bump the count for future ones */ 178 if (!mark_lock && 179 tdb->methods->tdb_brlock(tdb,FREELIST_TOP+4*list, ltype, op, 180 0, 1)) { 181 return -1; 182 } 183 184 tdb->num_locks++; 185 186 tdb->lockrecs[tdb->num_lockrecs].list = list; 292 if (tdb_brlock(tdb, ltype, offset, 1, flags)) { 293 return -1; 294 } 295 296 tdb->lockrecs[tdb->num_lockrecs].off = offset; 187 297 tdb->lockrecs[tdb->num_lockrecs].count = 1; 188 298 tdb->lockrecs[tdb->num_lockrecs].ltype = ltype; 189 tdb->num_lockrecs += 1;299 tdb->num_lockrecs++; 190 300 191 301 return 0; 302 } 303 304 static int tdb_lock_and_recover(struct tdb_context *tdb) 305 { 306 int ret; 307 308 /* We need to match locking order in transaction commit. */ 309 if (tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0, TDB_LOCK_WAIT)) { 310 return -1; 311 } 312 313 if (tdb_brlock(tdb, F_WRLCK, OPEN_LOCK, 1, TDB_LOCK_WAIT)) { 314 tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0); 315 return -1; 316 } 317 318 ret = tdb_transaction_recover(tdb); 319 320 tdb_brunlock(tdb, F_WRLCK, OPEN_LOCK, 1); 321 tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0); 322 323 return ret; 324 } 325 326 static bool have_data_locks(const struct tdb_context *tdb) 327 { 328 unsigned int i; 329 330 for (i = 0; i < tdb->num_lockrecs; i++) { 331 if (tdb->lockrecs[i].off >= lock_offset(-1)) 332 return true; 333 } 334 return false; 335 } 336 337 static int tdb_lock_list(struct tdb_context *tdb, int list, int ltype, 338 enum tdb_lock_flags waitflag) 339 { 340 int ret; 341 bool check = false; 342 343 /* a allrecord lock allows us to avoid per chain locks */ 344 if (tdb->allrecord_lock.count && 345 (ltype == tdb->allrecord_lock.ltype || ltype == F_RDLCK)) { 346 return 0; 347 } 348 349 if (tdb->allrecord_lock.count) { 350 tdb->ecode = TDB_ERR_LOCK; 351 ret = -1; 352 } else { 353 /* Only check when we grab first data lock. */ 354 check = !have_data_locks(tdb); 355 ret = tdb_nest_lock(tdb, lock_offset(list), ltype, waitflag); 356 357 if (ret == 0 && check && tdb_needs_recovery(tdb)) { 358 tdb_nest_unlock(tdb, lock_offset(list), ltype, false); 359 360 if (tdb_lock_and_recover(tdb) == -1) { 361 return -1; 362 } 363 return tdb_lock_list(tdb, list, ltype, waitflag); 364 } 365 } 366 return ret; 192 367 } 193 368 … … 196 371 { 197 372 int ret; 198 ret = _tdb_lock(tdb, list, ltype, F_SETLKW); 373 374 ret = tdb_lock_list(tdb, list, ltype, TDB_LOCK_WAIT); 199 375 if (ret) { 200 376 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d " … … 207 383 int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype) 208 384 { 209 return _tdb_lock(tdb, list, ltype, F_SETLK); 210 } 211 212 213 /* unlock the database: returns void because it's too late for errors. */ 214 /* changed to return int it may be interesting to know there 215 has been an error --simo */ 216 int tdb_unlock(struct tdb_context *tdb, int list, int ltype) 385 return tdb_lock_list(tdb, list, ltype, TDB_LOCK_NOWAIT); 386 } 387 388 389 int tdb_nest_unlock(struct tdb_context *tdb, uint32_t offset, int ltype, 390 bool mark_lock) 217 391 { 218 392 int ret = -1; 219 int i; 220 struct tdb_lock_type *lck = NULL; 221 bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK); 222 223 ltype &= ~TDB_MARK_LOCK; 224 225 /* a global lock allows us to avoid per chain locks */ 226 if (tdb->global_lock.count && 227 (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) { 228 return 0; 229 } 230 231 if (tdb->global_lock.count) { 232 tdb->ecode = TDB_ERR_LOCK; 233 return -1; 234 } 393 struct tdb_lock_type *lck; 235 394 236 395 if (tdb->flags & TDB_NOLOCK) … … 238 397 239 398 /* Sanity checks */ 240 if ( list < -1 || list >= (int)tdb->header.hash_size) {241 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: list %d invalid (%d)\n", list, tdb->header.hash_size));399 if (offset >= lock_offset(tdb->header.hash_size)) { 400 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: offset %u invalid (%d)\n", offset, tdb->header.hash_size)); 242 401 return ret; 243 402 } 244 403 245 for (i=0; i<tdb->num_lockrecs; i++) { 246 if (tdb->lockrecs[i].list == list) { 247 lck = &tdb->lockrecs[i]; 248 break; 249 } 250 } 251 404 lck = find_nestlock(tdb, offset); 252 405 if ((lck == NULL) || (lck->count == 0)) { 253 406 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: count is 0\n")); … … 270 423 ret = 0; 271 424 } else { 272 ret = tdb->methods->tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK, 273 F_SETLKW, 0, 1); 274 } 275 tdb->num_locks--; 425 ret = tdb_brunlock(tdb, ltype, offset, 1); 426 } 276 427 277 428 /* … … 279 430 * last array element. 280 431 */ 281 282 if (tdb->num_lockrecs > 1) { 283 *lck = tdb->lockrecs[tdb->num_lockrecs-1]; 284 } 285 tdb->num_lockrecs -= 1; 432 *lck = tdb->lockrecs[--tdb->num_lockrecs]; 286 433 287 434 /* … … 299 446 } 300 447 448 int tdb_unlock(struct tdb_context *tdb, int list, int ltype) 449 { 450 /* a global lock allows us to avoid per chain locks */ 451 if (tdb->allrecord_lock.count && 452 (ltype == tdb->allrecord_lock.ltype || ltype == F_RDLCK)) { 453 return 0; 454 } 455 456 if (tdb->allrecord_lock.count) { 457 tdb->ecode = TDB_ERR_LOCK; 458 return -1; 459 } 460 461 return tdb_nest_unlock(tdb, lock_offset(list), ltype, false); 462 } 463 301 464 /* 302 465 get the transaction lock 303 466 */ 304 int tdb_transaction_lock(struct tdb_context *tdb, int ltype) 305 { 306 if (tdb->global_lock.count) { 307 return 0; 308 } 309 if (tdb->transaction_lock_count > 0) { 310 tdb->transaction_lock_count++; 311 return 0; 312 } 313 314 if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, ltype, 315 F_SETLKW, 0, 1) == -1) { 316 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_lock: failed to get transaction lock\n")); 317 tdb->ecode = TDB_ERR_LOCK; 318 return -1; 319 } 320 tdb->transaction_lock_count++; 321 return 0; 467 int tdb_transaction_lock(struct tdb_context *tdb, int ltype, 468 enum tdb_lock_flags lockflags) 469 { 470 return tdb_nest_lock(tdb, TRANSACTION_LOCK, ltype, lockflags); 322 471 } 323 472 … … 325 474 release the transaction lock 326 475 */ 327 int tdb_transaction_unlock(struct tdb_context *tdb) 328 { 329 int ret; 330 if (tdb->global_lock.count) { 331 return 0; 332 } 333 if (tdb->transaction_lock_count > 1) { 334 tdb->transaction_lock_count--; 335 return 0; 336 } 337 ret = tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1); 338 if (ret == 0) { 339 tdb->transaction_lock_count = 0; 340 } 341 return ret; 342 } 343 344 345 346 347 /* lock/unlock entire database */ 348 static int _tdb_lockall(struct tdb_context *tdb, int ltype, int op) 349 { 350 bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK); 351 352 ltype &= ~TDB_MARK_LOCK; 353 476 int tdb_transaction_unlock(struct tdb_context *tdb, int ltype) 477 { 478 return tdb_nest_unlock(tdb, TRANSACTION_LOCK, ltype, false); 479 } 480 481 /* Returns 0 if all done, -1 if error, 1 if ok. */ 482 static int tdb_allrecord_check(struct tdb_context *tdb, int ltype, 483 enum tdb_lock_flags flags, bool upgradable) 484 { 354 485 /* There are no locks on read-only dbs */ 355 486 if (tdb->read_only || tdb->traverse_read) { … … 358 489 } 359 490 360 if (tdb-> global_lock.count && tdb->global_lock.ltype == ltype) {361 tdb-> global_lock.count++;362 return 0; 363 } 364 365 if (tdb-> global_lock.count) {491 if (tdb->allrecord_lock.count && tdb->allrecord_lock.ltype == ltype) { 492 tdb->allrecord_lock.count++; 493 return 0; 494 } 495 496 if (tdb->allrecord_lock.count) { 366 497 /* a global lock of a different type exists */ 367 498 tdb->ecode = TDB_ERR_LOCK; 368 499 return -1; 369 500 } 370 371 if (tdb ->num_locks != 0) {501 502 if (tdb_have_extra_locks(tdb)) { 372 503 /* can't combine global and chain locks */ 373 504 tdb->ecode = TDB_ERR_LOCK; … … 375 506 } 376 507 377 if (!mark_lock && 378 tdb->methods->tdb_brlock(tdb, FREELIST_TOP, ltype, op, 379 0, 4*tdb->header.hash_size)) { 380 if (op == F_SETLKW) { 381 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lockall failed (%s)\n", strerror(errno))); 382 } 383 return -1; 384 } 385 386 tdb->global_lock.count = 1; 387 tdb->global_lock.ltype = ltype; 388 508 if (upgradable && ltype != F_RDLCK) { 509 /* tdb error: you can't upgrade a write lock! */ 510 tdb->ecode = TDB_ERR_LOCK; 511 return -1; 512 } 513 return 1; 514 } 515 516 /* We only need to lock individual bytes, but Linux merges consecutive locks 517 * so we lock in contiguous ranges. */ 518 static int tdb_chainlock_gradual(struct tdb_context *tdb, 519 int ltype, enum tdb_lock_flags flags, 520 size_t off, size_t len) 521 { 522 int ret; 523 enum tdb_lock_flags nb_flags = (flags & ~TDB_LOCK_WAIT); 524 525 if (len <= 4) { 526 /* Single record. Just do blocking lock. */ 527 return tdb_brlock(tdb, ltype, off, len, flags); 528 } 529 530 /* First we try non-blocking. */ 531 ret = tdb_brlock(tdb, ltype, off, len, nb_flags); 532 if (ret == 0) { 533 return 0; 534 } 535 536 /* Try locking first half, then second. */ 537 ret = tdb_chainlock_gradual(tdb, ltype, flags, off, len / 2); 538 if (ret == -1) 539 return -1; 540 541 ret = tdb_chainlock_gradual(tdb, ltype, flags, 542 off + len / 2, len - len / 2); 543 if (ret == -1) { 544 tdb_brunlock(tdb, ltype, off, len / 2); 545 return -1; 546 } 389 547 return 0; 390 548 } 391 549 550 /* lock/unlock entire database. It can only be upgradable if you have some 551 * other way of guaranteeing exclusivity (ie. transaction write lock). 552 * We do the locking gradually to avoid being starved by smaller locks. */ 553 int tdb_allrecord_lock(struct tdb_context *tdb, int ltype, 554 enum tdb_lock_flags flags, bool upgradable) 555 { 556 switch (tdb_allrecord_check(tdb, ltype, flags, upgradable)) { 557 case -1: 558 return -1; 559 case 0: 560 return 0; 561 } 562 563 /* We cover two kinds of locks: 564 * 1) Normal chain locks. Taken for almost all operations. 565 * 3) Individual records locks. Taken after normal or free 566 * chain locks. 567 * 568 * It is (1) which cause the starvation problem, so we're only 569 * gradual for that. */ 570 if (tdb_chainlock_gradual(tdb, ltype, flags, FREELIST_TOP, 571 tdb->header.hash_size * 4) == -1) { 572 return -1; 573 } 574 575 /* Grab individual record locks. */ 576 if (tdb_brlock(tdb, ltype, lock_offset(tdb->header.hash_size), 0, 577 flags) == -1) { 578 tdb_brunlock(tdb, ltype, FREELIST_TOP, 579 tdb->header.hash_size * 4); 580 return -1; 581 } 582 583 tdb->allrecord_lock.count = 1; 584 /* If it's upgradable, it's actually exclusive so we can treat 585 * it as a write lock. */ 586 tdb->allrecord_lock.ltype = upgradable ? F_WRLCK : ltype; 587 tdb->allrecord_lock.off = upgradable; 588 589 if (tdb_needs_recovery(tdb)) { 590 bool mark = flags & TDB_LOCK_MARK_ONLY; 591 tdb_allrecord_unlock(tdb, ltype, mark); 592 if (mark) { 593 tdb->ecode = TDB_ERR_LOCK; 594 TDB_LOG((tdb, TDB_DEBUG_ERROR, 595 "tdb_lockall_mark cannot do recovery\n")); 596 return -1; 597 } 598 if (tdb_lock_and_recover(tdb) == -1) { 599 return -1; 600 } 601 return tdb_allrecord_lock(tdb, ltype, flags, upgradable); 602 } 603 604 return 0; 605 } 606 392 607 393 608 394 609 /* unlock entire db */ 395 static int _tdb_unlockall(struct tdb_context *tdb, int ltype) 396 { 397 bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK); 398 399 ltype &= ~TDB_MARK_LOCK; 400 610 int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock) 611 { 401 612 /* There are no locks on read-only dbs */ 402 613 if (tdb->read_only || tdb->traverse_read) { … … 405 616 } 406 617 407 if (tdb->global_lock.ltype != ltype || tdb->global_lock.count == 0) { 408 tdb->ecode = TDB_ERR_LOCK; 409 return -1; 410 } 411 412 if (tdb->global_lock.count > 1) { 413 tdb->global_lock.count--; 414 return 0; 415 } 416 417 if (!mark_lock && 418 tdb->methods->tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 419 0, 4*tdb->header.hash_size)) { 618 if (tdb->allrecord_lock.count == 0) { 619 tdb->ecode = TDB_ERR_LOCK; 620 return -1; 621 } 622 623 /* Upgradable locks are marked as write locks. */ 624 if (tdb->allrecord_lock.ltype != ltype 625 && (!tdb->allrecord_lock.off || ltype != F_RDLCK)) { 626 tdb->ecode = TDB_ERR_LOCK; 627 return -1; 628 } 629 630 if (tdb->allrecord_lock.count > 1) { 631 tdb->allrecord_lock.count--; 632 return 0; 633 } 634 635 if (!mark_lock && tdb_brunlock(tdb, ltype, FREELIST_TOP, 0)) { 420 636 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlockall failed (%s)\n", strerror(errno))); 421 637 return -1; 422 638 } 423 639 424 tdb-> global_lock.count = 0;425 tdb-> global_lock.ltype = 0;640 tdb->allrecord_lock.count = 0; 641 tdb->allrecord_lock.ltype = 0; 426 642 427 643 return 0; … … 429 645 430 646 /* lock entire database with write lock */ 431 int tdb_lockall(struct tdb_context *tdb)647 _PUBLIC_ int tdb_lockall(struct tdb_context *tdb) 432 648 { 433 649 tdb_trace(tdb, "tdb_lockall"); 434 return _tdb_lockall(tdb, F_WRLCK, F_SETLKW);650 return tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false); 435 651 } 436 652 437 653 /* lock entire database with write lock - mark only */ 438 int tdb_lockall_mark(struct tdb_context *tdb)654 _PUBLIC_ int tdb_lockall_mark(struct tdb_context *tdb) 439 655 { 440 656 tdb_trace(tdb, "tdb_lockall_mark"); 441 return _tdb_lockall(tdb, F_WRLCK | TDB_MARK_LOCK, F_SETLKW);657 return tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_MARK_ONLY, false); 442 658 } 443 659 444 660 /* unlock entire database with write lock - unmark only */ 445 int tdb_lockall_unmark(struct tdb_context *tdb)661 _PUBLIC_ int tdb_lockall_unmark(struct tdb_context *tdb) 446 662 { 447 663 tdb_trace(tdb, "tdb_lockall_unmark"); 448 return _tdb_unlockall(tdb, F_WRLCK | TDB_MARK_LOCK);664 return tdb_allrecord_unlock(tdb, F_WRLCK, true); 449 665 } 450 666 451 667 /* lock entire database with write lock - nonblocking varient */ 452 int tdb_lockall_nonblock(struct tdb_context *tdb)453 { 454 int ret = _tdb_lockall(tdb, F_WRLCK, F_SETLK);668 _PUBLIC_ int tdb_lockall_nonblock(struct tdb_context *tdb) 669 { 670 int ret = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_NOWAIT, false); 455 671 tdb_trace_ret(tdb, "tdb_lockall_nonblock", ret); 456 672 return ret; … … 458 674 459 675 /* unlock entire database with write lock */ 460 int tdb_unlockall(struct tdb_context *tdb)676 _PUBLIC_ int tdb_unlockall(struct tdb_context *tdb) 461 677 { 462 678 tdb_trace(tdb, "tdb_unlockall"); 463 return _tdb_unlockall(tdb, F_WRLCK);679 return tdb_allrecord_unlock(tdb, F_WRLCK, false); 464 680 } 465 681 466 682 /* lock entire database with read lock */ 467 int tdb_lockall_read(struct tdb_context *tdb)683 _PUBLIC_ int tdb_lockall_read(struct tdb_context *tdb) 468 684 { 469 685 tdb_trace(tdb, "tdb_lockall_read"); 470 return _tdb_lockall(tdb, F_RDLCK, F_SETLKW);686 return tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, false); 471 687 } 472 688 473 689 /* lock entire database with read lock - nonblock varient */ 474 int tdb_lockall_read_nonblock(struct tdb_context *tdb)475 { 476 int ret = _tdb_lockall(tdb, F_RDLCK, F_SETLK);690 _PUBLIC_ int tdb_lockall_read_nonblock(struct tdb_context *tdb) 691 { 692 int ret = tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_NOWAIT, false); 477 693 tdb_trace_ret(tdb, "tdb_lockall_read_nonblock", ret); 478 694 return ret; … … 480 696 481 697 /* unlock entire database with read lock */ 482 int tdb_unlockall_read(struct tdb_context *tdb)698 _PUBLIC_ int tdb_unlockall_read(struct tdb_context *tdb) 483 699 { 484 700 tdb_trace(tdb, "tdb_unlockall_read"); 485 return _tdb_unlockall(tdb, F_RDLCK);701 return tdb_allrecord_unlock(tdb, F_RDLCK, false); 486 702 } 487 703 488 704 /* lock/unlock one hash chain. This is meant to be used to reduce 489 705 contention - it cannot guarantee how many records will be locked */ 490 int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key)706 _PUBLIC_ int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key) 491 707 { 492 708 int ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); … … 498 714 to reduce contention - it cannot guarantee how many records will be 499 715 locked */ 500 int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key)716 _PUBLIC_ int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key) 501 717 { 502 718 int ret = tdb_lock_nonblock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); … … 506 722 507 723 /* mark a chain as locked without actually locking it. Warning! use with great caution! */ 508 int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key) 509 { 510 int ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK); 724 _PUBLIC_ int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key) 725 { 726 int ret = tdb_nest_lock(tdb, lock_offset(BUCKET(tdb->hash_fn(&key))), 727 F_WRLCK, TDB_LOCK_MARK_ONLY); 511 728 tdb_trace_1rec(tdb, "tdb_chainlock_mark", key); 512 729 return ret; … … 514 731 515 732 /* unmark a chain as locked without actually locking it. Warning! use with great caution! */ 516 int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key)733 _PUBLIC_ int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key) 517 734 { 518 735 tdb_trace_1rec(tdb, "tdb_chainlock_unmark", key); 519 return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK); 520 } 521 522 int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key) 736 return tdb_nest_unlock(tdb, lock_offset(BUCKET(tdb->hash_fn(&key))), 737 F_WRLCK, true); 738 } 739 740 _PUBLIC_ int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key) 523 741 { 524 742 tdb_trace_1rec(tdb, "tdb_chainunlock", key); … … 526 744 } 527 745 528 int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key)746 _PUBLIC_ int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key) 529 747 { 530 748 int ret; … … 534 752 } 535 753 536 int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key)754 _PUBLIC_ int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key) 537 755 { 538 756 tdb_trace_1rec(tdb, "tdb_chainunlock_read", key); … … 540 758 } 541 759 542 543 544 760 /* record lock stops delete underneath */ 545 761 int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off) 546 762 { 547 if (tdb-> global_lock.count) {548 return 0; 549 } 550 return off ? tdb ->methods->tdb_brlock(tdb, off, F_RDLCK, F_SETLKW, 0, 1) : 0;763 if (tdb->allrecord_lock.count) { 764 return 0; 765 } 766 return off ? tdb_brlock(tdb, F_RDLCK, off, 1, TDB_LOCK_WAIT) : 0; 551 767 } 552 768 … … 562 778 if (i->off == off) 563 779 return -1; 564 return tdb->methods->tdb_brlock(tdb, off, F_WRLCK, F_SETLK, 1, 1); 565 } 566 567 /* 568 Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not 569 an error to fail to get the lock here. 570 */ 780 if (tdb->allrecord_lock.count) { 781 if (tdb->allrecord_lock.ltype == F_WRLCK) { 782 return 0; 783 } 784 return -1; 785 } 786 return tdb_brlock(tdb, F_WRLCK, off, 1, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE); 787 } 788 571 789 int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off) 572 790 { 573 return tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLK, 0, 1); 791 if (tdb->allrecord_lock.count) { 792 return 0; 793 } 794 return tdb_brunlock(tdb, F_WRLCK, off, 1); 574 795 } 575 796 … … 580 801 uint32_t count = 0; 581 802 582 if (tdb-> global_lock.count) {803 if (tdb->allrecord_lock.count) { 583 804 return 0; 584 805 } … … 589 810 if (i->off == off) 590 811 count++; 591 return (count == 1 ? tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLKW, 0, 1) : 0); 592 } 812 return (count == 1 ? tdb_brunlock(tdb, F_RDLCK, off, 1) : 0); 813 } 814 815 bool tdb_have_extra_locks(struct tdb_context *tdb) 816 { 817 unsigned int extra = tdb->num_lockrecs; 818 819 /* A transaction holds the lock for all records. */ 820 if (!tdb->transaction && tdb->allrecord_lock.count) { 821 return true; 822 } 823 824 /* We always hold the active lock if CLEAR_IF_FIRST. */ 825 if (find_nestlock(tdb, ACTIVE_LOCK)) { 826 extra--; 827 } 828 829 /* In a transaction, we expect to hold the transaction lock */ 830 if (tdb->transaction && find_nestlock(tdb, TRANSACTION_LOCK)) { 831 extra--; 832 } 833 834 return extra; 835 } 836 837 /* The transaction code uses this to remove all locks. */ 838 void tdb_release_transaction_locks(struct tdb_context *tdb) 839 { 840 unsigned int i, active = 0; 841 842 if (tdb->allrecord_lock.count != 0) { 843 tdb_brunlock(tdb, tdb->allrecord_lock.ltype, FREELIST_TOP, 0); 844 tdb->allrecord_lock.count = 0; 845 } 846 847 for (i=0;i<tdb->num_lockrecs;i++) { 848 struct tdb_lock_type *lck = &tdb->lockrecs[i]; 849 850 /* Don't release the active lock! Copy it to first entry. */ 851 if (lck->off == ACTIVE_LOCK) { 852 tdb->lockrecs[active++] = *lck; 853 } else { 854 tdb_brunlock(tdb, lck->ltype, lck->off, 1); 855 } 856 } 857 tdb->num_lockrecs = active; 858 if (tdb->num_lockrecs == 0) { 859 SAFE_FREE(tdb->lockrecs); 860 } 861 } -
vendor/current/lib/tdb/common/open.c
r414 r740 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 … … 31 31 static struct tdb_context *tdbs = NULL; 32 32 33 34 /* This is based on the hash algorithm from gdbm */ 35 static unsigned int default_tdb_hash(TDB_DATA *key) 36 { 37 uint32_t value; /* Used to compute the hash value. */ 38 uint32_t i; /* Used to cycle through random values. */ 39 40 /* Set the initial value from the key size. */ 41 for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++) 42 value = (value + (key->dptr[i] << (i*5 % 24))); 43 44 return (1103515243 * value + 12345); 45 } 46 33 /* We use two hashes to double-check they're using the right hash function. */ 34 void tdb_header_hash(struct tdb_context *tdb, 35 uint32_t *magic1_hash, uint32_t *magic2_hash) 36 { 37 TDB_DATA hash_key; 38 uint32_t tdb_magic = TDB_MAGIC; 39 40 hash_key.dptr = discard_const_p(unsigned char, TDB_MAGIC_FOOD); 41 hash_key.dsize = sizeof(TDB_MAGIC_FOOD); 42 *magic1_hash = tdb->hash_fn(&hash_key); 43 44 hash_key.dptr = (unsigned char *)CONVERT(tdb_magic); 45 hash_key.dsize = sizeof(tdb_magic); 46 *magic2_hash = tdb->hash_fn(&hash_key); 47 48 /* Make sure at least one hash is non-zero! */ 49 if (*magic1_hash == 0 && *magic2_hash == 0) 50 *magic1_hash = 1; 51 } 47 52 48 53 /* initialise a new database with a specified hash size */ … … 52 57 size_t size; 53 58 int ret = -1; 54 ssize_t written;55 59 56 60 /* We make it up in memory, then write it out if not internal */ … … 64 68 newdb->version = TDB_VERSION; 65 69 newdb->hash_size = hash_size; 70 71 tdb_header_hash(tdb, &newdb->magic1_hash, &newdb->magic2_hash); 72 73 /* Make sure older tdbs (which don't check the magic hash fields) 74 * will refuse to open this TDB. */ 75 if (tdb->flags & TDB_INCOMPATIBLE_HASH) 76 newdb->rwlocks = TDB_HASH_RWLOCK_MAGIC; 77 66 78 if (tdb->flags & TDB_INTERNAL) { 67 79 tdb->map_size = size; … … 84 96 memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1); 85 97 /* we still have "ret == -1" here */ 86 written = write(tdb->fd, newdb, size); 87 if (written == size) { 98 if (tdb_write_all(tdb->fd, newdb, size)) 88 99 ret = 0; 89 } else if (written != -1) {90 /* call write once again, this usually should return -1 and91 * set errno appropriately */92 size -= written;93 written = write(tdb->fd, newdb+written, size);94 if (written == size) {95 ret = 0;96 } else if (written >= 0) {97 /* a second incomplete write - we give up.98 * guessing the errno... */99 errno = ENOSPC;100 }101 }102 100 103 101 fail: … … 112 110 { 113 111 struct tdb_context *i; 114 112 115 113 for (i = tdbs; i; i = i->next) { 116 114 if (i->device == device && i->inode == ino) { … … 132 130 133 131 @param name may be NULL for internal databases. */ 134 struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,132 _PUBLIC_ struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags, 135 133 int open_flags, mode_t mode) 136 134 { … … 144 142 } 145 143 146 147 struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, 144 static bool check_header_hash(struct tdb_context *tdb, 145 bool default_hash, uint32_t *m1, uint32_t *m2) 146 { 147 tdb_header_hash(tdb, m1, m2); 148 if (tdb->header.magic1_hash == *m1 && 149 tdb->header.magic2_hash == *m2) { 150 return true; 151 } 152 153 /* If they explicitly set a hash, always respect it. */ 154 if (!default_hash) 155 return false; 156 157 /* Otherwise, try the other inbuilt hash. */ 158 if (tdb->hash_fn == tdb_old_hash) 159 tdb->hash_fn = tdb_jenkins_hash; 160 else 161 tdb->hash_fn = tdb_old_hash; 162 return check_header_hash(tdb, false, m1, m2); 163 } 164 165 _PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, 148 166 int open_flags, mode_t mode, 149 167 const struct tdb_logging_context *log_ctx, … … 156 174 uint32_t vertest; 157 175 unsigned v; 176 const char *hash_alg; 177 uint32_t magic1, magic2; 158 178 159 179 if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) { … … 177 197 tdb->log.log_private = NULL; 178 198 } 179 tdb->hash_fn = hash_fn ? hash_fn : default_tdb_hash; 199 200 if (name == NULL && (tdb_flags & TDB_INTERNAL)) { 201 name = "__TDB_INTERNAL__"; 202 } 203 204 if (name == NULL) { 205 tdb->name = discard_const_p(char, "__NULL__"); 206 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: called with name == NULL\n")); 207 tdb->name = NULL; 208 errno = EINVAL; 209 goto fail; 210 } 211 212 /* now make a copy of the name, as the caller memory might went away */ 213 if (!(tdb->name = (char *)strdup(name))) { 214 /* 215 * set the name as the given string, so that tdb_name() will 216 * work in case of an error. 217 */ 218 tdb->name = discard_const_p(char, name); 219 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't strdup(%s)\n", 220 name)); 221 tdb->name = NULL; 222 errno = ENOMEM; 223 goto fail; 224 } 225 226 if (hash_fn) { 227 tdb->hash_fn = hash_fn; 228 hash_alg = "the user defined"; 229 } else { 230 /* This controls what we use when creating a tdb. */ 231 if (tdb->flags & TDB_INCOMPATIBLE_HASH) { 232 tdb->hash_fn = tdb_jenkins_hash; 233 } else { 234 tdb->hash_fn = tdb_old_hash; 235 } 236 hash_alg = "either default"; 237 } 180 238 181 239 /* cache the page size */ … … 193 251 goto fail; 194 252 } 195 253 196 254 if (hash_size == 0) 197 255 hash_size = DEFAULT_HASH_SIZE; … … 212 270 } 213 271 272 if (getenv("TDB_NO_FSYNC")) { 273 tdb->flags |= TDB_NOSYNC; 274 } 275 214 276 /* 215 277 * TDB_ALLOW_NESTING is the default behavior. … … 242 304 243 305 /* ensure there is only one process initialising at once */ 244 if (tdb ->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {245 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get globallock on %s: %s\n",306 if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) { 307 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get open lock on %s: %s\n", 246 308 name, strerror(errno))); 247 309 goto fail; /* errno set by tdb_brlock */ … … 251 313 if ((tdb_flags & TDB_CLEAR_IF_FIRST) && 252 314 (!tdb->read_only) && 253 (locked = (tdb ->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0, 1) == 0))) {315 (locked = (tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE) == 0))) { 254 316 open_flags |= O_CREAT; 255 317 if (ftruncate(tdb->fd, 0) == -1) { … … 290 352 goto fail; 291 353 292 if (tdb->header.rwlocks != 0) { 354 if (tdb->header.rwlocks != 0 && 355 tdb->header.rwlocks != TDB_HASH_RWLOCK_MAGIC) { 293 356 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n")); 357 goto fail; 358 } 359 360 if ((tdb->header.magic1_hash == 0) && (tdb->header.magic2_hash == 0)) { 361 /* older TDB without magic hash references */ 362 tdb->hash_fn = tdb_old_hash; 363 } else if (!check_header_hash(tdb, !hash_fn, &magic1, &magic2)) { 364 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: " 365 "%s was not created with %s hash function we are using\n" 366 "magic1_hash[0x%08X %s 0x%08X] " 367 "magic2_hash[0x%08X %s 0x%08X]\n", 368 name, hash_alg, 369 tdb->header.magic1_hash, 370 (tdb->header.magic1_hash == magic1) ? "==" : "!=", 371 magic1, 372 tdb->header.magic2_hash, 373 (tdb->header.magic2_hash == magic2) ? "==" : "!=", 374 magic2)); 375 errno = EINVAL; 294 376 goto fail; 295 377 } … … 304 386 } 305 387 306 if (!(tdb->name = (char *)strdup(name))) {307 errno = ENOMEM;308 goto fail;309 }310 311 388 tdb->map_size = st.st_size; 312 389 tdb->device = st.st_dev; … … 314 391 tdb_mmap(tdb); 315 392 if (locked) { 316 if (tdb ->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0, 1) == -1) {393 if (tdb_nest_unlock(tdb, ACTIVE_LOCK, F_WRLCK, false) == -1) { 317 394 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: " 318 "failed to take ACTIVE_LOCK on %s: %s\n",395 "failed to release ACTIVE_LOCK on %s: %s\n", 319 396 name, strerror(errno))); 320 397 goto fail; … … 329 406 if (tdb_flags & TDB_CLEAR_IF_FIRST) { 330 407 /* leave this lock in place to indicate it's in use */ 331 if (tdb ->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)408 if (tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) { 332 409 goto fail; 410 } 333 411 } 334 412 … … 357 435 /* Internal (memory-only) databases skip all the code above to 358 436 * do with disk files, and resume here by releasing their 359 * global lock and hooking into the active list. */ 360 if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1) == -1) 361 goto fail; 437 * open lock and hooking into the active list. */ 438 if (tdb_nest_unlock(tdb, OPEN_LOCK, F_WRLCK, false) == -1) { 439 goto fail; 440 } 362 441 tdb->next = tdbs; 363 442 tdbs = tdb; … … 379 458 tdb_munmap(tdb); 380 459 } 381 SAFE_FREE(tdb->name);382 460 if (tdb->fd != -1) 383 461 if (close(tdb->fd) != 0) 384 462 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n")); 463 SAFE_FREE(tdb->lockrecs); 464 SAFE_FREE(tdb->name); 385 465 SAFE_FREE(tdb); 386 466 errno = save_errno; … … 393 473 */ 394 474 395 void tdb_set_max_dead(struct tdb_context *tdb, int max_dead)475 _PUBLIC_ void tdb_set_max_dead(struct tdb_context *tdb, int max_dead) 396 476 { 397 477 tdb->max_dead_records = max_dead; … … 403 483 * @returns -1 for error; 0 for success. 404 484 **/ 405 int tdb_close(struct tdb_context *tdb)485 _PUBLIC_ int tdb_close(struct tdb_context *tdb) 406 486 { 407 487 struct tdb_context **i; 408 488 int ret = 0; 409 489 490 if (tdb->transaction) { 491 tdb_transaction_cancel(tdb); 492 } 410 493 tdb_trace(tdb, "tdb_close"); 411 if (tdb->transaction) {412 _tdb_transaction_cancel(tdb);413 }414 494 415 495 if (tdb->map_ptr) { … … 444 524 445 525 /* register a loging function */ 446 void tdb_set_logging_function(struct tdb_context *tdb,447 const struct tdb_logging_context *log_ctx)526 _PUBLIC_ void tdb_set_logging_function(struct tdb_context *tdb, 527 const struct tdb_logging_context *log_ctx) 448 528 { 449 529 tdb->log = *log_ctx; 450 530 } 451 531 452 void *tdb_get_logging_private(struct tdb_context *tdb)532 _PUBLIC_ void *tdb_get_logging_private(struct tdb_context *tdb) 453 533 { 454 534 return tdb->log.log_private; … … 466 546 } 467 547 468 if (tdb ->num_locks != 0 || tdb->global_lock.count) {548 if (tdb_have_extra_locks(tdb)) { 469 549 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed with locks held\n")); 470 550 goto fail; … … 501 581 #endif /* fake pread or pwrite */ 502 582 503 if (active_lock && 504 (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)) { 583 /* We may still think we hold the active lock. */ 584 tdb->num_lockrecs = 0; 585 SAFE_FREE(tdb->lockrecs); 586 587 if (active_lock && tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) { 505 588 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n")); 506 589 goto fail; … … 516 599 /* reopen a tdb - this can be used after a fork to ensure that we have an independent 517 600 seek pointer from our parent and to re-establish locks */ 518 int tdb_reopen(struct tdb_context *tdb)601 _PUBLIC_ int tdb_reopen(struct tdb_context *tdb) 519 602 { 520 603 return tdb_reopen_internal(tdb, tdb->flags & TDB_CLEAR_IF_FIRST); … … 522 605 523 606 /* reopen all tdb's */ 524 int tdb_reopen_all(int parent_longlived)607 _PUBLIC_ int tdb_reopen_all(int parent_longlived) 525 608 { 526 609 struct tdb_context *tdb; -
vendor/current/lib/tdb/common/tdb.c
r414 r740 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 … … 28 28 #include "tdb_private.h" 29 29 30 TDB_DATA tdb_null;30 _PUBLIC_ TDB_DATA tdb_null; 31 31 32 32 /* … … 34 34 the TDB_SEQNUM flag 35 35 */ 36 void tdb_increment_seqnum_nonblock(struct tdb_context *tdb)36 _PUBLIC_ void tdb_increment_seqnum_nonblock(struct tdb_context *tdb) 37 37 { 38 38 tdb_off_t seqnum=0; 39 39 40 40 if (!(tdb->flags & TDB_SEQNUM)) { 41 41 return; … … 60 60 } 61 61 62 if (tdb_brlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, F_SETLKW, 1, 1) != 0) { 62 if (tdb_nest_lock(tdb, TDB_SEQNUM_OFS, F_WRLCK, 63 TDB_LOCK_WAIT|TDB_LOCK_PROBE) != 0) { 63 64 return; 64 65 } … … 66 67 tdb_increment_seqnum_nonblock(tdb); 67 68 68 tdb_ brlock(tdb, TDB_SEQNUM_OFS, F_UNLCK, F_SETLKW, 1, 1);69 tdb_nest_unlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, false); 69 70 } 70 71 … … 80 81 { 81 82 tdb_off_t rec_ptr; 82 83 83 84 /* read in the hash top */ 84 85 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) … … 154 155 } 155 156 } 156 157 157 158 158 /* must be long enough key, data and tailer */ … … 171 171 return tdb_rec_write(tdb, rec_ptr, &rec); 172 172 } 173 173 174 174 return 0; 175 175 } … … 200 200 } 201 201 202 TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)202 _PUBLIC_ TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key) 203 203 { 204 204 TDB_DATA ret = _tdb_fetch(tdb, key); … … 213 213 * should be fast and should not block on other syscalls. 214 214 * 215 * DON T CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS.215 * DON'T CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS. 216 216 * 217 217 * For mmapped tdb's that do not have a transaction open it points the parsing … … 222 222 * This is interesting for all readers of potentially large data structures in 223 223 * the tdb records, ldb indexes being one example. 224 * 225 * Return -1 if the record was not found. 224 226 */ 225 227 226 int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,228 _PUBLIC_ int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key, 227 229 int (*parser)(TDB_DATA key, TDB_DATA data, 228 230 void *private_data), … … 238 240 239 241 if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) { 242 /* record not found */ 240 243 tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, -1); 241 244 tdb->ecode = TDB_ERR_NOEXIST; 242 return 0;245 return -1; 243 246 } 244 247 tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, 0); … … 261 264 { 262 265 struct tdb_record rec; 263 266 264 267 if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0) 265 268 return 0; … … 268 271 } 269 272 270 int tdb_exists(struct tdb_context *tdb, TDB_DATA key)273 _PUBLIC_ int tdb_exists(struct tdb_context *tdb, TDB_DATA key) 271 274 { 272 275 uint32_t hash = tdb->hash_fn(&key); … … 319 322 tdb_off_t rec_ptr; 320 323 struct tdb_record rec; 321 324 322 325 /* read in the hash top */ 323 326 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) … … 348 351 return -1; 349 352 } 350 353 351 354 /* read in the hash top */ 352 355 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) … … 427 430 } 428 431 429 int tdb_delete(struct tdb_context *tdb, TDB_DATA key)432 _PUBLIC_ int tdb_delete(struct tdb_context *tdb, TDB_DATA key) 430 433 { 431 434 uint32_t hash = tdb->hash_fn(&key); … … 444 447 { 445 448 tdb_off_t rec_ptr; 446 449 447 450 /* read in the hash top */ 448 451 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) … … 597 600 return 0 on success, -1 on failure 598 601 */ 599 int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)602 _PUBLIC_ int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag) 600 603 { 601 604 uint32_t hash; … … 620 623 621 624 /* Append to an entry. Create if not exist. */ 622 int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)625 _PUBLIC_ int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf) 623 626 { 624 627 uint32_t hash; … … 659 662 ret = _tdb_store(tdb, key, dbuf, 0, hash); 660 663 tdb_trace_2rec_retrec(tdb, "tdb_append", key, new_dbuf, dbuf); 661 664 662 665 failed: 663 666 tdb_unlock(tdb, BUCKET(hash), F_WRLCK); … … 671 674 useful for external logging functions 672 675 */ 673 const char *tdb_name(struct tdb_context *tdb)676 _PUBLIC_ const char *tdb_name(struct tdb_context *tdb) 674 677 { 675 678 return tdb->name; … … 681 684 of the fd 682 685 */ 683 int tdb_fd(struct tdb_context *tdb)686 _PUBLIC_ int tdb_fd(struct tdb_context *tdb) 684 687 { 685 688 return tdb->fd; … … 690 693 useful for external tdb routines that wish to log tdb errors 691 694 */ 692 tdb_log_func tdb_log_fn(struct tdb_context *tdb)695 _PUBLIC_ tdb_log_func tdb_log_fn(struct tdb_context *tdb) 693 696 { 694 697 return tdb->log.log_fn; … … 706 709 test of a possible tdb change. 707 710 */ 708 int tdb_get_seqnum(struct tdb_context *tdb)711 _PUBLIC_ int tdb_get_seqnum(struct tdb_context *tdb) 709 712 { 710 713 tdb_off_t seqnum=0; … … 714 717 } 715 718 716 int tdb_hash_size(struct tdb_context *tdb)719 _PUBLIC_ int tdb_hash_size(struct tdb_context *tdb) 717 720 { 718 721 return tdb->header.hash_size; 719 722 } 720 723 721 size_t tdb_map_size(struct tdb_context *tdb)724 _PUBLIC_ size_t tdb_map_size(struct tdb_context *tdb) 722 725 { 723 726 return tdb->map_size; 724 727 } 725 728 726 int tdb_get_flags(struct tdb_context *tdb)729 _PUBLIC_ int tdb_get_flags(struct tdb_context *tdb) 727 730 { 728 731 return tdb->flags; 729 732 } 730 733 731 void tdb_add_flags(struct tdb_context *tdb, unsigned flags)734 _PUBLIC_ void tdb_add_flags(struct tdb_context *tdb, unsigned flags) 732 735 { 733 736 if ((flags & TDB_ALLOW_NESTING) && … … 749 752 } 750 753 751 void tdb_remove_flags(struct tdb_context *tdb, unsigned flags)754 _PUBLIC_ void tdb_remove_flags(struct tdb_context *tdb, unsigned flags) 752 755 { 753 756 if ((flags & TDB_ALLOW_NESTING) && … … 773 776 enable sequence number handling on an open tdb 774 777 */ 775 void tdb_enable_seqnum(struct tdb_context *tdb)778 _PUBLIC_ void tdb_enable_seqnum(struct tdb_context *tdb) 776 779 { 777 780 tdb->flags |= TDB_SEQNUM; … … 805 808 /* 806 809 wipe the entire database, deleting all records. This can be done 807 very fast by using a globallock. The entire data portion of the810 very fast by using a allrecord lock. The entire data portion of the 808 811 file becomes a single entry in the freelist. 809 812 810 813 This code carefully steps around the recovery area, leaving it alone 811 814 */ 812 int tdb_wipe_all(struct tdb_context *tdb)815 _PUBLIC_ int tdb_wipe_all(struct tdb_context *tdb) 813 816 { 814 817 int i; … … 917 920 repack a tdb 918 921 */ 919 int tdb_repack(struct tdb_context *tdb)922 _PUBLIC_ int tdb_repack(struct tdb_context *tdb) 920 923 { 921 924 struct tdb_context *tmp_db; … … 987 990 } 988 991 992 /* Even on files, we can get partial writes due to signals. */ 993 bool tdb_write_all(int fd, const void *buf, size_t count) 994 { 995 while (count) { 996 ssize_t ret; 997 ret = write(fd, buf, count); 998 if (ret < 0) 999 return false; 1000 buf = (const char *)buf + ret; 1001 count -= ret; 1002 } 1003 return true; 1004 } 1005 989 1006 #ifdef TDB_TRACE 990 1007 static void tdb_trace_write(struct tdb_context *tdb, const char *str) 991 1008 { 992 if ( write(tdb->tracefd, str, strlen(str)) !=strlen(str)) {1009 if (!tdb_write_alltdb->tracefd, str, strlen(str)) { 993 1010 close(tdb->tracefd); 994 1011 tdb->tracefd = -1; -
vendor/current/lib/tdb/common/tdb_private.h
r414 r740 5 5 6 6 Copyright (C) Andrew Tridgell 2005 7 7 8 8 ** NOTE! The following LGPL license applies to the tdb 9 9 ** library. This does NOT imply that all of Samba is released 10 10 ** under the LGPL 11 11 12 12 This library is free software; you can redistribute it and/or 13 13 modify it under the terms of the GNU Lesser General Public … … 50 50 #define TDB_DEAD_MAGIC (0xFEE1DEAD) 51 51 #define TDB_RECOVERY_MAGIC (0xf53bc0e7U) 52 #define TDB_RECOVERY_INVALID_MAGIC (0x0) 53 #define TDB_HASH_RWLOCK_MAGIC (0xbad1a51U) 52 54 #define TDB_ALIGNMENT 4 53 55 #define DEFAULT_HASH_SIZE 131 … … 102 104 103 105 /* lock offsets */ 104 #define GLOBAL_LOCK0106 #define OPEN_LOCK 0 105 107 #define ACTIVE_LOCK 4 106 108 #define TRANSACTION_LOCK 8 … … 147 149 tdb_off_t recovery_start; /* offset of transaction recovery region */ 148 150 tdb_off_t sequence_number; /* used when TDB_SEQNUM is set */ 149 tdb_off_t reserved[29]; 151 uint32_t magic1_hash; /* hash of TDB_MAGIC_FOOD. */ 152 uint32_t magic2_hash; /* hash of TDB_MAGIC. */ 153 tdb_off_t reserved[27]; 150 154 }; 151 155 152 156 struct tdb_lock_type { 153 int list;157 uint32_t off; 154 158 uint32_t count; 155 159 uint32_t ltype; … … 163 167 }; 164 168 169 enum tdb_lock_flags { 170 /* WAIT == F_SETLKW, NOWAIT == F_SETLK */ 171 TDB_LOCK_NOWAIT = 0, 172 TDB_LOCK_WAIT = 1, 173 /* If set, don't log an error on failure. */ 174 TDB_LOCK_PROBE = 2, 175 /* If set, don't actually lock at all. */ 176 TDB_LOCK_MARK_ONLY = 4, 177 }; 165 178 166 179 struct tdb_methods { … … 170 183 int (*tdb_oob)(struct tdb_context *, tdb_off_t , int ); 171 184 int (*tdb_expand_file)(struct tdb_context *, tdb_off_t , tdb_off_t ); 172 int (*tdb_brlock)(struct tdb_context *, tdb_off_t , int, int, int, size_t);173 185 }; 174 186 … … 181 193 int traverse_read; /* read-only traversal */ 182 194 int traverse_write; /* read-write traversal */ 183 struct tdb_lock_type global_lock;195 struct tdb_lock_type allrecord_lock; /* .offset == upgradable */ 184 196 int num_lockrecs; 185 197 struct tdb_lock_type *lockrecs; /* only real locks, all with count>0 */ … … 194 206 unsigned int (*hash_fn)(TDB_DATA *key); 195 207 int open_flags; /* flags used in the open - needed by reopen */ 196 unsigned int num_locks; /* number of chain locks held */197 208 const struct tdb_methods *methods; 198 209 struct tdb_transaction *transaction; 199 210 int page_size; 200 211 int max_dead_records; 201 int transaction_lock_count;202 212 #ifdef TDB_TRACE 203 213 int tracefd; … … 214 224 int tdb_lock(struct tdb_context *tdb, int list, int ltype); 215 225 int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype); 226 int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype, 227 enum tdb_lock_flags flags); 228 int tdb_nest_unlock(struct tdb_context *tdb, uint32_t offset, int ltype, 229 bool mark_lock); 216 230 int tdb_unlock(struct tdb_context *tdb, int list, int ltype); 217 int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset, int rw_type, int lck_type, int probe, size_t len); 218 int tdb_transaction_lock(struct tdb_context *tdb, int ltype); 219 int tdb_transaction_unlock(struct tdb_context *tdb); 220 int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len); 231 int tdb_brlock(struct tdb_context *tdb, 232 int rw_type, tdb_off_t offset, size_t len, 233 enum tdb_lock_flags flags); 234 int tdb_brunlock(struct tdb_context *tdb, 235 int rw_type, tdb_off_t offset, size_t len); 236 bool tdb_have_extra_locks(struct tdb_context *tdb); 237 void tdb_release_transaction_locks(struct tdb_context *tdb); 238 int tdb_transaction_lock(struct tdb_context *tdb, int ltype, 239 enum tdb_lock_flags lockflags); 240 int tdb_transaction_unlock(struct tdb_context *tdb, int ltype); 241 int tdb_recovery_area(struct tdb_context *tdb, 242 const struct tdb_methods *methods, 243 tdb_off_t *recovery_offset, 244 struct tdb_record *rec); 245 int tdb_allrecord_lock(struct tdb_context *tdb, int ltype, 246 enum tdb_lock_flags flags, bool upgradable); 247 int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock); 248 int tdb_allrecord_upgrade(struct tdb_context *tdb); 221 249 int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off); 222 250 int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off); … … 230 258 int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off); 231 259 int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off); 232 int _tdb_transaction_cancel(struct tdb_context *tdb);260 bool tdb_needs_recovery(struct tdb_context *tdb); 233 261 int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec); 234 262 int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec); … … 246 274 int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off, 247 275 struct tdb_record *rec); 248 249 276 bool tdb_write_all(int fd, const void *buf, size_t count); 277 int tdb_transaction_recover(struct tdb_context *tdb); 278 void tdb_header_hash(struct tdb_context *tdb, 279 uint32_t *magic1_hash, uint32_t *magic2_hash); 280 unsigned int tdb_old_hash(TDB_DATA *key); 281 size_t tdb_dead_space(struct tdb_context *tdb, tdb_off_t off); -
vendor/current/lib/tdb/common/transaction.c
r414 r740 9 9 ** library. This does NOT imply that all of Samba is released 10 10 ** under the LGPL 11 11 12 12 This library is free software; you can redistribute it and/or 13 13 modify it under the terms of the GNU Lesser General Public … … 60 60 existing transaction record. If the inner transaction is cancelled 61 61 then a subsequent commit will fail 62 62 63 63 - keep a mirrored copy of the tdb hash chain heads to allow for the 64 64 fast hash heads scan on traverse, updating the mirrored copy in … … 77 77 78 78 - check for a valid recovery record on open of the tdb, while the 79 globallock is held. Automatically recover from the transaction79 open lock is held. Automatically recover from the transaction 80 80 recovery area if needed, then continue with the open as 81 81 usual. This allows for smooth crash recovery with no administrator … … 136 136 tdb_off_t magic_offset; 137 137 138 /* set when the GLOBAL_LOCK has been taken */139 bool global_lock_taken;140 141 138 /* old file size before transaction */ 142 139 tdb_len_t old_map_size; 143 140 144 /* we should re-pack on commit*/145 bool need_repack;141 /* did we expand in this transaction */ 142 bool expanded; 146 143 }; 147 144 … … 189 186 } 190 187 } 191 188 192 189 /* now copy it out of this block */ 193 190 memcpy(buf, tdb->transaction->blocks[blk] + (off % tdb->transaction->block_size), len); … … 296 293 } 297 294 } 298 295 299 296 /* overwrite part of an existing block */ 300 297 if (buf == NULL) { … … 407 404 } 408 405 409 tdb->transaction->need_repack = true; 410 411 return 0; 412 } 413 414 /* 415 brlock during a transaction - ignore them 416 */ 417 static int transaction_brlock(struct tdb_context *tdb, tdb_off_t offset, 418 int rw_type, int lck_type, int probe, size_t len) 419 { 406 tdb->transaction->expanded = true; 407 420 408 return 0; 421 409 } … … 427 415 transaction_oob, 428 416 transaction_expand_file, 429 transaction_brlock430 417 }; 431 418 … … 435 422 transaction is allowed to be pending per tdb_context 436 423 */ 437 int tdb_transaction_start(struct tdb_context *tdb) 424 static int _tdb_transaction_start(struct tdb_context *tdb, 425 enum tdb_lock_flags lockflags) 438 426 { 439 427 /* some sanity checks */ … … 456 444 } 457 445 458 if (tdb ->num_locks != 0 || tdb->global_lock.count) {446 if (tdb_have_extra_locks(tdb)) { 459 447 /* the caller must not have any locks when starting a 460 448 transaction as otherwise we'll be screwed by lack … … 487 475 discussed with Volker, there are a number of ways we could 488 476 make this async, which we will probably do in the future */ 489 if (tdb_transaction_lock(tdb, F_WRLCK ) == -1) {477 if (tdb_transaction_lock(tdb, F_WRLCK, lockflags) == -1) { 490 478 SAFE_FREE(tdb->transaction->blocks); 491 479 SAFE_FREE(tdb->transaction); 492 return -1; 493 } 494 480 if ((lockflags & TDB_LOCK_WAIT) == 0) { 481 tdb->ecode = TDB_ERR_NOLOCK; 482 } 483 return -1; 484 } 485 495 486 /* get a read lock from the freelist to the end of file. This 496 487 is upgraded to a write lock during the commit */ 497 if (tdb_ brlock(tdb, FREELIST_TOP, F_RDLCK, F_SETLKW, 0, 0) == -1) {488 if (tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, true) == -1) { 498 489 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to get hash locks\n")); 499 tdb->ecode = TDB_ERR_LOCK; 500 goto fail; 490 goto fail_allrecord_lock; 501 491 } 502 492 … … 529 519 tdb_trace(tdb, "tdb_transaction_start"); 530 520 return 0; 531 521 532 522 fail: 533 tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0); 534 tdb_transaction_unlock(tdb); 523 tdb_allrecord_unlock(tdb, F_RDLCK, false); 524 fail_allrecord_lock: 525 tdb_transaction_unlock(tdb, F_WRLCK); 535 526 SAFE_FREE(tdb->transaction->blocks); 536 527 SAFE_FREE(tdb->transaction->hash_heads); … … 539 530 } 540 531 532 _PUBLIC_ int tdb_transaction_start(struct tdb_context *tdb) 533 { 534 return _tdb_transaction_start(tdb, TDB_LOCK_WAIT); 535 } 536 537 _PUBLIC_ int tdb_transaction_start_nonblock(struct tdb_context *tdb) 538 { 539 return _tdb_transaction_start(tdb, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE); 540 } 541 541 542 542 /* … … 549 549 } 550 550 551 #ifdef HAVE_FDATASYNC 552 if (fdatasync(tdb->fd) != 0) { 553 #else 551 554 if (fsync(tdb->fd) != 0) { 555 #endif 552 556 tdb->ecode = TDB_ERR_IO; 553 557 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n")); … … 570 574 571 575 572 int _tdb_transaction_cancel(struct tdb_context *tdb)576 static int _tdb_transaction_cancel(struct tdb_context *tdb) 573 577 { 574 578 int i, ret = 0; … … 597 601 if (tdb->transaction->magic_offset) { 598 602 const struct tdb_methods *methods = tdb->transaction->io_methods; 599 uint32_t zero = 0;603 const uint32_t invalid = TDB_RECOVERY_INVALID_MAGIC; 600 604 601 605 /* remove the recovery marker */ 602 if (methods->tdb_write(tdb, tdb->transaction->magic_offset, & zero, 4) == -1 ||606 if (methods->tdb_write(tdb, tdb->transaction->magic_offset, &invalid, 4) == -1 || 603 607 transaction_sync(tdb, tdb->transaction->magic_offset, 4) == -1) { 604 608 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_cancel: failed to remove recovery magic\n")); … … 607 611 } 608 612 609 if (tdb->transaction->global_lock_taken) { 610 tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1); 611 tdb->transaction->global_lock_taken = false; 612 } 613 614 /* remove any global lock created during the transaction */ 615 if (tdb->global_lock.count != 0) { 616 tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 4*tdb->header.hash_size); 617 tdb->global_lock.count = 0; 618 } 619 620 /* remove any locks created during the transaction */ 621 if (tdb->num_locks != 0) { 622 for (i=0;i<tdb->num_lockrecs;i++) { 623 tdb_brlock(tdb,FREELIST_TOP+4*tdb->lockrecs[i].list, 624 F_UNLCK,F_SETLKW, 0, 1); 625 } 626 tdb->num_locks = 0; 627 tdb->num_lockrecs = 0; 628 SAFE_FREE(tdb->lockrecs); 629 } 613 /* This also removes the OPEN_LOCK, if we have it. */ 614 tdb_release_transaction_locks(tdb); 630 615 631 616 /* restore the normal io methods */ 632 617 tdb->methods = tdb->transaction->io_methods; 633 618 634 tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0);635 tdb_transaction_unlock(tdb);636 619 SAFE_FREE(tdb->transaction->hash_heads); 637 620 SAFE_FREE(tdb->transaction); 638 621 639 622 return ret; 640 623 } … … 643 626 cancel the current transaction 644 627 */ 645 int tdb_transaction_cancel(struct tdb_context *tdb)628 _PUBLIC_ int tdb_transaction_cancel(struct tdb_context *tdb) 646 629 { 647 630 tdb_trace(tdb, "tdb_transaction_cancel"); … … 676 659 } 677 660 661 int tdb_recovery_area(struct tdb_context *tdb, 662 const struct tdb_methods *methods, 663 tdb_off_t *recovery_offset, 664 struct tdb_record *rec) 665 { 666 if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, recovery_offset) == -1) { 667 return -1; 668 } 669 670 if (*recovery_offset == 0) { 671 rec->rec_len = 0; 672 return 0; 673 } 674 675 if (methods->tdb_read(tdb, *recovery_offset, rec, sizeof(*rec), 676 DOCONV()) == -1) { 677 return -1; 678 } 679 680 /* ignore invalid recovery regions: can happen in crash */ 681 if (rec->magic != TDB_RECOVERY_MAGIC && 682 rec->magic != TDB_RECOVERY_INVALID_MAGIC) { 683 *recovery_offset = 0; 684 rec->rec_len = 0; 685 } 686 return 0; 687 } 688 678 689 /* 679 690 allocate the recovery area, or use an existing recovery area if it is … … 689 700 tdb_off_t recovery_head; 690 701 691 if (tdb_ ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {702 if (tdb_recovery_area(tdb, methods, &recovery_head, &rec) == -1) { 692 703 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery head\n")); 693 return -1;694 }695 696 rec.rec_len = 0;697 698 if (recovery_head != 0 &&699 methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {700 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery record\n"));701 704 return -1; 702 705 } … … 794 797 memset(rec, 0, sizeof(*rec)); 795 798 796 rec->magic = 0;799 rec->magic = TDB_RECOVERY_INVALID_MAGIC; 797 800 rec->data_len = recovery_size; 798 801 rec->rec_len = recovery_max_size; 799 802 rec->key_len = old_map_size; 800 CONVERT( rec);803 CONVERT(*rec); 801 804 802 805 /* build the recovery data into a single blob to allow us to do a single … … 816 819 length = tdb->transaction->last_block_size; 817 820 } 818 821 819 822 if (offset >= old_map_size) { 820 823 continue; … … 845 848 tailer = sizeof(*rec) + recovery_max_size; 846 849 memcpy(p, &tailer, 4); 847 CONVERT(p); 850 if (DOCONV()) { 851 tdb_convert(p, 4); 852 } 848 853 849 854 /* write the recovery data to the recovery area */ … … 929 934 930 935 methods = tdb->transaction->io_methods; 931 936 932 937 /* if there are any locks pending then the caller has not 933 938 nested their locks properly, so fail the transaction */ 934 if (tdb ->num_locks || tdb->global_lock.count) {939 if (tdb_have_extra_locks(tdb)) { 935 940 tdb->ecode = TDB_ERR_LOCK; 936 941 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: locks pending on commit\n")); … … 940 945 941 946 /* upgrade the main transaction lock region to a write lock */ 942 if (tdb_ brlock_upgrade(tdb, FREELIST_TOP, 0) == -1) {947 if (tdb_allrecord_upgrade(tdb) == -1) { 943 948 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to upgrade hash locks\n")); 944 tdb->ecode = TDB_ERR_LOCK;945 949 _tdb_transaction_cancel(tdb); 946 950 return -1; 947 951 } 948 952 949 /* get the globallock - this prevents new users attaching to the database953 /* get the open lock - this prevents new users attaching to the database 950 954 during the commit */ 951 if (tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) { 952 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to get global lock\n")); 953 tdb->ecode = TDB_ERR_LOCK; 955 if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) { 956 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to get open lock\n")); 954 957 _tdb_transaction_cancel(tdb); 955 958 return -1; 956 959 } 957 958 tdb->transaction->global_lock_taken = true;959 960 960 961 if (!(tdb->flags & TDB_NOSYNC)) { … … 983 984 } 984 985 985 /* Keep the globallock until the actual commit */986 /* Keep the open lock until the actual commit */ 986 987 987 988 return 0; … … 991 992 prepare to commit the current transaction 992 993 */ 993 int tdb_transaction_prepare_commit(struct tdb_context *tdb)994 { 994 _PUBLIC_ int tdb_transaction_prepare_commit(struct tdb_context *tdb) 995 { 995 996 tdb_trace(tdb, "tdb_transaction_prepare_commit"); 996 997 return _tdb_transaction_prepare_commit(tdb); 997 998 } 998 999 1000 /* A repack is worthwhile if the largest is less than half total free. */ 1001 static bool repack_worthwhile(struct tdb_context *tdb) 1002 { 1003 tdb_off_t ptr; 1004 struct tdb_record rec; 1005 tdb_len_t total = 0, largest = 0; 1006 1007 if (tdb_ofs_read(tdb, FREELIST_TOP, &ptr) == -1) { 1008 return false; 1009 } 1010 1011 while (ptr != 0 && tdb_rec_free_read(tdb, ptr, &rec) == 0) { 1012 total += rec.rec_len; 1013 if (rec.rec_len > largest) { 1014 largest = rec.rec_len; 1015 } 1016 ptr = rec.next; 1017 } 1018 1019 return total > largest * 2; 1020 } 1021 999 1022 /* 1000 1023 commit the current transaction 1001 1024 */ 1002 int tdb_transaction_commit(struct tdb_context *tdb)1003 { 1025 _PUBLIC_ int tdb_transaction_commit(struct tdb_context *tdb) 1026 { 1004 1027 const struct tdb_methods *methods; 1005 1028 int i; 1006 bool need_repack ;1029 bool need_repack = false; 1007 1030 1008 1031 if (tdb->transaction == NULL) { … … 1057 1080 if (methods->tdb_write(tdb, offset, tdb->transaction->blocks[i], length) == -1) { 1058 1081 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed during commit\n")); 1059 1082 1060 1083 /* we've overwritten part of the data and 1061 1084 possibly expanded the file, so we need to … … 1071 1094 SAFE_FREE(tdb->transaction->blocks[i]); 1072 1095 } 1096 1097 /* Do this before we drop lock or blocks. */ 1098 if (tdb->transaction->expanded) { 1099 need_repack = repack_worthwhile(tdb); 1100 } 1073 1101 1074 1102 SAFE_FREE(tdb->transaction->blocks); … … 1095 1123 #endif 1096 1124 1097 need_repack = tdb->transaction->need_repack;1098 1099 1125 /* use a transaction cancel to free memory and remove the 1100 1126 transaction locks */ … … 1111 1137 /* 1112 1138 recover from an aborted transaction. Must be called with exclusive 1113 database write access already established (including the global1139 database write access already established (including the open 1114 1140 lock to prevent new processes attaching) 1115 1141 */ … … 1212 1238 return -1; 1213 1239 } 1214 1215 /* reduce the file size to the old size */1216 tdb_munmap(tdb);1217 if (ftruncate(tdb->fd, recovery_eof) != 0) {1218 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to reduce to recovery size\n"));1219 tdb->ecode = TDB_ERR_IO;1220 return -1;1221 }1222 tdb->map_size = recovery_eof;1223 tdb_mmap(tdb);1224 1240 1225 1241 if (transaction_sync(tdb, 0, recovery_eof) == -1) { … … 1235 1251 return 0; 1236 1252 } 1253 1254 /* Any I/O failures we say "needs recovery". */ 1255 bool tdb_needs_recovery(struct tdb_context *tdb) 1256 { 1257 tdb_off_t recovery_head; 1258 struct tdb_record rec; 1259 1260 /* find the recovery area */ 1261 if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) { 1262 return true; 1263 } 1264 1265 if (recovery_head == 0) { 1266 /* we have never allocated a recovery record */ 1267 return false; 1268 } 1269 1270 /* read the recovery record */ 1271 if (tdb->methods->tdb_read(tdb, recovery_head, &rec, 1272 sizeof(rec), DOCONV()) == -1) { 1273 return true; 1274 } 1275 1276 return (rec.magic == TDB_RECOVERY_MAGIC); 1277 } -
vendor/current/lib/tdb/common/traverse.c
r414 r740 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 … … 45 45 hashes are used. In that case we spend most of our 46 46 time in tdb_brlock(), locking empty hash chains. 47 47 48 48 To avoid this, we do an unlocked pre-check to see 49 49 if the hash chain is empty before starting to look … … 53 53 lock, so instead we get the lock and re-fetch the 54 54 value below. 55 55 56 56 Notice that not doing this optimisation on the 57 57 first hash chain is critical. We must guarantee … … 63 63 could miss them anyway without this trick, so the 64 64 semantics don't change. 65 65 66 66 With a non-indexed ldb search this trick gains us a 67 67 factor of around 80 in speed on a linux 2.6.x … … 213 213 a write style traverse - temporarily marks the db read only 214 214 */ 215 int tdb_traverse_read(struct tdb_context *tdb,215 _PUBLIC_ int tdb_traverse_read(struct tdb_context *tdb, 216 216 tdb_traverse_func fn, void *private_data) 217 217 { … … 221 221 /* we need to get a read lock on the transaction lock here to 222 222 cope with the lock ordering semantics of solaris10 */ 223 if (tdb_transaction_lock(tdb, F_RDLCK )) {223 if (tdb_transaction_lock(tdb, F_RDLCK, TDB_LOCK_WAIT)) { 224 224 return -1; 225 225 } … … 230 230 tdb->traverse_read--; 231 231 232 tdb_transaction_unlock(tdb );232 tdb_transaction_unlock(tdb, F_RDLCK); 233 233 234 234 return ret; … … 242 242 alignment restrictions malloc gives you. 243 243 */ 244 int tdb_traverse(struct tdb_context *tdb,244 _PUBLIC_ int tdb_traverse(struct tdb_context *tdb, 245 245 tdb_traverse_func fn, void *private_data) 246 246 { … … 252 252 } 253 253 254 if (tdb_transaction_lock(tdb, F_WRLCK )) {254 if (tdb_transaction_lock(tdb, F_WRLCK, TDB_LOCK_WAIT)) { 255 255 return -1; 256 256 } … … 261 261 tdb->traverse_write--; 262 262 263 tdb_transaction_unlock(tdb );263 tdb_transaction_unlock(tdb, F_WRLCK); 264 264 265 265 return ret; … … 268 268 269 269 /* find the first entry in the database and return its key */ 270 TDB_DATA tdb_firstkey(struct tdb_context *tdb)270 _PUBLIC_ TDB_DATA tdb_firstkey(struct tdb_context *tdb) 271 271 { 272 272 TDB_DATA key; … … 299 299 300 300 /* find the next entry in the database, returning its key */ 301 TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)301 _PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey) 302 302 { 303 303 uint32_t oldhash;
Note:
See TracChangeset
for help on using the changeset viewer.