IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 哈工大李治军老师操作系统实验之PROC文件系统实现 -> 正文阅读

[系统运维]哈工大李治军老师操作系统实验之PROC文件系统实现

实验目的

  • 掌握虚拟文件系统的实现原理
  • 实践文件、目录、文件系统等概念

实验内容

在Linux0.11 上实现procfs(proc文件系统)内的psinfo结点。读取此结点内容时,可得到系统当前所有进程的状态信息。例如用cat命令显示/proc/psinfo的内容:

cat /proc/psinfo
pid      state    father     counter      start_time
0        1          -1          0              0
1        1          0           28             1
2        1          1           1              73
4        1          1           27             63
6        0          4           12             817

procfs及其结点要在内核启动时创建。相关功能实现在fs/proc.c文件当中。

实验过程

  1. include/sys/stat.h 中增加一种文件类型,实验手册里面有写。

    .....
    //定义一种新的文件类型
    #define S_IFPROC 0060000
    .....
    //定义测试宏
    #define S_ISPROC(m) (((m)&S_IFMT) == S_IFPROC)
    ....
    
  2. psinfo结点通过fs/namei.c 文件中的mknod() 系统调用(用户态调用)建立,由于我们添加了新的文件类型,需要在该文件下增加对新文件类型的支持使得在第三步能通过mknod()函数创建psinfo 文件,我们可以直接修改该系统调用的内核实现sys_mknod()

    ....
    inode->i_mode = mode;
    	if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISPROC(mode))
    		inode->i_zone[0] = dev;
    .....
    
  3. 接下来就是建立/proc 目录以及在该目录下面 创建psinfo 文件。

    创建目录我们在终端一般使用mkdir 命令, 在内核态使用sys_mkdir函数。

    创建文件我们在第二步已经在mknod() 函数添加了对新文件类型的支持,在内核态使用sys_mknod()函数

    我们可以在系统启动时就建立那些proc文件系统(注意这些文件系统是挂载在根文件系统 下面的,我们自定义的proc文件系统在系统中的位置是根文件系统/proc)Linux对文件系统的初始化是在根文件系统挂载之后才开始的。对根文件系统是在init/main.c 文件下面的init()函数中完成的。

    void init(void)
    {
    	int pid,i;
       //挂载文件系统
    	setup((void *) &drive_info);
    	(void) open("/dev/tty0",O_RDWR,0);
    	....
    }
    

    现在只要在挂载根文件系统之后就可以创建我们的目录以及文件了,但是有个地方需要注意:此时我们处在用户态,因此我们不能直接使用内核态才能使用的sys_mkdir()以及sys_mknod() ,如果我们需要调用内核态的函数,我们需要先实现用户态的API接口然后通过中断进入内核态调用相应的函数(这是我们在实现操作系统实验二----系统调用中已经学到的知识)。

    static inline _syscall0(int,fork)
    static inline _syscall0(int,pause)
    static inline _syscall1(int,setup,void *,BIOS)
    static inline _syscall0(int,sync)
    //用户态API实现
    _syscall2(int,mkdir,const char*,name,mode_t,mode)
    _syscall3(int,mknod,const char*,filename,mode_t,mode,dev_t,dev)
    void init(void)
    {
        .....
         setup((void *) &drive_info);
    	(void) open("/dev/tty0",O_RDWR,0);
    	(void) dup(0);
    	(void) dup(0);
    	
    	//创建目录以及文件
    	mkdir("/proc",0755);
    	mknod("/proc/psinfo",S_IFPROC|0444,0);
    	mknod("/proc/meminfo",S_IFPROC|0444,1);
    	mknod("/proc/hdinfo",S_IFPROC|0444,2);
       /*
        * 目录文件权限设置可以自行去查找相关资料,这里不再阐述。在创建结点的时候最后一个参数代表设备编     * 号是可以自定义的,主要是用于区分当前目录不同的文件。
    	*
    	*/
    	printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS,
    		NR_BUFFERS*BLOCK_SIZE);
       .....
    }
     
    
  4. 此时进入Linux 0.11编译以下,并进入模拟器运行以下指令:

    ll /proc
    

    显示我们刚刚创建的三个结点,就说明以上步骤无误,也就是说我们能够通过sys_open()能正常打开根目录下的刚刚创建的新文件系统proc.

    但是如果我们用cat指令去读取proc目录下刚刚创建的psinfo结点时出错(返回EINVAL ),说明内核对psinfo文件类型的读取存在问题,返回的EINVAL 说明还没有实现处理函数,因此我们需要去修改sys_read()

  5. 为了让proc目录下面的文件可读,我们需要添加一个处理函数proc_read

    //我们先看看fs/read_write.c文件下面的内容
    if (inode->i_pipe)
    		return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO;
    	if (S_ISCHR(inode->i_mode))
    		return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos);
    	if (S_ISBLK(inode->i_mode))
    		return block_read(inode->i_zone[0],&file->f_pos,buf,count);
    	if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) {
    		if (count+file->f_pos > inode->i_size)
    			count = inode->i_size - file->f_pos;
    		if (count<=0)
    			return 0;
    		return file_read(inode,file,buf,count);
    	}
    	printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode);
    	return -EINVAL;
    

    显然,我们需要在这一群if中加上S_IFPROC 的分支来决定是否进入对proc 文件的处理函数。在此之前我们先分析以下需要传给处理函数的参数:

    inode->i_zone[0]; //这是在修改mknod() 时我们自定义的设备编号
    buf;//指向用户空间,用于接收数据
    count;//说明buf指向的缓冲区大小
    &file->f_pos;//上一次读取文件结束时文件位置指针的指向,由于我们要返回读取的字符个数,因此这个参数很重要。
    

    由于我们处理函数是在单独的文件里面实现,在.c文件中引入另外一个文件的全局变量或者函数就需要用extern 来声明以下。在read_write.c文件开始的地方添加以下声明:

    extern int rw_char(int rw,int dev, char * buf, int count, off_t * pos);
    extern int read_pipe(struct m_inode * inode, char * buf, int count);
    extern int write_pipe(struct m_inode * inode, char * buf, int count);
    //表示引用的是外部函数
    extern int proc_read(int dev,char *buf,int count, unsigned long *pos);
    
    extern int block_read(int dev, off_t * pos, char * buf, int count);
    

    然后再添加分支

    if (inode->i_pipe)
    		return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO;
    	if (S_ISCHR(inode->i_mode))
    		return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos);
    	if (S_ISBLK(inode->i_mode))
    		return block_read(inode->i_zone[0],&file->f_pos,buf,count);
        //加入判断分支
    	if(S_ISPROC(inode->i_mode))
    		return proc_read(inode->i_zone[0],buf,count,&file->f_pos);
    	
    	if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) {
    
  6. 接下来当然要去实现pro_read函数。

    linux/fs/目录下创建一个新文件proc.c。在实现该程序之前我们先弄清楚几个概念,这样就会更好理解代码。先上硬盘设备上的分区以及文件系统图表。
    在这里插入图片描述

    • i节点:

      i结点就是inode,在Linux当中不是通过文件名来查找文件的, 而是通过inode来实现文件的定位。我们可以把想象成一个文件的身份证(记录着文件的位置,数据大小,等信息但不保存文件名信息),虽然inode记录文件在硬盘中的位置,我们不能直接使用inode当中的位置信息,而是通过文件名间接使用的。文件名保存在文件所属的目录文件当中,每个目录项包含着文件名和对应的inode。

在这里插入图片描述

  • 逻辑块与磁盘块:逻辑块与磁盘块大小一样(1KB)。

  • s_nzones: 表示设备上以逻辑块为单位的总逻辑块数。

  • s_ninodes :表示设备上的i节点总数。

  • s_imap_blocks: i节点位图所占用的磁盘块数。

  • s_zmap_blocks: 逻辑块位图所占用的磁盘块数。

//fs/proc_dev.c
#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 psinfo(unsigned long * pos, char * buf, int count)
{
    struct task_struct ** p;
    int output_count=0;
    char * psbuf=NULL;
    int chars=0;
    int offset=*pos;

    if((psbuf=(char *)malloc(sizeof(char *)*1024))==NULL)
    {
        printk("psinfo - malloc error!\n");
        
    }

    chars=sprintf(psbuf,"pid\tstate\tfather\tcounter\tstart_time\n");

    for(p = &LAST_TASK ; p >= &FIRST_TASK ; --p)
    {
        if(*p)
        {
            chars+=sprintf(psbuf+chars,"%d\t%d\t%d\t%d\t%d\n",(*p)->pid,(*p)->state,(*p)->father,(*p)->counter,(*p)->start_time);
        }
    }

    *(psbuf+chars)='\0';

    while(count>0)
    {
        if(offset>chars)
        {
            break;
        }

        put_fs_byte(*(psbuf+offset),buf++);
        offset++;
        output_count++;
        count--;

    }

    (*pos)+=output_count;

    free(psbuf);
    return output_count;
}

int hdinfo(unsigned long * pos, char * buf, int count)
{
    struct super_block * sb; 
    struct buffer_head * bh;
    int total_blocks;
    int total_inodes;
    int used_blocks=0;
    int free_blocks=0;
    int i,j,z;
    char * p=NULL;

    int chars=0;
    int offset=*pos;
    int output_count=0;
    char * hdbuf=NULL;

    sb=get_super(current->root->i_dev);
    total_blocks = sb->s_nzones;
    total_inodes=sb->s_ninodes;
    for(i=0;i<sb->s_zmap_blocks;i++)
    {
        bh=sb->s_zmap[i];
        p=(char*)bh->b_data;
        for(j=0;j<1024;j++)
        {
            for(z=1;z<=8;z++)
            {
                if((used_blocks+free_blocks)>=total_blocks)
                    break;
                if( *(p+j) & z)
                    used_blocks++;
                else
                    free_blocks++;
            }
        }
    }

    hdbuf=(char*)malloc(sizeof(char*)*512);
    chars=sprintf(hdbuf,"s_imap_blocks:%d\ns_zmap_blocks:%d\n",sb->s_imap_blocks,sb->s_zmap_blocks);
    chars+=sprintf(hdbuf+chars,"total_blocks:%d\nfree_blcoks:%d\nused_blocks:%d\ntotal_indoes:%d\n",total_blocks,free_blocks,used_blocks,total_inodes);
    //*(hduf+chars)='\n';

    while(count>0)
    {
        if(offset>chars)
            break;

        put_fs_byte(*(hdbuf+offset),buf++);
        offset++;
        output_count++;
        count--;
    }

    (*pos)+=output_count;
    free(hdbuf);
    return output_count;

}
int proc_read(int dev,char *buf,int count, unsigned long *pos)
{
  if(dev==0)
     {
         return psinfo(pos,buf,count);
     }
     if(dev==1)
     {
         return hdinfo(pos,buf,count);
     }

     return 0;
}
  1. 修改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_dev.o  
    ### Dependencies:
    
    bitmap.o: bitmap.c ../include/string.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/linux/kernel.h
    block_dev.o: block_dev.c ../include/errno.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/linux/kernel.h \
      ../include/asm/segment.h ../include/asm/system.h
    proc_dev.o: proc_dev.c ../include/errno.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/linux/kernel.h \
      ../include/asm/segment.h ../include/asm/system.h ../include/stdarg.h
    
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-09-07 11:12:00  更:2021-09-07 11:12:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 13:43:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码