[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