@@ -22,10 +22,41 @@
const char *data_file = "/sys/kernel/tracing/user_events_data";
const char *enable_file = "/sys/kernel/tracing/events/user_events/__abi_event/enable";
+const char *temp_enable_file = "/sys/kernel/tracing/events/user_events/__abi_temp_event/enable";
-static int change_event(bool enable)
+static bool temp_exists(int grace_ms)
+{
+ int fd;
+
+ usleep(grace_ms * 1000);
+
+ fd = open(temp_enable_file, O_RDONLY);
+
+ if (fd == -1)
+ return false;
+
+ close(fd);
+
+ return true;
+}
+
+static int clear_temp(void)
+{
+ int fd = open(data_file, O_RDWR);
+ int ret = 0;
+
+ if (ioctl(fd, DIAG_IOCSDEL, "__abi_temp_event") == -1)
+ if (errno != ENOENT)
+ ret = -1;
+
+ close(fd);
+
+ return ret;
+}
+
+static int __change_event(const char *path, bool enable)
{
- int fd = open(enable_file, O_RDWR);
+ int fd = open(path, O_RDWR);
int ret;
if (fd < 0)
@@ -46,22 +77,48 @@ static int change_event(bool enable)
return ret;
}
-static int reg_enable(long *enable, int size, int bit)
+static int change_temp_event(bool enable)
+{
+ return __change_event(temp_enable_file, enable);
+}
+
+static int change_event(bool enable)
+{
+ return __change_event(enable_file, enable);
+}
+
+static int __reg_enable(int *fd, const char *name, long *enable, int size,
+ int bit, int flags)
{
struct user_reg reg = {0};
- int fd = open(data_file, O_RDWR);
- int ret;
- if (fd < 0)
+ *fd = open(data_file, O_RDWR);
+
+ if (*fd < 0)
return -1;
reg.size = sizeof(reg);
- reg.name_args = (__u64)"__abi_event";
+ reg.name_args = (__u64)name;
reg.enable_bit = bit;
reg.enable_addr = (__u64)enable;
reg.enable_size = size;
+ reg.flags = flags;
+
+ return ioctl(*fd, DIAG_IOCSREG, ®);
+}
- ret = ioctl(fd, DIAG_IOCSREG, ®);
+static int reg_enable_temp(int *fd, long *enable, int size, int bit)
+{
+ return __reg_enable(fd, "__abi_temp_event", enable, size, bit,
+ USER_EVENT_REG_AUTO_DEL);
+}
+
+static int reg_enable(long *enable, int size, int bit)
+{
+ int ret;
+ int fd;
+
+ ret = __reg_enable(&fd, "__abi_event", enable, size, bit, 0);
close(fd);
@@ -98,6 +155,7 @@ FIXTURE_SETUP(user) {
}
FIXTURE_TEARDOWN(user) {
+ clear_temp();
}
TEST_F(user, enablement) {
@@ -223,6 +281,47 @@ TEST_F(user, clones) {
ASSERT_EQ(0, change_event(false));
}
+TEST_F(user, flags) {
+ int grace = 100;
+ int fd;
+
+ /* FLAG: USER_EVENT_REG_AUTO_DEL */
+ /* Removal path 1, close on last fd ref */
+ ASSERT_EQ(0, clear_temp());
+ ASSERT_EQ(0, reg_enable_temp(&fd, &self->check, sizeof(int), 0));
+ ASSERT_EQ(0, reg_disable(&self->check, 0));
+ close(fd);
+ ASSERT_EQ(false, temp_exists(grace));
+
+ /* Removal path 2, close on last enabler */
+ ASSERT_EQ(0, clear_temp());
+ ASSERT_EQ(0, reg_enable_temp(&fd, &self->check, sizeof(int), 0));
+ close(fd);
+ ASSERT_EQ(true, temp_exists(grace));
+ ASSERT_EQ(0, reg_disable(&self->check, 0));
+ ASSERT_EQ(false, temp_exists(grace));
+
+ /* Removal path 3, close on last trace_event ref */
+ ASSERT_EQ(0, clear_temp());
+ ASSERT_EQ(0, reg_enable_temp(&fd, &self->check, sizeof(int), 0));
+ ASSERT_EQ(0, reg_disable(&self->check, 0));
+ ASSERT_EQ(0, change_temp_event(true));
+ close(fd);
+ ASSERT_EQ(true, temp_exists(grace));
+ ASSERT_EQ(0, change_temp_event(false));
+ ASSERT_EQ(false, temp_exists(grace));
+
+ /* FLAG: Non-ABI */
+ /* Unknown flags should fail with EINVAL */
+ ASSERT_EQ(-1, __reg_enable(&fd, "__abi_invalid_event", &self->check,
+ sizeof(int), 0, USER_EVENT_REG_MAX));
+ ASSERT_EQ(EINVAL, errno);
+
+ ASSERT_EQ(-1, __reg_enable(&fd, "__abi_invalid_event", &self->check,
+ sizeof(int), 0, USER_EVENT_REG_MAX + 1));
+ ASSERT_EQ(EINVAL, errno);
+}
+
int main(int argc, char **argv)
{
return test_harness_run(argc, argv);