summaryrefslogtreecommitdiff
path: root/na/fs
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-07-10 11:31:46 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-07-10 11:31:46 +0800
commite90b72ec3082588b296956730bd2930cf8d5d671 (patch)
tree36ff6916af9b4176ea5a9662219d11e721f0b691 /na/fs
parent1767d390fbf3d0c65389de46caf0b6d43ef3b6ad (diff)
downloadlume-e90b72ec3082588b296956730bd2930cf8d5d671.tar.gz
lume-e90b72ec3082588b296956730bd2930cf8d5d671.tar.xz
refactor: promote new architecture to repository root
Archive the deprecated implementation under lume-legacy, make the new kernel the default root-level build, and update repository entry points without changing kernel behavior.
Diffstat (limited to 'na/fs')
-rw-r--r--na/fs/chardev.cc43
-rw-r--r--na/fs/dcache.cc287
-rw-r--r--na/fs/devfs.cc137
-rw-r--r--na/fs/fd.cc216
-rw-r--r--na/fs/file_table.cc164
-rw-r--r--na/fs/fs_struct.cc90
-rw-r--r--na/fs/initramfs.cc285
-rw-r--r--na/fs/inode.cc166
-rw-r--r--na/fs/module.mk17
-rw-r--r--na/fs/namei.cc250
-rw-r--r--na/fs/pipe.cc278
-rw-r--r--na/fs/ramfs/file.cc216
-rw-r--r--na/fs/ramfs/inode.cc164
-rw-r--r--na/fs/ramfs/super.cc154
-rw-r--r--na/fs/super.cc95
-rw-r--r--na/fs/vfs_init.cc78
16 files changed, 0 insertions, 2640 deletions
diff --git a/na/fs/chardev.cc b/na/fs/chardev.cc
deleted file mode 100644
index fa96276..0000000
--- a/na/fs/chardev.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* Copyright (C) 2026 Richard Qin */
-
-/*
- * chardev.cc — Character device registry
- *
- * Simple linked list of registered cdevs, searched by dev number.
- */
-
-#include <lume/chardev.h>
-#include <lume/list.h>
-#include <lume/klog.h>
-#include <kernel/sync/spinlock.h>
-
-static list_node g_cdev_list;
-static Spinlock g_cdev_lock;
-
-void cdev_init()
-{
- list_init(&g_cdev_list);
-}
-
-void cdev_register(cdev* dev)
-{
- LockGuard guard(g_cdev_lock);
- list_init(&dev->list);
- list_add_tail(&dev->list, &g_cdev_list);
- printk("[cdev] registered '%s' (%d,%d)\n",
- dev->name, MAJOR(dev->dev), MINOR(dev->dev));
-}
-
-cdev* cdev_find(uint32 dev_nr)
-{
- LockGuard guard(g_cdev_lock);
- list_node* pos;
- for (pos = g_cdev_list.prev; pos != &g_cdev_list; pos = pos->prev) {
- cdev* cd = container_of(pos, cdev, list);
- if (cd->dev == dev_nr) {
- return cd;
- }
- }
- return nullptr;
-}
diff --git a/na/fs/dcache.cc b/na/fs/dcache.cc
deleted file mode 100644
index 94ab287..0000000
--- a/na/fs/dcache.cc
+++ /dev/null
@@ -1,287 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* Copyright (C) 2026 Richard Qin */
-
-/*
- * dcache.cc — Directory entry cache
- *
- * Provides dentry allocation, lookup, instantiation, and d_path.
- */
-
-#include <lume/dcache.h>
-#include <lume/fs.h>
-#include <lume/file.h>
-#include <lume/slab.h>
-#include <lume/errno.h>
-#include <lume/fs_types.h>
-
-/* ================================================================== */
-/* Hash function */
-/* ================================================================== */
-
-uint32 full_name_hash(const char* name, uint32 len)
-{
- uint32 hash = 0;
- for (uint32 i = 0; i < len; i++)
- hash = hash * 31 + static_cast<uint8>(name[i]);
- return hash;
-}
-
-/* ================================================================== */
-/* d_set_type — set DCACHE_*_TYPE bits from inode mode */
-/* ================================================================== */
-
-void d_set_type(dentry* de, uint32 i_mode)
-{
- de->d_flags &= ~DCACHE_ENTRY_TYPE;
-
- if (S_ISDIR(i_mode))
- de->d_flags |= DCACHE_DIRECTORY_TYPE;
- else if (S_ISLNK(i_mode))
- de->d_flags |= DCACHE_SYMLINK_TYPE;
- else if (S_ISREG(i_mode))
- de->d_flags |= DCACHE_REGULAR_TYPE;
- else
- de->d_flags |= DCACHE_SPECIAL_TYPE;
-}
-
-/* ================================================================== */
-/* d_alloc — allocate a dentry under a parent */
-/* ================================================================== */
-
-static void dentry_init(dentry* de, dentry* parent, const qstr* name)
-{
- de->d_flags = DCACHE_MISS_TYPE; /* negative until instantiated */
- de->d_parent = parent ? parent : de;
- de->d_inode = nullptr;
- de->d_op = nullptr;
- de->d_sb = parent ? parent->d_sb : nullptr;
- de->d_time = 0;
- de->d_fsdata = nullptr;
- de->d_lockref.store(1);
-
- list_init(&de->d_lru);
- list_init(&de->d_child);
- list_init(&de->d_children);
- list_init(&de->d_alias);
-
- /* Copy name */
- if (name && name->name && name->len > 0) {
- uint32 len = name->len;
- if (len < DNAME_INLINE_LEN) {
- for (uint32 i = 0; i < len; i++)
- de->d_iname[i] = name->name[i];
- de->d_iname[len] = '\0';
- de->d_name.name = reinterpret_cast<const char*>(de->d_iname);
- } else {
- /* Heap-allocate for long names */
- char* buf = new char[len + 1];
- for (uint32 i = 0; i < len; i++)
- buf[i] = name->name[i];
- buf[len] = '\0';
- de->d_name.name = buf;
- }
- de->d_name.len = len;
- de->d_name.hash = name->hash ? name->hash : full_name_hash(name->name, len);
- } else {
- de->d_iname[0] = '\0';
- de->d_name.name = reinterpret_cast<const char*>(de->d_iname);
- de->d_name.len = 0;
- de->d_name.hash = 0;
- }
-}
-
-dentry* d_alloc(dentry* parent, const qstr* name)
-{
- auto* de = new dentry{};
- if (!de) return nullptr;
-
- dentry_init(de, parent, name);
- de->d_sb = parent->d_sb;
-
- /* Use sb default d_op if set */
- if (parent->d_sb->s_d_op)
- de->d_op = parent->d_sb->s_d_op;
-
- /* Link into parent's children list */
- if (parent) {
- LockGuard guard(parent->d_lock);
- list_add_tail(&de->d_child, &parent->d_children);
- dget(parent); /* child holds ref on parent */
- }
-
- return de;
-}
-
-dentry* d_alloc_anon(super_block* sb)
-{
- auto* de = new dentry{};
- if (!de) return nullptr;
-
- dentry_init(de, nullptr, nullptr);
- de->d_sb = sb;
- de->d_parent = de; /* root: parent is self */
-
- return de;
-}
-
-/* ================================================================== */
-/* d_instantiate — bind an inode to a dentry */
-/* ================================================================== */
-
-void d_instantiate(dentry* de, inode* ip)
-{
- if (!ip) return;
-
- LockGuard guard(de->d_lock);
- de->d_inode = ip;
- d_set_type(de, ip->i_mode);
-
- /* Add to inode's alias list */
- list_add_tail(&de->d_alias, &ip->i_dentry);
-}
-
-/* ================================================================== */
-/* d_make_root — create root dentry for a superblock */
-/* ================================================================== */
-
-dentry* d_make_root(inode* root_inode)
-{
- if (!root_inode) return nullptr;
-
- dentry* de = d_alloc_anon(root_inode->i_sb);
- if (!de) {
- iput(root_inode);
- return nullptr;
- }
-
- d_instantiate(de, root_inode);
- return de;
-}
-
-/* ================================================================== */
-/* d_add — combined d_instantiate + d_rehash */
-/* ================================================================== */
-
-void d_add(dentry* de, inode* ip)
-{
- d_instantiate(de, ip);
- /* d_rehash would add to dcache hash table; simplified for now */
-}
-
-/* ================================================================== */
-/* d_lookup — search children of parent for a name match */
-/* ================================================================== */
-
-dentry* d_lookup(const dentry* parent, const qstr* name)
-{
- LockGuard guard(const_cast<Spinlock&>(parent->d_lock));
-
- list_node* pos;
- list_for_each(pos, &parent->d_children) {
- dentry* child = list_entry(pos, dentry, d_child);
-
- if (child->d_name.len != name->len)
- continue;
-
- /* Compare names */
- const char* a = child->d_name.name;
- const char* b = name->name;
- uint32 len = name->len;
- bool match = true;
- for (uint32 i = 0; i < len; i++) {
- if (a[i] != b[i]) { match = false; break; }
- }
- if (match) {
- dget(child);
- return child;
- }
- }
-
- return nullptr;
-}
-
-/* ================================================================== */
-/* dget / dput — dentry reference counting */
-/* ================================================================== */
-
-dentry* dget(dentry* de)
-{
- if (de)
- de->d_lockref.fetch_add(1);
- return de;
-}
-
-void dput(dentry* de)
-{
- if (!de) return;
-
- int old = de->d_lockref.fetch_sub(1);
- if (old > 1) return;
-
- /* Last reference — could free, but for ramfs we keep dentries alive.
- * A real implementation would check d_op->d_delete and possibly
- * add to LRU for later reclaim. For now, just leak (Phase 1). */
-}
-
-/* ================================================================== */
-/* d_drop / d_delete */
-/* ================================================================== */
-
-void d_drop(dentry* de)
-{
- /* Remove from parent's children list */
- LockGuard guard(de->d_lock);
- if (!list_empty(&de->d_child))
- list_del_init(&de->d_child);
-}
-
-void d_delete(dentry* de)
-{
- d_drop(de);
-}
-
-/* ================================================================== */
-/* d_path — build absolute pathname from a path */
-/* ================================================================== */
-
-char* d_path(const path* p, char* buf, int buflen)
-{
- if (!p || !p->de || buflen <= 0)
- return nullptr;
-
- /* Build path by walking up d_parent chain, writing backwards */
- char* end = buf + buflen - 1;
- *end = '\0';
-
- dentry* de = p->de;
-
- if (d_is_root(de)) {
- if (end <= buf) return nullptr;
- *(--end) = '/';
- return end;
- }
-
- while (!d_is_root(de)) {
- uint32 len = de->d_name.len;
- end -= len;
- if (end <= buf) return nullptr;
-
- const char* name = de->d_name.name;
- for (uint32 i = 0; i < len; i++)
- end[i] = name[i];
-
- *(--end) = '/';
- de = de->d_parent;
- }
-
- return end;
-}
-
-/* ================================================================== */
-/* dcache_init */
-/* ================================================================== */
-
-void dcache_init()
-{
- /* Future: init dcache hash table */
-}
diff --git a/na/fs/devfs.cc b/na/fs/devfs.cc
deleted file mode 100644
index b4b2cf3..0000000
--- a/na/fs/devfs.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* Copyright (C) 2026 Richard Qin */
-
-/*
- * devfs.cc — /dev population and chardev-aware open
- *
- * Creates /dev as a subdirectory under the ramfs root, then
- * populates device nodes. On open(), if the inode is S_IFCHR,
- * we look up the cdev by i_rdev and use its fops.
- */
-
-#include <lume/fs.h>
-#include <lume/dcache.h>
-#include <lume/file.h>
-#include <lume/chardev.h>
-#include <lume/mount.h>
-#include <lume/klog.h>
-#include <lume/errno.h>
-#include <lume/fs_types.h>
-
-/* ================================================================== */
-/* devfs_create_node — create a char device inode under parent */
-/* ================================================================== */
-
-static int devfs_create_node(dentry* parent, const char* name,
- uint32 major, uint32 minor)
-{
- inode* dir_ip = parent->d_inode;
- if (!dir_ip || !dir_ip->i_op || !dir_ip->i_op->mknod) {
- return -EPERM;
- }
-
- qstr q{};
- q.name = name;
- q.len = 0;
- for (const char* s = name; *s; s++) {
- q.len++;
- }
-
- dentry* de = d_alloc(parent, &q);
- if (!de) {
- return -ENOMEM;
- }
-
- int err = dir_ip->i_op->mknod(dir_ip, de, S_IFCHR | 0666,
- MKDEV(major, minor));
- if (err) {
- return err;
- }
-
- return 0;
-}
-
-/* ================================================================== */
-/* devfs_open — chardev-aware open hook */
-/* ================================================================== */
-
-/*
- * Called from sys_openat when the inode is S_IFCHR.
- * Replaces f_op with the chardev's file_operations.
- */
-int devfs_chrdev_open(inode* ip, file* fp)
-{
- if (!S_ISCHR(ip->i_mode)) {
- return 0;
- }
-
- cdev* cd = cdev_find(ip->i_rdev);
- if (!cd || !cd->fops) {
- return -ENXIO; /* No such device */
- }
-
- fp->f_op = cd->fops;
-
- /* Call the device's own open if it has one */
- if (fp->f_op->open) {
- return fp->f_op->open(ip, fp);
- }
-
- return 0;
-}
-
-/* ================================================================== */
-/* devfs_init — create /dev and populate device nodes */
-/* ================================================================== */
-
-void devfs_init()
-{
- if (!g_root_dentry || !g_root_dentry->d_inode) {
- printk(KERN_ERR "[devfs] no root filesystem!\n");
- return;
- }
-
- /* Create /dev directory — or reuse if initramfs already created it.
- * Linux: devtmpfs similarly handles pre-existing directories. */
- inode* root_ip = g_root_dentry->d_inode;
-
- qstr dev_name{};
- dev_name.name = "dev";
- dev_name.len = 3;
- dev_name.hash = full_name_hash("dev", 3);
-
- dentry* dev_de = d_lookup(g_root_dentry, &dev_name);
- if (dev_de) {
- /* /dev already exists (from initramfs) — reuse it */
- printk("[devfs] reusing existing /dev directory\n");
- } else {
- /* Create /dev from scratch */
- if (!root_ip->i_op || !root_ip->i_op->mkdir) {
- printk(KERN_ERR "[devfs] root has no mkdir!\n");
- return;
- }
-
- dev_de = d_alloc(g_root_dentry, &dev_name);
- if (!dev_de) {
- printk(KERN_ERR "[devfs] failed to alloc /dev dentry\n");
- return;
- }
-
- int err = root_ip->i_op->mkdir(root_ip, dev_de, S_IFDIR | 0755);
- if (err) {
- printk(KERN_ERR "[devfs] mkdir /dev failed: %d\n", err);
- return;
- }
- }
-
- /* Populate: /dev/console (5,1) */
- devfs_create_node(dev_de, "console", 5, 1);
-
- /* Populate: /dev/null (1,3) */
- devfs_create_node(dev_de, "null", 1, 3);
-
- /* Populate: /dev/zero (1,5) */
- devfs_create_node(dev_de, "zero", 1, 5);
-
- printk("[devfs] /dev populated (console, null, zero)\n");
-}
diff --git a/na/fs/fd.cc b/na/fs/fd.cc
deleted file mode 100644
index 5fc8ab0..0000000
--- a/na/fs/fd.cc
+++ /dev/null
@@ -1,216 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* Copyright (C) 2026 Richard Qin */
-
-/*
- * fd.cc — File descriptor table management
- */
-
-#include <lume/fdtable.h>
-#include <lume/file.h>
-#include <lume/slab.h>
-#include <lume/errno.h>
-
-/* ================================================================== */
-/* Bitmap helpers */
-/* ================================================================== */
-
-static inline bool bit_test(const uint64* bmap, int bit) {
- return (bmap[bit / 64] >> (bit % 64)) & 1;
-}
-static inline void bit_set(uint64* bmap, int bit) {
- bmap[bit / 64] |= (1ULL << (bit % 64));
-}
-static inline void bit_clear(uint64* bmap, int bit) {
- bmap[bit / 64] &= ~(1ULL << (bit % 64));
-}
-
-/* ================================================================== */
-/* alloc_files_struct */
-/* ================================================================== */
-
-files_struct* alloc_files_struct()
-{
- auto* files = new files_struct{};
- if (!files) return nullptr;
-
- files->count.store(1);
- files->next_fd = 0;
- files->max_fds = NR_OPEN_DEFAULT;
-
- for (int i = 0; i < NR_OPEN_DEFAULT; i++)
- files->fd_array[i] = nullptr;
-
- int bmap_words = (NR_OPEN_DEFAULT + 63) / 64;
- for (int i = 0; i < bmap_words; i++) {
- files->close_on_exec_init[i] = 0;
- files->open_fds_init[i] = 0;
- }
-
- return files;
-}
-
-/* ================================================================== */
-/* put_files_struct — drop reference, free on last */
-/* ================================================================== */
-
-void put_files_struct(files_struct* files)
-{
- if (!files) return;
-
- int old = files->count.fetch_sub(1);
- if (old > 1) return;
-
- /* Close all open fds */
- for (int i = 0; i < files->max_fds; i++) {
- if (files->fd_array[i]) {
- fput(files->fd_array[i]);
- files->fd_array[i] = nullptr;
- }
- }
-
- delete files;
-}
-
-/* ================================================================== */
-/* dup_fd — duplicate entire fd table (for fork) */
-/* ================================================================== */
-
-files_struct* dup_fd(files_struct* old_files)
-{
- auto* new_files = alloc_files_struct();
- if (!new_files) return nullptr;
-
- LockGuard guard(old_files->file_lock);
-
- for (int i = 0; i < old_files->max_fds; i++) {
- file* fp = old_files->fd_array[i];
- if (fp) {
- get_file(fp);
- new_files->fd_array[i] = fp;
- }
- }
-
- /* Copy bitmaps */
- int bmap_words = (NR_OPEN_DEFAULT + 63) / 64;
- for (int i = 0; i < bmap_words; i++) {
- new_files->open_fds_init[i] = old_files->open_fds_init[i];
- new_files->close_on_exec_init[i] = old_files->close_on_exec_init[i];
- }
-
- new_files->next_fd = old_files->next_fd;
-
- return new_files;
-}
-
-/* ================================================================== */
-/* alloc_fd — find lowest free fd >= start */
-/* ================================================================== */
-
-int alloc_fd(files_struct* files, unsigned int start)
-{
- LockGuard guard(files->file_lock);
-
- for (int fd = static_cast<int>(start); fd < files->max_fds; fd++) {
- if (!bit_test(files->open_fds_init, fd)) {
- bit_set(files->open_fds_init, fd);
- files->fd_array[fd] = nullptr; /* placeholder, fd_install sets real file */
- if (fd >= files->next_fd)
- files->next_fd = fd + 1;
- return fd;
- }
- }
-
- return -EMFILE;
-}
-
-/* ================================================================== */
-/* fd_install — place a file* at a given fd */
-/* ================================================================== */
-
-void fd_install(files_struct* files, int fd, file* fp)
-{
- LockGuard guard(files->file_lock);
- files->fd_array[fd] = fp;
-}
-
-/* ================================================================== */
-/* fcheck — look up file by fd (no refcount bump) */
-/* ================================================================== */
-
-file* fcheck(files_struct* files, int fd)
-{
- if (fd < 0 || fd >= files->max_fds) return nullptr;
- return files->fd_array[fd];
-}
-
-/* ================================================================== */
-/* close_fd */
-/* ================================================================== */
-
-int close_fd(files_struct* files, int fd)
-{
- file* fp;
- {
- LockGuard guard(files->file_lock);
- if (fd < 0 || fd >= files->max_fds) return -EBADF;
-
- fp = files->fd_array[fd];
- if (!fp) return -EBADF;
-
- files->fd_array[fd] = nullptr;
- bit_clear(files->open_fds_init, fd);
- bit_clear(files->close_on_exec_init, fd);
- }
-
- fput(fp);
- return 0;
-}
-
-/* ================================================================== */
-/* do_dup2 — duplicate oldfd to newfd */
-/* ================================================================== */
-
-int do_dup2(files_struct* files, int oldfd, int newfd, int flags)
-{
- if (oldfd == newfd) return -EINVAL;
-
- file* existing = nullptr;
- {
- LockGuard guard(files->file_lock);
-
- if (oldfd < 0 || oldfd >= files->max_fds) return -EBADF;
- if (newfd < 0 || newfd >= files->max_fds) return -EBADF;
-
- file* old_fp = files->fd_array[oldfd];
- if (!old_fp) return -EBADF;
-
- existing = files->fd_array[newfd];
-
- get_file(old_fp);
- files->fd_array[newfd] = old_fp;
- bit_set(files->open_fds_init, newfd);
-
- if (flags & O_CLOEXEC)
- bit_set(files->close_on_exec_init, newfd);
- else
- bit_clear(files->close_on_exec_init, newfd);
- }
-
- if (existing)
- fput(existing);
-
- return newfd;
-}
-
-/* ================================================================== */
-/* do_close_on_exec — close all fds with CLOEXEC set */
-/* ================================================================== */
-
-void do_close_on_exec(files_struct* files)
-{
- for (int fd = 0; fd < files->max_fds; fd++) {
- if (bit_test(files->close_on_exec_init, fd)) {
- close_fd(files, fd);
- }
- }
-}
diff --git a/na/fs/file_table.cc b/na/fs/file_table.cc
deleted file mode 100644
index 06095c1..0000000
--- a/na/fs/file_table.cc
+++ /dev/null
@@ -1,164 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* Copyright (C) 2026 Richard Qin */
-
-/*
- * file_table.cc — Open file allocation and reference counting
- */
-
-#include <lume/file.h>
-#include <lume/fs.h>
-#include <lume/dcache.h>
-#include <lume/slab.h>
-#include <lume/errno.h>
-
-/* ================================================================== */
-/* alloc_empty_file */
-/* ================================================================== */
-
-file* alloc_empty_file(int flags)
-{
- auto* fp = new file{};
- if (!fp) return nullptr;
-
- fp->f_count.store(1);
- fp->f_flags = flags;
- fp->f_mode = 0;
- fp->f_op = nullptr;
- fp->f_mapping = nullptr;
- fp->f_inode = nullptr;
- fp->f_pos = 0;
- fp->private_data = nullptr;
- fp->f_path.mnt = nullptr;
- fp->f_path.de = nullptr;
-
- /* Derive f_mode from O_* flags */
- int acc = flags & O_ACCMODE;
- if (acc == O_RDONLY)
- fp->f_mode = FMODE_READ | FMODE_CAN_READ;
- else if (acc == O_WRONLY)
- fp->f_mode = FMODE_WRITE | FMODE_CAN_WRITE;
- else if (acc == O_RDWR)
- fp->f_mode = FMODE_READ | FMODE_WRITE | FMODE_CAN_READ | FMODE_CAN_WRITE;
-
- fp->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
-
- return fp;
-}
-
-/* ================================================================== */
-/* get_file / fput */
-/* ================================================================== */
-
-file* get_file(file* f)
-{
- f->f_count.fetch_add(1);
- return f;
-}
-
-void fput(file* fp)
-{
- if (!fp) return;
-
- int old = fp->f_count.fetch_sub(1);
- if (old > 1) return;
-
- /* Last reference — release */
- if (fp->f_op && fp->f_op->release)
- fp->f_op->release(fp->f_inode, fp);
-
- if (fp->f_path.de)
- dput(fp->f_path.de);
-
- /* Future: mntput(fp->f_path.mnt) */
-
- delete fp;
-}
-
-/* ================================================================== */
-/* vfs_read / vfs_write / vfs_llseek / vfs_fstat */
-/* ================================================================== */
-
-int64 vfs_read(file* fp, char* buf, uint64 count, int64* pos)
-{
- if (!(fp->f_mode & FMODE_CAN_READ))
- return -EBADF;
- if (!fp->f_op || !fp->f_op->read)
- return -EINVAL;
-
- return fp->f_op->read(fp, buf, count, pos);
-}
-
-int64 vfs_write(file* fp, const char* buf, uint64 count, int64* pos)
-{
- if (!(fp->f_mode & FMODE_CAN_WRITE))
- return -EBADF;
- if (!fp->f_op || !fp->f_op->write)
- return -EINVAL;
-
- return fp->f_op->write(fp, buf, count, pos);
-}
-
-int64 vfs_llseek(file* fp, int64 offset, int whence)
-{
- if (fp->f_op && fp->f_op->llseek)
- return fp->f_op->llseek(fp, offset, whence);
- return generic_file_llseek(fp, offset, whence);
-}
-
-int64 generic_file_llseek(file* fp, int64 offset, int whence)
-{
- int64 new_pos;
- switch (whence) {
- case SEEK_SET:
- new_pos = offset;
- break;
- case SEEK_CUR:
- new_pos = fp->f_pos + offset;
- break;
- case SEEK_END:
- new_pos = fp->f_inode->i_size + offset;
- break;
- default:
- return -EINVAL;
- }
-
- if (new_pos < 0) return -EINVAL;
- fp->f_pos = new_pos;
- return new_pos;
-}
-
-int vfs_fstat(file* fp, kstat* stat)
-{
- inode* ip = file_inode(fp);
- if (!ip) return -EBADF;
-
- if (ip->i_op && ip->i_op->getattr) {
- return ip->i_op->getattr(&fp->f_path, stat, 0, 0);
- }
-
- generic_fillattr(ip, stat);
- return 0;
-}
-
-/* ================================================================== */
-/* path_get / path_put (simplified) */
-/* ================================================================== */
-
-void path_get(const path* p)
-{
- if (p->de) dget(p->de);
- /* Future: mntget(p->mnt) */
-}
-
-void path_put(const path* p)
-{
- if (p->de) dput(p->de);
- /* Future: mntput(p->mnt) */
-}
-
-/* ================================================================== */
-/* mntget / mntput (stubs for Phase 1) */
-/* ================================================================== */
-
-vfsmount* mntget(vfsmount* mnt) { return mnt; }
-void mntput(vfsmount*) {}
diff --git a/na/fs/fs_struct.cc b/na/fs/fs_struct.cc
deleted file mode 100644
index 090819f..0000000
--- a/na/fs/fs_struct.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* Copyright (C) 2026 Richard Qin */
-
-/*
- * fs_struct.cc — Per-task filesystem context (cwd, root)
- */
-
-#include <lume/fs_struct.h>
-#include <lume/slab.h>
-
-/* ================================================================== */
-/* alloc_fs_struct */
-/* ================================================================== */
-
-fs_struct* alloc_fs_struct()
-{
- auto* fs = new fs_struct{};
- if (!fs) return nullptr;
-
- fs->count.store(1);
- fs->umask = 022;
- fs->root = {nullptr, nullptr};
- fs->pwd = {nullptr, nullptr};
-
- return fs;
-}
-
-/* ================================================================== */
-/* put_fs_struct */
-/* ================================================================== */
-
-void put_fs_struct(fs_struct* fs)
-{
- if (!fs) return;
-
- int old = fs->count.fetch_sub(1);
- if (old > 1) return;
-
- path_put(&fs->root);
- path_put(&fs->pwd);
- delete fs;
-}
-
-/* ================================================================== */
-/* copy_fs_struct — for fork without CLONE_FS */
-/* ================================================================== */
-
-fs_struct* copy_fs_struct(const fs_struct* old_fs)
-{
- auto* fs = alloc_fs_struct();
- if (!fs) return nullptr;
-
- fs->umask = old_fs->umask;
-
- fs->root = old_fs->root;
- path_get(&fs->root);
-
- fs->pwd = old_fs->pwd;
- path_get(&fs->pwd);
-
- return fs;
-}
-
-/* ================================================================== */
-/* set_fs_root / set_fs_pwd */
-/* ================================================================== */
-
-void set_fs_root(fs_struct* fs, const path* p)
-{
- path old_root;
- {
- LockGuard guard(fs->lock);
- old_root = fs->root;
- fs->root = *p;
- path_get(p);
- }
- path_put(&old_root);
-}
-
-void set_fs_pwd(fs_struct* fs, const path* p)
-{
- path old_pwd;
- {
- LockGuard guard(fs->lock);
- old_pwd = fs->pwd;
- fs->pwd = *p;
- path_get(p);
- }
- path_put(&old_pwd);
-}
diff --git a/na/fs/initramfs.cc b/na/fs/initramfs.cc
deleted file mode 100644
index ba10a3e..0000000
--- a/na/fs/initramfs.cc
+++ /dev/null
@@ -1,285 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* Copyright (C) 2026 Richard Qin */
-
-/*
- * initramfs.cc — Unpack embedded CPIO archive into ramfs
- *
- * The build system embeds a newc-format CPIO archive into the kernel
- * ELF as the section .init.ramfs. The linker script exports
- * __initramfs_start / __initramfs_end symbols.
- *
- * At boot, populate_rootfs() walks the CPIO entries and creates
- * directories and files in the already-mounted ramfs root.
- *
- * Reference: Linux init/initramfs.c
- *
- * CPIO "newc" header format (110 bytes, ASCII hex fields):
- * magic[6] "070701"
- * ino[8] mode[8] uid[8] gid[8] nlink[8] mtime[8]
- * filesize[8] devmajor[8] devminor[8] rdevmajor[8] rdevminor[8]
- * namesize[8] check[8]
- * filename (namesize bytes, NUL terminated, padded to 4-byte boundary)
- * file data (filesize bytes, padded to 4-byte boundary)
- */
-
-#include <lume/klog.h>
-#include <lume/fs.h>
-#include <lume/dcache.h>
-#include <lume/file.h>
-#include <lume/errno.h>
-#include <lume/fs_types.h>
-
-/* Linker-provided symbols for the embedded CPIO archive */
-extern "C" const char __initramfs_start[];
-extern "C" const char __initramfs_end[];
-
-/* ramfs inode creation (from fs/ramfs/inode.cc) */
-extern inode* ramfs_get_inode(super_block* sb, const inode* dir,
- uint32 mode, uint32 rdev);
-
-/* Global root dentry (from fs/vfs_init.cc) */
-extern dentry* g_root_dentry;
-
-/* ================================================================== */
-/* CPIO newc header parsing */
-/* ================================================================== */
-
-struct cpio_header {
- char magic[6];
- char ino[8];
- char mode[8];
- char uid[8];
- char gid[8];
- char nlink[8];
- char mtime[8];
- char filesize[8];
- char devmajor[8];
- char devminor[8];
- char rdevmajor[8];
- char rdevminor[8];
- char namesize[8];
- char check[8];
-};
-
-static constexpr int kCpioHeaderSize = 110;
-
-static uint32 parse_hex8(const char* s)
-{
- uint32 val = 0;
- for (int i = 0; i < 8; i++) {
- char c = s[i];
- uint32 nibble;
- if (c >= '0' && c <= '9') nibble = c - '0';
- else if (c >= 'a' && c <= 'f') nibble = c - 'a' + 10;
- else if (c >= 'A' && c <= 'F') nibble = c - 'A' + 10;
- else return val;
- val = (val << 4) | nibble;
- }
- return val;
-}
-
-static inline uint32 align4(uint32 v)
-{
- return (v + 3) & ~3U;
-}
-
-/* ================================================================== */
-/* Path resolution helpers */
-/* ================================================================== */
-
-static dentry* cpio_mkdir_p(dentry* root, const char* path,
- const char** out_name)
-{
- dentry* cur = root;
-
- while (*path == '/') path++;
-
- while (true) {
- const char* slash = path;
- while (*slash && *slash != '/') slash++;
-
- if (*slash == '\0') {
- *out_name = path;
- return cur;
- }
-
- uint32 len = static_cast<uint32>(slash - path);
-
- qstr name;
- name.name = path;
- name.len = len;
- name.hash = full_name_hash(path, len);
-
- dentry* child = d_lookup(cur, &name);
- if (!child) {
- child = d_alloc(cur, &name);
- if (!child) return nullptr;
-
- inode* ip = ramfs_get_inode(cur->d_inode->i_sb, cur->d_inode,
- S_IFDIR | 0755, 0);
- if (!ip) return nullptr;
-
- d_instantiate(child, ip);
- dget(child);
- inc_nlink(cur->d_inode);
- }
-
- cur = child;
- path = slash + 1;
- while (*path == '/') path++;
- }
-}
-
-/* ================================================================== */
-/* populate_rootfs — the main entry point */
-/* ================================================================== */
-
-void populate_rootfs()
-{
- const char* p = __initramfs_start;
- const char* end = __initramfs_end;
- uint64 archive_size = static_cast<uint64>(end - p);
-
- if (archive_size == 0) {
- printk("[initramfs] no embedded archive found\n");
- return;
- }
-
- printk("[initramfs] unpacking %llu bytes...\n", archive_size);
-
- int file_count = 0;
- int dir_count = 0;
-
- while (p + kCpioHeaderSize <= end) {
- auto* hdr = reinterpret_cast<const cpio_header*>(p);
-
- /* Verify magic */
- if (hdr->magic[0] != '0' || hdr->magic[1] != '7' ||
- hdr->magic[2] != '0' || hdr->magic[3] != '7' ||
- hdr->magic[4] != '0' || hdr->magic[5] != '1') {
- printk("[initramfs] bad cpio magic at offset %llu\n",
- static_cast<uint64>(p - __initramfs_start));
- break;
- }
-
- uint32 mode = parse_hex8(hdr->mode);
- uint32 filesize = parse_hex8(hdr->filesize);
- uint32 namesize = parse_hex8(hdr->namesize);
-
- const char* name = p + kCpioHeaderSize;
- uint32 name_padded = align4(kCpioHeaderSize + namesize);
- const char* data = p + name_padded;
- uint32 data_padded = align4(filesize);
-
- const char* next = p + name_padded + data_padded;
-
- /* Check for TRAILER!!! end-of-archive marker */
- if (namesize == 11 && name[0] == 'T' && name[1] == 'R' &&
- name[2] == 'A' && name[3] == 'I' && name[4] == 'L' &&
- name[5] == 'E' && name[6] == 'R' && name[7] == '!' &&
- name[8] == '!' && name[9] == '!') {
- break;
- }
-
- /* Skip "." entry */
- if (namesize == 2 && name[0] == '.' && name[1] == '\0') {
- p = next;
- continue;
- }
-
- /* Resolve parent directory, creating intermediate dirs */
- const char* basename = nullptr;
- dentry* parent = cpio_mkdir_p(g_root_dentry, name, &basename);
- if (!parent || !basename || basename[0] == '\0') {
- p = next;
- continue;
- }
-
- /* Build qstr for the final component */
- uint32 blen = 0;
- while (basename[blen] && basename[blen] != '/') blen++;
-
- qstr bname;
- bname.name = basename;
- bname.len = blen;
- bname.hash = full_name_hash(basename, blen);
-
- if (S_ISDIR(mode)) {
- dentry* existing = d_lookup(parent, &bname);
- if (!existing) {
- dentry* de = d_alloc(parent, &bname);
- if (de) {
- inode* ip = ramfs_get_inode(parent->d_inode->i_sb,
- parent->d_inode,
- S_IFDIR | (mode & 0777), 0);
- if (ip) {
- d_instantiate(de, ip);
- dget(de);
- inc_nlink(parent->d_inode);
- dir_count++;
- }
- }
- }
- } else if (S_ISREG(mode)) {
- dentry* de = d_alloc(parent, &bname);
- if (de) {
- inode* ip = ramfs_get_inode(parent->d_inode->i_sb,
- parent->d_inode,
- S_IFREG | (mode & 0777), 0);
- if (ip) {
- d_instantiate(de, ip);
- dget(de);
-
- /* Write file content via ramfs write path */
- if (filesize > 0 && ip->i_fop && ip->i_fop->write) {
- file tmp_fp = {};
- tmp_fp.f_inode = ip;
- tmp_fp.f_path.de = de;
- tmp_fp.f_pos = 0;
- tmp_fp.f_flags = O_WRONLY;
- tmp_fp.f_count.store(1);
-
- int64 pos = 0;
- ip->i_fop->write(&tmp_fp, data,
- filesize, &pos);
- }
-
- file_count++;
- printk("[initramfs] %s (%u bytes, mode %03o)\n",
- name, filesize, mode & 0777);
- }
- }
- } else if (S_ISLNK(mode)) {
- /* Symlink: file data is the target path (not NUL-terminated).
- * Linux: init/initramfs.c do_symlink() */
- dentry* de = d_alloc(parent, &bname);
- if (de) {
- inode* ip = ramfs_get_inode(parent->d_inode->i_sb,
- parent->d_inode,
- S_IFLNK | 0777, 0);
- if (ip) {
- /* Store symlink target in inode.
- * Allocate a kernel buffer and copy the target. */
- char* target = new char[filesize + 1];
- if (target) {
- for (uint32 i = 0; i < filesize; i++)
- target[i] = data[i];
- target[filesize] = '\0';
- ip->i_link = target;
- }
-
- d_instantiate(de, ip);
- dget(de);
- file_count++;
- printk("[initramfs] %s -> %s (symlink)\n",
- name, target ? target : "?");
- }
- }
- }
-
- p = next;
- }
-
- printk("[initramfs] done: %d files, %d dirs\n",
- file_count, dir_count);
-}
diff --git a/na/fs/inode.cc b/na/fs/inode.cc
deleted file mode 100644
index 1d3d006..0000000
--- a/na/fs/inode.cc
+++ /dev/null
@@ -1,166 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* Copyright (C) 2026 Richard Qin */
-
-/*
- * inode.cc — Inode allocation, lifecycle, and generic helpers
- */
-
-#include <lume/fs.h>
-#include <lume/dcache.h>
-#include <lume/slab.h>
-#include <lume/errno.h>
-
-namespace {
-lume::atomic<uint64> g_next_ino{1};
-} // namespace
-
-/* ================================================================== */
-/* new_inode — allocate a fresh inode on a superblock */
-/* ================================================================== */
-
-inode* new_inode(super_block* sb)
-{
- inode* ip = nullptr;
-
- if (sb->s_op && sb->s_op->alloc_inode)
- ip = sb->s_op->alloc_inode(sb);
- else
- ip = new inode{};
-
- if (!ip) return nullptr;
-
- /* Zero-init key fields */
- ip->i_sb = sb;
- ip->i_ino = g_next_ino.fetch_add(1);
- ip->i_mode = 0;
- ip->i_flags = 0;
- ip->i_uid = 0;
- ip->i_gid = 0;
- ip->i_nlink = 1;
- ip->i_rdev = 0;
- ip->i_size = 0;
- ip->i_blocks = 0;
- ip->i_bytes = 0;
- ip->i_blkbits = sb->s_blocksize_bits;
- ip->i_generation = 0;
- ip->i_state = I_NEW;
- ip->i_count.store(1);
- ip->i_writecount.store(0);
-
- ip->i_atime_sec = ip->i_mtime_sec = ip->i_ctime_sec = 0;
- ip->i_atime_nsec = ip->i_mtime_nsec = ip->i_ctime_nsec = 0;
-
- ip->i_op = nullptr;
- ip->i_fop = nullptr;
- ip->i_mapping = &ip->i_data;
- ip->i_private = nullptr;
- ip->i_pipe = nullptr;
-
- /* Init embedded address_space */
- ip->i_data.host = ip;
- ip->i_data.a_ops = nullptr;
- ip->i_data.nrpages = 0;
- ip->i_data.flags = 0;
-
- /* Init lists */
- list_init(&ip->i_sb_list);
- list_init(&ip->i_dentry);
-
- /* Add to superblock's inode list */
- {
- LockGuard guard(sb->s_inode_list_lock);
- list_add_tail(&ip->i_sb_list, &sb->s_inodes);
- }
-
- return ip;
-}
-
-/* ================================================================== */
-/* ihold / iput — reference counting */
-/* ================================================================== */
-
-void ihold(inode* ip)
-{
- ip->i_count.fetch_add(1);
-}
-
-void iput(inode* ip)
-{
- if (!ip) return;
-
- int old = ip->i_count.fetch_sub(1);
- if (old > 1) return;
-
- /* Last reference dropped — evict */
- if (ip->i_sb->s_op && ip->i_sb->s_op->evict_inode)
- ip->i_sb->s_op->evict_inode(ip);
-
- /* Remove from sb list */
- {
- LockGuard guard(ip->i_sb->s_inode_list_lock);
- list_del(&ip->i_sb_list);
- }
-
- if (ip->i_sb->s_op && ip->i_sb->s_op->destroy_inode)
- ip->i_sb->s_op->destroy_inode(ip);
- else
- delete ip;
-}
-
-/* ================================================================== */
-/* nlink helpers */
-/* ================================================================== */
-
-void set_nlink(inode* ip, uint32 nlink) { ip->i_nlink = nlink; }
-void inc_nlink(inode* ip) { ip->i_nlink++; }
-void drop_nlink(inode* ip) { ip->i_nlink--; }
-void clear_nlink(inode* ip) { ip->i_nlink = 0; }
-
-/* ================================================================== */
-/* inode_init_owner */
-/* ================================================================== */
-
-void inode_init_owner(inode* ip, const inode* dir, uint32 mode)
-{
- ip->i_uid = 0; /* Phase 1: always root */
- ip->i_gid = 0;
- ip->i_mode = mode;
-}
-
-/* ================================================================== */
-/* generic_fillattr — fill kstat from inode (used by getattr) */
-/* ================================================================== */
-
-void generic_fillattr(inode* ip, kstat* stat)
-{
- stat->st_dev = ip->i_sb->s_dev;
- stat->st_ino = ip->i_ino;
- stat->st_mode = ip->i_mode;
- stat->st_nlink = ip->i_nlink;
- stat->st_uid = ip->i_uid;
- stat->st_gid = ip->i_gid;
- stat->st_rdev = ip->i_rdev;
- stat->__pad = 0;
- stat->st_size = ip->i_size;
- stat->st_blksize = 1 << ip->i_blkbits;
- stat->__pad2 = 0;
- stat->st_blocks = ip->i_blocks;
- stat->st_atime_sec = ip->i_atime_sec;
- stat->st_atime_nsec = ip->i_atime_nsec;
- stat->st_mtime_sec = ip->i_mtime_sec;
- stat->st_mtime_nsec = ip->i_mtime_nsec;
- stat->st_ctime_sec = ip->i_ctime_sec;
- stat->st_ctime_nsec = ip->i_ctime_nsec;
- stat->__unused[0] = 0;
- stat->__unused[1] = 0;
-}
-
-/* ================================================================== */
-/* mark_inode_dirty (stub) */
-/* ================================================================== */
-
-void mark_inode_dirty(inode* ip)
-{
- ip->i_state |= I_DIRTY_SYNC;
- /* Phase 1: no writeback, ramfs is memory-only */
-}
diff --git a/na/fs/module.mk b/na/fs/module.mk
deleted file mode 100644
index f1be157..0000000
--- a/na/fs/module.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-# fs/module.mk — VFS subsystem build rules
-
-SRCS_CC += fs/super.cc
-SRCS_CC += fs/inode.cc
-SRCS_CC += fs/dcache.cc
-SRCS_CC += fs/file_table.cc
-SRCS_CC += fs/fd.cc
-SRCS_CC += fs/fs_struct.cc
-SRCS_CC += fs/namei.cc
-SRCS_CC += fs/ramfs/inode.cc
-SRCS_CC += fs/ramfs/file.cc
-SRCS_CC += fs/ramfs/super.cc
-SRCS_CC += fs/vfs_init.cc
-SRCS_CC += fs/chardev.cc
-SRCS_CC += fs/devfs.cc
-SRCS_CC += fs/pipe.cc
-SRCS_CC += fs/initramfs.cc
diff --git a/na/fs/namei.cc b/na/fs/namei.cc
deleted file mode 100644
index 9124ea9..0000000
--- a/na/fs/namei.cc
+++ /dev/null
@@ -1,250 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* Copyright (C) 2026 Richard Qin */
-
-/*
- * namei.cc — Pathname resolution (path lookup)
- *
- * Simplified Phase 1: no symlink, no RCU, no mount traversal.
- */
-
-#include <lume/namei.h>
-#include <lume/dcache.h>
-#include <lume/fs.h>
-#include <lume/file.h>
-#include <lume/fdtable.h>
-#include <lume/fs_struct.h>
-#include <lume/mount.h>
-#include <lume/task.h>
-#include <lume/errno.h>
-#include <lume/fs_types.h>
-
-/* ================================================================== */
-/* Helpers */
-/* ================================================================== */
-
-static const char* next_component(const char* path, qstr* result)
-{
- while (*path == '/') path++;
- if (*path == '\0') return nullptr;
-
- const char* start = path;
- while (*path != '\0' && *path != '/') path++;
-
- uint32 len = static_cast<uint32>(path - start);
- result->name = start;
- result->len = len;
- result->hash = full_name_hash(start, len);
-
- return path;
-}
-
-static bool is_dot(const qstr* name) {
- return name->len == 1 && name->name[0] == '.';
-}
-static bool is_dotdot(const qstr* name) {
- return name->len == 2 && name->name[0] == '.' && name->name[1] == '.';
-}
-
-/* ================================================================== */
-/* walk_component */
-/* ================================================================== */
-
-static dentry* walk_component(dentry* parent, const qstr* name)
-{
- if (!parent->d_inode || !S_ISDIR(parent->d_inode->i_mode))
- return reinterpret_cast<dentry*>(-ENOTDIR);
-
- if (is_dot(name))
- return dget(parent);
-
- if (is_dotdot(name))
- return dget(parent->d_parent);
-
- /* Try dcache */
- dentry* child = d_lookup(parent, name);
- if (child)
- return child;
-
- /* Cache miss — call filesystem lookup */
- inode* dir = parent->d_inode;
- if (!dir->i_op || !dir->i_op->lookup)
- return reinterpret_cast<dentry*>(-ENOENT);
-
- child = d_alloc(parent, name);
- if (!child)
- return reinterpret_cast<dentry*>(-ENOMEM);
-
- dentry* result = dir->i_op->lookup(dir, child, 0);
- if (result) {
- dput(child);
- return result;
- }
-
- /* If lookup didn't set an inode, this is a negative dentry
- * (file doesn't exist). Remove from dcache and return error. */
- if (!child->d_inode) {
- d_drop(child);
- dput(child);
- return reinterpret_cast<dentry*>(-ENOENT);
- }
-
- return child;
-}
-
-/* ================================================================== */
-/* filename_lookup */
-/* ================================================================== */
-
-int filename_lookup(int dfd, const char* name, unsigned int flags, path* result)
-{
- if (!name || !result)
- return -EINVAL;
-
- TaskControlBlock* task = current_task();
- dentry* start;
-
- /* Determine starting dentry */
- if (name[0] == '/') {
- start = task->fs->root.de;
- if (!start) start = g_root_dentry;
- name++;
- } else if (dfd == AT_FDCWD) {
- start = task->fs->pwd.de;
- if (!start) start = g_root_dentry;
- } else {
- file* dir_fp = fcheck(task->files, dfd);
- if (!dir_fp) return -EBADF;
- start = dir_fp->f_path.de;
- if (!start || !start->d_inode || !S_ISDIR(start->d_inode->i_mode))
- return -ENOTDIR;
- }
-
- dentry* current_de = dget(start);
- const char* p = name;
-
- while (p && *p) {
- qstr component;
- const char* next = next_component(p, &component);
- if (!next && component.len == 0)
- break;
-
- const char* after = next;
- while (after && *after == '/') after++;
- bool is_last = (!after || *after == '\0');
-
- if (is_last && (flags & LOOKUP_PARENT)) {
- result->de = current_de;
- result->mnt = task->fs->root.mnt;
- return 0;
- }
-
- dentry* child = walk_component(current_de, &component);
-
- int64 err = reinterpret_cast<int64>(child);
- if (err < 0 && err >= -4095) {
- dput(current_de);
- return static_cast<int>(err);
- }
-
- /* ---- Symlink following (Linux: step_into → pick_link) ----
- * If the resolved component is a symlink, follow it.
- * Linux limits this to MAXSYMLINKS (40); we use 8. */
- constexpr int kMaxSymlinks = 8;
- int symlink_depth = 0;
- while (child->d_inode && S_ISLNK(child->d_inode->i_mode) &&
- child->d_inode->i_link && symlink_depth < kMaxSymlinks) {
- symlink_depth++;
- const char* target = child->d_inode->i_link;
- dput(child);
-
- /* Absolute symlink: restart from root.
- * Relative symlink: resolve from current parent. */
- dentry* link_start;
- if (target[0] == '/') {
- link_start = dget(task->fs->root.de ? task->fs->root.de : g_root_dentry);
- target++;
- } else {
- link_start = dget(current_de);
- }
-
- /* Walk each component of the symlink target */
- dentry* link_cur = link_start;
- const char* lp = target;
- qstr lcomp;
- while (lp && *lp) {
- const char* lnext = next_component(lp, &lcomp);
- if (!lnext && lcomp.len == 0) break;
-
- dentry* lchild = walk_component(link_cur, &lcomp);
- int64 lerr = reinterpret_cast<int64>(lchild);
- if (lerr < 0 && lerr >= -4095) {
- dput(link_cur);
- dput(current_de);
- return static_cast<int>(lerr);
- }
-
- dput(link_cur);
- link_cur = lchild;
- lp = lnext;
- }
-
- child = link_cur;
- }
-
- if (symlink_depth >= kMaxSymlinks) {
- dput(child);
- dput(current_de);
- return -ELOOP;
- }
-
- if (!is_last && child->d_inode && !S_ISDIR(child->d_inode->i_mode)) {
- dput(child);
- dput(current_de);
- return -ENOTDIR;
- }
-
- if (!is_last && !child->d_inode) {
- dput(child);
- dput(current_de);
- return -ENOENT;
- }
-
- dput(current_de);
- current_de = child;
- p = next;
- }
-
- if ((flags & LOOKUP_DIRECTORY) && current_de->d_inode &&
- !S_ISDIR(current_de->d_inode->i_mode)) {
- dput(current_de);
- return -ENOTDIR;
- }
-
- /* Negative dentry: the path was walked, but the final component
- * does not exist (d_inode == NULL). Return -ENOENT. */
- if (!current_de->d_inode) {
- dput(current_de);
- return -ENOENT;
- }
-
- result->de = current_de;
- result->mnt = task->fs->root.mnt;
- return 0;
-}
-
-int kern_path(const char* name, unsigned int flags, path* result)
-{
- return filename_lookup(AT_FDCWD, name, flags, result);
-}
-
-dentry* lookup_one_len(const char* name, dentry* parent, int len)
-{
- qstr q;
- q.name = name;
- q.len = static_cast<uint32>(len);
- q.hash = full_name_hash(name, q.len);
-
- return walk_component(parent, &q);
-}
-
-void namei_init() {}
diff --git a/na/fs/pipe.cc b/na/fs/pipe.cc
deleted file mode 100644
index f7708f5..0000000
--- a/na/fs/pipe.cc
+++ /dev/null
@@ -1,278 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* Copyright (C) 2026 Richard Qin */
-
-/*
- * pipe.cc — Pipe implementation
- *
- * Implements unidirectional byte-stream pipes with blocking I/O.
- * Each pipe has a 4KB circular buffer. Reads block when empty,
- * writes block when full (unless O_NONBLOCK).
- *
- * When all writers close, read returns 0 (EOF).
- * When all readers close, write returns -EPIPE.
- */
-
-#include <lume/pipe.h>
-#include <lume/file.h>
-#include <lume/fdtable.h>
-#include <lume/errno.h>
-#include <lume/slab.h>
-#include <lume/fs_types.h>
-#include <lume/klog.h>
-#include <lume/sched.h>
-
-/* ================================================================== */
-/* pipe_inode_info lifecycle */
-/* ================================================================== */
-
-pipe_inode_info* alloc_pipe_info()
-{
- auto* pi = new pipe_inode_info{};
- if (!pi) return nullptr;
-
- pi->rd_pos = 0;
- pi->wr_pos = 0;
- pi->len = 0;
- pi->rd_wait.init("pipe_rd");
- pi->wr_wait.init("pipe_wr");
- pi->readers.store(0);
- pi->writers.store(0);
- pi->refcount.store(1);
- return pi;
-}
-
-void free_pipe_info(pipe_inode_info* pipe)
-{
- delete pipe;
-}
-
-static void pipe_get(pipe_inode_info* pi)
-{
- pi->refcount.fetch_add(1);
-}
-
-static void pipe_put(pipe_inode_info* pi)
-{
- if (pi->refcount.fetch_sub(1) == 1) {
- free_pipe_info(pi);
- }
-}
-
-/* ================================================================== */
-/* pipe_read */
-/* ================================================================== */
-
-static int64 pipe_read(file* fp, char* buf, uint64 count, int64* /*pos*/)
-{
- pipe_inode_info* pi = static_cast<pipe_inode_info*>(fp->private_data);
- if (!pi) return -EBADF;
-
- while (true) {
- pi->lock.acquire();
-
- if (pi->len > 0) {
- /* Data available — copy out */
- int64 to_read = static_cast<int64>(count);
- if (to_read > pi->len) to_read = pi->len;
-
- for (int64 i = 0; i < to_read; i++) {
- buf[i] = pi->buf[pi->rd_pos];
- pi->rd_pos = (pi->rd_pos + 1) % PIPE_BUF_SIZE;
- }
- pi->len -= static_cast<int>(to_read);
-
- pi->lock.release();
-
- /* Wake any blocked writers */
- pi->wr_wait.wake_all();
- return to_read;
- }
-
- /* Buffer empty */
- if (pi->writers.load() == 0) {
- /* No writers left — EOF */
- pi->lock.release();
- return 0;
- }
-
- if (fp->f_flags & O_NONBLOCK) {
- pi->lock.release();
- return -EAGAIN;
- }
-
- pi->lock.release();
-
- /* Sleep until data or writer closes */
- pi->rd_wait.sleep();
- }
-}
-
-/* ================================================================== */
-/* pipe_write */
-/* ================================================================== */
-
-static int64 pipe_write(file* fp, const char* buf, uint64 count, int64* /*pos*/)
-{
- pipe_inode_info* pi = static_cast<pipe_inode_info*>(fp->private_data);
- if (!pi) return -EBADF;
-
- if (pi->readers.load() == 0) {
- return -EPIPE; /* Broken pipe */
- }
-
- int64 written = 0;
-
- while (static_cast<uint64>(written) < count) {
- pi->lock.acquire();
-
- if (pi->len < PIPE_BUF_SIZE) {
- /* Space available — copy in */
- int avail = PIPE_BUF_SIZE - pi->len;
- int64 remaining = static_cast<int64>(count) - written;
- int to_write = avail < static_cast<int>(remaining)
- ? avail
- : static_cast<int>(remaining);
-
- for (int i = 0; i < to_write; i++) {
- pi->buf[pi->wr_pos] = buf[written + i];
- pi->wr_pos = (pi->wr_pos + 1) % PIPE_BUF_SIZE;
- }
- pi->len += to_write;
- written += to_write;
-
- pi->lock.release();
-
- /* Wake any blocked readers */
- pi->rd_wait.wake_all();
- continue;
- }
-
- /* Buffer full */
- if (pi->readers.load() == 0) {
- pi->lock.release();
- return written > 0 ? written : -EPIPE;
- }
-
- if (fp->f_flags & O_NONBLOCK) {
- pi->lock.release();
- return written > 0 ? written : -EAGAIN;
- }
-
- pi->lock.release();
-
- /* Sleep until space or reader closes */
- pi->wr_wait.sleep();
- }
-
- return written;
-}
-
-/* ================================================================== */
-/* pipe_release — called on last fput of a pipe fd */
-/* ================================================================== */
-
-static int pipe_read_release(inode* /*ip*/, file* fp)
-{
- pipe_inode_info* pi = static_cast<pipe_inode_info*>(fp->private_data);
- if (pi) {
- pi->readers.fetch_sub(1);
- /* Wake writers so they see readers==0 and get EPIPE */
- pi->wr_wait.wake_all();
- pipe_put(pi);
- }
- return 0;
-}
-
-static int pipe_write_release(inode* /*ip*/, file* fp)
-{
- pipe_inode_info* pi = static_cast<pipe_inode_info*>(fp->private_data);
- if (pi) {
- pi->writers.fetch_sub(1);
- /* Wake readers so they see writers==0 and get EOF */
- pi->rd_wait.wake_all();
- pipe_put(pi);
- }
- return 0;
-}
-
-/* ================================================================== */
-/* file_operations tables */
-/* ================================================================== */
-
-static file_operations pipe_read_fops;
-static file_operations pipe_write_fops;
-static bool pipe_fops_initialized = false;
-
-static void pipe_fops_init()
-{
- if (pipe_fops_initialized) return;
-
- pipe_read_fops = {};
- pipe_read_fops.read = pipe_read;
- pipe_read_fops.release = pipe_read_release;
-
- pipe_write_fops = {};
- pipe_write_fops.write = pipe_write;
- pipe_write_fops.release = pipe_write_release;
-
- pipe_fops_initialized = true;
-}
-
-/* ================================================================== */
-/* do_pipe2 — create a pipe, install two fds */
-/* ================================================================== */
-
-int do_pipe2(files_struct* files, int fds[2], int flags)
-{
- pipe_fops_init();
-
- pipe_inode_info* pi = alloc_pipe_info();
- if (!pi) return -ENOMEM;
-
- /* Create read-end file */
- file* rd_fp = alloc_empty_file(O_RDONLY | (flags & O_NONBLOCK));
- if (!rd_fp) {
- free_pipe_info(pi);
- return -ENFILE;
- }
- rd_fp->f_op = &pipe_read_fops;
- rd_fp->private_data = pi;
-
- /* Create write-end file */
- file* wr_fp = alloc_empty_file(O_WRONLY | (flags & O_NONBLOCK));
- if (!wr_fp) {
- fput(rd_fp);
- free_pipe_info(pi);
- return -ENFILE;
- }
- wr_fp->f_op = &pipe_write_fops;
- wr_fp->private_data = pi;
-
- /* Bump pipe refcount for the two files */
- pipe_get(pi); /* wr_fp gets second ref */
- pi->readers.store(1);
- pi->writers.store(1);
-
- /* Allocate fds */
- int rd_fd = alloc_fd(files, 0);
- if (rd_fd < 0) {
- fput(rd_fp);
- fput(wr_fp);
- return rd_fd;
- }
-
- int wr_fd = alloc_fd(files, 0);
- if (wr_fd < 0) {
- close_fd(files, rd_fd);
- fput(wr_fp);
- return wr_fd;
- }
-
- fd_install(files, rd_fd, rd_fp);
- fd_install(files, wr_fd, wr_fp);
-
- fds[0] = rd_fd;
- fds[1] = wr_fd;
-
- return 0;
-}
diff --git a/na/fs/ramfs/file.cc b/na/fs/ramfs/file.cc
deleted file mode 100644
index 6d9a070..0000000
--- a/na/fs/ramfs/file.cc
+++ /dev/null
@@ -1,216 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* Copyright (C) 2026 Richard Qin */
-
-/*
- * ramfs/file.cc — RamFS file operations (read/write via in-memory pages)
- *
- * Phase 1: simple flat buffer per-inode via i_private.
- * Will migrate to page_cache integration later.
- */
-
-#include <lume/fs.h>
-#include <lume/file.h>
-#include <lume/dcache.h>
-#include <lume/slab.h>
-#include <lume/errno.h>
-#include <lume/fs_types.h>
-
-/*
- * Simplest possible in-memory file storage:
- * i_private points to a dynamically grown buffer.
- */
-struct ramfs_file_data {
- char* buf;
- uint64 capacity;
-};
-
-static ramfs_file_data* get_or_create_data(inode* ip)
-{
- if (!ip->i_private) {
- auto* data = new ramfs_file_data{};
- data->buf = nullptr;
- data->capacity = 0;
- ip->i_private = data;
- }
- return static_cast<ramfs_file_data*>(ip->i_private);
-}
-
-static int ensure_capacity(ramfs_file_data* data, uint64 needed)
-{
- if (needed <= data->capacity) return 0;
-
- /* Round up to page size */
- uint64 new_cap = (needed + 4095) & ~4095ULL;
- char* new_buf = new char[new_cap];
- if (!new_buf) return -ENOMEM;
-
- /* Copy old data */
- if (data->buf && data->capacity > 0) {
- for (uint64 i = 0; i < data->capacity; i++)
- new_buf[i] = data->buf[i];
- }
- /* Zero new region */
- for (uint64 i = data->capacity; i < new_cap; i++)
- new_buf[i] = 0;
-
- delete[] data->buf;
- data->buf = new_buf;
- data->capacity = new_cap;
- return 0;
-}
-
-/* ================================================================== */
-/* ramfs_read */
-/* ================================================================== */
-
-static int64 ramfs_read(file* fp, char* buf, uint64 count, int64* pos)
-{
- inode* ip = file_inode(fp);
- int64 offset = *pos;
-
- if (offset < 0) return -EINVAL;
- if (offset >= ip->i_size) return 0;
-
- int64 avail = ip->i_size - offset;
- if (static_cast<int64>(count) > avail)
- count = static_cast<uint64>(avail);
-
- auto* data = static_cast<ramfs_file_data*>(ip->i_private);
- if (!data || !data->buf) return 0;
-
- /* Copy to user buffer.
- * TODO: use copy_to_user when called from syscall context */
- for (uint64 i = 0; i < count; i++)
- buf[i] = data->buf[offset + i];
-
- *pos += count;
- return static_cast<int64>(count);
-}
-
-/* ================================================================== */
-/* ramfs_write */
-/* ================================================================== */
-
-static int64 ramfs_write(file* fp, const char* buf, uint64 count, int64* pos)
-{
- inode* ip = file_inode(fp);
- int64 offset = *pos;
-
- if (fp->f_flags & O_APPEND)
- offset = ip->i_size;
-
- if (offset < 0) return -EINVAL;
-
- auto* data = get_or_create_data(ip);
- uint64 end = static_cast<uint64>(offset) + count;
-
- int err = ensure_capacity(data, end);
- if (err) return err;
-
- /* Copy from user buffer */
- for (uint64 i = 0; i < count; i++)
- data->buf[offset + i] = buf[i];
-
- if (static_cast<int64>(end) > ip->i_size)
- ip->i_size = end;
-
- *pos = end;
- mark_inode_dirty(ip);
- return static_cast<int64>(count);
-}
-
-/* ================================================================== */
-/* ramfs_dir_iterate — getdents64 */
-/* ================================================================== */
-
-static int ramfs_dir_iterate(file* fp, dir_context* ctx)
-{
- dentry* dir_de = file_dentry(fp);
- inode* dir_ip = file_inode(fp);
- int64 pos = ctx->pos;
- int count = 0;
-
- /* pos 0: emit "." */
- if (pos == 0) {
- if (!ctx->actor(ctx, ".", 1, pos, dir_ip->i_ino, DT_DIR))
- return 0;
- ctx->pos = 1;
- pos = 1;
- count++;
- }
-
- /* pos 1: emit ".." */
- if (pos == 1) {
- uint64 parent_ino = dir_de->d_parent->d_inode
- ? dir_de->d_parent->d_inode->i_ino : dir_ip->i_ino;
- if (!ctx->actor(ctx, "..", 2, pos, parent_ino, DT_DIR))
- return 0;
- ctx->pos = 2;
- pos = 2;
- count++;
- }
-
- /* pos >= 2: iterate children */
- int64 child_idx = 2;
- list_node* node;
- list_for_each(node, &dir_de->d_children) {
- dentry* child = list_entry(node, dentry, d_child);
-
- if (!child->d_inode)
- continue; /* skip negative dentries */
-
- if (child_idx >= pos) {
- uint8 d_type = DT_UNKNOWN;
- if (S_ISDIR(child->d_inode->i_mode)) d_type = DT_DIR;
- else if (S_ISREG(child->d_inode->i_mode)) d_type = DT_REG;
- else if (S_ISCHR(child->d_inode->i_mode)) d_type = DT_CHR;
- else if (S_ISBLK(child->d_inode->i_mode)) d_type = DT_BLK;
- else if (S_ISLNK(child->d_inode->i_mode)) d_type = DT_LNK;
- else if (S_ISFIFO(child->d_inode->i_mode)) d_type = DT_FIFO;
-
- if (!ctx->actor(ctx, child->d_name.name,
- static_cast<int>(child->d_name.len),
- child_idx, child->d_inode->i_ino, d_type))
- return 0;
-
- ctx->pos = child_idx + 1;
- count++;
- }
- child_idx++;
- }
-
- return count;
-}
-
-extern file_operations ramfs_file_operations;
-extern file_operations ramfs_dir_operations;
-
-file_operations ramfs_file_operations;
-file_operations ramfs_dir_operations;
-
-void ramfs_file_ops_init()
-{
- ramfs_file_operations.llseek = nullptr;
- ramfs_file_operations.read = ramfs_read;
- ramfs_file_operations.write = ramfs_write;
- ramfs_file_operations.iterate_shared = nullptr;
- ramfs_file_operations.poll = nullptr;
- ramfs_file_operations.unlocked_ioctl = nullptr;
- ramfs_file_operations.mmap = nullptr;
- ramfs_file_operations.open = nullptr;
- ramfs_file_operations.flush = nullptr;
- ramfs_file_operations.release = nullptr;
- ramfs_file_operations.fsync = nullptr;
-
- ramfs_dir_operations.llseek = nullptr;
- ramfs_dir_operations.read = nullptr;
- ramfs_dir_operations.write = nullptr;
- ramfs_dir_operations.iterate_shared = ramfs_dir_iterate;
- ramfs_dir_operations.poll = nullptr;
- ramfs_dir_operations.unlocked_ioctl = nullptr;
- ramfs_dir_operations.mmap = nullptr;
- ramfs_dir_operations.open = nullptr;
- ramfs_dir_operations.flush = nullptr;
- ramfs_dir_operations.release = nullptr;
- ramfs_dir_operations.fsync = nullptr;
-}
diff --git a/na/fs/ramfs/inode.cc b/na/fs/ramfs/inode.cc
deleted file mode 100644
index c5e49bf..0000000
--- a/na/fs/ramfs/inode.cc
+++ /dev/null
@@ -1,164 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* Copyright (C) 2026 Richard Qin */
-
-/*
- * ramfs/inode.cc — RamFS inode operations
- *
- * A simple in-memory filesystem (like Linux tmpfs without swap).
- * All data lives in memory via the page cache.
- */
-
-#include <lume/fs.h>
-#include <lume/dcache.h>
-#include <lume/file.h>
-#include <lume/slab.h>
-#include <lume/errno.h>
-#include <lume/fs_types.h>
-
-/* Forward declarations */
-extern file_operations ramfs_file_operations;
-extern file_operations ramfs_dir_operations;
-extern inode_operations ramfs_dir_inode_operations;
-
-/* ================================================================== */
-/* ramfs_get_inode — allocate + init an inode for ramfs */
-/* ================================================================== */
-
-inode* ramfs_get_inode(super_block* sb, const inode* dir, uint32 mode, uint32 rdev)
-{
- inode* ip = new_inode(sb);
- if (!ip) return nullptr;
-
- inode_init_owner(ip, dir, mode);
- /* TODO: set timestamps to current time when we have a time source */
-
- switch (mode & S_IFMT) {
- case S_IFREG:
- ip->i_op = nullptr; /* regular files don't need inode_ops for Phase 1 */
- ip->i_fop = &ramfs_file_operations;
- break;
- case S_IFDIR:
- ip->i_op = &ramfs_dir_inode_operations;
- ip->i_fop = &ramfs_dir_operations;
- inc_nlink(ip); /* directories start with nlink=2 (. and parent's link) */
- break;
- case S_IFLNK:
- /* Symlink: stub for Phase 1 */
- break;
- default:
- /* Character/block devices: i_rdev */
- ip->i_rdev = rdev;
- break;
- }
-
- return ip;
-}
-
-/* ================================================================== */
-/* Directory inode operations */
-/* ================================================================== */
-
-static dentry* ramfs_lookup(inode* dir, dentry* de, unsigned int flags)
-{
- (void)dir;
- (void)flags;
- /* For ramfs, everything is in dcache. If we get here, it means
- * d_lookup() already failed, so this is a negative dentry.
- * Just return nullptr to let the caller see de->d_inode == NULL. */
- return nullptr;
-}
-
-static int ramfs_create(inode* dir, dentry* de, uint32 mode, bool excl)
-{
- (void)excl;
- inode* ip = ramfs_get_inode(dir->i_sb, dir, mode | S_IFREG, 0);
- if (!ip) return -ENOMEM;
-
- d_instantiate(de, ip);
- dget(de);
- dir->i_size += de->d_name.len;
- mark_inode_dirty(dir);
- return 0;
-}
-
-static int ramfs_mkdir(inode* dir, dentry* de, uint32 mode)
-{
- inode* ip = ramfs_get_inode(dir->i_sb, dir, mode | S_IFDIR, 0);
- if (!ip) return -ENOMEM;
-
- d_instantiate(de, ip);
- dget(de);
- inc_nlink(dir);
- dir->i_size += de->d_name.len;
- mark_inode_dirty(dir);
- return 0;
-}
-
-static int ramfs_rmdir(inode* dir, dentry* de)
-{
- /* Check if directory is empty */
- if (!list_empty(&de->d_children))
- return -ENOTEMPTY;
-
- drop_nlink(de->d_inode); /* remove . link */
- drop_nlink(de->d_inode); /* remove parent's link */
- drop_nlink(dir);
- d_delete(de);
- dir->i_size -= de->d_name.len;
- mark_inode_dirty(dir);
- return 0;
-}
-
-static int ramfs_unlink(inode* dir, dentry* de)
-{
- drop_nlink(de->d_inode);
- d_delete(de);
- dir->i_size -= de->d_name.len;
- mark_inode_dirty(dir);
- return 0;
-}
-
-static int ramfs_link(dentry* old_de, inode* dir, dentry* new_de)
-{
- inode* ip = old_de->d_inode;
- if (!ip) return -ENOENT;
-
- inc_nlink(ip);
- ihold(ip);
- d_instantiate(new_de, ip);
- dget(new_de);
- dir->i_size += new_de->d_name.len;
- mark_inode_dirty(dir);
- return 0;
-}
-
-static int ramfs_mknod(inode* dir, dentry* de, uint32 mode, uint32 rdev)
-{
- inode* ip = ramfs_get_inode(dir->i_sb, dir, mode, rdev);
- if (!ip) return -ENOMEM;
-
- d_instantiate(de, ip);
- dget(de);
- dir->i_size += de->d_name.len;
- mark_inode_dirty(dir);
- return 0;
-}
-
-inode_operations ramfs_dir_inode_operations;
-
-void ramfs_dir_inode_ops_init()
-{
- ramfs_dir_inode_operations.lookup = ramfs_lookup;
- ramfs_dir_inode_operations.create = ramfs_create;
- ramfs_dir_inode_operations.link = ramfs_link;
- ramfs_dir_inode_operations.unlink = ramfs_unlink;
- ramfs_dir_inode_operations.symlink = nullptr;
- ramfs_dir_inode_operations.mkdir = ramfs_mkdir;
- ramfs_dir_inode_operations.rmdir = ramfs_rmdir;
- ramfs_dir_inode_operations.mknod = ramfs_mknod;
- ramfs_dir_inode_operations.rename = nullptr;
- ramfs_dir_inode_operations.setattr = nullptr;
- ramfs_dir_inode_operations.getattr = nullptr;
- ramfs_dir_inode_operations.get_link = nullptr;
- ramfs_dir_inode_operations.permission = nullptr;
-}
diff --git a/na/fs/ramfs/super.cc b/na/fs/ramfs/super.cc
deleted file mode 100644
index 6f929f2..0000000
--- a/na/fs/ramfs/super.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* Copyright (C) 2026 Richard Qin */
-
-/*
- * ramfs/super.cc — RamFS superblock: mount, fill_super, and init
- */
-
-#include <lume/fs.h>
-#include <lume/dcache.h>
-#include <lume/file.h>
-#include <lume/mount.h>
-#include <lume/slab.h>
-#include <lume/kprintf.h>
-#include <lume/errno.h>
-#include <lume/fs_types.h>
-
-extern inode* ramfs_get_inode(super_block* sb, const inode* dir,
- uint32 mode, uint32 rdev);
-
-/* Superblock allocation helper (defined in super.cc) */
-extern super_block* alloc_super(file_system_type* type);
-
-/* ================================================================== */
-/* ramfs super_operations */
-/* ================================================================== */
-
-static inode* ramfs_alloc_inode(super_block* sb)
-{
- return new inode{};
-}
-
-static void ramfs_destroy_inode(inode* ip)
-{
- /* Free ramfs_file_data if any */
- if (ip->i_private) {
- struct ramfs_file_data {
- char* buf;
- uint64 capacity;
- };
- auto* data = static_cast<ramfs_file_data*>(ip->i_private);
- delete[] data->buf;
- delete data;
- }
- delete ip;
-}
-
-static int ramfs_statfs(dentry* de, kstatfs* buf)
-{
- /* Simple fake values */
- buf->f_type = 0x858458f6; /* RAMFS_MAGIC */
- buf->f_bsize = 4096;
- buf->f_blocks = 0;
- buf->f_bfree = 0;
- buf->f_bavail = 0;
- buf->f_files = 0;
- buf->f_ffree = 0;
- buf->f_namelen = 255;
- buf->f_frsize = 4096;
- buf->f_flags = 0;
- return 0;
-}
-
-static super_operations ramfs_sops;
-
-static void ramfs_sops_init()
-{
- ramfs_sops.alloc_inode = ramfs_alloc_inode;
- ramfs_sops.destroy_inode = ramfs_destroy_inode;
- ramfs_sops.free_inode = nullptr;
- ramfs_sops.dirty_inode = nullptr;
- ramfs_sops.write_inode = nullptr;
- ramfs_sops.drop_inode = nullptr;
- ramfs_sops.evict_inode = nullptr;
- ramfs_sops.put_super = nullptr;
- ramfs_sops.sync_fs = nullptr;
- ramfs_sops.statfs = ramfs_statfs;
- ramfs_sops.umount_begin = nullptr;
-}
-
-/* ================================================================== */
-/* ramfs_fill_super */
-/* ================================================================== */
-
-static int ramfs_fill_super(super_block* sb, void* data, int silent)
-{
- sb->s_op = &ramfs_sops;
- sb->s_magic = 0x858458f6;
- sb->s_blocksize = 4096;
- sb->s_blocksize_bits = 12;
- sb->s_maxbytes = 0x7FFFFFFFFFFFFFFFLL;
- sb->s_time_gran = 1;
-
- /* Create root inode */
- inode* root_ip = ramfs_get_inode(sb, nullptr, S_IFDIR | 0755, 0);
- if (!root_ip) return -ENOMEM;
-
- /* Create root dentry */
- sb->s_root = d_make_root(root_ip);
- if (!sb->s_root)
- return -ENOMEM;
-
- return 0;
-}
-
-/* ================================================================== */
-/* ramfs_mount */
-/* ================================================================== */
-
-static super_block* ramfs_mount(file_system_type* type, int flags,
- const char* dev_name, void* data)
-{
- super_block* sb = alloc_super(type);
- if (!sb) return nullptr;
-
- int err = ramfs_fill_super(sb, data, flags & SB_SILENT);
- if (err) {
- delete sb;
- return nullptr;
- }
-
- return sb;
-}
-
-static void ramfs_kill_sb(super_block* sb)
-{
- /* Phase 1: no cleanup needed for ramfs */
- (void)sb;
-}
-
-/* ================================================================== */
-/* Filesystem type registration */
-/* ================================================================== */
-
-static file_system_type ramfs_fs_type;
-
-extern void ramfs_file_ops_init();
-extern void ramfs_dir_inode_ops_init();
-
-void ramfs_init()
-{
- /* Runtime init to avoid un-relocated absolute pointers in .data */
- ramfs_sops_init();
- ramfs_file_ops_init();
- ramfs_dir_inode_ops_init();
-
- ramfs_fs_type.name = "ramfs";
- ramfs_fs_type.fs_flags = FS_NO_DEVICE;
- ramfs_fs_type.mount = ramfs_mount;
- ramfs_fs_type.kill_sb = ramfs_kill_sb;
- list_init(&ramfs_fs_type.fs_list);
-
- register_filesystem(&ramfs_fs_type);
-}
-
diff --git a/na/fs/super.cc b/na/fs/super.cc
deleted file mode 100644
index 231b57c..0000000
--- a/na/fs/super.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* Copyright (C) 2026 Richard Qin */
-
-/*
- * super.cc — Superblock lifecycle + filesystem type registry
- */
-
-#include <lume/fs.h>
-#include <lume/dcache.h>
-#include <lume/mount.h>
-#include <lume/klog.h>
-#include <lume/slab.h>
-#include <lume/errno.h>
-
-/* Global root filesystem entry points */
-vfsmount* g_root_mnt = nullptr;
-dentry* g_root_dentry = nullptr;
-
-/* ================================================================== */
-/* Filesystem type registry */
-/* ================================================================== */
-
-namespace {
-
-list_head g_fs_types;
-Spinlock g_fs_type_lock;
-
-} // namespace
-
-int register_filesystem(file_system_type* fs)
-{
- LockGuard guard(g_fs_type_lock);
- list_add_tail(&fs->fs_list, &g_fs_types);
- printk("[vfs] registered filesystem: %s\n", fs->name);
- return 0;
-}
-
-file_system_type* get_fs_type(const char* name)
-{
- LockGuard guard(g_fs_type_lock);
- list_node* pos;
- list_for_each(pos, &g_fs_types) {
- auto* fs = list_entry(pos, file_system_type, fs_list);
- /* Simple strcmp */
- const char* a = fs->name;
- const char* b = name;
- while (*a && *a == *b) { a++; b++; }
- if (*a == '\0' && *b == '\0')
- return fs;
- }
- return nullptr;
-}
-
-/* ================================================================== */
-/* Superblock allocation */
-/* ================================================================== */
-
-super_block* alloc_super(file_system_type* type)
-{
- auto* sb = new super_block{};
- if (!sb) return nullptr;
-
- list_init(&sb->s_list);
- list_init(&sb->s_inodes);
- sb->s_type = type;
- sb->s_op = nullptr;
- sb->s_root = nullptr;
- sb->s_fs_info = nullptr;
- sb->s_blocksize = 4096;
- sb->s_blocksize_bits = 12;
- sb->s_maxbytes = 0x7FFFFFFFFFFFFFFFLL;
- sb->s_time_gran = 1;
- sb->s_time_min = 0;
- sb->s_time_max = 0x7FFFFFFFFFFFFFFFLL;
- sb->s_flags = 0;
- sb->s_magic = 0;
- sb->s_active.store(1);
- sb->s_count = 1;
- sb->s_max_links = 0;
- sb->s_d_op = nullptr;
- sb->s_mounts = nullptr;
- sb->s_dev = 0;
- for (int i = 0; i < 32; i++) sb->s_id[i] = 0;
-
- return sb;
-}
-
-/* ================================================================== */
-/* Init */
-/* ================================================================== */
-
-void super_init()
-{
- list_init(&g_fs_types);
-}
diff --git a/na/fs/vfs_init.cc b/na/fs/vfs_init.cc
deleted file mode 100644
index ec56e88..0000000
--- a/na/fs/vfs_init.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* Copyright (C) 2026 Richard Qin */
-
-/*
- * vfs_init.cc — Bootstrap the VFS: mount ramfs root, set global root
- *
- * Called from kernel_main() after slab_init() and ramfs_init().
- * This is the moral equivalent of Linux's vfs_caches_init() +
- * mnt_init() + init_rootfs().
- */
-
-#include <lume/fs.h>
-#include <lume/dcache.h>
-#include <lume/file.h>
-#include <lume/mount.h>
-#include <lume/fdtable.h>
-#include <lume/fs_struct.h>
-#include <lume/klog.h>
-#include <lume/kprintf.h>
-#include <lume/task.h>
-#include <lume/sched.h>
-
-/* ================================================================== */
-/* vfs_init — mount ramfs as root filesystem */
-/* ================================================================== */
-
-/*
- * ramfs_mount is called internally via the file_system_type::mount
- * callback registered by ramfs_init(). We look it up by name.
- */
-extern file_system_type* get_fs_type(const char* name);
-extern super_block* alloc_super(file_system_type* type);
-
-void vfs_init()
-{
- /* 1. Look up the ramfs filesystem type */
- file_system_type* ramfs_type = get_fs_type("ramfs");
- if (!ramfs_type || !ramfs_type->mount) {
- printk(KERN_ERR "vfs_init: ramfs not registered!\n");
- return;
- }
-
- /* 2. Mount ramfs */
- super_block* sb = ramfs_type->mount(ramfs_type, 0, "ramfs", nullptr);
- if (!sb || !sb->s_root) {
- printk(KERN_ERR "vfs_init: failed to mount ramfs!\n");
- return;
- }
-
- /* 3. Set global root */
- g_root_dentry = sb->s_root;
- g_root_mnt = nullptr; /* TODO: allocate a proper vfsmount when mount.cc lands */
-
- dget(g_root_dentry); /* Hold a reference for the global root */
-
- printk(KERN_INFO "[vfs] root filesystem mounted (ramfs)\n");
-
- /* 4. Set up VFS state for the current (BSP idle) task,
- * which will be inherited by all subsequently created tasks. */
- TaskControlBlock* bsp = current_task();
- if (bsp) {
- if (!bsp->files) {
- bsp->files = alloc_files_struct();
- }
- if (!bsp->fs) {
- bsp->fs = alloc_fs_struct();
- if (bsp->fs) {
- bsp->fs->root.de = g_root_dentry;
- bsp->fs->root.mnt = g_root_mnt;
- bsp->fs->pwd.de = g_root_dentry;
- bsp->fs->pwd.mnt = g_root_mnt;
- dget(g_root_dentry); /* root ref */
- dget(g_root_dentry); /* pwd ref */
- }
- }
- printk(KERN_INFO "[vfs] BSP task VFS context initialized\n");
- }
-}