From nobody Mon Jun 8 06:35:51 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 60B143BBFB9 for ; Fri, 5 Jun 2026 23:36:57 +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=1780702619; cv=none; b=Lxh7Ll8Lve6KUeFHbmtndAwGMDJ4roFx9Edgr51AIjsUjHlMQgX9IH2TKnjr3nzhBq4OFg8AiF/EnO+m+Eg265TeGOFJHsGZMJp5SPnaXxooZZsxUQOFAtHb+EEctp/5KUYwfKPxs8KbxKJqhzFognrusM6wFhZaNgXWxpffhIs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780702619; c=relaxed/simple; bh=rfmhKs2K1cdVmIRueMgrXrOaDiEpDBo9ae/lzf/HCjM=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=JqaGZI8kMPSPzsn4kXErnsPEDOZnN8VPn9MxGY0LImAaPJBIoX3ouHoyeg1TL1xOHq/XWW8GXsVUAVzBVTAhcwxYPS7Q5ge04644huIlZy5Is85BIrSd0FLLBO+wc/fsdkgFhIflzDCeYbM0JI2sLY7r/b2Mpic+lOqFaNzMZN4= 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=cfchEO97; 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="cfchEO97" Received: by mail-dy1-f201.google.com with SMTP id 5a478bee46e88-304e7fc90b1so2302790eec.1 for ; Fri, 05 Jun 2026 16:36:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1780702616; x=1781307416; 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=DkqVffYh6nrcGAjKl2Ew9k2LxbC2nGZuNzPcyrtCv9k=; b=cfchEO97DM7EW8Ydy4DksdwRxywm+JfboCYzcODQA50O5wmq9J6XkOShsz8VSBb9cV MglZ4BXj8/P6j+JFQzVeqf3bsqp/KyMjhwOnC5GdRxthJFYvb5XNgslIUaaTKUQplvrl W6cPjxmLcLcReEpWfener005a0F5fjIeK+C4/rFYRjZAQCPMKOboBwt0NRMndQP1Vu3Y aMoa3HjIr4l7UyjSEdcNy2CaTFPHWmnS1h85awWqh4fE/qyXtjfXjKY7V7rrIGijtz6d +ZWFB9AsGKanekK1z9yYOCyHjR5n2NGUhHC1a7rRQf+n80vbN7RJtbigFH9sL9pE9fN+ 6WYw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780702616; x=1781307416; 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=DkqVffYh6nrcGAjKl2Ew9k2LxbC2nGZuNzPcyrtCv9k=; b=n5tlmDtZpsRjV9KDH/hj6qy4WB2aVSOKwnEqnPJ4emT9GkchiZY/H5wiND+dITTgFa dc4Rt66Hftl9pJXKhGoFiCt4+DNHFkAoH9FYGBg06Li3PKb/HjbqU0n5Uug+owQaxi45 i2AgkvABhPlJ7qVBNbLBCaboU6lqST875H7101+XEHoBvsKCxgM1ewuxbwtBG9FQAN5a yUcnb/dY3pG3tiWxrhTLe+O/GHUoIpOejav+zyYKWReWPZDhv5FGSwNzVrP0SZjPQQy5 QIjR7KzStF+4YA5NUmPypjrLYpe/ulYaFBGHBbzH2ki72sp8HjheTvDfROf6bWVeu3Yw RCBw== X-Forwarded-Encrypted: i=1; AFNElJ9I5ka8XuwM6HLcGVyFyD+Uvt+XlHXgydydIj1b7WEjjcIcE83zTphmb/54VKvzhLuFvSsGYckHJHQTUqc=@vger.kernel.org X-Gm-Message-State: AOJu0YwTc3G8i2EzmUFb+osiCKxW5HnXmcbbbtTo9hwDIDpOUe6Gqf6O kkjd49dHr5rJvGiDjmbh/aYE/DpDFiVW3bsSUk+vPdtWaMULOnFi0oAm+R5kD9H0ksT/Y3mmJGI CvXxYlryFOBKilT3LW2X4PN+5ckURK4Y8HQ== X-Received: from dyah11-n1.prod.google.com ([2002:a05:693c:83cb:10b0:304:e502:fe2d]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:230b:b0:304:dd1c:737e with SMTP id 5a478bee46e88-3077b22a7abmr3337554eec.16.1780702616096; Fri, 05 Jun 2026 16:36:56 -0700 (PDT) Date: Fri, 5 Jun 2026 23:36:46 +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.1032.g2f8565e1d1-goog Message-ID: <0e91fdd3a88dbe5220d15c4c8ff7b8f66e86af7c.1780701922.git.abhishekbapat@google.com> Subject: [PATCH v3 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 --- 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 | 54 ++++ lib/alloc_tag.c | 232 +++++++++++++++++- lib/codetag.c | 18 ++ 7 files changed, 312 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 a31f6f207afd..77f3fc487691 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16711,6 +16711,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..901199bad514 --- /dev/null +++ b/include/uapi/linux/alloc_tag.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * include/linux/alloc_tag.h + */ + +#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.1032.g2f8565e1d1-goog From nobody Mon Jun 8 06:35:51 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 359893CEB8F for ; Fri, 5 Jun 2026 23:36:58 +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=1780702620; cv=none; b=TJn2lvpWarF3+tcdEbqvuft4lNVKRQZfQe7tCNPL63/9lxoBS0LKiNDXHcWj0ffJqqFjGGsgPQSiF1Uo/GVZ6eW/+bDlZvFx5ZSWPnDtP+aSzNbcT1PvPJoLqS8QPuxqgnS8X9/ErapsNwhqAMJ+vD/mMfRE4y8R7pScem45yOo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780702620; c=relaxed/simple; bh=CP2yswF2iDfvmx/kUnu8csyxgl+J+SO7fMl+IEIYCaU=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=StWrFrNsBB7vm4qS/FDhckFEH0v6U8HppI5ukIM7HGe37cqplIZTKpIKb+JSHDzNmH9+OZTRa2lbw+oNjURC187EcU6hxo+Vij6wefyDRe3rTuo0bfdoWJshLV8AIdEiOQOtDrFjYITjnijqOKsxqBaWKHxYavkwMToHrbE7uvo= 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=WK/m7R6E; 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="WK/m7R6E" Received: by mail-dy1-f202.google.com with SMTP id 5a478bee46e88-304e4636205so4637047eec.1 for ; Fri, 05 Jun 2026 16:36:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1780702617; x=1781307417; 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=CUz21q/5HxpYzbtjUddcLYZc4KL4hA6ns2oMTMr5vuE=; b=WK/m7R6EIcpZSfOJIeiHFXsla+OtHHZ9HqOvdp79B0zl9P/bGEJoZD6zFXh6OUaQEl hfuL6HJK3tFUCGla79nf6cXX2MOeXpJxmiMQhbgKuO5dN0+D1EXq9ltd3gnO0XQXC8xJ WMhFri28TKMseFrhxYK7MBMKST7VYAiawyK0DHGnBDLzjO6dqofh5WnpN8xUKPIiqxPp aQwCWPs4vaZM4I2VkO8YpQZHkX4A4t42E7vuhQLwcVBfSUaj0AiQ65GnrZjZUnKRhhHS 4MnMhpSH+fRvYkONlmca7fHQQzuYylIqejlFm0rBhSl3/UQL+rsUeuFL9x1OvYZYaY59 NmHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780702617; x=1781307417; 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=CUz21q/5HxpYzbtjUddcLYZc4KL4hA6ns2oMTMr5vuE=; b=dInqs7o6V2hO4vvJFbFiUPww8uxDAdy8Tc7h2EQbztm22j81aFuAtLLpyMNa4K+qna vX/IAu5LolKk9hcnmRPWI4XLtikx032ILkQCAaTMU+QTnDhxDAMMb2x/7Bz4s7m2pZla 6gwvhgCukaRbrwr/OfFaunfuDfxayBOzCi3hO8SkZCvIxS6MIMO2XgomU2W5GhKzjRwd iYC+NO0eJiLWVAVPIxz/Hod0X3j6ttFDDbZkBshSiMEH70zwNx9DpUEyo8FWhguS31a4 LQZvbGKZljorgXv/Wf/Fm+llVbn7FNkali8aHcPBYuI2HNnC8wyIjaXF/H8VPJN12dGF WFOw== X-Forwarded-Encrypted: i=1; AFNElJ8MCc5l+jzgWCWqe/2uLXZmWuvD+HPxL/mh0aLfBIN3k2k3XU4BTv+cd3Tn8epash8oIqc4TSJ7K2wZ9K0=@vger.kernel.org X-Gm-Message-State: AOJu0YzQwiTPCFnQjHFz8jxAACPCxYakknAtdy2efFl8eR5uJlq0rgYh 3poksEUEZDVvfvsqQb7RQeX4CJtlG39+asy7CIrEeQdD01ZuYF8FCKKA+tgShT0oTMyLtvEehYG 6jN1mW+r4BJCfoyzrkjEjEoN360qa5gOeUg== X-Received: from dyba16.prod.google.com ([2002:a05:693c:63d0:b0:304:cde4:bdc3]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:80c8:b0:307:37a4:15dd with SMTP id 5a478bee46e88-3077b26f364mr3065770eec.26.1780702617066; Fri, 05 Jun 2026 16:36:57 -0700 (PDT) Date: Fri, 5 Jun 2026 23:36:47 +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.1032.g2f8565e1d1-goog Message-ID: <6f3b4aa0aa294cd56a73854c631de3ab7c0c5e01.1780701922.git.abhishekbapat@google.com> Subject: [PATCH v3 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 901199bad514..cffb0c46e0b1 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; }; =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..93bc976ac505 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 it's 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.funct= ion))) + return false; + + if ((filter->mask & ALLOCINFO_FILTER_MASK_FILENAME) && + ct->filename && (allocinfo_cmp_str(ct->filename, filter->fields.filen= ame))) + 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.1032.g2f8565e1d1-goog From nobody Mon Jun 8 06:35:51 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 EEFF43F8257 for ; Fri, 5 Jun 2026 23:36:58 +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=1780702620; cv=none; b=Waii884GdCOHLu+sr1McEDMu6xO8McMct4zlXVvperCTOMu9To1sqEq8vnTfUXuDs6NlXnqPFiyz9gqjD95yQY/hxrgZe81EqL3CB1paGXu00NeOows87Ng0oYT/sEyMOTSAvlGvE8qkAF5b9PFYebG5UNBn6YHtdKaFuzz6TCA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780702620; c=relaxed/simple; bh=SoEAP8EZFSElkjNp12+P+W8eAzWWZNKyZe7QThIlPJs=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=D+q5AL5mMcG13HGDhuYqoeuapcD1+E/1stOR5O2h0ArMtTdQFYBsN91GrzOi3sbSrOyOKWKp8zEBQ5v2EIWFdu2ppLvUQFQtL/OtqUa5jJSBvQZlIsxiDky/hBHl+orqV+VP4I1XW1E6K7/SluJCkM0dTRSBfumagLsCX1BGA8g= 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=GoFqafWV; 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="GoFqafWV" Received: by mail-dy1-f201.google.com with SMTP id 5a478bee46e88-304f23c55b2so2401950eec.0 for ; Fri, 05 Jun 2026 16:36:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1780702618; x=1781307418; 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=JoFYWRQDoOC6tOfcHj/jj7qJpnwdSFC+5s/raUx2KnQ=; b=GoFqafWVsfzzqS34SFL9mRLxJXLff7KPDuR/LbttOK/JA2sytjmxCd9q6MLHlXaFR1 EE3/9ghm1MvXMvT5CmyFH0vfry3qlxkzoX3bHxqgmSP3fmMgo849VLoDdNkldE7bzK/N cgXLRCAuckoWqx2kee5Nlka8anU6YVBy5qru7nsfkwjppIg4hWam+6Git2P59SvdfsvS hCpwazi+fcDBfIYSt7soP2sS82sJ+RkOZ73voGI4y7M1XhGeXsryWD6mTDb11MZHC+YN HqIwODrOhZW/IV6z4RxQVuAhoO1T+JbIyAR5lAJbplJEPyDWqnqqb7H1dg7Q8Vezw3Md ReGw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780702618; x=1781307418; 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=JoFYWRQDoOC6tOfcHj/jj7qJpnwdSFC+5s/raUx2KnQ=; b=F9k4H5kHxqDptRS6kgFV7TBZm96uhGkeRl9iQfX6EYU6i+GMlpoAY9JEUM56DA92pk +YqJIv+WrgCtZTC4BB4pbLqTC+kXg+1yQ9SXDDpocZd3A4NglmevXX1UlQ1OpRmzoihY LicxJ7Icbh+C5E5XunlJQ7aX4ZEeHas4flesMDzToiW2dY4qIng+0vzLRhWM3oQ+7OpL GlRre114xo/eeI3tsXgRZ91m8iP1pPtqs5P9XXTm+Q74LuYC9gtHZxchu2cLrwwFem4L eYBBH5yJmGd0VxU9QbNCnqjDzarsvkgsB6q4yT2Nr8itTuT45oO50ksq0az0EdALerCZ K/yg== X-Forwarded-Encrypted: i=1; AFNElJ+SdrokJFf/biK0RyL5p6HsU30S1T7nOYEImukghe1TIuXS22ayYMRIalQCtR9Jd9vtDXqGXg/Dkfg/bRc=@vger.kernel.org X-Gm-Message-State: AOJu0Yw2CUR00Dxllagiq5UZmBJic+wVP/fdoKVfiEy4mydfg53FhLGa gsTk8gvy48GbvQ4SqLSFocUVNbf9Db14cm2ErsBp8tAB74wZcjTgpx0I1LU/IEG/mAle0VJlmMh IfKdlwfpyIoDGI+e8NvntUnTtcnBLs1aCTQ== X-Received: from dyek9.prod.google.com ([2002:a05:7300:6409:b0:2f9:af7:5039]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:d517:b0:304:de94:1c2c with SMTP id 5a478bee46e88-3077b866467mr3627728eec.34.1780702618006; Fri, 05 Jun 2026 16:36:58 -0700 (PDT) Date: Fri, 5 Jun 2026 23:36:48 +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.1032.g2f8565e1d1-goog Message-ID: Subject: [PATCH v3 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 --- include/uapi/linux/alloc_tag.h | 8 +++- lib/alloc_tag.c | 68 +++++++++++++++++++++++++++------- 2 files changed, 62 insertions(+), 14 deletions(-) diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h index cffb0c46e0b1..0e648192df4d 100644 --- a/include/uapi/linux/alloc_tag.h +++ b/include/uapi/linux/alloc_tag.h @@ -39,13 +39,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) @@ -53,6 +57,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 93bc976ac505..ddc6946f56ab 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 it's 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; @@ -247,20 +260,34 @@ static bool matches_filter(struct codetag *ct, struct= allocinfo_filter *filter) return false; } else if (allocinfo_cmp_str(ct->modname, filter->fields.modname)) return false; + } } =20 if ((filter->mask & ALLOCINFO_FILTER_MASK_FUNCTION) && - ct->function && (allocinfo_cmp_str(ct->function, filter->fields.funct= ion))) + ct->function && allocinfo_cmp_str(ct->function, filter->fields.functi= on)) return false; =20 if ((filter->mask & ALLOCINFO_FILTER_MASK_FILENAME) && - ct->filename && (allocinfo_cmp_str(ct->filename, filter->fields.filen= ame))) + ct->filename && allocinfo_cmp_str(ct->filename, filter->fields.filena= me)) return false; =20 if ((filter->mask & ALLOCINFO_FILTER_MASK_LINENO) && 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 +301,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 +310,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 +338,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 +348,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 +374,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 +389,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.1032.g2f8565e1d1-goog From nobody Mon Jun 8 06:35:51 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 CE46F3B71BF for ; Fri, 5 Jun 2026 23:36:59 +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=1780702621; cv=none; b=LAZlBnXD8f6Dc2ojLblqA2i7G+Qjx3Hs5Q/GjMM5h2u5mMElX5P5IDJr67jJGSB+uYo236nmjfz5rUlIx2Jo82SIhCf/fG56c6gwyYT8ogD2FtI0D6iKB54m3JTDEaLC0eHDiV661imK0C8O/3vRnCbDVx6yk2v9ZdqifpS79hY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780702621; c=relaxed/simple; bh=neSocN6TVKBA4t2f9Vylz4lp+6WndAneTxpc6BpvXCA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=BwzJYdcu/niLhn5/RlJvhF1T4LlFmTqs4S5KrDVD+4l6WxH1dPRdssGdJyiw8Z/cLBOpSISXzcK+Jjw4yRnQMXZyMArxm87Tc0HbuamHnifLwHqn31uV1a8ekzsVo5xYzSyCYdK7rbRfnWQC5zSdmbB9dF2+iwE1ReXzlMscIXk= 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=NYwbYczf; 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="NYwbYczf" Received: by mail-dy1-f201.google.com with SMTP id 5a478bee46e88-304e4636205so4637107eec.1 for ; Fri, 05 Jun 2026 16:36:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1780702619; x=1781307419; 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=UFvPWrQD/AjvIlGDL+q8aROizOfdZdfW4UIDnk6moas=; b=NYwbYczfg/RTU0jPcb80YucAkFuDc1HbnFkSf3ON9QPyNL+QZTK0zsbTQGrwdA9xy7 f2veMaY6dAIOJZprZ8Pw1OzUMDIF/HuNmtQhccuqs1FryyQzWJ0gmaVi2AQxLSds6Gv1 lg/H98gcU7f+R7IKal24RXyPbOEIYHUPcfnvVmFR8Ou3faYZihKf0i4LFZ8BN3xdhvGG gpyva12Uaf63GkU9UBfT3W0HCxRKA0sqrFyeQcXidszQgYdNeVMt1zGEcrTutNYeueZ7 769ezJ5O66gTO0OMcIJfxcL5o9w6m1pBYvFR5NfMwphb9I4KXY5ASjwuTDSgXCNxHolR oUNw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780702619; x=1781307419; 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=UFvPWrQD/AjvIlGDL+q8aROizOfdZdfW4UIDnk6moas=; b=KFmOMejadACZ6+Yc0nYhgArF2tHBvIMxVX6vqr6S0UEyBABqdX5UyCxoXkHlBj3h86 0X7svGQpmMYdODkfCa4UylxOdYA/whBbtVPSXSNUWai+a9WWLVVqFVLxPo5wuU634LZ9 LSdCQNF3e5DNP0zI68sULcyN6OMsyAfEacG/hTxMEkY/uhp01slyR8KDHeeEWbYbnbcc xf2krz712YzcUSV1nnRpbnAvVGZTqtl3mGdVfRGXpGOdKBfeWXoUBKTw3guliCo/4EbZ lmeUveUe84OxlHFZk000fWK5503O7IsDEdZquBXnBEn3etSAUu6HWd/fAnTgZspB8rI8 FsxQ== X-Forwarded-Encrypted: i=1; AFNElJ+g86BPsFAhHRp7BXXlkHhCXaBEWCn/OGm+AUnmzKUKPRj4EHAPnM3qx5cF5/nqcbA0etQE1KtvQpck/lI=@vger.kernel.org X-Gm-Message-State: AOJu0Yyiwr8QZuQpV3LjG9uf5PQYQ4REYiSLaoQSXyJJSgN89DpAIR1a AN7gpXG/pulg47wjQNXJ1iJNjzRNEANw3uMWnVNV9h+2qhNitn05b5OpQJuZUTGu2b/fxN5hWP6 sqpTqmZVIYvZCPleIlfiBioZwCA6wwzBLNA== X-Received: from dyvs26.prod.google.com ([2002:a05:693c:42da:b0:304:cda1:27ce]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:572a:b0:304:aca:35c5 with SMTP id 5a478bee46e88-3077b22c938mr2897763eec.23.1780702618822; Fri, 05 Jun 2026 16:36:58 -0700 (PDT) Date: Fri, 5 Jun 2026 23:36:49 +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.1032.g2f8565e1d1-goog Message-ID: Subject: [PATCH v3 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 --- include/uapi/linux/alloc_tag.h | 3 +++ lib/alloc_tag.c | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h index 0e648192df4d..42445bdb11c5 100644 --- a/include/uapi/linux/alloc_tag.h +++ b/include/uapi/linux/alloc_tag.h @@ -20,6 +20,7 @@ struct allocinfo_tag { char function[ALLOCINFO_STR_SIZE]; char filename[ALLOCINFO_STR_SIZE]; __u64 lineno; + __u64 inaccurate; }; =20 /* The alignment ensures 32-bit compatible interfaces are not broken */ @@ -39,6 +40,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 @@ -48,6 +50,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 ddc6946f56ab..cbcd12c4ef9c 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 @@ -275,6 +277,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.1032.g2f8565e1d1-goog From nobody Mon Jun 8 06:35:51 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 BBD2640B36C for ; Fri, 5 Jun 2026 23:37:00 +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=1780702622; cv=none; b=JHgR+54lwcxWmHOx0p12NUlEC5M3N2y0gVx7JblEuLhh3fbQG/xpptpMQ6DkjXPHN6lQHIE/nDjl3/yz3F8ww0HAEOSxnjCkHrAmqdMXbfXGq/PfVPob1nw+waD3p9E+CGWVKjO9ywj26zrgfz0OK7GROvOkzfR26R7zDn69fVA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780702622; c=relaxed/simple; bh=UdPpGV4DJ3YysLWBztNcRp9bVRk0/aVKVXcmdkelFGg=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=spKh49xMc9ho+YcKSWRXpbkGgSFkzhsBXk04h46B5hoRohcP5x/qOkbOs56BaYC2s3Svo9IauDLDg/kGv19QpNA6OavYrnqwW79M8z3vR/hMsk6gB25LHywtOEJqF15gevbn4qnjw1+E1QiilvrC/UBsGwpI2Douvp1Wsm56res= 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=necYDO+K; 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="necYDO+K" Received: by mail-dy1-f201.google.com with SMTP id 5a478bee46e88-304df51ff3eso2170843eec.0 for ; Fri, 05 Jun 2026 16:37:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1780702620; x=1781307420; 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=9NxfV6YXwXpQ4VQFQi0PhdP0vstNIfBR6RPix449NHw=; b=necYDO+KL+nAbGq/8Zt7YyhXYLss8MitMByFCp3XDreoy5nJpZHH6ht0wngodAccW+ Svr6o4jz7Y33LTPp7pn7EDyjcxFK1HD0Kq6qyc/RDTAadpoZDx6z1mYDWy4GGoQNmAhN ItDqHAi1Ca3uYzaWzMGzTz49rTOV1Fd5PEYZhfHj6kGWvesFJL6vUZtoTj4s1Su9fcI7 7jpggftrSgGSXTPr1xBDqEraghONnnJWZ5w2DS4VhYl4C/ACxMz3OiBVBwhSCWff3lQq E4pSzIo7G5lWoXnBvGU15oZ9mu7MpiN+yP9eMIBjWh8bNPfG14/vgMHmc02U1l6trY7u XQ9Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780702620; x=1781307420; 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=9NxfV6YXwXpQ4VQFQi0PhdP0vstNIfBR6RPix449NHw=; b=RfVMJ3oJr8DltpYyCCOMLvP8rvUPrXP+FOg8AL18yhUu/stAP37gP2RkHxHHxEZKUw FoWAXd2exl6o9n3lLNaFlRDiVsZPqvys6Lsd/39ezEFgwXZ1TB9kwkr4JF8OMSwHhr+Q MsQEJmONGpmvAGm4isUiKQBXyvSwDVLaN3dqriqiFGCIfyGd5azkYjRidIJr9rCpXiA1 jQXfSWRRv3GRYKUWM6BNDvnOSS8SCJ6CEJMqN/PiQm8iyRHNq62MXEDnlvS7MfmA0MnL IWjTicehDi6GG/HYLmizt14Jv8wzDnn8dg4qbOgNbS6b5lL9DquOOHgV6b79xwsGVkJN UZIQ== X-Forwarded-Encrypted: i=1; AFNElJ8cjKfRy3yMwivMQwifNJ2PhRDV0y2EG9dqvCgpKMhp/skmAYRKp0I7mS1Gu4tVPEcRq8g5tAYZQ9VTvm4=@vger.kernel.org X-Gm-Message-State: AOJu0YyEHK+DkH31/B9aQzUNOiZS89PsbKlbTi6NYQ4PDpAVoQA+M/1z Mt6Y24FaLYsRnk/s0AHiAxdBBGhX4q7/dQVle8KuvKCWouQW2Rhzb7tj2v5gw6yOE7ykOTla/PI nGjtJCFWieh3epUP39O3WtOdzN70j5ZE34Q== X-Received: from dybrh10.prod.google.com ([2002:a05:7300:f00a:b0:304:561f:1afb]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:8ca0:b0:2ea:b85c:153d with SMTP id 5a478bee46e88-3077b285d5bmr3088153eec.27.1780702619770; Fri, 05 Jun 2026 16:36:59 -0700 (PDT) Date: Fri, 5 Jun 2026 23:36:50 +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.1032.g2f8565e1d1-goog Message-ID: <2e55b3b1388a4f7a59f670a83f222ba6c836ac4e.1780701922.git.abhishekbapat@google.com> Subject: [PATCH v3 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 --- MAINTAINERS | 1 + tools/testing/selftests/alloc_tag/Makefile | 9 + .../alloc_tag/allocinfo_ioctl_test.c | 313 ++++++++++++++++++ 3 files changed, 323 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 77f3fc487691..80560f5f1292 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16713,6 +16713,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..5c3c16e86c23 --- /dev/null +++ b/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c @@ -0,0 +1,313 @@ +// 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 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) { + + memset(&procfs_entry, 0, sizeof(procfs_entry)); + matches =3D sscanf(line, "%llu %llu %[^:]:%llu func:%s", + &procfs_entry.counter.bytes, + &procfs_entry.counter.calls, + procfs_entry.tag.filename, + &procfs_entry.tag.lineno, + procfs_entry.tag.function); + + if (matches !=3D 5) + continue; + + 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_exit_skip("Failed to open " ALLOCINFO_PROC ": %s\n", strerror(errno= )); + ret =3D KSFT_FAIL; + 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.1032.g2f8565e1d1-goog From nobody Mon Jun 8 06:35:51 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 960C640B38E for ; Fri, 5 Jun 2026 23:37:01 +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=1780702623; cv=none; b=t2hMhJrkSNQRqYV3g7B1ONEoomEeut5ovmQyfFjQtBrLr7/FujNQTl44KqsD+BY1WT4X+z1Wjoq//w20zsNWHpDMQsbZpv6lf9FHne7OFey1wcDaougLzJG+PsE/bBjQCWzbool7DXIE0cMDnksgJU4XzwwfqaxfnRxcXZ6JG5E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780702623; c=relaxed/simple; bh=vcXAW+5zKQFSC2JOqf/9aioIlc38daQCQJUIgHBFZ/c=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=s92nTTCMUlAqIUFp5/G9OMs7hA3pB8Lk3yUi301aFZbfd+6T7XLfStKt0OBL4tFj/TkTs4rrZOEKez9UZH75clVZZJdhHK/btW/0NGxE4ZgflcI6jB/nHTFQjT/dcwjJx998haU8wiPq4SQMue7RsfMuSwrgsHmhg++UEp+dD48= 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=haFxk5mJ; 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="haFxk5mJ" Received: by mail-dy1-f201.google.com with SMTP id 5a478bee46e88-3074797dfa9so3480552eec.1 for ; Fri, 05 Jun 2026 16:37:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1780702621; x=1781307421; 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=v4NFxVZN6hRoyN4q6+cvZk4sgGHzCYBtGGyUkSu34A8=; b=haFxk5mJAhdvVIiFp4Hxfyp9GB591c+Um4Zn2u2983+9eE9HgBllOz4v5nqU8eiEVD rPWeKN0Bd1Mg0sQKoF6nN314ldYfScGDMW3kSR4xqQXWQ9Vjpy1ZrQIuXhkRxyqikcO7 ilhxMXcbJFSd0vsUyEmSNtUpo3XNAwOxPLMRci1vZGiyIRLh/3r9EKoGyBcLcenaq7Hm aXmu5xj/1OUY3KQLGARlzW8RYNQapPVds1yvFu5Cr467kt6Oi2SVYUynzE52EVamvIBt 9VeLmikZeKIvD5aC3FtL/VXiRmKxXSQVpNvJ9r6i5ZHCE5eJRfrObMuxxT80uRP5AZHt y+Kg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780702621; x=1781307421; 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=v4NFxVZN6hRoyN4q6+cvZk4sgGHzCYBtGGyUkSu34A8=; b=i7YoqKYjl0ibNe2v5hRI/Rx4fSSqnC2SWNL461GkQKT0TOyokiOH18nYFchtBvQXQP dpr5G0kY/Z9CnZx1M6CAXCiFAkfSuSgVl00aRfQvKXCTKpQ5VWbJgZv1RCYzq/dShbXw RPHWrHaz0po7ya88nQZ/KUCu57mG6sYiU42mW140ej7gSrxhbNSPIVUIRQV5lKDw5Eon L7V3IBzz/OOQ3G5RVJDAnxz51RPLuar5FEQzl+7+/LkLUSQbFFrvyRWGviP4MOlpIDga FmdkHHl5w8WqxY16O53FGPQP5tpUSdef2AF9Tv3wDTwxwMytZqeRGeT19FDtzO+usdfD gjCg== X-Forwarded-Encrypted: i=1; AFNElJ+lCvQCsVG93kyX9wg0x/vXpH6Yi7Tz01j85ljZfbuOlYyfCMq24HDgBUuItkQAGlVnFm/vaOoCoZzhwk4=@vger.kernel.org X-Gm-Message-State: AOJu0YwBCCIuOLDoktB6G04skD73vQ0xaWYLdEw9HrBVlQH0g+YhCgZE 8cFG1vsbpLWwgSBhmtwcK842RR5lPZnHIxfSvh5TKFA4DhEaqibGto3DFQXxOlPG4URzQPwBcJN dFPRdT+rlQN8dyF6ICDWvyXgBw9Etd2FjPA== X-Received: from dyvt1.prod.google.com ([2002:a05:7301:d801:b0:304:d771:74aa]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:4347:b0:304:d388:c33e with SMTP id 5a478bee46e88-3077ae8681cmr3200526eec.1.1780702620573; Fri, 05 Jun 2026 16:37:00 -0700 (PDT) Date: Fri, 5 Jun 2026 23:36:51 +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.1032.g2f8565e1d1-goog Message-ID: Subject: [PATCH v3 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 | 194 +++++++++++++++++- 1 file changed, 193 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 5c3c16e86c23..ce3576e3cd9b 100644 --- a/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c +++ b/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c @@ -291,11 +291,191 @@ 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; + bool found =3D false; + const char *target_function =3D "do_init_module"; + + 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)); + 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; + } + + /* + * We depend on the result of procfs entries to create the ioctl_filter. = Hence we + * cannot recycle the run_filter_test function here. + */ + 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_M= AX_SIZE; + filter.min_size =3D target_size; + filter.max_size =3D target_size; + + __u64 pos =3D 0; + enum ioctl_ret ioctl_status; + + /* + * This loop is required because the first 32 entries fetched by the IOCT= L based on + * the size parameter might not contain the exact entry that was used fro= m procfs. + * If that happens, we must update pos and fetch again until we find the = exact entry. + */ + while (1) { + ioctl_status =3D get_filtered_ioctl_entries(tags, &filter, fd, pos); + 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 (strcmp(tags->tag[i].tag.function, target_function) =3D=3D 0) { + found =3D true; + break; + } + } + + if (found) + break; + + if (tags->count < VEC_MAX_ENTRIES) + break; + + pos +=3D tags->count; + } + + if (!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; + } + + if (tags->count =3D=3D 0) { + ksft_print_msg("IOCTL returned 0 matches for target lineno %llu.\n", tar= get_lineno); + 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) @@ -309,5 +489,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.1032.g2f8565e1d1-goog