From nobody Thu Jun 11 10:15:32 2026 Received: from mail-dy1-f201.google.com (mail-dy1-f201.google.com [74.125.82.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 06DAF35950 for ; Wed, 10 Jun 2026 00:13:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781050394; cv=none; b=SdZYmqu2HTFKI+mAtiT+mah+9QaDtbbUnEtrvKVZMxmVtgj3Vi0o0+gRBN/HYmwQk575BdFHI0B08819bltMpOdHyQrEbZvbkUF6+jzGP8dMHrFfEJ0U/GYdzAeFRrhupNBW87Z/RDdGHimCFZpjz2G5CTUMke5mmQZBxaNSw0M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781050394; c=relaxed/simple; bh=BZf0wDvNuVRGRuk8LJUc1Se3/VWVcKA15PwHSou/QvQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Dtwu+6IdqPqz9WZLd+HtXphQmoUS1f8H0sbl5bUty6UGEtx2RgrCWW8vNXtbjMTgm1+mZJ9mFmGN1ENKZrAfZM8RU6tWXMAoGWTDcVFvKuVrxlkvxqXLmqGd/3EppDcGKOpplzqPZ7lG7YnaI6FlruVFVeMXpHDgV5QtI/gNcL8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--abhishekbapat.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=D6EH+tQs; arc=none smtp.client-ip=74.125.82.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--abhishekbapat.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="D6EH+tQs" Received: by mail-dy1-f201.google.com with SMTP id 5a478bee46e88-304ea1eea05so46853eec.0 for ; Tue, 09 Jun 2026 17:13:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1781050390; x=1781655190; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=hq94XP/6nim6n9o42jIr9a4u0pAoRXZGfLL46kf9Ra0=; b=D6EH+tQsHTZ3c1RgbK7z8DxXABamQYuk2PkQBAxaX4qLEZrQR71SiwBj9ijE3mofxr MwcXWOm2POSJmMTFcud3sC9DllIkE/k55BoyxeiLVaE/K7RToVNoYmR+0LDFKKyhF/wX iPT1l6OsNrDqMbFH2OAtxXmyB5eEFrmvJFd8FrQl6C4feao+yKn7wHsXiJUogZ//iaHz 18qY9wvPnrx90enFrBEkD0dIbDRsKpNEr+JMhTNl72T82wMoQn815RLqQ07jN1k+BZr4 6O7s7QYTw5gbadoYyIcsodq3PeEAGyC6prokqPvllT8c714RvuzVyLQtdEo3Etn1vprZ LTCQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781050390; x=1781655190; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=hq94XP/6nim6n9o42jIr9a4u0pAoRXZGfLL46kf9Ra0=; b=DE8jlkLTde5yVm37KgMUBHvnWWlHU/6OOPyuTUppQfv/ffNpo3g2iq+PapNRwOOb64 K7HgvNB4UwoD36DcMQtH+vd3X9M6LszH0oB4nfPPLTmpZYSN9WeLHqwmWoVa2vnhJVng eoVjjGwIDqTQJxiskcRG6rJITBPD/ukCMSlQfRL0q69JunCr5zIEewn0x1IlF9l2uhFo hDsTi2IywYom3YEuCvAsr45D9dUUA/jMcdrudBDOwM1RrY26mbMii6khymXEe4QhA5Z+ yjhylVbXBO+dBzu+Af0pw3VVZMqvLBv5/KX6oalpFvmTEV9PKD/9D8mSuiWlU82FTuJs 4AMw== X-Forwarded-Encrypted: i=1; AFNElJ96ajzDqyPTPOR+en5JWPz2zy/x75cuUMF6+MNrR1U8g5ZdYFBgPgWNEBQLD6acVi4dZQGs/aKqcYfZy94=@vger.kernel.org X-Gm-Message-State: AOJu0Yxc4U40VtF9G8HJoGiaiRvJHjLOSFm8inbJ7k0k+jGE6LPRdP2R /MeMHVcSujaBsFVsFr07+zR5qrEPwl29LE7bH7iyNAGNtLN5OEKU7D2DM+U6+HaFGs/aHIkqKOu tAwTQWeXmPYIzX1uIw0HKnM+o0Y8Gto5reg== X-Received: from dyeg12.prod.google.com ([2002:a05:7300:538c:b0:2da:2af9:bfe2]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:5b88:b0:304:d14b:b706 with SMTP id 5a478bee46e88-3077b271f5emr13780687eec.27.1781050389798; Tue, 09 Jun 2026 17:13:09 -0700 (PDT) Date: Wed, 10 Jun 2026 00:12:54 +0000 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.54.0.1099.g489fc7bff1-goog Message-ID: Subject: [PATCH v4 1/6] alloc_tag: add ioctl to /proc/allocinfo From: Abhishek Bapat To: Suren Baghdasaryan , Andrew Morton , Kent Overstreet , Hao Ge Cc: Shuah Khan , Jonathan Corbet , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, Sourav Panda , Abhishek Bapat Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Suren Baghdasaryan Add the following ioctl commands for /proc/allocinfo file: ALLOCINFO_IOC_CONTENT_ID - gets content identifier which can be used to check whether the file content has changed specifically due to module load/unload. Every time a module is loaded / unloaded, the returned value will be different. By comparing the identifier value at the beginning and at the end of the content retrieval operation, users can validate retrieved information for consistency. ALLOCINFO_IOC_GET_AT - gets the record at the specified position. This is the position of a record in /proc/allocinfo. ALLOCINFO_IOC_GET_NEXT - gets the record next to the last retrieved one. If no records were previously retrieved, returns the first record. Signed-off-by: Suren Baghdasaryan Signed-off-by: Abhishek Bapat Acked-by: Hao Ge --- Documentation/mm/allocation-profiling.rst | 5 + .../userspace-api/ioctl/ioctl-number.rst | 2 + MAINTAINERS | 1 + include/linux/codetag.h | 2 + include/uapi/linux/alloc_tag.h | 60 +++++ lib/alloc_tag.c | 232 +++++++++++++++++- lib/codetag.c | 18 ++ 7 files changed, 318 insertions(+), 2 deletions(-) create mode 100644 include/uapi/linux/alloc_tag.h diff --git a/Documentation/mm/allocation-profiling.rst b/Documentation/mm/a= llocation-profiling.rst index 5389d241176a..c3a28467955f 100644 --- a/Documentation/mm/allocation-profiling.rst +++ b/Documentation/mm/allocation-profiling.rst @@ -46,6 +46,11 @@ sysctl: Runtime info: /proc/allocinfo =20 + Profiling data can be retrieved either by reading `/proc/allocinfo` dire= ctly as + text or programmatically via `ioctl()` calls defined in ``. + The ioctl interface supports structured binary data extraction as well a= s filtering + by module name, function, file, line number, accuracy, or allocation siz= e limits. + Example output:: =20 root@moria-kvm:~# sort -g /proc/allocinfo|tail|numfmt --to=3Diec diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documenta= tion/userspace-api/ioctl/ioctl-number.rst index 331223761fff..84f6808a8578 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -349,6 +349,8 @@ Code Seq# Include File = Comments 0xA5 20-2F linux/surface_aggregator/dtx.h Mic= rosoft Surface DTX driver +0xA6 00-0F uapi/linux/alloc_tag.h Mem= ory allocation profiling + 0xAA 00-3F linux/uapi/linux/userfaultfd.h 0xAB 00-1F linux/nbd.h 0xAC 00-1F linux/raw.h diff --git a/MAINTAINERS b/MAINTAINERS index 65bd4328fe05..019cc4c285a3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16713,6 +16713,7 @@ S: Maintained F: Documentation/mm/allocation-profiling.rst F: include/linux/alloc_tag.h F: include/linux/pgalloc_tag.h +F: include/uapi/linux/alloc_tag.h F: lib/alloc_tag.c =20 MEMORY CONTROLLER DRIVERS diff --git a/include/linux/codetag.h b/include/linux/codetag.h index ddae7484ca45..a25a085c2df1 100644 --- a/include/linux/codetag.h +++ b/include/linux/codetag.h @@ -77,6 +77,8 @@ struct codetag_iterator { void codetag_lock_module_list(struct codetag_type *cttype); bool codetag_trylock_module_list(struct codetag_type *cttype); void codetag_unlock_module_list(struct codetag_type *cttype); +unsigned long codetag_get_content_id(struct codetag_type *cttype); +unsigned int codetag_get_count(struct codetag_type *cttype); struct codetag_iterator codetag_get_ct_iter(struct codetag_type *cttype); struct codetag *codetag_next_ct(struct codetag_iterator *iter); =20 diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h new file mode 100644 index 000000000000..0928e1a48d49 --- /dev/null +++ b/include/uapi/linux/alloc_tag.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * alloc_tag IOCTL API definition + * + * Copyright (C) 2026 Google, LLC. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _UAPI_ALLOC_TAG_H +#define _UAPI_ALLOC_TAG_H + +#include + +#define ALLOCINFO_STR_SIZE 64 + +struct allocinfo_content_id { + __u64 id; +}; + +struct allocinfo_tag { + /* Longer names are trimmed */ + char modname[ALLOCINFO_STR_SIZE]; + char function[ALLOCINFO_STR_SIZE]; + char filename[ALLOCINFO_STR_SIZE]; + __u64 lineno; +}; + +/* The alignment ensures 32-bit compatible interfaces are not broken */ +struct allocinfo_counter { + __u64 bytes; + __u64 calls; + __u8 accurate; +} __attribute__((aligned(8))); + +struct allocinfo_tag_data { + struct allocinfo_tag tag; + struct allocinfo_counter counter; +}; + +struct allocinfo_get_at { + __u64 pos; /* input */ + struct allocinfo_tag_data data; +}; + +#define _ALLOCINFO_IOC_CONTENT_ID 0 +#define _ALLOCINFO_IOC_GET_AT 1 +#define _ALLOCINFO_IOC_GET_NEXT 2 + +#define ALLOCINFO_IOC_BASE 0xA6 +#define ALLOCINFO_IOC_CONTENT_ID _IOR(ALLOCINFO_IOC_BASE, _ALLOCINFO_IOC_C= ONTENT_ID, \ + struct allocinfo_content_id) +#define ALLOCINFO_IOC_GET_AT _IOWR(ALLOCINFO_IOC_BASE, _ALLOCINFO_IOC_GET= _AT, \ + struct allocinfo_get_at) +#define ALLOCINFO_IOC_GET_NEXT _IOR(ALLOCINFO_IOC_BASE, _ALLOCINFO_IOC_GE= T_NEXT, \ + struct allocinfo_tag_data) + +#endif /* _UAPI_ALLOC_TAG_H */ diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c index d9be1cf5187d..a0577215eb3d 100644 --- a/lib/alloc_tag.c +++ b/lib/alloc_tag.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include =20 #define ALLOCINFO_FILE_NAME "allocinfo" #define MODULE_ALLOC_TAG_VMAP_SIZE (100000UL * sizeof(struct alloc_tag)) @@ -47,6 +49,10 @@ struct allocinfo_private { struct codetag_iterator iter; struct codetag_iterator reported_iter; bool print_header; + /* ioctl uses a separate iterator not to interfere with reads */ + struct codetag_iterator ioctl_iter; + bool positioned; /* seq_open_private() sets to 0 */ + struct mutex ioctl_lock; }; =20 static void *allocinfo_start(struct seq_file *m, loff_t *pos) @@ -130,6 +136,229 @@ static const struct seq_operations allocinfo_seq_op = =3D { .show =3D allocinfo_show, }; =20 +/* + * Initializes seq_file operations and allocates private state when opening + * the /proc/allocinfo procfs entry. + */ +static int allocinfo_open(struct inode *inode, struct file *file) +{ + int ret; + + ret =3D seq_open_private(file, &allocinfo_seq_op, + sizeof(struct allocinfo_private)); + if (!ret) { + struct seq_file *m =3D file->private_data; + struct allocinfo_private *priv =3D m->private; + + mutex_init(&priv->ioctl_lock); + } + return ret; +} + +/* + * Cleans up the seq_file state and frees up the private state allocated in + * allocinfo_open() when closing the /proc/allocinfo file descriptor. + */ +static int allocinfo_release(struct inode *inode, struct file *file) +{ + return seq_release_private(inode, file); +} + +/* + * Returns a pointer to the suffix of a string so that its length fits wit= hin + * ALLOCINFO_STR_SIZE, preserving the trailing characters. + */ +static const char *allocinfo_str(const char *str) +{ + size_t len =3D strlen(str); + + /* Keep an extra space for the trailing NULL. */ + if (len >=3D ALLOCINFO_STR_SIZE) + str +=3D (len - ALLOCINFO_STR_SIZE) + 1; + return str; +} + +/* Copy a string and trim from the beginning if it's too long */ +static void allocinfo_copy_str(char *dest, const char *src) +{ + strscpy_pad(dest, allocinfo_str(src), ALLOCINFO_STR_SIZE); +} + +/* + * Populates the UAPI allocinfo_tag_data structure with active runtime + * profiling counters extracted from the given kernel codetag. + */ +static void allocinfo_to_params(struct codetag *ct, + struct allocinfo_tag_data *data) +{ + struct alloc_tag *tag =3D ct_to_alloc_tag(ct); + struct alloc_tag_counters counter =3D alloc_tag_read(tag); + + if (ct->modname) + allocinfo_copy_str(data->tag.modname, ct->modname); + else + data->tag.modname[0] =3D '\0'; + allocinfo_copy_str(data->tag.function, ct->function); + allocinfo_copy_str(data->tag.filename, ct->filename); + data->tag.lineno =3D ct->lineno; + data->counter.bytes =3D counter.bytes; + data->counter.calls =3D counter.calls; + data->counter.accurate =3D !alloc_tag_is_inaccurate(tag); +} + +/* + * Retrieves the unique content ID representing the current allocation tag= module + * layout, allowing userspace to detect if modules were loaded / unloaded. + */ +static int allocinfo_ioctl_get_content_id(struct seq_file *m, void __user = *arg) +{ + struct allocinfo_content_id params; + + codetag_lock_module_list(alloc_tag_cttype); + params.id =3D codetag_get_content_id(alloc_tag_cttype); + codetag_unlock_module_list(alloc_tag_cttype); + if (copy_to_user(arg, ¶ms, sizeof(params))) + return -EFAULT; + + return 0; +} + +/* + * Seeks the ioctl iterator to the specified 0-indexed tag position, reads= its + * profiling data and returns it to userspace. + */ +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 =3D {0}; + + if (copy_from_user(¶ms, arg, sizeof(params))) + return -EFAULT; + + priv =3D m->private; + pos =3D params.pos; + + mutex_lock(&priv->ioctl_lock); + codetag_lock_module_list(alloc_tag_cttype); + + if (pos >=3D codetag_get_count(alloc_tag_cttype)) { + codetag_unlock_module_list(alloc_tag_cttype); + mutex_unlock(&priv->ioctl_lock); + return -ENOENT; + } + + /* Find the codetag */ + priv->ioctl_iter =3D codetag_get_ct_iter(alloc_tag_cttype); + ct =3D codetag_next_ct(&priv->ioctl_iter); + while (ct && pos--) + ct =3D codetag_next_ct(&priv->ioctl_iter); + if (ct) { + allocinfo_to_params(ct, ¶ms.data); + priv->positioned =3D true; + } + + codetag_unlock_module_list(alloc_tag_cttype); + mutex_unlock(&priv->ioctl_lock); + + if (!ct) + return -ENOENT; + + if (copy_to_user(arg, ¶ms, sizeof(params))) + return -EFAULT; + + return 0; +} + +/* + * Advances the ioctl iterator to the next allocation tag in the sequence = and + * returns its profiling data to userspace. + */ +static int allocinfo_ioctl_get_next(struct seq_file *m, void __user *arg) +{ + struct allocinfo_private *priv; + struct codetag *ct; + struct allocinfo_tag_data params; + int ret =3D 0; + + memset(¶ms, 0, sizeof(params)); + priv =3D m->private; + + mutex_lock(&priv->ioctl_lock); + codetag_lock_module_list(alloc_tag_cttype); + + if (!priv->positioned) { + priv->ioctl_iter =3D codetag_get_ct_iter(alloc_tag_cttype); + priv->positioned =3D true; + } + + ct =3D codetag_next_ct(&priv->ioctl_iter); + if (ct) + allocinfo_to_params(ct, ¶ms); + + if (!ct) { + priv->positioned =3D false; + ret =3D -ENOENT; + } + codetag_unlock_module_list(alloc_tag_cttype); + mutex_unlock(&priv->ioctl_lock); + + if (ret =3D=3D 0) { + if (copy_to_user(arg, ¶ms, sizeof(params))) + return -EFAULT; + } + return ret; +} + +/* + * Entry point ioctl function for /proc/allocinfo routing requests to fetc= h the + * layout content ID, seek to a specific tag, or read sequential tags. + */ +static long allocinfo_ioctl(struct file *file, unsigned int cmd, + unsigned long __arg) +{ + void __user *arg =3D (void __user *)__arg; + int ret; + + switch (cmd) { + case ALLOCINFO_IOC_CONTENT_ID: + ret =3D allocinfo_ioctl_get_content_id(file->private_data, arg); + break; + case ALLOCINFO_IOC_GET_AT: + ret =3D allocinfo_ioctl_get_at(file->private_data, arg); + break; + case ALLOCINFO_IOC_GET_NEXT: + ret =3D allocinfo_ioctl_get_next(file->private_data, arg); + break; + default: + ret =3D -ENOIOCTLCMD; + break; + } + + return ret; +} + +#ifdef CONFIG_COMPAT +static long allocinfo_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return allocinfo_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + +static const struct proc_ops allocinfo_proc_ops =3D { + .proc_open =3D allocinfo_open, + .proc_read_iter =3D seq_read_iter, + .proc_lseek =3D seq_lseek, + .proc_release =3D allocinfo_release, + .proc_ioctl =3D allocinfo_ioctl, +#ifdef CONFIG_COMPAT + .proc_compat_ioctl =3D allocinfo_compat_ioctl, +#endif + +}; + size_t alloc_tag_top_users(struct codetag_bytes *tags, size_t count, bool = can_sleep) { struct codetag_iterator iter; @@ -993,8 +1222,7 @@ static int __init alloc_tag_init(void) return 0; } =20 - if (!proc_create_seq_private(ALLOCINFO_FILE_NAME, 0400, NULL, &allocinfo_= seq_op, - sizeof(struct allocinfo_private), NULL)) { + if (!proc_create(ALLOCINFO_FILE_NAME, 0400, NULL, &allocinfo_proc_ops)) { pr_err("Failed to create %s file\n", ALLOCINFO_FILE_NAME); shutdown_mem_profiling(false); return -ENOMEM; diff --git a/lib/codetag.c b/lib/codetag.c index 4001a7ea6675..a9cda4c962a3 100644 --- a/lib/codetag.c +++ b/lib/codetag.c @@ -19,6 +19,8 @@ struct codetag_type { struct codetag_type_desc desc; /* generates unique sequence number for module load */ unsigned long next_mod_seq; + /* bumped on every module load and unload */ + unsigned long content_id; }; =20 struct codetag_range { @@ -50,6 +52,20 @@ void codetag_unlock_module_list(struct codetag_type *ctt= ype) up_read(&cttype->mod_lock); } =20 +unsigned long codetag_get_content_id(struct codetag_type *cttype) +{ + lockdep_assert_held(&cttype->mod_lock); + + return cttype->content_id; +} + +unsigned int codetag_get_count(struct codetag_type *cttype) +{ + lockdep_assert_held(&cttype->mod_lock); + + return cttype->count; +} + struct codetag_iterator codetag_get_ct_iter(struct codetag_type *cttype) { struct codetag_iterator iter =3D { @@ -204,6 +220,7 @@ static int codetag_module_init(struct codetag_type *ctt= ype, struct module *mod) =20 down_write(&cttype->mod_lock); cmod->mod_seq =3D ++cttype->next_mod_seq; + ++cttype->content_id; mod_id =3D idr_alloc(&cttype->mod_idr, cmod, 0, 0, GFP_KERNEL); if (mod_id >=3D 0) { if (cttype->desc.module_load) { @@ -368,6 +385,7 @@ void codetag_unload_module(struct module *mod) cttype->count -=3D range_size(cttype, &cmod->range); idr_remove(&cttype->mod_idr, mod_id); kfree(cmod); + ++cttype->content_id; } up_write(&cttype->mod_lock); if (found && cttype->desc.free_section_mem) --=20 2.54.0.1099.g489fc7bff1-goog From nobody Thu Jun 11 10:15:32 2026 Received: from mail-dl1-f73.google.com (mail-dl1-f73.google.com [74.125.82.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EAF003BB48 for ; Wed, 10 Jun 2026 00:13:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781050393; cv=none; b=Y102sgt17S5NVXjfRrL17NZ+F4loqZkxQ7wFUyYAOoYrQuToLmtIVdx4Hk2c3aOAt8zb6/x4W1AKUZRNzJjlbvfZVmhLWtPI6RCTNLYkec41zAhxQQ8fgGpRuDe2WwXCE/P1OGhUQR4p6A3wtlkcPUnBIA8zHXyS8NcGCxgVg9U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781050393; c=relaxed/simple; bh=Z7ffwxw0napNaUds37qYbwJH+a7GQhHdlnpEXkywxXk=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=FPdmC/JjqMBkOm2lfXazviOmjnRoFL9h/uChJpKxH0fDrvHf3PG3RPgWTA2tYAkP36Vtzt9HvLweIYwG9g7hz17i2ZNwkCNtbO3/wXHD+df8fzSgk3yKksTAbM1zVNIl6nA029KsOmkAqvHNhOWFGDPQce7kTjnTjd0VXH5/gRs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--abhishekbapat.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=N3hmImlq; arc=none smtp.client-ip=74.125.82.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--abhishekbapat.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="N3hmImlq" Received: by mail-dl1-f73.google.com with SMTP id a92af1059eb24-137fe4a3640so9045767c88.0 for ; Tue, 09 Jun 2026 17:13:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1781050391; x=1781655191; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=GuiL1uopUb0V1ZSKvFrHplWv7LS00WDxcZQ+1Oh0CoI=; b=N3hmImlq2zt+a/42M4Agbq5PMsEsYxw7boLSfgpTQK0qowQuLcxmkf2wZiPGZbb20z itgl4HUMvltZ89wlYJ2nvicxwUgNkH4YZOTShqUHc5s2k+t9NoyGyE3vmlU8fFD6hzah CH0wCk/3cNqRSNsucFiWX5ziIkLr8P13SIr8FdEPcRtwc5IOgMZ5wG3d5jFxdW/zjdEV NenqPwLgibfBYcynvni//NmQ3t6U36WIvRkLSdBhTJjIpsdptkYkLEKNT44MIgmczacM uYjVDyGo9IO07QjZtSTWKMgtVHE2XAT7bI2luj3/dqYhQRT0DhrVJLm8A9ur7Jm7XOId VPvQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781050391; x=1781655191; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=GuiL1uopUb0V1ZSKvFrHplWv7LS00WDxcZQ+1Oh0CoI=; b=C/3sRrtrEMDL9lgoeBsGJtH+IDHDxDF3vxfN67AxAFiEExjdZTWuSybo/wmEBvDNoh nE/sRvlaDswHJyHTXrW4TVRq1neyEGEGjsDYN7YkitX9nBJWH1Q4xuIk6aadRoTAcQpU r+VLbKtpFRxc7ntp4p3kwUKMfqHSPhIA5sseO+gwOmhMfEEZkTYoEaeCiz+l5y7d4bCd Kz+0Ex9LjaRpHTeGSC9BfvA4337t7pSjJcsWhm62ksVZBIZ8jgRiTaZw4LGChgLWvZ4l 79pn1DI7NWrpeJVEeoV7dFWXWg0SbBbkRnYvWNqye5Vp+CcD5NS9C4CXpXkMupijhEK2 9fFg== X-Forwarded-Encrypted: i=1; AFNElJ9i0tqQ/zjO09zh0w26CrjdqQn3WR1q8sKRWMgXhisctfMcyFWDn1Pg5oB7KSRPy9+WbdaZi1BUUHJGoSM=@vger.kernel.org X-Gm-Message-State: AOJu0YyBME9gE1zFZSo2INjZrCFxnbIu3PqJ0lwjkJzduE97QwbOAwXo icsZuhIQQSvxE7lbqalY8D2oqhS3k+cicy+BiubL0ST9reXtMKmHh4t4+ueAbtIXw1I2ShnNk7E KIJvykYYJq2hlBHwkPbVtB1hfPYnQAZ4JJQ== X-Received: from dld33.prod.google.com ([2002:a05:7022:321:b0:138:281:799f]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:e01:b0:12d:de3f:f3e6 with SMTP id a92af1059eb24-1380675c41cmr10307493c88.38.1781050390727; Tue, 09 Jun 2026 17:13:10 -0700 (PDT) Date: Wed, 10 Jun 2026 00:12:55 +0000 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.54.0.1099.g489fc7bff1-goog Message-ID: <8cd864b3bdbf89973e9a1fbd6e8ed1e9c08989b9.1781042698.git.abhishekbapat@google.com> Subject: [PATCH v4 2/6] alloc_tag: add ioctl filters to /proc/allocinfo From: Abhishek Bapat To: Suren Baghdasaryan , Andrew Morton , Kent Overstreet , Hao Ge Cc: Shuah Khan , Jonathan Corbet , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, Sourav Panda , Abhishek Bapat Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 Acked-by: Hao Ge --- include/uapi/linux/alloc_tag.h | 26 ++++++++++++- lib/alloc_tag.c | 68 ++++++++++++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 5 deletions(-) diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h index 0928e1a48d49..3b11877955b9 100644 --- a/include/uapi/linux/alloc_tag.h +++ b/include/uapi/linux/alloc_tag.h @@ -40,8 +40,32 @@ struct allocinfo_tag_data { struct allocinfo_counter counter; }; =20 +enum { + ALLOCINFO_FILTER_MODNAME, + ALLOCINFO_FILTER_FUNCTION, + ALLOCINFO_FILTER_FILENAME, + ALLOCINFO_FILTER_LINENO, + __ALLOCINFO_FILTER_LAST =3D 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; }; =20 diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c index a0577215eb3d..378fcd63b6c9 100644 --- a/lib/alloc_tag.c +++ b/lib/alloc_tag.c @@ -49,6 +49,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 */ @@ -184,6 +185,12 @@ static void allocinfo_copy_str(char *dest, const char = *src) strscpy_pad(dest, allocinfo_str(src), ALLOCINFO_STR_SIZE); } =20 +/* Compare two strings and only consider the trimmed suffix if s1 is too l= ong */ +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. @@ -223,6 +230,40 @@ static int allocinfo_ioctl_get_content_id(struct seq_f= ile *m, void __user *arg) return 0; } =20 +/* + * Verifies whether a given codetag satisfies the active filtering criteri= a by + * matching its characteristics against the specified filter. + */ +static bool matches_filter(struct codetag *ct, struct allocinfo_filter *fi= lter) +{ + 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] !=3D '\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.functi= on)) + return false; + + if ((filter->mask & ALLOCINFO_FILTER_MASK_FILENAME) && + ct->filename && allocinfo_cmp_str(ct->filename, filter->fields.filena= me)) + return false; + + if ((filter->mask & ALLOCINFO_FILTER_MASK_LINENO) && + ct->lineno !=3D 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. @@ -231,29 +272,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 =3D {0}; + __u64 skip_count; =20 if (copy_from_user(¶ms, arg, sizeof(params))) return -EFAULT; =20 + if (params.filter.mask & ~ALLOCINFO_FILTER_MASKS) + return -EINVAL; + priv =3D m->private; - pos =3D params.pos; =20 mutex_lock(&priv->ioctl_lock); codetag_lock_module_list(alloc_tag_cttype); =20 - if (pos >=3D codetag_get_count(alloc_tag_cttype)) { + if (params.pos >=3D codetag_get_count(alloc_tag_cttype)) { codetag_unlock_module_list(alloc_tag_cttype); mutex_unlock(&priv->ioctl_lock); return -ENOENT; } =20 + skip_count =3D params.pos; + + if (params.filter.mask) + priv->filter =3D params.filter; + else + priv->filter.mask =3D 0; + /* Find the codetag */ priv->ioctl_iter =3D codetag_get_ct_iter(alloc_tag_cttype); ct =3D codetag_next_ct(&priv->ioctl_iter); - while (ct && pos--) + + while (ct) { + if (matches_filter(ct, &priv->filter)) { + if (skip_count =3D=3D 0) + break; + skip_count--; + } ct =3D codetag_next_ct(&priv->ioctl_iter); + } + if (ct) { allocinfo_to_params(ct, ¶ms.data); priv->positioned =3D true; @@ -294,6 +352,8 @@ static int allocinfo_ioctl_get_next(struct seq_file *m,= void __user *arg) } =20 ct =3D codetag_next_ct(&priv->ioctl_iter); + while (ct && !matches_filter(ct, &priv->filter)) + ct =3D codetag_next_ct(&priv->ioctl_iter); if (ct) allocinfo_to_params(ct, ¶ms); =20 --=20 2.54.0.1099.g489fc7bff1-goog From nobody Thu Jun 11 10:15:32 2026 Received: from mail-dy1-f202.google.com (mail-dy1-f202.google.com [74.125.82.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B1D7D7261A for ; Wed, 10 Jun 2026 00:13:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781050395; cv=none; b=JgGNlBF5n/0Bfkp2Dvk92JwfKLgrn8KKxTov+bpGeUhekDR60wLHa/LCmUvU6le28oaKc87DfGhMfeSXClnKGMvUcUsgYec9A7mMqC3a3WcuWaRG+g6I6l6rWGQ7uyY7477zxVVdwGNMsao29eTrNNuchItIpR7Q3KjMtRDmpZs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781050395; c=relaxed/simple; bh=c6Afjof3186R10N3oEQB1VIOdka+uqVO0M7bR2gVFh0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=gy7MvQAloUL2ywLeOTbHUcKpYBxoNxjkLZQvLUG+3/8s8ObpGwL2Cr5Y0L2CxoPJFC3pXjVIsrPetnhR09Wvp5Xo+gx9Y/OEBD1hZb6pEH3rW5A1IbCqErEesYw1dzMC8CNhXGhZOzfHZyu9UziVuDdxkUuTqJLcO0xIXFCOZqI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--abhishekbapat.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=LPxU43Tm; arc=none smtp.client-ip=74.125.82.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--abhishekbapat.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="LPxU43Tm" Received: by mail-dy1-f202.google.com with SMTP id 5a478bee46e88-30762d67a64so815442eec.0 for ; Tue, 09 Jun 2026 17:13:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1781050392; x=1781655192; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=++tB77hzD2q8vCe8TMYSjrltZ0zPb6nZ4tH02lhBM58=; b=LPxU43TmcFLm4H82X733gc7l0U6nP1AeM0d661LnZXz3X7rz2vENzOcbm41PvP7O0w ZuO9hDu2zzSFYnY5Md4/1Vsd07BUJK7oY/fpNEt4/klAv/SyL1ZkIICv57K2GrLd9A1v q61+Wf84jL9ntW3KRbqxEzvMX2G+Jf72kXXwbeKg/gB1ZlHCgyBgL45q2EVxH6Trrebj nbCaN4q0QKDw/PqnPverk7zmqcVPzCchIIoCXrlsRTLocNPjyQ53pCcA+SCEd8lwAO4K frwTYAV2kQd8elmVkiRImHvz+G9FKmnyDO4vgz/VLlYDlA7JQ/98sWuf1ke8RfdUVG78 Ojlw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781050392; x=1781655192; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=++tB77hzD2q8vCe8TMYSjrltZ0zPb6nZ4tH02lhBM58=; b=H2JfV5PkWDKeMX/2lA8bmkDdvSKFERNzyY+rWw7cZmIKNPHy7NZWnO/MqLy5zgsf8Q wZgeTbyNAZwv+BoC9tDrfOyyZ6+llXGP6Xi0EGbpdRMdNCGReRGZOQovjLMAQLK08pi6 GP2qbQYFesxrWUibyPagMXPWqe5I6GMSi3VmdR/zNC3pPUbqSd8uzclZkwSrL/lry/Wk MqwjTf6PaCJc0b2Z4AbVZHvlm9xZRVjwv8zSaB98qcA5hSGuMPHx3/x9Ohm7N9VBKrjl dpoiemUjJsaP+RL6WZ2fsaYKVfbuAYHKJBouP5FsmhWRc7hxj8534H0kRgXBbnqDMy0a NQAQ== X-Forwarded-Encrypted: i=1; AFNElJ8Ao68rjYWE2GyxDJUlySjydYIzCDOW6yEwr9RNg8nj3vKbN6QZrThQOFjwADZ0b7IfnG/i93hnl5yCuSU=@vger.kernel.org X-Gm-Message-State: AOJu0YwQk1ZSF82r7XI1g6/BNZ40LSCNOmw9/kyX37diC+uxyTAT1xHd IHnHukC7DRRzH5OnhGJVFpp1/p6n371KnYoXDlTBtlMhRvG0YJvIOAxoBwq28Rqihm3JO6ZVNQk noZpCQmi98O8AnNEA9j0l7gOUVB2xdWjxBw== X-Received: from dynm18.prod.google.com ([2002:a05:7300:2a92:b0:2df:46bf:2390]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7301:9f0f:b0:303:f295:4db2 with SMTP id 5a478bee46e88-3077ae8e8femr14895652eec.0.1781050391622; Tue, 09 Jun 2026 17:13:11 -0700 (PDT) Date: Wed, 10 Jun 2026 00:12:56 +0000 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.54.0.1099.g489fc7bff1-goog Message-ID: <4e2a75c69fe350358e1fef3e4e25435f6a3d4e77.1781042698.git.abhishekbapat@google.com> Subject: [PATCH v4 3/6] alloc_tag: add size-based filtering to ioctl From: Abhishek Bapat To: Suren Baghdasaryan , Andrew Morton , Kent Overstreet , Hao Ge Cc: Shuah Khan , Jonathan Corbet , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, Sourav Panda , Abhishek Bapat Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Extend the allocinfo filtering mechanism to allow users to filter tags based on the total number of bytes allocated [min_size, max_size]. The size range is inclusive. Filtering by size involves retrieving allocinfo per-CPU counters, which is an expensive operation. Hence, the performance of size-based filtering will be worse than other filters. Signed-off-by: Abhishek Bapat Acked-by: Hao Ge --- include/uapi/linux/alloc_tag.h | 8 ++++- lib/alloc_tag.c | 63 ++++++++++++++++++++++++++++------ 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h index 3b11877955b9..7f5acbb44c14 100644 --- a/include/uapi/linux/alloc_tag.h +++ b/include/uapi/linux/alloc_tag.h @@ -45,13 +45,17 @@ enum { ALLOCINFO_FILTER_FUNCTION, ALLOCINFO_FILTER_FILENAME, ALLOCINFO_FILTER_LINENO, - __ALLOCINFO_FILTER_LAST =3D ALLOCINFO_FILTER_LINENO + ALLOCINFO_FILTER_MIN_SIZE, + ALLOCINFO_FILTER_MAX_SIZE, + __ALLOCINFO_FILTER_LAST =3D ALLOCINFO_FILTER_MAX_SIZE }; =20 #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_MASK_MIN_SIZE (1 << ALLOCINFO_FILTER_MIN_SIZE) +#define ALLOCINFO_FILTER_MASK_MAX_SIZE (1 << ALLOCINFO_FILTER_MAX_SIZE) =20 #define ALLOCINFO_FILTER_MASKS \ ((1 << (__ALLOCINFO_FILTER_LAST + 1)) - 1) @@ -59,6 +63,8 @@ enum { struct allocinfo_filter { __u64 mask; /* bitmask of the filter fields used */ struct allocinfo_tag fields; + __u64 min_size; + __u64 max_size; }; =20 struct allocinfo_get_at { diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c index 378fcd63b6c9..a936cf18611a 100644 --- a/lib/alloc_tag.c +++ b/lib/alloc_tag.c @@ -191,15 +191,26 @@ static int allocinfo_cmp_str(const char *str, const c= har *template) return strncmp(allocinfo_str(str), template, ALLOCINFO_STR_SIZE); } =20 +/* Fetch the per-CPU counters */ +static inline struct alloc_tag_counters allocinfo_prefetch_counters(struct= codetag *ct) +{ + return alloc_tag_read(ct_to_alloc_tag(ct)); +} + /* * Populates the UAPI allocinfo_tag_data structure with active runtime * profiling counters extracted from the given kernel codetag. */ static void allocinfo_to_params(struct codetag *ct, - struct allocinfo_tag_data *data) + struct allocinfo_tag_data *data, + struct alloc_tag_counters *counters) { - struct alloc_tag *tag =3D ct_to_alloc_tag(ct); - struct alloc_tag_counters counter =3D alloc_tag_read(tag); + struct alloc_tag_counters local_counters; + + if (!counters) { + local_counters =3D allocinfo_prefetch_counters(ct); + counters =3D &local_counters; + } =20 if (ct->modname) allocinfo_copy_str(data->tag.modname, ct->modname); @@ -208,9 +219,9 @@ static void allocinfo_to_params(struct codetag *ct, allocinfo_copy_str(data->tag.function, ct->function); allocinfo_copy_str(data->tag.filename, ct->filename); data->tag.lineno =3D ct->lineno; - data->counter.bytes =3D counter.bytes; - data->counter.calls =3D counter.calls; - data->counter.accurate =3D !alloc_tag_is_inaccurate(tag); + data->counter.bytes =3D counters->bytes; + data->counter.calls =3D counters->calls; + data->counter.accurate =3D !alloc_tag_is_inaccurate(ct_to_alloc_tag(ct)); } =20 /* @@ -234,7 +245,9 @@ static int allocinfo_ioctl_get_content_id(struct seq_fi= le *m, void __user *arg) * Verifies whether a given codetag satisfies the active filtering criteri= a by * matching its characteristics against the specified filter. */ -static bool matches_filter(struct codetag *ct, struct allocinfo_filter *fi= lter) +static bool matches_filter(struct codetag *ct, struct allocinfo_filter *fi= lter, + struct alloc_tag_counters *counters, + bool *fetched_counters) { if (!filter || !filter->mask) return true; @@ -261,6 +274,19 @@ static bool matches_filter(struct codetag *ct, struct = allocinfo_filter *filter) ct->lineno !=3D filter->fields.lineno) return false; =20 + if (filter->mask & (ALLOCINFO_FILTER_MASK_MIN_SIZE | ALLOCINFO_FILTER_MAS= K_MAX_SIZE)) { + if (!*fetched_counters) { + *counters =3D allocinfo_prefetch_counters(ct); + *fetched_counters =3D true; + } + if ((filter->mask & ALLOCINFO_FILTER_MASK_MIN_SIZE) && + counters->bytes < filter->min_size) + return false; + if ((filter->mask & ALLOCINFO_FILTER_MASK_MAX_SIZE) && + counters->bytes > filter->max_size) + return false; + } + return true; } =20 @@ -274,6 +300,8 @@ static int allocinfo_ioctl_get_at(struct seq_file *m, v= oid __user *arg) struct codetag *ct; struct allocinfo_get_at params =3D {0}; __u64 skip_count; + struct alloc_tag_counters counters; + bool fetched_counters; =20 if (copy_from_user(¶ms, arg, sizeof(params))) return -EFAULT; @@ -281,6 +309,11 @@ static int allocinfo_ioctl_get_at(struct seq_file *m, = void __user *arg) if (params.filter.mask & ~ALLOCINFO_FILTER_MASKS) return -EINVAL; =20 + if ((params.filter.mask & ALLOCINFO_FILTER_MASK_MIN_SIZE) && + (params.filter.mask & ALLOCINFO_FILTER_MASK_MAX_SIZE) && + params.filter.min_size > params.filter.max_size) + return -EINVAL; + priv =3D m->private; =20 mutex_lock(&priv->ioctl_lock); @@ -304,7 +337,8 @@ static int allocinfo_ioctl_get_at(struct seq_file *m, v= oid __user *arg) ct =3D codetag_next_ct(&priv->ioctl_iter); =20 while (ct) { - if (matches_filter(ct, &priv->filter)) { + fetched_counters =3D false; + if (matches_filter(ct, &priv->filter, &counters, &fetched_counters)) { if (skip_count =3D=3D 0) break; skip_count--; @@ -313,7 +347,7 @@ static int allocinfo_ioctl_get_at(struct seq_file *m, v= oid __user *arg) } =20 if (ct) { - allocinfo_to_params(ct, ¶ms.data); + allocinfo_to_params(ct, ¶ms.data, fetched_counters ? &counters : NUL= L); priv->positioned =3D true; } =20 @@ -339,6 +373,8 @@ static int allocinfo_ioctl_get_next(struct seq_file *m,= void __user *arg) struct codetag *ct; struct allocinfo_tag_data params; int ret =3D 0; + struct alloc_tag_counters counters; + bool fetched_counters; =20 memset(¶ms, 0, sizeof(params)); priv =3D m->private; @@ -352,10 +388,15 @@ static int allocinfo_ioctl_get_next(struct seq_file *= m, void __user *arg) } =20 ct =3D codetag_next_ct(&priv->ioctl_iter); - while (ct && !matches_filter(ct, &priv->filter)) + while (ct) { + fetched_counters =3D false; + if (matches_filter(ct, &priv->filter, &counters, &fetched_counters)) + break; ct =3D codetag_next_ct(&priv->ioctl_iter); + } + if (ct) - allocinfo_to_params(ct, ¶ms); + allocinfo_to_params(ct, ¶ms, fetched_counters ? &counters : NULL); =20 if (!ct) { priv->positioned =3D false; --=20 2.54.0.1099.g489fc7bff1-goog From nobody Thu Jun 11 10:15:32 2026 Received: from mail-dy1-f202.google.com (mail-dy1-f202.google.com [74.125.82.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8B53E3FBA7 for ; Wed, 10 Jun 2026 00:13:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781050394; cv=none; b=XBIG8WEGcTqA4XFX/2Z3M7W15SfwsP/VJ4TD6hl2F97x2w286zZfMWqC6GFbV1aze1t4Q8HgAQWnYkgtiytvEjU+26ebK+/qG6hP0+a51AohkSy0r44ZfjRaBLC84aV6CLB0SQwLshbFfB7wtpt5lbVesNcOCJDJvYSsUxGQdyM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781050394; c=relaxed/simple; bh=2F4bd5gtwgtf5S4NAHS/fmmXGiRksDRvErNcvp7U2WM=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=kgbh+UnovqZq0GJ3LU+nv4pZeYz5uCYLm5R61+/tiAiIcW50pjPTawsAc7rEfDPZ13qAjWnvKEDzosPHBDvHSGandxMLDKL4rVd2fC9OWUcVJOI5vK/1OkRJF1+m4eMkiEOzbzWAbgheezFyhWZnvYtqapL5ZI81sL2reJc2E/w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--abhishekbapat.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=ai58Gfj1; arc=none smtp.client-ip=74.125.82.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--abhishekbapat.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="ai58Gfj1" Received: by mail-dy1-f202.google.com with SMTP id 5a478bee46e88-304b8d0ee63so8556296eec.0 for ; Tue, 09 Jun 2026 17:13:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1781050393; x=1781655193; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=VHbnDTTx4SUTRx8/0+aZqHaMkKtJnoW/wRc2CebNntU=; b=ai58Gfj1z0luwGZHdj5PtYzoOt8M5SjWNneG1/qdbYo6LzMWT8tAExtQ+QVDi2jbOh BURAfB65G1/St8+Jlserz7Q8vz6GvkD/8p/8q+zwAIHiixFQCTiMIFVcqASrtSuHZjwi 62bhrbfjmeeKdVaqhtPZi0HK+7uFgM0HymFqNKeZdRvd9I2sPKUPcPq92Gdq9YeQpzdT YE5K67sJMuZBoL3AMCevhdwhPOA8GnIHJW2euA3Ga2gwxkqltbKMgZxKJxqGtszyeJIX hCzEXwclZiTAl23W/9eQwfcKz9QnAITCIZ2vAZtvKPvbP6RpRuC6THSmQylWQMOAhIP7 a6Hw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781050393; x=1781655193; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=VHbnDTTx4SUTRx8/0+aZqHaMkKtJnoW/wRc2CebNntU=; b=GTA7xSkBCNMwiXwmQtd+QNUHxDDYEGnHer1qHhv7vq6U50d3gSxHtTA+VqqopWi9aW grMDz29XAARfwGAA35N4ZntRjzn/zQo3k8aj9lcWPc5Lwo5aHkmu9V9tUobgb5xco8oY wYnLqGjwnBk0hhgAMLZJP5zLURpU9+8OmMJMb2yj4eA6xHNPffpa/SYvTKhQZHTgMGDW GbTWAU40eCR+Fuk0uV+/mD7MKAQQygtyEMFgfD999H8JZ/EU1wal+TNzaP3YEyeaP6wk xwimt9UoIM8QKteZyBBJrBiVNUxdI2Whvy7/+G7weWd+jwntZtt5Sh/0dICF7AzfX9J1 O1qQ== X-Forwarded-Encrypted: i=1; AFNElJ/UBf8K58sybL3Ts+BvAIY7oReoqaCOJ+WpZWed64t7K2uiHmh8cO4DxMrdmOB8BPtT1hCv+evV3vQ43B0=@vger.kernel.org X-Gm-Message-State: AOJu0YyfiAYI4lKPuVCH+GmdXYzOK36/N9VeD5A7CW+PUhfhhrC/UNj2 tHuCZvtO359BsuH7P7iIR+NRcVzZWjteJcd2ou7B3Mk7x0XZiN7y+k8ZHTJIz/DlQa5s7EUg/Uf oNfOZnq9uL8T99hOOJFVHr0MS6Uv2eAdqVA== X-Received: from dyba14.prod.google.com ([2002:a05:693c:63ce:b0:2f4:b34a:2550]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7301:9bc1:b0:2ff:c611:82c7 with SMTP id 5a478bee46e88-3077b0847camr13528502eec.12.1781050392582; Tue, 09 Jun 2026 17:13:12 -0700 (PDT) Date: Wed, 10 Jun 2026 00:12:57 +0000 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.54.0.1099.g489fc7bff1-goog Message-ID: <7f3a4ddb3f132464f17716eaae657a6367d6dd05.1781042698.git.abhishekbapat@google.com> Subject: [PATCH v4 4/6] alloc_tag: add accuracy based filtering to ioctl From: Abhishek Bapat To: Suren Baghdasaryan , Andrew Morton , Kent Overstreet , Hao Ge Cc: Shuah Khan , Jonathan Corbet , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, Sourav Panda , Abhishek Bapat Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Extend the allocinfo filtering mechanism to allow users to filter tags based on their accuracy. Signed-off-by: Abhishek Bapat Acked-by: Hao Ge --- include/uapi/linux/alloc_tag.h | 4 ++++ lib/alloc_tag.c | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h index 7f5acbb44c14..6ea39c4869fe 100644 --- a/include/uapi/linux/alloc_tag.h +++ b/include/uapi/linux/alloc_tag.h @@ -26,6 +26,8 @@ struct allocinfo_tag { char function[ALLOCINFO_STR_SIZE]; char filename[ALLOCINFO_STR_SIZE]; __u64 lineno; + /* filter criteria only; see allocinfo_counter.accurate for actual accura= cy */ + __u64 inaccurate; }; =20 /* The alignment ensures 32-bit compatible interfaces are not broken */ @@ -45,6 +47,7 @@ enum { ALLOCINFO_FILTER_FUNCTION, ALLOCINFO_FILTER_FILENAME, ALLOCINFO_FILTER_LINENO, + ALLOCINFO_FILTER_INACCURATE, ALLOCINFO_FILTER_MIN_SIZE, ALLOCINFO_FILTER_MAX_SIZE, __ALLOCINFO_FILTER_LAST =3D ALLOCINFO_FILTER_MAX_SIZE @@ -54,6 +57,7 @@ enum { #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_MASK_INACCURATE (1 << ALLOCINFO_FILTER_INACCURATE) #define ALLOCINFO_FILTER_MASK_MIN_SIZE (1 << ALLOCINFO_FILTER_MIN_SIZE) #define ALLOCINFO_FILTER_MASK_MAX_SIZE (1 << ALLOCINFO_FILTER_MAX_SIZE) =20 diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c index a936cf18611a..73fb3d0ab821 100644 --- a/lib/alloc_tag.c +++ b/lib/alloc_tag.c @@ -249,6 +249,8 @@ static bool matches_filter(struct codetag *ct, struct a= llocinfo_filter *filter, struct alloc_tag_counters *counters, bool *fetched_counters) { + bool inaccurate; + if (!filter || !filter->mask) return true; =20 @@ -274,6 +276,12 @@ static bool matches_filter(struct codetag *ct, struct = allocinfo_filter *filter, ct->lineno !=3D filter->fields.lineno) return false; =20 + if (filter->mask & ALLOCINFO_FILTER_MASK_INACCURATE) { + inaccurate =3D !!(ct->flags & CODETAG_FLAG_INACCURATE); + if (inaccurate !=3D !!(filter->fields.inaccurate)) + return false; + } + if (filter->mask & (ALLOCINFO_FILTER_MASK_MIN_SIZE | ALLOCINFO_FILTER_MAS= K_MAX_SIZE)) { if (!*fetched_counters) { *counters =3D allocinfo_prefetch_counters(ct); --=20 2.54.0.1099.g489fc7bff1-goog From nobody Thu Jun 11 10:15:32 2026 Received: from mail-dy1-f201.google.com (mail-dy1-f201.google.com [74.125.82.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AF31E7081E for ; Wed, 10 Jun 2026 00:13:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781050404; cv=none; b=KZML9SlZ+ADFWBMXggn0EVIc2sCCib82WkemfNcta+c/AqJGJV9mRkE4T/xs4asccAg9mb1IEh/BZXnUzKULXH9qYYRBtElJLT8FC2/6DizqQpFIEhJEndopN6g5QT3T9P/mewUJphRLGBz73kjQWjZEVcJS6JkRCLLxgZsaksY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781050404; c=relaxed/simple; bh=GB0qiIU0pFwCbNTZ07zDMXtUG9ZkF02sSnBxgOP4/Bo=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Is2EfYx8XrQsukuIauoTrpmcFMx1Tv56VUpS8x0xl87VJU7H1e0b45PaA3B3Xt2ZsM04CCDwui+Y7pXWm4YkKVxfYfrS0z7xOUaknEtIOdHfTqPGkZxzXYtAaulxgd1oODugX8LzDlvsWbaJyxnNw1CDiYJOuY+NeQDjwfUtWiE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--abhishekbapat.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=WXieXbOV; arc=none smtp.client-ip=74.125.82.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--abhishekbapat.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="WXieXbOV" Received: by mail-dy1-f201.google.com with SMTP id 5a478bee46e88-304d8613efbso6321530eec.1 for ; Tue, 09 Jun 2026 17:13:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1781050394; x=1781655194; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=nVf/RXEIe8nRDG8lQtZXHCUMhxu4R3A4/WUkqUAovZA=; b=WXieXbOVOSD1Vdcx7g8auhRx0oMnSC2y+gE854HnICu7pvbV/SJ6YAiLsu1Yp7rsSE AEF9Ucw4U9KFeFlaM45j0oL8Fy9CSMWnN90vdpl3W+MMc2WAuS1czRGXfuCNc3VaoI/e iOd4Tw8wEDFb5IFcrmtSx+nZcAHLizQvAUpWWI/v1dkqTraB8UlztbPf1IXDFJNsIY2N AguGAFFOfKHeC8qXRUyFoffySnp5fsM8Itji0N49ZHlFCyOWOWI/wQqb8T0gf5dUpoYz xCpK0IgZNCczSMCzkzyg4WXmnnda9T2/5jorLH5iP6LjnKC1e4XPkFFHmQCthzRTrF/l 6Vag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781050394; x=1781655194; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=nVf/RXEIe8nRDG8lQtZXHCUMhxu4R3A4/WUkqUAovZA=; b=QaNMTMP1qhqFgsBfXsNyGAi6cCGe/dPtg5NPD6pTOD+FIs2wWpSRMx0EDVk7QS1tWf 6M/TL/9rDcJaQ/xLEX8sAq+SG3vkTgQPZAIf97a5GdTFiEoCFvvz5t27KNXy6gfE+aQw M3Mu966SLUiz/R9IZ0/tAbqUpHuBxnodnyWh0k7fsx4clkoE2KcVOExHH4ag6iKtsCOq VzT0NKwgfIR3qLILfTkhaxZBjk3nIzvIKMuk2g9fvMD1Cqe+dmlFmb1osITefvE2ZTfp QtUoE3h4L0EC69lf9wix8YcEq/0mWFByXNfojMLbsJXxBYz12aJ5bBC55bcAyCDWLjS+ qw9Q== X-Forwarded-Encrypted: i=1; AFNElJ93Um0cfI30ywIVzYf6J67jG81JeLr4YYkc+bM52YN48iQ32g4UbLDdZOfioGJlJHkARakyCQa+qlaC9Z4=@vger.kernel.org X-Gm-Message-State: AOJu0Yx3b4P0nUJDiR6BrWP6KYut3ay6MnpX0B1TX9p8Ij97OIz8R3BL FdTfgTsnRXbwlX1qeVqxdLAvqSKaAWt2sdGhzz9nCGJauXwX9OltVdR+5nOznfoDmB7QRtq12ae UU8wZc+NF0ABjz6a+MO966dMNmSeh3mhFRA== X-Received: from dycso24.prod.google.com ([2002:a05:693c:3618:b0:304:e89d:c06b]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:4347:b0:304:bce9:25fa with SMTP id 5a478bee46e88-3077b3305c5mr13833111eec.4.1781050393499; Tue, 09 Jun 2026 17:13:13 -0700 (PDT) Date: Wed, 10 Jun 2026 00:12:58 +0000 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.54.0.1099.g489fc7bff1-goog Message-ID: Subject: [PATCH v4 5/6] kselftest: alloc_tag: add kselftest for ioctl interface From: Abhishek Bapat To: Suren Baghdasaryan , Andrew Morton , Kent Overstreet , Hao Ge Cc: Shuah Khan , Jonathan Corbet , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, Sourav Panda , Abhishek Bapat Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Introduce a kselftest to verify the new IOCTL-based interface for /proc/allocinfo. The test covers: 1. Validation of the filename filter. 2. Validation of the function filter. The first test validates the functionality of the filename filter. Using "mm/memory.c" as the candidate filename filter, it retrieves filtered entries from both procfs and ioctl and matches the first VEC_MAX_ENTRIES entries. The second test validates the functionality of the function filter. It uses "dup_mm" as the candidate function as we do not expect this function name to change frequently and hence won't be needing to modify this test often. Note that both the tests match line no, function name and file name fields. Bytes allocated and calls are not matched as those values may change in the time when the data is being read from procfs and ioctl and hence can lead to false negatives. Signed-off-by: Abhishek Bapat Acked-by: Hao Ge --- MAINTAINERS | 1 + tools/testing/selftests/alloc_tag/Makefile | 9 + .../alloc_tag/allocinfo_ioctl_test.c | 333 ++++++++++++++++++ 3 files changed, 343 insertions(+) create mode 100644 tools/testing/selftests/alloc_tag/Makefile create mode 100644 tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c diff --git a/MAINTAINERS b/MAINTAINERS index 019cc4c285a3..6610dd42e484 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16715,6 +16715,7 @@ F: include/linux/alloc_tag.h F: include/linux/pgalloc_tag.h F: include/uapi/linux/alloc_tag.h F: lib/alloc_tag.c +F: tools/testing/selftests/alloc_tag/ =20 MEMORY CONTROLLER DRIVERS M: Krzysztof Kozlowski diff --git a/tools/testing/selftests/alloc_tag/Makefile b/tools/testing/sel= ftests/alloc_tag/Makefile new file mode 100644 index 000000000000..f2b8fc022c3b --- /dev/null +++ b/tools/testing/selftests/alloc_tag/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 + +TEST_GEN_PROGS :=3D allocinfo_ioctl_test + +CFLAGS +=3D -Wall +CFLAGS +=3D -I../../../../usr/include + +include ../lib.mk + diff --git a/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c b/too= ls/testing/selftests/alloc_tag/allocinfo_ioctl_test.c new file mode 100644 index 000000000000..cd9cf229ae1f --- /dev/null +++ b/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* kselftest for allocinfo ioctl + * allocinfo ioctl retrives allocinfo data through ioctl + * Copyright (C) 2026 Google, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../kselftest.h" + +#define MAX_LINE_LEN 512 +#define ALLOCINFO_PROC "/proc/allocinfo" + +enum ioctl_ret { + IOCTL_SUCCESS =3D 0, + IOCTL_FAILURE =3D 1, + IOCTL_INVALID_DATA =3D 2, +}; + +#define VEC_MAX_ENTRIES 32 + +struct allocinfo_tag_data_vec { + struct allocinfo_tag_data tag[VEC_MAX_ENTRIES]; + __u64 count; +}; + +static inline int __allocinfo_get_content_id(int dev_fd, struct allocinfo_= content_id *params) +{ + return ioctl(dev_fd, ALLOCINFO_IOC_CONTENT_ID, params); +} + +static inline int __allocinfo_get_at(int dev_fd, struct allocinfo_get_at *= params) +{ + return ioctl(dev_fd, ALLOCINFO_IOC_GET_AT, params); +} + +static inline int __allocinfo_get_next(int dev_fd, struct allocinfo_tag_da= ta *params) +{ + return ioctl(dev_fd, ALLOCINFO_IOC_GET_NEXT, params); +} + +static bool match_entry(const struct allocinfo_tag_data *procfs_entry, + const struct allocinfo_tag_data *tag_data, + bool match_bytes, bool match_calls, bool match_lineno, + bool match_function, bool match_filename) +{ + if (match_bytes && tag_data->counter.bytes !=3D procfs_entry->counter.byt= es) { + ksft_print_msg("size retrieved through ioctl does not match procfs\n"); + return false; + } + + if (match_calls && tag_data->counter.calls !=3D procfs_entry->counter.cal= ls) { + ksft_print_msg("call count retrieved through ioctl does not match procfs= \n"); + return false; + } + + if (match_lineno && tag_data->tag.lineno !=3D procfs_entry->tag.lineno) { + ksft_print_msg("lineno retrieved through ioctl does not match procfs\n"); + return false; + } + + if (match_function && + strncmp(tag_data->tag.function, procfs_entry->tag.function, ALLOCINFO= _STR_SIZE)) { + ksft_print_msg("function retrieved through ioctl does not match procfs\n= "); + return false; + } + + if (match_filename && + strncmp(tag_data->tag.filename, procfs_entry->tag.filename, ALLOCINFO= _STR_SIZE)) { + ksft_print_msg("filename retrieved through ioctl does not match procfs\n= "); + return false; + } + return true; +} + +static bool match_entries(const struct allocinfo_tag_data_vec *procfs_entr= ies, + const struct allocinfo_tag_data_vec *tags, + bool match_bytes, bool match_calls, bool match_lineno, + bool match_function, bool match_filename) +{ + __u64 i; + + if (procfs_entries->count !=3D tags->count) { + ksft_print_msg("Entry count mismatch. ioctl entries: %llu, proc entries:= %llu\n", + tags->count, procfs_entries->count); + return false; + } + for (i =3D 0; i < procfs_entries->count; i++) { + if (!match_entry(&procfs_entries->tag[i], &tags->tag[i], + match_bytes, match_calls, match_lineno, + match_function, match_filename)) { + ksft_print_msg("%lluth entry does not match.\n", i); + return false; + } + } + return true; +} + +static const char *allocinfo_str(const char *str) +{ + size_t len =3D strlen(str); + + if (len >=3D ALLOCINFO_STR_SIZE) + str +=3D (len - ALLOCINFO_STR_SIZE) + 1; + return str; +} + +static void allocinfo_copy_str(char *dest, const char *src) +{ + strncpy(dest, allocinfo_str(src), ALLOCINFO_STR_SIZE - 1); + dest[ALLOCINFO_STR_SIZE - 1] =3D '\0'; +} + +static int get_filtered_procfs_entries(struct allocinfo_tag_data_vec *proc= fs_entries, + const struct allocinfo_filter *filter, int fd) +{ + FILE *fp =3D fdopen(fd, "r"); + char line[MAX_LINE_LEN]; + int matches; + struct allocinfo_tag_data procfs_entry; + + if (!fp) { + ksft_print_msg("Failed to open " ALLOCINFO_PROC " for reading\n"); + return 1; + } + memset(procfs_entries, 0, sizeof(*procfs_entries)); + while (fgets(line, sizeof(line), fp) && procfs_entries->count < VEC_MAX_E= NTRIES) { + char filename[MAX_LINE_LEN]; + char function[MAX_LINE_LEN]; + + memset(&procfs_entry, 0, sizeof(procfs_entry)); + matches =3D sscanf(line, "%llu %llu %[^:]:%llu func:%s", + &procfs_entry.counter.bytes, + &procfs_entry.counter.calls, + filename, + &procfs_entry.tag.lineno, + function); + + if (matches !=3D 5) + continue; + + allocinfo_copy_str(procfs_entry.tag.filename, filename); + allocinfo_copy_str(procfs_entry.tag.function, function); + + if (filter->mask & ALLOCINFO_FILTER_MASK_FILENAME) { + if (strncmp(procfs_entry.tag.filename, + filter->fields.filename, ALLOCINFO_STR_SIZE)) + continue; + } + if (filter->mask & ALLOCINFO_FILTER_MASK_FUNCTION) { + if (strncmp(procfs_entry.tag.function, + filter->fields.function, ALLOCINFO_STR_SIZE)) + continue; + } + if (filter->mask & ALLOCINFO_FILTER_MASK_LINENO) { + if (procfs_entry.tag.lineno !=3D filter->fields.lineno) + continue; + } + if (filter->mask & ALLOCINFO_FILTER_MASK_MIN_SIZE) { + if (procfs_entry.counter.bytes < filter->min_size) + continue; + } + if (filter->mask & ALLOCINFO_FILTER_MASK_MAX_SIZE) { + if (procfs_entry.counter.bytes > filter->max_size) + continue; + } + + memcpy(&procfs_entries->tag[procfs_entries->count++], &procfs_entry, + sizeof(procfs_entry)); + } + return 0; +} + +static enum ioctl_ret get_filtered_ioctl_entries(struct allocinfo_tag_data= _vec *tags, + const struct allocinfo_filter *filter, int fd, + __u64 start_pos) +{ + struct allocinfo_content_id start_cont_id, end_cont_id; + struct allocinfo_get_at get_at_params; + const int max_retries =3D 10; + int retry_count =3D 0; + int status; + + /* + * __allocinfo_get_content_id may return different values if a kernel mod= ule was loaded + * between the two calls. If that happens, the data gathered cannot be co= nsidered consistent + * and hence needs to be fetched again to avoid flakiness. + */ + do { + if (__allocinfo_get_content_id(fd, &start_cont_id)) { + ksft_print_msg("allocinfo_get_content_id failed\n"); + return IOCTL_FAILURE; + } + + memset(tags, 0, sizeof(*tags)); + memset(&get_at_params, 0, sizeof(get_at_params)); + memcpy(&get_at_params.filter, filter, sizeof(*filter)); + get_at_params.pos =3D start_pos; + if (__allocinfo_get_at(fd, &get_at_params)) { + ksft_print_msg("allocinfo_get_at failed\n"); + return IOCTL_FAILURE; + } + memcpy(&tags->tag[tags->count++], &get_at_params.data, sizeof(get_at_par= ams.data)); + + while (tags->count < VEC_MAX_ENTRIES && + __allocinfo_get_next(fd, &tags->tag[tags->count]) =3D=3D 0) + tags->count++; + + if (__allocinfo_get_content_id(fd, &end_cont_id)) { + ksft_print_msg("allocinfo_get_content_id failed\n"); + return IOCTL_FAILURE; + } + + if (start_cont_id.id =3D=3D end_cont_id.id) { + status =3D IOCTL_SUCCESS; + } else { + ksft_print_msg("allocinfo_get_content_id mismatch, retrying...\n"); + status =3D IOCTL_INVALID_DATA; + } + } while (status =3D=3D IOCTL_INVALID_DATA && retry_count++ < max_retries); + + return status; +} + +static int run_filter_test(const struct allocinfo_filter *filter) +{ + int fd; + struct allocinfo_tag_data_vec *tags =3D malloc(sizeof(*tags)); + struct allocinfo_tag_data_vec *procfs_entries =3D malloc(sizeof(*procfs_e= ntries)); + int ioctl_status; + int ret =3D KSFT_PASS; + + if (!tags || !procfs_entries) { + ksft_print_msg("Memory allocation failed.\n"); + ret =3D KSFT_FAIL; + goto freemem; + } + + fd =3D open(ALLOCINFO_PROC, O_RDONLY); + if (fd < 0) { + ksft_print_msg("Failed to open " ALLOCINFO_PROC ": %s\n", strerror(errno= )); + ret =3D KSFT_SKIP; + goto freemem; + } + + if (get_filtered_procfs_entries(procfs_entries, filter, fd)) { + ksft_print_msg("Error retrieving entries from " ALLOCINFO_PROC "\n"); + ret =3D KSFT_FAIL; + goto exit; + } + + if (procfs_entries->count =3D=3D 0) { + ksft_print_msg("No entries found in " ALLOCINFO_PROC ", skipping test\n"= ); + ret =3D KSFT_SKIP; + goto exit; + } + + ioctl_status =3D get_filtered_ioctl_entries(tags, filter, fd, 0); + if (ioctl_status =3D=3D IOCTL_INVALID_DATA) { + ksft_print_msg("Trouble retrieving valid IOCTL entries, skipping.\n"); + ret =3D KSFT_SKIP; + goto exit; + } + if (ioctl_status =3D=3D IOCTL_FAILURE) { + ksft_print_msg("Error retrieving IOCTL entries.\n"); + ret =3D KSFT_FAIL; + goto exit; + } + + if (!match_entries(procfs_entries, tags, false, false, true, true, true)) + ret =3D KSFT_FAIL; + +exit: + close(fd); +freemem: + free(tags); + free(procfs_entries); + return ret; +} + +static int test_filename_filter(void) +{ + struct allocinfo_filter filter; + const char *target_filename =3D "mm/memory.c"; + + memset(&filter, 0, sizeof(filter)); + filter.mask |=3D ALLOCINFO_FILTER_MASK_FILENAME; + strncpy(filter.fields.filename, target_filename, ALLOCINFO_STR_SIZE); + + return run_filter_test(&filter); +} + +static int test_function_filter(void) +{ + struct allocinfo_filter filter; + const char *target_function =3D "dup_mm"; + + memset(&filter, 0, sizeof(filter)); + filter.mask |=3D ALLOCINFO_FILTER_MASK_FUNCTION; + strncpy(filter.fields.function, target_function, ALLOCINFO_STR_SIZE); + + return run_filter_test(&filter); +} + +int main(int argc, char *argv[]) +{ + int ret; + + ksft_set_plan(2); + + ret =3D test_filename_filter(); + if (ret =3D=3D KSFT_SKIP) + ksft_test_result_skip("Skipping test_filename_filter\n"); + else + ksft_test_result(ret =3D=3D KSFT_PASS, "test_filename_filter\n"); + + ret =3D test_function_filter(); + if (ret =3D=3D KSFT_SKIP) + ksft_test_result_skip("Skipping test_function_filter\n"); + else + ksft_test_result(ret =3D=3D KSFT_PASS, "test_function_filter\n"); + + ksft_finished(); +} --=20 2.54.0.1099.g489fc7bff1-goog From nobody Thu Jun 11 10:15:32 2026 Received: from mail-dy1-f202.google.com (mail-dy1-f202.google.com [74.125.82.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7D53482866 for ; Wed, 10 Jun 2026 00:13:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781050404; cv=none; b=NS4olw3pCFI9PB+iWjl8c2Wk5INq3ahdYzlkUVrVOMGbTnYlBVj+0MI1XCe9LEQ6Nl27oUGmZuCy+3ZXTJGPsf5ovmdbbMz79/EpOA9HgeDRJvKCyj8QuTPjy88VdVcQRPcr458tut+4dDHhHSQjsVAgv5js6b6l3pD9jzO9mdw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781050404; c=relaxed/simple; bh=4GP0tDPNcXk0hPmuURDf0OIrTBTNq23K0FE7mxsWqOc=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=YYE13O+zW7kezYE7r9HUhFR9DGPSekmEfgLf+ukb7cG7tuGro1GaOWQ59up5n52pWZG6MzdXgZnZI+dmZMGjU8ESVqph6TNN7vKkdanT3W4qNwDNcpyr1E9SbtmAprd/s5iQNXlCJEHdFWdhQSwTeEX2M07xyxXruQfnXabC8xw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--abhishekbapat.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=pOmdF7R7; arc=none smtp.client-ip=74.125.82.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--abhishekbapat.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="pOmdF7R7" Received: by mail-dy1-f202.google.com with SMTP id 5a478bee46e88-30761ab3483so531180eec.0 for ; Tue, 09 Jun 2026 17:13:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1781050395; x=1781655195; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=UqbNILcH5wHHhr41jH351ypxsRzTCj5EvG750gJRyes=; b=pOmdF7R7fKwh2Lj3C7vsXBo8YMqPolLci9o7CTZWPvvrnoBm5QTvZtIywcaE6086+s eGZ3AUggw+JdL2Hd0TBOWwIISOVPc+XkiurLbkelTvvXx4gMLrJ7hqi6R4bRGVhr/OsT kyBsey/dwOZ77j7XHyPJIuvfRVH3OczZnklThNpPi+6b6d9JmUAwJxqxRIHevO6vZ1cw VogEHxZdtCOEahqTwqO6ooKKRaDwckkkXBs9L4elMzcse2jJhhSEN34uW2yTiCEdbsAk 6t3JFo/9Z4rWO4r4mY47T06YCSp9oAhFD3+i8MzXLJDatLaHM70lQhatEXeJUNAF7jPT DmUA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781050395; x=1781655195; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=UqbNILcH5wHHhr41jH351ypxsRzTCj5EvG750gJRyes=; b=dBDSNYxD4qkOFOLMzR5dG0HZNedZwAxUpvWSJr+E9CPUsvbC3Bfsy5FERKIJsh+EVL fRATSwb4ArGKd2uICkDyc4JcXWR/sdurKHqwcnBPL+hCy4P84HchdjAsl9i1VeRji5im K8BgF5/aAwJ11tqlhLYCZVqrcJxdKDm7DVAD7zL3dWMeCL88x9/Xrv5OLGWegwc5/k3I 8wif7JrqnGo6HA7R5qR/YVpnWVFKr+10Yn1Y0Tpq4sjRAn7EXsRfoO4db2gfiDAGkCC3 41TRQNmLldDR6Anqgdx4p6Y7nP3qmVOV2ohAY3Fos1t1tTTnzwfbq6tLidqoynUQHOry QWuA== X-Forwarded-Encrypted: i=1; AFNElJ+0KNZv4lb7Atpgx2nbDua5as6ybEg59RfBdWzuWPqZSbSbWUyOAR5g4qEQIXIUpKUMKRgaPh0p/JSHB34=@vger.kernel.org X-Gm-Message-State: AOJu0YxdWmoAKNm6qRl5vxVphl0NqdDTLhV4zLiC/xW7x4LgUea10MOq C1lYH6cr9PDlr9/vI/DUw2hPIG241NAcacatIcbvnnOBznReJKPdmMq9LKNhIEQdu0MZTeQ6qNC xbY5YzsYwPnwNK9c5LUPYKVZ8Aie/jfHDBA== X-Received: from dyev5.prod.google.com ([2002:a05:7300:4305:b0:307:a303:44ea]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:534f:b0:304:c520:4e0c with SMTP id 5a478bee46e88-307d5fc2817mr4420578eec.6.1781050394482; Tue, 09 Jun 2026 17:13:14 -0700 (PDT) Date: Wed, 10 Jun 2026 00:12:59 +0000 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.54.0.1099.g489fc7bff1-goog Message-ID: Subject: [PATCH v4 6/6] kselftest: alloc_tag: extend the allocinfo ioctl kselftest From: Abhishek Bapat To: Suren Baghdasaryan , Andrew Morton , Kent Overstreet , Hao Ge Cc: Shuah Khan , Jonathan Corbet , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, Sourav Panda , Abhishek Bapat Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add the following 2 scenarios to the allocinfo ioctl kselftest: 1. Validate size based filtering 2. Validate lineno based filtering The first test uses "do_init_module" as the candidate function for the test. This is because the associated site will only allocate memory when a kernel module is loaded. The return value of get_content_id() changes every time modules are loaded or unloaded. Hence, as long as get_content_id() values at the start and the end of the test are the same, the memory allocated by the do_init_module call site should also remain the same. Consequently, the test can assume consistency between the value returned by the ioctl and the procfs resulting in less flakiness. Signed-off-by: Abhishek Bapat --- .../alloc_tag/allocinfo_ioctl_test.c | 204 +++++++++++++++++- 1 file changed, 203 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c b/too= ls/testing/selftests/alloc_tag/allocinfo_ioctl_test.c index cd9cf229ae1f..5d2f13900a47 100644 --- a/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c +++ b/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c @@ -311,11 +311,201 @@ static int test_function_filter(void) return run_filter_test(&filter); } =20 +static int test_size_filter(void) +{ + int fd; + struct allocinfo_tag_data_vec *tags =3D malloc(sizeof(*tags)); + struct allocinfo_tag_data_vec *procfs_entries =3D malloc(sizeof(*procfs_e= ntries)); + struct allocinfo_filter filter; + int ret =3D KSFT_PASS; + __u64 target_size, i, pos; + bool found; + const char *target_function =3D "do_init_module"; + struct allocinfo_content_id start_cont_id, end_cont_id; + int retry =3D 0; + const int max_retries =3D 10; + + if (!tags || !procfs_entries) { + ksft_print_msg("Memory allocation failed.\n"); + ret =3D KSFT_FAIL; + goto freemem; + } + + fd =3D open(ALLOCINFO_PROC, O_RDONLY); + if (fd < 0) { + ksft_exit_skip("Failed to open " ALLOCINFO_PROC ": %s\n", strerror(errno= )); + ret =3D KSFT_FAIL; + goto freemem; + } + + do { + found =3D false; + pos =3D 0; + + if (__allocinfo_get_content_id(fd, &start_cont_id)) { + ksft_print_msg("allocinfo_get_content_id failed\n"); + ret =3D KSFT_FAIL; + goto exit; + } + + memset(&filter, 0, sizeof(filter)); + filter.mask |=3D ALLOCINFO_FILTER_MASK_FUNCTION; + strncpy(filter.fields.function, target_function, ALLOCINFO_STR_SIZE); + + if (get_filtered_procfs_entries(procfs_entries, &filter, fd)) { + ksft_print_msg("Error retrieving entries from " ALLOCINFO_PROC "\n"); + ret =3D KSFT_FAIL; + goto exit; + } + + if (procfs_entries->count =3D=3D 0) { + ksft_print_msg("Function %s not found in procfs\n", target_function); + ret =3D KSFT_SKIP; + goto exit; + } + + target_size =3D procfs_entries->tag[0].counter.bytes; + + memset(&filter, 0, sizeof(filter)); + filter.mask |=3D ALLOCINFO_FILTER_MASK_MIN_SIZE | ALLOCINFO_FILTER_MASK_= MAX_SIZE; + filter.min_size =3D target_size; + filter.max_size =3D target_size; + + while (1) { + struct allocinfo_get_at get_at_params; + + memset(&get_at_params, 0, sizeof(get_at_params)); + memcpy(&get_at_params.filter, &filter, sizeof(filter)); + get_at_params.pos =3D pos; + + if (__allocinfo_get_at(fd, &get_at_params)) + break; + + tags->count =3D 0; + memcpy(&tags->tag[tags->count++], &get_at_params.data, + sizeof(get_at_params.data)); + + while (tags->count < VEC_MAX_ENTRIES && + __allocinfo_get_next(fd, &tags->tag[tags->count]) =3D=3D 0) + tags->count++; + + for (i =3D 0; i < tags->count; i++) { + if (strcmp(tags->tag[i].tag.function, target_function) =3D=3D 0) { + found =3D true; + break; + } + } + + if (found || tags->count < VEC_MAX_ENTRIES) + break; + + pos +=3D tags->count; + } + + if (__allocinfo_get_content_id(fd, &end_cont_id)) { + ksft_print_msg("allocinfo_get_content_id failed\n"); + ret =3D KSFT_FAIL; + goto exit; + } + + if (start_cont_id.id =3D=3D end_cont_id.id) + break; + + ksft_print_msg("Module load detected during size verification, retrying.= ..\n"); + } while (retry++ < max_retries); + + if (start_cont_id.id =3D=3D end_cont_id.id && !found) { + ksft_print_msg("Entry with function %s not found in IOCTL results\n", + target_function); + ret =3D KSFT_FAIL; + } + +exit: + close(fd); +freemem: + free(tags); + free(procfs_entries); + return ret; +} + +static int test_lineno_filter(void) +{ + int fd; + struct allocinfo_tag_data_vec *tags =3D malloc(sizeof(*tags)); + struct allocinfo_tag_data_vec *procfs_entries =3D malloc(sizeof(*procfs_e= ntries)); + struct allocinfo_filter filter; + enum ioctl_ret ioctl_status; + int ret =3D KSFT_PASS; + __u64 target_lineno, i; + + if (!tags || !procfs_entries) { + ksft_print_msg("Memory allocation failed.\n"); + ret =3D KSFT_FAIL; + goto freemem; + } + + fd =3D open(ALLOCINFO_PROC, O_RDONLY); + if (fd < 0) { + ksft_exit_skip("Failed to open " ALLOCINFO_PROC ": %s\n", strerror(errno= )); + ret =3D KSFT_FAIL; + goto freemem; + } + + memset(&filter, 0, sizeof(filter)); + + if (get_filtered_procfs_entries(procfs_entries, &filter, fd)) { + ksft_print_msg("Error retrieving entries from " ALLOCINFO_PROC "\n"); + ret =3D KSFT_FAIL; + goto exit; + } + if (procfs_entries->count =3D=3D 0) { + ksft_print_msg("Could not retrieve procfs entries\n"); + ret =3D KSFT_SKIP; + goto exit; + } + /* + * We depend on the result of procfs entries to create the ioctl_filter. = Hence we + * cannot recycle the run_filter_test function here. + */ + target_lineno =3D procfs_entries->tag[0].tag.lineno; + + filter.mask |=3D ALLOCINFO_FILTER_MASK_LINENO; + filter.fields.lineno =3D target_lineno; + + ioctl_status =3D get_filtered_ioctl_entries(tags, &filter, fd, 0); + if (ioctl_status =3D=3D IOCTL_INVALID_DATA) { + ksft_print_msg("Trouble retrieving valid IOCTL entries, skipping.\n"); + ret =3D KSFT_SKIP; + goto exit; + } + if (ioctl_status =3D=3D IOCTL_FAILURE) { + ksft_print_msg("Error retrieving IOCTL entries.\n"); + ret =3D KSFT_FAIL; + goto exit; + } + + for (i =3D 0; i < tags->count; i++) { + if (tags->tag[i].tag.lineno !=3D target_lineno) { + ksft_print_msg("IOCTL entry %llu has incorrect lineno %llu.\n", + i, tags->tag[i].tag.lineno); + ret =3D KSFT_FAIL; + goto exit; + } + } + +exit: + close(fd); +freemem: + free(tags); + free(procfs_entries); + return ret; +} + int main(int argc, char *argv[]) { int ret; =20 - ksft_set_plan(2); + ksft_set_plan(4); =20 ret =3D test_filename_filter(); if (ret =3D=3D KSFT_SKIP) @@ -329,5 +519,17 @@ int main(int argc, char *argv[]) else ksft_test_result(ret =3D=3D KSFT_PASS, "test_function_filter\n"); =20 + ret =3D test_size_filter(); + if (ret =3D=3D KSFT_SKIP) + ksft_test_result_skip("Skipping test_size_filter\n"); + else + ksft_test_result(ret =3D=3D KSFT_PASS, "test_size_filter\n"); + + ret =3D test_lineno_filter(); + if (ret =3D=3D KSFT_SKIP) + ksft_test_result_skip("Skipping test_lineno_filter\n"); + else + ksft_test_result(ret =3D=3D KSFT_PASS, "test_lineno_filter\n"); + ksft_finished(); } --=20 2.54.0.1099.g489fc7bff1-goog