Project 4: s2fs (Super Simple File System)

  • Handed out: Wednesday, 4/30/2025

  • Due dates

    • 5/13/2025 11:59pm

Introduction

The goal of this project is to implement a simple virtual file system that can be used to access the information stored in task_struct of each process.

Part 1 to Part 3 are mandatory.

Part 4 is optional, no extra credit, just sweat, tears, and eternal bragging rights. Proceed at your own risk :)

Part 1. Print the Process Tree of Linux

Part 1.1. Implement a kernel module

[50 points] Linux kernel stores the information of a process in task_struct structure. A process can create zero or more processes called child process. Children of same process are called sibilings. task_struct stores this information using children and sibling pointer in task struct. The children and sibling pointer together form a tree called the process tree of the kernel. In Part 1, you have to iterate recursively from the root of the process tree to print the process tree in a hierarchical fashion (children of same parent should be at same indent level). Please submit you code as a tarball named s2fs_part_1.tar.gz and it should include a makefile to compile and load the kernel module.

Part 1.2. Test your code

[50 points] To test your code, load the kernel module and check the dmesg output. Compare your dmesg output with the output of pstree command. Upload a screen shot of 2 terminals, with left side terminal showing the output of your dmesg and the right side terminal showing the pstree command. Make sure to show the dmesg command and pstree command.

screenshots/proctree.png

Part 2: Mount and Unmount a Pseudo File system

A pseudo filesystem is not backed by disk but resides in memory and is usually used to provide information regarding the kernel to the user (e.g., /proc file system). In Part 2, you will need to create a minimal mountable prototype of a pseudo filesystem which we will name as s2fs. For this part, s2fs should mount and unmount on a mount point safely. Implementation of file operations is not required. Please read the following article to understand how to write a simple VFS using libfs.

The article is for Linux 2.6, so some of the API might have been renamed/removed but it is a good starting point for understanding how a pseudo filesystem is built, its inner workings, and what functionality is needed to be implemented for the current Linux kernel we are using. Understanding the full source code is highly recommended.

Part 2.1: Minimal Mountable Filesystem Prototype

[100 points] The following is a guide to make a minimal mountable filesystem prototype

Please note the above tutorial is for disk backed filesystem. Use the code in Part 2.1 and the above guide to implement a virtual filesystem prototype. You do not need to implement file operations. The file system is required to mount and unmount safely for full points.

Submit your code as a tarball named s2fs_part2.tar.gz. Include a makefile to compile, load and mount the kernel module. The filesystem will be mounted to a directory mnt in the current folder.

Part 2.2: Test Your Code

[100 points] To check whether you filesystem mounts successfully, use the following commands.


 $ mkdir mnt
 $ sudo insmod s2fs.ko # Inserting the filesystem kernel module
 $ sudo mount -t s2fs nodev mnt # Mount at dir mnt with option nodev
 $ mount # Print out all mounted file systems
 $ sudo umount ./mnt # Unmount the file system
 $ sudo rmmod s2fs.ko # Remove the kernel module

screenshots/mount_unmount.png

Add the screenshot of the output of mount command. If mount is successful, the command will show s2fs as a mounted file system.

Part 3: Implement File Operations

Now we will add inode and file operations to s2fs. In this part, upon mounting, s2fs will create a directory named foo and inside the directory it will create a file named bar. You can use code from Part 2.1.

Part 3.1: Function to create Inode with given mode

[50 points] Implement a function with prototype: static struct inode *s2fs_make_inode(struct super_block *sb, int mode);. The function accepts two inputs, the superblock of the filesystem and the mode which decides if the inode is for a directory or file and the permission bits. Make sure you set the i_ino field of inode to get_next_ino().

For submission: Please list the file name and line number of your implementation of the function static struct inode *s2fs_make_inode(struct super_block *sb, int mode); for grading.

Part 3.2: Function to create directory

[50 points] Next, implement a function to create a directory. The function prototype will be static struct dentry *s2fs_create_dir(struct super_block *sb, struct dentry *parent, const char *dir_name);

For submission: Please list the file name and line number of your implementation of the function static struct dentry *s2fs_create_dir(struct super_block *sb, struct dentry *parent, const char *dir_name); for grading.

Part 3.3: Functions to perform file operations

[50 points] To handle a file, the filesystem needs to know how to open, read and write a file. Implement three functions, s2fs_open, s2fs_read_file, and s2fs_write_file. In this project we will not use the open and the write function so it will just return 0. The read function should return “Hello World!” string to the user. Create a s2fs_fops of type file_operations and assign .read, .write and .open to the functions you have written.

For submission: Please list the file name and line number where you define s2fs_fops.

Part 3.4: Function to create file

