[PATCH] g_lock_ping_pong

Volker Lendecke Volker.Lendecke at SerNet.DE
Thu Jul 6 14:17:22 UTC 2017


Hi!

Attached find a patchset that implements a g_lock performance test
along with some modifications for correctness and performance.

Review appreciated!

Thanks, Volker

-- 
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de, mailto:kontakt at sernet.de
-------------- next part --------------
From d3c7576c58922731e1fa1c7f17c3d0ec94d8a7fa Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 22 May 2017 21:55:11 +0200
Subject: [PATCH 01/41] torture: Add local-g-lock-ping-pong

This is similar to the ctdb ping_pong test.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/torture/proto.h       |   1 +
 source3/torture/test_g_lock.c | 100 ++++++++++++++++++++++++++++++++++++++++--
 source3/torture/torture.c     |   1 +
 3 files changed, 98 insertions(+), 4 deletions(-)

diff --git a/source3/torture/proto.h b/source3/torture/proto.h
index 4c3e540..fc46898 100644
--- a/source3/torture/proto.h
+++ b/source3/torture/proto.h
@@ -130,5 +130,6 @@ bool run_g_lock2(int dummy);
 bool run_g_lock3(int dummy);
 bool run_g_lock4(int dummy);
 bool run_g_lock5(int dummy);
+bool run_g_lock_ping_pong(int dummy);
 
 #endif /* __TORTURE_H__ */
diff --git a/source3/torture/test_g_lock.c b/source3/torture/test_g_lock.c
index ca37312..61ec69d 100644
--- a/source3/torture/test_g_lock.c
+++ b/source3/torture/test_g_lock.c
@@ -30,12 +30,12 @@ static bool get_g_lock_ctx(TALLOC_CTX *mem_ctx,
 			   struct messaging_context **msg,
 			   struct g_lock_ctx **ctx)
 {
-	*ev = samba_tevent_context_init(mem_ctx);
+	*ev = server_event_context();
 	if (*ev == NULL) {
 		fprintf(stderr, "tevent_context_init failed\n");
 		return false;
 	}
-	*msg = messaging_init(*ev, *ev);
+	*msg = server_messaging_context();
 	if (*msg == NULL) {
 		fprintf(stderr, "messaging_init failed\n");
 		TALLOC_FREE(*ev);
@@ -558,8 +558,8 @@ bool run_g_lock5(int dummy)
 
 		if (child == 0) {
 			TALLOC_FREE(ctx);
-			TALLOC_FREE(msg);
-			TALLOC_FREE(ev);
+
+			status = reinit_after_fork(msg, ev, false, "");
 
 			close(ready_pipe[0]);
 			close(exit_pipe[1]);
@@ -642,3 +642,95 @@ bool run_g_lock5(int dummy)
 
 	return true;
 }
+
+extern int torture_numops;
+extern int torture_nprocs;
+
+static struct timeval tp1, tp2;
+
+static void start_timer(void)
+{
+	gettimeofday(&tp1,NULL);
+}
+
+static double end_timer(void)
+{
+	gettimeofday(&tp2,NULL);
+	return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) -
+		(tp1.tv_sec + (tp1.tv_usec*1.0e-6));
+}
+
+/*
+ * g_lock ping_pong
+ */
+
+bool run_g_lock_ping_pong(int dummy)
+{
+	struct tevent_context *ev = NULL;
+	struct messaging_context *msg = NULL;
+	struct g_lock_ctx *ctx = NULL;
+	fstring name;
+	NTSTATUS status;
+	int i = 0;
+	bool ret = false;
+	bool ok;
+	unsigned count = 0;
+
+	torture_nprocs = MAX(2, torture_nprocs);
+
+	ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
+	if (!ok) {
+		goto fail;
+	}
+
+	start_timer();
+
+	snprintf(name, sizeof(name), "ping_pong_%d", i);
+
+	status = g_lock_lock(ctx, name, G_LOCK_WRITE,
+			     (struct timeval) { .tv_sec = 60 });
+	if (!NT_STATUS_IS_OK(status)) {
+		fprintf(stderr, "g_lock_lock failed: %s\n",
+			nt_errstr(status));
+		goto fail;
+	}
+
+	for (i=0; i<torture_numops; i++) {
+
+		name[10] = '0' + ((i+1) % torture_nprocs);
+
+		status = g_lock_lock(ctx, name, G_LOCK_WRITE,
+				     (struct timeval) { .tv_sec = 60 });
+		if (!NT_STATUS_IS_OK(status)) {
+			fprintf(stderr, "g_lock_lock failed: %s\n",
+				nt_errstr(status));
+			goto fail;
+		}
+
+		name[10] = '0' + ((i) % torture_nprocs);
+
+		status = g_lock_unlock(ctx, name);
+		if (!NT_STATUS_IS_OK(status)) {
+			fprintf(stderr, "g_lock_unlock failed: %s\n",
+				nt_errstr(status));
+			goto fail;
+		}
+
+		count++;
+
+		if (end_timer() > 1.0) {
+			printf("%8u locks/sec\r",
+			       (unsigned)(2*count/end_timer()));
+			fflush(stdout);
+			start_timer();
+			count=0;
+		}
+	}
+
+	ret = true;
+fail:
+	TALLOC_FREE(ctx);
+	TALLOC_FREE(msg);
+	TALLOC_FREE(ev);
+	return ret;
+}
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 6959b71..64caca5 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -11556,6 +11556,7 @@ static struct {
 	{ "LOCAL-G-LOCK3", run_g_lock3, 0 },
 	{ "LOCAL-G-LOCK4", run_g_lock4, 0 },
 	{ "LOCAL-G-LOCK5", run_g_lock5, 0 },
+	{ "LOCAL-G-LOCK-PING-PONG", run_g_lock_ping_pong, 0 },
 	{ "LOCAL-CANONICALIZE-PATH", run_local_canonicalize_path, 0 },
 	{ "qpathinfo-bufsize", run_qpathinfo_bufsize, 0 },
 	{NULL, NULL, 0}};
-- 
2.1.4


From fe92b743b974d7464a03232a2db06c3df30544e0 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 12 Sep 2016 17:11:09 +0200
Subject: [PATCH 02/41] dbwrap: Add dbwrap_merge_dbufs

Transitional code to implement dbwrap_record_storev

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/dbwrap/dbwrap.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 lib/dbwrap/dbwrap.h |  3 +++
 2 files changed, 51 insertions(+)

diff --git a/lib/dbwrap/dbwrap.c b/lib/dbwrap/dbwrap.c
index 025d463..1f45558 100644
--- a/lib/dbwrap/dbwrap.c
+++ b/lib/dbwrap/dbwrap.c
@@ -556,3 +556,51 @@ const char *dbwrap_name(struct db_context *db)
 {
 	return db->name;
 }
+
+static ssize_t tdb_data_buf(const TDB_DATA *dbufs, int num_dbufs,
+			    uint8_t *buf, size_t buflen)
+{
+	size_t needed = 0;
+	uint8_t *p = buf;
+	int i;
+
+	for (i=0; i<num_dbufs; i++) {
+		size_t thislen = dbufs[i].dsize;
+		size_t tmp;
+
+		tmp = needed + thislen;
+		if (tmp < needed) {
+			/* wrap */
+			return -1;
+		}
+		needed = tmp;
+
+		if (needed <= buflen) {
+			memcpy(p, dbufs[i].dptr, thislen);
+			p += thislen;
+		}
+	}
+
+	return needed;
+}
+
+
+TDB_DATA dbwrap_merge_dbufs(TALLOC_CTX *mem_ctx,
+			    const TDB_DATA *dbufs, int num_dbufs)
+{
+	ssize_t len = tdb_data_buf(dbufs, num_dbufs, NULL, 0);
+	uint8_t *buf;
+
+	if (len == -1) {
+		return (TDB_DATA) {0};
+	}
+
+	buf = talloc_array(mem_ctx, uint8_t, len);
+	if (buf == NULL) {
+		return (TDB_DATA) {0};
+	}
+
+	tdb_data_buf(dbufs, num_dbufs, buf, len);
+
+	return (TDB_DATA) { .dptr = buf, .dsize = len };
+}
diff --git a/lib/dbwrap/dbwrap.h b/lib/dbwrap/dbwrap.h
index fac65ee..e34b2ab 100644
--- a/lib/dbwrap/dbwrap.h
+++ b/lib/dbwrap/dbwrap.h
@@ -216,6 +216,9 @@ NTSTATUS dbwrap_parse_marshall_buf(const uint8_t *buf, size_t buflen,
 NTSTATUS dbwrap_unmarshall(struct db_context *db, const uint8_t *buf,
 			   size_t buflen);
 
+TDB_DATA dbwrap_merge_dbufs(TALLOC_CTX *mem_ctx,
+			    const TDB_DATA *dbufs, int num_dbufs);
+
 
 /**
  * This opens a tdb file
-- 
2.1.4


From 311b01fed0711e101357059e038e7641bbd0145c Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 12 Sep 2016 17:30:55 +0200
Subject: [PATCH 03/41] dbwrap: Convert backend store to storev

Convert all implementors of dbwrap_store to a storev-style call
by using the dbwrap_merge_dbufs call

For dbwrap_tdb, this matches tdb_storev.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/dbwrap/dbwrap.c               |  2 +-
 lib/dbwrap/dbwrap_private.h       |  3 ++-
 lib/dbwrap/dbwrap_rbt.c           | 25 ++++++++++++++++++----
 lib/dbwrap/dbwrap_tdb.c           | 22 ++++++++++++--------
 source3/lib/dbwrap/dbwrap_ctdb.c  | 44 ++++++++++++++++++++++++++++++---------
 source3/lib/dbwrap/dbwrap_watch.c | 24 +++++++++++++++------
 6 files changed, 89 insertions(+), 31 deletions(-)

diff --git a/lib/dbwrap/dbwrap.c b/lib/dbwrap/dbwrap.c
index 1f45558..85f2213 100644
--- a/lib/dbwrap/dbwrap.c
+++ b/lib/dbwrap/dbwrap.c
@@ -86,7 +86,7 @@ NTSTATUS dbwrap_record_store(struct db_record *rec, TDB_DATA data, int flags)
 {
 	NTSTATUS status;
 
-	status = rec->store(rec, data, flags);
+	status = rec->storev(rec, &data, 1, flags);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
diff --git a/lib/dbwrap/dbwrap_private.h b/lib/dbwrap/dbwrap_private.h
index 9b50ccc..2858afd 100644
--- a/lib/dbwrap/dbwrap_private.h
+++ b/lib/dbwrap/dbwrap_private.h
@@ -29,7 +29,8 @@ struct tevent_req;
 struct db_record {
 	struct db_context *db;
 	TDB_DATA key, value;
-	NTSTATUS (*store)(struct db_record *rec, TDB_DATA data, int flag);
+	NTSTATUS (*storev)(struct db_record *rec, const TDB_DATA *dbufs,
+			   int num_dbufs, int flag);
 	NTSTATUS (*delete_rec)(struct db_record *rec);
 	void *private_data;
 };
diff --git a/lib/dbwrap/dbwrap_rbt.c b/lib/dbwrap/dbwrap_rbt.c
index eb5ef10..d9c743b 100644
--- a/lib/dbwrap/dbwrap_rbt.c
+++ b/lib/dbwrap/dbwrap_rbt.c
@@ -118,7 +118,8 @@ overflow:
 	return -1;
 }
 
-static NTSTATUS db_rbt_store(struct db_record *rec, TDB_DATA data, int flag)
+static NTSTATUS db_rbt_storev(struct db_record *rec,
+			      const TDB_DATA *dbufs, int num_dbufs, int flag)
 {
 	struct db_rbt_ctx *db_ctx = talloc_get_type_abort(
 		rec->db->private_data, struct db_rbt_ctx);
@@ -130,12 +131,23 @@ static NTSTATUS db_rbt_store(struct db_record *rec, TDB_DATA data, int flag)
 	struct db_rbt_node *parent_node = NULL;
 
 	ssize_t reclen;
-	TDB_DATA this_key, this_val;
+	TDB_DATA data, this_key, this_val;
+	void *to_free = NULL;
 
 	if (db_ctx->traverse_read > 0) {
 		return NT_STATUS_MEDIA_WRITE_PROTECTED;
 	}
 
+	if (num_dbufs == 1) {
+		data = dbufs[0];
+	} else {
+		data = dbwrap_merge_dbufs(rec, dbufs, num_dbufs);
+		if (data.dptr == NULL) {
+			return NT_STATUS_NO_MEMORY;
+		}
+		to_free = data.dptr;
+	}
+
 	if (rec_priv->node != NULL) {
 
 		/*
@@ -154,17 +166,20 @@ static NTSTATUS db_rbt_store(struct db_record *rec, TDB_DATA data, int flag)
 			 */
 			memcpy(this_val.dptr, data.dptr, data.dsize);
 			rec_priv->node->valuesize = data.dsize;
+			TALLOC_FREE(to_free);
 			return NT_STATUS_OK;
 		}
 	}
 
 	reclen = db_rbt_reclen(rec->key.dsize, data.dsize);
 	if (reclen == -1) {
+		TALLOC_FREE(to_free);
 		return NT_STATUS_INSUFFICIENT_RESOURCES;
 	}
 
 	node = talloc_zero_size(db_ctx, reclen);
 	if (node == NULL) {
+		TALLOC_FREE(to_free);
 		return NT_STATUS_NO_MEMORY;
 	}
 
@@ -232,6 +247,8 @@ static NTSTATUS db_rbt_store(struct db_record *rec, TDB_DATA data, int flag)
 	DLIST_ADD_AFTER(db_ctx->nodes, node, parent_node);
 	rb_insert_color(&node->rb_node, &db_ctx->tree);
 
+	TALLOC_FREE(to_free);
+
 	return NT_STATUS_OK;
 }
 
@@ -350,7 +367,7 @@ static struct db_record *db_rbt_fetch_locked(struct db_context *db_ctx,
 	rec_priv = (struct db_rbt_rec *)
 		((char *)result + DBWRAP_RBT_ALIGN(sizeof(struct db_record)));
 
-	result->store = db_rbt_store;
+	result->storev = db_rbt_storev;
 	result->delete_rec = db_rbt_delete;
 	result->private_data = rec_priv;
 
@@ -425,7 +442,7 @@ static int db_rbt_traverse_internal(struct db_context *db,
 		ZERO_STRUCT(rec);
 		rec.db = db;
 		rec.private_data = &rec_priv;
-		rec.store = db_rbt_store;
+		rec.storev = db_rbt_storev;
 		rec.delete_rec = db_rbt_delete;
 		db_rbt_parse_node(rec_priv.node, &rec.key, &rec.value);
 
diff --git a/lib/dbwrap/dbwrap_tdb.c b/lib/dbwrap/dbwrap_tdb.c
index e12ec44..9f8a9a6 100644
--- a/lib/dbwrap/dbwrap_tdb.c
+++ b/lib/dbwrap/dbwrap_tdb.c
@@ -35,7 +35,8 @@ struct db_tdb_ctx {
 	} id;
 };
 
-static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag);
+static NTSTATUS db_tdb_storev(struct db_record *rec,
+			      const TDB_DATA *dbufs, int num_dbufs, int flag);
 static NTSTATUS db_tdb_delete(struct db_record *rec);
 
 static void db_tdb_log_key(const char *prefix, TDB_DATA key)
