Skip to content

Novice06/vfs_simulator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

VFS Simulator

A Virtual File System Simulation for Hobby OS

This project is an educational implementation of a simple Virtual File System (VFS), It aims to simulate how operating systems abstract access to multiple file systems using a unified interface.

The core goals of this project are:

  • To mimic POSIX/Unix-like filesystem behavior.
  • To simulate a basic VFS layer that communicates with multiple backend filesystems.
  • To support mountable in-memory filesystems (RAMFS) for testing purpose.
  • To prepare the architecture for future integration of real disk-based filesystems (e.g., FAT12).

The system introduces basic device abstraction, enabling virtual devices (like RAMFS or .img files) to be mounted and accessed via a common interface. This setup is ideal for experimentation and portability in hobby OS development.

the test

Design Philosophy Inspired by Kleiman’s Vnode Architecture

This VFS simulation project is inspired by the design principles outlined in Kleiman’s Vnode Paper (1986). The goal was to implement a modular and Unix-like virtual file system architecture that separates file system-independent logic (VFS layer) from file system-specific implementations (FS layer), following the vnode abstraction model.

According to my understanding of the Vnode Paper, the responsibility for managing vnode object such as creation, deletion, and internal tracking lies with the file system-dependent code. The VFS layer itself does not directly manage vnode lifecycles; instead, it acts as a standardized interface that facilitates communication between user-level requests and the underlying file systems.

┌─────────────────────┐
│    User Interface   │
└─────────┬───────────┘
          │
┌─────────▼───────────┐
│      VFS Layer      │
└─────────┬───────────┘
          │
┌─────────▼───────────┐
│   Device Abstraction│
└──┬──────────┬───────┘
   │          │
┌──▼──┐    ┌──▼──┐
│RAMFS│    │FAT12│  ...
└─────┘    └─────┘

Project Structure Overview

  • disks/
    This directory contains raw .img files representing virtual storage devices. These images are intended to simulate real-world file systems, such as FAT12.

  • device.c / device.h
    Provides the abstraction for handling all file systems as generic devices. This layer allows for clean separation and portability across different environments, especially useful in hobby OS development.

  • disk.c / disk.h
    Responsible for detecting virtual disk images and registering them as usable devices in the system. This module simulates physical disk detection and setup.

  • ramfs.c / ramfs.h
    Implements a RAM-based file system and acts as the file system-dependent driver. It handles vnode creation, lookup, and file operations for files stored in memory.

  • vfs.c / vfs.h
    This is the core Virtual File System layer. It abstracts interactions with various file systems, providing a unified interface for mounting, file access, and directory traversal, inspired by the Kleiman vnode architecture.

  • main.c
    A simple test driver. It initializes the system, mounts various file systems, and tests file operations like opening, reading, writing, and navigating file structures using the VFS interface.

Device Abstraction for Filesystem Integration

To maintain consistency and ensure that the code remains easily portable into a hobby OS (specifically, mine), I introduced the notion of devices into the design even though I don’t yet fully understand all the nuances.

This idea was inspired by its frequent presence in many OS codebases.
Since mounting a file system typically requires a device, I decided that anything related to a file system whether it's a real hardware device or an in-memory file system like ramfs would be treated uniformly as a device.

Virtual Disk Images and Future Filesystem Support

Inside the disks/ directory, I’ve added several .img files that simulate real storage devices. These are raw disk images preformatted with the FAT12 file system.
Thanks to device abstraction, these images are treated just like any other device.
The next step of this simulation will be to implement support for reading and writing to these formatted images bringing the project closer to supporting real world file systems.

Program Lifecycle

As you can see in main.c, the program starts by detecting available disks through the call to disk_init().
This step simply registers all .img files in the disks/ directory as usable devices for testing purposes.

Next, the Virtual File System is initialized with vfs_init(), setting up its core data structures.
Afterward, supported filesystems are registered (currently FAT12 is included as an example).

Finally, the program runs some simple tests: mounting a device and attempting to read files from it using the VFS interface.
This provides a basic demonstration of how devices, filesystems, and the VFS layer interact.

Disks and Devices

In this project, a device represents anything that can be mounted or unmounted within the virtual file system.
For example, even an in-memory filesystem like RAMFS must be represented as a device in order to be mountable.
Inside ramfs.c, the function ramfs_init() creates RAM-based filesystems and registers them as devices.

A disk, on the other hand, is simply an abstraction of a .img file treated as a physical disk.
These disk images are formatted with real filesystems (currently FAT12) and exposed to the system.
You can check disk.h and disk.c to see how disks are represented via the disk_info structure, and how read/write operations are provided as function pointers when creating a device for a disk.

The VFS Layer

As mentioned earlier, the design of this VFS was inspired by Kleiman’s vnode paper, but it is not a direct implementation.
I only borrowed the core ideas and simplified them for the sake of testing.
Since my hobby OS is still in an early stage, I implemented only the minimum functionality needed to read from a disk.

For details on the data structures involved, you can refer to vfs.h, which defines the core structures and interfaces used by the VFS layer.

As previously mentioned, the responsibility for managing vnodes lies within the filesystem-dependent code rather than the VFS layer itself.

To illustrate this concept, you can take a look at the implementation of the FAT12 or RAMFS drivers.
For instance, in the FAT12 driver, the fat12_info structure (which stores filesystem-specific state and is assigned to the vfs_data field during mount) contains the following member:

vnode_t* total_vnode[MAX_VNODE_PER_VFS];

This array represents the maximum number of vnodes that can be created for a mounted filesystem instance. However, it also acts as a cache meaning that once a vnode is created for a given inode, it is reused rather than recreated, ensuring there is no redundancy in vnode allocation.

You can observe this behavior in the create_vnode() function inside the FAT12 driver. This function is responsible for creating a vnode corresponding to a given inode, but it first checks if a vnode for that inode already exists in the cache before allocating a new one.

About

Simulating a VFS based on the concepts from Kleiman’s vnode paper.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors