1 #include "procfs.h"
2 
3 //定义文件类型
4 #define PROC_STATUS 1
5 
6 //定义buffer大小
7 #define FDATA_RBUF_SIZE 1024
8 
9 struct vfs_super_block_operations_t procfs_sb_ops;
10 struct vfs_dir_entry_operations_t procfs_dentry_ops;
11 struct vfs_file_operations_t procfs_file_ops;
12 struct vfs_inode_operations_t procfs_inode_ops;
13 
14 struct vfs_superblock_t procfs_sb = {0};
15 struct vfs_dir_entry_t *procfs_root_dentry; // 根结点的dentry
16 static spinlock_t procfs_global_lock;       // procfs的全局锁
17 const char __procfs_mount_path[] = "/proc"; // 挂在路径
18 
19 static int64_t proc_create_file(const char *path, mode_t type, long pid);
20 static int __check_name_available(const char *name, int namelen, int8_t reserved);
21 static long simple_procfs_read(void *to, int64_t count, long *position, void *from, int64_t available);
22 
23 /**
24  * @brief 文件的私有信息结构
25  *
26  */
27 struct procfs_file_private_data
28 {
29     int readlen;
30     char *rbuffer;
31     int writelen;
32     char *wbuffer;
33 };
34 
35 /**
36  * @brief 创建procfs的super block
37  *
38  * @param blk 未使用(procfs为伪文件系统,不需要物理设备)
39  * @return struct vfs_superblock_t*
40  */
procfs_read_superblock(struct block_device * blk)41 struct vfs_superblock_t *procfs_read_superblock(struct block_device *blk)
42 {
43     procfs_sb.blk_device = NULL;
44     procfs_sb.root = procfs_root_dentry;
45     procfs_sb.sb_ops = &procfs_sb_ops;
46     procfs_sb.dir_ops = &procfs_dentry_ops;
47     procfs_sb.private_sb_info = NULL;
48     kdebug("procfs read superblock done");
49     return &procfs_sb;
50 }
51 
procfs_write_superblock(struct vfs_superblock_t * sb)52 static void procfs_write_superblock(struct vfs_superblock_t *sb)
53 {
54     return;
55 }
procfs_put_superblock(struct vfs_superblock_t * sb)56 static void procfs_put_superblock(struct vfs_superblock_t *sb)
57 {
58     return;
59 }
procfs_write_inode(struct vfs_index_node_t * inode)60 static void procfs_write_inode(struct vfs_index_node_t *inode)
61 {
62     return;
63 }
64 struct vfs_super_block_operations_t procfs_sb_ops = {
65     .write_superblock = &procfs_write_superblock,
66     .put_superblock = &procfs_put_superblock,
67     .write_inode = &procfs_write_inode,
68 };
69 
procfs_compare(struct vfs_dir_entry_t * parent_dEntry,char * source_filename,char * dest_filename)70 static long procfs_compare(struct vfs_dir_entry_t *parent_dEntry, char *source_filename, char *dest_filename)
71 {
72     return 0;
73 }
procfs_hash(struct vfs_dir_entry_t * dEntry,char * filename)74 static long procfs_hash(struct vfs_dir_entry_t *dEntry, char *filename)
75 {
76     return 0;
77 }
procfs_release(struct vfs_dir_entry_t * dEntry)78 static long procfs_release(struct vfs_dir_entry_t *dEntry)
79 {
80     return 0;
81 }
procfs_iput(struct vfs_dir_entry_t * dEntry,struct vfs_index_node_t * inode)82 static long procfs_iput(struct vfs_dir_entry_t *dEntry, struct vfs_index_node_t *inode)
83 {
84     return 0;
85 }
86 struct vfs_dir_entry_operations_t procfs_dentry_ops = {
87     .compare = &procfs_compare,
88     .hash = &procfs_hash,
89     .release = &procfs_release,
90     .iput = &procfs_iput,
91 };
92 
data_puts(struct procfs_file_private_data * fdata,const char * s)93 void data_puts(struct procfs_file_private_data *fdata, const char *s)
94 {
95     int len = strlen(s);
96     if(fdata->readlen+len > FDATA_RBUF_SIZE)
97     {
98         kerror("out of buffer");
99         return;
100     }
101     strncpy(fdata->rbuffer + fdata->readlen, s, len);
102     fdata->readlen += len;
103 }
104 
procfs_open(struct vfs_index_node_t * inode,struct vfs_file_t * file_ptr)105 static long procfs_open(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr)
106 {
107     if (inode->attribute & VFS_IF_DIR)
108     {
109         return 0;
110     }
111 
112     struct procfs_inode_info_t *finode = inode->private_inode_info;
113     if (finode == NULL)
114     {
115         return 0;
116     }
117     // kdebug("finode=%#018lx", finode);
118     struct procfs_file_private_data *fdata = kzalloc(sizeof(struct procfs_file_private_data), 0);
119     struct process_control_block *pcb_t = process_find_pcb_by_pid(finode->pid);
120     //判断文件类型
121     int mode = finode->type;
122     fdata->rbuffer = kzalloc(FDATA_RBUF_SIZE, 0);
123     int len = 0;
124     switch (mode)
125     {
126     case 1:
127         data_puts(fdata, "Name:\t");
128         data_puts(fdata, pcb_t->name);
129         data_puts(fdata, "\nstate:\t");
130         data_puts(fdata, ltoa(pcb_t->state));
131         data_puts(fdata, "\npid:\t");
132         data_puts(fdata, ltoa(pcb_t->pid));
133         data_puts(fdata, "\nPpid:\t");
134         data_puts(fdata, ltoa(pcb_t->parent_pcb->pid));
135         data_puts(fdata, "\ncpu_id:\t");
136         data_puts(fdata, ltoa(pcb_t->cpu_id));
137         data_puts(fdata, "\npriority:\t");
138         data_puts(fdata, ltoa(pcb_t->priority));
139         data_puts(fdata, "\npreempt:\t");
140         data_puts(fdata, ltoa(pcb_t->preempt_count));
141         data_puts(fdata, "\nvrtime:\t");
142         data_puts(fdata, ltoa(pcb_t->virtual_runtime));
143 
144         // data_puts(fdata,"\n");
145 
146         uint64_t hiwater_vm, text, data;
147         hiwater_vm = pcb_t->mm->vmas->vm_end - pcb_t->mm->vmas->vm_start;
148         text = pcb_t->mm->code_addr_end - pcb_t->mm->code_addr_start;
149         data = pcb_t->mm->data_addr_end - pcb_t->mm->data_addr_start;
150 
151         data_puts(fdata, "\nVmPeak:");
152         data_puts(fdata, ltoa(hiwater_vm));
153         data_puts(fdata, " kB");
154         data_puts(fdata, "\nVmData:");
155         data_puts(fdata, ltoa(data));
156         data_puts(fdata, " kB");
157         data_puts(fdata, "\nVmExe:");
158         data_puts(fdata, ltoa(text));
159         data_puts(fdata, " kB\n");
160 
161         break;
162 
163     default:
164         break;
165     }
166 
167     inode->file_size = fdata->readlen;
168     file_ptr->private_data = fdata;
169     return 0;
170 }
procfs_close(struct vfs_index_node_t * inode,struct vfs_file_t * file_ptr)171 static long procfs_close(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr)
172 {
173     return 0;
174 }
procfs_read(struct vfs_file_t * file_ptr,char * buf,int64_t count,long * position)175 static long procfs_read(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position)
176 {
177     // 获取私有信息
178     struct procfs_file_private_data *priv = (struct procfs_file_private_data *)file_ptr->private_data;
179     // kdebug("priv=%#018lx", priv);
180     if (!priv->rbuffer)
181         return -EINVAL;
182 
183     return simple_procfs_read(buf, count, position, priv->rbuffer, priv->readlen);
184 }
185 
186 /**
187  * @brief 检查读取并将数据从内核拷贝到用户
188  *
189  * @param to: 要读取的用户空间缓冲区
190  * @param count: 要读取的最大字节数
191  * @param position: 缓冲区中的当前位置
192  * @param from: 要读取的缓冲区
193  * @param available: 读取的缓冲区大小
194  *
195  * @return long 读取字节数
196  */
simple_procfs_read(void * to,int64_t count,long * position,void * from,int64_t available)197 static long simple_procfs_read(void *to, int64_t count, long *position, void *from, int64_t available)
198 {
199     long pos = *position;
200     // kdebug("pos:%ld",pos);
201     // kdebug("count:%ld",count);
202     // kdebug("available:%ld",available);
203     int64_t ret = 0;
204 
205     if (pos < 0)
206         return -EINVAL;
207     if (pos >= available || !count)
208         return 0;
209     if (count > available - pos)
210         count = available - pos;
211     // kdebug("count:%d",count);
212     ret = copy_to_user(to, from + pos, count);
213 
214     *position = pos + ret;
215     return ret;
216 }
217 
procfs_write(struct vfs_file_t * file_ptr,char * buf,int64_t count,long * position)218 static long procfs_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position)
219 {
220     return 0;
221 }
222 /**
223  * @brief 调整文件的访问位置
224  *
225  * @param file_ptr 文件描述符号
226  * @param offset 偏移量
227  * @param whence 调整模式
228  * @return uint64_t 调整结束后的文件访问位置
229  */
procfs_lseek(struct vfs_file_t * file_ptr,long offset,long whence)230 static long procfs_lseek(struct vfs_file_t *file_ptr, long offset, long whence)
231 {
232     struct vfs_index_node_t *inode = file_ptr->dEntry->dir_inode;
233 
234     long pos = 0;
235     switch (whence)
236     {
237     case SEEK_SET: // 相对于文件头
238         pos = offset;
239         break;
240     case SEEK_CUR: // 相对于当前位置
241         pos = file_ptr->position + offset;
242         break;
243     case SEEK_END: // 相对于文件末尾
244         pos = file_ptr->dEntry->dir_inode->file_size + offset;
245         break;
246 
247     default:
248         return -EINVAL;
249         break;
250     }
251 
252     if (pos < 0 || pos > file_ptr->dEntry->dir_inode->file_size)
253         return -EOVERFLOW;
254     file_ptr->position = pos;
255 
256     return pos;
257 }
procfs_ioctl(struct vfs_index_node_t * inode,struct vfs_file_t * file_ptr,uint64_t cmd,uint64_t arg)258 static long procfs_ioctl(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr, uint64_t cmd, uint64_t arg)
259 {
260     return 0;
261 }
262 
263 /**
264  * @brief 读取该目录下的目录项
265  *
266  * @param file_ptr 文件结构体的指针
267  * @param dirent 返回的dirent
268  * @param filler 填充dirent的函数
269  *
270  * @return long 错误码
271  */
procfs_readdir(struct vfs_file_t * file_ptr,void * dirent,vfs_filldir_t filler)272 static long procfs_readdir(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler)
273 {
274     struct vfs_dir_entry_t *dentry = file_ptr->dEntry;
275     struct List *list = &dentry->subdirs_list;
276     // 先切换到position处
277     for (int i = 0; i <= file_ptr->position; ++i)
278     {
279         list = list_next(list);
280         if (list == &dentry->subdirs_list) // 找完了
281             goto failed;
282     }
283 
284     // 若存在目录项,则增加偏移量
285     ++file_ptr->position;
286     // 获取目标dentry(由于是子目录项,因此是child_node_list)
287     struct vfs_dir_entry_t *target_dent = container_of(list, struct vfs_dir_entry_t, child_node_list);
288 
289     char *name = (char *)kzalloc(target_dent->name_length + 1, 0);
290     strncpy(name, target_dent->name, target_dent->name_length);
291     uint32_t dentry_type;
292     if (target_dent->dir_inode->attribute & VFS_IF_DIR)
293         dentry_type = VFS_IF_DIR;
294     else
295         dentry_type = VFS_IF_FILE;
296 
297     return filler(dirent, file_ptr->position - 1, name, target_dent->name_length, dentry_type, file_ptr->position - 1);
298 failed:;
299     return 0;
300 }
301 
302 struct vfs_file_operations_t procfs_file_ops = {
303     .open = &procfs_open,
304     .close = &procfs_close,
305     .read = &procfs_read,
306     .write = &procfs_write,
307     .lseek = &procfs_lseek,
308     .ioctl = &procfs_ioctl,
309     .readdir = &procfs_readdir,
310 };
311 
312 /**
313  * @brief 检查文件名是否合法
314  *
315  * @param name 文件名
316  * @param namelen 文件名长度
317  * @param reserved 保留字段
318  * @return int 合法:0, 其他:错误码
319  */
__check_name_available(const char * name,int namelen,int8_t reserved)320 static int __check_name_available(const char *name, int namelen, int8_t reserved)
321 {
322     if (namelen > 255 || namelen <= 0)
323         return -ENAMETOOLONG;
324     // 首个字符不能是空格或者'.'
325     if (name[0] == 0x20 || name[0] == '.')
326         return -EINVAL;
327 
328     return 0;
329 };
330 
331 /**
332  * @brief 在procfs中创建文件
333  *
334  * @param parent_inode 父目录的inode
335  * @param dest_dEntry 目标dentry
336  * @param mode 创建模式
337  * @return long 错误码
338  */
procfs_create(struct vfs_index_node_t * parent_inode,struct vfs_dir_entry_t * dest_dEntry,int mode)339 static long procfs_create(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry, int mode)
340 {
341     int64_t retval = 0;
342 
343     //检验名称和法性
344     retval = __check_name_available(dest_dEntry->name, dest_dEntry->name_length, 0);
345     if (retval != 0)
346         return retval;
347     if (dest_dEntry->dir_inode != NULL)
348         return -EEXIST;
349 
350     struct vfs_index_node_t *inode = vfs_alloc_inode();
351     dest_dEntry->dir_inode = inode;
352     dest_dEntry->dir_ops = &procfs_dentry_ops;
353 
354     inode->attribute = VFS_IF_FILE;
355     inode->file_ops = &procfs_file_ops;
356     inode->file_size = 0;
357     inode->sb = parent_inode->sb;
358     inode->inode_ops = &procfs_inode_ops;
359     // kdebug("finode:%#018lx",inode->private_inode_info);
360     inode->blocks = 0;
361 
362     return 0;
363 }
procfs_lookup(struct vfs_index_node_t * parent_inode,struct vfs_dir_entry_t * dest_dEntry)364 static struct vfs_dir_entry_t *procfs_lookup(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry)
365 {
366     return NULL;
367 }
368 
369 /**
370  * @brief 在procfs中创建文件夹(作用是完善子文件夹的inode信息)
371  *
372  * @param inode 父目录的inode
373  * @param dEntry 目标dentry
374  * @param mode 创建模式
375  * @return long 错误码
376  */
procfs_mkdir(struct vfs_index_node_t * parent_inode,struct vfs_dir_entry_t * dEntry,int mode)377 static long procfs_mkdir(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dEntry, int mode)
378 {
379     int64_t retval = 0;
380 
381     //检验名称和法性
382     retval = __check_name_available(dEntry->name, dEntry->name_length, 0);
383     if (retval != 0)
384         return retval;
385 
386     struct vfs_index_node_t *inode = vfs_alloc_inode();
387     dEntry->dir_inode = inode;
388     dEntry->dir_ops = &procfs_dentry_ops;
389 
390     //结点信息初始化
391     struct procfs_inode_info_t *finode = (struct procfs_inode_info_t *)kzalloc(sizeof(struct procfs_inode_info_t), 0);
392     finode->pid = 0;
393     finode->type = 0;
394 
395     inode->attribute = VFS_IF_DIR;
396     inode->file_ops = &procfs_file_ops;
397     inode->file_size = 0;
398     inode->sb = parent_inode->sb;
399     inode->inode_ops = &procfs_inode_ops;
400     inode->private_inode_info = (void *)finode;
401     // kdebug("inode->private_inode_info=%#018lx", inode->private_inode_info);
402     inode->blocks = 0;
403 
404     return 0;
405 }
406 struct vfs_inode_operations_t procfs_inode_ops = {
407     .create = &procfs_create,
408     .lookup = &procfs_lookup,
409     .mkdir = &procfs_mkdir,
410 };
411 
412 struct vfs_filesystem_type_t procfs_fs_type = {
413     .name = "procfs",
414     .fs_flags = 0,
415     .read_superblock = procfs_read_superblock,
416     .next = NULL,
417 };
418 
__procfs_init_root_inode()419 static __always_inline void __procfs_init_root_inode()
420 {
421     procfs_root_dentry->dir_inode = vfs_alloc_inode();
422     procfs_root_dentry->dir_inode->file_ops = &procfs_file_ops;
423     procfs_root_dentry->dir_inode->inode_ops = &procfs_inode_ops;
424 
425     procfs_root_dentry->dir_inode->private_inode_info = NULL;
426     procfs_root_dentry->dir_inode->sb = &procfs_sb;
427     procfs_root_dentry->dir_inode->attribute = VFS_IF_DIR;
428 }
429 /**
430  * @brief 初始化procfs的根dentry
431  */
__procfs_init_root_dentry()432 static __always_inline void __procfs_init_root_dentry()
433 {
434     procfs_root_dentry = vfs_alloc_dentry(0);
435     procfs_root_dentry->dir_ops = &procfs_dentry_ops;
436 
437     __procfs_init_root_inode();
438 }
439 
440 /**
441  * @brief 创建进程对应文件夹
442  *
443  * @param pid 进程号
444  * @return int64_t 错误码
445  */
procfs_register_pid(long pid)446 int64_t procfs_register_pid(long pid)
447 {
448     int retval = 0;
449 
450     //创建文件夹
451     char tmp[70] = {0};
452     int len = strlen(ltoa(pid));
453     // kdebug("len:%d",len);
454     strcpy(tmp, "/proc/");
455     strcpy(tmp + 6, ltoa(pid));
456     // kdebug("tmp:%s",tmp);
457     retval = vfs_mkdir(tmp, 0, false);
458 
459     // kdebug("aaaaaaaaaaaaaaa");
460     //创建各相关文件
461     strcpy(tmp + 6 + len, "/status");
462     // kdebug("tmp:%s",tmp);
463     retval = proc_create_file(tmp, PROC_STATUS, pid);
464 
465     return retval;
466 }
467 
468 /**
469  * @brief 创建文件
470  *
471  * @param path 文件夹路径
472  * @param type 文件类型
473  * @param pid pid
474  * @return int64_t 错误码
475  */
proc_create_file(const char * path,mode_t type,long pid)476 static int64_t proc_create_file(const char *path, mode_t type, long pid)
477 {
478     kdebug("procfs: Creating: %s", path);
479     int ret = do_open(path, O_CREAT, false);
480     // kdebug("ret:%d", ret);
481     struct vfs_dir_entry_t *dentry = vfs_path_walk(path, 0);
482     // kdebug("dentry=%#018lx", dentry);
483 
484     //结点信息配置
485     struct procfs_inode_info_t *finode = (struct procfs_inode_info_t *)kzalloc(sizeof(struct procfs_inode_info_t), 0);
486     finode->pid = pid;
487     // kdebug("pid:%d",finode->pid);
488     finode->type = type;
489     dentry->dir_inode->private_inode_info = (void *)finode;
490     ret = vfs_close(ret);
491 
492     return ret;
493 }
494 
495 /**
496  * @brief 初始化procfs
497  *
498  */
procfs_init()499 void procfs_init()
500 {
501     __procfs_init_root_dentry();
502     vfs_register_filesystem(&procfs_fs_type);
503     spin_init(&procfs_global_lock);
504     vfs_mount_fs(__procfs_mount_path, "procfs", NULL);
505 }
506