操作系統(tǒng)實驗:Lab8 文件系統(tǒng)

清華大學操作系統(tǒng)Lab8實驗報告
課程主頁:http://os.cs.tsinghua.edu.cn/oscourse/OS2018spring
實驗指導書:https://chyyuu.gitbooks.io/ucore_os_docs/content/
github:https://github.com/chyyuu/ucore_os_lab

實驗目的

  • 了解基本的文件系統(tǒng)系統(tǒng)調(diào)用的實現(xiàn)方法廓俭;
  • 了解一個基于索引節(jié)點組織方式的Simple FS文件系統(tǒng)的設計與實現(xiàn)云石;
  • 了解文件系統(tǒng)抽象層-VFS的設計與實現(xiàn);

練習1: 完成讀文件操作的實現(xiàn)

用戶程序讀文件需要使用系統(tǒng)調(diào)用研乒。在用戶程序執(zhí)行read操作時會調(diào)用sys_read系統(tǒng)調(diào)用留晚。根據(jù)ucore的中斷機制實現(xiàn),系統(tǒng)調(diào)用將通過trap_dispatch分發(fā)給syscall告嘲,隨后分發(fā)給讀的系統(tǒng)調(diào)用sys_read內(nèi)核函數(shù)。

sys_read內(nèi)核函數(shù)需要進一步調(diào)用sysfile_read內(nèi)核函數(shù)奖地,進入到文件系統(tǒng)抽象層處理流程完成進一步的讀文件操作橄唬。sysfile_read函數(shù)調(diào)用file_read函數(shù),file_read函數(shù)調(diào)用vop_read函數(shù)接口進入到文件系統(tǒng)實例的讀操作接口参歹。

vop_read函數(shù)實際上是對sfs_read的包裝仰楚。sfs_read函數(shù)調(diào)用sfs_io函數(shù)。它有三個參數(shù)犬庇,node是對應文件的inode僧界,iob是緩存,write表示是讀還是寫的布爾值( 0表示讀臭挽,1表示寫) 捂襟,這里是0。函數(shù)先找到inode對應sfs和sin欢峰,然后調(diào)用sfs_io_nolock函數(shù)進行讀取文件操作葬荷,最后調(diào)用iobuf_skip函數(shù)調(diào)整iobuf的指針。

sfs_io_nolock函數(shù)主要用來將磁盤中的一段數(shù)據(jù)讀入到內(nèi)存中或者將內(nèi)存中的一段數(shù)據(jù)寫入磁盤纽帖。需要補充的代碼用來對一段地址對應的磁盤塊讀或?qū)憽?/p>

// 讀取第一頁宠漩,可能不對齊
    if ((ret = sfs_bmap_load_nolock(sfs, sin, blkno, &ino)) != 0) {
        goto out;
    }
    blkoff = offset % SFS_BLKSIZE;
    size = (nblks != 0) ? (SFS_BLKSIZE - blkoff) : (endpos - offset);
    if ((ret = sfs_buf_op(sfs, buf, size, ino, blkoff)) != 0) {
        goto out;
    }
    alen += size;
// 如果超過一頁的話,
    if (nblks != 0) {
// 讀取第二頁到第n-1頁懊直,這些頁大小均為SFS_BLKSIZE
        for (int i = blkno + 1; i < blkno + nblks; ++i) {
            if ((ret = sfs_bmap_load_nolock(sfs, sin, i, &ino)) != 0) {
                goto out;
            }
            if ((ret = sfs_block_op(sfs, buf + alen, ino, 1)) != 0) {
                goto out;
            }
            alen += SFS_BLKSIZE;
        }
// 最后一頁扒吁,可能不對齊
        if (endpos % SFS_BLKSIZE != 0) {
            if ((ret = sfs_bmap_load_nolock(sfs, sin, blkno + nblks, &ino)) != 0) {
                goto out;
            }
            if ((ret = sfs_buf_op(sfs, buf + alen, endpos % SFS_BLKSIZE, ino, 0)) != 0) {
                goto out;
            }
            alen += endpos % SFS_BLKSIZE;
        }
    }
請在實驗報告中給出設計實現(xiàn)”UNIX的PIPE機制“的概要設方案,鼓勵給出詳細設計方案

PIPE在UNIX體系里也認為是一種文件室囊,參考STDIN雕崩、STDOUT以及SFS的設計魁索,可以將PIPE作為與這三者并列的一個子系統(tǒng)刺彩。

因此應當在初始化STDIN蟹略、STDOUT加入對于PIPE的初始化并創(chuàng)建PIPE的inode。同時為了完成PIPE中內(nèi)容的緩存瑰排,在內(nèi)存中開辟一塊區(qū)域給PIPE使用捉貌。

為了使用戶進程使用PIPE支鸡,應當添加同PIPE相關(guān)的系統(tǒng)調(diào)用,包括

  • 將PIPE和兩個進程相連
  • 向PIPE中寫入數(shù)據(jù)
  • 從PIPE中讀出數(shù)據(jù)

