/* 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);
/* ---- 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 */
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 */
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);
}