Remove unnecessary RCU read lock
[lttng-tools.git] / src / bin / lttng-sessiond / agent.c
index cf8264a307b7029f479b779dd846221212922567..0821630865106182365cd404fecaf0cd9bcb64cc 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #define _GNU_SOURCE
+#define _LGPL_SOURCE
 #include <assert.h>
 #include <urcu/uatomic.h>
 
 #include "agent.h"
 #include "ust-app.h"
 #include "utils.h"
+#include "error.h"
+
+#define AGENT_RET_CODE_INDEX(code) (code - AGENT_RET_CODE_SUCCESS)
+
+/*
+ * Human readable agent return code.
+ */
+static const char *error_string_array[] = {
+       [ AGENT_RET_CODE_INDEX(AGENT_RET_CODE_SUCCESS) ] = "Success",
+       [ AGENT_RET_CODE_INDEX(AGENT_RET_CODE_INVALID) ] = "Invalid command",
+       [ AGENT_RET_CODE_INDEX(AGENT_RET_CODE_UNKNOWN_NAME) ] = "Unknown logger name",
+
+       /* Last element */
+       [ AGENT_RET_CODE_INDEX(AGENT_RET_CODE_NR) ] = "Unknown code",
+};
+
+static
+void log_reply_code(uint32_t in_reply_ret_code)
+{
+       int level = PRINT_DBG3;
+       /*
+        * reply_ret_code and in_reply_ret_code are kept separate to have a
+        * sanitized value (used to retrieve the human readable string) and the
+        * original value which is logged as-is.
+        */
+       uint32_t reply_ret_code = in_reply_ret_code;
+
+       if (reply_ret_code < AGENT_RET_CODE_SUCCESS ||
+                       reply_ret_code >= AGENT_RET_CODE_NR) {
+               reply_ret_code = AGENT_RET_CODE_NR;
+               level = PRINT_ERR;
+       }
+
+       LOG(level, "Agent replied with retcode: %s (%"PRIu32")",
+                       error_string_array[AGENT_RET_CODE_INDEX(
+                       reply_ret_code)],
+                       in_reply_ret_code);
+}
 
 /*
  * Match function for the events hash table lookup by name.
@@ -234,6 +273,7 @@ static ssize_t list_events(struct agent_app *app, struct lttng_event **events)
        int ret, i, len = 0, offset = 0;
        uint32_t nb_event;
        size_t data_size;
+       uint32_t reply_ret_code;
        struct lttng_event *tmp_events = NULL;
        struct lttcomm_agent_list_reply *reply = NULL;
        struct lttcomm_agent_list_reply_hdr reply_hdr;
@@ -256,14 +296,14 @@ static ssize_t list_events(struct agent_app *app, struct lttng_event **events)
                goto error_io;
        }
 
-       switch (be32toh(reply_hdr.ret_code)) {
+       reply_ret_code = be32toh(reply_hdr.ret_code);
+       log_reply_code(reply_ret_code);
+       switch (reply_ret_code) {
        case AGENT_RET_CODE_SUCCESS:
                data_size = be32toh(reply_hdr.data_size) + sizeof(*reply);
                break;
        default:
-               ERR("Agent returned an unknown code: %" PRIu32,
-                               be32toh(reply_hdr.ret_code));
-               ret = LTTNG_ERR_FATAL;
+               ret = LTTNG_ERR_UNK;
                goto error;
        }
 
@@ -319,6 +359,7 @@ static int enable_event(struct agent_app *app, struct agent_event *event)
 {
        int ret;
        uint64_t data_size;
+       uint32_t reply_ret_code;
        struct lttcomm_agent_enable msg;
        struct lttcomm_agent_generic_reply reply;
 
@@ -350,16 +391,16 @@ static int enable_event(struct agent_app *app, struct agent_event *event)
                goto error_io;
        }
 
-       switch (be32toh(reply.ret_code)) {
+       reply_ret_code = be32toh(reply.ret_code);
+       log_reply_code(reply_ret_code);
+       switch (reply_ret_code) {
        case AGENT_RET_CODE_SUCCESS:
                break;
        case AGENT_RET_CODE_UNKNOWN_NAME:
                ret = LTTNG_ERR_UST_EVENT_NOT_FOUND;
                goto error;
        default:
-               ERR("Agent returned an unknown code: %" PRIu32,
-                               be32toh(reply.ret_code));
-               ret = LTTNG_ERR_FATAL;
+               ret = LTTNG_ERR_UNK;
                goto error;
        }
 
@@ -381,6 +422,7 @@ static int disable_event(struct agent_app *app, struct agent_event *event)
 {
        int ret;
        uint64_t data_size;
+       uint32_t reply_ret_code;
        struct lttcomm_agent_disable msg;
        struct lttcomm_agent_generic_reply reply;
 
@@ -410,16 +452,16 @@ static int disable_event(struct agent_app *app, struct agent_event *event)
                goto error_io;
        }
 
-       switch (be32toh(reply.ret_code)) {
+       reply_ret_code = be32toh(reply.ret_code);
+       log_reply_code(reply_ret_code);
+       switch (reply_ret_code) {
        case AGENT_RET_CODE_SUCCESS:
                break;
        case AGENT_RET_CODE_UNKNOWN_NAME:
                ret = LTTNG_ERR_UST_EVENT_NOT_FOUND;
                goto error;
        default:
-               ERR("Agent returned an unknown code: %" PRIu32,
-                               be32toh(reply.ret_code));
-               ret = LTTNG_ERR_FATAL;
+               ret = LTTNG_ERR_UNK;
                goto error;
        }
 
@@ -452,7 +494,8 @@ int agent_send_registration_done(struct agent_app *app)
  *
  * Return LTTNG_OK on success or else a LTTNG_ERR* code.
  */
