Extend the capability of the IOCTL mechanism to filter allocations based on tag's module name, function name, file name and line number. Signed-off-by: Abhishek Bapat --- include/uapi/linux/alloc_tag.h | 26 +++++++++++++++- lib/alloc_tag.c | 55 ++++++++++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h index e9a5b55fcc7a..0cc9db5298c6 100644 --- a/include/uapi/linux/alloc_tag.h +++ b/include/uapi/linux/alloc_tag.h @@ -34,8 +34,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; }; diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c index 5c24d2f954d4..7ff936e15e97 100644 --- a/lib/alloc_tag.c +++ b/lib/alloc_tag.c @@ -47,6 +47,7 @@ int alloc_tag_ref_offs; struct allocinfo_private { struct codetag_iterator 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 */ @@ -156,6 +157,11 @@ static void allocinfo_copy_str(char *dest, const char *src) strscpy(dest, allocinfo_str(src), ALLOCINFO_STR_SIZE); } +static int allocinfo_cmp_str(const char *str, const char *template) +{ + return strncmp(allocinfo_str(str), template, ALLOCINFO_STR_SIZE); +} + static void allocinfo_to_params(struct codetag *ct, struct allocinfo_tag_data *data) { @@ -187,26 +193,67 @@ static int allocinfo_ioctl_get_content_id(struct seq_file *m, void __user *arg) return 0; } +static bool matches_filter(struct codetag *ct, struct allocinfo_filter *filter) +{ + if (!ct || !filter || !filter->mask) + return true; + + if ((filter->mask & ALLOCINFO_FILTER_MASK_MODNAME) && + ct->modname && (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; +} + 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 = (struct allocinfo_private *)m->private; - pos = params.pos; + + skip_count = params.pos; codetag_lock_module_list(alloc_tag_cttype, true); + 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; @@ -240,6 +287,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); -- 2.54.0.545.g6539524ca2-goog