xref: /openbmc/linux/kernel/trace/trace_stat.c (revision 4e4f6e33)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2dbd0b4b3SFrederic Weisbecker /*
3dbd0b4b3SFrederic Weisbecker  * Infrastructure for statistic tracing (histogram output).
4dbd0b4b3SFrederic Weisbecker  *
58f184f27SFrederic Weisbecker  * Copyright (C) 2008-2009 Frederic Weisbecker <fweisbec@gmail.com>
6dbd0b4b3SFrederic Weisbecker  *
7dbd0b4b3SFrederic Weisbecker  * Based on the code from trace_branch.c which is
8dbd0b4b3SFrederic Weisbecker  * Copyright (C) 2008 Steven Rostedt <srostedt@redhat.com>
9dbd0b4b3SFrederic Weisbecker  *
10dbd0b4b3SFrederic Weisbecker  */
11dbd0b4b3SFrederic Weisbecker 
1217911ff3SSteven Rostedt (VMware) #include <linux/security.h>
13dbd0b4b3SFrederic Weisbecker #include <linux/list.h>
145a0e3ad6STejun Heo #include <linux/slab.h>
158f184f27SFrederic Weisbecker #include <linux/rbtree.h>
168434dc93SSteven Rostedt (Red Hat) #include <linux/tracefs.h>
17002bb86dSFrederic Weisbecker #include "trace_stat.h"
18dbd0b4b3SFrederic Weisbecker #include "trace.h"
19dbd0b4b3SFrederic Weisbecker 
20dbd0b4b3SFrederic Weisbecker 
218f184f27SFrederic Weisbecker /*
228f184f27SFrederic Weisbecker  * List of stat red-black nodes from a tracer
238f184f27SFrederic Weisbecker  * We use a such tree to sort quickly the stat
248f184f27SFrederic Weisbecker  * entries from the tracer.
258f184f27SFrederic Weisbecker  */
268f184f27SFrederic Weisbecker struct stat_node {
278f184f27SFrederic Weisbecker 	struct rb_node		node;
28dbd0b4b3SFrederic Weisbecker 	void			*stat;
29dbd0b4b3SFrederic Weisbecker };
30dbd0b4b3SFrederic Weisbecker 
31034939b6SFrederic Weisbecker /* A stat session is the stats output in one file */
320d64f834SFrederic Weisbecker struct stat_session {
33002bb86dSFrederic Weisbecker 	struct list_head	session_list;
34034939b6SFrederic Weisbecker 	struct tracer_stat	*ts;
358f184f27SFrederic Weisbecker 	struct rb_root		stat_root;
36034939b6SFrederic Weisbecker 	struct mutex		stat_mutex;
37002bb86dSFrederic Weisbecker 	struct dentry		*file;
38034939b6SFrederic Weisbecker };
39dbd0b4b3SFrederic Weisbecker 
4073d8b8bcSWenji Huang /* All of the sessions currently in use. Each stat file embed one session */
41002bb86dSFrederic Weisbecker static LIST_HEAD(all_stat_sessions);
42002bb86dSFrederic Weisbecker static DEFINE_MUTEX(all_stat_sessions_mutex);
43002bb86dSFrederic Weisbecker 
44002bb86dSFrederic Weisbecker /* The root directory for all stat files */
45002bb86dSFrederic Weisbecker static struct dentry		*stat_dir;
46dbd0b4b3SFrederic Weisbecker 
__reset_stat_session(struct stat_session * session)47636eaceeSLi Zefan static void __reset_stat_session(struct stat_session *session)
48dbd0b4b3SFrederic Weisbecker {
499cd804acSCody P Schafer 	struct stat_node *snode, *n;
50dbd0b4b3SFrederic Weisbecker 
519cd804acSCody P Schafer 	rbtree_postorder_for_each_entry_safe(snode, n, &session->stat_root, node) {
529cd804acSCody P Schafer 		if (session->ts->stat_release)
539cd804acSCody P Schafer 			session->ts->stat_release(snode->stat);
549cd804acSCody P Schafer 		kfree(snode);
559cd804acSCody P Schafer 	}
56dbd0b4b3SFrederic Weisbecker 
578f184f27SFrederic Weisbecker 	session->stat_root = RB_ROOT;
58dbd0b4b3SFrederic Weisbecker }
59dbd0b4b3SFrederic Weisbecker 
reset_stat_session(struct stat_session * session)60636eaceeSLi Zefan static void reset_stat_session(struct stat_session *session)
61636eaceeSLi Zefan {
62636eaceeSLi Zefan 	mutex_lock(&session->stat_mutex);
63636eaceeSLi Zefan 	__reset_stat_session(session);
64636eaceeSLi Zefan 	mutex_unlock(&session->stat_mutex);
65636eaceeSLi Zefan }
66636eaceeSLi Zefan 
destroy_session(struct stat_session * session)670d64f834SFrederic Weisbecker static void destroy_session(struct stat_session *session)
68dbd0b4b3SFrederic Weisbecker {
698434dc93SSteven Rostedt (Red Hat) 	tracefs_remove(session->file);
70636eaceeSLi Zefan 	__reset_stat_session(session);
71034939b6SFrederic Weisbecker 	mutex_destroy(&session->stat_mutex);
72034939b6SFrederic Weisbecker 	kfree(session);
73034939b6SFrederic Weisbecker }
74002bb86dSFrederic Weisbecker 
insert_stat(struct rb_root * root,void * stat,cmp_func_t cmp)7580042c8fSAndy Shevchenko static int insert_stat(struct rb_root *root, void *stat, cmp_func_t cmp)
768f184f27SFrederic Weisbecker {
778f184f27SFrederic Weisbecker 	struct rb_node **new = &(root->rb_node), *parent = NULL;
78dbd3fbdfSLi Zefan 	struct stat_node *data;
79dbd3fbdfSLi Zefan 
80dbd3fbdfSLi Zefan 	data = kzalloc(sizeof(*data), GFP_KERNEL);
81dbd3fbdfSLi Zefan 	if (!data)
82dbd3fbdfSLi Zefan 		return -ENOMEM;
83dbd3fbdfSLi Zefan 	data->stat = stat;
848f184f27SFrederic Weisbecker 
858f184f27SFrederic Weisbecker 	/*
868f184f27SFrederic Weisbecker 	 * Figure out where to put new node
878f184f27SFrederic Weisbecker 	 * This is a descendent sorting
888f184f27SFrederic Weisbecker 	 */
898f184f27SFrederic Weisbecker 	while (*new) {
908f184f27SFrederic Weisbecker 		struct stat_node *this;
918f184f27SFrederic Weisbecker 		int result;
928f184f27SFrederic Weisbecker 
938f184f27SFrederic Weisbecker 		this = container_of(*new, struct stat_node, node);
948f184f27SFrederic Weisbecker 		result = cmp(data->stat, this->stat);
958f184f27SFrederic Weisbecker 
968f184f27SFrederic Weisbecker 		parent = *new;
978f184f27SFrederic Weisbecker 		if (result >= 0)
988f184f27SFrederic Weisbecker 			new = &((*new)->rb_left);
998f184f27SFrederic Weisbecker 		else
1008f184f27SFrederic Weisbecker 			new = &((*new)->rb_right);
1018f184f27SFrederic Weisbecker 	}
1028f184f27SFrederic Weisbecker 
1038f184f27SFrederic Weisbecker 	rb_link_node(&data->node, parent, new);
1048f184f27SFrederic Weisbecker 	rb_insert_color(&data->node, root);
105dbd3fbdfSLi Zefan 	return 0;
1068f184f27SFrederic Weisbecker }
1078f184f27SFrederic Weisbecker 
108dbd0b4b3SFrederic Weisbecker /*
109dbd0b4b3SFrederic Weisbecker  * For tracers that don't provide a stat_cmp callback.
110dbd3fbdfSLi Zefan  * This one will force an insertion as right-most node
111dbd3fbdfSLi Zefan  * in the rbtree.
112dbd0b4b3SFrederic Weisbecker  */
dummy_cmp(const void * p1,const void * p2)11380042c8fSAndy Shevchenko static int dummy_cmp(const void *p1, const void *p2)
114dbd0b4b3SFrederic Weisbecker {
115b3dd7ba7SLi Zefan 	return -1;
116dbd0b4b3SFrederic Weisbecker }
117dbd0b4b3SFrederic Weisbecker 
118dbd0b4b3SFrederic Weisbecker /*
119dbd3fbdfSLi Zefan  * Initialize the stat rbtree at each trace_stat file opening.
120dbd0b4b3SFrederic Weisbecker  * All of these copies and sorting are required on all opening
121dbd0b4b3SFrederic Weisbecker  * since the stats could have changed between two file sessions.
122dbd0b4b3SFrederic Weisbecker  */
stat_seq_init(struct stat_session * session)1230d64f834SFrederic Weisbecker static int stat_seq_init(struct stat_session *session)
124dbd0b4b3SFrederic Weisbecker {
125034939b6SFrederic Weisbecker 	struct tracer_stat *ts = session->ts;
126dbd3fbdfSLi Zefan 	struct rb_root *root = &session->stat_root;
12709833521SSteven Rostedt 	void *stat;
128dbd0b4b3SFrederic Weisbecker 	int ret = 0;
129dbd0b4b3SFrederic Weisbecker 	int i;
130dbd0b4b3SFrederic Weisbecker 
131034939b6SFrederic Weisbecker 	mutex_lock(&session->stat_mutex);
132636eaceeSLi Zefan 	__reset_stat_session(session);
133dbd0b4b3SFrederic Weisbecker 
134034939b6SFrederic Weisbecker 	if (!ts->stat_cmp)
135034939b6SFrederic Weisbecker 		ts->stat_cmp = dummy_cmp;
136dbd0b4b3SFrederic Weisbecker 
13742548008SSteven Rostedt 	stat = ts->stat_start(ts);
13809833521SSteven Rostedt 	if (!stat)
13909833521SSteven Rostedt 		goto exit;
14009833521SSteven Rostedt 
141dbd3fbdfSLi Zefan 	ret = insert_stat(root, stat, ts->stat_cmp);
142dbd3fbdfSLi Zefan 	if (ret)
143dbd0b4b3SFrederic Weisbecker 		goto exit;
144dbd0b4b3SFrederic Weisbecker 
145dbd0b4b3SFrederic Weisbecker 	/*
146dbd3fbdfSLi Zefan 	 * Iterate over the tracer stat entries and store them in an rbtree.
147dbd0b4b3SFrederic Weisbecker 	 */
148dbd0b4b3SFrederic Weisbecker 	for (i = 1; ; i++) {
14909833521SSteven Rostedt 		stat = ts->stat_next(stat, i);
15009833521SSteven Rostedt 
15109833521SSteven Rostedt 		/* End of insertion */
15209833521SSteven Rostedt 		if (!stat)
15309833521SSteven Rostedt 			break;
15409833521SSteven Rostedt 
155dbd3fbdfSLi Zefan 		ret = insert_stat(root, stat, ts->stat_cmp);
156dbd3fbdfSLi Zefan 		if (ret)
157dbd3fbdfSLi Zefan 			goto exit_free_rbtree;
158dbd0b4b3SFrederic Weisbecker 	}
159220ba351SLai Jiangshan 
160dbd0b4b3SFrederic Weisbecker exit:
161034939b6SFrederic Weisbecker 	mutex_unlock(&session->stat_mutex);
162dbd0b4b3SFrederic Weisbecker 	return ret;
163dbd0b4b3SFrederic Weisbecker 
164dbd3fbdfSLi Zefan exit_free_rbtree:
165636eaceeSLi Zefan 	__reset_stat_session(session);
166034939b6SFrederic Weisbecker 	mutex_unlock(&session->stat_mutex);
167dbd0b4b3SFrederic Weisbecker 	return ret;
168dbd0b4b3SFrederic Weisbecker }
169dbd0b4b3SFrederic Weisbecker 
170dbd0b4b3SFrederic Weisbecker 
stat_seq_start(struct seq_file * s,loff_t * pos)171dbd0b4b3SFrederic Weisbecker static void *stat_seq_start(struct seq_file *s, loff_t *pos)
172dbd0b4b3SFrederic Weisbecker {
1730d64f834SFrederic Weisbecker 	struct stat_session *session = s->private;
1748f184f27SFrederic Weisbecker 	struct rb_node *node;
17597d53202SLi Zefan 	int n = *pos;
1768f184f27SFrederic Weisbecker 	int i;
177dbd0b4b3SFrederic Weisbecker 
178dbd3fbdfSLi Zefan 	/* Prevent from tracer switch or rbtree modification */
179034939b6SFrederic Weisbecker 	mutex_lock(&session->stat_mutex);
180dbd0b4b3SFrederic Weisbecker 
181dbd0b4b3SFrederic Weisbecker 	/* If we are in the beginning of the file, print the headers */
18297d53202SLi Zefan 	if (session->ts->stat_headers) {
18397d53202SLi Zefan 		if (n == 0)
184e6f48901SLai Jiangshan 			return SEQ_START_TOKEN;
18597d53202SLi Zefan 		n--;
18697d53202SLi Zefan 	}
187dbd0b4b3SFrederic Weisbecker 
1888f184f27SFrederic Weisbecker 	node = rb_first(&session->stat_root);
18997d53202SLi Zefan 	for (i = 0; node && i < n; i++)
1908f184f27SFrederic Weisbecker 		node = rb_next(node);
1918f184f27SFrederic Weisbecker 
1928f184f27SFrederic Weisbecker 	return node;
193dbd0b4b3SFrederic Weisbecker }
194dbd0b4b3SFrederic Weisbecker 
stat_seq_next(struct seq_file * s,void * p,loff_t * pos)195dbd0b4b3SFrederic Weisbecker static void *stat_seq_next(struct seq_file *s, void *p, loff_t *pos)
196dbd0b4b3SFrederic Weisbecker {
1970d64f834SFrederic Weisbecker 	struct stat_session *session = s->private;
1988f184f27SFrederic Weisbecker 	struct rb_node *node = p;
1998f184f27SFrederic Weisbecker 
2008f184f27SFrederic Weisbecker 	(*pos)++;
201dbd0b4b3SFrederic Weisbecker 
202e6f48901SLai Jiangshan 	if (p == SEQ_START_TOKEN)
2038f184f27SFrederic Weisbecker 		return rb_first(&session->stat_root);
204e6f48901SLai Jiangshan 
2058f184f27SFrederic Weisbecker 	return rb_next(node);
206dbd0b4b3SFrederic Weisbecker }
207dbd0b4b3SFrederic Weisbecker 
stat_seq_stop(struct seq_file * s,void * p)208034939b6SFrederic Weisbecker static void stat_seq_stop(struct seq_file *s, void *p)
209dbd0b4b3SFrederic Weisbecker {
2100d64f834SFrederic Weisbecker 	struct stat_session *session = s->private;
211034939b6SFrederic Weisbecker 	mutex_unlock(&session->stat_mutex);
212dbd0b4b3SFrederic Weisbecker }
213dbd0b4b3SFrederic Weisbecker 
stat_seq_show(struct seq_file * s,void * v)214dbd0b4b3SFrederic Weisbecker static int stat_seq_show(struct seq_file *s, void *v)
215dbd0b4b3SFrederic Weisbecker {
2160d64f834SFrederic Weisbecker 	struct stat_session *session = s->private;
2178f184f27SFrederic Weisbecker 	struct stat_node *l = container_of(v, struct stat_node, node);
218e8a9cbf6SSteven Rostedt 
219e6f48901SLai Jiangshan 	if (v == SEQ_START_TOKEN)
220e6f48901SLai Jiangshan 		return session->ts->stat_headers(s);
221e6f48901SLai Jiangshan 
222034939b6SFrederic Weisbecker 	return session->ts->stat_show(s, l->stat);
223dbd0b4b3SFrederic Weisbecker }
224dbd0b4b3SFrederic Weisbecker 
225dbd0b4b3SFrederic Weisbecker static const struct seq_operations trace_stat_seq_ops = {
226dbd0b4b3SFrederic Weisbecker 	.start		= stat_seq_start,
227dbd0b4b3SFrederic Weisbecker 	.next		= stat_seq_next,
228dbd0b4b3SFrederic Weisbecker 	.stop		= stat_seq_stop,
229dbd0b4b3SFrederic Weisbecker 	.show		= stat_seq_show
230dbd0b4b3SFrederic Weisbecker };
231dbd0b4b3SFrederic Weisbecker 
232034939b6SFrederic Weisbecker /* The session stat is refilled and resorted at each stat file opening */
tracing_stat_open(struct inode * inode,struct file * file)233dbd0b4b3SFrederic Weisbecker static int tracing_stat_open(struct inode *inode, struct file *file)
234dbd0b4b3SFrederic Weisbecker {
235dbd0b4b3SFrederic Weisbecker 	int ret;
236636eaceeSLi Zefan 	struct seq_file *m;
2370d64f834SFrederic Weisbecker 	struct stat_session *session = inode->i_private;
238034939b6SFrederic Weisbecker 
23917911ff3SSteven Rostedt (VMware) 	ret = security_locked_down(LOCKDOWN_TRACEFS);
24017911ff3SSteven Rostedt (VMware) 	if (ret)
24117911ff3SSteven Rostedt (VMware) 		return ret;
24217911ff3SSteven Rostedt (VMware) 
243034939b6SFrederic Weisbecker 	ret = stat_seq_init(session);
244636eaceeSLi Zefan 	if (ret)
245636eaceeSLi Zefan 		return ret;
246636eaceeSLi Zefan 
247636eaceeSLi Zefan 	ret = seq_open(file, &trace_stat_seq_ops);
248636eaceeSLi Zefan 	if (ret) {
249636eaceeSLi Zefan 		reset_stat_session(session);
250636eaceeSLi Zefan 		return ret;
251dbd0b4b3SFrederic Weisbecker 	}
252dbd0b4b3SFrederic Weisbecker 
253636eaceeSLi Zefan 	m = file->private_data;
254636eaceeSLi Zefan 	m->private = session;
255dbd0b4b3SFrederic Weisbecker 	return ret;
256dbd0b4b3SFrederic Weisbecker }
257dbd0b4b3SFrederic Weisbecker 
258dbd0b4b3SFrederic Weisbecker /*
259dbd3fbdfSLi Zefan  * Avoid consuming memory with our now useless rbtree.
260dbd0b4b3SFrederic Weisbecker  */
tracing_stat_release(struct inode * i,struct file * f)261dbd0b4b3SFrederic Weisbecker static int tracing_stat_release(struct inode *i, struct file *f)
262dbd0b4b3SFrederic Weisbecker {
2630d64f834SFrederic Weisbecker 	struct stat_session *session = i->i_private;
264034939b6SFrederic Weisbecker 
265034939b6SFrederic Weisbecker 	reset_stat_session(session);
266034939b6SFrederic Weisbecker 
267636eaceeSLi Zefan 	return seq_release(i, f);
268dbd0b4b3SFrederic Weisbecker }
269dbd0b4b3SFrederic Weisbecker 
270dbd0b4b3SFrederic Weisbecker static const struct file_operations tracing_stat_fops = {
271dbd0b4b3SFrederic Weisbecker 	.open		= tracing_stat_open,
272dbd0b4b3SFrederic Weisbecker 	.read		= seq_read,
273dbd0b4b3SFrederic Weisbecker 	.llseek		= seq_lseek,
274dbd0b4b3SFrederic Weisbecker 	.release	= tracing_stat_release
275dbd0b4b3SFrederic Weisbecker };
276dbd0b4b3SFrederic Weisbecker 
tracing_stat_init(void)277002bb86dSFrederic Weisbecker static int tracing_stat_init(void)
278dbd0b4b3SFrederic Weisbecker {
27922c36b18SWei Yang 	int ret;
280dbd0b4b3SFrederic Weisbecker 
28122c36b18SWei Yang 	ret = tracing_init_dentry();
28222c36b18SWei Yang 	if (ret)
283afccc00fSLuis Henriques 		return -ENODEV;
284dbd0b4b3SFrederic Weisbecker 
28522c36b18SWei Yang 	stat_dir = tracefs_create_dir("trace_stat", NULL);
286afccc00fSLuis Henriques 	if (!stat_dir) {
287a395d6a7SJoe Perches 		pr_warn("Could not create tracefs 'trace_stat' entry\n");
288afccc00fSLuis Henriques 		return -ENOMEM;
289afccc00fSLuis Henriques 	}
290dbd0b4b3SFrederic Weisbecker 	return 0;
291dbd0b4b3SFrederic Weisbecker }
292002bb86dSFrederic Weisbecker 
init_stat_file(struct stat_session * session)2930d64f834SFrederic Weisbecker static int init_stat_file(struct stat_session *session)
294002bb86dSFrederic Weisbecker {
295afccc00fSLuis Henriques 	int ret;
296afccc00fSLuis Henriques 
297afccc00fSLuis Henriques 	if (!stat_dir && (ret = tracing_stat_init()))
298afccc00fSLuis Henriques 		return ret;
299002bb86dSFrederic Weisbecker 
300*4e4f6e33SSteven Rostedt (VMware) 	session->file = tracefs_create_file(session->ts->name, TRACE_MODE_WRITE,
301*4e4f6e33SSteven Rostedt (VMware) 					    stat_dir, session,
302*4e4f6e33SSteven Rostedt (VMware) 					    &tracing_stat_fops);
303002bb86dSFrederic Weisbecker 	if (!session->file)
304002bb86dSFrederic Weisbecker 		return -ENOMEM;
305002bb86dSFrederic Weisbecker 	return 0;
306002bb86dSFrederic Weisbecker }
30755922173SIngo Molnar 
register_stat_tracer(struct tracer_stat * trace)30855922173SIngo Molnar int register_stat_tracer(struct tracer_stat *trace)
30955922173SIngo Molnar {
31043bd1236SFrederic Weisbecker 	struct stat_session *session, *node;
311dfb6cd1eSSteven Rostedt (VMware) 	int ret = -EINVAL;
31255922173SIngo Molnar 
31355922173SIngo Molnar 	if (!trace)
31455922173SIngo Molnar 		return -EINVAL;
31555922173SIngo Molnar 
31655922173SIngo Molnar 	if (!trace->stat_start || !trace->stat_next || !trace->stat_show)
31755922173SIngo Molnar 		return -EINVAL;
31855922173SIngo Molnar 
31955922173SIngo Molnar 	/* Already registered? */
32055922173SIngo Molnar 	mutex_lock(&all_stat_sessions_mutex);
32143bd1236SFrederic Weisbecker 	list_for_each_entry(node, &all_stat_sessions, session_list) {
322dfb6cd1eSSteven Rostedt (VMware) 		if (node->ts == trace)
323dfb6cd1eSSteven Rostedt (VMware) 			goto out;
32455922173SIngo Molnar 	}
32555922173SIngo Molnar 
326dfb6cd1eSSteven Rostedt (VMware) 	ret = -ENOMEM;
32755922173SIngo Molnar 	/* Init the session */
3288f184f27SFrederic Weisbecker 	session = kzalloc(sizeof(*session), GFP_KERNEL);
32955922173SIngo Molnar 	if (!session)
330dfb6cd1eSSteven Rostedt (VMware) 		goto out;
33155922173SIngo Molnar 
33255922173SIngo Molnar 	session->ts = trace;
33355922173SIngo Molnar 	INIT_LIST_HEAD(&session->session_list);
33455922173SIngo Molnar 	mutex_init(&session->stat_mutex);
33555922173SIngo Molnar 
33655922173SIngo Molnar 	ret = init_stat_file(session);
33755922173SIngo Molnar 	if (ret) {
33855922173SIngo Molnar 		destroy_session(session);
339dfb6cd1eSSteven Rostedt (VMware) 		goto out;
34055922173SIngo Molnar 	}
34155922173SIngo Molnar 
342dfb6cd1eSSteven Rostedt (VMware) 	ret = 0;
34355922173SIngo Molnar 	/* Register */
34455922173SIngo Molnar 	list_add_tail(&session->session_list, &all_stat_sessions);
345dfb6cd1eSSteven Rostedt (VMware)  out:
34655922173SIngo Molnar 	mutex_unlock(&all_stat_sessions_mutex);
34755922173SIngo Molnar 
348dfb6cd1eSSteven Rostedt (VMware) 	return ret;
34955922173SIngo Molnar }
35055922173SIngo Molnar 
unregister_stat_tracer(struct tracer_stat * trace)35155922173SIngo Molnar void unregister_stat_tracer(struct tracer_stat *trace)
35255922173SIngo Molnar {
3530d64f834SFrederic Weisbecker 	struct stat_session *node, *tmp;
35455922173SIngo Molnar 
35555922173SIngo Molnar 	mutex_lock(&all_stat_sessions_mutex);
35655922173SIngo Molnar 	list_for_each_entry_safe(node, tmp, &all_stat_sessions, session_list) {
35755922173SIngo Molnar 		if (node->ts == trace) {
35855922173SIngo Molnar 			list_del(&node->session_list);
35955922173SIngo Molnar 			destroy_session(node);
36055922173SIngo Molnar 			break;
36155922173SIngo Molnar 		}
36255922173SIngo Molnar 	}
36355922173SIngo Molnar 	mutex_unlock(&all_stat_sessions_mutex);
36455922173SIngo Molnar }
365