@@ -137,7 +138,7 @@ static struct db_record *db_tdb_fetch_locked_internal(
 	talloc_set_destructor(state.result, db_tdb_record_destr);
 
 	state.result->private_data = ctx;
-	state.result->store = db_tdb_store;
+	state.result->storev = db_tdb_storev;
 	state.result->delete_rec = db_tdb_delete;
 
 	DEBUG(10, ("Allocated locked data 0x%p\n", state.result));
@@ -173,7 +174,6 @@ static struct db_record *db_tdb_try_fetch_locked(
 	return db_tdb_fetch_locked_internal(db, mem_ctx, key);
 }
 
-
 static int db_tdb_exists(struct db_context *db, TDB_DATA key)
 {
 	struct db_tdb_ctx *ctx = talloc_get_type_abort(
@@ -236,10 +236,12 @@ static NTSTATUS db_tdb_parse(struct db_context *db, TDB_DATA key,
 	return NT_STATUS_OK;
 }
 
-static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag)
+static NTSTATUS db_tdb_storev(struct db_record *rec,
+			      const TDB_DATA *dbufs, int num_dbufs, int flag)
 {
 	struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
 						       struct db_tdb_ctx);
+	int ret;
 
 	/*
 	 * This has a bug: We need to replace rec->value for correct
@@ -247,8 +249,8 @@ static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag)
 	 * anymore after it was stored.
 	 */
 
-	return (tdb_store(ctx->wtdb->tdb, rec->key, data, flag) == 0) ?
-		NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+	ret = tdb_storev(ctx->wtdb->tdb, rec->key, dbufs, num_dbufs, flag);
+	return (ret == 0) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
 }
 
 static NTSTATUS db_tdb_delete(struct db_record *rec)
@@ -282,7 +284,7 @@ static int db_tdb_traverse_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
 
 	rec.key = kbuf;
 	rec.value = dbuf;
-	rec.store = db_tdb_store;
+	rec.storev = db_tdb_storev;
 	rec.delete_rec = db_tdb_delete;
 	rec.private_data = ctx->db->private_data;
 	rec.db = ctx->db;
@@ -304,7 +306,9 @@ static int db_tdb_traverse(struct db_context *db,
 	return tdb_traverse(db_ctx->wtdb->tdb, db_tdb_traverse_func, &ctx);
 }
 
-static NTSTATUS db_tdb_store_deny(struct db_record *rec, TDB_DATA data, int flag)
+static NTSTATUS db_tdb_storev_deny(struct db_record *rec,
+				   const TDB_DATA *dbufs, int num_dbufs,
+				   int flag)
 {
 	return NT_STATUS_MEDIA_WRITE_PROTECTED;
 }
@@ -323,7 +327,7 @@ static int db_tdb_traverse_read_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA d
 
 	rec.key = kbuf;
 	rec.value = dbuf;
-	rec.store = db_tdb_store_deny;
+	rec.storev = db_tdb_storev_deny;
 	rec.delete_rec = db_tdb_delete_deny;
 	rec.private_data = ctx->db->private_data;
 	rec.db = ctx->db;
diff --git a/source3/lib/dbwrap/dbwrap_ctdb.c b/source3/lib/dbwrap/dbwrap_ctdb.c
index 8e303e6..2969183 100644
--- a/source3/lib/dbwrap/dbwrap_ctdb.c
+++ b/source3/lib/dbwrap/dbwrap_ctdb.c
@@ -494,7 +494,9 @@ static bool pull_newest_from_marshall_buffer(struct ctdb_marshall_buffer *buf,
 	return true;
 }
 
-static NTSTATUS db_ctdb_store_transaction(struct db_record *rec, TDB_DATA data, int flag);
+static NTSTATUS db_ctdb_storev_transaction(struct db_record *rec,
+					   const TDB_DATA *dbufs, int num_dbufs,
+					   int flag);
 static NTSTATUS db_ctdb_delete_transaction(struct db_record *rec);
 
 static struct db_record *db_ctdb_fetch_locked_transaction(struct db_ctdb_ctx *ctx,
@@ -521,7 +523,7 @@ static struct db_record *db_ctdb_fetch_locked_transaction(struct db_ctdb_ctx *ct
 		return NULL;
 	}
 
-	result->store = db_ctdb_store_transaction;
+	result->storev = db_ctdb_storev_transaction;
 	result->delete_rec = db_ctdb_delete_transaction;
 
 	if (pull_newest_from_marshall_buffer(ctx->transaction->m_write, key,
@@ -656,13 +658,23 @@ static NTSTATUS db_ctdb_transaction_store(struct db_ctdb_transaction_handle *h,
 /* 
    a record store inside a transaction
  */
-static NTSTATUS db_ctdb_store_transaction(struct db_record *rec, TDB_DATA data, int flag)
+static NTSTATUS db_ctdb_storev_transaction(
+	struct db_record *rec, const TDB_DATA *dbufs, int num_dbufs, int flag)
 {
 	struct db_ctdb_transaction_handle *h = talloc_get_type_abort(
 		rec->private_data, struct db_ctdb_transaction_handle);
 	NTSTATUS status;
+	TDB_DATA data;
+
+	data = dbwrap_merge_dbufs(rec, dbufs, num_dbufs);
+	if (data.dptr == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
 
 	status = db_ctdb_transaction_store(h, rec->key, data);
+
+	TALLOC_FREE(data.dptr);
+
 	return status;
 }
 
@@ -887,12 +899,23 @@ static int db_ctdb_transaction_cancel(struct db_context *db)
 }
 
 
-static NTSTATUS db_ctdb_store(struct db_record *rec, TDB_DATA data, int flag)
+static NTSTATUS db_ctdb_storev(struct db_record *rec,
+			       const TDB_DATA *dbufs, int num_dbufs, int flag)
 {
 	struct db_ctdb_rec *crec = talloc_get_type_abort(
 		rec->private_data, struct db_ctdb_rec);
+	NTSTATUS status;
+	TDB_DATA data;
+
+	data = dbwrap_merge_dbufs(rec, dbufs, num_dbufs);
+	if (data.dptr == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
 
-	return db_ctdb_ltdb_store(crec->ctdb_ctx, rec->key, &(crec->header), data);
+	status = db_ctdb_ltdb_store(crec->ctdb_ctx, rec->key, &(crec->header),
+				    data);
+	TALLOC_FREE(data.dptr);
+	return status;
 }
 
 
@@ -954,7 +977,7 @@ static NTSTATUS db_ctdb_delete(struct db_record *rec)
 	 * tdb-level cleanup
 	 */
 
-	status = db_ctdb_store(rec, tdb_null, 0);
+	status = db_ctdb_storev(rec, &tdb_null, 1, 0);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
@@ -1125,7 +1148,7 @@ again:
 		return NULL;
 	}
 
-	result->store = db_ctdb_store;
+	result->storev = db_ctdb_storev;
 	result->delete_rec = db_ctdb_delete;
 	talloc_set_destructor(result, db_ctdb_record_destr);
 
@@ -1658,7 +1681,8 @@ static int db_ctdb_traverse(struct db_context *db,
 	return state.count;
 }
 
-static NTSTATUS db_ctdb_store_deny(struct db_record *rec, TDB_DATA data, int flag)
+static NTSTATUS db_ctdb_storev_deny(struct db_record *rec,
+				    const TDB_DATA *dbufs, int num_dbufs, int flag)
 {
 	return NT_STATUS_MEDIA_WRITE_PROTECTED;
 }
@@ -1677,7 +1701,7 @@ static void traverse_read_callback(TDB_DATA key, TDB_DATA data, void *private_da
 	rec.db = state->db;
 	rec.key = key;
 	rec.value = data;
-	rec.store = db_ctdb_store_deny;
+	rec.storev = db_ctdb_storev_deny;
 	rec.delete_rec = db_ctdb_delete_deny;
 	rec.private_data = NULL;
 	state->fn(&rec, state->private_data);
@@ -1704,7 +1728,7 @@ static int traverse_persistent_callback_read(TDB_CONTEXT *tdb, TDB_DATA kbuf, TD
 	rec.db = state->db;
 	rec.key = kbuf;
 	rec.value = dbuf;
-	rec.store = db_ctdb_store_deny;
+	rec.storev = db_ctdb_storev_deny;
 	rec.delete_rec = db_ctdb_delete_deny;
 	rec.private_data = NULL;
 
diff --git a/source3/lib/dbwrap/dbwrap_watch.c b/source3/lib/dbwrap/dbwrap_watch.c
index 585010f..ab59803 100644
--- a/source3/lib/dbwrap/dbwrap_watch.c
+++ b/source3/lib/dbwrap/dbwrap_watch.c
@@ -238,8 +238,9 @@ struct db_watched_subrec {
 	bool deleted;
 };
 
-static NTSTATUS dbwrap_watched_store(struct db_record *rec, TDB_DATA data,
-				     int flag);
+static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
+				      const TDB_DATA *dbufs, int num_dbufs,
+				      int flag);
 static NTSTATUS dbwrap_watched_delete(struct db_record *rec);
 
 static struct db_record *dbwrap_watched_fetch_locked(
@@ -271,7 +272,7 @@ static struct db_record *dbwrap_watched_fetch_locked(
 
 	rec->db = db;
 	rec->key = dbwrap_record_get_key(subrec->subrec);
-	rec->store = dbwrap_watched_store;
+	rec->storev = dbwrap_watched_storev;
 	rec->delete_rec = dbwrap_watched_delete;
 
 	subrec_value = dbwrap_record_get_value(subrec->subrec);
@@ -383,18 +384,29 @@ static NTSTATUS dbwrap_watched_save(struct db_watched_subrec *subrec,
 	return status;
 }
 
-static NTSTATUS dbwrap_watched_store(struct db_record *rec, TDB_DATA data,
-				     int flag)
+static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
+				      const TDB_DATA *dbufs, int num_dbufs,
+				      int flag)
 {
 	struct db_watched_subrec *subrec = talloc_get_type_abort(
 		rec->private_data, struct db_watched_subrec);
+	NTSTATUS status;
+	TDB_DATA data;
+
+	data = dbwrap_merge_dbufs(rec, dbufs, num_dbufs);
+	if (data.dptr == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
 
 	dbwrap_watched_wakeup(rec, subrec);
 
 	subrec->deleted = false;
 
-	return dbwrap_watched_save(subrec, data, flag);
+	status = dbwrap_watched_save(subrec, data, flag);
+
+	TALLOC_FREE(data.dptr);
 
+	return status;
 }
 
 static NTSTATUS dbwrap_watched_delete(struct db_record *rec)
-- 
2.1.4


From 6b9acf9b413cc221268d2bcf90e88000c35ed55c Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 13 Sep 2016 12:25:14 +0200
Subject: [PATCH 04/41] dbwrap: Add dbwrap_record_storev

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/dbwrap/dbwrap.c | 10 ++++++++--
 lib/dbwrap/dbwrap.h |  2 ++
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/lib/dbwrap/dbwrap.c b/lib/dbwrap/dbwrap.c
index 85f2213..713c420 100644
--- a/lib/dbwrap/dbwrap.c
+++ b/lib/dbwrap/dbwrap.c
@@ -82,17 +82,23 @@ TDB_DATA dbwrap_record_get_value(const struct db_record *rec)
 	return rec->value;
 }
 
-NTSTATUS dbwrap_record_store(struct db_record *rec, TDB_DATA data, int flags)
+NTSTATUS dbwrap_record_storev(struct db_record *rec,
+			      const TDB_DATA *dbufs, int num_dbufs, int flags)
 {
 	NTSTATUS status;
 
-	status = rec->storev(rec, &data, 1, flags);
+	status = rec->storev(rec, dbufs, num_dbufs, flags);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
 	return NT_STATUS_OK;
 }
 
+NTSTATUS dbwrap_record_store(struct db_record *rec, TDB_DATA data, int flags)
+{
+	return dbwrap_record_storev(rec, &data, 1, flags);
+}
+
 NTSTATUS dbwrap_record_delete(struct db_record *rec)
 {
 	NTSTATUS status;
diff --git a/lib/dbwrap/dbwrap.h b/lib/dbwrap/dbwrap.h
index e34b2ab..04e179e 100644
--- a/lib/dbwrap/dbwrap.h
+++ b/lib/dbwrap/dbwrap.h
@@ -72,6 +72,8 @@ enum dbwrap_req_state {
 TDB_DATA dbwrap_record_get_key(const struct db_record *rec);
 TDB_DATA dbwrap_record_get_value(const struct db_record *rec);
 NTSTATUS dbwrap_record_store(struct db_record *rec, TDB_DATA data, int flags);
+NTSTATUS dbwrap_record_storev(struct db_record *rec,
+			      const TDB_DATA *dbufs, int num_dbufs, int flags);
 NTSTATUS dbwrap_record_delete(struct db_record *rec);
 struct db_record *dbwrap_fetch_locked(struct db_context *db,
 				      TALLOC_CTX *mem_ctx,
-- 
2.1.4


From 89448c6c9a47ebc0778a4837b94c197ed159fcde Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 9 Nov 2016 08:45:59 +0100
Subject: [PATCH 05/41] dbwrap: Add dbwrap_do_locked

With a proper implementation this enables modifications without
having to allocate a record. In really performance sensitive code
paths this matters.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/dbwrap/dbwrap.c         | 25 +++++++++++++++++++++++++
 lib/dbwrap/dbwrap.h         |  5 +++++
 lib/dbwrap/dbwrap_private.h |  4 ++++
 3 files changed, 34 insertions(+)

diff --git a/lib/dbwrap/dbwrap.c b/lib/dbwrap/dbwrap.c
index 713c420..fc70491 100644
--- a/lib/dbwrap/dbwrap.c
+++ b/lib/dbwrap/dbwrap.c
@@ -486,6 +486,31 @@ NTSTATUS dbwrap_parse_record_recv(struct tevent_req *req)
 	return tevent_req_simple_recv_ntstatus(req);
 }
 
+NTSTATUS dbwrap_do_locked(struct db_context *db, TDB_DATA key,
+			  void (*fn)(struct db_record *rec,
+				     void *private_data),
+			  void *private_data)
+{
+	struct db_record *rec;
+
+	if (db->do_locked != NULL) {
+		NTSTATUS status;
+		status = db->do_locked(db, key, fn, private_data);
+		return status;
+	}
+
+	rec = dbwrap_fetch_locked(db, db, key);
+	if (rec == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	fn(rec, private_data);
+
+	TALLOC_FREE(rec);
+
+	return NT_STATUS_OK;
+}
+
 int dbwrap_wipe(struct db_context *db)
 {
 	if (db->wipe == NULL) {
diff --git a/lib/dbwrap/dbwrap.h b/lib/dbwrap/dbwrap.h
index 04e179e..1161bf0 100644
--- a/lib/dbwrap/dbwrap.h
+++ b/lib/dbwrap/dbwrap.h
@@ -83,6 +83,11 @@ struct db_record *dbwrap_try_fetch_locked(struct db_context *db,
 					  TDB_DATA key);
 struct db_context *dbwrap_record_get_db(struct db_record *rec);
 
+NTSTATUS dbwrap_do_locked(struct db_context *db, TDB_DATA key,
+			  void (*fn)(struct db_record *rec,
+				     void *private_data),
+			  void *private_data);
+
 NTSTATUS dbwrap_delete(struct db_context *db, TDB_DATA key);
 NTSTATUS dbwrap_store(struct db_context *db, TDB_DATA key,
 		      TDB_DATA data, int flags);
diff --git a/lib/dbwrap/dbwrap_private.h b/lib/dbwrap/dbwrap_private.h
index 2858afd..e757215 100644
--- a/lib/dbwrap/dbwrap_private.h
+++ b/lib/dbwrap/dbwrap_private.h
@@ -68,6 +68,10 @@ struct db_context {
 		void *private_data,
 		enum dbwrap_req_state *req_state);
 	NTSTATUS (*parse_record_recv)(struct tevent_req *req);
+	NTSTATUS (*do_locked)(struct db_context *db, TDB_DATA key,
+			      void (*fn)(struct db_record *rec,
+					 void *private_data),
+			      void *private_data);
 	int (*exists)(struct db_context *db,TDB_DATA key);
 	int (*wipe)(struct db_context *db);
 	int (*check)(struct db_context *db);
-- 
2.1.4


From 0c758c69923b1082d369bcc9f5536bc063a07eda Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 27 Jun 2017 08:25:36 +0200
Subject: [PATCH 06/41] torture3: Test dbwrap_do_locked

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/selftest/tests.py               |   1 +
 source3/torture/proto.h                 |   1 +
 source3/torture/test_dbwrap_do_locked.c | 132 ++++++++++++++++++++++++++++++++
 source3/torture/torture.c               |   1 +
 source3/wscript_build                   |   1 +
 5 files changed, 136 insertions(+)
 create mode 100644 source3/torture/test_dbwrap_do_locked.c

diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index d459ede..1594c19 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -148,6 +148,7 @@ local_tests = [
     "LOCAL-CANONICALIZE-PATH",
     "LOCAL-DBWRAP-WATCH1",
     "LOCAL-DBWRAP-WATCH2",
+    "LOCAL-DBWRAP-DO-LOCKED1",
     "LOCAL-G-LOCK1",
     "LOCAL-G-LOCK2",
     "LOCAL-G-LOCK3",
diff --git a/source3/torture/proto.h b/source3/torture/proto.h
index fc46898..8a032da 100644
--- a/source3/torture/proto.h
+++ b/source3/torture/proto.h
@@ -111,6 +111,7 @@ bool run_notify_bench2(int dummy);
 bool run_notify_bench3(int dummy);
 bool run_dbwrap_watch1(int dummy);
 bool run_dbwrap_watch2(int dummy);
+bool run_dbwrap_do_locked1(int dummy);
 bool run_idmap_tdb_common_test(int dummy);
 bool run_local_dbwrap_ctdb(int dummy);
 bool run_qpathinfo_bufsize(int dummy);
diff --git a/source3/torture/test_dbwrap_do_locked.c b/source3/torture/test_dbwrap_do_locked.c
new file mode 100644
index 0000000..92dec38
--- /dev/null
+++ b/source3/torture/test_dbwrap_do_locked.c
@@ -0,0 +1,132 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Test dbwrap_watch API
+ * Copyright (C) Volker Lendecke 2017
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "torture/proto.h"
+#include "system/filesys.h"
+#include "lib/dbwrap/dbwrap.h"
+#include "lib/dbwrap/dbwrap_open.h"
+#include "lib/dbwrap/dbwrap_watch.h"
+#include "lib/util/util_tdb.h"
+#include "source3/include/util_tdb.h"
+
+struct do_locked1_state {
+	TDB_DATA value;
+	NTSTATUS status;
+};
+
+static void do_locked1_cb(struct db_record *rec, void *private_data)
+{
+	struct do_locked1_state *state =
+		(struct do_locked1_state *)private_data;
+
+	state->status = dbwrap_record_store(rec, state->value, 0);
+}
+
+static void do_locked1_check(TDB_DATA key, TDB_DATA value,
+			     void *private_data)
+{
+	struct do_locked1_state *state =
+		(struct do_locked1_state *)private_data;
+	int ret;
+
+	ret = tdb_data_cmp(value, state->value);
+	if (ret != 0) {
+		state->status = NT_STATUS_DATA_ERROR;
+		return;
+	}
+
+	state->status = NT_STATUS_OK;
+}
+
+static void do_locked1_del(struct db_record *rec, void *private_data)
+{
+	struct do_locked1_state *state =
+		(struct do_locked1_state *)private_data;
+
+	state->status = dbwrap_record_delete(rec);
+}
+
+bool run_dbwrap_do_locked1(int dummy)
+{
+	struct db_context *db;
+	const char *dbname = "test_do_locked.tdb";
+	const char *keystr = "key";
+	TDB_DATA key = string_term_tdb_data(keystr);
+	const char *valuestr = "value";
+	TDB_DATA value = string_term_tdb_data(valuestr);
+	struct do_locked1_state state = { .value = value };
+	int ret = false;
+	NTSTATUS status;
+
+	db = db_open(talloc_tos(), dbname, 0, TDB_CLEAR_IF_FIRST,
+		     O_CREAT|O_RDWR, 0644, DBWRAP_LOCK_ORDER_1,
+		     DBWRAP_FLAG_NONE);
+	if (db == NULL) {
+		fprintf(stderr, "db_open failed: %s\n", strerror(errno));
+		return false;
+	}
+
+	status = dbwrap_do_locked(db, key, do_locked1_cb, &state);
+	if (!NT_STATUS_IS_OK(status)) {
+		fprintf(stderr, "dbwrap_do_locked failed: %s\n",
+			nt_errstr(status));
+		goto fail;
+	}
+	if (!NT_STATUS_IS_OK(state.status)) {
+		fprintf(stderr, "store returned %s\n", nt_errstr(status));
+		goto fail;
+	}
+
+	status = dbwrap_parse_record(db, key, do_locked1_check, &state);
+	if (!NT_STATUS_IS_OK(status)) {
+		fprintf(stderr, "dbwrap_parse_record failed: %s\n",
+			nt_errstr(status));
+		goto fail;
+	}
+	if (!NT_STATUS_IS_OK(state.status)) {
+		fprintf(stderr, "data compare returned %s\n",
+			nt_errstr(status));
+		goto fail;
+	}
+
+	status = dbwrap_do_locked(db, key, do_locked1_del, &state);
+	if (!NT_STATUS_IS_OK(status)) {
+		fprintf(stderr, "dbwrap_do_locked failed: %s\n",
+			nt_errstr(status));
+		goto fail;
+	}
+	if (!NT_STATUS_IS_OK(state.status)) {
+		fprintf(stderr, "delete returned %s\n", nt_errstr(status));
+		goto fail;
+	}
+
+	status = dbwrap_parse_record(db, key, do_locked1_check, &state);
+	if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+		fprintf(stderr, "parse_record returned %s, "
+			"expected NOT_FOUND\n", nt_errstr(status));
+		goto fail;
+	}
+
+	ret = true;
+fail:
+	TALLOC_FREE(db);
+	unlink(dbname);
+	return ret;
+}
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 64caca5..b8d4f5e 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -11523,6 +11523,7 @@ static struct {
 	{ "LOCAL-TALLOC-DICT", run_local_talloc_dict, 0},
 	{ "LOCAL-DBWRAP-WATCH1", run_dbwrap_watch1, 0 },
 	{ "LOCAL-DBWRAP-WATCH2", run_dbwrap_watch2, 0 },
+	{ "LOCAL-DBWRAP-DO-LOCKED1", run_dbwrap_do_locked1, 0 },
 	{ "LOCAL-MESSAGING-READ1", run_messaging_read1, 0 },
 	{ "LOCAL-MESSAGING-READ2", run_messaging_read2, 0 },
 	{ "LOCAL-MESSAGING-READ3", run_messaging_read3, 0 },
diff --git a/source3/wscript_build b/source3/wscript_build
index a030b8a..99f4a2b 100644
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -1203,6 +1203,7 @@ bld.SAMBA3_BINARY('smbtorture' + bld.env.suffix3,
                         torture/test_notify.c
                         lib/tevent_barrier.c
                         torture/test_dbwrap_watch.c
+                        torture/test_dbwrap_do_locked.c
                         torture/test_idmap_tdb_common.c
                         torture/test_dbwrap_ctdb.c
                         torture/test_buffersize.c
-- 
2.1.4


From 580a069ca0412a1f3e6efd67b8aac3b2a2d37ed5 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 27 Jun 2017 08:25:03 +0200
Subject: [PATCH 07/41] dbwrap_tdb: Implement do_locked

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/dbwrap/dbwrap_tdb.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/lib/dbwrap/dbwrap_tdb.c b/lib/dbwrap/dbwrap_tdb.c
index 9f8a9a6..c30bede 100644
--- a/lib/dbwrap/dbwrap_tdb.c
+++ b/lib/dbwrap/dbwrap_tdb.c
@@ -25,6 +25,7 @@
 #include "lib/util/util_tdb.h"
 #include "system/filesys.h"
 #include "lib/param/param.h"
+#include "libcli/util/error.h"
 
 struct db_tdb_ctx {
 	struct tdb_wrap *wtdb;
@@ -174,6 +175,51 @@ static struct db_record *db_tdb_try_fetch_locked(
 	return db_tdb_fetch_locked_internal(db, mem_ctx, key);
 }
 
+static NTSTATUS db_tdb_do_locked(struct db_context *db, TDB_DATA key,
+				 void (*fn)(struct db_record *rec,
+					    void *private_data),
+				 void *private_data)
+{
+	struct db_tdb_ctx *ctx = talloc_get_type_abort(
+		db->private_data, struct db_tdb_ctx);
+	uint8_t *buf = NULL;
+	struct db_record rec;
+	int ret;
+
+	ret = tdb_chainlock(ctx->wtdb->tdb, key);
+	if (ret == -1) {
+		enum TDB_ERROR err = tdb_error(ctx->wtdb->tdb);
+		DBG_DEBUG("tdb_chainlock failed: %s\n",
+			  tdb_errorstr(ctx->wtdb->tdb));
+		return map_nt_error_from_tdb(err);
+	}
+
+	ret = tdb_fetch_talloc(ctx->wtdb->tdb, key, ctx, &buf);
+
+	if ((ret != 0) && (ret != ENOENT)) {
+		DBG_DEBUG("tdb_fetch_talloc failed: %s\n",
+			  strerror(errno));
+		tdb_chainunlock(ctx->wtdb->tdb, key);
+		return map_nt_error_from_unix_common(ret);
+	}
+
+	rec = (struct db_record) {
+		.db = db, .key = key,
+		.value = (struct TDB_DATA) { .dptr = buf,
+					     .dsize = talloc_get_size(buf) },
+		.storev = db_tdb_storev, .delete_rec = db_tdb_delete,
+		.private_data = ctx
+	};
+
+	fn(&rec, private_data);
+
+	talloc_free(buf);
+
+	tdb_chainunlock(ctx->wtdb->tdb, key);
+
+	return NT_STATUS_OK;
+}
+
 static int db_tdb_exists(struct db_context *db, TDB_DATA key)
 {
 	struct db_tdb_ctx *ctx = talloc_get_type_abort(
@@ -446,6 +492,7 @@ struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
 
 	result->fetch_locked = db_tdb_fetch_locked;
 	result->try_fetch_locked = db_tdb_try_fetch_locked;
+	result->do_locked = db_tdb_do_locked;
 	result->traverse = db_tdb_traverse;
 	result->traverse_read = db_tdb_traverse_read;
 	result->parse_record = db_tdb_parse;
-- 
2.1.4


From bd8fad4cadce98d9f864fd578288822685a93692 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 1 Jul 2017 18:13:44 +0200
Subject: [PATCH 08/41] dbwrap_watch: Introduce dbwrap_watch_rec

The idea is to leave the "watchers" array unparsed until it's needed. This
avoids a few talloc calls and unnecessary parsing.

Also, it deletes quite a few lines of code and .text bytes.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/dbwrap/dbwrap_watch.c | 325 +++++++++++++++-----------------------
 1 file changed, 130 insertions(+), 195 deletions(-)

diff --git a/source3/lib/dbwrap/dbwrap_watch.c b/source3/lib/dbwrap/dbwrap_watch.c
index ab59803..6461067 100644
--- a/source3/lib/dbwrap/dbwrap_watch.c
+++ b/source3/lib/dbwrap/dbwrap_watch.c
@@ -116,16 +116,23 @@ static bool dbwrap_record_watchers_key_parse(
 #define NUM_WATCHERS_DELETED_BIT (1UL<<31)
 #define NUM_WATCHERS_MASK (NUM_WATCHERS_DELETED_BIT-1)
 
-static ssize_t dbwrap_watched_parse(TDB_DATA data, struct server_id *ids,
-				    size_t num_ids, bool *pdeleted,
-				    TDB_DATA *pdata)
+struct dbwrap_watch_rec {
+	uint8_t *watchers;
+	size_t num_watchers;
+	bool deleted;
+	TDB_DATA data;
+};
+
+static bool dbwrap_watch_rec_parse(TDB_DATA data,
+				   struct dbwrap_watch_rec *wrec)
 {
-	size_t i, num_watchers;
+	size_t num_watchers;
 	bool deleted;
+	TDB_DATA userdata = { 0 };
 
 	if (data.dsize < sizeof(uint32_t)) {
 		/* Fresh or invalid record */
-		return -1;
+		return false;
 	}
 
 	num_watchers = IVAL(data.dptr, 0);
@@ -138,93 +145,47 @@ static ssize_t dbwrap_watched_parse(TDB_DATA data, struct server_id *ids,
 
 	if (num_watchers > data.dsize/SERVER_ID_BUF_LENGTH) {
 		/* Invalid record */
-		return -1;
-	}
-
-	if (num_watchers > num_ids) {
-		/*
-		 * Not enough space to store the watchers server_id's.
-		 * Just move past all of them to allow the remaining part
-		 * of the record to be returned.
-		 */
-		data.dptr += num_watchers * SERVER_ID_BUF_LENGTH;
-		data.dsize -= num_watchers * SERVER_ID_BUF_LENGTH;
-		goto done;
+		return false;
 	}
 
-	/*
-	 * Note, even if marked deleted we still must
-	 * return the id's array to allow awoken
-	 * watchers to remove themselves.
-	 */
-
-	for (i=0; i<num_watchers; i++) {
-		server_id_get(&ids[i], data.dptr);
-		data.dptr += SERVER_ID_BUF_LENGTH;
-		data.dsize -= SERVER_ID_BUF_LENGTH;
+	if (!deleted) {
+		size_t watchers_len = num_watchers * SERVER_ID_BUF_LENGTH;
+		userdata = (TDB_DATA) {
+			.dptr = data.dptr + watchers_len,
+			.dsize = data.dsize - watchers_len
+		};
 	}
 
-done:
-	if (deleted) {
-		data = (TDB_DATA) {0};
-	}
-	if (pdata != NULL) {
-		*pdata = data;
-	}
-	if (pdeleted != NULL) {
-		*pdeleted = deleted;
-	}
+	*wrec = (struct dbwrap_watch_rec) {
+		.watchers = data.dptr, .num_watchers = num_watchers,
+		.deleted = deleted, .data = userdata
+	};
 
-	return num_watchers;
+	return true;
 }
 
-static ssize_t dbwrap_watched_unparse(const struct server_id *watchers,
-				      size_t num_watchers, bool deleted,
-				      TDB_DATA data,
-				      uint8_t *buf, size_t buflen)
+static void dbwrap_watch_rec_get_watcher(
+	struct dbwrap_watch_rec *wrec, size_t i, struct server_id *watcher)
 {
-	size_t i, len, ofs;
-	uint32_t num_watchers_buf;
-
-	if (num_watchers > UINT32_MAX/SERVER_ID_BUF_LENGTH) {
-		return -1;
+	if (i >= wrec->num_watchers) {
+		abort();
 	}
+	server_id_get(watcher, wrec->watchers + i * SERVER_ID_BUF_LENGTH);
+}
 
-	len = num_watchers * SERVER_ID_BUF_LENGTH;
-
-	len += sizeof(uint32_t);
-	if (len < sizeof(uint32_t)) {
-		return -1;
-	}
-
-	len += data.dsize;
-	if (len < data.dsize) {
-		return -1;
-	}
-
-	if (len > buflen) {
-		return len;
-	}
-
-	num_watchers_buf = num_watchers;
-	if (deleted) {
-		num_watchers_buf |= NUM_WATCHERS_DELETED_BIT;
-	}
-
-	ofs = 0;
-	SIVAL(buf, ofs, num_watchers_buf);
-	ofs += 4;
-
-	for (i=0; i<num_watchers; i++) {
-		server_id_put(buf+ofs, watchers[i]);
-		ofs += SERVER_ID_BUF_LENGTH;
+static void dbwrap_watch_rec_del_watcher(struct dbwrap_watch_rec *wrec,
+					 size_t i)
+{
+	if (i >= wrec->num_watchers) {
+		abort();
 	}
-
-	if ((data.dptr != NULL) && (data.dsize != 0)) {
-		memcpy(buf + ofs, data.dptr, data.dsize);
+	wrec->num_watchers -= 1;
+	if (i < wrec->num_watchers) {
+		uint8_t *wptr = wrec->watchers + i*SERVER_ID_BUF_LENGTH;
+		memcpy(wptr,
+		       wrec->watchers+wrec->num_watchers*SERVER_ID_BUF_LENGTH,
+		       SERVER_ID_BUF_LENGTH);
 	}
-
-	return len;
 }
 
 struct db_watched_ctx {
@@ -234,8 +195,7 @@ struct db_watched_ctx {
 
 struct db_watched_subrec {
 	struct db_record *subrec;
-	struct server_id *watchers;
-	bool deleted;
+	struct dbwrap_watch_rec wrec;
 };
 
 static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
@@ -251,7 +211,7 @@ static struct db_record *dbwrap_watched_fetch_locked(
 	struct db_record *rec;
 	struct db_watched_subrec *subrec;
 	TDB_DATA subrec_value;
-	ssize_t num_watchers;
+	bool ok;
 
 	rec = talloc_zero(mem_ctx, struct db_record);
 	if (rec == NULL) {
@@ -277,33 +237,21 @@ static struct db_record *dbwrap_watched_fetch_locked(
 
 	subrec_value = dbwrap_record_get_value(subrec->subrec);
 
-	num_watchers = dbwrap_watched_parse(subrec_value, NULL, 0, NULL, NULL);
-	if (num_watchers == -1) {
-		/* Fresh or invalid record */
-		rec->value = (TDB_DATA) { 0 };
-		return rec;
-	}
-
-	subrec->watchers = talloc_array(subrec, struct server_id,
-					num_watchers);
-	if (subrec->watchers == NULL) {
-		TALLOC_FREE(rec);
-		return NULL;
+	ok = dbwrap_watch_rec_parse(subrec_value, &subrec->wrec);
+	if (ok) {
+		rec->value = subrec->wrec.data;
 	}
 
-	dbwrap_watched_parse(subrec_value, subrec->watchers, num_watchers,
-			     &subrec->deleted, &rec->value);
-
 	return rec;
 }
 
 static void dbwrap_watched_wakeup(struct db_record *rec,
-				  struct db_watched_subrec *subrec)
+				  struct dbwrap_watch_rec *wrec)
 {
-	struct db_context *db = dbwrap_record_get_db(rec);
+	struct db_context *db = rec->db;
 	struct db_watched_ctx *ctx = talloc_get_type_abort(
 		db->private_data, struct db_watched_ctx);
-	size_t i, num_watchers;
+	size_t i;
 	size_t db_id_len = dbwrap_db_id(db, NULL, 0);
 	uint8_t db_id[db_id_len];
 	uint8_t len_buf[4];
@@ -318,32 +266,27 @@ static void dbwrap_watched_wakeup(struct db_record *rec,
 
 	dbwrap_db_id(db, db_id, db_id_len);
 
-	num_watchers = talloc_array_length(subrec->watchers);
-
 	i = 0;
 
-	while (i < num_watchers) {
+	while (i < wrec->num_watchers) {
+		struct server_id watcher;
 		NTSTATUS status;
 		struct server_id_buf tmp;
 
-		DBG_DEBUG("Alerting %s\n",
-			  server_id_str_buf(subrec->watchers[i], &tmp));
+		dbwrap_watch_rec_get_watcher(wrec, i, &watcher);
 
-		status = messaging_send_iov(ctx->msg, subrec->watchers[i],
+		DBG_DEBUG("Alerting %s\n", server_id_str_buf(watcher, &tmp));
+
+		status = messaging_send_iov(ctx->msg, watcher,
 					    MSG_DBWRAP_MODIFIED,
 					    iov, ARRAY_SIZE(iov), NULL, 0);
 		if (!NT_STATUS_IS_OK(status)) {
 			DBG_DEBUG("messaging_send_iov to %s failed: %s\n",
-				  server_id_str_buf(subrec->watchers[i], &tmp),
+				  server_id_str_buf(watcher, &tmp),
 				  nt_errstr(status));
 		}
 		if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
-			subrec->watchers[i] = subrec->watchers[num_watchers-1];
-			num_watchers -= 1;
-
-			subrec->watchers = talloc_realloc(
-				subrec, subrec->watchers, struct server_id,
-				num_watchers);
+			dbwrap_watch_rec_del_watcher(wrec, i);
 			continue;
 		}
 
@@ -351,61 +294,68 @@ static void dbwrap_watched_wakeup(struct db_record *rec,
 	}
 }
 
-static NTSTATUS dbwrap_watched_save(struct db_watched_subrec *subrec,
-				    TDB_DATA data, int flag)
+static NTSTATUS dbwrap_watched_save(struct db_record *rec,
+				    struct dbwrap_watch_rec *wrec,
+				    struct server_id *addwatch,
+				    const TDB_DATA *databufs,
+				    size_t num_databufs,
+				    int flags)
 {
-	size_t num_watchers;
-	ssize_t len;
-	uint8_t *buf;
+	uint32_t num_watchers_buf;
+	uint8_t sizebuf[4];
+	uint8_t addbuf[SERVER_ID_BUF_LENGTH];
 	NTSTATUS status;
+	struct TDB_DATA dbufs[num_databufs+3];
 
-	num_watchers = talloc_array_length(subrec->watchers);
+	dbufs[0] = (TDB_DATA) {
+		.dptr = sizebuf, .dsize = sizeof(sizebuf)
+	};
 
-	len = dbwrap_watched_unparse(subrec->watchers, num_watchers,
-				     subrec->deleted, data, NULL, 0);
-	if (len == -1) {
-		return NT_STATUS_INSUFFICIENT_RESOURCES;
-	}
+	dbufs[1] = (TDB_DATA) {
+		.dptr = wrec->watchers,
+		.dsize = wrec->num_watchers * SERVER_ID_BUF_LENGTH
+	};
 
-	buf = talloc_array(subrec, uint8_t, len);
-	if (buf == NULL) {
-		return NT_STATUS_NO_MEMORY;
+	if (addwatch != NULL) {
+		server_id_put(addbuf, *addwatch);
+
+		dbufs[2] = (TDB_DATA) {
+			.dptr = addbuf, .dsize = SERVER_ID_BUF_LENGTH
+		};
+		wrec->num_watchers += 1;
+	} else {
+		dbufs[2] = (TDB_DATA) { 0 };
 	}
 
-	dbwrap_watched_unparse(subrec->watchers, num_watchers,
-			       subrec->deleted, data, buf, len);
+	if (num_databufs != 0) {
+		memcpy(&dbufs[3], databufs, sizeof(TDB_DATA) * num_databufs);
+	}
 
-	status = dbwrap_record_store(
-		subrec->subrec, (TDB_DATA) { .dptr = buf, .dsize = len },
-		flag);
+	num_watchers_buf = wrec->num_watchers;
+	if (wrec->deleted) {
+		num_watchers_buf |= NUM_WATCHERS_DELETED_BIT;
+	}
 
-	TALLOC_FREE(buf);
+	SIVAL(sizebuf, 0, num_watchers_buf);
 
+	status = dbwrap_record_storev(rec, dbufs, ARRAY_SIZE(dbufs), flags);
 	return status;
 }
 
 static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
 				      const TDB_DATA *dbufs, int num_dbufs,
-				      int flag)
+				      int flags)
 {
 	struct db_watched_subrec *subrec = talloc_get_type_abort(
 		rec->private_data, struct db_watched_subrec);
 	NTSTATUS status;
-	TDB_DATA data;
 
-	data = dbwrap_merge_dbufs(rec, dbufs, num_dbufs);
-	if (data.dptr == NULL) {
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	dbwrap_watched_wakeup(rec, subrec);
-
-	subrec->deleted = false;
+	dbwrap_watched_wakeup(rec, &subrec->wrec);
 
-	status = dbwrap_watched_save(subrec, data, flag);
-
-	TALLOC_FREE(data.dptr);
+	subrec->wrec.deleted = false;
 
+	status = dbwrap_watched_save(subrec->subrec, &subrec->wrec, NULL,
+				     dbufs, num_dbufs, flags);
 	return status;
 }
 
@@ -413,18 +363,17 @@ static NTSTATUS dbwrap_watched_delete(struct db_record *rec)
 {
 	struct db_watched_subrec *subrec = talloc_get_type_abort(
 		rec->private_data, struct db_watched_subrec);
-	size_t num_watchers;
 
-	dbwrap_watched_wakeup(rec, subrec);
+	dbwrap_watched_wakeup(rec, &subrec->wrec);
 
-	num_watchers = talloc_array_length(subrec->watchers);
-	if (num_watchers == 0) {
+	if (subrec->wrec.num_watchers == 0) {
 		return dbwrap_record_delete(subrec->subrec);
 	}
 
-	subrec->deleted = true;
+	subrec->wrec.deleted = true;
 
-	return dbwrap_watched_save(subrec, (TDB_DATA) {0}, 0);
+	return dbwrap_watched_save(subrec->subrec, &subrec->wrec,
+				   NULL, NULL, 0, 0);
 }
 
 struct dbwrap_watched_traverse_state {
@@ -436,17 +385,17 @@ static int dbwrap_watched_traverse_fn(struct db_record *rec,
 				      void *private_data)
 {
 	struct dbwrap_watched_traverse_state *state = private_data;
-	ssize_t num_watchers;
 	struct db_record prec = *rec;
-	bool deleted;
-
-	num_watchers = dbwrap_watched_parse(rec->value, NULL, 0, &deleted,
-					    &prec.value);
+	struct dbwrap_watch_rec wrec;
+	bool ok;
 
-	if ((num_watchers == -1) || deleted) {
+	ok = dbwrap_watch_rec_parse(rec->value, &wrec);
+	if (!ok || wrec.deleted) {
 		return 0;
 	}
 
+	prec.value = wrec.data;
+
 	return state->fn(&prec, state->private_data);
 }
 
@@ -528,18 +477,16 @@ static void dbwrap_watched_parse_record_parser(TDB_DATA key, TDB_DATA data,
 					       void *private_data)
 {
 	struct dbwrap_watched_parse_record_state *state = private_data;
-	ssize_t num_watchers;
-	TDB_DATA userdata;
+	struct dbwrap_watch_rec wrec;
+	bool ok;
 
-	num_watchers = dbwrap_watched_parse(data, NULL, 0, &state->deleted,
-					    &userdata);
-	if (num_watchers == -1) {
+	ok = dbwrap_watch_rec_parse(data, &wrec);
+	if ((!ok) || (wrec.deleted)) {
 		state->deleted = true;
-	}
-	if (state->deleted) {
 		return;
 	}
-	state->parser(key, userdata, state->private_data);
+
+	state->parser(key, wrec.data, state->private_data);
 }
 
 static NTSTATUS dbwrap_watched_parse_record(
@@ -736,8 +683,6 @@ struct tevent_req *dbwrap_watched_watch_send(TALLOC_CTX *mem_ctx,
 	struct tevent_req *req, *subreq;
 	struct dbwrap_watched_watch_state *state;
 	ssize_t needed;
-	size_t num_watchers;
-	struct server_id *tmp;
 	NTSTATUS status;
 
 	req = tevent_req_create(mem_ctx, &state,
@@ -776,17 +721,8 @@ struct tevent_req *dbwrap_watched_watch_send(TALLOC_CTX *mem_ctx,
 	}
 	tevent_req_set_callback(subreq, dbwrap_watched_watch_done, req);
 
-	num_watchers = talloc_array_length(subrec->watchers);
-
-	tmp = talloc_realloc(subrec, subrec->watchers, struct server_id,
-			     num_watchers + 1);
-	if (tevent_req_nomem(tmp, req)) {
-		return tevent_req_post(req, ev);
-	}
-	subrec->watchers = tmp;
-	subrec->watchers[num_watchers] = state->me;
-
-	status = dbwrap_watched_save(subrec, rec->value, 0);
+	status = dbwrap_watched_save(subrec->subrec, &subrec->wrec, &state->me,
+				     &subrec->wrec.data, 1, 0);
 	if (tevent_req_nterror(req, status)) {
 		return tevent_req_post(req, ev);
 	}
@@ -823,30 +759,27 @@ static void dbwrap_watched_watch_blocker_died(struct tevent_req *subreq)
 	tevent_req_done(req);
 }
 
-static bool dbwrap_watched_remove_waiter(struct db_watched_subrec *subrec,
+static bool dbwrap_watched_remove_waiter(struct dbwrap_watch_rec *wrec,
 					 struct server_id id)
 {
-	size_t i, num_watchers;
+	size_t i;
 
-	num_watchers = talloc_array_length(subrec->watchers);
-
-	for (i=0; i<num_watchers; i++) {
-		if (server_id_equal(&id, &subrec->watchers[i])) {
+	for (i=0; i<wrec->num_watchers; i++) {
+		struct server_id watcher;
+		dbwrap_watch_rec_get_watcher(wrec, i, &watcher);
+		if (server_id_equal(&id, &watcher)) {
 			break;
 		}
 	}
 
-	if (i == num_watchers) {
+	if (i == wrec->num_watchers) {
 		struct server_id_buf buf;
 		DBG_WARNING("Did not find %s in state->watchers\n",
 			    server_id_str_buf(id, &buf));
 		return false;
 	}
 
-	subrec->watchers[i] = subrec->watchers[num_watchers-1];
-	subrec->watchers = talloc_realloc(subrec, subrec->watchers,
-					  struct server_id, num_watchers-1);
-
+	dbwrap_watch_rec_del_watcher(wrec, i);
 	return true;
 }
 
@@ -873,10 +806,11 @@ static int dbwrap_watched_watch_state_destructor(
 	subrec = talloc_get_type_abort(
 		rec->private_data, struct db_watched_subrec);
 
-	ok = dbwrap_watched_remove_waiter(subrec, state->me);
+	ok = dbwrap_watched_remove_waiter(&subrec->wrec, state->me);
 	if (ok) {
 		NTSTATUS status;
-		status = dbwrap_watched_save(subrec, rec->value, 0);
+		status = dbwrap_watched_save(subrec->subrec, &subrec->wrec,
+					     NULL, &subrec->wrec.data, 1, 0);
 		if (!NT_STATUS_IS_OK(status)) {
 			DBG_WARNING("dbwrap_watched_save failed: %s\n",
 				    nt_errstr(status));
@@ -967,9 +901,10 @@ NTSTATUS dbwrap_watched_watch_recv(struct tevent_req *req,
 	subrec = talloc_get_type_abort(
 		rec->private_data, struct db_watched_subrec);
 
-	ok = dbwrap_watched_remove_waiter(subrec, state->me);
+	ok = dbwrap_watched_remove_waiter(&subrec->wrec, state->me);
 	if (ok) {
-		status = dbwrap_watched_save(subrec, rec->value, 0);
+		status = dbwrap_watched_save(subrec->subrec, &subrec->wrec,
+					     NULL, &subrec->wrec.data, 1, 0);
 		if (!NT_STATUS_IS_OK(status)) {
 			DBG_WARNING("dbwrap_watched_save failed: %s\n",
 				    nt_errstr(status));
-- 
2.1.4


From 8e8a3709330f06a38d148f9dbd75ceda4bcf548a Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 27 Jun 2017 18:40:28 +0200
Subject: [PATCH 09/41] dbwrap_watch: Implement do_locked

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/dbwrap/dbwrap_watch.c       | 167 +++++++++++++++++++++++++++++---
 source3/torture/test_dbwrap_do_locked.c |  32 +++++-
 2 files changed, 182 insertions(+), 17 deletions(-)

diff --git a/source3/lib/dbwrap/dbwrap_watch.c b/source3/lib/dbwrap/dbwrap_watch.c
index 6461067..be0a0d3 100644
--- a/source3/lib/dbwrap/dbwrap_watch.c
+++ b/source3/lib/dbwrap/dbwrap_watch.c
@@ -198,10 +198,23 @@ struct db_watched_subrec {
 	struct dbwrap_watch_rec wrec;
 };
 
+static NTSTATUS dbwrap_watched_subrec_storev(
+	struct db_record *rec, struct db_watched_subrec *subrec,
+	const TDB_DATA *dbufs, int num_dbufs, int flags);
+static NTSTATUS dbwrap_watched_subrec_delete(
+	struct db_record *rec, struct db_watched_subrec *subrec);
 static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
 				      const TDB_DATA *dbufs, int num_dbufs,
-				      int flag);
+				      int flags);
 static NTSTATUS dbwrap_watched_delete(struct db_record *rec);
+static void dbwrap_watched_wakeup(struct db_record *rec,
+				  struct dbwrap_watch_rec *wrec);
+static NTSTATUS dbwrap_watched_save(struct db_record *rec,
+				    struct dbwrap_watch_rec *wrec,
+				    struct server_id *addwatch,
+				    const TDB_DATA *databufs,
+				    size_t num_databufs,
+				    int flags);
 
 static struct db_record *dbwrap_watched_fetch_locked(
 	struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
@@ -245,6 +258,95 @@ static struct db_record *dbwrap_watched_fetch_locked(
 	return rec;
 }
 
+struct dbwrap_watched_do_locked_state {
+	TALLOC_CTX *mem_ctx;
+	struct db_context *db;
+	void (*fn)(struct db_record *rec, void *private_data);
+	void *private_data;
+
+	struct db_watched_subrec subrec;
+
+	NTSTATUS status;
+};
+
+static NTSTATUS dbwrap_watched_do_locked_storev(
+	struct db_record *rec, const TDB_DATA *dbufs, int num_dbufs,
+	int flags)
+{
+	struct dbwrap_watched_do_locked_state *state = rec->private_data;
+	struct db_watched_subrec *subrec = &state->subrec;
+	NTSTATUS status;
+
+	status = dbwrap_watched_subrec_storev(rec, subrec, dbufs, num_dbufs,
+					      flags);
+	return status;
+}
+
+static NTSTATUS dbwrap_watched_do_locked_delete(struct db_record *rec)
+{
+	struct dbwrap_watched_do_locked_state *state = rec->private_data;
+	struct db_watched_subrec *subrec = &state->subrec;
+	NTSTATUS status;
+
+	status = dbwrap_watched_subrec_delete(rec, subrec);
+	return status;
+}
+
+static void dbwrap_watched_do_locked_fn(struct db_record *subrec,
+					void *private_data)
+{
+	struct dbwrap_watched_do_locked_state *state =
+		(struct dbwrap_watched_do_locked_state *)private_data;
+	TDB_DATA subrec_value = dbwrap_record_get_value(subrec);
+	struct db_record rec;
+	bool ok;
+
+	rec = (struct db_record) {
+		.db = state->db, .key = dbwrap_record_get_key(subrec),
+		.storev = dbwrap_watched_do_locked_storev,
+		.delete_rec = dbwrap_watched_do_locked_delete,
+		.private_data = state
+	};
+
+	state->subrec = (struct db_watched_subrec) {
+		.subrec = subrec
+	};
+
+	ok = dbwrap_watch_rec_parse(subrec_value, &state->subrec.wrec);
+	if (ok) {
+		rec.value = state->subrec.wrec.data;
+	}
+
+	state->fn(&rec, state->private_data);
+}
+
+static NTSTATUS dbwrap_watched_do_locked(struct db_context *db, TDB_DATA key,
+					 void (*fn)(struct db_record *rec,
+						    void *private_data),
+					 void *private_data)
+{
+	struct db_watched_ctx *ctx = talloc_get_type_abort(
+		db->private_data, struct db_watched_ctx);
+	struct dbwrap_watched_do_locked_state state = {
+		.mem_ctx = talloc_stackframe(),
+		.db = db, .fn = fn, .private_data = private_data
+	};
+	NTSTATUS status;
+
+	status = dbwrap_do_locked(
+		ctx->backend, key, dbwrap_watched_do_locked_fn, &state);
+	TALLOC_FREE(state.mem_ctx);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_DEBUG("dbwrap_do_locked returned %s\n", nt_errstr(status));
+		return status;
+	}
+
+	DBG_DEBUG("dbwrap_watched_do_locked_fn returned %s\n",
+		  nt_errstr(state.status));
+
+	return state.status;
+}
+
 static void dbwrap_watched_wakeup(struct db_record *rec,
 				  struct dbwrap_watch_rec *wrec)
 {
@@ -342,12 +444,10 @@ static NTSTATUS dbwrap_watched_save(struct db_record *rec,
 	return status;
 }
 
-static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
-				      const TDB_DATA *dbufs, int num_dbufs,
-				      int flags)
+static NTSTATUS dbwrap_watched_subrec_storev(
+	struct db_record *rec, struct db_watched_subrec *subrec,
+	const TDB_DATA *dbufs, int num_dbufs, int flags)
 {
-	struct db_watched_subrec *subrec = talloc_get_type_abort(
-		rec->private_data, struct db_watched_subrec);
 	NTSTATUS status;
 
 	dbwrap_watched_wakeup(rec, &subrec->wrec);
@@ -359,10 +459,23 @@ static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
 	return status;
 }
 
-static NTSTATUS dbwrap_watched_delete(struct db_record *rec)
+static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
+				      const TDB_DATA *dbufs, int num_dbufs,
+				      int flags)
 {
 	struct db_watched_subrec *subrec = talloc_get_type_abort(
 		rec->private_data, struct db_watched_subrec);
+	NTSTATUS status;
+
+	status = dbwrap_watched_subrec_storev(rec, subrec, dbufs, num_dbufs,
+					      flags);
+	return status;
+}
+
+static NTSTATUS dbwrap_watched_subrec_delete(
+	struct db_record *rec, struct db_watched_subrec *subrec)
+{
+	NTSTATUS status;
 
 	dbwrap_watched_wakeup(rec, &subrec->wrec);
 
@@ -372,8 +485,19 @@ static NTSTATUS dbwrap_watched_delete(struct db_record *rec)
 
 	subrec->wrec.deleted = true;
 
-	return dbwrap_watched_save(subrec->subrec, &subrec->wrec,
-				   NULL, NULL, 0, 0);
+	status = dbwrap_watched_save(subrec->subrec, &subrec->wrec,
+				     NULL, NULL, 0, 0);
+	return status;
+}
+
+static NTSTATUS dbwrap_watched_delete(struct db_record *rec)
+{
+	struct db_watched_subrec *subrec = talloc_get_type_abort(
+		rec->private_data, struct db_watched_subrec);
+	NTSTATUS status;
+
+	status = dbwrap_watched_subrec_delete(rec, subrec);
+	return status;
 }
 
 struct dbwrap_watched_traverse_state {
@@ -638,6 +762,7 @@ struct db_context *db_open_watched(TALLOC_CTX *mem_ctx,
 	ctx->backend = talloc_move(ctx, &backend);
 
 	db->fetch_locked = dbwrap_watched_fetch_locked;
+	db->do_locked = dbwrap_watched_do_locked;
 	db->traverse = dbwrap_watched_traverse;
 	db->traverse_read = dbwrap_watched_traverse_read;
 	db->get_seqnum = dbwrap_watched_get_seqnum;
@@ -674,12 +799,10 @@ struct tevent_req *dbwrap_watched_watch_send(TALLOC_CTX *mem_ctx,
 					     struct db_record *rec,
 					     struct server_id blocker)
 {
-	struct db_watched_subrec *subrec = talloc_get_type_abort(
-		rec->private_data, struct db_watched_subrec);
 	struct db_context *db = dbwrap_record_get_db(rec);
 	struct db_watched_ctx *ctx = talloc_get_type_abort(
 		db->private_data, struct db_watched_ctx);
-
+	struct db_watched_subrec *subrec = NULL;
 	struct tevent_req *req, *subreq;
 	struct dbwrap_watched_watch_state *state;
 	ssize_t needed;
@@ -698,6 +821,26 @@ struct tevent_req *dbwrap_watched_watch_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
+	/*
+	 * Figure out whether we're called as part of do_locked. If
+	 * so, we can't use talloc_get_type_abort, the
+	 * db_watched_subrec is stack-allocated in that case.
+	 */
+
+	if (rec->storev == dbwrap_watched_storev) {
+		subrec = talloc_get_type_abort(rec->private_data,
+					       struct db_watched_subrec);
+	}
+	if (rec->storev == dbwrap_watched_do_locked_storev) {
+		struct dbwrap_watched_do_locked_state *do_locked_state;
+		do_locked_state = rec->private_data;
+		subrec = &do_locked_state->subrec;
+	}
+	if (subrec == NULL) {
+		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+		return tevent_req_post(req, ev);
+	}
+
 	state->me = messaging_server_id(ctx->msg);
 
 	needed = dbwrap_record_watchers_key(db, rec, NULL, 0);
diff --git a/source3/torture/test_dbwrap_do_locked.c b/source3/torture/test_dbwrap_do_locked.c
index 92dec38..46b326b 100644
--- a/source3/torture/test_dbwrap_do_locked.c
+++ b/source3/torture/test_dbwrap_do_locked.c
@@ -65,6 +65,9 @@ static void do_locked1_del(struct db_record *rec, void *private_data)
 
 bool run_dbwrap_do_locked1(int dummy)
 {
+	struct tevent_context *ev;
+	struct messaging_context *msg;
+	struct db_context *backend;
 	struct db_context *db;
 	const char *dbname = "test_do_locked.tdb";
 	const char *keystr = "key";
@@ -75,14 +78,32 @@ bool run_dbwrap_do_locked1(int dummy)
 	int ret = false;
 	NTSTATUS status;
 
-	db = db_open(talloc_tos(), dbname, 0, TDB_CLEAR_IF_FIRST,
-		     O_CREAT|O_RDWR, 0644, DBWRAP_LOCK_ORDER_1,
-		     DBWRAP_FLAG_NONE);
-	if (db == NULL) {
+	ev = server_event_context();
+	if (ev == NULL) {
+		fprintf(stderr, "server_event_context() failed\n");
+		return false;
+	}
+	msg = server_messaging_context();
+	if (msg == NULL) {
+		fprintf(stderr, "server_messaging_context() failed\n");
+		return false;
+	}
+
+	backend = db_open(talloc_tos(), dbname, 0,
+			  TDB_CLEAR_IF_FIRST, O_CREAT|O_RDWR, 0644,
+			  DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
+	if (backend == NULL) {
 		fprintf(stderr, "db_open failed: %s\n", strerror(errno));
 		return false;
 	}
 
+	db = db_open_watched(talloc_tos(), backend, msg);
+	if (db == NULL) {
+		fprintf(stderr, "db_open_watched failed: %s\n",
+			strerror(errno));
+		return false;
+	}
+
 	status = dbwrap_do_locked(db, key, do_locked1_cb, &state);
 	if (!NT_STATUS_IS_OK(status)) {
 		fprintf(stderr, "dbwrap_do_locked failed: %s\n",
@@ -90,7 +111,8 @@ bool run_dbwrap_do_locked1(int dummy)
 		goto fail;
 	}
 	if (!NT_STATUS_IS_OK(state.status)) {
-		fprintf(stderr, "store returned %s\n", nt_errstr(status));
+		fprintf(stderr, "store returned %s\n",
+			nt_errstr(state.status));
 		goto fail;
 	}
 
-- 
2.1.4


From db5f5766f8384891f7c0fbd96997a03908c74730 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 28 Jun 2017 16:21:19 +0200
Subject: [PATCH 10/41] g_lock: Walk locks only once in g_lock_trylock

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/g_lock.c | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
index 198fe56..a22ec94 100644
--- a/source3/lib/g_lock.c
+++ b/source3/lib/g_lock.c
@@ -297,18 +297,11 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
 				goto done;
 			}
 			my_lock = i;
-			break;
-		}
-	}
-
-	for (i=0; i<num_locks; i++) {
-
-		if (i == my_lock) {
 			continue;
 		}
 
-		if (g_lock_conflicts(type, locks[i].lock_type)) {
-			struct server_id pid = locks[i].pid;
+		if (g_lock_conflicts(type, lock->lock_type)) {
+			struct server_id pid = lock->pid;
 
 			/*
 			 * As the serverid_exists might recurse into
@@ -319,7 +312,7 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
 
 			if (serverid_exists(&pid)) {
 				status = NT_STATUS_LOCK_NOT_GRANTED;
-				*blocker = locks[i].pid;
+				*blocker = lock->pid;
 				goto done;
 			}
 
-- 
2.1.4


From 0aeadbd41d9dfdf601b18856a8c0e91c807e160a Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 28 Jun 2017 19:12:36 +0200
Subject: [PATCH 11/41] g_lock: simplify g_lock_trylock

The now mandatory talloc_realloc_array will go away soon

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/g_lock.c | 33 ++++++++++++++++++---------------
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
index a22ec94..e93ef3f 100644
--- a/source3/lib/g_lock.c
+++ b/source3/lib/g_lock.c
@@ -257,7 +257,7 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
 			       struct server_id *blocker)
 {
 	TDB_DATA data, userdata;
-	size_t i, num_locks, my_lock;
+	size_t i, num_locks;
 	struct g_lock_rec *locks, *tmp;
 	NTSTATUS status;
 	bool modified = false;
@@ -270,8 +270,6 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
 		return status;
 	}
 
-	my_lock = num_locks;	/* doesn't exist yet */
-
 	if ((type == G_LOCK_READ) && (num_locks > 0)) {
 		/*
 		 * Read locks can stay around forever if the process
@@ -296,7 +294,12 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
 				status = NT_STATUS_WAS_LOCKED;
 				goto done;
 			}
-			my_lock = i;
+			/*
+			 * Remove "our" lock entry. Re-add it later
+			 * with our new lock type.
+			 */
+			locks[i] = locks[num_locks-1];
+			num_locks -= 1;
 			continue;
 		}
 
@@ -325,19 +328,19 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
 		}
 	}
 
-	if (my_lock >= num_locks) {
-		tmp = talloc_realloc(talloc_tos(), locks, struct g_lock_rec,
-				     num_locks+1);
-		if (tmp == NULL) {
-			status = NT_STATUS_NO_MEMORY;
-			goto done;
-		}
-		locks = tmp;
-		my_lock = num_locks;
-		num_locks += 1;
+	tmp = talloc_realloc(talloc_tos(), locks, struct g_lock_rec,
+			     num_locks+1);
+	if (tmp == NULL) {
+		status = NT_STATUS_NO_MEMORY;
+		goto done;
 	}
+	locks = tmp;
+
+	locks[num_locks] = (struct g_lock_rec) {
+		.pid = self, .lock_type = type
+	};
+	num_locks +=1 ;
 
-	locks[my_lock] = (struct g_lock_rec){ .pid = self, .lock_type = type };
 	modified = true;
 
 	status = NT_STATUS_OK;
-- 
2.1.4


From 35934b7fa74ae76313f88da470a139490a64e865 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 28 Jun 2017 13:36:53 +0200
Subject: [PATCH 12/41] g_lock: add "struct g_lock" without talloc

Enable handing the g_lock.tdb content without having to talloc

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/g_lock.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)

diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
index e93ef3f..e08f6a3 100644
--- a/source3/lib/g_lock.c
+++ b/source3/lib/g_lock.c
@@ -56,6 +56,91 @@ static void g_lock_rec_get(struct g_lock_rec *rec,
 	server_id_get(&rec->pid, buf+1);
 }
 
+struct g_lock {
+	uint8_t *recsbuf;
+	size_t num_recs;
+	uint8_t *data;
+	size_t datalen;
+};
+
+static bool g_lock_parse(uint8_t *buf, size_t buflen, struct g_lock *lck)
+{
+	size_t found_recs, data_ofs;
+
+	if (buflen < sizeof(uint32_t)) {
+		*lck = (struct g_lock) {0};
+		return true;
+	}
+
+	found_recs = IVAL(buf, 0);
+
+	if (found_recs > buflen/G_LOCK_REC_LENGTH) {
+		return false;
+	}
+
+	buf += sizeof(uint32_t);
+	buflen -= sizeof(uint32_t);
+	data_ofs = found_recs * G_LOCK_REC_LENGTH;
+
+	*lck = (struct g_lock) {
+		.recsbuf = buf, .num_recs = found_recs,
+		.data = buf+data_ofs, .datalen = buflen-data_ofs
+	};
+
+	return true;
+}
+
+static void g_lock_get_rec(struct g_lock *lck, size_t i,
+			   struct g_lock_rec *rec)
+{
+	if (i >= lck->num_recs) {
+		abort();
+	}
+	g_lock_rec_get(rec, lck->recsbuf + i*G_LOCK_REC_LENGTH);
+}
+
+static void g_lock_rec_del(struct g_lock *lck, size_t i)
+{
+	if (i >= lck->num_recs) {
+		abort();
+	}
+	lck->num_recs -= 1;
+	if (i < lck->num_recs) {
+		uint8_t *recptr = lck->recsbuf + i*G_LOCK_REC_LENGTH;
+		memcpy(recptr, lck->recsbuf + lck->num_recs*G_LOCK_REC_LENGTH,
+		       G_LOCK_REC_LENGTH);
+	}
+}
+
+static NTSTATUS g_lock_store(struct db_record *rec, struct g_lock *lck,
+			     struct g_lock_rec *add)
+{
+	uint8_t sizebuf[4];
+	uint8_t addbuf[G_LOCK_REC_LENGTH];
+
+	struct TDB_DATA dbufs[] = {
+		{ .dptr = sizebuf, .dsize = sizeof(sizebuf) },
+		{ .dptr = lck->recsbuf,
+		  .dsize = lck->num_recs * G_LOCK_REC_LENGTH },
+		{ 0 },
+		{ .dptr = lck->data, .dsize = lck->datalen }
+	};
+
+	if (add != NULL) {
+		g_lock_rec_put(addbuf, *add);
+
+		dbufs[2] = (TDB_DATA) {
+			.dptr = addbuf, .dsize = G_LOCK_REC_LENGTH
+		};
+
+		lck->num_recs += 1;
+	}
+
+	SIVAL(sizebuf, 0, lck->num_recs);
+
+	return dbwrap_record_storev(rec, dbufs, ARRAY_SIZE(dbufs), 0);
+}
+
 static ssize_t g_lock_put(uint8_t *buf, size_t buflen,
 			  const struct g_lock_rec *locks,
 			  size_t num_locks,
-- 
2.1.4


From 79af16a45e34c5207661569d7492104371689f8f Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 28 Jun 2017 15:39:49 +0200
Subject: [PATCH 13/41] g_lock: Implement g_lock_unlock without talloc

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/g_lock.c | 91 +++++++++++++++++++++++++++++-----------------------
 1 file changed, 50 insertions(+), 41 deletions(-)

diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
index e08f6a3..7a924b9 100644
--- a/source3/lib/g_lock.c
+++ b/source3/lib/g_lock.c
@@ -601,63 +601,72 @@ NTSTATUS g_lock_lock(struct g_lock_ctx *ctx, const char *name,
 	return status;
 }
 
-NTSTATUS g_lock_unlock(struct g_lock_ctx *ctx, const char *name)
-{
-	struct server_id self = messaging_server_id(ctx->msg);
-	struct db_record *rec = NULL;
-	struct g_lock_rec *locks = NULL;
-	size_t i, num_locks;
+struct g_lock_unlock_state {
+	const char *name;
+	struct server_id self;
 	NTSTATUS status;
-	TDB_DATA value, userdata;
+};
 
-	rec = dbwrap_fetch_locked(ctx->db, talloc_tos(),
-				  string_term_tdb_data(name));
-	if (rec == NULL) {
-		DEBUG(10, ("fetch_locked(\"%s\") failed\n", name));
-		status = NT_STATUS_INTERNAL_ERROR;
-		goto done;
-	}
+static void g_lock_unlock_fn(struct db_record *rec,
+			     void *private_data)
+{
+	struct g_lock_unlock_state *state = private_data;
+	TDB_DATA value;
+	struct g_lock lck;
+	size_t i;
+	bool ok;
 
 	value = dbwrap_record_get_value(rec);
 
-	status = g_lock_get_talloc(talloc_tos(), value, &locks, &num_locks,
-				   &userdata.dptr, &userdata.dsize);
-	if (!NT_STATUS_IS_OK(status)) {
-		DBG_DEBUG("g_lock_get for %s failed: %s\n", name,
-			  nt_errstr(status));
-		status = NT_STATUS_FILE_INVALID;
-		goto done;
+	ok = g_lock_parse(value.dptr, value.dsize, &lck);
+	if (!ok) {
+		DBG_DEBUG("g_lock_get for %s failed\n", state->name);
+		state->status = NT_STATUS_FILE_INVALID;
+		return;
 	}
-	for (i=0; i<num_locks; i++) {
-		if (serverid_equal(&self, &locks[i].pid)) {
+	for (i=0; i<lck.num_recs; i++) {
+		struct g_lock_rec lockrec;
+		g_lock_get_rec(&lck, i, &lockrec);
+		if (serverid_equal(&state->self, &lockrec.pid)) {
 			break;
 		}
 	}
-	if (i == num_locks) {
-		DBG_DEBUG("Lock not found, num_locks=%zu\n", num_locks);
-		status = NT_STATUS_NOT_FOUND;
-		goto done;
+	if (i == lck.num_recs) {
+		DBG_DEBUG("Lock not found, num_rec=%zu\n", lck.num_recs);
+		state->status = NT_STATUS_NOT_FOUND;
+		return;
 	}
 
-	locks[i] = locks[num_locks-1];
-	num_locks -= 1;
+	g_lock_rec_del(&lck, i);
 
-	if ((num_locks == 0) && (userdata.dsize == 0)) {
-		status = dbwrap_record_delete(rec);
-	} else {
-		status = g_lock_record_store(
-			rec, locks, num_locks, userdata.dptr, userdata.dsize);
+	if ((lck.num_recs == 0) && (lck.datalen == 0)) {
+		state->status = dbwrap_record_delete(rec);
+		return;
 	}
+	state->status = g_lock_store(rec, &lck, NULL);
+}
+
+NTSTATUS g_lock_unlock(struct g_lock_ctx *ctx, const char *name)
+{
+	struct g_lock_unlock_state state = {
+		.self = messaging_server_id(ctx->msg), .name = name
+	};
+	NTSTATUS status;
+
+	status = dbwrap_do_locked(ctx->db, string_term_tdb_data(name),
+				  g_lock_unlock_fn, &state);
 	if (!NT_STATUS_IS_OK(status)) {
-		DBG_WARNING("Could not store record: %s\n", nt_errstr(status));
-		goto done;
+		DBG_WARNING("dbwrap_do_locked failed: %s\n",
+			    nt_errstr(status));
+		return status;
+	}
+	if (!NT_STATUS_IS_OK(state.status)) {
+		DBG_WARNING("g_lock_unlock_fn failed: %s\n",
+			    nt_errstr(state.status));
+		return state.status;
 	}
 
-	status = NT_STATUS_OK;
-done:
-	TALLOC_FREE(rec);
-	TALLOC_FREE(locks);
-	return status;
+	return NT_STATUS_OK;
 }
 
 NTSTATUS g_lock_write_data(struct g_lock_ctx *ctx, const char *name,
-- 
2.1.4


From 12e24655135e4cb1fe3603db73fa3fa0e68437b6 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 5 Jul 2017 12:16:02 +0200
Subject: [PATCH 14/41] g_lock: Initialize variables

gcc -O3 complains, but I think this is a false positive

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/g_lock.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
index 7a924b9..a79a9cc 100644
--- a/source3/lib/g_lock.c
+++ b/source3/lib/g_lock.c
@@ -765,8 +765,8 @@ NTSTATUS g_lock_dump(struct g_lock_ctx *ctx, const char *name,
 	TDB_DATA data;
 	size_t num_locks;
 	struct g_lock_rec *locks = NULL;
-	uint8_t *userdata;
-	size_t userdatalen;
+	uint8_t *userdata = NULL;
+	size_t userdatalen = 0;
 	NTSTATUS status;
 
 	status = dbwrap_fetch_bystring(ctx->db, talloc_tos(), name, &data);
-- 
2.1.4


From df73403c69afc391a6ae40f37a82b3e6abf9bc02 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 28 Jun 2017 19:39:33 +0200
Subject: [PATCH 15/41] g_lock: Avoid talloc in g_lock_trylock

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/g_lock.c | 67 ++++++++++++++++++++++------------------------------
 1 file changed, 28 insertions(+), 39 deletions(-)

diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
index a79a9cc..7dcede4 100644
--- a/source3/lib/g_lock.c
+++ b/source3/lib/g_lock.c
@@ -341,41 +341,46 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
 			       enum g_lock_type type,
 			       struct server_id *blocker)
 {
-	TDB_DATA data, userdata;
-	size_t i, num_locks;
-	struct g_lock_rec *locks, *tmp;
+	TDB_DATA data;
+	size_t i;
+	struct g_lock lck;
 	NTSTATUS status;
 	bool modified = false;
+	bool ok;
 
 	data = dbwrap_record_get_value(rec);
 
-	status = g_lock_get_talloc(talloc_tos(), data, &locks, &num_locks,
-				   &userdata.dptr, &userdata.dsize);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
+	ok = g_lock_parse(data.dptr, data.dsize, &lck);
+	if (!ok) {
+		return NT_STATUS_INTERNAL_DB_CORRUPTION;
 	}
 
-	if ((type == G_LOCK_READ) && (num_locks > 0)) {
+	if ((type == G_LOCK_READ) && (lck.num_recs > 0)) {
+		struct g_lock_rec check_rec;
+
 		/*
 		 * Read locks can stay around forever if the process
 		 * dies. Do a heuristic check for process existence:
 		 * Check one random process for existence. Hopefully
 		 * this will keep runaway read locks under control.
 		 */
-		i = generate_random() % num_locks;
+		i = generate_random() % lck.num_recs;
 
-		if (!serverid_exists(&locks[i].pid)) {
-			locks[i] = locks[num_locks-1];
-			num_locks -=1;
+		g_lock_get_rec(&lck, i, &check_rec);
+
+		if (!serverid_exists(&check_rec.pid)) {
+			g_lock_rec_del(&lck, i);
 			modified = true;
 		}
 	}
 
-	for (i=0; i<num_locks; i++) {
-		struct g_lock_rec *lock = &locks[i];
+	for (i=0; i<lck.num_recs; i++) {
+		struct g_lock_rec lock;
 
-		if (serverid_equal(&self, &lock->pid)) {
-			if (lock->lock_type == type) {
+		g_lock_get_rec(&lck, i, &lock);
+
+		if (serverid_equal(&self, &lock.pid)) {
+			if (lock.lock_type == type) {
 				status = NT_STATUS_WAS_LOCKED;
 				goto done;
 			}
@@ -383,13 +388,12 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
 			 * Remove "our" lock entry. Re-add it later
 			 * with our new lock type.
 			 */
-			locks[i] = locks[num_locks-1];
-			num_locks -= 1;
+			g_lock_rec_del(&lck, i);
 			continue;
 		}
 
-		if (g_lock_conflicts(type, lock->lock_type)) {
-			struct server_id pid = lock->pid;
+		if (g_lock_conflicts(type, lock.lock_type)) {
+			struct server_id pid = lock.pid;
 
 			/*
 			 * As the serverid_exists might recurse into
@@ -400,47 +404,32 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
 
 			if (serverid_exists(&pid)) {
 				status = NT_STATUS_LOCK_NOT_GRANTED;
-				*blocker = lock->pid;
+				*blocker = lock.pid;
 				goto done;
 			}
 
 			/*
 			 * Delete stale conflicting entry
 			 */
-			locks[i] = locks[num_locks-1];
-			num_locks -= 1;
+			g_lock_rec_del(&lck, i);
 			modified = true;
 		}
 	}
 
-	tmp = talloc_realloc(talloc_tos(), locks, struct g_lock_rec,
-			     num_locks+1);
-	if (tmp == NULL) {
-		status = NT_STATUS_NO_MEMORY;
-		goto done;
-	}
-	locks = tmp;
-
-	locks[num_locks] = (struct g_lock_rec) {
-		.pid = self, .lock_type = type
-	};
-	num_locks +=1 ;
-
 	modified = true;
 
 	status = NT_STATUS_OK;
 done:
 	if (modified) {
+		struct g_lock_rec mylock = { .pid = self, .lock_type = type };
 		NTSTATUS store_status;
-		store_status = g_lock_record_store(
-			rec, locks, num_locks, userdata.dptr, userdata.dsize);
+		store_status = g_lock_store(rec, &lck, &mylock);
 		if (!NT_STATUS_IS_OK(store_status)) {
 			DBG_WARNING("g_lock_record_store failed: %s\n",
 				    nt_errstr(store_status));
 			status = store_status;
 		}
 	}
-	TALLOC_FREE(locks);
 	return status;
 }
 
-- 
2.1.4


From 12bfbc5d50b7b81e039eaa9a680ab708e0ac6f6b Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 28 Jun 2017 20:01:34 +0200
Subject: [PATCH 16/41] g_lock: Use dbwrap_do_locked for g_lock_lock

Don't talloc the record

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/g_lock.c | 64 +++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 43 insertions(+), 21 deletions(-)

diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
index 7dcede4..a6d341f 100644
--- a/source3/lib/g_lock.c
+++ b/source3/lib/g_lock.c
@@ -442,16 +442,38 @@ struct g_lock_lock_state {
 
 static void g_lock_lock_retry(struct tevent_req *subreq);
 
+struct g_lock_lock_fn_state {
+	struct g_lock_lock_state *state;
+	struct server_id self;
+
+	struct tevent_req *watch_req;
+	NTSTATUS status;
+};
+
+static void g_lock_lock_fn(struct db_record *rec, void *private_data)
+{
+	struct g_lock_lock_fn_state *state = private_data;
+	struct server_id blocker;
+
+	state->status = g_lock_trylock(rec, state->self, state->state->type,
+				       &blocker);
+	if (!NT_STATUS_EQUAL(state->status, NT_STATUS_LOCK_NOT_GRANTED)) {
+		return;
+	}
+
+	state->watch_req = dbwrap_watched_watch_send(
+		state->state, state->state->ev, rec, blocker);
+}
+
 struct tevent_req *g_lock_lock_send(TALLOC_CTX *mem_ctx,
 				    struct tevent_context *ev,
 				    struct g_lock_ctx *ctx,
 				    const char *name,
 				    enum g_lock_type type)
 {
-	struct tevent_req *req, *subreq;
+	struct tevent_req *req;
 	struct g_lock_lock_state *state;
-	struct db_record *rec;
-	struct server_id self, blocker;
+	struct g_lock_lock_fn_state fn_state;
 	NTSTATUS status;
 
 	req = tevent_req_create(mem_ctx, &state, struct g_lock_lock_state);
@@ -463,39 +485,39 @@ struct tevent_req *g_lock_lock_send(TALLOC_CTX *mem_ctx,
 	state->name = name;
 	state->type = type;
 
-	rec = dbwrap_fetch_locked(ctx->db, talloc_tos(),
-				  string_term_tdb_data(state->name));
-	if (rec == NULL) {
-		DEBUG(10, ("fetch_locked(\"%s\") failed\n", name));
-		tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
+	fn_state = (struct g_lock_lock_fn_state) {
+		.state = state, .self = messaging_server_id(ctx->msg)
+	};
+
+	status = dbwrap_do_locked(ctx->db, string_term_tdb_data(name),
+				  g_lock_lock_fn, &fn_state);
+	if (tevent_req_nterror(req, status)) {
+		DBG_DEBUG("dbwrap_do_locked failed: %s\n",
+			  nt_errstr(status));
 		return tevent_req_post(req, ev);
 	}
 
-	self = messaging_server_id(state->ctx->msg);
-
-	status = g_lock_trylock(rec, self, state->type, &blocker);
-	if (NT_STATUS_IS_OK(status)) {
-		TALLOC_FREE(rec);
+	if (NT_STATUS_IS_OK(fn_state.status)) {
 		tevent_req_done(req);
 		return tevent_req_post(req, ev);
 	}
-	if (!NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) {
-		TALLOC_FREE(rec);
-		tevent_req_nterror(req, status);
+	if (!NT_STATUS_EQUAL(fn_state.status, NT_STATUS_LOCK_NOT_GRANTED)) {
+		tevent_req_nterror(req, fn_state.status);
 		return tevent_req_post(req, ev);
 	}
-	subreq = dbwrap_watched_watch_send(state, state->ev, rec, blocker);
-	TALLOC_FREE(rec);
-	if (tevent_req_nomem(subreq, req)) {
+
+	if (tevent_req_nomem(fn_state.watch_req, req)) {
 		return tevent_req_post(req, ev);
 	}
+
+
 	if (!tevent_req_set_endtime(
-		    subreq, state->ev,
+		    fn_state.watch_req, state->ev,
 		    timeval_current_ofs(5 + sys_random() % 5, 0))) {
 		tevent_req_oom(req);
 		return tevent_req_post(req, ev);
 	}
-	tevent_req_set_callback(subreq, g_lock_lock_retry, req);
+	tevent_req_set_callback(fn_state.watch_req, g_lock_lock_retry, req);
 	return req;
 }
 
-- 
2.1.4


From f0434a2f7a87ff721585d7e49f394510306e6cd5 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 30 Jun 2017 22:20:41 +0200
Subject: [PATCH 17/41] g_lock: Use dbwrap_do_locked in g_lock_lock_retry

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/g_lock.c | 53 +++++++++++++++++++++++++---------------------------
 1 file changed, 25 insertions(+), 28 deletions(-)

diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
index a6d341f..3c4bcbf 100644
--- a/source3/lib/g_lock.c
+++ b/source3/lib/g_lock.c
@@ -510,7 +510,6 @@ struct tevent_req *g_lock_lock_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
-
 	if (!tevent_req_set_endtime(
 		    fn_state.watch_req, state->ev,
 		    timeval_current_ofs(5 + sys_random() % 5, 0))) {
@@ -527,54 +526,52 @@ static void g_lock_lock_retry(struct tevent_req *subreq)
 		subreq, struct tevent_req);
 	struct g_lock_lock_state *state = tevent_req_data(
 		req, struct g_lock_lock_state);
-	struct server_id self = messaging_server_id(state->ctx->msg);
-	struct server_id blocker;
-	struct db_record *rec;
+	struct g_lock_lock_fn_state fn_state;
 	NTSTATUS status;
 
-	status = dbwrap_watched_watch_recv(subreq, talloc_tos(), &rec, NULL,
-					   NULL);
+	status = dbwrap_watched_watch_recv(subreq, NULL, NULL, NULL, NULL);
+	DBG_DEBUG("watch_recv returned %s\n", nt_errstr(status));
 	TALLOC_FREE(subreq);
 
-	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
-		rec = dbwrap_fetch_locked(
-			state->ctx->db, talloc_tos(),
-			string_term_tdb_data(state->name));
-		if (rec == NULL) {
-			status = map_nt_error_from_unix(errno);
-		} else {
-			status = NT_STATUS_OK;
-		}
+	if (!NT_STATUS_IS_OK(status) &&
+	    !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+		tevent_req_nterror(req, status);
+		return;
 	}
 
+	fn_state = (struct g_lock_lock_fn_state) {
+		.state = state, .self = messaging_server_id(state->ctx->msg)
+	};
+
+	status = dbwrap_do_locked(state->ctx->db,
+				  string_term_tdb_data(state->name),
+				  g_lock_lock_fn, &fn_state);
 	if (tevent_req_nterror(req, status)) {
+		DBG_DEBUG("dbwrap_do_locked failed: %s\n",
+			  nt_errstr(status));
 		return;
 	}
-	status = g_lock_trylock(rec, self, state->type, &blocker);
-	if (NT_STATUS_IS_OK(status)) {
-		TALLOC_FREE(rec);
+
+	if (NT_STATUS_IS_OK(fn_state.status)) {
 		tevent_req_done(req);
 		return;
 	}
-	if (!NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) {
-		TALLOC_FREE(rec);
-		tevent_req_nterror(req, status);
+	if (!NT_STATUS_EQUAL(fn_state.status, NT_STATUS_LOCK_NOT_GRANTED)) {
+		tevent_req_nterror(req, fn_state.status);
 		return;
 	}
-	subreq = dbwrap_watched_watch_send(state, state->ev, rec, blocker);
-	TALLOC_FREE(rec);
-	if (tevent_req_nomem(subreq, req)) {
+
+	if (tevent_req_nomem(fn_state.watch_req, req)) {
 		return;
 	}
+
 	if (!tevent_req_set_endtime(
-		    subreq, state->ev,
+		    fn_state.watch_req, state->ev,
 		    timeval_current_ofs(5 + sys_random() % 5, 0))) {
 		tevent_req_oom(req);
 		return;
 	}
-	tevent_req_set_callback(subreq, g_lock_lock_retry, req);
-	return;
-
+	tevent_req_set_callback(fn_state.watch_req, g_lock_lock_retry, req);
 }
 
 NTSTATUS g_lock_lock_recv(struct tevent_req *req)
-- 
2.1.4


From 1beeb25069057c9f4d580eadaf0d2b85eb823c11 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 3 Jul 2017 08:09:18 +0200
Subject: [PATCH 18/41] torture3: Add verification for g_lock_retry

During development I had a bug that would have been found early
by this

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/torture/test_g_lock.c | 52 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/source3/torture/test_g_lock.c b/source3/torture/test_g_lock.c
index 61ec69d..253d20c 100644
--- a/source3/torture/test_g_lock.c
+++ b/source3/torture/test_g_lock.c
@@ -397,6 +397,41 @@ static void lock4_waited(struct tevent_req *subreq)
 	printf("child %d exited with %d\n", (int)child, status);
 }
 
+struct lock4_check_state {
+	struct server_id me;
+	bool ok;
+};
+
+static void lock4_check(const struct g_lock_rec *locks,
+			size_t num_locks,
+			const uint8_t *data,
+			size_t datalen,
+			void *private_data)
+{
+	struct lock4_check_state *state = private_data;
+
+	if (num_locks != 1) {
+		fprintf(stderr, "num_locks=%zu\n", num_locks);
+		return;
+	}
+
+	if (!serverid_equal(&state->me, &locks[0].pid)) {
+		struct server_id_buf buf1, buf2;
+		fprintf(stderr, "me=%s, locker=%s\n",
+			server_id_str_buf(state->me, &buf1),
+			server_id_str_buf(locks[0].pid, &buf2));
+		return;
+	}
+
+	if (locks[0].lock_type != G_LOCK_WRITE) {
+		fprintf(stderr, "wrong lock type: %d\n",
+			(int)locks[0].lock_type);
+		return;
+	}
+
+	state->ok = true;
+}
+
 /*
  * Test a lock conflict
  */
@@ -493,6 +528,23 @@ bool run_g_lock4(int dummy)
 		}
 	}
 
+	{
+		struct lock4_check_state state = {
+			.me = messaging_server_id(msg)
+		};
+
+		status = g_lock_dump(ctx, lockname, lock4_check, &state);
+		if (!NT_STATUS_IS_OK(status)) {
+			fprintf(stderr, "g_lock_dump failed: %s\n",
+				nt_errstr(status));
+			goto fail;
+		}
+		if (!state.ok) {
+			fprintf(stderr, "lock4_check failed\n");
+			goto fail;
+		}
+	}
+
 	ret = true;
 fail:
 	TALLOC_FREE(ctx);
-- 
2.1.4


From f48527c3a8d4328f4997e596fe40b34eb00bc8e3 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 30 Jun 2017 19:42:50 +0200
Subject: [PATCH 19/41] g_lock: Use dbwrap_do_locked in g_lock_write_data

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/g_lock.c | 88 ++++++++++++++++++++++++++++++++--------------------
 1 file changed, 54 insertions(+), 34 deletions(-)

diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
index 3c4bcbf..25d9629 100644
--- a/source3/lib/g_lock.c
+++ b/source3/lib/g_lock.c
@@ -677,53 +677,73 @@ NTSTATUS g_lock_unlock(struct g_lock_ctx *ctx, const char *name)
 	return NT_STATUS_OK;
 }
 
-NTSTATUS g_lock_write_data(struct g_lock_ctx *ctx, const char *name,
-			   const uint8_t *buf, size_t buflen)
-{
-	struct server_id self = messaging_server_id(ctx->msg);
-	struct db_record *rec = NULL;
-	struct g_lock_rec *locks = NULL;
-	size_t i, num_locks;
+struct g_lock_write_data_state {
+	const char *name;
+	struct server_id self;
+	const uint8_t *data;
+	size_t datalen;
 	NTSTATUS status;
-	TDB_DATA value;
+};
 
-	rec = dbwrap_fetch_locked(ctx->db, talloc_tos(),
-				  string_term_tdb_data(name));
-	if (rec == NULL) {
-		DEBUG(10, ("fetch_locked(\"%s\") failed\n", name));
-		status = NT_STATUS_INTERNAL_ERROR;
-		goto done;
-	}
+static void g_lock_write_data_fn(struct db_record *rec,
+				 void *private_data)
+{
+	struct g_lock_write_data_state *state = private_data;
+	TDB_DATA value;
+	struct g_lock lck;
+	size_t i;
+	bool ok;
 
 	value = dbwrap_record_get_value(rec);
 
-	status = g_lock_get_talloc(talloc_tos(), value, &locks, &num_locks,
-				   NULL, NULL);
-	if (!NT_STATUS_IS_OK(status)) {
-		DBG_DEBUG("g_lock_get for %s failed: %s\n", name,
-			  nt_errstr(status));
-		status = NT_STATUS_FILE_INVALID;
-		goto done;
+	ok = g_lock_parse(value.dptr, value.dsize, &lck);
+	if (!ok) {
+		DBG_DEBUG("g_lock_parse for %s failed\n", state->name);
+		state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+		return;
 	}
-
-	for (i=0; i<num_locks; i++) {
-		if (server_id_equal(&self, &locks[i].pid) &&
-		    (locks[i].lock_type == G_LOCK_WRITE)) {
+	for (i=0; i<lck.num_recs; i++) {
+		struct g_lock_rec lockrec;
+		g_lock_get_rec(&lck, i, &lockrec);
+		if ((lockrec.lock_type == G_LOCK_WRITE) &&
+		    serverid_equal(&state->self, &lockrec.pid)) {
 			break;
 		}
 	}
-	if (i == num_locks) {
+	if (i == lck.num_recs) {
 		DBG_DEBUG("Not locked by us\n");
-		status = NT_STATUS_NOT_LOCKED;
-		goto done;
+		state->status = NT_STATUS_NOT_LOCKED;
+		return;
 	}
 
-	status = g_lock_record_store(rec, locks, num_locks, buf, buflen);
+	lck.data = discard_const_p(uint8_t, state->data);
+	lck.datalen = state->datalen;
+	state->status = g_lock_store(rec, &lck, NULL);
+}
 
-done:
-	TALLOC_FREE(locks);
-	TALLOC_FREE(rec);
-	return status;
+NTSTATUS g_lock_write_data(struct g_lock_ctx *ctx, const char *name,
+			   const uint8_t *buf, size_t buflen)
+{
+	struct g_lock_write_data_state state = {
+		.name = name, .self = messaging_server_id(ctx->msg),
+		.data = buf, .datalen = buflen
+	};
+	NTSTATUS status;
+
+	status = dbwrap_do_locked(ctx->db, string_term_tdb_data(name),
+				  g_lock_write_data_fn, &state);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_WARNING("dbwrap_do_locked failed: %s\n",
+			    nt_errstr(status));
+		return status;
+	}
+	if (!NT_STATUS_IS_OK(state.status)) {
+		DBG_WARNING("g_lock_write_data_fn failed: %s\n",
+			    nt_errstr(state.status));
+		return state.status;
+	}
+
+	return NT_STATUS_OK;
 }
 
 struct g_lock_locks_state {
-- 
2.1.4


From c018d3cab53282f8f5b9b50eb3875f327c479711 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 30 Jun 2017 22:09:12 +0200
Subject: [PATCH 20/41] g_lock: Use parse_record in g_lock_dump

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/g_lock.c | 84 +++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 60 insertions(+), 24 deletions(-)

diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
index 25d9629..9b971ae 100644
--- a/source3/lib/g_lock.c
+++ b/source3/lib/g_lock.c
@@ -782,6 +782,54 @@ int g_lock_locks(struct g_lock_ctx *ctx,
 	return count;
 }
 
+struct g_lock_dump_state {
+	TALLOC_CTX *mem_ctx;
+	const char *name;
+	void (*fn)(const struct g_lock_rec *locks,
+		   size_t num_locks,
+		   const uint8_t *data,
+		   size_t datalen,
+		   void *private_data);
+	void *private_data;
+	NTSTATUS status;
+};
+
+static void g_lock_dump_fn(TDB_DATA key, TDB_DATA data,
+			   void *private_data)
+{
+	struct g_lock_dump_state *state = private_data;
+	struct g_lock_rec *recs;
+	struct g_lock lck;
+	size_t i;
+	bool ok;
+
+	ok = g_lock_parse(data.dptr, data.dsize, &lck);
+	if (!ok) {
+		DBG_DEBUG("g_lock_parse failed for %s\n",
+			  state->name);
+		state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+		return;
+	}
+
+	recs = talloc_array(state->mem_ctx, struct g_lock_rec, lck.num_recs);
+	if (recs == NULL) {
+		DBG_DEBUG("talloc failed\n");
+		state->status = NT_STATUS_NO_MEMORY;
+		return;
+	}
+
+	for (i=0; i<lck.num_recs; i++) {
+		g_lock_get_rec(&lck, i, &recs[i]);
+	}
+
+	state->fn(recs, lck.num_recs, lck.data, lck.datalen,
+		  state->private_data);
+
+	TALLOC_FREE(recs);
+
+	state->status = NT_STATUS_OK;
+}
+
 NTSTATUS g_lock_dump(struct g_lock_ctx *ctx, const char *name,
 		     void (*fn)(const struct g_lock_rec *locks,
 				size_t num_locks,
@@ -790,36 +838,24 @@ NTSTATUS g_lock_dump(struct g_lock_ctx *ctx, const char *name,
 				void *private_data),
 		     void *private_data)
 {
-	TDB_DATA data;
-	size_t num_locks;
-	struct g_lock_rec *locks = NULL;
-	uint8_t *userdata = NULL;
-	size_t userdatalen = 0;
+	struct g_lock_dump_state state = {
+		.mem_ctx = ctx, .name = name,
+		.fn = fn, .private_data = private_data
+	};
 	NTSTATUS status;
 
-	status = dbwrap_fetch_bystring(ctx->db, talloc_tos(), name, &data);
+	status = dbwrap_parse_record(ctx->db, string_term_tdb_data(name),
+				     g_lock_dump_fn, &state);
 	if (!NT_STATUS_IS_OK(status)) {
+		DBG_DEBUG("dbwrap_parse_record returned %s\n",
+			  nt_errstr(status));
 		return status;
 	}
-
-	if ((data.dsize == 0) || (data.dptr == NULL)) {
-		return NT_STATUS_OK;
-	}
-
-	status = g_lock_get_talloc(talloc_tos(), data, &locks, &num_locks,
-				   &userdata, &userdatalen);
-
-	if (!NT_STATUS_IS_OK(status)) {
-		DBG_DEBUG("g_lock_get for %s failed: %s\n", name,
-			  nt_errstr(status));
-		TALLOC_FREE(data.dptr);
-		return NT_STATUS_INTERNAL_ERROR;
+	if (!NT_STATUS_IS_OK(state.status)) {
+		DBG_DEBUG("g_lock_dump_fn returned %s\n",
+			  nt_errstr(state.status));
+		return state.status;
 	}
-
-	fn(locks, num_locks, userdata, userdatalen, private_data);
-
-	TALLOC_FREE(locks);
-	TALLOC_FREE(data.dptr);
 	return NT_STATUS_OK;
 }
 
-- 
2.1.4


From cd82f112847a8149342ee8a23cf4a8e765bf3765 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 30 Jun 2017 22:14:58 +0200
Subject: [PATCH 21/41] g_lock: Remove unused code

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/g_lock.c | 144 ---------------------------------------------------
 1 file changed, 144 deletions(-)

diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
index 9b971ae..8709052 100644
--- a/source3/lib/g_lock.c
+++ b/source3/lib/g_lock.c
@@ -141,121 +141,6 @@ static NTSTATUS g_lock_store(struct db_record *rec, struct g_lock *lck,
 	return dbwrap_record_storev(rec, dbufs, ARRAY_SIZE(dbufs), 0);
 }
 
-static ssize_t g_lock_put(uint8_t *buf, size_t buflen,
-			  const struct g_lock_rec *locks,
-			  size_t num_locks,
-			  const uint8_t *data, size_t datalen)
-{
-	size_t i, len, ofs;
-
-	if (num_locks > UINT32_MAX/G_LOCK_REC_LENGTH) {
-		return -1;
-	}
-
-	len = num_locks * G_LOCK_REC_LENGTH;
-
-	len += sizeof(uint32_t);
-	if (len < sizeof(uint32_t)) {
-		return -1;
-	}
-
-	len += datalen;
-	if (len < datalen) {
-		return -1;
-	}
-
-	if (len > buflen) {
-		return len;
-	}
-
-	ofs = 0;
-	SIVAL(buf, ofs, num_locks);
-	ofs += sizeof(uint32_t);
-
-	for (i=0; i<num_locks; i++) {
-		g_lock_rec_put(buf+ofs, locks[i]);
-		ofs += G_LOCK_REC_LENGTH;
-	}
-
-	if ((data != NULL) && (datalen != 0)) {
-		memcpy(buf+ofs, data, datalen);
-	}
-
-	return len;
-}
-
-static ssize_t g_lock_get(TDB_DATA recval,
-			  struct g_lock_rec *locks, size_t num_locks,
-			  uint8_t **data, size_t *datalen)
-{
-	size_t found_locks;
-
-	if (recval.dsize < sizeof(uint32_t)) {
-		/* Fresh or invalid record */
-		found_locks = 0;
-		goto done;
-	}
-
-	found_locks = IVAL(recval.dptr, 0);
-	recval.dptr += sizeof(uint32_t);
-	recval.dsize -= sizeof(uint32_t);
-
-	if (found_locks > recval.dsize/G_LOCK_REC_LENGTH) {
-		/* Invalid record */
-		return 0;
-	}
-
-	if (found_locks <= num_locks) {
-		size_t i;
-
-		for (i=0; i<found_locks; i++) {
-			g_lock_rec_get(&locks[i], recval.dptr);
-			recval.dptr += G_LOCK_REC_LENGTH;
-			recval.dsize -= G_LOCK_REC_LENGTH;
-		}
-	} else {
-		/*
-		 * Not enough space passed in by the caller, don't
-		 * parse the locks.
-		 */
-		recval.dptr += found_locks * G_LOCK_REC_LENGTH;
-		recval.dsize -= found_locks * G_LOCK_REC_LENGTH;
-	}
-
-done:
-	if (data != NULL) {
-		*data = recval.dptr;
-	}
-	if (datalen != NULL) {
-		*datalen = recval.dsize;
-	}
-	return found_locks;
-}
-
-static NTSTATUS g_lock_get_talloc(TALLOC_CTX *mem_ctx, TDB_DATA recval,
-				  struct g_lock_rec **plocks,
-				  size_t *pnum_locks,
-				  uint8_t **data, size_t *datalen)
-{
-	struct g_lock_rec *locks;
-	ssize_t num_locks;
-
-	num_locks = g_lock_get(recval, NULL, 0, NULL, NULL);
-	if (num_locks == -1) {
-		return NT_STATUS_INTERNAL_DB_CORRUPTION;
-	}
-	locks = talloc_array(mem_ctx, struct g_lock_rec, num_locks);
-	if (locks == NULL) {
-		return NT_STATUS_NO_MEMORY;
-	}
-	g_lock_get(recval, locks, num_locks, data, datalen);
-
-	*plocks = locks;
-	*pnum_locks = num_locks;
-
-	return NT_STATUS_OK;
-}
-
 struct g_lock_ctx *g_lock_ctx_init(TALLOC_CTX *mem_ctx,
 				   struct messaging_context *msg)
 {
@@ -308,35 +193,6 @@ static bool g_lock_conflicts(enum g_lock_type l1, enum g_lock_type l2)
 	return true;
 }
 
-static NTSTATUS g_lock_record_store(struct db_record *rec,
-				    const struct g_lock_rec *locks,
-				    size_t num_locks,
-				    const uint8_t *data, size_t datalen)
-{
-	ssize_t len;
-	uint8_t *buf;
-	NTSTATUS status;
-
-	len = g_lock_put(NULL, 0, locks, num_locks, data, datalen);
-	if (len == -1) {
-		return NT_STATUS_BUFFER_TOO_SMALL;
-	}
-
-	buf = talloc_array(rec, uint8_t, len);
-	if (buf == NULL) {
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	g_lock_put(buf, len, locks, num_locks, data, datalen);
-
-	status = dbwrap_record_store(
-		rec, (TDB_DATA) { .dptr = buf, .dsize = len }, 0);
-
-	TALLOC_FREE(buf);
-
-	return status;
-}
-
 static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
 			       enum g_lock_type type,
 			       struct server_id *blocker)
-- 
2.1.4


From 5a7ed6737f91afaf5b353ed731457e9bf7982eb1 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 17 Jun 2017 15:43:14 +0200
Subject: [PATCH 22/41] messaging: Factor out messaging_dispatch_waiters

No real code change: This makes dispatching to non-classic receives available
for other callers.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/messages.c | 56 +++++++++++++++++++++++++++++---------------------
 1 file changed, 33 insertions(+), 23 deletions(-)

diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index b94a696..02aa16c 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -87,6 +87,9 @@ struct messaging_context {
 
 static struct messaging_rec *messaging_rec_dup(TALLOC_CTX *mem_ctx,
 					       struct messaging_rec *rec);
+static bool messaging_dispatch_waiters(struct messaging_context *msg_ctx,
+				       struct tevent_context *ev,
+				       struct messaging_rec *rec);
 static void messaging_dispatch_rec(struct messaging_context *msg_ctx,
 				   struct tevent_context *ev,
 				   struct messaging_rec *rec);
@@ -966,32 +969,14 @@ static bool messaging_dispatch_classic(struct messaging_context *msg_ctx,
 	return false;
 }
 
-/*
-  Dispatch one messaging_rec
-*/
-static void messaging_dispatch_rec(struct messaging_context *msg_ctx,
-				   struct tevent_context *ev,
-				   struct messaging_rec *rec)
+static bool messaging_dispatch_waiters(struct messaging_context *msg_ctx,
+				       struct tevent_context *ev,
+				       struct messaging_rec *rec)
 {
 	size_t i;
-	bool consumed;
-
-	if (ev == msg_ctx->event_ctx) {
-		consumed = messaging_dispatch_classic(msg_ctx, rec);
-		if (consumed) {
-			return;
-		}
-	}
 
 	if (!messaging_append_new_waiters(msg_ctx)) {
-		size_t j;
-		for (j=0; j < rec->num_fds; j++) {
-			int fd = rec->fds[j];
-			close(fd);
-		}
-		rec->num_fds = 0;
-		rec->fds = NULL;
-		return;
+		return false;
 	}
 
 	i = 0;
@@ -1022,12 +1007,37 @@ static void messaging_dispatch_rec(struct messaging_context *msg_ctx,
 		if ((ev == state->ev) &&
 		    state->filter(rec, state->private_data)) {
 			messaging_filtered_read_done(req, rec);
-			return;
+			return true;
 		}
 
 		i += 1;
 	}
 
+	return false;
+}
+
+/*
+  Dispatch one messaging_rec
+*/
+static void messaging_dispatch_rec(struct messaging_context *msg_ctx,
+				   struct tevent_context *ev,
+				   struct messaging_rec *rec)
+{
+	bool consumed;
+	size_t i;
+
+	if (ev == msg_ctx->event_ctx) {
+		consumed = messaging_dispatch_classic(msg_ctx, rec);
+		if (consumed) {
+			return;
+		}
+	}
+
+	consumed = messaging_dispatch_waiters(msg_ctx, ev, rec);
+	if (consumed) {
+		return;
+	}
+
 	if (ev != msg_ctx->event_ctx) {
 		struct iovec iov;
 		int fds[rec->num_fds];
-- 
2.1.4


From 51f1f74184fdd0b6e0d6aa636ba57f9e59c0a697 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 17 Jun 2017 08:48:35 +0200
Subject: [PATCH 23/41] messaging: Add DLIST pointers to messaging_rec

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 librpc/idl/messaging.idl | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/librpc/idl/messaging.idl b/librpc/idl/messaging.idl
index b962ab1..37f8fcc 100644
--- a/librpc/idl/messaging.idl
+++ b/librpc/idl/messaging.idl
@@ -159,6 +159,8 @@ interface messaging
 	/* messaging struct sent across the sockets and stored in the tdb */
 
 	typedef [public] struct {
+		[skip] messaging_rec *prev;
+		[skip] messaging_rec *next;
 		uint32 msg_version;
 		messaging_type msg_type;
 		server_id dest;
-- 
2.1.4


From 42dce196fc5d4b25c1aa3361d16aa5abbc8c058a Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 22 Jun 2017 08:34:34 +0200
Subject: [PATCH 24/41] messaging: Keep an array of event contexts registered

This is done with an explicit reference-counting and without talloc
destructors. The code is isolated enough for now that explicit refcount
management seems simpler. This might change in the future, but for
now keep it simple.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/messages.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)

diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index 02aa16c..61005ab 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -68,11 +68,18 @@ struct messaging_callback {
 	void *private_data;
 };
 
+struct messaging_registered_ev {
+	struct tevent_context *ev;
+	size_t refcount;
+};
+
 struct messaging_context {
 	struct server_id id;
 	struct tevent_context *event_ctx;
 	struct messaging_callback *callbacks;
 
+	struct messaging_registered_ev *event_contexts;
+
 	struct tevent_req **new_waiters;
 	size_t num_new_waiters;
 
@@ -160,6 +167,76 @@ struct messaging_rec *messaging_rec_create(
 	return result;
 }
 
+static bool messaging_register_event_context(struct messaging_context *ctx,
+					     struct tevent_context *ev)
+{
+	size_t i, num_event_contexts;
+	struct messaging_registered_ev *free_reg = NULL;
+	struct messaging_registered_ev *tmp;
+
+	num_event_contexts = talloc_array_length(ctx->event_contexts);
+
+	for (i=0; i<num_event_contexts; i++) {
+		struct messaging_registered_ev *reg = &ctx->event_contexts[i];
+
+		if (reg->ev == ev) {
+			reg->refcount += 1;
+			return true;
+		}
+		if (reg->refcount == 0) {
+			if (reg->ev != NULL) {
+				abort();
+			}
+			free_reg = reg;
+		}
+	}
+
+	if (free_reg == NULL) {
+		tmp = talloc_realloc(ctx, ctx->event_contexts,
+				     struct messaging_registered_ev,
+				     num_event_contexts+1);
+		if (tmp == NULL) {
+			return false;
+		}
+		ctx->event_contexts = tmp;
+
+		free_reg = &ctx->event_contexts[num_event_contexts];
+	}
+
+	*free_reg = (struct messaging_registered_ev) { .ev = ev, .refcount = 1 };
+
+	return true;
+}
+
+static bool messaging_deregister_event_context(struct messaging_context *ctx,
+					       struct tevent_context *ev)
+{
+	size_t i, num_event_contexts;
+
+	num_event_contexts = talloc_array_length(ctx->event_contexts);
+
+	for (i=0; i<num_event_contexts; i++) {
+		struct messaging_registered_ev *reg = &ctx->event_contexts[i];
+
+		if (reg->ev == ev) {
+			if (reg->refcount == 0) {
+				return false;
+			}
+			reg->refcount -= 1;
+
+			if (reg->refcount == 0) {
+				/*
+				 * Not strictly necessary, just
+				 * paranoia
+				 */
+				reg->ev = NULL;
+			}
+			return true;
+		}
+	}
+	return false;
+}
+
 static void messaging_recv_cb(struct tevent_context *ev,
 			      const uint8_t *msg, size_t msg_len,
 			      int *fds, size_t num_fds,
@@ -295,6 +372,12 @@ static NTSTATUS messaging_init_internal(TALLOC_CTX *mem_ctx,
 
 	ctx->event_ctx = ev;
 
+	ok = messaging_register_event_context(ctx, ev);
+	if (!ok) {
+		status = NT_STATUS_NO_MEMORY;
+		goto done;
+	}
+
 	sec_init();
 
 	ctx->msg_dgm_ref = messaging_dgm_ref(ctx,
@@ -716,6 +799,7 @@ struct tevent_req *messaging_filtered_read_send(
 	struct tevent_req *req;
 	struct messaging_filtered_read_state *state;
 	size_t new_waiters_len;
+	bool ok;
 
 	req = tevent_req_create(mem_ctx, &state,
 				struct messaging_filtered_read_state);
@@ -763,6 +847,12 @@ struct tevent_req *messaging_filtered_read_send(
 	msg_ctx->num_new_waiters += 1;
 	tevent_req_set_cleanup_fn(req, messaging_filtered_read_cleanup);
 
+	ok = messaging_register_event_context(msg_ctx, ev);
+	if (!ok) {
+		tevent_req_oom(req);
+		return tevent_req_post(req, ev);
+	}
+
 	return req;
 }
 
@@ -773,11 +863,17 @@ static void messaging_filtered_read_cleanup(struct tevent_req *req,
 		req, struct messaging_filtered_read_state);
 	struct messaging_context *msg_ctx = state->msg_ctx;
 	size_t i;
+	bool ok;
 
 	tevent_req_set_cleanup_fn(req, NULL);
 
 	TALLOC_FREE(state->fde);
 
+	ok = messaging_deregister_event_context(msg_ctx, state->ev);
+	if (!ok) {
+		abort();
+	}
+
 	/*
 	 * Just set the [new_]waiters entry to NULL, be careful not to mess
 	 * with the other "waiters" array contents. We are often called from
-- 
2.1.4


From b3a18d4cb8468b78a10320b9028c9bc8a6221b3a Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 22 Jun 2017 08:54:56 +0200
Subject: [PATCH 25/41] messaging: Broadcast messages to all event contexts

We must give all event contexts that might be interested the chance to pick up
the message. If we send a message to ourselves via messaging_send_iov_from,
nested event contexts need to get a chance to see the message. Before this
patch only the main event context in msg_ctx got it.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/messages.c | 165 +++++++++++++++++++++++++++++++++++++------------
 1 file changed, 127 insertions(+), 38 deletions(-)

diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index 61005ab..5c10013 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -70,6 +70,7 @@ struct messaging_callback {
 
 struct messaging_registered_ev {
 	struct tevent_context *ev;
+	struct tevent_immediate *im;
 	size_t refcount;
 };
 
@@ -78,6 +79,8 @@ struct messaging_context {
 	struct tevent_context *event_ctx;
 	struct messaging_callback *callbacks;
 
+	struct messaging_rec *posted_msgs;
+
 	struct messaging_registered_ev *event_contexts;
 
 	struct tevent_req **new_waiters;
@@ -94,6 +97,8 @@ struct messaging_context {
 
 static struct messaging_rec *messaging_rec_dup(TALLOC_CTX *mem_ctx,
 					       struct messaging_rec *rec);
+static bool messaging_dispatch_classic(struct messaging_context *msg_ctx,
+				       struct messaging_rec *rec);
 static bool messaging_dispatch_waiters(struct messaging_context *msg_ctx,
 				       struct tevent_context *ev,
 				       struct messaging_rec *rec);
@@ -230,6 +235,11 @@ static bool messaging_deregister_event_context(struct messaging_context *ctx,
 				 * paranoia
 				 */
 				reg->ev = NULL;
+
+				/*
+				 * Do not talloc_free(reg->im),
+				 * recycle immediates events.
+				 */
 			}
 			return true;
 		}
@@ -237,6 +247,105 @@ static bool messaging_deregister_event_context(struct messaging_context *ctx,
 	return false;
 }
 
+static void messaging_post_main_event_context(struct tevent_context *ev,
+					      struct tevent_immediate *im,
+					      void *private_data)
+{
+	struct messaging_context *ctx = talloc_get_type_abort(
+		private_data, struct messaging_context);
+
+	while (ctx->posted_msgs != NULL) {
+		struct messaging_rec *rec = ctx->posted_msgs;
+		bool consumed;
+
+		DLIST_REMOVE(ctx->posted_msgs, rec);
+
+		consumed = messaging_dispatch_classic(ctx, rec);
+		if (!consumed) {
+			consumed = messaging_dispatch_waiters(
+				ctx, ctx->event_ctx, rec);
+		}
+
+		if (!consumed) {
+			uint8_t i;
+
+			for (i=0; i<rec->num_fds; i++) {
+				close(rec->fds[i]);
+			}
+		}
+
+		TALLOC_FREE(rec);
+	}
+}
+
+static void messaging_post_sub_event_context(struct tevent_context *ev,
+					     struct tevent_immediate *im,
+					     void *private_data)
+{
+	struct messaging_context *ctx = talloc_get_type_abort(
+		private_data, struct messaging_context);
+	struct messaging_rec *rec, *next;
+
+	for (rec = ctx->posted_msgs; rec != NULL; rec = next) {
+		bool consumed;
+
+		next = rec->next;
+
+		consumed = messaging_dispatch_waiters(ctx, ev, rec);
+		if (consumed) {
+			DLIST_REMOVE(ctx->posted_msgs, rec);
+			TALLOC_FREE(rec);
+		}
+	}
+}
+
+static bool messaging_alert_event_contexts(struct messaging_context *ctx)
+{
+	size_t i, num_event_contexts;
+
+	num_event_contexts = talloc_array_length(ctx->event_contexts);
+
+	for (i=0; i<num_event_contexts; i++) {
+		struct messaging_registered_ev *reg = &ctx->event_contexts[i];
+
+		if (reg->refcount == 0) {
+			continue;
+		}
+
+		if (reg->im == NULL) {
+			reg->im = tevent_create_immediate(
+				ctx->event_contexts);
+		}
+		if (reg->im == NULL) {
+			DBG_WARNING("Could not create immediate\n");
+			continue;
+		}
+
+		/*
+		 * We depend on schedule_immediate to work
+		 * multiple times. Might be a bit inefficient,
+		 * but this needs to be proven in tests. The
+		 * alternatively would be to track whether the
+		 * immediate has already been scheduled. For
+		 * now, avoid that complexity here.
+		 */
+
+		if (reg->ev == ctx->event_ctx) {
+			tevent_schedule_immediate(
+				reg->im, reg->ev,
+				messaging_post_main_event_context,
+				ctx);
+		} else {
+			tevent_schedule_immediate(
+				reg->im, reg->ev,
+				messaging_post_sub_event_context,
+				ctx);
+		}
+
+	}
+	return true;
+}
+
 static void messaging_recv_cb(struct tevent_context *ev,
 			      const uint8_t *msg, size_t msg_len,
 			      int *fds, size_t num_fds,
@@ -308,6 +417,13 @@ static int messaging_context_destructor(struct messaging_context *ctx)
 		}
 	}
 
+	/*
+	 * The immediates from messaging_alert_event_contexts
+	 * reference "ctx". Don't let them outlive the
+	 * messaging_context we're destroying here.
+	 */
+	TALLOC_FREE(ctx->event_contexts);
+
 	return 0;
 }
 
@@ -612,57 +728,30 @@ NTSTATUS messaging_send_buf(struct messaging_context *msg_ctx,
 	return messaging_send(msg_ctx, server, msg_type, &blob);
 }
 
-struct messaging_post_state {
-	struct messaging_context *msg_ctx;
-	struct messaging_rec *rec;
-};
-
-static void messaging_post_handler(struct tevent_context *ev,
-				   struct tevent_immediate *ti,
-				   void *private_data);
-
 static int messaging_post_self(struct messaging_context *msg_ctx,
 			       struct server_id src, struct server_id dst,
 			       uint32_t msg_type,
 			       const struct iovec *iov, int iovlen,
 			       const int *fds, size_t num_fds)
 {
-	struct tevent_immediate *ti;
-	struct messaging_post_state *state;
+	struct messaging_rec *rec;
+	bool ok;
 
-	state = talloc(msg_ctx, struct messaging_post_state);
-	if (state == NULL) {
+	rec = messaging_rec_create(
+		msg_ctx, src, dst, msg_type, iov, iovlen, fds, num_fds);
+	if (rec == NULL) {
 		return ENOMEM;
 	}
-	state->msg_ctx = msg_ctx;
 
-	ti = tevent_create_immediate(state);
-	if (ti == NULL) {
-		goto fail;
-	}
-	state->rec = messaging_rec_create(
-		state, src, dst, msg_type, iov, iovlen, fds, num_fds);
-	if (state->rec == NULL) {
-		goto fail;
+	ok = messaging_alert_event_contexts(msg_ctx);
+	if (!ok) {
+		TALLOC_FREE(rec);
+		return ENOMEM;
 	}
 
-	tevent_schedule_immediate(ti, msg_ctx->event_ctx,
-				  messaging_post_handler, state);
-	return 0;
+	DLIST_ADD_END(msg_ctx->posted_msgs, rec);
 
-fail:
-	TALLOC_FREE(state);
-	return ENOMEM;
-}
-
-static void messaging_post_handler(struct tevent_context *ev,
-				   struct tevent_immediate *ti,
-				   void *private_data)
-{
-	struct messaging_post_state *state = talloc_get_type_abort(
-		private_data, struct messaging_post_state);
-	messaging_dispatch_rec(state->msg_ctx, ev, state->rec);
-	TALLOC_FREE(state);
+	return 0;
 }
 
 int messaging_send_iov_from(struct messaging_context *msg_ctx,
-- 
2.1.4


From 11d72abc872688fb08d4a11eaf36413e9ab69cb2 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 1 Jun 2017 17:45:47 +0200
Subject: [PATCH 26/41] ctdbd_conn: Pass "ev" through ctdb connection callbacks

This prepares the same logic we've implemented in messages_dgm for clustering
that is used in 6d3c064f1a5: We need to reply for messages from ctdb in nested
event contexts properly.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/include/ctdbd_conn.h   |  6 ++++--
 source3/lib/ctdb_dummy.c       |  6 ++++--
 source3/lib/ctdbd_conn.c       | 12 ++++++++----
 source3/lib/messages_ctdbd.c   |  1 +
 source3/smbd/notifyd/notifyd.c |  6 ++++--
 source3/smbd/process.c         |  3 ++-
 source3/smbd/server.c          |  1 +
 7 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h
index 06fbcc3..44ee8ab 100644
--- a/source3/include/ctdbd_conn.h
+++ b/source3/include/ctdbd_conn.h
@@ -73,7 +73,8 @@ int ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id,
 int ctdbd_register_ips(struct ctdbd_connection *conn,
 		       const struct sockaddr_storage *server,
 		       const struct sockaddr_storage *client,
-		       int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
+		       int (*cb)(struct tevent_context *ev,
+				 uint32_t src_vnn, uint32_t dst_vnn,
 				 uint64_t dst_srvid,
 				 const uint8_t *msg, size_t msglen,
 				 void *private_data),
@@ -89,7 +90,8 @@ int ctdb_unwatch(struct ctdbd_connection *conn);
 struct ctdb_req_message_old;
 
 int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
-			int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
+			int (*cb)(struct tevent_context *ev,
+				  uint32_t src_vnn, uint32_t dst_vnn,
 				  uint64_t dst_srvid,
 				  const uint8_t *msg, size_t msglen,
 				  void *private_data),
diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
index 2ed7b10..4e3e4bc 100644
--- a/source3/lib/ctdb_dummy.c
+++ b/source3/lib/ctdb_dummy.c
@@ -38,7 +38,8 @@ int ctdbd_messaging_send_iov(struct ctdbd_connection *conn,
 }
 
 int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
-			int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
+			int (*cb)(struct tevent_context *ev,
+				  uint32_t src_vnn, uint32_t dst_vnn,
 				  uint64_t dst_srvid,
 				  const uint8_t *msg, size_t msglen,
 				  void *private_data),
@@ -50,7 +51,8 @@ int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
 int ctdbd_register_ips(struct ctdbd_connection *conn,
 		       const struct sockaddr_storage *_server,
 		       const struct sockaddr_storage *_client,
-		       int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
+		       int (*cb)(struct tevent_context *ev,
+				 uint32_t src_vnn, uint32_t dst_vnn,
 				 uint64_t dst_srvid,
 				 const uint8_t *msg, size_t msglen,
 				 void *private_data),
diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c
index 3adb57d..88d45b4 100644
--- a/source3/lib/ctdbd_conn.c
+++ b/source3/lib/ctdbd_conn.c
@@ -41,7 +41,8 @@
 
 struct ctdbd_srvid_cb {
 	uint64_t srvid;
-	int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
+	int (*cb)(struct tevent_context *ev,
+		  uint32_t src_vnn, uint32_t dst_vnn,
 		  uint64_t dst_srvid,
 		  const uint8_t *msg, size_t msglen,
 		  void *private_data);
@@ -143,7 +144,8 @@ static void ctdb_packet_dump(struct ctdb_req_header *hdr)
  * Register a srvid with ctdbd
  */
 int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
-			int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
+			int (*cb)(struct tevent_context *ev,
+				  uint32_t src_vnn, uint32_t dst_vnn,
 				  uint64_t dst_srvid,
 				  const uint8_t *msg, size_t msglen,
 				  void *private_data),
@@ -204,7 +206,8 @@ static int ctdbd_msg_call_back(struct ctdbd_connection *conn,
 		if ((cb->srvid == msg->srvid) && (cb->cb != NULL)) {
 			int ret;
 
-			ret = cb->cb(msg->hdr.srcnode, msg->hdr.destnode,
+			ret = cb->cb(NULL,
+				     msg->hdr.srcnode, msg->hdr.destnode,
 				     msg->srvid, msg->data, msg->datalen,
 				     cb->private_data);
 			if (ret != 0) {
@@ -1154,7 +1157,8 @@ static void smbd_ctdb_canonicalize_ip(const struct sockaddr_storage *in,
 int ctdbd_register_ips(struct ctdbd_connection *conn,
 		       const struct sockaddr_storage *_server,
 		       const struct sockaddr_storage *_client,
-		       int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
+		       int (*cb)(struct tevent_context *ev,
+				 uint32_t src_vnn, uint32_t dst_vnn,
 				 uint64_t dst_srvid,
 				 const uint8_t *msg, size_t msglen,
 				 void *private_data),
diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c
index 6ecec32..10696ac 100644
--- a/source3/lib/messages_ctdbd.c
+++ b/source3/lib/messages_ctdbd.c
@@ -109,6 +109,7 @@ static int messaging_ctdbd_destructor(struct messaging_ctdbd_context *ctx)
 }
 
 static int messaging_ctdb_recv(
+	struct tevent_context *ev,
 	uint32_t src_vnn, uint32_t dst_vnn, uint64_t dst_srvid,
 	const uint8_t *msg, size_t msg_len, void *private_data)
 {
diff --git a/source3/smbd/notifyd/notifyd.c b/source3/smbd/notifyd/notifyd.c
index caf894e..11059ec 100644
--- a/source3/smbd/notifyd/notifyd.c
+++ b/source3/smbd/notifyd/notifyd.c
@@ -179,7 +179,8 @@ static int sys_notify_watch_dummy(
 #ifdef CLUSTER_SUPPORT
 static void notifyd_broadcast_reclog_finished(struct tevent_req *subreq);
 static void notifyd_clean_peers_finished(struct tevent_req *subreq);
-static int notifyd_snoop_broadcast(uint32_t src_vnn, uint32_t dst_vnn,
+static int notifyd_snoop_broadcast(struct tevent_context *ev,
+				   uint32_t src_vnn, uint32_t dst_vnn,
 				   uint64_t dst_srvid,
 				   const uint8_t *msg, size_t msglen,
 				   void *private_data);
@@ -1387,7 +1388,8 @@ fail:
  * broadcast, which will then trigger a fresh database pull.
  */
 
-static int notifyd_snoop_broadcast(uint32_t src_vnn, uint32_t dst_vnn,
+static int notifyd_snoop_broadcast(struct tevent_context *ev,
+				   uint32_t src_vnn, uint32_t dst_vnn,
 				   uint64_t dst_srvid,
 				   const uint8_t *msg, size_t msglen,
 				   void *private_data)
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index a19b8b7..4abaf37 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -2695,7 +2695,8 @@ static void smbd_release_ip_immediate(struct tevent_context *ctx,
 /****************************************************************************
 received when we should release a specific IP
 ****************************************************************************/
-static int release_ip(uint32_t src_vnn, uint32_t dst_vnn,
+static int release_ip(struct tevent_context *ev,
+		      uint32_t src_vnn, uint32_t dst_vnn,
 		      uint64_t dst_srvid,
 		      const uint8_t *msg, size_t msglen,
 		      void *private_data)
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index e18a4e5..91fa1c3 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -276,6 +276,7 @@ static void smbd_parent_id_cache_delete(struct messaging_context *ctx,
 
 #ifdef CLUSTER_SUPPORT
 static int smbd_parent_ctdb_reconfigured(
+	struct tevent_context *ev,
 	uint32_t src_vnn, uint32_t dst_vnn, uint64_t dst_srvid,
 	const uint8_t *msg, size_t msglen, void *private_data)
 {
-- 
2.1.4


From 1ac08cb17739a4588eb5d64c76ccd04f4bcf474e Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 1 Jun 2017 17:49:56 +0200
Subject: [PATCH 27/41] ctdbd_conn: Pass "ev" through ctdbd_msg_call_back

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/ctdbd_conn.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c
index 88d45b4..8fb951d 100644
--- a/source3/lib/ctdbd_conn.c
+++ b/source3/lib/ctdbd_conn.c
@@ -179,7 +179,8 @@ int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
 	return 0;
 }
 
-static int ctdbd_msg_call_back(struct ctdbd_connection *conn,
+static int ctdbd_msg_call_back(struct tevent_context *ev,
+			       struct ctdbd_connection *conn,
 			       struct ctdb_req_message_old *msg)
 {
 	uint32_t msg_len;
@@ -206,7 +207,7 @@ static int ctdbd_msg_call_back(struct ctdbd_connection *conn,
 		if ((cb->srvid == msg->srvid) && (cb->cb != NULL)) {
 			int ret;
 
-			ret = cb->cb(NULL,
+			ret = cb->cb(ev,
 				     msg->hdr.srcnode, msg->hdr.destnode,
 				     msg->srvid, msg->data, msg->datalen,
 				     cb->private_data);
@@ -414,7 +415,7 @@ static int ctdb_read_req(struct ctdbd_connection *conn, uint32_t reqid,
 	if (hdr->operation == CTDB_REQ_MESSAGE) {
 		struct ctdb_req_message_old *msg = (struct ctdb_req_message_old *)hdr;
 
-		ret = ctdbd_msg_call_back(conn, msg);
+		ret = ctdbd_msg_call_back(NULL, conn, msg);
 		if (ret != 0) {
 			TALLOC_FREE(hdr);
 			return ret;
@@ -586,7 +587,7 @@ static int ctdb_handle_message(struct ctdbd_connection *conn,
 
 	msg = (struct ctdb_req_message_old *)hdr;
 
-	ctdbd_msg_call_back(conn, msg);
+	ctdbd_msg_call_back(NULL, conn, msg);
 
 	return 0;
 }
-- 
2.1.4


From 585a44ea0c232f846e0105e28ccca39e414e333e Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 1 Jun 2017 17:55:06 +0200
Subject: [PATCH 28/41] ctdbd_conn: Pass "ev" through ctdb_handle_message

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/ctdbd_conn.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c
index 8fb951d..41c9af0 100644
--- a/source3/lib/ctdbd_conn.c
+++ b/source3/lib/ctdbd_conn.c
@@ -574,7 +574,8 @@ int ctdbd_conn_get_fd(struct ctdbd_connection *conn)
 /*
  * Packet handler to receive and handle a ctdb message
  */
-static int ctdb_handle_message(struct ctdbd_connection *conn,
+static int ctdb_handle_message(struct tevent_context *ev,
+			       struct ctdbd_connection *conn,
 			       struct ctdb_req_header *hdr)
 {
 	struct ctdb_req_message_old *msg;
@@ -587,7 +588,7 @@ static int ctdb_handle_message(struct ctdbd_connection *conn,
 
 	msg = (struct ctdb_req_message_old *)hdr;
 
-	ctdbd_msg_call_back(NULL, conn, msg);
+	ctdbd_msg_call_back(ev, conn, msg);
 
 	return 0;
 }
@@ -603,7 +604,7 @@ void ctdbd_socket_readable(struct ctdbd_connection *conn)
 		cluster_fatal("ctdbd died\n");
 	}
 
-	ret = ctdb_handle_message(conn, hdr);
+	ret = ctdb_handle_message(NULL, conn, hdr);
 
 	TALLOC_FREE(hdr);
 
-- 
2.1.4


From 2ac86e871cbd56224b3993a75c513eeb633249ba Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 1 Jun 2017 18:00:45 +0200
Subject: [PATCH 29/41] ctdbd_conn: Pass "ev" through ctdbd_socket_readable

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/include/ctdbd_conn.h | 3 ++-
 source3/lib/ctdbd_conn.c     | 5 +++--
 source3/lib/messages_ctdbd.c | 2 +-
 3 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h
index 44ee8ab..1a21c75 100644
--- a/source3/include/ctdbd_conn.h
+++ b/source3/include/ctdbd_conn.h
@@ -42,7 +42,8 @@ int ctdbd_setup_fde(struct ctdbd_connection *conn, struct tevent_context *ev);
 uint32_t ctdbd_vnn(const struct ctdbd_connection *conn);
 
 int ctdbd_conn_get_fd(struct ctdbd_connection *conn);
-void ctdbd_socket_readable(struct ctdbd_connection *conn);
+void ctdbd_socket_readable(struct tevent_context *ev,
+			   struct ctdbd_connection *conn);
 
 int ctdbd_messaging_send_iov(struct ctdbd_connection *conn,
 			     uint32_t dst_vnn, uint64_t dst_srvid,
diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c
index 41c9af0..94cd22e 100644
--- a/source3/lib/ctdbd_conn.c
+++ b/source3/lib/ctdbd_conn.c
@@ -593,7 +593,8 @@ static int ctdb_handle_message(struct tevent_context *ev,
 	return 0;
 }
 
-void ctdbd_socket_readable(struct ctdbd_connection *conn)
+void ctdbd_socket_readable(struct tevent_context *ev,
+			   struct ctdbd_connection *conn)
 {
 	struct ctdb_req_header *hdr = NULL;
 	int ret;
@@ -604,7 +605,7 @@ void ctdbd_socket_readable(struct ctdbd_connection *conn)
 		cluster_fatal("ctdbd died\n");
 	}
 
-	ret = ctdb_handle_message(NULL, conn, hdr);
+	ret = ctdb_handle_message(ev, conn, hdr);
 
 	TALLOC_FREE(hdr);
 
diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c
index 10696ac..48d5488 100644
--- a/source3/lib/messages_ctdbd.c
+++ b/source3/lib/messages_ctdbd.c
@@ -174,7 +174,7 @@ static void messaging_ctdbd_readable(struct tevent_context *ev,
 	if ((flags & TEVENT_FD_READ) == 0) {
 		return;
 	}
-	ctdbd_socket_readable(conn);
+	ctdbd_socket_readable(ev, conn);
 }
 
 static int messaging_ctdbd_init_internal(struct messaging_context *msg_ctx,
-- 
2.1.4


From 5f5a735a1f3c7088ec6e8eeba378d237bfe8230b Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 8 Jun 2017 12:51:29 +0200
Subject: [PATCH 30/41] messaging: Add messaging_ctdbd_register_tevent_context

We need to listen for the ctdb socket in nested event contexts

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/ctdb_dummy.c     |   7 +++
 source3/lib/messages.c       |  30 +++++++++++-
 source3/lib/messages_ctdbd.c | 109 +++++++++++++++++++++++++++++++++++++------
 source3/lib/messages_ctdbd.h |   5 ++
 4 files changed, 135 insertions(+), 16 deletions(-)

diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
index 4e3e4bc..4c0403c 100644
--- a/source3/lib/ctdb_dummy.c
+++ b/source3/lib/ctdb_dummy.c
@@ -93,6 +93,13 @@ int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
 	return ENOSYS;
 }
 
+struct messaging_ctdbd_fde *messaging_ctdbd_register_tevent_context(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	struct messaging_backend *backend)
+{
+	return NULL;
+}
+
 struct ctdbd_connection *messaging_ctdbd_connection(void)
 {
 	return NULL;
diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index 5c10013..759cc8b 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -91,6 +91,7 @@ struct messaging_context {
 
 	void *msg_dgm_ref;
 	struct messaging_backend *remote;
+	struct messaging_ctdbd_fde *cluster_fde;
 
 	struct server_id_db *names_db;
 };
@@ -520,6 +521,14 @@ static NTSTATUS messaging_init_internal(TALLOC_CTX *mem_ctx,
 			status = map_nt_error_from_unix(ret);
 			goto done;
 		}
+		ctx->cluster_fde = messaging_ctdbd_register_tevent_context(
+			ctx, ctx->event_ctx, ctx->remote);
+		if (ctx->cluster_fde == NULL) {
+			DBG_WARNING("messaging_ctdbd_register_tevent_context "
+				    "failed\n");
+			status = NT_STATUS_NO_MEMORY;
+			goto done;
+		}
 	}
 	ctx->id.vnn = get_my_vnn();
 
@@ -616,14 +625,23 @@ NTSTATUS messaging_reinit(struct messaging_context *msg_ctx)
 	}
 
 	if (lp_clustering()) {
+		TALLOC_FREE(msg_ctx->cluster_fde);
+
 		ret = messaging_ctdbd_reinit(msg_ctx, msg_ctx,
 					     msg_ctx->remote);
-
 		if (ret != 0) {
 			DEBUG(1, ("messaging_ctdbd_init failed: %s\n",
 				  strerror(ret)));
 			return map_nt_error_from_unix(ret);
 		}
+
+		msg_ctx->cluster_fde = messaging_ctdbd_register_tevent_context(
+			msg_ctx, msg_ctx->event_ctx, msg_ctx->remote);
+		if (msg_ctx->cluster_fde == NULL) {
+			DBG_WARNING("messaging_ctdbd_register_tevent_context "
+				    "failed\n");
+			return NT_STATUS_NO_MEMORY;
+		}
 	}
 
 	server_id_db_reinit(msg_ctx->names_db, msg_ctx->id);
@@ -869,6 +887,7 @@ struct messaging_filtered_read_state {
 	struct tevent_context *ev;
 	struct messaging_context *msg_ctx;
 	struct messaging_dgm_fde *fde;
+	struct messaging_ctdbd_fde *cluster_fde;
 
 	bool (*filter)(struct messaging_rec *rec, void *private_data);
 	void *private_data;
@@ -911,6 +930,14 @@ struct tevent_req *messaging_filtered_read_send(
 		return tevent_req_post(req, ev);
 	}
 
+	if (msg_ctx->remote != NULL) {
+		state->cluster_fde = messaging_ctdbd_register_tevent_context(
+			state, ev, msg_ctx->remote);
+		if (tevent_req_nomem(state->cluster_fde, req)) {
+			return tevent_req_post(req, ev);
+		}
+	}
+
 	/*
 	 * We add ourselves to the "new_waiters" array, not the "waiters"
 	 * array. If we are called from within messaging_read_done,
@@ -957,6 +984,7 @@ static void messaging_filtered_read_cleanup(struct tevent_req *req,
 	tevent_req_set_cleanup_fn(req, NULL);
 
 	TALLOC_FREE(state->fde);
+	TALLOC_FREE(state->cluster_fde);
 
 	ok = messaging_deregister_event_context(msg_ctx, state->ev);
 	if (!ok) {
diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c
index 48d5488..62b5082 100644
--- a/source3/lib/messages_ctdbd.c
+++ b/source3/lib/messages_ctdbd.c
@@ -27,10 +27,26 @@
 #include "ctdbd_conn.h"
 #include "lib/cluster_support.h"
 
+struct messaging_ctdbd_context;
+
+struct messaging_ctdbd_fde_ev {
+	struct messaging_ctdbd_fde_ev *prev, *next;
+
+	/*
+	 * Backreference to enable DLIST_REMOVE from our
+	 * destructor. Also, set to NULL when the dgm_context dies
+	 * before the messaging_dgm_fde_ev.
+	 */
+	struct messaging_ctdbd_context *ctx;
+
+	struct tevent_context *ev;
+	struct tevent_fd *fde;
+};
 
 struct messaging_ctdbd_context {
 	struct ctdbd_connection *conn;
-	struct tevent_fd *fde;
+
+	struct messaging_ctdbd_fde_ev *fde_evs;
 };
 
 /*
@@ -182,12 +198,9 @@ static int messaging_ctdbd_init_internal(struct messaging_context *msg_ctx,
 					 struct messaging_ctdbd_context *ctx,
 					 bool reinit)
 {
-	struct tevent_context *ev;
-	int ret, ctdb_fd;
+	int ret;
 
 	if (reinit) {
-		TALLOC_FREE(ctx->fde);
-
 		ret = ctdbd_reinit_connection(ctx,
 					      lp_ctdbd_socket(),
 					      lp_ctdb_timeout(),
@@ -224,15 +237,6 @@ static int messaging_ctdbd_init_internal(struct messaging_context *msg_ctx,
 		return ret;
 	}
 
-	ctdb_fd = ctdbd_conn_get_fd(ctx->conn);
-	ev = messaging_tevent_context(msg_ctx);
-
-	ctx->fde = tevent_add_fd(ev, ctx, ctdb_fd, TEVENT_FD_READ,
-				 messaging_ctdbd_readable, ctx->conn);
-	if (ctx->fde == NULL) {
-		return ENOMEM;
-	}
-
 	global_ctdb_connection_pid = getpid();
 	global_ctdbd_connection = ctx->conn;
 	talloc_set_destructor(ctx, messaging_ctdbd_destructor);
@@ -255,7 +259,7 @@ int messaging_ctdbd_init(struct messaging_context *msg_ctx,
 		return ENOMEM;
 	}
 
-	if (!(ctx = talloc(result, struct messaging_ctdbd_context))) {
+	if (!(ctx = talloc_zero(result, struct messaging_ctdbd_context))) {
 		DEBUG(0, ("talloc failed\n"));
 		TALLOC_FREE(result);
 		return ENOMEM;
@@ -289,3 +293,78 @@ int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
 
 	return 0;
 }
+
+struct messaging_ctdbd_fde {
+	struct tevent_fd *fde;
+};
+
+static int messaging_ctdbd_fde_ev_destructor(
+	struct messaging_ctdbd_fde_ev *fde_ev)
+{
+	if (fde_ev->ctx != NULL) {
+		DLIST_REMOVE(fde_ev->ctx->fde_evs, fde_ev);
+		fde_ev->ctx = NULL;
+	}
+	return 0;
+}
+
+struct messaging_ctdbd_fde *messaging_ctdbd_register_tevent_context(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	struct messaging_backend *backend)
+{
+	struct messaging_ctdbd_context *ctx = talloc_get_type_abort(
+		backend->private_data, struct messaging_ctdbd_context);
+	struct messaging_ctdbd_fde_ev *fde_ev;
+	struct messaging_ctdbd_fde *fde;
+
+	if (ctx == NULL) {
+		return NULL;
+	}
+
+	fde = talloc(mem_ctx, struct messaging_ctdbd_fde);
+	if (fde == NULL) {
+		return NULL;
+	}
+
+	for (fde_ev = ctx->fde_evs; fde_ev != NULL; fde_ev = fde_ev->next) {
+		if ((fde_ev->ev == ev) &&
+		    (tevent_fd_get_flags(fde_ev->fde) != 0)) {
+			break;
+		}
+	}
+
+	if (fde_ev == NULL) {
+		int fd = ctdbd_conn_get_fd(ctx->conn);
+
+		fde_ev = talloc(fde, struct messaging_ctdbd_fde_ev);
+		if (fde_ev == NULL) {
+			return NULL;
+		}
+		fde_ev->fde = tevent_add_fd(
+			ev, fde_ev, fd, TEVENT_FD_READ,
+			messaging_ctdbd_readable, ctx->conn);
+		if (fde_ev->fde == NULL) {
+			TALLOC_FREE(fde);
+			return NULL;
+		}
+		fde_ev->ev = ev;
+		fde_ev->ctx = ctx;
+		DLIST_ADD(ctx->fde_evs, fde_ev);
+		talloc_set_destructor(
+			fde_ev, messaging_ctdbd_fde_ev_destructor);
+	} else {
+		/*
+		 * Same trick as with tdb_wrap: The caller will never
+		 * see the talloc_referenced object, the
+		 * messaging_ctdbd_fde_ev, so problems with
+		 * talloc_unlink will not happen.
+		 */
+		if (talloc_reference(fde, fde_ev) == NULL) {
+			TALLOC_FREE(fde);
+			return NULL;
+		}
+	}
+
+	fde->fde = fde_ev->fde;
+	return fde;
+}
diff --git a/source3/lib/messages_ctdbd.h b/source3/lib/messages_ctdbd.h
index 67ec4b7..c13079d 100644
--- a/source3/lib/messages_ctdbd.h
+++ b/source3/lib/messages_ctdbd.h
@@ -35,4 +35,9 @@ int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
 			   struct messaging_backend *backend);
 struct ctdbd_connection *messaging_ctdbd_connection(void);
 
+struct messaging_ctdbd_fde;
+struct messaging_ctdbd_fde *messaging_ctdbd_register_tevent_context(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	struct messaging_backend *backend);
+
 #endif
-- 
2.1.4


From 44b399093c5e9ca31bdc835af6c74d80bd39a53f Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 1 Jun 2017 18:58:16 +0200
Subject: [PATCH 31/41] messages_ctdb: Handle async msgs for nested event
 contexts

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/ctdb_dummy.c     | 10 +++++
 source3/lib/messages.c       |  9 +++--
 source3/lib/messages_ctdbd.c | 88 ++++++++++++++++++--------------------------
 source3/lib/messages_ctdbd.h | 10 +++++
 4 files changed, 62 insertions(+), 55 deletions(-)

diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
index 4c0403c..b6ec228 100644
--- a/source3/lib/ctdb_dummy.c
+++ b/source3/lib/ctdb_dummy.c
@@ -81,6 +81,11 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 
 int messaging_ctdbd_init(struct messaging_context *msg_ctx,
 			 TALLOC_CTX *mem_ctx,
+			 void (*recv_cb)(struct tevent_context *ev,
+					 const uint8_t *msg, size_t msg_len,
+					 int *fds, size_t num_fds,
+					 void *private_data),
+			 void *private_data,
 			      struct messaging_backend **presult)
 {
 	return ENOSYS;
@@ -88,6 +93,11 @@ int messaging_ctdbd_init(struct messaging_context *msg_ctx,
 
 int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
 			   TALLOC_CTX *mem_ctx,
+			   void (*recv_cb)(struct tevent_context *ev,
+					   const uint8_t *msg, size_t msg_len,
+					   int *fds, size_t num_fds,
+					   void *private_data),
+			   void *private_data,
 			   struct messaging_backend *backend)
 {
 	return ENOSYS;
diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index 759cc8b..4e838b0 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -513,7 +513,8 @@ static NTSTATUS messaging_init_internal(TALLOC_CTX *mem_ctx,
 	talloc_set_destructor(ctx, messaging_context_destructor);
 
 	if (lp_clustering()) {
-		ret = messaging_ctdbd_init(ctx, ctx, &ctx->remote);
+		ret = messaging_ctdbd_init(
+			ctx, ctx, messaging_recv_cb, ctx, &ctx->remote);
 
 		if (ret != 0) {
 			DEBUG(2, ("messaging_ctdbd_init failed: %s\n",
@@ -627,8 +628,10 @@ NTSTATUS messaging_reinit(struct messaging_context *msg_ctx)
 	if (lp_clustering()) {
 		TALLOC_FREE(msg_ctx->cluster_fde);
 
-		ret = messaging_ctdbd_reinit(msg_ctx, msg_ctx,
-					     msg_ctx->remote);
+		ret = messaging_ctdbd_reinit(
+			msg_ctx, msg_ctx, messaging_recv_cb, msg_ctx,
+			msg_ctx->remote);
+
 		if (ret != 0) {
 			DEBUG(1, ("messaging_ctdbd_init failed: %s\n",
 				  strerror(ret)));
diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c
index 62b5082..b1af4f8 100644
--- a/source3/lib/messages_ctdbd.c
+++ b/source3/lib/messages_ctdbd.c
@@ -47,6 +47,12 @@ struct messaging_ctdbd_context {
 	struct ctdbd_connection *conn;
 
 	struct messaging_ctdbd_fde_ev *fde_evs;
+
+	void (*recv_cb)(struct tevent_context *ev,
+			const uint8_t *msg, size_t msg_len,
+			int *fds, size_t num_fds,
+			void *private_data);
+	void *private_data;
 };
 
 /*
@@ -129,52 +135,10 @@ static int messaging_ctdb_recv(
 	uint32_t src_vnn, uint32_t dst_vnn, uint64_t dst_srvid,
 	const uint8_t *msg, size_t msg_len, void *private_data)
 {
-	struct messaging_context *msg_ctx = talloc_get_type_abort(
-		private_data, struct messaging_context);
-	struct server_id me = messaging_server_id(msg_ctx);
-	int ret;
-	struct iovec iov;
-	struct server_id src, dst;
-	enum messaging_type msg_type;
-	struct server_id_buf idbuf;
-
-	if (msg_len < MESSAGE_HDR_LENGTH) {
-		DEBUG(1, ("%s: message too short: %u\n", __func__,
-			  (unsigned)msg_len));
-		return 0;
-	}
-
-	message_hdr_get(&msg_type, &src, &dst, msg);
-
-	iov = (struct iovec) {
-		.iov_base = discard_const_p(uint8_t, msg) + MESSAGE_HDR_LENGTH,
-		.iov_len = msg_len - MESSAGE_HDR_LENGTH
-	};
-
-	DEBUG(10, ("%s: Received message 0x%x len %u from %s\n",
-		   __func__, (unsigned)msg_type, (unsigned)msg_len,
-		   server_id_str_buf(src, &idbuf)));
-
-	if (!server_id_same_process(&me, &dst)) {
-		struct server_id_buf id1, id2;
-
-		DEBUG(10, ("%s: I'm %s, ignoring msg to %s\n", __func__,
-			   server_id_str_buf(me, &id1),
-			   server_id_str_buf(dst, &id2)));
-		return 0;
-	}
-
-	/*
-	 * Go through the event loop
-	 */
-
-	ret = messaging_send_iov_from(msg_ctx, src, dst, msg_type,
-				      &iov, 1, NULL, 0);
+	struct messaging_ctdbd_context *ctx = talloc_get_type_abort(
+		private_data, struct messaging_ctdbd_context);
 
-	if (ret != 0) {
-		DEBUG(10, ("%s: messaging_send_iov_from failed: %s\n",
-			   __func__, strerror(ret)));
-	}
+	ctx->recv_cb(ev, msg, msg_len, NULL, 0, ctx->private_data);
 
 	return 0;
 }
@@ -193,10 +157,15 @@ static void messaging_ctdbd_readable(struct tevent_context *ev,
 	ctdbd_socket_readable(ev, conn);
 }
 
-static int messaging_ctdbd_init_internal(struct messaging_context *msg_ctx,
-					 TALLOC_CTX *mem_ctx,
-					 struct messaging_ctdbd_context *ctx,
-					 bool reinit)
+static int messaging_ctdbd_init_internal(
+	struct messaging_context *msg_ctx, TALLOC_CTX *mem_ctx,
+	struct messaging_ctdbd_context *ctx,
+	void (*recv_cb)(struct tevent_context *ev,
+			const uint8_t *msg, size_t msg_len,
+			int *fds, size_t num_fds,
+			void *private_data),
+	void *private_data,
+	bool reinit)
 {
 	int ret;
 
@@ -229,8 +198,11 @@ static int messaging_ctdbd_init_internal(struct messaging_context *msg_ctx,
 		return ret;
 	}
 
+	ctx->recv_cb = recv_cb;
+	ctx->private_data = private_data;
+
 	ret = register_with_ctdbd(ctx->conn, getpid(),
-				  messaging_ctdb_recv, msg_ctx);
+				  messaging_ctdb_recv, ctx);
 	if (ret != 0) {
 		DEBUG(10, ("register_with_ctdbd failed: %s\n",
 			   strerror(ret)));
@@ -248,6 +220,11 @@ static int messaging_ctdbd_init_internal(struct messaging_context *msg_ctx,
 
 int messaging_ctdbd_init(struct messaging_context *msg_ctx,
 			 TALLOC_CTX *mem_ctx,
+			 void (*recv_cb)(struct tevent_context *ev,
+					 const uint8_t *msg, size_t msg_len,
+					 int *fds, size_t num_fds,
+					 void *private_data),
+			 void *private_data,
 			 struct messaging_backend **presult)
 {
 	struct messaging_backend *result;
@@ -265,7 +242,8 @@ int messaging_ctdbd_init(struct messaging_context *msg_ctx,
 		return ENOMEM;
 	}
 
-	ret = messaging_ctdbd_init_internal(msg_ctx, mem_ctx, ctx, false);
+	ret = messaging_ctdbd_init_internal(msg_ctx, mem_ctx, ctx,
+					    recv_cb, private_data, false);
 	if (ret != 0) {
 		TALLOC_FREE(result);
 		return ret;
@@ -280,13 +258,19 @@ int messaging_ctdbd_init(struct messaging_context *msg_ctx,
 
 int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
 			   TALLOC_CTX *mem_ctx,
+			   void (*recv_cb)(struct tevent_context *ev,
+					   const uint8_t *msg, size_t msg_len,
+					   int *fds, size_t num_fds,
+					   void *private_data),
+			   void *private_data,
 			   struct messaging_backend *backend)
 {
 	struct messaging_ctdbd_context *ctx = talloc_get_type_abort(
 		backend->private_data, struct messaging_ctdbd_context);
 	int ret;
 
-	ret = messaging_ctdbd_init_internal(msg_ctx, mem_ctx, ctx, true);
+	ret = messaging_ctdbd_init_internal(msg_ctx, mem_ctx, ctx,
+					    recv_cb, private_data, true);
 	if (ret != 0) {
 		return ret;
 	}
diff --git a/source3/lib/messages_ctdbd.h b/source3/lib/messages_ctdbd.h
index c13079d..7d928fe 100644
--- a/source3/lib/messages_ctdbd.h
+++ b/source3/lib/messages_ctdbd.h
@@ -29,9 +29,19 @@ struct ctdbd_connection;
 
 int messaging_ctdbd_init(struct messaging_context *msg_ctx,
 			 TALLOC_CTX *mem_ctx,
+			 void (*recv_cb)(struct tevent_context *ev,
+					 const uint8_t *msg, size_t msg_len,
+					 int *fds, size_t num_fds,
+					 void *private_data),
+			 void *private_data,
 			 struct messaging_backend **presult);
 int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
 			   TALLOC_CTX *mem_ctx,
+			   void (*recv_cb)(struct tevent_context *ev,
+					   const uint8_t *msg, size_t msg_len,
+					   int *fds, size_t num_fds,
+					   void *private_data),
+			   void *private_data,
 			   struct messaging_backend *backend);
 struct ctdbd_connection *messaging_ctdbd_connection(void);
 
-- 
2.1.4


From 962359dc5c074763d4be1ade8058103e2f7c35eb Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 13 Sep 2016 14:22:05 +0200
Subject: [PATCH 32/41] dbwrap: Avoid dbwrap_merge_dbufs in db_ctdb_storev

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/dbwrap/dbwrap_ctdb.c | 17 +++++------------
 1 file changed, 5 insertions(+), 12 deletions(-)

diff --git a/source3/lib/dbwrap/dbwrap_ctdb.c b/source3/lib/dbwrap/dbwrap_ctdb.c
index 2969183..b722714 100644
--- a/source3/lib/dbwrap/dbwrap_ctdb.c
+++ b/source3/lib/dbwrap/dbwrap_ctdb.c
@@ -182,16 +182,16 @@ static NTSTATUS db_ctdb_ltdb_parse(
 static NTSTATUS db_ctdb_ltdb_store(struct db_ctdb_ctx *db,
 				   TDB_DATA key,
 				   struct ctdb_ltdb_header *header,
-				   TDB_DATA data)
+				   const TDB_DATA *dbufs, int num_dbufs)
 {
-	TDB_DATA recs[2];
+	TDB_DATA recs[num_dbufs+1];
 	int ret;
 
 	recs[0] = (TDB_DATA) { .dptr = (uint8_t *)header,
 			       .dsize = sizeof(struct ctdb_ltdb_header) };
-	recs[1] = data;
+	memcpy(&recs[1], dbufs, sizeof(TDB_DATA) * num_dbufs);
 
-	ret = tdb_storev(db->wtdb->tdb, key, recs, 2, TDB_REPLACE);
+	ret = tdb_storev(db->wtdb->tdb, key, recs, num_dbufs + 1, TDB_REPLACE);
 
 	return (ret == 0) ? NT_STATUS_OK
 			  : tdb_error_to_ntstatus(db->wtdb->tdb);
@@ -905,16 +905,9 @@ static NTSTATUS db_ctdb_storev(struct db_record *rec,
 	struct db_ctdb_rec *crec = talloc_get_type_abort(
 		rec->private_data, struct db_ctdb_rec);
 	NTSTATUS status;
-	TDB_DATA data;
-
-	data = dbwrap_merge_dbufs(rec, dbufs, num_dbufs);
-	if (data.dptr == NULL) {
-		return NT_STATUS_NO_MEMORY;
-	}
 
 	status = db_ctdb_ltdb_store(crec->ctdb_ctx, rec->key, &(crec->header),
-				    data);
-	TALLOC_FREE(data.dptr);
+				    dbufs, num_dbufs);
 	return status;
 }
 
-- 
2.1.4


From 5163e1d5937dfacc6942b15b3f4970496f3e7c38 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 11 Jun 2017 10:45:25 +0200
Subject: [PATCH 33/41] messaging: Add messaging_ctdb_init/destroy

This models connecting to ctdb after the dgm code. The main point
is that we should never open more than more ctdb socket for messaging.

With more than one socket, we might end up with our pid registered with
ctdb on more than one socket. This could lead to memory overconsumption
in ctdb. ctdbd will eventually throw away messages, but they will take
up space unnecessarily.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/ctdb_dummy.c    |  13 +++
 source3/lib/messages_ctdb.c | 260 ++++++++++++++++++++++++++++++++++++++++++++
 source3/lib/messages_ctdb.h |  42 +++++++
 source3/wscript_build       |   1 +
 4 files changed, 316 insertions(+)
 create mode 100644 source3/lib/messages_ctdb.c
 create mode 100644 source3/lib/messages_ctdb.h

diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
index b6ec228..855f56d 100644
--- a/source3/lib/ctdb_dummy.c
+++ b/source3/lib/ctdb_dummy.c
@@ -20,6 +20,7 @@
 #include "includes.h"
 #include "messages.h"
 #include "lib/messages_ctdbd.h"
+#include "lib/messages_ctdb.h"
 #include "ctdbd_conn.h"
 #include "lib/dbwrap/dbwrap.h"
 #include "lib/dbwrap/dbwrap_ctdb.h"
@@ -91,6 +92,18 @@ int messaging_ctdbd_init(struct messaging_context *msg_ctx,
 	return ENOSYS;
 }
 
+int messaging_ctdb_send(uint32_t dst_vnn, uint64_t dst_srvid,
+			const struct iovec *iov, int iovlen)
+{
+	return ENOSYS;
+}
+
+struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev)
+{
+	return NULL;
+}
+
 int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
 			   TALLOC_CTX *mem_ctx,
 			   void (*recv_cb)(struct tevent_context *ev,
diff --git a/source3/lib/messages_ctdb.c b/source3/lib/messages_ctdb.c
new file mode 100644
index 0000000..5bc494d
--- /dev/null
+++ b/source3/lib/messages_ctdb.c
@@ -0,0 +1,260 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba internal messaging functions
+ * Copyright (C) 2017 by Volker Lendecke
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "lib/messages_ctdb.h"
+#include "lib/util/server_id.h"
+#include "messages.h"
+#include "util_tdb.h"
+#include "lib/util/iov_buf.h"
+#include "lib/messages_util.h"
+#include "ctdbd_conn.h"
+#include "lib/cluster_support.h"
+
+struct messaging_ctdb_context;
+
+/*
+ * We can only have one tevent_fd per ctdb_context and per
+ * tevent_context. Maintain a list of registered tevent_contexts per
+ * ctdb_context.
+ */
+struct messaging_ctdb_fde_ev {
+	struct messaging_ctdb_fde_ev *prev, *next;
+
+	/*
+	 * Backreference to enable DLIST_REMOVE from our
+	 * destructor. Also, set to NULL when the ctdb_context dies
+	 * before the messaging_ctdb_fde_ev.
+	 */
+	struct messaging_ctdb_context *ctx;
+
+	struct tevent_context *ev;
+	struct tevent_fd *fde;
+};
+
+struct messaging_ctdb_context {
+	struct ctdbd_connection *conn;
+
+	void (*recv_cb)(struct tevent_context *ev,
+			const uint8_t *msg, size_t msg_len,
+			int *fds, size_t num_fds,
+			void *private_data);
+	void *recv_cb_private_data;
+
+	struct messaging_ctdb_fde_ev *fde_evs;
+};
+
+static int messaging_ctdb_recv(
+	struct tevent_context *ev,
+	uint32_t src_vnn, uint32_t dst_vnn, uint64_t dst_srvid,
+	const uint8_t *msg, size_t msg_len, void *private_data)
+{
+	struct messaging_ctdb_context *state = talloc_get_type_abort(
+		private_data, struct messaging_ctdb_context);
+
+	state->recv_cb(ev, msg, msg_len, NULL, 0, state->recv_cb_private_data);
+
+	return 0;
+}
+
+struct messaging_ctdb_context *global_ctdb_context;
+
+int messaging_ctdb_init(const char *sockname, int timeout, uint64_t unique_id,
+			void (*recv_cb)(struct tevent_context *ev,
+					const uint8_t *msg, size_t msg_len,
+					int *fds, size_t num_fds,
+					void *private_data),
+			void *private_data)
+{
+	struct messaging_ctdb_context *ctx;
+	int ret;
+
+	if (global_ctdb_context != NULL) {
+		return EBUSY;
+	}
+
+	ctx = talloc_zero(NULL, struct messaging_ctdb_context);
+	if (ctx == NULL) {
+		return ENOMEM;
+	}
+	ctx->recv_cb = recv_cb;
+	ctx->recv_cb_private_data = private_data;
+
+	ret = ctdbd_init_connection(ctx, sockname, timeout, &ctx->conn);
+	if (ret != 0) {
+		DBG_DEBUG("ctdbd_init_connection returned %s\n",
+			  strerror(ret));
+		goto fail;
+	}
+
+	ret = register_with_ctdbd(ctx->conn, getpid(), messaging_ctdb_recv,
+				  ctx);
+	if (ret != 0) {
+		DBG_DEBUG("register_with_ctdbd returned %s (%d)\n",
+			  strerror(ret), ret);
+		goto fail;
+	}
+
+	ret = register_with_ctdbd(ctx->conn, unique_id, NULL, NULL);
+	if (ret != 0) {
+		DBG_DEBUG("register_with_ctdbd returned %s (%d)\n",
+			  strerror(ret), ret);
+		goto fail;
+	}
+
+	set_my_vnn(ctdbd_vnn(ctx->conn));
+
+	global_ctdb_context = ctx;
+	return 0;
+fail:
+	TALLOC_FREE(ctx);
+	return ret;
+}
+
+void messaging_ctdb_destroy(void)
+{
+	TALLOC_FREE(global_ctdb_context);
+}
+
+int messaging_ctdb_send(uint32_t dst_vnn, uint64_t dst_srvid,
+			const struct iovec *iov, int iovlen)
+{
+	struct messaging_ctdb_context *ctx = global_ctdb_context;
+	int ret;
+
+	if (ctx == NULL) {
+		return ENOTCONN;
+	}
+
+	ret = ctdbd_messaging_send_iov(ctx->conn, dst_vnn, dst_srvid,
+				       iov, iovlen);
+	return ret;
+}
+
+static void messaging_ctdb_read_handler(struct tevent_context *ev,
+					struct tevent_fd *fde,
+					uint16_t flags,
+					void *private_data)
+{
+	struct messaging_ctdb_context *ctx = talloc_get_type_abort(
+		private_data, struct messaging_ctdb_context);
+
+	if ((flags & TEVENT_FD_READ) == 0) {
+		return;
+	}
+	ctdbd_socket_readable(ev, ctx->conn);
+}
+
+struct messaging_ctdb_fde {
+	struct tevent_fd *fde;
+};
+
+static int messaging_ctdb_fde_ev_destructor(
+	struct messaging_ctdb_fde_ev *fde_ev)
+{
+	if (fde_ev->ctx != NULL) {
+		DLIST_REMOVE(fde_ev->ctx->fde_evs, fde_ev);
+		fde_ev->ctx = NULL;
+	}
+	return 0;
+}
+
+/*
+ * Reference counter for a struct tevent_fd messaging read event
+ * (with callback function) on a struct tevent_context registered
+ * on a messaging context.
+ *
+ * If we've already registered this struct tevent_context before
+ * (so already have a read event), just increase the reference count.
+ *
+ * Otherwise create a new struct tevent_fd messaging read event on the
+ * previously unseen struct tevent_context - this is what drives
+ * the message receive processing.
+ *
+ */
+
+struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev)
+{
+	struct messaging_ctdb_context *ctx = global_ctdb_context;
+	struct messaging_ctdb_fde_ev *fde_ev;
+	struct messaging_ctdb_fde *fde;
+
+	if (ctx == NULL) {
+		return NULL;
+	}
+
+	fde = talloc(mem_ctx, struct messaging_ctdb_fde);
+	if (fde == NULL) {
+		return NULL;
+	}
+
+	for (fde_ev = ctx->fde_evs; fde_ev != NULL; fde_ev = fde_ev->next) {
+		if ((fde_ev->ev == ev) &&
+		    (tevent_fd_get_flags(fde_ev->fde) != 0)) {
+			break;
+		}
+	}
+
+	if (fde_ev == NULL) {
+		int sock = ctdbd_conn_get_fd(ctx->conn);
+
+		fde_ev = talloc(fde, struct messaging_ctdb_fde_ev);
+		if (fde_ev == NULL) {
+			return NULL;
+		}
+		fde_ev->fde = tevent_add_fd(
+			ev, fde_ev, sock, TEVENT_FD_READ,
+			messaging_ctdb_read_handler, ctx);
+		if (fde_ev->fde == NULL) {
+			TALLOC_FREE(fde);
+			return NULL;
+		}
+		fde_ev->ev = ev;
+		fde_ev->ctx = ctx;
+		DLIST_ADD(ctx->fde_evs, fde_ev);
+		talloc_set_destructor(
+			fde_ev, messaging_ctdb_fde_ev_destructor);
+	} else {
+		/*
+		 * Same trick as with tdb_wrap: The caller will never
+		 * see the talloc_referenced object, the
+		 * messaging_ctdb_fde_ev, so problems with
+		 * talloc_unlink will not happen.
+		 */
+		if (talloc_reference(fde, fde_ev) == NULL) {
+			TALLOC_FREE(fde);
+			return NULL;
+		}
+	}
+
+	fde->fde = fde_ev->fde;
+	return fde;
+}
+
+bool messaging_ctdb_fde_active(struct messaging_ctdb_fde *fde)
+{
+	uint16_t flags;
+
+	if (fde == NULL) {
+		return false;
+	}
+	flags = tevent_fd_get_flags(fde->fde);
+	return (flags != 0);
+}
diff --git a/source3/lib/messages_ctdb.h b/source3/lib/messages_ctdb.h
new file mode 100644
index 0000000..006821b
--- /dev/null
+++ b/source3/lib/messages_ctdb.h
@@ -0,0 +1,42 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba internal messaging functions
+ * Copyright (C) 2017 by Volker Lendecke
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MESSAGES_CTDB_H__
+#define __MESSAGES_CTDB_H__
+
+#include "replace.h"
+#include "system/filesys.h"
+#include <tevent.h>
+
+int messaging_ctdb_init(const char *sockname, int timeout, uint64_t unique_id,
+			void (*recv_cb)(struct tevent_context *ev,
+					const uint8_t *msg, size_t msg_len,
+					int *fds, size_t num_fds,
+					void *private_data),
+			void *private_data);
+void messaging_ctdb_destroy(void);
+int messaging_ctdb_send(uint32_t dst_vnn, uint64_t dst_srvid,
+			const struct iovec *iov, int iovlen);
+
+struct messaging_ctdb_fde;
+struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev);
+bool messaging_ctdb_fde_active(struct messaging_ctdb_fde *fde);
+
+#endif
diff --git a/source3/wscript_build b/source3/wscript_build
index 99f4a2b..a57217c 100644
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -331,6 +331,7 @@ if bld.env.with_ctdb:
                      lib/cluster_support.c
                      lib/dbwrap/dbwrap_ctdb.c
                      lib/messages_ctdbd.c
+                     lib/messages_ctdb.c
                      lib/ctdbd_conn.c
                    '''
     SAMBA_CLUSTER_SUPPORT_DEPS='''
-- 
2.1.4


From a49a4c25116eced0859491b834154a7b4143744a Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 12 Jun 2017 16:50:16 +0200
Subject: [PATCH 34/41] messaging: Add messages_ctdb_ref

Modeled after messages_dgm_ref

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/ctdb_dummy.c        |  13 ++++
 source3/lib/messages_ctdb_ref.c | 145 ++++++++++++++++++++++++++++++++++++++++
 source3/lib/messages_ctdb_ref.h |  35 ++++++++++
 source3/wscript_build           |   1 +
 4 files changed, 194 insertions(+)
 create mode 100644 source3/lib/messages_ctdb_ref.c
 create mode 100644 source3/lib/messages_ctdb_ref.h

diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
index 855f56d..2d7ba25 100644
--- a/source3/lib/ctdb_dummy.c
+++ b/source3/lib/ctdb_dummy.c
@@ -21,6 +21,7 @@
 #include "messages.h"
 #include "lib/messages_ctdbd.h"
 #include "lib/messages_ctdb.h"
+#include "lib/messages_ctdb_ref.h"
 #include "ctdbd_conn.h"
 #include "lib/dbwrap/dbwrap.h"
 #include "lib/dbwrap/dbwrap_ctdb.h"
@@ -98,6 +99,18 @@ int messaging_ctdb_send(uint32_t dst_vnn, uint64_t dst_srvid,
 	return ENOSYS;
 }
 
+void *messaging_ctdb_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			 const char *sockname, int timeout, uint64_t unique_id,
+			 void (*recv_cb)(struct tevent_context *ev,
+					 const uint8_t *msg, size_t msg_len,
+					 int *fds, size_t num_fds,
+					 void *private_data),
+			 void *private_data,
+			 int *err)
+{
+	return NULL;
+}
+
 struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
 	TALLOC_CTX *mem_ctx, struct tevent_context *ev)
 {
diff --git a/source3/lib/messages_ctdb_ref.c b/source3/lib/messages_ctdb_ref.c
new file mode 100644
index 0000000..3570ed8
--- /dev/null
+++ b/source3/lib/messages_ctdb_ref.c
@@ -0,0 +1,145 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba internal messaging functions
+ * Copyright (C) 2017 by Volker Lendecke
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include <talloc.h>
+#include "messages_ctdb.h"
+#include "messages_ctdb_ref.h"
+#include "lib/util/debug.h"
+#include "lib/util/dlinklist.h"
+
+struct msg_ctdb_ref {
+	struct msg_ctdb_ref *prev, *next;
+	struct messaging_ctdb_fde *fde;
+	void (*recv_cb)(struct tevent_context *ev,
+			const uint8_t *msg, size_t msg_len,
+			int *fds, size_t num_fds, void *private_data);
+	void *recv_cb_private_data;
+};
+
+static pid_t ctdb_pid = 0;
+static struct msg_ctdb_ref *refs = NULL;
+
+static int msg_ctdb_ref_destructor(struct msg_ctdb_ref *r);
+static void msg_ctdb_ref_recv(struct tevent_context *ev,
+			      const uint8_t *msg, size_t msg_len,
+			      int *fds, size_t num_fds, void *private_data);
+
+void *messaging_ctdb_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			 const char *sockname, int timeout, uint64_t unique_id,
+			 void (*recv_cb)(struct tevent_context *ev,
+					 const uint8_t *msg, size_t msg_len,
+					 int *fds, size_t num_fds,
+					 void *private_data),
+			 void *recv_cb_private_data,
+			 int *err)
+{
+	struct msg_ctdb_ref *result, *tmp_refs;
+
+	result = talloc(mem_ctx, struct msg_ctdb_ref);
+	if (result == NULL) {
+		*err = ENOMEM;
+		return NULL;
+	}
+	result->fde = NULL;
+
+	tmp_refs = refs;
+
+	if ((refs != NULL) && (ctdb_pid != getpid())) {
+		/*
+		 * Have to reinit after fork
+		 */
+		messaging_ctdb_destroy();
+		refs = NULL;
+	}
+
+	if (refs == NULL) {
+		int ret;
+
+		ret = messaging_ctdb_init(sockname, timeout, unique_id,
+					  msg_ctdb_ref_recv, NULL);
+		DBG_DEBUG("messaging_ctdb_init returned %s\n", strerror(ret));
+		if (ret != 0) {
+			DEBUG(10, ("messaging_ctdb_init failed: %s\n",
+				   strerror(ret)));
+			TALLOC_FREE(result);
+			*err = ret;
+			return NULL;
+		}
+		ctdb_pid = getpid();
+	}
+
+	result->fde = messaging_ctdb_register_tevent_context(result, ev);
+	if (result->fde == NULL) {
+		TALLOC_FREE(result);
+		*err = ENOMEM;
+		return NULL;
+	}
+
+	refs = tmp_refs;
+
+	result->recv_cb = recv_cb;
+	result->recv_cb_private_data = recv_cb_private_data;
+	DLIST_ADD(refs, result);
+	talloc_set_destructor(result, msg_ctdb_ref_destructor);
+
+	return result;
+}
+
+static void msg_ctdb_ref_recv(struct tevent_context *ev,
+			      const uint8_t *msg, size_t msg_len,
+			      int *fds, size_t num_fds, void *private_data)
+{
+	struct msg_ctdb_ref *r, *next;
+
+	for (r = refs; r != NULL; r = next) {
+		bool active;
+
+		next = r->next;
+
+		active = messaging_ctdb_fde_active(r->fde);
+		if (!active) {
+			/*
+			 * r's tevent_context has died.
+			 */
+			continue;
+		}
+
+		r->recv_cb(ev, msg, msg_len, fds, num_fds,
+			   r->recv_cb_private_data);
+		break;
+	}
+}
+
+static int msg_ctdb_ref_destructor(struct msg_ctdb_ref *r)
+{
+	if (refs == NULL) {
+		abort();
+	}
+	DLIST_REMOVE(refs, r);
+
+	TALLOC_FREE(r->fde);
+
+	DBG_DEBUG("refs=%p\n", refs);
+
+	if (refs == NULL) {
+		messaging_ctdb_destroy();
+	}
+	return 0;
+}
diff --git a/source3/lib/messages_ctdb_ref.h b/source3/lib/messages_ctdb_ref.h
new file mode 100644
index 0000000..44541d8
--- /dev/null
+++ b/source3/lib/messages_ctdb_ref.h
@@ -0,0 +1,35 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Samba internal messaging functions
+ * Copyright (C) 2017 by Volker Lendecke
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MESSAGES_CTDB_REF_H__
+#define __MESSAGES_CTDB_REF_H__
+
+#include "replace.h"
+#include <tevent.h>
+
+void *messaging_ctdb_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			 const char *sockname, int timeout, uint64_t unique_id,
+			 void (*recv_cb)(struct tevent_context *ev,
+					 const uint8_t *msg, size_t msg_len,
+					 int *fds, size_t num_fds,
+					 void *private_data),
+			 void *private_data,
+			 int *err);
+
+#endif
diff --git a/source3/wscript_build b/source3/wscript_build
index a57217c..cffcca3 100644
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -332,6 +332,7 @@ if bld.env.with_ctdb:
                      lib/dbwrap/dbwrap_ctdb.c
                      lib/messages_ctdbd.c
                      lib/messages_ctdb.c
+                     lib/messages_ctdb_ref.c
                      lib/ctdbd_conn.c
                    '''
     SAMBA_CLUSTER_SUPPORT_DEPS='''
-- 
2.1.4


From 63e8dfd533a64881bc8f11a94abfcd144054b07e Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 16 Jun 2017 17:11:48 +0200
Subject: [PATCH 35/41] dbwrap_ctdb: Use messaging_ctdbd_connection

With messages_ctdb, the global ctdb connection will change after fork.

Don't store the wrong parent connection across a fork. The alternative would
be to do a reinit on all dbwrap_ctdb databases, but that seems overkill
given that we only have one "standard" ctdb connection anyway.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/ctdb_dummy.c           |  1 -
 source3/lib/dbwrap/dbwrap_ctdb.c   | 34 ++++++++++++++++++----------------
 source3/lib/dbwrap/dbwrap_ctdb.h   |  1 -
 source3/lib/dbwrap/dbwrap_open.c   |  2 +-
 source3/torture/test_dbwrap_ctdb.c |  8 +-------
 5 files changed, 20 insertions(+), 26 deletions(-)

diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
index 2d7ba25..891e7c3 100644
--- a/source3/lib/ctdb_dummy.c
+++ b/source3/lib/ctdb_dummy.c
@@ -70,7 +70,6 @@ bool ctdbd_process_exists(struct ctdbd_connection *conn, uint32_t vnn, pid_t pid
 
 struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 				struct messaging_context *msg_ctx,
-				struct ctdbd_connection *conn,
 				const char *name,
 				int hash_size, int tdb_flags,
 				int open_flags, mode_t mode,
diff --git a/source3/lib/dbwrap/dbwrap_ctdb.c b/source3/lib/dbwrap/dbwrap_ctdb.c
index b722714..2cee058 100644
--- a/source3/lib/dbwrap/dbwrap_ctdb.c
+++ b/source3/lib/dbwrap/dbwrap_ctdb.c
@@ -34,6 +34,7 @@
 #include "dbwrap/dbwrap_ctdb.h"
 #include "g_lock.h"
 #include "messages.h"
+#include "messages_ctdbd.h"
 #include "lib/cluster_support.h"
 #include "lib/util/tevent_ntstatus.h"
 
@@ -50,7 +51,6 @@ struct db_ctdb_transaction_handle {
 
 struct db_ctdb_ctx {
 	struct db_context *db;
-	struct ctdbd_connection *conn;
 	struct tdb_wrap *wtdb;
 	uint32_t db_id;
 	struct db_ctdb_transaction_handle *transaction;
@@ -640,7 +640,7 @@ static NTSTATUS db_ctdb_transaction_store(struct db_ctdb_transaction_handle *h,
 		SAFE_FREE(rec.dptr);
 	}
 
-	header.dmaster = ctdbd_vnn(h->ctx->conn);
+	header.dmaster = get_my_vnn();
 	header.rsn++;
 
 	h->m_write = db_ctdb_marshall_add(h, h->m_write, h->ctx->db_id, 0, key, &header, data);
@@ -821,7 +821,8 @@ static int db_ctdb_transaction_commit(struct db_context *db)
 
 again:
 	/* tell ctdbd to commit to the other nodes */
-	ret = ctdbd_control_local(ctx->conn, CTDB_CONTROL_TRANS3_COMMIT,
+	ret = ctdbd_control_local(messaging_ctdbd_connection(),
+				  CTDB_CONTROL_TRANS3_COMMIT,
 				  h->ctx->db_id, 0,
 				  db_ctdb_marshall_finish(h->m_write),
 				  NULL, NULL, &status);
@@ -937,7 +938,7 @@ static NTSTATUS db_ctdb_send_schedule_for_deletion(struct db_record *rec)
 	dd->keylen = rec->key.dsize;
 	memcpy(dd->key, rec->key.dptr, rec->key.dsize);
 
-	ret = ctdbd_control_local(ctx->conn,
+	ret = ctdbd_control_local(messaging_ctdbd_connection(),
 				  CTDB_CONTROL_SCHEDULE_FOR_DELETION,
 				  crec->ctdb_ctx->db_id,
 				  CTDB_CTRL_FLAG_NOREPLY, /* flags */
@@ -1152,8 +1153,7 @@ again:
 	 * take the shortcut and just return it.
 	 */
 
-	if (!db_ctdb_can_use_local_copy(ctdb_data, ctdbd_vnn(ctx->conn),
-					false)) {
+	if (!db_ctdb_can_use_local_copy(ctdb_data, get_my_vnn(), false)) {
 		SAFE_FREE(ctdb_data.dptr);
 		tdb_chainunlock(ctx->wtdb->tdb, key);
 		talloc_set_destructor(result, NULL);
@@ -1171,12 +1171,13 @@ again:
 			   ctdb_data.dptr, ctdb_data.dptr ?
 			   ((struct ctdb_ltdb_header *)ctdb_data.dptr)->dmaster :
 			   UINT32_MAX,
-			   ctdbd_vnn(ctx->conn),
+			   get_my_vnn(),
 			   ctdb_data.dptr ?
 			   ((struct ctdb_ltdb_header *)ctdb_data.dptr)->flags : 0));
 
 		GetTimeOfDay(&ctdb_start_time);
-		ret = ctdbd_migrate(ctx->conn, ctx->db_id, key);
+		ret = ctdbd_migrate(messaging_ctdbd_connection(), ctx->db_id,
+				    key);
 		ctdb_time += timeval_elapsed(&ctdb_start_time);
 
 		if (ret != 0) {
@@ -1396,7 +1397,7 @@ static NTSTATUS db_ctdb_parse_record(struct db_context *db, TDB_DATA key,
 
 	state.parser = parser;
 	state.private_data = private_data;
-	state.my_vnn = ctdbd_vnn(ctx->conn);
+	state.my_vnn = get_my_vnn();
 	state.empty_record = false;
 
 	status = db_ctdb_try_parse_local_record(ctx, key, &state);
@@ -1404,7 +1405,7 @@ static NTSTATUS db_ctdb_parse_record(struct db_context *db, TDB_DATA key,
 		return status;
 	}
 
-	ret = ctdbd_parse(ctx->conn, ctx->db_id, key,
+	ret = ctdbd_parse(messaging_ctdbd_connection(), ctx->db_id, key,
 			  state.ask_for_readonly_copy, parser, private_data);
 	if (ret != 0) {
 		if (ret == ENOENT) {
@@ -1453,7 +1454,7 @@ static struct tevent_req *db_ctdb_parse_record_send(
 	*state = (struct db_ctdb_parse_record_state) {
 		.parser = parser,
 		.private_data = private_data,
-		.my_vnn = ctdbd_vnn(ctx->conn),
+		.my_vnn = get_my_vnn(),
 		.empty_record = false,
 	};
 
@@ -1785,7 +1786,6 @@ static size_t db_ctdb_id(struct db_context *db, uint8_t *id, size_t idlen)
 
 struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 				struct messaging_context *msg_ctx,
-				struct ctdbd_connection *conn,
 				const char *name,
 				int hash_size, int tdb_flags,
 				int open_flags, mode_t mode,
@@ -1825,9 +1825,9 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 
 	db_ctdb->transaction = NULL;
 	db_ctdb->db = result;
-	db_ctdb->conn = conn;
 
-	ret = ctdbd_db_attach(db_ctdb->conn, name, &db_ctdb->db_id, tdb_flags);
+	ret = ctdbd_db_attach(messaging_ctdbd_connection(), name,
+			      &db_ctdb->db_id, tdb_flags);
 	if (ret != 0) {
 		DEBUG(0, ("ctdbd_db_attach failed for %s: %s\n", name,
 			  strerror(ret)));
@@ -1835,7 +1835,8 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 		return NULL;
 	}
 
-	db_path = ctdbd_dbpath(db_ctdb->conn, db_ctdb, db_ctdb->db_id);
+	db_path = ctdbd_dbpath(messaging_ctdbd_connection(), db_ctdb,
+			       db_ctdb->db_id);
 
 	result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
 	result->lock_order = lock_order;
@@ -1862,7 +1863,8 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 				       sizeof(db_ctdb->db_id));
 
 		ret = ctdbd_control_local(
-			db_ctdb->conn, CTDB_CONTROL_SET_DB_READONLY, 0, 0,
+			messaging_ctdbd_connection(),
+			CTDB_CONTROL_SET_DB_READONLY, 0, 0,
 			indata, NULL, NULL, &cstatus);
 		if ((ret != 0) || (cstatus != 0)) {
 			DEBUG(1, ("CTDB_CONTROL_SET_DB_READONLY failed: "
diff --git a/source3/lib/dbwrap/dbwrap_ctdb.h b/source3/lib/dbwrap/dbwrap_ctdb.h
index 42c831f..0b82479 100644
--- a/source3/lib/dbwrap/dbwrap_ctdb.h
+++ b/source3/lib/dbwrap/dbwrap_ctdb.h
@@ -30,7 +30,6 @@ struct ctdbd_connection;
 
 struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 				struct messaging_context *msg_ctx,
-				struct ctdbd_connection *conn,
 				const char *name,
 				int hash_size, int tdb_flags,
 				int open_flags, mode_t mode,
diff --git a/source3/lib/dbwrap/dbwrap_open.c b/source3/lib/dbwrap/dbwrap_open.c
index 55e0adb..dfb87e1 100644
--- a/source3/lib/dbwrap/dbwrap_open.c
+++ b/source3/lib/dbwrap/dbwrap_open.c
@@ -156,7 +156,7 @@ struct db_context *db_open(TALLOC_CTX *mem_ctx,
 			}
 			msg_ctx = server_messaging_context();
 
-			result = db_open_ctdb(mem_ctx, msg_ctx, conn, partname,
+			result = db_open_ctdb(mem_ctx, msg_ctx, partname,
 					      hash_size,
 					      tdb_flags, open_flags, mode,
 					      lock_order, dbwrap_flags);
diff --git a/source3/torture/test_dbwrap_ctdb.c b/source3/torture/test_dbwrap_ctdb.c
index 4512358..cc6fd0c 100644
--- a/source3/torture/test_dbwrap_ctdb.c
+++ b/source3/torture/test_dbwrap_ctdb.c
@@ -33,16 +33,10 @@ bool run_local_dbwrap_ctdb(int dummy)
 	NTSTATUS status;
 	uint32_t val;
 	struct messaging_context *msg_ctx;
-	struct ctdbd_connection *conn;
 
 	msg_ctx = server_messaging_context();
-	conn = messaging_ctdbd_connection();
-	if (conn == NULL) {
-		fprintf(stderr, "no ctdbd connection\n");
-		goto fail;
-	}
 
-	db = db_open_ctdb(talloc_tos(), msg_ctx, conn, "torture.tdb",
+	db = db_open_ctdb(talloc_tos(), msg_ctx, "torture.tdb",
 			  0, TDB_DEFAULT,
 			  O_RDWR, 0755, DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
 	if (db == NULL) {
-- 
2.1.4


From 1d66e896110db886554043a16d128607e9575115 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 16 Jun 2017 15:20:39 +0200
Subject: [PATCH 36/41] smbpasswd: Initialize messaging for messaging_ctdb_conn

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/utils/smbpasswd.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/source3/utils/smbpasswd.c b/source3/utils/smbpasswd.c
index 437a5e5..aa6b857 100644
--- a/source3/utils/smbpasswd.c
+++ b/source3/utils/smbpasswd.c
@@ -603,6 +603,10 @@ int main(int argc, char **argv)
 
 	setup_logging("smbpasswd", DEBUG_STDERR);
 
+	if (server_messaging_context() == NULL) {
+		return 1;
+	}
+
 	/*
 	 * Set the machine NETBIOS name if not already
 	 * set from the config file. 
-- 
2.1.4


From f3c7775b1d0a23d2223ab72aa0806418d1644e6d Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 5 Jul 2017 19:13:23 +0200
Subject: [PATCH 37/41] messages_ctdb: Add messaging_ctdb_connection

This will be the replacement for messaging_ctdbd_connection(). This does not
default to initializing messaging but panics. We just don't have correct
default arguments for messaging_init. Implicit multiple messaging and event
contexts is a bug also.

It *might* be that some tools fail due to this, but this needs fixing in
different ways. See the previous commit for smbpasswd.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/messages_ctdb.c | 8 ++++++++
 source3/lib/messages_ctdb.h | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/source3/lib/messages_ctdb.c b/source3/lib/messages_ctdb.c
index 5bc494d..a2a7c21 100644
--- a/source3/lib/messages_ctdb.c
+++ b/source3/lib/messages_ctdb.c
@@ -258,3 +258,11 @@ bool messaging_ctdb_fde_active(struct messaging_ctdb_fde *fde)
 	flags = tevent_fd_get_flags(fde->fde);
 	return (flags != 0);
 }
+
+struct ctdbd_connection *messaging_ctdb_connection(void)
+{
+	if (global_ctdb_context == NULL) {
+		smb_panic("messaging not initialized\n");
+	}
+	return global_ctdb_context->conn;
+}
diff --git a/source3/lib/messages_ctdb.h b/source3/lib/messages_ctdb.h
index 006821b..9d56343 100644
--- a/source3/lib/messages_ctdb.h
+++ b/source3/lib/messages_ctdb.h
@@ -39,4 +39,6 @@ struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
 	TALLOC_CTX *mem_ctx, struct tevent_context *ev);
 bool messaging_ctdb_fde_active(struct messaging_ctdb_fde *fde);
 
+struct ctdbd_connection *messaging_ctdb_connection(void);
+
 #endif
-- 
2.1.4


From 1d8de56b4fd79306bf28d55231785999708d6498 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 5 Jul 2017 19:20:09 +0200
Subject: [PATCH 38/41] messaging: Use messaging_ctdb_ref()

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/messages.c | 83 ++++++++++++++++++++------------------------------
 1 file changed, 33 insertions(+), 50 deletions(-)

diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index 4e838b0..765add9 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -53,11 +53,13 @@
 #include "lib/util/tevent_unix.h"
 #include "lib/background.h"
 #include "lib/messages_dgm.h"
-#include "lib/messages_ctdbd.h"
 #include "lib/util/iov_buf.h"
 #include "lib/util/server_id_db.h"
 #include "lib/messages_dgm_ref.h"
+#include "lib/messages_ctdb.h"
+#include "lib/messages_ctdb_ref.h"
 #include "lib/messages_util.h"
+#include "cluster_support.h"
 
 struct messaging_callback {
 	struct messaging_callback *prev, *next;
@@ -90,8 +92,7 @@ struct messaging_context {
 	size_t num_waiters;
 
 	void *msg_dgm_ref;
-	struct messaging_backend *remote;
-	struct messaging_ctdbd_fde *cluster_fde;
+	void *msg_ctdb_ref;
 
 	struct server_id_db *names_db;
 };
@@ -513,23 +514,16 @@ static NTSTATUS messaging_init_internal(TALLOC_CTX *mem_ctx,
 	talloc_set_destructor(ctx, messaging_context_destructor);
 
 	if (lp_clustering()) {
-		ret = messaging_ctdbd_init(
-			ctx, ctx, messaging_recv_cb, ctx, &ctx->remote);
-
-		if (ret != 0) {
-			DEBUG(2, ("messaging_ctdbd_init failed: %s\n",
-				  strerror(ret)));
+		ctx->msg_ctdb_ref = messaging_ctdb_ref(
+			ctx, ctx->event_ctx,
+			lp_ctdbd_socket(), lp_ctdb_timeout(),
+			ctx->id.unique_id, messaging_recv_cb, ctx, &ret);
+		if (ctx->msg_ctdb_ref == NULL) {
+			DBG_NOTICE("messaging_ctdb_ref failed: %s\n",
+				   strerror(ret));
 			status = map_nt_error_from_unix(ret);
 			goto done;
 		}
-		ctx->cluster_fde = messaging_ctdbd_register_tevent_context(
-			ctx, ctx->event_ctx, ctx->remote);
-		if (ctx->cluster_fde == NULL) {
-			DBG_WARNING("messaging_ctdbd_register_tevent_context "
-				    "failed\n");
-			status = NT_STATUS_NO_MEMORY;
-			goto done;
-		}
 	}
 	ctx->id.vnn = get_my_vnn();
 
@@ -605,6 +599,7 @@ NTSTATUS messaging_reinit(struct messaging_context *msg_ctx)
 	char *lck_path;
 
 	TALLOC_FREE(msg_ctx->msg_dgm_ref);
+	TALLOC_FREE(msg_ctx->msg_ctdb_ref);
 
 	msg_ctx->id = (struct server_id) {
 		.pid = getpid(), .vnn = msg_ctx->id.vnn
@@ -626,25 +621,16 @@ NTSTATUS messaging_reinit(struct messaging_context *msg_ctx)
 	}
 
 	if (lp_clustering()) {
-		TALLOC_FREE(msg_ctx->cluster_fde);
-
-		ret = messaging_ctdbd_reinit(
-			msg_ctx, msg_ctx, messaging_recv_cb, msg_ctx,
-			msg_ctx->remote);
-
-		if (ret != 0) {
-			DEBUG(1, ("messaging_ctdbd_init failed: %s\n",
-				  strerror(ret)));
+		msg_ctx->msg_ctdb_ref = messaging_ctdb_ref(
+			msg_ctx, msg_ctx->event_ctx,
+			lp_ctdbd_socket(), lp_ctdb_timeout(),
+			msg_ctx->id.unique_id, messaging_recv_cb, msg_ctx,
+			&ret);
+		if (msg_ctx->msg_ctdb_ref == NULL) {
+			DBG_NOTICE("messaging_ctdb_ref failed: %s\n",
+				   strerror(ret));
 			return map_nt_error_from_unix(ret);
 		}
-
-		msg_ctx->cluster_fde = messaging_ctdbd_register_tevent_context(
-			msg_ctx, msg_ctx->event_ctx, msg_ctx->remote);
-		if (msg_ctx->cluster_fde == NULL) {
-			DBG_WARNING("messaging_ctdbd_register_tevent_context "
-				    "failed\n");
-			return NT_STATUS_NO_MEMORY;
-		}
 	}
 
 	server_id_db_reinit(msg_ctx->names_db, msg_ctx->id);
@@ -793,18 +779,6 @@ int messaging_send_iov_from(struct messaging_context *msg_ctx,
 		return EINVAL;
 	}
 
-	if (dst.vnn != msg_ctx->id.vnn) {
-		if (num_fds > 0) {
-			return ENOSYS;
-		}
-
-		ret = msg_ctx->remote->send_fn(src, dst,
-					       msg_type, iov, iovlen,
-					       NULL, 0,
-					       msg_ctx->remote);
-		return ret;
-	}
-
 	if (server_id_equal(&dst, &msg_ctx->id)) {
 		ret = messaging_post_self(msg_ctx, src, dst, msg_type,
 					  iov, iovlen, fds, num_fds);
@@ -815,6 +789,15 @@ int messaging_send_iov_from(struct messaging_context *msg_ctx,
 	iov2[0] = (struct iovec){ .iov_base = hdr, .iov_len = sizeof(hdr) };
 	memcpy(&iov2[1], iov, iovlen * sizeof(*iov));
 
+	if (dst.vnn != msg_ctx->id.vnn) {
+		if (num_fds > 0) {
+			return ENOSYS;
+		}
+
+		ret = messaging_ctdb_send(dst.vnn, dst.pid, iov2, iovlen+1);
+		return ret;
+	}
+
 	ret = messaging_dgm_send(dst.pid, iov2, iovlen+1, fds, num_fds);
 
 	if (ret == EACCES) {
@@ -890,7 +873,7 @@ struct messaging_filtered_read_state {
 	struct tevent_context *ev;
 	struct messaging_context *msg_ctx;
 	struct messaging_dgm_fde *fde;
-	struct messaging_ctdbd_fde *cluster_fde;
+	struct messaging_ctdb_fde *cluster_fde;
 
 	bool (*filter)(struct messaging_rec *rec, void *private_data);
 	void *private_data;
@@ -933,9 +916,9 @@ struct tevent_req *messaging_filtered_read_send(
 		return tevent_req_post(req, ev);
 	}
 
-	if (msg_ctx->remote != NULL) {
-		state->cluster_fde = messaging_ctdbd_register_tevent_context(
-			state, ev, msg_ctx->remote);
+	if (lp_clustering()) {
+		state->cluster_fde =
+			messaging_ctdb_register_tevent_context(state, ev);
 		if (tevent_req_nomem(state->cluster_fde, req)) {
 			return tevent_req_post(req, ev);
 		}
-- 
2.1.4


From 815850ea501f04901767797b33bc764d1650e686 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 16 Jun 2017 13:00:59 +0200
Subject: [PATCH 39/41] ctdb_conn: Use messaging_ctdb_connection

Replace messaging_ctdbd_connection

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/ctdb_dummy.c           |  2 +-
 source3/lib/dbwrap/dbwrap_ctdb.c   | 16 ++++++++--------
 source3/lib/dbwrap/dbwrap_open.c   |  4 ++--
 source3/lib/serverid.c             |  6 +++---
 source3/smbd/notifyd/notifydd.c    |  4 ++--
 source3/smbd/process.c             |  4 ++--
 source3/smbd/server.c              |  6 +++---
 source3/torture/test_dbwrap_ctdb.c |  2 +-
 source3/wscript_build              |  1 -
 9 files changed, 22 insertions(+), 23 deletions(-)

diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
index 891e7c3..f301c1f 100644
--- a/source3/lib/ctdb_dummy.c
+++ b/source3/lib/ctdb_dummy.c
@@ -135,7 +135,7 @@ struct messaging_ctdbd_fde *messaging_ctdbd_register_tevent_context(
 	return NULL;
 }
 
-struct ctdbd_connection *messaging_ctdbd_connection(void)
+struct ctdbd_connection *messaging_ctdb_connection(void)
 {
 	return NULL;
 }
diff --git a/source3/lib/dbwrap/dbwrap_ctdb.c b/source3/lib/dbwrap/dbwrap_ctdb.c
index 2cee058..3dba85d 100644
--- a/source3/lib/dbwrap/dbwrap_ctdb.c
+++ b/source3/lib/dbwrap/dbwrap_ctdb.c
@@ -34,7 +34,7 @@
 #include "dbwrap/dbwrap_ctdb.h"
 #include "g_lock.h"
 #include "messages.h"
-#include "messages_ctdbd.h"
+#include "messages_ctdb.h"
 #include "lib/cluster_support.h"
 #include "lib/util/tevent_ntstatus.h"
 
@@ -821,7 +821,7 @@ static int db_ctdb_transaction_commit(struct db_context *db)
 
 again:
 	/* tell ctdbd to commit to the other nodes */
-	ret = ctdbd_control_local(messaging_ctdbd_connection(),
+	ret = ctdbd_control_local(messaging_ctdb_connection(),
 				  CTDB_CONTROL_TRANS3_COMMIT,
 				  h->ctx->db_id, 0,
 				  db_ctdb_marshall_finish(h->m_write),
@@ -938,7 +938,7 @@ static NTSTATUS db_ctdb_send_schedule_for_deletion(struct db_record *rec)
 	dd->keylen = rec->key.dsize;
 	memcpy(dd->key, rec->key.dptr, rec->key.dsize);
 
-	ret = ctdbd_control_local(messaging_ctdbd_connection(),
+	ret = ctdbd_control_local(messaging_ctdb_connection(),
 				  CTDB_CONTROL_SCHEDULE_FOR_DELETION,
 				  crec->ctdb_ctx->db_id,
 				  CTDB_CTRL_FLAG_NOREPLY, /* flags */
@@ -1176,7 +1176,7 @@ again:
 			   ((struct ctdb_ltdb_header *)ctdb_data.dptr)->flags : 0));
 
 		GetTimeOfDay(&ctdb_start_time);
-		ret = ctdbd_migrate(messaging_ctdbd_connection(), ctx->db_id,
+		ret = ctdbd_migrate(messaging_ctdb_connection(), ctx->db_id,
 				    key);
 		ctdb_time += timeval_elapsed(&ctdb_start_time);
 
@@ -1405,7 +1405,7 @@ static NTSTATUS db_ctdb_parse_record(struct db_context *db, TDB_DATA key,
 		return status;
 	}
 
-	ret = ctdbd_parse(messaging_ctdbd_connection(), ctx->db_id, key,
+	ret = ctdbd_parse(messaging_ctdb_connection(), ctx->db_id, key,
 			  state.ask_for_readonly_copy, parser, private_data);
 	if (ret != 0) {
 		if (ret == ENOENT) {
@@ -1826,7 +1826,7 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 	db_ctdb->transaction = NULL;
 	db_ctdb->db = result;
 
-	ret = ctdbd_db_attach(messaging_ctdbd_connection(), name,
+	ret = ctdbd_db_attach(messaging_ctdb_connection(), name,
 			      &db_ctdb->db_id, tdb_flags);
 	if (ret != 0) {
 		DEBUG(0, ("ctdbd_db_attach failed for %s: %s\n", name,
@@ -1835,7 +1835,7 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 		return NULL;
 	}
 
-	db_path = ctdbd_dbpath(messaging_ctdbd_connection(), db_ctdb,
+	db_path = ctdbd_dbpath(messaging_ctdb_connection(), db_ctdb,
 			       db_ctdb->db_id);
 
 	result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
@@ -1863,7 +1863,7 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 				       sizeof(db_ctdb->db_id));
 
 		ret = ctdbd_control_local(
-			messaging_ctdbd_connection(),
+			messaging_ctdb_connection(),
 			CTDB_CONTROL_SET_DB_READONLY, 0, 0,
 			indata, NULL, NULL, &cstatus);
 		if ((ret != 0) || (cstatus != 0)) {
diff --git a/source3/lib/dbwrap/dbwrap_open.c b/source3/lib/dbwrap/dbwrap_open.c
index dfb87e1..64627d1 100644
--- a/source3/lib/dbwrap/dbwrap_open.c
+++ b/source3/lib/dbwrap/dbwrap_open.c
@@ -26,7 +26,7 @@
 #include "dbwrap/dbwrap_ctdb.h"
 #include "lib/param/param.h"
 #include "lib/cluster_support.h"
-#include "lib/messages_ctdbd.h"
+#include "lib/messages_ctdb.h"
 #include "util_tdb.h"
 #include "ctdbd_conn.h"
 #include "messages.h"
@@ -148,7 +148,7 @@ struct db_context *db_open(TALLOC_CTX *mem_ctx,
 			struct messaging_context *msg_ctx;
 			struct ctdbd_connection *conn;
 
-			conn = messaging_ctdbd_connection();
+			conn = messaging_ctdb_connection();
 			if (conn == NULL) {
 				DBG_WARNING("No ctdb connection\n");
 				errno = EIO;
diff --git a/source3/lib/serverid.c b/source3/lib/serverid.c
index fb32526..ca4bb27 100644
--- a/source3/lib/serverid.c
+++ b/source3/lib/serverid.c
@@ -28,7 +28,7 @@
 #include "lib/param/param.h"
 #include "ctdbd_conn.h"
 #include "messages.h"
-#include "lib/messages_ctdbd.h"
+#include "lib/messages_ctdb.h"
 #include "lib/messages_dgm.h"
 
 struct serverid_key {
@@ -124,7 +124,7 @@ bool serverid_register(const struct server_id id, uint32_t msg_flags)
 	}
 
 	if (lp_clustering()) {
-		register_with_ctdbd(messaging_ctdbd_connection(), id.unique_id,
+		register_with_ctdbd(messaging_ctdb_connection(), id.unique_id,
 				    NULL, NULL);
 	}
 
@@ -198,7 +198,7 @@ bool serverid_exists(const struct server_id *id)
 	}
 
 	if (lp_clustering()) {
-		return ctdbd_process_exists(messaging_ctdbd_connection(),
+		return ctdbd_process_exists(messaging_ctdb_connection(),
 					    id->vnn, id->pid);
 	}
 
diff --git a/source3/smbd/notifyd/notifydd.c b/source3/smbd/notifyd/notifydd.c
index ad3621a..faad4e7 100644
--- a/source3/smbd/notifyd/notifydd.c
+++ b/source3/smbd/notifyd/notifydd.c
@@ -19,7 +19,7 @@
 
 #include "replace.h"
 #include "notifyd.h"
-#include "lib/messages_ctdbd.h"
+#include "lib/messages_ctdb.h"
 #include <tevent.h>
 #include "lib/util/tevent_unix.h"
 
@@ -59,7 +59,7 @@ int main(int argc, const char *argv[])
 		return 1;
 	}
 
-	req = notifyd_send(ev, ev, msg, messaging_ctdbd_connection(),
+	req = notifyd_send(ev, ev, msg, messaging_ctdb_connection(),
 			   NULL, NULL);
 	if (req == NULL) {
 		fprintf(stderr, "notifyd_send failed\n");
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 4abaf37..7dc9b34 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -32,7 +32,7 @@
 #include "passdb.h"
 #include "auth.h"
 #include "messages.h"
-#include "lib/messages_ctdbd.h"
+#include "lib/messages_ctdb.h"
 #include "smbprofile.h"
 #include "rpc_server/spoolss/srv_spoolss_nt.h"
 #include "libsmb/libsmb.h"
@@ -2775,7 +2775,7 @@ static NTSTATUS smbd_register_ips(struct smbXsrv_connection *xconn,
 	struct ctdbd_connection *cconn;
 	int ret;
 
-	cconn = messaging_ctdbd_connection();
+	cconn = messaging_ctdb_connection();
 	if (cconn == NULL) {
 		return NT_STATUS_NO_MEMORY;
 	}
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 91fa1c3..f87bb0d 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -40,7 +40,7 @@
 #include "passdb.h"
 #include "auth.h"
 #include "messages.h"
-#include "messages_ctdbd.h"
+#include "messages_ctdb.h"
 #include "smbprofile.h"
 #include "lib/id_cache.h"
 #include "lib/param/param.h"
@@ -361,7 +361,7 @@ static struct tevent_req *notifyd_req(struct messaging_context *msg_ctx,
 	}
 
 	if (lp_clustering()) {
-		ctdbd_conn = messaging_ctdbd_connection();
+		ctdbd_conn = messaging_ctdb_connection();
 	}
 
 	req = notifyd_send(msg_ctx, ev, msg_ctx, ctdbd_conn,
@@ -1296,7 +1296,7 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
 
 #ifdef CLUSTER_SUPPORT
 	if (lp_clustering()) {
-		struct ctdbd_connection *conn = messaging_ctdbd_connection();
+		struct ctdbd_connection *conn = messaging_ctdb_connection();
 
 		register_with_ctdbd(conn, CTDB_SRVID_RECONFIGURE,
 				    smbd_parent_ctdb_reconfigured, msg_ctx);
diff --git a/source3/torture/test_dbwrap_ctdb.c b/source3/torture/test_dbwrap_ctdb.c
index cc6fd0c..1da5c94 100644
--- a/source3/torture/test_dbwrap_ctdb.c
+++ b/source3/torture/test_dbwrap_ctdb.c
@@ -23,7 +23,7 @@
 #include "lib/dbwrap/dbwrap.h"
 #include "lib/dbwrap/dbwrap_ctdb.h"
 #include "messages.h"
-#include "lib/messages_ctdbd.h"
+#include "lib/messages_ctdb.h"
 
 bool run_local_dbwrap_ctdb(int dummy)
 {
diff --git a/source3/wscript_build b/source3/wscript_build
index cffcca3..3f62bc2 100644
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -330,7 +330,6 @@ if bld.env.with_ctdb:
     SAMBA_CLUSTER_SUPPORT_SOURCES='''
                      lib/cluster_support.c
                      lib/dbwrap/dbwrap_ctdb.c
-                     lib/messages_ctdbd.c
                      lib/messages_ctdb.c
                      lib/messages_ctdb_ref.c
                      lib/ctdbd_conn.c
-- 
2.1.4


From 448620755d1fc43864242cdf2aa0853614d4e764 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 5 Jul 2017 19:24:32 +0200
Subject: [PATCH 40/41] messaging: Remove messages_ctdbd.c

Replaced by messages_ctdb.[ch]

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/lib/ctdb_dummy.c     |  32 ----
 source3/lib/messages_ctdbd.c | 354 -------------------------------------------
 source3/lib/messages_ctdbd.h |  53 -------
 3 files changed, 439 deletions(-)
 delete mode 100644 source3/lib/messages_ctdbd.c
 delete mode 100644 source3/lib/messages_ctdbd.h

diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
index f301c1f..8a06b0c 100644
--- a/source3/lib/ctdb_dummy.c
+++ b/source3/lib/ctdb_dummy.c
@@ -19,7 +19,6 @@
 
 #include "includes.h"
 #include "messages.h"
-#include "lib/messages_ctdbd.h"
 #include "lib/messages_ctdb.h"
 #include "lib/messages_ctdb_ref.h"
 #include "ctdbd_conn.h"
@@ -80,18 +79,6 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 	return NULL;
 }
 
-int messaging_ctdbd_init(struct messaging_context *msg_ctx,
-			 TALLOC_CTX *mem_ctx,
-			 void (*recv_cb)(struct tevent_context *ev,
-					 const uint8_t *msg, size_t msg_len,
-					 int *fds, size_t num_fds,
-					 void *private_data),
-			 void *private_data,
-			      struct messaging_backend **presult)
-{
-	return ENOSYS;
-}
-
 int messaging_ctdb_send(uint32_t dst_vnn, uint64_t dst_srvid,
 			const struct iovec *iov, int iovlen)
 {
@@ -116,25 +103,6 @@ struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
 	return NULL;
 }
 
-int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
-			   TALLOC_CTX *mem_ctx,
-			   void (*recv_cb)(struct tevent_context *ev,
-					   const uint8_t *msg, size_t msg_len,
-					   int *fds, size_t num_fds,
-					   void *private_data),
-			   void *private_data,
-			   struct messaging_backend *backend)
-{
-	return ENOSYS;
-}
-
-struct messaging_ctdbd_fde *messaging_ctdbd_register_tevent_context(
-	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
-	struct messaging_backend *backend)
-{
-	return NULL;
-}
-
 struct ctdbd_connection *messaging_ctdb_connection(void)
 {
 	return NULL;
diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c
deleted file mode 100644
index b1af4f8..0000000
--- a/source3/lib/messages_ctdbd.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-   Samba internal messaging functions
-   Copyright (C) 2007 by Volker Lendecke
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "lib/messages_ctdbd.h"
-#include "lib/util/server_id.h"
-#include "messages.h"
-#include "util_tdb.h"
-#include "lib/util/iov_buf.h"
-#include "lib/messages_util.h"
-#include "ctdbd_conn.h"
-#include "lib/cluster_support.h"
-
-struct messaging_ctdbd_context;
-
-struct messaging_ctdbd_fde_ev {
-	struct messaging_ctdbd_fde_ev *prev, *next;
-
-	/*
-	 * Backreference to enable DLIST_REMOVE from our
-	 * destructor. Also, set to NULL when the dgm_context dies
-	 * before the messaging_dgm_fde_ev.
-	 */
-	struct messaging_ctdbd_context *ctx;
-
-	struct tevent_context *ev;
-	struct tevent_fd *fde;
-};
-
-struct messaging_ctdbd_context {
-	struct ctdbd_connection *conn;
-
-	struct messaging_ctdbd_fde_ev *fde_evs;
-
-	void (*recv_cb)(struct tevent_context *ev,
-			const uint8_t *msg, size_t msg_len,
-			int *fds, size_t num_fds,
-			void *private_data);
-	void *private_data;
-};
-
-/*
- * This is a Samba3 hack/optimization. Routines like process_exists need to
- * talk to ctdbd, and they don't get handed a messaging context.
- */
-static struct ctdbd_connection *global_ctdbd_connection;
-static int global_ctdb_connection_pid;
-
-struct ctdbd_connection *messaging_ctdbd_connection(void)
-{
-	if (!lp_clustering()) {
-		return NULL;
-	}
-
-	if (global_ctdb_connection_pid == 0 &&
-	    global_ctdbd_connection == NULL) {
-		struct tevent_context *ev;
-		struct messaging_context *msg;
-
-		ev = samba_tevent_context_init(NULL);
-		if (!ev) {
-			DEBUG(0,("samba_tevent_context_init failed\n"));
-			return NULL;
-		}
-
-		msg = messaging_init(NULL, ev);
-		if (!msg) {
-			DEBUG(0,("messaging_init failed\n"));
-			return NULL;
-		}
-	}
-
-	if (global_ctdb_connection_pid != getpid()) {
-		DEBUG(0,("messaging_ctdbd_connection():"
-			 "valid for pid[%jd] but it's [%jd]\n",
-			 (intmax_t)global_ctdb_connection_pid,
-			 (intmax_t)getpid()));
-		smb_panic("messaging_ctdbd_connection() invalid process\n");
-	}
-
-	return global_ctdbd_connection;
-}
-
-static int messaging_ctdb_send(struct server_id src,
-			       struct server_id pid, int msg_type,
-			       const struct iovec *iov, int iovlen,
-			       const int *fds, size_t num_fds,
-			       struct messaging_backend *backend)
-{
-	struct messaging_ctdbd_context *ctx = talloc_get_type_abort(
-		backend->private_data, struct messaging_ctdbd_context);
-	uint8_t hdr[MESSAGE_HDR_LENGTH];
-	struct iovec iov2[iovlen+1];
-
-	if (num_fds > 0) {
-		return ENOSYS;
-	}
-
-	message_hdr_put(hdr, msg_type, src, pid);
-	iov2[0] = (struct iovec){ .iov_base = hdr, .iov_len = sizeof(hdr) };
-	memcpy(&iov2[1], iov, iovlen * sizeof(*iov));
-
-	return ctdbd_messaging_send_iov(ctx->conn, pid.vnn, pid.pid,
-					iov2, iovlen+1);
-}
-
-static int messaging_ctdbd_destructor(struct messaging_ctdbd_context *ctx)
-{
-	/*
-	 * The global connection just went away
-	 */
-	global_ctdb_connection_pid = 0;
-	global_ctdbd_connection = NULL;
-	return 0;
-}
-
-static int messaging_ctdb_recv(
-	struct tevent_context *ev,
-	uint32_t src_vnn, uint32_t dst_vnn, uint64_t dst_srvid,
-	const uint8_t *msg, size_t msg_len, void *private_data)
-{
-	struct messaging_ctdbd_context *ctx = talloc_get_type_abort(
-		private_data, struct messaging_ctdbd_context);
-
-	ctx->recv_cb(ev, msg, msg_len, NULL, 0, ctx->private_data);
-
-	return 0;
-}
-
-static void messaging_ctdbd_readable(struct tevent_context *ev,
-				     struct tevent_fd *fde,
-				     uint16_t flags,
-				     void *private_data)
-{
-	struct ctdbd_connection *conn = talloc_get_type_abort(
-		private_data, struct ctdbd_connection);
-
-	if ((flags & TEVENT_FD_READ) == 0) {
-		return;
-	}
-	ctdbd_socket_readable(ev, conn);
-}
-
-static int messaging_ctdbd_init_internal(
-	struct messaging_context *msg_ctx, TALLOC_CTX *mem_ctx,
-	struct messaging_ctdbd_context *ctx,
-	void (*recv_cb)(struct tevent_context *ev,
-			const uint8_t *msg, size_t msg_len,
-			int *fds, size_t num_fds,
-			void *private_data),
-	void *private_data,
-	bool reinit)
-{
-	int ret;
-
-	if (reinit) {
-		ret = ctdbd_reinit_connection(ctx,
-					      lp_ctdbd_socket(),
-					      lp_ctdb_timeout(),
-					      ctx->conn);
-		if (ret != 0) {
-			DBG_ERR("ctdbd_reinit_connection failed: %s\n",
-				strerror(ret));
-			return ret;
-		}
-	} else {
-		ret = ctdbd_init_connection(ctx,
-					    lp_ctdbd_socket(),
-					    lp_ctdb_timeout(),
-					    &ctx->conn);
-		if (ret != 0) {
-			DBG_ERR("ctdbd_init_connection failed: %s\n",
-				strerror(ret));
-			return ret;
-		}
-	}
-
-	ret = register_with_ctdbd(ctx->conn, MSG_SRVID_SAMBA, NULL, NULL);
-	if (ret != 0) {
-		DBG_DEBUG("Could not register MSG_SRVID_SAMBA: %s\n",
-			  strerror(ret));
-		return ret;
-	}
-
-	ctx->recv_cb = recv_cb;
-	ctx->private_data = private_data;
-
-	ret = register_with_ctdbd(ctx->conn, getpid(),
-				  messaging_ctdb_recv, ctx);
-	if (ret != 0) {
-		DEBUG(10, ("register_with_ctdbd failed: %s\n",
-			   strerror(ret)));
-		return ret;
-	}
-
-	global_ctdb_connection_pid = getpid();
-	global_ctdbd_connection = ctx->conn;
-	talloc_set_destructor(ctx, messaging_ctdbd_destructor);
-
-	set_my_vnn(ctdbd_vnn(ctx->conn));
-
-	return 0;
-}
-
-int messaging_ctdbd_init(struct messaging_context *msg_ctx,
-			 TALLOC_CTX *mem_ctx,
-			 void (*recv_cb)(struct tevent_context *ev,
-					 const uint8_t *msg, size_t msg_len,
-					 int *fds, size_t num_fds,
-					 void *private_data),
-			 void *private_data,
-			 struct messaging_backend **presult)
-{
-	struct messaging_backend *result;
-	struct messaging_ctdbd_context *ctx;
-	int ret;
-
-	if (!(result = talloc(mem_ctx, struct messaging_backend))) {
-		DEBUG(0, ("talloc failed\n"));
-		return ENOMEM;
-	}
-
-	if (!(ctx = talloc_zero(result, struct messaging_ctdbd_context))) {
-		DEBUG(0, ("talloc failed\n"));
-		TALLOC_FREE(result);
-		return ENOMEM;
-	}
-
-	ret = messaging_ctdbd_init_internal(msg_ctx, mem_ctx, ctx,
-					    recv_cb, private_data, false);
-	if (ret != 0) {
-		TALLOC_FREE(result);
-		return ret;
-	}
-
-	result->send_fn = messaging_ctdb_send;
-	result->private_data = (void *)ctx;
-
-	*presult = result;
-	return 0;
-}
-
-int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
-			   TALLOC_CTX *mem_ctx,
-			   void (*recv_cb)(struct tevent_context *ev,
-					   const uint8_t *msg, size_t msg_len,
-					   int *fds, size_t num_fds,
-					   void *private_data),
-			   void *private_data,
-			   struct messaging_backend *backend)
-{
-	struct messaging_ctdbd_context *ctx = talloc_get_type_abort(
-		backend->private_data, struct messaging_ctdbd_context);
-	int ret;
-
-	ret = messaging_ctdbd_init_internal(msg_ctx, mem_ctx, ctx,
-					    recv_cb, private_data, true);
-	if (ret != 0) {
-		return ret;
-	}
-
-	return 0;
-}
-
-struct messaging_ctdbd_fde {
-	struct tevent_fd *fde;
-};
-
-static int messaging_ctdbd_fde_ev_destructor(
-	struct messaging_ctdbd_fde_ev *fde_ev)
-{
-	if (fde_ev->ctx != NULL) {
-		DLIST_REMOVE(fde_ev->ctx->fde_evs, fde_ev);
-		fde_ev->ctx = NULL;
-	}
-	return 0;
-}
-
-struct messaging_ctdbd_fde *messaging_ctdbd_register_tevent_context(
-	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
-	struct messaging_backend *backend)
-{
-	struct messaging_ctdbd_context *ctx = talloc_get_type_abort(
-		backend->private_data, struct messaging_ctdbd_context);
-	struct messaging_ctdbd_fde_ev *fde_ev;
-	struct messaging_ctdbd_fde *fde;
-
-	if (ctx == NULL) {
-		return NULL;
-	}
-
-	fde = talloc(mem_ctx, struct messaging_ctdbd_fde);
-	if (fde == NULL) {
-		return NULL;
-	}
-
-	for (fde_ev = ctx->fde_evs; fde_ev != NULL; fde_ev = fde_ev->next) {
-		if ((fde_ev->ev == ev) &&
-		    (tevent_fd_get_flags(fde_ev->fde) != 0)) {
-			break;
-		}
-	}
-
-	if (fde_ev == NULL) {
-		int fd = ctdbd_conn_get_fd(ctx->conn);
-
-		fde_ev = talloc(fde, struct messaging_ctdbd_fde_ev);
-		if (fde_ev == NULL) {
-			return NULL;
-		}
-		fde_ev->fde = tevent_add_fd(
-			ev, fde_ev, fd, TEVENT_FD_READ,
-			messaging_ctdbd_readable, ctx->conn);
-		if (fde_ev->fde == NULL) {
-			TALLOC_FREE(fde);
-			return NULL;
-		}
-		fde_ev->ev = ev;
-		fde_ev->ctx = ctx;
-		DLIST_ADD(ctx->fde_evs, fde_ev);
-		talloc_set_destructor(
-			fde_ev, messaging_ctdbd_fde_ev_destructor);
-	} else {
-		/*
-		 * Same trick as with tdb_wrap: The caller will never
-		 * see the talloc_referenced object, the
-		 * messaging_ctdbd_fde_ev, so problems with
-		 * talloc_unlink will not happen.
-		 */
-		if (talloc_reference(fde, fde_ev) == NULL) {
-			TALLOC_FREE(fde);
-			return NULL;
-		}
-	}
-
-	fde->fde = fde_ev->fde;
-	return fde;
-}
diff --git a/source3/lib/messages_ctdbd.h b/source3/lib/messages_ctdbd.h
deleted file mode 100644
index 7d928fe..0000000
--- a/source3/lib/messages_ctdbd.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Unix SMB/CIFS implementation.
- * messages_ctdb.c header
- * Copyright (C) Volker Lendecke 2017
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef _MESSAGES_CTDB_H_
-#define _MESSAGES_CTDB_H_
-
-#include "replace.h"
-#include <talloc.h>
-
-struct messaging_context;
-struct messaging_backend;
-struct ctdbd_connection;
-
-int messaging_ctdbd_init(struct messaging_context *msg_ctx,
-			 TALLOC_CTX *mem_ctx,
-			 void (*recv_cb)(struct tevent_context *ev,
-					 const uint8_t *msg, size_t msg_len,
-					 int *fds, size_t num_fds,
-					 void *private_data),
-			 void *private_data,
-			 struct messaging_backend **presult);
-int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
-			   TALLOC_CTX *mem_ctx,
-			   void (*recv_cb)(struct tevent_context *ev,
-					   const uint8_t *msg, size_t msg_len,
-					   int *fds, size_t num_fds,
-					   void *private_data),
-			   void *private_data,
-			   struct messaging_backend *backend);
-struct ctdbd_connection *messaging_ctdbd_connection(void);
-
-struct messaging_ctdbd_fde;
-struct messaging_ctdbd_fde *messaging_ctdbd_register_tevent_context(
-	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
-	struct messaging_backend *backend);
-
-#endif
-- 
2.1.4


From 889967a52fc6727e1b6528eb6b37b40c8a713d63 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 5 Jul 2017 19:26:22 +0200
Subject: [PATCH 41/41] messaging: Remove "struct messaging_backend"

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/include/messages.h | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/source3/include/messages.h b/source3/include/messages.h
index 970dc38..8d3b1d8 100644
--- a/source3/include/messages.h
+++ b/source3/include/messages.h
@@ -56,15 +56,6 @@
 struct messaging_context;
 struct messaging_rec;
 
-struct messaging_backend {
-	int (*send_fn)(struct server_id src,
-		       struct server_id pid, int msg_type,
-		       const struct iovec *iov, int iovlen,
-		       const int *fds, size_t num_fds,
-		       struct messaging_backend *backend);
-	void *private_data;
-};
-
 struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, 
 					 struct tevent_context *ev);
 NTSTATUS messaging_init_client(TALLOC_CTX *mem_ctx,
-- 
2.1.4



More information about the samba-technical mailing list