[50 points] Implement a function: static struct dentry *s2fs_create_file(struct super_block *sb, struct dentry *dir, const char *file_name); This function should create a file with name stored in file_name inside directory pointed by dir dentry.

For submission: Please list the file name and line number of your implementation of the function static struct dentry *s2fs_create_file(struct super_block *sb, struct dentry *dir, const char *file_name); for grading.

Part 3.5: Putting it all together

[50 points] With all these implemented functions from earlier parts, Please modify the mounting procedure code such that after mounting:

  • The code will create a directory named foo in the root folder
  • Inside foo create a file named bar.
  • They can be created using the s2fs_create_dir and s2fs_create_file functions.

Submit a tarball with your code and makefile named s2fs_part3.tar.gz.

Part 3.6: Testing the code

[150 points] First mount the filesystem. Then change directory to foo. Then use cat bar to check if reading the file outputs Hello World!

 $ sudo insmod s2fs.ko
 $ sudo mount -t s2fs nodev mnt
 $ cd mnt/foo
 $ cat bar
 $ cd ../..
 $ sudo umount ./mnt
 $ sudo rmmod s2fs.ko

Add the screenshot of the above commands to your submission.

screenshots/foo_bar.png

Part 4: Use s2fs to get task information

In part 4, we will use part 1 and part 3 to display information related to process tasks.

Part 4.1: Creating files/directory corresponding to each PID

Part 4.1.1: Create files/directory on mounting

[100 points] Modify the part 3 code to create directories and files at mount time in a recursive manner as explained below for currently active tasks:

  • If a task has children
  • Create a folder with name being the pid of the task
  • Inside the created folder, create a file with the pid of the task
  • Recursively follow the rule for all children of the task
  • If a task has no children, create a file in it’s parent task’s folder

For example, if 0 has children 1, 2, 3 and 1 has children 4. Then the directory structure will look like as follows.

  0
  |--0
  |--1
  |  |--1
  |  |--4
  |--2
  |--3

For submission: Please list the file name and line number(s) of your implementation changes to support 4.1.1

Part 4.1.2: Testing Code

[100 points] Mount your file system and run tree command on the mount folder to see your resulting directory tree.

For submission: Add screen the screenshot showing you running this command, showing that you are able to create files/directories on your virtual file system.

Part 4.2: Reading a file with name X should give task info of PID X

For part 4.2, modify the functions s2fs_read_file and s2fs_open, so that when you read a file with name X it will output the task info specific to the task with PID X.

Part 4.2.1: Get Task Info

[100 points] Implement a function int get_task_info(int pid, char* data) which takes input:

  • an int pid
  • a char* buffer

and returns number of bytes written to the data buffer and also populates the task information into the data buffer. If the task does not exists, it should return -1 and nothing should be put into the data buffer. The information that should be written to the data buffer is:

  • Task Name
  • Task State
  • Process Id
  • CPU ID
  • Thead Group ID (TGID)
  • Parent’s PID (PPID)
  • Start Time
  • Dynamic Priority
  • Static Priority
  • Normal Priority
  • Real-time Priority
  • Memory Map Base
  • Virtual Memory Space
  • Virtual Memory Usage
  • No. of Virtual Memory Address
  • Total Pages Mapped

The data should be organized into the buffer with the title of data parameter (e.g., Task Name) and followed by the value. Each parameter should be separated by a new line.

Formatting should look like:

  Task Name: cycle
  Task State: RUNNING
  Process ID: 3423425
  CPU ID: 0
  etc... (for all remaining above parameters)

For submission: Please list the file name and line number(s) of your implementation changes to support 4.2.1

Part 4.2.2: Modify the inode creation file to store the PID

[100 points] Modify your code such that, when creating file for a task, it stores the PID in inode->i_private. Post a file name and line number where you assign inode->i_private.

Part 4.2.3: Modify the file open and read function

[100 points] Modify the s2fs_open function to get the pid from the file inode and store it in filp->private_data. Modify the s2fs_read_file function to call get_task_info and output the task information instead of Hello World.

If the task does not exists, output Task no longer exists.

Create a tarball named s2fs_part4.tar.gz of your code and include a Makefile.

Part 4.2.4: Test your code

[200 points] Add screenshot of following commands.


 $ mkdir mnt
 $ sudo insmod s2fs.ko # Inserting the filesystem kernel module
 $ sudo mount -t s2fs nodev mnt # Mount at dir mnt with option nodev
 $ mount # List all mounted file system
 $ cat mnt/0/1/1 # Print out task information of the systemd process
 $ sudo umount ./mnt # Unmount the file system
 $ sudo rmmod s2fs.ko # Remove the kernel module
 $ dmesg

Back to top

LKP: (Advanced) Linux Kernel Programming (Spring 2025) - Huaicheng Li