xv6 一個簡單的,類unix適於教學的操做系統

Contentsnode

0  操做系統接口數組

1 第一個進程數據結構

2 頁表ide

3 陷阱(traps), 中斷,以及驅動函數

4 鎖ui

5 調試 (scheduling)操作系統

6 文件系統線程

A PC 硬件3d

B boot loaderunix

index


前言以及致謝


這個是爲操做系統課程寫的草稿,它經過一個叫xv6的內核來解釋操做系統中的主要概念,xv6 從新實現的Dennis Ritchie和Ken

Thompson的UNIX 第六版。xv6 在結構和風格上面基本上和v6同樣,可是它是基於X86多處理器用ANSI C實現的。


這本書應該和 xv6的源代碼一塊兒閱讀.這個方法的靈感來源於John Lions對UNIX 第六版的評註。


咱們有在MIT6.828操做系統課程中使用這本教材,咱們感謝全部教職員工,助教,以及全部直接或間接對xv6做出貢獻的人。

特別的,咱們想感謝Austin Clements和Nickolai Zeldovich.


第0章

操做系統接口

操做系統的職責是將一臺計算機分配給多個程序而且提供一系列比單純硬件更有用的服務,操做系統管理以及抽象底層硬件,因此

文字處理軟件不用關心他在哪一種類型的磁盤上工做,它還能夠協調各類硬件,使得多個程序共享硬件資源而且看起來在同時運行,最後,

操做系統提供


第六章

文件系統

       文件系統的做用是組織和存儲數據,一個典型的用途就是在用戶和應用程序之間傳遞數據,還有數據持久化(persistence),這

樣,在重啓以後,數據仍然存在。

       xv6 文件系統提供了unix-like 的文件,文件夾(directories) 還有路徑(pathname). 文件存放在ide 磁盤上面。一個文件系統主要面臨着下面這些

問題:

  •   須要用磁盤上的數據結構去表示文件夾(directory) 文件, 還有標識block 的各類信息,block中的內容還有哪些block是空的。
  • 文件系統,必需要支持災難恢復(crash recover). 就是說,若是發生了crash(好比忽然掉電了),文件系統必須是重啓以後,可以正常工做
  • 不一樣的進程可能同時對一個文件進行操做, 因此須要文件系統去維護一致性(maintain invariant).
  • 訪問磁盤要比訪問內存慢幾個數量級,因此,須要將常常用到的文件cache 到主存上面。
     接下來的內容就是講xv6 是怎麼面對這些問題的。


     先簡單說一下
XV6的文件實現分紅了七層。

disk 層負責從磁盤上去讀寫一個block. 
buffer cache 將磁盤上的文件緩衝並同步到主存上面,確保同一時間只有一個內核進程去修改數據。
Logging 層  使得協議棧上層可以同時去操做不少個block, 還有確保一致性(要麼你們都更新,要麼你們都不)。
inode 對每個獨立的文件進行描述,每個文件都有一個inode 去描述它,而且有一個惟一的編號。
Directory 也是一個文件,裏面放着文件的名字還有 i-number.
Pathname包含了層次性的文件結構,好比  /usr/rtm/xv6/fs.c
File descriptor 使用操做系統的接口,抽象了不少unix 資源,好比 pipes, devices, files.


在剩下來的章節裏,咱們就詳細講解各層的實現。
buffer cache 負責兩項事情: 1,將磁盤的上block 同步到主存上面,同時保證,同一時間,內核裏只有一個線程在使用它。  2。 將最經常使用到的block cache 到內存中,這樣避免了屢次去讀很慢的磁盤上去讀數據。


1. Buffer cache 層
buffer cache 層主要暴露(exported) 兩個接口(interface) : bread 和 bread;前者負責從磁盤上得到一個block ,緩衝到內存上
使得能夠在主存上去讀寫(modify).   後者負責將修改後的數據寫到磁盤上合適的位置。一個內核線程在完成這些操做以後,須要
調用brelse 去釋放這個buffer.
 

