From 7b805f2495776eed1e00600c5d930458d5dd9407 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Tue, 21 Dec 2004 22:00:00 -0500 Subject: [PATCH] Import backup from 2004-12-21 --- Makefile | 2 +- kernel/fs/ext2.c | 8 ++- kernel/fs/ext2.h | 177 +++++++++++++++++++++++++++++++---------------- kernel/fs/vfs.c | 101 +++++++++++++++++++++++---- kernel/fs/vfs.h | 28 +++++--- 5 files changed, 233 insertions(+), 83 deletions(-) diff --git a/Makefile b/Makefile index 74375cd..585cfac 100644 --- a/Makefile +++ b/Makefile @@ -59,7 +59,7 @@ install_img: initrd: dd if=/dev/zero of=$(INITRD) bs=1024 count=$(INITRD_SIZE) - mke2fs -Fv -m0 $(INITRD) + mke2fs -Fv -m0 -r0 $(INITRD) -mkdir $(INITRD_MOUNT) # mount -t ext2 -o loop $(INITRD) $(INITRD_MOUNT) # mkdir $(INITRD_MOUNT)/bin diff --git a/kernel/fs/ext2.c b/kernel/fs/ext2.c index eb919ff..6a99d20 100644 --- a/kernel/fs/ext2.c +++ b/kernel/fs/ext2.c @@ -10,6 +10,11 @@ #include "mm/vmm.h" #include "fs/vfs.h" +/* Turning an inode number into a (group, inode_index) pair: + * group = (inode - 1) / s_inodes_per_group + * index = (inode - 1) % s_inodes_per_group + */ + int ext2_init(int fsID) { @@ -36,11 +41,12 @@ void *ext2_mount_super(major_t major, minor_t minor) { ext2_super_block_t *super = kmalloc(1024); block_read(major, minor, 2, 2, super); - if (super->s_magic != EXT2_MAGIC) + if (super->s_magic != EXT2_MAGIC) // not an ext2 filesystem { kfree(super); return NULL; } + return super; } diff --git a/kernel/fs/ext2.h b/kernel/fs/ext2.h index 2fae121..b71eedd 100644 --- a/kernel/fs/ext2.h +++ b/kernel/fs/ext2.h @@ -10,72 +10,131 @@ #include "fs/devices.h" #define EXT2_MAGIC 0xEF53 +#define EXT2_NAME_LEN 255 -typedef struct { - u32_t s_inodes_count; /* Inodes count */ - u32_t s_blocks_count; /* Blocks count */ - u32_t s_r_blocks_count; /* Reserved blocks count */ - u32_t s_free_blocks_count; /* Free blocks count */ - u32_t s_free_inodes_count; /* Free inodes count */ - u32_t s_first_data_block; /* First Data Block */ - u32_t s_log_block_size; /* Block size */ - int s_log_frag_size; /* Fragment size */ - u32_t s_blocks_per_group; /* # Blocks per group */ - u32_t s_frags_per_group; /* # Fragments per group */ - u32_t s_inodes_per_group; /* # Inodes per group */ - u32_t s_mtime; /* Mount time */ - u32_t s_wtime; /* Write time */ - u16_t s_mnt_count; /* Mount count */ - short s_max_mnt_count; /* Maximal mount count */ - u16_t s_magic; /* Magic signature */ - u16_t s_state; /* File system state */ - u16_t s_errors; /* Behaviour when detecting errors */ - u16_t s_minor_rev_level; /* minor revision level */ - u32_t s_lastcheck; /* time of last check */ - u32_t s_checkinterval; /* max. time between checks */ - u32_t s_creator_os; /* OS */ - u32_t s_rev_level; /* Revision level */ - u16_t s_def_resuid; /* Default uid for reserved blocks */ - u16_t s_def_resgid; /* Default gid for reserved blocks */ +#define EXT2_I_MODE_OX 0x0001 +#define EXT2_I_MODE_OW 0x0002 +#define EXT2_I_MODE_OR 0x0004 +#define EXT2_I_MODE_GX 0x0008 +#define EXT2_I_MODE_GW 0x0010 +#define EXT2_I_MODE_GR 0x0020 +#define EXT2_I_MODE_UX 0x0040 +#define EXT2_I_MODE_UW 0x0080 +#define EXT2_I_MODE_UR 0x0100 +#define EXT2_I_MODE_STICKY 0x0200 +#define EXT2_I_MODE_SGID 0x0400 +#define EXT2_I_MODE_SUID 0x0800 +#define EXT2_I_MODE_TYPE_MASK 0xF000 +#define EXT2_I_MODE_FIFO 0x1000 +#define EXT2_I_MODE_CHAR 0x2000 +#define EXT2_I_MODE_DIR 0x4000 +#define EXT2_I_MODE_BLOCK 0x6000 +#define EXT2_I_MODE_FILE 0x8000 +#define EXT2_I_MODE_SYM 0xA000 +#define EXT2_I_MODE_SOCK 0xC000 - /* - * EXT2_DYNAMIC_REV fields... - */ - u32_t s_first_ino; /* First non-reserved inode */ - u16_t s_inode_size; /* size of inode structure */ - u16_t s_block_group_nr; /* block group # of this superblock */ - u32_t s_feature_compat; /* compatible feature set */ - u32_t s_feature_incompat; /* incompatible feature set */ - u32_t s_feature_ro_compat; /* readonly-compatible feature set */ - u8_t s_uuid[16]; /* 128-bit uuid for volume */ - char s_volume_name[16]; /* volume name */ - char s_last_mounted[64]; /* directory where last mounted */ - u32_t s_algorithm_usage_bitmap; /* For compression */ +#define EXT2_I_FLAGS_SEC_DEL 0x01 +#define EXT2_I_FLAGS_UNDELETE 0x02 +#define EXT2_I_FLAGS_COMPRESS 0x04 +#define EXT2_I_FLAGS_SYNC 0x08 +#define EXT2_I_FLAGS_IMMUTABLE 0x10 +#define EXT2_I_FLAGS_APPEND 0x20 +#define EXT2_I_FLAGS_NODUMP 0x40 - /* - * Performance hints... - */ - u8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate */ - u8_t s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ - u16_t s_padding1; +#define EXT2_INODE_BAD_BLOCKS 1 +#define EXT2_INODE_ROOT 2 +#define EXT2_INODE_ACL_INDEX 3 +#define EXT2_INODE_ACL_DATA 4 +#define EXT2_INODE_BOOT_LOADER 5 +#define EXT2_INODE_UNDELETE_DIR 6 +#define EXT2_INODE_AVAIL 11 - /* - * Journaling information... - */ - u8_t s_journal_uuid[16]; /* uuid of journal superblock */ - u32_t s_journal_inum; /* inode number of journal file */ - u32_t s_journal_dev; /* device number of journal file */ - u32_t s_last_orphan; /* start of list of inodes to delete */ - u32_t s_hash_seed[4]; /* HTREE hash seed */ - u8_t s_def_hash_version; /* Default hash version to use */ - u8_t s_reserved_char_pad; - u16_t s_reserved_word_pad; - u32_t s_default_mount_opts; - u32_t s_first_meta_bg; /* First metablock block group */ - u32_t s_reserved[190]; /* Padding to the end of the block */ +#define EXT2_FT_UNKNOWN 0 +#define EXT2_FT_FILE 1 +#define EXT2_FT_DIR 2 +#define EXT2_FT_CHAR 3 +#define EXT2_FT_BLOCK 4 +#define EXT2_FT_FIFO 5 +#define EXT2_FT_SOCK 6 +#define EXT2_FT_SYMLINK 7 +#define EXT2_FT_MAX 8 +typedef struct +{ + u32_t s_inodes_count; /* Inodes count */ + u32_t s_blocks_count; /* Blocks count */ + u32_t s_r_blocks_count; /* Reserved blocks count */ + u32_t s_free_blocks_count; /* Free blocks count */ + u32_t s_free_inodes_count; /* Free inodes count */ + u32_t s_first_data_block; /* First Data Block */ + u32_t s_log_block_size; /* Block size: 0->1024, 1->2048, 4->4096 */ + int s_log_frag_size; /* Fragment size */ + u32_t s_blocks_per_group; /* # Blocks per group */ + u32_t s_frags_per_group; /* # Fragments per group */ + u32_t s_inodes_per_group; /* # Inodes per group */ + u32_t s_mtime; /* Mount time */ + u32_t s_wtime; /* Write time */ + u16_t s_mnt_count; /* Mount count */ + short s_max_mnt_count; /* Maximal mount count */ + u16_t s_magic; /* Magic signature */ + u16_t s_state; /* File system state */ + u16_t s_errors; /* Behaviour when detecting errors */ + u16_t s_minor_rev_level; /* minor revision level */ + u32_t s_lastcheck; /* time of last check */ + u32_t s_checkinterval; /* max. time between checks */ + u32_t s_creator_os; /* OS */ + u32_t s_rev_level; /* Revision level */ + u16_t s_def_resuid; /* Default uid for reserved blocks */ + u16_t s_def_resgid; /* Default gid for reserved blocks */ + + u32_t s_reserved[235]; } ext2_super_block_t; +typedef struct +{ + u32_t bg_block_bitmap; // Blocks bitmap block + u32_t bg_inode_bitmap; // Inode bitmap block + u32_t bg_inode_table; // Inode table block + u16_t bg_free_blocks_count; // Free blocks count + u16_t bg_free_inodes_count; // Free Inodes count + u16_t bg_used_dirs_count; // Directories count + u16_t bg_pad1; + u32_t bg_reserved[3]; +} ext2_group_desc_t; + +typedef struct +{ + u16_t i_mode; // File mode + u16_t i_uid; // Owner UID + u32_t i_size; // Size in bytes + u32_t i_atime; // Access time + u32_t i_ctime; // Creation time + u32_t i_mtime; // Modification time + u32_t i_dtime; // Deletion time + u16_t i_gid; // Group ID + u16_t i_links_count; // Links count + u32_t i_blocks; // Blocks count + u32_t i_flags; // File flags + u32_t i_reserved1; + u32_t i_block[15]; // Pointers to file blocks + u32_t i_version; // File version (NFS?) + u32_t i_file_acl; // File ACL + u32_t i_dir_acl; // Directory ACL + u32_t i_faddr; // Fragment address + u8_t i_frag; // Fragment number + u8_t i_fsize; // Fragment size + u16_t i_pad1; + u32_t i_reserved2[2]; +} ext2_inode_t; + +typedef struct +{ + u32_t inode; // inode number + u16_t length; // directory entry length + u8_t name_length; // name length + u8_t file_type; // File type + char name[EXT2_NAME_LEN]; +} ext2_dir_entry_t; int ext2_init(int fsID); void *ext2_mount_super(major_t major, minor_t minor); diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c index ddc0fe9..ca52d0b 100644 --- a/kernel/fs/vfs.c +++ b/kernel/fs/vfs.c @@ -1,7 +1,7 @@ // vfs.c // Author: Josh Holtrop // Date: 08/22/04 -// Modified: 12/20/04 +// Modified: 12/21/04 #include "hos_defines.h" #include "kout.h" @@ -9,16 +9,19 @@ #include "fs/ext2.h" #include "kernel.h" #include "mm/vmm.h" +#include "lang/asmfuncs.h" -vfs_fs_t *fses[VFS_MAX_FS]; -vfs_node_t *vfsMountTree; +vfs_fs_t *fses[VFS_MAX_FS]; // a vfs_fs structure for every filesystem we support +vfs_node_t *vfsMountTree; // points to the root node ('/') of the VFS Mount Tree +// basic initialization routine, init all filesystem drivers int vfs_init() { k_check(ext2_init(FS_EXT2), "ext2_init() failed!"); return 0; } +// called by a filesystem driver to let us know that it is ready to handle fs requests int vfs_register_fs(int fsn, vfs_fs_t *fs) { if (fsn < 0 || fsn >= VFS_MAX_FS || fses[fsn]) @@ -30,16 +33,20 @@ int vfs_register_fs(int fsn, vfs_fs_t *fs) return 0; } +// called to mount a block device with a certain filesystem to a part of our VFS Mount Tree int vfs_mount(major_t maj, minor_t min, int fsType, char *mountPoint) { if (mountPoint[0] != '/') return -1; // mount point must be absolute + int l = strlen(mountPoint); + if (l < 1) + return -7; // mount point must be non-null string + if (mountPoint[l-1] != '/') + return -8; // mount point must end with a '/' character if (fsType < 0 || fsType >= VFS_MAX_FS || !fses[fsType]) return -2; // invalid filesystem type if (vfs_find_mount(mountPoint)) - { return -5; // mount point already mounted - } void *super = fses[fsType]->mount_super(maj, min); if (!super) return -6; // filesystem superblock not correctly identified @@ -58,6 +65,7 @@ int vfs_mount(major_t maj, minor_t min, int fsType, char *mountPoint) return 0; } +// invoked by vfs_mount to do the "dirty work" of adding the nodes to the tree int vfs_add_mount(vfs_mount_t *mnt, char *mountPoint) { vfs_node_t *node = vfsMountTree; @@ -114,9 +122,10 @@ int vfs_add_mount(vfs_mount_t *mnt, char *mountPoint) } } +// lookup a path and return the match structure for the deepest path matched vfs_mount_match_t vfs_get_rel_path(char *path) { - vfs_mount_match_t matched; + vfs_mount_match_t matched = {NULL, 0}; char *pp = path; int length = 0; vfs_node_t *node = vfsMountTree; @@ -126,14 +135,13 @@ vfs_mount_match_t vfs_get_rel_path(char *path) break; if (node->chr == *pp) // got a character match { + length++; if (node->mount) // and there is something mounted here { - matched.major = node->mount->major; - matched.minor = node->mount->minor; + matched.mount = node->mount; matched.length = length; } pp++; - length++; node = node->down; } else @@ -142,6 +150,8 @@ vfs_mount_match_t vfs_get_rel_path(char *path) return matched; } +// is mountPoint a valid mount point? +// returns a pointer to the mount structure if so vfs_mount_t *vfs_find_mount(char *mountPoint) { char *mp = mountPoint; @@ -161,9 +171,76 @@ vfs_mount_t *vfs_find_mount(char *mountPoint) return NULL; } -/*void vfs_dump_tree() +// unmount the mountPoint, remove nodes from tree that aren't used anymore +int vfs_umount(char *mountPoint) { - vfs_dump_node(vfsMountTree, 0); + char *mp = mountPoint; + vfs_node_t *node = vfsMountTree; + while (node) + { + if (node->chr == *mp) + { + mp++; + if (*mp == 0) // we matched the whole mount point string + { + // is there something mounted underneath this directory? + if (node->down) + return -3; // yes, don't umount + kfree(node->mount); + node->mount = NULL; + return vfs_retire_node(node); + } + node = node->down; + } + else + node = node->next; + } + return -2; // mount point does not exist +} + +// remove this node from the tree if it is not needed anymore +int vfs_retire_node(vfs_node_t *node) +{ + if (node->down) + return 0; // node is part of another mount point, don't remove + if (node->mount) + return 0; // something is still mounted here + if (!node->up) + { + kfree(node); + vfsMountTree = NULL; + return 0; // we unmounted the root directory + } + // 3 cases left: node is first child (or only child), middle child, or last child + if (node->up->down == node) // first child + { + node->up->down = node->next; // re-point parent to next child + int r = vfs_retire_node(node->up); // retire parent if we were an only-child + kfree(node); + return r; + } + vfs_node_t *onode = node->up->down; // onode points to first child + while (onode) + { + if (onode->next == node) // onode is child before node + { + onode->next = node->next; + kfree(node); + return 0; + } + onode = onode->next; + } + return -1; // node wasn't found following onode +} + + +// debug routine to draw the VFS Mount Tree +void vfs_dump_tree() +{ + if (!vfsMountTree) + kprintf("vfsMountTree == NULL!\n"); + else + vfs_dump_node(vfsMountTree, 0); } void vfs_dump_node(vfs_node_t *node, int level) @@ -182,5 +259,5 @@ void vfs_dump_node(vfs_node_t *node, int level) vfs_dump_node(node, level + 1); node = node->next; } -}*/ +} diff --git a/kernel/fs/vfs.h b/kernel/fs/vfs.h index 6e2c035..327bce3 100644 --- a/kernel/fs/vfs.h +++ b/kernel/fs/vfs.h @@ -1,7 +1,7 @@ // vfs.h // Author: Josh Holtrop // Date: 08/22/04 -// Modified: 12/20/04 +// Modified: 12/21/04 #ifndef __HOS_VFS_H__ #define __HOS_VFS_H__ __HOS_VFS_H__ @@ -13,6 +13,7 @@ #define VFS_MAX_FS 10 +/* Structure to hold information about a mount point */ typedef struct { int refs; @@ -21,27 +22,32 @@ typedef struct minor_t minor; } vfs_mount_t; +/* Every filesystem must provide pointers to its respective functions in a structure like this */ typedef struct { void *(*mount_super)(major_t major, minor_t minor); int (*mkfs)(major_t major, minor_t minor); } vfs_fs_t; +/* This structure represents a node of the "VFS Mount Tree" */ struct vfs_node_s { - char chr; - vfs_mount_t *mount; - struct vfs_node_s *up; - struct vfs_node_s *next; - struct vfs_node_s *down; + char chr; // the character we are at + vfs_mount_t *mount; // is there a mount at this character? + struct vfs_node_s *up; // the parent + struct vfs_node_s *next; // the next sibling + struct vfs_node_s *down; // subtree for submounts }; typedef struct vfs_node_s vfs_node_t; +/* This structure is generated when a path is matched. For example, if /dev is mounted on + device (4,2) and '/dev/yoda' is looked up, the structure returned would be + {4, 2, 4} and then the lookup could continue on device (4,2) with 4 characters stripped + off the front of the initial path (ex '/yoda') */ typedef struct { - major_t major; - minor_t minor; + vfs_mount_t *mount; int length; } vfs_mount_match_t; @@ -52,8 +58,10 @@ int vfs_register_fs(int fsn, vfs_fs_t *fs); int vfs_add_mount(vfs_mount_t *mnt, char *mountPoint); vfs_mount_t *vfs_find_mount(char *mountPoint); vfs_mount_match_t vfs_get_rel_path(char *path); -/*void vfs_dump_tree(); -void vfs_dump_node(vfs_node_t *node, int level);*/ +int vfs_umount(char *mountPoint); +int vfs_retire_node(vfs_node_t *node); +void vfs_dump_tree(); +void vfs_dump_node(vfs_node_t *node, int level); #endif