小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

哈工大操作系統(tǒng)實(shí)驗(yàn)---lab8:proc文件的實(shí)現(xiàn)

 印度阿三17 2019-06-28

實(shí)驗(yàn)內(nèi)容

在Linux0.11上實(shí)現(xiàn)procfs(proc文件系統(tǒng))內(nèi)的psinfo節(jié)點(diǎn),當(dāng)讀取此節(jié)點(diǎn)的內(nèi)容的時(shí)候,可得到系統(tǒng)當(dāng)前所有進(jìn)程的狀態(tài)信息,例如,用cat命令顯示/proc/procfo的內(nèi)容,可得到:

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

# cat /proc/hdinfo 
total_blocks:    62000;
free_blocks:     39037;
used_blocks:     22963;

procfs及其節(jié)點(diǎn)要在內(nèi)核啟動(dòng)時(shí)自動(dòng)創(chuàng)建,相關(guān)功能的實(shí)現(xiàn)放在fs/proc.c文件。


實(shí)驗(yàn)過(guò)程

  • 第一步: 增加新文件類(lèi)型,在include/sys/stat.h文件中定義了幾種文件類(lèi)型和相應(yīng)的測(cè)試宏:

//已有的宏定義
#define S_IFMT 00170000 //文件類(lèi)型(都是8進(jìn)制表示)
#define S_IFREG 0100000	//普通文件
#define S_IFCHAR 0020000 //字符設(shè)備文件
#define S_ISREG(m)  (((m) & S_IFMT) == S_IFREG) //測(cè)試m是否是普通文件
#define S_ISCHAR(m) (((m) & S_IFMT) == S_IFCHAR) //測(cè)試m是否是字符設(shè)備文件
//proc文件的宏定義/宏函數(shù)
#define S_IFPROC 0030000
#define S_ISPROC(m) (((m) & S_IFMT) ==  S_IFPROC) //測(cè)試m是否是proc文件

在這里插入圖片描述

  • 第二步: 讓mknod()支持新的文件類(lèi)型,文件/proc/psinfo以及/proc/hdinfo索引節(jié)點(diǎn)需要通過(guò)mknod()系統(tǒng)調(diào)用建立,所以要讓它支持新的文件類(lèi)型,直接修改fs/namei.c文件中的sys_mknod()函數(shù)的代碼,在其中增加關(guān)于proc文件系統(tǒng)的判斷:

if(S_ISBLK(mode) || S_ISCHAR(mode) || S_ISPROC(mode))
	inode->izone[0] = dev;

在這里插入圖片描述

  • 第三步: 進(jìn)程proc文件初始化,可以在系統(tǒng)啟動(dòng)時(shí)就建立那些proc文件系統(tǒng)(根目錄/proc)下的proc文件(其下的子文件/proc/psinfo、/proc/hdinfo),通常Linux操作系統(tǒng)也都是在系統(tǒng)啟動(dòng)以后就直接創(chuàng)建那些proc文件的,顯然要修改系統(tǒng)啟動(dòng)時(shí)的調(diào)用的main(),因?yàn)槭且獎(jiǎng)?chuàng)建文件,所以當(dāng)然應(yīng)該在文件系統(tǒng)已經(jīng)掛載以后才可以操作,在main()的最后會(huì)從內(nèi)核態(tài)切換到用戶態(tài),并調(diào)用init(),而init()要做的第一件事就是掛載根文件系統(tǒng):

void init(void)
{
	setup((void *) &drive_info);
}

顯然在執(zhí)行setup((void *) &drive_info)的時(shí)候,也就是根文件系統(tǒng)掛載以后就可以創(chuàng)建proc文件了,首先建立/proc目錄,然后再建立該目錄下的各個(gè)proc文件節(jié)點(diǎn),建立目錄用mkdir(),建立文件用mknod()。
現(xiàn)在可以調(diào)用mkdir()來(lái)創(chuàng)建proc目錄,調(diào)用mknod()來(lái)創(chuàng)建proc目錄下的各個(gè)proc文件節(jié)點(diǎn)了。
內(nèi)核初始化的全部工作是在main()中完成,而/init/main()在最后從內(nèi)核態(tài)切換到用戶態(tài),并調(diào)用init()init()做的第一件事情就是掛載根文件系統(tǒng):setup((void *) &drive_info);