代碼:block allocator

文件還有directory(文件夾)都存在磁盤的block 上面,這些block 必須從空閒的pool 中分配出來,xv6 block 分配器會在磁盤上維持(maintain) 一個位示圖,每個block 用一個
bit 表示是空閒的,仍是被佔用的,0 表示這個block 是free(空閒)的, 1 表示 這個block 是被佔用(in use)的。boot sector, superblock, inode block , bitmap block 都被設爲1.


block allocator 提供了兩個函數: balloc 和 bree. 前者用來分配一個新的block, 後才用來free 一個block.

Balloc 首先調用readsb 從disk 中讀出superblock,放到sb裏面。第一個for 循環從0 一直到sb.size 去檢查每個block. 就是去看誰的bitmap 
位是0, 是0代表這個block 是空閒的,若是找到了這樣的block,先更新它的bitmap ,而後返回這個block.
// Blocks.

// Allocate a zeroed disk block.
static uint
balloc(uint dev)
{
  int b, bi, m;
  struct buf *bp;
  struct superblock sb;

  bp = 0;
  readsb(dev, &sb);
  for (b = 0; b <sb.size; b+= BPB) {
    bp = bread(dev, BBLOCK(b, sb.ninodes));
    for(bi = 0; bi < BPB && b + bi < sb.size; bi++){
      m = 1 << (bi % 8);
      if ((bp->data[bi/8] & m) ==0) {   // Is block free ?
      bp->data[bi/8] |= m;       // Mark block in use.
      log_write(bp);
      brelse(bp);
      bzero(dev, b + bi);
      return b + bi;
     }
    }
    brelse(bp);
   }
  panic("balloc: out of blocks");
}

Bfree 找到要找的block,而後清掉相應的bit.

// Free a disk block.
static void
bfree(int dev, uint b)
{
  struct buf *bp;
  struct superblock sb;
  int bi, m;

  readsb(dev, &sb);
  bp = bread(dev, BBLOCK(b, sb.ninodes));
  bi = b % BPB;
  m = 1 << (bi % 8);
  if ((bp->data[bi/8] &m) == 0)
    panic("free free block");
  bp->data[bi/8] &= ~m;
  log_write(bp);
  brelse(bp);
}

代碼:inode layer

對於術語inode 有兩個相關聯的含義,一個是位於磁盤上的,一個是位於內存上的,內存上的基本是磁盤上的一份複製,但又加了

額外的信息。


全部 on-disk inode 都放在一個叫inode block 的連續區域。 每個inode 都有着相同的大小,很容易的,給每個inode 一個編號n.

事實上,這個編號n 叫inode 號,或者 i-number.在inode 的實現時面,也是用inode 去惟一標識一個inode.


on-disk(磁盤上)的inode 用一個叫dinode 的結構體去寶義,其中type 成員用於區分這個文件是 file, directory, 或者special files(device).

成員 nlink 用於計數有多少個directory entries 指向這個inode. 成員 size  記錄了文件的大小, 數組 addrs 記錄了存放文件內容數據的

block 號。

// On-disk inode structure
shruct dinode {
  short type;           // File type
  short major;          // Major device number (T_DEV only)
  short minor;          // Minor device number (T_DEV only)
  short nlink;          // Number of links to inode in file system
  uint  size;           // Size of file (bytes)
  uint addrs[NDIRECT+1];  // Data block address
};


對於某個正在被用到的文件,內核會在內存中放一份inode. 成員 ref 指的是有多少個指針在引用這個inode.

// in-memory copy of an inode
struct inode {
  uint dev;              // Device number
  uint inum;             // Inode number
  int ref;               // Reference count
  int flags;             // I_BUSY, I_VALID
  
  short type;             //copy of disk inode
  short major;
  short minor;
  short nlink;
  uint  size;
  uint  addrs[NDIRECT+1];
};