Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

tracing: Add events to trace remotes

An event is predefined point in the writer code that allows to log
data. Following the same scheme as kernel events, add remote events,
described to user-space within the events/ tracefs directory found in
the corresponding trace remote.

Remote events are expected to be described during the trace remote
registration.

Add also a .enable_event callback for trace_remote to toggle the event
logging, if supported.

Link: https://patch.msgid.link/20260309162516.2623589-10-vdonnefort@google.com
Reviewed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

authored by

Vincent Donnefort and committed by
Steven Rostedt (Google)
07252915 bf2ba0f8

+288 -6
+6 -1
include/linux/trace_remote.h
··· 5 5 6 6 #include <linux/dcache.h> 7 7 #include <linux/ring_buffer.h> 8 + #include <linux/trace_remote_event.h> 8 9 9 10 /** 10 11 * struct trace_remote_callbacks - Callbacks used by Tracefs to control the remote ··· 24 23 * @reset: Called on `echo 0 > trace`. It is expected from the 25 24 * remote to reset all ring-buffer pages. 26 25 * new reader-page from the @cpu ring-buffer. 26 + * @enable_event: Called on events/event_name/enable. It is expected from 27 + * the remote to allow the writing event @id. 27 28 */ 28 29 struct trace_remote_callbacks { 29 30 int (*init)(struct dentry *d, void *priv); ··· 34 31 int (*enable_tracing)(bool enable, void *priv); 35 32 int (*swap_reader_page)(unsigned int cpu, void *priv); 36 33 int (*reset)(unsigned int cpu, void *priv); 34 + int (*enable_event)(unsigned short id, bool enable, void *priv); 37 35 }; 38 36 39 - int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs, void *priv); 37 + int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs, void *priv, 38 + struct remote_event *events, size_t nr_events); 40 39 41 40 int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size, size_t buffer_size, 42 41 const struct cpumask *cpumask);
+23
include/linux/trace_remote_event.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef _LINUX_TRACE_REMOTE_EVENTS_H 4 + #define _LINUX_TRACE_REMOTE_EVENTS_H 5 + 6 + struct trace_remote; 7 + struct trace_event_fields; 8 + 9 + struct remote_event_hdr { 10 + unsigned short id; 11 + }; 12 + 13 + #define REMOTE_EVENT_NAME_MAX 30 14 + struct remote_event { 15 + char name[REMOTE_EVENT_NAME_MAX]; 16 + unsigned short id; 17 + bool enabled; 18 + struct trace_remote *remote; 19 + struct trace_event_fields *fields; 20 + char *print_fmt; 21 + void (*print)(void *evt, struct trace_seq *seq); 22 + }; 23 + #endif
+259 -5
kernel/trace/trace_remote.c
··· 31 31 u64 ts; 32 32 struct ring_buffer_iter *rb_iter; 33 33 struct ring_buffer_iter **rb_iters; 34 + struct remote_event_hdr *evt; 34 35 int cpu; 35 36 int evt_cpu; 36 37 loff_t pos; ··· 43 42 void *priv; 44 43 struct trace_buffer *trace_buffer; 45 44 struct trace_buffer_desc *trace_buffer_desc; 45 + struct dentry *dentry; 46 + struct eventfs_inode *eventfs; 47 + struct remote_event *events; 48 + unsigned long nr_events; 46 49 unsigned long trace_buffer_size; 47 50 struct ring_buffer_remote rb_remote; 48 51 struct mutex lock; ··· 173 168 static ssize_t 174 169 tracing_on_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) 175 170 { 176 - struct trace_remote *remote = filp->private_data; 171 + struct seq_file *seq = filp->private_data; 172 + struct trace_remote *remote = seq->private; 177 173 unsigned long val; 178 174 int ret; 179 175 ··· 203 197 static ssize_t buffer_size_kb_write(struct file *filp, const char __user *ubuf, size_t cnt, 204 198 loff_t *ppos) 205 199 { 206 - struct trace_remote *remote = filp->private_data; 200 + struct seq_file *seq = filp->private_data; 201 + struct trace_remote *remote = seq->private; 207 202 unsigned long val; 208 203 int ret; 209 204 ··· 491 484 static bool trace_remote_iter_read_event(struct trace_remote_iterator *iter) 492 485 { 493 486 struct trace_buffer *trace_buffer = iter->remote->trace_buffer; 487 + struct ring_buffer_event *rb_evt; 494 488 int cpu = iter->cpu; 495 489 496 490 if (cpu != RING_BUFFER_ALL_CPUS) { 497 491 if (ring_buffer_empty_cpu(trace_buffer, cpu)) 498 492 return false; 499 493 500 - if (!__peek_event(iter, cpu, &iter->ts, &iter->lost_events)) 494 + rb_evt = __peek_event(iter, cpu, &iter->ts, &iter->lost_events); 495 + if (!rb_evt) 501 496 return false; 502 497 503 498 iter->evt_cpu = cpu; 499 + iter->evt = ring_buffer_event_data(rb_evt); 504 500 return true; 505 501 } 506 502 ··· 515 505 if (ring_buffer_empty_cpu(trace_buffer, cpu)) 516 506 continue; 517 507 518 - if (!__peek_event(iter, cpu, &ts, &lost_events)) 508 + rb_evt = __peek_event(iter, cpu, &ts, &lost_events); 509 + if (!rb_evt) 519 510 continue; 520 511 521 512 if (ts >= iter->ts) ··· 524 513 525 514 iter->ts = ts; 526 515 iter->evt_cpu = cpu; 516 + iter->evt = ring_buffer_event_data(rb_evt); 527 517 iter->lost_events = lost_events; 528 518 } 529 519 ··· 545 533 } 546 534 } 547 535 536 + static struct remote_event *trace_remote_find_event(struct trace_remote *remote, unsigned short id); 537 + 548 538 static int trace_remote_iter_print_event(struct trace_remote_iterator *iter) 549 539 { 540 + struct remote_event *evt; 550 541 unsigned long usecs_rem; 551 542 u64 ts = iter->ts; 552 543 ··· 562 547 563 548 trace_seq_printf(&iter->seq, "[%03d]\t%5llu.%06lu: ", iter->evt_cpu, 564 549 ts, usecs_rem); 550 + 551 + evt = trace_remote_find_event(iter->remote, iter->evt->id); 552 + if (!evt) 553 + trace_seq_printf(&iter->seq, "UNKNOWN id=%d\n", iter->evt->id); 554 + else 555 + evt->print(iter->evt, &iter->seq); 565 556 566 557 return trace_seq_has_overflowed(&iter->seq) ? -EOVERFLOW : 0; 567 558 } ··· 850 829 goto err; 851 830 } 852 831 832 + remote->dentry = remote_d; 833 + 853 834 return 0; 854 835 855 836 err: ··· 864 841 865 842 return -ENOMEM; 866 843 } 844 + 845 + static int trace_remote_register_events(const char *remote_name, struct trace_remote *remote, 846 + struct remote_event *events, size_t nr_events); 867 847 868 848 /** 869 849 * trace_remote_register() - Register a Tracefs remote ··· 886 860 * 887 861 * Return: 0 on success, negative error code on failure. 888 862 */ 889 - int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs, void *priv) 863 + int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs, void *priv, 864 + struct remote_event *events, size_t nr_events) 890 865 { 891 866 struct trace_remote *remote; 892 867 int ret; ··· 906 879 if (trace_remote_init_tracefs(name, remote)) { 907 880 kfree(remote); 908 881 return -ENOMEM; 882 + } 883 + 884 + ret = trace_remote_register_events(name, remote, events, nr_events); 885 + if (ret) { 886 + pr_err("Failed to register events for trace remote '%s' (%d)\n", 887 + name, ret); 888 + return ret; 909 889 } 910 890 911 891 ret = cbs->init ? cbs->init(remote->dentry, priv) : 0; ··· 1010 976 return ret; 1011 977 } 1012 978 EXPORT_SYMBOL_GPL(trace_remote_alloc_buffer); 979 + 980 + static int 981 + trace_remote_enable_event(struct trace_remote *remote, struct remote_event *evt, bool enable) 982 + { 983 + int ret; 984 + 985 + lockdep_assert_held(&remote->lock); 986 + 987 + if (evt->enabled == enable) 988 + return 0; 989 + 990 + ret = remote->cbs->enable_event(evt->id, enable, remote->priv); 991 + if (ret) 992 + return ret; 993 + 994 + evt->enabled = enable; 995 + 996 + return 0; 997 + } 998 + 999 + static int remote_event_enable_show(struct seq_file *s, void *unused) 1000 + { 1001 + struct remote_event *evt = s->private; 1002 + 1003 + seq_printf(s, "%d\n", evt->enabled); 1004 + 1005 + return 0; 1006 + } 1007 + 1008 + static ssize_t remote_event_enable_write(struct file *filp, const char __user *ubuf, 1009 + size_t count, loff_t *ppos) 1010 + { 1011 + struct seq_file *seq = filp->private_data; 1012 + struct remote_event *evt = seq->private; 1013 + struct trace_remote *remote = evt->remote; 1014 + u8 enable; 1015 + int ret; 1016 + 1017 + ret = kstrtou8_from_user(ubuf, count, 10, &enable); 1018 + if (ret) 1019 + return ret; 1020 + 1021 + guard(mutex)(&remote->lock); 1022 + 1023 + ret = trace_remote_enable_event(remote, evt, enable); 1024 + if (ret) 1025 + return ret; 1026 + 1027 + return count; 1028 + } 1029 + DEFINE_SHOW_STORE_ATTRIBUTE(remote_event_enable); 1030 + 1031 + static int remote_event_id_show(struct seq_file *s, void *unused) 1032 + { 1033 + struct remote_event *evt = s->private; 1034 + 1035 + seq_printf(s, "%d\n", evt->id); 1036 + 1037 + return 0; 1038 + } 1039 + DEFINE_SHOW_ATTRIBUTE(remote_event_id); 1040 + 1041 + static int remote_event_format_show(struct seq_file *s, void *unused) 1042 + { 1043 + size_t offset = sizeof(struct remote_event_hdr); 1044 + struct remote_event *evt = s->private; 1045 + struct trace_event_fields *field; 1046 + 1047 + seq_printf(s, "name: %s\n", evt->name); 1048 + seq_printf(s, "ID: %d\n", evt->id); 1049 + seq_puts(s, 1050 + "format:\n\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n\n"); 1051 + 1052 + field = &evt->fields[0]; 1053 + while (field->name) { 1054 + seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%u;\tsigned:%d;\n", 1055 + field->type, field->name, offset, field->size, 1056 + field->is_signed); 1057 + offset += field->size; 1058 + field++; 1059 + } 1060 + 1061 + if (field != &evt->fields[0]) 1062 + seq_puts(s, "\n"); 1063 + 1064 + seq_printf(s, "print fmt: %s\n", evt->print_fmt); 1065 + 1066 + return 0; 1067 + } 1068 + DEFINE_SHOW_ATTRIBUTE(remote_event_format); 1069 + 1070 + static int remote_event_callback(const char *name, umode_t *mode, void **data, 1071 + const struct file_operations **fops) 1072 + { 1073 + if (!strcmp(name, "enable")) { 1074 + *mode = TRACEFS_MODE_WRITE; 1075 + *fops = &remote_event_enable_fops; 1076 + return 1; 1077 + } 1078 + 1079 + if (!strcmp(name, "id")) { 1080 + *mode = TRACEFS_MODE_READ; 1081 + *fops = &remote_event_id_fops; 1082 + return 1; 1083 + } 1084 + 1085 + if (!strcmp(name, "format")) { 1086 + *mode = TRACEFS_MODE_READ; 1087 + *fops = &remote_event_format_fops; 1088 + return 1; 1089 + } 1090 + 1091 + return 0; 1092 + } 1093 + 1094 + static int trace_remote_init_eventfs(const char *remote_name, struct trace_remote *remote, 1095 + struct remote_event *evt) 1096 + { 1097 + struct eventfs_inode *eventfs = remote->eventfs; 1098 + static struct eventfs_entry entries[] = { 1099 + { 1100 + .name = "enable", 1101 + .callback = remote_event_callback, 1102 + }, { 1103 + .name = "id", 1104 + .callback = remote_event_callback, 1105 + }, { 1106 + .name = "format", 1107 + .callback = remote_event_callback, 1108 + } 1109 + }; 1110 + bool eventfs_create = false; 1111 + 1112 + if (!eventfs) { 1113 + eventfs = eventfs_create_events_dir("events", remote->dentry, NULL, 0, NULL); 1114 + if (IS_ERR(eventfs)) 1115 + return PTR_ERR(eventfs); 1116 + 1117 + /* 1118 + * Create similar hierarchy as local events even if a single system is supported at 1119 + * the moment 1120 + */ 1121 + eventfs = eventfs_create_dir(remote_name, eventfs, NULL, 0, NULL); 1122 + if (IS_ERR(eventfs)) 1123 + return PTR_ERR(eventfs); 1124 + 1125 + remote->eventfs = eventfs; 1126 + eventfs_create = true; 1127 + } 1128 + 1129 + eventfs = eventfs_create_dir(evt->name, eventfs, entries, ARRAY_SIZE(entries), evt); 1130 + if (IS_ERR(eventfs)) { 1131 + if (eventfs_create) { 1132 + eventfs_remove_events_dir(remote->eventfs); 1133 + remote->eventfs = NULL; 1134 + } 1135 + return PTR_ERR(eventfs); 1136 + } 1137 + 1138 + return 0; 1139 + } 1140 + 1141 + static int trace_remote_attach_events(struct trace_remote *remote, struct remote_event *events, 1142 + size_t nr_events) 1143 + { 1144 + int i; 1145 + 1146 + for (i = 0; i < nr_events; i++) { 1147 + struct remote_event *evt = &events[i]; 1148 + 1149 + if (evt->remote) 1150 + return -EEXIST; 1151 + 1152 + evt->remote = remote; 1153 + 1154 + /* We need events to be sorted for efficient lookup */ 1155 + if (i && evt->id <= events[i - 1].id) 1156 + return -EINVAL; 1157 + } 1158 + 1159 + remote->events = events; 1160 + remote->nr_events = nr_events; 1161 + 1162 + return 0; 1163 + } 1164 + 1165 + static int trace_remote_register_events(const char *remote_name, struct trace_remote *remote, 1166 + struct remote_event *events, size_t nr_events) 1167 + { 1168 + int i, ret; 1169 + 1170 + ret = trace_remote_attach_events(remote, events, nr_events); 1171 + if (ret) 1172 + return ret; 1173 + 1174 + for (i = 0; i < nr_events; i++) { 1175 + struct remote_event *evt = &events[i]; 1176 + 1177 + ret = trace_remote_init_eventfs(remote_name, remote, evt); 1178 + if (ret) 1179 + pr_warn("Failed to init eventfs for event '%s' (%d)", 1180 + evt->name, ret); 1181 + } 1182 + 1183 + return 0; 1184 + } 1185 + 1186 + static int __cmp_events(const void *key, const void *data) 1187 + { 1188 + const struct remote_event *evt = data; 1189 + int id = (int)((long)key); 1190 + 1191 + return id - (int)evt->id; 1192 + } 1193 + 1194 + static struct remote_event *trace_remote_find_event(struct trace_remote *remote, unsigned short id) 1195 + { 1196 + return bsearch((const void *)(unsigned long)id, remote->events, remote->nr_events, 1197 + sizeof(*remote->events), __cmp_events); 1198 + }