Files
2020-08-08 01:06:06 +03:00

153 lines
4.1 KiB
C

#include "fs/ext2/block.h"
#include "fs/ext2/ext2.h"
#include "fs/ext2/node.h"
#include "fs/fs.h"
#include "fs/node.h"
#include "sys/assert.h"
#include "sys/attr.h"
#include "sys/block/blk.h"
#include "sys/debug.h"
#include "sys/heap.h"
#include "sys/mem/slab.h"
#include "sys/string.h"
#include "user/errno.h"
#include "user/mount.h"
static int ext2_init(struct fs *ext2, const char *opt);
static void ext2_destroy(struct fs *ext2);
static struct vnode *ext2_get_root(struct fs *ext2);
////
static struct fs_class g_ext2 = {
.name = "ext2",
.opt = 0,
.init = ext2_init,
.destroy = ext2_destroy,
.get_root = ext2_get_root
};
////
static int ext2_init(struct fs *ext2, const char *opt) {
_assert(ext2->blk);
struct ext2_data *data = kmalloc(sizeof(struct ext2_data));
_assert(data);
ext2->fs_private = data;
int res;
if (!(ext2->flags & MS_SYNCHRONOUS)) {
// 16MiB cache
blk_set_cache(ext2->blk, 4096);
} else {
kdebug("Not using cache\n");
}
// Read superblock
if ((res = ext2_read_superblock(ext2)) != 0) {
kfree(data);
ext2->fs_private = NULL;
return res;
}
// Check the signature
if (data->sb.ext2_signature != EXT2_SIGNATURE) {
kerror("Invalid ext2 signature\n");
kfree(data);
ext2->fs_private = NULL;
return -EINVAL;
}
// TODO: perform some kind of fsck?
kinfo("Volume ID: \"%s\"\n", data->sb.volume_name);
kinfo("Filesystem version: %d.%d\n", data->sb.version_major, data->sb.version_minor);
// Calculate filesystem parameters
data->block_size = 1024 << data->sb.log2_block_size;
if (data->sb.version_major != 0) {
data->inode_size = data->sb.inode_size;
} else {
data->inode_size = 128;
}
// Create a slab cache for inode objects
data->inode_cache = slab_cache_get(data->inode_size);
if (!data->inode_cache) {
// TODO: error handling
panic("Failed to allocate a slab cache of size %d for inodes\n", data->inode_size);
}
data->inodes_per_block = data->block_size / data->inode_size;
data->blkgrp_inode_blocks = data->sb.block_group_inodes / data->inodes_per_block;
kinfo("Block size: %u, inode size: %u\n", data->block_size, data->inode_size);
data->bgdt_entry_count = (data->sb.block_count + data->sb.block_group_blocks - 1) / data->sb.block_group_blocks;
uint32_t bgdt_size = data->bgdt_entry_count * sizeof(struct ext2_blkgrp_desc);
data->bgdt_size_blocks = (bgdt_size + data->block_size - 1) / data->block_size;
kinfo("Block groups: %u\n", data->bgdt_entry_count);
kinfo("BGDT occupies %u block(s)\n", data->bgdt_size_blocks);
data->bgdt = kmalloc(data->bgdt_size_blocks * data->block_size);
_assert(data->bgdt);
// BGDT starts with block 2
for (uint32_t i = 0; i < data->bgdt_size_blocks; ++i) {
if ((res = ext2_read_block(ext2, ((void *) data->bgdt) + i * data->block_size, i + 2)) != 0) {
kfree(data->bgdt);
kfree(data);
ext2->fs_private = NULL;
return res;
}
}
data->root_inode = slab_calloc(data->inode_cache);
_assert(data->root_inode);
data->root = vnode_create(VN_DIR, NULL);
_assert(data->root);
// Read root inode
if ((res = ext2_read_inode(ext2, data->root_inode, 2)) != 0) {
kfree(data->root_inode);
kfree(data->root);
kfree(data->bgdt);
kfree(data);
return res;
}
data->root->fs = ext2;
ext2_inode_to_vnode(data->root, data->root_inode, 2);
return 0;
}
static void ext2_destroy(struct fs *ext2) {
struct ext2_data *data = ext2->fs_private;
_assert(data);
if (!(ext2->flags & MS_SYNCHRONOUS)) {
blk_cache_release(ext2->blk);
}
kfree(data->root_inode);
kfree(data->root);
kfree(data->bgdt);
kfree(data);
}
static struct vnode *ext2_get_root(struct fs *ext2) {
struct ext2_data *data = ext2->fs_private;
_assert(data);
_assert(data->root);
return data->root;
}
__init(ext2_class_init) {
fs_class_register(&g_ext2);
}