1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
235e8e302SSteven Rostedt /*
335e8e302SSteven Rostedt  * trace context switch
435e8e302SSteven Rostedt  *
535e8e302SSteven Rostedt  * Copyright (C) 2007 Steven Rostedt <[email protected]>
635e8e302SSteven Rostedt  *
735e8e302SSteven Rostedt  */
835e8e302SSteven Rostedt #include <linux/module.h>
935e8e302SSteven Rostedt #include <linux/kallsyms.h>
1035e8e302SSteven Rostedt #include <linux/uaccess.h>
112cc621fdSSteven Rostedt (Google) #include <linux/kmemleak.h>
1235e8e302SSteven Rostedt #include <linux/ftrace.h>
13ad8d75ffSSteven Rostedt #include <trace/events/sched.h>
1435e8e302SSteven Rostedt 
1535e8e302SSteven Rostedt #include "trace.h"
1635e8e302SSteven Rostedt 
17d914ba37SJoel Fernandes #define RECORD_CMDLINE	1
18d914ba37SJoel Fernandes #define RECORD_TGID	2
19d914ba37SJoel Fernandes 
20d914ba37SJoel Fernandes static int		sched_cmdline_ref;
21d914ba37SJoel Fernandes static int		sched_tgid_ref;
22efade6e7SFrederic Weisbecker static DEFINE_MUTEX(sched_register_mutex);
2382e04af4SFrederic Weisbecker 
24e309b41dSIngo Molnar static void
probe_sched_switch(void * ignore,bool preempt,struct task_struct * prev,struct task_struct * next,unsigned int prev_state)25c73464b1SPeter Zijlstra probe_sched_switch(void *ignore, bool preempt,
269c2136beSDelyan Kratunov 		   struct task_struct *prev, struct task_struct *next,
279c2136beSDelyan Kratunov 		   unsigned int prev_state)
2835e8e302SSteven Rostedt {
29d914ba37SJoel Fernandes 	int flags;
30b07c3f19SMathieu Desnoyers 
31d914ba37SJoel Fernandes 	flags = (RECORD_TGID * !!sched_tgid_ref) +
32d914ba37SJoel Fernandes 		(RECORD_CMDLINE * !!sched_cmdline_ref);
33d914ba37SJoel Fernandes 
34d914ba37SJoel Fernandes 	if (!flags)
35d914ba37SJoel Fernandes 		return;
36d914ba37SJoel Fernandes 	tracing_record_taskinfo_sched_switch(prev, next, flags);
3735e8e302SSteven Rostedt }
3835e8e302SSteven Rostedt 
395b82a1b0SMathieu Desnoyers static void
probe_sched_wakeup(void * ignore,struct task_struct * wakee)40fbd705a0SPeter Zijlstra probe_sched_wakeup(void *ignore, struct task_struct *wakee)
415b82a1b0SMathieu Desnoyers {
42d914ba37SJoel Fernandes 	int flags;
43dcef788eSZhaolei 
44d914ba37SJoel Fernandes 	flags = (RECORD_TGID * !!sched_tgid_ref) +
45d914ba37SJoel Fernandes 		(RECORD_CMDLINE * !!sched_cmdline_ref);
46d914ba37SJoel Fernandes 
47d914ba37SJoel Fernandes 	if (!flags)
48d914ba37SJoel Fernandes 		return;
4955bc8384SSteven Rostedt (Google) 	tracing_record_taskinfo_sched_switch(current, wakee, flags);
5057422797SIngo Molnar }
5157422797SIngo Molnar 
tracing_sched_register(void)525b82a1b0SMathieu Desnoyers static int tracing_sched_register(void)
535b82a1b0SMathieu Desnoyers {
545b82a1b0SMathieu Desnoyers 	int ret;
555b82a1b0SMathieu Desnoyers 
5638516ab5SSteven Rostedt 	ret = register_trace_sched_wakeup(probe_sched_wakeup, NULL);
575b82a1b0SMathieu Desnoyers 	if (ret) {
58b07c3f19SMathieu Desnoyers 		pr_info("wakeup trace: Couldn't activate tracepoint"
595b82a1b0SMathieu Desnoyers 			" probe to kernel_sched_wakeup\n");
605b82a1b0SMathieu Desnoyers 		return ret;
615b82a1b0SMathieu Desnoyers 	}
625b82a1b0SMathieu Desnoyers 
6338516ab5SSteven Rostedt 	ret = register_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
645b82a1b0SMathieu Desnoyers 	if (ret) {
65b07c3f19SMathieu Desnoyers 		pr_info("wakeup trace: Couldn't activate tracepoint"
665b82a1b0SMathieu Desnoyers 			" probe to kernel_sched_wakeup_new\n");
675b82a1b0SMathieu Desnoyers 		goto fail_deprobe;
685b82a1b0SMathieu Desnoyers 	}
695b82a1b0SMathieu Desnoyers 
7038516ab5SSteven Rostedt 	ret = register_trace_sched_switch(probe_sched_switch, NULL);
715b82a1b0SMathieu Desnoyers 	if (ret) {
72b07c3f19SMathieu Desnoyers 		pr_info("sched trace: Couldn't activate tracepoint"
7373d8b8bcSWenji Huang 			" probe to kernel_sched_switch\n");
745b82a1b0SMathieu Desnoyers 		goto fail_deprobe_wake_new;
755b82a1b0SMathieu Desnoyers 	}
765b82a1b0SMathieu Desnoyers 
775b82a1b0SMathieu Desnoyers 	return ret;
785b82a1b0SMathieu Desnoyers fail_deprobe_wake_new:
7938516ab5SSteven Rostedt 	unregister_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
805b82a1b0SMathieu Desnoyers fail_deprobe:
8138516ab5SSteven Rostedt 	unregister_trace_sched_wakeup(probe_sched_wakeup, NULL);
825b82a1b0SMathieu Desnoyers 	return ret;
835b82a1b0SMathieu Desnoyers }
845b82a1b0SMathieu Desnoyers 
tracing_sched_unregister(void)855b82a1b0SMathieu Desnoyers static void tracing_sched_unregister(void)
865b82a1b0SMathieu Desnoyers {
8738516ab5SSteven Rostedt 	unregister_trace_sched_switch(probe_sched_switch, NULL);
8838516ab5SSteven Rostedt 	unregister_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
8938516ab5SSteven Rostedt 	unregister_trace_sched_wakeup(probe_sched_wakeup, NULL);
905b82a1b0SMathieu Desnoyers }
915b82a1b0SMathieu Desnoyers 
tracing_start_sched_switch(int ops)92d914ba37SJoel Fernandes static void tracing_start_sched_switch(int ops)
935b82a1b0SMathieu Desnoyers {
9464ae572bSMathieu Desnoyers 	bool sched_register;
9564ae572bSMathieu Desnoyers 
96efade6e7SFrederic Weisbecker 	mutex_lock(&sched_register_mutex);
9764ae572bSMathieu Desnoyers 	sched_register = (!sched_cmdline_ref && !sched_tgid_ref);
98d914ba37SJoel Fernandes 
99d914ba37SJoel Fernandes 	switch (ops) {
100d914ba37SJoel Fernandes 	case RECORD_CMDLINE:
101d914ba37SJoel Fernandes 		sched_cmdline_ref++;
102d914ba37SJoel Fernandes 		break;
103d914ba37SJoel Fernandes 
104d914ba37SJoel Fernandes 	case RECORD_TGID:
105d914ba37SJoel Fernandes 		sched_tgid_ref++;
106d914ba37SJoel Fernandes 		break;
107d914ba37SJoel Fernandes 	}
108d914ba37SJoel Fernandes 
109d914ba37SJoel Fernandes 	if (sched_register && (sched_cmdline_ref || sched_tgid_ref))
1105b82a1b0SMathieu Desnoyers 		tracing_sched_register();
111efade6e7SFrederic Weisbecker 	mutex_unlock(&sched_register_mutex);
1125b82a1b0SMathieu Desnoyers }
1135b82a1b0SMathieu Desnoyers 
tracing_stop_sched_switch(int ops)114d914ba37SJoel Fernandes static void tracing_stop_sched_switch(int ops)
1155b82a1b0SMathieu Desnoyers {
116efade6e7SFrederic Weisbecker 	mutex_lock(&sched_register_mutex);
117d914ba37SJoel Fernandes 
118d914ba37SJoel Fernandes 	switch (ops) {
119d914ba37SJoel Fernandes 	case RECORD_CMDLINE:
120d914ba37SJoel Fernandes 		sched_cmdline_ref--;
121d914ba37SJoel Fernandes 		break;
122d914ba37SJoel Fernandes 
123d914ba37SJoel Fernandes 	case RECORD_TGID:
124d914ba37SJoel Fernandes 		sched_tgid_ref--;
125d914ba37SJoel Fernandes 		break;
126d914ba37SJoel Fernandes 	}
127d914ba37SJoel Fernandes 
128d914ba37SJoel Fernandes 	if (!sched_cmdline_ref && !sched_tgid_ref)
1295b82a1b0SMathieu Desnoyers 		tracing_sched_unregister();
130efade6e7SFrederic Weisbecker 	mutex_unlock(&sched_register_mutex);
1315b82a1b0SMathieu Desnoyers }
1325b82a1b0SMathieu Desnoyers 
tracing_start_cmdline_record(void)13341bc8144SSteven Rostedt void tracing_start_cmdline_record(void)
13441bc8144SSteven Rostedt {
135d914ba37SJoel Fernandes 	tracing_start_sched_switch(RECORD_CMDLINE);
13641bc8144SSteven Rostedt }
13741bc8144SSteven Rostedt 
tracing_stop_cmdline_record(void)13841bc8144SSteven Rostedt void tracing_stop_cmdline_record(void)
13941bc8144SSteven Rostedt {
140d914ba37SJoel Fernandes 	tracing_stop_sched_switch(RECORD_CMDLINE);
141d914ba37SJoel Fernandes }
142d914ba37SJoel Fernandes 
tracing_start_tgid_record(void)143d914ba37SJoel Fernandes void tracing_start_tgid_record(void)
144d914ba37SJoel Fernandes {
145d914ba37SJoel Fernandes 	tracing_start_sched_switch(RECORD_TGID);
146d914ba37SJoel Fernandes }
147d914ba37SJoel Fernandes 
tracing_stop_tgid_record(void)148d914ba37SJoel Fernandes void tracing_stop_tgid_record(void)
149d914ba37SJoel Fernandes {
150d914ba37SJoel Fernandes 	tracing_stop_sched_switch(RECORD_TGID);
15141bc8144SSteven Rostedt }
1522cc621fdSSteven Rostedt (Google) 
1532cc621fdSSteven Rostedt (Google) /*
1542cc621fdSSteven Rostedt (Google)  * The tgid_map array maps from pid to tgid; i.e. the value stored at index i
1552cc621fdSSteven Rostedt (Google)  * is the tgid last observed corresponding to pid=i.
1562cc621fdSSteven Rostedt (Google)  */
1572cc621fdSSteven Rostedt (Google) static int *tgid_map;
1582cc621fdSSteven Rostedt (Google) 
1592cc621fdSSteven Rostedt (Google) /* The maximum valid index into tgid_map. */
1602cc621fdSSteven Rostedt (Google) static size_t tgid_map_max;
1612cc621fdSSteven Rostedt (Google) 
1622cc621fdSSteven Rostedt (Google) #define SAVED_CMDLINES_DEFAULT 128
1632cc621fdSSteven Rostedt (Google) #define NO_CMDLINE_MAP UINT_MAX
1642cc621fdSSteven Rostedt (Google) /*
1652cc621fdSSteven Rostedt (Google)  * Preemption must be disabled before acquiring trace_cmdline_lock.
1662cc621fdSSteven Rostedt (Google)  * The various trace_arrays' max_lock must be acquired in a context
1672cc621fdSSteven Rostedt (Google)  * where interrupt is disabled.
1682cc621fdSSteven Rostedt (Google)  */
1692cc621fdSSteven Rostedt (Google) static arch_spinlock_t trace_cmdline_lock = __ARCH_SPIN_LOCK_UNLOCKED;
1702cc621fdSSteven Rostedt (Google) struct saved_cmdlines_buffer {
1712cc621fdSSteven Rostedt (Google) 	unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1];
1722cc621fdSSteven Rostedt (Google) 	unsigned *map_cmdline_to_pid;
1732cc621fdSSteven Rostedt (Google) 	unsigned cmdline_num;
1742cc621fdSSteven Rostedt (Google) 	int cmdline_idx;
1752cc621fdSSteven Rostedt (Google) 	char saved_cmdlines[];
1762cc621fdSSteven Rostedt (Google) };
1772cc621fdSSteven Rostedt (Google) static struct saved_cmdlines_buffer *savedcmd;
1782cc621fdSSteven Rostedt (Google) 
1792cc621fdSSteven Rostedt (Google) /* Holds the size of a cmdline and pid element */
1802cc621fdSSteven Rostedt (Google) #define SAVED_CMDLINE_MAP_ELEMENT_SIZE(s)			\
1812cc621fdSSteven Rostedt (Google) 	(TASK_COMM_LEN + sizeof((s)->map_cmdline_to_pid[0]))
1822cc621fdSSteven Rostedt (Google) 
get_saved_cmdlines(int idx)1832cc621fdSSteven Rostedt (Google) static inline char *get_saved_cmdlines(int idx)
1842cc621fdSSteven Rostedt (Google) {
1852cc621fdSSteven Rostedt (Google) 	return &savedcmd->saved_cmdlines[idx * TASK_COMM_LEN];
1862cc621fdSSteven Rostedt (Google) }
1872cc621fdSSteven Rostedt (Google) 
set_cmdline(int idx,const char * cmdline)1882cc621fdSSteven Rostedt (Google) static inline void set_cmdline(int idx, const char *cmdline)
1892cc621fdSSteven Rostedt (Google) {
190242b32d8SJinjie Ruan 	strscpy(get_saved_cmdlines(idx), cmdline, TASK_COMM_LEN);
1912cc621fdSSteven Rostedt (Google) }
1922cc621fdSSteven Rostedt (Google) 
free_saved_cmdlines_buffer(struct saved_cmdlines_buffer * s)1932cc621fdSSteven Rostedt (Google) static void free_saved_cmdlines_buffer(struct saved_cmdlines_buffer *s)
1942cc621fdSSteven Rostedt (Google) {
1952cc621fdSSteven Rostedt (Google) 	int order = get_order(sizeof(*s) + s->cmdline_num * TASK_COMM_LEN);
1962cc621fdSSteven Rostedt (Google) 
1972cc621fdSSteven Rostedt (Google) 	kmemleak_free(s);
1982cc621fdSSteven Rostedt (Google) 	free_pages((unsigned long)s, order);
1992cc621fdSSteven Rostedt (Google) }
2002cc621fdSSteven Rostedt (Google) 
allocate_cmdlines_buffer(unsigned int val)2012cc621fdSSteven Rostedt (Google) static struct saved_cmdlines_buffer *allocate_cmdlines_buffer(unsigned int val)
2022cc621fdSSteven Rostedt (Google) {
2032cc621fdSSteven Rostedt (Google) 	struct saved_cmdlines_buffer *s;
2042cc621fdSSteven Rostedt (Google) 	struct page *page;
2052cc621fdSSteven Rostedt (Google) 	int orig_size, size;
2062cc621fdSSteven Rostedt (Google) 	int order;
2072cc621fdSSteven Rostedt (Google) 
2082cc621fdSSteven Rostedt (Google) 	/* Figure out how much is needed to hold the given number of cmdlines */
2092cc621fdSSteven Rostedt (Google) 	orig_size = sizeof(*s) + val * SAVED_CMDLINE_MAP_ELEMENT_SIZE(s);
2102cc621fdSSteven Rostedt (Google) 	order = get_order(orig_size);
2112cc621fdSSteven Rostedt (Google) 	size = 1 << (order + PAGE_SHIFT);
2122cc621fdSSteven Rostedt (Google) 	page = alloc_pages(GFP_KERNEL, order);
2132cc621fdSSteven Rostedt (Google) 	if (!page)
2142cc621fdSSteven Rostedt (Google) 		return NULL;
2152cc621fdSSteven Rostedt (Google) 
2162cc621fdSSteven Rostedt (Google) 	s = page_address(page);
2172cc621fdSSteven Rostedt (Google) 	kmemleak_alloc(s, size, 1, GFP_KERNEL);
2182cc621fdSSteven Rostedt (Google) 	memset(s, 0, sizeof(*s));
2192cc621fdSSteven Rostedt (Google) 
2202cc621fdSSteven Rostedt (Google) 	/* Round up to actual allocation */
2212cc621fdSSteven Rostedt (Google) 	val = (size - sizeof(*s)) / SAVED_CMDLINE_MAP_ELEMENT_SIZE(s);
2222cc621fdSSteven Rostedt (Google) 	s->cmdline_num = val;
2232cc621fdSSteven Rostedt (Google) 
2242cc621fdSSteven Rostedt (Google) 	/* Place map_cmdline_to_pid array right after saved_cmdlines */
2252cc621fdSSteven Rostedt (Google) 	s->map_cmdline_to_pid = (unsigned *)&s->saved_cmdlines[val * TASK_COMM_LEN];
2262cc621fdSSteven Rostedt (Google) 
2272cc621fdSSteven Rostedt (Google) 	s->cmdline_idx = 0;
2282cc621fdSSteven Rostedt (Google) 	memset(&s->map_pid_to_cmdline, NO_CMDLINE_MAP,
2292cc621fdSSteven Rostedt (Google) 	       sizeof(s->map_pid_to_cmdline));
2302cc621fdSSteven Rostedt (Google) 	memset(s->map_cmdline_to_pid, NO_CMDLINE_MAP,
2312cc621fdSSteven Rostedt (Google) 	       val * sizeof(*s->map_cmdline_to_pid));
2322cc621fdSSteven Rostedt (Google) 
2332cc621fdSSteven Rostedt (Google) 	return s;
2342cc621fdSSteven Rostedt (Google) }
2352cc621fdSSteven Rostedt (Google) 
trace_create_savedcmd(void)2362cc621fdSSteven Rostedt (Google) int trace_create_savedcmd(void)
2372cc621fdSSteven Rostedt (Google) {
2382cc621fdSSteven Rostedt (Google) 	savedcmd = allocate_cmdlines_buffer(SAVED_CMDLINES_DEFAULT);
2392cc621fdSSteven Rostedt (Google) 
2402cc621fdSSteven Rostedt (Google) 	return savedcmd ? 0 : -ENOMEM;
2412cc621fdSSteven Rostedt (Google) }
2422cc621fdSSteven Rostedt (Google) 
trace_save_cmdline(struct task_struct * tsk)2432cc621fdSSteven Rostedt (Google) int trace_save_cmdline(struct task_struct *tsk)
2442cc621fdSSteven Rostedt (Google) {
2452cc621fdSSteven Rostedt (Google) 	unsigned tpid, idx;
2462cc621fdSSteven Rostedt (Google) 
2472cc621fdSSteven Rostedt (Google) 	/* treat recording of idle task as a success */
2482cc621fdSSteven Rostedt (Google) 	if (!tsk->pid)
2492cc621fdSSteven Rostedt (Google) 		return 1;
2502cc621fdSSteven Rostedt (Google) 
2512cc621fdSSteven Rostedt (Google) 	tpid = tsk->pid & (PID_MAX_DEFAULT - 1);
2522cc621fdSSteven Rostedt (Google) 
2532cc621fdSSteven Rostedt (Google) 	/*
2542cc621fdSSteven Rostedt (Google) 	 * It's not the end of the world if we don't get
2552cc621fdSSteven Rostedt (Google) 	 * the lock, but we also don't want to spin
2562cc621fdSSteven Rostedt (Google) 	 * nor do we want to disable interrupts,
2572cc621fdSSteven Rostedt (Google) 	 * so if we miss here, then better luck next time.
2582cc621fdSSteven Rostedt (Google) 	 *
2592cc621fdSSteven Rostedt (Google) 	 * This is called within the scheduler and wake up, so interrupts
2602cc621fdSSteven Rostedt (Google) 	 * had better been disabled and run queue lock been held.
2612cc621fdSSteven Rostedt (Google) 	 */
2622cc621fdSSteven Rostedt (Google) 	lockdep_assert_preemption_disabled();
2632cc621fdSSteven Rostedt (Google) 	if (!arch_spin_trylock(&trace_cmdline_lock))
2642cc621fdSSteven Rostedt (Google) 		return 0;
2652cc621fdSSteven Rostedt (Google) 
2662cc621fdSSteven Rostedt (Google) 	idx = savedcmd->map_pid_to_cmdline[tpid];
2672cc621fdSSteven Rostedt (Google) 	if (idx == NO_CMDLINE_MAP) {
2682cc621fdSSteven Rostedt (Google) 		idx = (savedcmd->cmdline_idx + 1) % savedcmd->cmdline_num;
2692cc621fdSSteven Rostedt (Google) 
2702cc621fdSSteven Rostedt (Google) 		savedcmd->map_pid_to_cmdline[tpid] = idx;
2712cc621fdSSteven Rostedt (Google) 		savedcmd->cmdline_idx = idx;
2722cc621fdSSteven Rostedt (Google) 	}
2732cc621fdSSteven Rostedt (Google) 
2742cc621fdSSteven Rostedt (Google) 	savedcmd->map_cmdline_to_pid[idx] = tsk->pid;
2752cc621fdSSteven Rostedt (Google) 	set_cmdline(idx, tsk->comm);
2762cc621fdSSteven Rostedt (Google) 
2772cc621fdSSteven Rostedt (Google) 	arch_spin_unlock(&trace_cmdline_lock);
2782cc621fdSSteven Rostedt (Google) 
2792cc621fdSSteven Rostedt (Google) 	return 1;
2802cc621fdSSteven Rostedt (Google) }
2812cc621fdSSteven Rostedt (Google) 
__trace_find_cmdline(int pid,char comm[])2822cc621fdSSteven Rostedt (Google) static void __trace_find_cmdline(int pid, char comm[])
2832cc621fdSSteven Rostedt (Google) {
2842cc621fdSSteven Rostedt (Google) 	unsigned map;
2852cc621fdSSteven Rostedt (Google) 	int tpid;
2862cc621fdSSteven Rostedt (Google) 
2872cc621fdSSteven Rostedt (Google) 	if (!pid) {
2882cc621fdSSteven Rostedt (Google) 		strcpy(comm, "<idle>");
2892cc621fdSSteven Rostedt (Google) 		return;
2902cc621fdSSteven Rostedt (Google) 	}
2912cc621fdSSteven Rostedt (Google) 
2922cc621fdSSteven Rostedt (Google) 	if (WARN_ON_ONCE(pid < 0)) {
2932cc621fdSSteven Rostedt (Google) 		strcpy(comm, "<XXX>");
2942cc621fdSSteven Rostedt (Google) 		return;
2952cc621fdSSteven Rostedt (Google) 	}
2962cc621fdSSteven Rostedt (Google) 
2972cc621fdSSteven Rostedt (Google) 	tpid = pid & (PID_MAX_DEFAULT - 1);
2982cc621fdSSteven Rostedt (Google) 	map = savedcmd->map_pid_to_cmdline[tpid];
2992cc621fdSSteven Rostedt (Google) 	if (map != NO_CMDLINE_MAP) {
3002cc621fdSSteven Rostedt (Google) 		tpid = savedcmd->map_cmdline_to_pid[map];
3012cc621fdSSteven Rostedt (Google) 		if (tpid == pid) {
3022cc621fdSSteven Rostedt (Google) 			strscpy(comm, get_saved_cmdlines(map), TASK_COMM_LEN);
3032cc621fdSSteven Rostedt (Google) 			return;
3042cc621fdSSteven Rostedt (Google) 		}
3052cc621fdSSteven Rostedt (Google) 	}
3062cc621fdSSteven Rostedt (Google) 	strcpy(comm, "<...>");
3072cc621fdSSteven Rostedt (Google) }
3082cc621fdSSteven Rostedt (Google) 
trace_find_cmdline(int pid,char comm[])3092cc621fdSSteven Rostedt (Google) void trace_find_cmdline(int pid, char comm[])
3102cc621fdSSteven Rostedt (Google) {
3112cc621fdSSteven Rostedt (Google) 	preempt_disable();
3122cc621fdSSteven Rostedt (Google) 	arch_spin_lock(&trace_cmdline_lock);
3132cc621fdSSteven Rostedt (Google) 
3142cc621fdSSteven Rostedt (Google) 	__trace_find_cmdline(pid, comm);
3152cc621fdSSteven Rostedt (Google) 
3162cc621fdSSteven Rostedt (Google) 	arch_spin_unlock(&trace_cmdline_lock);
3172cc621fdSSteven Rostedt (Google) 	preempt_enable();
3182cc621fdSSteven Rostedt (Google) }
3192cc621fdSSteven Rostedt (Google) 
trace_find_tgid_ptr(int pid)3202cc621fdSSteven Rostedt (Google) static int *trace_find_tgid_ptr(int pid)
3212cc621fdSSteven Rostedt (Google) {
3222cc621fdSSteven Rostedt (Google) 	/*
3232cc621fdSSteven Rostedt (Google) 	 * Pairs with the smp_store_release in set_tracer_flag() to ensure that
3242cc621fdSSteven Rostedt (Google) 	 * if we observe a non-NULL tgid_map then we also observe the correct
3252cc621fdSSteven Rostedt (Google) 	 * tgid_map_max.
3262cc621fdSSteven Rostedt (Google) 	 */
3272cc621fdSSteven Rostedt (Google) 	int *map = smp_load_acquire(&tgid_map);
3282cc621fdSSteven Rostedt (Google) 
3292cc621fdSSteven Rostedt (Google) 	if (unlikely(!map || pid > tgid_map_max))
3302cc621fdSSteven Rostedt (Google) 		return NULL;
3312cc621fdSSteven Rostedt (Google) 
3322cc621fdSSteven Rostedt (Google) 	return &map[pid];
3332cc621fdSSteven Rostedt (Google) }
3342cc621fdSSteven Rostedt (Google) 
trace_find_tgid(int pid)3352cc621fdSSteven Rostedt (Google) int trace_find_tgid(int pid)
3362cc621fdSSteven Rostedt (Google) {
3372cc621fdSSteven Rostedt (Google) 	int *ptr = trace_find_tgid_ptr(pid);
3382cc621fdSSteven Rostedt (Google) 
3392cc621fdSSteven Rostedt (Google) 	return ptr ? *ptr : 0;
3402cc621fdSSteven Rostedt (Google) }
3412cc621fdSSteven Rostedt (Google) 
trace_save_tgid(struct task_struct * tsk)3422cc621fdSSteven Rostedt (Google) static int trace_save_tgid(struct task_struct *tsk)
3432cc621fdSSteven Rostedt (Google) {
3442cc621fdSSteven Rostedt (Google) 	int *ptr;
3452cc621fdSSteven Rostedt (Google) 
3462cc621fdSSteven Rostedt (Google) 	/* treat recording of idle task as a success */
3472cc621fdSSteven Rostedt (Google) 	if (!tsk->pid)
3482cc621fdSSteven Rostedt (Google) 		return 1;
3492cc621fdSSteven Rostedt (Google) 
3502cc621fdSSteven Rostedt (Google) 	ptr = trace_find_tgid_ptr(tsk->pid);
3512cc621fdSSteven Rostedt (Google) 	if (!ptr)
3522cc621fdSSteven Rostedt (Google) 		return 0;
3532cc621fdSSteven Rostedt (Google) 
3542cc621fdSSteven Rostedt (Google) 	*ptr = tsk->tgid;
3552cc621fdSSteven Rostedt (Google) 	return 1;
3562cc621fdSSteven Rostedt (Google) }
3572cc621fdSSteven Rostedt (Google) 
tracing_record_taskinfo_skip(int flags)3582cc621fdSSteven Rostedt (Google) static bool tracing_record_taskinfo_skip(int flags)
3592cc621fdSSteven Rostedt (Google) {
3602cc621fdSSteven Rostedt (Google) 	if (unlikely(!(flags & (TRACE_RECORD_CMDLINE | TRACE_RECORD_TGID))))
3612cc621fdSSteven Rostedt (Google) 		return true;
3622cc621fdSSteven Rostedt (Google) 	if (!__this_cpu_read(trace_taskinfo_save))
3632cc621fdSSteven Rostedt (Google) 		return true;
3642cc621fdSSteven Rostedt (Google) 	return false;
3652cc621fdSSteven Rostedt (Google) }
3662cc621fdSSteven Rostedt (Google) 
3672cc621fdSSteven Rostedt (Google) /**
3682cc621fdSSteven Rostedt (Google)  * tracing_record_taskinfo - record the task info of a task
3692cc621fdSSteven Rostedt (Google)  *
3702cc621fdSSteven Rostedt (Google)  * @task:  task to record
3712cc621fdSSteven Rostedt (Google)  * @flags: TRACE_RECORD_CMDLINE for recording comm
3722cc621fdSSteven Rostedt (Google)  *         TRACE_RECORD_TGID for recording tgid
3732cc621fdSSteven Rostedt (Google)  */
tracing_record_taskinfo(struct task_struct * task,int flags)3742cc621fdSSteven Rostedt (Google) void tracing_record_taskinfo(struct task_struct *task, int flags)
3752cc621fdSSteven Rostedt (Google) {
3762cc621fdSSteven Rostedt (Google) 	bool done;
3772cc621fdSSteven Rostedt (Google) 
3782cc621fdSSteven Rostedt (Google) 	if (tracing_record_taskinfo_skip(flags))
3792cc621fdSSteven Rostedt (Google) 		return;
3802cc621fdSSteven Rostedt (Google) 
3812cc621fdSSteven Rostedt (Google) 	/*
3822cc621fdSSteven Rostedt (Google) 	 * Record as much task information as possible. If some fail, continue
3832cc621fdSSteven Rostedt (Google) 	 * to try to record the others.
3842cc621fdSSteven Rostedt (Google) 	 */
3852cc621fdSSteven Rostedt (Google) 	done = !(flags & TRACE_RECORD_CMDLINE) || trace_save_cmdline(task);
3862cc621fdSSteven Rostedt (Google) 	done &= !(flags & TRACE_RECORD_TGID) || trace_save_tgid(task);
3872cc621fdSSteven Rostedt (Google) 
3882cc621fdSSteven Rostedt (Google) 	/* If recording any information failed, retry again soon. */
3892cc621fdSSteven Rostedt (Google) 	if (!done)
3902cc621fdSSteven Rostedt (Google) 		return;
3912cc621fdSSteven Rostedt (Google) 
3922cc621fdSSteven Rostedt (Google) 	__this_cpu_write(trace_taskinfo_save, false);
3932cc621fdSSteven Rostedt (Google) }
3942cc621fdSSteven Rostedt (Google) 
3952cc621fdSSteven Rostedt (Google) /**
3962cc621fdSSteven Rostedt (Google)  * tracing_record_taskinfo_sched_switch - record task info for sched_switch
3972cc621fdSSteven Rostedt (Google)  *
3982cc621fdSSteven Rostedt (Google)  * @prev: previous task during sched_switch
3992cc621fdSSteven Rostedt (Google)  * @next: next task during sched_switch
4002cc621fdSSteven Rostedt (Google)  * @flags: TRACE_RECORD_CMDLINE for recording comm
4012cc621fdSSteven Rostedt (Google)  *         TRACE_RECORD_TGID for recording tgid
4022cc621fdSSteven Rostedt (Google)  */
tracing_record_taskinfo_sched_switch(struct task_struct * prev,struct task_struct * next,int flags)4032cc621fdSSteven Rostedt (Google) void tracing_record_taskinfo_sched_switch(struct task_struct *prev,
4042cc621fdSSteven Rostedt (Google) 					  struct task_struct *next, int flags)
4052cc621fdSSteven Rostedt (Google) {
4062cc621fdSSteven Rostedt (Google) 	bool done;
4072cc621fdSSteven Rostedt (Google) 
4082cc621fdSSteven Rostedt (Google) 	if (tracing_record_taskinfo_skip(flags))
4092cc621fdSSteven Rostedt (Google) 		return;
4102cc621fdSSteven Rostedt (Google) 
4112cc621fdSSteven Rostedt (Google) 	/*
4122cc621fdSSteven Rostedt (Google) 	 * Record as much task information as possible. If some fail, continue
4132cc621fdSSteven Rostedt (Google) 	 * to try to record the others.
4142cc621fdSSteven Rostedt (Google) 	 */
4152cc621fdSSteven Rostedt (Google) 	done  = !(flags & TRACE_RECORD_CMDLINE) || trace_save_cmdline(prev);
4162cc621fdSSteven Rostedt (Google) 	done &= !(flags & TRACE_RECORD_CMDLINE) || trace_save_cmdline(next);
4172cc621fdSSteven Rostedt (Google) 	done &= !(flags & TRACE_RECORD_TGID) || trace_save_tgid(prev);
4182cc621fdSSteven Rostedt (Google) 	done &= !(flags & TRACE_RECORD_TGID) || trace_save_tgid(next);
4192cc621fdSSteven Rostedt (Google) 
4202cc621fdSSteven Rostedt (Google) 	/* If recording any information failed, retry again soon. */
4212cc621fdSSteven Rostedt (Google) 	if (!done)
4222cc621fdSSteven Rostedt (Google) 		return;
4232cc621fdSSteven Rostedt (Google) 
4242cc621fdSSteven Rostedt (Google) 	__this_cpu_write(trace_taskinfo_save, false);
4252cc621fdSSteven Rostedt (Google) }
4262cc621fdSSteven Rostedt (Google) 
4272cc621fdSSteven Rostedt (Google) /* Helpers to record a specific task information */
tracing_record_cmdline(struct task_struct * task)4282cc621fdSSteven Rostedt (Google) void tracing_record_cmdline(struct task_struct *task)
4292cc621fdSSteven Rostedt (Google) {
4302cc621fdSSteven Rostedt (Google) 	tracing_record_taskinfo(task, TRACE_RECORD_CMDLINE);
4312cc621fdSSteven Rostedt (Google) }
4322cc621fdSSteven Rostedt (Google) 
tracing_record_tgid(struct task_struct * task)4332cc621fdSSteven Rostedt (Google) void tracing_record_tgid(struct task_struct *task)
4342cc621fdSSteven Rostedt (Google) {
4352cc621fdSSteven Rostedt (Google) 	tracing_record_taskinfo(task, TRACE_RECORD_TGID);
4362cc621fdSSteven Rostedt (Google) }
4372cc621fdSSteven Rostedt (Google) 
trace_alloc_tgid_map(void)4382cc621fdSSteven Rostedt (Google) int trace_alloc_tgid_map(void)
4392cc621fdSSteven Rostedt (Google) {
4402cc621fdSSteven Rostedt (Google) 	int *map;
4412cc621fdSSteven Rostedt (Google) 
4422cc621fdSSteven Rostedt (Google) 	if (tgid_map)
4432cc621fdSSteven Rostedt (Google) 		return 0;
4442cc621fdSSteven Rostedt (Google) 
445*7863dcc7SChristian Brauner 	tgid_map_max = init_pid_ns.pid_max;
4462cc621fdSSteven Rostedt (Google) 	map = kvcalloc(tgid_map_max + 1, sizeof(*tgid_map),
4472cc621fdSSteven Rostedt (Google) 		       GFP_KERNEL);
4482cc621fdSSteven Rostedt (Google) 	if (!map)
4492cc621fdSSteven Rostedt (Google) 		return -ENOMEM;
4502cc621fdSSteven Rostedt (Google) 
4512cc621fdSSteven Rostedt (Google) 	/*
4522cc621fdSSteven Rostedt (Google) 	 * Pairs with smp_load_acquire() in
4532cc621fdSSteven Rostedt (Google) 	 * trace_find_tgid_ptr() to ensure that if it observes
4542cc621fdSSteven Rostedt (Google) 	 * the tgid_map we just allocated then it also observes
4552cc621fdSSteven Rostedt (Google) 	 * the corresponding tgid_map_max value.
4562cc621fdSSteven Rostedt (Google) 	 */
4572cc621fdSSteven Rostedt (Google) 	smp_store_release(&tgid_map, map);
4582cc621fdSSteven Rostedt (Google) 	return 0;
4592cc621fdSSteven Rostedt (Google) }
4602cc621fdSSteven Rostedt (Google) 
saved_tgids_next(struct seq_file * m,void * v,loff_t * pos)4612cc621fdSSteven Rostedt (Google) static void *saved_tgids_next(struct seq_file *m, void *v, loff_t *pos)
4622cc621fdSSteven Rostedt (Google) {
4632cc621fdSSteven Rostedt (Google) 	int pid = ++(*pos);
4642cc621fdSSteven Rostedt (Google) 
4652cc621fdSSteven Rostedt (Google) 	return trace_find_tgid_ptr(pid);
4662cc621fdSSteven Rostedt (Google) }
4672cc621fdSSteven Rostedt (Google) 
saved_tgids_start(struct seq_file * m,loff_t * pos)4682cc621fdSSteven Rostedt (Google) static void *saved_tgids_start(struct seq_file *m, loff_t *pos)
4692cc621fdSSteven Rostedt (Google) {
4702cc621fdSSteven Rostedt (Google) 	int pid = *pos;
4712cc621fdSSteven Rostedt (Google) 
4722cc621fdSSteven Rostedt (Google) 	return trace_find_tgid_ptr(pid);
4732cc621fdSSteven Rostedt (Google) }
4742cc621fdSSteven Rostedt (Google) 
saved_tgids_stop(struct seq_file * m,void * v)4752cc621fdSSteven Rostedt (Google) static void saved_tgids_stop(struct seq_file *m, void *v)
4762cc621fdSSteven Rostedt (Google) {
4772cc621fdSSteven Rostedt (Google) }
4782cc621fdSSteven Rostedt (Google) 
saved_tgids_show(struct seq_file * m,void * v)4792cc621fdSSteven Rostedt (Google) static int saved_tgids_show(struct seq_file *m, void *v)
4802cc621fdSSteven Rostedt (Google) {
4812cc621fdSSteven Rostedt (Google) 	int *entry = (int *)v;
4822cc621fdSSteven Rostedt (Google) 	int pid = entry - tgid_map;
4832cc621fdSSteven Rostedt (Google) 	int tgid = *entry;
4842cc621fdSSteven Rostedt (Google) 
4852cc621fdSSteven Rostedt (Google) 	if (tgid == 0)
4862cc621fdSSteven Rostedt (Google) 		return SEQ_SKIP;
4872cc621fdSSteven Rostedt (Google) 
4882cc621fdSSteven Rostedt (Google) 	seq_printf(m, "%d %d\n", pid, tgid);
4892cc621fdSSteven Rostedt (Google) 	return 0;
4902cc621fdSSteven Rostedt (Google) }
4912cc621fdSSteven Rostedt (Google) 
4922cc621fdSSteven Rostedt (Google) static const struct seq_operations tracing_saved_tgids_seq_ops = {
4932cc621fdSSteven Rostedt (Google) 	.start		= saved_tgids_start,
4942cc621fdSSteven Rostedt (Google) 	.stop		= saved_tgids_stop,
4952cc621fdSSteven Rostedt (Google) 	.next		= saved_tgids_next,
4962cc621fdSSteven Rostedt (Google) 	.show		= saved_tgids_show,
4972cc621fdSSteven Rostedt (Google) };
4982cc621fdSSteven Rostedt (Google) 
tracing_saved_tgids_open(struct inode * inode,struct file * filp)4992cc621fdSSteven Rostedt (Google) static int tracing_saved_tgids_open(struct inode *inode, struct file *filp)
5002cc621fdSSteven Rostedt (Google) {
5012cc621fdSSteven Rostedt (Google) 	int ret;
5022cc621fdSSteven Rostedt (Google) 
5032cc621fdSSteven Rostedt (Google) 	ret = tracing_check_open_get_tr(NULL);
5042cc621fdSSteven Rostedt (Google) 	if (ret)
5052cc621fdSSteven Rostedt (Google) 		return ret;
5062cc621fdSSteven Rostedt (Google) 
5072cc621fdSSteven Rostedt (Google) 	return seq_open(filp, &tracing_saved_tgids_seq_ops);
5082cc621fdSSteven Rostedt (Google) }
5092cc621fdSSteven Rostedt (Google) 
5102cc621fdSSteven Rostedt (Google) 
5112cc621fdSSteven Rostedt (Google) const struct file_operations tracing_saved_tgids_fops = {
5122cc621fdSSteven Rostedt (Google) 	.open		= tracing_saved_tgids_open,
5132cc621fdSSteven Rostedt (Google) 	.read		= seq_read,
5142cc621fdSSteven Rostedt (Google) 	.llseek		= seq_lseek,
5152cc621fdSSteven Rostedt (Google) 	.release	= seq_release,
5162cc621fdSSteven Rostedt (Google) };
5172cc621fdSSteven Rostedt (Google) 
saved_cmdlines_next(struct seq_file * m,void * v,loff_t * pos)5182cc621fdSSteven Rostedt (Google) static void *saved_cmdlines_next(struct seq_file *m, void *v, loff_t *pos)
5192cc621fdSSteven Rostedt (Google) {
5202cc621fdSSteven Rostedt (Google) 	unsigned int *ptr = v;
5212cc621fdSSteven Rostedt (Google) 
5222cc621fdSSteven Rostedt (Google) 	if (*pos || m->count)
5232cc621fdSSteven Rostedt (Google) 		ptr++;
5242cc621fdSSteven Rostedt (Google) 
5252cc621fdSSteven Rostedt (Google) 	(*pos)++;
5262cc621fdSSteven Rostedt (Google) 
5272cc621fdSSteven Rostedt (Google) 	for (; ptr < &savedcmd->map_cmdline_to_pid[savedcmd->cmdline_num];
5282cc621fdSSteven Rostedt (Google) 	     ptr++) {
5292cc621fdSSteven Rostedt (Google) 		if (*ptr == -1 || *ptr == NO_CMDLINE_MAP)
5302cc621fdSSteven Rostedt (Google) 			continue;
5312cc621fdSSteven Rostedt (Google) 
5322cc621fdSSteven Rostedt (Google) 		return ptr;
5332cc621fdSSteven Rostedt (Google) 	}
5342cc621fdSSteven Rostedt (Google) 
5352cc621fdSSteven Rostedt (Google) 	return NULL;
5362cc621fdSSteven Rostedt (Google) }
5372cc621fdSSteven Rostedt (Google) 
saved_cmdlines_start(struct seq_file * m,loff_t * pos)5382cc621fdSSteven Rostedt (Google) static void *saved_cmdlines_start(struct seq_file *m, loff_t *pos)
5392cc621fdSSteven Rostedt (Google) {
5402cc621fdSSteven Rostedt (Google) 	void *v;
5412cc621fdSSteven Rostedt (Google) 	loff_t l = 0;
5422cc621fdSSteven Rostedt (Google) 
5432cc621fdSSteven Rostedt (Google) 	preempt_disable();
5442cc621fdSSteven Rostedt (Google) 	arch_spin_lock(&trace_cmdline_lock);
5452cc621fdSSteven Rostedt (Google) 
5462cc621fdSSteven Rostedt (Google) 	v = &savedcmd->map_cmdline_to_pid[0];
5472cc621fdSSteven Rostedt (Google) 	while (l <= *pos) {
5482cc621fdSSteven Rostedt (Google) 		v = saved_cmdlines_next(m, v, &l);
5492cc621fdSSteven Rostedt (Google) 		if (!v)
5502cc621fdSSteven Rostedt (Google) 			return NULL;
5512cc621fdSSteven Rostedt (Google) 	}
5522cc621fdSSteven Rostedt (Google) 
5532cc621fdSSteven Rostedt (Google) 	return v;
5542cc621fdSSteven Rostedt (Google) }
5552cc621fdSSteven Rostedt (Google) 
saved_cmdlines_stop(struct seq_file * m,void * v)5562cc621fdSSteven Rostedt (Google) static void saved_cmdlines_stop(struct seq_file *m, void *v)
5572cc621fdSSteven Rostedt (Google) {
5582cc621fdSSteven Rostedt (Google) 	arch_spin_unlock(&trace_cmdline_lock);
5592cc621fdSSteven Rostedt (Google) 	preempt_enable();
5602cc621fdSSteven Rostedt (Google) }
5612cc621fdSSteven Rostedt (Google) 
saved_cmdlines_show(struct seq_file * m,void * v)5622cc621fdSSteven Rostedt (Google) static int saved_cmdlines_show(struct seq_file *m, void *v)
5632cc621fdSSteven Rostedt (Google) {
5642cc621fdSSteven Rostedt (Google) 	char buf[TASK_COMM_LEN];
5652cc621fdSSteven Rostedt (Google) 	unsigned int *pid = v;
5662cc621fdSSteven Rostedt (Google) 
5672cc621fdSSteven Rostedt (Google) 	__trace_find_cmdline(*pid, buf);
5682cc621fdSSteven Rostedt (Google) 	seq_printf(m, "%d %s\n", *pid, buf);
5692cc621fdSSteven Rostedt (Google) 	return 0;
5702cc621fdSSteven Rostedt (Google) }
5712cc621fdSSteven Rostedt (Google) 
5722cc621fdSSteven Rostedt (Google) static const struct seq_operations tracing_saved_cmdlines_seq_ops = {
5732cc621fdSSteven Rostedt (Google) 	.start		= saved_cmdlines_start,
5742cc621fdSSteven Rostedt (Google) 	.next		= saved_cmdlines_next,
5752cc621fdSSteven Rostedt (Google) 	.stop		= saved_cmdlines_stop,
5762cc621fdSSteven Rostedt (Google) 	.show		= saved_cmdlines_show,
5772cc621fdSSteven Rostedt (Google) };
5782cc621fdSSteven Rostedt (Google) 
tracing_saved_cmdlines_open(struct inode * inode,struct file * filp)5792cc621fdSSteven Rostedt (Google) static int tracing_saved_cmdlines_open(struct inode *inode, struct file *filp)
5802cc621fdSSteven Rostedt (Google) {
5812cc621fdSSteven Rostedt (Google) 	int ret;
5822cc621fdSSteven Rostedt (Google) 
5832cc621fdSSteven Rostedt (Google) 	ret = tracing_check_open_get_tr(NULL);
5842cc621fdSSteven Rostedt (Google) 	if (ret)
5852cc621fdSSteven Rostedt (Google) 		return ret;
5862cc621fdSSteven Rostedt (Google) 
5872cc621fdSSteven Rostedt (Google) 	return seq_open(filp, &tracing_saved_cmdlines_seq_ops);
5882cc621fdSSteven Rostedt (Google) }
5892cc621fdSSteven Rostedt (Google) 
5902cc621fdSSteven Rostedt (Google) const struct file_operations tracing_saved_cmdlines_fops = {
5912cc621fdSSteven Rostedt (Google) 	.open		= tracing_saved_cmdlines_open,
5922cc621fdSSteven Rostedt (Google) 	.read		= seq_read,
5932cc621fdSSteven Rostedt (Google) 	.llseek		= seq_lseek,
5942cc621fdSSteven Rostedt (Google) 	.release	= seq_release,
5952cc621fdSSteven Rostedt (Google) };
5962cc621fdSSteven Rostedt (Google) 
5972cc621fdSSteven Rostedt (Google) static ssize_t
tracing_saved_cmdlines_size_read(struct file * filp,char __user * ubuf,size_t cnt,loff_t * ppos)5982cc621fdSSteven Rostedt (Google) tracing_saved_cmdlines_size_read(struct file *filp, char __user *ubuf,
5992cc621fdSSteven Rostedt (Google) 				 size_t cnt, loff_t *ppos)
6002cc621fdSSteven Rostedt (Google) {
6012cc621fdSSteven Rostedt (Google) 	char buf[64];
6022cc621fdSSteven Rostedt (Google) 	int r;
6032cc621fdSSteven Rostedt (Google) 
6042cc621fdSSteven Rostedt (Google) 	preempt_disable();
6052cc621fdSSteven Rostedt (Google) 	arch_spin_lock(&trace_cmdline_lock);
6062cc621fdSSteven Rostedt (Google) 	r = scnprintf(buf, sizeof(buf), "%u\n", savedcmd->cmdline_num);
6072cc621fdSSteven Rostedt (Google) 	arch_spin_unlock(&trace_cmdline_lock);
6082cc621fdSSteven Rostedt (Google) 	preempt_enable();
6092cc621fdSSteven Rostedt (Google) 
6102cc621fdSSteven Rostedt (Google) 	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
6112cc621fdSSteven Rostedt (Google) }
6122cc621fdSSteven Rostedt (Google) 
trace_free_saved_cmdlines_buffer(void)6132cc621fdSSteven Rostedt (Google) void trace_free_saved_cmdlines_buffer(void)
6142cc621fdSSteven Rostedt (Google) {
6152cc621fdSSteven Rostedt (Google) 	free_saved_cmdlines_buffer(savedcmd);
6162cc621fdSSteven Rostedt (Google) }
6172cc621fdSSteven Rostedt (Google) 
tracing_resize_saved_cmdlines(unsigned int val)6182cc621fdSSteven Rostedt (Google) static int tracing_resize_saved_cmdlines(unsigned int val)
6192cc621fdSSteven Rostedt (Google) {
6202cc621fdSSteven Rostedt (Google) 	struct saved_cmdlines_buffer *s, *savedcmd_temp;
6212cc621fdSSteven Rostedt (Google) 
6222cc621fdSSteven Rostedt (Google) 	s = allocate_cmdlines_buffer(val);
6232cc621fdSSteven Rostedt (Google) 	if (!s)
6242cc621fdSSteven Rostedt (Google) 		return -ENOMEM;
6252cc621fdSSteven Rostedt (Google) 
6262cc621fdSSteven Rostedt (Google) 	preempt_disable();
6272cc621fdSSteven Rostedt (Google) 	arch_spin_lock(&trace_cmdline_lock);
6282cc621fdSSteven Rostedt (Google) 	savedcmd_temp = savedcmd;
6292cc621fdSSteven Rostedt (Google) 	savedcmd = s;
6302cc621fdSSteven Rostedt (Google) 	arch_spin_unlock(&trace_cmdline_lock);
6312cc621fdSSteven Rostedt (Google) 	preempt_enable();
6322cc621fdSSteven Rostedt (Google) 	free_saved_cmdlines_buffer(savedcmd_temp);
6332cc621fdSSteven Rostedt (Google) 
6342cc621fdSSteven Rostedt (Google) 	return 0;
6352cc621fdSSteven Rostedt (Google) }
6362cc621fdSSteven Rostedt (Google) 
6372cc621fdSSteven Rostedt (Google) static ssize_t
tracing_saved_cmdlines_size_write(struct file * filp,const char __user * ubuf,size_t cnt,loff_t * ppos)6382cc621fdSSteven Rostedt (Google) tracing_saved_cmdlines_size_write(struct file *filp, const char __user *ubuf,
6392cc621fdSSteven Rostedt (Google) 				  size_t cnt, loff_t *ppos)
6402cc621fdSSteven Rostedt (Google) {
6412cc621fdSSteven Rostedt (Google) 	unsigned long val;
6422cc621fdSSteven Rostedt (Google) 	int ret;
6432cc621fdSSteven Rostedt (Google) 
6442cc621fdSSteven Rostedt (Google) 	ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
6452cc621fdSSteven Rostedt (Google) 	if (ret)
6462cc621fdSSteven Rostedt (Google) 		return ret;
6472cc621fdSSteven Rostedt (Google) 
6482cc621fdSSteven Rostedt (Google) 	/* must have at least 1 entry or less than PID_MAX_DEFAULT */
6492cc621fdSSteven Rostedt (Google) 	if (!val || val > PID_MAX_DEFAULT)
6502cc621fdSSteven Rostedt (Google) 		return -EINVAL;
6512cc621fdSSteven Rostedt (Google) 
6522cc621fdSSteven Rostedt (Google) 	ret = tracing_resize_saved_cmdlines((unsigned int)val);
6532cc621fdSSteven Rostedt (Google) 	if (ret < 0)
6542cc621fdSSteven Rostedt (Google) 		return ret;
6552cc621fdSSteven Rostedt (Google) 
6562cc621fdSSteven Rostedt (Google) 	*ppos += cnt;
6572cc621fdSSteven Rostedt (Google) 
6582cc621fdSSteven Rostedt (Google) 	return cnt;
6592cc621fdSSteven Rostedt (Google) }
6602cc621fdSSteven Rostedt (Google) 
6612cc621fdSSteven Rostedt (Google) const struct file_operations tracing_saved_cmdlines_size_fops = {
6622cc621fdSSteven Rostedt (Google) 	.open		= tracing_open_generic,
6632cc621fdSSteven Rostedt (Google) 	.read		= tracing_saved_cmdlines_size_read,
6642cc621fdSSteven Rostedt (Google) 	.write		= tracing_saved_cmdlines_size_write,
6652cc621fdSSteven Rostedt (Google) };
666