public inbox for cgroups@vger.kernel.org
 help / color / mirror / Atom feed
From: Tejun Heo <tj@kernel.org>
To: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: cgroups@vger.kernel.org, linux-kernel@vger.kernel.org,
	"Michal Koutný" <mkoutny@suse.com>,
	"Paul E. McKenney" <paulmck@kernel.org>,
	"Boqun Feng" <boqun.feng@gmail.com>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Hillf Danton" <hdanton@sina.com>,
	"Johannes Weiner" <hannes@cmpxchg.org>,
	"Marco Elver" <elver@google.com>,
	"Zefan Li" <lizefan.x@bytedance.com>,
	tglx@linutronix.de,
	syzbot+6ea37e2e6ffccf41a7e6@syzkaller.appspotmail.com
Subject: Re: [PATCH v3] kernfs: Use RCU for kernfs_node::name and ::parent lookup.
Date: Tue, 3 Dec 2024 12:21:55 -1000	[thread overview]
Message-ID: <Z0-Eg0B09JQUZG2N@slm.duckdns.org> (raw)
In-Reply-To: <20241121175250.EJbI7VMb@linutronix.de>

Hello, sorry about the delay.

Generally looks good to me but I have some rcu deref accessor related
comments.

On Thu, Nov 21, 2024 at 06:52:50PM +0100, Sebastian Andrzej Siewior wrote:
> diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h
...
> @@ -1312,6 +1314,11 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp)
>  		ret = -EINVAL;
>  		goto out_region;
>  	}
> +	kn_name = kstrdup(rdt_kn_get_name(rdtgrp->kn), GFP_KERNEL);

Shouldn't this be freed somewhere?

> +	if (!kn_name) {
> +		ret = -ENOMEM;
> +		goto out_cstates;
> +	}
>  
>  	plr->thread_done = 0;
>  
...
> diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
...
> @@ -533,7 +543,8 @@ static void kernfs_free_rcu(struct rcu_head *rcu)
>  {
>  	struct kernfs_node *kn = container_of(rcu, struct kernfs_node, rcu);
>  
> -	kfree_const(kn->name);
> +	/* If the whole node goes away, the name can't be used outside */
> +	kfree_const(rcu_dereference_check(kn->name, true));

rcu_access_pointer()?

> @@ -557,16 +568,18 @@ void kernfs_put(struct kernfs_node *kn)
>  	if (!kn || !atomic_dec_and_test(&kn->count))
>  		return;
>  	root = kernfs_root(kn);
> +	guard(rcu)();
>   repeat:
>  	/*
>  	 * Moving/renaming is always done while holding reference.
>  	 * kn->parent won't change beneath us.
>  	 */
> -	parent = kn->parent;
> +	parent = rcu_dereference(kn->parent);

I wonder whether it'd be better to encode the reference count rule (ie. add
the condition kn->count == 0 to deref_check) in the kn->parent deref
accessor. This function doesn't need RCU read lock and holding it makes it
more confusing.

> diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
> index 8502ef68459b9..05f7b30283150 100644
> --- a/fs/kernfs/file.c
> +++ b/fs/kernfs/file.c
> @@ -911,9 +911,11 @@ static void kernfs_notify_workfn(struct work_struct *work)
>  	/* kick fsnotify */
>  
>  	down_read(&root->kernfs_supers_rwsem);
> +	down_read(&root->kernfs_rwsem);

Why is this addition necessary? Hmm... was the code previously broken w.r.t.
renaming? Can this be RCU?

> diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
> index 1358c21837f1a..db71faba3bb53 100644
> --- a/fs/kernfs/mount.c
> +++ b/fs/kernfs/mount.c
> @@ -145,8 +145,10 @@ static struct dentry *kernfs_fh_to_parent(struct super_block *sb,
>  static struct dentry *kernfs_get_parent_dentry(struct dentry *child)
>  {
>  	struct kernfs_node *kn = kernfs_dentry_node(child);
> +	struct kernfs_root *root = kernfs_root(kn);
>  
> -	return d_obtain_alias(kernfs_get_inode(child->d_sb, kn->parent));
> +	guard(rwsem_read)(&root->kernfs_rwsem);
> +	return d_obtain_alias(kernfs_get_inode(child->d_sb, kernfs_rcu_get_parent(kn)));

Ditto.

> @@ -186,10 +188,10 @@ static struct kernfs_node *find_next_ancestor(struct kernfs_node *child,
>  		return NULL;
>  	}
>  
> -	while (child->parent != parent) {
> -		if (!child->parent)
> +	while (kernfs_rcu_get_parent(child) != parent) {
> +		child = kernfs_rcu_get_parent(child);
> +		if (!child)

I think kernfs_rcu_get_parent() name is a bit confusing given that it allows
derefing without RCU if the rwsem is locked. Maybe just kernfs_get_parent()
or kernfs_parent()?

> @@ -216,6 +219,9 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
>  	if (!kn->parent)
>  		return dentry;
>  
> +	root = kernfs_root(kn);
> +	guard(rwsem_read)(&root->kernfs_rwsem);

Here too, it's a bit confusing that it's adding new locking. Was the code
broken before? If so, it'd be clearer if the fixes were in their own patch.

> diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
> index d1995e2d6c943..e9bfe3e80809d 100644
> --- a/fs/sysfs/file.c
> +++ b/fs/sysfs/file.c
> @@ -19,13 +19,19 @@
>  
>  #include "sysfs.h"
>  
> +static struct kobject *sysfs_file_kobj(struct kernfs_node *kn)
> +{
> +	guard(rcu)();
> +	return rcu_dereference(kn->parent)->priv;
> +}

I wonder whether it'd be better to rename kn->parent to something like
kn->__parent (or maybe some other suffix) to clarify that the field is not
to be deref'ed directly and kernfs_parent() helper is made available to the
users. That way, users can benefit from the additional conditions in
rcu_dereference_check().

> diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
> index e28d5f0d20ed0..202e329759b12 100644
> --- a/kernel/cgroup/cgroup-v1.c
> +++ b/kernel/cgroup/cgroup-v1.c
> @@ -844,7 +844,7 @@ static int cgroup1_rename(struct kernfs_node *kn, struct kernfs_node *new_parent
>  
>  	if (kernfs_type(kn) != KERNFS_DIR)
>  		return -ENOTDIR;
> -	if (kn->parent != new_parent)
> +	if (rcu_dereference_check(kn->parent, true) != new_parent)
>  		return -EIO;

This isn't being derefed, rcu_access_pointer()?

>  	/*
> diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
> index 044c7ba1cc482..d11d05a53783c 100644
> --- a/kernel/cgroup/cgroup.c
> +++ b/kernel/cgroup/cgroup.c
> @@ -633,9 +633,15 @@ int cgroup_task_count(const struct cgroup *cgrp)
>  	return count;
>  }
>  
> +static struct cgroup *cg_get_parent_priv(struct kernfs_node *kn)
> +{
> +	/* The parent can not be changed */
> +	return rcu_dereference_check(kn->parent, true)->priv;
> +}

e.g. Here, it'd be a lot better if kernfs provided helper can be used so
that deref condition check can be preserved.

Thanks.

-- 
tejun

  parent reply	other threads:[~2024-12-03 22:21 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-11-21 17:52 [PATCH v3] kernfs: Use RCU for kernfs_node::name and ::parent lookup Sebastian Andrzej Siewior
2024-11-25 14:49 ` Michal Koutný
2024-11-25 18:02   ` Sebastian Andrzej Siewior
2024-12-11 15:36     ` Michal Koutný
2024-12-03 22:21 ` Tejun Heo [this message]
2025-01-16 13:27   ` Sebastian Andrzej Siewior
2025-01-16 13:39     ` Sebastian Andrzej Siewior
2025-01-16 17:32     ` Tejun Heo

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=Z0-Eg0B09JQUZG2N@slm.duckdns.org \
    --to=tj@kernel.org \
    --cc=bigeasy@linutronix.de \
    --cc=boqun.feng@gmail.com \
    --cc=cgroups@vger.kernel.org \
    --cc=elver@google.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=hannes@cmpxchg.org \
    --cc=hdanton@sina.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lizefan.x@bytedance.com \
    --cc=mkoutny@suse.com \
    --cc=paulmck@kernel.org \
    --cc=syzbot+6ea37e2e6ffccf41a7e6@syzkaller.appspotmail.com \
    --cc=tglx@linutronix.de \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox