Messaging patches

Jeremy Allison jra at samba.org
Tue Apr 29 23:02:05 MDT 2014


On Tue, Apr 29, 2014 at 05:03:22PM +0200, Volker Lendecke wrote:
> Hi!
> 
> Attached find a few patches for messaging3, one critical
> bugfix (I believe). Right now autobuild is pretty flaky for
> me, so I could not successfully run this through autobuild
> yet. It does survive some simple tests for me though.
> 
> Posting it here for preliminary review, we need to wait I
> guess until sn-devel settles down a bit again.

OK, here is a 'Reviewed-by: <jra at samba.org>' version
of the patchset that now passes samba3.raw.mux tests.

The first patch is the fix for the wildcard unlink
bug, so Volker or Michael if you could review that
I'd appreciate it (it's a pretty obvious bugfix)
so I can push it all in one go.

Volker, the rest of it is your patchset with one
minor change to fix the re-ordering of messages
that caused the test to fail - in messaging_dispatch_rec() 
when req == NULL you swapped the end pointer with
the NULL pointer in the array - this is the
re-ordering that caused the samba3.raw.mux test
to fail. I replaced it with a memmove which
is less efficient but preserves the ordering
of the message responses. Here is the change
on top of your patchset:

diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index e4fc4ec..9284ac1 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -623,11 +623,17 @@ void messaging_dispatch_rec(struct messaging_context *msg_ctx,
                req = msg_ctx->waiters[i];
                if (req == NULL) {
                        /*
-                        * This got cleaned up in the meantime, get the one
-                        * from the end of the array
+                        * This got cleaned up. In the meantime,
+                        * move everything down one. We need
+                        * to keep the order of waiters, as
+                        * other code may depend on this.
                         */
-                       msg_ctx->waiters[i] =
-                               msg_ctx->waiters[msg_ctx->num_waiters-1];
+                       if (i <  msg_ctx->num_waiters - 1) {
+                               memmove(&msg_ctx->waiters[i],
+                                       &msg_ctx->waiters[i+1],
+                                       sizeof(struct tevent_req *) *
+                                               (msg_ctx->num_waiters - i - 1));
+                       }
                        msg_ctx->num_waiters -= 1;
                        continue;
                }

For the attached patch I've squashed this
into your original change and added my
Reviewed-by's to all the patches.

If you are OK with this I'll push it when
I get into work tomorrow !

Cheers,

	Jeremy.
-------------- next part --------------
>From 8118eb31f571827a8ba723a1a9999cd04748dec9 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 29 Apr 2014 16:59:55 -0700
Subject: [PATCH 1/7] s3: smbd : Fix wildcard unlink to fail if we get an error
 rather than trying to continue.

This can break smbd if we end up leaving a SHARING_VIOLATION
retry record on the queue.

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 source3/smbd/reply.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index da59ca7..f737d74 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -2909,9 +2909,10 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
 
 			status = do_unlink(conn, req, smb_fname, dirtype);
 			if (!NT_STATUS_IS_OK(status)) {
+				TALLOC_FREE(dir_hnd);
 				TALLOC_FREE(frame);
 				TALLOC_FREE(talloced);
-				continue;
+				goto out;
 			}
 
 			count++;
-- 
1.9.1


>From d774911a69c42513ae16a8cc80627f5bc4c81ded Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 29 Apr 2014 14:08:29 +0200
Subject: [PATCH 2/7] messaging3: Fix formatting

This went over the 80-char limit

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 source3/lib/messages.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index b6fe423..9354ac8 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -526,7 +526,8 @@ static void messaging_read_cleanup(struct tevent_req *req,
 	}
 }
 
-static void messaging_read_done(struct tevent_req *req, struct messaging_rec *rec)
+static void messaging_read_done(struct tevent_req *req,
+				struct messaging_rec *rec)
 {
 	struct messaging_read_state *state = tevent_req_data(
 		req, struct messaging_read_state);
-- 
1.9.1


>From dd994c58f107d1b3cd77893f2078adc05f5369c4 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 29 Apr 2014 14:10:04 +0200
Subject: [PATCH 3/7] torture3: Add a bit more coverage to messaging_read

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 source3/torture/test_dbwrap_watch.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/source3/torture/test_dbwrap_watch.c b/source3/torture/test_dbwrap_watch.c
index 4e699fe..ab9330f 100644
--- a/source3/torture/test_dbwrap_watch.c
+++ b/source3/torture/test_dbwrap_watch.c
@@ -67,6 +67,13 @@ bool run_dbwrap_watch1(int dummy)
 	}
 	TALLOC_FREE(rec);
 
