From nobody Sat Jun 20 07:01:37 2026 Received: from mail-dl1-f74.google.com (mail-dl1-f74.google.com [74.125.82.74]) (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 96F1F306B0A for ; Thu, 18 Jun 2026 17:36:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781804203; cv=none; b=bKT2EVgpvJ0GSXNNbmtY6DvT4lVfd+VwNMzaLIPqLvczURKDB4B+huVMOCeEQ9A3FTGtCokuJ6fVsp2fJ1VERYO5SgUPVzDmGf7lskozt21fN/JIKdZSEGtZ+3HUf7mZIsk7UAJ8JxopAzbdNOGEh2NvEhkbpNIDQzqeV/sEWrQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781804203; c=relaxed/simple; bh=h5o3A/NOXr4NHd4faiMP8fX2T9KykuKilrX7qdGPC9g=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=ID27WETKJD98NyuQ7JLddNzVhe4Qyit9FJ4bfM0bt5dx5TnX5+z6/XEeirn6jNwyX8zITAIy+H05O6Ahxm0dJAEoZG5K9lzbYK0NfoUonAWd1cIubQaqGizMF3mTcoHP0p/EDb4q7tS12MUYkBmqx45a5WDa6e7O0g7IzkIQ9Lk= 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=HzTpnc4C; arc=none smtp.client-ip=74.125.82.74 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="HzTpnc4C" Received: by mail-dl1-f74.google.com with SMTP id a92af1059eb24-13980b6561dso4954223c88.1 for ; Thu, 18 Jun 2026 10:36:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1781804200; x=1782409000; 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=cF5jQ5tJT2uZF60ESi1BIZkiOEzJiLBY4qt7NfDR8CE=; b=HzTpnc4CfJ05yosyiOR0R1pFRSTxnVz0ik0FAnTbQpk9VGE6Mjt2bo/xaGootTL3+j /1UmaRoKTCEAjb0IYxIGvkLUqudt/vC8kvvUJPGojECaP9v9cbYmc8j3VTyP/poY/fn3 0xfyI5EPSKX6dmKiPKe3B6YQl9IlU+UQmSjpxJup/NDywI/WuMMp9jzv9oyuJEHXSB3A ZNBO9RVWTG4X0t1VoU/6l6f1j+J8jKYGzY9EB34j9do+Pa3saePKsGNZn3vEchyGg8yn tdLlYjsu1KEmDDb+WbZY/4OTnZ+Xv0KJ+b2vVberh0c6g8VbpPPcE+L/R7EdIhmVGkaS wHpQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781804200; x=1782409000; 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=cF5jQ5tJT2uZF60ESi1BIZkiOEzJiLBY4qt7NfDR8CE=; b=HOToSf+W1cvoexGSsOKfY6zZBL0YtHIrMP1sCEuDu+zus+5KCTn2R/d/aFvCMmGDcS mZqw7WSE4WjppKVCgYx0bU7WsTduvtbt5KgqW32VvVHmYnnIkMcM+pmgG5TMMvHACb4I PjwArO8xHuQZm4PGjxBaHJRYfM1a1WAZE0k9Nx08SKLuHf8w5VWhsVULEzlWMo+o7fzX 4vTYPT4wJ7V2rsFLwo/p5WpyMr5PDtiWlIKlsWgWbCn0W6+PA/lXwpwtXBEFgO3uTpQ1 0PC+Np7BMEfsylZIIteRH138+jIJuHKWjgBVKu0V9r8shPOt3Y5OUTT/+FN624SidjN3 QZJA== X-Forwarded-Encrypted: i=1; AFNElJ8J5a2VIvbpFOFJBZLqw45snGmou9Rb6RhZREzkHKmombNTt8t12R405neiA5FYPAKEAN71ScOy//uVwa8=@vger.kernel.org X-Gm-Message-State: AOJu0YyNC/c4B0tLGMCfm2LttVrFLAH2mnxMLCuCPUGIH10ehoulVrl3 3F1JPN6BSArsqgjckJNYNfCocqUrVcGTd69uNl1/ncOD9dmtWkFSyfItYthafxsYyhZCaZeZ5yq YAgBGPd0T0IZt5bXj31RDj3Znotv6B4rE3A== X-Received: from dymh25.prod.google.com ([2002:a05:7300:1c19:b0:30c:2e1:d2bf]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:2509:b0:137:ae1d:5b58 with SMTP id a92af1059eb24-139a2194979mr516145c88.20.1781804199379; Thu, 18 Jun 2026 10:36:39 -0700 (PDT) Date: Thu, 18 Jun 2026 17:36:30 +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.55.0.rc0.786.g65d90a0328-goog Message-ID: Subject: [PATCH v6 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. Note, function file and module names often have the same prefixes, therefore when filtering for them, we compare the last 64 characters to minimize the chances of name collisions. 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 | 65 +++++ lib/alloc_tag.c | 238 +++++++++++++++++- lib/codetag.c | 18 ++ 7 files changed, 329 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..ee6a023cbaf4 --- /dev/null +++ b/include/uapi/linux/alloc_tag.h @@ -0,0 +1,65 @@ +/* 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 + +/* + * Function, file and module names often have the same prefixes, therefore + * when filtering by these criteria, we compare the last 64 characters to + * minimize the chances of name collisions + */ +#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..c73195000830 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,235 @@ 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) +{ + struct seq_file *m =3D file->private_data; + struct allocinfo_private *priv =3D m->private; + + mutex_destroy(&priv->ioctl_lock); + 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. + * Function, file and module names often have the same prefixes, therefore + * when filtering by these criteria, we compare the last 64 characters to + * minimize the chances of name collisions + */ +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 +1228,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.55.0.rc0.786.g65d90a0328-goog From nobody Sat Jun 20 07:01:37 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 A38C62D9EE4 for ; Thu, 18 Jun 2026 17:36:41 +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=1781804203; cv=none; b=EQMPRPVl42hAu77FIkHVuDH6YSaAuELyhs9L8LGTAnYn7f/6FWyt+3MDpEqKOB3hoLcqfDAQbKfDTWSUunDiG8Ib/bS3eoYfdJZzwJw9ae/P8h5wUAQJS3n6B0vBRNDqMK3HH6+wCgdeDRKduxaz1Tgoj3dDs5Y1WUYIHLPFbnA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781804203; c=relaxed/simple; bh=cUjQS07B251HxhgYe8x119C3DSLaApPbrYj/OT5KTQQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=JA/A3ftv6l5LLm8k8yX+y0SD2DsDEq83WGFbkQ6UrLzNLCVv8Ut3eOIdc/dzPoeHwAi4DjHgv8vX/LPvIq0kjgKmcDJCEYtH06Sb3KAdjeixqUX8hDCTeP8fkEDzAS0d+ud22waKJHTVi/afOCGABOvnhK1oWx5/woZI9b/V4KQ= 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=HLrcDk2/; 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="HLrcDk2/" Received: by mail-dy1-f201.google.com with SMTP id 5a478bee46e88-30bef75a41eso5028329eec.0 for ; Thu, 18 Jun 2026 10:36:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1781804201; x=1782409001; 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=DrCKQmndYCTLKZMT11TnLt2FQ5FzBuck7HJJlx0dbhM=; b=HLrcDk2/7V2AZv1OI6i4MpnzCtfs97JP1VVv0G8JRUm2l8XVdDKiCFsQNvgMuhaKKV 7BElrjnCcn82tbDN3PP1KFERuiVx/M5EkXZqF9bcLACgNJhY39ieZ/1tAM/+sOu1V+lT P0P2viMBrdkw4NZ/+qYGJF4hXuBtSlHHmfXVdV+0GqK7aUMqbU2R91ItF7M0+EMq5nKp hNwfKIVXUML+BmxnMYY4MZfxGf94m2YiJTKSbHXjeyM7vyKvadbewTyxoAkpD1e9/zZs Ch7q50J27eykQYUpKpcqjbi1W52CGu5HzOBFNW3YeEkulRUcOVggHX6OppQ+klKRqSMX avvQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781804201; x=1782409001; 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=DrCKQmndYCTLKZMT11TnLt2FQ5FzBuck7HJJlx0dbhM=; b=GJcXG0W76ws2SRyTTZAtYBqtMAbDXiBKaCK8+T8xh+iGLdH3Yt0uTvUZQ5jvjwUrfk IwmXszg6vmxplLrSYXG9NbLIYyDbnSQ+dqV4ED3efstIsLCVfI6Y1fPfmLkTPElm8VbI ZhXP14ipy72b2j7MWiBid67CKfofmo8fzNfjr6cHRFzvAGAxiuFxG3ZcZrUryng9/jVf 0ZZm+ZBrpOMeSAb3AGqTQT7VsI2Jahr7aI0Y8lbBtUJNJwKWHjv9UcjULEeP/MFjKjj/ uNk67LjCF5+KWWsCeCWizS373olrMdg6IG34USv5INA+uNhbg5Ba2+qdBrwoxpEP4Vvj u+jQ== X-Forwarded-Encrypted: i=1; AFNElJ/2B5hWQfkWiyrErI39Fqgm+b8Mwn/h4d+1ZbUHQWv7XgIHTsHhpMoQRsjniEjAgi8gG+nF/PKZqwp6W80=@vger.kernel.org X-Gm-Message-State: AOJu0YyZChP186F69ySF9swnwaUKojkDX5YaFyTolKsT8vdIEsog6Zaj vaz6t8yhMyaeNQkPwZAqfz9xe49dPDLbDjwCjyEdWUyvxrdeWGhPAPS3pN0MsgyoAjzIB5XJI58 mh4UCsKR3pBpEgwlr1T50HL+ENDPVHIU3hQ== X-Received: from dycmd11.prod.google.com ([2002:a05:693c:23cb:b0:30b:f184:dc27]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:7fab:b0:2ed:27a3:eae2 with SMTP id 5a478bee46e88-30c070b3bf4mr148588eec.15.1781804200369; Thu, 18 Jun 2026 10:36:40 -0700 (PDT) Date: Thu, 18 Jun 2026 17:36:31 +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.55.0.rc0.786.g65d90a0328-goog Message-ID: Subject: [PATCH v6 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 Acked-by: Suren Baghdasaryan --- 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 ee6a023cbaf4..13e9b5916bf5 100644 --- a/include/uapi/linux/alloc_tag.h +++ b/include/uapi/linux/alloc_tag.h @@ -45,8 +45,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 c73195000830..f00d731b81cf 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 */ @@ -191,6 +192,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. @@ -230,6 +237,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. @@ -238,29 +279,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; @@ -301,6 +359,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.55.0.rc0.786.g65d90a0328-goog From nobody Sat Jun 20 07:01:37 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 9085B3446DA for ; Thu, 18 Jun 2026 17:36:42 +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=1781804204; cv=none; b=a1ExLhSW4bLxNpJVr1rOuw6CHdIuwHTR4Pa/I1fq1OsLk+MQwqaxQpgIP1P1XNFBRLl3BSH0Idq0Wi5D3WddxyWHSUhBHBE98Hp5SSQ4uamp9V3U180ABCDlntljh3deiH80phHRWt9J2y6K/KzmMb1ySQpZTTx2BwHfAZ3aBjA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781804204; c=relaxed/simple; bh=/65iuVbWXZWJNbI/HcTYI7feMzMolTXI82K/xqiPh6k=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=FOv/dGZqIyV2pHTyC+PhBdGODrrWcFjl7tXsfH6LDUtB9BhRXFAzRt6C0k4Y+EyWsQ4YSvHED4gmB7L90QsSW4nXKHr/YUKqNQvoqrr9PY3sU+cLrO8LXSRE3KuDHsNR+XiIDANtJpofUV3Pv3izOIo8JSD+FUwwPKlOzkKLICs= 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=wXXsDxgM; 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="wXXsDxgM" Received: by mail-dy1-f202.google.com with SMTP id 5a478bee46e88-30762d67a64so1700429eec.0 for ; Thu, 18 Jun 2026 10:36:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1781804202; x=1782409002; 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=Kcggm+vLyoh+gfR/AuH54hFzP3M8T4keypwurXRVhSU=; b=wXXsDxgMrX81D/J0PnjxHBXgDBdpOUVAV17VpIUoOU3PbRrvDqEo/J473s1EMFm7hm 96vvIbS/vD2zqiIQB9MqXJ2QxC8eFDrSeIsUKTwIkXNXZb8qc0re0iATFKR1et1426c/ vBzjTNhQf9wV7G23V1hyvswUYGZlkdwRvTyIT2q3OP479TtiLmcw+BgAhG/eCDTiPKjm v3kgKx2YynJQsOl/WhDxLHvccl0r9a49YTr2CalR4nhi/OXnfAn5h029aEY75S4JmgS7 +MMkdel2CDw6JYh5k7cvO+it7PBARD7OAXTivgfPzTIDeM5dNF7oY+hS7ijZJAdL9svr ir3A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781804202; x=1782409002; 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=Kcggm+vLyoh+gfR/AuH54hFzP3M8T4keypwurXRVhSU=; b=GdC0k4kEV8Zv4N92hKK2MR6AY+TlmV9U3OVIxXjBKoT218tabrD4wKSi//Y8nOURrL 3ahDekoFrtABcjxwUxW5g8nT+AgtG+E3u0Ef+qCjVP2wprjbJ3vPGFTn8Wm60amEPUQ/ jVa6f2BCwz58uCy1XpnLWMjd6pIYVSqXvB4l7yd/cEMEtJSG3gjPOqTeNcLkwbPMtpYk xnNyqxHBDI5O7QQb3i8Satn+amrrTAHC40PApI189xEDaQmwGAzHlV/z4fnvrOhgLf56 bjMZ7jiXMGNndl15X8OjheH7CJmBt0WBcSlZTvKOuQbFQY3ArZrsmUyoVszJlFcSajOb NiWw== X-Forwarded-Encrypted: i=1; AFNElJ8cNazyjMS3x8a2IaPayLx877rgweUUBEKd/gTlPrnPle3Jc49wTGQHdyTbdM6auGqNf2ePwKAK6fPoeUM=@vger.kernel.org X-Gm-Message-State: AOJu0YymL9ukcdbBmZ4dnTg6LTXspaAMawuKrkxSrbtL4zr8blnzi7dp ktU+U8ZbvY1V6UnqPzF/Hlu260Gn1c7Z+PCDwjcUbf5akEpmBJ+GKBxw562Jf5tK1x2OejmBZ3K bC8yufT9YAi3eog8jpI45Qt1KBXpkTUCfhA== X-Received: from dydn14.prod.google.com ([2002:a05:7300:730e:b0:2f9:af7:5041]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:4306:b0:30b:f6cd:fdca with SMTP id 5a478bee46e88-30c06e0c62bmr222134eec.17.1781804201397; Thu, 18 Jun 2026 10:36:41 -0700 (PDT) Date: Thu, 18 Jun 2026 17:36:32 +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.55.0.rc0.786.g65d90a0328-goog Message-ID: <6944ab65167d8884ce0d856184730d06ead68cb5.1781803482.git.abhishekbapat@google.com> Subject: [PATCH v6 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 | 64 +++++++++++++++++++++++++++------- 2 files changed, 58 insertions(+), 14 deletions(-) diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h index 13e9b5916bf5..0de5fc180790 100644 --- a/include/uapi/linux/alloc_tag.h +++ b/include/uapi/linux/alloc_tag.h @@ -50,13 +50,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) @@ -64,6 +68,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 f00d731b81cf..ad33d63ef7b4 100644 --- a/lib/alloc_tag.c +++ b/lib/alloc_tag.c @@ -198,16 +198,20 @@ 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); - if (ct->modname) allocinfo_copy_str(data->tag.modname, ct->modname); else @@ -215,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 /* @@ -241,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; @@ -268,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 @@ -281,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; @@ -288,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); @@ -311,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--; @@ -320,7 +347,9 @@ static int allocinfo_ioctl_get_at(struct seq_file *m, v= oid __user *arg) } =20 if (ct) { - allocinfo_to_params(ct, ¶ms.data); + if (!fetched_counters) + counters =3D allocinfo_prefetch_counters(ct); + allocinfo_to_params(ct, ¶ms.data, &counters); priv->positioned =3D true; } =20 @@ -346,6 +375,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; @@ -359,11 +390,18 @@ 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); + } =20 + if (ct) { + if (!fetched_counters) + counters =3D allocinfo_prefetch_counters(ct); + allocinfo_to_params(ct, ¶ms, &counters); + } if (!ct) { priv->positioned =3D false; ret =3D -ENOENT; --=20 2.55.0.rc0.786.g65d90a0328-goog From nobody Sat Jun 20 07:01:37 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 C4E1B35200C for ; Thu, 18 Jun 2026 17:36:43 +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=1781804205; cv=none; b=ubniXNBQ/jUICUJHUn4nyStu/zob7Mnpvr5tOqDE8Y1rn/7UOZOWQrn3Z/3xXEjqhCYUFwjaHK5o+886c8Q7M2e4Tqzl1qh8k1Ym+sY5G6GC0eNPRYl6L8Psy9i9hamho+C0YQAmkqaSCn3cqbGstR0q1KMRQJ86hbt/hi7Wey0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781804205; c=relaxed/simple; bh=Y3sanpjKdCcYm+ZMDa/2RLR+quJCGnQ3tTczyoKyUhA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=NfilZdtWQKmMFeHIi7YHt0EXOK9lym2easWdjmC2IryCxUdEpfzP1Qka2UotuXXYoX/ojjWTT6jZ9u2OpbFxokh+yx9+jFnCjzGgi4HOCnsHM1sxwByLPE+ai8Hb3IGR1MhhEwh0H/I9l3H6TtcR/ZqElPJQbaoEC6gr023XmpA= 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=LnqTVVdd; 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="LnqTVVdd" Received: by mail-dl1-f73.google.com with SMTP id a92af1059eb24-138156c0492so4336197c88.1 for ; Thu, 18 Jun 2026 10:36:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1781804203; x=1782409003; 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=2HvIid687XPWlqwQBXwULFWBBKUy8bJsEI/wYE9guJc=; b=LnqTVVddIht/t+GrCK+8N0gmT/LyY79nc9w1mtsFLyWT3rNlDAX9UrqANXduRvXeRG X72FhBBNXA20T1AaWEFjKJGtSJQlp0G8HT5sCTHyhXQBSm92CAg9vFMQDSzUwA6/Edlt sDH74kFDC5QEXHfav46KomqiOct/DaCvv6uVyFnIi0nWu2IjqsVsFCqtfEFRsK/nrM/g +1fbN/Nx3SJFuaGTwZb9s6uLotbvD3AvcltYDZAcNbU9GcyXokp/plIfDwyZDmzgAsIE 7eYXCcS8z30oZx/m6yHjSiSFlkdgBydTVRvV9Hcm8WezszJ2lZMANP9s36shIUt2uS3h XDTA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781804203; x=1782409003; 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=2HvIid687XPWlqwQBXwULFWBBKUy8bJsEI/wYE9guJc=; b=pAqazePWMqRPqfZTRJzsTqnJHKBptnw37ppQ5JPn9mIULkigPsjCD9y+75qj6RJ6Y6 N/sq5VIUH9DZpsqhdeGNcR/Wh70+SCYsNoHu13jHsVVGr36Gz0SROg3HHArQ+PeL1NuM J1ifCp+DogLoVi3OhC4ofh9hhWalze16LgVnZW8buqxEE7JQz9HMLcTH6RrJhLC6+skR I4uC6WYqhj+C1W4MOKNwsxb7ZhDYC0rXACrEDstcOgno7G8xysgcxxzb3VZLzhwQbMoO xgtDqG0Y5GCOTCnBlKKo6U7wAomnw4SVVwOxNu1nle+LVHVnEqv+pLFjMVKSN9FGFyr6 0RNg== X-Forwarded-Encrypted: i=1; AFNElJ/tGOQKPmLWM8UnUQszS0nS5PstTsXu+OXCsQ8bU2Nh+vZ8zlSCc6tPcPDPYdluBpWMNryrwbIx6xmVTcA=@vger.kernel.org X-Gm-Message-State: AOJu0Yz6YcnZ2OUmOMI7BtEFmmfWl7okcFpN5a3vh7Jhmr0PO6OtsCnY gj1yhGovOmZp3o0AhdBeF2TKzVbiumoy0FLNF1exEmT+nQnNmufxmlGTxeGm9B2h21KIJmdezU9 z2Lst5TSQOnpnrCgbv6VessQRDhklL68QnA== X-Received: from dlbqd13.prod.google.com ([2002:a05:7023:b0d:b0:137:e7d3:1490]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:688a:b0:138:2f96:dc0d with SMTP id a92af1059eb24-139a20faaf9mr460012c88.9.1781804202465; Thu, 18 Jun 2026 10:36:42 -0700 (PDT) Date: Thu, 18 Jun 2026 17:36:33 +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.55.0.rc0.786.g65d90a0328-goog Message-ID: Subject: [PATCH v6 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 Acked-by: Suren Baghdasaryan --- 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 0de5fc180790..270f693b1822 100644 --- a/include/uapi/linux/alloc_tag.h +++ b/include/uapi/linux/alloc_tag.h @@ -31,6 +31,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 */ @@ -50,6 +52,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 @@ -59,6 +62,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 ad33d63ef7b4..32ac0674d8bf 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.55.0.rc0.786.g65d90a0328-goog From nobody Sat Jun 20 07:01:37 2026 Received: from mail-dl1-f74.google.com (mail-dl1-f74.google.com [74.125.82.74]) (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 C57CD3546C5 for ; Thu, 18 Jun 2026 17:36:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781804206; cv=none; b=PcxqgLob6GD8UPgZLCa9wyjWKVwshaJ8R6RJ+G3z6mYaSsCHEprNTdA1cqblqNxnMJcnXcGzJGVa2QlrOBPU83bB8J4qoKJrrM8t+xFbDsJemspSkucSDnxdwZXXbFc2LJMsa/Cssk7pEEAwEaaAwepc1ifc4vKk/mqAA9UWI4c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781804206; c=relaxed/simple; bh=G+/S/zBUNlacXIpXt9A+VSLEyCZDWOzWrppcM7qUM7Y=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Tpknpd06QVqm+qOyHWPAfxqSsFO6lLnf/C6o1mgDxmduErM/btSQffzhNwXKW331206ffwfeK17/Qru08KQ1Jo92g2TCUJRntIwxmWltq6DzRzZzAsdBq9+EjRQRwZ+aSM6niOfjpxc5dfSihfY7TEF2FipwVsVt3gq593HkSyM= 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=NjO0kF4C; arc=none smtp.client-ip=74.125.82.74 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="NjO0kF4C" Received: by mail-dl1-f74.google.com with SMTP id a92af1059eb24-13992d6a729so3337037c88.0 for ; Thu, 18 Jun 2026 10:36:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1781804204; x=1782409004; 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=SJ5dFOiSjPf9OrULYCjNPZvX3O6ck7gOoqkGo0Qh7k8=; b=NjO0kF4CjZclqwOfLNTN5k+NQ5+T6GhesIm5DnG0riE7616mcC53UliqK/YtkbdePH 4AgxXwGyxDMHBQr74VCiC/VMuQuaiBb8/t+OEsNro88k39oHBRH9UMIVGhhWKuO+CBMk HrgPuMudKy5a6TwZ0kxRlqeGHgamWoRX9lF4RGkYnOVF/tkLuYQE0d3aOTsEN/A954aG cAe31T7t+H0iAhSY6uDNI261wTOSRtM0pWmZNbA3xfmr/YVfingBPxuC2Fd6yhTA9jIl KPvjN8ZmTasCnk91Ktmk+lXIJnv8DRzKc5ya8bE4GH+mMj7YYPGfZXCycFPi4idGaEoF rPyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781804204; x=1782409004; 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=SJ5dFOiSjPf9OrULYCjNPZvX3O6ck7gOoqkGo0Qh7k8=; b=Vf38MAoRmF60CPGdZSoq0n8dQtGDbPwa7A4k3yBvAllaTAIf29RsY7jHyRP+cq4le4 fPlVmmd0tnVIrSRv8Yn9wRIECx8QuRIt+LuYnhUlrZ2gcTF4guVDDy3Cw44Yuy6uINDO e4J6v2EPPXhYwXIN3ajiXTw4gjjJ23+Ivt2nIK2hjqbU3yOCBSLvbNkPKwcwBJLs78Bj uN5HwZS+5FJTkMReZDrteB70prpWZXpxpwZ5tGjAi/+sJSey87J7u/BfHj2f62ss4LR4 Rstrxm067Mf13mIcHXV3WqBOXAmQz56egGnqOOAakESiGWEHqmA0wHAitcEYaKBTlu4S bfPA== X-Forwarded-Encrypted: i=1; AFNElJ9G+w7r7b0qyl7jpsQK//i0GWSoAczOLu5G6hTSlumCRHBBmSubh456XdDZZkbRI2qUFtOW9qpPs1bQ89U=@vger.kernel.org X-Gm-Message-State: AOJu0Ywn6y/TGypQ/zWTQYuhRwvXXTrEs5JfIUIi8zxMVDPwmYZJEVsR bYxA0t+9kM22z5sKG4Sf/9y19HDnJrWswQ6eNEgMYLQzR1J4JC6w+fzrG4lISSq9yRv+l2FiCwB UirsY8oIdwB9cJl6vKR5iNZdCVBQBI5Ax/g== X-Received: from dyer31.prod.google.com ([2002:a05:7300:231f:b0:304:2d1f:6ca6]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:911:b0:134:df7f:910d with SMTP id a92af1059eb24-139a2035fdemr476935c88.7.1781804203522; Thu, 18 Jun 2026 10:36:43 -0700 (PDT) Date: Thu, 18 Jun 2026 17:36:34 +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.55.0.rc0.786.g65d90a0328-goog Message-ID: <1d729195a8d11fadb1a1fb78c64633d46843ffe3.1781803482.git.abhishekbapat@google.com> Subject: [PATCH v6 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/Makefile | 1 + tools/testing/selftests/alloc_tag/Makefile | 9 + .../alloc_tag/allocinfo_ioctl_test.c | 335 ++++++++++++++++++ 4 files changed, 346 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/Makefile b/tools/testing/selftests/Mak= efile index 6e59b8f63e41..276a78c64736 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 TARGETS +=3D acct +TARGETS +=3D alloc_tag TARGETS +=3D alsa TARGETS +=3D amd-pstate TARGETS +=3D arm64 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..1ae0291f2245 --- /dev/null +++ b/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c @@ -0,0 +1,335 @@ +// 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 "../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) +{ + FILE *fp =3D fopen(ALLOCINFO_PROC, "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)); + } + fclose(fp); + return 0; +} + +static enum ioctl_ret get_filtered_ioctl_entries(struct allocinfo_tag_data= _vec *tags, + const struct allocinfo_filter *filter, + __u64 start_pos) +{ + int fd =3D open(ALLOCINFO_PROC, O_RDONLY); + + if (fd < 0) { + ksft_print_msg("Failed to open " ALLOCINFO_PROC " for IOCTL\n"); + return IOCTL_FAILURE; + } + + 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"); + status =3D IOCTL_FAILURE; + goto exit; + } + + 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"); + status =3D IOCTL_FAILURE; + goto exit; + } + 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"); + status =3D IOCTL_FAILURE; + goto exit; + } + + 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); + +exit: + close(fd); + return status; +} + +static int run_filter_test(const struct allocinfo_filter *filter) +{ + 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 exit; + } + + if (get_filtered_procfs_entries(procfs_entries, filter)) { + ksft_print_msg("Error retrieving entries from " ALLOCINFO_PROC "\n"); + ret =3D KSFT_SKIP; + 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, 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: + 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.55.0.rc0.786.g65d90a0328-goog From nobody Sat Jun 20 07:01:37 2026 Received: from mail-dl1-f74.google.com (mail-dl1-f74.google.com [74.125.82.74]) (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 B70F6351C0C for ; Thu, 18 Jun 2026 17:36:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781804207; cv=none; b=i0+dWn5M7K5BC04yV5ALJ04fIMPEp2a6rmsGbgi9PyMojIxM3h+RuyN3ikCgarWcz9l78pf8m2MF01h3HuJ3M5Cg/68liht9wsB+de8YdEplK0nHxUX9zoDjDxDzwH/Hg/YgMH8zSXQkZ+OBRaplWHyTwNWCAtwq0XLTqF1b3Q4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781804207; c=relaxed/simple; bh=di97Zc59fIt8ExMVeLUwFDZ7sLWY8hthB7JbwTh9eus=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=jWVPItPTR2dBhUGDspHblKkHfNi8IWjezdcLh7qLfJMrDRlm/JO/LnmceDPrJCRRsg//vuzOqIKhAPF0CljJRhCQfmDfiOy7UX3kknUtwkNSrGu8fjL3aRUR4Ytg9RNwTmF8p792G3Yx2TnjmOUM7JREPDsXFUvS2jKEN9AJIno= 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=gS4LehCx; arc=none smtp.client-ip=74.125.82.74 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="gS4LehCx" Received: by mail-dl1-f74.google.com with SMTP id a92af1059eb24-137f3465368so1912946c88.1 for ; Thu, 18 Jun 2026 10:36:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1781804205; x=1782409005; 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=/r4FYf30y6HeoEJoxw8dAX2UIKuxqRqzUodrZTJeu7U=; b=gS4LehCxPpXAGU/7jwCiVRN/pNWSLuDh6HN9ozi95Lkqds6Hl73L3efZDHsXmgAuvL Aoox3b5qFJf/YOn8SW/Flmmckmk+5U4m2qEouD7Pj8mVFl4dVYL95ACpaK4ukzh/TQoI k00UslOwhGgG/++555hYQiLxKIsbI7jkRivtoCrlDBGKl1XuiOpsNapPnccOwf1eItnS 3ifBkqQdUaLQ4PIVIicJL1DeKSvptj+HtEXFsMvaiZzDUWrOFTuXgWydgGWUco8msrw2 tOWhOhlZMqLMQAF0Bns5s+W7ZUucP8HnYkDbia0/gVB9ZLhHp1I6C2ftw4ZCxvzBiJzf CKKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781804205; x=1782409005; 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=/r4FYf30y6HeoEJoxw8dAX2UIKuxqRqzUodrZTJeu7U=; b=ruozA2hxzwK0lU57K6u/cUdeFEBIofegEaoUGRUhjCQyn9bzqWsCi4za0KOnjQOV5y 4AM3e7fJdnX9cSTuKVJ5E2aa6Hq51oYsTXsee6MdjaKqPKfnp3IZMSIxAfmFfQ4mJL9K s4sk9gIuW5bx4LkKmUm4JitIfz6/EZQu9LpS1RRdQQQX7r0xcx/4Lnsgay2lkwcFddta 0NGNgHLUSCu2T90l3bhi4wYb2QbFjQ2Ft8z1cGzwC8yCIHSwbjtP1LvxBLTHSsxDIMjV TfDsLphrXT4UOkhoxJm5cCfZEvCDSeiTWas9Eoiiw2WpYCK+asKGGtsrNu+qSDwW8xw4 JpNg== X-Forwarded-Encrypted: i=1; AFNElJ/zYKNCP8yqC/qu43iKmm+sD3hzbE1NTPWX4iRarq7hPTWrNbfD9sQlecEO8lBFR9qZDbWH/ezInmtKZFo=@vger.kernel.org X-Gm-Message-State: AOJu0YwzU6mKiRMruePtafdXxsacD/1WRlWAPA3DxpRi8Odm1pm6jh8V dumsfNYCD74Er0XVZkOOpF9KOo5B5fj0qTFdMrFYR8Ip3jkJs63fWj9dbfsHc/hseEwifNv+8kP YK9oKnwXzDvs7b9H9R5IC8Rb7OLzBQ43uTA== X-Received: from dlbvv27.prod.google.com ([2002:a05:7022:5f1b:b0:137:ee55:b187]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:488:b0:139:879c:dba1 with SMTP id a92af1059eb24-139a202ec4amr496602c88.5.1781804204535; Thu, 18 Jun 2026 10:36:44 -0700 (PDT) Date: Thu, 18 Jun 2026 17:36:35 +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.55.0.rc0.786.g65d90a0328-goog Message-ID: <5a485adaa95f8bdce7d29ddab30238b34e949f28.1781803482.git.abhishekbapat@google.com> Subject: [PATCH v6 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 | 198 +++++++++++++++++- 1 file changed, 197 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 1ae0291f2245..50755a45d3fe 100644 --- a/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c +++ b/tools/testing/selftests/alloc_tag/allocinfo_ioctl_test.c @@ -5,6 +5,7 @@ * Copyright (C) 2026 Google, Inc. */ =20 +#include #include #include #include @@ -313,11 +314,194 @@ 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_print_msg("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)) { + 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; + } else if (start_cont_id.id !=3D end_cont_id.id) { + ksft_print_msg("Failed to match content_ids for procfs and IOCTL, skippi= ng...\n"); + ret =3D KSFT_SKIP; + } + +exit: + close(fd); +freemem: + free(tags); + free(procfs_entries); + return ret; +} + +static int test_lineno_filter(void) +{ + 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 exit; + } + + memset(&filter, 0, sizeof(filter)); + + if (get_filtered_procfs_entries(procfs_entries, &filter)) { + 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, 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: + 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) @@ -331,5 +515,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.55.0.rc0.786.g65d90a0328-goog