• 掌握虚拟文件系统的实现原理;
• 实践文件、目录、文件系统等概念。
实验内容:
在 Linux 0.11 上实现 procfs(proc 文件系统)内的 psinfo 结点。当读取此结点的内容时,可得到系统当前所有进程的状态信息。
实验步骤:
2.使创建结点的mknod() 函数支持新的文件类型,修改 fs/namei.c 文件中的 sys_mknod() 函数
3.建立 / proc目录和目录下的结点
建立目录和结点分别需要调用mkdir()和mknod()系统调用。因为初始化时已经在用户态,所以不能直接调用sys_mkdir()和sys_mknod()。必须在初始化代码所在文件中实现这两个系统调用的用户态接口
接下来即可在init()中创建目录和节点,增加如下代码
4.修改sys_read()系统调用,使之能够读取proc类型文件。打开文件fs/read_write.c ,在其中的sys_read函数中,增添如下语句
在文件开头添加全局声明
在fs目录下创建proc.c文件,实现了vsprintf和proc_read代码如下
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <stdarg.h>
#include <stddef.h>
extern int vsprintf(char * buf, const char * fmt, va_list args);
int sprintf(char *buf, const char *fmt, ...){
va_list args; int i;
va_start(args, fmt);
i=vsprintf(buf, fmt, args);
va_end(args);
return i;
}
int proc_read(int dev, char * buf, int count, unsigned long * pos){
struct task_struct ** p;
int output_count=0;
char * proc_buf=NULL;
int file_size=0;
int offset=*pos;
struct super_block * sb;
struct buffer_head * bh;
int total_blocks, total_inodes;
int used_blocks=0, free_blocks=0;
int i,j,k;
char * db=NULL;
unsigned short s_imap_blocks;
unsigned short s_zmap_blocks;
//硬盘总共有多少块(空闲 + 非空闲),有多少inode索引节点等信息都放在super块中。
sb=get_super(current->root->i_dev);
total_blocks = sb->s_nzones;
total_inodes=sb->s_ninodes;
s_imap_blocks = sb->s_imap_blocks;
s_zmap_blocks = sb->s_zmap_blocks;
if(dev==0)
{
proc_buf=(char *)malloc(sizeof(char *)*1024);
file_size=sprintf(proc_buf,"pid\tstate\tfather\tcounter\tstart_time\n");
//借鉴进程切换函数schedule()的代码,也就是遍历系统全部的进程。
for(p = &LAST_TASK ; p >= &FIRST_TASK ; --p)
if(*p)
file_size+=sprintf(proc_buf+file_size,"%d\t%d\t%d\t%d\t%d\n",(*p)->pid,(*p)->state,(*p)->father,(*p)->counter,(*p)->start_time);
*(proc_buf+file_size)='\0';
}
//hdinfo: 打印出硬盘信息,
if(dev==1)
{
for(i=0;i<sb->s_zmap_blocks;i++)
{
bh=sb->s_zmap[i];
db=(char*)bh->b_data;
for(j=0;j<1024;j++){
for(k=1;k<=8;k++){
if((used_blocks+free_blocks)>=total_blocks)
break;
if( *(db+j) & k)
used_blocks++;
else
free_blocks++;
}
}
}
proc_buf=(char*)malloc(sizeof(char*)*512);
file_size=sprintf(proc_buf,"s_imap_blocks:%d\ns_zmap_blocks:%d\n",s_imap_blocks,s_zmap_blocks);
file_size+=sprintf(proc_buf+file_size,"total_blocks:%d\nfree_blcoks:%d\nused_blocks:%d\ntotal_indoes:%d\n",total_blocks,free_blocks,used_blocks,total_inodes);
}
//将proc_buf缓冲区的内容放入文件
while(count>0){
if(offset>file_size)
break;
put_fs_byte(*(proc_buf+offset),buf++);
offset++;
output_count++;
count--;
}
//重置文件的pos位置,也就是指向文件末尾的指针
(*pos)+=output_count;
free(proc_buf);
return output_count;
}
copy
由于添加了一个新文件,所以需要修改fs/Makefile中的编译规则
然后在dependencies中增加如下代码
6.编译内核,运行,测试
在linux-0.11的目录下make all
然后../run
在模拟器界面输入cat /proc/psinfo
cat /proc/hdinfo
查看信息:
• 如果要求你在psinfo之外再实现另一个结点,具体内容自选,那么你会实现一个给出什么信息的结点?为什么?
答:如果再实现另一个结点,我想会选内存使用的信息情况,因为它是外存与CPU进行沟通的桥梁。计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大,能及时了解内存的使用情况是有意义的。
• 一次read()未必能读出所有的数据,需要继续read(),直到把数据读空为止。而数次read()之间,进程的状态可能会发生变化。你认为后几次read()传给用户的数据,应该是变化后的,还是变化前的? 如果是变化后的,那么用户得到的数据衔接部分是否会有混乱?如何防止混乱? 如果是变化前的,那么该在什么样的情况下更新psinfo的内容?
答:(1)是变化后,可能会导致信息混乱。(2)如果要防止混乱发生,可以考虑将取到的进程信息保存在硬盘的一个文件中,读取时只要该文件存在,就从文件中直接读取,而不是每次read都重新生成进程信息,而一次读动作完成后(返回0)就将硬盘上的文件删除。这样下次再时再次生成文件。这样可以保证传递的数据是一致的。
学习时间 210分钟
操作时间 30分钟
按键次数 3054次
实验次数 3次
报告字数 4944字
是否完成 完成