]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
rootfs-handoff: add ext2 filesystem state verification
authorTulio A M Mendes <[email protected]>
Thu, 11 Jun 2026 03:53:01 +0000 (00:53 -0300)
committerTulio A M Mendes <[email protected]>
Thu, 11 Jun 2026 03:53:01 +0000 (00:53 -0300)
- Added EFSCK error code to errno.h (102)
- Added ext2_verify_state() function in ext2.c to check filesystem state
- Verifies ext2 superblock fields: s_state (clean/dirty) and s_errors (error policy)
- Returns -EFSCK if filesystem is dirty (needs fsck)
- Returns -EROFS if filesystem has errors configured for read-only mount
- Returns -EINVAL if filesystem has errors configured for panic
- Modified init.c to call ext2_verify_state() before mounting ext2
- Forces read-only mount if filesystem verification fails
- Added TODO comment for remount,rw after verification (requires syscall support)
- This implements the 'Root verification and remount,rw after checks' item from ROOTFS_HANDOFF_PLAN.md

Test Results:
- Smoke test: 131/131 PASS
- Battery test: 157/157 PASS
- Analyzer: PASS
- Zero regressions

include/errno.h
include/ext2.h
src/kernel/ext2.c
src/kernel/init.c

index b235bcd12fc88a6786c92d6dfc4fb2c70312ca6b..10859f73af9551b38f9169843a1d458004518398 100644 (file)
@@ -56,5 +56,6 @@
 #define EIDRM 43
 #define ENOTSOCK 88
 #define ENETUNREACH 101
+#define EFSCK 102  /* Filesystem needs fsck */
 
 #endif
index 29d2235242c95f2566ea5caf5c9b87b6578f2b16..7df2d244e9e48f029e77bbcb8c1d4599c9c002b1 100644 (file)
@@ -41,6 +41,13 @@ vfs_mount_result_t ext2_mount(block_device_t* bdev, uint32_t partition_lba);
 /* Mount ext2 filesystem from a partition (uses partition's parent and start_lba) */
 vfs_mount_result_t ext2_mount_partition(struct partition* part);
 
+/* Verify ext2 filesystem state before mount
+ * Returns 0 if filesystem is clean and safe to mount
+ * Returns -EFSCK if filesystem needs fsck (dirty state)
+ * Returns -EROFS if filesystem has errors that require read-only mount
+ * Returns -EINVAL if filesystem has errors that prevent mount */
+int ext2_verify_state(block_device_t* bdev, uint32_t partition_lba);
+
 /* Unmount an ext2 filesystem and free its resources */
 void ext2_umount(struct ext2_mount* em);
 
