From 421cebff27c591fe6e7102334e7a02dec197af94 Mon Sep 17 00:00:00 2001
From: Marvin Borner
Date: Sun, 12 Sep 2021 17:00:09 +0200
Subject: Dynamic inode size detection using extensions

---
 kernel/features/fs.c | 50 +++++++++++++++++++++++++++++++++++---------------
 kernel/inc/fs.h      | 16 ++++++++++++++--
 2 files changed, 49 insertions(+), 17 deletions(-)

(limited to 'kernel')

diff --git a/kernel/features/fs.c b/kernel/features/fs.c
index 7902d56..145c47a 100644
--- a/kernel/features/fs.c
+++ b/kernel/features/fs.c
@@ -217,41 +217,63 @@ CLEAR void vfs_install(void)
  * EXT2
  */
 
-INLINE static void ext2_buffer_read(u32 block, void *buf, struct vfs_dev *dev)
+static void ext2_buffer_read(u32 block, void *buf, struct vfs_dev *dev)
 {
 	dev->read(buf, block * SECTOR_COUNT, SECTOR_COUNT, dev);
 }
 
-static void ext2_superblock(struct ext2_superblock *buf, struct vfs_dev *dev)
+static u8 ext2_verify(struct vfs_dev *dev)
 {
 	u8 data[BLOCK_SIZE] = { 0 };
 	ext2_buffer_read(EXT2_SUPER, data, dev);
-	memcpy(buf, data, sizeof(*buf));
+	struct ext2_superblock *sb = (struct ext2_superblock *)data;
+	return sb->magic == EXT2_MAGIC;
+}
+
+static struct ext2_superblock *ext2_superblock(struct vfs_dev *dev)
+{
+	struct ext2_superblock *sb;
 
-	assert(buf->magic == EXT2_MAGIC);
+	if (dev->vfs->data) {
+		sb = dev->vfs->data;
+	} else {
+		sb = malloc(BLOCK_SIZE); // TODO: Destroy malloced superblock?
+		ext2_buffer_read(EXT2_SUPER, sb, dev);
+		dev->vfs->data = sb;
+	}
+
+	assert(sb->magic == EXT2_MAGIC);
+	return sb;
+}
+
+static u32 ext2_inode_size(struct vfs_dev *dev)
+{
+	struct ext2_superblock *sb = ext2_superblock(dev);
+	if (sb->major_version == 1)
+		return sb->inode_size;
+	return 128; // Or 256?
 }
 
 static struct ext2_inode *ext2_inode(u32 i, struct ext2_inode *in_buf, struct vfs_dev *dev)
 {
-	struct ext2_superblock sb = { 0 };
-	ext2_superblock(&sb, dev);
+	struct ext2_superblock *sb = ext2_superblock(dev);
+	u32 inode_size = ext2_inode_size(dev);
 
 	u8 data[BLOCK_SIZE] = { 0 };
 	ext2_buffer_read(EXT2_SUPER + 1, data, dev);
 	struct ext2_bgd *bgd = (struct ext2_bgd *)data;
 
-	u32 block_group = (i - 1) / sb.inodes_per_group;
-	u32 index = (i - 1) % sb.inodes_per_group;
-	u32 block = (index * EXT2_INODE_SIZE) / BLOCK_SIZE;
+	u32 block_group = (i - 1) / sb->inodes_per_group;
+	u32 index = (i - 1) % sb->inodes_per_group;
+	u32 block = (index * inode_size) / BLOCK_SIZE;
 	bgd += block_group;
 
 	u8 buf[BLOCK_SIZE] = { 0 };
 	ext2_buffer_read(bgd->inode_table + block, buf, dev);
 	struct ext2_inode *in =
-		(struct ext2_inode *)((u32)buf +
-				      (index % (BLOCK_SIZE / EXT2_INODE_SIZE)) * EXT2_INODE_SIZE);
+		(struct ext2_inode *)((u32)buf + (index % (BLOCK_SIZE / inode_size)) * inode_size);
 
-	memcpy(in_buf, in, sizeof(*in_buf));
+	memcpy(in_buf, in, inode_size);
 
 	return in_buf;
 }
@@ -477,9 +499,7 @@ static res ext2_perm(const char *path, enum vfs_perm perm, struct vfs_dev *dev)
 
 CLEAR u8 ext2_load(struct vfs_dev *dev)
 {
-	struct ext2_superblock sb = { 0 };
-	ext2_superblock(&sb, dev);
-	if (sb.magic != EXT2_MAGIC)
+	if (!ext2_verify(dev))
 		return 0;
 
 	struct vfs *vfs = zalloc(sizeof(*vfs));
diff --git a/kernel/inc/fs.h b/kernel/inc/fs.h
index 04d3624..210f0c2 100644
--- a/kernel/inc/fs.h
+++ b/kernel/inc/fs.h
@@ -112,6 +112,20 @@ struct ext2_superblock {
 	u32 major_version;
 	u16 res_block_uid;
 	u16 res_block_gid;
+	// From here on only if major_version >=1
+	u32 first_inode;
+	u16 inode_size;
+	u16 block_group_number;
+	u32 compatible_features;
+	u32 incompatible_features;
+	u32 ro_compatible_features;
+	u8 uuid[16];
+	char volume_name[16];
+	char last_mounted_dir[64];
+	u32 algorithm_usage;
+	u8 preallocate_blocks;
+	u8 preallocate_dir_blocks;
+	u8 padding[50]; // idk? Doesn't really matter
 };
 
 struct ext2_bgd {
@@ -152,8 +166,6 @@ struct ext2_inode {
 	u8 extension[128]; // TODO: 2038 extension time support
 };
 
-#define EXT2_INODE_SIZE (sizeof(struct ext2_inode))
-
 struct ext2_dirent {
 	u32 inode_num;
 	u16 total_len;
-- 
cgit v1.2.3