[PATCH] g_lock_ping_pong

Jeremy Allison jra at samba.org
Thu Jul 6 22:52:46 UTC 2017


On Thu, Jul 06, 2017 at 04:17:22PM +0200, Volker Lendecke via samba-technical wrote:
> Hi!
> 
> Attached find a patchset that implements a g_lock performance test
> along with some modifications for correctness and performance.
> 
> Review appreciated!

This looks great - lots of code deletion :-) :-).

Going to take a little while to go through though,
but just wanted to let you know I'm looking at it.

Cheers,

Jeremy.

> -- 
> 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

> From d3c7576c58922731e1fa1c7f17c3d0ec94d8a7fa Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Mon, 22 May 2017 21:55:11 +0200
> Subject: [PATCH 01/41] torture: Add local-g-lock-ping-pong
> 
> This is similar to the ctdb ping_pong test.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/torture/proto.h       |   1 +
>  source3/torture/test_g_lock.c | 100 ++++++++++++++++++++++++++++++++++++++++--
>  source3/torture/torture.c     |   1 +
>  3 files changed, 98 insertions(+), 4 deletions(-)
> 
> diff --git a/source3/torture/proto.h b/source3/torture/proto.h
> index 4c3e540..fc46898 100644
> --- a/source3/torture/proto.h
> +++ b/source3/torture/proto.h
> @@ -130,5 +130,6 @@ bool run_g_lock2(int dummy);
>  bool run_g_lock3(int dummy);
>  bool run_g_lock4(int dummy);
>  bool run_g_lock5(int dummy);
> +bool run_g_lock_ping_pong(int dummy);
>  
>  #endif /* __TORTURE_H__ */
> diff --git a/source3/torture/test_g_lock.c b/source3/torture/test_g_lock.c
> index ca37312..61ec69d 100644
> --- a/source3/torture/test_g_lock.c
> +++ b/source3/torture/test_g_lock.c
> @@ -30,12 +30,12 @@ static bool get_g_lock_ctx(TALLOC_CTX *mem_ctx,
>  			   struct messaging_context **msg,
>  			   struct g_lock_ctx **ctx)
>  {
> -	*ev = samba_tevent_context_init(mem_ctx);
> +	*ev = server_event_context();
>  	if (*ev == NULL) {
>  		fprintf(stderr, "tevent_context_init failed\n");
>  		return false;
>  	}
> -	*msg = messaging_init(*ev, *ev);
> +	*msg = server_messaging_context();
>  	if (*msg == NULL) {
>  		fprintf(stderr, "messaging_init failed\n");
>  		TALLOC_FREE(*ev);
> @@ -558,8 +558,8 @@ bool run_g_lock5(int dummy)
>  
>  		if (child == 0) {
>  			TALLOC_FREE(ctx);
> -			TALLOC_FREE(msg);
> -			TALLOC_FREE(ev);
> +
> +			status = reinit_after_fork(msg, ev, false, "");
>  
>  			close(ready_pipe[0]);
>  			close(exit_pipe[1]);
> @@ -642,3 +642,95 @@ bool run_g_lock5(int dummy)
>  
>  	return true;
>  }
> +
> +extern int torture_numops;
> +extern int torture_nprocs;
> +
> +static struct timeval tp1, tp2;
> +
> +static void start_timer(void)
> +{
> +	gettimeofday(&tp1,NULL);
> +}
> +
> +static double end_timer(void)
> +{
> +	gettimeofday(&tp2,NULL);
> +	return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) -
> +		(tp1.tv_sec + (tp1.tv_usec*1.0e-6));
> +}
> +
> +/*
> + * g_lock ping_pong
> + */
> +
> +bool run_g_lock_ping_pong(int dummy)
> +{
> +	struct tevent_context *ev = NULL;
> +	struct messaging_context *msg = NULL;
> +	struct g_lock_ctx *ctx = NULL;
> +	fstring name;
> +	NTSTATUS status;
> +	int i = 0;
> +	bool ret = false;
> +	bool ok;
> +	unsigned count = 0;
> +
> +	torture_nprocs = MAX(2, torture_nprocs);
> +
> +	ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
> +	if (!ok) {
> +		goto fail;
> +	}
> +
> +	start_timer();
> +
> +	snprintf(name, sizeof(name), "ping_pong_%d", i);
> +
> +	status = g_lock_lock(ctx, name, G_LOCK_WRITE,
> +			     (struct timeval) { .tv_sec = 60 });
> +	if (!NT_STATUS_IS_OK(status)) {
> +		fprintf(stderr, "g_lock_lock failed: %s\n",
> +			nt_errstr(status));
> +		goto fail;
> +	}
> +
> +	for (i=0; i<torture_numops; i++) {
> +
> +		name[10] = '0' + ((i+1) % torture_nprocs);
> +
> +		status = g_lock_lock(ctx, name, G_LOCK_WRITE,
> +				     (struct timeval) { .tv_sec = 60 });
> +		if (!NT_STATUS_IS_OK(status)) {
> +			fprintf(stderr, "g_lock_lock failed: %s\n",
> +				nt_errstr(status));
> +			goto fail;
> +		}
> +
> +		name[10] = '0' + ((i) % torture_nprocs);
> +
> +		status = g_lock_unlock(ctx, name);
> +		if (!NT_STATUS_IS_OK(status)) {
> +			fprintf(stderr, "g_lock_unlock failed: %s\n",
> +				nt_errstr(status));
> +			goto fail;
> +		}
> +
> +		count++;
> +
> +		if (end_timer() > 1.0) {
> +			printf("%8u locks/sec\r",
> +			       (unsigned)(2*count/end_timer()));
> +			fflush(stdout);
> +			start_timer();
> +			count=0;
> +		}
> +	}
> +
> +	ret = true;
> +fail:
> +	TALLOC_FREE(ctx);
> +	TALLOC_FREE(msg);
> +	TALLOC_FREE(ev);
> +	return ret;
> +}
> diff --git a/source3/torture/torture.c b/source3/torture/torture.c
> index 6959b71..64caca5 100644
> --- a/source3/torture/torture.c
> +++ b/source3/torture/torture.c
> @@ -11556,6 +11556,7 @@ static struct {
>  	{ "LOCAL-G-LOCK3", run_g_lock3, 0 },
>  	{ "LOCAL-G-LOCK4", run_g_lock4, 0 },
>  	{ "LOCAL-G-LOCK5", run_g_lock5, 0 },
> +	{ "LOCAL-G-LOCK-PING-PONG", run_g_lock_ping_pong, 0 },
>  	{ "LOCAL-CANONICALIZE-PATH", run_local_canonicalize_path, 0 },
>  	{ "qpathinfo-bufsize", run_qpathinfo_bufsize, 0 },
>  	{NULL, NULL, 0}};
> -- 
> 2.1.4
> 
> 
> From fe92b743b974d7464a03232a2db06c3df30544e0 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Mon, 12 Sep 2016 17:11:09 +0200
> Subject: [PATCH 02/41] dbwrap: Add dbwrap_merge_dbufs
> 
> Transitional code to implement dbwrap_record_storev
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  lib/dbwrap/dbwrap.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/dbwrap/dbwrap.h |  3 +++
>  2 files changed, 51 insertions(+)
> 
> diff --git a/lib/dbwrap/dbwrap.c b/lib/dbwrap/dbwrap.c
> index 025d463..1f45558 100644
> --- a/lib/dbwrap/dbwrap.c
> +++ b/lib/dbwrap/dbwrap.c
> @@ -556,3 +556,51 @@ const char *dbwrap_name(struct db_context *db)
>  {
>  	return db->name;
>  }
> +
> +static ssize_t tdb_data_buf(const TDB_DATA *dbufs, int num_dbufs,
> +			    uint8_t *buf, size_t buflen)
> +{
> +	size_t needed = 0;
> +	uint8_t *p = buf;
> +	int i;
> +
> +	for (i=0; i<num_dbufs; i++) {
> +		size_t thislen = dbufs[i].dsize;
> +		size_t tmp;
> +
> +		tmp = needed + thislen;
> +		if (tmp < needed) {
> +			/* wrap */
> +			return -1;
> +		}
> +		needed = tmp;
> +
> +		if (needed <= buflen) {
> +			memcpy(p, dbufs[i].dptr, thislen);
> +			p += thislen;
> +		}
> +	}
> +
> +	return needed;
> +}
> +
> +
> +TDB_DATA dbwrap_merge_dbufs(TALLOC_CTX *mem_ctx,
> +			    const TDB_DATA *dbufs, int num_dbufs)
> +{
> +	ssize_t len = tdb_data_buf(dbufs, num_dbufs, NULL, 0);
> +	uint8_t *buf;
> +
> +	if (len == -1) {
> +		return (TDB_DATA) {0};
> +	}
> +
> +	buf = talloc_array(mem_ctx, uint8_t, len);
> +	if (buf == NULL) {
> +		return (TDB_DATA) {0};
> +	}
> +
> +	tdb_data_buf(dbufs, num_dbufs, buf, len);
> +
> +	return (TDB_DATA) { .dptr = buf, .dsize = len };
> +}
> diff --git a/lib/dbwrap/dbwrap.h b/lib/dbwrap/dbwrap.h
> index fac65ee..e34b2ab 100644
> --- a/lib/dbwrap/dbwrap.h
> +++ b/lib/dbwrap/dbwrap.h
> @@ -216,6 +216,9 @@ NTSTATUS dbwrap_parse_marshall_buf(const uint8_t *buf, size_t buflen,
>  NTSTATUS dbwrap_unmarshall(struct db_context *db, const uint8_t *buf,
>  			   size_t buflen);
>  
> +TDB_DATA dbwrap_merge_dbufs(TALLOC_CTX *mem_ctx,
> +			    const TDB_DATA *dbufs, int num_dbufs);
> +
>  
>  /**
>   * This opens a tdb file
> -- 
> 2.1.4
> 
> 
> From 311b01fed0711e101357059e038e7641bbd0145c Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Mon, 12 Sep 2016 17:30:55 +0200
> Subject: [PATCH 03/41] dbwrap: Convert backend store to storev
> 
> Convert all implementors of dbwrap_store to a storev-style call
> by using the dbwrap_merge_dbufs call
> 
> For dbwrap_tdb, this matches tdb_storev.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  lib/dbwrap/dbwrap.c               |  2 +-
>  lib/dbwrap/dbwrap_private.h       |  3 ++-
>  lib/dbwrap/dbwrap_rbt.c           | 25 ++++++++++++++++++----
>  lib/dbwrap/dbwrap_tdb.c           | 22 ++++++++++++--------
>  source3/lib/dbwrap/dbwrap_ctdb.c  | 44 ++++++++++++++++++++++++++++++---------
>  source3/lib/dbwrap/dbwrap_watch.c | 24 +++++++++++++++------
>  6 files changed, 89 insertions(+), 31 deletions(-)
> 
> diff --git a/lib/dbwrap/dbwrap.c b/lib/dbwrap/dbwrap.c
> index 1f45558..85f2213 100644
> --- a/lib/dbwrap/dbwrap.c
> +++ b/lib/dbwrap/dbwrap.c
> @@ -86,7 +86,7 @@ NTSTATUS dbwrap_record_store(struct db_record *rec, TDB_DATA data, int flags)
>  {
>  	NTSTATUS status;
>  
> -	status = rec->store(rec, data, flags);
> +	status = rec->storev(rec, &data, 1, flags);
>  	if (!NT_STATUS_IS_OK(status)) {
>  		return status;
>  	}
> diff --git a/lib/dbwrap/dbwrap_private.h b/lib/dbwrap/dbwrap_private.h
> index 9b50ccc..2858afd 100644
> --- a/lib/dbwrap/dbwrap_private.h
> +++ b/lib/dbwrap/dbwrap_private.h
> @@ -29,7 +29,8 @@ struct tevent_req;
>  struct db_record {
>  	struct db_context *db;
>  	TDB_DATA key, value;
> -	NTSTATUS (*store)(struct db_record *rec, TDB_DATA data, int flag);
> +	NTSTATUS (*storev)(struct db_record *rec, const TDB_DATA *dbufs,
> +			   int num_dbufs, int flag);
>  	NTSTATUS (*delete_rec)(struct db_record *rec);
>  	void *private_data;
>  };
> diff --git a/lib/dbwrap/dbwrap_rbt.c b/lib/dbwrap/dbwrap_rbt.c
> index eb5ef10..d9c743b 100644
> --- a/lib/dbwrap/dbwrap_rbt.c
> +++ b/lib/dbwrap/dbwrap_rbt.c
> @@ -118,7 +118,8 @@ overflow:
>  	return -1;
>  }
>  
> -static NTSTATUS db_rbt_store(struct db_record *rec, TDB_DATA data, int flag)
> +static NTSTATUS db_rbt_storev(struct db_record *rec,
> +			      const TDB_DATA *dbufs, int num_dbufs, int flag)
>  {
>  	struct db_rbt_ctx *db_ctx = talloc_get_type_abort(
>  		rec->db->private_data, struct db_rbt_ctx);
> @@ -130,12 +131,23 @@ static NTSTATUS db_rbt_store(struct db_record *rec, TDB_DATA data, int flag)
>  	struct db_rbt_node *parent_node = NULL;
>  
>  	ssize_t reclen;
> -	TDB_DATA this_key, this_val;
> +	TDB_DATA data, this_key, this_val;
> +	void *to_free = NULL;
>  
>  	if (db_ctx->traverse_read > 0) {
>  		return NT_STATUS_MEDIA_WRITE_PROTECTED;
>  	}
>  
> +	if (num_dbufs == 1) {
> +		data = dbufs[0];
> +	} else {
> +		data = dbwrap_merge_dbufs(rec, dbufs, num_dbufs);
> +		if (data.dptr == NULL) {
> +			return NT_STATUS_NO_MEMORY;
> +		}
> +		to_free = data.dptr;
> +	}
> +
>  	if (rec_priv->node != NULL) {
>  
>  		/*
> @@ -154,17 +166,20 @@ static NTSTATUS db_rbt_store(struct db_record *rec, TDB_DATA data, int flag)
>  			 */
>  			memcpy(this_val.dptr, data.dptr, data.dsize);
>  			rec_priv->node->valuesize = data.dsize;
> +			TALLOC_FREE(to_free);
>  			return NT_STATUS_OK;
>  		}
>  	}
>  
>  	reclen = db_rbt_reclen(rec->key.dsize, data.dsize);
>  	if (reclen == -1) {
> +		TALLOC_FREE(to_free);
>  		return NT_STATUS_INSUFFICIENT_RESOURCES;
>  	}
>  
>  	node = talloc_zero_size(db_ctx, reclen);
>  	if (node == NULL) {
> +		TALLOC_FREE(to_free);
>  		return NT_STATUS_NO_MEMORY;
>  	}
>  
> @@ -232,6 +247,8 @@ static NTSTATUS db_rbt_store(struct db_record *rec, TDB_DATA data, int flag)
>  	DLIST_ADD_AFTER(db_ctx->nodes, node, parent_node);
>  	rb_insert_color(&node->rb_node, &db_ctx->tree);
>  
> +	TALLOC_FREE(to_free);
> +
>  	return NT_STATUS_OK;
>  }
>  
> @@ -350,7 +367,7 @@ static struct db_record *db_rbt_fetch_locked(struct db_context *db_ctx,
>  	rec_priv = (struct db_rbt_rec *)
>  		((char *)result + DBWRAP_RBT_ALIGN(sizeof(struct db_record)));
>  
> -	result->store = db_rbt_store;
> +	result->storev = db_rbt_storev;
>  	result->delete_rec = db_rbt_delete;
>  	result->private_data = rec_priv;
>  
> @@ -425,7 +442,7 @@ static int db_rbt_traverse_internal(struct db_context *db,
>  		ZERO_STRUCT(rec);
>  		rec.db = db;
>  		rec.private_data = &rec_priv;
> -		rec.store = db_rbt_store;
> +		rec.storev = db_rbt_storev;
>  		rec.delete_rec = db_rbt_delete;
>  		db_rbt_parse_node(rec_priv.node, &rec.key, &rec.value);
>  
> diff --git a/lib/dbwrap/dbwrap_tdb.c b/lib/dbwrap/dbwrap_tdb.c
> index e12ec44..9f8a9a6 100644
> --- a/lib/dbwrap/dbwrap_tdb.c
> +++ b/lib/dbwrap/dbwrap_tdb.c
> @@ -35,7 +35,8 @@ struct db_tdb_ctx {
>  	} id;
>  };
>  
> -static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag);
> +static NTSTATUS db_tdb_storev(struct db_record *rec,
> +			      const TDB_DATA *dbufs, int num_dbufs, int flag);
>  static NTSTATUS db_tdb_delete(struct db_record *rec);
>  
>  static void db_tdb_log_key(const char *prefix, TDB_DATA key)
> @@ -137,7 +138,7 @@ static struct db_record *db_tdb_fetch_locked_internal(
>  	talloc_set_destructor(state.result, db_tdb_record_destr);
>  
>  	state.result->private_data = ctx;
> -	state.result->store = db_tdb_store;
> +	state.result->storev = db_tdb_storev;
>  	state.result->delete_rec = db_tdb_delete;
>  
>  	DEBUG(10, ("Allocated locked data 0x%p\n", state.result));
> @@ -173,7 +174,6 @@ static struct db_record *db_tdb_try_fetch_locked(
>  	return db_tdb_fetch_locked_internal(db, mem_ctx, key);
>  }
>  
> -
>  static int db_tdb_exists(struct db_context *db, TDB_DATA key)
>  {
>  	struct db_tdb_ctx *ctx = talloc_get_type_abort(
> @@ -236,10 +236,12 @@ static NTSTATUS db_tdb_parse(struct db_context *db, TDB_DATA key,
>  	return NT_STATUS_OK;
>  }
>  
> -static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag)
> +static NTSTATUS db_tdb_storev(struct db_record *rec,
> +			      const TDB_DATA *dbufs, int num_dbufs, int flag)
>  {
>  	struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
>  						       struct db_tdb_ctx);
> +	int ret;
>  
>  	/*
>  	 * This has a bug: We need to replace rec->value for correct
> @@ -247,8 +249,8 @@ static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag)
>  	 * anymore after it was stored.
>  	 */
>  
> -	return (tdb_store(ctx->wtdb->tdb, rec->key, data, flag) == 0) ?
> -		NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
> +	ret = tdb_storev(ctx->wtdb->tdb, rec->key, dbufs, num_dbufs, flag);
> +	return (ret == 0) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
>  }
>  
>  static NTSTATUS db_tdb_delete(struct db_record *rec)
> @@ -282,7 +284,7 @@ static int db_tdb_traverse_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
>  
>  	rec.key = kbuf;
>  	rec.value = dbuf;
> -	rec.store = db_tdb_store;
> +	rec.storev = db_tdb_storev;
>  	rec.delete_rec = db_tdb_delete;
>  	rec.private_data = ctx->db->private_data;
>  	rec.db = ctx->db;
> @@ -304,7 +306,9 @@ static int db_tdb_traverse(struct db_context *db,
>  	return tdb_traverse(db_ctx->wtdb->tdb, db_tdb_traverse_func, &ctx);
>  }
>  
> -static NTSTATUS db_tdb_store_deny(struct db_record *rec, TDB_DATA data, int flag)
> +static NTSTATUS db_tdb_storev_deny(struct db_record *rec,
> +				   const TDB_DATA *dbufs, int num_dbufs,
> +				   int flag)
>  {
>  	return NT_STATUS_MEDIA_WRITE_PROTECTED;
>  }
> @@ -323,7 +327,7 @@ static int db_tdb_traverse_read_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA d
>  
>  	rec.key = kbuf;
>  	rec.value = dbuf;
> -	rec.store = db_tdb_store_deny;
> +	rec.storev = db_tdb_storev_deny;
>  	rec.delete_rec = db_tdb_delete_deny;
>  	rec.private_data = ctx->db->private_data;
>  	rec.db = ctx->db;
> diff --git a/source3/lib/dbwrap/dbwrap_ctdb.c b/source3/lib/dbwrap/dbwrap_ctdb.c
> index 8e303e6..2969183 100644
> --- a/source3/lib/dbwrap/dbwrap_ctdb.c
> +++ b/source3/lib/dbwrap/dbwrap_ctdb.c
> @@ -494,7 +494,9 @@ static bool pull_newest_from_marshall_buffer(struct ctdb_marshall_buffer *buf,
>  	return true;
>  }
>  
> -static NTSTATUS db_ctdb_store_transaction(struct db_record *rec, TDB_DATA data, int flag);
> +static NTSTATUS db_ctdb_storev_transaction(struct db_record *rec,
> +					   const TDB_DATA *dbufs, int num_dbufs,
> +					   int flag);
>  static NTSTATUS db_ctdb_delete_transaction(struct db_record *rec);
>  
>  static struct db_record *db_ctdb_fetch_locked_transaction(struct db_ctdb_ctx *ctx,
> @@ -521,7 +523,7 @@ static struct db_record *db_ctdb_fetch_locked_transaction(struct db_ctdb_ctx *ct
>  		return NULL;
>  	}
>  
> -	result->store = db_ctdb_store_transaction;
> +	result->storev = db_ctdb_storev_transaction;
>  	result->delete_rec = db_ctdb_delete_transaction;
>  
>  	if (pull_newest_from_marshall_buffer(ctx->transaction->m_write, key,
> @@ -656,13 +658,23 @@ static NTSTATUS db_ctdb_transaction_store(struct db_ctdb_transaction_handle *h,
>  /* 
>     a record store inside a transaction
>   */
> -static NTSTATUS db_ctdb_store_transaction(struct db_record *rec, TDB_DATA data, int flag)
> +static NTSTATUS db_ctdb_storev_transaction(
> +	struct db_record *rec, const TDB_DATA *dbufs, int num_dbufs, int flag)
>  {
>  	struct db_ctdb_transaction_handle *h = talloc_get_type_abort(
>  		rec->private_data, struct db_ctdb_transaction_handle);
>  	NTSTATUS status;
> +	TDB_DATA data;
> +
> +	data = dbwrap_merge_dbufs(rec, dbufs, num_dbufs);
> +	if (data.dptr == NULL) {
> +		return NT_STATUS_NO_MEMORY;
> +	}
>  
>  	status = db_ctdb_transaction_store(h, rec->key, data);
> +
> +	TALLOC_FREE(data.dptr);
> +
>  	return status;
>  }
>  
> @@ -887,12 +899,23 @@ static int db_ctdb_transaction_cancel(struct db_context *db)
>  }
>  
>  
> -static NTSTATUS db_ctdb_store(struct db_record *rec, TDB_DATA data, int flag)
> +static NTSTATUS db_ctdb_storev(struct db_record *rec,
> +			       const TDB_DATA *dbufs, int num_dbufs, int flag)
>  {
>  	struct db_ctdb_rec *crec = talloc_get_type_abort(
>  		rec->private_data, struct db_ctdb_rec);
> +	NTSTATUS status;
> +	TDB_DATA data;
> +
> +	data = dbwrap_merge_dbufs(rec, dbufs, num_dbufs);
> +	if (data.dptr == NULL) {
> +		return NT_STATUS_NO_MEMORY;
> +	}
>  
> -	return db_ctdb_ltdb_store(crec->ctdb_ctx, rec->key, &(crec->header), data);
> +	status = db_ctdb_ltdb_store(crec->ctdb_ctx, rec->key, &(crec->header),
> +				    data);
> +	TALLOC_FREE(data.dptr);
> +	return status;
>  }
>  
>  
> @@ -954,7 +977,7 @@ static NTSTATUS db_ctdb_delete(struct db_record *rec)
>  	 * tdb-level cleanup
>  	 */
>  
> -	status = db_ctdb_store(rec, tdb_null, 0);
> +	status = db_ctdb_storev(rec, &tdb_null, 1, 0);
>  	if (!NT_STATUS_IS_OK(status)) {
>  		return status;
>  	}
> @@ -1125,7 +1148,7 @@ again:
>  		return NULL;
>  	}
>  
> -	result->store = db_ctdb_store;
> +	result->storev = db_ctdb_storev;
>  	result->delete_rec = db_ctdb_delete;
>  	talloc_set_destructor(result, db_ctdb_record_destr);
>  
> @@ -1658,7 +1681,8 @@ static int db_ctdb_traverse(struct db_context *db,
>  	return state.count;
>  }
>  
> -static NTSTATUS db_ctdb_store_deny(struct db_record *rec, TDB_DATA data, int flag)
> +static NTSTATUS db_ctdb_storev_deny(struct db_record *rec,
> +				    const TDB_DATA *dbufs, int num_dbufs, int flag)
>  {
>  	return NT_STATUS_MEDIA_WRITE_PROTECTED;
>  }
> @@ -1677,7 +1701,7 @@ static void traverse_read_callback(TDB_DATA key, TDB_DATA data, void *private_da
>  	rec.db = state->db;
>  	rec.key = key;
>  	rec.value = data;
> -	rec.store = db_ctdb_store_deny;
> +	rec.storev = db_ctdb_storev_deny;
>  	rec.delete_rec = db_ctdb_delete_deny;
>  	rec.private_data = NULL;
>  	state->fn(&rec, state->private_data);
> @@ -1704,7 +1728,7 @@ static int traverse_persistent_callback_read(TDB_CONTEXT *tdb, TDB_DATA kbuf, TD
>  	rec.db = state->db;
>  	rec.key = kbuf;
>  	rec.value = dbuf;
> -	rec.store = db_ctdb_store_deny;
> +	rec.storev = db_ctdb_storev_deny;
>  	rec.delete_rec = db_ctdb_delete_deny;
>  	rec.private_data = NULL;
>  
> diff --git a/source3/lib/dbwrap/dbwrap_watch.c b/source3/lib/dbwrap/dbwrap_watch.c
> index 585010f..ab59803 100644
> --- a/source3/lib/dbwrap/dbwrap_watch.c
> +++ b/source3/lib/dbwrap/dbwrap_watch.c
> @@ -238,8 +238,9 @@ struct db_watched_subrec {
>  	bool deleted;
>  };
>  
> -static NTSTATUS dbwrap_watched_store(struct db_record *rec, TDB_DATA data,
> -				     int flag);
> +static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
> +				      const TDB_DATA *dbufs, int num_dbufs,
> +				      int flag);
>  static NTSTATUS dbwrap_watched_delete(struct db_record *rec);
>  
>  static struct db_record *dbwrap_watched_fetch_locked(
> @@ -271,7 +272,7 @@ static struct db_record *dbwrap_watched_fetch_locked(
>  
>  	rec->db = db;
>  	rec->key = dbwrap_record_get_key(subrec->subrec);
> -	rec->store = dbwrap_watched_store;
> +	rec->storev = dbwrap_watched_storev;
>  	rec->delete_rec = dbwrap_watched_delete;
>  
>  	subrec_value = dbwrap_record_get_value(subrec->subrec);
> @@ -383,18 +384,29 @@ static NTSTATUS dbwrap_watched_save(struct db_watched_subrec *subrec,
>  	return status;
>  }
>  
> -static NTSTATUS dbwrap_watched_store(struct db_record *rec, TDB_DATA data,
> -				     int flag)
> +static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
> +				      const TDB_DATA *dbufs, int num_dbufs,
> +				      int flag)
>  {
>  	struct db_watched_subrec *subrec = talloc_get_type_abort(
>  		rec->private_data, struct db_watched_subrec);
> +	NTSTATUS status;
> +	TDB_DATA data;
> +
> +	data = dbwrap_merge_dbufs(rec, dbufs, num_dbufs);
> +	if (data.dptr == NULL) {
> +		return NT_STATUS_NO_MEMORY;
> +	}
>  
>  	dbwrap_watched_wakeup(rec, subrec);
>  
>  	subrec->deleted = false;
>  
> -	return dbwrap_watched_save(subrec, data, flag);
> +	status = dbwrap_watched_save(subrec, data, flag);
> +
> +	TALLOC_FREE(data.dptr);
>  
> +	return status;
>  }
>  
>  static NTSTATUS dbwrap_watched_delete(struct db_record *rec)
> -- 
> 2.1.4
> 
> 
> From 6b9acf9b413cc221268d2bcf90e88000c35ed55c Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Tue, 13 Sep 2016 12:25:14 +0200
> Subject: [PATCH 04/41] dbwrap: Add dbwrap_record_storev
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  lib/dbwrap/dbwrap.c | 10 ++++++++--
>  lib/dbwrap/dbwrap.h |  2 ++
>  2 files changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/lib/dbwrap/dbwrap.c b/lib/dbwrap/dbwrap.c
> index 85f2213..713c420 100644
> --- a/lib/dbwrap/dbwrap.c
> +++ b/lib/dbwrap/dbwrap.c
> @@ -82,17 +82,23 @@ TDB_DATA dbwrap_record_get_value(const struct db_record *rec)
>  	return rec->value;
>  }
>  
> -NTSTATUS dbwrap_record_store(struct db_record *rec, TDB_DATA data, int flags)
> +NTSTATUS dbwrap_record_storev(struct db_record *rec,
> +			      const TDB_DATA *dbufs, int num_dbufs, int flags)
>  {
>  	NTSTATUS status;
>  
> -	status = rec->storev(rec, &data, 1, flags);
> +	status = rec->storev(rec, dbufs, num_dbufs, flags);
>  	if (!NT_STATUS_IS_OK(status)) {
>  		return status;
>  	}
>  	return NT_STATUS_OK;
>  }
>  
> +NTSTATUS dbwrap_record_store(struct db_record *rec, TDB_DATA data, int flags)
> +{
> +	return dbwrap_record_storev(rec, &data, 1, flags);
> +}
> +
>  NTSTATUS dbwrap_record_delete(struct db_record *rec)
>  {
>  	NTSTATUS status;
> diff --git a/lib/dbwrap/dbwrap.h b/lib/dbwrap/dbwrap.h
> index e34b2ab..04e179e 100644
> --- a/lib/dbwrap/dbwrap.h
> +++ b/lib/dbwrap/dbwrap.h
> @@ -72,6 +72,8 @@ enum dbwrap_req_state {
>  TDB_DATA dbwrap_record_get_key(const struct db_record *rec);
>  TDB_DATA dbwrap_record_get_value(const struct db_record *rec);
>  NTSTATUS dbwrap_record_store(struct db_record *rec, TDB_DATA data, int flags);
> +NTSTATUS dbwrap_record_storev(struct db_record *rec,
> +			      const TDB_DATA *dbufs, int num_dbufs, int flags);
>  NTSTATUS dbwrap_record_delete(struct db_record *rec);
>  struct db_record *dbwrap_fetch_locked(struct db_context *db,
>  				      TALLOC_CTX *mem_ctx,
> -- 
> 2.1.4
> 
> 
> From 89448c6c9a47ebc0778a4837b94c197ed159fcde Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Wed, 9 Nov 2016 08:45:59 +0100
> Subject: [PATCH 05/41] dbwrap: Add dbwrap_do_locked
> 
> With a proper implementation this enables modifications without
> having to allocate a record. In really performance sensitive code
> paths this matters.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  lib/dbwrap/dbwrap.c         | 25 +++++++++++++++++++++++++
>  lib/dbwrap/dbwrap.h         |  5 +++++
>  lib/dbwrap/dbwrap_private.h |  4 ++++
>  3 files changed, 34 insertions(+)
> 
> diff --git a/lib/dbwrap/dbwrap.c b/lib/dbwrap/dbwrap.c
> index 713c420..fc70491 100644
> --- a/lib/dbwrap/dbwrap.c
> +++ b/lib/dbwrap/dbwrap.c
> @@ -486,6 +486,31 @@ NTSTATUS dbwrap_parse_record_recv(struct tevent_req *req)
>  	return tevent_req_simple_recv_ntstatus(req);
>  }
>  
> +NTSTATUS dbwrap_do_locked(struct db_context *db, TDB_DATA key,
> +			  void (*fn)(struct db_record *rec,
> +				     void *private_data),
> +			  void *private_data)
> +{
> +	struct db_record *rec;
> +
> +	if (db->do_locked != NULL) {
> +		NTSTATUS status;
> +		status = db->do_locked(db, key, fn, private_data);
> +		return status;
> +	}
> +
> +	rec = dbwrap_fetch_locked(db, db, key);
> +	if (rec == NULL) {
> +		return NT_STATUS_NO_MEMORY;
> +	}
> +
> +	fn(rec, private_data);
> +
> +	TALLOC_FREE(rec);
> +
> +	return NT_STATUS_OK;
> +}
> +
>  int dbwrap_wipe(struct db_context *db)
>  {
>  	if (db->wipe == NULL) {
> diff --git a/lib/dbwrap/dbwrap.h b/lib/dbwrap/dbwrap.h
> index 04e179e..1161bf0 100644
> --- a/lib/dbwrap/dbwrap.h
> +++ b/lib/dbwrap/dbwrap.h
> @@ -83,6 +83,11 @@ struct db_record *dbwrap_try_fetch_locked(struct db_context *db,
>  					  TDB_DATA key);
>  struct db_context *dbwrap_record_get_db(struct db_record *rec);
>  
> +NTSTATUS dbwrap_do_locked(struct db_context *db, TDB_DATA key,
> +			  void (*fn)(struct db_record *rec,
> +				     void *private_data),
> +			  void *private_data);
> +
>  NTSTATUS dbwrap_delete(struct db_context *db, TDB_DATA key);
>  NTSTATUS dbwrap_store(struct db_context *db, TDB_DATA key,
>  		      TDB_DATA data, int flags);
> diff --git a/lib/dbwrap/dbwrap_private.h b/lib/dbwrap/dbwrap_private.h
> index 2858afd..e757215 100644
> --- a/lib/dbwrap/dbwrap_private.h
> +++ b/lib/dbwrap/dbwrap_private.h
> @@ -68,6 +68,10 @@ struct db_context {
>  		void *private_data,
>  		enum dbwrap_req_state *req_state);
>  	NTSTATUS (*parse_record_recv)(struct tevent_req *req);
> +	NTSTATUS (*do_locked)(struct db_context *db, TDB_DATA key,
> +			      void (*fn)(struct db_record *rec,
> +					 void *private_data),
> +			      void *private_data);
>  	int (*exists)(struct db_context *db,TDB_DATA key);
>  	int (*wipe)(struct db_context *db);
>  	int (*check)(struct db_context *db);
> -- 
> 2.1.4
> 
> 
> From 0c758c69923b1082d369bcc9f5536bc063a07eda Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Tue, 27 Jun 2017 08:25:36 +0200
> Subject: [PATCH 06/41] torture3: Test dbwrap_do_locked
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/selftest/tests.py               |   1 +
>  source3/torture/proto.h                 |   1 +
>  source3/torture/test_dbwrap_do_locked.c | 132 ++++++++++++++++++++++++++++++++
>  source3/torture/torture.c               |   1 +
>  source3/wscript_build                   |   1 +
>  5 files changed, 136 insertions(+)
>  create mode 100644 source3/torture/test_dbwrap_do_locked.c
> 
> diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
> index d459ede..1594c19 100755
> --- a/source3/selftest/tests.py
> +++ b/source3/selftest/tests.py
> @@ -148,6 +148,7 @@ local_tests = [
>      "LOCAL-CANONICALIZE-PATH",
>      "LOCAL-DBWRAP-WATCH1",
>      "LOCAL-DBWRAP-WATCH2",
> +    "LOCAL-DBWRAP-DO-LOCKED1",
>      "LOCAL-G-LOCK1",
>      "LOCAL-G-LOCK2",
>      "LOCAL-G-LOCK3",
> diff --git a/source3/torture/proto.h b/source3/torture/proto.h
> index fc46898..8a032da 100644
> --- a/source3/torture/proto.h
> +++ b/source3/torture/proto.h
> @@ -111,6 +111,7 @@ bool run_notify_bench2(int dummy);
>  bool run_notify_bench3(int dummy);
>  bool run_dbwrap_watch1(int dummy);
>  bool run_dbwrap_watch2(int dummy);
> +bool run_dbwrap_do_locked1(int dummy);
>  bool run_idmap_tdb_common_test(int dummy);
>  bool run_local_dbwrap_ctdb(int dummy);
>  bool run_qpathinfo_bufsize(int dummy);
> diff --git a/source3/torture/test_dbwrap_do_locked.c b/source3/torture/test_dbwrap_do_locked.c
> new file mode 100644
> index 0000000..92dec38
> --- /dev/null
> +++ b/source3/torture/test_dbwrap_do_locked.c
> @@ -0,0 +1,132 @@
> +/*
> + * Unix SMB/CIFS implementation.
> + * Test dbwrap_watch API
> + * Copyright (C) Volker Lendecke 2017
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "includes.h"
> +#include "torture/proto.h"
> +#include "system/filesys.h"
> +#include "lib/dbwrap/dbwrap.h"
> +#include "lib/dbwrap/dbwrap_open.h"
> +#include "lib/dbwrap/dbwrap_watch.h"
> +#include "lib/util/util_tdb.h"
> +#include "source3/include/util_tdb.h"
> +
> +struct do_locked1_state {
> +	TDB_DATA value;
> +	NTSTATUS status;
> +};
> +
> +static void do_locked1_cb(struct db_record *rec, void *private_data)
> +{
> +	struct do_locked1_state *state =
> +		(struct do_locked1_state *)private_data;
> +
> +	state->status = dbwrap_record_store(rec, state->value, 0);
> +}
> +
> +static void do_locked1_check(TDB_DATA key, TDB_DATA value,
> +			     void *private_data)
> +{
> +	struct do_locked1_state *state =
> +		(struct do_locked1_state *)private_data;
> +	int ret;
> +
> +	ret = tdb_data_cmp(value, state->value);
> +	if (ret != 0) {
> +		state->status = NT_STATUS_DATA_ERROR;
> +		return;
> +	}
> +
> +	state->status = NT_STATUS_OK;
> +}
> +
> +static void do_locked1_del(struct db_record *rec, void *private_data)
> +{
> +	struct do_locked1_state *state =
> +		(struct do_locked1_state *)private_data;
> +
> +	state->status = dbwrap_record_delete(rec);
> +}
> +
> +bool run_dbwrap_do_locked1(int dummy)
> +{
> +	struct db_context *db;
> +	const char *dbname = "test_do_locked.tdb";
> +	const char *keystr = "key";
> +	TDB_DATA key = string_term_tdb_data(keystr);
> +	const char *valuestr = "value";
> +	TDB_DATA value = string_term_tdb_data(valuestr);
> +	struct do_locked1_state state = { .value = value };
> +	int ret = false;
> +	NTSTATUS status;
> +
> +	db = db_open(talloc_tos(), dbname, 0, TDB_CLEAR_IF_FIRST,
> +		     O_CREAT|O_RDWR, 0644, DBWRAP_LOCK_ORDER_1,
> +		     DBWRAP_FLAG_NONE);
> +	if (db == NULL) {
> +		fprintf(stderr, "db_open failed: %s\n", strerror(errno));
> +		return false;
> +	}
> +
> +	status = dbwrap_do_locked(db, key, do_locked1_cb, &state);
> +	if (!NT_STATUS_IS_OK(status)) {
> +		fprintf(stderr, "dbwrap_do_locked failed: %s\n",
> +			nt_errstr(status));
> +		goto fail;
> +	}
> +	if (!NT_STATUS_IS_OK(state.status)) {
> +		fprintf(stderr, "store returned %s\n", nt_errstr(status));
> +		goto fail;
> +	}
> +
> +	status = dbwrap_parse_record(db, key, do_locked1_check, &state);
> +	if (!NT_STATUS_IS_OK(status)) {
> +		fprintf(stderr, "dbwrap_parse_record failed: %s\n",
> +			nt_errstr(status));
> +		goto fail;
> +	}
> +	if (!NT_STATUS_IS_OK(state.status)) {
> +		fprintf(stderr, "data compare returned %s\n",
> +			nt_errstr(status));
> +		goto fail;
> +	}
> +
> +	status = dbwrap_do_locked(db, key, do_locked1_del, &state);
> +	if (!NT_STATUS_IS_OK(status)) {
> +		fprintf(stderr, "dbwrap_do_locked failed: %s\n",
> +			nt_errstr(status));
> +		goto fail;
> +	}
> +	if (!NT_STATUS_IS_OK(state.status)) {
> +		fprintf(stderr, "delete returned %s\n", nt_errstr(status));
> +		goto fail;
> +	}
> +
> +	status = dbwrap_parse_record(db, key, do_locked1_check, &state);
> +	if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
> +		fprintf(stderr, "parse_record returned %s, "
> +			"expected NOT_FOUND\n", nt_errstr(status));
> +		goto fail;
> +	}
> +
> +	ret = true;
> +fail:
> +	TALLOC_FREE(db);
> +	unlink(dbname);
> +	return ret;
> +}
> diff --git a/source3/torture/torture.c b/source3/torture/torture.c
> index 64caca5..b8d4f5e 100644
> --- a/source3/torture/torture.c
> +++ b/source3/torture/torture.c
> @@ -11523,6 +11523,7 @@ static struct {
>  	{ "LOCAL-TALLOC-DICT", run_local_talloc_dict, 0},
>  	{ "LOCAL-DBWRAP-WATCH1", run_dbwrap_watch1, 0 },
>  	{ "LOCAL-DBWRAP-WATCH2", run_dbwrap_watch2, 0 },
> +	{ "LOCAL-DBWRAP-DO-LOCKED1", run_dbwrap_do_locked1, 0 },
>  	{ "LOCAL-MESSAGING-READ1", run_messaging_read1, 0 },
>  	{ "LOCAL-MESSAGING-READ2", run_messaging_read2, 0 },
>  	{ "LOCAL-MESSAGING-READ3", run_messaging_read3, 0 },
> diff --git a/source3/wscript_build b/source3/wscript_build
> index a030b8a..99f4a2b 100644
> --- a/source3/wscript_build
> +++ b/source3/wscript_build
> @@ -1203,6 +1203,7 @@ bld.SAMBA3_BINARY('smbtorture' + bld.env.suffix3,
>                          torture/test_notify.c
>                          lib/tevent_barrier.c
>                          torture/test_dbwrap_watch.c
> +                        torture/test_dbwrap_do_locked.c
>                          torture/test_idmap_tdb_common.c
>                          torture/test_dbwrap_ctdb.c
>                          torture/test_buffersize.c
> -- 
> 2.1.4
> 
> 
> From 580a069ca0412a1f3e6efd67b8aac3b2a2d37ed5 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Tue, 27 Jun 2017 08:25:03 +0200
> Subject: [PATCH 07/41] dbwrap_tdb: Implement do_locked
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  lib/dbwrap/dbwrap_tdb.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 47 insertions(+)
> 
> diff --git a/lib/dbwrap/dbwrap_tdb.c b/lib/dbwrap/dbwrap_tdb.c
> index 9f8a9a6..c30bede 100644
> --- a/lib/dbwrap/dbwrap_tdb.c
> +++ b/lib/dbwrap/dbwrap_tdb.c
> @@ -25,6 +25,7 @@
>  #include "lib/util/util_tdb.h"
>  #include "system/filesys.h"
>  #include "lib/param/param.h"
> +#include "libcli/util/error.h"
>  
>  struct db_tdb_ctx {
>  	struct tdb_wrap *wtdb;
> @@ -174,6 +175,51 @@ static struct db_record *db_tdb_try_fetch_locked(
>  	return db_tdb_fetch_locked_internal(db, mem_ctx, key);
>  }
>  
> +static NTSTATUS db_tdb_do_locked(struct db_context *db, TDB_DATA key,
> +				 void (*fn)(struct db_record *rec,
> +					    void *private_data),
> +				 void *private_data)
> +{
> +	struct db_tdb_ctx *ctx = talloc_get_type_abort(
> +		db->private_data, struct db_tdb_ctx);
> +	uint8_t *buf = NULL;
> +	struct db_record rec;
> +	int ret;
> +
> +	ret = tdb_chainlock(ctx->wtdb->tdb, key);
> +	if (ret == -1) {
> +		enum TDB_ERROR err = tdb_error(ctx->wtdb->tdb);
> +		DBG_DEBUG("tdb_chainlock failed: %s\n",
> +			  tdb_errorstr(ctx->wtdb->tdb));
> +		return map_nt_error_from_tdb(err);
> +	}
> +
> +	ret = tdb_fetch_talloc(ctx->wtdb->tdb, key, ctx, &buf);
> +
> +	if ((ret != 0) && (ret != ENOENT)) {
> +		DBG_DEBUG("tdb_fetch_talloc failed: %s\n",
> +			  strerror(errno));
> +		tdb_chainunlock(ctx->wtdb->tdb, key);
> +		return map_nt_error_from_unix_common(ret);
> +	}
> +
> +	rec = (struct db_record) {
> +		.db = db, .key = key,
> +		.value = (struct TDB_DATA) { .dptr = buf,
> +					     .dsize = talloc_get_size(buf) },
> +		.storev = db_tdb_storev, .delete_rec = db_tdb_delete,
> +		.private_data = ctx
> +	};
> +
> +	fn(&rec, private_data);
> +
> +	talloc_free(buf);
> +
> +	tdb_chainunlock(ctx->wtdb->tdb, key);
> +
> +	return NT_STATUS_OK;
> +}
> +
>  static int db_tdb_exists(struct db_context *db, TDB_DATA key)
>  {
>  	struct db_tdb_ctx *ctx = talloc_get_type_abort(
> @@ -446,6 +492,7 @@ struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
>  
>  	result->fetch_locked = db_tdb_fetch_locked;
>  	result->try_fetch_locked = db_tdb_try_fetch_locked;
> +	result->do_locked = db_tdb_do_locked;
>  	result->traverse = db_tdb_traverse;
>  	result->traverse_read = db_tdb_traverse_read;
>  	result->parse_record = db_tdb_parse;
> -- 
> 2.1.4
> 
> 
> From bd8fad4cadce98d9f864fd578288822685a93692 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Sat, 1 Jul 2017 18:13:44 +0200
> Subject: [PATCH 08/41] dbwrap_watch: Introduce dbwrap_watch_rec
> 
> The idea is to leave the "watchers" array unparsed until it's needed. This
> avoids a few talloc calls and unnecessary parsing.
> 
> Also, it deletes quite a few lines of code and .text bytes.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/dbwrap/dbwrap_watch.c | 325 +++++++++++++++-----------------------
>  1 file changed, 130 insertions(+), 195 deletions(-)
> 
> diff --git a/source3/lib/dbwrap/dbwrap_watch.c b/source3/lib/dbwrap/dbwrap_watch.c
> index ab59803..6461067 100644
> --- a/source3/lib/dbwrap/dbwrap_watch.c
> +++ b/source3/lib/dbwrap/dbwrap_watch.c
> @@ -116,16 +116,23 @@ static bool dbwrap_record_watchers_key_parse(
>  #define NUM_WATCHERS_DELETED_BIT (1UL<<31)
>  #define NUM_WATCHERS_MASK (NUM_WATCHERS_DELETED_BIT-1)
>  
> -static ssize_t dbwrap_watched_parse(TDB_DATA data, struct server_id *ids,
> -				    size_t num_ids, bool *pdeleted,
> -				    TDB_DATA *pdata)
> +struct dbwrap_watch_rec {
> +	uint8_t *watchers;
> +	size_t num_watchers;
> +	bool deleted;
> +	TDB_DATA data;
> +};
> +
> +static bool dbwrap_watch_rec_parse(TDB_DATA data,
> +				   struct dbwrap_watch_rec *wrec)
>  {
> -	size_t i, num_watchers;
> +	size_t num_watchers;
>  	bool deleted;
> +	TDB_DATA userdata = { 0 };
>  
>  	if (data.dsize < sizeof(uint32_t)) {
>  		/* Fresh or invalid record */
> -		return -1;
> +		return false;
>  	}
>  
>  	num_watchers = IVAL(data.dptr, 0);
> @@ -138,93 +145,47 @@ static ssize_t dbwrap_watched_parse(TDB_DATA data, struct server_id *ids,
>  
>  	if (num_watchers > data.dsize/SERVER_ID_BUF_LENGTH) {
>  		/* Invalid record */
> -		return -1;
> -	}
> -
> -	if (num_watchers > num_ids) {
> -		/*
> -		 * Not enough space to store the watchers server_id's.
> -		 * Just move past all of them to allow the remaining part
> -		 * of the record to be returned.
> -		 */
> -		data.dptr += num_watchers * SERVER_ID_BUF_LENGTH;
> -		data.dsize -= num_watchers * SERVER_ID_BUF_LENGTH;
> -		goto done;
> +		return false;
>  	}
>  
> -	/*
> -	 * Note, even if marked deleted we still must
> -	 * return the id's array to allow awoken
> -	 * watchers to remove themselves.
> -	 */
> -
> -	for (i=0; i<num_watchers; i++) {
> -		server_id_get(&ids[i], data.dptr);
> -		data.dptr += SERVER_ID_BUF_LENGTH;
> -		data.dsize -= SERVER_ID_BUF_LENGTH;
> +	if (!deleted) {
> +		size_t watchers_len = num_watchers * SERVER_ID_BUF_LENGTH;
> +		userdata = (TDB_DATA) {
> +			.dptr = data.dptr + watchers_len,
> +			.dsize = data.dsize - watchers_len
> +		};
>  	}
>  
> -done:
> -	if (deleted) {
> -		data = (TDB_DATA) {0};
> -	}
> -	if (pdata != NULL) {
> -		*pdata = data;
> -	}
> -	if (pdeleted != NULL) {
> -		*pdeleted = deleted;
> -	}
> +	*wrec = (struct dbwrap_watch_rec) {
> +		.watchers = data.dptr, .num_watchers = num_watchers,
> +		.deleted = deleted, .data = userdata
> +	};
>  
> -	return num_watchers;
> +	return true;
>  }
>  
> -static ssize_t dbwrap_watched_unparse(const struct server_id *watchers,
> -				      size_t num_watchers, bool deleted,
> -				      TDB_DATA data,
> -				      uint8_t *buf, size_t buflen)
> +static void dbwrap_watch_rec_get_watcher(
> +	struct dbwrap_watch_rec *wrec, size_t i, struct server_id *watcher)
>  {
> -	size_t i, len, ofs;
> -	uint32_t num_watchers_buf;
> -
> -	if (num_watchers > UINT32_MAX/SERVER_ID_BUF_LENGTH) {
> -		return -1;
> +	if (i >= wrec->num_watchers) {
> +		abort();
>  	}
> +	server_id_get(watcher, wrec->watchers + i * SERVER_ID_BUF_LENGTH);
> +}
>  
> -	len = num_watchers * SERVER_ID_BUF_LENGTH;
> -
> -	len += sizeof(uint32_t);
> -	if (len < sizeof(uint32_t)) {
> -		return -1;
> -	}
> -
> -	len += data.dsize;
> -	if (len < data.dsize) {
> -		return -1;
> -	}
> -
> -	if (len > buflen) {
> -		return len;
> -	}
> -
> -	num_watchers_buf = num_watchers;
> -	if (deleted) {
> -		num_watchers_buf |= NUM_WATCHERS_DELETED_BIT;
> -	}
> -
> -	ofs = 0;
> -	SIVAL(buf, ofs, num_watchers_buf);
> -	ofs += 4;
> -
> -	for (i=0; i<num_watchers; i++) {
> -		server_id_put(buf+ofs, watchers[i]);
> -		ofs += SERVER_ID_BUF_LENGTH;
> +static void dbwrap_watch_rec_del_watcher(struct dbwrap_watch_rec *wrec,
> +					 size_t i)
> +{
> +	if (i >= wrec->num_watchers) {
> +		abort();
>  	}
> -
> -	if ((data.dptr != NULL) && (data.dsize != 0)) {
> -		memcpy(buf + ofs, data.dptr, data.dsize);
> +	wrec->num_watchers -= 1;
> +	if (i < wrec->num_watchers) {
> +		uint8_t *wptr = wrec->watchers + i*SERVER_ID_BUF_LENGTH;
> +		memcpy(wptr,
> +		       wrec->watchers+wrec->num_watchers*SERVER_ID_BUF_LENGTH,
> +		       SERVER_ID_BUF_LENGTH);
>  	}
> -
> -	return len;
>  }
>  
>  struct db_watched_ctx {
> @@ -234,8 +195,7 @@ struct db_watched_ctx {
>  
>  struct db_watched_subrec {
>  	struct db_record *subrec;
> -	struct server_id *watchers;
> -	bool deleted;
> +	struct dbwrap_watch_rec wrec;
>  };
>  
>  static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
> @@ -251,7 +211,7 @@ static struct db_record *dbwrap_watched_fetch_locked(
>  	struct db_record *rec;
>  	struct db_watched_subrec *subrec;
>  	TDB_DATA subrec_value;
> -	ssize_t num_watchers;
> +	bool ok;
>  
>  	rec = talloc_zero(mem_ctx, struct db_record);
>  	if (rec == NULL) {
> @@ -277,33 +237,21 @@ static struct db_record *dbwrap_watched_fetch_locked(
>  
>  	subrec_value = dbwrap_record_get_value(subrec->subrec);
>  
> -	num_watchers = dbwrap_watched_parse(subrec_value, NULL, 0, NULL, NULL);
> -	if (num_watchers == -1) {
> -		/* Fresh or invalid record */
> -		rec->value = (TDB_DATA) { 0 };
> -		return rec;
> -	}
> -
> -	subrec->watchers = talloc_array(subrec, struct server_id,
> -					num_watchers);
> -	if (subrec->watchers == NULL) {
> -		TALLOC_FREE(rec);
> -		return NULL;
> +	ok = dbwrap_watch_rec_parse(subrec_value, &subrec->wrec);
> +	if (ok) {
> +		rec->value = subrec->wrec.data;
>  	}
>  
> -	dbwrap_watched_parse(subrec_value, subrec->watchers, num_watchers,
> -			     &subrec->deleted, &rec->value);
> -
>  	return rec;
>  }
>  
>  static void dbwrap_watched_wakeup(struct db_record *rec,
> -				  struct db_watched_subrec *subrec)
> +				  struct dbwrap_watch_rec *wrec)
>  {
> -	struct db_context *db = dbwrap_record_get_db(rec);
> +	struct db_context *db = rec->db;
>  	struct db_watched_ctx *ctx = talloc_get_type_abort(
>  		db->private_data, struct db_watched_ctx);
> -	size_t i, num_watchers;
> +	size_t i;
>  	size_t db_id_len = dbwrap_db_id(db, NULL, 0);
>  	uint8_t db_id[db_id_len];
>  	uint8_t len_buf[4];
> @@ -318,32 +266,27 @@ static void dbwrap_watched_wakeup(struct db_record *rec,
>  
>  	dbwrap_db_id(db, db_id, db_id_len);
>  
> -	num_watchers = talloc_array_length(subrec->watchers);
> -
>  	i = 0;
>  
> -	while (i < num_watchers) {
> +	while (i < wrec->num_watchers) {
> +		struct server_id watcher;
>  		NTSTATUS status;
>  		struct server_id_buf tmp;
>  
> -		DBG_DEBUG("Alerting %s\n",
> -			  server_id_str_buf(subrec->watchers[i], &tmp));
> +		dbwrap_watch_rec_get_watcher(wrec, i, &watcher);
>  
> -		status = messaging_send_iov(ctx->msg, subrec->watchers[i],
> +		DBG_DEBUG("Alerting %s\n", server_id_str_buf(watcher, &tmp));
> +
> +		status = messaging_send_iov(ctx->msg, watcher,
>  					    MSG_DBWRAP_MODIFIED,
>  					    iov, ARRAY_SIZE(iov), NULL, 0);
>  		if (!NT_STATUS_IS_OK(status)) {
>  			DBG_DEBUG("messaging_send_iov to %s failed: %s\n",
> -				  server_id_str_buf(subrec->watchers[i], &tmp),
> +				  server_id_str_buf(watcher, &tmp),
>  				  nt_errstr(status));
>  		}
>  		if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
> -			subrec->watchers[i] = subrec->watchers[num_watchers-1];
> -			num_watchers -= 1;
> -
> -			subrec->watchers = talloc_realloc(
> -				subrec, subrec->watchers, struct server_id,
> -				num_watchers);
> +			dbwrap_watch_rec_del_watcher(wrec, i);
>  			continue;
>  		}
>  
> @@ -351,61 +294,68 @@ static void dbwrap_watched_wakeup(struct db_record *rec,
>  	}
>  }
>  
> -static NTSTATUS dbwrap_watched_save(struct db_watched_subrec *subrec,
> -				    TDB_DATA data, int flag)
> +static NTSTATUS dbwrap_watched_save(struct db_record *rec,
> +				    struct dbwrap_watch_rec *wrec,
> +				    struct server_id *addwatch,
> +				    const TDB_DATA *databufs,
> +				    size_t num_databufs,
> +				    int flags)
>  {
> -	size_t num_watchers;
> -	ssize_t len;
> -	uint8_t *buf;
> +	uint32_t num_watchers_buf;
> +	uint8_t sizebuf[4];
> +	uint8_t addbuf[SERVER_ID_BUF_LENGTH];
>  	NTSTATUS status;
> +	struct TDB_DATA dbufs[num_databufs+3];
>  
> -	num_watchers = talloc_array_length(subrec->watchers);
> +	dbufs[0] = (TDB_DATA) {
> +		.dptr = sizebuf, .dsize = sizeof(sizebuf)
> +	};
>  
> -	len = dbwrap_watched_unparse(subrec->watchers, num_watchers,
> -				     subrec->deleted, data, NULL, 0);
> -	if (len == -1) {
> -		return NT_STATUS_INSUFFICIENT_RESOURCES;
> -	}
> +	dbufs[1] = (TDB_DATA) {
> +		.dptr = wrec->watchers,
> +		.dsize = wrec->num_watchers * SERVER_ID_BUF_LENGTH
> +	};
>  
> -	buf = talloc_array(subrec, uint8_t, len);
> -	if (buf == NULL) {
> -		return NT_STATUS_NO_MEMORY;
> +	if (addwatch != NULL) {
> +		server_id_put(addbuf, *addwatch);
> +
> +		dbufs[2] = (TDB_DATA) {
> +			.dptr = addbuf, .dsize = SERVER_ID_BUF_LENGTH
> +		};
> +		wrec->num_watchers += 1;
> +	} else {
> +		dbufs[2] = (TDB_DATA) { 0 };
>  	}
>  
> -	dbwrap_watched_unparse(subrec->watchers, num_watchers,
> -			       subrec->deleted, data, buf, len);
> +	if (num_databufs != 0) {
> +		memcpy(&dbufs[3], databufs, sizeof(TDB_DATA) * num_databufs);
> +	}
>  
> -	status = dbwrap_record_store(
> -		subrec->subrec, (TDB_DATA) { .dptr = buf, .dsize = len },
> -		flag);
> +	num_watchers_buf = wrec->num_watchers;
> +	if (wrec->deleted) {
> +		num_watchers_buf |= NUM_WATCHERS_DELETED_BIT;
> +	}
>  
> -	TALLOC_FREE(buf);
> +	SIVAL(sizebuf, 0, num_watchers_buf);
>  
> +	status = dbwrap_record_storev(rec, dbufs, ARRAY_SIZE(dbufs), flags);
>  	return status;
>  }
>  
>  static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
>  				      const TDB_DATA *dbufs, int num_dbufs,
> -				      int flag)
> +				      int flags)
>  {
>  	struct db_watched_subrec *subrec = talloc_get_type_abort(
>  		rec->private_data, struct db_watched_subrec);
>  	NTSTATUS status;
> -	TDB_DATA data;
>  
> -	data = dbwrap_merge_dbufs(rec, dbufs, num_dbufs);
> -	if (data.dptr == NULL) {
> -		return NT_STATUS_NO_MEMORY;
> -	}
> -
> -	dbwrap_watched_wakeup(rec, subrec);
> -
> -	subrec->deleted = false;
> +	dbwrap_watched_wakeup(rec, &subrec->wrec);
>  
> -	status = dbwrap_watched_save(subrec, data, flag);
> -
> -	TALLOC_FREE(data.dptr);
> +	subrec->wrec.deleted = false;
>  
> +	status = dbwrap_watched_save(subrec->subrec, &subrec->wrec, NULL,
> +				     dbufs, num_dbufs, flags);
>  	return status;
>  }
>  
> @@ -413,18 +363,17 @@ static NTSTATUS dbwrap_watched_delete(struct db_record *rec)
>  {
>  	struct db_watched_subrec *subrec = talloc_get_type_abort(
>  		rec->private_data, struct db_watched_subrec);
> -	size_t num_watchers;
>  
> -	dbwrap_watched_wakeup(rec, subrec);
> +	dbwrap_watched_wakeup(rec, &subrec->wrec);
>  
> -	num_watchers = talloc_array_length(subrec->watchers);
> -	if (num_watchers == 0) {
> +	if (subrec->wrec.num_watchers == 0) {
>  		return dbwrap_record_delete(subrec->subrec);
>  	}
>  
> -	subrec->deleted = true;
> +	subrec->wrec.deleted = true;
>  
> -	return dbwrap_watched_save(subrec, (TDB_DATA) {0}, 0);
> +	return dbwrap_watched_save(subrec->subrec, &subrec->wrec,
> +				   NULL, NULL, 0, 0);
>  }
>  
>  struct dbwrap_watched_traverse_state {
> @@ -436,17 +385,17 @@ static int dbwrap_watched_traverse_fn(struct db_record *rec,
>  				      void *private_data)
>  {
>  	struct dbwrap_watched_traverse_state *state = private_data;
> -	ssize_t num_watchers;
>  	struct db_record prec = *rec;
> -	bool deleted;
> -
> -	num_watchers = dbwrap_watched_parse(rec->value, NULL, 0, &deleted,
> -					    &prec.value);
> +	struct dbwrap_watch_rec wrec;
> +	bool ok;
>  
> -	if ((num_watchers == -1) || deleted) {
> +	ok = dbwrap_watch_rec_parse(rec->value, &wrec);
> +	if (!ok || wrec.deleted) {
>  		return 0;
>  	}
>  
> +	prec.value = wrec.data;
> +
>  	return state->fn(&prec, state->private_data);
>  }
>  
> @@ -528,18 +477,16 @@ static void dbwrap_watched_parse_record_parser(TDB_DATA key, TDB_DATA data,
>  					       void *private_data)
>  {
>  	struct dbwrap_watched_parse_record_state *state = private_data;
> -	ssize_t num_watchers;
> -	TDB_DATA userdata;
> +	struct dbwrap_watch_rec wrec;
> +	bool ok;
>  
> -	num_watchers = dbwrap_watched_parse(data, NULL, 0, &state->deleted,
> -					    &userdata);
> -	if (num_watchers == -1) {
> +	ok = dbwrap_watch_rec_parse(data, &wrec);
> +	if ((!ok) || (wrec.deleted)) {
>  		state->deleted = true;
> -	}
> -	if (state->deleted) {
>  		return;
>  	}
> -	state->parser(key, userdata, state->private_data);
> +
> +	state->parser(key, wrec.data, state->private_data);
>  }
>  
>  static NTSTATUS dbwrap_watched_parse_record(
> @@ -736,8 +683,6 @@ struct tevent_req *dbwrap_watched_watch_send(TALLOC_CTX *mem_ctx,
>  	struct tevent_req *req, *subreq;
>  	struct dbwrap_watched_watch_state *state;
>  	ssize_t needed;
> -	size_t num_watchers;
> -	struct server_id *tmp;
>  	NTSTATUS status;
>  
>  	req = tevent_req_create(mem_ctx, &state,
> @@ -776,17 +721,8 @@ struct tevent_req *dbwrap_watched_watch_send(TALLOC_CTX *mem_ctx,
>  	}
>  	tevent_req_set_callback(subreq, dbwrap_watched_watch_done, req);
>  
> -	num_watchers = talloc_array_length(subrec->watchers);
> -
> -	tmp = talloc_realloc(subrec, subrec->watchers, struct server_id,
> -			     num_watchers + 1);
> -	if (tevent_req_nomem(tmp, req)) {
> -		return tevent_req_post(req, ev);
> -	}
> -	subrec->watchers = tmp;
> -	subrec->watchers[num_watchers] = state->me;
> -
> -	status = dbwrap_watched_save(subrec, rec->value, 0);
> +	status = dbwrap_watched_save(subrec->subrec, &subrec->wrec, &state->me,
> +				     &subrec->wrec.data, 1, 0);
>  	if (tevent_req_nterror(req, status)) {
>  		return tevent_req_post(req, ev);
>  	}
> @@ -823,30 +759,27 @@ static void dbwrap_watched_watch_blocker_died(struct tevent_req *subreq)
>  	tevent_req_done(req);
>  }
>  
> -static bool dbwrap_watched_remove_waiter(struct db_watched_subrec *subrec,
> +static bool dbwrap_watched_remove_waiter(struct dbwrap_watch_rec *wrec,
>  					 struct server_id id)
>  {
> -	size_t i, num_watchers;
> +	size_t i;
>  
> -	num_watchers = talloc_array_length(subrec->watchers);
> -
> -	for (i=0; i<num_watchers; i++) {
> -		if (server_id_equal(&id, &subrec->watchers[i])) {
> +	for (i=0; i<wrec->num_watchers; i++) {
> +		struct server_id watcher;
> +		dbwrap_watch_rec_get_watcher(wrec, i, &watcher);
> +		if (server_id_equal(&id, &watcher)) {
>  			break;
>  		}
>  	}
>  
> -	if (i == num_watchers) {
> +	if (i == wrec->num_watchers) {
>  		struct server_id_buf buf;
>  		DBG_WARNING("Did not find %s in state->watchers\n",
>  			    server_id_str_buf(id, &buf));
>  		return false;
>  	}
>  
> -	subrec->watchers[i] = subrec->watchers[num_watchers-1];
> -	subrec->watchers = talloc_realloc(subrec, subrec->watchers,
> -					  struct server_id, num_watchers-1);
> -
> +	dbwrap_watch_rec_del_watcher(wrec, i);
>  	return true;
>  }
>  
> @@ -873,10 +806,11 @@ static int dbwrap_watched_watch_state_destructor(
>  	subrec = talloc_get_type_abort(
>  		rec->private_data, struct db_watched_subrec);
>  
> -	ok = dbwrap_watched_remove_waiter(subrec, state->me);
> +	ok = dbwrap_watched_remove_waiter(&subrec->wrec, state->me);
>  	if (ok) {
>  		NTSTATUS status;
> -		status = dbwrap_watched_save(subrec, rec->value, 0);
> +		status = dbwrap_watched_save(subrec->subrec, &subrec->wrec,
> +					     NULL, &subrec->wrec.data, 1, 0);
>  		if (!NT_STATUS_IS_OK(status)) {
>  			DBG_WARNING("dbwrap_watched_save failed: %s\n",
>  				    nt_errstr(status));
> @@ -967,9 +901,10 @@ NTSTATUS dbwrap_watched_watch_recv(struct tevent_req *req,
>  	subrec = talloc_get_type_abort(
>  		rec->private_data, struct db_watched_subrec);
>  
> -	ok = dbwrap_watched_remove_waiter(subrec, state->me);
> +	ok = dbwrap_watched_remove_waiter(&subrec->wrec, state->me);
>  	if (ok) {
> -		status = dbwrap_watched_save(subrec, rec->value, 0);
> +		status = dbwrap_watched_save(subrec->subrec, &subrec->wrec,
> +					     NULL, &subrec->wrec.data, 1, 0);
>  		if (!NT_STATUS_IS_OK(status)) {
>  			DBG_WARNING("dbwrap_watched_save failed: %s\n",
>  				    nt_errstr(status));
> -- 
> 2.1.4
> 
> 
> From 8e8a3709330f06a38d148f9dbd75ceda4bcf548a Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Tue, 27 Jun 2017 18:40:28 +0200
> Subject: [PATCH 09/41] dbwrap_watch: Implement do_locked
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/dbwrap/dbwrap_watch.c       | 167 +++++++++++++++++++++++++++++---
>  source3/torture/test_dbwrap_do_locked.c |  32 +++++-
>  2 files changed, 182 insertions(+), 17 deletions(-)
> 
> diff --git a/source3/lib/dbwrap/dbwrap_watch.c b/source3/lib/dbwrap/dbwrap_watch.c
> index 6461067..be0a0d3 100644
> --- a/source3/lib/dbwrap/dbwrap_watch.c
> +++ b/source3/lib/dbwrap/dbwrap_watch.c
> @@ -198,10 +198,23 @@ struct db_watched_subrec {
>  	struct dbwrap_watch_rec wrec;
>  };
>  
> +static NTSTATUS dbwrap_watched_subrec_storev(
> +	struct db_record *rec, struct db_watched_subrec *subrec,
> +	const TDB_DATA *dbufs, int num_dbufs, int flags);
> +static NTSTATUS dbwrap_watched_subrec_delete(
> +	struct db_record *rec, struct db_watched_subrec *subrec);
>  static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
>  				      const TDB_DATA *dbufs, int num_dbufs,
> -				      int flag);
> +				      int flags);
>  static NTSTATUS dbwrap_watched_delete(struct db_record *rec);
> +static void dbwrap_watched_wakeup(struct db_record *rec,
> +				  struct dbwrap_watch_rec *wrec);
> +static NTSTATUS dbwrap_watched_save(struct db_record *rec,
> +				    struct dbwrap_watch_rec *wrec,
> +				    struct server_id *addwatch,
> +				    const TDB_DATA *databufs,
> +				    size_t num_databufs,
> +				    int flags);
>  
>  static struct db_record *dbwrap_watched_fetch_locked(
>  	struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
> @@ -245,6 +258,95 @@ static struct db_record *dbwrap_watched_fetch_locked(
>  	return rec;
>  }
>  
> +struct dbwrap_watched_do_locked_state {
> +	TALLOC_CTX *mem_ctx;
> +	struct db_context *db;
> +	void (*fn)(struct db_record *rec, void *private_data);
> +	void *private_data;
> +
> +	struct db_watched_subrec subrec;
> +
> +	NTSTATUS status;
> +};
> +
> +static NTSTATUS dbwrap_watched_do_locked_storev(
> +	struct db_record *rec, const TDB_DATA *dbufs, int num_dbufs,
> +	int flags)
> +{
> +	struct dbwrap_watched_do_locked_state *state = rec->private_data;
> +	struct db_watched_subrec *subrec = &state->subrec;
> +	NTSTATUS status;
> +
> +	status = dbwrap_watched_subrec_storev(rec, subrec, dbufs, num_dbufs,
> +					      flags);
> +	return status;
> +}
> +
> +static NTSTATUS dbwrap_watched_do_locked_delete(struct db_record *rec)
> +{
> +	struct dbwrap_watched_do_locked_state *state = rec->private_data;
> +	struct db_watched_subrec *subrec = &state->subrec;
> +	NTSTATUS status;
> +
> +	status = dbwrap_watched_subrec_delete(rec, subrec);
> +	return status;
> +}
> +
> +static void dbwrap_watched_do_locked_fn(struct db_record *subrec,
> +					void *private_data)
> +{
> +	struct dbwrap_watched_do_locked_state *state =
> +		(struct dbwrap_watched_do_locked_state *)private_data;
> +	TDB_DATA subrec_value = dbwrap_record_get_value(subrec);
> +	struct db_record rec;
> +	bool ok;
> +
> +	rec = (struct db_record) {
> +		.db = state->db, .key = dbwrap_record_get_key(subrec),
> +		.storev = dbwrap_watched_do_locked_storev,
> +		.delete_rec = dbwrap_watched_do_locked_delete,
> +		.private_data = state
> +	};
> +
> +	state->subrec = (struct db_watched_subrec) {
> +		.subrec = subrec
> +	};
> +
> +	ok = dbwrap_watch_rec_parse(subrec_value, &state->subrec.wrec);
> +	if (ok) {
> +		rec.value = state->subrec.wrec.data;
> +	}
> +
> +	state->fn(&rec, state->private_data);
> +}
> +
> +static NTSTATUS dbwrap_watched_do_locked(struct db_context *db, TDB_DATA key,
> +					 void (*fn)(struct db_record *rec,
> +						    void *private_data),
> +					 void *private_data)
> +{
> +	struct db_watched_ctx *ctx = talloc_get_type_abort(
> +		db->private_data, struct db_watched_ctx);
> +	struct dbwrap_watched_do_locked_state state = {
> +		.mem_ctx = talloc_stackframe(),
> +		.db = db, .fn = fn, .private_data = private_data
> +	};
> +	NTSTATUS status;
> +
> +	status = dbwrap_do_locked(
> +		ctx->backend, key, dbwrap_watched_do_locked_fn, &state);
> +	TALLOC_FREE(state.mem_ctx);
> +	if (!NT_STATUS_IS_OK(status)) {
> +		DBG_DEBUG("dbwrap_do_locked returned %s\n", nt_errstr(status));
> +		return status;
> +	}
> +
> +	DBG_DEBUG("dbwrap_watched_do_locked_fn returned %s\n",
> +		  nt_errstr(state.status));
> +
> +	return state.status;
> +}
> +
>  static void dbwrap_watched_wakeup(struct db_record *rec,
>  				  struct dbwrap_watch_rec *wrec)
>  {
> @@ -342,12 +444,10 @@ static NTSTATUS dbwrap_watched_save(struct db_record *rec,
>  	return status;
>  }
>  
> -static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
> -				      const TDB_DATA *dbufs, int num_dbufs,
> -				      int flags)
> +static NTSTATUS dbwrap_watched_subrec_storev(
> +	struct db_record *rec, struct db_watched_subrec *subrec,
> +	const TDB_DATA *dbufs, int num_dbufs, int flags)
>  {
> -	struct db_watched_subrec *subrec = talloc_get_type_abort(
> -		rec->private_data, struct db_watched_subrec);
>  	NTSTATUS status;
>  
>  	dbwrap_watched_wakeup(rec, &subrec->wrec);
> @@ -359,10 +459,23 @@ static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
>  	return status;
>  }
>  
> -static NTSTATUS dbwrap_watched_delete(struct db_record *rec)
> +static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
> +				      const TDB_DATA *dbufs, int num_dbufs,
> +				      int flags)
>  {
>  	struct db_watched_subrec *subrec = talloc_get_type_abort(
>  		rec->private_data, struct db_watched_subrec);
> +	NTSTATUS status;
> +
> +	status = dbwrap_watched_subrec_storev(rec, subrec, dbufs, num_dbufs,
> +					      flags);
> +	return status;
> +}
> +
> +static NTSTATUS dbwrap_watched_subrec_delete(
> +	struct db_record *rec, struct db_watched_subrec *subrec)
> +{
> +	NTSTATUS status;
>  
>  	dbwrap_watched_wakeup(rec, &subrec->wrec);
>  
> @@ -372,8 +485,19 @@ static NTSTATUS dbwrap_watched_delete(struct db_record *rec)
>  
>  	subrec->wrec.deleted = true;
>  
> -	return dbwrap_watched_save(subrec->subrec, &subrec->wrec,
> -				   NULL, NULL, 0, 0);
> +	status = dbwrap_watched_save(subrec->subrec, &subrec->wrec,
> +				     NULL, NULL, 0, 0);
> +	return status;
> +}
> +
> +static NTSTATUS dbwrap_watched_delete(struct db_record *rec)
> +{
> +	struct db_watched_subrec *subrec = talloc_get_type_abort(
> +		rec->private_data, struct db_watched_subrec);
> +	NTSTATUS status;
> +
> +	status = dbwrap_watched_subrec_delete(rec, subrec);
> +	return status;
>  }
>  
>  struct dbwrap_watched_traverse_state {
> @@ -638,6 +762,7 @@ struct db_context *db_open_watched(TALLOC_CTX *mem_ctx,
>  	ctx->backend = talloc_move(ctx, &backend);
>  
>  	db->fetch_locked = dbwrap_watched_fetch_locked;
> +	db->do_locked = dbwrap_watched_do_locked;
>  	db->traverse = dbwrap_watched_traverse;
>  	db->traverse_read = dbwrap_watched_traverse_read;
>  	db->get_seqnum = dbwrap_watched_get_seqnum;
> @@ -674,12 +799,10 @@ struct tevent_req *dbwrap_watched_watch_send(TALLOC_CTX *mem_ctx,
>  					     struct db_record *rec,
>  					     struct server_id blocker)
>  {
> -	struct db_watched_subrec *subrec = talloc_get_type_abort(
> -		rec->private_data, struct db_watched_subrec);
>  	struct db_context *db = dbwrap_record_get_db(rec);
>  	struct db_watched_ctx *ctx = talloc_get_type_abort(
>  		db->private_data, struct db_watched_ctx);
> -
> +	struct db_watched_subrec *subrec = NULL;
>  	struct tevent_req *req, *subreq;
>  	struct dbwrap_watched_watch_state *state;
>  	ssize_t needed;
> @@ -698,6 +821,26 @@ struct tevent_req *dbwrap_watched_watch_send(TALLOC_CTX *mem_ctx,
>  		return tevent_req_post(req, ev);
>  	}
>  
> +	/*
> +	 * Figure out whether we're called as part of do_locked. If
> +	 * so, we can't use talloc_get_type_abort, the
> +	 * db_watched_subrec is stack-allocated in that case.
> +	 */
> +
> +	if (rec->storev == dbwrap_watched_storev) {
> +		subrec = talloc_get_type_abort(rec->private_data,
> +					       struct db_watched_subrec);
> +	}
> +	if (rec->storev == dbwrap_watched_do_locked_storev) {
> +		struct dbwrap_watched_do_locked_state *do_locked_state;
> +		do_locked_state = rec->private_data;
> +		subrec = &do_locked_state->subrec;
> +	}
> +	if (subrec == NULL) {
> +		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
> +		return tevent_req_post(req, ev);
> +	}
> +
>  	state->me = messaging_server_id(ctx->msg);
>  
>  	needed = dbwrap_record_watchers_key(db, rec, NULL, 0);
> diff --git a/source3/torture/test_dbwrap_do_locked.c b/source3/torture/test_dbwrap_do_locked.c
> index 92dec38..46b326b 100644
> --- a/source3/torture/test_dbwrap_do_locked.c
> +++ b/source3/torture/test_dbwrap_do_locked.c
> @@ -65,6 +65,9 @@ static void do_locked1_del(struct db_record *rec, void *private_data)
>  
>  bool run_dbwrap_do_locked1(int dummy)
>  {
> +	struct tevent_context *ev;
> +	struct messaging_context *msg;
> +	struct db_context *backend;
>  	struct db_context *db;
>  	const char *dbname = "test_do_locked.tdb";
>  	const char *keystr = "key";
> @@ -75,14 +78,32 @@ bool run_dbwrap_do_locked1(int dummy)
>  	int ret = false;
>  	NTSTATUS status;
>  
> -	db = db_open(talloc_tos(), dbname, 0, TDB_CLEAR_IF_FIRST,
> -		     O_CREAT|O_RDWR, 0644, DBWRAP_LOCK_ORDER_1,
> -		     DBWRAP_FLAG_NONE);
> -	if (db == NULL) {
> +	ev = server_event_context();
> +	if (ev == NULL) {
> +		fprintf(stderr, "server_event_context() failed\n");
> +		return false;
> +	}
> +	msg = server_messaging_context();
> +	if (msg == NULL) {
> +		fprintf(stderr, "server_messaging_context() failed\n");
> +		return false;
> +	}
> +
> +	backend = db_open(talloc_tos(), dbname, 0,
> +			  TDB_CLEAR_IF_FIRST, O_CREAT|O_RDWR, 0644,
> +			  DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
> +	if (backend == NULL) {
>  		fprintf(stderr, "db_open failed: %s\n", strerror(errno));
>  		return false;
>  	}
>  
> +	db = db_open_watched(talloc_tos(), backend, msg);
> +	if (db == NULL) {
> +		fprintf(stderr, "db_open_watched failed: %s\n",
> +			strerror(errno));
> +		return false;
> +	}
> +
>  	status = dbwrap_do_locked(db, key, do_locked1_cb, &state);
>  	if (!NT_STATUS_IS_OK(status)) {
>  		fprintf(stderr, "dbwrap_do_locked failed: %s\n",
> @@ -90,7 +111,8 @@ bool run_dbwrap_do_locked1(int dummy)
>  		goto fail;
>  	}
>  	if (!NT_STATUS_IS_OK(state.status)) {
> -		fprintf(stderr, "store returned %s\n", nt_errstr(status));
> +		fprintf(stderr, "store returned %s\n",
> +			nt_errstr(state.status));
>  		goto fail;
>  	}
>  
> -- 
> 2.1.4
> 
> 
> From db5f5766f8384891f7c0fbd96997a03908c74730 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Wed, 28 Jun 2017 16:21:19 +0200
> Subject: [PATCH 10/41] g_lock: Walk locks only once in g_lock_trylock
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/g_lock.c | 13 +++----------
>  1 file changed, 3 insertions(+), 10 deletions(-)
> 
> diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
> index 198fe56..a22ec94 100644
> --- a/source3/lib/g_lock.c
> +++ b/source3/lib/g_lock.c
> @@ -297,18 +297,11 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
>  				goto done;
>  			}
>  			my_lock = i;
> -			break;
> -		}
> -	}
> -
> -	for (i=0; i<num_locks; i++) {
> -
> -		if (i == my_lock) {
>  			continue;
>  		}
>  
> -		if (g_lock_conflicts(type, locks[i].lock_type)) {
> -			struct server_id pid = locks[i].pid;
> +		if (g_lock_conflicts(type, lock->lock_type)) {
> +			struct server_id pid = lock->pid;
>  
>  			/*
>  			 * As the serverid_exists might recurse into
> @@ -319,7 +312,7 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
>  
>  			if (serverid_exists(&pid)) {
>  				status = NT_STATUS_LOCK_NOT_GRANTED;
> -				*blocker = locks[i].pid;
> +				*blocker = lock->pid;
>  				goto done;
>  			}
>  
> -- 
> 2.1.4
> 
> 
> From 0aeadbd41d9dfdf601b18856a8c0e91c807e160a Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Wed, 28 Jun 2017 19:12:36 +0200
> Subject: [PATCH 11/41] g_lock: simplify g_lock_trylock
> 
> The now mandatory talloc_realloc_array will go away soon
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/g_lock.c | 33 ++++++++++++++++++---------------
>  1 file changed, 18 insertions(+), 15 deletions(-)
> 
> diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
> index a22ec94..e93ef3f 100644
> --- a/source3/lib/g_lock.c
> +++ b/source3/lib/g_lock.c
> @@ -257,7 +257,7 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
>  			       struct server_id *blocker)
>  {
>  	TDB_DATA data, userdata;
> -	size_t i, num_locks, my_lock;
> +	size_t i, num_locks;
>  	struct g_lock_rec *locks, *tmp;
>  	NTSTATUS status;
>  	bool modified = false;
> @@ -270,8 +270,6 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
>  		return status;
>  	}
>  
> -	my_lock = num_locks;	/* doesn't exist yet */
> -
>  	if ((type == G_LOCK_READ) && (num_locks > 0)) {
>  		/*
>  		 * Read locks can stay around forever if the process
> @@ -296,7 +294,12 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
>  				status = NT_STATUS_WAS_LOCKED;
>  				goto done;
>  			}
> -			my_lock = i;
> +			/*
> +			 * Remove "our" lock entry. Re-add it later
> +			 * with our new lock type.
> +			 */
> +			locks[i] = locks[num_locks-1];
> +			num_locks -= 1;
>  			continue;
>  		}
>  
> @@ -325,19 +328,19 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
>  		}
>  	}
>  
> -	if (my_lock >= num_locks) {
> -		tmp = talloc_realloc(talloc_tos(), locks, struct g_lock_rec,
> -				     num_locks+1);
> -		if (tmp == NULL) {
> -			status = NT_STATUS_NO_MEMORY;
> -			goto done;
> -		}
> -		locks = tmp;
> -		my_lock = num_locks;
> -		num_locks += 1;
> +	tmp = talloc_realloc(talloc_tos(), locks, struct g_lock_rec,
> +			     num_locks+1);
> +	if (tmp == NULL) {
> +		status = NT_STATUS_NO_MEMORY;
> +		goto done;
>  	}
> +	locks = tmp;
> +
> +	locks[num_locks] = (struct g_lock_rec) {
> +		.pid = self, .lock_type = type
> +	};
> +	num_locks +=1 ;
>  
> -	locks[my_lock] = (struct g_lock_rec){ .pid = self, .lock_type = type };
>  	modified = true;
>  
>  	status = NT_STATUS_OK;
> -- 
> 2.1.4
> 
> 
> From 35934b7fa74ae76313f88da470a139490a64e865 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Wed, 28 Jun 2017 13:36:53 +0200
> Subject: [PATCH 12/41] g_lock: add "struct g_lock" without talloc
> 
> Enable handing the g_lock.tdb content without having to talloc
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/g_lock.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 85 insertions(+)
> 
> diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
> index e93ef3f..e08f6a3 100644
> --- a/source3/lib/g_lock.c
> +++ b/source3/lib/g_lock.c
> @@ -56,6 +56,91 @@ static void g_lock_rec_get(struct g_lock_rec *rec,
>  	server_id_get(&rec->pid, buf+1);
>  }
>  
> +struct g_lock {
> +	uint8_t *recsbuf;
> +	size_t num_recs;
> +	uint8_t *data;
> +	size_t datalen;
> +};
> +
> +static bool g_lock_parse(uint8_t *buf, size_t buflen, struct g_lock *lck)
> +{
> +	size_t found_recs, data_ofs;
> +
> +	if (buflen < sizeof(uint32_t)) {
> +		*lck = (struct g_lock) {0};
> +		return true;
> +	}
> +
> +	found_recs = IVAL(buf, 0);
> +
> +	if (found_recs > buflen/G_LOCK_REC_LENGTH) {
> +		return false;
> +	}
> +
> +	buf += sizeof(uint32_t);
> +	buflen -= sizeof(uint32_t);
> +	data_ofs = found_recs * G_LOCK_REC_LENGTH;
> +
> +	*lck = (struct g_lock) {
> +		.recsbuf = buf, .num_recs = found_recs,
> +		.data = buf+data_ofs, .datalen = buflen-data_ofs
> +	};
> +
> +	return true;
> +}
> +
> +static void g_lock_get_rec(struct g_lock *lck, size_t i,
> +			   struct g_lock_rec *rec)
> +{
> +	if (i >= lck->num_recs) {
> +		abort();
> +	}
> +	g_lock_rec_get(rec, lck->recsbuf + i*G_LOCK_REC_LENGTH);
> +}
> +
> +static void g_lock_rec_del(struct g_lock *lck, size_t i)
> +{
> +	if (i >= lck->num_recs) {
> +		abort();
> +	}
> +	lck->num_recs -= 1;
> +	if (i < lck->num_recs) {
> +		uint8_t *recptr = lck->recsbuf + i*G_LOCK_REC_LENGTH;
> +		memcpy(recptr, lck->recsbuf + lck->num_recs*G_LOCK_REC_LENGTH,
> +		       G_LOCK_REC_LENGTH);
> +	}
> +}
> +
> +static NTSTATUS g_lock_store(struct db_record *rec, struct g_lock *lck,
> +			     struct g_lock_rec *add)
> +{
> +	uint8_t sizebuf[4];
> +	uint8_t addbuf[G_LOCK_REC_LENGTH];
> +
> +	struct TDB_DATA dbufs[] = {
> +		{ .dptr = sizebuf, .dsize = sizeof(sizebuf) },
> +		{ .dptr = lck->recsbuf,
> +		  .dsize = lck->num_recs * G_LOCK_REC_LENGTH },
> +		{ 0 },
> +		{ .dptr = lck->data, .dsize = lck->datalen }
> +	};
> +
> +	if (add != NULL) {
> +		g_lock_rec_put(addbuf, *add);
> +
> +		dbufs[2] = (TDB_DATA) {
> +			.dptr = addbuf, .dsize = G_LOCK_REC_LENGTH
> +		};
> +
> +		lck->num_recs += 1;
> +	}
> +
> +	SIVAL(sizebuf, 0, lck->num_recs);
> +
> +	return dbwrap_record_storev(rec, dbufs, ARRAY_SIZE(dbufs), 0);
> +}
> +
>  static ssize_t g_lock_put(uint8_t *buf, size_t buflen,
>  			  const struct g_lock_rec *locks,
>  			  size_t num_locks,
> -- 
> 2.1.4
> 
> 
> From 79af16a45e34c5207661569d7492104371689f8f Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Wed, 28 Jun 2017 15:39:49 +0200
> Subject: [PATCH 13/41] g_lock: Implement g_lock_unlock without talloc
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/g_lock.c | 91 +++++++++++++++++++++++++++++-----------------------
>  1 file changed, 50 insertions(+), 41 deletions(-)
> 
> diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
> index e08f6a3..7a924b9 100644
> --- a/source3/lib/g_lock.c
> +++ b/source3/lib/g_lock.c
> @@ -601,63 +601,72 @@ NTSTATUS g_lock_lock(struct g_lock_ctx *ctx, const char *name,
>  	return status;
>  }
>  
> -NTSTATUS g_lock_unlock(struct g_lock_ctx *ctx, const char *name)
> -{
> -	struct server_id self = messaging_server_id(ctx->msg);
> -	struct db_record *rec = NULL;
> -	struct g_lock_rec *locks = NULL;
> -	size_t i, num_locks;
> +struct g_lock_unlock_state {
> +	const char *name;
> +	struct server_id self;
>  	NTSTATUS status;
> -	TDB_DATA value, userdata;
> +};
>  
> -	rec = dbwrap_fetch_locked(ctx->db, talloc_tos(),
> -				  string_term_tdb_data(name));
> -	if (rec == NULL) {
> -		DEBUG(10, ("fetch_locked(\"%s\") failed\n", name));
> -		status = NT_STATUS_INTERNAL_ERROR;
> -		goto done;
> -	}
> +static void g_lock_unlock_fn(struct db_record *rec,
> +			     void *private_data)
> +{
> +	struct g_lock_unlock_state *state = private_data;
> +	TDB_DATA value;
> +	struct g_lock lck;
> +	size_t i;
> +	bool ok;
>  
>  	value = dbwrap_record_get_value(rec);
>  
> -	status = g_lock_get_talloc(talloc_tos(), value, &locks, &num_locks,
> -				   &userdata.dptr, &userdata.dsize);
> -	if (!NT_STATUS_IS_OK(status)) {
> -		DBG_DEBUG("g_lock_get for %s failed: %s\n", name,
> -			  nt_errstr(status));
> -		status = NT_STATUS_FILE_INVALID;
> -		goto done;
> +	ok = g_lock_parse(value.dptr, value.dsize, &lck);
> +	if (!ok) {
> +		DBG_DEBUG("g_lock_get for %s failed\n", state->name);
> +		state->status = NT_STATUS_FILE_INVALID;
> +		return;
>  	}
> -	for (i=0; i<num_locks; i++) {
> -		if (serverid_equal(&self, &locks[i].pid)) {
> +	for (i=0; i<lck.num_recs; i++) {
> +		struct g_lock_rec lockrec;
> +		g_lock_get_rec(&lck, i, &lockrec);
> +		if (serverid_equal(&state->self, &lockrec.pid)) {
>  			break;
>  		}
>  	}
> -	if (i == num_locks) {
> -		DBG_DEBUG("Lock not found, num_locks=%zu\n", num_locks);
> -		status = NT_STATUS_NOT_FOUND;
> -		goto done;
> +	if (i == lck.num_recs) {
> +		DBG_DEBUG("Lock not found, num_rec=%zu\n", lck.num_recs);
> +		state->status = NT_STATUS_NOT_FOUND;
> +		return;
>  	}
>  
> -	locks[i] = locks[num_locks-1];
> -	num_locks -= 1;
> +	g_lock_rec_del(&lck, i);
>  
> -	if ((num_locks == 0) && (userdata.dsize == 0)) {
> -		status = dbwrap_record_delete(rec);
> -	} else {
> -		status = g_lock_record_store(
> -			rec, locks, num_locks, userdata.dptr, userdata.dsize);
> +	if ((lck.num_recs == 0) && (lck.datalen == 0)) {
> +		state->status = dbwrap_record_delete(rec);
> +		return;
>  	}
> +	state->status = g_lock_store(rec, &lck, NULL);
> +}
> +
> +NTSTATUS g_lock_unlock(struct g_lock_ctx *ctx, const char *name)
> +{
> +	struct g_lock_unlock_state state = {
> +		.self = messaging_server_id(ctx->msg), .name = name
> +	};
> +	NTSTATUS status;
> +
> +	status = dbwrap_do_locked(ctx->db, string_term_tdb_data(name),
> +				  g_lock_unlock_fn, &state);
>  	if (!NT_STATUS_IS_OK(status)) {
> -		DBG_WARNING("Could not store record: %s\n", nt_errstr(status));
> -		goto done;
> +		DBG_WARNING("dbwrap_do_locked failed: %s\n",
> +			    nt_errstr(status));
> +		return status;
> +	}
> +	if (!NT_STATUS_IS_OK(state.status)) {
> +		DBG_WARNING("g_lock_unlock_fn failed: %s\n",
> +			    nt_errstr(state.status));
> +		return state.status;
>  	}
>  
> -	status = NT_STATUS_OK;
> -done:
> -	TALLOC_FREE(rec);
> -	TALLOC_FREE(locks);
> -	return status;
> +	return NT_STATUS_OK;
>  }
>  
>  NTSTATUS g_lock_write_data(struct g_lock_ctx *ctx, const char *name,
> -- 
> 2.1.4
> 
> 
> From 12e24655135e4cb1fe3603db73fa3fa0e68437b6 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Wed, 5 Jul 2017 12:16:02 +0200
> Subject: [PATCH 14/41] g_lock: Initialize variables
> 
> gcc -O3 complains, but I think this is a false positive
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/g_lock.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
> index 7a924b9..a79a9cc 100644
> --- a/source3/lib/g_lock.c
> +++ b/source3/lib/g_lock.c
> @@ -765,8 +765,8 @@ NTSTATUS g_lock_dump(struct g_lock_ctx *ctx, const char *name,
>  	TDB_DATA data;
>  	size_t num_locks;
>  	struct g_lock_rec *locks = NULL;
> -	uint8_t *userdata;
> -	size_t userdatalen;
> +	uint8_t *userdata = NULL;
> +	size_t userdatalen = 0;
>  	NTSTATUS status;
>  
>  	status = dbwrap_fetch_bystring(ctx->db, talloc_tos(), name, &data);
> -- 
> 2.1.4
> 
> 
> From df73403c69afc391a6ae40f37a82b3e6abf9bc02 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Wed, 28 Jun 2017 19:39:33 +0200
> Subject: [PATCH 15/41] g_lock: Avoid talloc in g_lock_trylock
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/g_lock.c | 67 ++++++++++++++++++++++------------------------------
>  1 file changed, 28 insertions(+), 39 deletions(-)
> 
> diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
> index a79a9cc..7dcede4 100644
> --- a/source3/lib/g_lock.c
> +++ b/source3/lib/g_lock.c
> @@ -341,41 +341,46 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
>  			       enum g_lock_type type,
>  			       struct server_id *blocker)
>  {
> -	TDB_DATA data, userdata;
> -	size_t i, num_locks;
> -	struct g_lock_rec *locks, *tmp;
> +	TDB_DATA data;
> +	size_t i;
> +	struct g_lock lck;
>  	NTSTATUS status;
>  	bool modified = false;
> +	bool ok;
>  
>  	data = dbwrap_record_get_value(rec);
>  
> -	status = g_lock_get_talloc(talloc_tos(), data, &locks, &num_locks,
> -				   &userdata.dptr, &userdata.dsize);
> -	if (!NT_STATUS_IS_OK(status)) {
> -		return status;
> +	ok = g_lock_parse(data.dptr, data.dsize, &lck);
> +	if (!ok) {
> +		return NT_STATUS_INTERNAL_DB_CORRUPTION;
>  	}
>  
> -	if ((type == G_LOCK_READ) && (num_locks > 0)) {
> +	if ((type == G_LOCK_READ) && (lck.num_recs > 0)) {
> +		struct g_lock_rec check_rec;
> +
>  		/*
>  		 * Read locks can stay around forever if the process
>  		 * dies. Do a heuristic check for process existence:
>  		 * Check one random process for existence. Hopefully
>  		 * this will keep runaway read locks under control.
>  		 */
> -		i = generate_random() % num_locks;
> +		i = generate_random() % lck.num_recs;
>  
> -		if (!serverid_exists(&locks[i].pid)) {
> -			locks[i] = locks[num_locks-1];
> -			num_locks -=1;
> +		g_lock_get_rec(&lck, i, &check_rec);
> +
> +		if (!serverid_exists(&check_rec.pid)) {
> +			g_lock_rec_del(&lck, i);
>  			modified = true;
>  		}
>  	}
>  
> -	for (i=0; i<num_locks; i++) {
> -		struct g_lock_rec *lock = &locks[i];
> +	for (i=0; i<lck.num_recs; i++) {
> +		struct g_lock_rec lock;
>  
> -		if (serverid_equal(&self, &lock->pid)) {
> -			if (lock->lock_type == type) {
> +		g_lock_get_rec(&lck, i, &lock);
> +
> +		if (serverid_equal(&self, &lock.pid)) {
> +			if (lock.lock_type == type) {
>  				status = NT_STATUS_WAS_LOCKED;
>  				goto done;
>  			}
> @@ -383,13 +388,12 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
>  			 * Remove "our" lock entry. Re-add it later
>  			 * with our new lock type.
>  			 */
> -			locks[i] = locks[num_locks-1];
> -			num_locks -= 1;
> +			g_lock_rec_del(&lck, i);
>  			continue;
>  		}
>  
> -		if (g_lock_conflicts(type, lock->lock_type)) {
> -			struct server_id pid = lock->pid;
> +		if (g_lock_conflicts(type, lock.lock_type)) {
> +			struct server_id pid = lock.pid;
>  
>  			/*
>  			 * As the serverid_exists might recurse into
> @@ -400,47 +404,32 @@ static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
>  
>  			if (serverid_exists(&pid)) {
>  				status = NT_STATUS_LOCK_NOT_GRANTED;
> -				*blocker = lock->pid;
> +				*blocker = lock.pid;
>  				goto done;
>  			}
>  
>  			/*
>  			 * Delete stale conflicting entry
>  			 */
> -			locks[i] = locks[num_locks-1];
> -			num_locks -= 1;
> +			g_lock_rec_del(&lck, i);
>  			modified = true;
>  		}
>  	}
>  
> -	tmp = talloc_realloc(talloc_tos(), locks, struct g_lock_rec,
> -			     num_locks+1);
> -	if (tmp == NULL) {
> -		status = NT_STATUS_NO_MEMORY;
> -		goto done;
> -	}
> -	locks = tmp;
> -
> -	locks[num_locks] = (struct g_lock_rec) {
> -		.pid = self, .lock_type = type
> -	};
> -	num_locks +=1 ;
> -
>  	modified = true;
>  
>  	status = NT_STATUS_OK;
>  done:
>  	if (modified) {
> +		struct g_lock_rec mylock = { .pid = self, .lock_type = type };
>  		NTSTATUS store_status;
> -		store_status = g_lock_record_store(
> -			rec, locks, num_locks, userdata.dptr, userdata.dsize);
> +		store_status = g_lock_store(rec, &lck, &mylock);
>  		if (!NT_STATUS_IS_OK(store_status)) {
>  			DBG_WARNING("g_lock_record_store failed: %s\n",
>  				    nt_errstr(store_status));
>  			status = store_status;
>  		}
>  	}
> -	TALLOC_FREE(locks);
>  	return status;
>  }
>  
> -- 
> 2.1.4
> 
> 
> From 12bfbc5d50b7b81e039eaa9a680ab708e0ac6f6b Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Wed, 28 Jun 2017 20:01:34 +0200
> Subject: [PATCH 16/41] g_lock: Use dbwrap_do_locked for g_lock_lock
> 
> Don't talloc the record
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/g_lock.c | 64 +++++++++++++++++++++++++++++++++++-----------------
>  1 file changed, 43 insertions(+), 21 deletions(-)
> 
> diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
> index 7dcede4..a6d341f 100644
> --- a/source3/lib/g_lock.c
> +++ b/source3/lib/g_lock.c
> @@ -442,16 +442,38 @@ struct g_lock_lock_state {
>  
>  static void g_lock_lock_retry(struct tevent_req *subreq);
>  
> +struct g_lock_lock_fn_state {
> +	struct g_lock_lock_state *state;
> +	struct server_id self;
> +
> +	struct tevent_req *watch_req;
> +	NTSTATUS status;
> +};
> +
> +static void g_lock_lock_fn(struct db_record *rec, void *private_data)
> +{
> +	struct g_lock_lock_fn_state *state = private_data;
> +	struct server_id blocker;
> +
> +	state->status = g_lock_trylock(rec, state->self, state->state->type,
> +				       &blocker);
> +	if (!NT_STATUS_EQUAL(state->status, NT_STATUS_LOCK_NOT_GRANTED)) {
> +		return;
> +	}
> +
> +	state->watch_req = dbwrap_watched_watch_send(
> +		state->state, state->state->ev, rec, blocker);
> +}
> +
>  struct tevent_req *g_lock_lock_send(TALLOC_CTX *mem_ctx,
>  				    struct tevent_context *ev,
>  				    struct g_lock_ctx *ctx,
>  				    const char *name,
>  				    enum g_lock_type type)
>  {
> -	struct tevent_req *req, *subreq;
> +	struct tevent_req *req;
>  	struct g_lock_lock_state *state;
> -	struct db_record *rec;
> -	struct server_id self, blocker;
> +	struct g_lock_lock_fn_state fn_state;
>  	NTSTATUS status;
>  
>  	req = tevent_req_create(mem_ctx, &state, struct g_lock_lock_state);
> @@ -463,39 +485,39 @@ struct tevent_req *g_lock_lock_send(TALLOC_CTX *mem_ctx,
>  	state->name = name;
>  	state->type = type;
>  
> -	rec = dbwrap_fetch_locked(ctx->db, talloc_tos(),
> -				  string_term_tdb_data(state->name));
> -	if (rec == NULL) {
> -		DEBUG(10, ("fetch_locked(\"%s\") failed\n", name));
> -		tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
> +	fn_state = (struct g_lock_lock_fn_state) {
> +		.state = state, .self = messaging_server_id(ctx->msg)
> +	};
> +
> +	status = dbwrap_do_locked(ctx->db, string_term_tdb_data(name),
> +				  g_lock_lock_fn, &fn_state);
> +	if (tevent_req_nterror(req, status)) {
> +		DBG_DEBUG("dbwrap_do_locked failed: %s\n",
> +			  nt_errstr(status));
>  		return tevent_req_post(req, ev);
>  	}
>  
> -	self = messaging_server_id(state->ctx->msg);
> -
> -	status = g_lock_trylock(rec, self, state->type, &blocker);
> -	if (NT_STATUS_IS_OK(status)) {
> -		TALLOC_FREE(rec);
> +	if (NT_STATUS_IS_OK(fn_state.status)) {
>  		tevent_req_done(req);
>  		return tevent_req_post(req, ev);
>  	}
> -	if (!NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) {
> -		TALLOC_FREE(rec);
> -		tevent_req_nterror(req, status);
> +	if (!NT_STATUS_EQUAL(fn_state.status, NT_STATUS_LOCK_NOT_GRANTED)) {
> +		tevent_req_nterror(req, fn_state.status);
>  		return tevent_req_post(req, ev);
>  	}
> -	subreq = dbwrap_watched_watch_send(state, state->ev, rec, blocker);
> -	TALLOC_FREE(rec);
> -	if (tevent_req_nomem(subreq, req)) {
> +
> +	if (tevent_req_nomem(fn_state.watch_req, req)) {
>  		return tevent_req_post(req, ev);
>  	}
> +
> +
>  	if (!tevent_req_set_endtime(
> -		    subreq, state->ev,
> +		    fn_state.watch_req, state->ev,
>  		    timeval_current_ofs(5 + sys_random() % 5, 0))) {
>  		tevent_req_oom(req);
>  		return tevent_req_post(req, ev);
>  	}
> -	tevent_req_set_callback(subreq, g_lock_lock_retry, req);
> +	tevent_req_set_callback(fn_state.watch_req, g_lock_lock_retry, req);
>  	return req;
>  }
>  
> -- 
> 2.1.4
> 
> 
> From f0434a2f7a87ff721585d7e49f394510306e6cd5 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Fri, 30 Jun 2017 22:20:41 +0200
> Subject: [PATCH 17/41] g_lock: Use dbwrap_do_locked in g_lock_lock_retry
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/g_lock.c | 53 +++++++++++++++++++++++++---------------------------
>  1 file changed, 25 insertions(+), 28 deletions(-)
> 
> diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
> index a6d341f..3c4bcbf 100644
> --- a/source3/lib/g_lock.c
> +++ b/source3/lib/g_lock.c
> @@ -510,7 +510,6 @@ struct tevent_req *g_lock_lock_send(TALLOC_CTX *mem_ctx,
>  		return tevent_req_post(req, ev);
>  	}
>  
> -
>  	if (!tevent_req_set_endtime(
>  		    fn_state.watch_req, state->ev,
>  		    timeval_current_ofs(5 + sys_random() % 5, 0))) {
> @@ -527,54 +526,52 @@ static void g_lock_lock_retry(struct tevent_req *subreq)
>  		subreq, struct tevent_req);
>  	struct g_lock_lock_state *state = tevent_req_data(
>  		req, struct g_lock_lock_state);
> -	struct server_id self = messaging_server_id(state->ctx->msg);
> -	struct server_id blocker;
> -	struct db_record *rec;
> +	struct g_lock_lock_fn_state fn_state;
>  	NTSTATUS status;
>  
> -	status = dbwrap_watched_watch_recv(subreq, talloc_tos(), &rec, NULL,
> -					   NULL);
> +	status = dbwrap_watched_watch_recv(subreq, NULL, NULL, NULL, NULL);
> +	DBG_DEBUG("watch_recv returned %s\n", nt_errstr(status));
>  	TALLOC_FREE(subreq);
>  
> -	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
> -		rec = dbwrap_fetch_locked(
> -			state->ctx->db, talloc_tos(),
> -			string_term_tdb_data(state->name));
> -		if (rec == NULL) {
> -			status = map_nt_error_from_unix(errno);
> -		} else {
> -			status = NT_STATUS_OK;
> -		}
> +	if (!NT_STATUS_IS_OK(status) &&
> +	    !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
> +		tevent_req_nterror(req, status);
> +		return;
>  	}
>  
> +	fn_state = (struct g_lock_lock_fn_state) {
> +		.state = state, .self = messaging_server_id(state->ctx->msg)
> +	};
> +
> +	status = dbwrap_do_locked(state->ctx->db,
> +				  string_term_tdb_data(state->name),
> +				  g_lock_lock_fn, &fn_state);
>  	if (tevent_req_nterror(req, status)) {
> +		DBG_DEBUG("dbwrap_do_locked failed: %s\n",
> +			  nt_errstr(status));
>  		return;
>  	}
> -	status = g_lock_trylock(rec, self, state->type, &blocker);
> -	if (NT_STATUS_IS_OK(status)) {
> -		TALLOC_FREE(rec);
> +
> +	if (NT_STATUS_IS_OK(fn_state.status)) {
>  		tevent_req_done(req);
>  		return;
>  	}
> -	if (!NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) {
> -		TALLOC_FREE(rec);
> -		tevent_req_nterror(req, status);
> +	if (!NT_STATUS_EQUAL(fn_state.status, NT_STATUS_LOCK_NOT_GRANTED)) {
> +		tevent_req_nterror(req, fn_state.status);
>  		return;
>  	}
> -	subreq = dbwrap_watched_watch_send(state, state->ev, rec, blocker);
> -	TALLOC_FREE(rec);
> -	if (tevent_req_nomem(subreq, req)) {
> +
> +	if (tevent_req_nomem(fn_state.watch_req, req)) {
>  		return;
>  	}
> +
>  	if (!tevent_req_set_endtime(
> -		    subreq, state->ev,
> +		    fn_state.watch_req, state->ev,
>  		    timeval_current_ofs(5 + sys_random() % 5, 0))) {
>  		tevent_req_oom(req);
>  		return;
>  	}
> -	tevent_req_set_callback(subreq, g_lock_lock_retry, req);
> -	return;
> -
> +	tevent_req_set_callback(fn_state.watch_req, g_lock_lock_retry, req);
>  }
>  
>  NTSTATUS g_lock_lock_recv(struct tevent_req *req)
> -- 
> 2.1.4
> 
> 
> From 1beeb25069057c9f4d580eadaf0d2b85eb823c11 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Mon, 3 Jul 2017 08:09:18 +0200
> Subject: [PATCH 18/41] torture3: Add verification for g_lock_retry
> 
> During development I had a bug that would have been found early
> by this
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/torture/test_g_lock.c | 52 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 52 insertions(+)
> 
> diff --git a/source3/torture/test_g_lock.c b/source3/torture/test_g_lock.c
> index 61ec69d..253d20c 100644
> --- a/source3/torture/test_g_lock.c
> +++ b/source3/torture/test_g_lock.c
> @@ -397,6 +397,41 @@ static void lock4_waited(struct tevent_req *subreq)
>  	printf("child %d exited with %d\n", (int)child, status);
>  }
>  
> +struct lock4_check_state {
> +	struct server_id me;
> +	bool ok;
> +};
> +
> +static void lock4_check(const struct g_lock_rec *locks,
> +			size_t num_locks,
> +			const uint8_t *data,
> +			size_t datalen,
> +			void *private_data)
> +{
> +	struct lock4_check_state *state = private_data;
> +
> +	if (num_locks != 1) {
> +		fprintf(stderr, "num_locks=%zu\n", num_locks);
> +		return;
> +	}
> +
> +	if (!serverid_equal(&state->me, &locks[0].pid)) {
> +		struct server_id_buf buf1, buf2;
> +		fprintf(stderr, "me=%s, locker=%s\n",
> +			server_id_str_buf(state->me, &buf1),
> +			server_id_str_buf(locks[0].pid, &buf2));
> +		return;
> +	}
> +
> +	if (locks[0].lock_type != G_LOCK_WRITE) {
> +		fprintf(stderr, "wrong lock type: %d\n",
> +			(int)locks[0].lock_type);
> +		return;
> +	}
> +
> +	state->ok = true;
> +}
> +
>  /*
>   * Test a lock conflict
>   */
> @@ -493,6 +528,23 @@ bool run_g_lock4(int dummy)
>  		}
>  	}
>  
> +	{
> +		struct lock4_check_state state = {
> +			.me = messaging_server_id(msg)
> +		};
> +
> +		status = g_lock_dump(ctx, lockname, lock4_check, &state);
> +		if (!NT_STATUS_IS_OK(status)) {
> +			fprintf(stderr, "g_lock_dump failed: %s\n",
> +				nt_errstr(status));
> +			goto fail;
> +		}
> +		if (!state.ok) {
> +			fprintf(stderr, "lock4_check failed\n");
> +			goto fail;
> +		}
> +	}
> +
>  	ret = true;
>  fail:
>  	TALLOC_FREE(ctx);
> -- 
> 2.1.4
> 
> 
> From f48527c3a8d4328f4997e596fe40b34eb00bc8e3 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Fri, 30 Jun 2017 19:42:50 +0200
> Subject: [PATCH 19/41] g_lock: Use dbwrap_do_locked in g_lock_write_data
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/g_lock.c | 88 ++++++++++++++++++++++++++++++++--------------------
>  1 file changed, 54 insertions(+), 34 deletions(-)
> 
> diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
> index 3c4bcbf..25d9629 100644
> --- a/source3/lib/g_lock.c
> +++ b/source3/lib/g_lock.c
> @@ -677,53 +677,73 @@ NTSTATUS g_lock_unlock(struct g_lock_ctx *ctx, const char *name)
>  	return NT_STATUS_OK;
>  }
>  
> -NTSTATUS g_lock_write_data(struct g_lock_ctx *ctx, const char *name,
> -			   const uint8_t *buf, size_t buflen)
> -{
> -	struct server_id self = messaging_server_id(ctx->msg);
> -	struct db_record *rec = NULL;
> -	struct g_lock_rec *locks = NULL;
> -	size_t i, num_locks;
> +struct g_lock_write_data_state {
> +	const char *name;
> +	struct server_id self;
> +	const uint8_t *data;
> +	size_t datalen;
>  	NTSTATUS status;
> -	TDB_DATA value;
> +};
>  
> -	rec = dbwrap_fetch_locked(ctx->db, talloc_tos(),
> -				  string_term_tdb_data(name));
> -	if (rec == NULL) {
> -		DEBUG(10, ("fetch_locked(\"%s\") failed\n", name));
> -		status = NT_STATUS_INTERNAL_ERROR;
> -		goto done;
> -	}
> +static void g_lock_write_data_fn(struct db_record *rec,
> +				 void *private_data)
> +{
> +	struct g_lock_write_data_state *state = private_data;
> +	TDB_DATA value;
> +	struct g_lock lck;
> +	size_t i;
> +	bool ok;
>  
>  	value = dbwrap_record_get_value(rec);
>  
> -	status = g_lock_get_talloc(talloc_tos(), value, &locks, &num_locks,
> -				   NULL, NULL);
> -	if (!NT_STATUS_IS_OK(status)) {
> -		DBG_DEBUG("g_lock_get for %s failed: %s\n", name,
> -			  nt_errstr(status));
> -		status = NT_STATUS_FILE_INVALID;
> -		goto done;
> +	ok = g_lock_parse(value.dptr, value.dsize, &lck);
> +	if (!ok) {
> +		DBG_DEBUG("g_lock_parse for %s failed\n", state->name);
> +		state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
> +		return;
>  	}
> -
> -	for (i=0; i<num_locks; i++) {
> -		if (server_id_equal(&self, &locks[i].pid) &&
> -		    (locks[i].lock_type == G_LOCK_WRITE)) {
> +	for (i=0; i<lck.num_recs; i++) {
> +		struct g_lock_rec lockrec;
> +		g_lock_get_rec(&lck, i, &lockrec);
> +		if ((lockrec.lock_type == G_LOCK_WRITE) &&
> +		    serverid_equal(&state->self, &lockrec.pid)) {
>  			break;
>  		}
>  	}
> -	if (i == num_locks) {
> +	if (i == lck.num_recs) {
>  		DBG_DEBUG("Not locked by us\n");
> -		status = NT_STATUS_NOT_LOCKED;
> -		goto done;
> +		state->status = NT_STATUS_NOT_LOCKED;
> +		return;
>  	}
>  
> -	status = g_lock_record_store(rec, locks, num_locks, buf, buflen);
> +	lck.data = discard_const_p(uint8_t, state->data);
> +	lck.datalen = state->datalen;
> +	state->status = g_lock_store(rec, &lck, NULL);
> +}
>  
> -done:
> -	TALLOC_FREE(locks);
> -	TALLOC_FREE(rec);
> -	return status;
> +NTSTATUS g_lock_write_data(struct g_lock_ctx *ctx, const char *name,
> +			   const uint8_t *buf, size_t buflen)
> +{
> +	struct g_lock_write_data_state state = {
> +		.name = name, .self = messaging_server_id(ctx->msg),
> +		.data = buf, .datalen = buflen
> +	};
> +	NTSTATUS status;
> +
> +	status = dbwrap_do_locked(ctx->db, string_term_tdb_data(name),
> +				  g_lock_write_data_fn, &state);
> +	if (!NT_STATUS_IS_OK(status)) {
> +		DBG_WARNING("dbwrap_do_locked failed: %s\n",
> +			    nt_errstr(status));
> +		return status;
> +	}
> +	if (!NT_STATUS_IS_OK(state.status)) {
> +		DBG_WARNING("g_lock_write_data_fn failed: %s\n",
> +			    nt_errstr(state.status));
> +		return state.status;
> +	}
> +
> +	return NT_STATUS_OK;
>  }
>  
>  struct g_lock_locks_state {
> -- 
> 2.1.4
> 
> 
> From c018d3cab53282f8f5b9b50eb3875f327c479711 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Fri, 30 Jun 2017 22:09:12 +0200
> Subject: [PATCH 20/41] g_lock: Use parse_record in g_lock_dump
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/g_lock.c | 84 +++++++++++++++++++++++++++++++++++++---------------
>  1 file changed, 60 insertions(+), 24 deletions(-)
> 
> diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
> index 25d9629..9b971ae 100644
> --- a/source3/lib/g_lock.c
> +++ b/source3/lib/g_lock.c
> @@ -782,6 +782,54 @@ int g_lock_locks(struct g_lock_ctx *ctx,
>  	return count;
>  }
>  
> +struct g_lock_dump_state {
> +	TALLOC_CTX *mem_ctx;
> +	const char *name;
> +	void (*fn)(const struct g_lock_rec *locks,
> +		   size_t num_locks,
> +		   const uint8_t *data,
> +		   size_t datalen,
> +		   void *private_data);
> +	void *private_data;
> +	NTSTATUS status;
> +};
> +
> +static void g_lock_dump_fn(TDB_DATA key, TDB_DATA data,
> +			   void *private_data)
> +{
> +	struct g_lock_dump_state *state = private_data;
> +	struct g_lock_rec *recs;
> +	struct g_lock lck;
> +	size_t i;
> +	bool ok;
> +
> +	ok = g_lock_parse(data.dptr, data.dsize, &lck);
> +	if (!ok) {
> +		DBG_DEBUG("g_lock_parse failed for %s\n",
> +			  state->name);
> +		state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
> +		return;
> +	}
> +
> +	recs = talloc_array(state->mem_ctx, struct g_lock_rec, lck.num_recs);
> +	if (recs == NULL) {
> +		DBG_DEBUG("talloc failed\n");
> +		state->status = NT_STATUS_NO_MEMORY;
> +		return;
> +	}
> +
> +	for (i=0; i<lck.num_recs; i++) {
> +		g_lock_get_rec(&lck, i, &recs[i]);
> +	}
> +
> +	state->fn(recs, lck.num_recs, lck.data, lck.datalen,
> +		  state->private_data);
> +
> +	TALLOC_FREE(recs);
> +
> +	state->status = NT_STATUS_OK;
> +}
> +
>  NTSTATUS g_lock_dump(struct g_lock_ctx *ctx, const char *name,
>  		     void (*fn)(const struct g_lock_rec *locks,
>  				size_t num_locks,
> @@ -790,36 +838,24 @@ NTSTATUS g_lock_dump(struct g_lock_ctx *ctx, const char *name,
>  				void *private_data),
>  		     void *private_data)
>  {
> -	TDB_DATA data;
> -	size_t num_locks;
> -	struct g_lock_rec *locks = NULL;
> -	uint8_t *userdata = NULL;
> -	size_t userdatalen = 0;
> +	struct g_lock_dump_state state = {
> +		.mem_ctx = ctx, .name = name,
> +		.fn = fn, .private_data = private_data
> +	};
>  	NTSTATUS status;
>  
> -	status = dbwrap_fetch_bystring(ctx->db, talloc_tos(), name, &data);
> +	status = dbwrap_parse_record(ctx->db, string_term_tdb_data(name),
> +				     g_lock_dump_fn, &state);
>  	if (!NT_STATUS_IS_OK(status)) {
> +		DBG_DEBUG("dbwrap_parse_record returned %s\n",
> +			  nt_errstr(status));
>  		return status;
>  	}
> -
> -	if ((data.dsize == 0) || (data.dptr == NULL)) {
> -		return NT_STATUS_OK;
> -	}
> -
> -	status = g_lock_get_talloc(talloc_tos(), data, &locks, &num_locks,
> -				   &userdata, &userdatalen);
> -
> -	if (!NT_STATUS_IS_OK(status)) {
> -		DBG_DEBUG("g_lock_get for %s failed: %s\n", name,
> -			  nt_errstr(status));
> -		TALLOC_FREE(data.dptr);
> -		return NT_STATUS_INTERNAL_ERROR;
> +	if (!NT_STATUS_IS_OK(state.status)) {
> +		DBG_DEBUG("g_lock_dump_fn returned %s\n",
> +			  nt_errstr(state.status));
> +		return state.status;
>  	}
> -
> -	fn(locks, num_locks, userdata, userdatalen, private_data);
> -
> -	TALLOC_FREE(locks);
> -	TALLOC_FREE(data.dptr);
>  	return NT_STATUS_OK;
>  }
>  
> -- 
> 2.1.4
> 
> 
> From cd82f112847a8149342ee8a23cf4a8e765bf3765 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Fri, 30 Jun 2017 22:14:58 +0200
> Subject: [PATCH 21/41] g_lock: Remove unused code
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/g_lock.c | 144 ---------------------------------------------------
>  1 file changed, 144 deletions(-)
> 
> diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
> index 9b971ae..8709052 100644
> --- a/source3/lib/g_lock.c
> +++ b/source3/lib/g_lock.c
> @@ -141,121 +141,6 @@ static NTSTATUS g_lock_store(struct db_record *rec, struct g_lock *lck,
>  	return dbwrap_record_storev(rec, dbufs, ARRAY_SIZE(dbufs), 0);
>  }
>  
> -static ssize_t g_lock_put(uint8_t *buf, size_t buflen,
> -			  const struct g_lock_rec *locks,
> -			  size_t num_locks,
> -			  const uint8_t *data, size_t datalen)
> -{
> -	size_t i, len, ofs;
> -
> -	if (num_locks > UINT32_MAX/G_LOCK_REC_LENGTH) {
> -		return -1;
> -	}
> -
> -	len = num_locks * G_LOCK_REC_LENGTH;
> -
> -	len += sizeof(uint32_t);
> -	if (len < sizeof(uint32_t)) {
> -		return -1;
> -	}
> -
> -	len += datalen;
> -	if (len < datalen) {
> -		return -1;
> -	}
> -
> -	if (len > buflen) {
> -		return len;
> -	}
> -
> -	ofs = 0;
> -	SIVAL(buf, ofs, num_locks);
> -	ofs += sizeof(uint32_t);
> -
> -	for (i=0; i<num_locks; i++) {
> -		g_lock_rec_put(buf+ofs, locks[i]);
> -		ofs += G_LOCK_REC_LENGTH;
> -	}
> -
> -	if ((data != NULL) && (datalen != 0)) {
> -		memcpy(buf+ofs, data, datalen);
> -	}
> -
> -	return len;
> -}
> -
> -static ssize_t g_lock_get(TDB_DATA recval,
> -			  struct g_lock_rec *locks, size_t num_locks,
> -			  uint8_t **data, size_t *datalen)
> -{
> -	size_t found_locks;
> -
> -	if (recval.dsize < sizeof(uint32_t)) {
> -		/* Fresh or invalid record */
> -		found_locks = 0;
> -		goto done;
> -	}
> -
> -	found_locks = IVAL(recval.dptr, 0);
> -	recval.dptr += sizeof(uint32_t);
> -	recval.dsize -= sizeof(uint32_t);
> -
> -	if (found_locks > recval.dsize/G_LOCK_REC_LENGTH) {
> -		/* Invalid record */
> -		return 0;
> -	}
> -
> -	if (found_locks <= num_locks) {
> -		size_t i;
> -
> -		for (i=0; i<found_locks; i++) {
> -			g_lock_rec_get(&locks[i], recval.dptr);
> -			recval.dptr += G_LOCK_REC_LENGTH;
> -			recval.dsize -= G_LOCK_REC_LENGTH;
> -		}
> -	} else {
> -		/*
> -		 * Not enough space passed in by the caller, don't
> -		 * parse the locks.
> -		 */
> -		recval.dptr += found_locks * G_LOCK_REC_LENGTH;
> -		recval.dsize -= found_locks * G_LOCK_REC_LENGTH;
> -	}
> -
> -done:
> -	if (data != NULL) {
> -		*data = recval.dptr;
> -	}
> -	if (datalen != NULL) {
> -		*datalen = recval.dsize;
> -	}
> -	return found_locks;
> -}
> -
> -static NTSTATUS g_lock_get_talloc(TALLOC_CTX *mem_ctx, TDB_DATA recval,
> -				  struct g_lock_rec **plocks,
> -				  size_t *pnum_locks,
> -				  uint8_t **data, size_t *datalen)
> -{
> -	struct g_lock_rec *locks;
> -	ssize_t num_locks;
> -
> -	num_locks = g_lock_get(recval, NULL, 0, NULL, NULL);
> -	if (num_locks == -1) {
> -		return NT_STATUS_INTERNAL_DB_CORRUPTION;
> -	}
> -	locks = talloc_array(mem_ctx, struct g_lock_rec, num_locks);
> -	if (locks == NULL) {
> -		return NT_STATUS_NO_MEMORY;
> -	}
> -	g_lock_get(recval, locks, num_locks, data, datalen);
> -
> -	*plocks = locks;
> -	*pnum_locks = num_locks;
> -
> -	return NT_STATUS_OK;
> -}
> -
>  struct g_lock_ctx *g_lock_ctx_init(TALLOC_CTX *mem_ctx,
>  				   struct messaging_context *msg)
>  {
> @@ -308,35 +193,6 @@ static bool g_lock_conflicts(enum g_lock_type l1, enum g_lock_type l2)
>  	return true;
>  }
>  
> -static NTSTATUS g_lock_record_store(struct db_record *rec,
> -				    const struct g_lock_rec *locks,
> -				    size_t num_locks,
> -				    const uint8_t *data, size_t datalen)
> -{
> -	ssize_t len;
> -	uint8_t *buf;
> -	NTSTATUS status;
> -
> -	len = g_lock_put(NULL, 0, locks, num_locks, data, datalen);
> -	if (len == -1) {
> -		return NT_STATUS_BUFFER_TOO_SMALL;
> -	}
> -
> -	buf = talloc_array(rec, uint8_t, len);
> -	if (buf == NULL) {
> -		return NT_STATUS_NO_MEMORY;
> -	}
> -
> -	g_lock_put(buf, len, locks, num_locks, data, datalen);
> -
> -	status = dbwrap_record_store(
> -		rec, (TDB_DATA) { .dptr = buf, .dsize = len }, 0);
> -
> -	TALLOC_FREE(buf);
> -
> -	return status;
> -}
> -
>  static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
>  			       enum g_lock_type type,
>  			       struct server_id *blocker)
> -- 
> 2.1.4
> 
> 
> From 5a7ed6737f91afaf5b353ed731457e9bf7982eb1 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Sat, 17 Jun 2017 15:43:14 +0200
> Subject: [PATCH 22/41] messaging: Factor out messaging_dispatch_waiters
> 
> No real code change: This makes dispatching to non-classic receives available
> for other callers.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/messages.c | 56 +++++++++++++++++++++++++++++---------------------
>  1 file changed, 33 insertions(+), 23 deletions(-)
> 
> diff --git a/source3/lib/messages.c b/source3/lib/messages.c
> index b94a696..02aa16c 100644
> --- a/source3/lib/messages.c
> +++ b/source3/lib/messages.c
> @@ -87,6 +87,9 @@ struct messaging_context {
>  
>  static struct messaging_rec *messaging_rec_dup(TALLOC_CTX *mem_ctx,
>  					       struct messaging_rec *rec);
> +static bool messaging_dispatch_waiters(struct messaging_context *msg_ctx,
> +				       struct tevent_context *ev,
> +				       struct messaging_rec *rec);
>  static void messaging_dispatch_rec(struct messaging_context *msg_ctx,
>  				   struct tevent_context *ev,
>  				   struct messaging_rec *rec);
> @@ -966,32 +969,14 @@ static bool messaging_dispatch_classic(struct messaging_context *msg_ctx,
>  	return false;
>  }
>  
> -/*
> -  Dispatch one messaging_rec
> -*/
> -static void messaging_dispatch_rec(struct messaging_context *msg_ctx,
> -				   struct tevent_context *ev,
> -				   struct messaging_rec *rec)
> +static bool messaging_dispatch_waiters(struct messaging_context *msg_ctx,
> +				       struct tevent_context *ev,
> +				       struct messaging_rec *rec)
>  {
>  	size_t i;
> -	bool consumed;
> -
> -	if (ev == msg_ctx->event_ctx) {
> -		consumed = messaging_dispatch_classic(msg_ctx, rec);
> -		if (consumed) {
> -			return;
> -		}
> -	}
>  
>  	if (!messaging_append_new_waiters(msg_ctx)) {
> -		size_t j;
> -		for (j=0; j < rec->num_fds; j++) {
> -			int fd = rec->fds[j];
> -			close(fd);
> -		}
> -		rec->num_fds = 0;
> -		rec->fds = NULL;
> -		return;
> +		return false;
>  	}
>  
>  	i = 0;
> @@ -1022,12 +1007,37 @@ static void messaging_dispatch_rec(struct messaging_context *msg_ctx,
>  		if ((ev == state->ev) &&
>  		    state->filter(rec, state->private_data)) {
>  			messaging_filtered_read_done(req, rec);
> -			return;
> +			return true;
>  		}
>  
>  		i += 1;
>  	}
>  
> +	return false;
> +}
> +
> +/*
> +  Dispatch one messaging_rec
> +*/
> +static void messaging_dispatch_rec(struct messaging_context *msg_ctx,
> +				   struct tevent_context *ev,
> +				   struct messaging_rec *rec)
> +{
> +	bool consumed;
> +	size_t i;
> +
> +	if (ev == msg_ctx->event_ctx) {
> +		consumed = messaging_dispatch_classic(msg_ctx, rec);
> +		if (consumed) {
> +			return;
> +		}
> +	}
> +
> +	consumed = messaging_dispatch_waiters(msg_ctx, ev, rec);
> +	if (consumed) {
> +		return;
> +	}
> +
>  	if (ev != msg_ctx->event_ctx) {
>  		struct iovec iov;
>  		int fds[rec->num_fds];
> -- 
> 2.1.4
> 
> 
> From 51f1f74184fdd0b6e0d6aa636ba57f9e59c0a697 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Sat, 17 Jun 2017 08:48:35 +0200
> Subject: [PATCH 23/41] messaging: Add DLIST pointers to messaging_rec
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  librpc/idl/messaging.idl | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/librpc/idl/messaging.idl b/librpc/idl/messaging.idl
> index b962ab1..37f8fcc 100644
> --- a/librpc/idl/messaging.idl
> +++ b/librpc/idl/messaging.idl
> @@ -159,6 +159,8 @@ interface messaging
>  	/* messaging struct sent across the sockets and stored in the tdb */
>  
>  	typedef [public] struct {
> +		[skip] messaging_rec *prev;
> +		[skip] messaging_rec *next;
>  		uint32 msg_version;
>  		messaging_type msg_type;
>  		server_id dest;
> -- 
> 2.1.4
> 
> 
> From 42dce196fc5d4b25c1aa3361d16aa5abbc8c058a Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Thu, 22 Jun 2017 08:34:34 +0200
> Subject: [PATCH 24/41] messaging: Keep an array of event contexts registered
> 
> This is done with an explicit reference-counting and without talloc
> destructors. The code is isolated enough for now that explicit refcount
> management seems simpler. This might change in the future, but for
> now keep it simple.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/messages.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 96 insertions(+)
> 
> diff --git a/source3/lib/messages.c b/source3/lib/messages.c
> index 02aa16c..61005ab 100644
> --- a/source3/lib/messages.c
> +++ b/source3/lib/messages.c
> @@ -68,11 +68,18 @@ struct messaging_callback {
>  	void *private_data;
>  };
>  
> +struct messaging_registered_ev {
> +	struct tevent_context *ev;
> +	size_t refcount;
> +};
> +
>  struct messaging_context {
>  	struct server_id id;
>  	struct tevent_context *event_ctx;
>  	struct messaging_callback *callbacks;
>  
> +	struct messaging_registered_ev *event_contexts;
> +
>  	struct tevent_req **new_waiters;
>  	size_t num_new_waiters;
>  
> @@ -160,6 +167,76 @@ struct messaging_rec *messaging_rec_create(
>  	return result;
>  }
>  
> +static bool messaging_register_event_context(struct messaging_context *ctx,
> +					     struct tevent_context *ev)
> +{
> +	size_t i, num_event_contexts;
> +	struct messaging_registered_ev *free_reg = NULL;
> +	struct messaging_registered_ev *tmp;
> +
> +	num_event_contexts = talloc_array_length(ctx->event_contexts);
> +
> +	for (i=0; i<num_event_contexts; i++) {
> +		struct messaging_registered_ev *reg = &ctx->event_contexts[i];
> +
> +		if (reg->ev == ev) {
> +			reg->refcount += 1;
> +			return true;
> +		}
> +		if (reg->refcount == 0) {
> +			if (reg->ev != NULL) {
> +				abort();
> +			}
> +			free_reg = reg;
> +		}
> +	}
> +
> +	if (free_reg == NULL) {
> +		tmp = talloc_realloc(ctx, ctx->event_contexts,
> +				     struct messaging_registered_ev,
> +				     num_event_contexts+1);
> +		if (tmp == NULL) {
> +			return false;
> +		}
> +		ctx->event_contexts = tmp;
> +
> +		free_reg = &ctx->event_contexts[num_event_contexts];
> +	}
> +
> +	*free_reg = (struct messaging_registered_ev) { .ev = ev, .refcount = 1 };
> +
> +	return true;
> +}
> +
> +static bool messaging_deregister_event_context(struct messaging_context *ctx,
> +					       struct tevent_context *ev)
> +{
> +	size_t i, num_event_contexts;
> +
> +	num_event_contexts = talloc_array_length(ctx->event_contexts);
> +
> +	for (i=0; i<num_event_contexts; i++) {
> +		struct messaging_registered_ev *reg = &ctx->event_contexts[i];
> +
> +		if (reg->ev == ev) {
> +			if (reg->refcount == 0) {
> +				return false;
> +			}
> +			reg->refcount -= 1;
> +
> +			if (reg->refcount == 0) {
> +				/*
> +				 * Not strictly necessary, just
> +				 * paranoia
> +				 */
> +				reg->ev = NULL;
> +			}
> +			return true;
> +		}
> +	}
> +	return false;
> +}
> +
>  static void messaging_recv_cb(struct tevent_context *ev,
>  			      const uint8_t *msg, size_t msg_len,
>  			      int *fds, size_t num_fds,
> @@ -295,6 +372,12 @@ static NTSTATUS messaging_init_internal(TALLOC_CTX *mem_ctx,
>  
>  	ctx->event_ctx = ev;
>  
> +	ok = messaging_register_event_context(ctx, ev);
> +	if (!ok) {
> +		status = NT_STATUS_NO_MEMORY;
> +		goto done;
> +	}
> +
>  	sec_init();
>  
>  	ctx->msg_dgm_ref = messaging_dgm_ref(ctx,
> @@ -716,6 +799,7 @@ struct tevent_req *messaging_filtered_read_send(
>  	struct tevent_req *req;
>  	struct messaging_filtered_read_state *state;
>  	size_t new_waiters_len;
> +	bool ok;
>  
>  	req = tevent_req_create(mem_ctx, &state,
>  				struct messaging_filtered_read_state);
> @@ -763,6 +847,12 @@ struct tevent_req *messaging_filtered_read_send(
>  	msg_ctx->num_new_waiters += 1;
>  	tevent_req_set_cleanup_fn(req, messaging_filtered_read_cleanup);
>  
> +	ok = messaging_register_event_context(msg_ctx, ev);
> +	if (!ok) {
> +		tevent_req_oom(req);
> +		return tevent_req_post(req, ev);
> +	}
> +
>  	return req;
>  }
>  
> @@ -773,11 +863,17 @@ static void messaging_filtered_read_cleanup(struct tevent_req *req,
>  		req, struct messaging_filtered_read_state);
>  	struct messaging_context *msg_ctx = state->msg_ctx;
>  	size_t i;
> +	bool ok;
>  
>  	tevent_req_set_cleanup_fn(req, NULL);
>  
>  	TALLOC_FREE(state->fde);
>  
> +	ok = messaging_deregister_event_context(msg_ctx, state->ev);
> +	if (!ok) {
> +		abort();
> +	}
> +
>  	/*
>  	 * Just set the [new_]waiters entry to NULL, be careful not to mess
>  	 * with the other "waiters" array contents. We are often called from
> -- 
> 2.1.4
> 
> 
> From b3a18d4cb8468b78a10320b9028c9bc8a6221b3a Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Thu, 22 Jun 2017 08:54:56 +0200
> Subject: [PATCH 25/41] messaging: Broadcast messages to all event contexts
> 
> We must give all event contexts that might be interested the chance to pick up
> the message. If we send a message to ourselves via messaging_send_iov_from,
> nested event contexts need to get a chance to see the message. Before this
> patch only the main event context in msg_ctx got it.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/messages.c | 165 +++++++++++++++++++++++++++++++++++++------------
>  1 file changed, 127 insertions(+), 38 deletions(-)
> 
> diff --git a/source3/lib/messages.c b/source3/lib/messages.c
> index 61005ab..5c10013 100644
> --- a/source3/lib/messages.c
> +++ b/source3/lib/messages.c
> @@ -70,6 +70,7 @@ struct messaging_callback {
>  
>  struct messaging_registered_ev {
>  	struct tevent_context *ev;
> +	struct tevent_immediate *im;
>  	size_t refcount;
>  };
>  
> @@ -78,6 +79,8 @@ struct messaging_context {
>  	struct tevent_context *event_ctx;
>  	struct messaging_callback *callbacks;
>  
> +	struct messaging_rec *posted_msgs;
> +
>  	struct messaging_registered_ev *event_contexts;
>  
>  	struct tevent_req **new_waiters;
> @@ -94,6 +97,8 @@ struct messaging_context {
>  
>  static struct messaging_rec *messaging_rec_dup(TALLOC_CTX *mem_ctx,
>  					       struct messaging_rec *rec);
> +static bool messaging_dispatch_classic(struct messaging_context *msg_ctx,
> +				       struct messaging_rec *rec);
>  static bool messaging_dispatch_waiters(struct messaging_context *msg_ctx,
>  				       struct tevent_context *ev,
>  				       struct messaging_rec *rec);
> @@ -230,6 +235,11 @@ static bool messaging_deregister_event_context(struct messaging_context *ctx,
>  				 * paranoia
>  				 */
>  				reg->ev = NULL;
> +
> +				/*
> +				 * Do not talloc_free(reg->im),
> +				 * recycle immediates events.
> +				 */
>  			}
>  			return true;
>  		}
> @@ -237,6 +247,105 @@ static bool messaging_deregister_event_context(struct messaging_context *ctx,
>  	return false;
>  }
>  
> +static void messaging_post_main_event_context(struct tevent_context *ev,
> +					      struct tevent_immediate *im,
> +					      void *private_data)
> +{
> +	struct messaging_context *ctx = talloc_get_type_abort(
> +		private_data, struct messaging_context);
> +
> +	while (ctx->posted_msgs != NULL) {
> +		struct messaging_rec *rec = ctx->posted_msgs;
> +		bool consumed;
> +
> +		DLIST_REMOVE(ctx->posted_msgs, rec);
> +
> +		consumed = messaging_dispatch_classic(ctx, rec);
> +		if (!consumed) {
> +			consumed = messaging_dispatch_waiters(
> +				ctx, ctx->event_ctx, rec);
> +		}
> +
> +		if (!consumed) {
> +			uint8_t i;
> +
> +			for (i=0; i<rec->num_fds; i++) {
> +				close(rec->fds[i]);
> +			}
> +		}
> +
> +		TALLOC_FREE(rec);
> +	}
> +}
> +
> +static void messaging_post_sub_event_context(struct tevent_context *ev,
> +					     struct tevent_immediate *im,
> +					     void *private_data)
> +{
> +	struct messaging_context *ctx = talloc_get_type_abort(
> +		private_data, struct messaging_context);
> +	struct messaging_rec *rec, *next;
> +
> +	for (rec = ctx->posted_msgs; rec != NULL; rec = next) {
> +		bool consumed;
> +
> +		next = rec->next;
> +
> +		consumed = messaging_dispatch_waiters(ctx, ev, rec);
> +		if (consumed) {
> +			DLIST_REMOVE(ctx->posted_msgs, rec);
> +			TALLOC_FREE(rec);
> +		}
> +	}
> +}
> +
> +static bool messaging_alert_event_contexts(struct messaging_context *ctx)
> +{
> +	size_t i, num_event_contexts;
> +
> +	num_event_contexts = talloc_array_length(ctx->event_contexts);
> +
> +	for (i=0; i<num_event_contexts; i++) {
> +		struct messaging_registered_ev *reg = &ctx->event_contexts[i];
> +
> +		if (reg->refcount == 0) {
> +			continue;
> +		}
> +
> +		if (reg->im == NULL) {
> +			reg->im = tevent_create_immediate(
> +				ctx->event_contexts);
> +		}
> +		if (reg->im == NULL) {
> +			DBG_WARNING("Could not create immediate\n");
> +			continue;
> +		}
> +
> +		/*
> +		 * We depend on schedule_immediate to work
> +		 * multiple times. Might be a bit inefficient,
> +		 * but this needs to be proven in tests. The
> +		 * alternatively would be to track whether the
> +		 * immediate has already been scheduled. For
> +		 * now, avoid that complexity here.
> +		 */
> +
> +		if (reg->ev == ctx->event_ctx) {
> +			tevent_schedule_immediate(
> +				reg->im, reg->ev,
> +				messaging_post_main_event_context,
> +				ctx);
> +		} else {
> +			tevent_schedule_immediate(
> +				reg->im, reg->ev,
> +				messaging_post_sub_event_context,
> +				ctx);
> +		}
> +
> +	}
> +	return true;
> +}
> +
>  static void messaging_recv_cb(struct tevent_context *ev,
>  			      const uint8_t *msg, size_t msg_len,
>  			      int *fds, size_t num_fds,
> @@ -308,6 +417,13 @@ static int messaging_context_destructor(struct messaging_context *ctx)
>  		}
>  	}
>  
> +	/*
> +	 * The immediates from messaging_alert_event_contexts
> +	 * reference "ctx". Don't let them outlive the
> +	 * messaging_context we're destroying here.
> +	 */
> +	TALLOC_FREE(ctx->event_contexts);
> +
>  	return 0;
>  }
>  
> @@ -612,57 +728,30 @@ NTSTATUS messaging_send_buf(struct messaging_context *msg_ctx,
>  	return messaging_send(msg_ctx, server, msg_type, &blob);
>  }
>  
> -struct messaging_post_state {
> -	struct messaging_context *msg_ctx;
> -	struct messaging_rec *rec;
> -};
> -
> -static void messaging_post_handler(struct tevent_context *ev,
> -				   struct tevent_immediate *ti,
> -				   void *private_data);
> -
>  static int messaging_post_self(struct messaging_context *msg_ctx,
>  			       struct server_id src, struct server_id dst,
>  			       uint32_t msg_type,
>  			       const struct iovec *iov, int iovlen,
>  			       const int *fds, size_t num_fds)
>  {
> -	struct tevent_immediate *ti;
> -	struct messaging_post_state *state;
> +	struct messaging_rec *rec;
> +	bool ok;
>  
> -	state = talloc(msg_ctx, struct messaging_post_state);
> -	if (state == NULL) {
> +	rec = messaging_rec_create(
> +		msg_ctx, src, dst, msg_type, iov, iovlen, fds, num_fds);
> +	if (rec == NULL) {
>  		return ENOMEM;
>  	}
> -	state->msg_ctx = msg_ctx;
>  
> -	ti = tevent_create_immediate(state);
> -	if (ti == NULL) {
> -		goto fail;
> -	}
> -	state->rec = messaging_rec_create(
> -		state, src, dst, msg_type, iov, iovlen, fds, num_fds);
> -	if (state->rec == NULL) {
> -		goto fail;
> +	ok = messaging_alert_event_contexts(msg_ctx);
> +	if (!ok) {
> +		TALLOC_FREE(rec);
> +		return ENOMEM;
>  	}
>  
> -	tevent_schedule_immediate(ti, msg_ctx->event_ctx,
> -				  messaging_post_handler, state);
> -	return 0;
> +	DLIST_ADD_END(msg_ctx->posted_msgs, rec);
>  
> -fail:
> -	TALLOC_FREE(state);
> -	return ENOMEM;
> -}
> -
> -static void messaging_post_handler(struct tevent_context *ev,
> -				   struct tevent_immediate *ti,
> -				   void *private_data)
> -{
> -	struct messaging_post_state *state = talloc_get_type_abort(
> -		private_data, struct messaging_post_state);
> -	messaging_dispatch_rec(state->msg_ctx, ev, state->rec);
> -	TALLOC_FREE(state);
> +	return 0;
>  }
>  
>  int messaging_send_iov_from(struct messaging_context *msg_ctx,
> -- 
> 2.1.4
> 
> 
> From 11d72abc872688fb08d4a11eaf36413e9ab69cb2 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Thu, 1 Jun 2017 17:45:47 +0200
> Subject: [PATCH 26/41] ctdbd_conn: Pass "ev" through ctdb connection callbacks
> 
> This prepares the same logic we've implemented in messages_dgm for clustering
> that is used in 6d3c064f1a5: We need to reply for messages from ctdb in nested
> event contexts properly.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/include/ctdbd_conn.h   |  6 ++++--
>  source3/lib/ctdb_dummy.c       |  6 ++++--
>  source3/lib/ctdbd_conn.c       | 12 ++++++++----
>  source3/lib/messages_ctdbd.c   |  1 +
>  source3/smbd/notifyd/notifyd.c |  6 ++++--
>  source3/smbd/process.c         |  3 ++-
>  source3/smbd/server.c          |  1 +
>  7 files changed, 24 insertions(+), 11 deletions(-)
> 
> diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h
> index 06fbcc3..44ee8ab 100644
> --- a/source3/include/ctdbd_conn.h
> +++ b/source3/include/ctdbd_conn.h
> @@ -73,7 +73,8 @@ int ctdbd_traverse(struct ctdbd_connection *master, uint32_t db_id,
>  int ctdbd_register_ips(struct ctdbd_connection *conn,
>  		       const struct sockaddr_storage *server,
>  		       const struct sockaddr_storage *client,
> -		       int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
> +		       int (*cb)(struct tevent_context *ev,
> +				 uint32_t src_vnn, uint32_t dst_vnn,
>  				 uint64_t dst_srvid,
>  				 const uint8_t *msg, size_t msglen,
>  				 void *private_data),
> @@ -89,7 +90,8 @@ int ctdb_unwatch(struct ctdbd_connection *conn);
>  struct ctdb_req_message_old;
>  
>  int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
> -			int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
> +			int (*cb)(struct tevent_context *ev,
> +				  uint32_t src_vnn, uint32_t dst_vnn,
>  				  uint64_t dst_srvid,
>  				  const uint8_t *msg, size_t msglen,
>  				  void *private_data),
> diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
> index 2ed7b10..4e3e4bc 100644
> --- a/source3/lib/ctdb_dummy.c
> +++ b/source3/lib/ctdb_dummy.c
> @@ -38,7 +38,8 @@ int ctdbd_messaging_send_iov(struct ctdbd_connection *conn,
>  }
>  
>  int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
> -			int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
> +			int (*cb)(struct tevent_context *ev,
> +				  uint32_t src_vnn, uint32_t dst_vnn,
>  				  uint64_t dst_srvid,
>  				  const uint8_t *msg, size_t msglen,
>  				  void *private_data),
> @@ -50,7 +51,8 @@ int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
>  int ctdbd_register_ips(struct ctdbd_connection *conn,
>  		       const struct sockaddr_storage *_server,
>  		       const struct sockaddr_storage *_client,
> -		       int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
> +		       int (*cb)(struct tevent_context *ev,
> +				 uint32_t src_vnn, uint32_t dst_vnn,
>  				 uint64_t dst_srvid,
>  				 const uint8_t *msg, size_t msglen,
>  				 void *private_data),
> diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c
> index 3adb57d..88d45b4 100644
> --- a/source3/lib/ctdbd_conn.c
> +++ b/source3/lib/ctdbd_conn.c
> @@ -41,7 +41,8 @@
>  
>  struct ctdbd_srvid_cb {
>  	uint64_t srvid;
> -	int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
> +	int (*cb)(struct tevent_context *ev,
> +		  uint32_t src_vnn, uint32_t dst_vnn,
>  		  uint64_t dst_srvid,
>  		  const uint8_t *msg, size_t msglen,
>  		  void *private_data);
> @@ -143,7 +144,8 @@ static void ctdb_packet_dump(struct ctdb_req_header *hdr)
>   * Register a srvid with ctdbd
>   */
>  int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
> -			int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
> +			int (*cb)(struct tevent_context *ev,
> +				  uint32_t src_vnn, uint32_t dst_vnn,
>  				  uint64_t dst_srvid,
>  				  const uint8_t *msg, size_t msglen,
>  				  void *private_data),
> @@ -204,7 +206,8 @@ static int ctdbd_msg_call_back(struct ctdbd_connection *conn,
>  		if ((cb->srvid == msg->srvid) && (cb->cb != NULL)) {
>  			int ret;
>  
> -			ret = cb->cb(msg->hdr.srcnode, msg->hdr.destnode,
> +			ret = cb->cb(NULL,
> +				     msg->hdr.srcnode, msg->hdr.destnode,
>  				     msg->srvid, msg->data, msg->datalen,
>  				     cb->private_data);
>  			if (ret != 0) {
> @@ -1154,7 +1157,8 @@ static void smbd_ctdb_canonicalize_ip(const struct sockaddr_storage *in,
>  int ctdbd_register_ips(struct ctdbd_connection *conn,
>  		       const struct sockaddr_storage *_server,
>  		       const struct sockaddr_storage *_client,
> -		       int (*cb)(uint32_t src_vnn, uint32_t dst_vnn,
> +		       int (*cb)(struct tevent_context *ev,
> +				 uint32_t src_vnn, uint32_t dst_vnn,
>  				 uint64_t dst_srvid,
>  				 const uint8_t *msg, size_t msglen,
>  				 void *private_data),
> diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c
> index 6ecec32..10696ac 100644
> --- a/source3/lib/messages_ctdbd.c
> +++ b/source3/lib/messages_ctdbd.c
> @@ -109,6 +109,7 @@ static int messaging_ctdbd_destructor(struct messaging_ctdbd_context *ctx)
>  }
>  
>  static int messaging_ctdb_recv(
> +	struct tevent_context *ev,
>  	uint32_t src_vnn, uint32_t dst_vnn, uint64_t dst_srvid,
>  	const uint8_t *msg, size_t msg_len, void *private_data)
>  {
> diff --git a/source3/smbd/notifyd/notifyd.c b/source3/smbd/notifyd/notifyd.c
> index caf894e..11059ec 100644
> --- a/source3/smbd/notifyd/notifyd.c
> +++ b/source3/smbd/notifyd/notifyd.c
> @@ -179,7 +179,8 @@ static int sys_notify_watch_dummy(
>  #ifdef CLUSTER_SUPPORT
>  static void notifyd_broadcast_reclog_finished(struct tevent_req *subreq);
>  static void notifyd_clean_peers_finished(struct tevent_req *subreq);
> -static int notifyd_snoop_broadcast(uint32_t src_vnn, uint32_t dst_vnn,
> +static int notifyd_snoop_broadcast(struct tevent_context *ev,
> +				   uint32_t src_vnn, uint32_t dst_vnn,
>  				   uint64_t dst_srvid,
>  				   const uint8_t *msg, size_t msglen,
>  				   void *private_data);
> @@ -1387,7 +1388,8 @@ fail:
>   * broadcast, which will then trigger a fresh database pull.
>   */
>  
> -static int notifyd_snoop_broadcast(uint32_t src_vnn, uint32_t dst_vnn,
> +static int notifyd_snoop_broadcast(struct tevent_context *ev,
> +				   uint32_t src_vnn, uint32_t dst_vnn,
>  				   uint64_t dst_srvid,
>  				   const uint8_t *msg, size_t msglen,
>  				   void *private_data)
> diff --git a/source3/smbd/process.c b/source3/smbd/process.c
> index a19b8b7..4abaf37 100644
> --- a/source3/smbd/process.c
> +++ b/source3/smbd/process.c
> @@ -2695,7 +2695,8 @@ static void smbd_release_ip_immediate(struct tevent_context *ctx,
>  /****************************************************************************
>  received when we should release a specific IP
>  ****************************************************************************/
> -static int release_ip(uint32_t src_vnn, uint32_t dst_vnn,
> +static int release_ip(struct tevent_context *ev,
> +		      uint32_t src_vnn, uint32_t dst_vnn,
>  		      uint64_t dst_srvid,
>  		      const uint8_t *msg, size_t msglen,
>  		      void *private_data)
> diff --git a/source3/smbd/server.c b/source3/smbd/server.c
> index e18a4e5..91fa1c3 100644
> --- a/source3/smbd/server.c
> +++ b/source3/smbd/server.c
> @@ -276,6 +276,7 @@ static void smbd_parent_id_cache_delete(struct messaging_context *ctx,
>  
>  #ifdef CLUSTER_SUPPORT
>  static int smbd_parent_ctdb_reconfigured(
> +	struct tevent_context *ev,
>  	uint32_t src_vnn, uint32_t dst_vnn, uint64_t dst_srvid,
>  	const uint8_t *msg, size_t msglen, void *private_data)
>  {
> -- 
> 2.1.4
> 
> 
> From 1ac08cb17739a4588eb5d64c76ccd04f4bcf474e Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Thu, 1 Jun 2017 17:49:56 +0200
> Subject: [PATCH 27/41] ctdbd_conn: Pass "ev" through ctdbd_msg_call_back
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/ctdbd_conn.c | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c
> index 88d45b4..8fb951d 100644
> --- a/source3/lib/ctdbd_conn.c
> +++ b/source3/lib/ctdbd_conn.c
> @@ -179,7 +179,8 @@ int register_with_ctdbd(struct ctdbd_connection *conn, uint64_t srvid,
>  	return 0;
>  }
>  
> -static int ctdbd_msg_call_back(struct ctdbd_connection *conn,
> +static int ctdbd_msg_call_back(struct tevent_context *ev,
> +			       struct ctdbd_connection *conn,
>  			       struct ctdb_req_message_old *msg)
>  {
>  	uint32_t msg_len;
> @@ -206,7 +207,7 @@ static int ctdbd_msg_call_back(struct ctdbd_connection *conn,
>  		if ((cb->srvid == msg->srvid) && (cb->cb != NULL)) {
>  			int ret;
>  
> -			ret = cb->cb(NULL,
> +			ret = cb->cb(ev,
>  				     msg->hdr.srcnode, msg->hdr.destnode,
>  				     msg->srvid, msg->data, msg->datalen,
>  				     cb->private_data);
> @@ -414,7 +415,7 @@ static int ctdb_read_req(struct ctdbd_connection *conn, uint32_t reqid,
>  	if (hdr->operation == CTDB_REQ_MESSAGE) {
>  		struct ctdb_req_message_old *msg = (struct ctdb_req_message_old *)hdr;
>  
> -		ret = ctdbd_msg_call_back(conn, msg);
> +		ret = ctdbd_msg_call_back(NULL, conn, msg);
>  		if (ret != 0) {
>  			TALLOC_FREE(hdr);
>  			return ret;
> @@ -586,7 +587,7 @@ static int ctdb_handle_message(struct ctdbd_connection *conn,
>  
>  	msg = (struct ctdb_req_message_old *)hdr;
>  
> -	ctdbd_msg_call_back(conn, msg);
> +	ctdbd_msg_call_back(NULL, conn, msg);
>  
>  	return 0;
>  }
> -- 
> 2.1.4
> 
> 
> From 585a44ea0c232f846e0105e28ccca39e414e333e Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Thu, 1 Jun 2017 17:55:06 +0200
> Subject: [PATCH 28/41] ctdbd_conn: Pass "ev" through ctdb_handle_message
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/ctdbd_conn.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c
> index 8fb951d..41c9af0 100644
> --- a/source3/lib/ctdbd_conn.c
> +++ b/source3/lib/ctdbd_conn.c
> @@ -574,7 +574,8 @@ int ctdbd_conn_get_fd(struct ctdbd_connection *conn)
>  /*
>   * Packet handler to receive and handle a ctdb message
>   */
> -static int ctdb_handle_message(struct ctdbd_connection *conn,
> +static int ctdb_handle_message(struct tevent_context *ev,
> +			       struct ctdbd_connection *conn,
>  			       struct ctdb_req_header *hdr)
>  {
>  	struct ctdb_req_message_old *msg;
> @@ -587,7 +588,7 @@ static int ctdb_handle_message(struct ctdbd_connection *conn,
>  
>  	msg = (struct ctdb_req_message_old *)hdr;
>  
> -	ctdbd_msg_call_back(NULL, conn, msg);
> +	ctdbd_msg_call_back(ev, conn, msg);
>  
>  	return 0;
>  }
> @@ -603,7 +604,7 @@ void ctdbd_socket_readable(struct ctdbd_connection *conn)
>  		cluster_fatal("ctdbd died\n");
>  	}
>  
> -	ret = ctdb_handle_message(conn, hdr);
> +	ret = ctdb_handle_message(NULL, conn, hdr);
>  
>  	TALLOC_FREE(hdr);
>  
> -- 
> 2.1.4
> 
> 
> From 2ac86e871cbd56224b3993a75c513eeb633249ba Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Thu, 1 Jun 2017 18:00:45 +0200
> Subject: [PATCH 29/41] ctdbd_conn: Pass "ev" through ctdbd_socket_readable
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/include/ctdbd_conn.h | 3 ++-
>  source3/lib/ctdbd_conn.c     | 5 +++--
>  source3/lib/messages_ctdbd.c | 2 +-
>  3 files changed, 6 insertions(+), 4 deletions(-)
> 
> diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h
> index 44ee8ab..1a21c75 100644
> --- a/source3/include/ctdbd_conn.h
> +++ b/source3/include/ctdbd_conn.h
> @@ -42,7 +42,8 @@ int ctdbd_setup_fde(struct ctdbd_connection *conn, struct tevent_context *ev);
>  uint32_t ctdbd_vnn(const struct ctdbd_connection *conn);
>  
>  int ctdbd_conn_get_fd(struct ctdbd_connection *conn);
> -void ctdbd_socket_readable(struct ctdbd_connection *conn);
> +void ctdbd_socket_readable(struct tevent_context *ev,
> +			   struct ctdbd_connection *conn);
>  
>  int ctdbd_messaging_send_iov(struct ctdbd_connection *conn,
>  			     uint32_t dst_vnn, uint64_t dst_srvid,
> diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c
> index 41c9af0..94cd22e 100644
> --- a/source3/lib/ctdbd_conn.c
> +++ b/source3/lib/ctdbd_conn.c
> @@ -593,7 +593,8 @@ static int ctdb_handle_message(struct tevent_context *ev,
>  	return 0;
>  }
>  
> -void ctdbd_socket_readable(struct ctdbd_connection *conn)
> +void ctdbd_socket_readable(struct tevent_context *ev,
> +			   struct ctdbd_connection *conn)
>  {
>  	struct ctdb_req_header *hdr = NULL;
>  	int ret;
> @@ -604,7 +605,7 @@ void ctdbd_socket_readable(struct ctdbd_connection *conn)
>  		cluster_fatal("ctdbd died\n");
>  	}
>  
> -	ret = ctdb_handle_message(NULL, conn, hdr);
> +	ret = ctdb_handle_message(ev, conn, hdr);
>  
>  	TALLOC_FREE(hdr);
>  
> diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c
> index 10696ac..48d5488 100644
> --- a/source3/lib/messages_ctdbd.c
> +++ b/source3/lib/messages_ctdbd.c
> @@ -174,7 +174,7 @@ static void messaging_ctdbd_readable(struct tevent_context *ev,
>  	if ((flags & TEVENT_FD_READ) == 0) {
>  		return;
>  	}
> -	ctdbd_socket_readable(conn);
> +	ctdbd_socket_readable(ev, conn);
>  }
>  
>  static int messaging_ctdbd_init_internal(struct messaging_context *msg_ctx,
> -- 
> 2.1.4
> 
> 
> From 5f5a735a1f3c7088ec6e8eeba378d237bfe8230b Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Thu, 8 Jun 2017 12:51:29 +0200
> Subject: [PATCH 30/41] messaging: Add messaging_ctdbd_register_tevent_context
> 
> We need to listen for the ctdb socket in nested event contexts
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/ctdb_dummy.c     |   7 +++
>  source3/lib/messages.c       |  30 +++++++++++-
>  source3/lib/messages_ctdbd.c | 109 +++++++++++++++++++++++++++++++++++++------
>  source3/lib/messages_ctdbd.h |   5 ++
>  4 files changed, 135 insertions(+), 16 deletions(-)
> 
> diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
> index 4e3e4bc..4c0403c 100644
> --- a/source3/lib/ctdb_dummy.c
> +++ b/source3/lib/ctdb_dummy.c
> @@ -93,6 +93,13 @@ int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
>  	return ENOSYS;
>  }
>  
> +struct messaging_ctdbd_fde *messaging_ctdbd_register_tevent_context(
> +	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
> +	struct messaging_backend *backend)
> +{
> +	return NULL;
> +}
> +
>  struct ctdbd_connection *messaging_ctdbd_connection(void)
>  {
>  	return NULL;
> diff --git a/source3/lib/messages.c b/source3/lib/messages.c
> index 5c10013..759cc8b 100644
> --- a/source3/lib/messages.c
> +++ b/source3/lib/messages.c
> @@ -91,6 +91,7 @@ struct messaging_context {
>  
>  	void *msg_dgm_ref;
>  	struct messaging_backend *remote;
> +	struct messaging_ctdbd_fde *cluster_fde;
>  
>  	struct server_id_db *names_db;
>  };
> @@ -520,6 +521,14 @@ static NTSTATUS messaging_init_internal(TALLOC_CTX *mem_ctx,
>  			status = map_nt_error_from_unix(ret);
>  			goto done;
>  		}
> +		ctx->cluster_fde = messaging_ctdbd_register_tevent_context(
> +			ctx, ctx->event_ctx, ctx->remote);
> +		if (ctx->cluster_fde == NULL) {
> +			DBG_WARNING("messaging_ctdbd_register_tevent_context "
> +				    "failed\n");
> +			status = NT_STATUS_NO_MEMORY;
> +			goto done;
> +		}
>  	}
>  	ctx->id.vnn = get_my_vnn();
>  
> @@ -616,14 +625,23 @@ NTSTATUS messaging_reinit(struct messaging_context *msg_ctx)
>  	}
>  
>  	if (lp_clustering()) {
> +		TALLOC_FREE(msg_ctx->cluster_fde);
> +
>  		ret = messaging_ctdbd_reinit(msg_ctx, msg_ctx,
>  					     msg_ctx->remote);
> -
>  		if (ret != 0) {
>  			DEBUG(1, ("messaging_ctdbd_init failed: %s\n",
>  				  strerror(ret)));
>  			return map_nt_error_from_unix(ret);
>  		}
> +
> +		msg_ctx->cluster_fde = messaging_ctdbd_register_tevent_context(
> +			msg_ctx, msg_ctx->event_ctx, msg_ctx->remote);
> +		if (msg_ctx->cluster_fde == NULL) {
> +			DBG_WARNING("messaging_ctdbd_register_tevent_context "
> +				    "failed\n");
> +			return NT_STATUS_NO_MEMORY;
> +		}
>  	}
>  
>  	server_id_db_reinit(msg_ctx->names_db, msg_ctx->id);
> @@ -869,6 +887,7 @@ struct messaging_filtered_read_state {
>  	struct tevent_context *ev;
>  	struct messaging_context *msg_ctx;
>  	struct messaging_dgm_fde *fde;
> +	struct messaging_ctdbd_fde *cluster_fde;
>  
>  	bool (*filter)(struct messaging_rec *rec, void *private_data);
>  	void *private_data;
> @@ -911,6 +930,14 @@ struct tevent_req *messaging_filtered_read_send(
>  		return tevent_req_post(req, ev);
>  	}
>  
> +	if (msg_ctx->remote != NULL) {
> +		state->cluster_fde = messaging_ctdbd_register_tevent_context(
> +			state, ev, msg_ctx->remote);
> +		if (tevent_req_nomem(state->cluster_fde, req)) {
> +			return tevent_req_post(req, ev);
> +		}
> +	}
> +
>  	/*
>  	 * We add ourselves to the "new_waiters" array, not the "waiters"
>  	 * array. If we are called from within messaging_read_done,
> @@ -957,6 +984,7 @@ static void messaging_filtered_read_cleanup(struct tevent_req *req,
>  	tevent_req_set_cleanup_fn(req, NULL);
>  
>  	TALLOC_FREE(state->fde);
> +	TALLOC_FREE(state->cluster_fde);
>  
>  	ok = messaging_deregister_event_context(msg_ctx, state->ev);
>  	if (!ok) {
> diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c
> index 48d5488..62b5082 100644
> --- a/source3/lib/messages_ctdbd.c
> +++ b/source3/lib/messages_ctdbd.c
> @@ -27,10 +27,26 @@
>  #include "ctdbd_conn.h"
>  #include "lib/cluster_support.h"
>  
> +struct messaging_ctdbd_context;
> +
> +struct messaging_ctdbd_fde_ev {
> +	struct messaging_ctdbd_fde_ev *prev, *next;
> +
> +	/*
> +	 * Backreference to enable DLIST_REMOVE from our
> +	 * destructor. Also, set to NULL when the dgm_context dies
> +	 * before the messaging_dgm_fde_ev.
> +	 */
> +	struct messaging_ctdbd_context *ctx;
> +
> +	struct tevent_context *ev;
> +	struct tevent_fd *fde;
> +};
>  
>  struct messaging_ctdbd_context {
>  	struct ctdbd_connection *conn;
> -	struct tevent_fd *fde;
> +
> +	struct messaging_ctdbd_fde_ev *fde_evs;
>  };
>  
>  /*
> @@ -182,12 +198,9 @@ static int messaging_ctdbd_init_internal(struct messaging_context *msg_ctx,
>  					 struct messaging_ctdbd_context *ctx,
>  					 bool reinit)
>  {
> -	struct tevent_context *ev;
> -	int ret, ctdb_fd;
> +	int ret;
>  
>  	if (reinit) {
> -		TALLOC_FREE(ctx->fde);
> -
>  		ret = ctdbd_reinit_connection(ctx,
>  					      lp_ctdbd_socket(),
>  					      lp_ctdb_timeout(),
> @@ -224,15 +237,6 @@ static int messaging_ctdbd_init_internal(struct messaging_context *msg_ctx,
>  		return ret;
>  	}
>  
> -	ctdb_fd = ctdbd_conn_get_fd(ctx->conn);
> -	ev = messaging_tevent_context(msg_ctx);
> -
> -	ctx->fde = tevent_add_fd(ev, ctx, ctdb_fd, TEVENT_FD_READ,
> -				 messaging_ctdbd_readable, ctx->conn);
> -	if (ctx->fde == NULL) {
> -		return ENOMEM;
> -	}
> -
>  	global_ctdb_connection_pid = getpid();
>  	global_ctdbd_connection = ctx->conn;
>  	talloc_set_destructor(ctx, messaging_ctdbd_destructor);
> @@ -255,7 +259,7 @@ int messaging_ctdbd_init(struct messaging_context *msg_ctx,
>  		return ENOMEM;
>  	}
>  
> -	if (!(ctx = talloc(result, struct messaging_ctdbd_context))) {
> +	if (!(ctx = talloc_zero(result, struct messaging_ctdbd_context))) {
>  		DEBUG(0, ("talloc failed\n"));
>  		TALLOC_FREE(result);
>  		return ENOMEM;
> @@ -289,3 +293,78 @@ int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
>  
>  	return 0;
>  }
> +
> +struct messaging_ctdbd_fde {
> +	struct tevent_fd *fde;
> +};
> +
> +static int messaging_ctdbd_fde_ev_destructor(
> +	struct messaging_ctdbd_fde_ev *fde_ev)
> +{
> +	if (fde_ev->ctx != NULL) {
> +		DLIST_REMOVE(fde_ev->ctx->fde_evs, fde_ev);
> +		fde_ev->ctx = NULL;
> +	}
> +	return 0;
> +}
> +
> +struct messaging_ctdbd_fde *messaging_ctdbd_register_tevent_context(
> +	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
> +	struct messaging_backend *backend)
> +{
> +	struct messaging_ctdbd_context *ctx = talloc_get_type_abort(
> +		backend->private_data, struct messaging_ctdbd_context);
> +	struct messaging_ctdbd_fde_ev *fde_ev;
> +	struct messaging_ctdbd_fde *fde;
> +
> +	if (ctx == NULL) {
> +		return NULL;
> +	}
> +
> +	fde = talloc(mem_ctx, struct messaging_ctdbd_fde);
> +	if (fde == NULL) {
> +		return NULL;
> +	}
> +
> +	for (fde_ev = ctx->fde_evs; fde_ev != NULL; fde_ev = fde_ev->next) {
> +		if ((fde_ev->ev == ev) &&
> +		    (tevent_fd_get_flags(fde_ev->fde) != 0)) {
> +			break;
> +		}
> +	}
> +
> +	if (fde_ev == NULL) {
> +		int fd = ctdbd_conn_get_fd(ctx->conn);
> +
> +		fde_ev = talloc(fde, struct messaging_ctdbd_fde_ev);
> +		if (fde_ev == NULL) {
> +			return NULL;
> +		}
> +		fde_ev->fde = tevent_add_fd(
> +			ev, fde_ev, fd, TEVENT_FD_READ,
> +			messaging_ctdbd_readable, ctx->conn);
> +		if (fde_ev->fde == NULL) {
> +			TALLOC_FREE(fde);
> +			return NULL;
> +		}
> +		fde_ev->ev = ev;
> +		fde_ev->ctx = ctx;
> +		DLIST_ADD(ctx->fde_evs, fde_ev);
> +		talloc_set_destructor(
> +			fde_ev, messaging_ctdbd_fde_ev_destructor);
> +	} else {
> +		/*
> +		 * Same trick as with tdb_wrap: The caller will never
> +		 * see the talloc_referenced object, the
> +		 * messaging_ctdbd_fde_ev, so problems with
> +		 * talloc_unlink will not happen.
> +		 */
> +		if (talloc_reference(fde, fde_ev) == NULL) {
> +			TALLOC_FREE(fde);
> +			return NULL;
> +		}
> +	}
> +
> +	fde->fde = fde_ev->fde;
> +	return fde;
> +}
> diff --git a/source3/lib/messages_ctdbd.h b/source3/lib/messages_ctdbd.h
> index 67ec4b7..c13079d 100644
> --- a/source3/lib/messages_ctdbd.h
> +++ b/source3/lib/messages_ctdbd.h
> @@ -35,4 +35,9 @@ int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
>  			   struct messaging_backend *backend);
>  struct ctdbd_connection *messaging_ctdbd_connection(void);
>  
> +struct messaging_ctdbd_fde;
> +struct messaging_ctdbd_fde *messaging_ctdbd_register_tevent_context(
> +	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
> +	struct messaging_backend *backend);
> +
>  #endif
> -- 
> 2.1.4
> 
> 
> From 44b399093c5e9ca31bdc835af6c74d80bd39a53f Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Thu, 1 Jun 2017 18:58:16 +0200
> Subject: [PATCH 31/41] messages_ctdb: Handle async msgs for nested event
>  contexts
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/ctdb_dummy.c     | 10 +++++
>  source3/lib/messages.c       |  9 +++--
>  source3/lib/messages_ctdbd.c | 88 ++++++++++++++++++--------------------------
>  source3/lib/messages_ctdbd.h | 10 +++++
>  4 files changed, 62 insertions(+), 55 deletions(-)
> 
> diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
> index 4c0403c..b6ec228 100644
> --- a/source3/lib/ctdb_dummy.c
> +++ b/source3/lib/ctdb_dummy.c
> @@ -81,6 +81,11 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
>  
>  int messaging_ctdbd_init(struct messaging_context *msg_ctx,
>  			 TALLOC_CTX *mem_ctx,
> +			 void (*recv_cb)(struct tevent_context *ev,
> +					 const uint8_t *msg, size_t msg_len,
> +					 int *fds, size_t num_fds,
> +					 void *private_data),
> +			 void *private_data,
>  			      struct messaging_backend **presult)
>  {
>  	return ENOSYS;
> @@ -88,6 +93,11 @@ int messaging_ctdbd_init(struct messaging_context *msg_ctx,
>  
>  int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
>  			   TALLOC_CTX *mem_ctx,
> +			   void (*recv_cb)(struct tevent_context *ev,
> +					   const uint8_t *msg, size_t msg_len,
> +					   int *fds, size_t num_fds,
> +					   void *private_data),
> +			   void *private_data,
>  			   struct messaging_backend *backend)
>  {
>  	return ENOSYS;
> diff --git a/source3/lib/messages.c b/source3/lib/messages.c
> index 759cc8b..4e838b0 100644
> --- a/source3/lib/messages.c
> +++ b/source3/lib/messages.c
> @@ -513,7 +513,8 @@ static NTSTATUS messaging_init_internal(TALLOC_CTX *mem_ctx,
>  	talloc_set_destructor(ctx, messaging_context_destructor);
>  
>  	if (lp_clustering()) {
> -		ret = messaging_ctdbd_init(ctx, ctx, &ctx->remote);
> +		ret = messaging_ctdbd_init(
> +			ctx, ctx, messaging_recv_cb, ctx, &ctx->remote);
>  
>  		if (ret != 0) {
>  			DEBUG(2, ("messaging_ctdbd_init failed: %s\n",
> @@ -627,8 +628,10 @@ NTSTATUS messaging_reinit(struct messaging_context *msg_ctx)
>  	if (lp_clustering()) {
>  		TALLOC_FREE(msg_ctx->cluster_fde);
>  
> -		ret = messaging_ctdbd_reinit(msg_ctx, msg_ctx,
> -					     msg_ctx->remote);
> +		ret = messaging_ctdbd_reinit(
> +			msg_ctx, msg_ctx, messaging_recv_cb, msg_ctx,
> +			msg_ctx->remote);
> +
>  		if (ret != 0) {
>  			DEBUG(1, ("messaging_ctdbd_init failed: %s\n",
>  				  strerror(ret)));
> diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c
> index 62b5082..b1af4f8 100644
> --- a/source3/lib/messages_ctdbd.c
> +++ b/source3/lib/messages_ctdbd.c
> @@ -47,6 +47,12 @@ struct messaging_ctdbd_context {
>  	struct ctdbd_connection *conn;
>  
>  	struct messaging_ctdbd_fde_ev *fde_evs;
> +
> +	void (*recv_cb)(struct tevent_context *ev,
> +			const uint8_t *msg, size_t msg_len,
> +			int *fds, size_t num_fds,
> +			void *private_data);
> +	void *private_data;
>  };
>  
>  /*
> @@ -129,52 +135,10 @@ static int messaging_ctdb_recv(
>  	uint32_t src_vnn, uint32_t dst_vnn, uint64_t dst_srvid,
>  	const uint8_t *msg, size_t msg_len, void *private_data)
>  {
> -	struct messaging_context *msg_ctx = talloc_get_type_abort(
> -		private_data, struct messaging_context);
> -	struct server_id me = messaging_server_id(msg_ctx);
> -	int ret;
> -	struct iovec iov;
> -	struct server_id src, dst;
> -	enum messaging_type msg_type;
> -	struct server_id_buf idbuf;
> -
> -	if (msg_len < MESSAGE_HDR_LENGTH) {
> -		DEBUG(1, ("%s: message too short: %u\n", __func__,
> -			  (unsigned)msg_len));
> -		return 0;
> -	}
> -
> -	message_hdr_get(&msg_type, &src, &dst, msg);
> -
> -	iov = (struct iovec) {
> -		.iov_base = discard_const_p(uint8_t, msg) + MESSAGE_HDR_LENGTH,
> -		.iov_len = msg_len - MESSAGE_HDR_LENGTH
> -	};
> -
> -	DEBUG(10, ("%s: Received message 0x%x len %u from %s\n",
> -		   __func__, (unsigned)msg_type, (unsigned)msg_len,
> -		   server_id_str_buf(src, &idbuf)));
> -
> -	if (!server_id_same_process(&me, &dst)) {
> -		struct server_id_buf id1, id2;
> -
> -		DEBUG(10, ("%s: I'm %s, ignoring msg to %s\n", __func__,
> -			   server_id_str_buf(me, &id1),
> -			   server_id_str_buf(dst, &id2)));
> -		return 0;
> -	}
> -
> -	/*
> -	 * Go through the event loop
> -	 */
> -
> -	ret = messaging_send_iov_from(msg_ctx, src, dst, msg_type,
> -				      &iov, 1, NULL, 0);
> +	struct messaging_ctdbd_context *ctx = talloc_get_type_abort(
> +		private_data, struct messaging_ctdbd_context);
>  
> -	if (ret != 0) {
> -		DEBUG(10, ("%s: messaging_send_iov_from failed: %s\n",
> -			   __func__, strerror(ret)));
> -	}
> +	ctx->recv_cb(ev, msg, msg_len, NULL, 0, ctx->private_data);
>  
>  	return 0;
>  }
> @@ -193,10 +157,15 @@ static void messaging_ctdbd_readable(struct tevent_context *ev,
>  	ctdbd_socket_readable(ev, conn);
>  }
>  
> -static int messaging_ctdbd_init_internal(struct messaging_context *msg_ctx,
> -					 TALLOC_CTX *mem_ctx,
> -					 struct messaging_ctdbd_context *ctx,
> -					 bool reinit)
> +static int messaging_ctdbd_init_internal(
> +	struct messaging_context *msg_ctx, TALLOC_CTX *mem_ctx,
> +	struct messaging_ctdbd_context *ctx,
> +	void (*recv_cb)(struct tevent_context *ev,
> +			const uint8_t *msg, size_t msg_len,
> +			int *fds, size_t num_fds,
> +			void *private_data),
> +	void *private_data,
> +	bool reinit)
>  {
>  	int ret;
>  
> @@ -229,8 +198,11 @@ static int messaging_ctdbd_init_internal(struct messaging_context *msg_ctx,
>  		return ret;
>  	}
>  
> +	ctx->recv_cb = recv_cb;
> +	ctx->private_data = private_data;
> +
>  	ret = register_with_ctdbd(ctx->conn, getpid(),
> -				  messaging_ctdb_recv, msg_ctx);
> +				  messaging_ctdb_recv, ctx);
>  	if (ret != 0) {
>  		DEBUG(10, ("register_with_ctdbd failed: %s\n",
>  			   strerror(ret)));
> @@ -248,6 +220,11 @@ static int messaging_ctdbd_init_internal(struct messaging_context *msg_ctx,
>  
>  int messaging_ctdbd_init(struct messaging_context *msg_ctx,
>  			 TALLOC_CTX *mem_ctx,
> +			 void (*recv_cb)(struct tevent_context *ev,
> +					 const uint8_t *msg, size_t msg_len,
> +					 int *fds, size_t num_fds,
> +					 void *private_data),
> +			 void *private_data,
>  			 struct messaging_backend **presult)
>  {
>  	struct messaging_backend *result;
> @@ -265,7 +242,8 @@ int messaging_ctdbd_init(struct messaging_context *msg_ctx,
>  		return ENOMEM;
>  	}
>  
> -	ret = messaging_ctdbd_init_internal(msg_ctx, mem_ctx, ctx, false);
> +	ret = messaging_ctdbd_init_internal(msg_ctx, mem_ctx, ctx,
> +					    recv_cb, private_data, false);
>  	if (ret != 0) {
>  		TALLOC_FREE(result);
>  		return ret;
> @@ -280,13 +258,19 @@ int messaging_ctdbd_init(struct messaging_context *msg_ctx,
>  
>  int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
>  			   TALLOC_CTX *mem_ctx,
> +			   void (*recv_cb)(struct tevent_context *ev,
> +					   const uint8_t *msg, size_t msg_len,
> +					   int *fds, size_t num_fds,
> +					   void *private_data),
> +			   void *private_data,
>  			   struct messaging_backend *backend)
>  {
>  	struct messaging_ctdbd_context *ctx = talloc_get_type_abort(
>  		backend->private_data, struct messaging_ctdbd_context);
>  	int ret;
>  
> -	ret = messaging_ctdbd_init_internal(msg_ctx, mem_ctx, ctx, true);
> +	ret = messaging_ctdbd_init_internal(msg_ctx, mem_ctx, ctx,
> +					    recv_cb, private_data, true);
>  	if (ret != 0) {
>  		return ret;
>  	}
> diff --git a/source3/lib/messages_ctdbd.h b/source3/lib/messages_ctdbd.h
> index c13079d..7d928fe 100644
> --- a/source3/lib/messages_ctdbd.h
> +++ b/source3/lib/messages_ctdbd.h
> @@ -29,9 +29,19 @@ struct ctdbd_connection;
>  
>  int messaging_ctdbd_init(struct messaging_context *msg_ctx,
>  			 TALLOC_CTX *mem_ctx,
> +			 void (*recv_cb)(struct tevent_context *ev,
> +					 const uint8_t *msg, size_t msg_len,
> +					 int *fds, size_t num_fds,
> +					 void *private_data),
> +			 void *private_data,
>  			 struct messaging_backend **presult);
>  int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
>  			   TALLOC_CTX *mem_ctx,
> +			   void (*recv_cb)(struct tevent_context *ev,
> +					   const uint8_t *msg, size_t msg_len,
> +					   int *fds, size_t num_fds,
> +					   void *private_data),
> +			   void *private_data,
>  			   struct messaging_backend *backend);
>  struct ctdbd_connection *messaging_ctdbd_connection(void);
>  
> -- 
> 2.1.4
> 
> 
> From 962359dc5c074763d4be1ade8058103e2f7c35eb Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Tue, 13 Sep 2016 14:22:05 +0200
> Subject: [PATCH 32/41] dbwrap: Avoid dbwrap_merge_dbufs in db_ctdb_storev
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/dbwrap/dbwrap_ctdb.c | 17 +++++------------
>  1 file changed, 5 insertions(+), 12 deletions(-)
> 
> diff --git a/source3/lib/dbwrap/dbwrap_ctdb.c b/source3/lib/dbwrap/dbwrap_ctdb.c
> index 2969183..b722714 100644
> --- a/source3/lib/dbwrap/dbwrap_ctdb.c
> +++ b/source3/lib/dbwrap/dbwrap_ctdb.c
> @@ -182,16 +182,16 @@ static NTSTATUS db_ctdb_ltdb_parse(
>  static NTSTATUS db_ctdb_ltdb_store(struct db_ctdb_ctx *db,
>  				   TDB_DATA key,
>  				   struct ctdb_ltdb_header *header,
> -				   TDB_DATA data)
> +				   const TDB_DATA *dbufs, int num_dbufs)
>  {
> -	TDB_DATA recs[2];
> +	TDB_DATA recs[num_dbufs+1];
>  	int ret;
>  
>  	recs[0] = (TDB_DATA) { .dptr = (uint8_t *)header,
>  			       .dsize = sizeof(struct ctdb_ltdb_header) };
> -	recs[1] = data;
> +	memcpy(&recs[1], dbufs, sizeof(TDB_DATA) * num_dbufs);
>  
> -	ret = tdb_storev(db->wtdb->tdb, key, recs, 2, TDB_REPLACE);
> +	ret = tdb_storev(db->wtdb->tdb, key, recs, num_dbufs + 1, TDB_REPLACE);
>  
>  	return (ret == 0) ? NT_STATUS_OK
>  			  : tdb_error_to_ntstatus(db->wtdb->tdb);
> @@ -905,16 +905,9 @@ static NTSTATUS db_ctdb_storev(struct db_record *rec,
>  	struct db_ctdb_rec *crec = talloc_get_type_abort(
>  		rec->private_data, struct db_ctdb_rec);
>  	NTSTATUS status;
> -	TDB_DATA data;
> -
> -	data = dbwrap_merge_dbufs(rec, dbufs, num_dbufs);
> -	if (data.dptr == NULL) {
> -		return NT_STATUS_NO_MEMORY;
> -	}
>  
>  	status = db_ctdb_ltdb_store(crec->ctdb_ctx, rec->key, &(crec->header),
> -				    data);
> -	TALLOC_FREE(data.dptr);
> +				    dbufs, num_dbufs);
>  	return status;
>  }
>  
> -- 
> 2.1.4
> 
> 
> From 5163e1d5937dfacc6942b15b3f4970496f3e7c38 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Sun, 11 Jun 2017 10:45:25 +0200
> Subject: [PATCH 33/41] messaging: Add messaging_ctdb_init/destroy
> 
> This models connecting to ctdb after the dgm code. The main point
> is that we should never open more than more ctdb socket for messaging.
> 
> With more than one socket, we might end up with our pid registered with
> ctdb on more than one socket. This could lead to memory overconsumption
> in ctdb. ctdbd will eventually throw away messages, but they will take
> up space unnecessarily.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/ctdb_dummy.c    |  13 +++
>  source3/lib/messages_ctdb.c | 260 ++++++++++++++++++++++++++++++++++++++++++++
>  source3/lib/messages_ctdb.h |  42 +++++++
>  source3/wscript_build       |   1 +
>  4 files changed, 316 insertions(+)
>  create mode 100644 source3/lib/messages_ctdb.c
>  create mode 100644 source3/lib/messages_ctdb.h
> 
> diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
> index b6ec228..855f56d 100644
> --- a/source3/lib/ctdb_dummy.c
> +++ b/source3/lib/ctdb_dummy.c
> @@ -20,6 +20,7 @@
>  #include "includes.h"
>  #include "messages.h"
>  #include "lib/messages_ctdbd.h"
> +#include "lib/messages_ctdb.h"
>  #include "ctdbd_conn.h"
>  #include "lib/dbwrap/dbwrap.h"
>  #include "lib/dbwrap/dbwrap_ctdb.h"
> @@ -91,6 +92,18 @@ int messaging_ctdbd_init(struct messaging_context *msg_ctx,
>  	return ENOSYS;
>  }
>  
> +int messaging_ctdb_send(uint32_t dst_vnn, uint64_t dst_srvid,
> +			const struct iovec *iov, int iovlen)
> +{
> +	return ENOSYS;
> +}
> +
> +struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
> +	TALLOC_CTX *mem_ctx, struct tevent_context *ev)
> +{
> +	return NULL;
> +}
> +
>  int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
>  			   TALLOC_CTX *mem_ctx,
>  			   void (*recv_cb)(struct tevent_context *ev,
> diff --git a/source3/lib/messages_ctdb.c b/source3/lib/messages_ctdb.c
> new file mode 100644
> index 0000000..5bc494d
> --- /dev/null
> +++ b/source3/lib/messages_ctdb.c
> @@ -0,0 +1,260 @@
> +/*
> + * Unix SMB/CIFS implementation.
> + * Samba internal messaging functions
> + * Copyright (C) 2017 by Volker Lendecke
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "includes.h"
> +#include "lib/messages_ctdb.h"
> +#include "lib/util/server_id.h"
> +#include "messages.h"
> +#include "util_tdb.h"
> +#include "lib/util/iov_buf.h"
> +#include "lib/messages_util.h"
> +#include "ctdbd_conn.h"
> +#include "lib/cluster_support.h"
> +
> +struct messaging_ctdb_context;
> +
> +/*
> + * We can only have one tevent_fd per ctdb_context and per
> + * tevent_context. Maintain a list of registered tevent_contexts per
> + * ctdb_context.
> + */
> +struct messaging_ctdb_fde_ev {
> +	struct messaging_ctdb_fde_ev *prev, *next;
> +
> +	/*
> +	 * Backreference to enable DLIST_REMOVE from our
> +	 * destructor. Also, set to NULL when the ctdb_context dies
> +	 * before the messaging_ctdb_fde_ev.
> +	 */
> +	struct messaging_ctdb_context *ctx;
> +
> +	struct tevent_context *ev;
> +	struct tevent_fd *fde;
> +};
> +
> +struct messaging_ctdb_context {
> +	struct ctdbd_connection *conn;
> +
> +	void (*recv_cb)(struct tevent_context *ev,
> +			const uint8_t *msg, size_t msg_len,
> +			int *fds, size_t num_fds,
> +			void *private_data);
> +	void *recv_cb_private_data;
> +
> +	struct messaging_ctdb_fde_ev *fde_evs;
> +};
> +
> +static int messaging_ctdb_recv(
> +	struct tevent_context *ev,
> +	uint32_t src_vnn, uint32_t dst_vnn, uint64_t dst_srvid,
> +	const uint8_t *msg, size_t msg_len, void *private_data)
> +{
> +	struct messaging_ctdb_context *state = talloc_get_type_abort(
> +		private_data, struct messaging_ctdb_context);
> +
> +	state->recv_cb(ev, msg, msg_len, NULL, 0, state->recv_cb_private_data);
> +
> +	return 0;
> +}
> +
> +struct messaging_ctdb_context *global_ctdb_context;
> +
> +int messaging_ctdb_init(const char *sockname, int timeout, uint64_t unique_id,
> +			void (*recv_cb)(struct tevent_context *ev,
> +					const uint8_t *msg, size_t msg_len,
> +					int *fds, size_t num_fds,
> +					void *private_data),
> +			void *private_data)
> +{
> +	struct messaging_ctdb_context *ctx;
> +	int ret;
> +
> +	if (global_ctdb_context != NULL) {
> +		return EBUSY;
> +	}
> +
> +	ctx = talloc_zero(NULL, struct messaging_ctdb_context);
> +	if (ctx == NULL) {
> +		return ENOMEM;
> +	}
> +	ctx->recv_cb = recv_cb;
> +	ctx->recv_cb_private_data = private_data;
> +
> +	ret = ctdbd_init_connection(ctx, sockname, timeout, &ctx->conn);
> +	if (ret != 0) {
> +		DBG_DEBUG("ctdbd_init_connection returned %s\n",
> +			  strerror(ret));
> +		goto fail;
> +	}
> +
> +	ret = register_with_ctdbd(ctx->conn, getpid(), messaging_ctdb_recv,
> +				  ctx);
> +	if (ret != 0) {
> +		DBG_DEBUG("register_with_ctdbd returned %s (%d)\n",
> +			  strerror(ret), ret);
> +		goto fail;
> +	}
> +
> +	ret = register_with_ctdbd(ctx->conn, unique_id, NULL, NULL);
> +	if (ret != 0) {
> +		DBG_DEBUG("register_with_ctdbd returned %s (%d)\n",
> +			  strerror(ret), ret);
> +		goto fail;
> +	}
> +
> +	set_my_vnn(ctdbd_vnn(ctx->conn));
> +
> +	global_ctdb_context = ctx;
> +	return 0;
> +fail:
> +	TALLOC_FREE(ctx);
> +	return ret;
> +}
> +
> +void messaging_ctdb_destroy(void)
> +{
> +	TALLOC_FREE(global_ctdb_context);
> +}
> +
> +int messaging_ctdb_send(uint32_t dst_vnn, uint64_t dst_srvid,
> +			const struct iovec *iov, int iovlen)
> +{
> +	struct messaging_ctdb_context *ctx = global_ctdb_context;
> +	int ret;
> +
> +	if (ctx == NULL) {
> +		return ENOTCONN;
> +	}
> +
> +	ret = ctdbd_messaging_send_iov(ctx->conn, dst_vnn, dst_srvid,
> +				       iov, iovlen);
> +	return ret;
> +}
> +
> +static void messaging_ctdb_read_handler(struct tevent_context *ev,
> +					struct tevent_fd *fde,
> +					uint16_t flags,
> +					void *private_data)
> +{
> +	struct messaging_ctdb_context *ctx = talloc_get_type_abort(
> +		private_data, struct messaging_ctdb_context);
> +
> +	if ((flags & TEVENT_FD_READ) == 0) {
> +		return;
> +	}
> +	ctdbd_socket_readable(ev, ctx->conn);
> +}
> +
> +struct messaging_ctdb_fde {
> +	struct tevent_fd *fde;
> +};
> +
> +static int messaging_ctdb_fde_ev_destructor(
> +	struct messaging_ctdb_fde_ev *fde_ev)
> +{
> +	if (fde_ev->ctx != NULL) {
> +		DLIST_REMOVE(fde_ev->ctx->fde_evs, fde_ev);
> +		fde_ev->ctx = NULL;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * Reference counter for a struct tevent_fd messaging read event
> + * (with callback function) on a struct tevent_context registered
> + * on a messaging context.
> + *
> + * If we've already registered this struct tevent_context before
> + * (so already have a read event), just increase the reference count.
> + *
> + * Otherwise create a new struct tevent_fd messaging read event on the
> + * previously unseen struct tevent_context - this is what drives
> + * the message receive processing.
> + *
> + */
> +
> +struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
> +	TALLOC_CTX *mem_ctx, struct tevent_context *ev)
> +{
> +	struct messaging_ctdb_context *ctx = global_ctdb_context;
> +	struct messaging_ctdb_fde_ev *fde_ev;
> +	struct messaging_ctdb_fde *fde;
> +
> +	if (ctx == NULL) {
> +		return NULL;
> +	}
> +
> +	fde = talloc(mem_ctx, struct messaging_ctdb_fde);
> +	if (fde == NULL) {
> +		return NULL;
> +	}
> +
> +	for (fde_ev = ctx->fde_evs; fde_ev != NULL; fde_ev = fde_ev->next) {
> +		if ((fde_ev->ev == ev) &&
> +		    (tevent_fd_get_flags(fde_ev->fde) != 0)) {
> +			break;
> +		}
> +	}
> +
> +	if (fde_ev == NULL) {
> +		int sock = ctdbd_conn_get_fd(ctx->conn);
> +
> +		fde_ev = talloc(fde, struct messaging_ctdb_fde_ev);
> +		if (fde_ev == NULL) {
> +			return NULL;
> +		}
> +		fde_ev->fde = tevent_add_fd(
> +			ev, fde_ev, sock, TEVENT_FD_READ,
> +			messaging_ctdb_read_handler, ctx);
> +		if (fde_ev->fde == NULL) {
> +			TALLOC_FREE(fde);
> +			return NULL;
> +		}
> +		fde_ev->ev = ev;
> +		fde_ev->ctx = ctx;
> +		DLIST_ADD(ctx->fde_evs, fde_ev);
> +		talloc_set_destructor(
> +			fde_ev, messaging_ctdb_fde_ev_destructor);
> +	} else {
> +		/*
> +		 * Same trick as with tdb_wrap: The caller will never
> +		 * see the talloc_referenced object, the
> +		 * messaging_ctdb_fde_ev, so problems with
> +		 * talloc_unlink will not happen.
> +		 */
> +		if (talloc_reference(fde, fde_ev) == NULL) {
> +			TALLOC_FREE(fde);
> +			return NULL;
> +		}
> +	}
> +
> +	fde->fde = fde_ev->fde;
> +	return fde;
> +}
> +
> +bool messaging_ctdb_fde_active(struct messaging_ctdb_fde *fde)
> +{
> +	uint16_t flags;
> +
> +	if (fde == NULL) {
> +		return false;
> +	}
> +	flags = tevent_fd_get_flags(fde->fde);
> +	return (flags != 0);
> +}
> diff --git a/source3/lib/messages_ctdb.h b/source3/lib/messages_ctdb.h
> new file mode 100644
> index 0000000..006821b
> --- /dev/null
> +++ b/source3/lib/messages_ctdb.h
> @@ -0,0 +1,42 @@
> +/*
> + * Unix SMB/CIFS implementation.
> + * Samba internal messaging functions
> + * Copyright (C) 2017 by Volker Lendecke
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef __MESSAGES_CTDB_H__
> +#define __MESSAGES_CTDB_H__
> +
> +#include "replace.h"
> +#include "system/filesys.h"
> +#include <tevent.h>
> +
> +int messaging_ctdb_init(const char *sockname, int timeout, uint64_t unique_id,
> +			void (*recv_cb)(struct tevent_context *ev,
> +					const uint8_t *msg, size_t msg_len,
> +					int *fds, size_t num_fds,
> +					void *private_data),
> +			void *private_data);
> +void messaging_ctdb_destroy(void);
> +int messaging_ctdb_send(uint32_t dst_vnn, uint64_t dst_srvid,
> +			const struct iovec *iov, int iovlen);
> +
> +struct messaging_ctdb_fde;
> +struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
> +	TALLOC_CTX *mem_ctx, struct tevent_context *ev);
> +bool messaging_ctdb_fde_active(struct messaging_ctdb_fde *fde);
> +
> +#endif
> diff --git a/source3/wscript_build b/source3/wscript_build
> index 99f4a2b..a57217c 100644
> --- a/source3/wscript_build
> +++ b/source3/wscript_build
> @@ -331,6 +331,7 @@ if bld.env.with_ctdb:
>                       lib/cluster_support.c
>                       lib/dbwrap/dbwrap_ctdb.c
>                       lib/messages_ctdbd.c
> +                     lib/messages_ctdb.c
>                       lib/ctdbd_conn.c
>                     '''
>      SAMBA_CLUSTER_SUPPORT_DEPS='''
> -- 
> 2.1.4
> 
> 
> From a49a4c25116eced0859491b834154a7b4143744a Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Mon, 12 Jun 2017 16:50:16 +0200
> Subject: [PATCH 34/41] messaging: Add messages_ctdb_ref
> 
> Modeled after messages_dgm_ref
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/ctdb_dummy.c        |  13 ++++
>  source3/lib/messages_ctdb_ref.c | 145 ++++++++++++++++++++++++++++++++++++++++
>  source3/lib/messages_ctdb_ref.h |  35 ++++++++++
>  source3/wscript_build           |   1 +
>  4 files changed, 194 insertions(+)
>  create mode 100644 source3/lib/messages_ctdb_ref.c
>  create mode 100644 source3/lib/messages_ctdb_ref.h
> 
> diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
> index 855f56d..2d7ba25 100644
> --- a/source3/lib/ctdb_dummy.c
> +++ b/source3/lib/ctdb_dummy.c
> @@ -21,6 +21,7 @@
>  #include "messages.h"
>  #include "lib/messages_ctdbd.h"
>  #include "lib/messages_ctdb.h"
> +#include "lib/messages_ctdb_ref.h"
>  #include "ctdbd_conn.h"
>  #include "lib/dbwrap/dbwrap.h"
>  #include "lib/dbwrap/dbwrap_ctdb.h"
> @@ -98,6 +99,18 @@ int messaging_ctdb_send(uint32_t dst_vnn, uint64_t dst_srvid,
>  	return ENOSYS;
>  }
>  
> +void *messaging_ctdb_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
> +			 const char *sockname, int timeout, uint64_t unique_id,
> +			 void (*recv_cb)(struct tevent_context *ev,
> +					 const uint8_t *msg, size_t msg_len,
> +					 int *fds, size_t num_fds,
> +					 void *private_data),
> +			 void *private_data,
> +			 int *err)
> +{
> +	return NULL;
> +}
> +
>  struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
>  	TALLOC_CTX *mem_ctx, struct tevent_context *ev)
>  {
> diff --git a/source3/lib/messages_ctdb_ref.c b/source3/lib/messages_ctdb_ref.c
> new file mode 100644
> index 0000000..3570ed8
> --- /dev/null
> +++ b/source3/lib/messages_ctdb_ref.c
> @@ -0,0 +1,145 @@
> +/*
> + * Unix SMB/CIFS implementation.
> + * Samba internal messaging functions
> + * Copyright (C) 2017 by Volker Lendecke
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "replace.h"
> +#include <talloc.h>
> +#include "messages_ctdb.h"
> +#include "messages_ctdb_ref.h"
> +#include "lib/util/debug.h"
> +#include "lib/util/dlinklist.h"
> +
> +struct msg_ctdb_ref {
> +	struct msg_ctdb_ref *prev, *next;
> +	struct messaging_ctdb_fde *fde;
> +	void (*recv_cb)(struct tevent_context *ev,
> +			const uint8_t *msg, size_t msg_len,
> +			int *fds, size_t num_fds, void *private_data);
> +	void *recv_cb_private_data;
> +};
> +
> +static pid_t ctdb_pid = 0;
> +static struct msg_ctdb_ref *refs = NULL;
> +
> +static int msg_ctdb_ref_destructor(struct msg_ctdb_ref *r);
> +static void msg_ctdb_ref_recv(struct tevent_context *ev,
> +			      const uint8_t *msg, size_t msg_len,
> +			      int *fds, size_t num_fds, void *private_data);
> +
> +void *messaging_ctdb_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
> +			 const char *sockname, int timeout, uint64_t unique_id,
> +			 void (*recv_cb)(struct tevent_context *ev,
> +					 const uint8_t *msg, size_t msg_len,
> +					 int *fds, size_t num_fds,
> +					 void *private_data),
> +			 void *recv_cb_private_data,
> +			 int *err)
> +{
> +	struct msg_ctdb_ref *result, *tmp_refs;
> +
> +	result = talloc(mem_ctx, struct msg_ctdb_ref);
> +	if (result == NULL) {
> +		*err = ENOMEM;
> +		return NULL;
> +	}
> +	result->fde = NULL;
> +
> +	tmp_refs = refs;
> +
> +	if ((refs != NULL) && (ctdb_pid != getpid())) {
> +		/*
> +		 * Have to reinit after fork
> +		 */
> +		messaging_ctdb_destroy();
> +		refs = NULL;
> +	}
> +
> +	if (refs == NULL) {
> +		int ret;
> +
> +		ret = messaging_ctdb_init(sockname, timeout, unique_id,
> +					  msg_ctdb_ref_recv, NULL);
> +		DBG_DEBUG("messaging_ctdb_init returned %s\n", strerror(ret));
> +		if (ret != 0) {
> +			DEBUG(10, ("messaging_ctdb_init failed: %s\n",
> +				   strerror(ret)));
> +			TALLOC_FREE(result);
> +			*err = ret;
> +			return NULL;
> +		}
> +		ctdb_pid = getpid();
> +	}
> +
> +	result->fde = messaging_ctdb_register_tevent_context(result, ev);
> +	if (result->fde == NULL) {
> +		TALLOC_FREE(result);
> +		*err = ENOMEM;
> +		return NULL;
> +	}
> +
> +	refs = tmp_refs;
> +
> +	result->recv_cb = recv_cb;
> +	result->recv_cb_private_data = recv_cb_private_data;
> +	DLIST_ADD(refs, result);
> +	talloc_set_destructor(result, msg_ctdb_ref_destructor);
> +
> +	return result;
> +}
> +
> +static void msg_ctdb_ref_recv(struct tevent_context *ev,
> +			      const uint8_t *msg, size_t msg_len,
> +			      int *fds, size_t num_fds, void *private_data)
> +{
> +	struct msg_ctdb_ref *r, *next;
> +
> +	for (r = refs; r != NULL; r = next) {
> +		bool active;
> +
> +		next = r->next;
> +
> +		active = messaging_ctdb_fde_active(r->fde);
> +		if (!active) {
> +			/*
> +			 * r's tevent_context has died.
> +			 */
> +			continue;
> +		}
> +
> +		r->recv_cb(ev, msg, msg_len, fds, num_fds,
> +			   r->recv_cb_private_data);
> +		break;
> +	}
> +}
> +
> +static int msg_ctdb_ref_destructor(struct msg_ctdb_ref *r)
> +{
> +	if (refs == NULL) {
> +		abort();
> +	}
> +	DLIST_REMOVE(refs, r);
> +
> +	TALLOC_FREE(r->fde);
> +
> +	DBG_DEBUG("refs=%p\n", refs);
> +
> +	if (refs == NULL) {
> +		messaging_ctdb_destroy();
> +	}
> +	return 0;
> +}
> diff --git a/source3/lib/messages_ctdb_ref.h b/source3/lib/messages_ctdb_ref.h
> new file mode 100644
> index 0000000..44541d8
> --- /dev/null
> +++ b/source3/lib/messages_ctdb_ref.h
> @@ -0,0 +1,35 @@
> +/*
> + * Unix SMB/CIFS implementation.
> + * Samba internal messaging functions
> + * Copyright (C) 2017 by Volker Lendecke
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef __MESSAGES_CTDB_REF_H__
> +#define __MESSAGES_CTDB_REF_H__
> +
> +#include "replace.h"
> +#include <tevent.h>
> +
> +void *messaging_ctdb_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
> +			 const char *sockname, int timeout, uint64_t unique_id,
> +			 void (*recv_cb)(struct tevent_context *ev,
> +					 const uint8_t *msg, size_t msg_len,
> +					 int *fds, size_t num_fds,
> +					 void *private_data),
> +			 void *private_data,
> +			 int *err);
> +
> +#endif
> diff --git a/source3/wscript_build b/source3/wscript_build
> index a57217c..cffcca3 100644
> --- a/source3/wscript_build
> +++ b/source3/wscript_build
> @@ -332,6 +332,7 @@ if bld.env.with_ctdb:
>                       lib/dbwrap/dbwrap_ctdb.c
>                       lib/messages_ctdbd.c
>                       lib/messages_ctdb.c
> +                     lib/messages_ctdb_ref.c
>                       lib/ctdbd_conn.c
>                     '''
>      SAMBA_CLUSTER_SUPPORT_DEPS='''
> -- 
> 2.1.4
> 
> 
> From 63e8dfd533a64881bc8f11a94abfcd144054b07e Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Fri, 16 Jun 2017 17:11:48 +0200
> Subject: [PATCH 35/41] dbwrap_ctdb: Use messaging_ctdbd_connection
> 
> With messages_ctdb, the global ctdb connection will change after fork.
> 
> Don't store the wrong parent connection across a fork. The alternative would
> be to do a reinit on all dbwrap_ctdb databases, but that seems overkill
> given that we only have one "standard" ctdb connection anyway.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/ctdb_dummy.c           |  1 -
>  source3/lib/dbwrap/dbwrap_ctdb.c   | 34 ++++++++++++++++++----------------
>  source3/lib/dbwrap/dbwrap_ctdb.h   |  1 -
>  source3/lib/dbwrap/dbwrap_open.c   |  2 +-
>  source3/torture/test_dbwrap_ctdb.c |  8 +-------
>  5 files changed, 20 insertions(+), 26 deletions(-)
> 
> diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
> index 2d7ba25..891e7c3 100644
> --- a/source3/lib/ctdb_dummy.c
> +++ b/source3/lib/ctdb_dummy.c
> @@ -70,7 +70,6 @@ bool ctdbd_process_exists(struct ctdbd_connection *conn, uint32_t vnn, pid_t pid
>  
>  struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
>  				struct messaging_context *msg_ctx,
> -				struct ctdbd_connection *conn,
>  				const char *name,
>  				int hash_size, int tdb_flags,
>  				int open_flags, mode_t mode,
> diff --git a/source3/lib/dbwrap/dbwrap_ctdb.c b/source3/lib/dbwrap/dbwrap_ctdb.c
> index b722714..2cee058 100644
> --- a/source3/lib/dbwrap/dbwrap_ctdb.c
> +++ b/source3/lib/dbwrap/dbwrap_ctdb.c
> @@ -34,6 +34,7 @@
>  #include "dbwrap/dbwrap_ctdb.h"
>  #include "g_lock.h"
>  #include "messages.h"
> +#include "messages_ctdbd.h"
>  #include "lib/cluster_support.h"
>  #include "lib/util/tevent_ntstatus.h"
>  
> @@ -50,7 +51,6 @@ struct db_ctdb_transaction_handle {
>  
>  struct db_ctdb_ctx {
>  	struct db_context *db;
> -	struct ctdbd_connection *conn;
>  	struct tdb_wrap *wtdb;
>  	uint32_t db_id;
>  	struct db_ctdb_transaction_handle *transaction;
> @@ -640,7 +640,7 @@ static NTSTATUS db_ctdb_transaction_store(struct db_ctdb_transaction_handle *h,
>  		SAFE_FREE(rec.dptr);
>  	}
>  
> -	header.dmaster = ctdbd_vnn(h->ctx->conn);
> +	header.dmaster = get_my_vnn();
>  	header.rsn++;
>  
>  	h->m_write = db_ctdb_marshall_add(h, h->m_write, h->ctx->db_id, 0, key, &header, data);
> @@ -821,7 +821,8 @@ static int db_ctdb_transaction_commit(struct db_context *db)
>  
>  again:
>  	/* tell ctdbd to commit to the other nodes */
> -	ret = ctdbd_control_local(ctx->conn, CTDB_CONTROL_TRANS3_COMMIT,
> +	ret = ctdbd_control_local(messaging_ctdbd_connection(),
> +				  CTDB_CONTROL_TRANS3_COMMIT,
>  				  h->ctx->db_id, 0,
>  				  db_ctdb_marshall_finish(h->m_write),
>  				  NULL, NULL, &status);
> @@ -937,7 +938,7 @@ static NTSTATUS db_ctdb_send_schedule_for_deletion(struct db_record *rec)
>  	dd->keylen = rec->key.dsize;
>  	memcpy(dd->key, rec->key.dptr, rec->key.dsize);
>  
> -	ret = ctdbd_control_local(ctx->conn,
> +	ret = ctdbd_control_local(messaging_ctdbd_connection(),
>  				  CTDB_CONTROL_SCHEDULE_FOR_DELETION,
>  				  crec->ctdb_ctx->db_id,
>  				  CTDB_CTRL_FLAG_NOREPLY, /* flags */
> @@ -1152,8 +1153,7 @@ again:
>  	 * take the shortcut and just return it.
>  	 */
>  
> -	if (!db_ctdb_can_use_local_copy(ctdb_data, ctdbd_vnn(ctx->conn),
> -					false)) {
> +	if (!db_ctdb_can_use_local_copy(ctdb_data, get_my_vnn(), false)) {
>  		SAFE_FREE(ctdb_data.dptr);
>  		tdb_chainunlock(ctx->wtdb->tdb, key);
>  		talloc_set_destructor(result, NULL);
> @@ -1171,12 +1171,13 @@ again:
>  			   ctdb_data.dptr, ctdb_data.dptr ?
>  			   ((struct ctdb_ltdb_header *)ctdb_data.dptr)->dmaster :
>  			   UINT32_MAX,
> -			   ctdbd_vnn(ctx->conn),
> +			   get_my_vnn(),
>  			   ctdb_data.dptr ?
>  			   ((struct ctdb_ltdb_header *)ctdb_data.dptr)->flags : 0));
>  
>  		GetTimeOfDay(&ctdb_start_time);
> -		ret = ctdbd_migrate(ctx->conn, ctx->db_id, key);
> +		ret = ctdbd_migrate(messaging_ctdbd_connection(), ctx->db_id,
> +				    key);
>  		ctdb_time += timeval_elapsed(&ctdb_start_time);
>  
>  		if (ret != 0) {
> @@ -1396,7 +1397,7 @@ static NTSTATUS db_ctdb_parse_record(struct db_context *db, TDB_DATA key,
>  
>  	state.parser = parser;
>  	state.private_data = private_data;
> -	state.my_vnn = ctdbd_vnn(ctx->conn);
> +	state.my_vnn = get_my_vnn();
>  	state.empty_record = false;
>  
>  	status = db_ctdb_try_parse_local_record(ctx, key, &state);
> @@ -1404,7 +1405,7 @@ static NTSTATUS db_ctdb_parse_record(struct db_context *db, TDB_DATA key,
>  		return status;
>  	}
>  
> -	ret = ctdbd_parse(ctx->conn, ctx->db_id, key,
> +	ret = ctdbd_parse(messaging_ctdbd_connection(), ctx->db_id, key,
>  			  state.ask_for_readonly_copy, parser, private_data);
>  	if (ret != 0) {
>  		if (ret == ENOENT) {
> @@ -1453,7 +1454,7 @@ static struct tevent_req *db_ctdb_parse_record_send(
>  	*state = (struct db_ctdb_parse_record_state) {
>  		.parser = parser,
>  		.private_data = private_data,
> -		.my_vnn = ctdbd_vnn(ctx->conn),
> +		.my_vnn = get_my_vnn(),
>  		.empty_record = false,
>  	};
>  
> @@ -1785,7 +1786,6 @@ static size_t db_ctdb_id(struct db_context *db, uint8_t *id, size_t idlen)
>  
>  struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
>  				struct messaging_context *msg_ctx,
> -				struct ctdbd_connection *conn,
>  				const char *name,
>  				int hash_size, int tdb_flags,
>  				int open_flags, mode_t mode,
> @@ -1825,9 +1825,9 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
>  
>  	db_ctdb->transaction = NULL;
>  	db_ctdb->db = result;
> -	db_ctdb->conn = conn;
>  
> -	ret = ctdbd_db_attach(db_ctdb->conn, name, &db_ctdb->db_id, tdb_flags);
> +	ret = ctdbd_db_attach(messaging_ctdbd_connection(), name,
> +			      &db_ctdb->db_id, tdb_flags);
>  	if (ret != 0) {
>  		DEBUG(0, ("ctdbd_db_attach failed for %s: %s\n", name,
>  			  strerror(ret)));
> @@ -1835,7 +1835,8 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
>  		return NULL;
>  	}
>  
> -	db_path = ctdbd_dbpath(db_ctdb->conn, db_ctdb, db_ctdb->db_id);
> +	db_path = ctdbd_dbpath(messaging_ctdbd_connection(), db_ctdb,
> +			       db_ctdb->db_id);
>  
>  	result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
>  	result->lock_order = lock_order;
> @@ -1862,7 +1863,8 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
>  				       sizeof(db_ctdb->db_id));
>  
>  		ret = ctdbd_control_local(
> -			db_ctdb->conn, CTDB_CONTROL_SET_DB_READONLY, 0, 0,
> +			messaging_ctdbd_connection(),
> +			CTDB_CONTROL_SET_DB_READONLY, 0, 0,
>  			indata, NULL, NULL, &cstatus);
>  		if ((ret != 0) || (cstatus != 0)) {
>  			DEBUG(1, ("CTDB_CONTROL_SET_DB_READONLY failed: "
> diff --git a/source3/lib/dbwrap/dbwrap_ctdb.h b/source3/lib/dbwrap/dbwrap_ctdb.h
> index 42c831f..0b82479 100644
> --- a/source3/lib/dbwrap/dbwrap_ctdb.h
> +++ b/source3/lib/dbwrap/dbwrap_ctdb.h
> @@ -30,7 +30,6 @@ struct ctdbd_connection;
>  
>  struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
>  				struct messaging_context *msg_ctx,
> -				struct ctdbd_connection *conn,
>  				const char *name,
>  				int hash_size, int tdb_flags,
>  				int open_flags, mode_t mode,
> diff --git a/source3/lib/dbwrap/dbwrap_open.c b/source3/lib/dbwrap/dbwrap_open.c
> index 55e0adb..dfb87e1 100644
> --- a/source3/lib/dbwrap/dbwrap_open.c
> +++ b/source3/lib/dbwrap/dbwrap_open.c
> @@ -156,7 +156,7 @@ struct db_context *db_open(TALLOC_CTX *mem_ctx,
>  			}
>  			msg_ctx = server_messaging_context();
>  
> -			result = db_open_ctdb(mem_ctx, msg_ctx, conn, partname,
> +			result = db_open_ctdb(mem_ctx, msg_ctx, partname,
>  					      hash_size,
>  					      tdb_flags, open_flags, mode,
>  					      lock_order, dbwrap_flags);
> diff --git a/source3/torture/test_dbwrap_ctdb.c b/source3/torture/test_dbwrap_ctdb.c
> index 4512358..cc6fd0c 100644
> --- a/source3/torture/test_dbwrap_ctdb.c
> +++ b/source3/torture/test_dbwrap_ctdb.c
> @@ -33,16 +33,10 @@ bool run_local_dbwrap_ctdb(int dummy)
>  	NTSTATUS status;
>  	uint32_t val;
>  	struct messaging_context *msg_ctx;
> -	struct ctdbd_connection *conn;
>  
>  	msg_ctx = server_messaging_context();
> -	conn = messaging_ctdbd_connection();
> -	if (conn == NULL) {
> -		fprintf(stderr, "no ctdbd connection\n");
> -		goto fail;
> -	}
>  
> -	db = db_open_ctdb(talloc_tos(), msg_ctx, conn, "torture.tdb",
> +	db = db_open_ctdb(talloc_tos(), msg_ctx, "torture.tdb",
>  			  0, TDB_DEFAULT,
>  			  O_RDWR, 0755, DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
>  	if (db == NULL) {
> -- 
> 2.1.4
> 
> 
> From 1d66e896110db886554043a16d128607e9575115 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Fri, 16 Jun 2017 15:20:39 +0200
> Subject: [PATCH 36/41] smbpasswd: Initialize messaging for messaging_ctdb_conn
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/utils/smbpasswd.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/source3/utils/smbpasswd.c b/source3/utils/smbpasswd.c
> index 437a5e5..aa6b857 100644
> --- a/source3/utils/smbpasswd.c
> +++ b/source3/utils/smbpasswd.c
> @@ -603,6 +603,10 @@ int main(int argc, char **argv)
>  
>  	setup_logging("smbpasswd", DEBUG_STDERR);
>  
> +	if (server_messaging_context() == NULL) {
> +		return 1;
> +	}
> +
>  	/*
>  	 * Set the machine NETBIOS name if not already
>  	 * set from the config file. 
> -- 
> 2.1.4
> 
> 
> From f3c7775b1d0a23d2223ab72aa0806418d1644e6d Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Wed, 5 Jul 2017 19:13:23 +0200
> Subject: [PATCH 37/41] messages_ctdb: Add messaging_ctdb_connection
> 
> This will be the replacement for messaging_ctdbd_connection(). This does not
> default to initializing messaging but panics. We just don't have correct
> default arguments for messaging_init. Implicit multiple messaging and event
> contexts is a bug also.
> 
> It *might* be that some tools fail due to this, but this needs fixing in
> different ways. See the previous commit for smbpasswd.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/messages_ctdb.c | 8 ++++++++
>  source3/lib/messages_ctdb.h | 2 ++
>  2 files changed, 10 insertions(+)
> 
> diff --git a/source3/lib/messages_ctdb.c b/source3/lib/messages_ctdb.c
> index 5bc494d..a2a7c21 100644
> --- a/source3/lib/messages_ctdb.c
> +++ b/source3/lib/messages_ctdb.c
> @@ -258,3 +258,11 @@ bool messaging_ctdb_fde_active(struct messaging_ctdb_fde *fde)
>  	flags = tevent_fd_get_flags(fde->fde);
>  	return (flags != 0);
>  }
> +
> +struct ctdbd_connection *messaging_ctdb_connection(void)
> +{
> +	if (global_ctdb_context == NULL) {
> +		smb_panic("messaging not initialized\n");
> +	}
> +	return global_ctdb_context->conn;
> +}
> diff --git a/source3/lib/messages_ctdb.h b/source3/lib/messages_ctdb.h
> index 006821b..9d56343 100644
> --- a/source3/lib/messages_ctdb.h
> +++ b/source3/lib/messages_ctdb.h
> @@ -39,4 +39,6 @@ struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
>  	TALLOC_CTX *mem_ctx, struct tevent_context *ev);
>  bool messaging_ctdb_fde_active(struct messaging_ctdb_fde *fde);
>  
> +struct ctdbd_connection *messaging_ctdb_connection(void);
> +
>  #endif
> -- 
> 2.1.4
> 
> 
> From 1d8de56b4fd79306bf28d55231785999708d6498 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Wed, 5 Jul 2017 19:20:09 +0200
> Subject: [PATCH 38/41] messaging: Use messaging_ctdb_ref()
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/messages.c | 83 ++++++++++++++++++++------------------------------
>  1 file changed, 33 insertions(+), 50 deletions(-)
> 
> diff --git a/source3/lib/messages.c b/source3/lib/messages.c
> index 4e838b0..765add9 100644
> --- a/source3/lib/messages.c
> +++ b/source3/lib/messages.c
> @@ -53,11 +53,13 @@
>  #include "lib/util/tevent_unix.h"
>  #include "lib/background.h"
>  #include "lib/messages_dgm.h"
> -#include "lib/messages_ctdbd.h"
>  #include "lib/util/iov_buf.h"
>  #include "lib/util/server_id_db.h"
>  #include "lib/messages_dgm_ref.h"
> +#include "lib/messages_ctdb.h"
> +#include "lib/messages_ctdb_ref.h"
>  #include "lib/messages_util.h"
> +#include "cluster_support.h"
>  
>  struct messaging_callback {
>  	struct messaging_callback *prev, *next;
> @@ -90,8 +92,7 @@ struct messaging_context {
>  	size_t num_waiters;
>  
>  	void *msg_dgm_ref;
> -	struct messaging_backend *remote;
> -	struct messaging_ctdbd_fde *cluster_fde;
> +	void *msg_ctdb_ref;
>  
>  	struct server_id_db *names_db;
>  };
> @@ -513,23 +514,16 @@ static NTSTATUS messaging_init_internal(TALLOC_CTX *mem_ctx,
>  	talloc_set_destructor(ctx, messaging_context_destructor);
>  
>  	if (lp_clustering()) {
> -		ret = messaging_ctdbd_init(
> -			ctx, ctx, messaging_recv_cb, ctx, &ctx->remote);
> -
> -		if (ret != 0) {
> -			DEBUG(2, ("messaging_ctdbd_init failed: %s\n",
> -				  strerror(ret)));
> +		ctx->msg_ctdb_ref = messaging_ctdb_ref(
> +			ctx, ctx->event_ctx,
> +			lp_ctdbd_socket(), lp_ctdb_timeout(),
> +			ctx->id.unique_id, messaging_recv_cb, ctx, &ret);
> +		if (ctx->msg_ctdb_ref == NULL) {
> +			DBG_NOTICE("messaging_ctdb_ref failed: %s\n",
> +				   strerror(ret));
>  			status = map_nt_error_from_unix(ret);
>  			goto done;
>  		}
> -		ctx->cluster_fde = messaging_ctdbd_register_tevent_context(
> -			ctx, ctx->event_ctx, ctx->remote);
> -		if (ctx->cluster_fde == NULL) {
> -			DBG_WARNING("messaging_ctdbd_register_tevent_context "
> -				    "failed\n");
> -			status = NT_STATUS_NO_MEMORY;
> -			goto done;
> -		}
>  	}
>  	ctx->id.vnn = get_my_vnn();
>  
> @@ -605,6 +599,7 @@ NTSTATUS messaging_reinit(struct messaging_context *msg_ctx)
>  	char *lck_path;
>  
>  	TALLOC_FREE(msg_ctx->msg_dgm_ref);
> +	TALLOC_FREE(msg_ctx->msg_ctdb_ref);
>  
>  	msg_ctx->id = (struct server_id) {
>  		.pid = getpid(), .vnn = msg_ctx->id.vnn
> @@ -626,25 +621,16 @@ NTSTATUS messaging_reinit(struct messaging_context *msg_ctx)
>  	}
>  
>  	if (lp_clustering()) {
> -		TALLOC_FREE(msg_ctx->cluster_fde);
> -
> -		ret = messaging_ctdbd_reinit(
> -			msg_ctx, msg_ctx, messaging_recv_cb, msg_ctx,
> -			msg_ctx->remote);
> -
> -		if (ret != 0) {
> -			DEBUG(1, ("messaging_ctdbd_init failed: %s\n",
> -				  strerror(ret)));
> +		msg_ctx->msg_ctdb_ref = messaging_ctdb_ref(
> +			msg_ctx, msg_ctx->event_ctx,
> +			lp_ctdbd_socket(), lp_ctdb_timeout(),
> +			msg_ctx->id.unique_id, messaging_recv_cb, msg_ctx,
> +			&ret);
> +		if (msg_ctx->msg_ctdb_ref == NULL) {
> +			DBG_NOTICE("messaging_ctdb_ref failed: %s\n",
> +				   strerror(ret));
>  			return map_nt_error_from_unix(ret);
>  		}
> -
> -		msg_ctx->cluster_fde = messaging_ctdbd_register_tevent_context(
> -			msg_ctx, msg_ctx->event_ctx, msg_ctx->remote);
> -		if (msg_ctx->cluster_fde == NULL) {
> -			DBG_WARNING("messaging_ctdbd_register_tevent_context "
> -				    "failed\n");
> -			return NT_STATUS_NO_MEMORY;
> -		}
>  	}
>  
>  	server_id_db_reinit(msg_ctx->names_db, msg_ctx->id);
> @@ -793,18 +779,6 @@ int messaging_send_iov_from(struct messaging_context *msg_ctx,
>  		return EINVAL;
>  	}
>  
> -	if (dst.vnn != msg_ctx->id.vnn) {
> -		if (num_fds > 0) {
> -			return ENOSYS;
> -		}
> -
> -		ret = msg_ctx->remote->send_fn(src, dst,
> -					       msg_type, iov, iovlen,
> -					       NULL, 0,
> -					       msg_ctx->remote);
> -		return ret;
> -	}
> -
>  	if (server_id_equal(&dst, &msg_ctx->id)) {
>  		ret = messaging_post_self(msg_ctx, src, dst, msg_type,
>  					  iov, iovlen, fds, num_fds);
> @@ -815,6 +789,15 @@ int messaging_send_iov_from(struct messaging_context *msg_ctx,
>  	iov2[0] = (struct iovec){ .iov_base = hdr, .iov_len = sizeof(hdr) };
>  	memcpy(&iov2[1], iov, iovlen * sizeof(*iov));
>  
> +	if (dst.vnn != msg_ctx->id.vnn) {
> +		if (num_fds > 0) {
> +			return ENOSYS;
> +		}
> +
> +		ret = messaging_ctdb_send(dst.vnn, dst.pid, iov2, iovlen+1);
> +		return ret;
> +	}
> +
>  	ret = messaging_dgm_send(dst.pid, iov2, iovlen+1, fds, num_fds);
>  
>  	if (ret == EACCES) {
> @@ -890,7 +873,7 @@ struct messaging_filtered_read_state {
>  	struct tevent_context *ev;
>  	struct messaging_context *msg_ctx;
>  	struct messaging_dgm_fde *fde;
> -	struct messaging_ctdbd_fde *cluster_fde;
> +	struct messaging_ctdb_fde *cluster_fde;
>  
>  	bool (*filter)(struct messaging_rec *rec, void *private_data);
>  	void *private_data;
> @@ -933,9 +916,9 @@ struct tevent_req *messaging_filtered_read_send(
>  		return tevent_req_post(req, ev);
>  	}
>  
> -	if (msg_ctx->remote != NULL) {
> -		state->cluster_fde = messaging_ctdbd_register_tevent_context(
> -			state, ev, msg_ctx->remote);
> +	if (lp_clustering()) {
> +		state->cluster_fde =
> +			messaging_ctdb_register_tevent_context(state, ev);
>  		if (tevent_req_nomem(state->cluster_fde, req)) {
>  			return tevent_req_post(req, ev);
>  		}
> -- 
> 2.1.4
> 
> 
> From 815850ea501f04901767797b33bc764d1650e686 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Fri, 16 Jun 2017 13:00:59 +0200
> Subject: [PATCH 39/41] ctdb_conn: Use messaging_ctdb_connection
> 
> Replace messaging_ctdbd_connection
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/ctdb_dummy.c           |  2 +-
>  source3/lib/dbwrap/dbwrap_ctdb.c   | 16 ++++++++--------
>  source3/lib/dbwrap/dbwrap_open.c   |  4 ++--
>  source3/lib/serverid.c             |  6 +++---
>  source3/smbd/notifyd/notifydd.c    |  4 ++--
>  source3/smbd/process.c             |  4 ++--
>  source3/smbd/server.c              |  6 +++---
>  source3/torture/test_dbwrap_ctdb.c |  2 +-
>  source3/wscript_build              |  1 -
>  9 files changed, 22 insertions(+), 23 deletions(-)
> 
> diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
> index 891e7c3..f301c1f 100644
> --- a/source3/lib/ctdb_dummy.c
> +++ b/source3/lib/ctdb_dummy.c
> @@ -135,7 +135,7 @@ struct messaging_ctdbd_fde *messaging_ctdbd_register_tevent_context(
>  	return NULL;
>  }
>  
> -struct ctdbd_connection *messaging_ctdbd_connection(void)
> +struct ctdbd_connection *messaging_ctdb_connection(void)
>  {
>  	return NULL;
>  }
> diff --git a/source3/lib/dbwrap/dbwrap_ctdb.c b/source3/lib/dbwrap/dbwrap_ctdb.c
> index 2cee058..3dba85d 100644
> --- a/source3/lib/dbwrap/dbwrap_ctdb.c
> +++ b/source3/lib/dbwrap/dbwrap_ctdb.c
> @@ -34,7 +34,7 @@
>  #include "dbwrap/dbwrap_ctdb.h"
>  #include "g_lock.h"
>  #include "messages.h"
> -#include "messages_ctdbd.h"
> +#include "messages_ctdb.h"
>  #include "lib/cluster_support.h"
>  #include "lib/util/tevent_ntstatus.h"
>  
> @@ -821,7 +821,7 @@ static int db_ctdb_transaction_commit(struct db_context *db)
>  
>  again:
>  	/* tell ctdbd to commit to the other nodes */
> -	ret = ctdbd_control_local(messaging_ctdbd_connection(),
> +	ret = ctdbd_control_local(messaging_ctdb_connection(),
>  				  CTDB_CONTROL_TRANS3_COMMIT,
>  				  h->ctx->db_id, 0,
>  				  db_ctdb_marshall_finish(h->m_write),
> @@ -938,7 +938,7 @@ static NTSTATUS db_ctdb_send_schedule_for_deletion(struct db_record *rec)
>  	dd->keylen = rec->key.dsize;
>  	memcpy(dd->key, rec->key.dptr, rec->key.dsize);
>  
> -	ret = ctdbd_control_local(messaging_ctdbd_connection(),
> +	ret = ctdbd_control_local(messaging_ctdb_connection(),
>  				  CTDB_CONTROL_SCHEDULE_FOR_DELETION,
>  				  crec->ctdb_ctx->db_id,
>  				  CTDB_CTRL_FLAG_NOREPLY, /* flags */
> @@ -1176,7 +1176,7 @@ again:
>  			   ((struct ctdb_ltdb_header *)ctdb_data.dptr)->flags : 0));
>  
>  		GetTimeOfDay(&ctdb_start_time);
> -		ret = ctdbd_migrate(messaging_ctdbd_connection(), ctx->db_id,
> +		ret = ctdbd_migrate(messaging_ctdb_connection(), ctx->db_id,
>  				    key);
>  		ctdb_time += timeval_elapsed(&ctdb_start_time);
>  
> @@ -1405,7 +1405,7 @@ static NTSTATUS db_ctdb_parse_record(struct db_context *db, TDB_DATA key,
>  		return status;
>  	}
>  
> -	ret = ctdbd_parse(messaging_ctdbd_connection(), ctx->db_id, key,
> +	ret = ctdbd_parse(messaging_ctdb_connection(), ctx->db_id, key,
>  			  state.ask_for_readonly_copy, parser, private_data);
>  	if (ret != 0) {
>  		if (ret == ENOENT) {
> @@ -1826,7 +1826,7 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
>  	db_ctdb->transaction = NULL;
>  	db_ctdb->db = result;
>  
> -	ret = ctdbd_db_attach(messaging_ctdbd_connection(), name,
> +	ret = ctdbd_db_attach(messaging_ctdb_connection(), name,
>  			      &db_ctdb->db_id, tdb_flags);
>  	if (ret != 0) {
>  		DEBUG(0, ("ctdbd_db_attach failed for %s: %s\n", name,
> @@ -1835,7 +1835,7 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
>  		return NULL;
>  	}
>  
> -	db_path = ctdbd_dbpath(messaging_ctdbd_connection(), db_ctdb,
> +	db_path = ctdbd_dbpath(messaging_ctdb_connection(), db_ctdb,
>  			       db_ctdb->db_id);
>  
>  	result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
> @@ -1863,7 +1863,7 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
>  				       sizeof(db_ctdb->db_id));
>  
>  		ret = ctdbd_control_local(
> -			messaging_ctdbd_connection(),
> +			messaging_ctdb_connection(),
>  			CTDB_CONTROL_SET_DB_READONLY, 0, 0,
>  			indata, NULL, NULL, &cstatus);
>  		if ((ret != 0) || (cstatus != 0)) {
> diff --git a/source3/lib/dbwrap/dbwrap_open.c b/source3/lib/dbwrap/dbwrap_open.c
> index dfb87e1..64627d1 100644
> --- a/source3/lib/dbwrap/dbwrap_open.c
> +++ b/source3/lib/dbwrap/dbwrap_open.c
> @@ -26,7 +26,7 @@
>  #include "dbwrap/dbwrap_ctdb.h"
>  #include "lib/param/param.h"
>  #include "lib/cluster_support.h"
> -#include "lib/messages_ctdbd.h"
> +#include "lib/messages_ctdb.h"
>  #include "util_tdb.h"
>  #include "ctdbd_conn.h"
>  #include "messages.h"
> @@ -148,7 +148,7 @@ struct db_context *db_open(TALLOC_CTX *mem_ctx,
>  			struct messaging_context *msg_ctx;
>  			struct ctdbd_connection *conn;
>  
> -			conn = messaging_ctdbd_connection();
> +			conn = messaging_ctdb_connection();
>  			if (conn == NULL) {
>  				DBG_WARNING("No ctdb connection\n");
>  				errno = EIO;
> diff --git a/source3/lib/serverid.c b/source3/lib/serverid.c
> index fb32526..ca4bb27 100644
> --- a/source3/lib/serverid.c
> +++ b/source3/lib/serverid.c
> @@ -28,7 +28,7 @@
>  #include "lib/param/param.h"
>  #include "ctdbd_conn.h"
>  #include "messages.h"
> -#include "lib/messages_ctdbd.h"
> +#include "lib/messages_ctdb.h"
>  #include "lib/messages_dgm.h"
>  
>  struct serverid_key {
> @@ -124,7 +124,7 @@ bool serverid_register(const struct server_id id, uint32_t msg_flags)
>  	}
>  
>  	if (lp_clustering()) {
> -		register_with_ctdbd(messaging_ctdbd_connection(), id.unique_id,
> +		register_with_ctdbd(messaging_ctdb_connection(), id.unique_id,
>  				    NULL, NULL);
>  	}
>  
> @@ -198,7 +198,7 @@ bool serverid_exists(const struct server_id *id)
>  	}
>  
>  	if (lp_clustering()) {
> -		return ctdbd_process_exists(messaging_ctdbd_connection(),
> +		return ctdbd_process_exists(messaging_ctdb_connection(),
>  					    id->vnn, id->pid);
>  	}
>  
> diff --git a/source3/smbd/notifyd/notifydd.c b/source3/smbd/notifyd/notifydd.c
> index ad3621a..faad4e7 100644
> --- a/source3/smbd/notifyd/notifydd.c
> +++ b/source3/smbd/notifyd/notifydd.c
> @@ -19,7 +19,7 @@
>  
>  #include "replace.h"
>  #include "notifyd.h"
> -#include "lib/messages_ctdbd.h"
> +#include "lib/messages_ctdb.h"
>  #include <tevent.h>
>  #include "lib/util/tevent_unix.h"
>  
> @@ -59,7 +59,7 @@ int main(int argc, const char *argv[])
>  		return 1;
>  	}
>  
> -	req = notifyd_send(ev, ev, msg, messaging_ctdbd_connection(),
> +	req = notifyd_send(ev, ev, msg, messaging_ctdb_connection(),
>  			   NULL, NULL);
>  	if (req == NULL) {
>  		fprintf(stderr, "notifyd_send failed\n");
> diff --git a/source3/smbd/process.c b/source3/smbd/process.c
> index 4abaf37..7dc9b34 100644
> --- a/source3/smbd/process.c
> +++ b/source3/smbd/process.c
> @@ -32,7 +32,7 @@
>  #include "passdb.h"
>  #include "auth.h"
>  #include "messages.h"
> -#include "lib/messages_ctdbd.h"
> +#include "lib/messages_ctdb.h"
>  #include "smbprofile.h"
>  #include "rpc_server/spoolss/srv_spoolss_nt.h"
>  #include "libsmb/libsmb.h"
> @@ -2775,7 +2775,7 @@ static NTSTATUS smbd_register_ips(struct smbXsrv_connection *xconn,
>  	struct ctdbd_connection *cconn;
>  	int ret;
>  
> -	cconn = messaging_ctdbd_connection();
> +	cconn = messaging_ctdb_connection();
>  	if (cconn == NULL) {
>  		return NT_STATUS_NO_MEMORY;
>  	}
> diff --git a/source3/smbd/server.c b/source3/smbd/server.c
> index 91fa1c3..f87bb0d 100644
> --- a/source3/smbd/server.c
> +++ b/source3/smbd/server.c
> @@ -40,7 +40,7 @@
>  #include "passdb.h"
>  #include "auth.h"
>  #include "messages.h"
> -#include "messages_ctdbd.h"
> +#include "messages_ctdb.h"
>  #include "smbprofile.h"
>  #include "lib/id_cache.h"
>  #include "lib/param/param.h"
> @@ -361,7 +361,7 @@ static struct tevent_req *notifyd_req(struct messaging_context *msg_ctx,
>  	}
>  
>  	if (lp_clustering()) {
> -		ctdbd_conn = messaging_ctdbd_connection();
> +		ctdbd_conn = messaging_ctdb_connection();
>  	}
>  
>  	req = notifyd_send(msg_ctx, ev, msg_ctx, ctdbd_conn,
> @@ -1296,7 +1296,7 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
>  
>  #ifdef CLUSTER_SUPPORT
>  	if (lp_clustering()) {
> -		struct ctdbd_connection *conn = messaging_ctdbd_connection();
> +		struct ctdbd_connection *conn = messaging_ctdb_connection();
>  
>  		register_with_ctdbd(conn, CTDB_SRVID_RECONFIGURE,
>  				    smbd_parent_ctdb_reconfigured, msg_ctx);
> diff --git a/source3/torture/test_dbwrap_ctdb.c b/source3/torture/test_dbwrap_ctdb.c
> index cc6fd0c..1da5c94 100644
> --- a/source3/torture/test_dbwrap_ctdb.c
> +++ b/source3/torture/test_dbwrap_ctdb.c
> @@ -23,7 +23,7 @@
>  #include "lib/dbwrap/dbwrap.h"
>  #include "lib/dbwrap/dbwrap_ctdb.h"
>  #include "messages.h"
> -#include "lib/messages_ctdbd.h"
> +#include "lib/messages_ctdb.h"
>  
>  bool run_local_dbwrap_ctdb(int dummy)
>  {
> diff --git a/source3/wscript_build b/source3/wscript_build
> index cffcca3..3f62bc2 100644
> --- a/source3/wscript_build
> +++ b/source3/wscript_build
> @@ -330,7 +330,6 @@ if bld.env.with_ctdb:
>      SAMBA_CLUSTER_SUPPORT_SOURCES='''
>                       lib/cluster_support.c
>                       lib/dbwrap/dbwrap_ctdb.c
> -                     lib/messages_ctdbd.c
>                       lib/messages_ctdb.c
>                       lib/messages_ctdb_ref.c
>                       lib/ctdbd_conn.c
> -- 
> 2.1.4
> 
> 
> From 448620755d1fc43864242cdf2aa0853614d4e764 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Wed, 5 Jul 2017 19:24:32 +0200
> Subject: [PATCH 40/41] messaging: Remove messages_ctdbd.c
> 
> Replaced by messages_ctdb.[ch]
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/ctdb_dummy.c     |  32 ----
>  source3/lib/messages_ctdbd.c | 354 -------------------------------------------
>  source3/lib/messages_ctdbd.h |  53 -------
>  3 files changed, 439 deletions(-)
>  delete mode 100644 source3/lib/messages_ctdbd.c
>  delete mode 100644 source3/lib/messages_ctdbd.h
> 
> diff --git a/source3/lib/ctdb_dummy.c b/source3/lib/ctdb_dummy.c
> index f301c1f..8a06b0c 100644
> --- a/source3/lib/ctdb_dummy.c
> +++ b/source3/lib/ctdb_dummy.c
> @@ -19,7 +19,6 @@
>  
>  #include "includes.h"
>  #include "messages.h"
> -#include "lib/messages_ctdbd.h"
>  #include "lib/messages_ctdb.h"
>  #include "lib/messages_ctdb_ref.h"
>  #include "ctdbd_conn.h"
> @@ -80,18 +79,6 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
>  	return NULL;
>  }
>  
> -int messaging_ctdbd_init(struct messaging_context *msg_ctx,
> -			 TALLOC_CTX *mem_ctx,
> -			 void (*recv_cb)(struct tevent_context *ev,
> -					 const uint8_t *msg, size_t msg_len,
> -					 int *fds, size_t num_fds,
> -					 void *private_data),
> -			 void *private_data,
> -			      struct messaging_backend **presult)
> -{
> -	return ENOSYS;
> -}
> -
>  int messaging_ctdb_send(uint32_t dst_vnn, uint64_t dst_srvid,
>  			const struct iovec *iov, int iovlen)
>  {
> @@ -116,25 +103,6 @@ struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
>  	return NULL;
>  }
>  
> -int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
> -			   TALLOC_CTX *mem_ctx,
> -			   void (*recv_cb)(struct tevent_context *ev,
> -					   const uint8_t *msg, size_t msg_len,
> -					   int *fds, size_t num_fds,
> -					   void *private_data),
> -			   void *private_data,
> -			   struct messaging_backend *backend)
> -{
> -	return ENOSYS;
> -}
> -
> -struct messaging_ctdbd_fde *messaging_ctdbd_register_tevent_context(
> -	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
> -	struct messaging_backend *backend)
> -{
> -	return NULL;
> -}
> -
>  struct ctdbd_connection *messaging_ctdb_connection(void)
>  {
>  	return NULL;
> diff --git a/source3/lib/messages_ctdbd.c b/source3/lib/messages_ctdbd.c
> deleted file mode 100644
> index b1af4f8..0000000
> --- a/source3/lib/messages_ctdbd.c
> +++ /dev/null
> @@ -1,354 +0,0 @@
> -/* 
> -   Unix SMB/CIFS implementation.
> -   Samba internal messaging functions
> -   Copyright (C) 2007 by Volker Lendecke
> -
> -   This program is free software; you can redistribute it and/or modify
> -   it under the terms of the GNU General Public License as published by
> -   the Free Software Foundation; either version 3 of the License, or
> -   (at your option) any later version.
> -
> -   This program is distributed in the hope that it will be useful,
> -   but WITHOUT ANY WARRANTY; without even the implied warranty of
> -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> -   GNU General Public License for more details.
> -
> -   You should have received a copy of the GNU General Public License
> -   along with this program.  If not, see <http://www.gnu.org/licenses/>.
> -*/
> -
> -#include "includes.h"
> -#include "lib/messages_ctdbd.h"
> -#include "lib/util/server_id.h"
> -#include "messages.h"
> -#include "util_tdb.h"
> -#include "lib/util/iov_buf.h"
> -#include "lib/messages_util.h"
> -#include "ctdbd_conn.h"
> -#include "lib/cluster_support.h"
> -
> -struct messaging_ctdbd_context;
> -
> -struct messaging_ctdbd_fde_ev {
> -	struct messaging_ctdbd_fde_ev *prev, *next;
> -
> -	/*
> -	 * Backreference to enable DLIST_REMOVE from our
> -	 * destructor. Also, set to NULL when the dgm_context dies
> -	 * before the messaging_dgm_fde_ev.
> -	 */
> -	struct messaging_ctdbd_context *ctx;
> -
> -	struct tevent_context *ev;
> -	struct tevent_fd *fde;
> -};
> -
> -struct messaging_ctdbd_context {
> -	struct ctdbd_connection *conn;
> -
> -	struct messaging_ctdbd_fde_ev *fde_evs;
> -
> -	void (*recv_cb)(struct tevent_context *ev,
> -			const uint8_t *msg, size_t msg_len,
> -			int *fds, size_t num_fds,
> -			void *private_data);
> -	void *private_data;
> -};
> -
> -/*
> - * This is a Samba3 hack/optimization. Routines like process_exists need to
> - * talk to ctdbd, and they don't get handed a messaging context.
> - */
> -static struct ctdbd_connection *global_ctdbd_connection;
> -static int global_ctdb_connection_pid;
> -
> -struct ctdbd_connection *messaging_ctdbd_connection(void)
> -{
> -	if (!lp_clustering()) {
> -		return NULL;
> -	}
> -
> -	if (global_ctdb_connection_pid == 0 &&
> -	    global_ctdbd_connection == NULL) {
> -		struct tevent_context *ev;
> -		struct messaging_context *msg;
> -
> -		ev = samba_tevent_context_init(NULL);
> -		if (!ev) {
> -			DEBUG(0,("samba_tevent_context_init failed\n"));
> -			return NULL;
> -		}
> -
> -		msg = messaging_init(NULL, ev);
> -		if (!msg) {
> -			DEBUG(0,("messaging_init failed\n"));
> -			return NULL;
> -		}
> -	}
> -
> -	if (global_ctdb_connection_pid != getpid()) {
> -		DEBUG(0,("messaging_ctdbd_connection():"
> -			 "valid for pid[%jd] but it's [%jd]\n",
> -			 (intmax_t)global_ctdb_connection_pid,
> -			 (intmax_t)getpid()));
> -		smb_panic("messaging_ctdbd_connection() invalid process\n");
> -	}
> -
> -	return global_ctdbd_connection;
> -}
> -
> -static int messaging_ctdb_send(struct server_id src,
> -			       struct server_id pid, int msg_type,
> -			       const struct iovec *iov, int iovlen,
> -			       const int *fds, size_t num_fds,
> -			       struct messaging_backend *backend)
> -{
> -	struct messaging_ctdbd_context *ctx = talloc_get_type_abort(
> -		backend->private_data, struct messaging_ctdbd_context);
> -	uint8_t hdr[MESSAGE_HDR_LENGTH];
> -	struct iovec iov2[iovlen+1];
> -
> -	if (num_fds > 0) {
> -		return ENOSYS;
> -	}
> -
> -	message_hdr_put(hdr, msg_type, src, pid);
> -	iov2[0] = (struct iovec){ .iov_base = hdr, .iov_len = sizeof(hdr) };
> -	memcpy(&iov2[1], iov, iovlen * sizeof(*iov));
> -
> -	return ctdbd_messaging_send_iov(ctx->conn, pid.vnn, pid.pid,
> -					iov2, iovlen+1);
> -}
> -
> -static int messaging_ctdbd_destructor(struct messaging_ctdbd_context *ctx)
> -{
> -	/*
> -	 * The global connection just went away
> -	 */
> -	global_ctdb_connection_pid = 0;
> -	global_ctdbd_connection = NULL;
> -	return 0;
> -}
> -
> -static int messaging_ctdb_recv(
> -	struct tevent_context *ev,
> -	uint32_t src_vnn, uint32_t dst_vnn, uint64_t dst_srvid,
> -	const uint8_t *msg, size_t msg_len, void *private_data)
> -{
> -	struct messaging_ctdbd_context *ctx = talloc_get_type_abort(
> -		private_data, struct messaging_ctdbd_context);
> -
> -	ctx->recv_cb(ev, msg, msg_len, NULL, 0, ctx->private_data);
> -
> -	return 0;
> -}
> -
> -static void messaging_ctdbd_readable(struct tevent_context *ev,
> -				     struct tevent_fd *fde,
> -				     uint16_t flags,
> -				     void *private_data)
> -{
> -	struct ctdbd_connection *conn = talloc_get_type_abort(
> -		private_data, struct ctdbd_connection);
> -
> -	if ((flags & TEVENT_FD_READ) == 0) {
> -		return;
> -	}
> -	ctdbd_socket_readable(ev, conn);
> -}
> -
> -static int messaging_ctdbd_init_internal(
> -	struct messaging_context *msg_ctx, TALLOC_CTX *mem_ctx,
> -	struct messaging_ctdbd_context *ctx,
> -	void (*recv_cb)(struct tevent_context *ev,
> -			const uint8_t *msg, size_t msg_len,
> -			int *fds, size_t num_fds,
> -			void *private_data),
> -	void *private_data,
> -	bool reinit)
> -{
> -	int ret;
> -
> -	if (reinit) {
> -		ret = ctdbd_reinit_connection(ctx,
> -					      lp_ctdbd_socket(),
> -					      lp_ctdb_timeout(),
> -					      ctx->conn);
> -		if (ret != 0) {
> -			DBG_ERR("ctdbd_reinit_connection failed: %s\n",
> -				strerror(ret));
> -			return ret;
> -		}
> -	} else {
> -		ret = ctdbd_init_connection(ctx,
> -					    lp_ctdbd_socket(),
> -					    lp_ctdb_timeout(),
> -					    &ctx->conn);
> -		if (ret != 0) {
> -			DBG_ERR("ctdbd_init_connection failed: %s\n",
> -				strerror(ret));
> -			return ret;
> -		}
> -	}
> -
> -	ret = register_with_ctdbd(ctx->conn, MSG_SRVID_SAMBA, NULL, NULL);
> -	if (ret != 0) {
> -		DBG_DEBUG("Could not register MSG_SRVID_SAMBA: %s\n",
> -			  strerror(ret));
> -		return ret;
> -	}
> -
> -	ctx->recv_cb = recv_cb;
> -	ctx->private_data = private_data;
> -
> -	ret = register_with_ctdbd(ctx->conn, getpid(),
> -				  messaging_ctdb_recv, ctx);
> -	if (ret != 0) {
> -		DEBUG(10, ("register_with_ctdbd failed: %s\n",
> -			   strerror(ret)));
> -		return ret;
> -	}
> -
> -	global_ctdb_connection_pid = getpid();
> -	global_ctdbd_connection = ctx->conn;
> -	talloc_set_destructor(ctx, messaging_ctdbd_destructor);
> -
> -	set_my_vnn(ctdbd_vnn(ctx->conn));
> -
> -	return 0;
> -}
> -
> -int messaging_ctdbd_init(struct messaging_context *msg_ctx,
> -			 TALLOC_CTX *mem_ctx,
> -			 void (*recv_cb)(struct tevent_context *ev,
> -					 const uint8_t *msg, size_t msg_len,
> -					 int *fds, size_t num_fds,
> -					 void *private_data),
> -			 void *private_data,
> -			 struct messaging_backend **presult)
> -{
> -	struct messaging_backend *result;
> -	struct messaging_ctdbd_context *ctx;
> -	int ret;
> -
> -	if (!(result = talloc(mem_ctx, struct messaging_backend))) {
> -		DEBUG(0, ("talloc failed\n"));
> -		return ENOMEM;
> -	}
> -
> -	if (!(ctx = talloc_zero(result, struct messaging_ctdbd_context))) {
> -		DEBUG(0, ("talloc failed\n"));
> -		TALLOC_FREE(result);
> -		return ENOMEM;
> -	}
> -
> -	ret = messaging_ctdbd_init_internal(msg_ctx, mem_ctx, ctx,
> -					    recv_cb, private_data, false);
> -	if (ret != 0) {
> -		TALLOC_FREE(result);
> -		return ret;
> -	}
> -
> -	result->send_fn = messaging_ctdb_send;
> -	result->private_data = (void *)ctx;
> -
> -	*presult = result;
> -	return 0;
> -}
> -
> -int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
> -			   TALLOC_CTX *mem_ctx,
> -			   void (*recv_cb)(struct tevent_context *ev,
> -					   const uint8_t *msg, size_t msg_len,
> -					   int *fds, size_t num_fds,
> -					   void *private_data),
> -			   void *private_data,
> -			   struct messaging_backend *backend)
> -{
> -	struct messaging_ctdbd_context *ctx = talloc_get_type_abort(
> -		backend->private_data, struct messaging_ctdbd_context);
> -	int ret;
> -
> -	ret = messaging_ctdbd_init_internal(msg_ctx, mem_ctx, ctx,
> -					    recv_cb, private_data, true);
> -	if (ret != 0) {
> -		return ret;
> -	}
> -
> -	return 0;
> -}
> -
> -struct messaging_ctdbd_fde {
> -	struct tevent_fd *fde;
> -};
> -
> -static int messaging_ctdbd_fde_ev_destructor(
> -	struct messaging_ctdbd_fde_ev *fde_ev)
> -{
> -	if (fde_ev->ctx != NULL) {
> -		DLIST_REMOVE(fde_ev->ctx->fde_evs, fde_ev);
> -		fde_ev->ctx = NULL;
> -	}
> -	return 0;
> -}
> -
> -struct messaging_ctdbd_fde *messaging_ctdbd_register_tevent_context(
> -	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
> -	struct messaging_backend *backend)
> -{
> -	struct messaging_ctdbd_context *ctx = talloc_get_type_abort(
> -		backend->private_data, struct messaging_ctdbd_context);
> -	struct messaging_ctdbd_fde_ev *fde_ev;
> -	struct messaging_ctdbd_fde *fde;
> -
> -	if (ctx == NULL) {
> -		return NULL;
> -	}
> -
> -	fde = talloc(mem_ctx, struct messaging_ctdbd_fde);
> -	if (fde == NULL) {
> -		return NULL;
> -	}
> -
> -	for (fde_ev = ctx->fde_evs; fde_ev != NULL; fde_ev = fde_ev->next) {
> -		if ((fde_ev->ev == ev) &&
> -		    (tevent_fd_get_flags(fde_ev->fde) != 0)) {
> -			break;
> -		}
> -	}
> -
> -	if (fde_ev == NULL) {
> -		int fd = ctdbd_conn_get_fd(ctx->conn);
> -
> -		fde_ev = talloc(fde, struct messaging_ctdbd_fde_ev);
> -		if (fde_ev == NULL) {
> -			return NULL;
> -		}
> -		fde_ev->fde = tevent_add_fd(
> -			ev, fde_ev, fd, TEVENT_FD_READ,
> -			messaging_ctdbd_readable, ctx->conn);
> -		if (fde_ev->fde == NULL) {
> -			TALLOC_FREE(fde);
> -			return NULL;
> -		}
> -		fde_ev->ev = ev;
> -		fde_ev->ctx = ctx;
> -		DLIST_ADD(ctx->fde_evs, fde_ev);
> -		talloc_set_destructor(
> -			fde_ev, messaging_ctdbd_fde_ev_destructor);
> -	} else {
> -		/*
> -		 * Same trick as with tdb_wrap: The caller will never
> -		 * see the talloc_referenced object, the
> -		 * messaging_ctdbd_fde_ev, so problems with
> -		 * talloc_unlink will not happen.
> -		 */
> -		if (talloc_reference(fde, fde_ev) == NULL) {
> -			TALLOC_FREE(fde);
> -			return NULL;
> -		}
> -	}
> -
> -	fde->fde = fde_ev->fde;
> -	return fde;
> -}
> diff --git a/source3/lib/messages_ctdbd.h b/source3/lib/messages_ctdbd.h
> deleted file mode 100644
> index 7d928fe..0000000
> --- a/source3/lib/messages_ctdbd.h
> +++ /dev/null
> @@ -1,53 +0,0 @@
> -/*
> - * Unix SMB/CIFS implementation.
> - * messages_ctdb.c header
> - * Copyright (C) Volker Lendecke 2017
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 3 of the License, or
> - * (at your option) any later version.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#ifndef _MESSAGES_CTDB_H_
> -#define _MESSAGES_CTDB_H_
> -
> -#include "replace.h"
> -#include <talloc.h>
> -
> -struct messaging_context;
> -struct messaging_backend;
> -struct ctdbd_connection;
> -
> -int messaging_ctdbd_init(struct messaging_context *msg_ctx,
> -			 TALLOC_CTX *mem_ctx,
> -			 void (*recv_cb)(struct tevent_context *ev,
> -					 const uint8_t *msg, size_t msg_len,
> -					 int *fds, size_t num_fds,
> -					 void *private_data),
> -			 void *private_data,
> -			 struct messaging_backend **presult);
> -int messaging_ctdbd_reinit(struct messaging_context *msg_ctx,
> -			   TALLOC_CTX *mem_ctx,
> -			   void (*recv_cb)(struct tevent_context *ev,
> -					   const uint8_t *msg, size_t msg_len,
> -					   int *fds, size_t num_fds,
> -					   void *private_data),
> -			   void *private_data,
> -			   struct messaging_backend *backend);
> -struct ctdbd_connection *messaging_ctdbd_connection(void);
> -
> -struct messaging_ctdbd_fde;
> -struct messaging_ctdbd_fde *messaging_ctdbd_register_tevent_context(
> -	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
> -	struct messaging_backend *backend);
> -
> -#endif
> -- 
> 2.1.4
> 
> 
> From 889967a52fc6727e1b6528eb6b37b40c8a713d63 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Wed, 5 Jul 2017 19:26:22 +0200
> Subject: [PATCH 41/41] messaging: Remove "struct messaging_backend"
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/include/messages.h | 9 ---------
>  1 file changed, 9 deletions(-)
> 
> diff --git a/source3/include/messages.h b/source3/include/messages.h
> index 970dc38..8d3b1d8 100644
> --- a/source3/include/messages.h
> +++ b/source3/include/messages.h
> @@ -56,15 +56,6 @@
>  struct messaging_context;
>  struct messaging_rec;
>  
> -struct messaging_backend {
> -	int (*send_fn)(struct server_id src,
> -		       struct server_id pid, int msg_type,
> -		       const struct iovec *iov, int iovlen,
> -		       const int *fds, size_t num_fds,
> -		       struct messaging_backend *backend);
> -	void *private_data;
> -};
> -
>  struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, 
>  					 struct tevent_context *ev);
>  NTSTATUS messaging_init_client(TALLOC_CTX *mem_ctx,
> -- 
> 2.1.4
> 




More information about the samba-technical mailing list