return ecode;
}
+/* For TDB1 tdbs, read traverse vs normal matters: write traverse
+ locks the entire thing! */
+int64_t tdb_traverse_read_(struct tdb_context *tdb,
+ int (*fn)(struct tdb_context *,
+ TDB_DATA, TDB_DATA,
+ void *),
+ void *p)
+{
+ int64_t ret;
+
+ if (tdb_get_flags(tdb) & TDB_RDONLY) {
+ return tdb_traverse(tdb, fn, p);
+ }
+
+ tdb_add_flag(tdb, TDB_RDONLY);
+ ret = tdb_traverse(tdb, fn, p);
+ tdb_remove_flag(tdb, TDB_RDONLY);
+ return ret;
+}
+
/*
* This handles TDB_CLEAR_IF_FIRST.
*/
static enum TDB_ERROR clear_if_first(int fd, void *unused)
{
- /* We hold a lock offset 63 always, so we can tell if anyone else is. */
+ /* We hold a lock offset 4 always, so we can tell if anyone else is. */
struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
- fl.l_start = 63;
+ fl.l_start = 4; /* ACTIVE_LOCK */
fl.l_len = 1;
if (fcntl(fd, F_SETLK, &fl) == 0) {
void *data),
void *log_data)
{
- union tdb_attribute cif, log, *attr = NULL;
+ union tdb_attribute cif, log, hash, *attr = NULL;
if (log_fn) {
log.log.base.attr = TDB_ATTRIBUTE_LOG;
tdb_flags &= ~TDB_CLEAR_IF_FIRST;
}
+ if (tdb_flags & TDB_INCOMPATIBLE_HASH) {
+ if (tdb_flags & TDB_VERSION1) {
+ hash.hash.base.attr = TDB_ATTRIBUTE_HASH;
+ hash.hash.base.next = attr;
+ hash.hash.fn = tdb1_incompatible_hash;
+ attr = &hash;
+ }
+ tdb_flags &= ~TDB_INCOMPATIBLE_HASH;
+ }
+
/* Testsuite uses this to speed things up. */
if (getenv("TDB_NO_FSYNC")) {
tdb_flags |= TDB_NOSYNC;
return tdb_open(name, tdb_flags|TDB_ALLOW_NESTING, open_flags, mode,
attr);
}
+
+/* We only need these for the CLEAR_IF_FIRST lock. */
+static int reacquire_cif_lock(struct tdb_context *tdb, bool *fail)
+{
+ struct flock fl;
+ union tdb_attribute cif;
+
+ cif.openhook.base.attr = TDB_ATTRIBUTE_OPENHOOK;
+ cif.openhook.base.next = NULL;
+
+ if (tdb_get_attribute(tdb, &cif) != TDB_SUCCESS
+ || cif.openhook.fn != clear_if_first) {
+ return 0;
+ }
+
+ /* We hold a lock offset 4 always, so we can tell if anyone else is. */
+ fl.l_type = F_RDLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 4; /* ACTIVE_LOCK */
+ fl.l_len = 1;
+ if (fcntl(tdb_fd(tdb), F_SETLKW, &fl) != 0) {
+ *fail = true;
+ return -1;
+ }
+ return 0;
+}
+
+int tdb_reopen(struct tdb_context *tdb)
+{
+ bool unused;
+ return reacquire_cif_lock(tdb, &unused);
+}
+
+int tdb_reopen_all(int parent_longlived)
+{
+ bool fail = false;
+
+ if (parent_longlived) {
+ return 0;
+ }
+
+ tdb_foreach(reacquire_cif_lock, &fail);
+ if (fail)
+ return -1;
+ return 0;
+}
#endif