Add EXT2 insert into dirent
diff --git a/include/kernel/dri/fs/ext2/ext2.h b/include/kernel/dri/fs/ext2/ext2.h
index 87191b1..df2b0fe 100644
--- a/include/kernel/dri/fs/ext2/ext2.h
+++ b/include/kernel/dri/fs/ext2/ext2.h
@@ -246,6 +246,18 @@
char name[];
};
+enum
+{
+ EXT2_FT_UNKNOWN = 0,
+ EXT2_FT_REGULAR_FILE,
+ EXT2_FT_DIR,
+ EXT2_FT_CHRDEV,
+ EXT2_FT_BLKDEV,
+ EXT2_FT_FIFO,
+ EXT2_FT_SOCK,
+ EXT2_FT_SYMLINK,
+};
+
/// Read a file system block (0-indexed), if necessary multiple disk blocks
/// will be read automatically
void ext2_read_block(struct ext2_superblock *sb, void *buffer, uint block);
@@ -255,7 +267,7 @@
void ext2_write_superblock(struct ext2_superblock *sb);
-// Just for fun, corrupt the superblock (obviously don't actually do this)
+/// Just for fun, corrupt the superblock (obviously don't actually do this)
void ext2_corrupt_superblock_for_fun();
void ext2_mount(struct fs_node *where);
@@ -283,6 +295,10 @@
void *buffer,
uint block);
+/// Write a data block for the inode, 0 being the first block of the file.
+bool ext2_write_inode_block(struct ext2_superblock *sb, struct ext2_inode *dir,
+ void *buffer, uint block);
+
ssize_t ext2_read_inode(struct ext2_superblock *sb, struct ext2_inode *inode, void *buffer, ssize_t size);
/**
@@ -317,4 +333,11 @@
uint ext2_first_zero_bit(struct ext2_superblock *sb, uint bitmap_block,
uint num_blocks, uint start_at);
+/**
+ * Find the first free inode number.
+ * @returns The inode if it was found, 0 if there are no free inodes.
+ */
uint ext2_first_free_inode(struct ext2_superblock *sb);
+
+void ext2_insert_into_dir(struct ext2_superblock *sb, struct ext2_inode *dir,
+ char *name, uint name_len, uint inode, uchar type);
diff --git a/include/kernel/kint.h b/include/kernel/kint.h
index 66f22b6..e3e12d7 100644
--- a/include/kernel/kint.h
+++ b/include/kernel/kint.h
@@ -21,5 +21,11 @@
#define MIN(a, b) ((a)>(b)?(b):(a))
#define MAX(a, b) ((a)>(b)?(a):(b))
+/// Pads num to an integer size boundary
+#define PAD(num) ((num + 3) & (~0b11))
+
+/// Perform integer division and round up
+#define IDIV_CEIL(num, den) (((num) + ((den) - 1)) / (den))
+
// Coerce into 1 or 0
#define BOOL(a) (!(!(a)))
diff --git a/src/kernel/Jmk b/src/kernel/Jmk
index 93af5fc..4b78fbb 100644
--- a/src/kernel/Jmk
+++ b/src/kernel/Jmk
@@ -29,7 +29,7 @@
LDFLAGS += -Tlink.ld -melf_i386
ASMFLAGS += -felf -Fdwarf
-QEMUFLAGS = -hda hd0_ext2.img
+QEMUFLAGS = -drive file=hd0_ext2.img,format=raw
OBJECTS = boot.o \
main.o \
@@ -80,6 +80,14 @@
fs-info: hd0_$(FS).img
tune2fs -l $< | grep -i inode
+reset-fs:
+ @rm hd0_ext2.img
+ @$(MAKE) hd0_ext2.img
+ @sudo $(MAKE) mount
+ @echo 'hi' | sudo tee $(ROOT)/mnt/hello.txt
+ @sudo $(MAKE) umount
+ @$(MAKE) qemu
+
qemu: kernel.elf hd0_$(FS).img
qemu-system-i386 $(QEMUFLAGS) -d cpu_reset -monitor stdio -kernel kernel.elf -no-reboot
@@ -91,7 +99,6 @@
mount: hd0_$(FS).img
status_log(MOUNT, $^ $(ROOT)/mnt)
- @if [ "$(whoami)" = root ]; then echo "DON'T RUN THIS AS ROOT" && exit 1; fi
@mkdir -p $(ROOT)/mnt
@mount $^ $(ROOT)/mnt
diff --git a/src/kernel/dri/fs/ext2/ext2.c b/src/kernel/dri/fs/ext2/ext2.c
index 78dd24e..1ac52b9 100644
--- a/src/kernel/dri/fs/ext2/ext2.c
+++ b/src/kernel/dri/fs/ext2/ext2.c
@@ -38,8 +38,8 @@
uint ext2_num_block_groups(struct ext2_superblock *sb)
{
// This is a mildly janky way of rounding up
- uint a = (sb->total_blocks - 1) / (sb->blocks_per_block_group + 1);
- uint b = (sb->total_inodes - 1) / (sb->inodes_per_block_group + 1);
+ uint a = IDIV_CEIL(sb->total_blocks, sb->blocks_per_block_group);
+ uint b = IDIV_CEIL(sb->total_inodes, sb->inodes_per_block_group);
if (a == b)
{
@@ -90,6 +90,8 @@
{
kprintf("%d\t %s\n", inode, name);
+ return;
+
struct ext2_inode in;
if (ext2_find_inode(sb, inode, &in))
@@ -124,6 +126,11 @@
kassert((root.mode & 0xf000) == EXT2_S_IFDIR,
"Root (inode 2) is not a directory.");
+ char *name = "hello-hl.txt";
+ kprintf(INFO "Creating hard link %s -> hello.txt\n", name);
+ ext2_insert_into_dir(&sb, &root, name, strlen(name), 12,
+ EXT2_FT_REGULAR_FILE);
+
kprintf("ls /\n");
kprintf("inode\t name\n");
kprintf("--------------------\n");
@@ -220,11 +227,13 @@
if (cb)
{
- char name[257];
+ char name[256];
+ uint name_len = MIN(ent->name_len, 255);
- memcpy(name, ent->name, ent->name_len);
- name[ent->name_len] = '\0';
+ memcpy(name, ent->name, name_len);
+ name[name_len] = '\0';
+ // kprintf("@ b=%d,ent=%p\n", i, (uint)ent - (uint)buffer);
cb(ent->inode, name, data);
}
@@ -237,6 +246,103 @@
return true;
}
+static void ext2_show_dirent(struct ext2_dirent *ent)
+{
+ char name[ent->name_len + 1];
+ memcpy(name, ent->name, ent->name_len);
+ name[ent->name_len] = '\0';
+
+ kprintf(DEBUG "<ent ft=%p, i=%d, s=%s, l=%d>\n", ent->file_type, ent->inode,
+ ent->name, ent->rec_len);
+}
+
+void ext2_insert_into_dir(struct ext2_superblock *sb, struct ext2_inode *dir,
+ char *name, uint name_len, uint inode, uchar type)
+{
+ name_len = MIN(name_len, 255);
+ const uint min_size = PAD(name_len + sizeof(struct ext2_dirent));
+ const uint block_size = ext2_block_size(sb);
+
+ if ((dir->mode & 0xf000) != EXT2_S_IFDIR)
+ return;
+
+ uchar buffer[block_size];
+ uint i; // block #
+
+ for (i = 0; i < dir->num_blocks; i++)
+ {
+ ext2_read_inode_block(sb, dir, buffer, i);
+
+ struct ext2_dirent *ent = (void *)buffer;
+
+ // While there are files in this block
+ while ((uint)ent < (uint)(buffer + block_size))
+ {
+ // kprintf(" %d@%db,%d-%d", ent->inode, i, (uint)ent - (uint)buffer,
+ // ent->rec_len);
+ if (ent->inode == 0)
+ {
+ // This is the last item, just insert it at the end
+ // TODO: check this actually fits!
+ // TODO: if we are in a new block, actually create it!
+
+ ent->rec_len = min_size;
+ ent->name_len = name_len;
+ memcpy(ent->name, name, name_len);
+ ent->inode = inode;
+ ent->file_type = type;
+
+ kprintf(DEBUG
+ "Inserted into dir (appending) at block=%d, b=%p \n",
+ i, (uint)ent - (uint)buffer);
+
+ goto finish;
+ }
+
+ uint this_min_size =
+ PAD(ent->name_len + sizeof(struct ext2_dirent));
+ uint available_size = ent->rec_len - this_min_size;
+
+ // kprintf(",%d=%d/%d", ent->name_len, this_min_size, available_size);
+
+ if (available_size >= min_size)
+ {
+ // We can fit this in here
+ struct ext2_dirent *inserting =
+ (void *)(((uint)(void *)ent) + this_min_size);
+
+ ent->rec_len = this_min_size;
+
+ inserting->rec_len = available_size;
+ inserting->name_len = name_len;
+ inserting->inode = inode;
+ inserting->file_type = type;
+ memcpy(inserting->name, name, name_len);
+
+ kprintf(DEBUG
+ "Inserted into dir (splicing) at block=%d, b=%p \n",
+ i, (uint)inserting - (uint)buffer);
+
+ // Done!
+ goto finish;
+ }
+
+ ent = (void *)(((uint)(void *)ent) + ent->rec_len);
+ }
+ // We ran out of files in this block, continue to the next one. This
+ // works because files cannot span blocks
+ }
+
+ kprintf("\n");
+
+ kprintf(WARN "Failed to insert!\n");
+
+finish:
+ kprintf("\n");
+ ext2_write_inode_block(sb, dir, buffer, i);
+ kprintf(DEBUG "[insert] writing inode block %d\n", i);
+}
+
ssize_t ext2_read_inode(struct ext2_superblock *sb, struct ext2_inode *inode,
void *buffer, ssize_t size)
{
@@ -265,8 +371,8 @@
return fsize;
}
-bool ext2_read_inode_block(struct ext2_superblock *sb, struct ext2_inode *inode,
- void *buffer, uint block)
+static uint ext2_compute_absolute_block(struct ext2_superblock *sb,
+ struct ext2_inode *inode, uint block)
{
if (block >= 12)
{
@@ -276,6 +382,13 @@
kpanic("Invalid inode block");
}
+ return block;
+}
+
+bool ext2_read_inode_block(struct ext2_superblock *sb, struct ext2_inode *inode,
+ void *buffer, uint block)
+{
+ block = ext2_compute_absolute_block(sb, inode, block);
uint block_address = inode->blocks[block];
ext2_read_block(sb, buffer, block_address);
@@ -283,6 +396,20 @@
return true;
}
+bool ext2_write_inode_block(struct ext2_superblock *sb, struct ext2_inode *dir,
+ void *buffer, uint block)
+{
+ block = ext2_compute_absolute_block(sb, dir, block);
+ uint block_address = dir->blocks[block];
+
+ kprintf(DEBUG "Writing size=%d, inode block %p, b=%d\n",
+ ext2_block_size(sb), block_address * ext2_block_size(sb), block);
+
+ ext2_write_block(sb, buffer, block_address);
+
+ return true;
+}
+
static const uint ext2_bitmap_block(struct ext2_superblock *sb,
uint *bitmap_block, uint *index)
{
@@ -354,9 +481,6 @@
uint index =
(4 * 8 * i) + (block - bitmap_block) * 8 * block_size;
- kprintf(DEBUG "buffer[i] = 0x%x, i = %d, index = %d\n",
- buffer[i], i, index);
-
// __builtin_ffs gives us 1+the index of the least-significant 1
// bit. Since we take the bitwise inverse this is actuall the
// least significant 0 bit. This is a GCC intrinsic. This works
@@ -371,8 +495,6 @@
// This means that the LSB is also the first bit in the bitset.
uint trailing = __builtin_ffs(~buffer[i]) - 1;
- kprintf(DEBUG "Trailing = %d, 0x%x\n", trailing, trailing);
-
return trailing + index;
}
}
@@ -383,23 +505,58 @@
uint ext2_first_free_inode(struct ext2_superblock *sb)
{
- // For now just check the first block group
- struct ext2_block_group_descriptor bgd =
- ext2_load_block_group_descriptor(sb, 0);
+ uint num_block_groups = ext2_num_block_groups(sb);
- const uint block_size = ext2_block_size(sb);
- // + 1 because we need to round up (ie 1025 for 1024 size blocks will yield
- // 1, should 2)
- uint bitset_blocks = (sb->inodes_per_block_group / 8) / block_size + 1;
+ kprintf(INFO "%d block groups\n", num_block_groups);
- // inodes start at 1
- uint inode = ext2_first_zero_bit(sb, bgd.inode_bitmap, bitset_blocks, 12) + 1;
- // This will overflow back to zero if no inode was found
-
- if (!inode)
+ for (int bg_num = 0; bg_num < num_block_groups; bg_num++)
{
- kpanic("No inodes left in first block group, FIXME");
+ struct ext2_block_group_descriptor bgd =
+ ext2_load_block_group_descriptor(sb, 0);
+
+ const uint block_size = ext2_block_size(sb);
+ // + 1 because we need to round up (ie 1025 for 1024 size blocks will
+ // yield 1, should 2)
+ uint bitset_blocks = (sb->inodes_per_block_group / 8) / block_size + 1;
+
+ // inodes start at 1
+ uint inode =
+ ext2_first_zero_bit(sb, bgd.inode_bitmap, bitset_blocks, 12) + 1;
+ // This will overflow back to zero if no inode was found
+
+ if (inode)
+ return inode;
}
- return inode;
+ return 0;
+}
+
+// ^
+// | this and | this are awfully similar, should refactor
+// v
+
+uint ext2_first_free_block(struct ext2_superblock *sb)
+{
+ uint num_block_groups = ext2_num_block_groups(sb);
+
+ 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);
+
+ const uint block_size = ext2_block_size(sb);
+ // + 1 because we need to round up (ie 1025 for 1024 size blocks will
+ // yield 1, should 2)
+ uint bitset_blocks = (sb->blocks_per_block_group / 8) / block_size + 1;
+
+ // inodes start at 1
+ uint block_no =
+ ext2_first_zero_bit(sb, bgd.block_bitmap, bitset_blocks, 0);
+ // This will overflow back to zero if no inode was found
+
+ if (block_no != 0xffffffff)
+ return block_no;
+ }
+
+ return 0;
}
diff --git a/src/kernel/log.c b/src/kernel/log.c
index ff22727..0ea6822 100644
--- a/src/kernel/log.c
+++ b/src/kernel/log.c
@@ -22,10 +22,17 @@
break;
}
+ case 'p':
+ vga_put('0');
+ vga_put('x');
+
case 'x': {
// consider hex always unsigned
uint x = (uint)va_arg(args, uint);
- vga_putx(x);
+ if (x)
+ vga_putx(x);
+ else
+ vga_put('0');
break;
}
diff --git a/src/kernel/sync.c b/src/kernel/sync.c
index 0db5022..4b210ca 100644
--- a/src/kernel/sync.c
+++ b/src/kernel/sync.c
@@ -70,14 +70,14 @@
{
// Add this task to the waiting list
// This will be quick, so just use a spinlock
- sl_acquire(sm->task_lock);
+ sl_acquire(&sm->task_lock);
kprintf(INFO "Semaphore waiting\n");
struct sm_task *task = malloc(sizeof(struct sm_task));
task->next = NULL;
- task->tid = task_id();
+ task->tid = get_task_id();
if (sm->last)
{
@@ -89,9 +89,9 @@
sm->last = sm->first = task;
}
- sl_release(sm->task_lock);
+ sl_release(&sm->task_lock);
- set_waiting(task_id(), true);
+ set_waiting(get_task_id(), true);
sys_giveup();
}
@@ -104,7 +104,7 @@
if (sm->sm <= 0)
{
- sl_acquire(sm->task_lock);
+ sl_acquire(&sm->task_lock);
if (sm->first)
{
@@ -116,7 +116,7 @@
free(f);
}
- sl_release(sm->task_lock);
+ sl_release(&sm->task_lock);
}
}
diff --git a/src/kernel/vga.c b/src/kernel/vga.c
index 394d9c8..d77313c 100644
--- a/src/kernel/vga.c
+++ b/src/kernel/vga.c
@@ -185,10 +185,9 @@
static bool vga_put_nibble(uchar n, bool first)
{
- // if (first && n == 0)
- // return true;
-
- if (n <= 9)
+ if (first && n == 0)
+ return true;
+ else if (n <= 9)
vga_put('0' + n);
else
vga_put('A' + n - 10);
@@ -198,7 +197,7 @@
void vga_putx(uint x)
{
- bool first = false;
+ bool first = true;
for (int shift = 24; shift >= 0; shift -= 8)
{