mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 14:04:27 -04:00
alloc_tag: add ioctl filters to /proc/allocinfo
Extend the capability of the IOCTL mechanism to filter allocations based on tag's module name, function name, file name and line number. Link: https://lore.kernel.org/6a6100c0c58cb2911f39126b9fe177a8c17db16f.1783532853.git.abhishekbapat@google.com Signed-off-by: Abhishek Bapat <abhishekbapat@google.com> Acked-by: Hao Ge <hao.ge@linux.dev> Acked-by: Suren Baghdasaryan <surenb@google.com> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Kent Overstreet <kent.overstreet@linux.dev> Cc: Sourav Panda <souravpanda@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
committed by
Andrew Morton
parent
1d581ab234
commit
5732a4e4c1
@@ -45,8 +45,32 @@ struct allocinfo_tag_data {
|
||||
struct allocinfo_counter counter;
|
||||
};
|
||||
|
||||
enum {
|
||||
ALLOCINFO_FILTER_MODNAME,
|
||||
ALLOCINFO_FILTER_FUNCTION,
|
||||
ALLOCINFO_FILTER_FILENAME,
|
||||
ALLOCINFO_FILTER_LINENO,
|
||||
__ALLOCINFO_FILTER_LAST = ALLOCINFO_FILTER_LINENO
|
||||
};
|
||||
|
||||
#define ALLOCINFO_FILTER_MASK_MODNAME (1 << ALLOCINFO_FILTER_MODNAME)
|
||||
#define ALLOCINFO_FILTER_MASK_FUNCTION (1 << ALLOCINFO_FILTER_FUNCTION)
|
||||
#define ALLOCINFO_FILTER_MASK_FILENAME (1 << ALLOCINFO_FILTER_FILENAME)
|
||||
#define ALLOCINFO_FILTER_MASK_LINENO (1 << ALLOCINFO_FILTER_LINENO)
|
||||
|
||||
#define ALLOCINFO_FILTER_MASKS \
|
||||
((1 << (__ALLOCINFO_FILTER_LAST + 1)) - 1)
|
||||
|
||||
struct allocinfo_filter {
|
||||
__u64 mask; /* bitmask of the filter fields used */
|
||||
struct allocinfo_tag fields;
|
||||
};
|
||||
|
||||
struct allocinfo_get_at {
|
||||
__u64 pos; /* input */
|
||||
/* inputs */
|
||||
__u64 pos;
|
||||
struct allocinfo_filter filter;
|
||||
/* output */
|
||||
struct allocinfo_tag_data data;
|
||||
};
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ struct allocinfo_private {
|
||||
struct codetag_iterator iter;
|
||||
struct codetag_iterator reported_iter;
|
||||
bool print_header;
|
||||
struct allocinfo_filter filter;
|
||||
/* ioctl uses a separate iterator not to interfere with reads */
|
||||
struct codetag_iterator ioctl_iter;
|
||||
bool positioned; /* seq_open_private() sets to 0 */
|
||||
@@ -204,6 +205,12 @@ static void allocinfo_copy_str(char *dest, const char *src)
|
||||
strscpy_pad(dest, allocinfo_str(src), ALLOCINFO_STR_SIZE);
|
||||
}
|
||||
|
||||
/* Compare two strings and only consider the trimmed suffix if s1 is too long */
|
||||
static int allocinfo_cmp_str(const char *str, const char *template)
|
||||
{
|
||||
return strncmp(allocinfo_str(str), template, ALLOCINFO_STR_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Populates the UAPI allocinfo_tag_data structure with active runtime
|
||||
* profiling counters extracted from the given kernel codetag.
|
||||
@@ -243,6 +250,40 @@ static int allocinfo_ioctl_get_content_id(struct seq_file *m, void __user *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies whether a given codetag satisfies the active filtering criteria by
|
||||
* matching its characteristics against the specified filter.
|
||||
*/
|
||||
static bool matches_filter(struct codetag *ct, struct allocinfo_filter *filter)
|
||||
{
|
||||
if (!filter || !filter->mask)
|
||||
return true;
|
||||
|
||||
if (filter->mask & ALLOCINFO_FILTER_MASK_MODNAME) {
|
||||
/* user wants to filter by modname but ct->modname is NULL */
|
||||
if (!ct->modname) {
|
||||
/* validate if user was attempting to filter for built-in allocations */
|
||||
if (filter->fields.modname[0] != '\0')
|
||||
return false;
|
||||
} else if (allocinfo_cmp_str(ct->modname, filter->fields.modname))
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((filter->mask & ALLOCINFO_FILTER_MASK_FUNCTION) &&
|
||||
ct->function && allocinfo_cmp_str(ct->function, filter->fields.function))
|
||||
return false;
|
||||
|
||||
if ((filter->mask & ALLOCINFO_FILTER_MASK_FILENAME) &&
|
||||
ct->filename && allocinfo_cmp_str(ct->filename, filter->fields.filename))
|
||||
return false;
|
||||
|
||||
if ((filter->mask & ALLOCINFO_FILTER_MASK_LINENO) &&
|
||||
ct->lineno != filter->fields.lineno)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Seeks the ioctl iterator to the specified 0-indexed tag position, reads its
|
||||
* profiling data and returns it to userspace.
|
||||
@@ -251,29 +292,46 @@ static int allocinfo_ioctl_get_at(struct seq_file *m, void __user *arg)
|
||||
{
|
||||
struct allocinfo_private *priv;
|
||||
struct codetag *ct;
|
||||
__u64 pos;
|
||||
struct allocinfo_get_at params = {0};
|
||||
__u64 skip_count;
|
||||
|
||||
if (copy_from_user(¶ms, arg, sizeof(params)))
|
||||
return -EFAULT;
|
||||
|
||||
if (params.filter.mask & ~ALLOCINFO_FILTER_MASKS)
|
||||
return -EINVAL;
|
||||
|
||||
priv = m->private;
|
||||
pos = params.pos;
|
||||
|
||||
mutex_lock(&priv->ioctl_lock);
|
||||
codetag_lock_module_list(alloc_tag_cttype);
|
||||
|
||||
if (pos >= codetag_get_count(alloc_tag_cttype)) {
|
||||
if (params.pos >= codetag_get_count(alloc_tag_cttype)) {
|
||||
codetag_unlock_module_list(alloc_tag_cttype);
|
||||
mutex_unlock(&priv->ioctl_lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
skip_count = params.pos;
|
||||
|
||||
if (params.filter.mask)
|
||||
priv->filter = params.filter;
|
||||
else
|
||||
priv->filter.mask = 0;
|
||||
|
||||
/* Find the codetag */
|
||||
priv->ioctl_iter = codetag_get_ct_iter(alloc_tag_cttype);
|
||||
ct = codetag_next_ct(&priv->ioctl_iter);
|
||||
while (ct && pos--)
|
||||
|
||||
while (ct) {
|
||||
if (matches_filter(ct, &priv->filter)) {
|
||||
if (skip_count == 0)
|
||||
break;
|
||||
skip_count--;
|
||||
}
|
||||
ct = codetag_next_ct(&priv->ioctl_iter);
|
||||
}
|
||||
|
||||
if (ct) {
|
||||
allocinfo_to_params(ct, ¶ms.data);
|
||||
priv->positioned = true;
|
||||
@@ -314,6 +372,8 @@ static int allocinfo_ioctl_get_next(struct seq_file *m, void __user *arg)
|
||||
}
|
||||
|
||||
ct = codetag_next_ct(&priv->ioctl_iter);
|
||||
while (ct && !matches_filter(ct, &priv->filter))
|
||||
ct = codetag_next_ct(&priv->ioctl_iter);
|
||||
if (ct)
|
||||
allocinfo_to_params(ct, ¶ms);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user