procfs的初始化工作應(yīng)該在根文件系統(tǒng)掛載之后開(kāi)始。它包括兩個(gè)步驟:

  • 建立/proc目錄

  • 建立/proc目錄下的各個(gè)結(jié)點(diǎn)

建立目錄和結(jié)點(diǎn)分別需要調(diào)用mkdir()和mknod()系統(tǒng)調(diào)用。因?yàn)槌跏蓟瘯r(shí)已經(jīng)在用戶態(tài),所以不能直接調(diào)用sys_mkdir()和sys_mknod()。必須在初始化代碼所在文件中實(shí)現(xiàn)這兩個(gè)系統(tǒng)調(diào)用的用戶態(tài)接口,即API

_syscall2(int,mkdir,const char*,name,mode_t,mode)
_syscall3(int,mknod,const char *,filename,mode_t,mode,dev_t,dev)

在這里插入圖片描述
在這里插入圖片描述
mkdir()時(shí)mode參數(shù)的值可以是“0755”(rwxr-xr-x),表示只允許root用戶改寫(xiě)此目錄,其它人只能進(jìn)入和讀取此目錄。
procfs是一個(gè)只讀文件系統(tǒng),所以用mknod()建立psinfo結(jié)點(diǎn)時(shí),必須通過(guò)mode參數(shù)將其設(shè)為只讀。建議使用“S_IFPROC|0444”做為mode值,表示這是一個(gè)proc文件,權(quán)限為0444(r--r--r--),對(duì)所有用戶只讀。
mknod()的第三個(gè)參數(shù)dev用來(lái)說(shuō)明結(jié)點(diǎn)所代表的設(shè)備編號(hào)。對(duì)于procfs來(lái)說(shuō),此編號(hào)可以完全自定義。proc文件的處理函數(shù)將通過(guò)這個(gè)編號(hào)決定對(duì)應(yīng)文件包含的信息是什么。例如,可以把0對(duì)應(yīng)psinfo1對(duì)應(yīng)hdinfo,2對(duì)應(yīng)inodeinfo。
上述步驟完成以后,就可以使用make all編譯內(nèi)核,然后./run運(yùn)行內(nèi)核,使用ll /proc可以看到:

在這里插入圖片描述

inode->i_mode就是通過(guò)mknod()設(shè)置的mode。信息中的XXX和你設(shè)置的S_IFPROC有關(guān)。通過(guò)此值可以了解mknod()工作是否正常。這些信息說(shuō)明內(nèi)核在對(duì)psinfo進(jìn)行讀操作時(shí)不能正確處理,向cat返回了EINVAL錯(cuò)誤。因?yàn)檫€沒(méi)有實(shí)現(xiàn)處理函數(shù),所以這是很正常的。

注意:博主在此沒(méi)截使用cat命令的圖片,但是就是這個(gè)么道理,嘻嘻。

這些信息至少說(shuō)明,psinfo被正確open()了。所以我們不需要對(duì)sys_open()動(dòng)任何手腳,唯一要打補(bǔ)丁的,是sys_read()

  • 第四步: 讓proc文件(psinfo、hdinfo、inodeinfo)可讀
    open()沒(méi)有問(wèn)題,那么需要修改的就是sys_read()了。
    首先在fs/read_write.c中添加extern,表示proc_read函數(shù)是從外部調(diào)用的。

在.c文件中要引入另一個(gè)文件,而且是另一個(gè).c文件的全局變量或者函數(shù),就需要用extern來(lái)說(shuō)明一下。

在這里插入圖片描述
然后仿照其他if語(yǔ)句,添加proc文件的proc_read()調(diào)用。
在這里插入圖片描述

  • 第五步: 實(shí)現(xiàn)上述的proc_read()函數(shù),用于讀取proc文件內(nèi)容,實(shí)現(xiàn)在fs/proc.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);

