[PATCH] g_lock_ping_pong

Volker Lendecke Volker.Lendecke at SerNet.DE
Sat Jul 15 06:06:29 UTC 2017


On Fri, Jul 14, 2017 at 02:39:38PM +0200, Ralph Böhme via samba-technical wrote:
> > nah, I'll try to swallow the big pill. :)
> 
> doesn't apply to master, can you check?

The attached patchset survived a private autobuild against master as
of Friday around noon, and rebases properly on current master.

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 5d92ae944ffaa5f8c79ee771e5470c51db1cd0da 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}};
-- 
1.9.1


From d6201fe6ebe7a7b8d41999f6cf5b733aa4862456 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
-- 
1.9.1


From 03692cc4fc8ed1af9198bb1b3ded74c8077a72ed 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 6bdaab0..b26a2eb 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)
-- 
1.9.1


From 21c8998a2acc6ddd35d6c4b26cb4a84f6f778339 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,
-- 
1.9.1


From b19daefd07cb09193f2f4165b4b232525431dfd0 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);
-- 
1.9.1


From c5f5cd50d07f4bdaab14b72b02c5708c53007fe6 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 d352c14..59a64e8 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 1c5e4c8..7b3d383 100644
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -1195,6 +1195,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
-- 
1.9.1


From c6336602609bf3b844292514c3483f523d2ea044 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;
-- 
1.9.1


From 75f1e26ba03ad81a34c1c97ab5eebe6f733bee38 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));
-- 
1.9.1


From ea27437cc11eeb3b54897305312fc40dbab9fe33 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;
 	}
 
-- 
1.9.1


From 6f95e46b68af16ea4f11a7a1db1f57f205645729 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;
 			}
 
-- 
1.9.1


From cb316305635addd7610870328cbb455fe27586bf 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;
-- 
1.9.1


From f71749f3c525d15f1907ea7747c8527f7876c7e0 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,
-- 
1.9.1


From 9fe8805a6c9966b810f7b3496e77005876c8a03c 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,
-- 
1.9.1


From 4664ed5c170369eefa9da571ce315f6fd8e4a42c 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);
-- 
1.9.1


From 7a97b1de6ae3494f9df73d5f13ed2e80570767dd 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;
 }
 
-- 
1.9.1


From e8c767ac0e79369af7b45e128db461419e0fecce 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;
 }
 
-- 
1.9.1


From 8ed021bb37f5a6474310613b7caa8faca3662c83 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)
-- 
1.9.1


From 67680cd72938dee06faf55a5e496f37f1034de13 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);
-- 
1.9.1


From 3d5989186ac40885a4fb523b5847aabdfdf0b349 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 {
-- 
1.9.1


From 2f32d5246c697b01e16d50146dfb68c3661cca45 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;
 }
 
-- 
1.9.1


From 6bec48c2ff2a3830b165882abde8f14c608b502d 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)
-- 
1.9.1


From b7a698a1a9cc1d1391a8aac5848f97d6582ca28f 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];
-- 
1.9.1


From 65e5d79bed35d3ba1e9b192ca562ff6196454560 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;
-- 
1.9.1


From 24d8e040d612d3f54c20ebcad3ab3d0c728f502a 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
-- 
1.9.1


From 35f3faac8a6513a89ca955397f714bd5baf63020 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,
-- 
1.9.1


From ea0b7b2481f19207fded04cf596f09e9e2bf1269 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 38477d3..471a670 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 b81feca..fe4e0bc 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) {
@@ -1138,7 +1141,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 3765739..7de26f1 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 181bcd1..76c2d2a 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)
 {
-- 
1.9.1


From 440d049a10d4a78f151dbdfd3837b2d600ae40fe 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 fe4e0bc..633c5e1 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;
 }
-- 
1.9.1


From e19e36a41f2a495e19215fcf4e91b9a181d12b7c 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 633c5e1..17658f4 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);
 
-- 
1.9.1


From 963393d42816fd553855accbf95e17d49c0c8be1 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 471a670..4e7c1b0 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 17658f4..bab489e 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,
-- 
1.9.1


From 3266b2f2db5e16bd619d96f6f2393f28fc6ea4e1 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
-- 
1.9.1


From e0e2b34d26878b38ae57032c6c874fe257d86616 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);
 
-- 
1.9.1


From 01e242da3ab43b2f94b371d13449497f9ed94007 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 b26a2eb..57098f9 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;
 }
 
-- 
1.9.1


From 84eb5dcd6a68885202d1403f7ea437a4c567189b 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 7b3d383..3f3629e 100644
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -323,6 +323,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='''
-- 
1.9.1


From 9b642567f6d2bfb3480524e4f9e7a9d5aa9b7d5f 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 3f3629e..bc8c59b 100644
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -324,6 +324,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='''
-- 
1.9.1


