All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paul Moore <paul@paul-moore.com>
To: Ricardo Robaina <rrobaina@redhat.com>,
	audit@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: eparis@redhat.com, Ricardo Robaina <rrobaina@redhat.com>
Subject: Re: [PATCH v1] audit: merge loops in __audit_inode_child()
Date: Mon, 13 Oct 2025 15:17:19 -0400	[thread overview]
Message-ID: <afae09deb55bcbfabe607fc2ee7997bc@paul-moore.com> (raw)
In-Reply-To: <20250904165919.3362000-1-rrobaina@redhat.com>

On Sep  4, 2025 Ricardo Robaina <rrobaina@redhat.com> wrote:
> 
> Whenever there's audit context, __audit_inode_child() gets called
> numerous times, which can lead to high latency in scenarios that
> create too many sysfs/debugfs entries at once, for instance, upon
> device_add_disk() invocation.
> 
>    # uname -r
>    6.17.0-rc3+
> 
>    # auditctl -a always,exit -F path=/tmp -k foo
>    # time insmod loop max_loop=1000
>    real 0m42.753s
>    user 0m0.000s
>    sys  0m42.494s
> 
>    # perf record -a insmod loop max_loop=1000
>    # perf report --stdio |grep __audit_inode_child
>    37.95%  insmod  [kernel.kallsyms]  [k] __audit_inode_child
> 
> __audit_inode_child() searches for both the parent and the child
> in two different loops that iterate over the same list. This
> process can be optimized by merging these into a single loop,
> without changing the function behavior or affecting the code's
> readability.
> 
> This patch merges the two loops that walk through the list
> context->names_list into a single loop. This optimization resulted
> in around 54% performance enhancement for the benchmark.
> 
>    # uname -r
>    6.17.0-rc3+-enhanced
> 
>    # auditctl -a always,exit -F path=/tmp -k foo
>    # time insmod loop max_loop=1000
>    real 0m19.388s
>    user 0m0.000s
>    sys  0m19.149s
> 
> Signed-off-by: Ricardo Robaina <rrobaina@redhat.com>
> ---
>  kernel/auditsc.c | 40 ++++++++++++++++++----------------------
>  1 file changed, 18 insertions(+), 22 deletions(-)

Thanks Ricardo, that's a nice improvement!  I saw a few additional things
that could help simplify the code and possibly speed things up a bit
more, see my comments below.

> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index eb98cd6fe91f..7abfb68687fb 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -2437,44 +2437,40 @@ void __audit_inode_child(struct inode *parent,
>  	if (inode)
>  		handle_one(inode);
>  
> -	/* look for a parent entry first */
>  	list_for_each_entry(n, &context->names_list, list) {
> -		if (!n->name ||
> -		    (n->type != AUDIT_TYPE_PARENT &&
> -		     n->type != AUDIT_TYPE_UNKNOWN))
> +		/* can only match entries that have a name */
> +		if (!n->name)
>  			continue;
>  
> -		if (n->ino == parent->i_ino && n->dev == parent->i_sb->s_dev &&
> -		    !audit_compare_dname_path(dname,
> -					      n->name->name, n->name_len)) {
> +		/* look for a parent entry first */
> +		if (!found_parent &&
> +		    (n->type == AUDIT_TYPE_PARENT || n->type == AUDIT_TYPE_UNKNOWN) &&
> +		    (n->ino == parent->i_ino && n->dev == parent->i_sb->s_dev &&
> +		     !audit_compare_dname_path(dname, n->name->name, n->name_len))) {
>  			if (n->type == AUDIT_TYPE_UNKNOWN)
>  				n->type = AUDIT_TYPE_PARENT;

We probably don't need to check 'n->type' first, as we want it to always
be set to AUDIT_TYPE_PARENT regardless of it's current value.

>  			found_parent = n;

We can probably 'continue' here since a match can't be both a parent and
a child at the same time.

Similarly, if we add move the 'if (found_parent && found_child)' check
up to here we don't need to run it on every pass through the loop, just
when we find a match.

Taking the two comment above into account, I would imagine something like
this would good:

  found_parent = n;
  if (found_child)
    break;
  continue;

> -			break;
>  		}
> -	}
>  
> -	cond_resched();
> -
> -	/* is there a matching child entry? */
> -	list_for_each_entry(n, &context->names_list, list) {
> -		/* can only match entries that have a name */
> -		if (!n->name ||
> -		    (n->type != type && n->type != AUDIT_TYPE_UNKNOWN))
> -			continue;
> -
> -		if (!strcmp(dname->name, n->name->name) ||
> -		    !audit_compare_dname_path(dname, n->name->name,
> +		/* is there a matching child entry? */
> +		if (!found_child &&
> +		    (n->type == type || n->type == AUDIT_TYPE_UNKNOWN) &&
> +		    (!strcmp(dname->name, n->name->name) ||
> +		     !audit_compare_dname_path(dname, n->name->name,
>  						found_parent ?
>  						found_parent->name_len :
> -						AUDIT_NAME_FULL)) {
> +						AUDIT_NAME_FULL))) {
>  			if (n->type == AUDIT_TYPE_UNKNOWN)
>  				n->type = type;
>  			found_child = n;

Similar to the parent case above, let's check to see if both a parent and
a child have been found.  We can probably skip the 'continue' here are we
are at the end of the loop.

  found_child = n;
  if (found_parent)
    break;

> -			break;
>  		}
> +
> +		if (found_parent && found_child)
> +			break;
>  	}
>  
> +	cond_resched();

The 'cond_resched()' call was located between the two loops to help avoid
a soft lockup caused by running through both loops; since we are now
condensing that into one loop we can probably drop the 'cond_resched()'
call ... which is definitely a good thing as it was a bit of a hack, a
necessary hack, but still a hack :)

>  	if (!found_parent) {
>  		/* create a new, "anonymous" parent record */
>  		n = audit_alloc_name(context, AUDIT_TYPE_PARENT);
> -- 
> 2.51.0

--
paul-moore.com

  parent reply	other threads:[~2025-10-13 19:17 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-04 16:59 [PATCH v1] audit: merge loops in __audit_inode_child() Ricardo Robaina
2025-10-03 15:49 ` Ricardo Robaina
2025-10-06  3:21   ` Paul Moore
2025-10-06  9:51     ` Ricardo Robaina
2025-10-13 19:17 ` Paul Moore [this message]
2025-10-14 12:42   ` Ricardo Robaina

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=afae09deb55bcbfabe607fc2ee7997bc@paul-moore.com \
    --to=paul@paul-moore.com \
    --cc=audit@vger.kernel.org \
    --cc=eparis@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rrobaina@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.