From: Mathieu Desnoyers Date: Sat, 14 May 2011 14:35:32 +0000 (-0400) Subject: Fix teardown deadlock X-Git-Tag: v2.0-pre1~153 X-Git-Url: http://git.liburcu.org/?p=lttng-modules.git;a=commitdiff_plain;h=f40270adf3e31289ac13a482e830b4a19d8df3bf Fix teardown deadlock Don't wait on the readers from the session teardown anymore, because if the only thread that can complete reading the buffer is the same waiting on this condition, it deadlocks. If the session daemon needs to wait on consumers, it can always do that in user-space through some other mechanism. Signed-off-by: Mathieu Desnoyers --- diff --git a/lib/ringbuffer/frontend_types.h b/lib/ringbuffer/frontend_types.h index d269c00a..0fa2dddf 100644 --- a/lib/ringbuffer/frontend_types.h +++ b/lib/ringbuffer/frontend_types.h @@ -16,6 +16,7 @@ * Dual LGPL v2.1/GPL v2 license. */ +#include #include "../../wrapper/ringbuffer/config.h" #include "../../wrapper/ringbuffer/backend_types.h" #include "../../wrapper/prio_heap.h" /* For per-CPU read-side iterator */ @@ -62,7 +63,7 @@ struct channel { int hp_iter_enable:1; /* Enable hp iter notif. */ wait_queue_head_t read_wait; /* reader wait queue */ struct channel_iter iter; /* Channel read-side iterator */ - atomic_long_t read_ref; /* Reader reference count */ + struct kref ref; /* Reference count */ }; /* Per-subbuffer commit counters used on the hot path */ diff --git a/lib/ringbuffer/ring_buffer_frontend.c b/lib/ringbuffer/ring_buffer_frontend.c index 5e633f43..7d4dd838 100644 --- a/lib/ringbuffer/ring_buffer_frontend.c +++ b/lib/ringbuffer/ring_buffer_frontend.c @@ -624,6 +624,7 @@ struct channel *channel_create(const struct lib_ring_buffer_config *config, chan->commit_count_mask = (~0UL >> chan->backend.num_subbuf_order); chan->switch_timer_interval = usecs_to_jiffies(switch_timer_interval); chan->read_timer_interval = usecs_to_jiffies(read_timer_interval); + kref_init(&chan->ref); init_waitqueue_head(&chan->read_wait); if (config->alloc == RING_BUFFER_ALLOC_PER_CPU) { @@ -685,6 +686,13 @@ error: } EXPORT_SYMBOL_GPL(channel_create); +static +void channel_release(struct kref *kref) +{ + struct channel *chan = container_of(kref, struct channel, ref); + channel_free(chan); +} + /** * channel_destroy - Finalize, wait for q.s. and destroy channel. * @chan: channel to destroy @@ -741,13 +749,8 @@ void *channel_destroy(struct channel *chan) wake_up_interruptible(&buf->read_wait); } wake_up_interruptible(&chan->read_wait); - - while (atomic_long_read(&chan->read_ref) > 0) - msleep(100); - /* Finish waiting for refcount before free */ - smp_mb(); + kref_put(&chan->ref, channel_release); priv = chan->backend.priv; - channel_free(chan); return priv; } EXPORT_SYMBOL_GPL(channel_destroy); @@ -769,7 +772,7 @@ int lib_ring_buffer_open_read(struct lib_ring_buffer *buf) if (!atomic_long_add_unless(&buf->active_readers, 1, 1)) return -EBUSY; - atomic_long_inc(&chan->read_ref); + kref_get(&chan->ref); smp_mb__after_atomic_inc(); return 0; } @@ -781,8 +784,8 @@ void lib_ring_buffer_release_read(struct lib_ring_buffer *buf) CHAN_WARN_ON(chan, atomic_long_read(&buf->active_readers) != 1); smp_mb__before_atomic_dec(); - atomic_long_dec(&chan->read_ref); atomic_long_dec(&buf->active_readers); + kref_put(&chan->ref, channel_release); } EXPORT_SYMBOL_GPL(lib_ring_buffer_release_read); diff --git a/ltt-events.c b/ltt-events.c index cc189b31..b0191596 100644 --- a/ltt-events.c +++ b/ltt-events.c @@ -514,9 +514,10 @@ int _ltt_session_metadata_statedump(struct ltt_session *session) return 0; if (session->metadata_dumped) goto skip_session; - - - + if (!session->metadata) { + printk(KERN_WARNING "LTTng: tracing is starting, but metadata channel is not found\n"); + return -EPERM; + } skip_session: list_for_each_entry(chan, &session->chan, list) {