//Linux0.11沒(méi)有sprintf(),該函數(shù)是用于輸出結(jié)果到字符串中的,所以就實(shí)現(xiàn)一個(gè),這里是通過(guò)vsprintf()實(shí)現(xiàn)的。
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;

	//硬盤(pán)總共有多少塊(空閑   非空閑),有多少inode索引節(jié)點(diǎn)等信息都放在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;

	//psinfo: 對(duì)應(yīng)的就是輸出系統(tǒng)此時(shí)的全部進(jìn)程的狀態(tài)信息
    if(dev==0)
    { 
        proc_buf=(char *)malloc(sizeof(char *)*1024);
        file_size=sprintf(proc_buf,"pid\tstate\tfather\tcounter\tstart_time\n");

		//這里借鑒了,進(jìn)程切換函數(shù)schedule()的代碼,也就是遍歷系統(tǒng)全部的進(jìn)程。
        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: 打印出硬盤(pán)的一些信息,
	//s_imap_blocks、ns_zmap_blocks、
	//total_blocks、free_blocks、used_blocks、total_inodes
    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緩沖區(qū)的內(nèi)容放入文件
    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;
}

由于添加了一個(gè)文件proc.c,所以需要改下fs/Makefile,
在這里插入圖片描述
在這里插入圖片描述

上述的代碼,是用的這位同學(xué)的,在此表示感謝!
(但是我搞不清為什么是proc_dev,添加的文件不是proc.c嗎,如果有人可以解答,可以評(píng)論下。)

然后make all編譯內(nèi)核,./run運(yùn)行內(nèi)核,輸出cat命令,即可查看psinfo(當(dāng)前系統(tǒng)進(jìn)程狀態(tài)信息)和hdinfo(硬盤(pán)信息)的信息。
在這里插入圖片描述


實(shí)驗(yàn)問(wèn)題

  • 如果要求你在psinfo之外再實(shí)現(xiàn)另一個(gè)結(jié)點(diǎn),具體內(nèi)容自選,那么你會(huì)實(shí)現(xiàn)一個(gè)給出什么信息的結(jié)點(diǎn)?為什么?

我會(huì)實(shí)現(xiàn)meminfo、cpuinfo這些節(jié)點(diǎn),分別對(duì)應(yīng)的信息是系統(tǒng)內(nèi)存信息和cpu的信息,原因是我只知道這兩個(gè)名詞了

  • 一次read()未必能讀出所有的數(shù)據(jù),需要繼續(xù)read(),直到把數(shù)據(jù)讀空為止。而數(shù)次read()之間,進(jìn)程的狀態(tài)可能會(huì)發(fā)生變化。你認(rèn)為后幾次read()傳給用戶的數(shù)據(jù),應(yīng)該是變化后的,還是變化前的? 如果是變化后的,那么用戶得到的數(shù)據(jù)銜接部分是否會(huì)有混亂?如何防止混亂? 如果是變化前的,那么該在什么樣的情況下更新psinfo的內(nèi)容?

我認(rèn)為后幾次read()傳遞給用戶的數(shù)據(jù)應(yīng)該是變化前的,因?yàn)樽x完一部分?jǐn)?shù)據(jù)之后,之前讀取的進(jìn)程狀態(tài)信息可能已經(jīng)發(fā)生了改變了,那么讀給proc_buf緩沖區(qū)的內(nèi)容還是讀之前的,所以可能會(huì)導(dǎo)致讀到的數(shù)據(jù)出現(xiàn)混亂(數(shù)據(jù)不正確?),要使得數(shù)據(jù)讀的正確、不混亂,就要在讀的時(shí)候讓想要變化的進(jìn)程先等待,等讀完了數(shù)據(jù)放到了文件中以后,再喚醒要更新的進(jìn)程。

注:我的答案很可能不準(zhǔn)確,請(qǐng)別被我誤導(dǎo)了。


HIT-OS-LAB參考資料:
1.《操作系統(tǒng)原理、實(shí)現(xiàn)與實(shí)踐》-李治軍、劉宏偉 編著
2.《Linux內(nèi)核完全注釋》
3.兩個(gè)哈工大同學(xué)的實(shí)驗(yàn)源碼
4.Linux-0.11源代碼
(上述資料,如果有需要的話,請(qǐng)主動(dòng)聯(lián)系我))

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多