+	status = dbwrap_store_int32_bystring(db, "different_key", 1);
+	if (!NT_STATUS_IS_OK(status)) {
+		fprintf(stderr, "dbwrap_store_int32 failed: %s\n",
+			nt_errstr(status));
+		goto fail;
+	}
+
 	status = dbwrap_store_int32_bystring(db, keystr, 1);
 	if (!NT_STATUS_IS_OK(status)) {
 		fprintf(stderr, "dbwrap_store_int32 failed: %s\n",
-- 
1.9.1


>From 94c2dbf47dd853b9afb4de066ef4baff373de8e5 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 29 Apr 2014 14:12:26 +0200
Subject: [PATCH 4/7] messaging3: Make "presult" optional in
 messaging_read_recv

Callers might not be interested in the rec, just the fact that something
arrived

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 source3/lib/messages.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index 9354ac8..b0b2bb2 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -550,7 +550,9 @@ int messaging_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 		tevent_req_received(req);
 		return err;
 	}
-	*presult = talloc_move(mem_ctx, &state->rec);
+	if (presult != NULL) {
+		*presult = talloc_move(mem_ctx, &state->rec);
+	}
 	return 0;
 }
 
-- 
1.9.1


>From 3254adcd8013dccf04684ee205ba0b634d58dc63 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 29 Apr 2014 14:14:24 +0200
Subject: [PATCH 5/7] messaging3: Fix messaging_read_send/recv

messaging_read_send/recv was okay for just one handler in the queue. For
multiple handlers it was pretty broken.

A handler that deletes itself as part of the callback (pretty typical use
case...) drops the message for a subsequent handler that responds to the same
message type. In messaging_dispatch_rec we walk the array, however
messaging_read_cleanup has already changed the array. tevent_req_defer_callback
does not help here: It only defers the callback, it does not defer the cleanup
function.

This also happens when a callback deletes a different handler

A handler that re-installs itself in the callback might get a message twice.

This patch changes the code such that only messaging_dispatch_rec adds records
to msg_ctx->waiters, new waiters are put into a staging area first
(msg_ctx->new_waiters). Also messaging_read_cleanup does not move anything
around in msg_ctx->waiters, it only nulls out itself. messaging_dispatch_rec is
changed to cope with this.

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 source3/include/messages.h |  3 ++
 source3/lib/messages.c     | 90 +++++++++++++++++++++++++++++++++++++---------
 2 files changed, 77 insertions(+), 16 deletions(-)