From 672ce4d5678f3aea44bb09fe7620f2989008939e 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   | 40 +++++++++++++++++++++-----------------
 source3/lib/dbwrap/dbwrap_ctdb.h   |  1 -
 source3/lib/dbwrap/dbwrap_open.c   |  2 +-
 source3/torture/test_dbwrap_ctdb.c |  8 +-------
 5 files changed, 24 insertions(+), 28 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 57098f9..0ce63a5 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,
@@ -1827,9 +1827,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, persistent);
+	ret = ctdbd_db_attach(messaging_ctdbd_connection(), name,
+			      &db_ctdb->db_id, persistent);
 	if (ret != 0) {
 		DEBUG(0, ("ctdbd_db_attach failed for %s: %s\n", name,
 			  strerror(ret)));
@@ -1841,7 +1841,8 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 		data.dptr = (uint8_t *)&db_ctdb->db_id;
 		data.dsize = sizeof(db_ctdb->db_id);
 
-		ret = ctdbd_control_local(conn, CTDB_CONTROL_ENABLE_SEQNUM,
+		ret = ctdbd_control_local(messaging_ctdbd_connection(),
+					  CTDB_CONTROL_ENABLE_SEQNUM,
 					  0, 0, data,
 					  NULL, NULL, &cstatus);
 		if ((ret != 0) || cstatus != 0) {
@@ -1852,7 +1853,8 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	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 = persistent;
 	result->lock_order = lock_order;
@@ -1860,7 +1862,8 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 	data.dptr = (uint8_t *)&db_ctdb->db_id;
 	data.dsize = sizeof(db_ctdb->db_id);
 
-	ret = ctdbd_control_local(conn, CTDB_CONTROL_DB_OPEN_FLAGS,
+	ret = ctdbd_control_local(messaging_ctdbd_connection(),
+				  CTDB_CONTROL_DB_OPEN_FLAGS,
 				  0, 0, data, NULL, &data, &cstatus);
 	if (ret != 0) {
 		DBG_ERR(" ctdb control for db_open_flags "
@@ -1895,7 +1898,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 801ebcb..6ecf856 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) {
-- 
1.9.1


From b4421128b5c3be7d4c6ae8757ee28810d2ec5647 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. 
-- 
1.9.1


From c4b8493687df800f766610745afa862e67d7de3a 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
-- 
1.9.1


From 56dfda160b3e0e860b35cdb17f10e806547c544f 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);
 		}
-- 
1.9.1


From 6d73052853ca6d584de9e38c07d9e6d26485ff32 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   | 20 ++++++++++----------
 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, 24 insertions(+), 25 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 0ce63a5..d62e1cb 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) {
@@ -1828,7 +1828,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, persistent);
 	if (ret != 0) {
 		DEBUG(0, ("ctdbd_db_attach failed for %s: %s\n", name,
@@ -1841,7 +1841,7 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 		data.dptr = (uint8_t *)&db_ctdb->db_id;
 		data.dsize = sizeof(db_ctdb->db_id);
 
-		ret = ctdbd_control_local(messaging_ctdbd_connection(),
+		ret = ctdbd_control_local(messaging_ctdb_connection(),
 					  CTDB_CONTROL_ENABLE_SEQNUM,
 					  0, 0, data,
 					  NULL, NULL, &cstatus);
@@ -1853,7 +1853,7 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	db_path = ctdbd_dbpath(messaging_ctdbd_connection(), db_ctdb,
+	db_path = ctdbd_dbpath(messaging_ctdb_connection(), db_ctdb,
 			       db_ctdb->db_id);
 
 	result->persistent = persistent;
@@ -1862,7 +1862,7 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 	data.dptr = (uint8_t *)&db_ctdb->db_id;
 	data.dsize = sizeof(db_ctdb->db_id);
 
-	ret = ctdbd_control_local(messaging_ctdbd_connection(),
+	ret = ctdbd_control_local(messaging_ctdb_connection(),
 				  CTDB_CONTROL_DB_OPEN_FLAGS,
 				  0, 0, data, NULL, &data, &cstatus);
 	if (ret != 0) {
@@ -1898,7 +1898,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 6ecf856..a6bf30f 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 7de26f1..b65ae2c 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 76c2d2a..9167276 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,
@@ -1302,7 +1302,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 bc8c59b..4230b6a 100644
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -322,7 +322,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
-- 
1.9.1


From c0e7ababe898e081f638cfaad2c9fda77a85b1f7 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
-- 
1.9.1


From 8a35f031d2235b834e3e9d2e625ba3ee80d78360 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,
-- 
1.9.1



More information about the samba-technical mailing list