/* The code should barf on TDBs created with rwlocks. */
int main(int argc, char *argv[])
{
	struct tdb_context *tdb;
	unsigned int log_count;
	struct tdb_logging_context log_ctx = { log_fn, &log_count };
	int ret, status;
	pid_t child, wait_ret;
	int fromchild[2];
	int tochild[2];
	char c;
	int tdb_flags;
	bool runtime_support;

	runtime_support = tdb_runtime_check_for_robust_mutexes();

	if (!runtime_support) {
		skip(1, "No robust mutex support");
		return exit_status();
	}

	key.dsize = strlen("hi");
	key.dptr = discard_const_p(uint8_t, "hi");
	data.dsize = strlen("world");
	data.dptr = discard_const_p(uint8_t, "world");

	pipe(fromchild);
	pipe(tochild);

	tdb_flags = TDB_INCOMPATIBLE_HASH|
		TDB_MUTEX_LOCKING|
		TDB_CLEAR_IF_FIRST;

	child = fork();
	if (child == 0) {
		close(fromchild[0]);
		close(tochild[1]);
		return do_child(tdb_flags, fromchild[1], tochild[0]);
	}
	close(fromchild[1]);
	close(tochild[0]);

	read(fromchild[0], &c, sizeof(c));

	tdb = tdb_open_ex("mutex-allrecord-trylock.tdb", 0, tdb_flags,
			  O_RDWR|O_CREAT, 0755, &log_ctx, NULL);
	ok(tdb, "tdb_open_ex should succeed");

	ret = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_NOWAIT, false);
	ok(ret == -1, "tdb_allrecord_lock (nowait) should not succeed");

	write(tochild[1], &c, sizeof(c));

	wait_ret = wait(&status);
	ok(wait_ret == child, "child should have exited correctly");

	diag("done");
	return exit_status();
}
Exemple #2
0
enum TDB_ERROR tdb_wipe_all(struct tdb_context *tdb)
{
	enum TDB_ERROR ecode;
	int64_t count;

	if (tdb->flags & TDB_VERSION1) {
		if (tdb1_wipe_all(tdb) == -1)
			return tdb->last_error;
		return TDB_SUCCESS;
	}

	ecode = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false);
	if (ecode != TDB_SUCCESS)
		return tdb->last_error = ecode;

	/* FIXME: Be smarter. */
	count = tdb_traverse(tdb, wipe_one, &ecode);
	if (count < 0)
		ecode = TDB_OFF_TO_ERR(count);
	tdb_allrecord_unlock(tdb, F_WRLCK);
	return tdb->last_error = ecode;
}
Exemple #3
0
Fichier : lock.c Projet : hef/samba
/* lock entire database with read lock - nonblock varient */
_PUBLIC_ int tdb_lockall_read_nonblock(struct tdb_context *tdb)
{
	int ret = tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_NOWAIT, false);
	tdb_trace_ret(tdb, "tdb_lockall_read_nonblock", ret);
	return ret;
}
Exemple #4
0
Fichier : lock.c Projet : hef/samba
/* lock entire database with read lock */
_PUBLIC_ int tdb_lockall_read(struct tdb_context *tdb)
{
	tdb_trace(tdb, "tdb_lockall_read");
	return tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, false);
}
Exemple #5
0
Fichier : lock.c Projet : hef/samba
/* lock entire database with write lock - mark only */
_PUBLIC_ int tdb_lockall_mark(struct tdb_context *tdb)
{
	tdb_trace(tdb, "tdb_lockall_mark");
	return tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_MARK_ONLY, false);
}
Exemple #6
0
Fichier : lock.c Projet : hef/samba
/* lock/unlock entire database.  It can only be upgradable if you have some
 * other way of guaranteeing exclusivity (ie. transaction write lock).
 * We do the locking gradually to avoid being starved by smaller locks. */
int tdb_allrecord_lock(struct tdb_context *tdb, int ltype,
		       enum tdb_lock_flags flags, bool upgradable)
{
	int ret;

	switch (tdb_allrecord_check(tdb, ltype, flags, upgradable)) {
	case -1:
		return -1;
	case 0:
		return 0;
	}

	/* We cover two kinds of locks:
	 * 1) Normal chain locks.  Taken for almost all operations.
	 * 2) Individual records locks.  Taken after normal or free
	 *    chain locks.
	 *
	 * It is (1) which cause the starvation problem, so we're only
	 * gradual for that. */

	if (tdb_have_mutexes(tdb)) {
		ret = tdb_mutex_allrecord_lock(tdb, ltype, flags);
	} else {
		ret = tdb_chainlock_gradual(tdb, ltype, flags, FREELIST_TOP,
					    tdb->hash_size * 4);
	}

	if (ret == -1) {
		return -1;
	}

	/* Grab individual record locks. */
	if (tdb_brlock(tdb, ltype, lock_offset(tdb->hash_size), 0,
		       flags) == -1) {
		if (tdb_have_mutexes(tdb)) {
			tdb_mutex_allrecord_unlock(tdb);
		} else {
			tdb_brunlock(tdb, ltype, FREELIST_TOP,
				     tdb->hash_size * 4);
		}
		return -1;
	}

	tdb->allrecord_lock.count = 1;
	/* If it's upgradable, it's actually exclusive so we can treat
	 * it as a write lock. */
	tdb->allrecord_lock.ltype = upgradable ? F_WRLCK : ltype;
	tdb->allrecord_lock.off = upgradable;

	if (tdb_needs_recovery(tdb)) {
		bool mark = flags & TDB_LOCK_MARK_ONLY;
		tdb_allrecord_unlock(tdb, ltype, mark);
		if (mark) {
			tdb->ecode = TDB_ERR_LOCK;
			TDB_LOG((tdb, TDB_DEBUG_ERROR,
				 "tdb_lockall_mark cannot do recovery\n"));
			return -1;
		}
		if (tdb_lock_and_recover(tdb) == -1) {
			return -1;
		}
		return tdb_allrecord_lock(tdb, ltype, flags, upgradable);
	}

	return 0;
}