#include #include #include "vfs.h" #include "kprintf.h" #include "spinlock/spinlock.h" #include "hal/hal.h" #include "util/util.h" #include "hshtb.h" #include "assert.h" #include "errors.h" #include "fs/kvfs/kvfs.h" #include "fs/portlfs/portlfs.h" #include "storedev/storedev.h" #include "baseimg/baseimg.h" #include "dlmalloc/malloc.h" VfsTable VFS_TABLE; void vfs_init_kvfs(VfsMountPoint *mp) { mp->read = &kvfs_read; mp->write = &kvfs_write; mp->remove = &kvfs_remove; mp->check = &kvfs_check; mp->cleanup = &kvfs_cleanup; mp->create = &kvfs_create; } void vfs_init_littlefs(VfsMountPoint *mp) { struct lfs_config *cfg = dlmalloc(sizeof(*cfg)); hal_memset(cfg, 0, sizeof(*cfg)); cfg->context = mp; cfg->read = &portlfs_read; cfg->prog = &portlfs_prog; cfg->erase = &portlfs_erase; cfg->sync = &portlfs_sync; cfg->block_size = LITTLEFS_BLOCK_SIZE; cfg->block_count = mp->backingsd->capacity(mp->backingsd) / LITTLEFS_BLOCK_SIZE; cfg->read_size = 64; cfg->prog_size = 64; cfg->block_cycles = 16; cfg->cache_size = 64; cfg->lookahead_size = 64; cfg->read_buffer = NULL; cfg->prog_buffer = NULL; cfg->lookahead_buffer = NULL; cfg->name_max = 0; cfg->file_max = 0; cfg->attr_max = 0; int err = lfs_mount(&mp->fs.littlefs.instance, cfg); if (err < 0) { ERR("vfs", "Little FS mount failed\n"); } mp->read = &littlefs_read; mp->write = &littlefs_write; mp->remove = &littlefs_remove; mp->check = &littlefs_check; mp->cleanup = &littlefs_cleanup; mp->create = &littlefs_create; } int32_t vfs_mount(char *mountpoint, int32_t fstype, StoreDev *backingsd) { VfsMountPoint *mp = NULL; spinlock_acquire(&VFS_TABLE.spinlock); HSHTB_ALLOC(&VFS_TABLE, mountpoints, mountpoint, label, mp); spinlock_release(&VFS_TABLE.spinlock); if (mp == NULL) { return E_NOMEMORY; } hal_memcpy(mp->label, mountpoint, hal_strlen(mountpoint)); mp->backingsd = backingsd; mp->fstype = fstype; switch (fstype) { case VFS_KVFS: vfs_init_kvfs(mp); break; case VFS_LITTLEFS: vfs_init_littlefs(mp); break; default: return E_UNKNOWN_FSTYPE; } return E_OK; } int32_t vfs_unmount(char *mountpoint) { VfsMountPoint *mp = NULL; spinlock_acquire(&VFS_TABLE.spinlock); HSHTB_GET(&VFS_TABLE, mountpoints, mountpoint, label, mp); spinlock_release(&VFS_TABLE.spinlock); if (mp == NULL) { return E_NOENTRY; } spinlock_acquire(&mp->spinlock); int32_t err = mp->cleanup(mp); if (err != E_OK) { spinlock_release(&mp->spinlock); return err; } hal_memset(mp, 0, sizeof(*mp)); spinlock_release(&mp->spinlock); return E_OK; } int32_t vfs_read(char *mountpoint, const char *path, uint8_t *const buffer, size_t n, size_t off) { VfsMountPoint *mp = NULL; spinlock_acquire(&VFS_TABLE.spinlock); HSHTB_GET(&VFS_TABLE, mountpoints, mountpoint, label, mp); spinlock_release(&VFS_TABLE.spinlock); if (mp == NULL) { return E_NOENTRY; } return mp->read(mp, path, buffer, n, off); } int32_t vfs_create(char *mountpoint, const char *path, int32_t type) { VfsMountPoint *mp = NULL; spinlock_acquire(&VFS_TABLE.spinlock); HSHTB_GET(&VFS_TABLE, mountpoints, mountpoint, label, mp); spinlock_release(&VFS_TABLE.spinlock); if (mp == NULL) { return E_NOENTRY; } return mp->create(mp, path, type); } int32_t vfs_write(char *mountpoint, const char *path, const uint8_t *const buffer, size_t n, size_t off) { VfsMountPoint *mp = NULL; spinlock_acquire(&VFS_TABLE.spinlock); HSHTB_GET(&VFS_TABLE, mountpoints, mountpoint, label, mp); spinlock_release(&VFS_TABLE.spinlock); if (mp == NULL) { return E_NOENTRY; } return mp->write(mp, path, buffer, n, off); } int32_t vfs_remove(char *mountpoint, const char *path) { VfsMountPoint *mp = NULL; spinlock_acquire(&VFS_TABLE.spinlock); HSHTB_GET(&VFS_TABLE, mountpoints, mountpoint, label, mp); spinlock_release(&VFS_TABLE.spinlock); if (mp == NULL) { return E_NOENTRY; } return mp->remove(mp, path); } int32_t tmpvars_init(void) { RamSdInitExtra extra = { .capacity = KVFS_NODES_MAX * KVFS_BUFFER_SIZE }; StoreDev *backingsd = storedev_create(STOREDEV_RAMSD, &extra); if (backingsd == NULL) { return E_NOMEMORY; } return vfs_mount("tmpvars", VFS_KVFS, backingsd); } int32_t base_init(void) { RamSdInitExtra extra = { .capacity = baseimg_getsize(), .preallocbuffer = (uint8_t*)baseimg_getaddr() }; StoreDev *backingsd = storedev_create(STOREDEV_RAMSD, &extra); if (backingsd == NULL) { return E_NOMEMORY; } return vfs_mount("base", VFS_LITTLEFS, backingsd); } void vfs_init(void) { hal_memset(&VFS_TABLE, 0, sizeof(VFS_TABLE)); spinlock_init(&VFS_TABLE.spinlock); tmpvars_init(); base_init(); LOG("vfs", "init done\n"); for (size_t i = 0; i < LEN(VFS_TABLE.mountpoints); i++) { if (!VFS_TABLE.mountpoints[i].taken) continue; VfsMountPoint *vmp = &VFS_TABLE.mountpoints[i]; LOG("vfs", "mount point %s: %s, backing device: %s\n", vmp->label, vfs_strings[vmp->fstype], storedev_strings[vmp->backingsd->sdtype]); if (vmp->check != NULL) { bool ok = vmp->check(); if (ok) { LOG("vfs", "check = %s\n", "OK"); } else { ERR("vfs", "check = %s\n", "FAIL"); } } else { LOG("vfs", "check skipped\n"); } } }