[PATCH] avoid lock oder violation between xattr.tdb and g_lock.tdb

Jeremy Allison jra at samba.org
Thu Jul 14 22:22:00 UTC 2016


On Thu, Jul 14, 2016 at 07:52:28AM +0200, Volker Lendecke wrote:
> On Tue, Jul 12, 2016 at 05:12:48PM +0200, Michael Adam wrote:
> > > Not sure this will work. g_lock is a watched database, and if there is
> > > lock contention, this will conflict with dbwrap_watchers.tdb.
> > 
> > Ouch. So without the below-mentioned rework of dbwrap_watch
> > (or another solution), we would need an additional lock oder
> > value(4)?
> 
> Attached find a patchset that survived a private autobuild for me.
> 
> It is incomplete as it does not have the removal patch for the current
> version of dbwrap_record_watch_send. Also, I'm not sure about the
> performance implications of the malloc/memcpy when storing large
> records. But the typical record is normally not too large. The only
> case where this could matter is highly popular share root directories
> in locking.tdb. So sooner than later we might have to add a tdb_storev
> call and the related dbwrap support.
> 
> Comments?

FYI. Still reviewing this - got to  [PATCH 5/9] so far.

This is some *seriously* nice code !!!!

> From 886b4b5086711d7b20fc505cf20a57ba2bed292a Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Tue, 12 Jul 2016 15:33:59 +0200
> Subject: [PATCH 1/9] lib: Add server_id_watch_send
> 
> This is a brute force variant, trying twice a second. We'll have better
> variants with tmsgd in the future.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/server_id_watch.c | 106 ++++++++++++++++++++++++++++++++++++++++++
>  source3/lib/server_id_watch.h |  36 ++++++++++++++
>  source3/wscript_build         |   1 +
>  3 files changed, 143 insertions(+)
>  create mode 100644 source3/lib/server_id_watch.c
>  create mode 100644 source3/lib/server_id_watch.h
> 
> diff --git a/source3/lib/server_id_watch.c b/source3/lib/server_id_watch.c
> new file mode 100644
> index 0000000..0dfeb8c
> --- /dev/null
> +++ b/source3/lib/server_id_watch.c
> @@ -0,0 +1,106 @@
> +/*
> + * Unix SMB/CIFS implementation.
> + * Wait for process death
> + * Copyright (C) Volker Lendecke 2016
> + *
> + * 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 <tevent.h>
> +#include <talloc.h>
> +#include "serverid.h"
> +#include "server_id_watch.h"
> +#include "messages.h"
> +#include "lib/util/tevent_unix.h"
> +
> +struct server_id_watch_state {
> +	struct tevent_context *ev;
> +	struct server_id pid;
> +};
> +
> +static void server_id_watch_waited(struct tevent_req *subreq);
> +
> +struct tevent_req *server_id_watch_send(TALLOC_CTX *mem_ctx,
> +					struct tevent_context *ev,
> +					struct messaging_context *msg,
> +					struct server_id pid)
> +{
> +	struct tevent_req *req, *subreq;
> +	struct server_id_watch_state *state;
> +
> +	req = tevent_req_create(mem_ctx, &state, struct server_id_watch_state);
> +	if (req == NULL) {
> +		return NULL;
> +	}
> +	state->ev = ev;
> +	state->pid = pid;
> +
> +	if (!serverid_exists(&state->pid)) {
> +		tevent_req_done(req);
> +		return tevent_req_post(req, ev);
> +	}
> +
> +	subreq = tevent_wakeup_send(state, ev, timeval_current_ofs(0, 500000));
> +	if (tevent_req_nomem(subreq, req)) {
> +		return tevent_req_post(req, ev);
> +	}
> +	tevent_req_set_callback(subreq, server_id_watch_waited, req);
> +
> +	return req;
> +}
> +
> +static void server_id_watch_waited(struct tevent_req *subreq)
> +{
> +	struct tevent_req *req = tevent_req_callback_data(
> +		subreq, struct tevent_req);
> +	struct server_id_watch_state *state = tevent_req_data(
> +		req, struct server_id_watch_state);
> +	bool ok;
> +
> +	ok = tevent_wakeup_recv(subreq);
> +	TALLOC_FREE(subreq);
> +	if (!ok) {
> +		tevent_req_oom(req);
> +		return;
> +	}
> +
> +	if (!serverid_exists(&state->pid)) {
> +		tevent_req_done(req);
> +		return;
> +	}
> +
> +	subreq = tevent_wakeup_send(state, state->ev,
> +				    timeval_current_ofs(0, 500000));
> +	if (tevent_req_nomem(subreq, req)) {
> +		return;
> +	}
> +	tevent_req_set_callback(subreq, server_id_watch_waited, req);
> +}
> +
> +int server_id_watch_recv(struct tevent_req *req, struct server_id *pid)
> +{
> +	struct server_id_watch_state *state = tevent_req_data(
> +		req, struct server_id_watch_state);
> +	int err;
> +
> +	if (tevent_req_is_unix_error(req, &err)) {
> +		return err;
> +	}
> +	if (pid) {
> +		*pid = state->pid;
> +	}
> +	return 0;
> +}
> +
> diff --git a/source3/lib/server_id_watch.h b/source3/lib/server_id_watch.h
> new file mode 100644
> index 0000000..917dfeb
> --- /dev/null
> +++ b/source3/lib/server_id_watch.h
> @@ -0,0 +1,36 @@
> +/*
> + * Unix SMB/CIFS implementation.
> + * Wait for process death
> + * Copyright (C) Volker Lendecke 2016
> + *
> + * 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 __LIB_SERVER_ID_WATCH_H__
> +#define __LIB_SERVER_ID_WATCH_H__
> +
> +#include "replace.h"
> +#include <tevent.h>
> +#include <talloc.h>
> +#include "librpc/gen_ndr/server_id.h"
> +
> +struct messaging_context;
> +
> +struct tevent_req *server_id_watch_send(TALLOC_CTX *mem_ctx,
> +					struct tevent_context *ev,
> +					struct messaging_context *msg,
> +					struct server_id pid);
> +int server_id_watch_recv(struct tevent_req *req, struct server_id *pid);
> +
> +#endif
> diff --git a/source3/wscript_build b/source3/wscript_build
> index 365b250..b9a2ee6 100755
> --- a/source3/wscript_build
> +++ b/source3/wscript_build
> @@ -317,6 +317,7 @@ bld.SAMBA3_SUBSYSTEM('samba3core',
>                     lib/id_cache.c
>                     lib/talloc_dict.c
>                     lib/serverid.c
> +                   lib/server_id_watch.c
>                     lib/server_id_db_util.c
>                     lib/addrchange.c
>                     ../lib/util/debug_s3.c
> -- 
> 1.9.1
> 
> 
> From 2b1a4a3053f761b3af584d3314b183dc300c89ef Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Thu, 10 Mar 2016 14:37:12 +0100
> Subject: [PATCH 2/9] dbwrap: Add "blocker" to record_watch_send
> 
> Typicall, when we watch a record, we wait for a process to give up some
> resource. Be it an oplock, a share mode or the g_lock. If everything goes well,
> the blocker sends us a message. If the blocker dies hard, we want to also be
> informed immediately.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/dbwrap/dbwrap_watch.c   | 45 +++++++++++++++++++++++++++++++++++--
>  source3/lib/dbwrap/dbwrap_watch.h   |  7 ++++--
>  source3/lib/g_lock.c                |  9 +++++---
>  source3/smbd/open.c                 |  5 +++--
>  source3/smbd/smb2_setinfo.c         |  6 +++--
>  source3/smbd/smbXsrv_session.c      |  6 +++--
>  source3/torture/test_dbwrap_watch.c |  6 +++--
>  7 files changed, 69 insertions(+), 15 deletions(-)
> 
> diff --git a/source3/lib/dbwrap/dbwrap_watch.c b/source3/lib/dbwrap/dbwrap_watch.c
> index 09e67fb..714c54d 100644
> --- a/source3/lib/dbwrap/dbwrap_watch.c
> +++ b/source3/lib/dbwrap/dbwrap_watch.c
> @@ -24,6 +24,7 @@
>  #include "dbwrap_open.h"
>  #include "lib/util/util_tdb.h"
>  #include "lib/util/tevent_ntstatus.h"
> +#include "server_id_watch.h"
>  
>  static struct db_context *dbwrap_record_watchers_db(void)
>  {
> @@ -199,18 +200,22 @@ struct dbwrap_record_watch_state {
>  	struct tevent_req *req;
>  	struct messaging_context *msg;
>  	TDB_DATA w_key;
> +	bool blockerdead;
> +	struct server_id blocker;
>  };
>  
>  static bool dbwrap_record_watch_filter(struct messaging_rec *rec,
>  				       void *private_data);
>  static void dbwrap_record_watch_done(struct tevent_req *subreq);
> +static void dbwrap_record_watch_blocker_died(struct tevent_req *subreq);
>  static int dbwrap_record_watch_state_destructor(
>  	struct dbwrap_record_watch_state *state);
>  
>  struct tevent_req *dbwrap_record_watch_send(TALLOC_CTX *mem_ctx,
>  					    struct tevent_context *ev,
>  					    struct db_record *rec,
> -					    struct messaging_context *msg)
> +					    struct messaging_context *msg,
> +					    struct server_id blocker)
>  {
>  	struct tevent_req *req, *subreq;
>  	struct dbwrap_record_watch_state *state;
> @@ -226,6 +231,7 @@ struct tevent_req *dbwrap_record_watch_send(TALLOC_CTX *mem_ctx,
>  	state->ev = ev;
>  	state->req = req;
>  	state->msg = msg;
> +	state->blocker = blocker;
>  
>  	watchers_db = dbwrap_record_watchers_db();
>  	if (watchers_db == NULL) {
> @@ -250,6 +256,15 @@ struct tevent_req *dbwrap_record_watch_send(TALLOC_CTX *mem_ctx,
>  	}
>  	tevent_req_set_callback(subreq, dbwrap_record_watch_done, req);
>  
> +	if (blocker.pid != 0) {
> +		subreq = server_id_watch_send(state, ev, msg, blocker);
> +		if (tevent_req_nomem(subreq, req)) {
> +			return tevent_req_post(req, ev);
> +		}
> +		tevent_req_set_callback(
> +			subreq, dbwrap_record_watch_blocker_died, req);
> +	}
> +
>  	status = dbwrap_record_add_watcher(
>  		state->w_key, messaging_server_id(state->msg));
>  	if (tevent_req_nterror(req, status)) {
> @@ -371,9 +386,29 @@ static void dbwrap_record_watch_done(struct tevent_req *subreq)
>  	tevent_req_done(req);
>  }
>  
> +static void dbwrap_record_watch_blocker_died(struct tevent_req *subreq)
> +{
> +	struct tevent_req *req = tevent_req_callback_data(
> +		subreq, struct tevent_req);
> +	struct dbwrap_record_watch_state *state = tevent_req_data(
> +		req, struct dbwrap_record_watch_state);
> +	int ret;
> +
> +	ret = server_id_watch_recv(subreq, NULL);
> +	TALLOC_FREE(subreq);
> +	if (ret != 0) {
> +		tevent_req_nterror(req, map_nt_error_from_unix(ret));
> +		return;
> +	}
> +	state->blockerdead = true;
> +	tevent_req_done(req);
> +}
> +
>  NTSTATUS dbwrap_record_watch_recv(struct tevent_req *req,
>  				  TALLOC_CTX *mem_ctx,
> -				  struct db_record **prec)
> +				  struct db_record **prec,
> +				  bool *blockerdead,
> +				  struct server_id *blocker)
>  {
>  	struct dbwrap_record_watch_state *state = tevent_req_data(
>  		req, struct dbwrap_record_watch_state);
> @@ -385,6 +420,12 @@ NTSTATUS dbwrap_record_watch_recv(struct tevent_req *req,
>  	if (tevent_req_is_nterror(req, &status)) {
>  		return status;
>  	}
> +	if (blockerdead != NULL) {
> +		*blockerdead = state->blockerdead;
> +	}
> +	if (blocker != NULL) {
> +		*blocker = state->blocker;
> +	}
>  	if (prec == NULL) {
>  		return NT_STATUS_OK;
>  	}
> diff --git a/source3/lib/dbwrap/dbwrap_watch.h b/source3/lib/dbwrap/dbwrap_watch.h
> index 3362e45..b14128c 100644
> --- a/source3/lib/dbwrap/dbwrap_watch.h
> +++ b/source3/lib/dbwrap/dbwrap_watch.h
> @@ -29,10 +29,13 @@ void dbwrap_watch_db(struct db_context *db, struct messaging_context *msg);
>  struct tevent_req *dbwrap_record_watch_send(TALLOC_CTX *mem_ctx,
>  					    struct tevent_context *ev,
>  					    struct db_record *rec,
> -					    struct messaging_context *msg);
> +					    struct messaging_context *msg,
> +					    struct server_id blocker);
>  NTSTATUS dbwrap_record_watch_recv(struct tevent_req *req,
>  				  TALLOC_CTX *mem_ctx,
> -				  struct db_record **prec);
> +				  struct db_record **prec,
> +				  bool *blockerdead,
> +				  struct server_id *blocker);
>  
>  void dbwrap_watchers_traverse_read(
>  	int (*fn)(const uint8_t *db_id, size_t db_id_len, const TDB_DATA key,
> diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
> index 1928f5e..1976291 100644
> --- a/source3/lib/g_lock.c
> +++ b/source3/lib/g_lock.c
> @@ -237,7 +237,8 @@ struct tevent_req *g_lock_lock_send(TALLOC_CTX *mem_ctx,
>  		return tevent_req_post(req, ev);
>  	}
>  	subreq = dbwrap_record_watch_send(state, state->ev, rec,
> -					  state->ctx->msg);
> +					  state->ctx->msg,
> +					  (struct server_id){0});
>  	TALLOC_FREE(rec);
>  	if (tevent_req_nomem(subreq, req)) {
>  		return tevent_req_post(req, ev);
> @@ -262,7 +263,8 @@ static void g_lock_lock_retry(struct tevent_req *subreq)
>  	struct db_record *rec;
>  	NTSTATUS status;
>  
> -	status = dbwrap_record_watch_recv(subreq, talloc_tos(), &rec);
> +	status = dbwrap_record_watch_recv(subreq, talloc_tos(), &rec, NULL,
> +					  NULL);
>  	TALLOC_FREE(subreq);
>  
>  	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
> @@ -291,7 +293,8 @@ static void g_lock_lock_retry(struct tevent_req *subreq)
>  		return;
>  	}
>  	subreq = dbwrap_record_watch_send(state, state->ev, rec,
> -					  state->ctx->msg);
> +					  state->ctx->msg,
> +					  (struct server_id){0});
>  	TALLOC_FREE(rec);
>  	if (tevent_req_nomem(subreq, req)) {
>  		return;
> diff --git a/source3/smbd/open.c b/source3/smbd/open.c
> index 883c6ae..57cd4f1 100644
> --- a/source3/smbd/open.c
> +++ b/source3/smbd/open.c
> @@ -1954,7 +1954,7 @@ static void defer_open(struct share_mode_lock *lck,
>  
>  		watch_req = dbwrap_record_watch_send(
>  			watch_state, req->sconn->ev_ctx, lck->data->record,
> -			req->sconn->msg_ctx);
> +			req->sconn->msg_ctx, (struct server_id){0});
>  		if (watch_req == NULL) {
>  			exit_server("Could not watch share mode record");
>  		}
> @@ -1981,7 +1981,8 @@ static void defer_open_done(struct tevent_req *req)
>  	NTSTATUS status;
>  	bool ret;
>  
> -	status = dbwrap_record_watch_recv(req, talloc_tos(), NULL);
> +	status = dbwrap_record_watch_recv(req, talloc_tos(), NULL, NULL,
> +					  NULL);
>  	TALLOC_FREE(req);
>  	if (!NT_STATUS_IS_OK(status)) {
>  		DEBUG(5, ("dbwrap_record_watch_recv returned %s\n",
> diff --git a/source3/smbd/smb2_setinfo.c b/source3/smbd/smb2_setinfo.c
> index 2a02610..0a678ea 100644
> --- a/source3/smbd/smb2_setinfo.c
> +++ b/source3/smbd/smb2_setinfo.c
> @@ -252,7 +252,8 @@ static struct tevent_req *delay_rename_for_lease_break(struct tevent_req *req,
>  				rename_state,
>  				ev,
>  				lck->data->record,
> -				fsp->conn->sconn->msg_ctx);
> +				fsp->conn->sconn->msg_ctx,
> +				(struct server_id){0});
>  
>  	if (subreq == NULL) {
>  		exit_server("Could not watch share mode record for rename\n");
> @@ -279,7 +280,8 @@ static void defer_rename_done(struct tevent_req *subreq)
>  	int ret_size = 0;
>  	bool ok;
>  
> -	status = dbwrap_record_watch_recv(subreq, state->req, NULL);
> +	status = dbwrap_record_watch_recv(subreq, state->req, NULL, NULL,
> +					  NULL);
>  	TALLOC_FREE(subreq);
>  	if (!NT_STATUS_IS_OK(status)) {
>  		DEBUG(5, ("dbwrap_record_watch_recv returned %s\n",
> diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c
> index cdad47f..51668c2 100644
> --- a/source3/smbd/smbXsrv_session.c
> +++ b/source3/smbd/smbXsrv_session.c
> @@ -1066,7 +1066,8 @@ static void smb2srv_session_close_previous_check(struct tevent_req *req)
>  	}
>  
>  	subreq = dbwrap_record_watch_send(state, state->ev,
> -					  state->db_rec, conn->msg_ctx);
> +					  state->db_rec, conn->msg_ctx,
> +					  (struct server_id){0});
>  	if (tevent_req_nomem(subreq, req)) {
>  		TALLOC_FREE(state->db_rec);
>  		return;
> @@ -1120,7 +1121,8 @@ static void smb2srv_session_close_previous_modified(struct tevent_req *subreq)
>  		struct smb2srv_session_close_previous_state);
>  	NTSTATUS status;
>  
> -	status = dbwrap_record_watch_recv(subreq, state, &state->db_rec);
> +	status = dbwrap_record_watch_recv(subreq, state, &state->db_rec, NULL,
> +					  NULL);
>  	TALLOC_FREE(subreq);
>  	if (tevent_req_nterror(req, status)) {
>  		return;
> diff --git a/source3/torture/test_dbwrap_watch.c b/source3/torture/test_dbwrap_watch.c
> index ab9330f..a912bd2 100644
> --- a/source3/torture/test_dbwrap_watch.c
> +++ b/source3/torture/test_dbwrap_watch.c
> @@ -60,7 +60,8 @@ bool run_dbwrap_watch1(int dummy)
>  		fprintf(stderr, "dbwrap_fetch_locked failed\n");
>  		goto fail;
>  	}
> -	req = dbwrap_record_watch_send(talloc_tos(), ev, rec, msg);
> +	req = dbwrap_record_watch_send(talloc_tos(), ev, rec, msg,
> +				       (struct server_id){0});
>  	if (req == NULL) {
>  		fprintf(stderr, "dbwrap_record_watch_send failed\n");
>  		goto fail;
> @@ -86,7 +87,8 @@ bool run_dbwrap_watch1(int dummy)
>  		goto fail;
>  	}
>  
> -	status = dbwrap_record_watch_recv(req, talloc_tos(), &rec);
> +	status = dbwrap_record_watch_recv(req, talloc_tos(), &rec, NULL,
> +					  NULL);
>  	if (!NT_STATUS_IS_OK(status)) {
>  		fprintf(stderr, "dbwrap_record_watch_recv failed: %s\n",
>  			nt_errstr(status));
> -- 
> 1.9.1
> 
> 
> From 37954329c547a9b903a78f038999b08bde1881d5 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Tue, 12 Jul 2016 16:07:51 +0200
> Subject: [PATCH 3/9] g_lock: Use "blocker" argument to
>  dbwrap_record_watch_send
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/g_lock.c | 17 +++++++++--------
>  1 file changed, 9 insertions(+), 8 deletions(-)
> 
> diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
> index 1976291..7b91e3c 100644
> --- a/source3/lib/g_lock.c
> +++ b/source3/lib/g_lock.c
> @@ -111,7 +111,8 @@ static bool g_lock_parse(TALLOC_CTX *mem_ctx, TDB_DATA data,
>  }
>  
>  static NTSTATUS g_lock_trylock(struct db_record *rec, struct server_id self,
> -			       enum g_lock_type type)
> +			       enum g_lock_type type,
> +			       struct server_id *blocker)
>  {
>  	TDB_DATA data;
>  	unsigned i, num_locks;
> @@ -142,6 +143,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;
>  				goto done;
>  			}
>  
> @@ -203,7 +205,7 @@ struct tevent_req *g_lock_lock_send(TALLOC_CTX *mem_ctx,
>  	struct tevent_req *req, *subreq;
>  	struct g_lock_lock_state *state;
>  	struct db_record *rec;
> -	struct server_id self;
> +	struct server_id self, blocker;
>  	NTSTATUS status;
>  
>  	req = tevent_req_create(mem_ctx, &state, struct g_lock_lock_state);
> @@ -225,7 +227,7 @@ struct tevent_req *g_lock_lock_send(TALLOC_CTX *mem_ctx,
>  
>  	self = messaging_server_id(state->ctx->msg);
>  
> -	status = g_lock_trylock(rec, self, state->type);
> +	status = g_lock_trylock(rec, self, state->type, &blocker);
>  	if (NT_STATUS_IS_OK(status)) {
>  		TALLOC_FREE(rec);
>  		tevent_req_done(req);
> @@ -237,8 +239,7 @@ struct tevent_req *g_lock_lock_send(TALLOC_CTX *mem_ctx,
>  		return tevent_req_post(req, ev);
>  	}
>  	subreq = dbwrap_record_watch_send(state, state->ev, rec,
> -					  state->ctx->msg,
> -					  (struct server_id){0});
> +					  state->ctx->msg, blocker);
>  	TALLOC_FREE(rec);
>  	if (tevent_req_nomem(subreq, req)) {
>  		return tevent_req_post(req, ev);
> @@ -260,6 +261,7 @@ static void g_lock_lock_retry(struct tevent_req *subreq)
>  	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;
>  	NTSTATUS status;
>  
> @@ -281,7 +283,7 @@ static void g_lock_lock_retry(struct tevent_req *subreq)
>  	if (tevent_req_nterror(req, status)) {
>  		return;
>  	}
> -	status = g_lock_trylock(rec, self, state->type);
> +	status = g_lock_trylock(rec, self, state->type, &blocker);
>  	if (NT_STATUS_IS_OK(status)) {
>  		TALLOC_FREE(rec);
>  		tevent_req_done(req);
> @@ -293,8 +295,7 @@ static void g_lock_lock_retry(struct tevent_req *subreq)
>  		return;
>  	}
>  	subreq = dbwrap_record_watch_send(state, state->ev, rec,
> -					  state->ctx->msg,
> -					  (struct server_id){0});
> +					  state->ctx->msg, blocker);
>  	TALLOC_FREE(rec);
>  	if (tevent_req_nomem(subreq, req)) {
>  		return;
> -- 
> 1.9.1
> 
> 
> From 8f09c234b461531cad498a82edce1291d18e58a5 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Tue, 12 Jul 2016 15:57:29 +0200
> Subject: [PATCH 4/9] dbwrap: Add overflow protection to
>  dbwrap_record_watchers_key()
> 
> It's highly unlinkely that this will ever kick in, because our current tdb keys
> are rather small, but offset calculations without overflow checks are bad.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/dbwrap/dbwrap_watch.c | 25 +++++++++++++++++++------
>  1 file changed, 19 insertions(+), 6 deletions(-)
> 
> diff --git a/source3/lib/dbwrap/dbwrap_watch.c b/source3/lib/dbwrap/dbwrap_watch.c
> index 714c54d..a6e032a 100644
> --- a/source3/lib/dbwrap/dbwrap_watch.c
> +++ b/source3/lib/dbwrap/dbwrap_watch.c
> @@ -46,9 +46,9 @@ static struct db_context *dbwrap_record_watchers_db(void)
>  	return watchers_db;
>  }
>  
> -static size_t dbwrap_record_watchers_key(struct db_context *db,
> -					 struct db_record *rec,
> -					 uint8_t *wkey, size_t wkey_len)
> +static ssize_t dbwrap_record_watchers_key(struct db_context *db,
> +					  struct db_record *rec,
> +					  uint8_t *wkey, size_t wkey_len)
>  {
>  	size_t db_id_len = dbwrap_db_id(db, NULL, 0);
>  	uint8_t db_id[db_id_len];
> @@ -59,7 +59,15 @@ static size_t dbwrap_record_watchers_key(struct db_context *db,
>  
>  	key = dbwrap_record_get_key(rec);
>  
> -	needed = sizeof(uint32_t) + db_id_len + key.dsize;
> +	needed = sizeof(uint32_t) + db_id_len;
> +	if (needed < sizeof(uint32_t)) {
> +		return -1;
> +	}
> +
> +	needed += key.dsize;
> +	if (needed < key.dsize) {
> +		return -1;
> +	}
>  
>  	if (wkey_len >= needed) {
>  		SIVAL(wkey, 0, db_id_len);
> @@ -221,6 +229,7 @@ struct tevent_req *dbwrap_record_watch_send(TALLOC_CTX *mem_ctx,
>  	struct dbwrap_record_watch_state *state;
>  	struct db_context *watchers_db;
>  	NTSTATUS status;
> +	ssize_t needed;
>  
>  	req = tevent_req_create(mem_ctx, &state,
>  				struct dbwrap_record_watch_state);
> @@ -239,8 +248,12 @@ struct tevent_req *dbwrap_record_watch_send(TALLOC_CTX *mem_ctx,
>  		return tevent_req_post(req, ev);
>  	}
>  
> -	state->w_key.dsize = dbwrap_record_watchers_key(
> -		state->db, rec, NULL, 0);
> +	needed = dbwrap_record_watchers_key(state->db, rec, NULL, 0);
> +	if (needed == -1) {
> +		tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
> +		return tevent_req_post(req, ev);
> +	}
> +	state->w_key.dsize = needed;
>  
>  	state->w_key.dptr = talloc_array(state, uint8_t, state->w_key.dsize);
>  	if (tevent_req_nomem(state->w_key.dptr, req)) {
> -- 
> 1.9.1
> 
> 
> From 3bf4bf1ccff967397214aa954acac4d9139a9598 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Tue, 12 Jul 2016 15:59:56 +0200
> Subject: [PATCH 5/9] dbwrap: Add an alternative implementation of
>  dbwrap_watch_record_send
> 
> The existing one with a separate dbwrap_watchers.tdb turns out to
> create a performance penalty in a clustered environment. Non-clustered,
> dbwrap_parse_record on non-existent records is very cheap, but in a
> cluster environment this is very noticable.
> 
> This implementation puts the watcher information into the records itself. For
> large records, this might be another performance penalty, because we have to
> assemble the final record together with talloc and memcpy, but this might be
> fixed later with a tdb_storev call.
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/dbwrap/dbwrap_watch.c   | 755 ++++++++++++++++++++++++++++++++++++
>  source3/lib/dbwrap/dbwrap_watch.h   |  12 +
>  source3/torture/test_dbwrap_watch.c |  21 +-
>  3 files changed, 779 insertions(+), 9 deletions(-)
> 
> diff --git a/source3/lib/dbwrap/dbwrap_watch.c b/source3/lib/dbwrap/dbwrap_watch.c
> index a6e032a..f2cc381 100644
> --- a/source3/lib/dbwrap/dbwrap_watch.c
> +++ b/source3/lib/dbwrap/dbwrap_watch.c
> @@ -25,6 +25,7 @@
>  #include "lib/util/util_tdb.h"
>  #include "lib/util/tevent_ntstatus.h"
>  #include "server_id_watch.h"
> +#include "lib/dbwrap/dbwrap_private.h"
>  
>  static struct db_context *dbwrap_record_watchers_db(void)
>  {
> @@ -533,3 +534,757 @@ void dbwrap_watchers_wakeall(struct messaging_context *msg)
>  {
>  	dbwrap_watchers_traverse_read(dbwrap_wakeall_cb, msg);
>  }
> +
> +#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)
> +{
> +	size_t i, num_watchers;
> +	bool deleted;
> +
> +	if (data.dsize < sizeof(uint32_t)) {
> +		/* Fresh or invalid record */
> +		return -1;
> +	}
> +
> +	num_watchers = IVAL(data.dptr, 0);
> +
> +	deleted = num_watchers & NUM_WATCHERS_DELETED_BIT;
> +	num_watchers &= NUM_WATCHERS_MASK;
> +
> +	data.dptr += sizeof(uint32_t);
> +	data.dsize -= sizeof(uint32_t);
> +
> +	if (num_watchers > data.dsize/SERVER_ID_BUF_LENGTH) {
> +		/* Invalid record */
> +		return -1;
> +	}
> +
> +	if (num_watchers > num_ids) {
> +		data.dptr += num_watchers * SERVER_ID_BUF_LENGTH;
> +		data.dsize -= num_watchers * SERVER_ID_BUF_LENGTH;
> +		goto done;
> +	}
> +
> +	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;
> +	}
> +
> +done:
> +	if (deleted) {
> +		data = (TDB_DATA) {0};
> +	}
> +	if (pdata != NULL) {
> +		*pdata = data;
> +	}
> +	if (pdeleted != NULL) {
> +		*pdeleted = deleted;
> +	}
> +
> +	return num_watchers;
> +}
> +
> +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)
> +{
> +	size_t i, len, ofs;
> +	uint32_t num_watchers_buf;
> +
> +	if (num_watchers > UINT32_MAX/SERVER_ID_BUF_LENGTH) {
> +		return -1;
> +	}
> +
> +	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;
> +	}
> +
> +	if ((data.dptr != NULL) && (data.dsize != 0)) {
> +		memcpy(buf + ofs, data.dptr, data.dsize);
> +	}
> +
> +	return len;
> +}
> +
> +struct db_watched_ctx {
> +	struct db_context *backend;
> +	struct messaging_context *msg;
> +};
> +
> +struct db_watched_subrec {
> +	struct db_record *subrec;
> +	struct server_id *watchers;
> +	bool deleted;
> +};
> +
> +static NTSTATUS dbwrap_watched_store(struct db_record *rec, TDB_DATA data,
> +				     int flag);
> +static NTSTATUS dbwrap_watched_delete(struct db_record *rec);
> +
> +static struct db_record *dbwrap_watched_fetch_locked(
> +	struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
> +{
> +	struct db_watched_ctx *ctx = talloc_get_type_abort(
> +		db->private_data, struct db_watched_ctx);
> +	struct db_record *rec;
> +	struct db_watched_subrec *subrec;
> +	TDB_DATA subrec_value;
> +	ssize_t num_watchers;
> +
> +	rec = talloc_zero(mem_ctx, struct db_record);
> +	if (rec == NULL) {
> +		return NULL;
> +	}
> +	subrec = talloc_zero(rec, struct db_watched_subrec);
> +	if (subrec == NULL) {
> +		TALLOC_FREE(rec);
> +		return NULL;
> +	}
> +	rec->private_data = subrec;
> +
> +	subrec->subrec = dbwrap_fetch_locked(ctx->backend, subrec, key);
> +	if (subrec->subrec == NULL) {
> +		TALLOC_FREE(rec);
> +		return NULL;
> +	}
> +
> +	rec->db = db;
> +	rec->key = dbwrap_record_get_key(subrec->subrec);
> +	rec->store = dbwrap_watched_store;
> +	rec->delete_rec = dbwrap_watched_delete;
> +
> +	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) {};
> +		return rec;
> +	}
> +
> +	subrec->watchers = talloc_array(subrec, struct server_id,
> +					num_watchers);
> +	if (subrec->watchers == NULL) {
> +		TALLOC_FREE(rec);
> +		return NULL;
> +	}
> +
> +	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 db_context *db = dbwrap_record_get_db(rec);
> +	struct db_watched_ctx *ctx = talloc_get_type_abort(
> +		db->private_data, struct db_watched_ctx);
> +	size_t i, num_watchers;
> +	size_t db_id_len = dbwrap_db_id(db, NULL, 0);
> +	uint8_t db_id[db_id_len];
> +	uint8_t len_buf[4];
> +	struct iovec iov[3];
> +
> +	SIVAL(len_buf, 0, db_id_len);
> +
> +	iov[0] = (struct iovec) { .iov_base = len_buf, .iov_len = 4 };
> +	iov[1] = (struct iovec) { .iov_base = db_id, .iov_len = db_id_len };
> +	iov[2] = (struct iovec) { .iov_base = rec->key.dptr,
> +				  .iov_len = rec->key.dsize };
> +
> +	dbwrap_db_id(db, db_id, db_id_len);
> +
> +	num_watchers = talloc_array_length(subrec->watchers);
> +
> +	i = 0;
> +
> +	while (i < num_watchers) {
> +		NTSTATUS status;
> +		struct server_id_buf tmp;
> +
> +		DBG_DEBUG("Alerting %s\n",
> +			  server_id_str_buf(subrec->watchers[i], &tmp));
> +
> +		status = messaging_send_iov(ctx->msg, subrec->watchers[i],
> +					    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),
> +				  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);
> +			continue;
> +		}
> +
> +		i += 1;
> +	}
> +}
> +
> +static NTSTATUS dbwrap_watched_save(struct db_watched_subrec *subrec,
> +				    TDB_DATA data, int flag)
> +{
> +	size_t num_watchers;
> +	ssize_t len;
> +	uint8_t *buf;
> +	NTSTATUS status;
> +
> +	num_watchers = talloc_array_length(subrec->watchers);
> +
> +	len = dbwrap_watched_unparse(subrec->watchers, num_watchers,
> +				     subrec->deleted, data, NULL, 0);
> +	if (len == -1) {
> +		return NT_STATUS_INSUFFICIENT_RESOURCES;
> +	}
> +
> +	buf = talloc_array(subrec, uint8_t, len);
> +	if (buf == NULL) {
> +		return NT_STATUS_NO_MEMORY;
> +	}
> +
> +	dbwrap_watched_unparse(subrec->watchers, num_watchers,
> +			       subrec->deleted, data, buf, len);
> +
> +	status = dbwrap_record_store(
> +		subrec->subrec, (TDB_DATA) { .dptr = buf, .dsize = len },
> +		flag);
> +
> +	TALLOC_FREE(buf);
> +
> +	return status;
> +}
> +
> +static NTSTATUS dbwrap_watched_store(struct db_record *rec, TDB_DATA data,
> +				     int flag)
> +{
> +	struct db_watched_subrec *subrec = talloc_get_type_abort(
> +		rec->private_data, struct db_watched_subrec);
> +
> +	dbwrap_watched_wakeup(rec, subrec);
> +
> +	subrec->deleted = false;
> +
> +	return dbwrap_watched_save(subrec, data, flag);
> +
> +}
> +
> +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);
> +
> +	num_watchers = talloc_array_length(subrec->watchers);
> +	if (num_watchers == 0) {
> +		return dbwrap_record_delete(subrec->subrec);
> +	}
> +
> +	subrec->deleted = true;
> +
> +	return dbwrap_watched_save(subrec, (TDB_DATA) {0}, 0);
> +}
> +
> +struct dbwrap_watched_traverse_state {
> +	int (*fn)(struct db_record *rec, void *private_data);
> +	void *private_data;
> +};
> +
> +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);
> +
> +	if ((num_watchers == -1) || deleted) {
> +		return 0;
> +	}
> +
> +	return state->fn(&prec, state->private_data);
> +}
> +
> +static int dbwrap_watched_traverse(struct db_context *db,
> +				   int (*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_traverse_state state = {
> +		.fn = fn, .private_data = private_data };
> +	NTSTATUS status;
> +	int ret;
> +
> +	status = dbwrap_traverse(
> +		ctx->backend, dbwrap_watched_traverse_fn, &state, &ret);
> +	if (!NT_STATUS_IS_OK(status)) {
> +		return -1;
> +	}
> +	return ret;
> +}
> +
> +static int dbwrap_watched_traverse_read(struct db_context *db,
> +					int (*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_traverse_state state = {
> +		.fn = fn, .private_data = private_data };
> +	NTSTATUS status;
> +	int ret;
> +
> +	status = dbwrap_traverse_read(
> +		ctx->backend, dbwrap_watched_traverse_fn, &state, &ret);
> +	if (!NT_STATUS_IS_OK(status)) {
> +		return -1;
> +	}
> +	return ret;
> +}
> +
> +static int dbwrap_watched_get_seqnum(struct db_context *db)
> +{
> +	struct db_watched_ctx *ctx = talloc_get_type_abort(
> +		db->private_data, struct db_watched_ctx);
> +	return dbwrap_get_seqnum(ctx->backend);
> +}
> +
> +static int dbwrap_watched_transaction_start(struct db_context *db)
> +{
> +	struct db_watched_ctx *ctx = talloc_get_type_abort(
> +		db->private_data, struct db_watched_ctx);
> +	return dbwrap_transaction_start(ctx->backend);
> +}
> +
> +static int dbwrap_watched_transaction_commit(struct db_context *db)
> +{
> +	struct db_watched_ctx *ctx = talloc_get_type_abort(
> +		db->private_data, struct db_watched_ctx);
> +	return dbwrap_transaction_commit(ctx->backend);
> +}
> +
> +static int dbwrap_watched_transaction_cancel(struct db_context *db)
> +{
> +	struct db_watched_ctx *ctx = talloc_get_type_abort(
> +		db->private_data, struct db_watched_ctx);
> +	return dbwrap_transaction_cancel(ctx->backend);
> +}
> +
> +struct dbwrap_watched_parse_record_state {
> +	void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data);
> +	void *private_data;
> +	bool deleted;
> +};
> +
> +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;
> +
> +	num_watchers = dbwrap_watched_parse(data, NULL, 0, &state->deleted,
> +					    &userdata);
> +	if ((num_watchers == -1) || state->deleted) {
> +		return;
> +	}
> +	state->parser(key, userdata, state->private_data);
> +}
> +
> +static NTSTATUS dbwrap_watched_parse_record(
> +	struct db_context *db, TDB_DATA key,
> +	void (*parser)(TDB_DATA key, TDB_DATA data, 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_parse_record_state state = {
> +		.parser = parser, private_data = private_data,
> +		.deleted = false
> +	};
> +	NTSTATUS status;
> +
> +	status = dbwrap_parse_record(
> +		ctx->backend, key, dbwrap_watched_parse_record_parser, &state);
> +	if (!NT_STATUS_IS_OK(status)) {
> +		return status;
> +	}
> +	if (state.deleted) {
> +		return NT_STATUS_NOT_FOUND;
> +	}
> +	return NT_STATUS_OK;
> +}
> +
> +static int dbwrap_watched_exists(struct db_context *db, TDB_DATA key)
> +{
> +	struct db_watched_ctx *ctx = talloc_get_type_abort(
> +		db->private_data, struct db_watched_ctx);
> +
> +	return dbwrap_exists(ctx->backend, key);
> +}
> +
> +static size_t dbwrap_watched_id(struct db_context *db, uint8_t *id,
> +				size_t idlen)
> +{
> +	struct db_watched_ctx *ctx = talloc_get_type_abort(
> +		db->private_data, struct db_watched_ctx);
> +
> +	return dbwrap_db_id(ctx->backend, id, idlen);
> +}
> +
> +struct db_context *db_open_watched(TALLOC_CTX *mem_ctx,
> +				   struct db_context *backend,
> +				   struct messaging_context *msg)
> +{
> +	struct db_context *db;
> +	struct db_watched_ctx *ctx;
> +
> +	db = talloc_zero(mem_ctx, struct db_context);
> +	if (db == NULL) {
> +		return NULL;
> +	}
> +	ctx = talloc_zero(db, struct db_watched_ctx);
> +	if (ctx == NULL) {
> +		TALLOC_FREE(db);
> +		return NULL;
> +	}
> +	db->private_data = ctx;
> +
> +	ctx->msg = msg;
> +
> +	db->lock_order = backend->lock_order;
> +	backend->lock_order = DBWRAP_LOCK_ORDER_NONE;
> +	ctx->backend = talloc_move(ctx, &backend);
> +
> +	db->fetch_locked = dbwrap_watched_fetch_locked;
> +	db->traverse = dbwrap_watched_traverse;
> +	db->traverse_read = dbwrap_watched_traverse_read;
> +	db->get_seqnum = dbwrap_watched_get_seqnum;
> +	db->transaction_start = dbwrap_watched_transaction_start;
> +	db->transaction_commit = dbwrap_watched_transaction_commit;
> +	db->transaction_cancel = dbwrap_watched_transaction_cancel;
> +	db->parse_record = dbwrap_watched_parse_record;
> +	db->exists = dbwrap_watched_exists;
> +	db->id = dbwrap_watched_id;
> +	db->name = dbwrap_name(ctx->backend);
> +
> +	return db;
> +}
> +
> +struct dbwrap_watched_watch_state {
> +	struct db_context *db;
> +	struct server_id me;
> +	TDB_DATA w_key;
> +	struct server_id blocker;
> +	bool blockerdead;
> +};
> +
> +static bool dbwrap_watched_msg_filter(struct messaging_rec *rec,
> +				      void *private_data);
> +static void dbwrap_watched_watch_done(struct tevent_req *subreq);
> +static void dbwrap_watched_watch_blocker_died(struct tevent_req *subreq);
> +static int dbwrap_watched_watch_state_destructor(
> +	struct dbwrap_watched_watch_state *state);
> +
> +struct tevent_req *dbwrap_watched_watch_send(TALLOC_CTX *mem_ctx,
> +					     struct tevent_context *ev,
> +					     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 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,
> +				struct dbwrap_watched_watch_state);
> +	if (req == NULL) {
> +		return NULL;
> +	}
> +	state->db = db;
> +	state->blocker = blocker;
> +
> +	if (ctx->msg == NULL) {
> +		tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
> +		return tevent_req_post(req, ev);
> +	}
> +
> +	state->me = messaging_server_id(ctx->msg);
> +
> +	needed = dbwrap_record_watchers_key(db, rec, NULL, 0);
> +	if (needed == -1) {
> +		tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
> +		return tevent_req_post(req, ev);
> +	}
> +	state->w_key.dsize = needed;
> +
> +	state->w_key.dptr = talloc_array(state, uint8_t, state->w_key.dsize);
> +	if (tevent_req_nomem(state->w_key.dptr, req)) {
> +		return tevent_req_post(req, ev);
> +	}
> +	dbwrap_record_watchers_key(db, rec, state->w_key.dptr,
> +				   state->w_key.dsize);
> +
> +	subreq = messaging_filtered_read_send(
> +		state, ev, ctx->msg, dbwrap_watched_msg_filter, state);
> +	if (tevent_req_nomem(subreq, req)) {
> +		return tevent_req_post(req, ev);
> +	}
> +	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);
> +	if (tevent_req_nterror(req, status)) {
> +		return tevent_req_post(req, ev);
> +	}
> +
> +	talloc_set_destructor(state, dbwrap_watched_watch_state_destructor);
> +
> +	if (blocker.pid != 0) {
> +		subreq = server_id_watch_send(state, ev, ctx->msg, blocker);
> +		if (tevent_req_nomem(subreq, req)) {
> +			return tevent_req_post(req, ev);
> +		}
> +		tevent_req_set_callback(
> +			subreq, dbwrap_watched_watch_blocker_died, req);
> +	}
> +
> +	return req;
> +}
> +
> +static void dbwrap_watched_watch_blocker_died(struct tevent_req *subreq)
> +{
> +	struct tevent_req *req = tevent_req_callback_data(
> +		subreq, struct tevent_req);
> +	struct dbwrap_watched_watch_state *state = tevent_req_data(
> +		req, struct dbwrap_watched_watch_state);
> +	int ret;
> +
> +	ret = server_id_watch_recv(subreq, NULL);
> +	TALLOC_FREE(subreq);
> +	if (ret != 0) {
> +		tevent_req_nterror(req, map_nt_error_from_unix(ret));
> +		return;
> +	}
> +	state->blockerdead = true;
> +	tevent_req_done(req);
> +}
> +
> +static bool dbwrap_watched_remove_waiter(struct db_watched_subrec *subrec,
> +					 struct server_id id)
> +{
> +	size_t i, num_watchers;
> +
> +	num_watchers = talloc_array_length(subrec->watchers);
> +
> +	for (i=0; i<num_watchers; i++) {
> +		if (server_id_equal(&id, &subrec->watchers[i])) {
> +			break;
> +		}
> +	}
> +
> +	if (i == num_watchers) {
> +		DBG_WARNING("Did not find id in state->watchers\n");
> +		return false;
> +	}
> +
> +	subrec->watchers[i] = subrec->watchers[num_watchers-1];
> +	subrec->watchers = talloc_realloc(subrec, subrec->watchers,
> +					  struct server_id, num_watchers-1);
> +
> +	return true;
> +}
> +
> +static int dbwrap_watched_watch_state_destructor(
> +	struct dbwrap_watched_watch_state *state)
> +{
> +	struct db_record *rec;
> +	struct db_watched_subrec *subrec;
> +	TDB_DATA key;
> +	bool ok;
> +
> +	ok = dbwrap_record_watchers_key_parse(state->w_key, NULL, NULL, &key);
> +	if (!ok) {
> +		DBG_WARNING("dbwrap_record_watchers_key_parse failed\n");
> +		return 0;
> +	}
> +
> +	rec = dbwrap_fetch_locked(state->db, state, key);
> +	if (rec == NULL) {
> +		DBG_WARNING("dbwrap_fetch_locked failed\n");
> +		return 0;
> +	}
> +
> +	subrec = talloc_get_type_abort(
> +		rec->private_data, struct db_watched_subrec);
> +
> +	ok = dbwrap_watched_remove_waiter(subrec, state->me);
> +	if (ok) {
> +		NTSTATUS status;
> +		status = dbwrap_watched_save(subrec, rec->value, 0);
> +		if (!NT_STATUS_IS_OK(status)) {
> +			DBG_WARNING("dbwrap_watched_save failed: %s\n",
> +				    nt_errstr(status));
> +		}
> +	}
> +
> +	TALLOC_FREE(rec);
> +	return 0;
> +}
> +
> +static bool dbwrap_watched_msg_filter(struct messaging_rec *rec,
> +				      void *private_data)
> +{
> +	struct dbwrap_watched_watch_state *state = talloc_get_type_abort(
> +		private_data, struct dbwrap_watched_watch_state);
> +	int cmp;
> +
> +	if (rec->msg_type != MSG_DBWRAP_MODIFIED) {
> +		return false;
> +	}
> +	if (rec->num_fds != 0) {
> +		return false;
> +	}
> +	if (rec->buf.length != state->w_key.dsize) {
> +		return false;
> +	}
> +
> +	cmp = memcmp(rec->buf.data, state->w_key.dptr, rec->buf.length);
> +
> +	return (cmp == 0);
> +}
> +
> +static void dbwrap_watched_watch_done(struct tevent_req *subreq)
> +{
> +	struct tevent_req *req = tevent_req_callback_data(
> +		subreq, struct tevent_req);
> +	struct messaging_rec *rec;
> +	int ret;
> +
> +	ret = messaging_filtered_read_recv(subreq, talloc_tos(), &rec);
> +	TALLOC_FREE(subreq);
> +	if (ret != 0) {
> +		tevent_req_nterror(req, map_nt_error_from_unix(ret));
> +		return;
> +	}
> +	tevent_req_done(req);
> +}
> +
> +NTSTATUS dbwrap_watched_watch_recv(struct tevent_req *req,
> +				   TALLOC_CTX *mem_ctx,
> +				   struct db_record **prec,
> +				   bool *blockerdead,
> +				   struct server_id *blocker)
> +{
> +	struct dbwrap_watched_watch_state *state = tevent_req_data(
> +		req, struct dbwrap_watched_watch_state);
> +	struct db_watched_subrec *subrec;
> +	NTSTATUS status;
> +	TDB_DATA key;
> +	struct db_record *rec;
> +	bool ok;
> +
> +	if (tevent_req_is_nterror(req, &status)) {
> +		return status;
> +	}
> +	if (blockerdead != NULL) {
> +		*blockerdead = state->blockerdead;
> +	}
> +	if (blocker != NULL) {
> +		*blocker = state->blocker;
> +	}
> +	if (prec == NULL) {
> +		return NT_STATUS_OK;
> +	}
> +
> +	ok = dbwrap_record_watchers_key_parse(state->w_key, NULL, NULL, &key);
> +	if (!ok) {
> +		return NT_STATUS_INTERNAL_DB_ERROR;
> +	}
> +
> +	rec = dbwrap_fetch_locked(state->db, mem_ctx, key);
> +	if (rec == NULL) {
> +		return NT_STATUS_INTERNAL_DB_ERROR;
> +	}
> +
> +	talloc_set_destructor(state, NULL);
> +
> +	subrec = talloc_get_type_abort(
> +		rec->private_data, struct db_watched_subrec);
> +
> +	ok = dbwrap_watched_remove_waiter(subrec, state->me);
> +	if (ok) {
> +		status = dbwrap_watched_save(subrec, rec->value, 0);
> +		if (!NT_STATUS_IS_OK(status)) {
> +			DBG_WARNING("dbwrap_watched_save failed: %s\n",
> +				    nt_errstr(status));
> +		}
> +	}
> +
> +	*prec = rec;
> +	return NT_STATUS_OK;
> +}
> diff --git a/source3/lib/dbwrap/dbwrap_watch.h b/source3/lib/dbwrap/dbwrap_watch.h
> index b14128c..a23727c 100644
> --- a/source3/lib/dbwrap/dbwrap_watch.h
> +++ b/source3/lib/dbwrap/dbwrap_watch.h
> @@ -45,5 +45,17 @@ void dbwrap_watchers_traverse_read(
>  
>  void dbwrap_watchers_wakeall(struct messaging_context *msg);
>  
> +struct db_context *db_open_watched(TALLOC_CTX *mem_ctx,
> +				   struct db_context *backend,
> +				   struct messaging_context *msg);
> +struct tevent_req *dbwrap_watched_watch_send(TALLOC_CTX *mem_ctx,
> +					     struct tevent_context *ev,
> +					     struct db_record *rec,
> +					     struct server_id blocker);
> +NTSTATUS dbwrap_watched_watch_recv(struct tevent_req *req,
> +				   TALLOC_CTX *mem_ctx,
> +				   struct db_record **prec,
> +				   bool *blockerdead,
> +				   struct server_id *blocker);
>  
>  #endif /* __DBWRAP_WATCH_H__ */
> diff --git a/source3/torture/test_dbwrap_watch.c b/source3/torture/test_dbwrap_watch.c
> index a912bd2..d3eac6f 100644
> --- a/source3/torture/test_dbwrap_watch.c
> +++ b/source3/torture/test_dbwrap_watch.c
> @@ -29,6 +29,7 @@ bool run_dbwrap_watch1(int dummy)
>  {
>  	struct tevent_context *ev = NULL;
>  	struct messaging_context *msg = NULL;
> +	struct db_context *backend = NULL;
>  	struct db_context *db = NULL;
>  	const char *keystr = "key";
>  	TDB_DATA key = string_term_tdb_data(keystr);
> @@ -47,21 +48,23 @@ bool run_dbwrap_watch1(int dummy)
>  		fprintf(stderr, "messaging_init failed\n");
>  		goto fail;
>  	}
> -	db = db_open(msg, "test_watch.tdb", 0, TDB_DEFAULT,
> -		     O_CREAT|O_RDWR, 0644, DBWRAP_LOCK_ORDER_1,
> -		     DBWRAP_FLAG_NONE);
> -	if (db == NULL) {
> +	backend = db_open(msg, "test_watch.tdb", 0, TDB_DEFAULT,
> +			  O_CREAT|O_RDWR, 0644, DBWRAP_LOCK_ORDER_1,
> +			  DBWRAP_FLAG_NONE);
> +	if (backend == NULL) {
>  		fprintf(stderr, "db_open failed: %s\n", strerror(errno));
>  		goto fail;
>  	}
> -	dbwrap_watch_db(db, msg);
> +
> +	db = db_open_watched(ev, backend, msg);
> +
>  	rec = dbwrap_fetch_locked(db, db, key);
>  	if (rec == NULL) {
>  		fprintf(stderr, "dbwrap_fetch_locked failed\n");
>  		goto fail;
>  	}
> -	req = dbwrap_record_watch_send(talloc_tos(), ev, rec, msg,
> -				       (struct server_id){0});
> +	req = dbwrap_watched_watch_send(talloc_tos(), ev, rec,
> +					(struct server_id){0});
>  	if (req == NULL) {
>  		fprintf(stderr, "dbwrap_record_watch_send failed\n");
>  		goto fail;
> @@ -87,8 +90,8 @@ bool run_dbwrap_watch1(int dummy)
>  		goto fail;
>  	}
>  
> -	status = dbwrap_record_watch_recv(req, talloc_tos(), &rec, NULL,
> -					  NULL);
> +	status = dbwrap_watched_watch_recv(req, talloc_tos(), &rec, NULL,
> +					   NULL);
>  	if (!NT_STATUS_IS_OK(status)) {
>  		fprintf(stderr, "dbwrap_record_watch_recv failed: %s\n",
>  			nt_errstr(status));
> -- 
> 1.9.1
> 
> 
> From 004709fd5019cf0abec269b35d2a9e3974b425be Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Wed, 13 Jul 2016 07:26:52 +0200
> Subject: [PATCH 6/9] lib: Convert g_lock to new dbwrap_watch
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/lib/g_lock.c | 31 ++++++++++++++++++-------------
>  1 file changed, 18 insertions(+), 13 deletions(-)
> 
> diff --git a/source3/lib/g_lock.c b/source3/lib/g_lock.c
> index 7b91e3c..f954978 100644
> --- a/source3/lib/g_lock.c
> +++ b/source3/lib/g_lock.c
> @@ -48,6 +48,7 @@ struct g_lock_ctx *g_lock_ctx_init(TALLOC_CTX *mem_ctx,
>  				   struct messaging_context *msg)
>  {
>  	struct g_lock_ctx *result;
> +	struct db_context *backend;
>  	char *db_path;
>  
>  	result = talloc(mem_ctx, struct g_lock_ctx);
> @@ -62,18 +63,24 @@ struct g_lock_ctx *g_lock_ctx_init(TALLOC_CTX *mem_ctx,
>  		return NULL;
>  	}
>  
> -	result->db = db_open(result, db_path, 0,
> -			     TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
> -			     O_RDWR|O_CREAT, 0600,
> -			     DBWRAP_LOCK_ORDER_2,
> -			     DBWRAP_FLAG_NONE);
> +	backend = db_open(result, db_path, 0,
> +			  TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
> +			  O_RDWR|O_CREAT, 0600,
> +			  DBWRAP_LOCK_ORDER_2,
> +			  DBWRAP_FLAG_NONE);
>  	TALLOC_FREE(db_path);
> -	if (result->db == NULL) {
> +	if (backend == NULL) {
>  		DEBUG(1, ("g_lock_init: Could not open g_lock.tdb\n"));
>  		TALLOC_FREE(result);
>  		return NULL;
>  	}
> -	dbwrap_watch_db(result->db, msg);
> +
> +	result->db = db_open_watched(result, backend, msg);
> +	if (result->db == NULL) {
> +		DBG_WARNING("g_lock_init: db_open_watched failed\n");
> +		TALLOC_FREE(result);
> +		return NULL;
> +	}
>  	return result;
>  }
>  
> @@ -238,8 +245,7 @@ struct tevent_req *g_lock_lock_send(TALLOC_CTX *mem_ctx,
>  		tevent_req_nterror(req, status);
>  		return tevent_req_post(req, ev);
>  	}
> -	subreq = dbwrap_record_watch_send(state, state->ev, rec,
> -					  state->ctx->msg, blocker);
> +	subreq = dbwrap_watched_watch_send(state, state->ev, rec, blocker);
>  	TALLOC_FREE(rec);
>  	if (tevent_req_nomem(subreq, req)) {
>  		return tevent_req_post(req, ev);
> @@ -265,8 +271,8 @@ static void g_lock_lock_retry(struct tevent_req *subreq)
>  	struct db_record *rec;
>  	NTSTATUS status;
>  
> -	status = dbwrap_record_watch_recv(subreq, talloc_tos(), &rec, NULL,
> -					  NULL);
> +	status = dbwrap_watched_watch_recv(subreq, talloc_tos(), &rec, NULL,
> +					   NULL);
>  	TALLOC_FREE(subreq);
>  
>  	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
> @@ -294,8 +300,7 @@ static void g_lock_lock_retry(struct tevent_req *subreq)
>  		tevent_req_nterror(req, status);
>  		return;
>  	}
> -	subreq = dbwrap_record_watch_send(state, state->ev, rec,
> -					  state->ctx->msg, blocker);
> +	subreq = dbwrap_watched_watch_send(state, state->ev, rec, blocker);
>  	TALLOC_FREE(rec);
>  	if (tevent_req_nomem(subreq, req)) {
>  		return;
> -- 
> 1.9.1
> 
> 
> From 4811ed9e5cc61fedd4490102d768792540eb2e52 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Wed, 13 Jul 2016 07:27:30 +0200
> Subject: [PATCH 7/9] smbd: Convert locking.tdb to new dbwrap_watch
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/locking/share_mode_lock.c | 18 +++++++++++++-----
>  source3/smbd/open.c               |  8 ++++----
>  source3/smbd/smb2_setinfo.c       |  7 +++----
>  3 files changed, 20 insertions(+), 13 deletions(-)
> 
> diff --git a/source3/locking/share_mode_lock.c b/source3/locking/share_mode_lock.c
> index 4e9de03..b5a63f8 100644
> --- a/source3/locking/share_mode_lock.c
> +++ b/source3/locking/share_mode_lock.c
> @@ -60,6 +60,7 @@ static struct db_context *lock_db;
>  
>  static bool locking_init_internal(bool read_only)
>  {
> +	struct db_context *backend;
>  	char *db_path;
>  
>  	brl_init(read_only);
> @@ -72,21 +73,28 @@ static bool locking_init_internal(bool read_only)
>  		return false;
>  	}
>  
> -	lock_db = db_open(NULL, db_path,
> +	backend = db_open(NULL, db_path,
>  			  SMB_OPEN_DATABASE_TDB_HASH_SIZE,
>  			  TDB_DEFAULT|TDB_VOLATILE|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
>  			  read_only?O_RDONLY:O_RDWR|O_CREAT, 0644,
>  			  DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
>  	TALLOC_FREE(db_path);
> -	if (!lock_db) {
> +	if (!backend) {
>  		DEBUG(0,("ERROR: Failed to initialise locking database\n"));
>  		return False;
>  	}
>  
> -	if (!posix_locking_init(read_only))
> -		return False;
> +	lock_db = db_open_watched(NULL, backend, server_messaging_context());
> +	if (lock_db == NULL) {
> +		DBG_ERR("db_open_watched failed\n");
> +		TALLOC_FREE(backend);
> +		return false;
> +	}
>  
> -	dbwrap_watch_db(lock_db, server_messaging_context());
> +	if (!posix_locking_init(read_only)) {
> +		TALLOC_FREE(lock_db);
> +		return False;
> +	}
>  
>  	return True;
>  }
> diff --git a/source3/smbd/open.c b/source3/smbd/open.c
> index 57cd4f1..ab46fe0 100644
> --- a/source3/smbd/open.c
> +++ b/source3/smbd/open.c
> @@ -1952,9 +1952,9 @@ static void defer_open(struct share_mode_lock *lck,
>  		DEBUG(10, ("defering mid %llu\n",
>  			   (unsigned long long)req->mid));
>  
> -		watch_req = dbwrap_record_watch_send(
> +		watch_req = dbwrap_watched_watch_send(
>  			watch_state, req->sconn->ev_ctx, lck->data->record,
> -			req->sconn->msg_ctx, (struct server_id){0});
> +			(struct server_id){0});
>  		if (watch_req == NULL) {
>  			exit_server("Could not watch share mode record");
>  		}
> @@ -1981,11 +1981,11 @@ static void defer_open_done(struct tevent_req *req)
>  	NTSTATUS status;
>  	bool ret;
>  
> -	status = dbwrap_record_watch_recv(req, talloc_tos(), NULL, NULL,
> +	status = dbwrap_watched_watch_recv(req, talloc_tos(), NULL, NULL,
>  					  NULL);
>  	TALLOC_FREE(req);
>  	if (!NT_STATUS_IS_OK(status)) {
> -		DEBUG(5, ("dbwrap_record_watch_recv returned %s\n",
> +		DEBUG(5, ("dbwrap_watched_watch_recv returned %s\n",
>  			  nt_errstr(status)));
>  		/*
>  		 * Even if it failed, retry anyway. TODO: We need a way to
> diff --git a/source3/smbd/smb2_setinfo.c b/source3/smbd/smb2_setinfo.c
> index 0a678ea..db00ba0 100644
> --- a/source3/smbd/smb2_setinfo.c
> +++ b/source3/smbd/smb2_setinfo.c
> @@ -248,11 +248,10 @@ static struct tevent_req *delay_rename_for_lease_break(struct tevent_req *req,
>  
>  	talloc_set_destructor(rename_state, defer_rename_state_destructor);
>  
> -	subreq = dbwrap_record_watch_send(
> +	subreq = dbwrap_watched_watch_send(
>  				rename_state,
>  				ev,
>  				lck->data->record,
> -				fsp->conn->sconn->msg_ctx,
>  				(struct server_id){0});
>  
>  	if (subreq == NULL) {
> @@ -280,8 +279,8 @@ static void defer_rename_done(struct tevent_req *subreq)
>  	int ret_size = 0;
>  	bool ok;
>  
> -	status = dbwrap_record_watch_recv(subreq, state->req, NULL, NULL,
> -					  NULL);
> +	status = dbwrap_watched_watch_recv(subreq, state->req, NULL, NULL,
> +					   NULL);
>  	TALLOC_FREE(subreq);
>  	if (!NT_STATUS_IS_OK(status)) {
>  		DEBUG(5, ("dbwrap_record_watch_recv returned %s\n",
> -- 
> 1.9.1
> 
> 
> From 9906e1f15b9e2a33cd60bae32c9067a087448538 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Wed, 13 Jul 2016 07:41:02 +0200
> Subject: [PATCH 8/9] smbd: Convert smbXsrv_open_global.tdb to new dbwrap_watch
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/smbd/globals.h         |  2 +-
>  source3/smbd/server.c          |  2 +-
>  source3/smbd/smbXsrv_session.c | 42 +++++++++++++++++++++++-------------------
>  3 files changed, 25 insertions(+), 21 deletions(-)
> 
> diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
> index 9e3e95c..0266533 100644
> --- a/source3/smbd/globals.h
> +++ b/source3/smbd/globals.h
> @@ -554,7 +554,7 @@ NTSTATUS smb2srv_client_connection_pass(struct smbd_smb2_request *smb2req,
>  NTSTATUS smbXsrv_connection_init_tables(struct smbXsrv_connection *conn,
>  					enum protocol_types protocol);
>  
> -NTSTATUS smbXsrv_session_global_init(void);
> +NTSTATUS smbXsrv_session_global_init(struct messaging_context *msg_ctx);
>  NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
>  				NTTIME now,
>  				struct smbXsrv_session **_session);
> diff --git a/source3/smbd/server.c b/source3/smbd/server.c
> index 6e70edc..65dc173 100644
> --- a/source3/smbd/server.c
> +++ b/source3/smbd/server.c
> @@ -1582,7 +1582,7 @@ extern void build_options(bool screen);
>  		exit_daemon("Samba cannot init server context", EACCES);
>  	}
>  
> -	status = smbXsrv_session_global_init();
> +	status = smbXsrv_session_global_init(msg_ctx);
>  	if (!NT_STATUS_IS_OK(status)) {
>  		exit_daemon("Samba cannot init session context", EACCES);
>  	}
> diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c
> index 51668c2..381ce40 100644
> --- a/source3/smbd/smbXsrv_session.c
> +++ b/source3/smbd/smbXsrv_session.c
> @@ -53,9 +53,10 @@ struct smbXsrv_session_table {
>  
>  static struct db_context *smbXsrv_session_global_db_ctx = NULL;
>  
> -NTSTATUS smbXsrv_session_global_init(void)
> +NTSTATUS smbXsrv_session_global_init(struct messaging_context *msg_ctx)
>  {
>  	char *global_path = NULL;
> +	struct db_context *backend = NULL;
>  	struct db_context *db_ctx = NULL;
>  
>  	if (smbXsrv_session_global_db_ctx != NULL) {
> @@ -70,16 +71,16 @@ NTSTATUS smbXsrv_session_global_init(void)
>  		return NT_STATUS_NO_MEMORY;
>  	}
>  
> -	db_ctx = db_open(NULL, global_path,
> -			 0, /* hash_size */
> -			 TDB_DEFAULT |
> -			 TDB_CLEAR_IF_FIRST |
> -			 TDB_INCOMPATIBLE_HASH,
> -			 O_RDWR | O_CREAT, 0600,
> -			 DBWRAP_LOCK_ORDER_1,
> -			 DBWRAP_FLAG_NONE);
> +	backend = db_open(NULL, global_path,
> +			  0, /* hash_size */
> +			  TDB_DEFAULT |
> +			  TDB_CLEAR_IF_FIRST |
> +			  TDB_INCOMPATIBLE_HASH,
> +			  O_RDWR | O_CREAT, 0600,
> +			  DBWRAP_LOCK_ORDER_1,
> +			  DBWRAP_FLAG_NONE);
>  	TALLOC_FREE(global_path);
> -	if (db_ctx == NULL) {
> +	if (backend == NULL) {
>  		NTSTATUS status;
>  
>  		status = map_nt_error_from_unix_common(errno);
> @@ -87,6 +88,12 @@ NTSTATUS smbXsrv_session_global_init(void)
>  		return status;
>  	}
>  
> +	db_ctx = db_open_watched(NULL, backend, server_messaging_context());
> +	if (db_ctx == NULL) {
> +		TALLOC_FREE(backend);
> +		return NT_STATUS_NO_MEMORY;
> +	}
> +
>  	smbXsrv_session_global_db_ctx = db_ctx;
>  
>  	return NT_STATUS_OK;
> @@ -242,7 +249,7 @@ static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn,
>  	table->local.highest_id = highest_id;
>  	table->local.max_sessions = max_sessions;
>  
> -	status = smbXsrv_session_global_init();
> +	status = smbXsrv_session_global_init(client->msg_ctx);
>  	if (!NT_STATUS_IS_OK(status)) {
>  		TALLOC_FREE(table);
>  		return status;
> @@ -250,8 +257,6 @@ static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn,
>  
>  	table->global.db_ctx = smbXsrv_session_global_db_ctx;
>  
> -	dbwrap_watch_db(table->global.db_ctx, client->msg_ctx);
> -
>  	subreq = messaging_read_send(table, client->ev_ctx, client->msg_ctx,
>  				     MSG_SMBXSRV_SESSION_CLOSE);
>  	if (subreq == NULL) {
> @@ -1065,9 +1070,8 @@ static void smb2srv_session_close_previous_check(struct tevent_req *req)
>  		return;
>  	}
>  
> -	subreq = dbwrap_record_watch_send(state, state->ev,
> -					  state->db_rec, conn->msg_ctx,
> -					  (struct server_id){0});
> +	subreq = dbwrap_watched_watch_send(state, state->ev, state->db_rec,
> +					   (struct server_id){0});
>  	if (tevent_req_nomem(subreq, req)) {
>  		TALLOC_FREE(state->db_rec);
>  		return;
> @@ -1121,8 +1125,8 @@ static void smb2srv_session_close_previous_modified(struct tevent_req *subreq)
>  		struct smb2srv_session_close_previous_state);
>  	NTSTATUS status;
>  
> -	status = dbwrap_record_watch_recv(subreq, state, &state->db_rec, NULL,
> -					  NULL);
> +	status = dbwrap_watched_watch_recv(subreq, state, &state->db_rec, NULL,
> +					   NULL);
>  	TALLOC_FREE(subreq);
>  	if (tevent_req_nterror(req, status)) {
>  		return;
> @@ -1931,7 +1935,7 @@ NTSTATUS smbXsrv_session_global_traverse(
>  	};
>  
>  	become_root();
> -	status = smbXsrv_session_global_init();
> +	status = smbXsrv_session_global_init(NULL);
>  	if (!NT_STATUS_IS_OK(status)) {
>  		unbecome_root();
>  		DEBUG(0, ("Failed to initialize session_global: %s\n",
> -- 
> 1.9.1
> 
> 
> From aaadabf77970c686ed1330952b2039e85d175d12 Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Thu, 14 Jul 2016 07:43:20 +0200
> Subject: [PATCH 9/9] smbd: Remove a reference to dbwrap_watch_db()
> 
> This has never been watched, so it's an unnecessary overhead on
> dbwrap_record_store().
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> ---
>  source3/smbd/smbXsrv_client.c | 2 --
>  1 file changed, 2 deletions(-)
> 
> diff --git a/source3/smbd/smbXsrv_client.c b/source3/smbd/smbXsrv_client.c
> index 7286b6e..ca04ae7 100644
> --- a/source3/smbd/smbXsrv_client.c
> +++ b/source3/smbd/smbXsrv_client.c
> @@ -167,8 +167,6 @@ static NTSTATUS smbXsrv_client_table_create(TALLOC_CTX *mem_ctx,
>  
>  	table->global.db_ctx = smbXsrv_client_global_db_ctx;
>  
> -	dbwrap_watch_db(table->global.db_ctx, msg_ctx);
> -
>  	*_table = table;
>  	return NT_STATUS_OK;
>  }
> -- 
> 1.9.1
> 




More information about the samba-technical mailing list