[PATCH RFC DRAFT POC 08/11] fs: allow to pass lookup flags to filename_*()
From: Christian Brauner
Date: Tue Mar 03 2026 - 08:59:44 EST
Allow lookup flags to be passed to filename_*() so callers can pass
LOOUP_IN_INIT to explicitly opt-into to performing lookups in init's
filesystem state.
Signed-off-by: Christian Brauner <brauner@xxxxxxxxxx>
---
fs/coredump.c | 2 +-
fs/init.c | 12 ++++++------
fs/internal.h | 18 ++++++++++++------
fs/namei.c | 52 +++++++++++++++++++++++++++-------------------------
io_uring/fs.c | 10 +++++-----
5 files changed, 51 insertions(+), 43 deletions(-)
diff --git a/fs/coredump.c b/fs/coredump.c
index 29df8aa19e2e..550a1553f6cb 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -900,7 +900,7 @@ static bool coredump_file(struct core_name *cn, struct coredump_params *cprm,
* If it doesn't exist, that's fine. If there's some
* other problem, we'll catch it at the filp_open().
*/
- filename_unlinkat(AT_FDCWD, name);
+ filename_unlinkat(AT_FDCWD, name, 0);
}
/*
diff --git a/fs/init.c b/fs/init.c
index 33e312d74f58..a79872d5af3b 100644
--- a/fs/init.c
+++ b/fs/init.c
@@ -158,39 +158,39 @@ int __init init_stat(const char *filename, struct kstat *stat, int flags)
int __init init_mknod(const char *filename, umode_t mode, unsigned int dev)
{
CLASS(filename_kernel, name)(filename);
- return filename_mknodat(AT_FDCWD, name, mode, dev);
+ return filename_mknodat(AT_FDCWD, name, mode, dev, 0);
}
int __init init_link(const char *oldname, const char *newname)
{
CLASS(filename_kernel, old)(oldname);
CLASS(filename_kernel, new)(newname);
- return filename_linkat(AT_FDCWD, old, AT_FDCWD, new, 0);
+ return filename_linkat(AT_FDCWD, old, AT_FDCWD, new, 0, 0);
}
int __init init_symlink(const char *oldname, const char *newname)
{
CLASS(filename_kernel, old)(oldname);
CLASS(filename_kernel, new)(newname);
- return filename_symlinkat(old, AT_FDCWD, new);
+ return filename_symlinkat(old, AT_FDCWD, new, 0);
}
int __init init_unlink(const char *pathname)
{
CLASS(filename_kernel, name)(pathname);
- return filename_unlinkat(AT_FDCWD, name);
+ return filename_unlinkat(AT_FDCWD, name, 0);
}
int __init init_mkdir(const char *pathname, umode_t mode)
{
CLASS(filename_kernel, name)(pathname);
- return filename_mkdirat(AT_FDCWD, name, mode);
+ return filename_mkdirat(AT_FDCWD, name, mode, 0);
}
int __init init_rmdir(const char *pathname)
{
CLASS(filename_kernel, name)(pathname);
- return filename_rmdir(AT_FDCWD, name);
+ return filename_rmdir(AT_FDCWD, name, 0);
}
int __init init_utimes(char *filename, struct timespec64 *ts)
diff --git a/fs/internal.h b/fs/internal.h
index cbc384a1aa09..7302badcae69 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -53,16 +53,22 @@ extern int finish_clean_context(struct fs_context *fc);
*/
extern int filename_lookup(int dfd, struct filename *name, unsigned flags,
struct path *path, const struct path *root);
-int filename_rmdir(int dfd, struct filename *name);
-int filename_unlinkat(int dfd, struct filename *name);
+int filename_rmdir(int dfd, struct filename *name,
+ unsigned int lookup_flags);
+int filename_unlinkat(int dfd, struct filename *name,
+ unsigned int lookup_flags);
int may_linkat(struct mnt_idmap *idmap, const struct path *link);
int filename_renameat2(int olddfd, struct filename *oldname, int newdfd,
struct filename *newname, unsigned int flags);
-int filename_mkdirat(int dfd, struct filename *name, umode_t mode);
-int filename_mknodat(int dfd, struct filename *name, umode_t mode, unsigned int dev);
-int filename_symlinkat(struct filename *from, int newdfd, struct filename *to);
+int filename_mkdirat(int dfd, struct filename *name, umode_t mode,
+ unsigned int lookup_flags);
+int filename_mknodat(int dfd, struct filename *name, umode_t mode,
+ unsigned int dev, unsigned int lookup_flags);
+int filename_symlinkat(struct filename *from, int newdfd, struct filename *to,
+ unsigned int lookup_flags);
int filename_linkat(int olddfd, struct filename *old, int newdfd,
- struct filename *new, int flags);
+ struct filename *new, int flags,
+ unsigned int lookup_flags);
int vfs_tmpfile(struct mnt_idmap *idmap,
const struct path *parentpath,
struct file *file, umode_t mode);
diff --git a/fs/namei.c b/fs/namei.c
index dd2710d5f5df..5cf407aad5b3 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -5125,14 +5125,13 @@ static int may_mknod(umode_t mode)
}
int filename_mknodat(int dfd, struct filename *name, umode_t mode,
- unsigned int dev)
+ unsigned int dev, unsigned int lookup_flags)
{
struct delegated_inode di = { };
struct mnt_idmap *idmap;
struct dentry *dentry;
struct path path;
int error;
- unsigned int lookup_flags = 0;
error = may_mknod(mode);
if (error)
@@ -5181,13 +5180,13 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
unsigned int, dev)
{
CLASS(filename, name)(filename);
- return filename_mknodat(dfd, name, mode, dev);
+ return filename_mknodat(dfd, name, mode, dev, 0);
}
SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev)
{
CLASS(filename, name)(filename);
- return filename_mknodat(AT_FDCWD, name, mode, dev);
+ return filename_mknodat(AT_FDCWD, name, mode, dev, 0);
}
/**
@@ -5258,14 +5257,16 @@ struct dentry *vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
}
EXPORT_SYMBOL(vfs_mkdir);
-int filename_mkdirat(int dfd, struct filename *name, umode_t mode)
+int filename_mkdirat(int dfd, struct filename *name, umode_t mode,
+ unsigned int lookup_flags)
{
struct dentry *dentry;
struct path path;
int error;
- unsigned int lookup_flags = LOOKUP_DIRECTORY;
struct delegated_inode delegated_inode = { };
+ lookup_flags |= LOOKUP_DIRECTORY;
+
retry:
dentry = filename_create(dfd, name, &path, lookup_flags);
if (IS_ERR(dentry))
@@ -5295,13 +5296,13 @@ int filename_mkdirat(int dfd, struct filename *name, umode_t mode)
SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
{
CLASS(filename, name)(pathname);
- return filename_mkdirat(dfd, name, mode);
+ return filename_mkdirat(dfd, name, mode, 0);
}
SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
{
CLASS(filename, name)(pathname);
- return filename_mkdirat(AT_FDCWD, name, mode);
+ return filename_mkdirat(AT_FDCWD, name, mode, 0);
}
/**
@@ -5364,14 +5365,14 @@ int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir,
}
EXPORT_SYMBOL(vfs_rmdir);
-int filename_rmdir(int dfd, struct filename *name)
+int filename_rmdir(int dfd, struct filename *name,
+ unsigned int lookup_flags)
{
int error;
struct dentry *dentry;
struct path path;
struct qstr last;
int type;
- unsigned int lookup_flags = 0;
struct delegated_inode delegated_inode = { };
retry:
error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
@@ -5424,7 +5425,7 @@ int filename_rmdir(int dfd, struct filename *name)
SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
{
CLASS(filename, name)(pathname);
- return filename_rmdir(AT_FDCWD, name);
+ return filename_rmdir(AT_FDCWD, name, 0);
}
/**
@@ -5506,7 +5507,8 @@ EXPORT_SYMBOL(vfs_unlink);
* writeout happening, and we don't want to prevent access to the directory
* while waiting on the I/O.
*/
-int filename_unlinkat(int dfd, struct filename *name)
+int filename_unlinkat(int dfd, struct filename *name,
+ unsigned int lookup_flags)
{
int error;
struct dentry *dentry;
@@ -5515,7 +5517,6 @@ int filename_unlinkat(int dfd, struct filename *name)
int type;
struct inode *inode;
struct delegated_inode delegated_inode = { };
- unsigned int lookup_flags = 0;
retry:
error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
if (error)
@@ -5576,14 +5577,14 @@ SYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag)
CLASS(filename, name)(pathname);
if (flag & AT_REMOVEDIR)
- return filename_rmdir(dfd, name);
- return filename_unlinkat(dfd, name);
+ return filename_rmdir(dfd, name, 0);
+ return filename_unlinkat(dfd, name, 0);
}
SYSCALL_DEFINE1(unlink, const char __user *, pathname)
{
CLASS(filename, name)(pathname);
- return filename_unlinkat(AT_FDCWD, name);
+ return filename_unlinkat(AT_FDCWD, name, 0);
}
/**
@@ -5630,12 +5631,12 @@ int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
}
EXPORT_SYMBOL(vfs_symlink);
-int filename_symlinkat(struct filename *from, int newdfd, struct filename *to)
+int filename_symlinkat(struct filename *from, int newdfd, struct filename *to,
+ unsigned int lookup_flags)
{
int error;
struct dentry *dentry;
struct path path;
- unsigned int lookup_flags = 0;
struct delegated_inode delegated_inode = { };
if (IS_ERR(from))
@@ -5668,14 +5669,14 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
{
CLASS(filename, old)(oldname);
CLASS(filename, new)(newname);
- return filename_symlinkat(old, newdfd, new);
+ return filename_symlinkat(old, newdfd, new, 0);
}
SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newname)
{
CLASS(filename, old)(oldname);
CLASS(filename, new)(newname);
- return filename_symlinkat(old, AT_FDCWD, new);
+ return filename_symlinkat(old, AT_FDCWD, new, 0);
}
/**
@@ -5779,13 +5780,14 @@ EXPORT_SYMBOL(vfs_link);
* and other special files. --ADM
*/
int filename_linkat(int olddfd, struct filename *old,
- int newdfd, struct filename *new, int flags)
+ int newdfd, struct filename *new, int flags,
+ unsigned int lookup_flags)
{
struct mnt_idmap *idmap;
struct dentry *new_dentry;
struct path old_path, new_path;
struct delegated_inode delegated_inode = { };
- int how = 0;
+ int how = lookup_flags;
int error;
if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
@@ -5807,7 +5809,7 @@ int filename_linkat(int olddfd, struct filename *old,
return error;
new_dentry = filename_create(newdfd, new, &new_path,
- (how & LOOKUP_REVAL));
+ (how & (LOOKUP_REVAL | LOOKUP_IN_INIT)));
error = PTR_ERR(new_dentry);
if (IS_ERR(new_dentry))
goto out_putpath;
@@ -5848,14 +5850,14 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
{
CLASS(filename_uflags, old)(oldname, flags);
CLASS(filename, new)(newname);
- return filename_linkat(olddfd, old, newdfd, new, flags);
+ return filename_linkat(olddfd, old, newdfd, new, flags, 0);
}
SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname)
{
CLASS(filename, old)(oldname);
CLASS(filename, new)(newname);
- return filename_linkat(AT_FDCWD, old, AT_FDCWD, new, 0);
+ return filename_linkat(AT_FDCWD, old, AT_FDCWD, new, 0, 0);
}
/**
diff --git a/io_uring/fs.c b/io_uring/fs.c
index d0580c754bf8..1d9b2939f5ae 100644
--- a/io_uring/fs.c
+++ b/io_uring/fs.c
@@ -140,9 +140,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 = filename_rmdir(un->dfd, name);
+ ret = filename_rmdir(un->dfd, name, 0);
else
- ret = filename_unlinkat(un->dfd, name);
+ ret = filename_unlinkat(un->dfd, name, 0);
req->flags &= ~REQ_F_NEED_CLEANUP;
io_req_set_res(req, ret, 0);
@@ -188,7 +188,7 @@ int io_mkdirat(struct io_kiocb *req, unsigned int issue_flags)
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
- ret = filename_mkdirat(mkd->dfd, name, mkd->mode);
+ ret = filename_mkdirat(mkd->dfd, name, mkd->mode, 0);
req->flags &= ~REQ_F_NEED_CLEANUP;
io_req_set_res(req, ret, 0);
@@ -241,7 +241,7 @@ int io_symlinkat(struct io_kiocb *req, unsigned int issue_flags)
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
- ret = filename_symlinkat(old, sl->new_dfd, new);
+ ret = filename_symlinkat(old, sl->new_dfd, new, 0);
req->flags &= ~REQ_F_NEED_CLEANUP;
io_req_set_res(req, ret, 0);
@@ -289,7 +289,7 @@ int io_linkat(struct io_kiocb *req, unsigned int issue_flags)
WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
- ret = filename_linkat(lnk->old_dfd, old, lnk->new_dfd, new, lnk->flags);
+ ret = filename_linkat(lnk->old_dfd, old, lnk->new_dfd, new, lnk->flags, 0);
req->flags &= ~REQ_F_NEED_CLEANUP;
io_req_set_res(req, ret, 0);
--
2.47.3