让 proc 文件可读
文件位置:fs/read_write.c
添加extern,表示proc_read函数是从外部调用的
/*新增proc_read函数外部调用*/ extern int proc_read(int dev,char* buf,int count,unsigned long *pos);
然后在sys_read函数中仿照其他if语句,加上 S_IFPROC() 的分支,添加proc文件的proc_read()调用:
if (inode->i_pipe) return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO; /*新增proc_read调用*/ if (S_ISPROC(inode->i_mode)) return proc_read(inode->i_zone[0],&file->f_pos,buf,count); if (S_ISCHR(inode->i_mode)) return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos);
需要传给处理函数的参数包括:
inode->i_zone[0],这就是 mknod() 时指定的 dev ——设备编号
buf,指向用户空间,就是 read() 的第二个参数,用来接收数据
count,就是 read() 的第三个参数,说明 buf 指向的缓冲区大小
&file->f_pos,f_pos 是上一次读文件结束时“文件位置指针”的指向。这里必须传指针,因为处理函数需要根据传给 buf 的数据量修改 f_pos 的值。
实现 proc_read 函数
proc 文件的处理函数的功能是根据设备编号,把不同的内容写入到用户空间的 buf。写入的数据要从 f_pos 指向的位置开始,每次最多写 count 个字节,并根据实际写入的字节数调整 f_pos 的值,最后返回实际写入的字节数。当设备编号表明要读的是 psinfo 的内容时,就要按照 psinfo 的形式组织数据。
实现此函数可能要用到如下几个函数:
malloc() 函数
free() 函数
包含 linux/kernel.h 头文件后,就可以使用 malloc() 和 free() 函数。它们是可以被核心态代码调用的,唯一的限制是一次申请的内存大小不能超过一个页面。
文件位置:fs/proc.c
代码来自一位大佬的博客————参考代码
#include #include #include #include #include #include #define set_bit(bitnr,addr) ({ \ register int __res ; \ __asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \ __res; }) char proc_buf[4096] ={'\0'}; extern int vsprintf(char * buf, const char * fmt, va_list args); //Linux0.11没有sprintf(),该函数是用于输出结果到字符串中的,所以就实现一个,这里是通过vsprintf()实现的。 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 get_psinfo() { int read = 0; read += sprintf(proc_buf+read,"%s","pid\tstate\tfather\tcounter\tstart_time\n"); struct task_struct **p; for(p = &FIRST_TASK ; p <= &LAST_TASK ; ++p) if (*p != NULL) { read += sprintf(proc_buf+read,"%d\t",(*p)->pid); read += sprintf(proc_buf+read,"%d\t",(*p)->state); read += sprintf(proc_buf+read,"%d\t",(*p)->father); read += sprintf(proc_buf+read,"%d\t",(*p)->counter); read += sprintf(proc_buf+read,"%d\n",(*p)->start_time); } return read; } /* * 参考fs/super.c mount_root()函数 */ int get_hdinfo() { int read = 0; int i,used; struct super_block * sb; sb=get_super(0x301); /*磁盘设备号 3*256+1*/ /*Blocks信息*/ read += sprintf(proc_buf+read,"Total blocks:%d\n",sb->s_nzones); used = 0; i=sb->s_nzones; while(--i >= 0) { if(set_bit(i&8191,sb->s_zmap[i>>13]->b_data)) used++; } read += sprintf(proc_buf+read,"Used blocks:%d\n",used); read += sprintf(proc_buf+read,"Free blocks:%d\n",sb->s_nzones-used); /*Inodes 信息*/ read += sprintf(proc_buf+read,"Total inodes:%d\n",sb->s_ninodes); used = 0; i=sb->s_ninodes+1; while(--i >= 0) { if(set_bit(i&8191,sb->s_imap[i>>13]->b_data)) used++; } read += sprintf(proc_buf+read,"Used inodes:%d\n",used); read += sprintf(proc_buf+read,"Free inodes:%d\n",sb->s_ninodes-used); return read; } int get_inodeinfo() { int read = 0; int i; struct super_block * sb; struct m_inode *mi; sb=get_super(0x301); /*磁盘设备号 3*256+1*/ i=sb->s_ninodes+1; i=0; while(++i < sb->s_ninodes+1) { if(set_bit(i&8191,sb->s_imap[i>>13]->b_data)) { mi = iget(0x301,i); read += sprintf(proc_buf+read,"inr:%d;zone[0]:%d\n",mi->i_num,mi->i_zone[0]); iput(mi); } if(read >= 4000) { break; } } return read; } int proc_read(int dev, unsigned long * pos, char * buf, int count) { int i; if(*pos % 1024 == 0) { if(dev == 0) get_psinfo(); if(dev == 1) get_hdinfo(); if(dev == 2) get_inodeinfo(); } for(i=0;i { if(proc_buf[i+ *pos ] == '\0') break; put_fs_byte(proc_buf[i+ *pos],buf + i+ *pos); } *pos += i; return i; }
同时修改fs/Makefile文件:
OBJS= open.o read_write.o inode.o file_table.o buffer.o super.o \ block_dev.o char_dev.o file_dev.o stat.o exec.o pipe.o namei.o \ bitmap.o fcntl.o ioctl.o truncate.o proc.o //...... ### Dependencies: proc.o : proc.c ../include/linux/kernel.h ../include/linux/sched.h \ ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ ../include/linux/mm.h ../include/signal.h ../include/asm/segment.h
编译运行
再次重新编译内核make all,然后运行内核,查看psinfo(当前系统进程状态信息)和hdinfo(硬盘信息)的信息:
天道酬勤
byez