aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/trace/trace.c178
1 files changed, 154 insertions, 24 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 135af323608b..e29edee1542a 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1285,22 +1285,71 @@ void tracing_reset_all_online_cpus(void)
1285 } 1285 }
1286} 1286}
1287 1287
1288#define SAVED_CMDLINES 128 1288#define SAVED_CMDLINES_DEFAULT 128
1289#define NO_CMDLINE_MAP UINT_MAX 1289#define NO_CMDLINE_MAP UINT_MAX
1290static unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1];
1291static unsigned map_cmdline_to_pid[SAVED_CMDLINES];
1292static char saved_cmdlines[SAVED_CMDLINES][TASK_COMM_LEN];
1293static int cmdline_idx;
1294static arch_spinlock_t trace_cmdline_lock = __ARCH_SPIN_LOCK_UNLOCKED; 1290static arch_spinlock_t trace_cmdline_lock = __ARCH_SPIN_LOCK_UNLOCKED;
1291struct saved_cmdlines_buffer {
1292 unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1];
1293 unsigned *map_cmdline_to_pid;
1294 unsigned cmdline_num;
1295 int cmdline_idx;
1296 char *saved_cmdlines;
1297};
1298static struct saved_cmdlines_buffer *savedcmd;
1295 1299
1296/* temporary disable recording */ 1300/* temporary disable recording */
1297static atomic_t trace_record_cmdline_disabled __read_mostly; 1301static atomic_t trace_record_cmdline_disabled __read_mostly;
1298 1302
1299static void trace_init_cmdlines(void) 1303static inline char *get_saved_cmdlines(int idx)
1304{
1305 return &savedcmd->saved_cmdlines[idx * TASK_COMM_LEN];
1306}
1307
1308static inline void set_cmdline(int idx, const char *cmdline)
1300{ 1309{
1301 memset(&map_pid_to_cmdline, NO_CMDLINE_MAP, sizeof(map_pid_to_cmdline)); 1310 memcpy(get_saved_cmdlines(idx), cmdline, TASK_COMM_LEN);
1302 memset(&map_cmdline_to_pid, NO_CMDLINE_MAP, sizeof(map_cmdline_to_pid)); 1311}
1303 cmdline_idx = 0; 1312
1313static int allocate_cmdlines_buffer(unsigned int val,
1314 struct saved_cmdlines_buffer *s)
1315{
1316 s->map_cmdline_to_pid = kmalloc(val * sizeof(*s->map_cmdline_to_pid),
1317 GFP_KERNEL);
1318 if (!s->map_cmdline_to_pid)
1319 return -ENOMEM;
1320
1321 s->saved_cmdlines = kmalloc(val * TASK_COMM_LEN, GFP_KERNEL);
1322 if (!s->saved_cmdlines) {
1323 kfree(s->map_cmdline_to_pid);
1324 return -ENOMEM;
1325 }
1326
1327 s->cmdline_idx = 0;
1328 s->cmdline_num = val;
1329 memset(&s->map_pid_to_cmdline, NO_CMDLINE_MAP,
1330 sizeof(s->map_pid_to_cmdline));
1331 memset(s->map_cmdline_to_pid, NO_CMDLINE_MAP,
1332 val * sizeof(*s->map_cmdline_to_pid));
1333
1334 return 0;
1335}
1336
1337static int trace_create_savedcmd(void)
1338{
1339 int ret;
1340
1341 savedcmd = kmalloc(sizeof(struct saved_cmdlines_buffer), GFP_KERNEL);
1342 if (!savedcmd)
1343 return -ENOMEM;
1344
1345 ret = allocate_cmdlines_buffer(SAVED_CMDLINES_DEFAULT, savedcmd);
1346 if (ret < 0) {
1347 kfree(savedcmd);
1348 savedcmd = NULL;
1349 return -ENOMEM;
1350 }
1351
1352 return 0;
1304} 1353}
1305 1354
1306int is_tracing_stopped(void) 1355int is_tracing_stopped(void)
@@ -1457,9 +1506,9 @@ static int trace_save_cmdline(struct task_struct *tsk)
1457 if (!arch_spin_trylock(&trace_cmdline_lock)) 1506 if (!arch_spin_trylock(&trace_cmdline_lock))
1458 return 0; 1507 return 0;
1459 1508
1460 idx = map_pid_to_cmdline[tsk->pid]; 1509 idx = savedcmd->map_pid_to_cmdline[tsk->pid];
1461 if (idx == NO_CMDLINE_MAP) { 1510 if (idx == NO_CMDLINE_MAP) {
1462 idx = (cmdline_idx + 1) % SAVED_CMDLINES; 1511 idx = (savedcmd->cmdline_idx + 1) % savedcmd->cmdline_num;
1463 1512
1464 /* 1513 /*
1465 * Check whether the cmdline buffer at idx has a pid 1514 * Check whether the cmdline buffer at idx has a pid
@@ -1467,17 +1516,17 @@ static int trace_save_cmdline(struct task_struct *tsk)
1467 * need to clear the map_pid_to_cmdline. Otherwise we 1516 * need to clear the map_pid_to_cmdline. Otherwise we
1468 * would read the new comm for the old pid. 1517 * would read the new comm for the old pid.
1469 */ 1518 */
1470 pid = map_cmdline_to_pid[idx]; 1519 pid = savedcmd->map_cmdline_to_pid[idx];
1471 if (pid != NO_CMDLINE_MAP) 1520 if (pid != NO_CMDLINE_MAP)
1472 map_pid_to_cmdline[pid] = NO_CMDLINE_MAP; 1521 savedcmd->map_pid_to_cmdline[pid] = NO_CMDLINE_MAP;
1473 1522
1474 map_cmdline_to_pid[idx] = tsk->pid; 1523 savedcmd->map_cmdline_to_pid[idx] = tsk->pid;
1475 map_pid_to_cmdline[tsk->pid] = idx; 1524 savedcmd->map_pid_to_cmdline[tsk->pid] = idx;
1476 1525
1477 cmdline_idx = idx; 1526 savedcmd->cmdline_idx = idx;
1478 } 1527 }
1479 1528
1480 memcpy(&saved_cmdlines[idx], tsk->comm, TASK_COMM_LEN); 1529 set_cmdline(idx, tsk->comm);
1481 1530
1482 arch_spin_unlock(&trace_cmdline_lock); 1531 arch_spin_unlock(&trace_cmdline_lock);
1483 1532
@@ -1503,9 +1552,9 @@ static void __trace_find_cmdline(int pid, char comm[])
1503 return; 1552 return;
1504 } 1553 }
1505 1554
1506 map = map_pid_to_cmdline[pid]; 1555 map = savedcmd->map_pid_to_cmdline[pid];
1507 if (map != NO_CMDLINE_MAP) 1556 if (map != NO_CMDLINE_MAP)
1508 strcpy(comm, saved_cmdlines[map]); 1557 strcpy(comm, get_saved_cmdlines(map));
1509 else 1558 else
1510 strcpy(comm, "<...>"); 1559 strcpy(comm, "<...>");
1511} 1560}
@@ -3593,6 +3642,7 @@ static const char readme_msg[] =
3593 " trace_options\t\t- Set format or modify how tracing happens\n" 3642 " trace_options\t\t- Set format or modify how tracing happens\n"
3594 "\t\t\t Disable an option by adding a suffix 'no' to the\n" 3643 "\t\t\t Disable an option by adding a suffix 'no' to the\n"
3595 "\t\t\t option name\n" 3644 "\t\t\t option name\n"
3645 " saved_cmdlines_size\t- echo command number in here to store comm-pid list\n"
3596#ifdef CONFIG_DYNAMIC_FTRACE 3646#ifdef CONFIG_DYNAMIC_FTRACE
3597 "\n available_filter_functions - list of functions that can be filtered on\n" 3647 "\n available_filter_functions - list of functions that can be filtered on\n"
3598 " set_ftrace_filter\t- echo function name in here to only trace these\n" 3648 " set_ftrace_filter\t- echo function name in here to only trace these\n"
@@ -3715,7 +3765,8 @@ static void *saved_cmdlines_next(struct seq_file *m, void *v, loff_t *pos)
3715 3765
3716 (*pos)++; 3766 (*pos)++;
3717 3767
3718 for (; ptr < &map_cmdline_to_pid[SAVED_CMDLINES]; ptr++) { 3768 for (; ptr < &savedcmd->map_cmdline_to_pid[savedcmd->cmdline_num];
3769 ptr++) {
3719 if (*ptr == -1 || *ptr == NO_CMDLINE_MAP) 3770 if (*ptr == -1 || *ptr == NO_CMDLINE_MAP)
3720 continue; 3771 continue;
3721 3772
@@ -3733,7 +3784,7 @@ static void *saved_cmdlines_start(struct seq_file *m, loff_t *pos)
3733 preempt_disable(); 3784 preempt_disable();
3734 arch_spin_lock(&trace_cmdline_lock); 3785 arch_spin_lock(&trace_cmdline_lock);
3735 3786
3736 v = &map_cmdline_to_pid[0]; 3787 v = &savedcmd->map_cmdline_to_pid[0];
3737 while (l <= *pos) { 3788 while (l <= *pos) {
3738 v = saved_cmdlines_next(m, v, &l); 3789 v = saved_cmdlines_next(m, v, &l);
3739 if (!v) 3790 if (!v)
@@ -3782,6 +3833,79 @@ static const struct file_operations tracing_saved_cmdlines_fops = {
3782}; 3833};
3783 3834
3784static ssize_t 3835static ssize_t
3836tracing_saved_cmdlines_size_read(struct file *filp, char __user *ubuf,
3837 size_t cnt, loff_t *ppos)
3838{
3839 char buf[64];
3840 int r;
3841
3842 arch_spin_lock(&trace_cmdline_lock);
3843 r = sprintf(buf, "%u\n", savedcmd->cmdline_num);
3844 arch_spin_unlock(&trace_cmdline_lock);
3845
3846 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
3847}
3848
3849static void free_saved_cmdlines_buffer(struct saved_cmdlines_buffer *s)
3850{
3851 kfree(s->saved_cmdlines);
3852 kfree(s->map_cmdline_to_pid);
3853 kfree(s);
3854}
3855
3856static int tracing_resize_saved_cmdlines(unsigned int val)
3857{
3858 struct saved_cmdlines_buffer *s, *savedcmd_temp;
3859
3860 s = kmalloc(sizeof(struct saved_cmdlines_buffer), GFP_KERNEL);
3861 if (!s)
3862 return -ENOMEM;
3863
3864 if (allocate_cmdlines_buffer(val, s) < 0) {
3865 kfree(s);
3866 return -ENOMEM;
3867 }
3868
3869 arch_spin_lock(&trace_cmdline_lock);
3870 savedcmd_temp = savedcmd;
3871 savedcmd = s;
3872 arch_spin_unlock(&trace_cmdline_lock);
3873 free_saved_cmdlines_buffer(savedcmd_temp);
3874
3875 return 0;
3876}
3877
3878static ssize_t
3879tracing_saved_cmdlines_size_write(struct file *filp, const char __user *ubuf,
3880 size_t cnt, loff_t *ppos)
3881{
3882 unsigned long val;
3883 int ret;
3884
3885 ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
3886 if (ret)
3887 return ret;
3888
3889 /* must have at least 1 entry or less than PID_MAX_DEFAULT */
3890 if (!val || val > PID_MAX_DEFAULT)
3891 return -EINVAL;
3892
3893 ret = tracing_resize_saved_cmdlines((unsigned int)val);
3894 if (ret < 0)
3895 return ret;
3896
3897 *ppos += cnt;
3898
3899 return cnt;
3900}
3901
3902static const struct file_operations tracing_saved_cmdlines_size_fops = {
3903 .open = tracing_open_generic,
3904 .read = tracing_saved_cmdlines_size_read,
3905 .write = tracing_saved_cmdlines_size_write,
3906};
3907
3908static ssize_t
3785tracing_set_trace_read(struct file *filp, char __user *ubuf, 3909tracing_set_trace_read(struct file *filp, char __user *ubuf,
3786 size_t cnt, loff_t *ppos) 3910 size_t cnt, loff_t *ppos)
3787{ 3911{
@@ -6375,6 +6499,9 @@ static __init int tracer_init_debugfs(void)
6375 trace_create_file("saved_cmdlines", 0444, d_tracer, 6499 trace_create_file("saved_cmdlines", 0444, d_tracer,
6376 NULL, &tracing_saved_cmdlines_fops); 6500 NULL, &tracing_saved_cmdlines_fops);
6377 6501
6502 trace_create_file("saved_cmdlines_size", 0644, d_tracer,
6503 NULL, &tracing_saved_cmdlines_size_fops);
6504
6378#ifdef CONFIG_DYNAMIC_FTRACE 6505#ifdef CONFIG_DYNAMIC_FTRACE
6379 trace_create_file("dyn_ftrace_total_info", 0444, d_tracer, 6506 trace_create_file("dyn_ftrace_total_info", 0444, d_tracer,
6380 &ftrace_update_tot_cnt, &tracing_dyn_info_fops); 6507 &ftrace_update_tot_cnt, &tracing_dyn_info_fops);
@@ -6611,18 +6738,19 @@ __init static int tracer_alloc_buffers(void)
6611 if (!temp_buffer) 6738 if (!temp_buffer)
6612 goto out_free_cpumask; 6739 goto out_free_cpumask;
6613 6740
6741 if (trace_create_savedcmd() < 0)
6742 goto out_free_temp_buffer;
6743
6614 /* TODO: make the number of buffers hot pluggable with CPUS */ 6744 /* TODO: make the number of buffers hot pluggable with CPUS */
6615 if (allocate_trace_buffers(&global_trace, ring_buf_size) < 0) { 6745 if (allocate_trace_buffers(&global_trace, ring_buf_size) < 0) {
6616 printk(KERN_ERR "tracer: failed to allocate ring buffer!\n"); 6746 printk(KERN_ERR "tracer: failed to allocate ring buffer!\n");
6617 WARN_ON(1); 6747 WARN_ON(1);
6618 goto out_free_temp_buffer; 6748 goto out_free_savedcmd;
6619 } 6749 }
6620 6750
6621 if (global_trace.buffer_disabled) 6751 if (global_trace.buffer_disabled)
6622 tracing_off(); 6752 tracing_off();
6623 6753
6624 trace_init_cmdlines();
6625
6626 if (trace_boot_clock) { 6754 if (trace_boot_clock) {
6627 ret = tracing_set_clock(&global_trace, trace_boot_clock); 6755 ret = tracing_set_clock(&global_trace, trace_boot_clock);
6628 if (ret < 0) 6756 if (ret < 0)
@@ -6668,6 +6796,8 @@ __init static int tracer_alloc_buffers(void)
6668 6796
6669 return 0; 6797 return 0;
6670 6798
6799out_free_savedcmd:
6800 free_saved_cmdlines_buffer(savedcmd);
6671out_free_temp_buffer: 6801out_free_temp_buffer:
6672 ring_buffer_free(temp_buffer); 6802 ring_buffer_free(temp_buffer);
6673out_free_cpumask: 6803out_free_cpumask: