* [PATCH] fs: touch up predicts in putname()
@ 2025-10-29 13:49 Mateusz Guzik
2025-10-29 15:48 ` Markus Elfring
` (3 more replies)
0 siblings, 4 replies; 12+ messages in thread
From: Mateusz Guzik @ 2025-10-29 13:49 UTC (permalink / raw)
To: brauner; +Cc: viro, jack, linux-kernel, linux-fsdevel, Mateusz Guzik
1. we already expect the refcount is 1.
2. path creation predicts name == iname
I verified this straightens out the asm, no functional changes.
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
---
random annoyance i noticed while profiling
fs/namei.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index ba29ec7b67c5..4692f25e7cd9 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -282,7 +282,7 @@ void putname(struct filename *name)
return;
refcnt = atomic_read(&name->refcnt);
- if (refcnt != 1) {
+ if (unlikely(refcnt != 1)) {
if (WARN_ON_ONCE(!refcnt))
return;
@@ -290,7 +290,7 @@ void putname(struct filename *name)
return;
}
- if (name->name != name->iname) {
+ if (unlikely(name->name != name->iname)) {
__putname(name->name);
kfree(name);
} else
--
2.34.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH] fs: touch up predicts in putname()
2025-10-29 13:49 [PATCH] fs: touch up predicts in putname() Mateusz Guzik
@ 2025-10-29 15:48 ` Markus Elfring
2025-10-30 13:59 ` Jan Kara
` (2 subsequent siblings)
3 siblings, 0 replies; 12+ messages in thread
From: Markus Elfring @ 2025-10-29 15:48 UTC (permalink / raw)
To: Mateusz Guzik, linux-fsdevel, Christian Brauner
Cc: LKML, Alexander Viro, Jan Kara
…
> I verified this straightens out the asm, no functional changes.
Would a corresponding imperative wording become helpful for an improved change description?
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v6.18-rc3#n94
How do you think about to refer to predictions for condition checks?
Regards,
Markus
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] fs: touch up predicts in putname()
2025-10-29 13:49 [PATCH] fs: touch up predicts in putname() Mateusz Guzik
2025-10-29 15:48 ` Markus Elfring
@ 2025-10-30 13:59 ` Jan Kara
2025-10-31 12:18 ` Christian Brauner
2025-10-31 20:17 ` Al Viro
3 siblings, 0 replies; 12+ messages in thread
From: Jan Kara @ 2025-10-30 13:59 UTC (permalink / raw)
To: Mateusz Guzik; +Cc: brauner, viro, jack, linux-kernel, linux-fsdevel
On Wed 29-10-25 14:49:52, Mateusz Guzik wrote:
> 1. we already expect the refcount is 1.
> 2. path creation predicts name == iname
>
> I verified this straightens out the asm, no functional changes.
>
> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Looks sensible. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
>
> random annoyance i noticed while profiling
>
> fs/namei.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/fs/namei.c b/fs/namei.c
> index ba29ec7b67c5..4692f25e7cd9 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -282,7 +282,7 @@ void putname(struct filename *name)
> return;
>
> refcnt = atomic_read(&name->refcnt);
> - if (refcnt != 1) {
> + if (unlikely(refcnt != 1)) {
> if (WARN_ON_ONCE(!refcnt))
> return;
>
> @@ -290,7 +290,7 @@ void putname(struct filename *name)
> return;
> }
>
> - if (name->name != name->iname) {
> + if (unlikely(name->name != name->iname)) {
> __putname(name->name);
> kfree(name);
> } else
> --
> 2.34.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] fs: touch up predicts in putname()
2025-10-29 13:49 [PATCH] fs: touch up predicts in putname() Mateusz Guzik
2025-10-29 15:48 ` Markus Elfring
2025-10-30 13:59 ` Jan Kara
@ 2025-10-31 12:18 ` Christian Brauner
2025-10-31 20:17 ` Al Viro
3 siblings, 0 replies; 12+ messages in thread
From: Christian Brauner @ 2025-10-31 12:18 UTC (permalink / raw)
To: Mateusz Guzik; +Cc: Christian Brauner, viro, jack, linux-kernel, linux-fsdevel
On Wed, 29 Oct 2025 14:49:52 +0100, Mateusz Guzik wrote:
> 1. we already expect the refcount is 1.
> 2. path creation predicts name == iname
>
> I verified this straightens out the asm, no functional changes.
>
>
Applied to the vfs-6.19.misc branch of the vfs/vfs.git tree.
Patches in the vfs-6.19.misc branch should appear in linux-next soon.
Please report any outstanding bugs that were missed during review in a
new review to the original patch series allowing us to drop it.
It's encouraged to provide Acked-bys and Reviewed-bys even though the
patch has now been applied. If possible patch trailers will be updated.
Note that commit hashes shown below are subject to change due to rebase,
trailer updates or similar. If in doubt, please check the listed branch.
tree: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
branch: vfs-6.19.misc
[1/1] fs: touch up predicts in putname()
https://git.kernel.org/vfs/vfs/c/20052f2ef08a
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] fs: touch up predicts in putname()
2025-10-29 13:49 [PATCH] fs: touch up predicts in putname() Mateusz Guzik
` (2 preceding siblings ...)
2025-10-31 12:18 ` Christian Brauner
@ 2025-10-31 20:17 ` Al Viro
2025-11-01 6:05 ` Al Viro
3 siblings, 1 reply; 12+ messages in thread
From: Al Viro @ 2025-10-31 20:17 UTC (permalink / raw)
To: Mateusz Guzik; +Cc: brauner, jack, linux-kernel, linux-fsdevel
On Wed, Oct 29, 2025 at 02:49:52PM +0100, Mateusz Guzik wrote:
> 1. we already expect the refcount is 1.
> 2. path creation predicts name == iname
>
> I verified this straightens out the asm, no functional changes.
FWIW, I think I know how to get rid of atomic there. Doesn't
invalidate your patch...
Look:
0) get rid of audit_reusename() and aname->uptr (I have that series,
massaging it for posting at the moment). Basically, don't have
getname et.al. called in retry loops - there are few places doing
that, and they are not hard to fix.
1) provide getname_alien(), differing from plain getname() only
in the lack of audit_getname() call.
2) have io_uring use it for references that might be handled in
a worker thread.
3) provide something like
struct filename *take_filename(struct filename **p)
{
struct filename *res = no_free_ptr(*p);
audit_getname(res);
return res;
}
and have places like io_mkdirat() switch from
ret = do_mkdirat(mkd->dfd, mkd->filename, mkd->mode);
req->flags &= ~REQ_F_NEED_CLEANUP;
to
ret = do_mkdirat(mkd->dfd, take_filename(&mkd->filename), mkd->mode);
Voila - no need for atomic. Prior to audit_getname() it's going to be 1;
after that only the thread that has called audit_getname() is going to see
the address of the object (and all accesses are going to be process-synchronous).
IOW, it becomes a plain int refcount. Sure, we still want that prediction there,
but the atomicity cost is no more...
I'll post the ->uptr removal series tonight or tomorrow; figuring out the right
calling conventions for getname_alien() is the main obstacle for (1--3) ATM...
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] fs: touch up predicts in putname()
2025-10-31 20:17 ` Al Viro
@ 2025-11-01 6:05 ` Al Viro
2025-11-01 8:19 ` Mateusz Guzik
0 siblings, 1 reply; 12+ messages in thread
From: Al Viro @ 2025-11-01 6:05 UTC (permalink / raw)
To: Mateusz Guzik; +Cc: brauner, jack, linux-kernel, linux-fsdevel
On Fri, Oct 31, 2025 at 08:17:53PM +0000, Al Viro wrote:
> 0) get rid of audit_reusename() and aname->uptr (I have that series,
> massaging it for posting at the moment). Basically, don't have
> getname et.al. called in retry loops - there are few places doing
> that, and they are not hard to fix.
See #work.filename-uptr; I'll post individual patches tomorrow morning,
hopefully along with getname_alien()/take_filename() followups, including
the removal of atomic (still not settled on the calling conventions for
getname_alien()).
> I'll post the ->uptr removal series tonight or tomorrow; figuring out the right
> calling conventions for getname_alien() is the main obstacle for (1--3) ATM...
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] fs: touch up predicts in putname()
2025-11-01 6:05 ` Al Viro
@ 2025-11-01 8:19 ` Mateusz Guzik
2025-11-02 6:14 ` Al Viro
0 siblings, 1 reply; 12+ messages in thread
From: Mateusz Guzik @ 2025-11-01 8:19 UTC (permalink / raw)
To: Al Viro; +Cc: brauner, jack, linux-kernel, linux-fsdevel
On Sat, Nov 1, 2025 at 7:05 AM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> On Fri, Oct 31, 2025 at 08:17:53PM +0000, Al Viro wrote:
>
> > 0) get rid of audit_reusename() and aname->uptr (I have that series,
> > massaging it for posting at the moment). Basically, don't have
> > getname et.al. called in retry loops - there are few places doing
> > that, and they are not hard to fix.
>
> See #work.filename-uptr; I'll post individual patches tomorrow morning,
> hopefully along with getname_alien()/take_filename() followups, including
> the removal of atomic (still not settled on the calling conventions for
> getname_alien()).
>
Ok, in that case I think it will be most expedient if my patch gets
dropped and you just fold the updated predicts into your patchset
somewhere. I don't need any credit.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] fs: touch up predicts in putname()
2025-11-01 8:19 ` Mateusz Guzik
@ 2025-11-02 6:14 ` Al Viro
2025-11-02 22:42 ` Mateusz Guzik
0 siblings, 1 reply; 12+ messages in thread
From: Al Viro @ 2025-11-02 6:14 UTC (permalink / raw)
To: Mateusz Guzik; +Cc: brauner, jack, linux-kernel, linux-fsdevel
On Sat, Nov 01, 2025 at 09:19:21AM +0100, Mateusz Guzik wrote:
> On Sat, Nov 1, 2025 at 7:05 AM Al Viro <viro@zeniv.linux.org.uk> wrote:
> >
> > On Fri, Oct 31, 2025 at 08:17:53PM +0000, Al Viro wrote:
> >
> > > 0) get rid of audit_reusename() and aname->uptr (I have that series,
> > > massaging it for posting at the moment). Basically, don't have
> > > getname et.al. called in retry loops - there are few places doing
> > > that, and they are not hard to fix.
> >
> > See #work.filename-uptr; I'll post individual patches tomorrow morning,
> > hopefully along with getname_alien()/take_filename() followups, including
> > the removal of atomic (still not settled on the calling conventions for
> > getname_alien()).
> >
>
> Ok, in that case I think it will be most expedient if my patch gets
> dropped and you just fold the updated predicts into your patchset
> somewhere. I don't need any credit.
See #work.filename-refcnt. I'm not entirely happy about the API, if you
see a saner way to do it, I'd really like to hear it. Stuff in the series:
* get rid of getname in retry loops. Only 9 places like that left,
massaged out of existence one by one. (##1..9)
* drop audit_reusename() and filename->uptr (#10)
* get rid of mixing LOOKUP_EMPTY with the rest of the flags -
very few places do that at this point and they are not hard to take
care of (##11..15)
* take LOOKUP_EMPTY out of LOOKUP_... space entirely - make it
GETNAME_EMPTY and have it passed only to getname_flags() (#16)
* add GETNAME_NOAUDIT for "don't call audit_getname() there" (#17).
Helpers: getname_alien()/getname_uflags_alien() being wrappers for
that; io-uring switched to those for filename import (in ->prep()).
take_filename(): take a reference to struct filename, leaving NULL
behind, feed it to audit_getname() and return to caller. Used by
io-uring ->issue() instances that feed an imported filename to
do_{mkdir,mknod...}() - the stuff that does actual work, done in the
thread that will do that work.
* make filename->refcnt non-atomic; now it can be done (#19,
on top of merge from vfs-common/vfs-6.19.misc to bring your commit
in).
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] fs: touch up predicts in putname()
2025-11-02 6:14 ` Al Viro
@ 2025-11-02 22:42 ` Mateusz Guzik
2025-11-03 4:45 ` Al Viro
0 siblings, 1 reply; 12+ messages in thread
From: Mateusz Guzik @ 2025-11-02 22:42 UTC (permalink / raw)
To: Al Viro; +Cc: brauner, jack, linux-kernel, linux-fsdevel
On Sun, Nov 2, 2025 at 7:14 AM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> On Sat, Nov 01, 2025 at 09:19:21AM +0100, Mateusz Guzik wrote:
> > On Sat, Nov 1, 2025 at 7:05 AM Al Viro <viro@zeniv.linux.org.uk> wrote:
> > >
> > > On Fri, Oct 31, 2025 at 08:17:53PM +0000, Al Viro wrote:
> > >
> > > > 0) get rid of audit_reusename() and aname->uptr (I have that series,
> > > > massaging it for posting at the moment). Basically, don't have
> > > > getname et.al. called in retry loops - there are few places doing
> > > > that, and they are not hard to fix.
> > >
> > > See #work.filename-uptr; I'll post individual patches tomorrow morning,
> > > hopefully along with getname_alien()/take_filename() followups, including
> > > the removal of atomic (still not settled on the calling conventions for
> > > getname_alien()).
> > >
> >
> > Ok, in that case I think it will be most expedient if my patch gets
> > dropped and you just fold the updated predicts into your patchset
> > somewhere. I don't need any credit.
>
> See #work.filename-refcnt. I'm not entirely happy about the API, if you
> see a saner way to do it, I'd really like to hear it. Stuff in the series:
>
> * get rid of getname in retry loops. Only 9 places like that left,
> massaged out of existence one by one. (##1..9)
> * drop audit_reusename() and filename->uptr (#10)
> * get rid of mixing LOOKUP_EMPTY with the rest of the flags -
> very few places do that at this point and they are not hard to take
> care of (##11..15)
> * take LOOKUP_EMPTY out of LOOKUP_... space entirely - make it
> GETNAME_EMPTY and have it passed only to getname_flags() (#16)
> * add GETNAME_NOAUDIT for "don't call audit_getname() there" (#17).
> Helpers: getname_alien()/getname_uflags_alien() being wrappers for
> that; io-uring switched to those for filename import (in ->prep()).
> take_filename(): take a reference to struct filename, leaving NULL
> behind, feed it to audit_getname() and return to caller. Used by
> io-uring ->issue() instances that feed an imported filename to
> do_{mkdir,mknod...}() - the stuff that does actual work, done in the
> thread that will do that work.
> * make filename->refcnt non-atomic; now it can be done (#19,
> on top of merge from vfs-common/vfs-6.19.misc to bring your commit
> in).
I think the take_filename business invites misuse in the long run and
the API has no way of pointing out it happened.
Even ignoring the fact that there is a refcount and people may be
inclined to refname(name) + take_filename(name), the following already
breaks:
foo() {
name = getname(...);
if (!IS_ERR_OR_NULL(name))
bar(name);
putname(name);
}
bar(struct filename *name)
{
baz(take_filename(&name));
}
While the code as proposed in the branch does not do it, it is a
matter of time before something which can be distilled to the above
shows up.
I think the core idea of having io_uring bugger off from freeing the
filename thing has legs. I *suspect* the way forward is to implement
audit_delegate_free() or similar which would assert refcount == 1 and
would denote with a flag that audit takes ownership of freeing. Then
the regular putname() yells the flag when compiled with
CONFIG_DEBUG_VFS, catching regular misuse. audit itself, when done
with the buffer, would clear the flag and calls putname().
This is from top of my head, I would need to dig into it to validate
the above is feasible.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] fs: touch up predicts in putname()
2025-11-02 22:42 ` Mateusz Guzik
@ 2025-11-03 4:45 ` Al Viro
2025-11-03 16:44 ` Mateusz Guzik
0 siblings, 1 reply; 12+ messages in thread
From: Al Viro @ 2025-11-03 4:45 UTC (permalink / raw)
To: Mateusz Guzik; +Cc: brauner, jack, linux-kernel, linux-fsdevel
On Sun, Nov 02, 2025 at 11:42:03PM +0100, Mateusz Guzik wrote:
> Even ignoring the fact that there is a refcount and people may be
> inclined to refname(name) + take_filename(name), the following already
> breaks:
Er... refname() doesn't need to be seen for anyone other than auditsc.c
and core part of filename handling in fs/namei.c (I'd like to move it
to fs/filename.c someday)...
> foo() {
> name = getname(...);
> if (!IS_ERR_OR_NULL(name))
> bar(name);
> putname(name);
> }
>
> bar(struct filename *name)
> {
> baz(take_filename(&name));
> }
>
> While the code as proposed in the branch does not do it, it is a
> matter of time before something which can be distilled to the above
> shows up.
Breaks in which case, exactly? If baz() consumes its argument, we are
fine, if it does we have a leak...
I agree that 'take_filename' is inviting wrong connotations, though.
Hell knows - it might be worth thinking of that as claiming ownership.
Or, perhaps, transformation of the original object, if we separate
the notion of 'active filename' (absolutely tied to one thread, not
allowed to be reachable from any data structures shared with other
threads, etc.) from 'embryonic filename' (no refcounting whatsoever,
no copying of references, etc., consumed on transformation into
'active filename'). Then getname_alien() would create an embryo,
to be consumed before doing actual work. That could be expressed
in C type system... Need to think about that.
One possibility would be something like
struct alien_filename {
struct filename *__dont_touch_that;
};
int getname_alien(struct alien_filename *v, const char __user *string)
{
struct filename *res;
if (WARN_ON(v->__dont_touch_that))
return -EINVAL;
res = getname_flags(string, GETNAME_NOAUDIT);
if (IS_ERR(res))
return PTR_ERR(res);
v->__done_touch_that = res;
return 0;
}
void destroy_alien_filename(struct alient_filename *v)
{
putname(no_free_ptr(v->__dont_touch_that));
}
struct filename *claim_filename(struct alien_filename *v)
{
struct filename *res = no_free_ptr(v->__dont_touch_that);
if (!IS_ERR(res))
audit_getname(res);
return res;
}
and e.g.
struct io_rename {
struct file *file;
int old_dfd;
int new_dfd;
struct alien_filename oldpath;
struct alien_filename newpath;
int flags;
};
...
err = getname_alien(&ren->oldpath);
if (unlikely(err))
return err;
err = getname_alien(&ren->newpath);
if (unlikely(err)) {
destroy_alien_filename(&ren->oldpath);
return err;
}
...
/* note that do_renameat2() consumes filename references */
ret = do_renameat2(ren->old_dfd, claim_filename(&ren->oldpath),
ren->new_dfd, claim_filename(&ren->newpath),
ren->flags);
...
void io_renameat_cleanup(struct io_kiocb *req)
{
struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
destroy_alien_filename(&ren->oldpath);
destroy_alien_filename(&ren->newpath);
}
Might work... Anyone found adding any instances of __dont_touch_that anywhere in
the kernel would be obviously doing something fishy (and if they are playing silly
buggers with obfuscating that, s/doing something fishy/malicious/), so C typechecking
+ git grep once in a while should suffice for safety.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] fs: touch up predicts in putname()
2025-11-03 4:45 ` Al Viro
@ 2025-11-03 16:44 ` Mateusz Guzik
2025-11-05 6:25 ` Al Viro
0 siblings, 1 reply; 12+ messages in thread
From: Mateusz Guzik @ 2025-11-03 16:44 UTC (permalink / raw)
To: Al Viro; +Cc: brauner, jack, linux-kernel, linux-fsdevel
On Mon, Nov 3, 2025 at 5:45 AM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> On Sun, Nov 02, 2025 at 11:42:03PM +0100, Mateusz Guzik wrote:
>
> > Even ignoring the fact that there is a refcount and people may be
> > inclined to refname(name) + take_filename(name), the following already
> > breaks:
>
> Er... refname() doesn't need to be seen for anyone other than auditsc.c
> and core part of filename handling in fs/namei.c (I'd like to move it
> to fs/filename.c someday)...
>
> > foo() {
> > name = getname(...);
> > if (!IS_ERR_OR_NULL(name))
> > bar(name);
> > putname(name);
> > }
> >
> > bar(struct filename *name)
> > {
> > baz(take_filename(&name));
> > }
> >
> > While the code as proposed in the branch does not do it, it is a
> > matter of time before something which can be distilled to the above
> > shows up.
>
> Breaks in which case, exactly? If baz() consumes its argument, we are
> fine, if it does we have a leak...
>
My point is currently the idiomatic handling of struct filename is to
getname(), pass it around and then unconditionally call putname() on
it, which already branches on IS_ERR_OR_NULL. With the previous
proposed design it would be a matter of time before someone does that
and take_filename somewhere down the callstack, resulting in a bug.
The new alien_filename struct mostly sorts it out, but I have some notes on it.
> I agree that 'take_filename' is inviting wrong connotations, though.
>
> Hell knows - it might be worth thinking of that as claiming ownership.
> Or, perhaps, transformation of the original object, if we separate
> the notion of 'active filename' (absolutely tied to one thread, not
> allowed to be reachable from any data structures shared with other
> threads, etc.) from 'embryonic filename' (no refcounting whatsoever,
> no copying of references, etc., consumed on transformation into
> 'active filename'). Then getname_alien() would create an embryo,
> to be consumed before doing actual work. That could be expressed
> in C type system... Need to think about that.
>
> One possibility would be something like
>
> struct alien_filename {
> struct filename *__dont_touch_that;
> };
>
> int getname_alien(struct alien_filename *v, const char __user *string)
> {
> struct filename *res;
> if (WARN_ON(v->__dont_touch_that))
> return -EINVAL;
> res = getname_flags(string, GETNAME_NOAUDIT);
> if (IS_ERR(res))
> return PTR_ERR(res);
> v->__done_touch_that = res;
> return 0;
> }
>
> void destroy_alien_filename(struct alient_filename *v)
> {
> putname(no_free_ptr(v->__dont_touch_that));
> }
>
> struct filename *claim_filename(struct alien_filename *v)
> {
> struct filename *res = no_free_ptr(v->__dont_touch_that);
> if (!IS_ERR(res))
> audit_getname(res);
> return res;
> }
>
> and e.g.
>
> struct io_rename {
> struct file *file;
> int old_dfd;
> int new_dfd;
> struct alien_filename oldpath;
> struct alien_filename newpath;
> int flags;
> };
>
> ...
> err = getname_alien(&ren->oldpath);
> if (unlikely(err))
> return err;
> err = getname_alien(&ren->newpath);
> if (unlikely(err)) {
> destroy_alien_filename(&ren->oldpath);
> return err;
> }
>
> ...
> /* note that do_renameat2() consumes filename references */
> ret = do_renameat2(ren->old_dfd, claim_filename(&ren->oldpath),
> ren->new_dfd, claim_filename(&ren->newpath),
> ren->flags);
> ...
>
> void io_renameat_cleanup(struct io_kiocb *req)
> {
> struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
>
> destroy_alien_filename(&ren->oldpath);
> destroy_alien_filename(&ren->newpath);
> }
>
> Might work... Anyone found adding any instances of __dont_touch_that anywhere in
> the kernel would be obviously doing something fishy (and if they are playing silly
> buggers with obfuscating that, s/doing something fishy/malicious/), so C typechecking
> + git grep once in a while should suffice for safety.
I think this still wants some error-proofing to catch bad usage. Per
the above, the new thing deviates from the idiom claiming you can
always putname().
Perhaps like this:
struct alien_filename {
struct filename *__dont_touch_that;
struct task_struct *__who_can_free;
bool is_delegated;
};
It would start with __who_can_free == NULL and would need to be
populated by a helper before destroy_alien_name is legally callable.
The consumer would denote it does not intend to free the obj by
calling delegate_alien_name(), after which some other thread needs to
take ownership.
a sketch:
/* called by the thread which allocated the name if it decides to go
through with it */
delegate_alien_name(name) {
VFS_BUG_ON(name->delegated);
name->delegated = true;
}
/* called by the thread using the name */
claim_alien_name(name) {
VFS_BUG_ON(!name->delegated);
VFS_BUG_ON(name->__who_can_free != NULL);
name->__who_can_free = current;
}
destroy_alien_name(name) {
if (name->delegated) {
VFS_BUG_ON(name->__who_can_free == NULL);
VFS_BUG_ON(name->__who_can_free != current);
}
putname(..);
}
So a sample correct consumer looks like this:
err = getname_alien(&name);
....
err = other_prep();
if (!err)
actual_work(delegate_alien_name(name));
else
destroy_alien_name(name);
the *other* thread which eventually works on the name:
claim_alien_name(name);
/* hard work goes here */
destroy_alien_name(name);
Sample buggy consumer which both delegated the free *and* decided free
anyway is caught.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] fs: touch up predicts in putname()
2025-11-03 16:44 ` Mateusz Guzik
@ 2025-11-05 6:25 ` Al Viro
0 siblings, 0 replies; 12+ messages in thread
From: Al Viro @ 2025-11-05 6:25 UTC (permalink / raw)
To: Mateusz Guzik; +Cc: brauner, jack, linux-kernel, linux-fsdevel
On Mon, Nov 03, 2025 at 05:44:07PM +0100, Mateusz Guzik wrote:
> a sketch:
> /* called by the thread which allocated the name if it decides to go
> through with it */
> delegate_alien_name(name) {
> VFS_BUG_ON(name->delegated);
> name->delegated = true;
> }
>
> /* called by the thread using the name */
> claim_alien_name(name) {
> VFS_BUG_ON(!name->delegated);
> VFS_BUG_ON(name->__who_can_free != NULL);
> name->__who_can_free = current;
> }
>
> destroy_alien_name(name) {
> if (name->delegated) {
> VFS_BUG_ON(name->__who_can_free == NULL);
> VFS_BUG_ON(name->__who_can_free != current);
> }
> putname(..);
> }
>
> So a sample correct consumer looks like this:
> err = getname_alien(&name);
> ....
> err = other_prep();
> if (!err)
> actual_work(delegate_alien_name(name));
> else
> destroy_alien_name(name);
>
> the *other* thread which eventually works on the name:
> claim_alien_name(name);
> /* hard work goes here */
> destroy_alien_name(name);
>
> Sample buggy consumer which both delegated the free *and* decided free
> anyway is caught.
That would make sense had there been any places where we would want
use the alien_filename contents (hell, access it) in any way other
than "destroy and get a struct filename reference". I don't see any
candidates, TBH...
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2025-11-05 6:25 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-29 13:49 [PATCH] fs: touch up predicts in putname() Mateusz Guzik
2025-10-29 15:48 ` Markus Elfring
2025-10-30 13:59 ` Jan Kara
2025-10-31 12:18 ` Christian Brauner
2025-10-31 20:17 ` Al Viro
2025-11-01 6:05 ` Al Viro
2025-11-01 8:19 ` Mateusz Guzik
2025-11-02 6:14 ` Al Viro
2025-11-02 22:42 ` Mateusz Guzik
2025-11-03 4:45 ` Al Viro
2025-11-03 16:44 ` Mateusz Guzik
2025-11-05 6:25 ` Al Viro
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).