?? fs_virtfs.c
字號:
if (rootdev) { result->st_rdev.device_class = rootdev->dev_id.device_class; result->st_rdev.device_instance = rootdev->dev_id.device_instance; } } result->st_type = this->type; result->st_storage_location = this->storage_location; result->st_access_rights = this->access_rights; result->st_nlink = this->ondisk_lnk_cnt; if (this->type == SOS_FS_NODE_REGULAR_FILE) result->st_size = virtfsnode->file.size; else result->st_size = 0; return SOS_OK;}static sos_ret_t virtfs_truncate(struct sos_fs_node *this, sos_lsoffset_t length){ sos_ret_t retval; struct virtfs_node * virtfsnode; virtfsnode = (struct virtfs_node*) this->custom_data; if ( (virtfsnode->super.type != SOS_FS_NODE_REGULAR_FILE) && (virtfsnode->super.type != SOS_FS_NODE_SYMLINK)) return -SOS_ENOSUP; virtfs_lock(virtfsnode); retval = virtfs_resize(virtfsnode, length); virtfs_unlock(virtfsnode); return retval;}static sos_ret_t virtfs_sync_node(struct sos_fs_node *this){ /* No backing store for virtfs */ return SOS_OK;}static sos_ret_t virtfs_chmod_node(struct sos_fs_node * this, sos_ui32_t access_rights){ this->access_rights = access_rights; return SOS_OK;}/** Callback when nothing (in particular no sos_fs_nscache_node) make reference to the node */static sos_ret_t virtfs_node_destructor(struct sos_fs_node * this){ /* This callback is called only when the fsnode is not needed anymore by any process or by the kernel. But the node must remain stored "on disk" as long as the FS is mounted AND the node is still "on disk" */ if (this->ondisk_lnk_cnt <= 0) { struct virtfs_instance * virtfs = (struct virtfs_instance*)this->fs->custom_data; struct virtfs_node * virtfsnode = (struct virtfs_node*)this->custom_data; list_delete(virtfs->list_fsnodes, virtfsnode); sos_kfree((sos_vaddr_t) this->custom_data); } return SOS_OK;}static struct sos_fs_node_ops_file virtfs_ops_file = (struct sos_fs_node_ops_file){ .truncate = virtfs_truncate, .stat = virtfs_stat_node, .chmod = virtfs_chmod_node };static sos_ret_t virtfs_new_opened_file(struct sos_fs_node * this, const struct sos_process * owner, sos_ui32_t open_flags, struct sos_fs_opened_file ** result_of){ struct sos_fs_opened_file * of = (struct sos_fs_opened_file*)sos_kmalloc(sizeof(*of), 0); if (! of) return -SOS_ENOMEM; memset(of, 0x0, sizeof(*of)); of->owner = owner; of->duplicate = virtfs_duplicate_opened_file; of->open_flags = open_flags; of->ops_file = & virtfs_ops_opened_file; if (this->type == SOS_FS_NODE_DIRECTORY) of->ops_dir = & virtfs_ops_opened_dir; *result_of = of; return SOS_OK;}static sos_ret_t virtfs_close_opened_file(struct sos_fs_node * this, struct sos_fs_opened_file * of){ sos_kfree((sos_vaddr_t)of); return SOS_OK;}static sos_ret_t virtfs_symlink_expand(struct sos_fs_node *this, char const ** target, sos_size_t * target_len){ struct virtfs_node * virtfsnode = (struct virtfs_node*)this->custom_data; *target = virtfsnode->file.data; *target_len = virtfsnode->file.size; return SOS_OK;}static struct sos_fs_node_ops_symlink virtfs_ops_symlink = (struct sos_fs_node_ops_symlink){ .expand = virtfs_symlink_expand };static sos_ret_t virtfs_dir_lookup(struct sos_fs_node *this, const char * name, sos_ui16_t namelen, sos_ui64_t * result_storage_location){ struct virtfs_node * virtfsnode = (struct virtfs_node*)this->custom_data; struct virtfs_direntry * direntry; int nbentries; list_foreach_forward_named(virtfsnode->dir.list_entries, direntry, nbentries, sibling_prev, sibling_next) { if (!memcmp(name, direntry->name, namelen) && !direntry->name[namelen]) { *result_storage_location = direntry->fsnode->storage_location; return SOS_OK; } } return -SOS_ENOENT;}static sos_ret_t virtfs_link(struct sos_fs_node *this, const struct sos_process *actor, const char * entry_name, sos_ui16_t entry_namelen, struct sos_fs_node * node){ struct virtfs_node * parent = (struct virtfs_node*)this->custom_data; struct virtfs_direntry * direntry; direntry = (struct virtfs_direntry*)sos_kmalloc(sizeof(*direntry), 0); if (! direntry) return -SOS_ENOMEM; direntry->name = (char*)sos_kmalloc(entry_namelen + 1, 0); if (! direntry->name) { sos_kfree((sos_vaddr_t)direntry->name); return -SOS_ENOMEM; } memcpy(direntry->name, entry_name, entry_namelen); direntry->name[entry_namelen] = '\0'; direntry->fsnode = node; node->ondisk_lnk_cnt ++; this->ondisk_lnk_cnt ++; list_add_tail_named(parent->dir.list_entries, direntry, sibling_prev, sibling_next); /* Update the index of the new entry in order for the next readdirs to fetch this new entry */ parent->dir.top_creation_order ++; direntry->creation_order = parent->dir.top_creation_order; return SOS_OK;}static sos_ret_tvirtfs_unlink(struct sos_fs_node *this, const struct sos_process *actor, const char * entry_name, sos_ui16_t entry_namelen){ struct virtfs_node * parent = (struct virtfs_node*)this->custom_data; struct virtfs_direntry * direntry; int nbentries; list_foreach_forward_named(parent->dir.list_entries, direntry, nbentries, sibling_prev, sibling_next) { if (!memcmp(entry_name, direntry->name, entry_namelen) && !direntry->name[entry_namelen]) { list_delete_named(parent->dir.list_entries, direntry, sibling_prev, sibling_next); direntry->fsnode->ondisk_lnk_cnt --; this->ondisk_lnk_cnt --; sos_kfree((sos_vaddr_t)direntry); return SOS_OK; } } return -SOS_ENOENT;}static struct sos_fs_node_ops_dir virtfs_ops_dir = (struct sos_fs_node_ops_dir){ .lookup = virtfs_dir_lookup, .link = virtfs_link, .unlink = virtfs_unlink };/* ******************************************************** * FS instance operations *//** Simulate the access to a node located on disk. In virtfs, the "disk" is directly the kernel memory, so the "sos_fs_node::storage_location field corresponds to a kernel address */static sos_ret_tvirtfs_fetch_node_from_disk(struct sos_fs_manager_instance * this, sos_ui64_t storage_location, struct sos_fs_node ** result){ /* The "disk" is simply the ram */ struct virtfs_node * virtfsnode; virtfsnode = (struct virtfs_node *)((sos_vaddr_t)storage_location); *result = & virtfsnode->super; return SOS_OK;}static sos_ret_tvirtfs_allocate_new_node(struct sos_fs_manager_instance * this, sos_fs_node_type_t type, const struct sos_process * creator, sos_ui32_t access_rights, sos_ui32_t flags, struct sos_fs_node ** result){ struct virtfs_node * virtfsnode; /* Allow only DIRs, FILEs or special device files */ if ((type != SOS_FS_NODE_REGULAR_FILE) && (type != SOS_FS_NODE_SYMLINK) && (type != SOS_FS_NODE_DIRECTORY) && (type != SOS_FS_NODE_DEVICE_CHAR)) return -SOS_ENOSUP; virtfsnode = (struct virtfs_node*) sos_kmalloc(sizeof(*virtfsnode), 0); if (! virtfsnode) return -SOS_ENOMEM; memset(virtfsnode, 0x0, sizeof(*virtfsnode)); *result = & virtfsnode->super; /* Initialize "file" */ (*result)->inmem_ref_cnt = 1; (*result)->custom_data = virtfsnode; (*result)->storage_location = (sos_ui64_t)((sos_vaddr_t)virtfsnode); (*result)->type = type; (*result)->access_rights = access_rights; (*result)->destructor = virtfs_node_destructor; (*result)->ops_file = & virtfs_ops_file; /* The "file" functions are defined by the FS code only for non-special device files */ if (type != SOS_FS_NODE_DEVICE_CHAR) { (*result)->sync = virtfs_sync_node; (*result)->new_opened_file = virtfs_new_opened_file; (*result)->close_opened_file = virtfs_close_opened_file; } if (type == SOS_FS_NODE_SYMLINK) (*result)->ops_symlink = & virtfs_ops_symlink; else if (type == SOS_FS_NODE_DIRECTORY) (*result)->ops_dir = & virtfs_ops_dir; /* Initialize mapping structure */ if (type == SOS_FS_NODE_REGULAR_FILE) { virtfsnode->file.mapres.allowed_access_rights = SOS_VM_MAP_PROT_READ | SOS_VM_MAP_PROT_WRITE | SOS_VM_MAP_PROT_EXEC; virtfsnode->file.mapres.custom_data = virtfsnode; virtfsnode->file.mapres.mmap = virtfs_new_mapping; } list_add_tail(((struct virtfs_instance*)this->custom_data)->list_fsnodes, virtfsnode); return SOS_OK;}/* ******************************************************** * FS type (mount/umount) operations */static sos_ret_t virtfs_mount(struct sos_fs_manager_type * this, struct sos_fs_node * device, const char * args, struct sos_fs_manager_instance ** mounted_fs){ sos_ret_t retval; struct virtfs_instance * fs; struct sos_fs_node * fsnode_root; struct sos_hash_table * hash; *mounted_fs = (struct sos_fs_manager_instance*)NULL; /* Create FS node hash table */ hash = sos_hash_create("virtfs H", struct sos_fs_node, sos_hash_ui64, sos_hash_key_eq_ui64, 17, storage_location, hlink_nodecache); if (! hash) return -SOS_ENOMEM; fs = (struct virtfs_instance*) sos_kmalloc(sizeof(struct virtfs_instance), 0); if (! fs) { sos_hash_dispose(hash); return -SOS_ENOMEM; } memset(fs, 0x0, sizeof(struct virtfs_instance)); retval = sos_kmutex_init(& fs->lock, "virtfs", SOS_KWQ_ORDER_FIFO); if (SOS_OK != retval) { sos_hash_dispose(hash); sos_kfree((sos_vaddr_t) fs); return retval; } fs->super.custom_data = fs; fs->super.fs_type = this; fs->super.allocate_new_node = virtfs_allocate_new_node; fs->super.fetch_node_from_disk = virtfs_fetch_node_from_disk; fs->super.nodecache = hash; retval = virtfs_allocate_new_node(& fs->super, SOS_FS_NODE_DIRECTORY, NULL, SOS_FS_READABLE | SOS_FS_WRITABLE | SOS_FS_EXECUTABLE, 0, & fsnode_root); if (SOS_OK != retval) { sos_hash_dispose(hash); sos_kmutex_dispose(& fs->lock); sos_kfree((sos_vaddr_t) fs); return retval; } retval = sos_fs_register_fs_instance(& fs->super, fsnode_root); sos_fs_unref_fsnode(fsnode_root); if (SOS_OK != retval) { sos_hash_dispose(hash); sos_kmutex_dispose(& fs->lock); sos_kfree((sos_vaddr_t) fs); return retval; } *mounted_fs = & fs->super; return SOS_OK;}static sos_ret_t virtfs_umount(struct sos_fs_manager_type * this, struct sos_fs_manager_instance * mounted_fs){ struct virtfs_instance * virtfs = (struct virtfs_instance*)mounted_fs->custom_data; sos_hash_dispose(virtfs->super.nodecache); while (! list_is_empty(virtfs->list_fsnodes)) { struct virtfs_node * virtfsnode = list_pop_head(virtfs->list_fsnodes); if (virtfsnode->super.type == SOS_FS_NODE_REGULAR_FILE) { if (virtfsnode->file.size > 0) sos_kfree((sos_vaddr_t) virtfsnode->file.data); } else if (virtfsnode->super.type == SOS_FS_NODE_DIRECTORY) { while (! list_is_empty_named(virtfsnode->dir.list_entries, sibling_prev, sibling_next)) { struct virtfs_direntry * direntry = list_pop_head_named(virtfsnode->dir.list_entries, sibling_prev, sibling_next); sos_kfree((sos_vaddr_t)direntry->name); sos_kfree((sos_vaddr_t)direntry); } } sos_kfree((sos_vaddr_t)virtfsnode); } sos_fs_unregister_fs_instance(& virtfs->super); sos_kmutex_dispose(& virtfs->lock); sos_kfree((sos_vaddr_t)virtfs); return SOS_OK;}/* ******************************************************** * File mapping stuff */inline static struct virtfs_node *get_virtfsnode_of_vr(struct sos_umem_vmm_vr * vr){ struct sos_umem_vmm_mapped_resource *mr = sos_umem_vmm_get_mapped_resource_of_vr(vr); return (struct virtfs_node *)mr->custom_data;}static void virtfs_map_ref(struct sos_umem_vmm_vr * vr){ struct virtfs_node * virtfsnode = get_virtfsnode_of_vr(vr); sos_fs_ref_fsnode(& virtfsnode->super); virtfsnode->file.num_mappings ++;}static void virtfs_map_unref(struct sos_umem_vmm_vr * vr){ struct virtfs_node * virtfsnode = get_virtfsnode_of_vr(vr); SOS_ASSERT_FATAL(virtfsnode->file.num_mappings > 0); virtfsnode->file.num_mappings --; _sos_fs_unref_fsnode(& virtfsnode->super);}static sos_ret_t virtfs_map_page_in(struct sos_umem_vmm_vr * vr, sos_uaddr_t uaddr, sos_bool_t write_access){ struct virtfs_node * virtfsnode = get_virtfsnode_of_vr(vr); sos_luoffset_t offset = uaddr - sos_umem_vmm_get_start_of_vr(vr); sos_ret_t retval = SOS_OK; sos_paddr_t ppage_paddr; /* The region is not allowed to be resized */ if (SOS_PAGE_ALIGN_SUP(offset) > virtfsnode->file.size) return -SOS_EFAULT; /* Lookup physical kernel page */ ppage_paddr = sos_paging_get_paddr(SOS_PAGE_ALIGN_INF(virtfsnode->file.data + offset)); /* Cannot access unmapped kernel pages */ if (! ppage_paddr) return -SOS_EFAULT; /* Remap it in user space */ retval = sos_paging_map(ppage_paddr, SOS_PAGE_ALIGN_INF(uaddr), TRUE, sos_umem_vmm_get_prot_of_vr(vr)); return retval;}static struct sos_umem_vmm_vr_ops virtfs_map_ops = (struct sos_umem_vmm_vr_ops){ .ref = virtfs_map_ref, .unref = virtfs_map_unref, .page_in = virtfs_map_page_in };static sos_ret_t virtfs_new_mapping(struct sos_umem_vmm_vr *vr){ struct virtfs_node * virtfsnode = get_virtfsnode_of_vr(vr); sos_size_t reqsize; sos_ret_t retval; reqsize = sos_umem_vmm_get_offset_in_resource(vr); reqsize += sos_umem_vmm_get_size_of_vr(vr); /* Resize the region NOW */ if (reqsize > virtfsnode->file.size) { retval = virtfs_resize(virtfsnode, SOS_PAGE_ALIGN_SUP(reqsize)); if (SOS_OK != retval) return retval; } return sos_umem_vmm_set_ops_of_vr(vr, &virtfs_map_ops);}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -