diff options
| author | Li Zefan <lizf@cn.fujitsu.com> | 2009-06-01 03:35:46 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2009-06-01 23:25:15 -0400 |
| commit | 7fcb7c472f455d1711eb5a7633204dba8800a6d6 (patch) | |
| tree | ba64de513bdbe5550c6fc08078a356359830ec99 | |
| parent | a9c1c3abe1160a5632e48c929b02b740556bf423 (diff) | |
tracing/events: introduce __dynamic_array()
__string() is limited:
- it's a char array, but we may want to define array with other types
- a source string should be available, but we may just know the string size
We introduce __dynamic_array() to break those limitations, and __string()
becomes a wrapper of it. As a side effect, now __get_str() can be used
in TP_fast_assign but not only TP_print.
Take XFS for example, we have the string length in the dirent, but the
string itself is not NULL-terminated, so __dynamic_array() can be used:
TRACE_EVENT(xfs_dir2,
TP_PROTO(struct xfs_da_args *args),
TP_ARGS(args),
TP_STRUCT__entry(
__field(int, namelen)
__dynamic_array(char, name, args->namelen + 1)
...
),
TP_fast_assign(
char *name = __get_str(name);
if (args->namelen)
memcpy(name, args->name, args->namelen);
name[args->namelen] = '\0';
__entry->namelen = args->namelen;
),
TP_printk("name %.*s namelen %d",
__entry->namelen ? __get_str(name) : NULL
__entry->namelen)
);
[ Impact: allow defining dynamic size arrays ]
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
LKML-Reference: <4A2384D2.3080403@cn.fujitsu.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
| -rw-r--r-- | include/trace/ftrace.h | 122 | ||||
| -rw-r--r-- | kernel/trace/trace_events_filter.c | 6 |
2 files changed, 91 insertions, 37 deletions
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index ee9268222448..b5478dab579b 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
| @@ -18,14 +18,17 @@ | |||
| 18 | 18 | ||
| 19 | #include <linux/ftrace_event.h> | 19 | #include <linux/ftrace_event.h> |
| 20 | 20 | ||
| 21 | #undef __field | ||
| 22 | #define __field(type, item) type item; | ||
| 23 | |||
| 21 | #undef __array | 24 | #undef __array |
| 22 | #define __array(type, item, len) type item[len]; | 25 | #define __array(type, item, len) type item[len]; |
| 23 | 26 | ||
| 24 | #undef __field | 27 | #undef __dynamic_array |
| 25 | #define __field(type, item) type item; | 28 | #define __dynamic_array(type, item, len) unsigned short __data_loc_##item; |
| 26 | 29 | ||
| 27 | #undef __string | 30 | #undef __string |
| 28 | #define __string(item, src) unsigned short __str_loc_##item; | 31 | #define __string(item, src) __dynamic_array(char, item, -1) |
| 29 | 32 | ||
| 30 | #undef TP_STRUCT__entry | 33 | #undef TP_STRUCT__entry |
| 31 | #define TP_STRUCT__entry(args...) args | 34 | #define TP_STRUCT__entry(args...) args |
| @@ -35,7 +38,7 @@ | |||
| 35 | struct ftrace_raw_##name { \ | 38 | struct ftrace_raw_##name { \ |
| 36 | struct trace_entry ent; \ | 39 | struct trace_entry ent; \ |
| 37 | tstruct \ | 40 | tstruct \ |
| 38 | char __str_data[0]; \ | 41 | char __data[0]; \ |
| 39 | }; \ | 42 | }; \ |
| 40 | static struct ftrace_event_call event_##name | 43 | static struct ftrace_event_call event_##name |
| 41 | 44 | ||
| @@ -47,30 +50,31 @@ | |||
| 47 | * | 50 | * |
| 48 | * Include the following: | 51 | * Include the following: |
| 49 | * | 52 | * |
| 50 | * struct ftrace_str_offsets_<call> { | 53 | * struct ftrace_data_offsets_<call> { |
| 51 | * int <str1>; | 54 | * int <item1>; |
| 52 | * int <str2>; | 55 | * int <item2>; |
| 53 | * [...] | 56 | * [...] |
| 54 | * }; | 57 | * }; |
| 55 | * | 58 | * |
| 56 | * The __string() macro will create each int <str>, this is to | 59 | * The __dynamic_array() macro will create each int <item>, this is |
| 57 | * keep the offset of each string from the beggining of the event | 60 | * to keep the offset of each array from the beginning of the event. |
| 58 | * once we perform the strlen() of the src strings. | ||
| 59 | * | ||
| 60 | */ | 61 | */ |
| 61 | 62 | ||
| 63 | #undef __field | ||
| 64 | #define __field(type, item); | ||
| 65 | |||
| 62 | #undef __array | 66 | #undef __array |
| 63 | #define __array(type, item, len) | 67 | #define __array(type, item, len) |
| 64 | 68 | ||
| 65 | #undef __field | 69 | #undef __dynamic_array |
| 66 | #define __field(type, item); | 70 | #define __dynamic_array(type, item, len) int item; |
| 67 | 71 | ||
| 68 | #undef __string | 72 | #undef __string |
| 69 | #define __string(item, src) int item; | 73 | #define __string(item, src) __dynamic_array(char, item, -1) |
| 70 | 74 | ||
| 71 | #undef TRACE_EVENT | 75 | #undef TRACE_EVENT |
| 72 | #define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ | 76 | #define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ |
| 73 | struct ftrace_str_offsets_##call { \ | 77 | struct ftrace_data_offsets_##call { \ |
| 74 | tstruct; \ | 78 | tstruct; \ |
| 75 | }; | 79 | }; |
| 76 | 80 | ||
| @@ -119,8 +123,12 @@ | |||
| 119 | #undef TP_printk | 123 | #undef TP_printk |
| 120 | #define TP_printk(fmt, args...) fmt "\n", args | 124 | #define TP_printk(fmt, args...) fmt "\n", args |
| 121 | 125 | ||
| 126 | #undef __get_dynamic_array | ||
| 127 | #define __get_dynamic_array(field) \ | ||
| 128 | ((void *)__entry + __entry->__data_loc_##field) | ||
| 129 | |||
| 122 | #undef __get_str | 130 | #undef __get_str |
| 123 | #define __get_str(field) ((char *)__entry + __entry->__str_loc_##field) | 131 | #define __get_str(field) (char *)__get_dynamic_array(field) |
| 124 | 132 | ||
| 125 | #undef __print_flags | 133 | #undef __print_flags |
| 126 | #define __print_flags(flag, delim, flag_array...) \ | 134 | #define __print_flags(flag, delim, flag_array...) \ |
| @@ -207,16 +215,19 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \ | |||
| 207 | if (!ret) \ | 215 | if (!ret) \ |
| 208 | return 0; | 216 | return 0; |
| 209 | 217 | ||
| 210 | #undef __string | 218 | #undef __dynamic_array |
| 211 | #define __string(item, src) \ | 219 | #define __dynamic_array(type, item, len) \ |
| 212 | ret = trace_seq_printf(s, "\tfield:__str_loc " #item ";\t" \ | 220 | ret = trace_seq_printf(s, "\tfield:__data_loc " #item ";\t" \ |
| 213 | "offset:%u;\tsize:%u;\n", \ | 221 | "offset:%u;\tsize:%u;\n", \ |
| 214 | (unsigned int)offsetof(typeof(field), \ | 222 | (unsigned int)offsetof(typeof(field), \ |
| 215 | __str_loc_##item), \ | 223 | __data_loc_##item), \ |
| 216 | (unsigned int)sizeof(field.__str_loc_##item)); \ | 224 | (unsigned int)sizeof(field.__data_loc_##item)); \ |
| 217 | if (!ret) \ | 225 | if (!ret) \ |
| 218 | return 0; | 226 | return 0; |
| 219 | 227 | ||
| 228 | #undef __string | ||
| 229 | #define __string(item, src) __dynamic_array(char, item, -1) | ||
| 230 | |||
| 220 | #undef __entry | 231 | #undef __entry |
| 221 | #define __entry REC | 232 | #define __entry REC |
| 222 | 233 | ||
| @@ -260,11 +271,14 @@ ftrace_format_##call(struct trace_seq *s) \ | |||
| 260 | if (ret) \ | 271 | if (ret) \ |
| 261 | return ret; | 272 | return ret; |
| 262 | 273 | ||
| 274 | #undef __dynamic_array | ||
| 275 | #define __dynamic_array(type, item, len) \ | ||
| 276 | ret = trace_define_field(event_call, "__data_loc" "[" #type "]", #item,\ | ||
| 277 | offsetof(typeof(field), __data_loc_##item), \ | ||
| 278 | sizeof(field.__data_loc_##item), 0); | ||
| 279 | |||
| 263 | #undef __string | 280 | #undef __string |
| 264 | #define __string(item, src) \ | 281 | #define __string(item, src) __dynamic_array(char, item, -1) |
| 265 | ret = trace_define_field(event_call, "__str_loc", #item, \ | ||
| 266 | offsetof(typeof(field), __str_loc_##item), \ | ||
| 267 | sizeof(field.__str_loc_##item), 0); | ||
| 268 | 282 | ||
| 269 | #undef TRACE_EVENT | 283 | #undef TRACE_EVENT |
| 270 | #define TRACE_EVENT(call, proto, args, tstruct, func, print) \ | 284 | #define TRACE_EVENT(call, proto, args, tstruct, func, print) \ |
| @@ -289,6 +303,43 @@ ftrace_define_fields_##call(void) \ | |||
| 289 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) | 303 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) |
| 290 | 304 | ||
| 291 | /* | 305 | /* |
| 306 | * remember the offset of each array from the beginning of the event. | ||
| 307 | */ | ||
| 308 | |||
| 309 | #undef __entry | ||
| 310 | #define __entry entry | ||
| 311 | |||
| 312 | #undef __field | ||
| 313 | #define __field(type, item) | ||
| 314 | |||
| 315 | #undef __array | ||
| 316 | #define __array(type, item, len) | ||
| 317 | |||
| 318 | #undef __dynamic_array | ||
| 319 | #define __dynamic_array(type, item, len) \ | ||
| 320 | __data_offsets->item = __data_size + \ | ||
| 321 | offsetof(typeof(*entry), __data); \ | ||
| 322 | __data_size += (len) * sizeof(type); | ||
| 323 | |||
| 324 | #undef __string | ||
| 325 | #define __string(item, src) __dynamic_array(char, item, strlen(src) + 1) \ | ||
| 326 | |||
| 327 | #undef TRACE_EVENT | ||
| 328 | #define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ | ||
| 329 | static inline int ftrace_get_offsets_##call( \ | ||
| 330 | struct ftrace_data_offsets_##call *__data_offsets, proto) \ | ||
| 331 | { \ | ||
| 332 | int __data_size = 0; \ | ||
| 333 | struct ftrace_raw_##call __maybe_unused *entry; \ | ||
| 334 | \ | ||
| 335 | tstruct; \ | ||
| 336 | \ | ||
| 337 | return __data_size; \ | ||
| 338 | } | ||
| 339 | |||
| 340 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) | ||
| 341 | |||
| 342 | /* | ||
| 292 | * Stage 4 of the trace events. | 343 | * Stage 4 of the trace events. |
| 293 | * | 344 | * |
| 294 | * Override the macros in <trace/trace_events.h> to include the following: | 345 | * Override the macros in <trace/trace_events.h> to include the following: |
| @@ -432,15 +483,15 @@ static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\ | |||
| 432 | #undef __array | 483 | #undef __array |
| 433 | #define __array(type, item, len) | 484 | #define __array(type, item, len) |
| 434 | 485 | ||
| 486 | #undef __dynamic_array | ||
| 487 | #define __dynamic_array(type, item, len) \ | ||
| 488 | __entry->__data_loc_##item = __data_offsets.item; | ||
| 489 | |||
| 435 | #undef __string | 490 | #undef __string |
| 436 | #define __string(item, src) \ | 491 | #define __string(item, src) __dynamic_array(char, item, -1) \ |
| 437 | __str_offsets.item = __str_size + \ | ||
| 438 | offsetof(typeof(*entry), __str_data); \ | ||
| 439 | __str_size += strlen(src) + 1; | ||
| 440 | 492 | ||
| 441 | #undef __assign_str | 493 | #undef __assign_str |
| 442 | #define __assign_str(dst, src) \ | 494 | #define __assign_str(dst, src) \ |
| 443 | __entry->__str_loc_##dst = __str_offsets.dst; \ | ||
| 444 | strcpy(__get_str(dst), src); | 495 | strcpy(__get_str(dst), src); |
| 445 | 496 | ||
| 446 | #undef TRACE_EVENT | 497 | #undef TRACE_EVENT |
| @@ -451,26 +502,29 @@ static struct ftrace_event_call event_##call; \ | |||
| 451 | \ | 502 | \ |
| 452 | static void ftrace_raw_event_##call(proto) \ | 503 | static void ftrace_raw_event_##call(proto) \ |
| 453 | { \ | 504 | { \ |
| 454 | struct ftrace_str_offsets_##call __maybe_unused __str_offsets; \ | 505 | struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ |
| 455 | struct ftrace_event_call *event_call = &event_##call; \ | 506 | struct ftrace_event_call *event_call = &event_##call; \ |
| 456 | struct ring_buffer_event *event; \ | 507 | struct ring_buffer_event *event; \ |
| 457 | struct ftrace_raw_##call *entry; \ | 508 | struct ftrace_raw_##call *entry; \ |
| 458 | unsigned long irq_flags; \ | 509 | unsigned long irq_flags; \ |
| 459 | int __str_size = 0; \ | 510 | int __data_size; \ |
| 460 | int pc; \ | 511 | int pc; \ |
| 461 | \ | 512 | \ |
| 462 | local_save_flags(irq_flags); \ | 513 | local_save_flags(irq_flags); \ |
| 463 | pc = preempt_count(); \ | 514 | pc = preempt_count(); \ |
| 464 | \ | 515 | \ |
| 465 | tstruct; \ | 516 | __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ |
| 466 | \ | 517 | \ |
| 467 | event = trace_current_buffer_lock_reserve(event_##call.id, \ | 518 | event = trace_current_buffer_lock_reserve(event_##call.id, \ |
| 468 | sizeof(struct ftrace_raw_##call) + __str_size,\ | 519 | sizeof(*entry) + __data_size, \ |
| 469 | irq_flags, pc); \ | 520 | irq_flags, pc); \ |
| 470 | if (!event) \ | 521 | if (!event) \ |
| 471 | return; \ | 522 | return; \ |
| 472 | entry = ring_buffer_event_data(event); \ | 523 | entry = ring_buffer_event_data(event); \ |
| 473 | \ | 524 | \ |
| 525 | \ | ||
| 526 | tstruct \ | ||
| 527 | \ | ||
| 474 | { assign; } \ | 528 | { assign; } \ |
| 475 | \ | 529 | \ |
| 476 | if (!filter_current_check_discard(event_call, entry, event)) \ | 530 | if (!filter_current_check_discard(event_call, entry, event)) \ |
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index a7430b16d243..db6e54bdb596 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
| @@ -478,12 +478,12 @@ enum { | |||
| 478 | 478 | ||
| 479 | static int is_string_field(const char *type) | 479 | static int is_string_field(const char *type) |
| 480 | { | 480 | { |
| 481 | if (strstr(type, "__data_loc") && strstr(type, "char")) | ||
| 482 | return FILTER_DYN_STRING; | ||
| 483 | |||
| 481 | if (strchr(type, '[') && strstr(type, "char")) | 484 | if (strchr(type, '[') && strstr(type, "char")) |
| 482 | return FILTER_STATIC_STRING; | 485 | return FILTER_STATIC_STRING; |
| 483 | 486 | ||
| 484 | if (!strcmp(type, "__str_loc")) | ||
| 485 | return FILTER_DYN_STRING; | ||
| 486 | |||
| 487 | return 0; | 487 | return 0; |
| 488 | } | 488 | } |
| 489 | 489 | ||
