#include "procfs.h" //定义文件类型 #define PROC_STATUS 1 //定义buffer大小 #define FDATA_RBUF_SIZE 1024 struct vfs_super_block_operations_t procfs_sb_ops; struct vfs_dir_entry_operations_t procfs_dentry_ops; struct vfs_file_operations_t procfs_file_ops; struct vfs_inode_operations_t procfs_inode_ops; struct vfs_superblock_t procfs_sb = {0}; struct vfs_dir_entry_t *procfs_root_dentry; // 根结点的dentry static spinlock_t procfs_global_lock; // procfs的全局锁 const char __procfs_mount_path[] = "/proc"; // 挂在路径 static int64_t proc_create_file(const char *path, mode_t type, long pid); static int __check_name_available(const char *name, int namelen, int8_t reserved); static long simple_procfs_read(void *to, int64_t count, long *position, void *from, int64_t available); /** * @brief 文件的私有信息结构 * */ struct procfs_file_private_data { int readlen; char *rbuffer; int writelen; char *wbuffer; }; /** * @brief 创建procfs的super block * * @param blk 未使用(procfs为伪文件系统,不需要物理设备) * @return struct vfs_superblock_t* */ struct vfs_superblock_t *procfs_read_superblock(struct block_device *blk) { procfs_sb.blk_device = NULL; procfs_sb.root = procfs_root_dentry; procfs_sb.sb_ops = &procfs_sb_ops; procfs_sb.dir_ops = &procfs_dentry_ops; procfs_sb.private_sb_info = NULL; kdebug("procfs read superblock done"); return &procfs_sb; } static void procfs_write_superblock(struct vfs_superblock_t *sb) { return; } static void procfs_put_superblock(struct vfs_superblock_t *sb) { return; } static void procfs_write_inode(struct vfs_index_node_t *inode) { return; } struct vfs_super_block_operations_t procfs_sb_ops = { .write_superblock = &procfs_write_superblock, .put_superblock = &procfs_put_superblock, .write_inode = &procfs_write_inode, }; static long procfs_compare(struct vfs_dir_entry_t *parent_dEntry, char *source_filename, char *dest_filename) { return 0; } static long procfs_hash(struct vfs_dir_entry_t *dEntry, char *filename) { return 0; } static long procfs_release(struct vfs_dir_entry_t *dEntry) { return 0; } static long procfs_iput(struct vfs_dir_entry_t *dEntry, struct vfs_index_node_t *inode) { return 0; } struct vfs_dir_entry_operations_t procfs_dentry_ops = { .compare = &procfs_compare, .hash = &procfs_hash, .release = &procfs_release, .iput = &procfs_iput, }; void data_puts(struct procfs_file_private_data *fdata, const char *s) { int len = strlen(s); if(fdata->readlen+len > FDATA_RBUF_SIZE) { kerror("out of buffer"); return; } strncpy(fdata->rbuffer + fdata->readlen, s, len); fdata->readlen += len; } static long procfs_open(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) { if (inode->attribute & VFS_IF_DIR) { return 0; } struct procfs_inode_info_t *finode = inode->private_inode_info; if (finode == NULL) { return 0; } // kdebug("finode=%#018lx", finode); struct procfs_file_private_data *fdata = kzalloc(sizeof(struct procfs_file_private_data), 0); struct process_control_block *pcb_t = process_find_pcb_by_pid(finode->pid); //判断文件类型 int mode = finode->type; fdata->rbuffer = kzalloc(FDATA_RBUF_SIZE, 0); int len = 0; switch (mode) { case 1: data_puts(fdata, "Name:\t"); data_puts(fdata, pcb_t->name); data_puts(fdata, "\nstate:\t"); data_puts(fdata, ltoa(pcb_t->state)); data_puts(fdata, "\npid:\t"); data_puts(fdata, ltoa(pcb_t->pid)); data_puts(fdata, "\nPpid:\t"); data_puts(fdata, ltoa(pcb_t->parent_pcb->pid)); data_puts(fdata, "\ncpu_id:\t"); data_puts(fdata, ltoa(pcb_t->cpu_id)); data_puts(fdata, "\npriority:\t"); data_puts(fdata, ltoa(pcb_t->priority)); data_puts(fdata, "\npreempt:\t"); data_puts(fdata, ltoa(pcb_t->preempt_count)); data_puts(fdata, "\nvrtime:\t"); data_puts(fdata, ltoa(pcb_t->virtual_runtime)); // data_puts(fdata,"\n"); uint64_t hiwater_vm, text, data; hiwater_vm = pcb_t->mm->vmas->vm_end - pcb_t->mm->vmas->vm_start; text = pcb_t->mm->code_addr_end - pcb_t->mm->code_addr_start; data = pcb_t->mm->data_addr_end - pcb_t->mm->data_addr_start; data_puts(fdata, "\nVmPeak:"); data_puts(fdata, ltoa(hiwater_vm)); data_puts(fdata, " kB"); data_puts(fdata, "\nVmData:"); data_puts(fdata, ltoa(data)); data_puts(fdata, " kB"); data_puts(fdata, "\nVmExe:"); data_puts(fdata, ltoa(text)); data_puts(fdata, " kB\n"); break; default: break; } inode->file_size = fdata->readlen; file_ptr->private_data = fdata; return 0; } static long procfs_close(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) { return 0; } static long procfs_read(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) { // 获取私有信息 struct procfs_file_private_data *priv = (struct procfs_file_private_data *)file_ptr->private_data; // kdebug("priv=%#018lx", priv); if (!priv->rbuffer) return -EINVAL; return simple_procfs_read(buf, count, position, priv->rbuffer, priv->readlen); } /** * @brief 检查读取并将数据从内核拷贝到用户 * * @param to: 要读取的用户空间缓冲区 * @param count: 要读取的最大字节数 * @param position: 缓冲区中的当前位置 * @param from: 要读取的缓冲区 * @param available: 读取的缓冲区大小 * * @return long 读取字节数 */ static long simple_procfs_read(void *to, int64_t count, long *position, void *from, int64_t available) { long pos = *position; // kdebug("pos:%ld",pos); // kdebug("count:%ld",count); // kdebug("available:%ld",available); int64_t ret = 0; if (pos < 0) return -EINVAL; if (pos >= available || !count) return 0; if (count > available - pos) count = available - pos; // kdebug("count:%d",count); ret = copy_to_user(to, from + pos, count); *position = pos + ret; return ret; } static long procfs_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) { return 0; } /** * @brief 调整文件的访问位置 * * @param file_ptr 文件描述符号 * @param offset 偏移量 * @param whence 调整模式 * @return uint64_t 调整结束后的文件访问位置 */ static long procfs_lseek(struct vfs_file_t *file_ptr, long offset, long whence) { struct vfs_index_node_t *inode = file_ptr->dEntry->dir_inode; long pos = 0; switch (whence) { case SEEK_SET: // 相对于文件头 pos = offset; break; case SEEK_CUR: // 相对于当前位置 pos = file_ptr->position + offset; break; case SEEK_END: // 相对于文件末尾 pos = file_ptr->dEntry->dir_inode->file_size + offset; break; default: return -EINVAL; break; } if (pos < 0 || pos > file_ptr->dEntry->dir_inode->file_size) return -EOVERFLOW; file_ptr->position = pos; return pos; } static long procfs_ioctl(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr, uint64_t cmd, uint64_t arg) { return 0; } /** * @brief 读取该目录下的目录项 * * @param file_ptr 文件结构体的指针 * @param dirent 返回的dirent * @param filler 填充dirent的函数 * * @return long 错误码 */ static long procfs_readdir(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler) { struct vfs_dir_entry_t *dentry = file_ptr->dEntry; struct List *list = &dentry->subdirs_list; // 先切换到position处 for (int i = 0; i <= file_ptr->position; ++i) { list = list_next(list); if (list == &dentry->subdirs_list) // 找完了 goto failed; } // 若存在目录项,则增加偏移量 ++file_ptr->position; // 获取目标dentry(由于是子目录项,因此是child_node_list) struct vfs_dir_entry_t *target_dent = container_of(list, struct vfs_dir_entry_t, child_node_list); char *name = (char *)kzalloc(target_dent->name_length + 1, 0); strncpy(name, target_dent->name, target_dent->name_length); uint32_t dentry_type; if (target_dent->dir_inode->attribute & VFS_IF_DIR) dentry_type = VFS_IF_DIR; else dentry_type = VFS_IF_FILE; return filler(dirent, file_ptr->position - 1, name, target_dent->name_length, dentry_type, file_ptr->position - 1); failed:; return 0; } struct vfs_file_operations_t procfs_file_ops = { .open = &procfs_open, .close = &procfs_close, .read = &procfs_read, .write = &procfs_write, .lseek = &procfs_lseek, .ioctl = &procfs_ioctl, .readdir = &procfs_readdir, }; /** * @brief 检查文件名是否合法 * * @param name 文件名 * @param namelen 文件名长度 * @param reserved 保留字段 * @return int 合法:0, 其他:错误码 */ static int __check_name_available(const char *name, int namelen, int8_t reserved) { if (namelen > 255 || namelen <= 0) return -ENAMETOOLONG; // 首个字符不能是空格或者'.' if (name[0] == 0x20 || name[0] == '.') return -EINVAL; return 0; }; /** * @brief 在procfs中创建文件 * * @param parent_inode 父目录的inode * @param dest_dEntry 目标dentry * @param mode 创建模式 * @return long 错误码 */ static long procfs_create(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry, int mode) { int64_t retval = 0; //检验名称和法性 retval = __check_name_available(dest_dEntry->name, dest_dEntry->name_length, 0); if (retval != 0) return retval; if (dest_dEntry->dir_inode != NULL) return -EEXIST; struct vfs_index_node_t *inode = vfs_alloc_inode(); dest_dEntry->dir_inode = inode; dest_dEntry->dir_ops = &procfs_dentry_ops; inode->attribute = VFS_IF_FILE; inode->file_ops = &procfs_file_ops; inode->file_size = 0; inode->sb = parent_inode->sb; inode->inode_ops = &procfs_inode_ops; // kdebug("finode:%#018lx",inode->private_inode_info); inode->blocks = 0; return 0; } static struct vfs_dir_entry_t *procfs_lookup(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry) { return NULL; } /** * @brief 在procfs中创建文件夹(作用是完善子文件夹的inode信息) * * @param inode 父目录的inode * @param dEntry 目标dentry * @param mode 创建模式 * @return long 错误码 */ static long procfs_mkdir(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dEntry, int mode) { int64_t retval = 0; //检验名称和法性 retval = __check_name_available(dEntry->name, dEntry->name_length, 0); if (retval != 0) return retval; struct vfs_index_node_t *inode = vfs_alloc_inode(); dEntry->dir_inode = inode; dEntry->dir_ops = &procfs_dentry_ops; //结点信息初始化 struct procfs_inode_info_t *finode = (struct procfs_inode_info_t *)kzalloc(sizeof(struct procfs_inode_info_t), 0); finode->pid = 0; finode->type = 0; inode->attribute = VFS_IF_DIR; inode->file_ops = &procfs_file_ops; inode->file_size = 0; inode->sb = parent_inode->sb; inode->inode_ops = &procfs_inode_ops; inode->private_inode_info = (void *)finode; // kdebug("inode->private_inode_info=%#018lx", inode->private_inode_info); inode->blocks = 0; return 0; } struct vfs_inode_operations_t procfs_inode_ops = { .create = &procfs_create, .lookup = &procfs_lookup, .mkdir = &procfs_mkdir, }; struct vfs_filesystem_type_t procfs_fs_type = { .name = "procfs", .fs_flags = 0, .read_superblock = procfs_read_superblock, .next = NULL, }; static __always_inline void __procfs_init_root_inode() { procfs_root_dentry->dir_inode = vfs_alloc_inode(); procfs_root_dentry->dir_inode->file_ops = &procfs_file_ops; procfs_root_dentry->dir_inode->inode_ops = &procfs_inode_ops; procfs_root_dentry->dir_inode->private_inode_info = NULL; procfs_root_dentry->dir_inode->sb = &procfs_sb; procfs_root_dentry->dir_inode->attribute = VFS_IF_DIR; } /** * @brief 初始化procfs的根dentry */ static __always_inline void __procfs_init_root_dentry() { procfs_root_dentry = vfs_alloc_dentry(0); procfs_root_dentry->dir_ops = &procfs_dentry_ops; __procfs_init_root_inode(); } /** * @brief 创建进程对应文件夹 * * @param pid 进程号 * @return int64_t 错误码 */ int64_t procfs_register_pid(long pid) { int retval = 0; //创建文件夹 char tmp[70] = {0}; int len = strlen(ltoa(pid)); // kdebug("len:%d",len); strcpy(tmp, "/proc/"); strcpy(tmp + 6, ltoa(pid)); // kdebug("tmp:%s",tmp); retval = vfs_mkdir(tmp, 0, false); // kdebug("aaaaaaaaaaaaaaa"); //创建各相关文件 strcpy(tmp + 6 + len, "/status"); // kdebug("tmp:%s",tmp); retval = proc_create_file(tmp, PROC_STATUS, pid); return retval; } /** * @brief 创建文件 * * @param path 文件夹路径 * @param type 文件类型 * @param pid pid * @return int64_t 错误码 */ static int64_t proc_create_file(const char *path, mode_t type, long pid) { kdebug("procfs: Creating: %s", path); int ret = do_open(path, O_CREAT, false); // kdebug("ret:%d", ret); struct vfs_dir_entry_t *dentry = vfs_path_walk(path, 0); // kdebug("dentry=%#018lx", dentry); //结点信息配置 struct procfs_inode_info_t *finode = (struct procfs_inode_info_t *)kzalloc(sizeof(struct procfs_inode_info_t), 0); finode->pid = pid; // kdebug("pid:%d",finode->pid); finode->type = type; dentry->dir_inode->private_inode_info = (void *)finode; ret = vfs_close(ret); return ret; } /** * @brief 初始化procfs * */ void procfs_init() { __procfs_init_root_dentry(); vfs_register_filesystem(&procfs_fs_type); spin_init(&procfs_global_lock); vfs_mount_fs(__procfs_mount_path, "procfs", NULL); }