fs: Add support for a filesystem
The existing filesystem support is fairly basic. It supports access to only one filesystem at a time, does not allow caching, does not have an equivalent of Linux's VFS and uses global variables to keep track of which one is in use. As a starting point to improving this, provide a filesystem uclass. For now it only includes operations to mount and unmount. Provide a bootdev so that it is possible to locate bootflows on a filesystem. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
@@ -1182,6 +1182,12 @@ F: net/fastboot_tcp.c
|
||||
F: net/fastboot_udp.c
|
||||
F: test/dm/fastboot.c
|
||||
|
||||
FILESYSTEM LAYER
|
||||
M: Simon Glass <sjg@chromium.org>
|
||||
S: Maintained
|
||||
F: fs/fs-uclass.c
|
||||
F: include/fs.h
|
||||
|
||||
FPGA
|
||||
M: Michal Simek <michal.simek@amd.com>
|
||||
S: Maintained
|
||||
|
||||
@@ -4,6 +4,14 @@
|
||||
|
||||
menu "File systems"
|
||||
|
||||
config FS
|
||||
bool "Support for filesystems"
|
||||
default y if SANDBOX || VENDOR_EMULATION || ARCH_QEMU
|
||||
depends on EXPERT
|
||||
help
|
||||
Provides an interface for filesystems, allowing them to be
|
||||
persistently mounted. Filesystem can contain files and directory.
|
||||
|
||||
config FS_LEGACY
|
||||
def_bool y
|
||||
help
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
# Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
|
||||
|
||||
obj-$(CONFIG_$(PHASE_)FS_LEGACY) += fs_legacy.o fs_internal.o
|
||||
obj-$(CONFIG_$(PHASE_)FS) += fs-uclass.o
|
||||
|
||||
ifdef CONFIG_XPL_BUILD
|
||||
obj-$(CONFIG_SPL_FS_FAT) += fat/
|
||||
|
||||
113
fs/fs-uclass.c
Normal file
113
fs/fs-uclass.c
Normal file
@@ -0,0 +1,113 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Implementation of a filesystem, e.g. on a partition
|
||||
*
|
||||
* Copyright 2025 Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#define LOG_DEBUG
|
||||
#define LOG_CATEGORY UCLASS_FS
|
||||
|
||||
#include <bootdev.h>
|
||||
#include <bootmeth.h>
|
||||
#include <dm.h>
|
||||
#include <fs.h>
|
||||
#include <dm/device-internal.h>
|
||||
|
||||
int fs_mount(struct udevice *dev)
|
||||
{
|
||||
struct fs_ops *ops = fs_get_ops(dev);
|
||||
int ret;
|
||||
|
||||
ret = ops->mount(dev);
|
||||
if (ret)
|
||||
return log_msg_ret("fsm", ret);
|
||||
|
||||
ret = bootdev_setup_for_dev(dev, "fs_bootdev");
|
||||
if (ret)
|
||||
return log_msg_ret("fss", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fs_unmount(struct udevice *dev)
|
||||
{
|
||||
struct fs_ops *ops = fs_get_ops(dev);
|
||||
|
||||
return ops->unmount(dev);
|
||||
}
|
||||
|
||||
static int fs_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
|
||||
struct bootflow *bflow)
|
||||
{
|
||||
struct udevice *fsdev = dev_get_parent(dev);
|
||||
int ret;
|
||||
|
||||
log_debug("get_bootflow fs '%s'\n", fsdev->name);
|
||||
|
||||
ret = bootmeth_check(bflow->method, iter);
|
||||
if (ret)
|
||||
return log_msg_ret("check", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fs_bootdev_bind(struct udevice *dev)
|
||||
{
|
||||
struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
|
||||
|
||||
/*
|
||||
* we don't know what priority to give this, so pick something a little
|
||||
* slow for now
|
||||
*/
|
||||
ucp->prio = BOOTDEVP_3_INTERNAL_SLOW;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fs_bootdev_hunt(struct bootdev_hunter *info, bool show)
|
||||
{
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
/* mount all filesystems, which will create bootdevs for each */
|
||||
uclass_foreach_dev_probe(UCLASS_FS, dev) {
|
||||
ret = fs_mount(dev);
|
||||
if (ret)
|
||||
log_warning("Failed to mount filesystem '%s'\n",
|
||||
dev->name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct bootdev_ops fs_bootdev_ops = {
|
||||
.get_bootflow = fs_get_bootflow,
|
||||
};
|
||||
|
||||
static const struct udevice_id fs_bootdev_ids[] = {
|
||||
{ .compatible = "u-boot,bootdev-fs" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(fs_bootdev) = {
|
||||
.name = "fs_bootdev",
|
||||
.id = UCLASS_BOOTDEV,
|
||||
.ops = &fs_bootdev_ops,
|
||||
.bind = fs_bootdev_bind,
|
||||
.of_match = fs_bootdev_ids,
|
||||
};
|
||||
|
||||
BOOTDEV_HUNTER(fs_bootdev_hunter) = {
|
||||
.prio = BOOTDEVP_3_INTERNAL_SLOW,
|
||||
.uclass = UCLASS_FS,
|
||||
.hunt = fs_bootdev_hunt,
|
||||
.drv = DM_DRIVER_REF(fs_bootdev),
|
||||
};
|
||||
|
||||
UCLASS_DRIVER(fs) = {
|
||||
.name = "fs",
|
||||
.id = UCLASS_FS,
|
||||
.per_device_auto = sizeof(struct fs_priv),
|
||||
.per_device_plat_auto = sizeof(struct fs_plat),
|
||||
};
|
||||
@@ -68,6 +68,7 @@ enum uclass_id {
|
||||
UCLASS_FIRMWARE, /* Firmware */
|
||||
UCLASS_FPGA, /* FPGA device */
|
||||
UCLASS_FUZZING_ENGINE, /* Fuzzing engine */
|
||||
UCLASS_FS, /* Filesystem */
|
||||
UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */
|
||||
UCLASS_FWU_MDATA, /* FWU Metadata Access */
|
||||
UCLASS_GPIO, /* Bank of general-purpose I/O pins */
|
||||
|
||||
78
include/fs.h
Normal file
78
include/fs.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* U-Boot Filesystem layer
|
||||
*
|
||||
* Models a filesystem which can be mounted and unmounted. It also allows a
|
||||
* directory to be looked up.
|
||||
*
|
||||
* Copyright 2025 Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#ifndef __FS_H
|
||||
#define __FS_H
|
||||
|
||||
#include <fs_common.h>
|
||||
|
||||
struct udevice;
|
||||
|
||||
enum {
|
||||
/* Maximum length of the filesystem name */
|
||||
FS_MAX_NAME_LEN = 128,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct fs_plat - Filesystem information
|
||||
*
|
||||
* @name: Name of the filesystem, or empty if not available
|
||||
*/
|
||||
struct fs_plat {
|
||||
char name[FS_MAX_NAME_LEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct fs_priv - Private information for the FS devices
|
||||
*
|
||||
* @mounted: true if mounted
|
||||
*/
|
||||
struct fs_priv {
|
||||
bool mounted;
|
||||
};
|
||||
|
||||
struct fs_ops {
|
||||
/**
|
||||
* mount() - Mount the filesystem
|
||||
*
|
||||
* @dev: Filesystem device
|
||||
* Return 0 if OK, -EISCONN if already mounted, other -ve on error
|
||||
*/
|
||||
int (*mount)(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* unmount() - Unmount the filesystem
|
||||
*
|
||||
* @dev: Filesystem device
|
||||
* Return 0 if OK, -ENOTCONN if not mounted, other -ve on error
|
||||
*/
|
||||
int (*unmount)(struct udevice *dev);
|
||||
};
|
||||
|
||||
/* Get access to a filesystem's operations */
|
||||
#define fs_get_ops(dev) ((struct fs_ops *)(dev)->driver->ops)
|
||||
|
||||
/**
|
||||
* fs_mount() - Mount the filesystem
|
||||
*
|
||||
* @dev: Filesystem device
|
||||
* Return 0 if OK, -EISCONN if already mounted, other -ve on error
|
||||
*/
|
||||
int fs_mount(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* fs_unmount() - Unmount the filesystem
|
||||
*
|
||||
* @dev: Filesystem device
|
||||
* Return 0 if OK, -ENOTCONN if not mounted, other -ve on error
|
||||
*/
|
||||
int fs_unmount(struct udevice *dev);
|
||||
|
||||
#endif
|
||||
@@ -390,6 +390,7 @@ static int bootdev_test_hunter(struct unit_test_state *uts)
|
||||
ut_assert_nextlinen("----");
|
||||
ut_assert_nextline(" 6 ethernet eth_bootdev");
|
||||
ut_assert_nextline(" 1 simple_bus (none)");
|
||||
ut_assert_nextline(" 3 fs fs_bootdev");
|
||||
ut_assert_nextline(" 5 ide ide_bootdev");
|
||||
ut_assert_nextline(" 2 mmc mmc_bootdev");
|
||||
ut_assert_nextline(" 4 nvme nvme_bootdev");
|
||||
@@ -447,6 +448,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts)
|
||||
/* This is the extension feature which has no uclass at present */
|
||||
ut_assert_nextline("Hunting with: simple_bus");
|
||||
ut_assert_nextline("Found 2 extension board(s).");
|
||||
ut_assert_nextline("Hunting with: fs");
|
||||
ut_assert_nextline("Hunting with: ide");
|
||||
|
||||
/* mmc hunter has already been used so should not run again */
|
||||
@@ -468,6 +470,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts)
|
||||
ut_assert_nextlinen("----");
|
||||
ut_assert_nextline(" 6 * ethernet eth_bootdev");
|
||||
ut_assert_nextline(" 1 * simple_bus (none)");
|
||||
ut_assert_nextline(" 3 * fs fs_bootdev");
|
||||
ut_assert_nextline(" 5 * ide ide_bootdev");
|
||||
ut_assert_nextline(" 2 * mmc mmc_bootdev");
|
||||
ut_assert_nextline(" 4 * nvme nvme_bootdev");
|
||||
|
||||
@@ -24,10 +24,11 @@
|
||||
enum {
|
||||
HUNTER_ETH = 0,
|
||||
HUNTER_SIMPLE_BUS,
|
||||
HUNTER_MMC = 3,
|
||||
HUNTER_SCSI = 6,
|
||||
HUNTER_USB = 8,
|
||||
HUNTER_COUNT = 10,
|
||||
HUNTER_FS = 3,
|
||||
HUNTER_MMC, /* ID of MMC hunter */
|
||||
HUNTER_SCSI = 7, /* ID of SCSI hunter */
|
||||
HUNTER_USB = 9, /* ID of USB hunter */
|
||||
HUNTER_COUNT = 11,
|
||||
HUNTER_MAX = HUNTER_COUNT - 1,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user