diff --git a/rust/helpers.c b/rust/helpers.c
index f2ce3e7b688c..af335d1912e7 100644
--- a/rust/helpers.c
+++ b/rust/helpers.c
@@ -244,6 +244,12 @@ void rust_helper_mapping_set_large_folios(struct address_space *mapping)
 }
 EXPORT_SYMBOL_GPL(rust_helper_mapping_set_large_folios);
 
+unsigned int rust_helper_MKDEV(unsigned int major, unsigned int minor)
+{
+	return MKDEV(major, minor);
+}
+EXPORT_SYMBOL_GPL(rust_helper_MKDEV);
+
 /*
  * `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can
  * use it in contexts where Rust expects a `usize` like slice (array) indices.
diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs
index 8f34da50e694..5b7eaa16d254 100644
--- a/rust/kernel/fs.rs
+++ b/rust/kernel/fs.rs
@@ -112,8 +112,13 @@ pub enum DirEntryType {
 impl From<INodeType> for DirEntryType {
     fn from(value: INodeType) -> Self {
         match value {
+            INodeType::Fifo => DirEntryType::Fifo,
+            INodeType::Chr(_, _) => DirEntryType::Chr,
             INodeType::Dir => DirEntryType::Dir,
+            INodeType::Blk(_, _) => DirEntryType::Blk,
             INodeType::Reg => DirEntryType::Reg,
+            INodeType::Lnk => DirEntryType::Lnk,
+            INodeType::Sock => DirEntryType::Sock,
         }
     }
 }
@@ -281,6 +286,46 @@ pub fn init(self, params: INodeParams) -> Result<ARef<INode<T>>> {
                 unsafe { bindings::mapping_set_large_folios(inode.i_mapping) };
                 bindings::S_IFREG
             }
+            INodeType::Lnk => {
+                inode.i_op = &Tables::<T>::LNK_INODE_OPERATIONS;
+                inode.i_data.a_ops = &Tables::<T>::FILE_ADDRESS_SPACE_OPERATIONS;
+
+                // SAFETY: `inode` is valid for write as it's a new inode.
+                unsafe { bindings::inode_nohighmem(inode) };
+                bindings::S_IFLNK
+            }
+            INodeType::Fifo => {
+                // SAFETY: `inode` is valid for write as it's a new inode.
+                unsafe { bindings::init_special_inode(inode, bindings::S_IFIFO as _, 0) };
+                bindings::S_IFIFO
+            }
+            INodeType::Sock => {
+                // SAFETY: `inode` is valid for write as it's a new inode.
+                unsafe { bindings::init_special_inode(inode, bindings::S_IFSOCK as _, 0) };
+                bindings::S_IFSOCK
+            }
+            INodeType::Chr(major, minor) => {
+                // SAFETY: `inode` is valid for write as it's a new inode.
+                unsafe {
+                    bindings::init_special_inode(
+                        inode,
+                        bindings::S_IFCHR as _,
+                        bindings::MKDEV(major, minor & bindings::MINORMASK),
+                    )
+                };
+                bindings::S_IFCHR
+            }
+            INodeType::Blk(major, minor) => {
+                // SAFETY: `inode` is valid for write as it's a new inode.
+                unsafe {
+                    bindings::init_special_inode(
+                        inode,
+                        bindings::S_IFBLK as _,
+                        bindings::MKDEV(major, minor & bindings::MINORMASK),
+                    )
+                };
+                bindings::S_IFBLK
+            }
         };
 
         inode.i_mode = (params.mode & 0o777) | u16::try_from(mode)?;
@@ -315,11 +360,26 @@ fn drop(&mut self) {
 /// The type of the inode.
 #[derive(Copy, Clone)]
 pub enum INodeType {
+    /// Named pipe (first-in, first-out) type.
+    Fifo,
+
+    /// Character device type.
+    Chr(u32, u32),
+
     /// Directory type.
     Dir,
 
+    /// Block device type.
+    Blk(u32, u32),
+
     /// Regular file type.
     Reg,
+
+    /// Symbolic link type.
+    Lnk,
+
+    /// Named unix-domain socket type.
+    Sock,
 }
 
 /// Required inode parameters.
@@ -701,6 +761,34 @@ extern "C" fn lookup_callback(
         }
     }
 
+    const LNK_INODE_OPERATIONS: bindings::inode_operations = bindings::inode_operations {
+        lookup: None,
+        get_link: Some(bindings::page_get_link),
+        permission: None,
+        get_inode_acl: None,
+        readlink: None,
+        create: None,
+        link: None,
+        unlink: None,
+        symlink: None,
+        mkdir: None,
+        rmdir: None,
+        mknod: None,
+        rename: None,
+        setattr: None,
+        getattr: None,
+        listxattr: None,
+        fiemap: None,
+        update_time: None,
+        atomic_open: None,
+        tmpfile: None,
+        get_acl: None,
+        set_acl: None,
+        fileattr_set: None,
+        fileattr_get: None,
+        get_offset_ctx: None,
+    };
+
     const FILE_ADDRESS_SPACE_OPERATIONS: bindings::address_space_operations =
         bindings::address_space_operations {
             writepage: None,
diff --git a/samples/rust/rust_rofs.rs b/samples/rust/rust_rofs.rs
index ef651ad38185..95ce28efa1c3 100644
--- a/samples/rust/rust_rofs.rs
+++ b/samples/rust/rust_rofs.rs
@@ -23,7 +23,7 @@ struct Entry {
     contents: &'static [u8],
 }
 
-const ENTRIES: [Entry; 3] = [
+const ENTRIES: [Entry; 4] = [
     Entry {
         name: b".",
         ino: 1,
@@ -42,6 +42,12 @@ struct Entry {
         etype: INodeType::Reg,
         contents: b"hello\n",
     },
+    Entry {
+        name: b"link.txt",
+        ino: 3,
+        etype: INodeType::Lnk,
+        contents: b"./test.txt",
+    },
 ];
 
 struct RoFs;
@@ -125,6 +131,7 @@ fn lookup(parent: &INode<Self>, name: &[u8]) -> Result<ARef<INode<Self>>> {
     fn read_folio(inode: &INode<Self>, mut folio: LockedFolio<'_>) -> Result {
         let data = match inode.ino() {
             2 => ENTRIES[2].contents,
+            3 => ENTRIES[3].contents,
             _ => return Err(EINVAL),
         };
 