這些系統(tǒng)調(diào)用通過文件系統(tǒng)提供給的接口趁窃,

練習2: 完成基于文件系統(tǒng)的執(zhí)行程序機制的實現(xiàn)

首先牧挣,需要在alloc_proc函數(shù)中對進程控制塊中和文件系統(tǒng)有關(guān)的部分進行初始化:

    proc -> filesp = files_create();

在進行fork時,將父進程的文件系統(tǒng)信息復制到子進程中去:

    int file_success = copy_files(clone_flags, proc);
    if (file_success != 0) {
        goto bad_fork_cleanup_fs;
    }

最后還要修改load_icode的代碼醒陆。之前的代碼是和操作系統(tǒng)一起load進來的瀑构,現(xiàn)在要改為在啟動操作系統(tǒng)后,通過文件系統(tǒng)加載進來刨摩。

static int
load_icode(int fd, int argc, char **kargv) {
    if (current->mm != NULL) {
        panic("load_icode: current->mm must be empty.\n");
    }
    int ret = -E_NO_MEM;
    struct mm_struct *mm;
//(1) create a new mm for current process
    if ((mm = mm_create()) == NULL) {
        goto bad_mm;
    }

//(2) create a new PDT, and mm->pgdir= kernel virtual addr of PDT
    if (setup_pgdir(mm) != 0) {
        goto bad_pgdir_cleanup_mm;
    }

//(3) copy TEXT/DATA/BSS parts in binary to memory space of process
    struct Page *page;

//(3.1) read raw data content in file and resolve elfhdr
    struct elfhdr __elf, *elf = &__elf;
    ret = load_icode_read(fd, elf, sizeof(struct elfhdr), 0);
    if (ret != 0) {
        goto bad_elf_cleanup_pgdir;
    }

    if (elf -> e_magic != ELF_MAGIC) {
        ret = -E_INVAL_ELF;
        goto bad_elf_cleanup_pgdir;
    }

    struct proghdr __ph, *ph = &__ph;
    uint32_t vm_flags, perm, phnum;
    for (phnum = 0; phnum < elf->e_phnum; phnum ++) {
//(3.2) read raw data content in file and resolve proghdr based on info in elfhdr
        off_t phoff = elf->e_phoff + sizeof(struct proghdr) * phnum;
        if ((ret = load_icode_read(fd, ph, sizeof(struct proghdr), phoff)) != 0) {
            goto bad_cleanup_mmap;
        }
        if (ph->p_type != ELF_PT_LOAD) {
            continue ;
        }
        if (ph->p_filesz > ph->p_memsz) {
            ret = -E_INVAL_ELF;
            goto bad_cleanup_mmap;
        }
        if (ph->p_filesz == 0) {
            continue ;
        }
        vm_flags = 0, perm = PTE_U;
        if (ph->p_flags & ELF_PF_X) vm_flags |= VM_EXEC;
        if (ph->p_flags & ELF_PF_W) vm_flags |= VM_WRITE;
        if (ph->p_flags & ELF_PF_R) vm_flags |= VM_READ;
        if (vm_flags & VM_WRITE) perm |= PTE_W;
       
 //(3.3) call mm_map to build vma related to TEXT/DATA
        if ((ret = mm_map(mm, ph->p_va, ph->p_memsz, vm_flags, NULL)) != 0) {
            goto bad_cleanup_mmap;
        }
        off_t offset = ph->p_offset;
        size_t off, size;
        uintptr_t start = ph->p_va, end, la = ROUNDDOWN(start, PGSIZE);

        ret = -E_NO_MEM;

//(3.4) callpgdir_alloc_page to allocate page for TEXT/DATA, read contents in file
        end = ph->p_va + ph->p_filesz;
        while (start < end) {
            if ((page = pgdir_alloc_page(mm->pgdir, la, perm)) == NULL) {
                ret = -E_NO_MEM;
                goto bad_cleanup_mmap;
            }
            off = start - la, size = PGSIZE - off, la += PGSIZE;
            if (end < la) {
                size -= la - end;
            }
            if ((ret = load_icode_read(fd, page2kva(page) + off, size, offset)) != 0) {
                goto bad_cleanup_mmap;
            }
            start += size, offset += size;
        }
        end = ph->p_va + ph->p_memsz;

(3.5) callpgdir_alloc_page to allocate pages for BSS, memset zero in these pages
        if (start < la) {
            if (start == end) {
                continue ;
            }
            off = start + PGSIZE - la, size = PGSIZE - off;
            if (end < la) {
                size -= la - end;
            }
            memset(page2kva(page) + off, 0, size);
            start += size;
            assert((end < la && start == end) || (end >= la && start == la));
        }
        while (start < end) {
            if ((page = pgdir_alloc_page(mm->pgdir, la, perm)) == NULL) {
                ret = -E_NO_MEM;
                goto bad_cleanup_mmap;
            }
            off = start - la, size = PGSIZE - off, la += PGSIZE;
            if (end < la) {
                size -= la - end;
            }
            memset(page2kva(page) + off, 0, size);
            start += size;
        }
    }
    sysfile_close(fd);

//(4) call mm_map to setup user stack, and put parameters into user stack
    vm_flags = VM_READ | VM_WRITE | VM_STACK;
    if ((ret = mm_map(mm, USTACKTOP - USTACKSIZE, USTACKSIZE, vm_flags, NULL)) != 0) {
        goto bad_cleanup_mmap;
    }
    assert(pgdir_alloc_page(mm->pgdir, USTACKTOP-PGSIZE , PTE_USER) != NULL);
    assert(pgdir_alloc_page(mm->pgdir, USTACKTOP-2*PGSIZE , PTE_USER) != NULL);
    assert(pgdir_alloc_page(mm->pgdir, USTACKTOP-3*PGSIZE , PTE_USER) != NULL);
    assert(pgdir_alloc_page(mm->pgdir, USTACKTOP-4*PGSIZE , PTE_USER) != NULL);

//(5) setup current process's mm, cr3, reset pgidr (using lcr3 MARCO)
    mm_count_inc(mm);
    current->mm = mm;
    current->cr3 = PADDR(mm->pgdir);
    lcr3(PADDR(mm->pgdir));

//(6) setup uargc and uargv in user stacks
    uint32_t argv_size=0, i;
    for (i = 0; i < argc; i ++) {
        argv_size += strnlen(kargv[i],EXEC_MAX_ARG_LEN + 1)+1;
    }

    uintptr_t stacktop = USTACKTOP - (argv_size/sizeof(long)+1)*sizeof(long);
    char** uargv=(char **)(stacktop  - argc * sizeof(char *));

    argv_size = 0;
    for (i = 0; i < argc; i ++) {
        uargv[i] = strcpy((char *)(stacktop + argv_size ), kargv[i]);
        argv_size +=  strnlen(kargv[i],EXEC_MAX_ARG_LEN + 1)+1;
    }

    stacktop = (uintptr_t)uargv - sizeof(int);
    *(int *)stacktop = argc;

//(7) setup trapframe for user environment
    struct trapframe *tf = current->tf;
    memset(tf, 0, sizeof(struct trapframe));
    tf->tf_cs = USER_CS;
    tf->tf_ds = tf->tf_es = tf->tf_ss = USER_DS;
    tf->tf_esp = stacktop;
    tf->tf_eip = elf->e_entry;
    tf->tf_eflags = FL_IF;
    ret = 0;

//(8) if up steps failed, you should cleanup the env.
out:
    return ret;
bad_cleanup_mmap:
    exit_mmap(mm);
bad_elf_cleanup_pgdir:
    put_pgdir(mm);
bad_pgdir_cleanup_mm:
    mm_destroy(mm);
bad_mm:
    goto out;
}
請在實驗報告中給出設計實現(xiàn)基于”UNIX的硬鏈接和軟鏈接機制“的概要設方案寺晌,鼓勵給出詳細設計方案

