static int tdb_lock_list(struct tdb_context *tdb, int list, int ltype, enum tdb_lock_flags waitflag) { int ret; bool check = false; if (tdb->allrecord_lock.count) { return tdb_lock_covered_by_allrecord_lock(tdb, ltype); } /* * Check for recoveries: Someone might have kill -9'ed a process * during a commit. */ check = !have_data_locks(tdb); ret = tdb_nest_lock(tdb, lock_offset(list), ltype, waitflag); if (ret == 0 && check && tdb_needs_recovery(tdb)) { tdb_nest_unlock(tdb, lock_offset(list), ltype, false); if (tdb_lock_and_recover(tdb) == -1) { return -1; } return tdb_lock_list(tdb, list, ltype, waitflag); } return ret; }
_PUBLIC_ int tdb_unlock(struct tdb_context *tdb, int list, int ltype) { /* a global lock allows us to avoid per chain locks */ if (tdb->allrecord_lock.count) { return tdb_lock_covered_by_allrecord_lock(tdb, ltype); } return tdb_nest_unlock(tdb, lock_offset(list), ltype, false); }
/* increment the tdb sequence number if the tdb has been opened using the TDB_SEQNUM flag */ static void tdb_increment_seqnum(struct tdb_context *tdb) { if (!(tdb->flags & TDB_SEQNUM)) { return; } if (tdb->transaction != NULL) { tdb_increment_seqnum_nonblock(tdb); return; } if (tdb_nest_lock(tdb, TDB_SEQNUM_OFS, F_WRLCK, TDB_LOCK_WAIT|TDB_LOCK_PROBE) != 0) { return; } tdb_increment_seqnum_nonblock(tdb); tdb_nest_unlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, false); }
_PUBLIC_ int tdb_transaction_write_lock_unmark(struct tdb_context *tdb) { return tdb_nest_unlock(tdb, TRANSACTION_LOCK, F_WRLCK, true); }
/* unmark a chain as locked without actually locking it. Warning! use with great caution! */ _PUBLIC_ int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key) { tdb_trace_1rec(tdb, "tdb_chainlock_unmark", key); return tdb_nest_unlock(tdb, lock_offset(BUCKET(tdb->hash_fn(&key))), F_WRLCK, true); }
/* release the transaction lock */ int tdb_transaction_unlock(struct tdb_context *tdb, int ltype) { return tdb_nest_unlock(tdb, TRANSACTION_LOCK, ltype, false); }
static bool tdb_mutex_open_ok(struct tdb_context *tdb, const struct tdb_header *header) { int locked; locked = tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE); if ((locked == -1) && (tdb->ecode == TDB_ERR_LOCK)) { /* * CLEAR_IF_FIRST still active. The tdb was created on this * host, so we can assume the mutex implementation is * compatible. Important for tools like tdbdump on a still * open locking.tdb. */ goto check_local_settings; } /* * We got the CLEAR_IF_FIRST lock. That means the database was * potentially copied from somewhere else. The mutex implementation * might be incompatible. */ if (tdb_nest_unlock(tdb, ACTIVE_LOCK, F_WRLCK, false) == -1) { /* * Should not happen */ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_mutex_open_ok: " "failed to release ACTIVE_LOCK on %s: %s\n", tdb->name, strerror(errno))); return false; } if (tdb->flags & TDB_NOLOCK) { /* * We don't look at locks, so it does not matter to have a * compatible mutex implementation. Allow the open. */ return true; } check_local_settings: if (!(tdb->flags & TDB_MUTEX_LOCKING)) { TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_mutex_open_ok[%s]: " "Can use mutexes only with " "MUTEX_LOCKING or NOLOCK\n", tdb->name)); return false; } if (tdb_mutex_size(tdb) != header->mutex_size) { TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_mutex_open_ok[%s]: " "Mutex size changed from %u to %u\n.", tdb->name, (unsigned int)header->mutex_size, (unsigned int)tdb_mutex_size(tdb))); return false; } return true; }