From 0fe4c3bf415eef3325b53383cbc3bc087db55d7f Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Wed, 23 Jan 2019 15:28:36 -0500 Subject: [PATCH] Fix: notification thread: RCU-safe reclaim of hash table nodes MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Adapted from master branch commit 83b934ad. Signed-off-by: Jérémie Galarneau --- .../notification-thread-commands.h | 2 + .../notification-thread-events.c | 70 ++++++++++++++++--- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/src/bin/lttng-sessiond/notification-thread-commands.h b/src/bin/lttng-sessiond/notification-thread-commands.h index 8885d4faf..0aceb1775 100644 --- a/src/bin/lttng-sessiond/notification-thread-commands.h +++ b/src/bin/lttng-sessiond/notification-thread-commands.h @@ -48,6 +48,8 @@ struct channel_info { char *channel_name; uint64_t capacity; struct cds_lfht_node channels_ht_node; + /* call_rcu delayed reclaim. */ + struct rcu_head rcu_node; }; struct notification_thread_command { diff --git a/src/bin/lttng-sessiond/notification-thread-events.c b/src/bin/lttng-sessiond/notification-thread-events.c index f54141e73..4799c7186 100644 --- a/src/bin/lttng-sessiond/notification-thread-events.c +++ b/src/bin/lttng-sessiond/notification-thread-events.c @@ -58,11 +58,15 @@ struct lttng_channel_trigger_list { struct channel_key channel_key; struct cds_list_head list; struct cds_lfht_node channel_triggers_ht_node; + /* call_rcu delayed reclaim. */ + struct rcu_head rcu_node; }; struct lttng_trigger_ht_element { struct lttng_trigger *trigger; struct cds_lfht_node node; + /* call_rcu delayed reclaim. */ + struct rcu_head rcu_node; }; struct lttng_condition_list_element { @@ -79,6 +83,8 @@ struct notification_client_list { struct lttng_trigger *trigger; struct cds_list_head list; struct cds_lfht_node notification_trigger_ht_node; + /* call_rcu delayed reclaim. */ + struct rcu_head rcu_node; }; struct notification_client { @@ -145,6 +151,8 @@ struct notification_client { struct lttng_dynamic_buffer buffer; } outbound; } communication; + /* call_rcu delayed reclaim. */ + struct rcu_head rcu_node; }; struct channel_state_sample { @@ -152,6 +160,8 @@ struct channel_state_sample { struct cds_lfht_node channel_state_ht_node; uint64_t highest_usage; uint64_t lowest_usage; + /* call_rcu delayed reclaim. */ + struct rcu_head rcu_node; }; static unsigned long hash_channel_key(struct channel_key *key); @@ -332,6 +342,12 @@ unsigned long hash_channel_key(struct channel_key *key) return key_hash ^ domain_hash; } +static +void free_channel_info_rcu(struct rcu_head *node) +{ + free(caa_container_of(node, struct channel_info, rcu_node)); +} + static void channel_info_destroy(struct channel_info *channel_info) { @@ -345,7 +361,7 @@ void channel_info_destroy(struct channel_info *channel_info) if (channel_info->channel_name) { free(channel_info->channel_name); } - free(channel_info); + call_rcu(&channel_info->rcu_node, free_channel_info_rcu); } static @@ -672,6 +688,12 @@ end: return 0; } +static +void free_notification_client_rcu(struct rcu_head *node) +{ + free(caa_container_of(node, struct notification_client, rcu_node)); +} + static void notification_client_destroy(struct notification_client *client, struct notification_thread_state *state) @@ -694,7 +716,7 @@ void notification_client_destroy(struct notification_client *client, } lttng_dynamic_buffer_reset(&client->communication.inbound.buffer); lttng_dynamic_buffer_reset(&client->communication.outbound.buffer); - free(client); + call_rcu(&client->rcu_node, free_notification_client_rcu); } /* @@ -821,6 +843,7 @@ int handle_notification_thread_command_add_channel( channel_key = &new_channel_info->key; + rcu_read_lock(); /* Build a list of all triggers applying to the new channel. */ cds_lfht_for_each_entry(state->triggers_ht, &iter, trigger_ht_element, node) { @@ -833,7 +856,7 @@ int handle_notification_thread_command_add_channel( new_element = zmalloc(sizeof(*new_element)); if (!new_element) { - goto error; + goto error_unlock; } CDS_INIT_LIST_HEAD(&new_element->node); new_element->trigger = trigger_ht_element->trigger; @@ -845,14 +868,13 @@ int handle_notification_thread_command_add_channel( trigger_count); channel_trigger_list = zmalloc(sizeof(*channel_trigger_list)); if (!channel_trigger_list) { - goto error; + goto error_unlock; } channel_trigger_list->channel_key = *channel_key; CDS_INIT_LIST_HEAD(&channel_trigger_list->list); cds_lfht_node_init(&channel_trigger_list->channel_triggers_ht_node); cds_list_splice(&trigger_list, &channel_trigger_list->list); - rcu_read_lock(); /* Add channel to the channel_ht which owns the channel_infos. */ cds_lfht_add(state->channels_ht, hash_channel_key(channel_key), @@ -867,12 +889,28 @@ int handle_notification_thread_command_add_channel( rcu_read_unlock(); *cmd_result = LTTNG_OK; return 0; +error_unlock: + rcu_read_unlock(); error: /* Empty trigger list */ channel_info_destroy(new_channel_info); return 1; } +static +void free_channel_trigger_list_rcu(struct rcu_head *node) +{ + free(caa_container_of(node, struct lttng_channel_trigger_list, + rcu_node)); +} + +static +void free_channel_state_sample_rcu(struct rcu_head *node) +{ + free(caa_container_of(node, struct channel_state_sample, + rcu_node)); +} + static int handle_notification_thread_command_remove_channel( struct notification_thread_state *state, @@ -915,7 +953,7 @@ int handle_notification_thread_command_remove_channel( free(trigger_list_element); } cds_lfht_del(state->channel_triggers_ht, node); - free(trigger_list); + call_rcu(&trigger_list->rcu_node, free_channel_trigger_list_rcu); /* Free sampled channel state. */ cds_lfht_lookup(state->channel_state_ht, @@ -934,7 +972,7 @@ int handle_notification_thread_command_remove_channel( channel_state_ht_node); cds_lfht_del(state->channel_state_ht, node); - free(sample); + call_rcu(&sample->rcu_node, free_channel_state_sample_rcu); } /* Remove the channel from the channels_ht and free it. */ @@ -1172,6 +1210,20 @@ error: return ret; } +static +void free_notification_client_list_rcu(struct rcu_head *node) +{ + free(caa_container_of(node, struct notification_client_list, + rcu_node)); +} + +static +void free_lttng_trigger_ht_element_rcu(struct rcu_head *node) +{ + free(caa_container_of(node, struct lttng_trigger_ht_element, + rcu_node)); +} + static int handle_notification_thread_command_unregister_trigger( struct notification_thread_state *state, @@ -1246,7 +1298,7 @@ int handle_notification_thread_command_unregister_trigger( free(client_list_element); } cds_lfht_del(state->notification_trigger_clients_ht, node); - free(client_list); + call_rcu(&client_list->rcu_node, free_notification_client_list_rcu); /* Remove trigger from triggers_ht. */ trigger_ht_element = caa_container_of(triggers_ht_node, @@ -1258,7 +1310,7 @@ int handle_notification_thread_command_unregister_trigger( action = lttng_trigger_get_action(trigger_ht_element->trigger); lttng_action_destroy(action); lttng_trigger_destroy(trigger_ht_element->trigger); - free(trigger_ht_element); + call_rcu(&trigger_ht_element->rcu_node, free_lttng_trigger_ht_element_rcu); end: rcu_read_unlock(); if (_cmd_reply) { -- 2.34.1