/* SPDX-License-Identifier: GPL-2.0 */
/*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* Authors : Waiman Long < waiman . long @ hpe . com >
*/
/*
* Collect locking event counts
*/
#include <linux/debugfs.h>
#include <linux/sched.h>
#include <linux/sched/clock.h>
#include <linux/fs.h>
#include "lock_events.h"
#undef LOCK_EVENT
#define LOCK_EVENT(name) [LOCKEVENT_ ## name] = #name ,
#define LOCK_EVENTS_DIR "lock_event_counts"
/*
* When CONFIG_LOCK_EVENT_COUNTS is enabled , event counts of different
* types of locks will be reported under the < debugfs > / lock_event_counts /
* directory . See lock_events_list . h for the list of available locking
* events .
*
* Writing to the special " . reset_counts " file will reset all the above
* locking event counts . This is a very slow operation and so should not
* be done frequently .
*
* These event counts are implemented as per - cpu variables which are
* summed and computed whenever the corresponding debugfs files are read . This
* minimizes added overhead making the counts usable even in a production
* environment .
*/
static const char * const lockevent_names[lockevent_num + 1 ] = {
#include "lock_events_list.h"
[LOCKEVENT_reset_cnts] = ".reset_counts" ,
};
/*
* Per - cpu counts
*/
DEFINE_PER_CPU(unsigned long , lockevents[lockevent_num]);
/*
* The lockevent_read ( ) function can be overridden .
*/
ssize_t __weak lockevent_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
char buf[64 ];
int cpu, id, len;
u64 sum = 0 ;
/*
* Get the counter ID stored in file - > f_inode - > i_private
*/
id = (long )file_inode(file)->i_private;
if (id >= lockevent_num)
return -EBADF;
for_each_possible_cpu(cpu)
sum += per_cpu(lockevents[id], cpu);
len = snprintf(buf, sizeof (buf) - 1 , "%llu\n" , sum);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
/*
* Function to handle write request
*
* When idx = reset_cnts , reset all the counts .
*/
static ssize_t lockevent_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
int cpu;
/*
* Get the counter ID stored in file - > f_inode - > i_private
*/
if ((long )file_inode(file)->i_private != LOCKEVENT_reset_cnts)
return count;
for_each_possible_cpu(cpu) {
int i;
unsigned long *ptr = per_cpu_ptr(lockevents, cpu);
for (i = 0 ; i < lockevent_num; i++)
WRITE_ONCE(ptr[i], 0 );
}
return count;
}
/*
* Debugfs data structures
*/
static const struct file_operations fops_lockevent = {
.read = lockevent_read,
.write = lockevent_write,
.llseek = default_llseek,
};
#ifdef CONFIG_PARAVIRT_SPINLOCKS
#include <asm /paravirt.h>
static bool __init skip_lockevent(const char *name)
{
static int pv_on __initdata = -1 ;
if (pv_on < 0 )
pv_on = !pv_is_native_spin_unlock();
/*
* Skip PV qspinlock events on bare metal .
*/
if (!pv_on && !memcmp(name, "pv_" , 3 ))
return true ;
return false ;
}
#else
static inline bool skip_lockevent(const char *name)
{
return false ;
}
#endif
/*
* Initialize debugfs for the locking event counts .
*/
static int __init init_lockevent_counts(void )
{
struct dentry *d_counts = debugfs_create_dir(LOCK_EVENTS_DIR, NULL);
int i;
if (IS_ERR(d_counts))
goto out;
/*
* Create the debugfs files
*
* As reading from and writing to the stat files can be slow , only
* root is allowed to do the read / write to limit impact to system
* performance .
*/
for (i = 0 ; i < lockevent_num; i++) {
if (skip_lockevent(lockevent_names[i]))
continue ;
if (IS_ERR(debugfs_create_file(lockevent_names[i], 0400 , d_counts,
(void *)(long )i, &fops_lockevent)))
goto fail_undo;
}
if (IS_ERR(debugfs_create_file(lockevent_names[LOCKEVENT_reset_cnts], 0200 ,
d_counts, (void *)(long )LOCKEVENT_reset_cnts,
&fops_lockevent)))
goto fail_undo;
return 0 ;
fail_undo:
debugfs_remove_recursive(d_counts);
out:
pr_warn("Could not create '%s' debugfs entries\n" , LOCK_EVENTS_DIR);
return -ENOMEM;
}
fs_initcall(init_lockevent_counts);
Messung V0.5 in Prozent C=94 H=84 G=88
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland