Add ext2 VFS implementation
diff --git a/src/kernel/dri/fs/ext2/ext2.c b/src/kernel/dri/fs/ext2/ext2.c
index 9ecbe51..9952948 100644
--- a/src/kernel/dri/fs/ext2/ext2.c
+++ b/src/kernel/dri/fs/ext2/ext2.c
@@ -19,11 +19,6 @@
 };
 #undef F
 
-inline uint ext2_block_size(struct ext2_superblock *sb)
-{
-	return 1024 << sb->block_size_shift;
-}
-
 void ext2_read_block(struct ext2_superblock *sb, void *buffer, uint block)
 {
 	uint block_size = ext2_block_size(sb) / 512;
@@ -68,9 +63,26 @@
 	}
 }
 
-struct ext2_block_group_descriptor ext2_load_block_group_descriptor(
+void ext2_write_bgd(struct ext2_superblock *sb, uint block_group,
+					struct ext2_block_group_descriptor *d)
+{
+	ext2_load_or_write_bgd(sb, block_group, d, true);
+}
+
+struct ext2_block_group_descriptor ext2_load_bgd(
 	struct ext2_superblock *sb, uint block_group)
 {
+	struct ext2_block_group_descriptor bgd;
+	ext2_load_or_write_bgd(sb, block_group, &bgd, false);
+
+	return bgd;
+}
+
+void ext2_load_or_write_bgd(struct ext2_superblock *sb,
+							uint block_group,
+							struct ext2_block_group_descriptor *d,
+							bool set)
+{
 	/**
 	 * The BGDT (not to be confused with the GDT) is located the block after the
 	 * superblock. On any block size EXCEPT 1024 (the minimum, remember that the
@@ -95,9 +107,17 @@
 
 	uint lba = (block_size / 512) * bgdt_block + hd_page;
 
-	ata_pio_read_sectors(&descriptors, lba, 1);
+	ata_pio_read_sectors(descriptors, lba, 1);
 
-	return descriptors[bgd_offset];
+	if (set)
+	{
+		descriptors[bgd_offset] = *d;
+		ata_pio_write_sectors(lba, 1, (ushort *)descriptors);
+	}
+	else
+	{
+		*d = descriptors[bgd_offset];
+	}
 }
 
 static bool print_entry(uint inode, const char *name, uint l, void *sb)
@@ -194,7 +214,7 @@
 
 	// Load this from the block group descriptor table
 	struct ext2_block_group_descriptor descriptor =
-		ext2_load_block_group_descriptor(sb, block_group);
+		ext2_load_bgd(sb, block_group);
 
 	// We need to figure out what FS block the inode is on, we know how many
 	// inodes there are total in this BGD and the number per page, so this is
@@ -579,7 +599,7 @@
 	for (int bg_num = 0; bg_num < num_block_groups; bg_num++)
 	{
 		struct ext2_block_group_descriptor bgd =
-			ext2_load_block_group_descriptor(sb, 0);
+			ext2_load_bgd(sb, 0);
 
 		const uint block_size = ext2_block_size(sb);
 		// + 1 because we need to round up (ie 1025 for 1024 size blocks will
@@ -609,7 +629,7 @@
 	for (int bg_num = 0; bg_num < num_block_groups; bg_num++)
 	{
 		struct ext2_block_group_descriptor bgd =
-			ext2_load_block_group_descriptor(sb, 0);
+			ext2_load_bgd(sb, 0);
 
 		const uint block_size = ext2_block_size(sb);
 		// + 1 because we need to round up (ie 1025 for 1024 size blocks will
@@ -706,3 +726,25 @@
 
 	return d.inode;
 }
+
+uint ext2_alloc_new_block(struct ext2_superblock *sb,
+						  uint block_group)
+{
+	struct ext2_block_group_descriptor bgd =
+		ext2_load_bgd(sb, block_group);
+
+	if (bgd.unallocated_blocks == 0)
+		// TODO: handle out of blocks
+		return ext2_alloc_new_block(sb, block_group + 1);
+
+	// We can safely pass ~0 here as long as the FS is well formed
+	// because we know there is at least 1 free block
+	uint block = ext2_first_zero_bit(sb, bgd.block_bitmap, ~0, 0);
+
+	ext2_set_in_bitmap(sb, bgd.block_bitmap, block, true);
+	bgd.unallocated_blocks--;
+
+	ext2_write_bgd(sb, block_group, &bgd);
+
+	return block;
+}