~swisschili/bluejay

36ed5d7f662f7efea11816cc98d8eaefe21b21be — swissChili 9 months ago caa2478
Add EXT2 insert into dirent
M include/kernel/dri/fs/ext2/ext2.h => include/kernel/dri/fs/ext2/ext2.h +24 -1
@@ 246,6 246,18 @@ struct ext2_dirent
	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 @@ struct ext2_superblock ext2_read_superblock();

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 @@ bool ext2_read_inode_block(struct ext2_superblock *sb,
						   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 @@ void ext2_set_in_bitmap(struct ext2_superblock *sb, uint bitmap_block,
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);

M include/kernel/kint.h => include/kernel/kint.h +6 -0
@@ 21,5 21,11 @@ enum
#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)))

M src/kernel/Jmk => src/kernel/Jmk +9 -2
@@ 29,7 29,7 @@ CFLAGS += -I $(ROOT)/include/kernel $(test_defines) -O0

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 @@ hd0_%.img:
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 @@ scan_codes.c: gen_scan_codes.py scan_codes.tsv

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


M src/kernel/dri/fs/ext2/ext2.c => src/kernel/dri/fs/ext2/ext2.c +182 -25
@@ 38,8 38,8 @@ struct ext2_superblock ext2_read_superblock()
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 @@ static void print_entry(uint inode, const char *name, void *sb)
{
	kprintf("%d\t %s\n", inode, name);

	return;

	struct ext2_inode in;

	if (ext2_find_inode(sb, inode, &in))


@@ 124,6 126,11 @@ void ext2_mount(struct fs_node *where)
		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 @@ bool ext2_dir_ls(struct ext2_superblock *sb, struct ext2_inode *dir,

			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 @@ bool ext2_dir_ls(struct ext2_superblock *sb, struct ext2_inode *dir,
	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 @@ ssize_t ext2_read_inode(struct ext2_superblock *sb, struct ext2_inode *inode,
	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 @@ bool ext2_read_inode_block(struct ext2_superblock *sb, struct ext2_inode *inode,
		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 @@ bool ext2_read_inode_block(struct ext2_superblock *sb, struct ext2_inode *inode,
	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 ext2_first_zero_bit(struct ext2_superblock *sb, uint bitmap_block,
				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 @@ uint ext2_first_zero_bit(struct ext2_superblock *sb, uint bitmap_block,
				// 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_zero_bit(struct ext2_superblock *sb, uint bitmap_block,

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);

	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);

	// 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
		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;

	if (!inode)
		// 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 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++)
	{
		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->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 inode;
	return 0;
}

M src/kernel/log.c => src/kernel/log.c +8 -1
@@ 22,10 22,17 @@ void kprintf(const char *format, ...)
				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;
			}


M src/kernel/sync.c => src/kernel/sync.c +6 -6
@@ 70,14 70,14 @@ static void sm_unsafe_wait(struct semaphore *sm)
	{
		// 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 @@ static void sm_unsafe_wait(struct semaphore *sm)
			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 @@ static void sm_unsafe_signal(struct semaphore *sm)

	if (sm->sm <= 0)
	{
		sl_acquire(sm->task_lock);
		sl_acquire(&sm->task_lock);

		if (sm->first)
		{


@@ 116,7 116,7 @@ static void sm_unsafe_signal(struct semaphore *sm)
			free(f);
		}

		sl_release(sm->task_lock);
		sl_release(&sm->task_lock);
	}
}


M src/kernel/vga.c => src/kernel/vga.c +4 -5
@@ 185,10 185,9 @@ void vga_putd(uint d)

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 @@ static bool vga_put_nibble(uchar n, bool first)

void vga_putx(uint x)
{
	bool first = false;
	bool first = true;

	for (int shift = 24; shift >= 0; shift -= 8)
	{