[PATCH 1/6] fs: use filename_create/filename_lookup instead of open-coding

Ahmad Fatoum a.fatoum at pengutronix.de
Wed Mar 19 22:20:14 PDT 2025


By reusing the existing file lookup code, open can open all directories,
e.g. / and /tmp/., which so far wasn't possible.

We need to be able to open these paths for directory FDs to work as one
would expect.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 fs/fs.c           | 55 ++++++++---------------------------------------
 test/self/dirfd.c |  7 +-----
 2 files changed, 10 insertions(+), 52 deletions(-)

diff --git a/fs/fs.c b/fs/fs.c
index 96ca60341ea4..1766719c567a 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -2543,9 +2543,7 @@ int openat(int dirfd, const char *pathname, int flags)
 	int error = 0;
 	struct inode *inode = NULL;
 	struct dentry *dentry = NULL;
-	struct nameidata nd;
-	const char *s;
-	struct filename *filename;
+	struct path path;
 
 	if (flags & O_TMPFILE) {
 		fsdev = get_fsdevice_by_path(dirfd, pathname);
@@ -2575,57 +2573,22 @@ int openat(int dirfd, const char *pathname, int flags)
 		return file_to_fd(f);
 	}
 
-	filename = getname(pathname);
-	if (IS_ERR(filename))
-		return PTR_ERR(filename);
-
-	set_nameidata(&nd, filename);
-
-	s = path_init(dirfd, &nd, LOOKUP_FOLLOW);
-	if (IS_ERR(s))
-		return PTR_ERR(s);
-
-	while (1) {
-		error = link_path_walk(s, &nd);
-		if (error)
-			break;
-
-		if (!d_is_dir(nd.path.dentry)) {
-			error = -ENOTDIR;
-			break;
-		}
-
-		dentry = __lookup_hash(&nd.last, nd.path.dentry, 0);
-		if (IS_ERR(dentry)) {
-			error = PTR_ERR(dentry);
-			break;
-		}
-
-		if (!d_is_symlink(dentry))
-			break;
-
-		dput(dentry);
-
-		error = lookup_last(&nd);
-		if (error <= 0)
-			break;
-
-		s = trailing_symlink(&nd);
-		if (IS_ERR(s)) {
-			error = PTR_ERR(s);
-			break;
-		}
+	if (flags & O_CREAT) {
+		dentry = filename_create(dirfd, getname(pathname), &path, 0);
+		error = PTR_ERR_OR_ZERO(dentry);
 	}
 
-	terminate_walk(&nd);
-	putname(nd.name);
+	if (!(flags & O_CREAT) || error == -EEXIST) {
+		error = filename_lookup(dirfd, getname(pathname), LOOKUP_FOLLOW, &path);
+		dentry = path.dentry;
+	}
 
 	if (error)
 		goto out1;
 
 	if (d_is_negative(dentry)) {
 		if (flags & O_CREAT) {
-			error = create(nd.path.dentry, dentry);
+			error = create(path.dentry, dentry);
 			if (error)
 				goto out1;
 		} else {
diff --git a/test/self/dirfd.c b/test/self/dirfd.c
index 644ff214fb37..20b54258715a 100644
--- a/test/self/dirfd.c
+++ b/test/self/dirfd.c
@@ -100,13 +100,8 @@ static void test_dirfd(void)
 	int fd;
 
 	fd = open("/", O_PATH);
-	if (expect(fd < 0, false, "open(/, O_PATH) = %d", fd)) {
+	if (expect(fd < 0, false, "open(/, O_PATH) = %d", fd))
 		close(fd);
-	} else {
-		pr_info("\tIgnoring expected failure\n");
-		failed_tests--;
-		skipped_tests++;
-	}
 
 #define B(dot, dotdot, zero, dev) 0b##dev##zero##dotdot##dot
 	/* We do fiften tests for every configuration
-- 
2.39.5




More information about the barebox mailing list