覆蓋的知識點

與參考答案的區(qū)別

  • 練習1:自己完成。
  • 練習2:load_icode部分參考了答案澡刹。

總結(jié)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末呻征,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子罢浇,更是在濱河造成了極大的恐慌陆赋,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嚷闭,死亡現(xiàn)場離奇詭異攒岛,居然都是意外死亡,警方通過查閱死者的電腦和手機胞锰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門灾锯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人嗅榕,你說我怎么就攤上這事挠进。” “怎么了誊册?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵领突,是天一觀的道長。 經(jīng)常有香客問我案怯,道長君旦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮金砍,結(jié)果婚禮上局蚀,老公的妹妹穿的比我還像新娘。我一直安慰自己恕稠,他們只是感情好琅绅,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鹅巍,像睡著了一般千扶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上骆捧,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天澎羞,我揣著相機與錄音,去河邊找鬼敛苇。 笑死妆绞,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的枫攀。 我是一名探鬼主播括饶,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼来涨!你這毒婦竟也來了巷帝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤扫夜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后驰徊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體笤闯,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年棍厂,在試婚紗的時候發(fā)現(xiàn)自己被綠了颗味。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡牺弹,死狀恐怖浦马,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情张漂,我是刑警寧澤晶默,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站航攒,受9級特大地震影響磺陡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一币他、第九天 我趴在偏房一處隱蔽的房頂上張望坞靶。 院中可真熱鬧,春花似錦蝴悉、人聲如沸彰阴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽尿这。三九已至,卻和暖如春倦微,著一層夾襖步出監(jiān)牢的瞬間妻味,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工欣福, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留责球,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓拓劝,卻偏偏與公主長得像雏逾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子郑临,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容