-int agent_enable_event(struct agent_event *event)
+int agent_enable_event(struct agent_event *event,
+               enum lttng_domain_type domain)
 {
        int ret;
        struct agent_app *app;
@@ -464,6 +507,10 @@ int agent_enable_event(struct agent_event *event)
 
        cds_lfht_for_each_entry(agent_apps_ht_by_sock->ht, &iter.iter, app,
                        node.node) {
+               if (app->domain != domain) {
+                       continue;
+               }
+
                /* Enable event on agent application through TCP socket. */
                ret = enable_event(app, event);
                if (ret != LTTNG_OK) {
@@ -485,18 +532,26 @@ error:
  *
  * Return LTTNG_OK on success or else a LTTNG_ERR* code.
  */
-int agent_disable_event(struct agent_event *event)
+int agent_disable_event(struct agent_event *event,
+               enum lttng_domain_type domain)
 {
-       int ret;
+       int ret = LTTNG_OK;
        struct agent_app *app;
        struct lttng_ht_iter iter;
 
        assert(event);
+       if (!event->enabled) {
+               goto end;
+       }
 
        rcu_read_lock();
 
        cds_lfht_for_each_entry(agent_apps_ht_by_sock->ht, &iter.iter, app,
                        node.node) {
+               if (app->domain != domain) {
+                       continue;
+               }
+
                /* Enable event on agent application through TCP socket. */
                ret = disable_event(app, event);
                if (ret != LTTNG_OK) {
@@ -505,10 +560,10 @@ int agent_disable_event(struct agent_event *event)
        }
 
        event->enabled = 0;
-       ret = LTTNG_OK;
 
 error:
        rcu_read_unlock();
+end:
        return ret;
 }
 
@@ -518,7 +573,8 @@ error:
  *
  * Return the number of events or else a negative value.
  */
-int agent_list_events(struct lttng_event **events)
+int agent_list_events(struct lttng_event **events,
+               enum lttng_domain_type domain)
 {
        int ret;
        size_t nbmem, count = 0;
@@ -528,6 +584,8 @@ int agent_list_events(struct lttng_event **events)
 
        assert(events);
 
+       DBG2("Agent listing events for domain %d", domain);
+
        nbmem = UST_APP_EVENT_LIST_SIZE;
        tmp_events = zmalloc(nbmem * sizeof(*tmp_events));
        if (!tmp_events) {
@@ -542,6 +600,11 @@ int agent_list_events(struct lttng_event **events)
                ssize_t nb_ev;
                struct lttng_event *agent_events;
 
+               /* Skip domain not asked by the list. */
+               if (app->domain != domain) {
+                       continue;
+               }
+
                nb_ev = list_events(app, &agent_events);
                if (nb_ev < 0) {
                        ret = nb_ev;
@@ -593,7 +656,8 @@ error:
  *
  * Return newly allocated object or else NULL on error.
  */
-struct agent_app *agent_create_app(pid_t pid, struct lttcomm_sock *sock)
+struct agent_app *agent_create_app(pid_t pid, enum lttng_domain_type domain,
+               struct lttcomm_sock *sock)
 {
        struct agent_app *app;
 
@@ -606,6 +670,7 @@ struct agent_app *agent_create_app(pid_t pid, struct lttcomm_sock *sock)
        }
 
        app->pid = pid;
+       app->domain = domain;
        app->sock = sock;
        lttng_ht_node_init_ulong(&app->node, (unsigned long) app->sock->fd);
 
@@ -651,14 +716,13 @@ void agent_add_app(struct agent_app *app)
        assert(app);
 
        DBG3("Agent adding app sock: %d and pid: %d to ht", app->sock->fd, app->pid);
-
-       rcu_read_lock();
        lttng_ht_add_unique_ulong(agent_apps_ht_by_sock, &app->node);
-       rcu_read_unlock();
 }
 
 /*
  * Delete agent application from the global hash table.
+ *
+ * rcu_read_lock() must be held by the caller.
  */
 void agent_delete_app(struct agent_app *app)
 {
@@ -670,14 +734,12 @@ void agent_delete_app(struct agent_app *app)
        DBG3("Agent deleting app pid: %d and sock: %d", app->pid, app->sock->fd);
 
        iter.iter.node = &app->node.node;
-       rcu_read_lock();
        ret = lttng_ht_del(agent_apps_ht_by_sock, &iter);
-       rcu_read_unlock();
        assert(!ret);
 }
 
 /*
- * Destroy a agent application object by detaching it from its corresponding
+ * Destroy an agent application object by detaching it from its corresponding
  * UST app if one is connected by closing the socket. Finally, perform a
  * delayed memory reclaim.
  */
@@ -709,6 +771,7 @@ int agent_init(struct agent *agt)
                ret = -ENOMEM;
                goto error;
        }
+       lttng_ht_node_init_u64(&agt->node, agt->domain);
 
        return 0;
 
@@ -716,6 +779,46 @@ error:
        return ret;
 }
 
+/*
+ * Add agent object to the given hash table.
+ */
+void agent_add(struct agent *agt, struct lttng_ht *ht)
+{
+       assert(agt);
+       assert(ht);
+
+       DBG3("Agent adding from domain %d", agt->domain);
+
+       lttng_ht_add_unique_u64(ht, &agt->node);
+}
+
+/*
+ * Create an agent object for the given domain.
+ *
+ * Return the allocated agent or NULL on error.
+ */
+struct agent *agent_create(enum lttng_domain_type domain)
+{
+       int ret;
+       struct agent *agt;
+
+       agt = zmalloc(sizeof(struct agent));
+       if (!agt) {
+               goto error;
+       }
+       agt->domain = domain;
+
+       ret = agent_init(agt);
+       if (ret < 0) {
+               free(agt);
+               agt = NULL;
+               goto error;
+       }
+
+error:
+       return agt;
+}
+
 /*
  * Create a newly allocated agent event data structure. If name is valid, it's
  * copied into the created event.
@@ -758,10 +861,7 @@ void agent_add_event(struct agent_event *event, struct agent *agt)
        assert(agt->events);
 
        DBG3("Agent adding event %s", event->name);
-
-       rcu_read_lock();
        add_unique_agent_event(agt->events, event);
-       rcu_read_unlock();
        agt->being_used = 1;
 }
 
@@ -836,7 +936,7 @@ struct agent_event *agent_find_event(const char *name, int loglevel,
        return caa_container_of(node, struct agent_event, node);
 
 error:
-       DBG3("Agent NOT found %s.", name);
+       DBG3("Agent event NOT found %s.", name);
        return NULL;
 }
 
@@ -849,6 +949,8 @@ void agent_destroy_event(struct agent_event *event)
 {
        assert(event);
 
+       free(event->filter);
+       free(event->filter_expression);
        free(event);
 }
 
@@ -892,20 +994,71 @@ void agent_destroy(struct agent *agt)
        }
        rcu_read_unlock();
 
-       lttng_ht_destroy(agt->events);
+       ht_cleanup_push(agt->events);
 }
 
 /*
- * Initialize agent subsystem.
+ * Allocate agent_apps_ht_by_sock.
  */
-int agent_setup(void)
+int agent_app_ht_alloc(void)
 {
+       int ret = 0;
+
        agent_apps_ht_by_sock = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
        if (!agent_apps_ht_by_sock) {
-               return -1;
+               ret = -1;
        }
 
-       return 0;
+       return ret;
+}
+
+/*
+ * Destroy a agent application by socket.
+ */
+void agent_destroy_app_by_sock(int sock)
+{
+       struct agent_app *app;
+
+       assert(sock >= 0);
+
+       /*
+        * Not finding an application is a very important error that should NEVER
+        * happen. The hash table deletion is ONLY done through this call when the
+        * main sessiond thread is torn down.
+        */
+       rcu_read_lock();
+       app = agent_find_app_by_sock(sock);
+       assert(app);
+
+       /* RCU read side lock is assumed to be held by this function. */
+       agent_delete_app(app);
+
+       /* The application is freed in a RCU call but the socket is closed here. */
+       agent_destroy_app(app);
+       rcu_read_unlock();
+}
+
+/*
+ * Clean-up the agent app hash table and destroy it.
+ */
+void agent_app_ht_clean(void)
+{
+       struct lttng_ht_node_ulong *node;
+       struct lttng_ht_iter iter;
+
+       if (!agent_apps_ht_by_sock) {
+               return;
+       }
+       rcu_read_lock();
+       cds_lfht_for_each_entry(agent_apps_ht_by_sock->ht, &iter.iter, node, node) {
+               struct agent_app *app;
+
+               app = caa_container_of(node, struct agent_app, node);
+               agent_destroy_app_by_sock(app->sock->fd);
+       }
+       rcu_read_unlock();
+
+       lttng_ht_destroy(agent_apps_ht_by_sock);
 }
 
 /*
This page took 0.027799 seconds and 4 git commands to generate.