/* Event notifier group file descriptor ioctl */
#define LTTNG_KERNEL_EVENT_NOTIFIER_CREATE \
_IOW(0xF6, 0xB0, struct lttng_kernel_event_notifier)
+#define LTTNG_KERNEL_EVENT_NOTIFIER_GROUP_NOTIFICATION_FD \
+ _IO(0xF6, 0xB1)
/*
* LTTng-specific ioctls for the lib ringbuffer.
--- /dev/null
+/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
+ *
+ * lttng/event-notifier-notification.h
+ *
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ */
+
+#ifndef _LTTNG_EVENT_NOTIFIER_NOTIFICATION_H
+#define _LTTNG_EVENT_NOTIFIER_NOTIFICATION_H
+
+#include <lttng/events.h>
+
+void lttng_event_notifier_notification_send(struct lttng_event_notifier *event_notifier);
+
+#endif /* _LTTNG_EVENT_NOTIFIER_NOTIFICATION_H */
#ifndef _LTTNG_EVENTS_H
#define _LTTNG_EVENTS_H
+#include <linux/irq_work.h>
#include <linux/version.h>
#include <linux/list.h>
#include <linux/kprobes.h>
struct list_head bytecode_runtime_head;
int has_enablers_without_bytecode;
+ void (*send_notification)(struct lttng_event_notifier *event_notifier);
struct lttng_event_notifier_group *group; /* Weak ref */
};
struct lttng_event_notifier_group {
struct file *file; /* File associated to event notifier group */
+ struct file *notif_file; /* File used to expose notifications to userspace. */
struct list_head node; /* event notifier group list */
struct list_head enablers_head; /* List of enablers */
struct list_head event_notifiers_head; /* List of event notifier */
struct lttng_transport *transport;
struct channel *chan; /* Ring buffer channel for event notifier group. */
struct lib_ring_buffer *buf; /* Ring buffer for event notifier group. */
+ wait_queue_head_t read_wait;
+ struct irq_work wakeup_pending; /* Pending wakeup irq work. */
};
struct lttng_metadata_cache {
lttng-filter-validator.o \
probes/lttng-probe-user.o \
lttng-tp-mempool.o \
+ lttng-event-notifier-notification.o
lttng-wrapper-objs := wrapper/page_alloc.o \
wrapper/random.o \
return ret;
}
+void event_notifier_send_notification_work_wakeup(struct irq_work *entry)
+{
+ struct lttng_event_notifier_group *event_notifier_group =
+ container_of(entry, struct lttng_event_notifier_group,
+ wakeup_pending);
+ wake_up_interruptible(&event_notifier_group->read_wait);
+}
+
static
int lttng_abi_create_event_notifier_group(void)
{
}
event_notifier_group->file = event_notifier_group_file;
+ init_waitqueue_head(&event_notifier_group->read_wait);
+ init_irq_work(&event_notifier_group->wakeup_pending,
+ event_notifier_send_notification_work_wakeup);
fd_install(event_notifier_group_fd, event_notifier_group_file);
return event_notifier_group_fd;
#endif
};
+static const struct file_operations lttng_event_notifier_group_notif_fops = {
+ .owner = THIS_MODULE,
+};
+
/**
* lttng_metadata_ring_buffer_poll - LTTng ring buffer poll file operation
* @filp: the file
return ret;
}
+static
+int lttng_abi_open_event_notifier_group_stream(struct file *notif_file)
+{
+ struct lttng_event_notifier_group *event_notifier_group = notif_file->private_data;
+ struct channel *chan = event_notifier_group->chan;
+ struct lib_ring_buffer *buf;
+ int ret;
+ void *stream_priv;
+
+ buf = event_notifier_group->ops->buffer_read_open(chan);
+ if (!buf)
+ return -ENOENT;
+
+ /* The event_notifier notification fd holds a reference on the event_notifier group */
+ if (!atomic_long_add_unless(¬if_file->f_count, 1, LONG_MAX)) {
+ ret = -EOVERFLOW;
+ goto refcount_error;
+ }
+ event_notifier_group->buf = buf;
+ stream_priv = event_notifier_group;
+ ret = lttng_abi_create_stream_fd(notif_file, stream_priv,
+ <tng_event_notifier_group_notif_fops,
+ "[lttng_event_notifier_stream]");
+ if (ret < 0)
+ goto fd_error;
+
+ return ret;
+
+fd_error:
+ atomic_long_dec(¬if_file->f_count);
+refcount_error:
+ event_notifier_group->ops->buffer_read_close(buf);
+ return ret;
+}
+
static
int lttng_abi_validate_event_param(struct lttng_kernel_event *event_param)
{
unsigned long arg)
{
switch (cmd) {
+ case LTTNG_KERNEL_EVENT_NOTIFIER_GROUP_NOTIFICATION_FD:
+ {
+ return lttng_abi_open_event_notifier_group_stream(file);
+ }
case LTTNG_KERNEL_EVENT_NOTIFIER_CREATE:
{
struct lttng_kernel_event_notifier uevent_notifier_param;
--- /dev/null
+/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
+ *
+ * lttng-event-notifier-notification.c
+ *
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ */
+
+#include <lttng/events.h>
+#include <lttng/event-notifier-notification.h>
+
+void lttng_event_notifier_notification_send(struct lttng_event_notifier *event_notifier)
+{
+ struct lttng_event_notifier_group *event_notifier_group = event_notifier->group;
+ struct lib_ring_buffer_ctx ctx;
+ int ret;
+
+ if (unlikely(!READ_ONCE(event_notifier->enabled)))
+ return;
+
+ lib_ring_buffer_ctx_init(&ctx, event_notifier_group->chan, NULL,
+ sizeof(event_notifier->user_token),
+ lttng_alignof(event_notifier->user_token), -1);
+ ret = event_notifier_group->ops->event_reserve(&ctx, 0);
+ if (ret < 0) {
+ //TODO: error handling with counter maps
+ //silently drop for now.
+ WARN_ON_ONCE(1);
+ return;
+ }
+ lib_ring_buffer_align_ctx(&ctx, lttng_alignof(event_notifier->user_token));
+ event_notifier_group->ops->event_write(&ctx, &event_notifier->user_token,
+ sizeof(event_notifier->user_token));
+ event_notifier_group->ops->event_commit(&ctx);
+ irq_work_queue(&event_notifier_group->wakeup_pending);
+}
#include <lttng/kernel-version.h>
#include <lttng/events.h>
#include <lttng/tracer.h>
+#include <lttng/event-notifier-notification.h>
#include <lttng/abi-old.h>
#include <lttng/endian.h>
#include <lttng/string-utils.h>
WARN_ON(ret);
}
+ irq_work_sync(&event_notifier_group->wakeup_pending);
+
list_for_each_entry_safe(event_notifier_enabler, tmp_event_notifier_enabler,
&event_notifier_group->enablers_head, node)
lttng_event_notifier_enabler_destroy(event_notifier_enabler);
ret = -ENOMEM;
goto cache_error;
}
+
event_notifier->group = event_notifier_group;
event_notifier->user_token = token;
event_notifier->filter = filter;
event_notifier->instrumentation = itype;
event_notifier->evtype = LTTNG_TYPE_EVENT;
+ event_notifier->send_notification = lttng_event_notifier_notification_send;
INIT_LIST_HEAD(&event_notifier->bytecode_runtime_head);
INIT_LIST_HEAD(&event_notifier->enablers_ref_head);