+/**
+ * lttng_counter_cmd - lttng control through object descriptors
+ *
+ * @objd: the object descriptor
+ * @cmd: the command
+ * @arg: command arg
+ * @uargs: UST arguments (internal)
+ * @owner: objd owner
+ *
+ * This object descriptor implements lttng commands:
+ * LTTNG_UST_COUNTER_GLOBAL:
+ * Returns a global counter object descriptor or failure.
+ * LTTNG_UST_COUNTER_CPU:
+ * Returns a per-cpu counter object descriptor or failure.
+ * LTTNG_UST_COUNTER_EVENT
+ * Returns an event object descriptor or failure.
+ * LTTNG_UST_ENABLE
+ * Enable recording for events in this channel (weak enable)
+ * LTTNG_UST_DISABLE
+ * Disable recording for events in this channel (strong disable)
+ *
+ * Counter and event object descriptors also hold a reference on the session.
+ */
+static
+long lttng_counter_cmd(int objd, unsigned int cmd, unsigned long arg,
+ union ust_args *uargs, void *owner)
+{
+ struct lttng_counter *counter = objd_private(objd);
+ struct lttng_event_container *container = lttng_counter_get_event_container(counter);
+
+ if (cmd != LTTNG_UST_COUNTER_GLOBAL && cmd != LTTNG_UST_COUNTER_CPU) {
+ /*
+ * Check if counter received all global/per-cpu objects.
+ */
+ if (!lttng_counter_ready(counter->counter))
+ return -EPERM;
+ }
+
+ switch (cmd) {
+ case LTTNG_UST_COUNTER_GLOBAL:
+ {
+ long ret;
+ int shm_fd;
+
+ shm_fd = uargs->counter_shm.shm_fd;
+ ret = lttng_counter_set_global_shm(counter->counter, shm_fd);
+ if (!ret) {
+ /* Take ownership of shm_fd. */
+ uargs->counter_shm.shm_fd = -1;
+ }
+ return ret;
+ }
+ case LTTNG_UST_COUNTER_CPU:
+ {
+ struct lttng_ust_counter_cpu *counter_cpu =
+ (struct lttng_ust_counter_cpu *) arg;
+ long ret;
+ int shm_fd;
+
+ shm_fd = uargs->counter_shm.shm_fd;
+ ret = lttng_counter_set_cpu_shm(counter->counter,
+ counter_cpu->cpu_nr, shm_fd);
+ if (!ret) {
+ /* Take ownership of shm_fd. */
+ uargs->counter_shm.shm_fd = -1;
+ }
+ return ret;
+ }
+ case LTTNG_UST_COUNTER_EVENT:
+ {
+ struct lttng_ust_counter_event *counter_event_param =
+ (struct lttng_ust_counter_event *) arg;
+ struct lttng_ust_event *event_param = &counter_event_param->event;
+ struct lttng_ust_counter_key *key_param = &counter_event_param->key;
+
+ if (strutils_is_star_glob_pattern(event_param->name)) {
+ /*
+ * If the event name is a star globbing pattern,
+ * we create the special star globbing enabler.
+ */
+ return lttng_abi_create_event_enabler(objd, container, event_param, key_param,
+ owner, LTTNG_ENABLER_FORMAT_STAR_GLOB);
+ } else {
+ return lttng_abi_create_event_enabler(objd, container, event_param, key_param,
+ owner, LTTNG_ENABLER_FORMAT_EVENT);
+ }
+ }
+ case LTTNG_UST_ENABLE:
+ return lttng_event_container_enable(container);
+ case LTTNG_UST_DISABLE:
+ return lttng_event_container_disable(container);
+ default:
+ return -EINVAL;
+ }
+}
+
+
+static
+int lttng_counter_release(int objd)
+{
+ struct lttng_counter *counter = objd_private(objd);
+
+ if (counter) {
+ struct lttng_event_container *container = lttng_counter_get_event_container(counter);
+
+ return lttng_ust_objd_unref(container->session->objd, 0);
+ }
+ return 0;
+}
+
+static const struct lttng_ust_objd_ops lttng_counter_ops = {
+ .release = lttng_counter_release,
+ .cmd = lttng_counter_cmd,
+};
+