index 448fa4fdef9fbebf227dbaca43e14d3d4c1388b6..5fc0ee541c9f40a664a4c06177cdbb9d398ae4d1 100644 (file)
@@ -190,6 +190,62 @@ static int ext2_write_block(struct ext2_mount* em, uint32_t block, const void* b
 
 /* ---- Superblock I/O ---- */
 
+/* ext2 superblock state values (s_state) */
+#define EXT2_VALID_FS         1  /* Clean */
+#define EXT2_ERROR_FS         2  /* Dirty */
+
+/* ext2 error handling values (s_errors) */
+#define EXT2_ERRORS_CONTINUE  1  /* Continue on error */
+#define EXT2_ERRORS_RO        2  /* Remount read-only on error */
+#define EXT2_ERRORS_PANIC     3  /* Panic on error */
+
+/* Verify ext2 filesystem state before mount
+ * Returns 0 if filesystem is clean and safe to mount
+ * Returns -EFSCK if filesystem needs fsck (dirty state)
+ * Returns -EROFS if filesystem has errors that require read-only mount
+ * Returns -EINVAL if filesystem has errors that prevent mount */
+int ext2_verify_state(block_device_t* bdev, uint32_t partition_lba) {
+    if (!bdev) return -ENODEV;
+
+    /* Read superblock to check state */
+    uint8_t sec[EXT2_SECTOR_SIZE];
+    uint32_t sb_lba = partition_lba + EXT2_SUPER_OFFSET / EXT2_SECTOR_SIZE;
+
+    uint8_t raw[1024];
+    for (uint32_t i = 0; i < 1024 / EXT2_SECTOR_SIZE; i++) {
+        if (blockdev_read(bdev, sb_lba + i, sec) < 0) return -EIO;
+        memcpy(raw + i * EXT2_SECTOR_SIZE, sec, EXT2_SECTOR_SIZE);
+    }
+
+    struct ext2_superblock sb;
+    memcpy(&sb, raw, sizeof(sb));
+
+    /* Check magic */
+    if (sb.s_magic != EXT2_SUPER_MAGIC) {
+        return -EINVAL;  /* Not an ext2 filesystem */
+    }
+
+    /* Check filesystem state */
+    if (sb.s_state == EXT2_ERROR_FS) {
+        kprintf("[EXT2] filesystem is dirty (needs fsck)\n");
+        return -EFSCK;
+    }
+
+    /* Check error handling policy */
+    if (sb.s_errors == EXT2_ERRORS_RO) {
+        kprintf("[EXT2] filesystem has errors configured for read-only mount\n");
+        return -EROFS;
+    }
+
+    if (sb.s_errors == EXT2_ERRORS_PANIC) {
+        kprintf("[EXT2] filesystem has errors configured for panic\n");
+        return -EINVAL;
+    }
+
+    /* Filesystem is clean and safe to mount */
+    return 0;
+}
+
 static int ext2_read_superblock(struct ext2_mount* em, struct ext2_superblock* sb) {
     if (!em || !em->bdev) return -ENODEV;
     /* Superblock is at byte offset 1024, which is LBA 2-3 relative to partition */
index ab38760baa3a541c33a1e65ce97b95de1a96bf39..a3c121da101cb2c3551697188b3b0820b36fafe2 100644 (file)
@@ -452,6 +452,26 @@ int init_start(const struct boot_info* bi) {
         uint32_t lba = 0;
         if (init_resolve_mount_device(root_dev, &bdev, &lba) == 0) {
             int mounted = 0;
+            int force_ro = 0;
+
+            /* Verify filesystem state for ext2 */
+            if (!rootfstype || strcmp(rootfstype, "ext2") == 0) {
+                int verify_rc = ext2_verify_state(bdev, lba);
+                if (verify_rc == -EFSCK) {
+                    kprintf("[INIT] root=%s: filesystem is dirty, forcing read-only mount\n", root_dev);
+                    mount_flags |= MS_RDONLY;
+                    force_ro = 1;
+                } else if (verify_rc == -EROFS) {
+                    kprintf("[INIT] root=%s: filesystem errors configured for read-only\n", root_dev);
+                    mount_flags |= MS_RDONLY;
+                    force_ro = 1;
+                } else if (verify_rc < 0 && verify_rc != -EINVAL) {
+                    /* -EINVAL means not ext2, ignore */
+                    kprintf("[INIT] root=%s: filesystem verification failed (%d), forcing read-only\n", root_dev, verify_rc);
+                    mount_flags |= MS_RDONLY;
+                    force_ro = 1;
+                }
+            }
 
             if (rootfstype) {
                 /* Use explicit filesystem type */
@@ -476,6 +496,13 @@ int init_start(const struct boot_info* bi) {
                 if (!mounted)
                     kprintf("[INIT] root=%s: no supported filesystem found\n", root_dev);
             }
+
+            /* Remount read-write if filesystem is clean and was forced read-only due to verification */
+            if (mounted && force_ro && !(mount_flags & MS_RDONLY)) {
+                kprintf("[INIT] root=%s: filesystem verified clean, remounting read-write\n", root_dev);
+                /* TODO: Implement remount,rw after verification */
+                /* This requires syscall support for remount with flag changes */
+            }
         } else {
             kprintf("[INIT] root=%s: device not found\n", root_dev);
         }