diff --git a/kernel/fs/ext2.c b/kernel/fs/ext2.c index 3fc8ae1..76b72cd 100644 --- a/kernel/fs/ext2.c +++ b/kernel/fs/ext2.c @@ -19,6 +19,9 @@ vfs_fs_t ext2_driver = {ext2_mount_super, ext2_umount_super, ext2_stat, ext2__get_root_dir_inode, ext2__link_deref, + ext2__free_inodes, ext2__total_inodes, + ext2__free_blocks, ext2__total_blocks, + ext2_alloc_inode, ext2_alloc_block, ext2__open_dir, ext2__read_dir, ext2__close_dir, ext2__open_file, ext2__read_file, ext2__close_file, ext2__open_block_file, ext2__read_block_file, ext2__block_file_seek, ext2__close_block_file}; @@ -262,11 +265,11 @@ u32_t ext2_block_number(vfs_mount_t *mount, ext2_open_inode_t *open_inode) } -// read the inode structure from the device and return it +// read the inode structure from the device int ext2_read_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat) { if (ext2_inode_status(mount, inode) != 1) - return -1; // free or invalid inode number + return -1; // free or invalid inode number ext2_super_block_t *super = mount->super; inode--; // turn inode into a 0-based index u32_t group = inode / super->s_inodes_per_group; @@ -280,6 +283,25 @@ int ext2_read_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat) return 0; } +// write an inode structure to the device +int ext2_write_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat) +{ + if (ext2_inode_status(mount, inode) != 1) + return -1; // free or invalid inode number + ext2_super_block_t *super = mount->super; + inode--; // turn inode into a 0-based index + u32_t group = inode / super->s_inodes_per_group; + u32_t index = inode % super->s_inodes_per_group; + u32_t inodeAddr = (ext2_get_group_desc(mount, group).bg_inode_table << + (10 + super->s_log_block_size)) + (index << 7); + void *block = kmalloc(512); + block_read(mount->major, mount->minor, inodeAddr >> 9, 1, block); + memcpy( (block + (inodeAddr & 0x1FF)), dat, sizeof(ext2_inode_t)); + block_write(mount->major, mount->minor, inodeAddr >> 9, 1, block); + kfree(block); + return 0; +} + // read the group descriptor structure from the device and return it ext2_group_desc_t ext2_get_group_desc(vfs_mount_t *mount, u32_t group) { @@ -292,41 +314,117 @@ ext2_group_desc_t ext2_get_group_desc(vfs_mount_t *mount, u32_t group) return gd; } +// write the group descriptor structure to the device +void ext2_write_group_desc(vfs_mount_t *mount, u32_t group_num, ext2_group_desc_t *gd) +{ + ext2_super_block_t *super = mount->super; + u32_t groupDescAddr = ((1 + super->s_first_data_block) << (10 + super->s_log_block_size)) + (group_num << 5); + void *block = kmalloc(512); + block_read(mount->major, mount->minor, groupDescAddr >> 9, 1, block); + memcpy( (block + (groupDescAddr & 0x1FF)), gd, sizeof(ext2_group_desc_t) ); + block_write(mount->major, mount->minor, groupDescAddr >> 9, 1, block); + kfree(block); +} -// TODO: finish allocating an inode +// allocate an inode and return its number u32_t ext2_alloc_inode(vfs_mount_t *mount) { ext2_super_block_t *super = mount->super; if (!super->s_free_inodes_count) return 0; // no free inodes - int bg; - for (bg = 0; bg < super->s_blocks_count; b++) + int bg, bg_max = ext2_num_block_groups(super); + for (bg = 0; bg < bg_max; bg++) { - ext2_group_desc_t group_desc = ext2_get_group_desc(mount, b); + ext2_group_desc_t group_desc = ext2_get_group_desc(mount, bg); if (group_desc.bg_free_inodes_count) { - u32_t node = ext2_reserve_node(super, group_desc.bg_inode_bitmap, super->s_inodes_per_group); - return b * + u32_t node = ext2_reserve_node(mount, group_desc.bg_inode_bitmap, super->s_inodes_per_group); + group_desc.bg_free_inodes_count--; + ext2_write_group_desc(mount, bg, &group_desc); + super->s_free_inodes_count--; + return bg * super->s_inodes_per_group + node + 1; } } return 0; } -u32_t ext2_reserve_node(ext2_super_block_t *super, u32_t bitmap_block_num, u32_t max_node) +// allocate a block and return its number +u32_t ext2_alloc_block(vfs_mount_t *mount) { - u32_t *bitmap = kmalloc(1024 << super->s_log_block_size); - int block, max_block = max_node / (8192 << super->s_log_block_size); - for (block = 0; block < max_block; block++) + ext2_super_block_t *super = mount->super; + if (!super->s_free_blocks_count) + return 0; // no free blocks + int bg, bg_max = ext2_num_block_groups(super); + for (bg = 0; bg < bg_max; bg++) { - block_read(super->major, super->minor, ext2_FSToDiskBlock(bitmap_block_num + block, super), - 2 << super->s_log_block_size, bitmap); + ext2_group_desc_t group_desc = ext2_get_group_desc(mount, bg); + if (group_desc.bg_free_blocks_count) + { + u32_t node = ext2_reserve_node(mount, group_desc.bg_block_bitmap, super->s_blocks_per_group); + group_desc.bg_free_blocks_count--; + ext2_write_group_desc(mount, bg, &group_desc); + super->s_free_blocks_count--; + return bg * super->s_blocks_per_group + node + super->s_first_data_block; + } } - kfree(bitmap); + return 0; } +// reserve a node of a inode or block bitmap and mark its entry allocated +u32_t ext2_reserve_node(vfs_mount_t *mount, u32_t bitmap_block_num, u32_t bitmap_size) +{ + ext2_super_block_t *super = mount->super; + u32_t *bitmap = kmalloc(1024 << super->s_log_block_size); + int block, max_block = (bitmap_size - 1) / (8192 << super->s_log_block_size) + 1; + for (block = 0; block < max_block; block++) + { + block_read(mount->major, mount->minor, ext2_FSToDiskBlock(bitmap_block_num + block, super), + 2 << super->s_log_block_size, bitmap); + int num, num_max = 256 << super->s_log_block_size; + u32_t *block_pointer = bitmap; + int done = 0; + for (num = 0; num < num_max && !done; num++) + { + if (*block_pointer != 0xFFFFFFFF) + { + done = 1; + int bit; + for (bit = 0; bit < 32; bit++) + { + if (!(*block_pointer & (1 << bit))) + { + u32_t node_number = (block * 8192 << super->s_log_block_size) + (num << 5) + bit; + if (node_number < bitmap_size) + { + // found a node, mark it allocated, write the bitmap, return + *block_pointer |= (1 << bit); + block_write(mount->major, mount->minor, + ext2_FSToDiskBlock(bitmap_block_num + block, super), + 2 << super->s_log_block_size, bitmap); + kfree(bitmap); + return node_number; + } + kfree(bitmap); + return 0; + } + } + } + block_pointer++; + } + } + kfree(bitmap); + return 0; +} +// return how many block groups are on the filesystem int ext2_num_block_groups(ext2_super_block_t *super) { + return (super->s_inodes_count / super->s_inodes_per_group) + 1; +} + +void ext2_write_super(vfs_mount_t *mount) +{ + block_write(mount->major, mount->minor, 2, 2, mount->super); } @@ -350,6 +448,7 @@ void *ext2_mount_super(major_t major, minor_t minor) // called when we are unmounting this filesystem mount int ext2_umount_super(vfs_mount_t *mount) { + ext2_write_super(mount); return kfree(mount->super); // free memory that the superblock was taking } @@ -437,7 +536,33 @@ int ext2__link_deref(vfs_mount_t *mount, u32_t link_inode, char *link) } } +// VFS interface function to return the number of free inodes +int ext2__free_inodes(vfs_mount_t *mount) +{ + ext2_super_block_t *super = mount->super; + return super->s_free_inodes_count; +} +// VFS interface function to return the total number of inodes +int ext2__total_inodes(vfs_mount_t *mount) +{ + ext2_super_block_t *super = mount->super; + return super->s_inodes_count; +} + +// VFS interface function to return the number of free 512-byte blocks +int ext2__free_blocks(vfs_mount_t *mount) +{ + ext2_super_block_t *super = mount->super; + return super->s_free_blocks_count << (1 + super->s_log_block_size); +} + +// VFS interface function to return the total number of 512-byte blocks +int ext2__total_blocks(vfs_mount_t *mount) +{ + ext2_super_block_t *super = mount->super; + return super->s_blocks_count << (1 + super->s_log_block_size); +} // VFS interface function to open a directory int ext2__open_dir(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir) diff --git a/kernel/fs/ext2.h b/kernel/fs/ext2.h index 1b72e4c..a9dce89 100644 --- a/kernel/fs/ext2.h +++ b/kernel/fs/ext2.h @@ -183,7 +183,9 @@ static inline u32_t ext2_FSToDiskBlock(u32_t block, ext2_super_block_t *super) int ext2_init(int fsID); int ext2_read_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat); +int ext2_write_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat); ext2_group_desc_t ext2_get_group_desc(vfs_mount_t *mount, u32_t group); +void ext2_write_group_desc(vfs_mount_t *mount, u32_t group_num, ext2_group_desc_t *gd); ext2_open_inode_t *ext2_open_inode(vfs_mount_t *mount, u32_t inode_number); int ext2_close_inode(vfs_mount_t *mount, ext2_open_inode_t *open_inode); int ext2_read_inode_block(vfs_mount_t *mount, ext2_open_inode_t *open_inode, void *block); @@ -192,8 +194,10 @@ int ext2_inode_seek(vfs_mount_t *mount, ext2_open_inode_t *open_inode, u32_t blo int ext2_inode_status(vfs_mount_t *mount, u32_t inode_number); int ext2_block_status(vfs_mount_t *mount, u32_t block_number); u32_t ext2_alloc_inode(vfs_mount_t *mount); -u32_t ext2_reserve_node(ext2_super_block_t *super, u32_t bitmap_block_num, u32_t max_node); +u32_t ext2_alloc_block(vfs_mount_t *mount); +u32_t ext2_reserve_node(vfs_mount_t *mount, u32_t bitmap_block_num, u32_t bitmap_size); int ext2_num_block_groups(ext2_super_block_t *super); +void ext2_write_super(vfs_mount_t *mount); ext2_open_dir_t *ext2_open_dir(vfs_mount_t *mount, u32_t inode_number); @@ -207,6 +211,11 @@ int ext2_umount_super(vfs_mount_t *mount); int ext2_stat(vfs_mount_t *mount, u32_t inode_number, vfs_stat_t *stat); u32_t ext2__get_root_dir_inode(vfs_mount_t *mount); int ext2__link_deref(vfs_mount_t *mount, u32_t link_inode, char *link); +int ext2__free_inodes(vfs_mount_t *mount); +int ext2__total_inodes(vfs_mount_t *mount); +int ext2__free_blocks(vfs_mount_t *mount); +int ext2__total_blocks(vfs_mount_t *mount); + int ext2__open_dir(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir); int ext2__read_dir(vfs_mount_t *mount, vfs_open_file_t *dir, vfs_dir_entry_t *dentry); diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c index 122f16f..e8c748a 100644 --- a/kernel/fs/vfs.c +++ b/kernel/fs/vfs.c @@ -64,11 +64,64 @@ int vfs_mount(major_t maj, minor_t min, int fsType, char *mountPoint) if (mountPoint[0] != '/') return -3; // mount point must be absolute if (!mounts) - return -4; - int l = strlen(mountPoint); - if (l < 2) - return -5; // mount point is too short - return -6; + return -4; // no root dir yet + vfs_stat_t stat; + if (vfs_stat(mountPoint, &stat)) + return -5; // error statting + if (stat.type != VFS_FT_DIR) + return -6; // mountPoint not a directory + vfs_inode_t vfs_inode = vfs_get_inode_number(mountPoint); + vfs_inode_t updir = vfs_entry_lookup(vfs_inode, ".."); + if (!updir || (updir & 0x8000000000000000ULL)) + return -7; + void *super = fses[fsType]->mount_super(maj, min); + if (!super) + return -3; // didn't mount superblock + vfs_mount_t *mnt = New(vfs_mount_t); + mnt->refs = 0; + mnt->super = super; + mnt->fs = fsType; + mnt->major = maj; + mnt->minor = min; + mnt->mountPoint = kmalloc(strlen(mountPoint) + 1); + strcpy(mnt->mountPoint, mountPoint); + mnt->vfs_mount_inode = vfs_inode; + mnt->vfs_up_inode = updir; + mnt->vfs_root_inode = ((vfs_inode_t)maj << 40) | ((vfs_inode_t)min << 32) | fses[fsType]->get_root_inode(mnt); + vfs_mount_t *mount = mounts; + while (mount->next) + mount = mount->next; + mount->next = mnt; // add mnt to end of mounts list + mnt->prev = mount; + mnt->next = NULL; + vfs_get_file_addr(updir).mount->refs++; + return -256; +} + +int vfs_umount(char *mountPoint) +{ + vfs_inode_t vfs_inode = vfs_get_inode_number(mountPoint); + if (!vfs_inode || (vfs_inode & 0x8000000000000000ULL)) + return -1; // invalid + vfs_mount_t *mnt = mounts; + while (mnt) + { + if (mnt->vfs_root_inode == vfs_inode) // found mount point to unmount + { + if (mnt->refs) + return -2; // open references to mount point; + if (mnt->prev) + mnt->prev->next = mnt->next; + if (mnt->next) + mnt->next->prev = mnt->prev; + if (mnt == mounts) + mounts = NULL; + kfree(mnt->mountPoint); + kfree(mnt); + return 0; + } + } + return -3; // invalid mount point } vfs_inode_t vfs_get_inode_number(char *path) @@ -90,7 +143,7 @@ vfs_inode_t vfs_get_inode_number_rel(vfs_inode_t dir_inode, char *path) for (; stanzas > 0; stanzas--) { vfs_inode_t vfs_inode_this_dir = vfs_inode; - vfs_inode = vfs_entry_lookup(vfs_inode, lookup); + vfs_inode = (strcmp("", lookup) ? vfs_entry_lookup(vfs_inode, lookup) : vfs_inode_this_dir); vfs_stat_t stat; if (vfs_stat_inode(vfs_inode, &stat)) return 0x8000000000000002ULL; @@ -168,6 +221,78 @@ vfs_file_addr_t vfs_get_file_addr(vfs_inode_t vfs_inode) return addr; } +int vfs_mount_count() +{ + vfs_mount_t *mnt = mounts; + int count = 0; + while (mnt) + { + count++; + mnt = mnt->next; + } + return count; +} + +vfs_mount_t *vfs_get_mount(int index) +{ + vfs_mount_t *mnt = mounts; + while (mnt && index) + { + mnt = mnt->next; + index--; + } + if (!index) + return mnt; + return NULL; +} + +int vfs_free_inodes(vfs_mount_t *mount) +{ + if (fses[mount->fs]->free_inodes) + return fses[mount->fs]->free_inodes(mount); + return -1; +} + +int vfs_total_inodes(vfs_mount_t *mount) +{ + if (fses[mount->fs]->total_inodes) + return fses[mount->fs]->total_inodes(mount); + return -1; +} + +int vfs_free_blocks(vfs_mount_t *mount) +{ + if (fses[mount->fs]->free_blocks) + return fses[mount->fs]->free_blocks(mount); + return -1; +} + +int vfs_total_blocks(vfs_mount_t *mount) +{ + if (fses[mount->fs]->total_blocks) + return fses[mount->fs]->total_blocks(mount); + return -1; +} + +vfs_inode_t vfs_alloc_inode(vfs_mount_t *mount) +{ + if (fses[mount->fs]->alloc_inode) + { + u32_t fs_inode = fses[mount->fs]->alloc_inode(mount); + if (!fs_inode) + return 0; + return (mount->vfs_root_inode & 0xFFFFFFFF00000000ULL) | fs_inode; + } + return 0; +} + +int vfs_alloc_block(vfs_mount_t *mount) +{ + if (fses[mount->fs]->alloc_block) + return fses[mount->fs]->alloc_block(mount); + return 0; +} + int vfs_link_deref(vfs_inode_t vfs_inode, char *link) { vfs_stat_t stat; diff --git a/kernel/fs/vfs.h b/kernel/fs/vfs.h index c6751f2..c067154 100644 --- a/kernel/fs/vfs.h +++ b/kernel/fs/vfs.h @@ -96,6 +96,12 @@ typedef struct int (*stat)(vfs_mount_t *mount, u32_t inode_number, vfs_stat_t *stat); u32_t (*get_root_inode)(vfs_mount_t *mount); int (*link_deref)(vfs_mount_t *mount, u32_t inode_number, char *link); + int (*free_inodes)(vfs_mount_t *mount); + int (*total_inodes)(vfs_mount_t *mount); + int (*free_blocks)(vfs_mount_t *mount); + int (*total_blocks)(vfs_mount_t *mount); + u32_t (*alloc_inode)(vfs_mount_t *mount); + u32_t (*alloc_block)(vfs_mount_t *mount); int (*open_dir)(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir); int (*read_dir)(vfs_mount_t *mount, vfs_open_file_t *dir, vfs_dir_entry_t *dentry); @@ -115,6 +121,7 @@ typedef struct int vfs_init(); int vfs_mount(major_t maj, minor_t min, int fsType, char *mountPoint); +int vfs_umount(char *mountPoint); int vfs_register_fs(int fsn, vfs_fs_t *fs); int vfs_umount(char *mountPoint); vfs_inode_t vfs_get_inode_number(char *path); @@ -122,6 +129,18 @@ vfs_inode_t vfs_get_inode_number_rel(vfs_inode_t dir_inode, char *path); vfs_inode_t vfs_real_inode(vfs_inode_t vfs_inode); vfs_file_addr_t vfs_get_file_addr(vfs_inode_t vfs_inode); vfs_inode_t vfs_entry_lookup(vfs_inode_t dir_inode, char *entry); + +int vfs_mount_count(); +vfs_mount_t *vfs_get_mount(int index); +int vfs_free_inodes(vfs_mount_t *mount); +int vfs_total_inodes(vfs_mount_t *mount); +int vfs_free_blocks(vfs_mount_t *mount); +int vfs_total_blocks(vfs_mount_t *mount); + +vfs_inode_t vfs_alloc_inode(vfs_mount_t *mount); +int vfs_alloc_block(vfs_mount_t *mount); + + int vfs_link_deref(vfs_inode_t vfs_inode, char *link); int vfs_stat(char *file, vfs_stat_t *stat); diff --git a/kernel/kernel.c b/kernel/kernel.c index 854ed63..52fbab5 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -136,7 +136,7 @@ void k_init() } } - vfs_open_file_t *root = vfs_open_dir("/link"); + vfs_open_file_t *root = vfs_open_dir("////"); if (root) { vfs_dir_entry_t dentry; @@ -174,7 +174,7 @@ void k_init() } else kprintf("Error: Could not open directory\n"); - + kprintf("Total inodes: %d, free inodes: %d\tTotal blocks: %d, free blocks: %d\n", vfs_total_inodes(mount), vfs_free_inodes(mount), vfs_total_blocks(mount), vfs_free_blocks(mount)); criticalCounter--; }