[Concept,11/34] vfs: Filter dir lookup to skip non-DIR children

Message ID 20260403140523.1998228-12-sjg@u-boot.org
State New
Headers
Series Add a virtual filesystem (VFS) layer to U-Boot |

Commit Message

Simon Glass April 3, 2026, 2:04 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

fs_lookup_dir() iterates all children of an FS device looking for a
cached directory but does not filter by uclass. With the addition of
the MOUNT uclass, a non-directory child whose uclass-private data is
misinterpreted as struct dir_uc_priv can cause a false path match.
Add a UCLASS_DIR check to skip non-directory children.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 fs/fs-uclass.c |  2 ++
 fs/vfs.c       |  7 +++++++
 fs/vfs_dir.c   | 10 ++++++++++
 include/vfs.h  |  8 ++++++++
 4 files changed, 27 insertions(+)
  

Patch

diff --git a/fs/fs-uclass.c b/fs/fs-uclass.c
index 6bb50bb2543..2525067f166 100644
--- a/fs/fs-uclass.c
+++ b/fs/fs-uclass.c
@@ -61,6 +61,8 @@  int fs_lookup_dir(struct udevice *dev, const char *path, struct udevice **dirp)
 
 		if (!device_active(dir))
 			continue;
+		if (device_get_uclass_id(dir) != UCLASS_DIR)
+			continue;
 
 		priv = dev_get_uclass_priv(dir);
 		log_debug("dir %s '%s' '%s'\n", dir->name, path, priv->path);
diff --git a/fs/vfs.c b/fs/vfs.c
index c42e60b4dc6..db1aa84bfd6 100644
--- a/fs/vfs.c
+++ b/fs/vfs.c
@@ -311,6 +311,13 @@  int vfs_umount_path(struct udevice *vfs, const char *path)
 	return vfs_umount(mnt_dev);
 }
 
+bool vfs_is_mount_point(struct udevice *dir)
+{
+	struct udevice *mnt;
+
+	return !find_mount(dir, &mnt);
+}
+
 void vfs_print_mounts(void)
 {
 	struct vfsmount *mnt;
diff --git a/fs/vfs_dir.c b/fs/vfs_dir.c
index 87a4193516e..5c3b5a2952b 100644
--- a/fs/vfs_dir.c
+++ b/fs/vfs_dir.c
@@ -13,6 +13,7 @@ 
 #include <dir.h>
 #include <dm.h>
 #include <fs.h>
+#include <vfs.h>
 #include <fs_common.h>
 
 static int vfs_rootfs_dir_open(struct udevice *dev,
@@ -81,8 +82,17 @@  static struct dir_ops vfs_rootfs_dir_ops = {
 	.close	= vfs_rootfs_dir_close,
 };
 
+static int vfs_rootfs_dir_remove(struct udevice *dev)
+{
+	if (vfs_is_mount_point(dev))
+		return log_msg_ret("drm", -EBUSY);
+
+	return 0;
+}
+
 U_BOOT_DRIVER(vfs_rootfs_dir) = {
 	.name	= "vfs_rootfs_dir",
 	.id	= UCLASS_DIR,
 	.ops	= &vfs_rootfs_dir_ops,
+	.remove	= vfs_rootfs_dir_remove,
 };
diff --git a/include/vfs.h b/include/vfs.h
index d7b6449b088..6673f9a5ef1 100644
--- a/include/vfs.h
+++ b/include/vfs.h
@@ -112,6 +112,14 @@  int vfs_umount_path(struct udevice *vfs, const char *path);
 int vfs_find_mount(struct udevice *vfs, const char *path,
 		   struct udevice **mntp, const char **subpathp);
 
+/**
+ * vfs_is_mount_point() - Check whether a directory is a mount point
+ *
+ * @dir: UCLASS_DIR device to check
+ * Return: true if this directory has an active mount, false otherwise
+ */
+bool vfs_is_mount_point(struct udevice *dir);
+
 /**
  * vfs_print_mounts() - Print all current mounts
  */