The Samba-Bugzilla – Attachment 13778 Details for
Bug 13130
smbd on disk file corruption bug under heavy threaded load.
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
tevent-0.9.34 for v4-6-test
tmp46.diff.txt (text/plain), 60.68 KB, created by
Stefan Metzmacher
on 2017-11-13 22:32:09 UTC
(
hide
)
Description:
tevent-0.9.34 for v4-6-test
Filename:
MIME Type:
Creator:
Stefan Metzmacher
Created:
2017-11-13 22:32:09 UTC
Size:
60.68 KB
patch
obsolete
>From a7155733a91e8c87c059b221a68bbc48d6a20be6 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Mon, 13 Nov 2017 23:29:42 +0100 >Subject: [PATCH 01/17] Revert "tevent: Fix a race condition" > >This reverts commit 6a43b1b17902c8fbc319e13f31f6c9177f38371c. > >This will reapplied shortly in the correct order relative to >other backports. > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >--- > lib/tevent/tevent_threads.c | 5 ++--- > 1 file changed, 2 insertions(+), 3 deletions(-) > >diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c >index 197ad1d..8197323 100644 >--- a/lib/tevent/tevent_threads.c >+++ b/lib/tevent/tevent_threads.c >@@ -434,7 +434,7 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx, > { > #ifdef HAVE_PTHREAD > struct tevent_context *ev; >- int ret, wakeup_fd; >+ int ret; > > ret = pthread_mutex_lock(&tctx->event_ctx_mutex); > if (ret != 0) { >@@ -442,7 +442,6 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx, > } > > ev = tctx->event_ctx; >- wakeup_fd = tctx->wakeup_fd; > > ret = pthread_mutex_unlock(&tctx->event_ctx_mutex); > if (ret != 0) { >@@ -490,7 +489,7 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx, > * than a noncontended one. So I'd opt for the lower footprint > * initially. Maybe we have to change that later. > */ >- tevent_common_wakeup_fd(wakeup_fd); >+ tevent_common_wakeup_fd(tctx->wakeup_fd); > #else > /* > * tevent_threaded_context_create() returned NULL with ENOSYS... >-- >1.9.1 > > >From 5dddf32ab79151c26a9e95aff13b1cae8f482815 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Mon, 5 Jun 2017 07:23:27 +0200 >Subject: [PATCH 02/17] tevent: Fix a typo > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >(cherry picked from commit b03475048a49db78422d1bfc11f2c69d56fbf87f) >--- > lib/tevent/tevent.h | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h >index ba4bb4d..728cf62 100644 >--- a/lib/tevent/tevent.h >+++ b/lib/tevent/tevent.h >@@ -1777,7 +1777,7 @@ void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp, > * > * It is the duty of the caller of tevent_threaded_context_create() to > * keep the event context around longer than any >- * tevent_threaded_context. tevent will abort if ev is talllc_free'ed >+ * tevent_threaded_context. tevent will abort if ev is talloc_free'ed > * with an active tevent_threaded_context. > * > * If tevent is build without pthread support, this always returns >-- >1.9.1 > > >From c7199c771bcd17cafc2f28fd728c3ba9bb5e4a9f Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Mon, 5 Jun 2017 06:58:37 +0200 >Subject: [PATCH 03/17] tevent: Factor out context initialization > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >(cherry picked from commit 97d912d99afb115e17f683a55aef447dc92ced49) >--- > lib/tevent/tevent.c | 59 ++++++++++++++++++++++++++++++----------------------- > 1 file changed, 34 insertions(+), 25 deletions(-) > >diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c >index 65b101f..68b9db6 100644 >--- a/lib/tevent/tevent.c >+++ b/lib/tevent/tevent.c >@@ -392,46 +392,26 @@ int tevent_common_context_destructor(struct tevent_context *ev) > return 0; > } > >-/* >- create a event_context structure for a specific implemementation. >- This must be the first events call, and all subsequent calls pass >- this event_context as the first element. Event handlers also >- receive this as their first argument. >- >- This function is for allowing third-party-applications to hook in gluecode >- to their own event loop code, so that they can make async usage of our client libs >- >- NOTE: use tevent_context_init() inside of samba! >-*/ >-struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx, >- const struct tevent_ops *ops, >- void *additional_data) >+static int tevent_common_context_constructor(struct tevent_context *ev) > { >- struct tevent_context *ev; > int ret; > >- ev = talloc_zero(mem_ctx, struct tevent_context); >- if (!ev) return NULL; >- > #ifdef HAVE_PTHREAD > > ret = pthread_once(&tevent_atfork_initialized, tevent_prep_atfork); > if (ret != 0) { >- talloc_free(ev); >- return NULL; >+ return ret; > } > > ret = pthread_mutex_init(&ev->scheduled_mutex, NULL); > if (ret != 0) { >- talloc_free(ev); >- return NULL; >+ return ret; > } > > ret = pthread_mutex_lock(&tevent_contexts_mutex); > if (ret != 0) { > pthread_mutex_destroy(&ev->scheduled_mutex); >- talloc_free(ev); >- return NULL; >+ return ret; > } > > DLIST_ADD(tevent_contexts, ev); >@@ -440,11 +420,40 @@ struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx, > if (ret != 0) { > abort(); > } >- > #endif > > talloc_set_destructor(ev, tevent_common_context_destructor); > >+ return 0; >+} >+ >+/* >+ create a event_context structure for a specific implemementation. >+ This must be the first events call, and all subsequent calls pass >+ this event_context as the first element. Event handlers also >+ receive this as their first argument. >+ >+ This function is for allowing third-party-applications to hook in gluecode >+ to their own event loop code, so that they can make async usage of our client libs >+ >+ NOTE: use tevent_context_init() inside of samba! >+*/ >+struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx, >+ const struct tevent_ops *ops, >+ void *additional_data) >+{ >+ struct tevent_context *ev; >+ int ret; >+ >+ ev = talloc_zero(mem_ctx, struct tevent_context); >+ if (!ev) return NULL; >+ >+ ret = tevent_common_context_constructor(ev); >+ if (ret != 0) { >+ talloc_free(ev); >+ return NULL; >+ } >+ > ev->ops = ops; > ev->additional_data = additional_data; > >-- >1.9.1 > > >From 9d20d1bdfb7bd1fead310176147056a2b57b5734 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Mon, 5 Jun 2017 07:16:17 +0200 >Subject: [PATCH 04/17] tevent: Re-init threading in tevent_re_initialise > >Without this threading is not usable after that call > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >(cherry picked from commit afe026d3030c0c05a31de872dd0d120511ba6652) >--- > lib/tevent/tevent.c | 2 ++ > 1 file changed, 2 insertions(+) > >diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c >index 68b9db6..7d59c8b 100644 >--- a/lib/tevent/tevent.c >+++ b/lib/tevent/tevent.c >@@ -884,6 +884,8 @@ int tevent_re_initialise(struct tevent_context *ev) > { > tevent_common_context_destructor(ev); > >+ tevent_common_context_constructor(ev); >+ > return ev->ops->context_init(ev); > } > >-- >1.9.1 > > >From 5115e8e1166c79c822cb49a8fdf456c7a8f4c285 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Mon, 5 Jun 2017 07:29:11 +0200 >Subject: [PATCH 05/17] tevent: Add tevent_re_initialise to threaded test > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >(cherry picked from commit ca715762418284a1a2acc81d40e9e429e407ce14) >--- > lib/tevent/testsuite.c | 8 ++++++++ > 1 file changed, 8 insertions(+) > >diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c >index 4783ab4..ee29e5b 100644 >--- a/lib/tevent/testsuite.c >+++ b/lib/tevent/testsuite.c >@@ -1207,6 +1207,14 @@ static bool test_multi_tevent_threaded_2(struct torture_context *test, > ev = tevent_context_init(test); > torture_assert(test, ev != NULL, "tevent_context_init failed"); > >+ /* >+ * tevent_re_initialise used to have a bug where it did not >+ * re-initialise the thread support after taking it >+ * down. Excercise that code path. >+ */ >+ ret = tevent_re_initialise(ev); >+ torture_assert(test, ret == 0, "tevent_re_initialise failed"); >+ > tctx = tevent_threaded_context_create(ev, ev); > torture_assert(test, tctx != NULL, > "tevent_threaded_context_create failed"); >-- >1.9.1 > > >From 2f514e47b2faa8f1c985bf7d68509cd790b1b2b7 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Wed, 24 May 2017 16:21:40 +0200 >Subject: [PATCH 06/17] tevent: Fix a memleak on FreeBSD > >FreeBSD has malloc'ed memory attached to mutexes. We need to clean this up. > >valgrind really helped here > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >(cherry picked from commit 00390ae27b6bd207add571d7975c37951e15a3e5) >--- > lib/tevent/tevent.c | 5 +++++ > 1 file changed, 5 insertions(+) > >diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c >index 7d59c8b..f3b18a1 100644 >--- a/lib/tevent/tevent.c >+++ b/lib/tevent/tevent.c >@@ -341,6 +341,11 @@ int tevent_common_context_destructor(struct tevent_context *ev) > > DLIST_REMOVE(ev->threaded_contexts, tctx); > } >+ >+ ret = pthread_mutex_destroy(&ev->scheduled_mutex); >+ if (ret != 0) { >+ abort(); >+ } > #endif > > tevent_common_wakeup_fini(ev); >-- >1.9.1 > > >From 9413f1c266b3b2286f25419bc799a6fd45822740 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Wed, 24 May 2017 16:22:34 +0200 >Subject: [PATCH 07/17] tevent: Fix a race condition in tevent context rundown > >We protect setting tctx->event_ctx=NULL with tctx->event_ctx_mutex. >But in _tevent_threaded_schedule_immediate we have the classic >TOCTOU race: After we checked "ev==NULL", looking at >tevent_common_context_destructor the event context can go after >_tevent_threaded_schedule_immediate checked. We need to serialize >things a bit by keeping tctx->event_ctx_mutex locked while we >reference "ev", in particular in the > >DLIST_ADD_END(ev->scheduled_immediates,im); > >I think the locking hierarchy is still maintained, tevent_atfork_prepare() >first locks all the tctx locks, and then the scheduled_mutex. Also, >I don't think this will impact parallelism too badly: event_ctx_mutex >is only used to protect setting tctx->ev. > >Found by staring at code while fixing the FreeBSD memleak due to >not destroying scheduled_mutex. > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> > >Autobuild-User(master): Jeremy Allison <jra@samba.org> >Autobuild-Date(master): Fri Jun 9 00:45:26 CEST 2017 on sn-devel-144 > >(cherry picked from commit 1828011317b0a8142c3b66fff22661a962760574) >--- > lib/tevent/tevent_threads.c | 14 +++++++++----- > 1 file changed, 9 insertions(+), 5 deletions(-) > >diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c >index 8197323..8ecda02 100644 >--- a/lib/tevent/tevent_threads.c >+++ b/lib/tevent/tevent_threads.c >@@ -443,15 +443,14 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx, > > ev = tctx->event_ctx; > >- ret = pthread_mutex_unlock(&tctx->event_ctx_mutex); >- if (ret != 0) { >- abort(); >- } >- > if (ev == NULL) { > /* > * Our event context is already gone. > */ >+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex); >+ if (ret != 0) { >+ abort(); >+ } > return; > } > >@@ -479,6 +478,11 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx, > abort(); > } > >+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex); >+ if (ret != 0) { >+ abort(); >+ } >+ > /* > * We might want to wake up the main thread under the lock. We > * had a slightly similar situation in pthreadpool, changed >-- >1.9.1 > > >From 07c3cb6ffde658f0c2b3cca891b7bd06e35b88e3 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Thu, 15 Jun 2017 11:48:24 +0200 >Subject: [PATCH 08/17] tevent_threads: Fix a rundown race introduced with > 1828011317b > >The race is easily reproduced by adding a poll(NULL,0,10) in between the two >pthread_mutex_unlock calls in _tevent_threaded_schedule_immediate. > >Before 1828011317b, the main thread was signalled only after the helper >had already unlocked event_ctx_mutex. > >Full explaination follows: >----------------------------------------------------------------- >Inside _tevent_threaded_schedule_immediate() we have: > >476 ret = pthread_mutex_unlock(&ev->scheduled_mutex); >477 if (ret != 0) { >478 abort(); >479 } > >HERE!!!! > >481 ret = pthread_mutex_unlock(&tctx->event_ctx_mutex); >482 if (ret != 0) { >483 abort(); >484 } > >At the HERE!!! point, what happens is tevent_common_threaded_activate_immediate(), >which is blocked on ev->scheduled_mutex, get released and does: > >514 while (ev->scheduled_immediates != NULL) { >515 struct tevent_immediate *im = ev->scheduled_immediates; >516 DLIST_REMOVE(ev->scheduled_immediates, im); >517 DLIST_ADD_END(ev->immediate_events, im); >518 } > >- making an immediate event ready to be scheduled. > >This then returns into epoll_event_loop_once(), which then calls: > >910 if (ev->immediate_events && >911 tevent_common_loop_immediate(ev)) { >912 return 0; >913 } > >which causes the immediate event to fire. This immediate >event is the pthread job terminate event, which was previously >set up in pthreadpool_tevent_job_signal() by: > >198 if (state->tctx != NULL) { >199 /* with HAVE_PTHREAD */ >200 tevent_threaded_schedule_immediate(state->tctx, state->im, >201 pthreadpool_tevent_job_done, >202 state); > >So we now call pthreadpool_tevent_job_done() - which does: > >225 TALLOC_FREE(state->tctx); > >calling tevent_threaded_context_destructor(): > >384 ret = pthread_mutex_destroy(&tctx->event_ctx_mutex); <---------------- BOOM returns an error ! >385 if (ret != 0) { >386 abort(); >387 } > >as we haven't gotten to line 481 above (the line after >HERE!!!!) so the tctx->event_ctx_mutex is still >locked when we try to destroy it. > >So doing an additional: > > ret = pthread_mutex_lock(&tctx->event_ctx_mutex); > ret = pthread_mutex_unlock(&tctx->event_ctx_mutex); > >(error checking elided) forces tevent_threaded_context_destructor() >to wait until tctx->event_ctx_mutex is unlocked before it locks/unlocks >and then is guaranteed safe to destroy. > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Stefan Metzmacher <metze@samba.org> >(cherry picked from commit 1fe7ec237a7036d76764ef1981de6b3000b2cfd3) >--- > lib/tevent/tevent_threads.c | 17 +++++++++++++++++ > 1 file changed, 17 insertions(+) > >diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c >index 8ecda02..4d1a880 100644 >--- a/lib/tevent/tevent_threads.c >+++ b/lib/tevent/tevent_threads.c >@@ -381,6 +381,23 @@ static int tevent_threaded_context_destructor( > DLIST_REMOVE(tctx->event_ctx->threaded_contexts, tctx); > } > >+ /* >+ * We have to coordinate with _tevent_threaded_schedule_immediate's >+ * unlock of the event_ctx_mutex. We're in the main thread here, >+ * and we can be scheduled before the helper thread finalizes its >+ * call _tevent_threaded_schedule_immediate. This means we would >+ * pthreadpool_destroy a locked mutex, which is illegal. >+ */ >+ ret = pthread_mutex_lock(&tctx->event_ctx_mutex); >+ if (ret != 0) { >+ abort(); >+ } >+ >+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex); >+ if (ret != 0) { >+ abort(); >+ } >+ > ret = pthread_mutex_destroy(&tctx->event_ctx_mutex); > if (ret != 0) { > abort(); >-- >1.9.1 > > >From 60ff7995dabb20dce32c534334326c376d479fd0 Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Sat, 17 Jun 2017 21:26:27 +0200 >Subject: [PATCH 09/17] tevent: Simplify create_immediate > >Not much change, just 9 lines less of code. > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> >(cherry picked from commit a7504f555eff101a10ded653ceac98d8294c1659) >--- > lib/tevent/tevent.c | 11 +---------- > 1 file changed, 1 insertion(+), 10 deletions(-) > >diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c >index f3b18a1..5f44b03 100644 >--- a/lib/tevent/tevent.c >+++ b/lib/tevent/tevent.c >@@ -616,16 +616,7 @@ struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx, > im = talloc(mem_ctx, struct tevent_immediate); > if (im == NULL) return NULL; > >- im->prev = NULL; >- im->next = NULL; >- im->event_ctx = NULL; >- im->create_location = location; >- im->handler = NULL; >- im->private_data = NULL; >- im->handler_name = NULL; >- im->schedule_location = NULL; >- im->cancel_fn = NULL; >- im->additional_data = NULL; >+ *im = (struct tevent_immediate) { .create_location = location }; > > return im; > } >-- >1.9.1 > > >From 7f41adaf822b4b2fe597f0d4ad6d97ab10f12dd7 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Wed, 14 Jun 2017 16:59:10 +0200 >Subject: [PATCH 10/17] tevent: include the finish location in > tevent_req_default_print() > >It's verify useful when debugging code without a debugger to >be able to use tevent_req_print() in DEBUG statements. > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Volker Lendecke <vl@samba.org> >(cherry picked from commit d7f649b7044a5579d321cc1cfa7893a8221f6412) >--- > lib/tevent/tevent_req.c | 5 +++-- > 1 file changed, 3 insertions(+), 2 deletions(-) > >diff --git a/lib/tevent/tevent_req.c b/lib/tevent/tevent_req.c >index e309c3d..22f7a4f 100644 >--- a/lib/tevent/tevent_req.c >+++ b/lib/tevent/tevent_req.c >@@ -31,14 +31,15 @@ char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx) > { > return talloc_asprintf(mem_ctx, > "tevent_req[%p/%s]: state[%d] error[%lld (0x%llX)] " >- " state[%s (%p)] timer[%p]", >+ " state[%s (%p)] timer[%p] finish[%s]", > req, req->internal.create_location, > req->internal.state, > (unsigned long long)req->internal.error, > (unsigned long long)req->internal.error, > talloc_get_name(req->data), > req->data, >- req->internal.timer >+ req->internal.timer, >+ req->internal.finish_location > ); > } > >-- >1.9.1 > > >From dc09cdf7bca87e9ac8e6d4850a80e104e528fcc2 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Tue, 20 Jun 2017 12:17:32 +0200 >Subject: [PATCH 11/17] tevent: version 0.9.32 > >* Fix mutex locking in tevent_threaded_context_destructor(). >* Fix a memleak on FreeBSD. >* Re-init threading in tevent_re_initialise(). >* Include the finish location in tevent_req_default_print(). > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Volker Lendecke <vl@samba.org> > >Autobuild-User(master): Stefan Metzmacher <metze@samba.org> >Autobuild-Date(master): Thu Jun 22 17:17:33 CEST 2017 on sn-devel-144 > >(cherry picked from commit e9b4978a764839a142d9f7c166db436bdabea82c) >--- > lib/tevent/ABI/tevent-0.9.32.sigs | 99 +++++++++++++++++++++++++++++++++++++++ > lib/tevent/wscript | 2 +- > 2 files changed, 100 insertions(+), 1 deletion(-) > create mode 100644 lib/tevent/ABI/tevent-0.9.32.sigs > >diff --git a/lib/tevent/ABI/tevent-0.9.32.sigs b/lib/tevent/ABI/tevent-0.9.32.sigs >new file mode 100644 >index 0000000..7a6a236 >--- /dev/null >+++ b/lib/tevent/ABI/tevent-0.9.32.sigs >@@ -0,0 +1,99 @@ >+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *) >+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *) >+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *) >+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *) >+_tevent_loop_once: int (struct tevent_context *, const char *) >+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *) >+_tevent_loop_wait: int (struct tevent_context *, const char *) >+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *) >+_tevent_req_callback_data: void *(struct tevent_req *) >+_tevent_req_cancel: bool (struct tevent_req *, const char *) >+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *) >+_tevent_req_data: void *(struct tevent_req *) >+_tevent_req_done: void (struct tevent_req *, const char *) >+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *) >+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *) >+_tevent_req_notify_callback: void (struct tevent_req *, const char *) >+_tevent_req_oom: void (struct tevent_req *, const char *) >+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *) >+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *) >+tevent_backend_list: const char **(TALLOC_CTX *) >+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *) >+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *) >+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *) >+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *) >+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *) >+tevent_common_check_signal: int (struct tevent_context *) >+tevent_common_context_destructor: int (struct tevent_context *) >+tevent_common_fd_destructor: int (struct tevent_fd *) >+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *) >+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t) >+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t) >+tevent_common_have_events: bool (struct tevent_context *) >+tevent_common_loop_immediate: bool (struct tevent_context *) >+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *) >+tevent_common_loop_wait: int (struct tevent_context *, const char *) >+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *) >+tevent_common_threaded_activate_immediate: void (struct tevent_context *) >+tevent_common_wakeup: int (struct tevent_context *) >+tevent_common_wakeup_fd: int (int) >+tevent_common_wakeup_init: int (struct tevent_context *) >+tevent_context_init: struct tevent_context *(TALLOC_CTX *) >+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *) >+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *) >+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...) >+tevent_fd_get_flags: uint16_t (struct tevent_fd *) >+tevent_fd_set_auto_close: void (struct tevent_fd *) >+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t) >+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t) >+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *) >+tevent_loop_allow_nesting: void (struct tevent_context *) >+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *) >+tevent_num_signals: size_t (void) >+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *) >+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *) >+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *) >+tevent_queue_length: size_t (struct tevent_queue *) >+tevent_queue_running: bool (struct tevent_queue *) >+tevent_queue_start: void (struct tevent_queue *) >+tevent_queue_stop: void (struct tevent_queue *) >+tevent_queue_wait_recv: bool (struct tevent_req *) >+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *) >+tevent_re_initialise: int (struct tevent_context *) >+tevent_register_backend: bool (const char *, const struct tevent_ops *) >+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *) >+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *) >+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *) >+tevent_req_is_in_progress: bool (struct tevent_req *) >+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *) >+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *) >+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *) >+tevent_req_received: void (struct tevent_req *) >+tevent_req_reset_endtime: void (struct tevent_req *) >+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *) >+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn) >+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn) >+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval) >+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn) >+tevent_sa_info_queue_count: size_t (void) >+tevent_set_abort_fn: void (void (*)(const char *)) >+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *) >+tevent_set_debug_stderr: int (struct tevent_context *) >+tevent_set_default_backend: void (const char *) >+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *) >+tevent_signal_support: bool (struct tevent_context *) >+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *) >+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *) >+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *) >+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t) >+tevent_timeval_compare: int (const struct timeval *, const struct timeval *) >+tevent_timeval_current: struct timeval (void) >+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t) >+tevent_timeval_is_zero: bool (const struct timeval *) >+tevent_timeval_set: struct timeval (uint32_t, uint32_t) >+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *) >+tevent_timeval_zero: struct timeval (void) >+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point) >+tevent_update_timer: void (struct tevent_timer *, struct timeval) >+tevent_wakeup_recv: bool (struct tevent_req *) >+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval) >diff --git a/lib/tevent/wscript b/lib/tevent/wscript >index 580ca4d..2ac9518 100755 >--- a/lib/tevent/wscript >+++ b/lib/tevent/wscript >@@ -1,7 +1,7 @@ > #!/usr/bin/env python > > APPNAME = 'tevent' >-VERSION = '0.9.31' >+VERSION = '0.9.32' > > blddir = 'bin' > >-- >1.9.1 > > >From 2c3314e66a39bf338221f7a4818b47973c01a02b Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Thu, 20 Jul 2017 14:16:44 +0200 >Subject: [PATCH 12/17] tevent: avoid calling talloc_get_name(NULL) in > tevent_req_default_print() > >We have the same information available under req->internal.private_type. > >This way it's possible to call tevent_req_print() after >tevent_req_received() was called. > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andreas Schneider <asn@samba.org> >(cherry picked from commit 21b56ffd983cc0b982bea55866bfa84c79133503) >(cherry picked from commit 3d87c0660eba61ac4b02e43798aa82ee9e64b454) >--- > lib/tevent/tevent_req.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/lib/tevent/tevent_req.c b/lib/tevent/tevent_req.c >index 22f7a4f..155746e 100644 >--- a/lib/tevent/tevent_req.c >+++ b/lib/tevent/tevent_req.c >@@ -36,7 +36,7 @@ char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx) > req->internal.state, > (unsigned long long)req->internal.error, > (unsigned long long)req->internal.error, >- talloc_get_name(req->data), >+ req->internal.private_type, > req->data, > req->internal.timer, > req->internal.finish_location >-- >1.9.1 > > >From 1dfafd6959bb914f201f2052a8ada8f1b0d92798 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Thu, 20 Jul 2017 14:20:03 +0200 >Subject: [PATCH 13/17] tevent: handle passing req = NULL to tevent_req_print() > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andreas Schneider <asn@samba.org> >(cherry picked from commit ca3e98488a45aa143e4ba454b4ba8763f09a6f50) >(cherry picked from commit ce417f5ceec42a70ab651bc3a0dc2ab29cb7efd2) >--- > lib/tevent/tevent_req.c | 4 ++++ > 1 file changed, 4 insertions(+) > >diff --git a/lib/tevent/tevent_req.c b/lib/tevent/tevent_req.c >index 155746e..15754d3 100644 >--- a/lib/tevent/tevent_req.c >+++ b/lib/tevent/tevent_req.c >@@ -45,6 +45,10 @@ char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx) > > char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req) > { >+ if (req == NULL) { >+ return talloc_strdup(mem_ctx, "tevent_req[NULL]"); >+ } >+ > if (!req->private_print) { > return tevent_req_default_print(req, mem_ctx); > } >-- >1.9.1 > > >From 609c293fbdb6aa0da72b94e392b7d6c40e011df0 Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Fri, 21 Jul 2017 14:34:59 +0200 >Subject: [PATCH 14/17] tevent: version 0.9.33 > >* make tevent_req_print() more robust against crashes > >Signed-off-by: Stefan Metzmacher <metze@samba.org> >Reviewed-by: Andreas Schneider <asn@samba.org> >(cherry picked from commit 7ad3a99d462e4a43c9f64b0877111d5e58f56e6e) > >Autobuild-User(v4-7-test): Stefan Metzmacher <metze@samba.org> >Autobuild-Date(v4-7-test): Sun Jul 23 14:41:25 CEST 2017 on sn-devel-144 > >(cherry picked from commit 892c3aaeb683f2ed51a60ac49fc2c2ea4dede6e8) >--- > lib/tevent/ABI/tevent-0.9.33.sigs | 99 +++++++++++++++++++++++++++++++++++++++ > lib/tevent/wscript | 2 +- > 2 files changed, 100 insertions(+), 1 deletion(-) > create mode 100644 lib/tevent/ABI/tevent-0.9.33.sigs > >diff --git a/lib/tevent/ABI/tevent-0.9.33.sigs b/lib/tevent/ABI/tevent-0.9.33.sigs >new file mode 100644 >index 0000000..7a6a236 >--- /dev/null >+++ b/lib/tevent/ABI/tevent-0.9.33.sigs >@@ -0,0 +1,99 @@ >+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *) >+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *) >+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *) >+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *) >+_tevent_loop_once: int (struct tevent_context *, const char *) >+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *) >+_tevent_loop_wait: int (struct tevent_context *, const char *) >+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *) >+_tevent_req_callback_data: void *(struct tevent_req *) >+_tevent_req_cancel: bool (struct tevent_req *, const char *) >+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *) >+_tevent_req_data: void *(struct tevent_req *) >+_tevent_req_done: void (struct tevent_req *, const char *) >+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *) >+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *) >+_tevent_req_notify_callback: void (struct tevent_req *, const char *) >+_tevent_req_oom: void (struct tevent_req *, const char *) >+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *) >+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *) >+tevent_backend_list: const char **(TALLOC_CTX *) >+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *) >+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *) >+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *) >+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *) >+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *) >+tevent_common_check_signal: int (struct tevent_context *) >+tevent_common_context_destructor: int (struct tevent_context *) >+tevent_common_fd_destructor: int (struct tevent_fd *) >+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *) >+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t) >+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t) >+tevent_common_have_events: bool (struct tevent_context *) >+tevent_common_loop_immediate: bool (struct tevent_context *) >+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *) >+tevent_common_loop_wait: int (struct tevent_context *, const char *) >+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *) >+tevent_common_threaded_activate_immediate: void (struct tevent_context *) >+tevent_common_wakeup: int (struct tevent_context *) >+tevent_common_wakeup_fd: int (int) >+tevent_common_wakeup_init: int (struct tevent_context *) >+tevent_context_init: struct tevent_context *(TALLOC_CTX *) >+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *) >+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *) >+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...) >+tevent_fd_get_flags: uint16_t (struct tevent_fd *) >+tevent_fd_set_auto_close: void (struct tevent_fd *) >+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t) >+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t) >+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *) >+tevent_loop_allow_nesting: void (struct tevent_context *) >+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *) >+tevent_num_signals: size_t (void) >+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *) >+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *) >+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *) >+tevent_queue_length: size_t (struct tevent_queue *) >+tevent_queue_running: bool (struct tevent_queue *) >+tevent_queue_start: void (struct tevent_queue *) >+tevent_queue_stop: void (struct tevent_queue *) >+tevent_queue_wait_recv: bool (struct tevent_req *) >+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *) >+tevent_re_initialise: int (struct tevent_context *) >+tevent_register_backend: bool (const char *, const struct tevent_ops *) >+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *) >+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *) >+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *) >+tevent_req_is_in_progress: bool (struct tevent_req *) >+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *) >+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *) >+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *) >+tevent_req_received: void (struct tevent_req *) >+tevent_req_reset_endtime: void (struct tevent_req *) >+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *) >+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn) >+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn) >+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval) >+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn) >+tevent_sa_info_queue_count: size_t (void) >+tevent_set_abort_fn: void (void (*)(const char *)) >+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *) >+tevent_set_debug_stderr: int (struct tevent_context *) >+tevent_set_default_backend: void (const char *) >+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *) >+tevent_signal_support: bool (struct tevent_context *) >+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *) >+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *) >+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *) >+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t) >+tevent_timeval_compare: int (const struct timeval *, const struct timeval *) >+tevent_timeval_current: struct timeval (void) >+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t) >+tevent_timeval_is_zero: bool (const struct timeval *) >+tevent_timeval_set: struct timeval (uint32_t, uint32_t) >+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *) >+tevent_timeval_zero: struct timeval (void) >+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point) >+tevent_update_timer: void (struct tevent_timer *, struct timeval) >+tevent_wakeup_recv: bool (struct tevent_req *) >+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval) >diff --git a/lib/tevent/wscript b/lib/tevent/wscript >index 2ac9518..c1c72b4 100755 >--- a/lib/tevent/wscript >+++ b/lib/tevent/wscript >@@ -1,7 +1,7 @@ > #!/usr/bin/env python > > APPNAME = 'tevent' >-VERSION = '0.9.32' >+VERSION = '0.9.33' > > blddir = 'bin' > >-- >1.9.1 > > >From 1b2e88cf958a5547d90552534b5a21e0cfa6c9cd Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Tue, 12 Sep 2017 12:08:38 -0700 >Subject: [PATCH 15/17] lib: tevent: Remove select backend. > >select() is no longer useful on modern systems. > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Volker Lendecke <vl@samba.org> > >Autobuild-User(master): Volker Lendecke <vl@samba.org> >Autobuild-Date(master): Sat Sep 16 08:35:39 CEST 2017 on sn-devel-144 > >(cherry picked from commit 2a003b1a576dcbbba0d60bae90427776a5c27867) >--- > lib/tevent/tevent.c | 1 - > lib/tevent/tevent_internal.h | 1 - > lib/tevent/tevent_select.c | 280 ------------------------------------------- > lib/tevent/wscript | 2 +- > source3/selftest/tests.py | 2 +- > source3/torture/torture.c | 10 +- > 6 files changed, 7 insertions(+), 289 deletions(-) > delete mode 100644 lib/tevent/tevent_select.c > >diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c >index 5f44b03..a2d2003 100644 >--- a/lib/tevent/tevent.c >+++ b/lib/tevent/tevent.c >@@ -128,7 +128,6 @@ static void tevent_backend_init(void) > > done = true; > >- tevent_select_init(); > tevent_poll_init(); > tevent_poll_mt_init(); > #if defined(HAVE_EPOLL) >diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h >index a5f1ebde..47ea39b 100644 >--- a/lib/tevent/tevent_internal.h >+++ b/lib/tevent/tevent_internal.h >@@ -377,7 +377,6 @@ int tevent_common_check_signal(struct tevent_context *ev); > void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se); > > bool tevent_standard_init(void); >-bool tevent_select_init(void); > bool tevent_poll_init(void); > void tevent_poll_event_add_fd_internal(struct tevent_context *ev, > struct tevent_fd *fde); >diff --git a/lib/tevent/tevent_select.c b/lib/tevent/tevent_select.c >deleted file mode 100644 >index 55dd0b6..0000000 >--- a/lib/tevent/tevent_select.c >+++ /dev/null >@@ -1,280 +0,0 @@ >-/* >- Unix SMB/CIFS implementation. >- main select loop and event handling >- Copyright (C) Andrew Tridgell 2003-2005 >- Copyright (C) Stefan Metzmacher 2005-2009 >- >- ** NOTE! The following LGPL license applies to the tevent >- ** library. This does NOT imply that all of Samba is released >- ** under the LGPL >- >- This library is free software; you can redistribute it and/or >- modify it under the terms of the GNU Lesser General Public >- License as published by the Free Software Foundation; either >- version 3 of the License, or (at your option) any later version. >- >- This library 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 >- Lesser General Public License for more details. >- >- You should have received a copy of the GNU Lesser General Public >- License along with this library; if not, see <http://www.gnu.org/licenses/>. >-*/ >- >-#include "replace.h" >-#include "system/filesys.h" >-#include "system/select.h" >-#include "tevent.h" >-#include "tevent_util.h" >-#include "tevent_internal.h" >- >-struct select_event_context { >- /* a pointer back to the generic event_context */ >- struct tevent_context *ev; >- >- /* the maximum file descriptor number in fd_events */ >- int maxfd; >-}; >- >-/* >- create a select_event_context structure. >-*/ >-static int select_event_context_init(struct tevent_context *ev) >-{ >- struct select_event_context *select_ev; >- >- /* >- * We might be called during tevent_re_initialise() >- * which means we need to free our old additional_data. >- */ >- TALLOC_FREE(ev->additional_data); >- >- select_ev = talloc_zero(ev, struct select_event_context); >- if (!select_ev) return -1; >- select_ev->ev = ev; >- >- ev->additional_data = select_ev; >- return 0; >-} >- >-/* >- recalculate the maxfd >-*/ >-static void calc_maxfd(struct select_event_context *select_ev) >-{ >- struct tevent_fd *fde; >- >- select_ev->maxfd = 0; >- for (fde = select_ev->ev->fd_events; fde; fde = fde->next) { >- if (fde->fd > select_ev->maxfd) { >- select_ev->maxfd = fde->fd; >- } >- } >-} >- >- >-/* to mark the ev->maxfd invalid >- * this means we need to recalculate it >- */ >-#define EVENT_INVALID_MAXFD (-1) >- >-/* >- destroy an fd_event >-*/ >-static int select_event_fd_destructor(struct tevent_fd *fde) >-{ >- struct tevent_context *ev = fde->event_ctx; >- struct select_event_context *select_ev = NULL; >- >- if (ev) { >- select_ev = talloc_get_type_abort(ev->additional_data, >- struct select_event_context); >- >- if (select_ev->maxfd == fde->fd) { >- select_ev->maxfd = EVENT_INVALID_MAXFD; >- } >- } >- >- return tevent_common_fd_destructor(fde); >-} >- >-/* >- add a fd based event >- return NULL on failure (memory allocation error) >-*/ >-static struct tevent_fd *select_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx, >- int fd, uint16_t flags, >- tevent_fd_handler_t handler, >- void *private_data, >- const char *handler_name, >- const char *location) >-{ >- struct select_event_context *select_ev = >- talloc_get_type_abort(ev->additional_data, >- struct select_event_context); >- struct tevent_fd *fde; >- >- if (fd < 0 || fd >= FD_SETSIZE) { >- errno = EBADF; >- return NULL; >- } >- >- fde = tevent_common_add_fd(ev, mem_ctx, fd, flags, >- handler, private_data, >- handler_name, location); >- if (!fde) return NULL; >- >- if ((select_ev->maxfd != EVENT_INVALID_MAXFD) >- && (fde->fd > select_ev->maxfd)) { >- select_ev->maxfd = fde->fd; >- } >- talloc_set_destructor(fde, select_event_fd_destructor); >- >- return fde; >-} >- >-/* >- event loop handling using select() >-*/ >-static int select_event_loop_select(struct select_event_context *select_ev, struct timeval *tvalp) >-{ >- fd_set r_fds, w_fds; >- struct tevent_fd *fde; >- int selrtn; >- int select_errno; >- >- /* we maybe need to recalculate the maxfd */ >- if (select_ev->maxfd == EVENT_INVALID_MAXFD) { >- calc_maxfd(select_ev); >- } >- >- FD_ZERO(&r_fds); >- FD_ZERO(&w_fds); >- >- /* setup any fd events */ >- for (fde = select_ev->ev->fd_events; fde; fde = fde->next) { >- if (fde->fd < 0 || fde->fd >= FD_SETSIZE) { >- tevent_debug(select_ev->ev, TEVENT_DEBUG_FATAL, >- "ERROR: EBADF fd[%d] >= %d " >- "select_event_loop_once\n", >- fde->fd, FD_SETSIZE); >- errno = EBADF; >- return -1; >- } >- >- if (fde->flags & TEVENT_FD_READ) { >- FD_SET(fde->fd, &r_fds); >- } >- if (fde->flags & TEVENT_FD_WRITE) { >- FD_SET(fde->fd, &w_fds); >- } >- } >- >- if (select_ev->ev->signal_events && >- tevent_common_check_signal(select_ev->ev)) { >- return 0; >- } >- >- tevent_trace_point_callback(select_ev->ev, TEVENT_TRACE_BEFORE_WAIT); >- selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp); >- select_errno = errno; >- tevent_trace_point_callback(select_ev->ev, TEVENT_TRACE_AFTER_WAIT); >- >- if (selrtn == -1 && select_errno == EINTR && >- select_ev->ev->signal_events) { >- tevent_common_check_signal(select_ev->ev); >- return 0; >- } >- >- if (selrtn == -1 && select_errno == EBADF) { >- /* the socket is dead! this should never >- happen as the socket should have first been >- made readable and that should have removed >- the event, so this must be a bug. This is a >- fatal error. */ >- tevent_debug(select_ev->ev, TEVENT_DEBUG_FATAL, >- "ERROR: EBADF on select_event_loop_once\n"); >- errno = select_errno; >- return -1; >- } >- >- if (selrtn == 0 && tvalp) { >- /* we don't care about a possible delay here */ >- tevent_common_loop_timer_delay(select_ev->ev); >- return 0; >- } >- >- if (selrtn > 0) { >- /* at least one file descriptor is ready - check >- which ones and call the handler, being careful to allow >- the handler to remove itself when called */ >- for (fde = select_ev->ev->fd_events; fde; fde = fde->next) { >- uint16_t flags = 0; >- >- if (FD_ISSET(fde->fd, &r_fds) && (fde->flags & TEVENT_FD_READ)) { >- flags |= TEVENT_FD_READ; >- } >- if (FD_ISSET(fde->fd, &w_fds) && (fde->flags & TEVENT_FD_WRITE)) { >- flags |= TEVENT_FD_WRITE; >- } >- if (flags) { >- DLIST_DEMOTE(select_ev->ev->fd_events, fde); >- fde->handler(select_ev->ev, fde, flags, fde->private_data); >- break; >- } >- } >- } >- >- return 0; >-} >- >-/* >- do a single event loop using the events defined in ev >-*/ >-static int select_event_loop_once(struct tevent_context *ev, const char *location) >-{ >- struct select_event_context *select_ev = >- talloc_get_type_abort(ev->additional_data, >- struct select_event_context); >- struct timeval tval; >- >- if (ev->signal_events && >- tevent_common_check_signal(ev)) { >- return 0; >- } >- >- if (ev->threaded_contexts != NULL) { >- tevent_common_threaded_activate_immediate(ev); >- } >- >- if (ev->immediate_events && >- tevent_common_loop_immediate(ev)) { >- return 0; >- } >- >- tval = tevent_common_loop_timer_delay(ev); >- if (tevent_timeval_is_zero(&tval)) { >- return 0; >- } >- >- return select_event_loop_select(select_ev, &tval); >-} >- >-static const struct tevent_ops select_event_ops = { >- .context_init = select_event_context_init, >- .add_fd = select_event_add_fd, >- .set_fd_close_fn = tevent_common_fd_set_close_fn, >- .get_fd_flags = tevent_common_fd_get_flags, >- .set_fd_flags = tevent_common_fd_set_flags, >- .add_timer = tevent_common_add_timer_v2, >- .schedule_immediate = tevent_common_schedule_immediate, >- .add_signal = tevent_common_add_signal, >- .loop_once = select_event_loop_once, >- .loop_wait = tevent_common_loop_wait, >-}; >- >-_PRIVATE_ bool tevent_select_init(void) >-{ >- return tevent_register_backend("select", &select_event_ops); >-} >diff --git a/lib/tevent/wscript b/lib/tevent/wscript >index c1c72b4..721c050 100755 >--- a/lib/tevent/wscript >+++ b/lib/tevent/wscript >@@ -82,7 +82,7 @@ def build(bld): > bld.RECURSE('lib/talloc') > > SRC = '''tevent.c tevent_debug.c tevent_fd.c tevent_immediate.c >- tevent_queue.c tevent_req.c tevent_select.c >+ tevent_queue.c tevent_req.c > tevent_poll.c tevent_threads.c > tevent_signal.c tevent_standard.c tevent_timed.c tevent_util.c tevent_wakeup.c''' > >diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py >index b877d47..fbd9a69 100755 >--- a/source3/selftest/tests.py >+++ b/source3/selftest/tests.py >@@ -128,7 +128,7 @@ local_tests = [ > "LOCAL-sid_to_string", > "LOCAL-binary_to_sid", > "LOCAL-DBTRANS", >- "LOCAL-TEVENT-SELECT", >+ "LOCAL-TEVENT-POLL", > "LOCAL-CONVERT-STRING", > "LOCAL-CONV-AUTH-INFO", > "LOCAL-IDMAP-TDB-COMMON", >diff --git a/source3/torture/torture.c b/source3/torture/torture.c >index 60e9247..015ea37 100644 >--- a/source3/torture/torture.c >+++ b/source3/torture/torture.c >@@ -10910,17 +10910,17 @@ static bool run_local_dbtrans(int dummy) > > /* > * Just a dummy test to be run under a debugger. There's no real way >- * to inspect the tevent_select specific function from outside of >- * tevent_select.c. >+ * to inspect the tevent_poll specific function from outside of >+ * tevent_poll.c. > */ > >-static bool run_local_tevent_select(int dummy) >+static bool run_local_tevent_poll(int dummy) > { > struct tevent_context *ev; > struct tevent_fd *fd1, *fd2; > bool result = false; > >- ev = tevent_context_init_byname(NULL, "select"); >+ ev = tevent_context_init_byname(NULL, "poll"); > if (ev == NULL) { > d_fprintf(stderr, "tevent_context_init_byname failed\n"); > goto fail; >@@ -11471,7 +11471,7 @@ static struct { > { "LOCAL-sid_to_string", run_local_sid_to_string, 0}, > { "LOCAL-binary_to_sid", run_local_binary_to_sid, 0}, > { "LOCAL-DBTRANS", run_local_dbtrans, 0}, >- { "LOCAL-TEVENT-SELECT", run_local_tevent_select, 0}, >+ { "LOCAL-TEVENT-POLL", run_local_tevent_poll, 0}, > { "LOCAL-CONVERT-STRING", run_local_convert_string, 0}, > { "LOCAL-CONV-AUTH-INFO", run_local_conv_auth_info, 0}, > { "LOCAL-hex_encode_buf", run_local_hex_encode_buf, 0}, >-- >1.9.1 > > >From f0d71c4c073e8ffdbd579f2f2dd9037df084982f Mon Sep 17 00:00:00 2001 >From: Volker Lendecke <vl@samba.org> >Date: Fri, 10 Nov 2017 21:22:26 +0100 >Subject: [PATCH 16/17] tevent: Fix a race condition > >We can't rely on tctx to exist after we unlocked the mutex. It took a >while, but this does lead to data corruption. If *tctx is replaced with >something where tctx->wakeup_fd points to a real, existing file >descriptor, we're screwed. And by screwed, this means file corruption >on disk. > >Again. I am not tall enough for this business. > >http://bholley.net/blog/2015/must-be-this-tall-to-write-multi-threaded-code.html > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=13130 > >Signed-off-by: Volker Lendecke <vl@samba.org> >Reviewed-by: Jeremy Allison <jra@samba.org> > >Autobuild-User(master): Jeremy Allison <jra@samba.org> >Autobuild-Date(master): Sat Nov 11 03:20:09 CET 2017 on sn-devel-144 > >(cherry picked from commit 20cfcb7dbc5dd099384b76a76e3d35cf627100b6) > >Autobuild-User(v4-7-test): Karolin Seeger <kseeger@samba.org> >Autobuild-Date(v4-7-test): Mon Nov 13 13:54:56 CET 2017 on sn-devel-144 > >(cherry picked from commit 5ec68b2e44e5c0c4e6fae362c7e36ad99124faa8) >--- > lib/tevent/tevent_threads.c | 6 ++++-- > 1 file changed, 4 insertions(+), 2 deletions(-) > >diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c >index 4d1a880..2e83f1b 100644 >--- a/lib/tevent/tevent_threads.c >+++ b/lib/tevent/tevent_threads.c >@@ -451,7 +451,7 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx, > { > #ifdef HAVE_PTHREAD > struct tevent_context *ev; >- int ret; >+ int ret, wakeup_fd; > > ret = pthread_mutex_lock(&tctx->event_ctx_mutex); > if (ret != 0) { >@@ -495,6 +495,8 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx, > abort(); > } > >+ wakeup_fd = tctx->wakeup_fd; >+ > ret = pthread_mutex_unlock(&tctx->event_ctx_mutex); > if (ret != 0) { > abort(); >@@ -510,7 +512,7 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx, > * than a noncontended one. So I'd opt for the lower footprint > * initially. Maybe we have to change that later. > */ >- tevent_common_wakeup_fd(tctx->wakeup_fd); >+ tevent_common_wakeup_fd(wakeup_fd); > #else > /* > * tevent_threaded_context_create() returned NULL with ENOSYS... >-- >1.9.1 > > >From 955596b440f3cb934f9ddf60e3858a7ec703b49e Mon Sep 17 00:00:00 2001 >From: Stefan Metzmacher <metze@samba.org> >Date: Mon, 13 Nov 2017 11:05:04 +0100 >Subject: [PATCH 17/17] tevent: version 0.9.34 > >* Remove unused select backend >* Fix a race condition in tevent_threaded_schedule_immediate() > (bug #13130) > >Signed-off-by: Stefan Metzmacher <metze@samba.org> > >Autobuild-User(master): Stefan Metzmacher <metze@samba.org> >Autobuild-Date(master): Mon Nov 13 18:02:46 CET 2017 on sn-devel-144 > >(cherry picked from commit 2e573eead96b2e98dd8a15c9c8e470679e530392) >--- > lib/tevent/ABI/tevent-0.9.34.sigs | 99 +++++++++++++++++++++++++++++++++++++++ > lib/tevent/wscript | 2 +- > 2 files changed, 100 insertions(+), 1 deletion(-) > create mode 100644 lib/tevent/ABI/tevent-0.9.34.sigs > >diff --git a/lib/tevent/ABI/tevent-0.9.34.sigs b/lib/tevent/ABI/tevent-0.9.34.sigs >new file mode 100644 >index 0000000..7a6a236 >--- /dev/null >+++ b/lib/tevent/ABI/tevent-0.9.34.sigs >@@ -0,0 +1,99 @@ >+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *) >+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *) >+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *) >+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *) >+_tevent_loop_once: int (struct tevent_context *, const char *) >+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *) >+_tevent_loop_wait: int (struct tevent_context *, const char *) >+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *) >+_tevent_req_callback_data: void *(struct tevent_req *) >+_tevent_req_cancel: bool (struct tevent_req *, const char *) >+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *) >+_tevent_req_data: void *(struct tevent_req *) >+_tevent_req_done: void (struct tevent_req *, const char *) >+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *) >+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *) >+_tevent_req_notify_callback: void (struct tevent_req *, const char *) >+_tevent_req_oom: void (struct tevent_req *, const char *) >+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *) >+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *) >+tevent_backend_list: const char **(TALLOC_CTX *) >+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *) >+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *) >+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *) >+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *) >+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *) >+tevent_common_check_signal: int (struct tevent_context *) >+tevent_common_context_destructor: int (struct tevent_context *) >+tevent_common_fd_destructor: int (struct tevent_fd *) >+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *) >+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t) >+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t) >+tevent_common_have_events: bool (struct tevent_context *) >+tevent_common_loop_immediate: bool (struct tevent_context *) >+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *) >+tevent_common_loop_wait: int (struct tevent_context *, const char *) >+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *) >+tevent_common_threaded_activate_immediate: void (struct tevent_context *) >+tevent_common_wakeup: int (struct tevent_context *) >+tevent_common_wakeup_fd: int (int) >+tevent_common_wakeup_init: int (struct tevent_context *) >+tevent_context_init: struct tevent_context *(TALLOC_CTX *) >+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *) >+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *) >+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...) >+tevent_fd_get_flags: uint16_t (struct tevent_fd *) >+tevent_fd_set_auto_close: void (struct tevent_fd *) >+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t) >+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t) >+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *) >+tevent_loop_allow_nesting: void (struct tevent_context *) >+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *) >+tevent_num_signals: size_t (void) >+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *) >+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *) >+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *) >+tevent_queue_length: size_t (struct tevent_queue *) >+tevent_queue_running: bool (struct tevent_queue *) >+tevent_queue_start: void (struct tevent_queue *) >+tevent_queue_stop: void (struct tevent_queue *) >+tevent_queue_wait_recv: bool (struct tevent_req *) >+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *) >+tevent_re_initialise: int (struct tevent_context *) >+tevent_register_backend: bool (const char *, const struct tevent_ops *) >+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *) >+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *) >+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *) >+tevent_req_is_in_progress: bool (struct tevent_req *) >+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *) >+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *) >+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *) >+tevent_req_received: void (struct tevent_req *) >+tevent_req_reset_endtime: void (struct tevent_req *) >+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *) >+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn) >+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn) >+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval) >+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn) >+tevent_sa_info_queue_count: size_t (void) >+tevent_set_abort_fn: void (void (*)(const char *)) >+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *) >+tevent_set_debug_stderr: int (struct tevent_context *) >+tevent_set_default_backend: void (const char *) >+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *) >+tevent_signal_support: bool (struct tevent_context *) >+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *) >+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *) >+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *) >+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t) >+tevent_timeval_compare: int (const struct timeval *, const struct timeval *) >+tevent_timeval_current: struct timeval (void) >+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t) >+tevent_timeval_is_zero: bool (const struct timeval *) >+tevent_timeval_set: struct timeval (uint32_t, uint32_t) >+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *) >+tevent_timeval_zero: struct timeval (void) >+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point) >+tevent_update_timer: void (struct tevent_timer *, struct timeval) >+tevent_wakeup_recv: bool (struct tevent_req *) >+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval) >diff --git a/lib/tevent/wscript b/lib/tevent/wscript >index 721c050..f9ff3fa 100755 >--- a/lib/tevent/wscript >+++ b/lib/tevent/wscript >@@ -1,7 +1,7 @@ > #!/usr/bin/env python > > APPNAME = 'tevent' >-VERSION = '0.9.33' >+VERSION = '0.9.34' > > blddir = 'bin' > >-- >1.9.1 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Flags:
jra
:
review+
Actions:
View
Attachments on
bug 13130
:
13766
|
13767
|
13768
|
13769
|
13777
| 13778