* [RFC PATCH v3 01/59] do_faccessat(): import pathname only once
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 02/59] do_fchmodat(): " Al Viro
` (58 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Convert the user_path_at() call inside a retry loop into getname_flags() +
filename_lookup() + putname() and leave only filename_lookup() inside
the loop.
Since we have the default logics for use of LOOKUP_EMPTY (passed iff
AT_EMPTY_PATH is present in flags), just use getname_uflags() and
don't bother with setting LOOKUP_EMPTY in lookup_flags - getname_uflags()
will pass the right thing to getname_flags() and filename_lookup()
doesn't care about LOOKUP_EMPTY at all.
The things could be further simplified by use of cleanup.h stuff, but
let's not clutter the patch with that.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/open.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index f328622061c5..f3bacc583ef0 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -468,6 +468,7 @@ static int do_faccessat(int dfd, const char __user *filename, int mode, int flag
int res;
unsigned int lookup_flags = LOOKUP_FOLLOW;
const struct cred *old_cred = NULL;
+ struct filename *name;
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
@@ -477,8 +478,6 @@ static int do_faccessat(int dfd, const char __user *filename, int mode, int flag
if (flags & AT_SYMLINK_NOFOLLOW)
lookup_flags &= ~LOOKUP_FOLLOW;
- if (flags & AT_EMPTY_PATH)
- lookup_flags |= LOOKUP_EMPTY;
if (access_need_override_creds(flags)) {
old_cred = access_override_creds();
@@ -486,8 +485,9 @@ static int do_faccessat(int dfd, const char __user *filename, int mode, int flag
return -ENOMEM;
}
+ name = getname_uflags(filename, flags);
retry:
- res = user_path_at(dfd, filename, lookup_flags, &path);
+ res = filename_lookup(dfd, name, lookup_flags, &path, NULL);
if (res)
goto out;
@@ -527,6 +527,7 @@ static int do_faccessat(int dfd, const char __user *filename, int mode, int flag
goto retry;
}
out:
+ putname(name);
if (old_cred)
put_cred(revert_creds(old_cred));
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 02/59] do_fchmodat(): import pathname only once
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 01/59] do_faccessat(): import pathname only once Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 03/59] do_fchownat(): " Al Viro
` (57 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Convert the user_path_at() call inside a retry loop into getname_flags() +
filename_lookup() + putname() and leave only filename_lookup() inside
the loop.
Since we have the default logics for use of LOOKUP_EMPTY (passed iff
AT_EMPTY_PATH is present in flags), just use getname_uflags() and
don't bother with setting LOOKUP_EMPTY in lookup_flags - getname_uflags()
will pass the right thing to getname_flags() and filename_lookup()
doesn't care about LOOKUP_EMPTY at all.
The things could be further simplified by use of cleanup.h stuff, but
let's not clutter the patch with that.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/open.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index f3bacc583ef0..82bfa06dbfa5 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -679,6 +679,7 @@ static int do_fchmodat(int dfd, const char __user *filename, umode_t mode,
unsigned int flags)
{
struct path path;
+ struct filename *name;
int error;
unsigned int lookup_flags;
@@ -686,11 +687,9 @@ static int do_fchmodat(int dfd, const char __user *filename, umode_t mode,
return -EINVAL;
lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
- if (flags & AT_EMPTY_PATH)
- lookup_flags |= LOOKUP_EMPTY;
-
+ name = getname_uflags(filename, flags);
retry:
- error = user_path_at(dfd, filename, lookup_flags, &path);
+ error = filename_lookup(dfd, name, lookup_flags, &path, NULL);
if (!error) {
error = chmod_common(&path, mode);
path_put(&path);
@@ -699,6 +698,7 @@ static int do_fchmodat(int dfd, const char __user *filename, umode_t mode,
goto retry;
}
}
+ putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 03/59] do_fchownat(): import pathname only once
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 01/59] do_faccessat(): import pathname only once Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 02/59] do_fchmodat(): " Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 04/59] do_utimes_path(): " Al Viro
` (56 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Convert the user_path_at() call inside a retry loop into getname_flags() +
filename_lookup() + putname() and leave only filename_lookup() inside
the loop.
Since we have the default logics for use of LOOKUP_EMPTY (passed iff
AT_EMPTY_PATH is present in flags), just use getname_uflags() and
don't bother with setting LOOKUP_EMPTY in lookup_flags - getname_uflags()
will pass the right thing to getname_flags() and filename_lookup()
doesn't care about LOOKUP_EMPTY at all.
The things could be further simplified by use of cleanup.h stuff, but
let's not clutter the patch with that.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/open.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index 82bfa06dbfa5..a2d775bec8c1 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -801,17 +801,17 @@ int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group,
int flag)
{
struct path path;
- int error = -EINVAL;
+ int error;
int lookup_flags;
+ struct filename *name;
if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
- goto out;
+ return -EINVAL;
lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
- if (flag & AT_EMPTY_PATH)
- lookup_flags |= LOOKUP_EMPTY;
+ name = getname_uflags(filename, flag);
retry:
- error = user_path_at(dfd, filename, lookup_flags, &path);
+ error = filename_lookup(dfd, name, lookup_flags, &path, NULL);
if (error)
goto out;
error = mnt_want_write(path.mnt);
@@ -826,6 +826,7 @@ int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group,
goto retry;
}
out:
+ putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 04/59] do_utimes_path(): import pathname only once
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (2 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 03/59] do_fchownat(): " Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 05/59] chdir(2): " Al Viro
` (55 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Convert the user_path_at() call inside a retry loop into getname_flags() +
filename_lookup() + putname() and leave only filename_lookup() inside
the loop.
Since we have the default logics for use of LOOKUP_EMPTY (passed iff
AT_EMPTY_PATH is present in flags), just use getname_uflags() and
don't bother with setting LOOKUP_EMPTY in lookup_flags - getname_uflags()
will pass the right thing to getname_flags() and filename_lookup()
doesn't care about LOOKUP_EMPTY at all.
The things could be further simplified by use of cleanup.h stuff, but
let's not clutter the patch with that.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/utimes.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/fs/utimes.c b/fs/utimes.c
index 86f8ce8cd6b1..84889ea1780e 100644
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -8,6 +8,7 @@
#include <linux/compat.h>
#include <asm/unistd.h>
#include <linux/filelock.h>
+#include "internal.h"
static bool nsec_valid(long nsec)
{
@@ -83,27 +84,27 @@ static int do_utimes_path(int dfd, const char __user *filename,
{
struct path path;
int lookup_flags = 0, error;
+ struct filename *name;
if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
return -EINVAL;
if (!(flags & AT_SYMLINK_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;
- if (flags & AT_EMPTY_PATH)
- lookup_flags |= LOOKUP_EMPTY;
+ name = getname_uflags(filename, flags);
retry:
- error = user_path_at(dfd, filename, lookup_flags, &path);
+ error = filename_lookup(dfd, name, lookup_flags, &path, NULL);
if (error)
- return error;
-
+ goto out;
error = vfs_utimes(&path, times);
path_put(&path);
if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
-
+out:
+ putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 05/59] chdir(2): import pathname only once
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (3 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 04/59] do_utimes_path(): " Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 06/59] chroot(2): " Al Viro
` (54 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Convert the user_path_at() call inside a retry loop into getname_flags() +
filename_lookup() + putname() and leave only filename_lookup() inside
the loop.
In this case we never pass LOOKUP_EMPTY, so getname_flags() is equivalent
to plain getname().
The things could be further simplified by use of cleanup.h stuff, but
let's not clutter the patch with that.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/open.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/fs/open.c b/fs/open.c
index a2d775bec8c1..67c114bdeac5 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -555,8 +555,9 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename)
struct path path;
int error;
unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+ struct filename *name = getname(filename);
retry:
- error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
+ error = filename_lookup(AT_FDCWD, name, lookup_flags, &path, NULL);
if (error)
goto out;
@@ -573,6 +574,7 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename)
goto retry;
}
out:
+ putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 06/59] chroot(2): import pathname only once
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (4 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 05/59] chdir(2): " Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 07/59] user_statfs(): " Al Viro
` (53 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Convert the user_path_at() call inside a retry loop into getname_flags() +
filename_lookup() + putname() and leave only filename_lookup() inside
the loop.
In this case we never pass LOOKUP_EMPTY, so getname_flags() is equivalent
to plain getname().
The things could be further simplified by use of cleanup.h stuff, but
let's not clutter the patch with that.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/open.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/fs/open.c b/fs/open.c
index 67c114bdeac5..6f48fa9c756a 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -600,8 +600,9 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
struct path path;
int error;
unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+ struct filename *name = getname(filename);
retry:
- error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
+ error = filename_lookup(AT_FDCWD, name, lookup_flags, &path, NULL);
if (error)
goto out;
@@ -625,6 +626,7 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
goto retry;
}
out:
+ putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 07/59] user_statfs(): import pathname only once
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (5 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 06/59] chroot(2): " Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 08/59] do_sys_truncate(): " Al Viro
` (52 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Convert the user_path_at() call inside a retry loop into getname_flags() +
filename_lookup() + putname() and leave only filename_lookup() inside
the loop.
In this case we never pass LOOKUP_EMPTY, so getname_flags() is equivalent
to plain getname().
The things could be further simplified by use of cleanup.h stuff, but
let's not clutter the patch with that.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/statfs.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/fs/statfs.c b/fs/statfs.c
index a45ac85e6048..a5671bf6c7f0 100644
--- a/fs/statfs.c
+++ b/fs/statfs.c
@@ -99,8 +99,9 @@ int user_statfs(const char __user *pathname, struct kstatfs *st)
struct path path;
int error;
unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT;
+ struct filename *name = getname(pathname);
retry:
- error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
+ error = filename_lookup(AT_FDCWD, name, lookup_flags, &path, NULL);
if (!error) {
error = vfs_statfs(&path, st);
path_put(&path);
@@ -109,6 +110,7 @@ int user_statfs(const char __user *pathname, struct kstatfs *st)
goto retry;
}
}
+ putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 08/59] do_sys_truncate(): import pathname only once
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (6 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 07/59] user_statfs(): " Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 09/59] do_readlinkat(): " Al Viro
` (51 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Convert the user_path_at() call inside a retry loop into getname_flags() +
filename_lookup() + putname() and leave only filename_lookup() inside
the loop.
In this case we never pass LOOKUP_EMPTY, so getname_flags() is equivalent
to plain getname().
The things could be further simplified by use of cleanup.h stuff, but
let's not clutter the patch with that.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/open.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/fs/open.c b/fs/open.c
index 6f48fa9c756a..2fea68991d42 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -129,14 +129,16 @@ EXPORT_SYMBOL_GPL(vfs_truncate);
int do_sys_truncate(const char __user *pathname, loff_t length)
{
unsigned int lookup_flags = LOOKUP_FOLLOW;
+ struct filename *name;
struct path path;
int error;
if (length < 0) /* sorry, but loff_t says... */
return -EINVAL;
+ name = getname(pathname);
retry:
- error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
+ error = filename_lookup(AT_FDCWD, name, lookup_flags, &path, NULL);
if (!error) {
error = vfs_truncate(&path, length);
path_put(&path);
@@ -145,6 +147,7 @@ int do_sys_truncate(const char __user *pathname, loff_t length)
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
+ putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 09/59] do_readlinkat(): import pathname only once
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (7 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 08/59] do_sys_truncate(): " Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 10/59] get rid of audit_reusename() Al Viro
` (50 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Take getname_flags() and putname() outside of retry loop.
Since getname_flags() is the only thing that cares about LOOKUP_EMPTY,
don't bother with setting LOOKUP_EMPTY in lookup_flags - just pass it
to getname_flags() and be done with that.
The things could be further simplified by use of cleanup.h stuff, but
let's not clutter the patch with that.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/stat.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/stat.c b/fs/stat.c
index 6c79661e1b96..ee9ae2c3273a 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -566,13 +566,13 @@ static int do_readlinkat(int dfd, const char __user *pathname,
struct path path;
struct filename *name;
int error;
- unsigned int lookup_flags = LOOKUP_EMPTY;
+ unsigned int lookup_flags = 0;
if (bufsiz <= 0)
return -EINVAL;
+ name = getname_flags(pathname, LOOKUP_EMPTY);
retry:
- name = getname_flags(pathname, lookup_flags);
error = filename_lookup(dfd, name, lookup_flags, &path, NULL);
if (unlikely(error)) {
putname(name);
@@ -593,11 +593,11 @@ static int do_readlinkat(int dfd, const char __user *pathname,
error = (name->name[0] == '\0') ? -ENOENT : -EINVAL;
}
path_put(&path);
- putname(name);
if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
+ putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 10/59] get rid of audit_reusename()
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (8 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 09/59] do_readlinkat(): " Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 11/59] ntfs: ->d_compare() must not block Al Viro
` (49 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Originally we tried to avoid multiple insertions into audit names array
during retry loop by a cute hack - memorize the userland pointer and
if there already is a match, just grab an extra reference to it.
Cute as it had been, it had problems - two identical pointers had
audit aux entries merged, two identical strings did not. Having
different behaviour for syscalls that differ only by addresses of
otherwise identical string arguments is obviously wrong - if nothing
else, compiler can decide to merge identical string literals.
Besides, this hack does nothing for non-audited processes - they get
a fresh copy for retry. It's not time-critical, but having behaviour
subtly differ that way is bogus.
These days we have very few places that import filename more than once
(9 functions total) and it's easy to massage them so we get rid of all
re-imports. With that done, we don't need audit_reusename() anymore.
There's no need to memorize userland pointer either.
Acked-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namei.c | 11 +++--------
include/linux/audit.h | 11 -----------
include/linux/fs.h | 1 -
kernel/auditsc.c | 23 -----------------------
4 files changed, 3 insertions(+), 43 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index bf0f66f0e9b9..f22cfdff72ab 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -125,9 +125,8 @@
#define EMBEDDED_NAME_MAX (PATH_MAX - offsetof(struct filename, iname))
-static inline void initname(struct filename *name, const char __user *uptr)
+static inline void initname(struct filename *name)
{
- name->uptr = uptr;
name->aname = NULL;
atomic_set(&name->refcnt, 1);
}
@@ -139,10 +138,6 @@ getname_flags(const char __user *filename, int flags)
char *kname;
int len;
- result = audit_reusename(filename);
- if (result)
- return result;
-
result = __getname();
if (unlikely(!result))
return ERR_PTR(-ENOMEM);
@@ -210,7 +205,7 @@ getname_flags(const char __user *filename, int flags)
return ERR_PTR(-ENAMETOOLONG);
}
}
- initname(result, filename);
+ initname(result);
audit_getname(result);
return result;
}
@@ -268,7 +263,7 @@ struct filename *getname_kernel(const char * filename)
return ERR_PTR(-ENAMETOOLONG);
}
memcpy((char *)result->name, filename, len);
- initname(result, NULL);
+ initname(result);
audit_getname(result);
return result;
}
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 536f8ee8da81..d936a604d056 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -316,7 +316,6 @@ extern void __audit_uring_exit(int success, long code);
extern void __audit_syscall_entry(int major, unsigned long a0, unsigned long a1,
unsigned long a2, unsigned long a3);
extern void __audit_syscall_exit(int ret_success, long ret_value);
-extern struct filename *__audit_reusename(const __user char *uptr);
extern void __audit_getname(struct filename *name);
extern void __audit_inode(struct filename *name, const struct dentry *dentry,
unsigned int flags);
@@ -380,12 +379,6 @@ static inline void audit_syscall_exit(void *pt_regs)
__audit_syscall_exit(success, return_code);
}
}
-static inline struct filename *audit_reusename(const __user char *name)
-{
- if (unlikely(!audit_dummy_context()))
- return __audit_reusename(name);
- return NULL;
-}
static inline void audit_getname(struct filename *name)
{
if (unlikely(!audit_dummy_context()))
@@ -624,10 +617,6 @@ static inline struct audit_context *audit_context(void)
{
return NULL;
}
-static inline struct filename *audit_reusename(const __user char *name)
-{
- return NULL;
-}
static inline void audit_getname(struct filename *name)
{ }
static inline void audit_inode(struct filename *name,
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 04ceeca12a0d..f48149f3c086 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2411,7 +2411,6 @@ extern struct kobject *fs_kobj;
struct audit_names;
struct filename {
const char *name; /* pointer to actual string */
- const __user char *uptr; /* original userland pointer */
atomic_t refcnt;
struct audit_names *aname;
const char iname[];
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index dd0563a8e0be..67d8da927381 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2169,29 +2169,6 @@ static struct audit_names *audit_alloc_name(struct audit_context *context,
return aname;
}
-/**
- * __audit_reusename - fill out filename with info from existing entry
- * @uptr: userland ptr to pathname
- *
- * Search the audit_names list for the current audit context. If there is an
- * existing entry with a matching "uptr" then return the filename
- * associated with that audit_name. If not, return NULL.
- */
-struct filename *
-__audit_reusename(const __user char *uptr)
-{
- struct audit_context *context = audit_context();
- struct audit_names *n;
-
- list_for_each_entry(n, &context->names_list, list) {
- if (!n->name)
- continue;
- if (n->name->uptr == uptr)
- return refname(n->name);
- }
- return NULL;
-}
-
/**
* __audit_getname - add a name to the list
* @name: name to add
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 11/59] ntfs: ->d_compare() must not block
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (9 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 10/59] get rid of audit_reusename() Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 12/59] getname_flags() massage, part 1 Al Viro
` (48 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
... so don't use __getname() there. Switch it (and ntfs_d_hash(), while
we are at it) to kmalloc(PATH_MAX, GFP_NOWAIT). Yes, ntfs_d_hash()
almost certainly can do with smaller allocations, but let ntfs folks
deal with that - keep the allocation size as-is for now.
Stop abusing names_cachep in ntfs, period - various uses of that thing
in there have nothing to do with pathnames; just use k[mz]alloc() and
be done with that. For now let's keep sizes as-in, but AFAICS none of
the users actually want PATH_MAX.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/ntfs3/inode.c | 6 +++---
fs/ntfs3/namei.c | 8 ++++----
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c
index 0a9ac5efeb67..d9782bdf8681 100644
--- a/fs/ntfs3/inode.c
+++ b/fs/ntfs3/inode.c
@@ -1281,7 +1281,7 @@ int ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
fa |= FILE_ATTRIBUTE_READONLY;
/* Allocate PATH_MAX bytes. */
- new_de = kmem_cache_zalloc(names_cachep, GFP_KERNEL);
+ new_de = kzalloc(PATH_MAX, GFP_KERNEL);
if (!new_de) {
err = -ENOMEM;
goto out1;
@@ -1723,7 +1723,7 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry)
struct NTFS_DE *de;
/* Allocate PATH_MAX bytes. */
- de = kmem_cache_zalloc(names_cachep, GFP_KERNEL);
+ de = kzalloc(PATH_MAX, GFP_KERNEL);
if (!de)
return -ENOMEM;
@@ -1761,7 +1761,7 @@ int ntfs_unlink_inode(struct inode *dir, const struct dentry *dentry)
return -EINVAL;
/* Allocate PATH_MAX bytes. */
- de = kmem_cache_zalloc(names_cachep, GFP_KERNEL);
+ de = kzalloc(PATH_MAX, GFP_KERNEL);
if (!de)
return -ENOMEM;
diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c
index 3b24ca02de61..cc1a701a4c72 100644
--- a/fs/ntfs3/namei.c
+++ b/fs/ntfs3/namei.c
@@ -407,7 +407,7 @@ static int ntfs_d_hash(const struct dentry *dentry, struct qstr *name)
/*
* Try slow way with current upcase table
*/
- uni = kmem_cache_alloc(names_cachep, GFP_NOWAIT);
+ uni = kmalloc(PATH_MAX, GFP_NOWAIT);
if (!uni)
return -ENOMEM;
@@ -429,7 +429,7 @@ static int ntfs_d_hash(const struct dentry *dentry, struct qstr *name)
err = 0;
out:
- kmem_cache_free(names_cachep, uni);
+ kfree(uni);
return err;
}
@@ -468,7 +468,7 @@ static int ntfs_d_compare(const struct dentry *dentry, unsigned int len1,
* Try slow way with current upcase table
*/
sbi = dentry->d_sb->s_fs_info;
- uni1 = __getname();
+ uni1 = kmalloc(PATH_MAX, GFP_NOWAIT);
if (!uni1)
return -ENOMEM;
@@ -498,7 +498,7 @@ static int ntfs_d_compare(const struct dentry *dentry, unsigned int len1,
ret = !ntfs_cmp_names_cpu(uni1, uni2, sbi->upcase, false) ? 0 : 1;
out:
- __putname(uni1);
+ kfree(uni1);
return ret;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 12/59] getname_flags() massage, part 1
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (10 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 11/59] ntfs: ->d_compare() must not block Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 13/59] getname_flags() massage, part 2 Al Viro
` (47 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
In case of long name don't reread what we'd already copied.
memmove() it instead. That avoids the possibility of ending
up with empty name there and the need to look at the flags
on the slow path.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namei.c | 33 ++++++++++++++++-----------------
1 file changed, 16 insertions(+), 17 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index f22cfdff72ab..ea7efbddc7f4 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -174,36 +174,35 @@ getname_flags(const char __user *filename, int flags)
*/
if (unlikely(len == EMBEDDED_NAME_MAX)) {
const size_t size = offsetof(struct filename, iname[1]);
- kname = (char *)result;
+ struct filename *p;
/*
* size is chosen that way we to guarantee that
* result->iname[0] is within the same object and that
* kname can't be equal to result->iname, no matter what.
*/
- result = kzalloc(size, GFP_KERNEL);
- if (unlikely(!result)) {
- __putname(kname);
+ p = kzalloc(size, GFP_KERNEL);
+ if (unlikely(!p)) {
+ __putname(result);
return ERR_PTR(-ENOMEM);
}
- result->name = kname;
- len = strncpy_from_user(kname, filename, PATH_MAX);
+ memmove(result, &result->iname, EMBEDDED_NAME_MAX);
+ kname = (char *)result;
+ p->name = kname;
+ len = strncpy_from_user(kname + EMBEDDED_NAME_MAX,
+ filename + EMBEDDED_NAME_MAX,
+ PATH_MAX - EMBEDDED_NAME_MAX);
if (unlikely(len < 0)) {
- __putname(kname);
- kfree(result);
+ kfree(p);
+ __putname(result);
return ERR_PTR(len);
}
- /* The empty path is special. */
- if (unlikely(!len) && !(flags & LOOKUP_EMPTY)) {
- __putname(kname);
- kfree(result);
- return ERR_PTR(-ENOENT);
- }
- if (unlikely(len == PATH_MAX)) {
- __putname(kname);
- kfree(result);
+ if (unlikely(len == PATH_MAX - EMBEDDED_NAME_MAX)) {
+ kfree(p);
+ __putname(result);
return ERR_PTR(-ENAMETOOLONG);
}
+ result = p;
}
initname(result);
audit_getname(result);
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 13/59] getname_flags() massage, part 2
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (11 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 12/59] getname_flags() massage, part 1 Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 14/59] struct filename: use names_cachep only for getname() and friends Al Viro
` (46 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Take the "long name" case into a helper (getname_long()). In
case of failure have the caller deal with freeing the original
struct filename.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namei.c | 56 ++++++++++++++++++++++++++++--------------------------
1 file changed, 29 insertions(+), 27 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index ea7efbddc7f4..471e4db2dbdb 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -131,6 +131,32 @@ static inline void initname(struct filename *name)
atomic_set(&name->refcnt, 1);
}
+static struct filename *getname_long(struct filename *old,
+ const char __user *filename)
+{
+ int len;
+ /*
+ * size is chosen that way we to guarantee that
+ * p->iname[0] is within the same object and that
+ * p->name can't be equal to p->iname, no matter what.
+ */
+ const size_t size = offsetof(struct filename, iname[1]);
+ struct filename *p __free(kfree) = kzalloc(size, GFP_KERNEL);
+ if (unlikely(!p))
+ return ERR_PTR(-ENOMEM);
+
+ memmove(old, &old->iname, EMBEDDED_NAME_MAX);
+ p->name = (char *)old;
+ len = strncpy_from_user((char *)old + EMBEDDED_NAME_MAX,
+ filename + EMBEDDED_NAME_MAX,
+ PATH_MAX - EMBEDDED_NAME_MAX);
+ if (unlikely(len < 0))
+ return ERR_PTR(len);
+ if (unlikely(len == PATH_MAX - EMBEDDED_NAME_MAX))
+ return ERR_PTR(-ENAMETOOLONG);
+ return no_free_ptr(p);
+}
+
struct filename *
getname_flags(const char __user *filename, int flags)
{
@@ -173,34 +199,10 @@ getname_flags(const char __user *filename, int flags)
* userland.
*/
if (unlikely(len == EMBEDDED_NAME_MAX)) {
- const size_t size = offsetof(struct filename, iname[1]);
- struct filename *p;
-
- /*
- * size is chosen that way we to guarantee that
- * result->iname[0] is within the same object and that
- * kname can't be equal to result->iname, no matter what.
- */
- p = kzalloc(size, GFP_KERNEL);
- if (unlikely(!p)) {
- __putname(result);
- return ERR_PTR(-ENOMEM);
- }
- memmove(result, &result->iname, EMBEDDED_NAME_MAX);
- kname = (char *)result;
- p->name = kname;
- len = strncpy_from_user(kname + EMBEDDED_NAME_MAX,
- filename + EMBEDDED_NAME_MAX,
- PATH_MAX - EMBEDDED_NAME_MAX);
- if (unlikely(len < 0)) {
- kfree(p);
- __putname(result);
- return ERR_PTR(len);
- }
- if (unlikely(len == PATH_MAX - EMBEDDED_NAME_MAX)) {
- kfree(p);
+ struct filename *p = getname_long(result, filename);
+ if (IS_ERR(p)) {
__putname(result);
- return ERR_PTR(-ENAMETOOLONG);
+ return p;
}
result = p;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 14/59] struct filename: use names_cachep only for getname() and friends
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (12 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 13/59] getname_flags() massage, part 2 Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 15/59] struct filename: saner handling of long names Al Viro
` (45 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Instances of struct filename come from names_cachep (via
__getname()). That is done by getname_flags() and getname_kernel()
and these two are the main callers of __getname(). However, there are
other callers that simply want to allocate PATH_MAX bytes for uses that
have nothing to do with struct filename.
We want saner allocation rules for long pathnames, so that struct
filename would *always* come from names_cachep, with the out-of-line
pathname getting kmalloc'ed. For that we need to be able to change the
size of objects allocated by getname_flags()/getname_kernel().
That requires the rest of __getname() users to stop using
names_cachep; we could explicitly switch all of those to kmalloc(),
but that would cause quite a bit of noise. So the plan is to switch
getname_...() to new helpers and turn __getname() into a wrapper for
kmalloc(). Remaining __getname() users could be converted to explicit
kmalloc() at leisure, hopefully along with figuring out what size do
they really want - PATH_MAX is an overkill for some of them, used out
of laziness ("we have a convenient helper that does 4K allocations and
that's large enough, let's use it").
As a side benefit, names_cachep is no longer used outside
of fs/namei.c, so we can move it there and be done with that.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/dcache.c | 8 +-------
fs/internal.h | 2 ++
fs/namei.c | 37 ++++++++++++++++++++++++++++---------
include/linux/fs.h | 6 ++----
4 files changed, 33 insertions(+), 20 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index dc2fff4811d1..cf865c12cdf9 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -3290,10 +3290,6 @@ static void __init dcache_init(void)
runtime_const_init(ptr, dentry_hashtable);
}
-/* SLAB cache for __getname() consumers */
-struct kmem_cache *names_cachep __ro_after_init;
-EXPORT_SYMBOL(names_cachep);
-
void __init vfs_caches_init_early(void)
{
int i;
@@ -3307,9 +3303,7 @@ void __init vfs_caches_init_early(void)
void __init vfs_caches_init(void)
{
- names_cachep = kmem_cache_create_usercopy("names_cache", PATH_MAX, 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, 0, PATH_MAX, NULL);
-
+ filename_init();
dcache_init();
inode_init();
files_init();
diff --git a/fs/internal.h b/fs/internal.h
index ab638d41ab81..e44146117a42 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -71,6 +71,8 @@ struct dentry *start_dirop(struct dentry *parent, struct qstr *name,
unsigned int lookup_flags);
int lookup_noperm_common(struct qstr *qname, struct dentry *base);
+void __init filename_init(void);
+
/*
* namespace.c
*/
diff --git a/fs/namei.c b/fs/namei.c
index 471e4db2dbdb..468e3db62f53 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -125,6 +125,25 @@
#define EMBEDDED_NAME_MAX (PATH_MAX - offsetof(struct filename, iname))
+/* SLAB cache for struct filename instances */
+static struct kmem_cache *names_cachep __ro_after_init;
+
+void __init filename_init(void)
+{
+ names_cachep = kmem_cache_create_usercopy("names_cache", PATH_MAX, 0,
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, 0, PATH_MAX, NULL);
+}
+
+static inline struct filename *alloc_filename(void)
+{
+ return kmem_cache_alloc(names_cachep, GFP_KERNEL);
+}
+
+static inline void free_filename(struct filename *p)
+{
+ kmem_cache_free(names_cachep, p);
+}
+
static inline void initname(struct filename *name)
{
name->aname = NULL;
@@ -164,7 +183,7 @@ getname_flags(const char __user *filename, int flags)
char *kname;
int len;
- result = __getname();
+ result = alloc_filename();
if (unlikely(!result))
return ERR_PTR(-ENOMEM);
@@ -181,13 +200,13 @@ getname_flags(const char __user *filename, int flags)
*/
if (unlikely(len <= 0)) {
if (unlikely(len < 0)) {
- __putname(result);
+ free_filename(result);
return ERR_PTR(len);
}
/* The empty path is special. */
if (!(flags & LOOKUP_EMPTY)) {
- __putname(result);
+ free_filename(result);
return ERR_PTR(-ENOENT);
}
}
@@ -201,7 +220,7 @@ getname_flags(const char __user *filename, int flags)
if (unlikely(len == EMBEDDED_NAME_MAX)) {
struct filename *p = getname_long(result, filename);
if (IS_ERR(p)) {
- __putname(result);
+ free_filename(result);
return p;
}
result = p;
@@ -242,7 +261,7 @@ struct filename *getname_kernel(const char * filename)
struct filename *result;
int len = strlen(filename) + 1;
- result = __getname();
+ result = alloc_filename();
if (unlikely(!result))
return ERR_PTR(-ENOMEM);
@@ -254,13 +273,13 @@ struct filename *getname_kernel(const char * filename)
tmp = kmalloc(size, GFP_KERNEL);
if (unlikely(!tmp)) {
- __putname(result);
+ free_filename(result);
return ERR_PTR(-ENOMEM);
}
tmp->name = (char *)result;
result = tmp;
} else {
- __putname(result);
+ free_filename(result);
return ERR_PTR(-ENAMETOOLONG);
}
memcpy((char *)result->name, filename, len);
@@ -287,10 +306,10 @@ void putname(struct filename *name)
}
if (unlikely(name->name != name->iname)) {
- __putname(name->name);
+ free_filename((struct filename *)name->name);
kfree(name);
} else
- __putname(name);
+ free_filename(name);
}
EXPORT_SYMBOL(putname);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f48149f3c086..c2ce1dc388cb 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2533,10 +2533,8 @@ static inline int finish_open_simple(struct file *file, int error)
extern void __init vfs_caches_init_early(void);
extern void __init vfs_caches_init(void);
-extern struct kmem_cache *names_cachep;
-
-#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL)
-#define __putname(name) kmem_cache_free(names_cachep, (void *)(name))
+#define __getname() kmalloc(PATH_MAX, GFP_KERNEL)
+#define __putname(name) kfree(name)
void emergency_thaw_all(void);
extern int sync_filesystem(struct super_block *);
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 15/59] struct filename: saner handling of long names
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (13 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 14/59] struct filename: use names_cachep only for getname() and friends Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 16/59] fs: hide names_cache behind runtime const machinery Al Viro
` (44 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Always allocate struct filename from names_cachep, long name or short;
short names would be embedded into struct filename. Longer ones do not
cannibalize the original struct filename - put them into PATH_MAX-sized
kmalloc'ed buffers.
Cutoff length for short names is chosen so that struct filename would be
192 bytes long - that's both a multiple of 64 and large enough to cover
the majority of real-world uses.
Simplifies logics in getname()/putname() and friends.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namei.c | 87 ++++++++++++++++++----------------------------
include/linux/fs.h | 10 ++++--
2 files changed, 41 insertions(+), 56 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 468e3db62f53..9053aeee05d5 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -123,15 +123,14 @@
* PATH_MAX includes the nul terminator --RR.
*/
-#define EMBEDDED_NAME_MAX (PATH_MAX - offsetof(struct filename, iname))
-
/* SLAB cache for struct filename instances */
static struct kmem_cache *names_cachep __ro_after_init;
void __init filename_init(void)
{
- names_cachep = kmem_cache_create_usercopy("names_cache", PATH_MAX, 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, 0, PATH_MAX, NULL);
+ names_cachep = kmem_cache_create_usercopy("names_cache", sizeof(struct filename), 0,
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, offsetof(struct filename, iname),
+ EMBEDDED_NAME_MAX, NULL);
}
static inline struct filename *alloc_filename(void)
@@ -150,30 +149,23 @@ static inline void initname(struct filename *name)
atomic_set(&name->refcnt, 1);
}
-static struct filename *getname_long(struct filename *old,
- const char __user *filename)
+static int getname_long(struct filename *name, const char __user *filename)
{
int len;
- /*
- * size is chosen that way we to guarantee that
- * p->iname[0] is within the same object and that
- * p->name can't be equal to p->iname, no matter what.
- */
- const size_t size = offsetof(struct filename, iname[1]);
- struct filename *p __free(kfree) = kzalloc(size, GFP_KERNEL);
+ char *p __free(kfree) = kmalloc(PATH_MAX, GFP_KERNEL);
if (unlikely(!p))
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
- memmove(old, &old->iname, EMBEDDED_NAME_MAX);
- p->name = (char *)old;
- len = strncpy_from_user((char *)old + EMBEDDED_NAME_MAX,
+ memcpy(p, &name->iname, EMBEDDED_NAME_MAX);
+ len = strncpy_from_user(p + EMBEDDED_NAME_MAX,
filename + EMBEDDED_NAME_MAX,
PATH_MAX - EMBEDDED_NAME_MAX);
if (unlikely(len < 0))
- return ERR_PTR(len);
+ return len;
if (unlikely(len == PATH_MAX - EMBEDDED_NAME_MAX))
- return ERR_PTR(-ENAMETOOLONG);
- return no_free_ptr(p);
+ return -ENAMETOOLONG;
+ name->name = no_free_ptr(p);
+ return 0;
}
struct filename *
@@ -199,16 +191,9 @@ getname_flags(const char __user *filename, int flags)
* Handle both empty path and copy failure in one go.
*/
if (unlikely(len <= 0)) {
- if (unlikely(len < 0)) {
- free_filename(result);
- return ERR_PTR(len);
- }
-
/* The empty path is special. */
- if (!(flags & LOOKUP_EMPTY)) {
- free_filename(result);
- return ERR_PTR(-ENOENT);
- }
+ if (!len && !(flags & LOOKUP_EMPTY))
+ len = -ENOENT;
}
/*
@@ -217,14 +202,13 @@ getname_flags(const char __user *filename, int flags)
* names_cache allocation for the pathname, and re-do the copy from
* userland.
*/
- if (unlikely(len == EMBEDDED_NAME_MAX)) {
- struct filename *p = getname_long(result, filename);
- if (IS_ERR(p)) {
- free_filename(result);
- return p;
- }
- result = p;
+ if (unlikely(len == EMBEDDED_NAME_MAX))
+ len = getname_long(result, filename);
+ if (unlikely(len < 0)) {
+ free_filename(result);
+ return ERR_PTR(len);
}
+
initname(result);
audit_getname(result);
return result;
@@ -260,29 +244,26 @@ struct filename *getname_kernel(const char * filename)
{
struct filename *result;
int len = strlen(filename) + 1;
+ char *p;
+
+ if (unlikely(len > PATH_MAX))
+ return ERR_PTR(-ENAMETOOLONG);
result = alloc_filename();
if (unlikely(!result))
return ERR_PTR(-ENOMEM);
if (len <= EMBEDDED_NAME_MAX) {
- result->name = (char *)result->iname;
- } else if (len <= PATH_MAX) {
- const size_t size = offsetof(struct filename, iname[1]);
- struct filename *tmp;
-
- tmp = kmalloc(size, GFP_KERNEL);
- if (unlikely(!tmp)) {
+ p = (char *)result->iname;
+ memcpy(p, filename, len);
+ } else {
+ p = kmemdup(filename, len, GFP_KERNEL);
+ if (unlikely(!p)) {
free_filename(result);
return ERR_PTR(-ENOMEM);
}
- tmp->name = (char *)result;
- result = tmp;
- } else {
- free_filename(result);
- return ERR_PTR(-ENAMETOOLONG);
}
- memcpy((char *)result->name, filename, len);
+ result->name = p;
initname(result);
audit_getname(result);
return result;
@@ -305,11 +286,9 @@ void putname(struct filename *name)
return;
}
- if (unlikely(name->name != name->iname)) {
- free_filename((struct filename *)name->name);
- kfree(name);
- } else
- free_filename(name);
+ if (unlikely(name->name != name->iname))
+ kfree(name->name);
+ free_filename(name);
}
EXPORT_SYMBOL(putname);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c2ce1dc388cb..42f175a4700a 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2409,13 +2409,19 @@ extern struct kobject *fs_kobj;
/* fs/open.c */
struct audit_names;
-struct filename {
+
+struct __filename_head {
const char *name; /* pointer to actual string */
atomic_t refcnt;
struct audit_names *aname;
- const char iname[];
+};
+#define EMBEDDED_NAME_MAX 192 - sizeof(struct __filename_head)
+struct filename {
+ struct __filename_head;
+ const char iname[EMBEDDED_NAME_MAX];
};
static_assert(offsetof(struct filename, iname) % sizeof(long) == 0);
+static_assert(sizeof(struct filename) % 64 == 0);
static inline struct mnt_idmap *file_mnt_idmap(const struct file *file)
{
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 16/59] fs: hide names_cache behind runtime const machinery
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (14 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 15/59] struct filename: saner handling of long names Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 17/59] allow incomplete imports of filenames Al Viro
` (43 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
From: Mateusz Guzik <mjguzik@gmail.com>
s/names_cachep/names_cache/ for consistency with dentry cache.
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namei.c | 16 ++++++++++------
include/asm-generic/vmlinux.lds.h | 3 ++-
2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 9053aeee05d5..15e14802cabb 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -41,6 +41,8 @@
#include <linux/init_task.h>
#include <linux/uaccess.h>
+#include <asm/runtime-const.h>
+
#include "internal.h"
#include "mount.h"
@@ -124,23 +126,25 @@
*/
/* SLAB cache for struct filename instances */
-static struct kmem_cache *names_cachep __ro_after_init;
+static struct kmem_cache *__names_cache __ro_after_init;
+#define names_cache runtime_const_ptr(__names_cache)
void __init filename_init(void)
{
- names_cachep = kmem_cache_create_usercopy("names_cache", sizeof(struct filename), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, offsetof(struct filename, iname),
- EMBEDDED_NAME_MAX, NULL);
+ __names_cache = kmem_cache_create_usercopy("names_cache", sizeof(struct filename), 0,
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, offsetof(struct filename, iname),
+ EMBEDDED_NAME_MAX, NULL);
+ runtime_const_init(ptr, __names_cache);
}
static inline struct filename *alloc_filename(void)
{
- return kmem_cache_alloc(names_cachep, GFP_KERNEL);
+ return kmem_cache_alloc(names_cache, GFP_KERNEL);
}
static inline void free_filename(struct filename *p)
{
- kmem_cache_free(names_cachep, p);
+ kmem_cache_free(names_cache, p);
}
static inline void initname(struct filename *name)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 8ca130af301f..eeb070f330bd 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -972,7 +972,8 @@
#define RUNTIME_CONST_VARIABLES \
RUNTIME_CONST(shift, d_hash_shift) \
RUNTIME_CONST(ptr, dentry_hashtable) \
- RUNTIME_CONST(ptr, __dentry_cache)
+ RUNTIME_CONST(ptr, __dentry_cache) \
+ RUNTIME_CONST(ptr, __names_cache)
/* Alignment must be consistent with (kunit_suite *) in include/kunit/test.h */
#define KUNIT_TABLE() \
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 17/59] allow incomplete imports of filenames
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (15 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 16/59] fs: hide names_cache behind runtime const machinery Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 18/59] struct filename ->refcnt doesn't need to be atomic Al Viro
` (42 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
There are two filename-related problems in io_uring and its
interplay with audit.
Filenames are imported when request is submitted and used when
it is processed. Unfortunately, the latter may very well
happen in a different thread. In that case the reference to
filename is put into the wrong audit_context - that of submitting
thread, not the processing one. Audit logics is called by
the latter, and it really wants to be able to find the names
in audit_context current (== processing) thread.
Another related problem is the headache with refcounts -
normally all references to given struct filename are visible
only to one thread (the one that uses that struct filename).
io_uring violates that - an extra reference is stashed in
audit_context of submitter. It gets dropped when submitter
returns to userland, which can happen simultaneously with
processing thread deciding to drop the reference it got.
We paper over that by making refcount atomic, but that means
pointless headache for everyone.
Solution: the notion of partially imported filenames. Namely,
already copied from userland, but *not* exposed to audit yet.
io_uring can create that in submitter thread, and complete the
import (obtaining the usual reference to struct filename) in
processing thread.
Object: struct delayed_filename.
Primitives for working with it:
delayed_getname(&delayed_filename, user_string) - copies the name
from userland, returning 0 and stashing the address of (still incomplete)
struct filename in delayed_filename on success and returning -E... on
error.
delayed_getname_uflags(&delayed_filename, user_string, atflags) - similar,
in the same relation to delayed_getname() as getname_uflags() is to getname()
complete_getname(&delayed_filename) - completes the import of filename stashed
in delayed_getname and returns struct filename to caller, emptying delayed_getname.
dismiss_delayed_filename(&delayed_filename) - destructor; drops whatever
might be stashed in delayed_getname, emptying it.
putname_to_delayed(&delayed_filename, name) - if name is shared,
stashes its copy into delayed_filename and drops the reference to name,
otherwise stashes the name itself in there.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namei.c | 67 +++++++++++++++++++++++++---
include/linux/fs.h | 11 +++++
io_uring/fs.c | 101 +++++++++++++++++++++++--------------------
io_uring/openclose.c | 26 +++++------
io_uring/statx.c | 17 +++-----
io_uring/xattr.c | 30 +++++--------
6 files changed, 157 insertions(+), 95 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 15e14802cabb..4faaae0239ad 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -172,8 +172,8 @@ static int getname_long(struct filename *name, const char __user *filename)
return 0;
}
-struct filename *
-getname_flags(const char __user *filename, int flags)
+static struct filename *
+do_getname(const char __user *filename, int flags, bool incomplete)
{
struct filename *result;
char *kname;
@@ -214,10 +214,17 @@ getname_flags(const char __user *filename, int flags)
}
initname(result);
- audit_getname(result);
+ if (likely(!incomplete))
+ audit_getname(result);
return result;
}
+struct filename *
+getname_flags(const char __user *filename, int flags)
+{
+ return do_getname(filename, flags, false);
+}
+
struct filename *getname_uflags(const char __user *filename, int uflags)
{
int flags = (uflags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
@@ -244,7 +251,7 @@ struct filename *__getname_maybe_null(const char __user *pathname)
return name;
}
-struct filename *getname_kernel(const char * filename)
+static struct filename *do_getname_kernel(const char *filename, bool incomplete)
{
struct filename *result;
int len = strlen(filename) + 1;
@@ -269,9 +276,15 @@ struct filename *getname_kernel(const char * filename)
}
result->name = p;
initname(result);
- audit_getname(result);
+ if (likely(!incomplete))
+ audit_getname(result);
return result;
}
+
+struct filename *getname_kernel(const char *filename)
+{
+ return do_getname_kernel(filename, false);
+}
EXPORT_SYMBOL(getname_kernel);
void putname(struct filename *name)
@@ -296,6 +309,50 @@ void putname(struct filename *name)
}
EXPORT_SYMBOL(putname);
+static inline int __delayed_getname(struct delayed_filename *v,
+ const char __user *string, int flags)
+{
+ v->__incomplete_filename = do_getname(string, flags, true);
+ return PTR_ERR_OR_ZERO(v->__incomplete_filename);
+}
+
+int delayed_getname(struct delayed_filename *v, const char __user *string)
+{
+ return __delayed_getname(v, string, 0);
+}
+
+int delayed_getname_uflags(struct delayed_filename *v, const char __user *string,
+ int uflags)
+{
+ int flags = (uflags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
+ return __delayed_getname(v, string, flags);
+}
+
+int putname_to_delayed(struct delayed_filename *v, struct filename *__name)
+{
+ struct filename *name __free(putname) = no_free_ptr(__name);
+
+ if (likely(atomic_read(&name->refcnt) == 1)) {
+ v->__incomplete_filename = no_free_ptr(name);
+ return 0;
+ }
+ v->__incomplete_filename = do_getname_kernel(name->name, true);
+ return PTR_ERR_OR_ZERO(v->__incomplete_filename);
+}
+
+void dismiss_delayed_filename(struct delayed_filename *v)
+{
+ putname(no_free_ptr(v->__incomplete_filename));
+}
+
+struct filename *complete_getname(struct delayed_filename *v)
+{
+ struct filename *res = no_free_ptr(v->__incomplete_filename);
+ if (!IS_ERR(res))
+ audit_getname(res);
+ return res;
+}
+
/**
* check_acl - perform ACL permission checking
* @idmap: idmap of the mount the inode was found from
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 42f175a4700a..e446cb8c1e37 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2516,6 +2516,17 @@ static inline struct filename *getname_maybe_null(const char __user *name, int f
extern void putname(struct filename *name);
DEFINE_FREE(putname, struct filename *, if (!IS_ERR_OR_NULL(_T)) putname(_T))
+struct delayed_filename {
+ struct filename *__incomplete_filename; // don't touch
+};
+#define INIT_DELAYED_FILENAME(ptr) \
+ ((void)(*(ptr) = (struct delayed_filename){}))
+int delayed_getname(struct delayed_filename *, const char __user *);
+int delayed_getname_uflags(struct delayed_filename *v, const char __user *, int);
+void dismiss_delayed_filename(struct delayed_filename *);
+int putname_to_delayed(struct delayed_filename *, struct filename *);
+struct filename *complete_getname(struct delayed_filename *);
+
static inline struct filename *refname(struct filename *name)
{
atomic_inc(&name->refcnt);
diff --git a/io_uring/fs.c b/io_uring/fs.c
index 37079a414eab..c04c6282210a 100644
--- a/io_uring/fs.c
+++ b/io_uring/fs.c
@@ -19,8 +19,8 @@ struct io_rename {
struct file *file;
int old_dfd;
int new_dfd;
- struct filename *oldpath;
- struct filename *newpath;
+ struct delayed_filename oldpath;
+ struct delayed_filename newpath;
int flags;
};
@@ -28,22 +28,22 @@ struct io_unlink {
struct file *file;
int dfd;
int flags;
- struct filename *filename;
+ struct delayed_filename filename;
};
struct io_mkdir {
struct file *file;
int dfd;
umode_t mode;
- struct filename *filename;
+ struct delayed_filename filename;
};
struct io_link {
struct file *file;
int old_dfd;
int new_dfd;
- struct filename *oldpath;
- struct filename *newpath;
+ struct delayed_filename oldpath;
+ struct delayed_filename newpath;
int flags;
};
@@ -51,6 +51,7 @@ int io_renameat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
{
struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
const char __user *oldf, *newf;
+ int err;
if (sqe->buf_index || sqe->splice_fd_in)
return -EINVAL;
@@ -63,14 +64,14 @@ int io_renameat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
ren->new_dfd = READ_ONCE(sqe->len);
ren->flags = READ_ONCE(sqe->rename_flags);
- ren->oldpath = getname(oldf);
- if (IS_ERR(ren->oldpath))
- return PTR_ERR(ren->oldpath);
+ err = delayed_getname(&ren->oldpath, oldf);
+ if (unlikely(err))
+ return err;
- ren->newpath = getname(newf);
- if (IS_ERR(ren->newpath)) {
- putname(ren->oldpath);
- return PTR_ERR(ren->newpath);
+ err = delayed_getname(&ren->newpath, newf);
+ if (unlikely(err)) {
+ dismiss_delayed_filename(&ren->oldpath);
+ return err;
}
req->flags |= REQ_F_NEED_CLEANUP;
@@ -85,8 +86,9 @@ int io_renameat(struct io_kiocb *req, unsigned int issue_flags)
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
- ret = do_renameat2(ren->old_dfd, ren->oldpath, ren->new_dfd,
- ren->newpath, ren->flags);
+ ret = do_renameat2(ren->old_dfd, complete_getname(&ren->oldpath),
+ ren->new_dfd, complete_getname(&ren->newpath),
+ ren->flags);
req->flags &= ~REQ_F_NEED_CLEANUP;
io_req_set_res(req, ret, 0);
@@ -97,14 +99,15 @@ void io_renameat_cleanup(struct io_kiocb *req)
{
struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
- putname(ren->oldpath);
- putname(ren->newpath);
+ dismiss_delayed_filename(&ren->oldpath);
+ dismiss_delayed_filename(&ren->newpath);
}
int io_unlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
{
struct io_unlink *un = io_kiocb_to_cmd(req, struct io_unlink);
const char __user *fname;
+ int err;
if (sqe->off || sqe->len || sqe->buf_index || sqe->splice_fd_in)
return -EINVAL;
@@ -118,9 +121,9 @@ int io_unlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
return -EINVAL;
fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
- un->filename = getname(fname);
- if (IS_ERR(un->filename))
- return PTR_ERR(un->filename);
+ err = delayed_getname(&un->filename, fname);
+ if (unlikely(err))
+ return err;
req->flags |= REQ_F_NEED_CLEANUP;
req->flags |= REQ_F_FORCE_ASYNC;
@@ -135,9 +138,9 @@ int io_unlinkat(struct io_kiocb *req, unsigned int issue_flags)
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
if (un->flags & AT_REMOVEDIR)
- ret = do_rmdir(un->dfd, un->filename);
+ ret = do_rmdir(un->dfd, complete_getname(&un->filename));
else
- ret = do_unlinkat(un->dfd, un->filename);
+ ret = do_unlinkat(un->dfd, complete_getname(&un->filename));
req->flags &= ~REQ_F_NEED_CLEANUP;
io_req_set_res(req, ret, 0);
@@ -148,13 +151,14 @@ void io_unlinkat_cleanup(struct io_kiocb *req)
{
struct io_unlink *ul = io_kiocb_to_cmd(req, struct io_unlink);
- putname(ul->filename);
+ dismiss_delayed_filename(&ul->filename);
}
int io_mkdirat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
{
struct io_mkdir *mkd = io_kiocb_to_cmd(req, struct io_mkdir);
const char __user *fname;
+ int err;
if (sqe->off || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
return -EINVAL;
@@ -165,9 +169,9 @@ int io_mkdirat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
mkd->mode = READ_ONCE(sqe->len);
fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
- mkd->filename = getname(fname);
- if (IS_ERR(mkd->filename))
- return PTR_ERR(mkd->filename);
+ err = delayed_getname(&mkd->filename, fname);
+ if (unlikely(err))
+ return err;
req->flags |= REQ_F_NEED_CLEANUP;
req->flags |= REQ_F_FORCE_ASYNC;
@@ -181,7 +185,7 @@ int io_mkdirat(struct io_kiocb *req, unsigned int issue_flags)
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
- ret = do_mkdirat(mkd->dfd, mkd->filename, mkd->mode);
+ ret = do_mkdirat(mkd->dfd, complete_getname(&mkd->filename), mkd->mode);
req->flags &= ~REQ_F_NEED_CLEANUP;
io_req_set_res(req, ret, 0);
@@ -192,13 +196,14 @@ void io_mkdirat_cleanup(struct io_kiocb *req)
{
struct io_mkdir *md = io_kiocb_to_cmd(req, struct io_mkdir);
- putname(md->filename);
+ dismiss_delayed_filename(&md->filename);
}
int io_symlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
{
struct io_link *sl = io_kiocb_to_cmd(req, struct io_link);
const char __user *oldpath, *newpath;
+ int err;
if (sqe->len || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
return -EINVAL;
@@ -209,14 +214,14 @@ int io_symlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
oldpath = u64_to_user_ptr(READ_ONCE(sqe->addr));
newpath = u64_to_user_ptr(READ_ONCE(sqe->addr2));
- sl->oldpath = getname(oldpath);
- if (IS_ERR(sl->oldpath))
- return PTR_ERR(sl->oldpath);
+ err = delayed_getname(&sl->oldpath, oldpath);
+ if (unlikely(err))
+ return err;
- sl->newpath = getname(newpath);
- if (IS_ERR(sl->newpath)) {
- putname(sl->oldpath);
- return PTR_ERR(sl->newpath);
+ err = delayed_getname(&sl->newpath, newpath);
+ if (unlikely(err)) {
+ dismiss_delayed_filename(&sl->oldpath);
+ return err;
}
req->flags |= REQ_F_NEED_CLEANUP;
@@ -231,7 +236,8 @@ int io_symlinkat(struct io_kiocb *req, unsigned int issue_flags)
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
- ret = do_symlinkat(sl->oldpath, sl->new_dfd, sl->newpath);
+ ret = do_symlinkat(complete_getname(&sl->oldpath), sl->new_dfd,
+ complete_getname(&sl->newpath));
req->flags &= ~REQ_F_NEED_CLEANUP;
io_req_set_res(req, ret, 0);
@@ -242,6 +248,7 @@ int io_linkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
{
struct io_link *lnk = io_kiocb_to_cmd(req, struct io_link);
const char __user *oldf, *newf;
+ int err;
if (sqe->buf_index || sqe->splice_fd_in)
return -EINVAL;
@@ -254,14 +261,14 @@ int io_linkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
newf = u64_to_user_ptr(READ_ONCE(sqe->addr2));
lnk->flags = READ_ONCE(sqe->hardlink_flags);
- lnk->oldpath = getname_uflags(oldf, lnk->flags);
- if (IS_ERR(lnk->oldpath))
- return PTR_ERR(lnk->oldpath);
+ err = delayed_getname_uflags(&lnk->oldpath, oldf, lnk->flags);
+ if (unlikely(err))
+ return err;
- lnk->newpath = getname(newf);
- if (IS_ERR(lnk->newpath)) {
- putname(lnk->oldpath);
- return PTR_ERR(lnk->newpath);
+ err = delayed_getname(&lnk->newpath, newf);
+ if (unlikely(err)) {
+ dismiss_delayed_filename(&lnk->oldpath);
+ return err;
}
req->flags |= REQ_F_NEED_CLEANUP;
@@ -276,8 +283,8 @@ int io_linkat(struct io_kiocb *req, unsigned int issue_flags)
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
- ret = do_linkat(lnk->old_dfd, lnk->oldpath, lnk->new_dfd,
- lnk->newpath, lnk->flags);
+ ret = do_linkat(lnk->old_dfd, complete_getname(&lnk->oldpath),
+ lnk->new_dfd, complete_getname(&lnk->newpath), lnk->flags);
req->flags &= ~REQ_F_NEED_CLEANUP;
io_req_set_res(req, ret, 0);
@@ -288,6 +295,6 @@ void io_link_cleanup(struct io_kiocb *req)
{
struct io_link *sl = io_kiocb_to_cmd(req, struct io_link);
- putname(sl->oldpath);
- putname(sl->newpath);
+ dismiss_delayed_filename(&sl->oldpath);
+ dismiss_delayed_filename(&sl->newpath);
}
diff --git a/io_uring/openclose.c b/io_uring/openclose.c
index bfeb91b31bba..95ba8c5b5fc8 100644
--- a/io_uring/openclose.c
+++ b/io_uring/openclose.c
@@ -23,7 +23,7 @@ struct io_open {
struct file *file;
int dfd;
u32 file_slot;
- struct filename *filename;
+ struct delayed_filename filename;
struct open_how how;
unsigned long nofile;
};
@@ -67,12 +67,9 @@ static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
open->dfd = READ_ONCE(sqe->fd);
fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
- open->filename = getname(fname);
- if (IS_ERR(open->filename)) {
- ret = PTR_ERR(open->filename);
- open->filename = NULL;
+ ret = delayed_getname(&open->filename, fname);
+ if (unlikely(ret))
return ret;
- }
open->file_slot = READ_ONCE(sqe->file_index);
if (open->file_slot && (open->how.flags & O_CLOEXEC))
@@ -121,6 +118,7 @@ int io_openat2(struct io_kiocb *req, unsigned int issue_flags)
struct file *file;
bool resolve_nonblock, nonblock_set;
bool fixed = !!open->file_slot;
+ struct filename *name __free(putname) = complete_getname(&open->filename);
int ret;
ret = build_open_flags(&open->how, &op);
@@ -140,7 +138,7 @@ int io_openat2(struct io_kiocb *req, unsigned int issue_flags)
goto err;
}
- file = do_filp_open(open->dfd, open->filename, &op);
+ file = do_filp_open(open->dfd, name, &op);
if (IS_ERR(file)) {
/*
* We could hang on to this 'fd' on retrying, but seems like
@@ -152,9 +150,13 @@ int io_openat2(struct io_kiocb *req, unsigned int issue_flags)
ret = PTR_ERR(file);
/* only retry if RESOLVE_CACHED wasn't already set by application */
- if (ret == -EAGAIN &&
- (!resolve_nonblock && (issue_flags & IO_URING_F_NONBLOCK)))
- return -EAGAIN;
+ if (ret == -EAGAIN && !resolve_nonblock &&
+ (issue_flags & IO_URING_F_NONBLOCK)) {
+ ret = putname_to_delayed(&open->filename,
+ no_free_ptr(name));
+ if (likely(!ret))
+ return -EAGAIN;
+ }
goto err;
}
@@ -167,7 +169,6 @@ int io_openat2(struct io_kiocb *req, unsigned int issue_flags)
ret = io_fixed_fd_install(req, issue_flags, file,
open->file_slot);
err:
- putname(open->filename);
req->flags &= ~REQ_F_NEED_CLEANUP;
if (ret < 0)
req_set_fail(req);
@@ -184,8 +185,7 @@ void io_open_cleanup(struct io_kiocb *req)
{
struct io_open *open = io_kiocb_to_cmd(req, struct io_open);
- if (open->filename)
- putname(open->filename);
+ dismiss_delayed_filename(&open->filename);
}
int __io_close_fixed(struct io_ring_ctx *ctx, unsigned int issue_flags,
diff --git a/io_uring/statx.c b/io_uring/statx.c
index 5111e9befbfe..dc10b48bcde6 100644
--- a/io_uring/statx.c
+++ b/io_uring/statx.c
@@ -16,7 +16,7 @@ struct io_statx {
int dfd;
unsigned int mask;
unsigned int flags;
- struct filename *filename;
+ struct delayed_filename filename;
struct statx __user *buffer;
};
@@ -24,6 +24,7 @@ int io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
{
struct io_statx *sx = io_kiocb_to_cmd(req, struct io_statx);
const char __user *path;
+ int ret;
if (sqe->buf_index || sqe->splice_fd_in)
return -EINVAL;
@@ -36,14 +37,10 @@ int io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
sx->buffer = u64_to_user_ptr(READ_ONCE(sqe->addr2));
sx->flags = READ_ONCE(sqe->statx_flags);
- sx->filename = getname_uflags(path, sx->flags);
-
- if (IS_ERR(sx->filename)) {
- int ret = PTR_ERR(sx->filename);
+ ret = delayed_getname_uflags(&sx->filename, path, sx->flags);
- sx->filename = NULL;
+ if (unlikely(ret))
return ret;
- }
req->flags |= REQ_F_NEED_CLEANUP;
req->flags |= REQ_F_FORCE_ASYNC;
@@ -53,11 +50,12 @@ int io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
int io_statx(struct io_kiocb *req, unsigned int issue_flags)
{
struct io_statx *sx = io_kiocb_to_cmd(req, struct io_statx);
+ struct filename *name __free(putname) = complete_getname(&sx->filename);
int ret;
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
- ret = do_statx(sx->dfd, sx->filename, sx->flags, sx->mask, sx->buffer);
+ ret = do_statx(sx->dfd, name, sx->flags, sx->mask, sx->buffer);
io_req_set_res(req, ret, 0);
return IOU_COMPLETE;
}
@@ -66,6 +64,5 @@ void io_statx_cleanup(struct io_kiocb *req)
{
struct io_statx *sx = io_kiocb_to_cmd(req, struct io_statx);
- if (sx->filename)
- putname(sx->filename);
+ dismiss_delayed_filename(&sx->filename);
}
diff --git a/io_uring/xattr.c b/io_uring/xattr.c
index 322b94ff9e4b..0fb4e5303500 100644
--- a/io_uring/xattr.c
+++ b/io_uring/xattr.c
@@ -19,16 +19,14 @@
struct io_xattr {
struct file *file;
struct kernel_xattr_ctx ctx;
- struct filename *filename;
+ struct delayed_filename filename;
};
void io_xattr_cleanup(struct io_kiocb *req)
{
struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
- if (ix->filename)
- putname(ix->filename);
-
+ dismiss_delayed_filename(&ix->filename);
kfree(ix->ctx.kname);
kvfree(ix->ctx.kvalue);
}
@@ -48,7 +46,7 @@ static int __io_getxattr_prep(struct io_kiocb *req,
const char __user *name;
int ret;
- ix->filename = NULL;
+ INIT_DELAYED_FILENAME(&ix->filename);
ix->ctx.kvalue = NULL;
name = u64_to_user_ptr(READ_ONCE(sqe->addr));
ix->ctx.value = u64_to_user_ptr(READ_ONCE(sqe->addr2));
@@ -93,11 +91,7 @@ int io_getxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
path = u64_to_user_ptr(READ_ONCE(sqe->addr3));
- ix->filename = getname(path);
- if (IS_ERR(ix->filename))
- return PTR_ERR(ix->filename);
-
- return 0;
+ return delayed_getname(&ix->filename, path);
}
int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags)
@@ -119,8 +113,8 @@ int io_getxattr(struct io_kiocb *req, unsigned int issue_flags)
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
- ret = filename_getxattr(AT_FDCWD, ix->filename, LOOKUP_FOLLOW, &ix->ctx);
- ix->filename = NULL;
+ ret = filename_getxattr(AT_FDCWD, complete_getname(&ix->filename),
+ LOOKUP_FOLLOW, &ix->ctx);
io_xattr_finish(req, ret);
return IOU_COMPLETE;
}
@@ -132,7 +126,7 @@ static int __io_setxattr_prep(struct io_kiocb *req,
const char __user *name;
int ret;
- ix->filename = NULL;
+ INIT_DELAYED_FILENAME(&ix->filename);
name = u64_to_user_ptr(READ_ONCE(sqe->addr));
ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2));
ix->ctx.kvalue = NULL;
@@ -169,11 +163,7 @@ int io_setxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
path = u64_to_user_ptr(READ_ONCE(sqe->addr3));
- ix->filename = getname(path);
- if (IS_ERR(ix->filename))
- return PTR_ERR(ix->filename);
-
- return 0;
+ return delayed_getname(&ix->filename, path);
}
int io_fsetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
@@ -200,8 +190,8 @@ int io_setxattr(struct io_kiocb *req, unsigned int issue_flags)
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
- ret = filename_setxattr(AT_FDCWD, ix->filename, LOOKUP_FOLLOW, &ix->ctx);
- ix->filename = NULL;
+ ret = filename_setxattr(AT_FDCWD, complete_getname(&ix->filename),
+ LOOKUP_FOLLOW, &ix->ctx);
io_xattr_finish(req, ret);
return IOU_COMPLETE;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 18/59] struct filename ->refcnt doesn't need to be atomic
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (16 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 17/59] allow incomplete imports of filenames Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 19/59] allow to use CLASS() for struct filename * Al Viro
` (41 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
... or visible outside of audit, really. Note that references
held in delayed_filename always have refcount 1, and from the
moment of complete_getname() or equivalent point in getname...()
there won't be any references to struct filename instance left
in places visible to other threads.
Acked-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namei.c | 10 +++++-----
include/linux/fs.h | 8 +-------
kernel/auditsc.c | 6 ++++++
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 4faaae0239ad..192d31acb4ff 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -150,7 +150,7 @@ static inline void free_filename(struct filename *p)
static inline void initname(struct filename *name)
{
name->aname = NULL;
- atomic_set(&name->refcnt, 1);
+ name->refcnt = 1;
}
static int getname_long(struct filename *name, const char __user *filename)
@@ -294,13 +294,13 @@ void putname(struct filename *name)
if (IS_ERR_OR_NULL(name))
return;
- refcnt = atomic_read(&name->refcnt);
+ refcnt = name->refcnt;
if (unlikely(refcnt != 1)) {
if (WARN_ON_ONCE(!refcnt))
return;
- if (!atomic_dec_and_test(&name->refcnt))
- return;
+ name->refcnt--;
+ return;
}
if (unlikely(name->name != name->iname))
@@ -332,7 +332,7 @@ int putname_to_delayed(struct delayed_filename *v, struct filename *__name)
{
struct filename *name __free(putname) = no_free_ptr(__name);
- if (likely(atomic_read(&name->refcnt) == 1)) {
+ if (likely(name->refcnt == 1)) {
v->__incomplete_filename = no_free_ptr(name);
return 0;
}
diff --git a/include/linux/fs.h b/include/linux/fs.h
index e446cb8c1e37..b711f46ba8f5 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2412,7 +2412,7 @@ struct audit_names;
struct __filename_head {
const char *name; /* pointer to actual string */
- atomic_t refcnt;
+ int refcnt;
struct audit_names *aname;
};
#define EMBEDDED_NAME_MAX 192 - sizeof(struct __filename_head)
@@ -2527,12 +2527,6 @@ void dismiss_delayed_filename(struct delayed_filename *);
int putname_to_delayed(struct delayed_filename *, struct filename *);
struct filename *complete_getname(struct delayed_filename *);
-static inline struct filename *refname(struct filename *name)
-{
- atomic_inc(&name->refcnt);
- return name;
-}
-
extern int finish_open(struct file *file, struct dentry *dentry,
int (*open)(struct inode *, struct file *));
extern int finish_no_open(struct file *file, struct dentry *dentry);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 67d8da927381..b1dc9284550a 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2169,6 +2169,12 @@ static struct audit_names *audit_alloc_name(struct audit_context *context,
return aname;
}
+static inline struct filename *refname(struct filename *name)
+{
+ name->refcnt++;
+ return name;
+}
+
/**
* __audit_getname - add a name to the list
* @name: name to add
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 19/59] allow to use CLASS() for struct filename *
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (17 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 18/59] struct filename ->refcnt doesn't need to be atomic Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 20/59] file_getattr(): filename_lookup() accepts ERR_PTR() as filename Al Viro
` (40 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Not all users match that model, but quite a few do. No mindless
mass conversions, please...
Added:
CLASS(filename, name)(user_path) =>
getname(user_path)
CLASS(filename_kernel, name)(string) =>
getname_kernel(string)
CLASS(filename_flags, name)(user_path, flags) =>
getname_flags(user_path, flags)
CLASS(filename_uflags, name)(user_path, flags) =>
getname_uflags(user_path, flags)
CLASS(filename_maybe_null, name)(user_path, flags) =>
getname_maybe_null(user_path, flags)
CLASS(filename_complete_delayed, name)(delayed) =>
complete_getname(delayed)
CLASS(filename_consume, name)(filename) =>
no_free_ptr(filename)
all with putname() as destructor.
"flags" in filename_flags() is in LOOKUP_... space, only LOOKUP_EMPTY matters.
"flags" in filename_uflags() and filename_maybe_null() is in AT_...... space,
and only AT_EMPTY_PATH matters.
These conventions might be worth reconsidering...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
include/linux/fs.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b711f46ba8f5..db0d89dd1229 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2527,6 +2527,14 @@ void dismiss_delayed_filename(struct delayed_filename *);
int putname_to_delayed(struct delayed_filename *, struct filename *);
struct filename *complete_getname(struct delayed_filename *);
+DEFINE_CLASS(filename, struct filename *, putname(_T), getname(p), const char __user *p)
+EXTEND_CLASS(filename, _kernel, getname_kernel(p), const char *p)
+EXTEND_CLASS(filename, _flags, getname_flags(p, f), const char __user *p, unsigned int f)
+EXTEND_CLASS(filename, _uflags, getname_uflags(p, f), const char __user *p, unsigned int f)
+EXTEND_CLASS(filename, _maybe_null, getname_maybe_null(p, f), const char __user *p, unsigned int f)
+EXTEND_CLASS(filename, _consume, no_free_ptr(p), struct filename *p)
+EXTEND_CLASS(filename, _complete_delayed, complete_getname(p), struct delayed_filename *p)
+
extern int finish_open(struct file *file, struct dentry *dentry,
int (*open)(struct inode *, struct file *));
extern int finish_no_open(struct file *file, struct dentry *dentry);
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 20/59] file_getattr(): filename_lookup() accepts ERR_PTR() as filename
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (18 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 19/59] allow to use CLASS() for struct filename * Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 21/59] file_setattr(): " Al Viro
` (39 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
no need to check it in the caller
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/file_attr.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/fs/file_attr.c b/fs/file_attr.c
index 4c4916632f11..f9e4d4014afc 100644
--- a/fs/file_attr.c
+++ b/fs/file_attr.c
@@ -394,9 +394,6 @@ SYSCALL_DEFINE5(file_getattr, int, dfd, const char __user *, filename,
return -EINVAL;
name = getname_maybe_null(filename, at_flags);
- if (IS_ERR(name))
- return PTR_ERR(name);
-
if (!name && dfd >= 0) {
CLASS(fd, f)(dfd);
if (fd_empty(f))
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 21/59] file_setattr(): filename_lookup() accepts ERR_PTR() as filename
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (19 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 20/59] file_getattr(): filename_lookup() accepts ERR_PTR() as filename Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 22/59] move_mount(): " Al Viro
` (38 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
no need to check it in the caller
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/file_attr.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/fs/file_attr.c b/fs/file_attr.c
index f9e4d4014afc..915e9a40cd42 100644
--- a/fs/file_attr.c
+++ b/fs/file_attr.c
@@ -457,9 +457,6 @@ SYSCALL_DEFINE5(file_setattr, int, dfd, const char __user *, filename,
return error;
name = getname_maybe_null(filename, at_flags);
- if (IS_ERR(name))
- return PTR_ERR(name);
-
if (!name && dfd >= 0) {
CLASS(fd, f)(dfd);
if (fd_empty(f))
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 22/59] move_mount(): filename_lookup() accepts ERR_PTR() as filename
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (20 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 21/59] file_setattr(): " Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 23/59] ksmbd_vfs_path_lookup(): vfs_path_parent_lookup() accepts ERR_PTR() as name Al Viro
` (37 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
no need to check it in the caller
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namespace.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index c58674a20cad..9d0d8ed16264 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -4427,9 +4427,6 @@ SYSCALL_DEFINE5(move_mount,
uflags = AT_EMPTY_PATH;
to_name = getname_maybe_null(to_pathname, uflags);
- if (IS_ERR(to_name))
- return PTR_ERR(to_name);
-
if (!to_name && to_dfd >= 0) {
CLASS(fd_raw, f_to)(to_dfd);
if (fd_empty(f_to))
@@ -4453,9 +4450,6 @@ SYSCALL_DEFINE5(move_mount,
uflags = AT_EMPTY_PATH;
from_name = getname_maybe_null(from_pathname, uflags);
- if (IS_ERR(from_name))
- return PTR_ERR(from_name);
-
if (!from_name && from_dfd >= 0) {
CLASS(fd_raw, f_from)(from_dfd);
if (fd_empty(f_from))
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 23/59] ksmbd_vfs_path_lookup(): vfs_path_parent_lookup() accepts ERR_PTR() as name
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (21 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 22/59] move_mount(): " Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 24/59] ksmbd_vfs_rename(): " Al Viro
` (36 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
no need to check in the caller
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/smb/server/vfs.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index 98b0eb966d91..e874b27666a1 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -67,9 +67,6 @@ static int ksmbd_vfs_path_lookup(struct ksmbd_share_config *share_conf,
}
filename = getname_kernel(pathname);
- if (IS_ERR(filename))
- return PTR_ERR(filename);
-
err = vfs_path_parent_lookup(filename, flags,
path, &last, &type,
root_share_path);
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 24/59] ksmbd_vfs_rename(): vfs_path_parent_lookup() accepts ERR_PTR() as name
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (22 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 23/59] ksmbd_vfs_path_lookup(): vfs_path_parent_lookup() accepts ERR_PTR() as name Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 25/59] do_filp_open(): DTRT when getting ERR_PTR() as pathname Al Viro
` (35 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
no need to check in the caller
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/smb/server/vfs.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index e874b27666a1..abfaebcf8cde 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -674,10 +674,6 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
return -ENOMEM;
to = getname_kernel(newname);
- if (IS_ERR(to)) {
- err = PTR_ERR(to);
- goto revert_fsids;
- }
retry:
err = vfs_path_parent_lookup(to, lookup_flags | LOOKUP_BENEATH,
@@ -737,7 +733,6 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
}
out1:
putname(to);
-revert_fsids:
ksmbd_revert_fsids(work);
return err;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 25/59] do_filp_open(): DTRT when getting ERR_PTR() as pathname
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (23 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 24/59] ksmbd_vfs_rename(): " Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 26/59] rename do_filp_open() to do_file_open() Al Viro
` (34 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
The rest of the set_nameidata() callers treat IS_ERR(pathname) as
"bail out immediately with PTR_ERR(pathname) as error". Makes
life simpler for callers; do_filp_open() is the only exception
and its callers would also benefit from such calling conventions
change.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namei.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/fs/namei.c b/fs/namei.c
index 192d31acb4ff..af7fd253a712 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4865,6 +4865,8 @@ struct file *do_filp_open(int dfd, struct filename *pathname,
int flags = op->lookup_flags;
struct file *filp;
+ if (IS_ERR(pathname))
+ return ERR_CAST(pathname);
set_nameidata(&nd, dfd, pathname, NULL);
filp = path_openat(&nd, op, flags | LOOKUP_RCU);
if (unlikely(filp == ERR_PTR(-ECHILD)))
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 26/59] rename do_filp_open() to do_file_open()
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (24 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 25/59] do_filp_open(): DTRT when getting ERR_PTR() as pathname Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 27/59] do_sys_openat2(): get rid of useless check, switch to CLASS(filename) Al Viro
` (33 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
"filp" thing never made sense; seeing that there are exactly 4 callers
in the entire tree (and it's neither exported nor even declared in
linux/*/*.h), there's no point keeping that ugliness.
FWIW, the 'filp' thing did originate in OSD&I; for some reason Tanenbaum
decided to call the object representing an opened file 'struct filp',
the last letter standing for 'position'. In all Unices, Linux included,
the corresponding object had always been 'struct file'...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/exec.c | 2 +-
fs/internal.h | 2 +-
fs/namei.c | 2 +-
fs/open.c | 4 ++--
io_uring/openclose.c | 2 +-
5 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/fs/exec.c b/fs/exec.c
index 9d5ebc9d15b0..b7d8081d12ea 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -780,7 +780,7 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
if (flags & AT_EMPTY_PATH)
open_exec_flags.lookup_flags |= LOOKUP_EMPTY;
- file = do_filp_open(fd, name, &open_exec_flags);
+ file = do_file_open(fd, name, &open_exec_flags);
if (IS_ERR(file))
return file;
diff --git a/fs/internal.h b/fs/internal.h
index e44146117a42..5c3e4eac34f2 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -189,7 +189,7 @@ struct open_flags {
int intent;
int lookup_flags;
};
-extern struct file *do_filp_open(int dfd, struct filename *pathname,
+extern struct file *do_file_open(int dfd, struct filename *pathname,
const struct open_flags *op);
extern struct file *do_file_open_root(const struct path *,
const char *, const struct open_flags *);
diff --git a/fs/namei.c b/fs/namei.c
index af7fd253a712..f6b5d6a657da 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4858,7 +4858,7 @@ static struct file *path_openat(struct nameidata *nd,
return ERR_PTR(error);
}
-struct file *do_filp_open(int dfd, struct filename *pathname,
+struct file *do_file_open(int dfd, struct filename *pathname,
const struct open_flags *op)
{
struct nameidata nd;
diff --git a/fs/open.c b/fs/open.c
index 2fea68991d42..3d2e2a2554c5 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -1382,7 +1382,7 @@ struct file *file_open_name(struct filename *name, int flags, umode_t mode)
int err = build_open_flags(&how, &op);
if (err)
return ERR_PTR(err);
- return do_filp_open(AT_FDCWD, name, &op);
+ return do_file_open(AT_FDCWD, name, &op);
}
/**
@@ -1436,7 +1436,7 @@ static int do_sys_openat2(int dfd, const char __user *filename,
if (IS_ERR(tmp))
return PTR_ERR(tmp);
- return FD_ADD(how->flags, do_filp_open(dfd, tmp, &op));
+ return FD_ADD(how->flags, do_file_open(dfd, tmp, &op));
}
int do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
diff --git a/io_uring/openclose.c b/io_uring/openclose.c
index 95ba8c5b5fc8..95fcb612ad9c 100644
--- a/io_uring/openclose.c
+++ b/io_uring/openclose.c
@@ -138,7 +138,7 @@ int io_openat2(struct io_kiocb *req, unsigned int issue_flags)
goto err;
}
- file = do_filp_open(open->dfd, name, &op);
+ file = do_file_open(open->dfd, name, &op);
if (IS_ERR(file)) {
/*
* We could hang on to this 'fd' on retrying, but seems like
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 27/59] do_sys_openat2(): get rid of useless check, switch to CLASS(filename)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (25 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 26/59] rename do_filp_open() to do_file_open() Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 20:08 ` Askar Safin
2025-12-16 3:54 ` [RFC PATCH v3 28/59] simplify the callers of file_open_name() Al Viro
` (32 subsequent siblings)
59 siblings, 1 reply; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
do_file_open() will do the right thing is given ERR_PTR() for name...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/open.c | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index 3d2e2a2554c5..ac8dedea8daf 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -1425,18 +1425,12 @@ static int do_sys_openat2(int dfd, const char __user *filename,
struct open_how *how)
{
struct open_flags op;
- struct filename *tmp __free(putname) = NULL;
- int err;
-
- err = build_open_flags(how, &op);
+ int err = build_open_flags(how, &op);
if (unlikely(err))
return err;
- tmp = getname(filename);
- if (IS_ERR(tmp))
- return PTR_ERR(tmp);
-
- return FD_ADD(how->flags, do_file_open(dfd, tmp, &op));
+ CLASS(filename, name)(filename);
+ return FD_ADD(how->flags, do_file_open(dfd, name, &op));
}
int do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* Re: [RFC PATCH v3 27/59] do_sys_openat2(): get rid of useless check, switch to CLASS(filename)
2025-12-16 3:54 ` [RFC PATCH v3 27/59] do_sys_openat2(): get rid of useless check, switch to CLASS(filename) Al Viro
@ 2025-12-16 20:08 ` Askar Safin
2025-12-16 20:29 ` Al Viro
0 siblings, 1 reply; 64+ messages in thread
From: Askar Safin @ 2025-12-16 20:08 UTC (permalink / raw)
To: viro
Cc: audit, axboe, brauner, io-uring, jack, linux-fsdevel,
linux-kernel, mjguzik, paul, torvalds
Al Viro <viro@zeniv.linux.org.uk>:
> do_file_open() will do the right thing is given ERR_PTR() for name...
Maybe you meant "right thing if given"?
--
Askar Safin
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [RFC PATCH v3 27/59] do_sys_openat2(): get rid of useless check, switch to CLASS(filename)
2025-12-16 20:08 ` Askar Safin
@ 2025-12-16 20:29 ` Al Viro
0 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 20:29 UTC (permalink / raw)
To: Askar Safin
Cc: audit, axboe, brauner, io-uring, jack, linux-fsdevel,
linux-kernel, mjguzik, paul, torvalds
On Tue, Dec 16, 2025 at 11:08:58PM +0300, Askar Safin wrote:
> Al Viro <viro@zeniv.linux.org.uk>:
> > do_file_open() will do the right thing is given ERR_PTR() for name...
>
> Maybe you meant "right thing if given"?
d'oh...
^ permalink raw reply [flat|nested] 64+ messages in thread
* [RFC PATCH v3 28/59] simplify the callers of file_open_name()
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (26 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 27/59] do_sys_openat2(): get rid of useless check, switch to CLASS(filename) Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 29/59] simplify the callers of do_open_execat() Al Viro
` (31 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
It accepts ERR_PTR() for name and does the right thing in that case.
That allows to simplify the logics in callers, making them trivial
to switch to CLASS(filename).
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/open.c | 10 ++--------
kernel/acct.c | 4 +---
mm/huge_memory.c | 15 +++------------
mm/swapfile.c | 21 +++------------------
4 files changed, 9 insertions(+), 41 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index ac8dedea8daf..7254eda9f4a5 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -1398,14 +1398,8 @@ struct file *file_open_name(struct filename *name, int flags, umode_t mode)
*/
struct file *filp_open(const char *filename, int flags, umode_t mode)
{
- struct filename *name = getname_kernel(filename);
- struct file *file = ERR_CAST(name);
-
- if (!IS_ERR(name)) {
- file = file_open_name(name, flags, mode);
- putname(name);
- }
- return file;
+ CLASS(filename_kernel, name)(filename);
+ return file_open_name(name, flags, mode);
}
EXPORT_SYMBOL(filp_open);
diff --git a/kernel/acct.c b/kernel/acct.c
index 2a2b3c874acd..812808e5b1b8 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -218,7 +218,6 @@ static int acct_on(const char __user *name)
/* Difference from BSD - they don't do O_APPEND */
const int open_flags = O_WRONLY|O_APPEND|O_LARGEFILE;
struct pid_namespace *ns = task_active_pid_ns(current);
- struct filename *pathname __free(putname) = getname(name);
struct file *original_file __free(fput) = NULL; // in that order
struct path internal __free(path_put) = {}; // in that order
struct file *file __free(fput_sync) = NULL; // in that order
@@ -226,8 +225,7 @@ static int acct_on(const char __user *name)
struct vfsmount *mnt;
struct fs_pin *old;
- if (IS_ERR(pathname))
- return PTR_ERR(pathname);
+ CLASS(filename, pathname)(name);
original_file = file_open_name(pathname, open_flags, 0);
if (IS_ERR(original_file))
return PTR_ERR(original_file);
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 40cf59301c21..a6d37902b73d 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -4692,23 +4692,18 @@ static int split_huge_pages_in_file(const char *file_path, pgoff_t off_start,
pgoff_t off_end, unsigned int new_order,
long in_folio_offset)
{
- struct filename *file;
struct file *candidate;
struct address_space *mapping;
- int ret = -EINVAL;
pgoff_t index;
int nr_pages = 1;
unsigned long total = 0, split = 0;
unsigned int min_order;
unsigned int target_order;
- file = getname_kernel(file_path);
- if (IS_ERR(file))
- return ret;
-
+ CLASS(filename_kernel, file)(file_path);
candidate = file_open_name(file, O_RDONLY, 0);
if (IS_ERR(candidate))
- goto out;
+ return -EINVAL;
pr_debug("split file-backed THPs in file: %s, page offset: [0x%lx - 0x%lx], new_order: %u, in_folio_offset: %ld\n",
file_path, off_start, off_end, new_order, in_folio_offset);
@@ -4757,12 +4752,8 @@ static int split_huge_pages_in_file(const char *file_path, pgoff_t off_start,
}
filp_close(candidate, NULL);
- ret = 0;
-
pr_debug("%lu of %lu file-backed THP split\n", split, total);
-out:
- putname(file);
- return ret;
+ return 0;
}
#define MAX_INPUT_BUF_SZ 255
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 46d2008e4b99..25120cf7c480 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -2831,7 +2831,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
struct file *swap_file, *victim;
struct address_space *mapping;
struct inode *inode;
- struct filename *pathname;
unsigned int maxpages;
int err, found = 0;
@@ -2840,14 +2839,10 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
BUG_ON(!current->mm);
- pathname = getname(specialfile);
- if (IS_ERR(pathname))
- return PTR_ERR(pathname);
-
+ CLASS(filename, pathname)(specialfile);
victim = file_open_name(pathname, O_RDWR|O_LARGEFILE, 0);
- err = PTR_ERR(victim);
if (IS_ERR(victim))
- goto out;
+ return PTR_ERR(victim);
mapping = victim->f_mapping;
spin_lock(&swap_lock);
@@ -2964,8 +2959,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
out_dput:
filp_close(victim, NULL);
-out:
- putname(pathname);
return err;
}
@@ -3392,7 +3385,6 @@ static struct swap_cluster_info *setup_clusters(struct swap_info_struct *si,
SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
{
struct swap_info_struct *si;
- struct filename *name;
struct file *swap_file = NULL;
struct address_space *mapping;
struct dentry *dentry;
@@ -3422,12 +3414,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
INIT_WORK(&si->discard_work, swap_discard_work);
INIT_WORK(&si->reclaim_work, swap_reclaim_work);
- name = getname(specialfile);
- if (IS_ERR(name)) {
- error = PTR_ERR(name);
- name = NULL;
- goto bad_swap;
- }
+ CLASS(filename, name)(specialfile);
swap_file = file_open_name(name, O_RDWR | O_LARGEFILE | O_EXCL, 0);
if (IS_ERR(swap_file)) {
error = PTR_ERR(swap_file);
@@ -3635,8 +3622,6 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
out:
if (!IS_ERR_OR_NULL(folio))
folio_release_kmap(folio, swap_header);
- if (name)
- putname(name);
if (inode)
inode_unlock(inode);
return error;
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 29/59] simplify the callers of do_open_execat()
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (27 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 28/59] simplify the callers of file_open_name() Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 30/59] simplify the callers of alloc_bprm() Al Viro
` (30 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/exec.c | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/fs/exec.c b/fs/exec.c
index b7d8081d12ea..5b4110c7522e 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -815,14 +815,8 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
*/
struct file *open_exec(const char *name)
{
- struct filename *filename = getname_kernel(name);
- struct file *f = ERR_CAST(filename);
-
- if (!IS_ERR(filename)) {
- f = do_open_execat(AT_FDCWD, filename, 0);
- putname(filename);
- }
- return f;
+ CLASS(filename_kernel, filename)(name);
+ return do_open_execat(AT_FDCWD, filename, 0);
}
EXPORT_SYMBOL(open_exec);
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 30/59] simplify the callers of alloc_bprm()
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (28 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 29/59] simplify the callers of do_open_execat() Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 31/59] switch {alloc,free}_bprm() to CLASS() Al Viro
` (29 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
alloc_bprm() starts with do_open_execat() and it will do the right
thing if given ERR_PTR() for name. Allows to drop such checks in
its callers...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/exec.c | 17 +++--------------
1 file changed, 3 insertions(+), 14 deletions(-)
diff --git a/fs/exec.c b/fs/exec.c
index 5b4110c7522e..1473e8c06a8c 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1782,9 +1782,6 @@ static int do_execveat_common(int fd, struct filename *filename,
struct linux_binprm *bprm;
int retval;
- if (IS_ERR(filename))
- return PTR_ERR(filename);
-
/*
* We move the actual failure in case of RLIMIT_NPROC excess from
* set*uid() to execve() because too many poorly written programs
@@ -1862,7 +1859,6 @@ static int do_execveat_common(int fd, struct filename *filename,
int kernel_execve(const char *kernel_filename,
const char *const *argv, const char *const *envp)
{
- struct filename *filename;
struct linux_binprm *bprm;
int fd = AT_FDCWD;
int retval;
@@ -1871,15 +1867,10 @@ int kernel_execve(const char *kernel_filename,
if (WARN_ON_ONCE(current->flags & PF_KTHREAD))
return -EINVAL;
- filename = getname_kernel(kernel_filename);
- if (IS_ERR(filename))
- return PTR_ERR(filename);
-
+ CLASS(filename_kernel, filename)(kernel_filename);
bprm = alloc_bprm(fd, filename, 0);
- if (IS_ERR(bprm)) {
- retval = PTR_ERR(bprm);
- goto out_ret;
- }
+ if (IS_ERR(bprm))
+ return PTR_ERR(bprm);
retval = count_strings_kernel(argv);
if (WARN_ON_ONCE(retval == 0))
@@ -1913,8 +1904,6 @@ int kernel_execve(const char *kernel_filename,
retval = bprm_execve(bprm);
out_free:
free_bprm(bprm);
-out_ret:
- putname(filename);
return retval;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 31/59] switch {alloc,free}_bprm() to CLASS()
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (29 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 30/59] simplify the callers of alloc_bprm() Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 32/59] file_[gs]etattr(2): switch to CLASS(filename_maybe_null) Al Viro
` (28 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
All linux_binprm instances come from alloc_bprm() and are unconditionally
destroyed by free_bprm() in the end of the same scope. IOW, CLASS()
machinery is a decent fit for those.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/exec.c | 68 +++++++++++++++++++++++--------------------------------
1 file changed, 28 insertions(+), 40 deletions(-)
diff --git a/fs/exec.c b/fs/exec.c
index 1473e8c06a8c..68986dca9b9d 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1465,6 +1465,9 @@ static struct linux_binprm *alloc_bprm(int fd, struct filename *filename, int fl
return ERR_PTR(retval);
}
+DEFINE_CLASS(bprm, struct linux_binprm *, if (!IS_ERR(_T)) free_bprm(_T),
+ alloc_bprm(fd, name, flags), int fd, struct filename *name, int flags)
+
int bprm_change_interp(const char *interp, struct linux_binprm *bprm)
{
/* If a binfmt changed the interp, free it first. */
@@ -1774,12 +1777,12 @@ static int bprm_execve(struct linux_binprm *bprm)
return retval;
}
-static int do_execveat_common(int fd, struct filename *filename,
+static int do_execveat_common(int fd, struct filename *__filename,
struct user_arg_ptr argv,
struct user_arg_ptr envp,
int flags)
{
- struct linux_binprm *bprm;
+ CLASS(filename_consume, filename)(__filename);
int retval;
/*
@@ -1788,48 +1791,44 @@ static int do_execveat_common(int fd, struct filename *filename,
* don't check setuid() return code. Here we additionally recheck
* whether NPROC limit is still exceeded.
*/
- if ((current->flags & PF_NPROC_EXCEEDED) &&
- is_rlimit_overlimit(current_ucounts(), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC))) {
- retval = -EAGAIN;
- goto out_ret;
- }
+ if (unlikely(current->flags & PF_NPROC_EXCEEDED) &&
+ is_rlimit_overlimit(current_ucounts(), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC)))
+ return -EAGAIN;
/* We're below the limit (still or again), so we don't want to make
* further execve() calls fail. */
current->flags &= ~PF_NPROC_EXCEEDED;
- bprm = alloc_bprm(fd, filename, flags);
- if (IS_ERR(bprm)) {
- retval = PTR_ERR(bprm);
- goto out_ret;
- }
+ CLASS(bprm, bprm)(fd, filename, flags);
+ if (IS_ERR(bprm))
+ return PTR_ERR(bprm);
retval = count(argv, MAX_ARG_STRINGS);
if (retval < 0)
- goto out_free;
+ return retval;
bprm->argc = retval;
retval = count(envp, MAX_ARG_STRINGS);
if (retval < 0)
- goto out_free;
+ return retval;
bprm->envc = retval;
retval = bprm_stack_limits(bprm);
if (retval < 0)
- goto out_free;
+ return retval;
retval = copy_string_kernel(bprm->filename, bprm);
if (retval < 0)
- goto out_free;
+ return retval;
bprm->exec = bprm->p;
retval = copy_strings(bprm->envc, envp, bprm);
if (retval < 0)
- goto out_free;
+ return retval;
retval = copy_strings(bprm->argc, argv, bprm);
if (retval < 0)
- goto out_free;
+ return retval;
/*
* When argv is empty, add an empty string ("") as argv[0] to
@@ -1840,27 +1839,19 @@ static int do_execveat_common(int fd, struct filename *filename,
if (bprm->argc == 0) {
retval = copy_string_kernel("", bprm);
if (retval < 0)
- goto out_free;
+ return retval;
bprm->argc = 1;
pr_warn_once("process '%s' launched '%s' with NULL argv: empty string added\n",
current->comm, bprm->filename);
}
- retval = bprm_execve(bprm);
-out_free:
- free_bprm(bprm);
-
-out_ret:
- putname(filename);
- return retval;
+ return bprm_execve(bprm);
}
int kernel_execve(const char *kernel_filename,
const char *const *argv, const char *const *envp)
{
- struct linux_binprm *bprm;
- int fd = AT_FDCWD;
int retval;
/* It is non-sense for kernel threads to call execve */
@@ -1868,43 +1859,40 @@ int kernel_execve(const char *kernel_filename,
return -EINVAL;
CLASS(filename_kernel, filename)(kernel_filename);
- bprm = alloc_bprm(fd, filename, 0);
+ CLASS(bprm, bprm)(AT_FDCWD, filename, 0);
if (IS_ERR(bprm))
return PTR_ERR(bprm);
retval = count_strings_kernel(argv);
if (WARN_ON_ONCE(retval == 0))
- retval = -EINVAL;
+ return -EINVAL;
if (retval < 0)
- goto out_free;
+ return retval;
bprm->argc = retval;
retval = count_strings_kernel(envp);
if (retval < 0)
- goto out_free;
+ return retval;
bprm->envc = retval;
retval = bprm_stack_limits(bprm);
if (retval < 0)
- goto out_free;
+ return retval;
retval = copy_string_kernel(bprm->filename, bprm);
if (retval < 0)
- goto out_free;
+ return retval;
bprm->exec = bprm->p;
retval = copy_strings_kernel(bprm->envc, envp, bprm);
if (retval < 0)
- goto out_free;
+ return retval;
retval = copy_strings_kernel(bprm->argc, argv, bprm);
if (retval < 0)
- goto out_free;
+ return retval;
- retval = bprm_execve(bprm);
-out_free:
- free_bprm(bprm);
- return retval;
+ return bprm_execve(bprm);
}
static int do_execve(struct filename *filename,
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 32/59] file_[gs]etattr(2): switch to CLASS(filename_maybe_null)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (30 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 31/59] switch {alloc,free}_bprm() to CLASS() Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 33/59] mount_setattr(2): don't mess with LOOKUP_EMPTY Al Viro
` (27 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/file_attr.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/fs/file_attr.c b/fs/file_attr.c
index 915e9a40cd42..b547161be742 100644
--- a/fs/file_attr.c
+++ b/fs/file_attr.c
@@ -372,7 +372,6 @@ SYSCALL_DEFINE5(file_getattr, int, dfd, const char __user *, filename,
unsigned int, at_flags)
{
struct path filepath __free(path_put) = {};
- struct filename *name __free(putname) = NULL;
unsigned int lookup_flags = 0;
struct file_attr fattr;
struct file_kattr fa;
@@ -393,7 +392,7 @@ SYSCALL_DEFINE5(file_getattr, int, dfd, const char __user *, filename,
if (usize < FILE_ATTR_SIZE_VER0)
return -EINVAL;
- name = getname_maybe_null(filename, at_flags);
+ CLASS(filename_maybe_null, name)(filename, at_flags);
if (!name && dfd >= 0) {
CLASS(fd, f)(dfd);
if (fd_empty(f))
@@ -426,7 +425,6 @@ SYSCALL_DEFINE5(file_setattr, int, dfd, const char __user *, filename,
unsigned int, at_flags)
{
struct path filepath __free(path_put) = {};
- struct filename *name __free(putname) = NULL;
unsigned int lookup_flags = 0;
struct file_attr fattr;
struct file_kattr fa;
@@ -456,7 +454,7 @@ SYSCALL_DEFINE5(file_setattr, int, dfd, const char __user *, filename,
if (error)
return error;
- name = getname_maybe_null(filename, at_flags);
+ CLASS(filename_maybe_null, name)(filename, at_flags);
if (!name && dfd >= 0) {
CLASS(fd, f)(dfd);
if (fd_empty(f))
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 33/59] mount_setattr(2): don't mess with LOOKUP_EMPTY
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (31 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 32/59] file_[gs]etattr(2): switch to CLASS(filename_maybe_null) Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 34/59] do_open_execat(): don't care about LOOKUP_EMPTY Al Viro
` (26 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
just use CLASS(filename_uflags) + filename_lookup()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namespace.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index 9d0d8ed16264..d632180f9b1a 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -4978,8 +4978,6 @@ SYSCALL_DEFINE5(mount_setattr, int, dfd, const char __user *, path,
lookup_flags &= ~LOOKUP_AUTOMOUNT;
if (flags & AT_SYMLINK_NOFOLLOW)
lookup_flags &= ~LOOKUP_FOLLOW;
- if (flags & AT_EMPTY_PATH)
- lookup_flags |= LOOKUP_EMPTY;
kattr = (struct mount_kattr) {
.lookup_flags = lookup_flags,
@@ -4992,7 +4990,8 @@ SYSCALL_DEFINE5(mount_setattr, int, dfd, const char __user *, path,
if (err <= 0)
return err;
- err = user_path_at(dfd, path, kattr.lookup_flags, &target);
+ CLASS(filename_uflags, name)(path, flags);
+ err = filename_lookup(dfd, name, kattr.lookup_flags, &target, NULL);
if (!err) {
err = do_mount_setattr(&target, &kattr);
path_put(&target);
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 34/59] do_open_execat(): don't care about LOOKUP_EMPTY
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (32 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 33/59] mount_setattr(2): don't mess with LOOKUP_EMPTY Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 35/59] vfs_open_tree(): use CLASS(filename_uflags) Al Viro
` (25 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
do_file_open() doesn't.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/exec.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/fs/exec.c b/fs/exec.c
index 68986dca9b9d..902561a878ff 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -777,8 +777,6 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
return ERR_PTR(-EINVAL);
if (flags & AT_SYMLINK_NOFOLLOW)
open_exec_flags.lookup_flags &= ~LOOKUP_FOLLOW;
- if (flags & AT_EMPTY_PATH)
- open_exec_flags.lookup_flags |= LOOKUP_EMPTY;
file = do_file_open(fd, name, &open_exec_flags);
if (IS_ERR(file))
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 35/59] vfs_open_tree(): use CLASS(filename_uflags)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (33 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 34/59] do_open_execat(): don't care about LOOKUP_EMPTY Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 36/59] name_to_handle_at(): " Al Viro
` (24 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namespace.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index d632180f9b1a..888df8ee43bc 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -3082,13 +3082,12 @@ static struct file *vfs_open_tree(int dfd, const char __user *filename, unsigned
lookup_flags &= ~LOOKUP_AUTOMOUNT;
if (flags & AT_SYMLINK_NOFOLLOW)
lookup_flags &= ~LOOKUP_FOLLOW;
- if (flags & AT_EMPTY_PATH)
- lookup_flags |= LOOKUP_EMPTY;
if (detached && !may_mount())
return ERR_PTR(-EPERM);
- ret = user_path_at(dfd, filename, lookup_flags, &path);
+ CLASS(filename_uflags, name)(filename, flags);
+ ret = filename_lookup(dfd, name, lookup_flags, &path, NULL);
if (unlikely(ret))
return ERR_PTR(ret);
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 36/59] name_to_handle_at(): use CLASS(filename_uflags)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (34 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 35/59] vfs_open_tree(): use CLASS(filename_uflags) Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 37/59] fspick(2): use CLASS(filename_flags) Al Viro
` (23 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/fhandle.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/fs/fhandle.c b/fs/fhandle.c
index 3de1547ec9d4..e15bcf4b0b23 100644
--- a/fs/fhandle.c
+++ b/fs/fhandle.c
@@ -157,9 +157,8 @@ SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
fh_flags |= EXPORT_FH_CONNECTABLE;
lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
- if (flag & AT_EMPTY_PATH)
- lookup_flags |= LOOKUP_EMPTY;
- err = user_path_at(dfd, name, lookup_flags, &path);
+ CLASS(filename_uflags, filename)(name, flag);
+ err = filename_lookup(dfd, filename, lookup_flags, &path, NULL);
if (!err) {
err = do_sys_name_to_handle(&path, handle, mnt_id,
flag & AT_HANDLE_MNT_ID_UNIQUE,
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 37/59] fspick(2): use CLASS(filename_flags)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (35 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 36/59] name_to_handle_at(): " Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 38/59] do_fchownat(): unspaghettify a bit Al Viro
` (22 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
That kills the last place where we mix LOOKUP_EMPTY with lookup
flags proper.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/fsopen.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/fsopen.c b/fs/fsopen.c
index f645c99204eb..70f4ab183c9e 100644
--- a/fs/fsopen.c
+++ b/fs/fsopen.c
@@ -181,9 +181,9 @@ SYSCALL_DEFINE3(fspick, int, dfd, const char __user *, path, unsigned int, flags
lookup_flags &= ~LOOKUP_FOLLOW;
if (flags & FSPICK_NO_AUTOMOUNT)
lookup_flags &= ~LOOKUP_AUTOMOUNT;
- if (flags & FSPICK_EMPTY_PATH)
- lookup_flags |= LOOKUP_EMPTY;
- ret = user_path_at(dfd, path, lookup_flags, &target);
+ CLASS(filename_flags, filename)(path,
+ (flags & FSPICK_EMPTY_PATH) ? LOOKUP_EMPTY : 0);
+ ret = filename_lookup(dfd, filename, lookup_flags, &target, NULL);
if (ret < 0)
goto err;
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 38/59] do_fchownat(): unspaghettify a bit...
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (36 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 37/59] fspick(2): use CLASS(filename_flags) Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 39/59] chdir(2): " Al Viro
` (21 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/open.c | 28 ++++++++++++----------------
1 file changed, 12 insertions(+), 16 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index 7254eda9f4a5..425c09d83d7f 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -810,30 +810,26 @@ int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group,
struct path path;
int error;
int lookup_flags;
- struct filename *name;
if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
return -EINVAL;
lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
- name = getname_uflags(filename, flag);
+ CLASS(filename_uflags, name)(filename, flag);
retry:
error = filename_lookup(dfd, name, lookup_flags, &path, NULL);
- if (error)
- goto out;
- error = mnt_want_write(path.mnt);
- if (error)
- goto out_release;
- error = chown_common(&path, user, group);
- mnt_drop_write(path.mnt);
-out_release:
- path_put(&path);
- if (retry_estale(error, lookup_flags)) {
- lookup_flags |= LOOKUP_REVAL;
- goto retry;
+ if (!error) {
+ error = mnt_want_write(path.mnt);
+ if (!error) {
+ error = chown_common(&path, user, group);
+ mnt_drop_write(path.mnt);
+ }
+ path_put(&path);
+ if (retry_estale(error, lookup_flags)) {
+ lookup_flags |= LOOKUP_REVAL;
+ goto retry;
+ }
}
-out:
- putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 39/59] chdir(2): unspaghettify a bit...
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (37 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 38/59] do_fchownat(): unspaghettify a bit Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:54 ` [RFC PATCH v3 40/59] do_utimes_path(): switch to CLASS(filename_uflags) Al Viro
` (20 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/open.c | 27 ++++++++++-----------------
1 file changed, 10 insertions(+), 17 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index 425c09d83d7f..bcaaf884e436 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -558,26 +558,19 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename)
struct path path;
int error;
unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
- struct filename *name = getname(filename);
+ CLASS(filename, name)(filename);
retry:
error = filename_lookup(AT_FDCWD, name, lookup_flags, &path, NULL);
- if (error)
- goto out;
-
- error = path_permission(&path, MAY_EXEC | MAY_CHDIR);
- if (error)
- goto dput_and_out;
-
- set_fs_pwd(current->fs, &path);
-
-dput_and_out:
- path_put(&path);
- if (retry_estale(error, lookup_flags)) {
- lookup_flags |= LOOKUP_REVAL;
- goto retry;
+ if (!error) {
+ error = path_permission(&path, MAY_EXEC | MAY_CHDIR);
+ if (!error)
+ set_fs_pwd(current->fs, &path);
+ path_put(&path);
+ if (retry_estale(error, lookup_flags)) {
+ lookup_flags |= LOOKUP_REVAL;
+ goto retry;
+ }
}
-out:
- putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 40/59] do_utimes_path(): switch to CLASS(filename_uflags)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (38 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 39/59] chdir(2): " Al Viro
@ 2025-12-16 3:54 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 41/59] do_sys_truncate(): switch to CLASS(filename) Al Viro
` (19 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:54 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/utimes.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/fs/utimes.c b/fs/utimes.c
index 84889ea1780e..e22664e4115f 100644
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -84,27 +84,24 @@ static int do_utimes_path(int dfd, const char __user *filename,
{
struct path path;
int lookup_flags = 0, error;
- struct filename *name;
if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
return -EINVAL;
if (!(flags & AT_SYMLINK_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;
- name = getname_uflags(filename, flags);
+ CLASS(filename_uflags, name)(filename, flags);
retry:
error = filename_lookup(dfd, name, lookup_flags, &path, NULL);
if (error)
- goto out;
+ return error;
error = vfs_utimes(&path, times);
path_put(&path);
if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
-out:
- putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 41/59] do_sys_truncate(): switch to CLASS(filename)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (39 preceding siblings ...)
2025-12-16 3:54 ` [RFC PATCH v3 40/59] do_utimes_path(): switch to CLASS(filename_uflags) Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 42/59] do_readlinkat(): switch to CLASS(filename_flags) Al Viro
` (18 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Note that failures from filename_lookup() are final - ESTALE returned
by it means that retry had been done by filename_lookup() and it failed
there.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/open.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index bcaaf884e436..34d9b1ecc141 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -129,25 +129,23 @@ EXPORT_SYMBOL_GPL(vfs_truncate);
int do_sys_truncate(const char __user *pathname, loff_t length)
{
unsigned int lookup_flags = LOOKUP_FOLLOW;
- struct filename *name;
struct path path;
int error;
if (length < 0) /* sorry, but loff_t says... */
return -EINVAL;
- name = getname(pathname);
+ CLASS(filename, name)(pathname);
retry:
error = filename_lookup(AT_FDCWD, name, lookup_flags, &path, NULL);
if (!error) {
error = vfs_truncate(&path, length);
path_put(&path);
+ if (retry_estale(error, lookup_flags)) {
+ lookup_flags |= LOOKUP_REVAL;
+ goto retry;
+ }
}
- if (retry_estale(error, lookup_flags)) {
- lookup_flags |= LOOKUP_REVAL;
- goto retry;
- }
- putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 42/59] do_readlinkat(): switch to CLASS(filename_flags)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (40 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 41/59] do_sys_truncate(): switch to CLASS(filename) Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 43/59] do_f{chmod,chown,access}at(): use CLASS(filename_uflags) Al Viro
` (17 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/stat.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/fs/stat.c b/fs/stat.c
index ee9ae2c3273a..d18577f3688c 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -564,20 +564,17 @@ static int do_readlinkat(int dfd, const char __user *pathname,
char __user *buf, int bufsiz)
{
struct path path;
- struct filename *name;
int error;
unsigned int lookup_flags = 0;
if (bufsiz <= 0)
return -EINVAL;
- name = getname_flags(pathname, LOOKUP_EMPTY);
+ CLASS(filename_flags, name)(pathname, LOOKUP_EMPTY);
retry:
error = filename_lookup(dfd, name, lookup_flags, &path, NULL);
- if (unlikely(error)) {
- putname(name);
+ if (unlikely(error))
return error;
- }
/*
* AFS mountpoints allow readlink(2) but are not symlinks
@@ -597,7 +594,6 @@ static int do_readlinkat(int dfd, const char __user *pathname,
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
- putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 43/59] do_f{chmod,chown,access}at(): use CLASS(filename_uflags)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (41 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 42/59] do_readlinkat(): switch to CLASS(filename_flags) Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 44/59] io_openat2(): use CLASS(filename_complete_delayed) Al Viro
` (16 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/open.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index 34d9b1ecc141..3c7081694326 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -469,7 +469,6 @@ static int do_faccessat(int dfd, const char __user *filename, int mode, int flag
int res;
unsigned int lookup_flags = LOOKUP_FOLLOW;
const struct cred *old_cred = NULL;
- struct filename *name;
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
@@ -486,7 +485,7 @@ static int do_faccessat(int dfd, const char __user *filename, int mode, int flag
return -ENOMEM;
}
- name = getname_uflags(filename, flags);
+ CLASS(filename_uflags, name)(filename, flags);
retry:
res = filename_lookup(dfd, name, lookup_flags, &path, NULL);
if (res)
@@ -528,7 +527,6 @@ static int do_faccessat(int dfd, const char __user *filename, int mode, int flag
goto retry;
}
out:
- putname(name);
if (old_cred)
put_cred(revert_creds(old_cred));
@@ -677,7 +675,6 @@ static int do_fchmodat(int dfd, const char __user *filename, umode_t mode,
unsigned int flags)
{
struct path path;
- struct filename *name;
int error;
unsigned int lookup_flags;
@@ -685,7 +682,7 @@ static int do_fchmodat(int dfd, const char __user *filename, umode_t mode,
return -EINVAL;
lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
- name = getname_uflags(filename, flags);
+ CLASS(filename_uflags, name)(filename, flags);
retry:
error = filename_lookup(dfd, name, lookup_flags, &path, NULL);
if (!error) {
@@ -696,7 +693,6 @@ static int do_fchmodat(int dfd, const char __user *filename, umode_t mode,
goto retry;
}
}
- putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 44/59] io_openat2(): use CLASS(filename_complete_delayed)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (42 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 43/59] do_f{chmod,chown,access}at(): use CLASS(filename_uflags) Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 45/59] io_statx(): " Al Viro
` (15 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
io_uring/openclose.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/io_uring/openclose.c b/io_uring/openclose.c
index 95fcb612ad9c..15da7f3aa37b 100644
--- a/io_uring/openclose.c
+++ b/io_uring/openclose.c
@@ -118,7 +118,7 @@ int io_openat2(struct io_kiocb *req, unsigned int issue_flags)
struct file *file;
bool resolve_nonblock, nonblock_set;
bool fixed = !!open->file_slot;
- struct filename *name __free(putname) = complete_getname(&open->filename);
+ CLASS(filename_complete_delayed, name)(&open->filename);
int ret;
ret = build_open_flags(&open->how, &op);
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 45/59] io_statx(): use CLASS(filename_complete_delayed)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (43 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 44/59] io_openat2(): use CLASS(filename_complete_delayed) Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 46/59] do_{renameat2,linkat,symlinkat}(): use CLASS(filename_consume) Al Viro
` (14 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
io_uring/statx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/io_uring/statx.c b/io_uring/statx.c
index dc10b48bcde6..7bcae4a6c4a3 100644
--- a/io_uring/statx.c
+++ b/io_uring/statx.c
@@ -50,7 +50,7 @@ int io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
int io_statx(struct io_kiocb *req, unsigned int issue_flags)
{
struct io_statx *sx = io_kiocb_to_cmd(req, struct io_statx);
- struct filename *name __free(putname) = complete_getname(&sx->filename);
+ CLASS(filename_complete_delayed, name)(&sx->filename);
int ret;
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 46/59] do_{renameat2,linkat,symlinkat}(): use CLASS(filename_consume)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (44 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 45/59] io_statx(): " Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 47/59] do_{mknodat,mkdirat,unlinkat,rmdir}(): " Al Viro
` (13 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
more explicit in what we do, lower odds of ending up with a leak,
fewer gotos...
... and if at some point in the future we decide to make some of those
non-consuming, it would be less noisy.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namei.c | 51 +++++++++++++++++++++------------------------------
1 file changed, 21 insertions(+), 30 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index f6b5d6a657da..fbf306fe8414 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -5575,23 +5575,22 @@ int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
}
EXPORT_SYMBOL(vfs_symlink);
-int do_symlinkat(struct filename *from, int newdfd, struct filename *to)
+int do_symlinkat(struct filename *__from, int newdfd, struct filename *__to)
{
+ CLASS(filename_consume, from)(__from);
+ CLASS(filename_consume, to)(__to);
int error;
struct dentry *dentry;
struct path path;
unsigned int lookup_flags = 0;
struct delegated_inode delegated_inode = { };
- if (IS_ERR(from)) {
- error = PTR_ERR(from);
- goto out_putnames;
- }
+ if (IS_ERR(from))
+ return PTR_ERR(from);
retry:
dentry = filename_create(newdfd, to, &path, lookup_flags);
- error = PTR_ERR(dentry);
if (IS_ERR(dentry))
- goto out_putnames;
+ return PTR_ERR(dentry);
error = security_path_symlink(&path, dentry, from->name);
if (!error)
@@ -5607,9 +5606,6 @@ int do_symlinkat(struct filename *from, int newdfd, struct filename *to)
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
-out_putnames:
- putname(to);
- putname(from);
return error;
}
@@ -5724,9 +5720,11 @@ EXPORT_SYMBOL(vfs_link);
* with linux 2.0, and to avoid hard-linking to directories
* and other special files. --ADM
*/
-int do_linkat(int olddfd, struct filename *old, int newdfd,
- struct filename *new, int flags)
+int do_linkat(int olddfd, struct filename *__old, int newdfd,
+ struct filename *__new, int flags)
{
+ CLASS(filename_consume, old)(__old);
+ CLASS(filename_consume, new)(__new);
struct mnt_idmap *idmap;
struct dentry *new_dentry;
struct path old_path, new_path;
@@ -5734,10 +5732,8 @@ int do_linkat(int olddfd, struct filename *old, int newdfd,
int how = 0;
int error;
- if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) {
- error = -EINVAL;
- goto out_putnames;
- }
+ if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
+ return -EINVAL;
/*
* To use null names we require CAP_DAC_READ_SEARCH or
* that the open-time creds of the dfd matches current.
@@ -5752,7 +5748,7 @@ int do_linkat(int olddfd, struct filename *old, int newdfd,
retry:
error = filename_lookup(olddfd, old, how, &old_path, NULL);
if (error)
- goto out_putnames;
+ return error;
new_dentry = filename_create(newdfd, new, &new_path,
(how & LOOKUP_REVAL));
@@ -5788,10 +5784,6 @@ int do_linkat(int olddfd, struct filename *old, int newdfd,
}
out_putpath:
path_put(&old_path);
-out_putnames:
- putname(old);
- putname(new);
-
return error;
}
@@ -6022,9 +6014,11 @@ int vfs_rename(struct renamedata *rd)
}
EXPORT_SYMBOL(vfs_rename);
-int do_renameat2(int olddfd, struct filename *from, int newdfd,
- struct filename *to, unsigned int flags)
+int do_renameat2(int olddfd, struct filename *__from, int newdfd,
+ struct filename *__to, unsigned int flags)
{
+ CLASS(filename_consume, from)(__from);
+ CLASS(filename_consume, to)(__to);
struct renamedata rd;
struct path old_path, new_path;
struct qstr old_last, new_last;
@@ -6032,20 +6026,20 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd,
struct delegated_inode delegated_inode = { };
unsigned int lookup_flags = 0;
bool should_retry = false;
- int error = -EINVAL;
+ int error;
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
- goto put_names;
+ return -EINVAL;
if ((flags & (RENAME_NOREPLACE | RENAME_WHITEOUT)) &&
(flags & RENAME_EXCHANGE))
- goto put_names;
+ return -EINVAL;
retry:
error = filename_parentat(olddfd, from, lookup_flags, &old_path,
&old_last, &old_type);
if (error)
- goto put_names;
+ return error;
error = filename_parentat(newdfd, to, lookup_flags, &new_path, &new_last,
&new_type);
@@ -6122,9 +6116,6 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd,
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
-put_names:
- putname(from);
- putname(to);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 47/59] do_{mknodat,mkdirat,unlinkat,rmdir}(): use CLASS(filename_consume)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (45 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 46/59] do_{renameat2,linkat,symlinkat}(): use CLASS(filename_consume) Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 48/59] namei.c: convert getname_kernel() callers to CLASS(filename_kernel) Al Viro
` (12 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
same rationale as for previous commit
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namei.c | 32 +++++++++++++-------------------
1 file changed, 13 insertions(+), 19 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index fbf306fe8414..0221cdb92297 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -5066,9 +5066,10 @@ static int may_mknod(umode_t mode)
}
}
-static int do_mknodat(int dfd, struct filename *name, umode_t mode,
+static int do_mknodat(int dfd, struct filename *__name, umode_t mode,
unsigned int dev)
{
+ CLASS(filename_consume, name)(__name);
struct delegated_inode di = { };
struct mnt_idmap *idmap;
struct dentry *dentry;
@@ -5078,12 +5079,11 @@ static int do_mknodat(int dfd, struct filename *name, umode_t mode,
error = may_mknod(mode);
if (error)
- goto out1;
+ return error;
retry:
dentry = filename_create(dfd, name, &path, lookup_flags);
- error = PTR_ERR(dentry);
if (IS_ERR(dentry))
- goto out1;
+ return PTR_ERR(dentry);
error = security_path_mknod(&path, dentry,
mode_strip_umask(path.dentry->d_inode, mode), dev);
@@ -5117,8 +5117,6 @@ static int do_mknodat(int dfd, struct filename *name, umode_t mode,
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
-out1:
- putname(name);
return error;
}
@@ -5201,8 +5199,9 @@ struct dentry *vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
}
EXPORT_SYMBOL(vfs_mkdir);
-int do_mkdirat(int dfd, struct filename *name, umode_t mode)
+int do_mkdirat(int dfd, struct filename *__name, umode_t mode)
{
+ CLASS(filename_consume, name)(__name);
struct dentry *dentry;
struct path path;
int error;
@@ -5211,9 +5210,8 @@ int do_mkdirat(int dfd, struct filename *name, umode_t mode)
retry:
dentry = filename_create(dfd, name, &path, lookup_flags);
- error = PTR_ERR(dentry);
if (IS_ERR(dentry))
- goto out_putname;
+ return PTR_ERR(dentry);
error = security_path_mkdir(&path, dentry,
mode_strip_umask(path.dentry->d_inode, mode));
@@ -5233,8 +5231,6 @@ int do_mkdirat(int dfd, struct filename *name, umode_t mode)
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
-out_putname:
- putname(name);
return error;
}
@@ -5308,8 +5304,9 @@ int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir,
}
EXPORT_SYMBOL(vfs_rmdir);
-int do_rmdir(int dfd, struct filename *name)
+int do_rmdir(int dfd, struct filename *__name)
{
+ CLASS(filename_consume, name)(__name);
int error;
struct dentry *dentry;
struct path path;
@@ -5320,7 +5317,7 @@ int do_rmdir(int dfd, struct filename *name)
retry:
error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
if (error)
- goto exit1;
+ return error;
switch (type) {
case LAST_DOTDOT:
@@ -5362,8 +5359,6 @@ int do_rmdir(int dfd, struct filename *name)
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
-exit1:
- putname(name);
return error;
}
@@ -5451,8 +5446,9 @@ EXPORT_SYMBOL(vfs_unlink);
* writeout happening, and we don't want to prevent access to the directory
* while waiting on the I/O.
*/
-int do_unlinkat(int dfd, struct filename *name)
+int do_unlinkat(int dfd, struct filename *__name)
{
+ CLASS(filename_consume, name)(__name);
int error;
struct dentry *dentry;
struct path path;
@@ -5464,7 +5460,7 @@ int do_unlinkat(int dfd, struct filename *name)
retry:
error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
if (error)
- goto exit_putname;
+ return error;
error = -EISDIR;
if (type != LAST_NORM)
@@ -5511,8 +5507,6 @@ int do_unlinkat(int dfd, struct filename *name)
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
-exit_putname:
- putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 48/59] namei.c: convert getname_kernel() callers to CLASS(filename_kernel)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (46 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 47/59] do_{mknodat,mkdirat,unlinkat,rmdir}(): " Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 49/59] namei.c: switch user pathname imports to CLASS(filename{,_flags}) Al Viro
` (11 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namei.c | 36 ++++++++++--------------------------
1 file changed, 10 insertions(+), 26 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 0221cdb92297..e0c8d3832861 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2996,7 +2996,7 @@ static struct dentry *__start_removing_path(int dfd, struct filename *name,
struct dentry *kern_path_parent(const char *name, struct path *path)
{
struct path parent_path __free(path_put) = {};
- struct filename *filename __free(putname) = getname_kernel(name);
+ CLASS(filename_kernel, filename)(name);
struct dentry *d;
struct qstr last;
int type, error;
@@ -3017,11 +3017,8 @@ struct dentry *kern_path_parent(const char *name, struct path *path)
struct dentry *start_removing_path(const char *name, struct path *path)
{
- struct filename *filename = getname_kernel(name);
- struct dentry *res = __start_removing_path(AT_FDCWD, filename, path);
-
- putname(filename);
- return res;
+ CLASS(filename_kernel, filename)(name);
+ return __start_removing_path(AT_FDCWD, filename, path);
}
struct dentry *start_removing_user_path_at(int dfd,
@@ -3038,12 +3035,8 @@ EXPORT_SYMBOL(start_removing_user_path_at);
int kern_path(const char *name, unsigned int flags, struct path *path)
{
- struct filename *filename = getname_kernel(name);
- int ret = filename_lookup(AT_FDCWD, filename, flags, path, NULL);
-
- putname(filename);
- return ret;
-
+ CLASS(filename_kernel, filename)(name);
+ return filename_lookup(AT_FDCWD, filename, flags, path, NULL);
}
EXPORT_SYMBOL(kern_path);
@@ -3077,15 +3070,11 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
const char *name, unsigned int flags,
struct path *path)
{
- struct filename *filename;
+ CLASS(filename_kernel, filename)(name);
struct path root = {.mnt = mnt, .dentry = dentry};
- int ret;
- filename = getname_kernel(name);
/* the first argument of filename_lookup() is ignored with root */
- ret = filename_lookup(AT_FDCWD, filename, flags, path, &root);
- putname(filename);
- return ret;
+ return filename_lookup(AT_FDCWD, filename, flags, path, &root);
}
EXPORT_SYMBOL(vfs_path_lookup);
@@ -4882,13 +4871,12 @@ struct file *do_file_open_root(const struct path *root,
{
struct nameidata nd;
struct file *file;
- struct filename *filename;
int flags = op->lookup_flags;
if (d_is_symlink(root->dentry) && op->intent & LOOKUP_OPEN)
return ERR_PTR(-ELOOP);
- filename = getname_kernel(name);
+ CLASS(filename_kernel, filename)(name);
if (IS_ERR(filename))
return ERR_CAST(filename);
@@ -4899,7 +4887,6 @@ struct file *do_file_open_root(const struct path *root,
if (unlikely(file == ERR_PTR(-ESTALE)))
file = path_openat(&nd, op, flags | LOOKUP_REVAL);
restore_nameidata();
- putname(filename);
return file;
}
@@ -4955,11 +4942,8 @@ static struct dentry *filename_create(int dfd, struct filename *name,
struct dentry *start_creating_path(int dfd, const char *pathname,
struct path *path, unsigned int lookup_flags)
{
- struct filename *filename = getname_kernel(pathname);
- struct dentry *res = filename_create(dfd, filename, path, lookup_flags);
-
- putname(filename);
- return res;
+ CLASS(filename_kernel, filename)(pathname);
+ return filename_create(dfd, filename, path, lookup_flags);
}
EXPORT_SYMBOL(start_creating_path);
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 49/59] namei.c: switch user pathname imports to CLASS(filename{,_flags})
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (47 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 48/59] namei.c: convert getname_kernel() callers to CLASS(filename_kernel) Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 50/59] filename_...xattr(): don't consume filename reference Al Viro
` (10 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
filename_flags is used by user_path_at(). I suspect that mixing
LOOKUP_EMPTY with real lookup flags had been a mistake all along; the
former belongs to pathname import, the latter - to pathwalk. Right now
none of the remaining in-tree callers of user_path_at() are getting
LOOKUP_EMPTY in flags, so user_path_at() could probably be switched
to CLASS(filename)...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namei.c | 21 ++++++---------------
1 file changed, 6 insertions(+), 15 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index e0c8d3832861..a564ca4f7ffd 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3025,11 +3025,8 @@ struct dentry *start_removing_user_path_at(int dfd,
const char __user *name,
struct path *path)
{
- struct filename *filename = getname(name);
- struct dentry *res = __start_removing_path(dfd, filename, path);
-
- putname(filename);
- return res;
+ CLASS(filename, filename)(name);
+ return __start_removing_path(dfd, filename, path);
}
EXPORT_SYMBOL(start_removing_user_path_at);
@@ -3607,11 +3604,8 @@ int path_pts(struct path *path)
int user_path_at(int dfd, const char __user *name, unsigned flags,
struct path *path)
{
- struct filename *filename = getname_flags(name, flags);
- int ret = filename_lookup(dfd, filename, flags, path, NULL);
-
- putname(filename);
- return ret;
+ CLASS(filename_flags, filename)(name, flags);
+ return filename_lookup(dfd, filename, flags, path, NULL);
}
EXPORT_SYMBOL(user_path_at);
@@ -4970,11 +4964,8 @@ inline struct dentry *start_creating_user_path(
int dfd, const char __user *pathname,
struct path *path, unsigned int lookup_flags)
{
- struct filename *filename = getname(pathname);
- struct dentry *res = filename_create(dfd, filename, path, lookup_flags);
-
- putname(filename);
- return res;
+ CLASS(filename, filename)(pathname);
+ return filename_create(dfd, filename, path, lookup_flags);
}
EXPORT_SYMBOL(start_creating_user_path);
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 50/59] filename_...xattr(): don't consume filename reference
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (48 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 49/59] namei.c: switch user pathname imports to CLASS(filename{,_flags}) Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 51/59] move_mount(2): switch to CLASS(filename_maybe_null) Al Viro
` (9 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Callers switched to CLASS(filename_maybe_null) (in fs/xattr.c)
and CLASS(filename_complete_delayed) (in io_uring/xattr.c).
Experimental calling conventions change; with the existing
infrastructure it does not inconvenience the callers, at least
for these ones...
Might be worth doing the same to do_renameat2() and friends.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/xattr.c | 33 ++++++++-------------------------
io_uring/xattr.c | 8 ++++----
2 files changed, 12 insertions(+), 29 deletions(-)
diff --git a/fs/xattr.c b/fs/xattr.c
index 32d445fb60aa..3e49e612e1ba 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -649,7 +649,6 @@ int file_setxattr(struct file *f, struct kernel_xattr_ctx *ctx)
return error;
}
-/* unconditionally consumes filename */
int filename_setxattr(int dfd, struct filename *filename,
unsigned int lookup_flags, struct kernel_xattr_ctx *ctx)
{
@@ -659,7 +658,7 @@ int filename_setxattr(int dfd, struct filename *filename,
retry:
error = filename_lookup(dfd, filename, lookup_flags, &path, NULL);
if (error)
- goto out;
+ return error;
error = mnt_want_write(path.mnt);
if (!error) {
error = do_setxattr(mnt_idmap(path.mnt), path.dentry, ctx);
@@ -670,9 +669,6 @@ int filename_setxattr(int dfd, struct filename *filename,
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
-
-out:
- putname(filename);
return error;
}
@@ -688,7 +684,6 @@ static int path_setxattrat(int dfd, const char __user *pathname,
.kname = &kname,
.flags = flags,
};
- struct filename *filename;
unsigned int lookup_flags = 0;
int error;
@@ -702,7 +697,7 @@ static int path_setxattrat(int dfd, const char __user *pathname,
if (error)
return error;
- filename = getname_maybe_null(pathname, at_flags);
+ CLASS(filename_maybe_null, filename)(pathname, at_flags);
if (!filename && dfd >= 0) {
CLASS(fd, f)(dfd);
if (fd_empty(f))
@@ -804,7 +799,6 @@ ssize_t file_getxattr(struct file *f, struct kernel_xattr_ctx *ctx)
return do_getxattr(file_mnt_idmap(f), f->f_path.dentry, ctx);
}
-/* unconditionally consumes filename */
ssize_t filename_getxattr(int dfd, struct filename *filename,
unsigned int lookup_flags, struct kernel_xattr_ctx *ctx)
{
@@ -813,15 +807,13 @@ ssize_t filename_getxattr(int dfd, struct filename *filename,
retry:
error = filename_lookup(dfd, filename, lookup_flags, &path, NULL);
if (error)
- goto out;
+ return error;
error = do_getxattr(mnt_idmap(path.mnt), path.dentry, ctx);
path_put(&path);
if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
-out:
- putname(filename);
return error;
}
@@ -836,7 +828,6 @@ static ssize_t path_getxattrat(int dfd, const char __user *pathname,
.kname = &kname,
.flags = 0,
};
- struct filename *filename;
ssize_t error;
if ((at_flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
@@ -846,7 +837,7 @@ static ssize_t path_getxattrat(int dfd, const char __user *pathname,
if (error)
return error;
- filename = getname_maybe_null(pathname, at_flags);
+ CLASS(filename_maybe_null, filename)(pathname, at_flags);
if (!filename && dfd >= 0) {
CLASS(fd, f)(dfd);
if (fd_empty(f))
@@ -943,7 +934,6 @@ ssize_t file_listxattr(struct file *f, char __user *list, size_t size)
return listxattr(f->f_path.dentry, list, size);
}
-/* unconditionally consumes filename */
static
ssize_t filename_listxattr(int dfd, struct filename *filename,
unsigned int lookup_flags,
@@ -954,15 +944,13 @@ ssize_t filename_listxattr(int dfd, struct filename *filename,
retry:
error = filename_lookup(dfd, filename, lookup_flags, &path, NULL);
if (error)
- goto out;
+ return error;
error = listxattr(path.dentry, list, size);
path_put(&path);
if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
-out:
- putname(filename);
return error;
}
@@ -970,13 +958,12 @@ static ssize_t path_listxattrat(int dfd, const char __user *pathname,
unsigned int at_flags, char __user *list,
size_t size)
{
- struct filename *filename;
int lookup_flags;
if ((at_flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
return -EINVAL;
- filename = getname_maybe_null(pathname, at_flags);
+ CLASS(filename_maybe_null, filename)(pathname, at_flags);
if (!filename) {
CLASS(fd, f)(dfd);
if (fd_empty(f))
@@ -1036,7 +1023,6 @@ static int file_removexattr(struct file *f, struct xattr_name *kname)
return error;
}
-/* unconditionally consumes filename */
static int filename_removexattr(int dfd, struct filename *filename,
unsigned int lookup_flags, struct xattr_name *kname)
{
@@ -1046,7 +1032,7 @@ static int filename_removexattr(int dfd, struct filename *filename,
retry:
error = filename_lookup(dfd, filename, lookup_flags, &path, NULL);
if (error)
- goto out;
+ return error;
error = mnt_want_write(path.mnt);
if (!error) {
error = removexattr(mnt_idmap(path.mnt), path.dentry, kname->name);
@@ -1057,8 +1043,6 @@ static int filename_removexattr(int dfd, struct filename *filename,
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
-out:
- putname(filename);
return error;
}
@@ -1066,7 +1050,6 @@ static int path_removexattrat(int dfd, const char __user *pathname,
unsigned int at_flags, const char __user *name)
{
struct xattr_name kname;
- struct filename *filename;
unsigned int lookup_flags;
int error;
@@ -1077,7 +1060,7 @@ static int path_removexattrat(int dfd, const char __user *pathname,
if (error)
return error;
- filename = getname_maybe_null(pathname, at_flags);
+ CLASS(filename_maybe_null, filename)(pathname, at_flags);
if (!filename) {
CLASS(fd, f)(dfd);
if (fd_empty(f))
diff --git a/io_uring/xattr.c b/io_uring/xattr.c
index 0fb4e5303500..ba2b98cf13f9 100644
--- a/io_uring/xattr.c
+++ b/io_uring/xattr.c
@@ -109,12 +109,12 @@ int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags)
int io_getxattr(struct io_kiocb *req, unsigned int issue_flags)
{
struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
+ CLASS(filename_complete_delayed, name)(&ix->filename);
int ret;
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
- ret = filename_getxattr(AT_FDCWD, complete_getname(&ix->filename),
- LOOKUP_FOLLOW, &ix->ctx);
+ ret = filename_getxattr(AT_FDCWD, name, LOOKUP_FOLLOW, &ix->ctx);
io_xattr_finish(req, ret);
return IOU_COMPLETE;
}
@@ -186,12 +186,12 @@ int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags)
int io_setxattr(struct io_kiocb *req, unsigned int issue_flags)
{
struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
+ CLASS(filename_complete_delayed, name)(&ix->filename);
int ret;
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
- ret = filename_setxattr(AT_FDCWD, complete_getname(&ix->filename),
- LOOKUP_FOLLOW, &ix->ctx);
+ ret = filename_setxattr(AT_FDCWD, name, LOOKUP_FOLLOW, &ix->ctx);
io_xattr_finish(req, ret);
return IOU_COMPLETE;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 51/59] move_mount(2): switch to CLASS(filename_maybe_null)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (49 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 50/59] filename_...xattr(): don't consume filename reference Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 52/59] chroot(2): switch to CLASS(filename) Al Viro
` (8 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/namespace.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index 888df8ee43bc..612757bd166a 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -4402,8 +4402,6 @@ SYSCALL_DEFINE5(move_mount,
{
struct path to_path __free(path_put) = {};
struct path from_path __free(path_put) = {};
- struct filename *to_name __free(putname) = NULL;
- struct filename *from_name __free(putname) = NULL;
unsigned int lflags, uflags;
enum mnt_tree_flags_t mflags = 0;
int ret = 0;
@@ -4425,7 +4423,7 @@ SYSCALL_DEFINE5(move_mount,
if (flags & MOVE_MOUNT_T_EMPTY_PATH)
uflags = AT_EMPTY_PATH;
- to_name = getname_maybe_null(to_pathname, uflags);
+ CLASS(filename_maybe_null,to_name)(to_pathname, uflags);
if (!to_name && to_dfd >= 0) {
CLASS(fd_raw, f_to)(to_dfd);
if (fd_empty(f_to))
@@ -4448,7 +4446,7 @@ SYSCALL_DEFINE5(move_mount,
if (flags & MOVE_MOUNT_F_EMPTY_PATH)
uflags = AT_EMPTY_PATH;
- from_name = getname_maybe_null(from_pathname, uflags);
+ CLASS(filename_maybe_null,from_name)(from_pathname, uflags);
if (!from_name && from_dfd >= 0) {
CLASS(fd_raw, f_from)(from_dfd);
if (fd_empty(f_from))
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 52/59] chroot(2): switch to CLASS(filename)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (50 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 51/59] move_mount(2): switch to CLASS(filename_maybe_null) Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 53/59] quotactl_block(): " Al Viro
` (7 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/open.c | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index 3c7081694326..4adfd7e1975a 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -592,11 +592,11 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
struct path path;
int error;
unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
- struct filename *name = getname(filename);
+ CLASS(filename, name)(filename);
retry:
error = filename_lookup(AT_FDCWD, name, lookup_flags, &path, NULL);
if (error)
- goto out;
+ return error;
error = path_permission(&path, MAY_EXEC | MAY_CHDIR);
if (error)
@@ -606,19 +606,14 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
if (!ns_capable(current_user_ns(), CAP_SYS_CHROOT))
goto dput_and_out;
error = security_path_chroot(&path);
- if (error)
- goto dput_and_out;
-
- set_fs_root(current->fs, &path);
- error = 0;
+ if (!error)
+ set_fs_root(current->fs, &path);
dput_and_out:
path_put(&path);
if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
-out:
- putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 53/59] quotactl_block(): switch to CLASS(filename)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (51 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 52/59] chroot(2): switch to CLASS(filename) Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 54/59] statx: switch to CLASS(filename_maybe_null) Al Viro
` (6 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/quota/quota.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 7c2b75a44485..ed906725e183 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -867,7 +867,7 @@ static struct super_block *quotactl_block(const char __user *special, int cmd)
{
#ifdef CONFIG_BLOCK
struct super_block *sb;
- struct filename *tmp = getname(special);
+ CLASS(filename, tmp)(special);
bool excl = false, thawed = false;
int error;
dev_t dev;
@@ -875,7 +875,6 @@ static struct super_block *quotactl_block(const char __user *special, int cmd)
if (IS_ERR(tmp))
return ERR_CAST(tmp);
error = lookup_bdev(tmp->name, &dev);
- putname(tmp);
if (error)
return ERR_PTR(error);
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 54/59] statx: switch to CLASS(filename_maybe_null)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (52 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 53/59] quotactl_block(): " Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 55/59] user_statfs(): switch to CLASS(filename) Al Viro
` (5 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/stat.c | 18 +++++-------------
1 file changed, 5 insertions(+), 13 deletions(-)
diff --git a/fs/stat.c b/fs/stat.c
index d18577f3688c..89909746bed1 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -365,17 +365,13 @@ static int vfs_statx(int dfd, struct filename *filename, int flags,
int vfs_fstatat(int dfd, const char __user *filename,
struct kstat *stat, int flags)
{
- int ret;
- int statx_flags = flags | AT_NO_AUTOMOUNT;
- struct filename *name = getname_maybe_null(filename, flags);
+ CLASS(filename_maybe_null, name)(filename, flags);
if (!name && dfd >= 0)
return vfs_fstat(dfd, stat);
- ret = vfs_statx(dfd, name, statx_flags, stat, STATX_BASIC_STATS);
- putname(name);
-
- return ret;
+ return vfs_statx(dfd, name, flags | AT_NO_AUTOMOUNT,
+ stat, STATX_BASIC_STATS);
}
#ifdef __ARCH_WANT_OLD_STAT
@@ -810,16 +806,12 @@ SYSCALL_DEFINE5(statx,
unsigned int, mask,
struct statx __user *, buffer)
{
- int ret;
- struct filename *name = getname_maybe_null(filename, flags);
+ CLASS(filename_maybe_null, name)(filename, flags);
if (!name && dfd >= 0)
return do_statx_fd(dfd, flags & ~AT_NO_AUTOMOUNT, mask, buffer);
- ret = do_statx(dfd, name, flags, mask, buffer);
- putname(name);
-
- return ret;
+ return do_statx(dfd, name, flags, mask, buffer);
}
#if defined(CONFIG_COMPAT) && defined(__ARCH_WANT_COMPAT_STAT)
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 55/59] user_statfs(): switch to CLASS(filename)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (53 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 54/59] statx: switch to CLASS(filename_maybe_null) Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 56/59] mqueue: " Al Viro
` (4 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/statfs.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/fs/statfs.c b/fs/statfs.c
index a5671bf6c7f0..377bcef7a561 100644
--- a/fs/statfs.c
+++ b/fs/statfs.c
@@ -99,7 +99,7 @@ int user_statfs(const char __user *pathname, struct kstatfs *st)
struct path path;
int error;
unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT;
- struct filename *name = getname(pathname);
+ CLASS(filename, name)(pathname);
retry:
error = filename_lookup(AT_FDCWD, name, lookup_flags, &path, NULL);
if (!error) {
@@ -110,7 +110,6 @@ int user_statfs(const char __user *pathname, struct kstatfs *st)
goto retry;
}
}
- putname(name);
return error;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 56/59] mqueue: switch to CLASS(filename)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (54 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 55/59] user_statfs(): switch to CLASS(filename) Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 57/59] ksmbd: use CLASS(filename_kernel) Al Viro
` (3 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
ipc/mqueue.c | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index c4f6d65596cf..53a58f9ba01f 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -912,13 +912,12 @@ static struct file *mqueue_file_open(struct filename *name,
static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
struct mq_attr *attr)
{
- struct filename *name __free(putname) = NULL;;
struct vfsmount *mnt = current->nsproxy->ipc_ns->mq_mnt;
int fd, ro;
audit_mq_open(oflag, mode, attr);
- name = getname(u_name);
+ CLASS(filename, name)(u_name);
if (IS_ERR(name))
return PTR_ERR(name);
@@ -942,20 +941,19 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
{
int err;
- struct filename *name;
struct dentry *dentry;
struct inode *inode;
struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
struct vfsmount *mnt = ipc_ns->mq_mnt;
+ CLASS(filename, name)(u_name);
- name = getname(u_name);
if (IS_ERR(name))
return PTR_ERR(name);
audit_inode_parent_hidden(name, mnt->mnt_root);
err = mnt_want_write(mnt);
if (err)
- goto out_name;
+ return err;
dentry = start_removing_noperm(mnt->mnt_root, &QSTR(name->name));
if (IS_ERR(dentry)) {
err = PTR_ERR(dentry);
@@ -971,9 +969,6 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
out_drop_write:
mnt_drop_write(mnt);
-out_name:
- putname(name);
-
return err;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 57/59] ksmbd: use CLASS(filename_kernel)
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (55 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 56/59] mqueue: " Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 58/59] alpha: switch osf_mount() to strndup_user() Al Viro
` (2 subsequent siblings)
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/smb/server/vfs.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index abfaebcf8cde..0fcf4898035e 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -54,7 +54,6 @@ static int ksmbd_vfs_path_lookup(struct ksmbd_share_config *share_conf,
struct path *path, bool for_remove)
{
struct qstr last;
- struct filename *filename __free(putname) = NULL;
const struct path *root_share_path = &share_conf->vfs_path;
int err, type;
struct dentry *d;
@@ -66,7 +65,7 @@ static int ksmbd_vfs_path_lookup(struct ksmbd_share_config *share_conf,
flags |= LOOKUP_BENEATH;
}
- filename = getname_kernel(pathname);
+ CLASS(filename_kernel, filename)(pathname);
err = vfs_path_parent_lookup(filename, flags,
path, &last, &type,
root_share_path);
@@ -664,7 +663,6 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
struct path new_path;
struct qstr new_last;
struct renamedata rd;
- struct filename *to;
struct ksmbd_share_config *share_conf = work->tcon->share_conf;
struct ksmbd_file *parent_fp;
int new_type;
@@ -673,7 +671,7 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
if (ksmbd_override_fsids(work))
return -ENOMEM;
- to = getname_kernel(newname);
+ CLASS(filename_kernel, to)(newname);
retry:
err = vfs_path_parent_lookup(to, lookup_flags | LOOKUP_BENEATH,
@@ -732,7 +730,6 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
goto retry;
}
out1:
- putname(to);
ksmbd_revert_fsids(work);
return err;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 58/59] alpha: switch osf_mount() to strndup_user()
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (56 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 57/59] ksmbd: use CLASS(filename_kernel) Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 3:55 ` [RFC PATCH v3 59/59] sysfs(2): fs_index() argument is _not_ a pathname Al Viro
2025-12-16 4:32 ` [RFC PATCH v3 00/59] struct filename work Linus Torvalds
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
... same as native mount(2) is doing for devname argument. While we
are at it, fix misspelling ufs_args as cdfs_args in osf_ufs_mount() -
layouts are identical, so it doesn't change anything, but the current
variant is confusing for no reason.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
arch/alpha/kernel/osf_sys.c | 34 +++++++++++-----------------------
1 file changed, 11 insertions(+), 23 deletions(-)
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index a08e8edef1a4..7b6543d2cca3 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -454,42 +454,30 @@ static int
osf_ufs_mount(const char __user *dirname,
struct ufs_args __user *args, int flags)
{
- int retval;
- struct cdfs_args tmp;
- struct filename *devname;
+ struct ufs_args tmp;
+ char *devname __free(kfree) = NULL;
- retval = -EFAULT;
if (copy_from_user(&tmp, args, sizeof(tmp)))
- goto out;
- devname = getname(tmp.devname);
- retval = PTR_ERR(devname);
+ return -EFAULT;
+ devname = strndup_user(tmp.devname, PATH_MAX);
if (IS_ERR(devname))
- goto out;
- retval = do_mount(devname->name, dirname, "ext2", flags, NULL);
- putname(devname);
- out:
- return retval;
+ return PTR_ERR(devname);
+ return do_mount(devname, dirname, "ext2", flags, NULL);
}
static int
osf_cdfs_mount(const char __user *dirname,
struct cdfs_args __user *args, int flags)
{
- int retval;
struct cdfs_args tmp;
- struct filename *devname;
+ char *devname __free(kfree) = NULL;
- retval = -EFAULT;
if (copy_from_user(&tmp, args, sizeof(tmp)))
- goto out;
- devname = getname(tmp.devname);
- retval = PTR_ERR(devname);
+ return -EFAULT;
+ devname = strndup_user(tmp.devname, PATH_MAX);
if (IS_ERR(devname))
- goto out;
- retval = do_mount(devname->name, dirname, "iso9660", flags, NULL);
- putname(devname);
- out:
- return retval;
+ return PTR_ERR(devname);
+ return do_mount(devname, dirname, "iso9660", flags, NULL);
}
static int
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH v3 59/59] sysfs(2): fs_index() argument is _not_ a pathname
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (57 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 58/59] alpha: switch osf_mount() to strndup_user() Al Viro
@ 2025-12-16 3:55 ` Al Viro
2025-12-16 4:32 ` [RFC PATCH v3 00/59] struct filename work Linus Torvalds
59 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 3:55 UTC (permalink / raw)
To: linux-fsdevel
Cc: torvalds, brauner, jack, mjguzik, paul, axboe, audit, io-uring,
linux-kernel
... it's a filesystem type name.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/filesystems.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/fs/filesystems.c b/fs/filesystems.c
index 95e5256821a5..0c7d2b7ac26c 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -132,24 +132,21 @@ EXPORT_SYMBOL(unregister_filesystem);
static int fs_index(const char __user * __name)
{
struct file_system_type * tmp;
- struct filename *name;
+ char *name __free(kfree) = strndup_user(__name, PATH_MAX);
int err, index;
- name = getname(__name);
- err = PTR_ERR(name);
if (IS_ERR(name))
- return err;
+ return PTR_ERR(name);
err = -EINVAL;
read_lock(&file_systems_lock);
for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) {
- if (strcmp(tmp->name, name->name) == 0) {
+ if (strcmp(tmp->name, name) == 0) {
err = index;
break;
}
}
read_unlock(&file_systems_lock);
- putname(name);
return err;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 64+ messages in thread* Re: [RFC PATCH v3 00/59] struct filename work
2025-12-16 3:54 [RFC PATCH v3 00/59] struct filename work Al Viro
` (58 preceding siblings ...)
2025-12-16 3:55 ` [RFC PATCH v3 59/59] sysfs(2): fs_index() argument is _not_ a pathname Al Viro
@ 2025-12-16 4:32 ` Linus Torvalds
2025-12-16 5:23 ` Al Viro
59 siblings, 1 reply; 64+ messages in thread
From: Linus Torvalds @ 2025-12-16 4:32 UTC (permalink / raw)
To: Al Viro
Cc: linux-fsdevel, brauner, jack, mjguzik, paul, axboe, audit,
io-uring, linux-kernel
So I like the whole series, but..
On Tue, 16 Dec 2025 at 15:56, Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> struct filename ->refcnt doesn't need to be atomic
Does ->refcnt need to exist _at_all_ if audit isn't enabled?
Are there any other users of it? Maybe I missed some?
Because I'm wondering if we could just encapsulate the thing entirely
in some #ifdef CONFIG_AUDIT check.
Now, I think absolutely everybody does enable audit, so it's not
because I'd try to save one word of memory and a few tests, it's more
of a "could we make it very explicit that all that code is purely
about the audit case"?
Linus
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [RFC PATCH v3 00/59] struct filename work
2025-12-16 4:32 ` [RFC PATCH v3 00/59] struct filename work Linus Torvalds
@ 2025-12-16 5:23 ` Al Viro
0 siblings, 0 replies; 64+ messages in thread
From: Al Viro @ 2025-12-16 5:23 UTC (permalink / raw)
To: Linus Torvalds
Cc: linux-fsdevel, brauner, jack, mjguzik, paul, axboe, audit,
io-uring, linux-kernel
On Tue, Dec 16, 2025 at 04:32:03PM +1200, Linus Torvalds wrote:
> So I like the whole series, but..
>
> On Tue, 16 Dec 2025 at 15:56, Al Viro <viro@zeniv.linux.org.uk> wrote:
> >
> > struct filename ->refcnt doesn't need to be atomic
>
> Does ->refcnt need to exist _at_all_ if audit isn't enabled?
>
> Are there any other users of it? Maybe I missed some?
>
> Because I'm wondering if we could just encapsulate the thing entirely
> in some #ifdef CONFIG_AUDIT check.
>
> Now, I think absolutely everybody does enable audit, so it's not
> because I'd try to save one word of memory and a few tests, it's more
> of a "could we make it very explicit that all that code is purely
> about the audit case"?
Umm... Not exactly. I mean, yes, at the moment we never increment the
refcount outside of kernel/auditsc.c, so it'll always be 1 if that thing
is disabled.
But if you mean to store it on caller's stack, that's another kettle of
fish - anything async with io_uring won't be able to do that, even we
ignore the stack footprint issues. In configs without audit we end up
1) allocating it and copying the pathname from userland on
request submission; pointer is stashed into request.
2) picking it in processing thread and doing the operation
there By that point submitted might have not just left the kernel,
but overwritten the pathname contents in userland.
3) either stashing it back into request or freeing it.
With audit (2) might become "... and have an extra ref stashed in audit
context" with (3) becoming "either stashing it back into request, if no
extra ref has appeared, or making a copy, stashing it back into request
and dropping the reference on the original"
So refcount may be audit-only thing, at least at the moment, but the
need to outlive the syscall where getname() had been called is very much
not audit-only.
And stack footprint is not trivial either, unless you limit embedded
case to something very short - even an extra hundred bytes (or two,
e.g. in case of rename()) is not something I'd be entirely comfortable
grabbing for pathname-related syscalls.
^ permalink raw reply [flat|nested] 64+ messages in thread