xv6 一个简单的,类unix适于教学的操作系统
2014-02-18 12:31
501 查看
Contents
0 操作系统接口
1 第一个进程
2 页表
3 陷阱(traps), 中断,以及驱动
4 锁
5 调试 (scheduling)
6 文件系统
A PC 硬件
B boot loader
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.
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.
Bfree 找到要找的block,然后清掉相应的bit.
代码: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 号。
对于某个正在被用到的文件,内核会在内存中放一份inode. 成员 ref 指的是有多少个指针在引用这个inode.
0 操作系统接口
1 第一个进程
2 页表
3 陷阱(traps), 中断,以及驱动
4 锁
5 调试 (scheduling)
6 文件系统
A PC 硬件
B boot loader
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]; };
相关文章推荐
- MFC视频教学第一课,做一个简单的界面,理解应用程序和操作系统之间的消息传递机制
- 一个简单的时间片轮转多道程序内核操作系统工作流程
- 一个简单的32位多任务操作系统的实现
- ARM嵌入式编程(无操作系统、基于MDK)之最简单的程序:点亮一个LED灯
- 一个单链表C++简单的实现版本-转自chinaunix
- 深入UNIX编程:一个简单聊天室的两种实现 (fcntl 和 select)(转)
- Unix 是简单的,你不需要成为一个天才或是计算机专家也能理解它!
- 一个Go语言接口和多操作系统实现的简单例子
- Linux操作系统的简单指令及如何使用vim编写一个程序,然后使用gcc查看【预处理】、【编译】、【汇编】、【链接】各阶段文件的内容。
- [unix] Unix 是简单的,你不需要成为一个天才或是计算机专家也能理解它!
- PHP on Windows Azure 入门教学系列(2) ——利用SQL Azure做一个简单的访问计数器
- csapp实验,一个简单的shell. Lab Assignment L5: Writing Your Own Unix Shell
- 搜索一个问题 C、C++判断操作系统 是 Linux还是windows 还是Unix【编译器内置宏 探索(不是特别满意)】
- unix ls命令的一个简单实现
- 一个简单的时间片轮转多道程序内核操作系统工作流程
- 深入UNIX编程:一个简单聊天室的两种实现 (fcntl 和 select)
- 操作系统是如何工作的-------通过一个简单的时间片轮转多道程序内核代码分析
- [unix] Unix 是简单的,你不需要成为一个天才或是计算机专家也能理解它!
- 操作系统——一个简单的Hello World
- 准备开发一个教学用的操作系统