diff options
author | Anton Kling <anton@kling.gg> | 2024-06-28 21:44:10 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2024-06-28 21:44:10 +0200 |
commit | 2bf9c84e110ff4bd163f0e395929c5df4bc85d2e (patch) | |
tree | 0765b85223ca6e5b99e319ba9046a787a03d94b1 /kernel/fs/ext2.c | |
parent | b747eb399c556858e05de51b1bb3e875c834c8e0 (diff) |
Ext2: Support block sizes other than 1024
Diffstat (limited to 'kernel/fs/ext2.c')
-rw-r--r-- | kernel/fs/ext2.c | 117 |
1 files changed, 95 insertions, 22 deletions
diff --git a/kernel/fs/ext2.c b/kernel/fs/ext2.c index 47d4d56..e755884 100644 --- a/kernel/fs/ext2.c +++ b/kernel/fs/ext2.c @@ -35,16 +35,16 @@ void get_inode_data_size(int inode_num, u64 *file_size) { struct BLOCK_CACHE { u32 last_use; u32 block_num; - u8 block[1024]; + u8 *block; }; #define NUM_BLOCK_CACHE 100 -struct BLOCK_CACHE *cache; +struct BLOCK_CACHE cache[NUM_BLOCK_CACHE]; u32 cold_cache_hits = 0; void cached_read_block(u32 block, void *address, size_t size, size_t offset) { - assert(offset + size <= 1024); + assert(offset + size <= block_byte_size); int free_found = -1; for (int i = 0; i < NUM_BLOCK_CACHE; i++) { if (cache[i].block_num == block) { @@ -72,7 +72,7 @@ void cached_read_block(u32 block, void *address, size_t size, size_t offset) { struct BLOCK_CACHE *c = &cache[free_found]; c->block_num = block; c->last_use = pit_num_ms(); - raw_vfs_pread(mount_fd, c->block, 1024, block * block_byte_size); + raw_vfs_pread(mount_fd, c->block, block_byte_size, block * block_byte_size); cached_read_block(block, address, size, offset); } @@ -354,7 +354,6 @@ int get_free_block(int allocate) { get_group_descriptor(g, &block_group); if (block_group.num_unallocated_blocks_in_group == 0) { - kprintf("skip\n"); continue; } @@ -369,6 +368,13 @@ int get_free_block(int allocate) { write_group_descriptor(g, &block_group); superblock->num_blocks_unallocated--; raw_vfs_pwrite(mount_fd, superblock, 2 * SECTOR_SIZE, 0); + + // TODO: Temporary due to other code not being able to handle + // offsets deep into files. + char buffer[block_byte_size]; + memset(buffer, 0, block_byte_size); + ext2_write_block(i + g * superblock->num_blocks_in_group + 1, buffer, + block_byte_size, 0); } return i + g * superblock->num_blocks_in_group + 1; } @@ -407,6 +413,66 @@ int get_free_inode(int allocate) { return -1; } +#define INDIRECT_BLOCK_CAPACITY (block_byte_size / sizeof(u32)) + +void write_to_indirect_block(u32 indirect_block, u32 index, u32 new_block) { + index %= INDIRECT_BLOCK_CAPACITY; + u32 buffer[INDIRECT_BLOCK_CAPACITY]; + ext2_read_block(indirect_block, buffer, block_byte_size, 0); + buffer[index] = new_block; + ext2_write_block(indirect_block, buffer, block_byte_size, 0); +} + +int ext2_allocate_block(inode_t *inode, u32 index) { + int b = get_free_block(1 /*true*/); + if (-1 == b) { + return 0; + } + if (index < 12) { + inode->block_pointers[index] = b; + return 1; + } + index -= 12; + if (index < INDIRECT_BLOCK_CAPACITY) { + if (0 == inode->single_indirect_block_pointer) { + int n = get_free_block(1 /*true*/); + if (-1 == n) { + return 0; + } + inode->single_indirect_block_pointer = n; + } + write_to_indirect_block(inode->single_indirect_block_pointer, index, b); + return 1; + } + index -= INDIRECT_BLOCK_CAPACITY; + if (index < INDIRECT_BLOCK_CAPACITY * INDIRECT_BLOCK_CAPACITY) { + if (0 == inode->double_indirect_block_pointer) { + int n = get_free_block(1 /*true*/); + if (-1 == n) { + return 0; + } + inode->double_indirect_block_pointer = n; + } + + u32 value = get_singly_block_index(inode->double_indirect_block_pointer, + index / INDIRECT_BLOCK_CAPACITY); + if (0 == value) { + int n = get_free_block(1 /*true*/); + if (-1 == n) { + return 0; + } + write_to_indirect_block(inode->double_indirect_block_pointer, + index / INDIRECT_BLOCK_CAPACITY, n); + value = n; + } + + write_to_indirect_block(value, index, b); + } else { + assert(0); + } + return 1; +} + int write_inode(int inode_num, u8 *data, u64 size, u64 offset, u64 *file_size, int append) { (void)file_size; @@ -429,15 +495,10 @@ int write_inode(int inode_num, u8 *data, u64 size, u64 offset, u64 *file_size, fsize = size + offset; } - int num_blocks_required = BLOCKS_REQUIRED(fsize, block_byte_size); + u32 num_blocks_required = BLOCKS_REQUIRED(fsize, block_byte_size); - for (int i = num_blocks_used; i < num_blocks_required; i++) { - if (i >= 12) { - assert(0); - } - int b = get_free_block(1 /*true*/); - assert(-1 != b); - inode->block_pointers[i] = b; + for (u32 i = num_blocks_used; i < num_blocks_required; i++) { + assert(ext2_allocate_block(inode, i)); } inode->num_disk_sectors = @@ -447,7 +508,6 @@ int write_inode(int inode_num, u8 *data, u64 size, u64 offset, u64 *file_size, for (int i = block_start; size; i++) { u32 block = get_block(inode, i); if (0 == block) { - kprintf("block_not_found\n"); break; } @@ -667,9 +727,10 @@ void ext2_create_entry(int directory_inode, direntry_header_t entry_header, entry_header.size = (sizeof(direntry_header_t) + entry_header.name_length); entry_header.size += (4 - (entry_header.size % 4)); - u32 length_till_next_block = 1024 - (new_entry_offset % 1024); + u32 length_till_next_block = + block_byte_size - (new_entry_offset % block_byte_size); if (0 == length_till_next_block) { - length_till_next_block = 1024; + length_till_next_block = block_byte_size; } assert(entry_header.size < length_till_next_block); entry_header.size = length_till_next_block; @@ -808,13 +869,8 @@ int ext2_create_file(const char *path, int mode) { } vfs_inode_t *ext2_mount(void) { - cache = kcalloc(NUM_BLOCK_CACHE, sizeof(struct BLOCK_CACHE)); - if (!cache) { - return NULL; - } int fd = vfs_open("/dev/sda", O_RDWR, 0); if (0 > fd) { - kfree(cache); return NULL; } // TODO: Can this be done better? Maybe create a seperate function in @@ -824,12 +880,29 @@ vfs_inode_t *ext2_mount(void) { // FIXME: This is a hacky solution relist_remove(¤t_task->file_descriptors, fd); parse_superblock(); - return vfs_create_inode( + + for (int i = 0; i < NUM_BLOCK_CACHE; i++) { + cache[i].block = kmalloc(block_byte_size); + if (!cache[i].block) { + goto ext2_mount_error; + } + } + vfs_inode_t *inode = vfs_create_inode( 0 /*inode_num*/, 0 /*type*/, 0 /*has_data*/, 0 /*can_write*/, 0 /*is_open*/, NULL /*internal_object*/, 0 /*file_size*/, ext2_open, ext2_create_file, ext2_read, ext2_write, ext2_close, ext2_create_directory, NULL /*get_vm_object*/, ext2_truncate /*truncate*/, ext2_stat, NULL /*send_signal*/, NULL /*connect*/); + if (!inode) { + goto ext2_mount_error; + } + return inode; +ext2_mount_error: + vfs_close(fd); + for (int i = 0; i < NUM_BLOCK_CACHE; i++) { + kfree(cache[i].block); + } + return NULL; } void parse_superblock(void) { |