menios
menios copied to clipboard
Implement VFS mount point support
Goal
Implement VFS mount point infrastructure to support mounting multiple filesystems at different paths in the directory tree (e.g., FAT32 at /boot, ext2 at /).
Context
Currently, meniOS VFS supports only a single root filesystem. To support the dual-partition layout (#228) and future multi-filesystem scenarios, we need:
- Mount point data structures
- Path lookup across mount boundaries
- Mount/unmount operations
- /proc/mounts support
This is a prerequisite for #228 (dual partition mount).
Dependencies
Required (Blocking)
- #65 - VFS layer ✅ COMPLETE
Blocks (Downstream)
- #228 - Dual partition mount (needs mount point support)
- Future: NFS, devfs, tmpfs, procfs mounting
Priority
Medium - Required for dual-partition boot, enables proper Linux-style mounts
Justification
- Foundation for multi-filesystem support
- Required for #228 (dual partition mount)
- Not blocking Doom or GCC milestones immediately
- Single filesystem works for current needs
- Standard Linux VFS feature
Implementation Scope
Phase 1: Mount Point Data Structures (2-3 days)
// Mount point structure
struct mount {
char *path; // Mount path (e.g., "/boot")
struct superblock *sb; // Mounted filesystem superblock
struct dentry *mount_point; // Dentry where mounted
struct dentry *root; // Root dentry of mounted fs
struct mount *parent; // Parent mount (for umount ordering)
struct list_head children; // Child mounts
struct list_head list; // Global mount list
uint32_t flags; // Mount flags (ro, noexec, etc.)
};
// Global mount table
struct list_head mount_table;
struct spinlock mount_lock;
struct mount *root_mount; // Root filesystem mount
Phase 2: Mount Operations (3-4 days)
// Mount API
int vfs_mount(struct superblock *sb, const char *path, uint32_t flags);
int vfs_umount(const char *path);
struct mount *vfs_find_mount(const char *path);
bool vfs_is_mount_point(struct dentry *dentry);
// Mount flags
#define MS_RDONLY 0x0001 // Read-only
#define MS_NOSUID 0x0002 // Ignore suid/sgid
#define MS_NODEV 0x0004 // Disallow device access
#define MS_NOEXEC 0x0008 // Disallow program execution
#define MS_SYNCHRONOUS 0x0010 // Sync writes
#define MS_REMOUNT 0x0020 // Remount existing mount
#define MS_BIND 0x1000 // Bind mount
Phase 3: Path Lookup with Mounts (4-5 days)
// Enhanced path lookup
struct dentry *vfs_path_lookup_with_mounts(const char *path) {
struct dentry *current = root_dentry;
struct mount *current_mount = root_mount;
// Parse path components
const char *next = path;
while (*next) {
// Skip leading slashes
while (*next == '/') next++;
// Get next component
const char *component = next;
while (*next && *next != '/') next++;
size_t len = next - component;
if (len == 0) break;
// Lookup component in current directory
struct dentry *child = dentry_lookup(current, component, len);
if (!child) {
return ERR_PTR(-ENOENT);
}
// Check if child is a mount point
struct mount *mount = vfs_find_mount_at_dentry(child);
if (mount) {
// Cross mount boundary
current = mount->root;
current_mount = mount;
} else {
current = child;
}
}
return current;
}
Phase 4: Mount Syscalls (2-3 days)
// System calls
long sys_mount(const char *source, const char *target,
const char *filesystemtype, unsigned long mountflags,
const void *data);
long sys_umount(const char *target);
long sys_umount2(const char *target, int flags);
// umount2 flags
#define MNT_FORCE 0x0001 // Force unmount even if busy
#define MNT_DETACH 0x0002 // Lazy unmount
#define MNT_EXPIRE 0x0004 // Mark for expiration
Phase 5: /proc/mounts (1-2 days)
// Expose mount table via /proc/mounts
// Format: device mountpoint fstype options
// Example:
// /dev/sda1 /boot fat32 rw 0 0
// /dev/sda2 / ext2 rw 0 0
int proc_mounts_show(struct seq_file *m, void *v) {
struct mount *mount;
list_for_each_entry(mount, &mount_table, list) {
seq_printf(m, "%s %s %s %s 0 0\n",
mount->sb->s_dev_name,
mount->path,
mount->sb->s_type->name,
mount_flags_to_string(mount->flags));
}
return 0;
}
Definition of Done
- [ ] Mount point data structures implemented
- [ ] Mount/umount operations working
- [ ] Path lookup crosses mount boundaries correctly
- [ ] Multiple filesystems can be mounted simultaneously
- [ ] Mount syscalls implemented
- [ ] /proc/mounts shows mounted filesystems
- [ ] Proper locking and synchronization
- [ ] Unit tests for mount operations
- [ ] Integration tests with FAT32 and ext2
- [ ] Documentation
Implementation Details
Mount Point Detection
// Check if dentry is a mount point
bool vfs_is_mount_point(struct dentry *dentry) {
struct mount *mount;
spin_lock(&mount_lock);
list_for_each_entry(mount, &mount_table, list) {
if (mount->mount_point == dentry) {
spin_unlock(&mount_lock);
return true;
}
}
spin_unlock(&mount_lock);
return false;
}
Mount Operation
int vfs_mount(struct superblock *sb, const char *path, uint32_t flags) {
// Lookup mount point
struct dentry *mount_point = vfs_path_lookup(path);
if (IS_ERR(mount_point)) {
return PTR_ERR(mount_point);
}
// Verify mount point is a directory
if (!S_ISDIR(mount_point->d_inode->i_mode)) {
return -ENOTDIR;
}
// Check if already mounted
if (vfs_is_mount_point(mount_point)) {
return -EBUSY;
}
// Create mount structure
struct mount *mount = kmalloc(sizeof(struct mount));
mount->path = kstrdup(path);
mount->sb = sb;
mount->mount_point = mount_point;
mount->root = sb->s_root;
mount->flags = flags;
// Add to mount table
spin_lock(&mount_lock);
list_add(&mount->list, &mount_table);
mount_point->d_flags |= DCACHE_MOUNTED;
spin_unlock(&mount_lock);
kprintf("Mounted %s at %s\n", sb->s_type->name, path);
return 0;
}
Unmount Operation
int vfs_umount(const char *path) {
struct mount *mount;
// Find mount by path
spin_lock(&mount_lock);
list_for_each_entry(mount, &mount_table, list) {
if (strcmp(mount->path, path) == 0) {
// Found it
goto found;
}
}
spin_unlock(&mount_lock);
return -EINVAL;
found:
// Check if busy (has children mounted)
if (!list_empty(&mount->children)) {
spin_unlock(&mount_lock);
return -EBUSY;
}
// Remove from mount table
list_del(&mount->list);
mount->mount_point->d_flags &= ~DCACHE_MOUNTED;
spin_unlock(&mount_lock);
// Sync and release filesystem
sb_sync(mount->sb);
sb_put(mount->sb);
kfree(mount->path);
kfree(mount);
kprintf("Unmounted %s\n", path);
return 0;
}
Testing Strategy
Unit Tests
- Mount filesystem at /mnt
- Mount filesystem at /boot
- Mount multiple filesystems
- Unmount filesystem
- Verify mount point detection
- Test mount over existing mount (should fail)
- Test umount of busy mount (should fail)
Integration Tests
// Test dual mount
void test_dual_mount(void) {
// Mount FAT32 at /boot
struct superblock *fat32_sb = fat32_mount(boot_device);
assert(vfs_mount(fat32_sb, "/boot", MS_RDONLY) == 0);
// Mount ext2 at /
struct superblock *ext2_sb = ext2_mount(root_device);
assert(vfs_mount(ext2_sb, "/", 0) == 0);
// Verify path lookup crosses mounts
struct dentry *boot_file = vfs_path_lookup("/boot/kernel.elf");
assert(boot_file != NULL);
assert(boot_file->d_sb == fat32_sb);
struct dentry *root_file = vfs_path_lookup("/bin/mosh");
assert(root_file != NULL);
assert(root_file->d_sb == ext2_sb);
// Unmount
assert(vfs_umount("/boot") == 0);
assert(vfs_umount("/") == 0);
}
Use Cases
Dual Partition Boot
void init_filesystems(void) {
// Mount boot partition (FAT32)
struct superblock *boot_sb = fat32_mount(boot_partition);
vfs_mount(boot_sb, "/boot", MS_RDONLY);
// Mount root partition (ext2)
struct superblock *root_sb = ext2_mount(root_partition);
vfs_mount(root_sb, "/", 0);
// Mount special filesystems
vfs_mount(devfs_mount(), "/dev", 0);
vfs_mount(tmpfs_mount(), "/tmp", 0);
vfs_mount(procfs_mount(), "/proc", MS_RDONLY);
}
Checking Mounts
$ cat /proc/mounts
/dev/sda1 /boot fat32 ro 0 0
/dev/sda2 / ext2 rw 0 0
devfs /dev devfs rw 0 0
tmpfs /tmp tmpfs rw 0 0
procfs /proc procfs ro 0 0
Files to Create/Modify
- src/kernel/fs/mount.c - Mount point management
- src/kernel/fs/vfs.c - Update path lookup for mounts
- src/kernel/syscalls/mount.c - Mount/umount syscalls
- src/kernel/proc/mounts.c - /proc/mounts implementation
- include/kernel/fs/mount.h - Mount API
- test/test_mount.c - Mount tests
Deliverables
- Mount point infrastructure
- Mount/umount operations
- Enhanced path lookup
- Mount syscalls
- /proc/mounts support
- Test suite
- Documentation
Performance Goals
- Mount/umount operations < 1ms
- Path lookup overhead minimal (1-2 extra checks)
- Minimal memory per mount point (~100 bytes)
Error Handling
- Prevent mount over non-directory
- Prevent mount over existing mount
- Prevent umount of busy filesystem
- Proper cleanup on mount failure
- Handle umount during active access
Security Considerations
- Check permissions on mount point
- Validate mount flags
- Prevent privilege escalation via mount
- Proper ownership of mounted files
Related Issues
- #228 - Dual partition mount (blocked by this)
- #65 - VFS layer ✅ COMPLETE
- Future: devfs, tmpfs, procfs mounting
Current Status
Ready to Start - VFS layer complete, can begin implementation