source: trunk/server/lib/tdb/common/open.c@ 895

Last change on this file since 895 was 895, checked in by Silvan Scherrer, 10 years ago

tdb: Use DosSetFileLocks directly for db locks.

This is to overcome some fcntl() API incompleteness in kLIBC
(like inability to upgrade locks or join adjacent lock regions
into one). It made the torture test run a bit better but there
are still two major problems both coming from DosSetFileLocks
impl (which fcntl() is currently based upon too): a) inability to
detect deadlocks and b) missing atomic unlock/lock support if
unlock/lock regions don't match.

With the current implementation, tdborture works fine for 1 or 2
worker processes but hangs when there are 3 or more. [Before that,
it would only work with 1 process and would likely to corrupt
the database and terminate if there were 2 or more processes].

Author: Dmitriy Kuminov (@dmik).

File size: 18.4 KB
Line 
1 /*
2 Unix SMB/CIFS implementation.
3
4 trivial database library
5
6 Copyright (C) Andrew Tridgell 1999-2005
7 Copyright (C) Paul `Rusty' Russell 2000
8 Copyright (C) Jeremy Allison 2000-2003
9
10 ** NOTE! The following LGPL license applies to the tdb
11 ** library. This does NOT imply that all of Samba is released
12 ** under the LGPL
13
14 This library is free software; you can redistribute it and/or
15 modify it under the terms of the GNU Lesser General Public
16 License as published by the Free Software Foundation; either
17 version 3 of the License, or (at your option) any later version.
18
19 This library is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 Lesser General Public License for more details.
23
24 You should have received a copy of the GNU Lesser General Public
25 License along with this library; if not, see <http://www.gnu.org/licenses/>.
26*/
27
28#include "tdb_private.h"
29
30/* all contexts, to ensure no double-opens (fcntl locks don't nest!) */
31static struct tdb_context *tdbs = NULL;
32
33/* We use two hashes to double-check they're using the right hash function. */
34void 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}
52
53/* initialise a new database with a specified hash size */
54static int tdb_new_database(struct tdb_context *tdb, int hash_size)
55{
56 struct tdb_header *newdb;
57 size_t size;
58 int ret = -1;
59
60 /* We make it up in memory, then write it out if not internal */
61 size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off_t);
62 if (!(newdb = (struct tdb_header *)calloc(size, 1))) {
63 tdb->ecode = TDB_ERR_OOM;
64 return -1;
65 }
66
67 /* Fill in the header */
68 newdb->version = TDB_VERSION;
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
78 if (tdb->flags & TDB_INTERNAL) {
79 tdb->map_size = size;
80 tdb->map_ptr = (char *)newdb;
81 memcpy(&tdb->header, newdb, sizeof(tdb->header));
82 /* Convert the `ondisk' version if asked. */
83 CONVERT(*newdb);
84 return 0;
85 }
86 if (lseek(tdb->fd, 0, SEEK_SET) == -1)
87 goto fail;
88
89 if (ftruncate(tdb->fd, 0) == -1)
90 goto fail;
91
92 /* This creates an endian-converted header, as if read from disk */
93 CONVERT(*newdb);
94 memcpy(&tdb->header, newdb, sizeof(tdb->header));
95 /* Don't endian-convert the magic food! */
96 memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
97 /* we still have "ret == -1" here */
98 if (tdb_write_all(tdb->fd, newdb, size))
99 ret = 0;
100
101 fail:
102 SAFE_FREE(newdb);
103 return ret;
104}
105
106
107
108static int tdb_already_open(dev_t device,
109 ino_t ino)
110{
111 struct tdb_context *i;
112
113 for (i = tdbs; i; i = i->next) {
114 if (i->device == device && i->inode == ino) {
115 return 1;
116 }
117 }
118
119 return 0;
120}
121
122/* open the database, creating it if necessary
123
124 The open_flags and mode are passed straight to the open call on the
125 database file. A flags value of O_WRONLY is invalid. The hash size
126 is advisory, use zero for a default value.
127
128 Return is NULL on error, in which case errno is also set. Don't
129 try to call tdb_error or tdb_errname, just do strerror(errno).
130
131 @param name may be NULL for internal databases. */
132_PUBLIC_ struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
133 int open_flags, mode_t mode)
134{
135 return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL, NULL);
136}
137
138/* a default logging function */
139static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
140static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
141{
142}
143
144static 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#ifdef __OS2__
166static int os2_create_lockfile(struct tdb_context *tdb, const char *name, const char *origin)
167{
168 /* name could be null, so handle it */
169 if (name == NULL)
170 return 0;
171
172 char lock_name[_MAX_PATH + 5];
173 snprintf(lock_name, sizeof(lock_name), "%s.lock", name);
174 tdb->lock_fd = open(lock_name, tdb->open_flags | O_CREAT | O_TRUNC, 0777);
175 if (tdb->lock_fd == -1) {
176 TDB_LOG((tdb, TDB_DEBUG_ERROR, "os2_create_lockfile: cannot create lock file %s, errno=%d\n",
177 lock_name, errno));
178 return -1;
179 }
180
181 return 0;
182}
183#endif
184
185_PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
186 int open_flags, mode_t mode,
187 const struct tdb_logging_context *log_ctx,
188 tdb_hash_func hash_fn)
189{
190 struct tdb_context *tdb;
191 struct stat st;
192 int rev = 0, locked = 0;
193 unsigned char *vp;
194 uint32_t vertest;
195 unsigned v;
196 const char *hash_alg;
197 uint32_t magic1, magic2;
198
199 if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) {
200 /* Can't log this */
201 errno = ENOMEM;
202 goto fail;
203 }
204 tdb_io_init(tdb);
205 tdb->fd = -1;
206#ifdef TDB_TRACE
207 tdb->tracefd = -1;
208#endif
209 tdb->name = NULL;
210 tdb->map_ptr = NULL;
211 tdb->flags = tdb_flags;
212 tdb->open_flags = open_flags;
213 if (log_ctx) {
214 tdb->log = *log_ctx;
215 } else {
216 tdb->log.log_fn = null_log_fn;
217 tdb->log.log_private = NULL;
218 }
219
220 if (name == NULL && (tdb_flags & TDB_INTERNAL)) {
221 name = "__TDB_INTERNAL__";
222 }
223
224 if (name == NULL) {
225 tdb->name = discard_const_p(char, "__NULL__");
226 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: called with name == NULL\n"));
227 tdb->name = NULL;
228 errno = EINVAL;
229 goto fail;
230 }
231
232 /* now make a copy of the name, as the caller memory might went away */
233 if (!(tdb->name = (char *)strdup(name))) {
234 /*
235 * set the name as the given string, so that tdb_name() will
236 * work in case of an error.
237 */
238 tdb->name = discard_const_p(char, name);
239 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't strdup(%s)\n",
240 name));
241 tdb->name = NULL;
242 errno = ENOMEM;
243 goto fail;
244 }
245
246 if (hash_fn) {
247 tdb->hash_fn = hash_fn;
248 hash_alg = "the user defined";
249 } else {
250 /* This controls what we use when creating a tdb. */
251 if (tdb->flags & TDB_INCOMPATIBLE_HASH) {
252 tdb->hash_fn = tdb_jenkins_hash;
253 } else {
254 tdb->hash_fn = tdb_old_hash;
255 }
256 hash_alg = "either default";
257 }
258
259 /* cache the page size */
260 tdb->page_size = getpagesize();
261 if (tdb->page_size <= 0) {
262 tdb->page_size = 0x2000;
263 }
264
265 tdb->max_dead_records = (tdb_flags & TDB_VOLATILE) ? 5 : 0;
266
267 if ((open_flags & O_ACCMODE) == O_WRONLY) {
268 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't open tdb %s write-only\n",
269 name));
270 errno = EINVAL;
271 goto fail;
272 }
273
274 if (hash_size == 0)
275 hash_size = DEFAULT_HASH_SIZE;
276 if ((open_flags & O_ACCMODE) == O_RDONLY) {
277 tdb->read_only = 1;
278 /* read only databases don't do locking or clear if first */
279 tdb->flags |= TDB_NOLOCK;
280 tdb->flags &= ~TDB_CLEAR_IF_FIRST;
281 }
282
283 if ((tdb->flags & TDB_ALLOW_NESTING) &&
284 (tdb->flags & TDB_DISALLOW_NESTING)) {
285 tdb->ecode = TDB_ERR_NESTING;
286 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
287 "allow_nesting and disallow_nesting are not allowed together!"));
288 errno = EINVAL;
289 goto fail;
290 }
291
292 if (getenv("TDB_NO_FSYNC")) {
293 tdb->flags |= TDB_NOSYNC;
294 }
295
296 /*
297 * TDB_ALLOW_NESTING is the default behavior.
298 * Note: this may change in future versions!
299 */
300 if (!(tdb->flags & TDB_DISALLOW_NESTING)) {
301 tdb->flags |= TDB_ALLOW_NESTING;
302 }
303
304 /* internal databases don't mmap or lock, and start off cleared */
305 if (tdb->flags & TDB_INTERNAL) {
306 tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
307 tdb->flags &= ~TDB_CLEAR_IF_FIRST;
308 if (tdb_new_database(tdb, hash_size) != 0) {
309 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: tdb_new_database failed!"));
310 goto fail;
311 }
312 goto internal;
313 }
314
315 if ((tdb->fd = open(name, open_flags, mode)) == -1) {
316 TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_open_ex: could not open file %s: %s\n",
317 name, strerror(errno)));
318 goto fail; /* errno set by open(2) */
319 }
320
321 /* on exec, don't inherit the fd */
322 v = fcntl(tdb->fd, F_GETFD, 0);
323 fcntl(tdb->fd, F_SETFD, v | FD_CLOEXEC);
324
325#ifdef __OS2__
326 if (os2_create_lockfile(tdb, name, "tdb_open_ex") != 0)
327 goto fail;
328#endif
329
330 /* ensure there is only one process initialising at once */
331 if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) {
332 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get open lock on %s: %s\n",
333 name, strerror(errno)));
334 goto fail; /* errno set by tdb_brlock */
335 }
336
337 /* we need to zero database if we are the only one with it open */
338 if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
339 (!tdb->read_only) &&
340 (locked = (tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE) == 0))) {
341 int ret;
342 ret = tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0,
343 TDB_LOCK_WAIT);
344 if (ret == -1) {
345 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
346 "tdb_brlock failed for %s: %s\n",
347 name, strerror(errno)));
348 goto fail;
349 }
350 ret = tdb_new_database(tdb, hash_size);
351 if (ret == -1) {
352 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
353 "tdb_new_database failed for %s: %s\n",
354 name, strerror(errno)));
355 tdb_unlockall(tdb);
356 goto fail;
357 }
358 ret = tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0);
359 if (ret == -1) {
360 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
361 "tdb_unlockall failed for %s: %s\n",
362 name, strerror(errno)));
363 goto fail;
364 }
365 ret = lseek(tdb->fd, 0, SEEK_SET);
366 if (ret == -1) {
367 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
368 "lseek failed for %s: %s\n",
369 name, strerror(errno)));
370 goto fail;
371 }
372 }
373
374 errno = 0;
375 if (read(tdb->fd, &tdb->header, sizeof(tdb->header)) != sizeof(tdb->header)
376 || strcmp(tdb->header.magic_food, TDB_MAGIC_FOOD) != 0) {
377 if (!(open_flags & O_CREAT) || tdb_new_database(tdb, hash_size) == -1) {
378 if (errno == 0) {
379 errno = EIO; /* ie bad format or something */
380 }
381 goto fail;
382 }
383 rev = (tdb->flags & TDB_CONVERT);
384 } else if (tdb->header.version != TDB_VERSION
385 && !(rev = (tdb->header.version==TDB_BYTEREV(TDB_VERSION)))) {
386 /* wrong version */
387 errno = EIO;
388 goto fail;
389 }
390 vp = (unsigned char *)&tdb->header.version;
391 vertest = (((uint32_t)vp[0]) << 24) | (((uint32_t)vp[1]) << 16) |
392 (((uint32_t)vp[2]) << 8) | (uint32_t)vp[3];
393 tdb->flags |= (vertest==TDB_VERSION) ? TDB_BIGENDIAN : 0;
394 if (!rev)
395 tdb->flags &= ~TDB_CONVERT;
396 else {
397 tdb->flags |= TDB_CONVERT;
398 tdb_convert(&tdb->header, sizeof(tdb->header));
399 }
400 if (fstat(tdb->fd, &st) == -1)
401 goto fail;
402
403 if (tdb->header.rwlocks != 0 &&
404 tdb->header.rwlocks != TDB_HASH_RWLOCK_MAGIC) {
405 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n"));
406 goto fail;
407 }
408
409 if ((tdb->header.magic1_hash == 0) && (tdb->header.magic2_hash == 0)) {
410 /* older TDB without magic hash references */
411 tdb->hash_fn = tdb_old_hash;
412 } else if (!check_header_hash(tdb, !hash_fn, &magic1, &magic2)) {
413 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
414 "%s was not created with %s hash function we are using\n"
415 "magic1_hash[0x%08X %s 0x%08X] "
416 "magic2_hash[0x%08X %s 0x%08X]\n",
417 name, hash_alg,
418 tdb->header.magic1_hash,
419 (tdb->header.magic1_hash == magic1) ? "==" : "!=",
420 magic1,
421 tdb->header.magic2_hash,
422 (tdb->header.magic2_hash == magic2) ? "==" : "!=",
423 magic2));
424 errno = EINVAL;
425 goto fail;
426 }
427
428 /* Is it already in the open list? If so, fail. */
429 if (tdb_already_open(st.st_dev, st.st_ino)) {
430 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
431 "%s (%d,%d) is already open in this process\n",
432 name, (int)st.st_dev, (int)st.st_ino));
433 errno = EBUSY;
434 goto fail;
435 }
436
437 tdb->map_size = st.st_size;
438 tdb->device = st.st_dev;
439 tdb->inode = st.st_ino;
440 tdb_mmap(tdb);
441 if (locked) {
442 if (tdb_nest_unlock(tdb, ACTIVE_LOCK, F_WRLCK, false) == -1) {
443 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
444 "failed to release ACTIVE_LOCK on %s: %s\n",
445 name, strerror(errno)));
446 goto fail;
447 }
448
449 }
450
451 /* We always need to do this if the CLEAR_IF_FIRST flag is set, even if
452 we didn't get the initial exclusive lock as we need to let all other
453 users know we're using it. */
454
455 if (tdb_flags & TDB_CLEAR_IF_FIRST) {
456 /* leave this lock in place to indicate it's in use */
457 if (tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) {
458 goto fail;
459 }
460 }
461
462 /* if needed, run recovery */
463 if (tdb_transaction_recover(tdb) == -1) {
464 goto fail;
465 }
466
467#ifdef TDB_TRACE
468 {
469 char tracefile[strlen(name) + 32];
470
471 snprintf(tracefile, sizeof(tracefile),
472 "%s.trace.%li", name, (long)getpid());
473 tdb->tracefd = open(tracefile, O_WRONLY|O_CREAT|O_EXCL, 0600);
474 if (tdb->tracefd >= 0) {
475 tdb_enable_seqnum(tdb);
476 tdb_trace_open(tdb, "tdb_open", hash_size, tdb_flags,
477 open_flags);
478 } else
479 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to open trace file %s!\n", tracefile));
480 }
481#endif
482
483 internal:
484 /* Internal (memory-only) databases skip all the code above to
485 * do with disk files, and resume here by releasing their
486 * open lock and hooking into the active list. */
487 if (tdb_nest_unlock(tdb, OPEN_LOCK, F_WRLCK, false) == -1) {
488 goto fail;
489 }
490 tdb->next = tdbs;
491 tdbs = tdb;
492 return tdb;
493
494 fail:
495 { int save_errno = errno;
496
497#ifdef __OS2__
498 close(tdb->lock_fd);
499 tdb->lock_fd = -1;
500#endif
501 if (!tdb)
502 return NULL;
503
504#ifdef TDB_TRACE
505 close(tdb->tracefd);
506#endif
507 if (tdb->map_ptr) {
508 if (tdb->flags & TDB_INTERNAL)
509 SAFE_FREE(tdb->map_ptr);
510 else
511 tdb_munmap(tdb);
512 }
513 if (tdb->fd != -1)
514 if (close(tdb->fd) != 0)
515 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n"));
516 SAFE_FREE(tdb->lockrecs);
517 SAFE_FREE(tdb->name);
518 SAFE_FREE(tdb);
519 errno = save_errno;
520 return NULL;
521 }
522}
523
524/*
525 * Set the maximum number of dead records per hash chain
526 */
527
528_PUBLIC_ void tdb_set_max_dead(struct tdb_context *tdb, int max_dead)
529{
530 tdb->max_dead_records = max_dead;
531}
532
533/**
534 * Close a database.
535 *
536 * @returns -1 for error; 0 for success.
537 **/
538_PUBLIC_ int tdb_close(struct tdb_context *tdb)
539{
540 struct tdb_context **i;
541 int ret = 0;
542
543 if (tdb->transaction) {
544 tdb_transaction_cancel(tdb);
545 }
546 tdb_trace(tdb, "tdb_close");
547
548 if (tdb->map_ptr) {
549 if (tdb->flags & TDB_INTERNAL)
550 SAFE_FREE(tdb->map_ptr);
551 else
552 tdb_munmap(tdb);
553 }
554 SAFE_FREE(tdb->name);
555 if (tdb->fd != -1) {
556 ret = close(tdb->fd);
557 tdb->fd = -1;
558 }
559 SAFE_FREE(tdb->lockrecs);
560
561 /* Remove from contexts list */
562 for (i = &tdbs; *i; i = &(*i)->next) {
563 if (*i == tdb) {
564 *i = tdb->next;
565 break;
566 }
567 }
568
569#ifdef __OS2__
570 close(tdb->lock_fd);
571 tdb->lock_fd = -1;
572#endif
573
574#ifdef TDB_TRACE
575 close(tdb->tracefd);
576#endif
577 memset(tdb, 0, sizeof(*tdb));
578 SAFE_FREE(tdb);
579
580 return ret;
581}
582
583/* register a loging function */
584_PUBLIC_ void tdb_set_logging_function(struct tdb_context *tdb,
585 const struct tdb_logging_context *log_ctx)
586{
587 tdb->log = *log_ctx;
588}
589
590_PUBLIC_ void *tdb_get_logging_private(struct tdb_context *tdb)
591{
592 return tdb->log.log_private;
593}
594
595static int tdb_reopen_internal(struct tdb_context *tdb, bool active_lock)
596{
597#if !defined(LIBREPLACE_PREAD_NOT_REPLACED) || \
598 !defined(LIBREPLACE_PWRITE_NOT_REPLACED)
599 struct stat st;
600#endif
601
602 if (tdb->flags & TDB_INTERNAL) {
603 return 0; /* Nothing to do. */
604 }
605
606 if (tdb_have_extra_locks(tdb)) {
607 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed with locks held\n"));
608 goto fail;
609 }
610
611 if (tdb->transaction != 0) {
612 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed inside a transaction\n"));
613 goto fail;
614 }
615
616/* If we have real pread & pwrite, we can skip reopen. */
617#if !defined(LIBREPLACE_PREAD_NOT_REPLACED) || \
618 !defined(LIBREPLACE_PWRITE_NOT_REPLACED)
619 if (tdb_munmap(tdb) != 0) {
620 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: munmap failed (%s)\n", strerror(errno)));
621 goto fail;
622 }
623 if (close(tdb->fd) != 0)
624 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: WARNING closing tdb->fd failed!\n"));
625 tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0);
626 if (tdb->fd == -1) {
627 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: open failed (%s)\n", strerror(errno)));
628 goto fail;
629 }
630 if (fstat(tdb->fd, &st) != 0) {
631 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: fstat failed (%s)\n", strerror(errno)));
632 goto fail;
633 }
634 if (st.st_ino != tdb->inode || st.st_dev != tdb->device) {
635 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: file dev/inode has changed!\n"));
636 goto fail;
637 }
638 tdb_mmap(tdb);
639#endif /* fake pread or pwrite */
640
641#ifdef __OS2__
642 close(tdb->lock_fd);
643 tdb->lock_fd = -1;
644
645 if (os2_create_lockfile(tdb, tdb->name, "tdb_reopen") != 0)
646 goto fail;
647#endif
648 /* We may still think we hold the active lock. */
649 tdb->num_lockrecs = 0;
650 SAFE_FREE(tdb->lockrecs);
651
652 if (active_lock && tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) {
653 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n"));
654 goto fail;
655 }
656
657 return 0;
658
659fail:
660 tdb_close(tdb);
661 return -1;
662}
663
664/* reopen a tdb - this can be used after a fork to ensure that we have an independent
665 seek pointer from our parent and to re-establish locks */
666_PUBLIC_ int tdb_reopen(struct tdb_context *tdb)
667{
668 return tdb_reopen_internal(tdb, tdb->flags & TDB_CLEAR_IF_FIRST);
669}
670
671/* reopen all tdb's */
672_PUBLIC_ int tdb_reopen_all(int parent_longlived)
673{
674 struct tdb_context *tdb;
675
676 for (tdb=tdbs; tdb; tdb = tdb->next) {
677 bool active_lock = (tdb->flags & TDB_CLEAR_IF_FIRST);
678
679 /*
680 * If the parent is longlived (ie. a
681 * parent daemon architecture), we know
682 * it will keep it's active lock on a
683 * tdb opened with CLEAR_IF_FIRST. Thus
684 * for child processes we don't have to
685 * add an active lock. This is essential
686 * to improve performance on systems that
687 * keep POSIX locks as a non-scalable data
688 * structure in the kernel.
689 */
690 if (parent_longlived) {
691 /* Ensure no clear-if-first. */
692 active_lock = false;
693 }
694
695 if (tdb_reopen_internal(tdb, active_lock) != 0)
696 return -1;
697 }
698
699 return 0;
700}
Note: See TracBrowser for help on using the repository browser.