diff options
Diffstat (limited to 'kernel/trace/trace.c')
| -rw-r--r-- | kernel/trace/trace.c | 326 |
1 files changed, 207 insertions, 119 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index ee9c921d7f21..e5df02c69b1d 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -343,26 +343,27 @@ unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK | | |||
| 343 | static int trace_stop_count; | 343 | static int trace_stop_count; |
| 344 | static DEFINE_SPINLOCK(tracing_start_lock); | 344 | static DEFINE_SPINLOCK(tracing_start_lock); |
| 345 | 345 | ||
| 346 | static void wakeup_work_handler(struct work_struct *work) | ||
| 347 | { | ||
| 348 | wake_up(&trace_wait); | ||
| 349 | } | ||
| 350 | |||
| 351 | static DECLARE_DELAYED_WORK(wakeup_work, wakeup_work_handler); | ||
| 352 | |||
| 346 | /** | 353 | /** |
| 347 | * trace_wake_up - wake up tasks waiting for trace input | 354 | * trace_wake_up - wake up tasks waiting for trace input |
| 348 | * | 355 | * |
| 349 | * Simply wakes up any task that is blocked on the trace_wait | 356 | * Schedules a delayed work to wake up any task that is blocked on the |
| 350 | * queue. These is used with trace_poll for tasks polling the trace. | 357 | * trace_wait queue. These is used with trace_poll for tasks polling the |
| 358 | * trace. | ||
| 351 | */ | 359 | */ |
| 352 | void trace_wake_up(void) | 360 | void trace_wake_up(void) |
| 353 | { | 361 | { |
| 354 | int cpu; | 362 | const unsigned long delay = msecs_to_jiffies(2); |
| 355 | 363 | ||
| 356 | if (trace_flags & TRACE_ITER_BLOCK) | 364 | if (trace_flags & TRACE_ITER_BLOCK) |
| 357 | return; | 365 | return; |
| 358 | /* | 366 | schedule_delayed_work(&wakeup_work, delay); |
| 359 | * The runqueue_is_locked() can fail, but this is the best we | ||
| 360 | * have for now: | ||
| 361 | */ | ||
| 362 | cpu = get_cpu(); | ||
| 363 | if (!runqueue_is_locked(cpu)) | ||
| 364 | wake_up(&trace_wait); | ||
| 365 | put_cpu(); | ||
| 366 | } | 367 | } |
| 367 | 368 | ||
| 368 | static int __init set_buf_size(char *str) | 369 | static int __init set_buf_size(char *str) |
| @@ -424,6 +425,7 @@ static const char *trace_options[] = { | |||
| 424 | "graph-time", | 425 | "graph-time", |
| 425 | "record-cmd", | 426 | "record-cmd", |
| 426 | "overwrite", | 427 | "overwrite", |
| 428 | "disable_on_free", | ||
| 427 | NULL | 429 | NULL |
| 428 | }; | 430 | }; |
| 429 | 431 | ||
| @@ -1191,6 +1193,18 @@ void trace_nowake_buffer_unlock_commit(struct ring_buffer *buffer, | |||
| 1191 | } | 1193 | } |
| 1192 | EXPORT_SYMBOL_GPL(trace_nowake_buffer_unlock_commit); | 1194 | EXPORT_SYMBOL_GPL(trace_nowake_buffer_unlock_commit); |
| 1193 | 1195 | ||
| 1196 | void trace_nowake_buffer_unlock_commit_regs(struct ring_buffer *buffer, | ||
| 1197 | struct ring_buffer_event *event, | ||
| 1198 | unsigned long flags, int pc, | ||
| 1199 | struct pt_regs *regs) | ||
| 1200 | { | ||
| 1201 | ring_buffer_unlock_commit(buffer, event); | ||
| 1202 | |||
| 1203 | ftrace_trace_stack_regs(buffer, flags, 0, pc, regs); | ||
| 1204 | ftrace_trace_userstack(buffer, flags, pc); | ||
| 1205 | } | ||
| 1206 | EXPORT_SYMBOL_GPL(trace_nowake_buffer_unlock_commit_regs); | ||
| 1207 | |||
| 1194 | void trace_current_buffer_discard_commit(struct ring_buffer *buffer, | 1208 | void trace_current_buffer_discard_commit(struct ring_buffer *buffer, |
| 1195 | struct ring_buffer_event *event) | 1209 | struct ring_buffer_event *event) |
| 1196 | { | 1210 | { |
| @@ -1234,30 +1248,103 @@ ftrace(struct trace_array *tr, struct trace_array_cpu *data, | |||
| 1234 | } | 1248 | } |
| 1235 | 1249 | ||
| 1236 | #ifdef CONFIG_STACKTRACE | 1250 | #ifdef CONFIG_STACKTRACE |
| 1251 | |||
| 1252 | #define FTRACE_STACK_MAX_ENTRIES (PAGE_SIZE / sizeof(unsigned long)) | ||
| 1253 | struct ftrace_stack { | ||
| 1254 | unsigned long calls[FTRACE_STACK_MAX_ENTRIES]; | ||
| 1255 | }; | ||
| 1256 | |||
| 1257 | static DEFINE_PER_CPU(struct ftrace_stack, ftrace_stack); | ||
| 1258 | static DEFINE_PER_CPU(int, ftrace_stack_reserve); | ||
| 1259 | |||
| 1237 | static void __ftrace_trace_stack(struct ring_buffer *buffer, | 1260 | static void __ftrace_trace_stack(struct ring_buffer *buffer, |
| 1238 | unsigned long flags, | 1261 | unsigned long flags, |
| 1239 | int skip, int pc) | 1262 | int skip, int pc, struct pt_regs *regs) |
| 1240 | { | 1263 | { |
| 1241 | struct ftrace_event_call *call = &event_kernel_stack; | 1264 | struct ftrace_event_call *call = &event_kernel_stack; |
| 1242 | struct ring_buffer_event *event; | 1265 | struct ring_buffer_event *event; |
| 1243 | struct stack_entry *entry; | 1266 | struct stack_entry *entry; |
| 1244 | struct stack_trace trace; | 1267 | struct stack_trace trace; |
| 1268 | int use_stack; | ||
| 1269 | int size = FTRACE_STACK_ENTRIES; | ||
| 1270 | |||
| 1271 | trace.nr_entries = 0; | ||
| 1272 | trace.skip = skip; | ||
| 1273 | |||
| 1274 | /* | ||
| 1275 | * Since events can happen in NMIs there's no safe way to | ||
| 1276 | * use the per cpu ftrace_stacks. We reserve it and if an interrupt | ||
| 1277 | * or NMI comes in, it will just have to use the default | ||
| 1278 | * FTRACE_STACK_SIZE. | ||
| 1279 | */ | ||
| 1280 | preempt_disable_notrace(); | ||
| 1281 | |||
| 1282 | use_stack = ++__get_cpu_var(ftrace_stack_reserve); | ||
| 1283 | /* | ||
| 1284 | * We don't need any atomic variables, just a barrier. | ||
| 1285 | * If an interrupt comes in, we don't care, because it would | ||
| 1286 | * have exited and put the counter back to what we want. | ||
| 1287 | * We just need a barrier to keep gcc from moving things | ||
| 1288 | * around. | ||
| 1289 | */ | ||
| 1290 | barrier(); | ||
| 1291 | if (use_stack == 1) { | ||
| 1292 | trace.entries = &__get_cpu_var(ftrace_stack).calls[0]; | ||
| 1293 | trace.max_entries = FTRACE_STACK_MAX_ENTRIES; | ||
| 1294 | |||
| 1295 | if (regs) | ||
| 1296 | save_stack_trace_regs(regs, &trace); | ||
| 1297 | else | ||
| 1298 | save_stack_trace(&trace); | ||
| 1299 | |||
| 1300 | if (trace.nr_entries > size) | ||
| 1301 | size = trace.nr_entries; | ||
| 1302 | } else | ||
| 1303 | /* From now on, use_stack is a boolean */ | ||
| 1304 | use_stack = 0; | ||
| 1305 | |||
| 1306 | size *= sizeof(unsigned long); | ||
| 1245 | 1307 | ||
| 1246 | event = trace_buffer_lock_reserve(buffer, TRACE_STACK, | 1308 | event = trace_buffer_lock_reserve(buffer, TRACE_STACK, |
| 1247 | sizeof(*entry), flags, pc); | 1309 | sizeof(*entry) + size, flags, pc); |
| 1248 | if (!event) | 1310 | if (!event) |
| 1249 | return; | 1311 | goto out; |
| 1250 | entry = ring_buffer_event_data(event); | 1312 | entry = ring_buffer_event_data(event); |
| 1251 | memset(&entry->caller, 0, sizeof(entry->caller)); | ||
| 1252 | 1313 | ||
| 1253 | trace.nr_entries = 0; | 1314 | memset(&entry->caller, 0, size); |
| 1254 | trace.max_entries = FTRACE_STACK_ENTRIES; | 1315 | |
| 1255 | trace.skip = skip; | 1316 | if (use_stack) |
| 1256 | trace.entries = entry->caller; | 1317 | memcpy(&entry->caller, trace.entries, |
| 1318 | trace.nr_entries * sizeof(unsigned long)); | ||
| 1319 | else { | ||
| 1320 | trace.max_entries = FTRACE_STACK_ENTRIES; | ||
| 1321 | trace.entries = entry->caller; | ||
| 1322 | if (regs) | ||
| 1323 | save_stack_trace_regs(regs, &trace); | ||
| 1324 | else | ||
| 1325 | save_stack_trace(&trace); | ||
| 1326 | } | ||
| 1327 | |||
| 1328 | entry->size = trace.nr_entries; | ||
| 1257 | 1329 | ||
| 1258 | save_stack_trace(&trace); | ||
| 1259 | if (!filter_check_discard(call, entry, buffer, event)) | 1330 | if (!filter_check_discard(call, entry, buffer, event)) |
| 1260 | ring_buffer_unlock_commit(buffer, event); | 1331 | ring_buffer_unlock_commit(buffer, event); |
| 1332 | |||
| 1333 | out: | ||
| 1334 | /* Again, don't let gcc optimize things here */ | ||
| 1335 | barrier(); | ||
| 1336 | __get_cpu_var(ftrace_stack_reserve)--; | ||
| 1337 | preempt_enable_notrace(); | ||
| 1338 | |||
| 1339 | } | ||
| 1340 | |||
| 1341 | void ftrace_trace_stack_regs(struct ring_buffer *buffer, unsigned long flags, | ||
| 1342 | int skip, int pc, struct pt_regs *regs) | ||
| 1343 | { | ||
| 1344 | if (!(trace_flags & TRACE_ITER_STACKTRACE)) | ||
| 1345 | return; | ||
| 1346 | |||
| 1347 | __ftrace_trace_stack(buffer, flags, skip, pc, regs); | ||
| 1261 | } | 1348 | } |
| 1262 | 1349 | ||
| 1263 | void ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags, | 1350 | void ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags, |
| @@ -1266,13 +1353,13 @@ void ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags, | |||
| 1266 | if (!(trace_flags & TRACE_ITER_STACKTRACE)) | 1353 | if (!(trace_flags & TRACE_ITER_STACKTRACE)) |
| 1267 | return; | 1354 | return; |
| 1268 | 1355 | ||
| 1269 | __ftrace_trace_stack(buffer, flags, skip, pc); | 1356 | __ftrace_trace_stack(buffer, flags, skip, pc, NULL); |
| 1270 | } | 1357 | } |
| 1271 | 1358 | ||
| 1272 | void __trace_stack(struct trace_array *tr, unsigned long flags, int skip, | 1359 | void __trace_stack(struct trace_array *tr, unsigned long flags, int skip, |
| 1273 | int pc) | 1360 | int pc) |
| 1274 | { | 1361 | { |
| 1275 | __ftrace_trace_stack(tr->buffer, flags, skip, pc); | 1362 | __ftrace_trace_stack(tr->buffer, flags, skip, pc, NULL); |
| 1276 | } | 1363 | } |
| 1277 | 1364 | ||
| 1278 | /** | 1365 | /** |
| @@ -1288,7 +1375,7 @@ void trace_dump_stack(void) | |||
| 1288 | local_save_flags(flags); | 1375 | local_save_flags(flags); |
| 1289 | 1376 | ||
| 1290 | /* skipping 3 traces, seems to get us at the caller of this function */ | 1377 | /* skipping 3 traces, seems to get us at the caller of this function */ |
| 1291 | __ftrace_trace_stack(global_trace.buffer, flags, 3, preempt_count()); | 1378 | __ftrace_trace_stack(global_trace.buffer, flags, 3, preempt_count(), NULL); |
| 1292 | } | 1379 | } |
| 1293 | 1380 | ||
| 1294 | static DEFINE_PER_CPU(int, user_stack_count); | 1381 | static DEFINE_PER_CPU(int, user_stack_count); |
| @@ -1536,7 +1623,12 @@ peek_next_entry(struct trace_iterator *iter, int cpu, u64 *ts, | |||
| 1536 | 1623 | ||
| 1537 | ftrace_enable_cpu(); | 1624 | ftrace_enable_cpu(); |
| 1538 | 1625 | ||
| 1539 | return event ? ring_buffer_event_data(event) : NULL; | 1626 | if (event) { |
| 1627 | iter->ent_size = ring_buffer_event_length(event); | ||
| 1628 | return ring_buffer_event_data(event); | ||
| 1629 | } | ||
| 1630 | iter->ent_size = 0; | ||
| 1631 | return NULL; | ||
| 1540 | } | 1632 | } |
| 1541 | 1633 | ||
| 1542 | static struct trace_entry * | 1634 | static struct trace_entry * |
| @@ -2051,6 +2143,9 @@ void trace_default_header(struct seq_file *m) | |||
| 2051 | { | 2143 | { |
| 2052 | struct trace_iterator *iter = m->private; | 2144 | struct trace_iterator *iter = m->private; |
| 2053 | 2145 | ||
| 2146 | if (!(trace_flags & TRACE_ITER_CONTEXT_INFO)) | ||
| 2147 | return; | ||
| 2148 | |||
| 2054 | if (iter->iter_flags & TRACE_FILE_LAT_FMT) { | 2149 | if (iter->iter_flags & TRACE_FILE_LAT_FMT) { |
| 2055 | /* print nothing if the buffers are empty */ | 2150 | /* print nothing if the buffers are empty */ |
| 2056 | if (trace_empty(iter)) | 2151 | if (trace_empty(iter)) |
| @@ -2701,20 +2796,11 @@ tracing_ctrl_write(struct file *filp, const char __user *ubuf, | |||
| 2701 | size_t cnt, loff_t *ppos) | 2796 | size_t cnt, loff_t *ppos) |
| 2702 | { | 2797 | { |
| 2703 | struct trace_array *tr = filp->private_data; | 2798 | struct trace_array *tr = filp->private_data; |
| 2704 | char buf[64]; | ||
| 2705 | unsigned long val; | 2799 | unsigned long val; |
| 2706 | int ret; | 2800 | int ret; |
| 2707 | 2801 | ||
| 2708 | if (cnt >= sizeof(buf)) | 2802 | ret = kstrtoul_from_user(ubuf, cnt, 10, &val); |
| 2709 | return -EINVAL; | 2803 | if (ret) |
| 2710 | |||
| 2711 | if (copy_from_user(&buf, ubuf, cnt)) | ||
| 2712 | return -EFAULT; | ||
| 2713 | |||
| 2714 | buf[cnt] = 0; | ||
| 2715 | |||
| 2716 | ret = strict_strtoul(buf, 10, &val); | ||
| 2717 | if (ret < 0) | ||
| 2718 | return ret; | 2804 | return ret; |
| 2719 | 2805 | ||
| 2720 | val = !!val; | 2806 | val = !!val; |
| @@ -2767,7 +2853,7 @@ int tracer_init(struct tracer *t, struct trace_array *tr) | |||
| 2767 | return t->init(tr); | 2853 | return t->init(tr); |
| 2768 | } | 2854 | } |
| 2769 | 2855 | ||
| 2770 | static int tracing_resize_ring_buffer(unsigned long size) | 2856 | static int __tracing_resize_ring_buffer(unsigned long size) |
| 2771 | { | 2857 | { |
| 2772 | int ret; | 2858 | int ret; |
| 2773 | 2859 | ||
| @@ -2819,6 +2905,41 @@ static int tracing_resize_ring_buffer(unsigned long size) | |||
| 2819 | return ret; | 2905 | return ret; |
| 2820 | } | 2906 | } |
| 2821 | 2907 | ||
| 2908 | static ssize_t tracing_resize_ring_buffer(unsigned long size) | ||
| 2909 | { | ||
| 2910 | int cpu, ret = size; | ||
| 2911 | |||
| 2912 | mutex_lock(&trace_types_lock); | ||
| 2913 | |||
| 2914 | tracing_stop(); | ||
| 2915 | |||
| 2916 | /* disable all cpu buffers */ | ||
| 2917 | for_each_tracing_cpu(cpu) { | ||
| 2918 | if (global_trace.data[cpu]) | ||
| 2919 | atomic_inc(&global_trace.data[cpu]->disabled); | ||
| 2920 | if (max_tr.data[cpu]) | ||
| 2921 | atomic_inc(&max_tr.data[cpu]->disabled); | ||
| 2922 | } | ||
| 2923 | |||
| 2924 | if (size != global_trace.entries) | ||
| 2925 | ret = __tracing_resize_ring_buffer(size); | ||
| 2926 | |||
| 2927 | if (ret < 0) | ||
| 2928 | ret = -ENOMEM; | ||
| 2929 | |||
| 2930 | for_each_tracing_cpu(cpu) { | ||
| 2931 | if (global_trace.data[cpu]) | ||
| 2932 | atomic_dec(&global_trace.data[cpu]->disabled); | ||
| 2933 | if (max_tr.data[cpu]) | ||
| 2934 | atomic_dec(&max_tr.data[cpu]->disabled); | ||
| 2935 | } | ||
| 2936 | |||
| 2937 | tracing_start(); | ||
| 2938 | mutex_unlock(&trace_types_lock); | ||
| 2939 | |||
| 2940 | return ret; | ||
| 2941 | } | ||
| 2942 | |||
| 2822 | 2943 | ||
| 2823 | /** | 2944 | /** |
| 2824 | * tracing_update_buffers - used by tracing facility to expand ring buffers | 2945 | * tracing_update_buffers - used by tracing facility to expand ring buffers |
| @@ -2836,7 +2957,7 @@ int tracing_update_buffers(void) | |||
| 2836 | 2957 | ||
| 2837 | mutex_lock(&trace_types_lock); | 2958 | mutex_lock(&trace_types_lock); |
| 2838 | if (!ring_buffer_expanded) | 2959 | if (!ring_buffer_expanded) |
| 2839 | ret = tracing_resize_ring_buffer(trace_buf_size); | 2960 | ret = __tracing_resize_ring_buffer(trace_buf_size); |
| 2840 | mutex_unlock(&trace_types_lock); | 2961 | mutex_unlock(&trace_types_lock); |
| 2841 | 2962 | ||
| 2842 | return ret; | 2963 | return ret; |
| @@ -2860,7 +2981,7 @@ static int tracing_set_tracer(const char *buf) | |||
| 2860 | mutex_lock(&trace_types_lock); | 2981 | mutex_lock(&trace_types_lock); |
| 2861 | 2982 | ||
| 2862 | if (!ring_buffer_expanded) { | 2983 | if (!ring_buffer_expanded) { |
| 2863 | ret = tracing_resize_ring_buffer(trace_buf_size); | 2984 | ret = __tracing_resize_ring_buffer(trace_buf_size); |
| 2864 | if (ret < 0) | 2985 | if (ret < 0) |
| 2865 | goto out; | 2986 | goto out; |
| 2866 | ret = 0; | 2987 | ret = 0; |
| @@ -2966,20 +3087,11 @@ tracing_max_lat_write(struct file *filp, const char __user *ubuf, | |||
| 2966 | size_t cnt, loff_t *ppos) | 3087 | size_t cnt, loff_t *ppos) |
| 2967 | { | 3088 | { |
| 2968 | unsigned long *ptr = filp->private_data; | 3089 | unsigned long *ptr = filp->private_data; |
| 2969 | char buf[64]; | ||
| 2970 | unsigned long val; | 3090 | unsigned long val; |
| 2971 | int ret; | 3091 | int ret; |
| 2972 | 3092 | ||
| 2973 | if (cnt >= sizeof(buf)) | 3093 | ret = kstrtoul_from_user(ubuf, cnt, 10, &val); |
| 2974 | return -EINVAL; | 3094 | if (ret) |
| 2975 | |||
| 2976 | if (copy_from_user(&buf, ubuf, cnt)) | ||
| 2977 | return -EFAULT; | ||
| 2978 | |||
| 2979 | buf[cnt] = 0; | ||
| 2980 | |||
| 2981 | ret = strict_strtoul(buf, 10, &val); | ||
| 2982 | if (ret < 0) | ||
| 2983 | return ret; | 3095 | return ret; |
| 2984 | 3096 | ||
| 2985 | *ptr = val * 1000; | 3097 | *ptr = val * 1000; |
| @@ -3434,67 +3546,54 @@ tracing_entries_write(struct file *filp, const char __user *ubuf, | |||
| 3434 | size_t cnt, loff_t *ppos) | 3546 | size_t cnt, loff_t *ppos) |
| 3435 | { | 3547 | { |
| 3436 | unsigned long val; | 3548 | unsigned long val; |
| 3437 | char buf[64]; | 3549 | int ret; |
| 3438 | int ret, cpu; | ||
| 3439 | |||
| 3440 | if (cnt >= sizeof(buf)) | ||
| 3441 | return -EINVAL; | ||
| 3442 | |||
| 3443 | if (copy_from_user(&buf, ubuf, cnt)) | ||
| 3444 | return -EFAULT; | ||
| 3445 | |||
| 3446 | buf[cnt] = 0; | ||
| 3447 | 3550 | ||
| 3448 | ret = strict_strtoul(buf, 10, &val); | 3551 | ret = kstrtoul_from_user(ubuf, cnt, 10, &val); |
| 3449 | if (ret < 0) | 3552 | if (ret) |
| 3450 | return ret; | 3553 | return ret; |
| 3451 | 3554 | ||
| 3452 | /* must have at least 1 entry */ | 3555 | /* must have at least 1 entry */ |
| 3453 | if (!val) | 3556 | if (!val) |
| 3454 | return -EINVAL; | 3557 | return -EINVAL; |
| 3455 | 3558 | ||
| 3456 | mutex_lock(&trace_types_lock); | ||
| 3457 | |||
| 3458 | tracing_stop(); | ||
| 3459 | |||
| 3460 | /* disable all cpu buffers */ | ||
| 3461 | for_each_tracing_cpu(cpu) { | ||
| 3462 | if (global_trace.data[cpu]) | ||
| 3463 | atomic_inc(&global_trace.data[cpu]->disabled); | ||
| 3464 | if (max_tr.data[cpu]) | ||
| 3465 | atomic_inc(&max_tr.data[cpu]->disabled); | ||
| 3466 | } | ||
| 3467 | |||
| 3468 | /* value is in KB */ | 3559 | /* value is in KB */ |
| 3469 | val <<= 10; | 3560 | val <<= 10; |
| 3470 | 3561 | ||
| 3471 | if (val != global_trace.entries) { | 3562 | ret = tracing_resize_ring_buffer(val); |
| 3472 | ret = tracing_resize_ring_buffer(val); | 3563 | if (ret < 0) |
| 3473 | if (ret < 0) { | 3564 | return ret; |
| 3474 | cnt = ret; | ||
| 3475 | goto out; | ||
| 3476 | } | ||
| 3477 | } | ||
| 3478 | 3565 | ||
| 3479 | *ppos += cnt; | 3566 | *ppos += cnt; |
| 3480 | 3567 | ||
| 3481 | /* If check pages failed, return ENOMEM */ | 3568 | return cnt; |
| 3482 | if (tracing_disabled) | 3569 | } |
| 3483 | cnt = -ENOMEM; | ||
| 3484 | out: | ||
| 3485 | for_each_tracing_cpu(cpu) { | ||
| 3486 | if (global_trace.data[cpu]) | ||
| 3487 | atomic_dec(&global_trace.data[cpu]->disabled); | ||
| 3488 | if (max_tr.data[cpu]) | ||
| 3489 | atomic_dec(&max_tr.data[cpu]->disabled); | ||
| 3490 | } | ||
| 3491 | 3570 | ||
| 3492 | tracing_start(); | 3571 | static ssize_t |
| 3493 | mutex_unlock(&trace_types_lock); | 3572 | tracing_free_buffer_write(struct file *filp, const char __user *ubuf, |
| 3573 | size_t cnt, loff_t *ppos) | ||
| 3574 | { | ||
| 3575 | /* | ||
| 3576 | * There is no need to read what the user has written, this function | ||
| 3577 | * is just to make sure that there is no error when "echo" is used | ||
| 3578 | */ | ||
| 3579 | |||
| 3580 | *ppos += cnt; | ||
| 3494 | 3581 | ||
| 3495 | return cnt; | 3582 | return cnt; |
| 3496 | } | 3583 | } |
| 3497 | 3584 | ||
| 3585 | static int | ||
| 3586 | tracing_free_buffer_release(struct inode *inode, struct file *filp) | ||
| 3587 | { | ||
| 3588 | /* disable tracing ? */ | ||
| 3589 | if (trace_flags & TRACE_ITER_STOP_ON_FREE) | ||
| 3590 | tracing_off(); | ||
| 3591 | /* resize the ring buffer to 0 */ | ||
| 3592 | tracing_resize_ring_buffer(0); | ||
| 3593 | |||
| 3594 | return 0; | ||
| 3595 | } | ||
| 3596 | |||
| 3498 | static int mark_printk(const char *fmt, ...) | 3597 | static int mark_printk(const char *fmt, ...) |
| 3499 | { | 3598 | { |
| 3500 | int ret; | 3599 | int ret; |
| @@ -3640,6 +3739,11 @@ static const struct file_operations tracing_entries_fops = { | |||
| 3640 | .llseek = generic_file_llseek, | 3739 | .llseek = generic_file_llseek, |
| 3641 | }; | 3740 | }; |
| 3642 | 3741 | ||
| 3742 | static const struct file_operations tracing_free_buffer_fops = { | ||
| 3743 | .write = tracing_free_buffer_write, | ||
| 3744 | .release = tracing_free_buffer_release, | ||
| 3745 | }; | ||
| 3746 | |||
| 3643 | static const struct file_operations tracing_mark_fops = { | 3747 | static const struct file_operations tracing_mark_fops = { |
| 3644 | .open = tracing_open_generic, | 3748 | .open = tracing_open_generic, |
| 3645 | .write = tracing_mark_write, | 3749 | .write = tracing_mark_write, |
| @@ -3696,7 +3800,7 @@ tracing_buffers_read(struct file *filp, char __user *ubuf, | |||
| 3696 | return 0; | 3800 | return 0; |
| 3697 | 3801 | ||
| 3698 | if (!info->spare) | 3802 | if (!info->spare) |
| 3699 | info->spare = ring_buffer_alloc_read_page(info->tr->buffer); | 3803 | info->spare = ring_buffer_alloc_read_page(info->tr->buffer, info->cpu); |
| 3700 | if (!info->spare) | 3804 | if (!info->spare) |
| 3701 | return -ENOMEM; | 3805 | return -ENOMEM; |
| 3702 | 3806 | ||
| @@ -3853,7 +3957,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, | |||
| 3853 | 3957 | ||
| 3854 | ref->ref = 1; | 3958 | ref->ref = 1; |
| 3855 | ref->buffer = info->tr->buffer; | 3959 | ref->buffer = info->tr->buffer; |
| 3856 | ref->page = ring_buffer_alloc_read_page(ref->buffer); | 3960 | ref->page = ring_buffer_alloc_read_page(ref->buffer, info->cpu); |
| 3857 | if (!ref->page) { | 3961 | if (!ref->page) { |
| 3858 | kfree(ref); | 3962 | kfree(ref); |
| 3859 | break; | 3963 | break; |
| @@ -3862,8 +3966,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, | |||
| 3862 | r = ring_buffer_read_page(ref->buffer, &ref->page, | 3966 | r = ring_buffer_read_page(ref->buffer, &ref->page, |
| 3863 | len, info->cpu, 1); | 3967 | len, info->cpu, 1); |
| 3864 | if (r < 0) { | 3968 | if (r < 0) { |
| 3865 | ring_buffer_free_read_page(ref->buffer, | 3969 | ring_buffer_free_read_page(ref->buffer, ref->page); |
| 3866 | ref->page); | ||
| 3867 | kfree(ref); | 3970 | kfree(ref); |
| 3868 | break; | 3971 | break; |
| 3869 | } | 3972 | } |
| @@ -4099,19 +4202,10 @@ trace_options_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
| 4099 | { | 4202 | { |
| 4100 | struct trace_option_dentry *topt = filp->private_data; | 4203 | struct trace_option_dentry *topt = filp->private_data; |
| 4101 | unsigned long val; | 4204 | unsigned long val; |
| 4102 | char buf[64]; | ||
| 4103 | int ret; | 4205 | int ret; |
| 4104 | 4206 | ||
| 4105 | if (cnt >= sizeof(buf)) | 4207 | ret = kstrtoul_from_user(ubuf, cnt, 10, &val); |
| 4106 | return -EINVAL; | 4208 | if (ret) |
| 4107 | |||
| 4108 | if (copy_from_user(&buf, ubuf, cnt)) | ||
| 4109 | return -EFAULT; | ||
| 4110 | |||
| 4111 | buf[cnt] = 0; | ||
| 4112 | |||
| 4113 | ret = strict_strtoul(buf, 10, &val); | ||
| 4114 | if (ret < 0) | ||
| 4115 | return ret; | 4209 | return ret; |
| 4116 | 4210 | ||
| 4117 | if (val != 0 && val != 1) | 4211 | if (val != 0 && val != 1) |
| @@ -4159,20 +4253,11 @@ trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
| 4159 | loff_t *ppos) | 4253 | loff_t *ppos) |
| 4160 | { | 4254 | { |
| 4161 | long index = (long)filp->private_data; | 4255 | long index = (long)filp->private_data; |
| 4162 | char buf[64]; | ||
| 4163 | unsigned long val; | 4256 | unsigned long val; |
| 4164 | int ret; | 4257 | int ret; |
| 4165 | 4258 | ||
| 4166 | if (cnt >= sizeof(buf)) | 4259 | ret = kstrtoul_from_user(ubuf, cnt, 10, &val); |
| 4167 | return -EINVAL; | 4260 | if (ret) |
| 4168 | |||
| 4169 | if (copy_from_user(&buf, ubuf, cnt)) | ||
| 4170 | return -EFAULT; | ||
| 4171 | |||
| 4172 | buf[cnt] = 0; | ||
| 4173 | |||
| 4174 | ret = strict_strtoul(buf, 10, &val); | ||
| 4175 | if (ret < 0) | ||
| 4176 | return ret; | 4261 | return ret; |
| 4177 | 4262 | ||
| 4178 | if (val != 0 && val != 1) | 4263 | if (val != 0 && val != 1) |
| @@ -4365,6 +4450,9 @@ static __init int tracer_init_debugfs(void) | |||
| 4365 | trace_create_file("buffer_size_kb", 0644, d_tracer, | 4450 | trace_create_file("buffer_size_kb", 0644, d_tracer, |
| 4366 | &global_trace, &tracing_entries_fops); | 4451 | &global_trace, &tracing_entries_fops); |
| 4367 | 4452 | ||
| 4453 | trace_create_file("free_buffer", 0644, d_tracer, | ||
| 4454 | &global_trace, &tracing_free_buffer_fops); | ||
| 4455 | |||
| 4368 | trace_create_file("trace_marker", 0220, d_tracer, | 4456 | trace_create_file("trace_marker", 0220, d_tracer, |
| 4369 | NULL, &tracing_mark_fops); | 4457 | NULL, &tracing_mark_fops); |
| 4370 | 4458 | ||
