};
/* Mount an ext2 filesystem on the given block device starting at the given
- * LBA offset. Returns a VFS root node or NULL on failure. */
-fs_node_t* ext2_mount(const block_device_t* bdev, uint32_t partition_lba);
+ * LBA offset. Returns a mount result with root node and superblock, or {NULL, NULL} on failure. */
+vfs_mount_result_t ext2_mount(const block_device_t* bdev, uint32_t partition_lba);
/* Unmount an ext2 filesystem and free its resources */
void ext2_umount(struct ext2_mount* em);
/* Mount a FAT12/16/32 filesystem on the given block device starting at
* the given LBA offset. Auto-detects FAT type from BPB.
- * Returns a VFS root node or NULL on failure. */
-fs_node_t* fat_mount(const block_device_t* bdev, uint32_t partition_lba);
+ * Returns a mount result with root node and superblock, or {NULL, NULL} on failure. */
+vfs_mount_result_t fat_mount(const block_device_t* bdev, uint32_t partition_lba);
/* Unmount a FAT filesystem and free its resources */
void fat_umount(struct fat_mount* fm);
#define FS_NEEDS_BDEV 0x01 /* Requires block device */
struct fs_node; /* forward declaration */
-
-/* Filesystem type structure */
-typedef struct vfs_fs_type {
- const char* name; /* e.g. "fat", "ext2" */
- uint32_t flags; /* FS_NEEDS_BDEV, etc. */
- struct fs_node* (*mount)(const block_device_t* bdev, uint32_t lba); /* Mount function */
-} vfs_fs_type_t;
+struct vfs_fs_type; /* forward declaration */
/* VFS superblock — per-mount filesystem metadata */
typedef struct vfs_superblock {
- const vfs_fs_type_t* fstype; /* Filesystem type */
+ const struct vfs_fs_type* fstype; /* Filesystem type */
const block_device_t* bdev; /* Block device (NULL for virtual FS) */
uint32_t lba; /* Partition start LBA (0 for whole disk) */
void* private_data; /* Filesystem-specific data (e.g. fat_mount, ext2_mount) */
} vfs_superblock_t;
+/* Mount result structure - returned by filesystem mount functions */
+typedef struct vfs_mount_result {
+ struct fs_node* root; /* VFS root node */
+ vfs_superblock_t* sb; /* Superblock (NULL for virtual FS) */
+} vfs_mount_result_t;
+
+/* Filesystem type structure */
+typedef struct vfs_fs_type {
+ const char* name; /* e.g. "fat", "ext2" */
+ uint32_t flags; /* FS_NEEDS_BDEV, etc. */
+ vfs_mount_result_t (*mount)(const block_device_t* bdev, uint32_t lba); /* Mount function */
+} vfs_fs_type_t;
+
/* poll() event flags — shared between kernel VFS and syscall layer */
#define VFS_POLL_IN 0x0001
#define VFS_POLL_OUT 0x0004
int vfs_mount(const char* mountpoint, fs_node_t* root);
int vfs_mount_full(const char* mountpoint, fs_node_t* root,
const char* fstype, const char* source,
- unsigned long flags, const block_device_t* bdev);
+ unsigned long flags, const block_device_t* bdev,
+ vfs_superblock_t* sb);
int vfs_umount(const char* mountpoint);
/* _nolock variants — caller must already hold g_vfs_lock.
*/
#include "ext2.h"
+#include "fs.h"
#include "blockdev.h"
#include "heap.h"
#include "utils.h"
/* ---- Mount ---- */
-fs_node_t* ext2_mount(const block_device_t* bdev, uint32_t partition_lba) {
+vfs_mount_result_t ext2_mount(const block_device_t* bdev, uint32_t partition_lba) {
+ vfs_mount_result_t result = {NULL, NULL};
+
if (!bdev) {
kprintf("[EXT2] No block device provided\n");
- return NULL;
+ return result;
}
/* Allocate mount structure */
struct ext2_mount* em = (struct ext2_mount*)kmalloc(sizeof(struct ext2_mount));
if (!em) {
kprintf("[EXT2] Failed to allocate mount structure\n");
- return NULL;
+ return result;
}
memset(em, 0, sizeof(*em));
if (ext2_read_superblock(em, &sb) < 0) {
kprintf("[EXT2] Failed to read superblock\n");
kfree(em);
- return NULL;
+ return result;
}
if (sb.s_magic != EXT2_SUPER_MAGIC) {
kprintf("[EXT2] Invalid magic: 0x%x\n", sb.s_magic);
kfree(em);
- return NULL;
+ return result;
}
em->block_size = 1024U << sb.s_log_block_size;
if (em->block_size > 4096) {
kprintf("[EXT2] Unsupported block size %u\n", em->block_size);
kfree(em);
- return NULL;
+ return result;
}
em->sectors_per_block = em->block_size / EXT2_SECTOR_SIZE;
em->inodes_per_group = sb.s_inodes_per_group;
if (!em->gdt) {
kprintf("[EXT2] Failed to allocate GDT (%u bytes)\n", gdt_bytes);
kfree(em);
- return NULL;
+ return result;
}
memset(em->gdt, 0, gdt_bytes);
kprintf("[EXT2] Failed to read GDT block %u\n", gdt_block + b);
kfree(em->gdt);
kfree(em);
- return NULL;
+ return result;
}
uint32_t to_copy = em->block_size;
if (to_copy > gdt_bytes - b * em->block_size)
kprintf("[EXT2] Failed to read root inode\n");
kfree(em->gdt);
kfree(em);
- return NULL;
+ return result;
}
/* Build root node */
kprintf("[EXT2] Failed to allocate root node\n");
kfree(em->gdt);
kfree(em);
- return NULL;
+ return result;
}
memset(root, 0, sizeof(*root));
root->mount = em;
root->vfs.f_ops = &ext2_dir_fops;
root->vfs.i_ops = &ext2_dir_iops;
+ /* Build superblock */
+ vfs_superblock_t* vfs_sb = (vfs_superblock_t*)kmalloc(sizeof(vfs_superblock_t));
+ if (!vfs_sb) {
+ kprintf("[EXT2] Failed to allocate superblock\n");
+ kfree(root);
+ kfree(em->gdt);
+ kfree(em);
+ return result;
+ }
+ memset(vfs_sb, 0, sizeof(*vfs_sb));
+ vfs_sb->bdev = bdev;
+ vfs_sb->lba = partition_lba;
+ vfs_sb->private_data = em;
+ /* fstype will be set by caller */
+
kprintf("[EXT2] Mounted at LBA %u (%u blocks, %u inodes, %u groups, %uB/block)\n",
partition_lba, em->total_blocks, em->total_inodes,
em->num_groups, em->block_size);
- return &root->vfs;
+ result.root = &root->vfs;
+ result.sb = vfs_sb;
+ return result;
}
void ext2_umount(struct ext2_mount* em) {
*/
#include "fat.h"
+#include "fs.h"
#include "blockdev.h"
#include "heap.h"
#include "utils.h"
/* ---- Mount ---- */
-fs_node_t* fat_mount(const block_device_t* bdev, uint32_t partition_lba) {
+vfs_mount_result_t fat_mount(const block_device_t* bdev, uint32_t partition_lba) {
+ vfs_mount_result_t result = {NULL, NULL};
+
if (!bdev) {
kprintf("[FAT] No block device provided\n");
- return NULL;
+ return result;
}
/* Allocate mount structure */
struct fat_mount* fm = (struct fat_mount*)kmalloc(sizeof(struct fat_mount));
if (!fm) {
kprintf("[FAT] Failed to allocate mount structure\n");
- return NULL;
+ return result;
}
memset(fm, 0, sizeof(*fm));
if (fat_read_sector(fm, partition_lba, boot_sec) < 0) {
kprintf("[FAT] Failed to read BPB at LBA %u\n", partition_lba);
kfree(fm);
- return NULL;
+ return result;
}
struct fat_bpb* bpb = (struct fat_bpb*)boot_sec;
if (bpb->bytes_per_sector != 512) {
kprintf("[FAT] Unsupported sector size %u\n", bpb->bytes_per_sector);
kfree(fm);
- return NULL;
+ return result;
}
if (bpb->num_fats == 0 || bpb->sectors_per_cluster == 0) {
kprintf("[FAT] Invalid BPB\n");
kfree(fm);
- return NULL;
+ return result;
}
fm->part_lba = partition_lba;
g_fat_root.vfs.f_ops = &fat_dir_fops;
g_fat_root.vfs.i_ops = &fat_dir_iops;
+ /* Build superblock */
+ vfs_superblock_t* sb = (vfs_superblock_t*)kmalloc(sizeof(vfs_superblock_t));
+ if (!sb) {
+ kprintf("[FAT] Failed to allocate superblock\n");
+ kfree(fm);
+ return result;
+ }
+ memset(sb, 0, sizeof(*sb));
+ sb->bdev = bdev;
+ sb->lba = partition_lba;
+ sb->private_data = fm;
+ /* fstype will be set by caller */
+
kprintf("[FAT] Mounted FAT%u at LBA %u (%u clusters)\n",
(unsigned)fm->type, partition_lba, fm->total_clusters);
- return &g_fat_root.vfs;
+ result.root = &g_fat_root.vfs;
+ result.sb = sb;
+ return result;
}
void fat_umount(struct fat_mount* fm) {
int vfs_mount_full(const char* mountpoint, fs_node_t* root,
const char* fstype, const char* source,
- unsigned long flags, const block_device_t* bdev) {
+ unsigned long flags, const block_device_t* bdev,
+ vfs_superblock_t* sb) {
uintptr_t fl = spin_lock_irqsave(&g_vfs_lock);
- int ret = vfs_mount_nolock_full(mountpoint, root, fstype, source, flags, bdev, NULL);
+ int ret = vfs_mount_nolock_full(mountpoint, root, fstype, source, flags, bdev, sb);
spin_unlock_irqrestore(&g_vfs_lock, fl);
return ret;
}
int vfs_mount(const char* mountpoint, fs_node_t* root) {
- return vfs_mount_full(mountpoint, root, NULL, NULL, 0, NULL);
+ return vfs_mount_full(mountpoint, root, NULL, NULL, 0, NULL, NULL);
}
int vfs_umount_nolock(const char* mountpoint) {
return -EINVAL;
}
- fs_node_t* root = fst->mount(bdev, lba);
- if (!root) {
+ vfs_mount_result_t mres = fst->mount(bdev, lba);
+ if (!mres.root) {
kprintf("[MOUNT] Failed to mount %s on %s at %s\n",
fstype, bdev ? bdev->name : "?",
mountpoint);
return -ENODEV;
}
+ /* Set fstype pointer in superblock */
+ if (mres.sb) {
+ mres.sb->fstype = fst;
+ }
+
/* Claim the block device */
if (bdev) {
blockdev_claim(bdev);
*dp = '\0';
}
- int rc = vfs_mount_full(mountpoint, root, fstype, devname, flags, bdev);
+ int rc = vfs_mount_full(mountpoint, mres.root, fstype, devname, flags, bdev, mres.sb);
if (rc < 0) {
kprintf("[MOUNT] Failed to register mount at %s (err=%d)\n", mountpoint, rc);
if (bdev) {
if (upper) {
fs_node_t* ovl = overlayfs_create_root(fs_root, upper);
if (ovl) {
- (void)vfs_mount_full("/", ovl, "overlayfs", "initrd", 0, NULL);
+ (void)vfs_mount_full("/", ovl, "overlayfs", "initrd", 0, NULL, NULL);
vfs_set_initrd_root(ovl);
}
}
fs_node_t* tmp = tmpfs_create_root();
if (tmp) {
- (void)vfs_mount_full("/tmp", tmp, "tmpfs", "none", 0, NULL);
+ (void)vfs_mount_full("/tmp", tmp, "tmpfs", "none", 0, NULL, NULL);
}
/* Register hardware drivers with HAL and init in priority order */
* existing entry so this is a harmless overlap. */
fs_node_t* dev = devfs_create_root();
if (dev) {
- (void)vfs_mount_full("/dev", dev, "devfs", "none", 0, NULL);
+ (void)vfs_mount_full("/dev", dev, "devfs", "none", 0, NULL, NULL);
}
vbe_register_devfs();
fs_node_t* proc = procfs_create_root();
if (proc) {
- (void)vfs_mount_full("/proc", proc, "procfs", "none", 0, NULL);
+ (void)vfs_mount_full("/proc", proc, "procfs", "none", 0, NULL, NULL);
}
/* Initialize ATA subsystem — probe all 4 drives
/* MS_REMOUNT: update flags on existing mount */
if (mount_flags & MS_REMOUNT) {
- sc_ret(regs) = (uint32_t)vfs_mount_full(kmp, NULL, NULL, NULL, mount_flags & ~MS_REMOUNT, NULL);
+ sc_ret(regs) = (uint32_t)vfs_mount_full(kmp, NULL, NULL, NULL, mount_flags & ~MS_REMOUNT, NULL, NULL);
return;
}
if (strcmp(ktype, "tmpfs") == 0) {
fs_node_t* tmp = tmpfs_create_root();
if (!tmp) { sc_ret(regs) = (uint32_t)-ENOMEM; return; }
- sc_ret(regs) = (uint32_t)vfs_mount_full(kmp, tmp, "tmpfs", kdev, mount_flags, NULL);
+ sc_ret(regs) = (uint32_t)vfs_mount_full(kmp, tmp, "tmpfs", kdev, mount_flags, NULL, NULL);
return;
}
if (strcmp(ktype, "devfs") == 0) {
extern fs_node_t* devfs_create_root(void);
fs_node_t* dev = devfs_create_root();
if (!dev) { sc_ret(regs) = (uint32_t)-ENOMEM; return; }
- sc_ret(regs) = (uint32_t)vfs_mount_full(kmp, dev, "devfs", kdev, mount_flags, NULL);
+ sc_ret(regs) = (uint32_t)vfs_mount_full(kmp, dev, "devfs", kdev, mount_flags, NULL, NULL);
return;
}
if (strcmp(ktype, "procfs") == 0) {
extern fs_node_t* procfs_create_root(void);
fs_node_t* proc = procfs_create_root();
if (!proc) { sc_ret(regs) = (uint32_t)-ENOMEM; return; }
- sc_ret(regs) = (uint32_t)vfs_mount_full(kmp, proc, "procfs", kdev, mount_flags, NULL);
+ sc_ret(regs) = (uint32_t)vfs_mount_full(kmp, proc, "procfs", kdev, mount_flags, NULL, NULL);
return;
}