diff --git a/source3/include/messages.h b/source3/include/messages.h
index 1681ec9..06c1748 100644
--- a/source3/include/messages.h
+++ b/source3/include/messages.h
@@ -76,6 +76,9 @@ struct messaging_context {
 	struct tevent_context *event_ctx;
 	struct messaging_callback *callbacks;
 
+	struct tevent_req **new_waiters;
+	unsigned num_new_waiters;
+
 	struct tevent_req **waiters;
 	unsigned num_waiters;
 
diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index b0b2bb2..9284ac1 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -475,7 +475,7 @@ struct tevent_req *messaging_read_send(TALLOC_CTX *mem_ctx,
 {
 	struct tevent_req *req;
 	struct messaging_read_state *state;
-	size_t waiters_len;
+	size_t new_waiters_len;
 
 	req = tevent_req_create(mem_ctx, &state,
 				struct messaging_read_state);
@@ -486,21 +486,21 @@ struct tevent_req *messaging_read_send(TALLOC_CTX *mem_ctx,
 	state->msg_ctx = msg_ctx;
 	state->msg_type = msg_type;
 
-	waiters_len = talloc_array_length(msg_ctx->waiters);
+	new_waiters_len = talloc_array_length(msg_ctx->new_waiters);
 
-	if (waiters_len == msg_ctx->num_waiters) {
+	if (new_waiters_len == msg_ctx->num_new_waiters) {
 		struct tevent_req **tmp;
 
-		tmp = talloc_realloc(msg_ctx, msg_ctx->waiters,
-				     struct tevent_req *, waiters_len+1);
+		tmp = talloc_realloc(msg_ctx, msg_ctx->new_waiters,
+				     struct tevent_req *, new_waiters_len+1);
 		if (tevent_req_nomem(tmp, req)) {
 			return tevent_req_post(req, ev);
 		}
-		msg_ctx->waiters = tmp;
+		msg_ctx->new_waiters = tmp;
 	}
 
-	msg_ctx->waiters[msg_ctx->num_waiters] = req;
-	msg_ctx->num_waiters += 1;
+	msg_ctx->new_waiters[msg_ctx->num_new_waiters] = req;
+	msg_ctx->num_new_waiters += 1;
 	tevent_req_set_cleanup_fn(req, messaging_read_cleanup);
 
 	return req;
@@ -512,15 +512,20 @@ static void messaging_read_cleanup(struct tevent_req *req,
 	struct messaging_read_state *state = tevent_req_data(
 		req, struct messaging_read_state);
 	struct messaging_context *msg_ctx = state->msg_ctx;
-	struct tevent_req **waiters = msg_ctx->waiters;
 	unsigned i;
 
 	tevent_req_set_cleanup_fn(req, NULL);
 
 	for (i=0; i<msg_ctx->num_waiters; i++) {
-		if (waiters[i] == req) {
-			waiters[i] = waiters[msg_ctx->num_waiters-1];
-			msg_ctx->num_waiters -= 1;
+		if (msg_ctx->waiters[i] == req) {
+			msg_ctx->waiters[i] = NULL;
+			return;
+		}
+	}
+
+	for (i=0; i<msg_ctx->num_new_waiters; i++) {
+		if (msg_ctx->new_waiters[i] == req) {
+			msg_ctx->new_waiters[i] = NULL;
 			return;
 		}
 	}
@@ -556,6 +561,34 @@ int messaging_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 	return 0;
 }
 
+static bool messaging_append_new_waiters(struct messaging_context *msg_ctx)
+{
+	if (msg_ctx->num_new_waiters == 0) {
+		return true;
+	}
+
+	if (talloc_array_length(msg_ctx->waiters) <
+	    (msg_ctx->num_waiters + msg_ctx->num_new_waiters)) {
+		struct tevent_req **tmp;
+		tmp = talloc_realloc(
+			msg_ctx, msg_ctx->waiters, struct tevent_req *,
+			msg_ctx->num_waiters + msg_ctx->num_new_waiters);
+		if (tmp == NULL) {
+			DEBUG(1, ("%s: talloc failed\n", __func__));
+			return false;
+		}
+		msg_ctx->waiters = tmp;
+	}
+
+	memcpy(&msg_ctx->waiters[msg_ctx->num_waiters], msg_ctx->new_waiters,
+	       sizeof(struct tevent_req *) * msg_ctx->num_new_waiters);
+
+	msg_ctx->num_waiters += msg_ctx->num_new_waiters;
+	msg_ctx->num_new_waiters = 0;
+
+	return true;
+}
+
 /*
   Dispatch one messaging_rec
 */
@@ -578,14 +611,39 @@ void messaging_dispatch_rec(struct messaging_context *msg_ctx,
 		}
 	}
 
-	for (i=0; i<msg_ctx->num_waiters; i++) {
-		struct tevent_req *req = msg_ctx->waiters[i];
-		struct messaging_read_state *state = tevent_req_data(
-			req, struct messaging_read_state);
+	if (!messaging_append_new_waiters(msg_ctx)) {
+		return;
+	}
+
+	i = 0;
+	while (i < msg_ctx->num_waiters) {
+		struct tevent_req *req;
+		struct messaging_read_state *state;
+
+		req = msg_ctx->waiters[i];
+		if (req == NULL) {
+			/*
+			 * This got cleaned up. In the meantime,
+			 * move everything down one. We need
+			 * to keep the order of waiters, as
+			 * other code may depend on this.
+			 */
+			if (i <  msg_ctx->num_waiters - 1) {
+				memmove(&msg_ctx->waiters[i],
+					&msg_ctx->waiters[i+1],
+					sizeof(struct tevent_req *) *
+						(msg_ctx->num_waiters - i - 1));
+			}
+			msg_ctx->num_waiters -= 1;
+			continue;
+		}
 
+		state = tevent_req_data(req, struct messaging_read_state);
 		if (state->msg_type == rec->msg_type) {
 			messaging_read_done(req, rec);
 		}
+
+		i += 1;
 	}
 	return;
 }
-- 
1.9.1


>From fe87df4b7c7ec256361a8674d7c1c6cafa2b4023 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 29 Apr 2014 14:25:14 +0200
Subject: [PATCH 6/7] torture3: Add local-messaging-read1

This covers deleting and re-adding a request in a callback

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 source3/selftest/tests.py             |   1 +
 source3/torture/proto.h               |   1 +
 source3/torture/test_messaging_read.c | 144 ++++++++++++++++++++++++++++++++++
 source3/torture/torture.c             |   1 +
 source3/wscript_build                 |   1 +
 5 files changed, 148 insertions(+)
 create mode 100644 source3/torture/test_messaging_read.c

diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 4357ed9..7200329 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -102,6 +102,7 @@ local_tests = [
     "LOCAL-CONVERT-STRING",
     "LOCAL-CONV-AUTH-INFO",
     "LOCAL-IDMAP-TDB-COMMON",
+    "LOCAL-MESSAGING-READ1",
     "LOCAL-hex_encode_buf",
     "LOCAL-sprintf_append",
     "LOCAL-remove_duplicate_addrs2"]
diff --git a/source3/torture/proto.h b/source3/torture/proto.h
index 3673d98..f23efa1 100644
--- a/source3/torture/proto.h
+++ b/source3/torture/proto.h
@@ -113,5 +113,6 @@ bool run_idmap_tdb_common_test(int dummy);
 bool run_local_dbwrap_ctdb(int dummy);
 bool run_qpathinfo_bufsize(int dummy);
 bool run_bench_pthreadpool(int dummy);
+bool run_messaging_read1(int dummy);
 
 #endif /* __TORTURE_H__ */
diff --git a/source3/torture/test_messaging_read.c b/source3/torture/test_messaging_read.c
new file mode 100644
index 0000000..6c8cdba
--- /dev/null
+++ b/source3/torture/test_messaging_read.c
@@ -0,0 +1,144 @@
+/*
+   Unix SMB/CIFS implementation.
+   Test for a messaging_read bug
+   Copyright (C) Volker Lendecke 2014
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/proto.h"
+#include "lib/util/tevent_unix.h"
+#include "messages.h"
+
+struct msg_count_state {
+	struct tevent_context *ev;
+	struct messaging_context *msg_ctx;
+	uint32_t msg_type;
+	unsigned *count;
+};
+
+static void msg_count_done(struct tevent_req *subreq);
+
+static struct tevent_req *msg_count_send(TALLOC_CTX *mem_ctx,
+					 struct tevent_context *ev,
+					 struct messaging_context *msg_ctx,
+					 uint32_t msg_type,
+					 unsigned *count)
+{
+	struct tevent_req *req, *subreq;
+	struct msg_count_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct msg_count_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->ev = ev;
+	state->msg_ctx = msg_ctx;
+	state->msg_type = msg_type;
+	state->count = count;
+
+	subreq = messaging_read_send(state, state->ev, state->msg_ctx,
+				     state->msg_type);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, msg_count_done, req);
+	return req;
+}
+
+static void msg_count_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct msg_count_state *state = tevent_req_data(
+		req, struct msg_count_state);
+	int ret;
+
+	ret = messaging_read_recv(subreq, NULL, NULL);
+	TALLOC_FREE(subreq);
+	if (tevent_req_error(req, ret)) {
+		return;
+	}
+	*state->count += 1;
+
+	subreq = messaging_read_send(state, state->ev, state->msg_ctx,
+				     state->msg_type);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, msg_count_done, req);
+}
+
+bool run_messaging_read1(int dummy)
+{
+	struct tevent_context *ev = NULL;
+	struct messaging_context *msg_ctx = NULL;
+	struct tevent_req *req1 = NULL;
+	unsigned count1 = 0;
+	struct tevent_req *req2 = NULL;
+	unsigned count2 = 0;
+	NTSTATUS status;
+	bool retval = false;
+
+	ev = samba_tevent_context_init(talloc_tos());
+	if (ev == NULL) {
+		fprintf(stderr, "tevent_context_init failed\n");
+		goto fail;
+	}
+	msg_ctx = messaging_init(ev, ev);
+	if (msg_ctx == NULL) {
+		fprintf(stderr, "messaging_init failed\n");
+		goto fail;
+	}
+
+	req1 = msg_count_send(ev, ev, msg_ctx, MSG_SMB_NOTIFY, &count1);
+	if (req1 == NULL) {
+		fprintf(stderr, "msg_count_send failed\n");
+		goto fail;
+	}
+	req2 = msg_count_send(ev, ev, msg_ctx, MSG_SMB_NOTIFY, &count2);
+	if (req1 == NULL) {
+		fprintf(stderr, "msg_count_send failed\n");
+		goto fail;
+	}
+	status = messaging_send_buf(msg_ctx, messaging_server_id(msg_ctx),
+				    MSG_SMB_NOTIFY, NULL, 0);
+	if (!NT_STATUS_IS_OK(status)) {
+		fprintf(stderr, "messaging_send_buf failed: %s\n",
+			nt_errstr(status));
+		goto fail;
+	}
+
+	if (tevent_loop_once(ev) != 0) {
+		fprintf(stderr, "tevent_loop_once failed\n");
+		goto fail;
+	}
+
+	printf("%u/%u\n", count1, count2);
+
+	if ((count1 != 1) || (count2 != 1)){
+		fprintf(stderr, "Got %u/%u msgs, expected 1 each\n",
+			count1, count2);
+		goto fail;
+	}
+
+	retval = true;
+fail:
+	TALLOC_FREE(req1);
+	TALLOC_FREE(req2);
+	TALLOC_FREE(msg_ctx);
+	TALLOC_FREE(ev);
+	return retval;
+}
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 61e9338..5d75bbf 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -9574,6 +9574,7 @@ static struct {
 	{ "LOCAL-TALLOC-DICT", run_local_talloc_dict, 0},
 	{ "LOCAL-CTDB-CONN", run_ctdb_conn, 0},
 	{ "LOCAL-DBWRAP-WATCH1", run_dbwrap_watch1, 0 },
+	{ "LOCAL-MESSAGING-READ1", run_messaging_read1, 0 },
 	{ "LOCAL-BASE64", run_local_base64, 0},
 	{ "LOCAL-RBTREE", run_local_rbtree, 0},
 	{ "LOCAL-MEMCACHE", run_local_memcache, 0},
diff --git a/source3/wscript_build b/source3/wscript_build
index e9c2f91..f13aa63 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -1256,6 +1256,7 @@ bld.SAMBA3_BINARY('smbtorture' + bld.env.suffix3,
                  torture/test_idmap_tdb_common.c
                  torture/test_dbwrap_ctdb.c
                  torture/test_buffersize.c
+                 torture/test_messaging_read.c
                  torture/t_strappend.c
                  torture/bench_pthreadpool.c
                  torture/wbc_async.c''',
-- 
1.9.1


>From 266cf220eda94f4e5e43d2a16d4fbfb3fcefba41 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 29 Apr 2014 14:27:03 +0200
Subject: [PATCH 7/7] torture3: Add a test deleting a different req

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 source3/selftest/tests.py             |   1 +
 source3/torture/proto.h               |   1 +
 source3/torture/test_messaging_read.c | 103 ++++++++++++++++++++++++++++++++++
 source3/torture/torture.c             |   1 +
 4 files changed, 106 insertions(+)

diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 7200329..fcf3cd5 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -103,6 +103,7 @@ local_tests = [
     "LOCAL-CONV-AUTH-INFO",
     "LOCAL-IDMAP-TDB-COMMON",
     "LOCAL-MESSAGING-READ1",
+    "LOCAL-MESSAGING-READ2",
     "LOCAL-hex_encode_buf",
     "LOCAL-sprintf_append",
     "LOCAL-remove_duplicate_addrs2"]
diff --git a/source3/torture/proto.h b/source3/torture/proto.h
index f23efa1..a737ea4 100644
--- a/source3/torture/proto.h
+++ b/source3/torture/proto.h
@@ -114,5 +114,6 @@ bool run_local_dbwrap_ctdb(int dummy);
 bool run_qpathinfo_bufsize(int dummy);
 bool run_bench_pthreadpool(int dummy);
 bool run_messaging_read1(int dummy);
+bool run_messaging_read2(int dummy);
 
 #endif /* __TORTURE_H__ */
diff --git a/source3/torture/test_messaging_read.c b/source3/torture/test_messaging_read.c
index 6c8cdba..387ebfd 100644
--- a/source3/torture/test_messaging_read.c
+++ b/source3/torture/test_messaging_read.c
@@ -142,3 +142,106 @@ fail:
 	TALLOC_FREE(ev);
 	return retval;
 }
+
+struct msg_free_state {
+	struct tevent_req **to_free;
+};
+
+static void msg_free_done(struct tevent_req *subreq);
+
+static struct tevent_req *msg_free_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct messaging_context *msg_ctx,
+					uint32_t msg_type,
+					struct tevent_req **to_free)
+{
+	struct tevent_req *req, *subreq;
+	struct msg_free_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct msg_free_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->to_free = to_free;
+
+	subreq = messaging_read_send(state, ev, msg_ctx, msg_type);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, msg_free_done, req);
+	return req;
+}
+
+static void msg_free_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct msg_free_state *state = tevent_req_data(
+		req, struct msg_free_state);
+	int ret;
+
+	ret = messaging_read_recv(subreq, NULL, NULL);
+	TALLOC_FREE(subreq);
+	if (tevent_req_error(req, ret)) {
+		return;
+	}
+	TALLOC_FREE(*state->to_free);
+	tevent_req_done(req);
+}
+
+bool run_messaging_read2(int dummy)
+{
+	struct tevent_context *ev = NULL;
+	struct messaging_context *msg_ctx = NULL;
+	struct tevent_req *req1 = NULL;
+	struct tevent_req *req2 = NULL;
+	unsigned count = 0;
+	NTSTATUS status;
+	bool retval = false;
+
+	ev = samba_tevent_context_init(talloc_tos());
+	if (ev == NULL) {
+		fprintf(stderr, "tevent_context_init failed\n");
+		goto fail;
+	}
+	msg_ctx = messaging_init(ev, ev);
+	if (msg_ctx == NULL) {
+		fprintf(stderr, "messaging_init failed\n");
+		goto fail;
+	}
+
+	req1 = msg_free_send(ev, ev, msg_ctx, MSG_SMB_NOTIFY, &req2);
+	if (req1 == NULL) {
+		fprintf(stderr, "msg_count_send failed\n");
+		goto fail;
+	}
+	req2 = msg_count_send(ev, ev, msg_ctx, MSG_SMB_NOTIFY, &count);
+	if (req1 == NULL) {
+		fprintf(stderr, "msg_count_send failed\n");
+		goto fail;
+	}
+	status = messaging_send_buf(msg_ctx, messaging_server_id(msg_ctx),
+				    MSG_SMB_NOTIFY, NULL, 0);
+	if (!NT_STATUS_IS_OK(status)) {
+		fprintf(stderr, "messaging_send_buf failed: %s\n",
+			nt_errstr(status));
+		goto fail;
+	}
+
+	if (!tevent_req_poll(req1, ev) != 0) {
+		fprintf(stderr, "tevent_req_poll failed\n");
+		goto fail;
+	}
+
+	if (count != 0) {
+		fprintf(stderr, "Got %u msgs, expected none\n", count);
+		goto fail;
+	}
+
+	retval = true;
+fail:
+	TALLOC_FREE(req1);
+	TALLOC_FREE(msg_ctx);
+	TALLOC_FREE(ev);
+	return retval;
+}
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 5d75bbf..f97119a 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -9575,6 +9575,7 @@ static struct {
 	{ "LOCAL-CTDB-CONN", run_ctdb_conn, 0},
 	{ "LOCAL-DBWRAP-WATCH1", run_dbwrap_watch1, 0 },
 	{ "LOCAL-MESSAGING-READ1", run_messaging_read1, 0 },
+	{ "LOCAL-MESSAGING-READ2", run_messaging_read2, 0 },
 	{ "LOCAL-BASE64", run_local_base64, 0},
 	{ "LOCAL-RBTREE", run_local_rbtree, 0},
 	{ "LOCAL-MEMCACHE", run_local_memcache, 0},
-- 
1.9.1



More information about the samba-technical mailing list