From nobody Sun May 24 20:33:02 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 A28053655F3 for ; Fri, 22 May 2026 17:45:48 +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=1779471950; cv=none; b=CXmzWzyAuWQ1z+IZzewQGBAJ2BaXwtRmir1FV40VhnAiYeXmSUCQDTnU5PJjBRnuC/B4IBmopyX+1HmSyiFFmwWplNfCUL8j90TQOJPjhkED9X2o8Dp+QCrMBp3Fl1L43C6DPBNmyW98+NKSah0DsMRgkjr0O6TtLkfRkpKsmik= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779471950; c=relaxed/simple; bh=4bUm2orcz2NN7K2IhDDBDyFNHYWvh/IXH3yg7ky+Ea8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=sDoCgZ+g7PS5Z4gteDxrUrKn15yFJ5+ZifVvU01HnObJTNuELcLYBYy0fTHGFLuoGKrLBzmI1jENChFyd4rZ5dzeacOFrhVi8OTpwKBfAVpo4YPICu2N5FqWoI/BZVcRMC9RjnvPf69/3M4U5BOq+chGV7OPQMci2VM9teIAcAk= 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=GTdTVA5H; 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="GTdTVA5H" Received: by mail-dy1-f201.google.com with SMTP id 5a478bee46e88-303b38ec2f6so11063988eec.0 for ; Fri, 22 May 2026 10:45:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1779471948; x=1780076748; 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=+tXuuAhgXpxxwMsr1wnQWACrH8a9haKBpqgpQfYI6/w=; b=GTdTVA5HhUwYReJs35/7NPVbTQFPbg5/nItYvG+R4VcqG9JQzhO1jyaFynG1/2Wjp6 2x/Lnjo9GpsVAhnva/ELWAZIwpEahhXr1AFF3wYWfAwWMY2J3rvnC+lfIvB5SWsd0o5g MrZh184Z5/5J65y0GhXyhcZYutBfDA5KPljbr7gNS1YQO9UgUkMn22duZLel+o60KzeW MYRhrJF8DOnuWEGi6D7f0uxSE9/M9+ZI32LMtvYej4jcnlRjY/QJeFMGuJanLKmrhS1A 30BIZlqk531LCbLviSpmypilEzSpmZm8ffNDFsnyzYQ+LFr2s1UK+GaneUtsqVgKY6RS i2aw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779471948; x=1780076748; 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=+tXuuAhgXpxxwMsr1wnQWACrH8a9haKBpqgpQfYI6/w=; b=bCd0MuRM8OJp8Z5/CloBDEPK83+HGcV1wrlxqaMsNL9eea3mtM5FCnkjEq+f3EPZ85 kJUyK/DiXKzd906TAuYbhYJEFvOhcuoCPLoIZl8z/nz9dJCWSnspVzcicnbJ7DhI+ayL s4KEK8IgGdnaIwRQ8jsN5+i6KE7ndREBcuKmdkp1E8u6M9+owKb6o0KZDW79A5mNNHRm KY1YseUW8hwaIMyPoINVsOYyWPBVM5v1kSX2mExv3jzOUeUOwsDUmCzxfVUxk6k9j7ty vZHxNRmIYTfRAA175EjOJWAfJHPSrNgQxmufziGOP+FQzHbJ1MAjwOTX7g/sXlBuiZS1 lfnA== X-Forwarded-Encrypted: i=1; AFNElJ/0V/YHGeW2m4YrLPK4gp0/tVreA67YnRIwoRnBr79qTiu1I1Ro9Q+mor/UOGuOL2MNC90ED5Jir3k+2HE=@vger.kernel.org X-Gm-Message-State: AOJu0YzQYUlHoLmFQgFxgCNkRAHV1G65EjAvMl4VgiCwHoGb3Fxwaa6z Vc9ZFibETm1kGlwxlXfYnyO3qnpS3bSJgamI3te67/CQf6EpzSPHDTeD9+CtTeXWYQu9xclNEDf 8g6ct4u8mOMv7mTSBN2GFuJyGP8cBCdo+ew== X-Received: from dyw1.prod.google.com ([2002:a05:7300:8801:b0:302:542a:8cad]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7301:1f0a:b0:2de:cc07:e83 with SMTP id 5a478bee46e88-304490d3d01mr2242275eec.15.1779471947395; Fri, 22 May 2026 10:45:47 -0700 (PDT) Date: Fri, 22 May 2026 17:45: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.54.0.746.g67dd491aae-goog Message-ID: <8ffa0cef49b10026f2171d41b963c39201c9bd5b.1779471082.git.abhishekbapat@google.com> Subject: [PATCH v2 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 --- .../userspace-api/ioctl/ioctl-number.rst | 2 + MAINTAINERS | 1 + include/linux/codetag.h | 1 + include/uapi/linux/alloc_tag.h | 54 +++++ lib/alloc_tag.c | 193 +++++++++++++++++- lib/codetag.c | 11 + 6 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 include/uapi/linux/alloc_tag.h 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 46ed0f0e76d8..d176bde8fbfc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16709,6 +16709,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 8ea2a5f7c98a..2bcd4e7c809e 100644 --- a/include/linux/codetag.h +++ b/include/linux/codetag.h @@ -76,6 +76,7 @@ struct codetag_iterator { =20 void codetag_lock_module_list(struct codetag_type *cttype, bool lock); bool codetag_trylock_module_list(struct codetag_type *cttype); +unsigned long codetag_get_content_id(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..e9a5b55fcc7a --- /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; +}; + +struct allocinfo_counter { + __u64 bytes; + __u64 calls; + __u8 accurate; + __u8 pad[7]; /* Add alignment to not break the 32-bit compatible interfac= e */ +}; + +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 b9ca95d1f506..3598735b6c93 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)) @@ -46,6 +48,10 @@ int alloc_tag_ref_offs; struct allocinfo_private { struct codetag_iterator 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) @@ -125,6 +131,190 @@ static const struct seq_operations allocinfo_seq_op = =3D { .show =3D allocinfo_show, }; =20 +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; +} + +static int allocinfo_release(struct inode *inode, struct file *file) +{ + return seq_release_private(inode, file); +} + +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(dest, allocinfo_str(src), ALLOCINFO_STR_SIZE); +} + +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); +} + +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, true); + params.id =3D codetag_get_content_id(alloc_tag_cttype); + codetag_lock_module_list(alloc_tag_cttype, false); + if (copy_to_user(arg, ¶ms, sizeof(params))) + return -EFAULT; + + return 0; +} + +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 (struct allocinfo_private *)m->private; + pos =3D params.pos; + + mutex_lock(&priv->ioctl_lock); + codetag_lock_module_list(alloc_tag_cttype, true); + + /* 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_lock_module_list(alloc_tag_cttype, false); + mutex_unlock(&priv->ioctl_lock); + + if (!ct) + return -ENOENT; + + if (copy_to_user(arg, ¶ms, sizeof(params))) + return -EFAULT; + + return 0; +} + +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 =3D {0}; + int ret =3D 0; + + priv =3D (struct allocinfo_private *)m->private; + + mutex_lock(&priv->ioctl_lock); + codetag_lock_module_list(alloc_tag_cttype, true); + + 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_lock_module_list(alloc_tag_cttype, false); + mutex_unlock(&priv->ioctl_lock); + + if (ret =3D=3D 0) { + if (copy_to_user(arg, ¶ms, sizeof(params))) + return -EFAULT; + } + return ret; +} + +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; @@ -989,8 +1179,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 304667897ad4..93aa30991563 100644 --- a/lib/codetag.c +++ b/lib/codetag.c @@ -48,6 +48,17 @@ bool codetag_trylock_module_list(struct codetag_type *ct= type) return down_read_trylock(&cttype->mod_lock) !=3D 0; } =20 +unsigned long codetag_get_content_id(struct codetag_type *cttype) +{ + lockdep_assert_held(&cttype->mod_lock); + + /* + * next_mod_seq is updated on every load, so can be used to identify + * content changes. + */ + return cttype->next_mod_seq; +} + struct codetag_iterator codetag_get_ct_iter(struct codetag_type *cttype) { struct codetag_iterator iter =3D { --=20 2.54.0.746.g67dd491aae-goog From nobody Sun May 24 20:33:02 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 85EE2367287 for ; Fri, 22 May 2026 17:45:49 +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=1779471951; cv=none; b=lxUAFCNQE/z6aS4FQ/nDTXWWU0rWkE0+f5fG2FWHP+NrArN1iv0euNqhfleVhnO9tnT3tuwEphXtQOmC+Fzf7Y9K/uFkXfJqjjGSmAG4UnqZsKjAKKIy8xdIGDShiAZiFWT7uZ0RdAfnqYb10TJI6yj+pptZpRI0T+QMY62SHFg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779471951; c=relaxed/simple; bh=u272ECOiUuYXoSauc1/mPi1P5NrYx29FhZNXkFrNXso=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=lIcatKOTdJPNASTm+f/9LvByAcQgzlGk3P1r5T0hHvVTta04RpN5z0LnOVx5+b2BbjWTN3yEfdkT02u0qfDeKDosnrUsI4GcU4tcn4iipu+8Qc07ax6LXYXmGJyzEz7f9vuME9G+7xVSd3wM4M1Z5+6IEMUoiyaQLUYTB4a8pIc= 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=kpwlcvI1; 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="kpwlcvI1" Received: by mail-dy1-f202.google.com with SMTP id 5a478bee46e88-2f2d983d109so3541963eec.0 for ; Fri, 22 May 2026 10:45:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1779471948; x=1780076748; 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=/jYkf4xPE5NaHstf7F4psma2bVLV13GjTGY2UjXb0AI=; b=kpwlcvI1qVPnJofcxcyTjzcGt8FkkXPcdI+sRd3zE5Whpt3imGUKqBBlSJUs76UASD XkUhTMRoEhsqRykQ0DUE82huhiUsVeTvCGdLeYogKSZ706fls/VfRZHN2ysPD6GMEFmr Z9o1iDHOFD+z2L6MNF9aWF/eC3Vl6kgrd2wYRTDEFvQaQcGT1wjDBPNncklVxnkY7SRT qqZFq8fwAZU9uJk0UqtfcAe82++m7de2Ju7KYiAzMEU1MXag1XXT7k72um2wqugRH/rh 3XcxhIstj47WMHui1VUj8CWCM+j2EvOx6Y+z8CQLHmDkLn0runfQtaBY+fdN95T28rwW ZxPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779471948; x=1780076748; 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=/jYkf4xPE5NaHstf7F4psma2bVLV13GjTGY2UjXb0AI=; b=Tju5fnh+B2uoNLnc0c/UhIRVquRB/VqhFiNTZPkiVMBwIPbThVxUKvsLmVq2nwlapf Oi4Wnc8OWxLRKafIU3UkfMCe3PVD+ail8bHCLJ0g5ycRPd9iAdwjJk7SiPZCVtQ2LMXo kTMZ9F+tj5+CVwmpWGVDaXxu48BWuHO46uIsAm6o1J79fcKowz6LxluIYWjA4r8hAPhj n22Ixn014eJwxzLPxM3UKmTEtPSegleg6N5Lef7giGcu00BQcUiRRRnsAxnynwY/1U1t vtN3tS5qaw7m8xOgoXyiaSXClxGd8ZnwEkds1dwI8g+6uC46AHm0x0fBm3d41B7RVW8J MSng== X-Forwarded-Encrypted: i=1; AFNElJ+rWQZMhqL0TWwsjBIr1syBEgzr6rooa++DOLUNGm936Mgwt055RQ9AvCVLDxi4Y07Aa7PhK9YNDF5/Jq0=@vger.kernel.org X-Gm-Message-State: AOJu0YzwyhcX5BxzAW0i7nu+R/2Gz9ghdg6BiLpGba/a52AcHziaXjmz CVn1Zeqkj3cCwA9Piigm1IG7yAuVgBVlth6ZWphO5semKjh59dxa+M1lZoZsD9D8C6S5n3PatY+ me+vG3PWvhaVjL3nMzooNKn+c+xhzRu4NEw== X-Received: from dykh11.prod.google.com ([2002:a05:7300:570b:b0:2f9:af7:504e]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:693c:2c8b:b0:304:67:ba1c with SMTP id 5a478bee46e88-30448ffd0f3mr2906032eec.6.1779471948351; Fri, 22 May 2026 10:45:48 -0700 (PDT) Date: Fri, 22 May 2026 17:45: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.54.0.746.g67dd491aae-goog Message-ID: Subject: [PATCH v2 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 --- include/uapi/linux/alloc_tag.h | 26 ++++++++++++++- lib/alloc_tag.c | 58 ++++++++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h index e9a5b55fcc7a..0cc9db5298c6 100644 --- a/include/uapi/linux/alloc_tag.h +++ b/include/uapi/linux/alloc_tag.h @@ -34,8 +34,32 @@ struct allocinfo_tag_data { struct allocinfo_counter counter; }; =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 3598735b6c93..56c394ef721f 100644 --- a/lib/alloc_tag.c +++ b/lib/alloc_tag.c @@ -48,6 +48,7 @@ int alloc_tag_ref_offs; struct allocinfo_private { struct codetag_iterator iter; bool print_header; + struct allocinfo_filter filter; /* ioctl uses a separate iterator not to interfere with reads */ struct codetag_iterator ioctl_iter; bool positioned; /* seq_open_private() sets to 0 */ @@ -167,6 +168,11 @@ static void allocinfo_copy_str(char *dest, const char = *src) strscpy(dest, allocinfo_str(src), ALLOCINFO_STR_SIZE); } =20 +static int allocinfo_cmp_str(const char *str, const char *template) +{ + return strncmp(allocinfo_str(str), template, ALLOCINFO_STR_SIZE); +} + static void allocinfo_to_params(struct codetag *ct, struct allocinfo_tag_data *data) { @@ -198,27 +204,71 @@ static int allocinfo_ioctl_get_content_id(struct seq_= file *m, void __user *arg) return 0; } =20 +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) { + if (!ct->modname) + return false; + 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; +} + 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 (struct allocinfo_private *)m->private; - pos =3D params.pos; + + skip_count =3D params.pos; =20 mutex_lock(&priv->ioctl_lock); codetag_lock_module_list(alloc_tag_cttype, true); =20 + 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; @@ -254,6 +304,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.746.g67dd491aae-goog From nobody Sun May 24 20:33:02 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 7536535677C for ; Fri, 22 May 2026 17:45:50 +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=1779471953; cv=none; b=LvFQhCnmpHhl0Z3P8n70+bX+TIKfIT1+Bl2pOFpzMBFH7IFwWB38DWJoxJEgfXTjnXRmGfQQqvCnH/097XKkU+vy29Nc6jhqdOd6FShOLDqCJx/14f5m817i/2PzipvrOKwdqmJXdvNrDMzMUsD4WH16dlN2AkBmm3kjjhpiRWg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779471953; c=relaxed/simple; bh=qti+yLFgmQzV95XINCYKK/2p+6Pek0xhYmrbzM7Zicw=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=nNPGOs7O44vNLNxW6KKfDYDn0c+VPQ3N7PTUO1/IlqNuvCU2eFXJyBXmSM4nQugK53r6KIY4dugrsq+mNiS92UgzeDKm9f4cZJEBxit22EzAiyW0Bf5EjgFOfKW1rcYfV4Ap1jDbBHmL9GwT53EuN0hKYiQ5d/zcvx2k6N+1iZo= 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=JMHtqxJ4; 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="JMHtqxJ4" Received: by mail-dy1-f201.google.com with SMTP id 5a478bee46e88-2fded513994so6381946eec.1 for ; Fri, 22 May 2026 10:45:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1779471949; x=1780076749; 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=m+ziR3ir5mA6/jcqBzHRUrW8UazgUIvdAYJekJ5g/uA=; b=JMHtqxJ40WB7eDRcKJrkoYMb7/2+7cfTaB5vpHrBgNduMUeDdcGIbw4qfftB3vBrmj Ub9C1deYcFNqokn7myw5dAmWukqB4cRJCmo0jmAASRFZNLMxc3iCM9TwMDOi2K1Mbqjj cJhe39AIjNTne1Ey7RUarct4T+8COStuakLOcD7bsljfMpXt1G4amNZQ1Ib9gchXZdqR UvIuXLNdP4rxGU4GH/2yNVxAcLOjvWBsvjRM6tuGRvhrQtdXYdsIHjYn658HPD9TFDAR yuYANbb1NDTro1Hu2riDlvRVIGvgBATMEUYkbkSO61admxrJQMLywPqaciSmNKhsOwcq Su5Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779471949; x=1780076749; 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=m+ziR3ir5mA6/jcqBzHRUrW8UazgUIvdAYJekJ5g/uA=; b=YoCzHaDtmmoC1pAsojy0k7Cww9Xq5UZkO3dKPh0rgzwKffzDye+tYvqKdqllFEb/3W 4oDbKSn8hpWuPCvhI5GAa01Zq7mVjOtkOIwwFW+s1LnmgWxQv/APx6JC3p0k+DV7fylB DATf/abmb8bybcOXlK1BN12vnFxd7TYWxjUm9JJlLFrhA+dxqI2VYJumHDVvSnzZfpXa MGecGXb6YJVu3bvRoW1ODqzJazTAwA6kv9C24RzuQZrmBQu4GUBDeJXvQr7DiYExev+P yaem5zVUdOFKjC6QnvknHNWo4FCXjA996cDsbHbLOp4Nzcz2/QRa/l9BOsgSeChxIz3m 81Rw== X-Forwarded-Encrypted: i=1; AFNElJ/zMVTmjh+mVu1vkv7d8Y9gdTkXbqrwONxrADIcTLhrPVWJolXC27v8sjiiG3vvciN6wmUQLx/KTy9w5LA=@vger.kernel.org X-Gm-Message-State: AOJu0YzjDVVkrkrlP9irHoe4Y+pOpCu5h3Vd4xemQQEo6KwqIoXvMI5X r6qFWVKrCpIbi3fhNsCLq4x1rC6LXCt6j3N1DLEMwNCH+yEXne4QSf25Mc61W28VrszY8RQYMur OtAgUO36ExZHbYJbfRhhdNyxiawuLm9oaiQ== X-Received: from dyox40.prod.google.com ([2002:a05:7300:7fa8:b0:303:9ed8:4d8a]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7301:6446:b0:2f2:8857:1804 with SMTP id 5a478bee46e88-3044905b3ecmr2504647eec.9.1779471949234; Fri, 22 May 2026 10:45:49 -0700 (PDT) Date: Fri, 22 May 2026 17:45: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.54.0.746.g67dd491aae-goog Message-ID: Subject: [PATCH v2 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 | 72 ++++++++++++++++++++++++++++------ 2 files changed, 68 insertions(+), 12 deletions(-) diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h index 0cc9db5298c6..45f158bee0a6 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 56c394ef721f..6c8743eead2d 100644 --- a/lib/alloc_tag.c +++ b/lib/alloc_tag.c @@ -173,11 +173,21 @@ static int allocinfo_cmp_str(const char *str, const c= har *template) return strncmp(allocinfo_str(str), template, ALLOCINFO_STR_SIZE); } =20 +static inline struct alloc_tag_counters allocinfo_prefetch_counters(struct= codetag *ct) +{ + return alloc_tag_read(ct_to_alloc_tag(ct)); +} + 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); @@ -186,9 +196,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 static int allocinfo_ioctl_get_content_id(struct seq_file *m, void __user = *arg) @@ -204,7 +214,8 @@ static int allocinfo_ioctl_get_content_id(struct seq_fi= le *m, void __user *arg) return 0; } =20 -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) { if (!filter || !filter->mask) return true; @@ -228,6 +239,17 @@ 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) || + (filter->mask & ALLOCINFO_FILTER_MASK_MAX_SIZE)) { + /* We assume counters is not NULL here as per caller logic */ + 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 @@ -237,6 +259,9 @@ 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; + bool sizes_set; + struct alloc_tag_counters counters; + struct alloc_tag_counters *counters_ptr =3D NULL; =20 if (copy_from_user(¶ms, arg, sizeof(params))) return -EFAULT; @@ -244,9 +269,16 @@ 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 (struct allocinfo_private *)m->private; =20 skip_count =3D params.pos; + sizes_set =3D (params.filter.mask & + (ALLOCINFO_FILTER_MASK_MIN_SIZE | ALLOCINFO_FILTER_MASK_MAX_SIZE)); =20 mutex_lock(&priv->ioctl_lock); codetag_lock_module_list(alloc_tag_cttype, true); @@ -261,7 +293,11 @@ static int allocinfo_ioctl_get_at(struct seq_file *m, = void __user *arg) ct =3D codetag_next_ct(&priv->ioctl_iter); =20 while (ct) { - if (matches_filter(ct, &priv->filter)) { + if (sizes_set) { + counters =3D allocinfo_prefetch_counters(ct); + counters_ptr =3D &counters; + } + if (matches_filter(ct, &priv->filter, counters_ptr)) { if (skip_count =3D=3D 0) break; skip_count--; @@ -270,7 +306,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, counters_ptr); priv->positioned =3D true; } =20 @@ -292,9 +328,15 @@ static int allocinfo_ioctl_get_next(struct seq_file *m= , void __user *arg) struct codetag *ct; struct allocinfo_tag_data params =3D {0}; int ret =3D 0; + bool sizes_set; + struct alloc_tag_counters counters; + struct alloc_tag_counters *counters_ptr =3D NULL; =20 priv =3D (struct allocinfo_private *)m->private; =20 + sizes_set =3D (priv->filter.mask & + (ALLOCINFO_FILTER_MASK_MIN_SIZE | ALLOCINFO_FILTER_MASK_MAX_SIZE)); + mutex_lock(&priv->ioctl_lock); codetag_lock_module_list(alloc_tag_cttype, true); =20 @@ -304,10 +346,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) { + if (sizes_set) { + counters =3D allocinfo_prefetch_counters(ct); + counters_ptr =3D &counters; + } + if (matches_filter(ct, &priv->filter, counters_ptr)) + break; ct =3D codetag_next_ct(&priv->ioctl_iter); + } + if (ct) - allocinfo_to_params(ct, ¶ms); + allocinfo_to_params(ct, ¶ms, counters_ptr); =20 if (!ct) { priv->positioned =3D false; --=20 2.54.0.746.g67dd491aae-goog From nobody Sun May 24 20:33:02 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 85FFC360EE9 for ; Fri, 22 May 2026 17:45:51 +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=1779471953; cv=none; b=ZX7MYErlNGVA8rLlfV1cPu1L3wCywIo5xVji2LaaYJGIXICp/pmF8grjA2bCnPAtYkaBE9NvAfWzB03KCIFSbyBJOaWWjSFyqjwQrZ05nccXMYgkSShPYAMyQnhVPpNxvxoHk97F3v3EB+/B7TsSDvpyxixGCpMw3OO4SCyyMFY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779471953; c=relaxed/simple; bh=aKZ5bfhVwmK5K+spCgfndMhC/1ExC+Zsl0CevB+/mtQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=PYc1sX1s4jdr1rV2tMkgd4Ly62jGK5fhzeSvqoUvvGq/9093Fly3A8D+XCb88/Eu57qbd/zMLxpTrM1P6xeLM59mka79lA/oYiBrFiThaW1FwH39/jblx5p81fe3v4wWmAFWt+BGOOg4mo/NboQUKc6/92bxtONr7jHea1y89Ic= 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=grG8ABz9; 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="grG8ABz9" Received: by mail-dy1-f202.google.com with SMTP id 5a478bee46e88-2ee5b73c5f2so8476380eec.0 for ; Fri, 22 May 2026 10:45:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1779471950; x=1780076750; 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=mYiP6dsX2SKN5nuRcokWCB8bypHWDNwNiF3PrVV8B9k=; b=grG8ABz9AyqeeegmmeY9M3Dw7UtQkYLOIBq1mEhOPDHDLn5FgcApObu2M0RMGtyP2J pxQNuxII3dX6koTpHKIMO8Y+GiSxPNjNnXzFC3KREaRgVkC7BBgYQTiSl0cqAPfhI8jp GK6hmDXwr3ag2sDp2JpTfj7uggYIdpqLyYHe+cgze4IsF0jRoiKGVImMGrQzfP/Vh5CI RdpRJ08tkBoD0yi8i6FJhjDUkOA+UJ4uwrM4UzGl1bcxh9sRLdisF0fz1AjwHP+8XnsN /aU7uWusvBEGRVbJXmQaX2L/ShgVz8OMeyAlxevbvylum3ROhjMzU4uwjLIYQL2ZZvmm iVOw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779471950; x=1780076750; 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=mYiP6dsX2SKN5nuRcokWCB8bypHWDNwNiF3PrVV8B9k=; b=ZNEKyirk30j/ell8+yFDIlmEEns4nxhE53ONMlfmBzYCkAQex8uHtyK3tcPmsSIaC8 UxHLNKITEYlmLNZMzlbEPfqp90Qpe6PzSNiwCL+CiEVgMgfYDREX683Uo6D6UGGPeuPH sSn/zrvDpfCQ55/W6yfAYAwRwWoJ83xCy70IRx+KUhotMFe8XmjQl2IPXIQZNpkGrEAg JsqeS5TMAgvOFsrNU6AeJURYBfyBAjsYALUEW2q/FFZQNiAQYJL6C2ukbwNB9WjYsZjY iEnCN3i9r31DjhfrPxKrArlNNrqIgzcr4nof8L3KNq+e0S/OnJigyiLvCKw7aE9eKKP7 Hpag== X-Forwarded-Encrypted: i=1; AFNElJ9LUUN5trSJqYjmn/yRHvv8BgGvppFMw6aw2dfS3Qt6PGImnqTclIngL7da8aZtOBbrSvs7Htcga+81TGE=@vger.kernel.org X-Gm-Message-State: AOJu0YwE2rCZ9mZx/XIWCGuzdJPoadao7PbFaQHeAadDWRZ1yD+mIvgh 35DuSxq3YI0wrhU+UqArcmAtoA8mGTEb+wkMsTUSHJ9ELq+z1amR/4Ue4lFAJ18kQMW0TNHuHn4 TMDhiFFy1lSvk7g5uKxEc1DnWyg49JKslwg== X-Received: from dybgn40.prod.google.com ([2002:a05:7301:2528:b0:303:971a:154d]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:693c:2c0c:b0:2da:b77a:d7a0 with SMTP id 5a478bee46e88-30448ff25bamr2480409eec.9.1779471950175; Fri, 22 May 2026 10:45:50 -0700 (PDT) Date: Fri, 22 May 2026 17:45:36 +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.746.g67dd491aae-goog Message-ID: <453a36b27b33b01aabf1d7d020bbbcb4acb3e12d.1779471082.git.abhishekbapat@google.com> Subject: [PATCH v2 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 45f158bee0a6..6c4c0e609cd9 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 struct allocinfo_counter { @@ -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 6c8743eead2d..b1fc14eed7f2 100644 --- a/lib/alloc_tag.c +++ b/lib/alloc_tag.c @@ -217,6 +217,8 @@ static int allocinfo_ioctl_get_content_id(struct seq_fi= le *m, void __user *arg) static bool matches_filter(struct codetag *ct, struct allocinfo_filter *fi= lter, struct alloc_tag_counters *counters) { + bool inaccurate; + if (!filter || !filter->mask) return true; =20 @@ -239,6 +241,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) || (filter->mask & ALLOCINFO_FILTER_MASK_MAX_SIZE)) { /* We assume counters is not NULL here as per caller logic */ --=20 2.54.0.746.g67dd491aae-goog From nobody Sun May 24 20:33:02 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 206BC3655FF for ; Fri, 22 May 2026 17:45:52 +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=1779471954; cv=none; b=QgtUjp5JnoB8bvHhouoNohfdDtFYJhjQon3x3sv/wrj9/T0GtNmYrJz9RQhodjPFhesMPkIGNuySH0ZA1CU4IDq4P8gf5IWfZjy4B6TZccnP5SLv5R9A5rmdr/Cc2RWN97m2a+YdYHYeokpV1Ez4uiMORwd7tRbTst5oKm+egcE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779471954; c=relaxed/simple; bh=7oos82HsrLgERa77uFE57n8dvWONg7rFAuPeAZBXIJY=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=uwC2Ir1g7E0uFRqcdtMprqgVzpcfsyFBbSFtjzLOcPSD2ZDZY5obj/iy/FvIcy9QcPj2ZP/H8HiT2UPavuL2sJsS6ulJIRRTLMD5U61SE63KP3PX9gRYUo+36CI6bM2d7wJ1PgDIdYDsOaQULN194QN3GKKwzYYAFrMHWXda1rA= 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=j1rYEw/M; 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="j1rYEw/M" Received: by mail-dy1-f202.google.com with SMTP id 5a478bee46e88-2f5943ca81aso28034236eec.0 for ; Fri, 22 May 2026 10:45:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1779471951; x=1780076751; 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=pnHehlpVxhvjKQsbhhQoILWStBVOI+qC0gTD8ncby9A=; b=j1rYEw/MI++wEMnCeLFjGNf8vvrfNTKENdlzjegOckAWhAbqCTHJKDfw6Ih8NhjlD8 oYJmZiiRVSx1uXXIZIfn4PhLD9LcVhR8sG+6l9d4SvodFRWwK0bj1SVctVYr3ja1/qhW rjsTNstBpDXTLJm25gMEe2Z59/xQoMtC7TJWWWzqYaJoqI7l6XsaFwP+oAwd17n331Q+ JBgLaKDAHYARKNE3LfyCklWLgRospzD9kLcjeMNKID5GOTAONSBCVAhJVL0TK6eFpBqe vZ5QmwWcySGpnuix8A0GctAa7/3apGiJTEj2x8aiK7rebCjH/DFxsmKvSl17A+L1fWcv HCpg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779471951; x=1780076751; 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=pnHehlpVxhvjKQsbhhQoILWStBVOI+qC0gTD8ncby9A=; b=HcZ5w2nsUh47r3CNFuZXWTrC1PFPwTnwR3OTgBxeL5L/5tYUSXDDIzrPUE7M3PpcLW 7LtxPcuG8/tFIRUGgvEAik6aPc+O/iWXr4JdeMAvXtCCuT79BCJiD+EBPNvtYfG4AsoL SpwsqzhOVzWCC4HsR1YwJHh+guGrSFojddTd8M6BtmNg0dNq7Vf22jjzbhJu9P1HWTzC Hh67DZzga8O+CtltHJcibpStI7UeuH9b+OlcIDAYeuF1/D+9qJvteu9ABM24CN113lEn ja8YiweQFh0cY7b4JfEAVEH+O4EYH/y1QyJDoTjJeDVNFaABs7A+exCHwJdNwEI2InXU PnlA== X-Forwarded-Encrypted: i=1; AFNElJ8yVoKeLi9SM0OcBLR/iJQ9iEyTnrKpGOWBbTahhkO+TMvSi9Iuz4nVgmiykTNCzodYcjT7npPscojwY/I=@vger.kernel.org X-Gm-Message-State: AOJu0YynjikQOJ2nbZw/b4UR0+wFyPWJKMCJ2xvrJllt/6Ju2Quz69wn nq2NKN+EXffsCbM4TN1lIkQmuymvOlGYb/6DgNDCkIL80TUX7wu8erX1s4l8q33iVkc9pR1tyIe z3wzga6yPVL/32VyPeA76WX0i5hpnFvV4oA== X-Received: from dyab3.prod.google.com ([2002:a05:693c:8303:b0:2ee:de47:cde3]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:ef83:b0:2f2:b544:2fd4 with SMTP id 5a478bee46e88-30449201503mr2426796eec.34.1779471951108; Fri, 22 May 2026 10:45:51 -0700 (PDT) Date: Fri, 22 May 2026 17:45:37 +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.746.g67dd491aae-goog Message-ID: <67aaeca4f720b13e84d89fdffcf96a2a66507dc0.1779471082.git.abhishekbapat@google.com> Subject: [PATCH v2 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 d176bde8fbfc..6d57ab4dfb8f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16711,6 +16711,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.746.g67dd491aae-goog From nobody Sun May 24 20:33:02 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 EAF1F34E771 for ; Fri, 22 May 2026 17:45:52 +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=1779471956; cv=none; b=REM0t97TMq0umBJospse8XPTUKqGGkzh3OelOlvw/4vzAMFMkim4+s7yOhHr19MGL+eSxB4si+5JjoXPHtr7cVsGSVal+HVRWat80Kjn6C+8vFM8p/0kfL4bYsORGiDu3boKUFv3HmLXCqHJPGaL9KX4wBBESnb4nXY6m7AW3s8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779471956; c=relaxed/simple; bh=JB4Hu76wjr0YkVBEWWP5py228goBaZacP8xfyeQFG8A=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=ZVpY8tgynggjLNmRrE7wC5W7PvDlO1miW1WPGJbMFQ5RYWqSQT3z3CCrGIqBx2gQjQ8vFayfemTHrbQX+cW/jGGiMHGwRFAFT9d6tUNQQuauLUnUYqhjsLcDXksXnwE8nrilmCYkUJ1teH63GSnRi9OfnT0hZpTUnzVfRRUDFKY= 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=jChpHl4y; 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="jChpHl4y" Received: by mail-dy1-f202.google.com with SMTP id 5a478bee46e88-304448ab58cso4443225eec.1 for ; Fri, 22 May 2026 10:45:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1779471952; x=1780076752; 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=ZTL5FG6+Kr2BWUUPWPXeiSAcbi1S62N6S7m7CP+BgJA=; b=jChpHl4ynVLKIWuj9fgSLP3IChzhqhedQowr2UzjFahRJs2Ft3NCZD71SePu+toqxF eNY03//AKFplb8F6MApKzrKUnHapTpD+xq7xY258kNfRVhGdjLTEYjvRLXQ8ZfyPgYyy qLOvOWdh8YGRWZ/NY29SSGCc93euGWe75zBid43cb9Yt5KBaywrmVDA65KUPaFyvzHiP mruVgkVYJLWlfYcfh10odwxSnBAZbx+Wwdo+iFKs4Uz50DxLceSm5nC5CZy8etGSqajb 3Rxdg9WO4A+YNSuKFvWJFS3228MrvfPUfPfJ44knXD46bbiXZ5PU+dF6jfqTStnU2Tmx D+WQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779471952; x=1780076752; 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=ZTL5FG6+Kr2BWUUPWPXeiSAcbi1S62N6S7m7CP+BgJA=; b=F1XGWoQQGFciubtYGca669YOKbSmSdi5YApxD6sJiK3WI7d2rqac2/eqEKZCkl+QXt m390wo2h0QfLTOQ/hRIOvIwYTDtwSl6aeDCwZA7epJ9VVhiZ1lHG7gNHLD4gljF4FDJU mygzUbyoGYGJ8MSMMxFXcvw1dxkKLcuKR6uktWHaMKg27r5RrYlR9cqsRKZL7E2ubuZx j2isZZCgzBjvm2hVZuKgUIRBtyJKIxWQRtUfg9NuuTmgE35jKt4SF8ed5pcmbfyJgPeu aOwltz2LpbHsYS7fLlkylraafD+R8sG6Mp8p6g/QUui6cnNx8f+tZ25r7A6/JHFGHpd1 KM6Q== X-Forwarded-Encrypted: i=1; AFNElJ9sR4thAcECPdGKSdSFIm4p4xU7+uL2IMgWRp5far4wVNuil7hr7aU6V+V512NUitFLyusFAn6H/efBCnM=@vger.kernel.org X-Gm-Message-State: AOJu0Yz5viQMR8z30joyl4t3MVIH8SGTdhmqUrFrE9EaN9cds/wnEh27 ifx5qm7T8YOSa0b3mxyPJRQeFymbGRe9eU2VyjqWCUd2YVxBi/qxPyn+pgx+AcLFMu/N/5geMMS FaqJ8XWU4dJ240d5U/S3229EO3c8MxR/MZQ== X-Received: from dybgh3.prod.google.com ([2002:a05:7301:3:b0:303:521c:29a5]) (user=abhishekbapat job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7301:1922:b0:2ef:8b91:212 with SMTP id 5a478bee46e88-30449063389mr2564519eec.14.1779471951995; Fri, 22 May 2026 10:45:51 -0700 (PDT) Date: Fri, 22 May 2026 17:45:38 +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.746.g67dd491aae-goog Message-ID: Subject: [PATCH v2 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.746.g67dd491aae-goog