9. Lab: file system
1. Large files (moderate)
1.1 要求
Modify bmap() so that it implements a doubly-indirect block, in addition to direct blocks and a singly-indirect block. You'll have to have only 11 direct blocks, rather than 12, to make room for your new doubly-indirect block; you're not allowed to change the size of an on-disk inode. The first 11 elements of ip->addrs[] should be direct blocks; the 12th should be a singly-indirect block (just like the current one); the 13th should be your new doubly-indirect block. You are done with this exercise when bigfile writes 65803 blocks and usertests runs successfully:
要求扩大 xv6 中文件大小上限。目前 xv6 文件限制为 268 个块,或 268*BSIZE
字节(在 xv6 中 BSIZE
为 1024)。 因为一个 xv6 inode
包含 12 个“直接”块号和一个“单独间接”块号,这是指一个块最多可以容纳 256 个块号,总共 12+256=268 块。
因此需要更改 xv6 文件系统代码以支持每个 inode
中的“双重间接”块,其中包含 256 个单间接块地址,每个块最多可包含 256 个数据块地址。 结果将是一个文件将能够包含多达 65803 个块,或 256*256+256+11 个块(11 个而不是 12 个,因为我们将为双间接块牺牲一个直接块号)
原来的结构如图下:
修改后的结构应当如下:
可以看到,有点类似多级页表的思路。
1.2 分析
要注意的点如下:
- 因为
inode.addrs
固定为13 个,因此需要减少一个DirectBlock
给Doubly-Indirect
使用 bmap
的函数签名如右:bmap(struct inode *ip, uint bn)
,bn
为 block number。需要注意,当bn
大于 256 + 11 的时候,需要开始在Doubly-Indirect
中找到合适的Direct-Block
,可以通过bn=bn-256-11
去掉偏移,然后bn/256
得到在第几块Singly-Indirect
,bn%256
得到目标块在Singly-Indirect
中的偏移。- 通过
bread
获取buf
之后,修改buf
后需要通过log_write
操作写入更新。
1.3 实现
- 修改直接块数量,注意需要修改
dinode
和inode
的addrs
大小
#define NDOUBLEINDIRECT (NINDIRECT * NINDIRECT)
#define NDIRECT 11
// On-disk inode structure
struct dinode {
short type; // File type
short major; // Major device number (T_DEVICE only)
short minor; // Minor device number (T_DEVICE only)
short nlink; // Number of links to inode in file system
uint size; // Size of file (bytes)
uint addrs[NDIRECT+2]; // Data block addresses
};
// in-memory copy of an inode
struct inode {
uint dev; // Device number
uint inum; // Inode number
int ref; // Reference count
struct sleeplock lock; // protects everything below here
int valid; // inode has been read from disk?
short type; // copy of disk inode
short major;
short minor;
short nlink;
uint size;
uint addrs[NDIRECT+2];
};
- 分配间接块,此处需要注意,只有当用到时才分配块,其次修改块时需要记得
log_write
static uint
bmap(struct inode *ip, uint bn)
{
uint addr, *a;
struct buf *bp, *inbp;
if(bn < (NDIRECT)){
if((addr = ip->addrs[bn]) == 0)
ip->addrs[bn] = addr = balloc(ip->dev);
return addr;
}
bn -= NDIRECT;
if(bn < NINDIRECT){
// Load indirect block, allocating if necessary.
if((addr = ip->addrs[NDIRECT]) == 0)
ip->addrs[NDIRECT] = addr = balloc(ip->dev);
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
if((addr = a[bn]) == 0){
a[bn] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
return addr;
}
bn -= NINDIRECT;
// load doublely-indirect block
if(bn < NDOUBLEINDIRECT){
if((addr = ip->addrs[NDIRECT + 1]) == 0)
ip->addrs[NDIRECT + 1] = addr = balloc(ip->dev); // alloc doublely-indirect block
// get indirect block index
inbp = bread(ip->dev, addr);
a = (uint*)(inbp->data);
uint in_index = bn / NINDIRECT;
uint bn_index = bn % NINDIRECT;
// Load indirect block, allocating if necessary.
if ((addr = a[in_index]) == 0){
a[in_index] = addr = balloc(ip->dev);
log_write(inbp);
}
brelse(inbp);
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
if ((addr = a[bn_index]) == 0){
a[bn_index] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
return addr;
}
panic("bmap: out of range");
}
- 释放块
// Truncate inode (discard contents).
// Caller must hold ip->lock.
void
itrunc(struct inode *ip)
{
int i, j, k;
struct buf *bp, *inbp;
uint *a;
uint *tmp;
for(i = 0; i < NDIRECT; i++){
if(ip->addrs[i]){
bfree(ip->dev, ip->addrs[i]);
ip->addrs[i] = 0;
}
}
if(ip->addrs[NDIRECT]){
bp = bread(ip->dev, ip->addrs[NDIRECT]);
a = (uint*)bp->data;
for(j = 0; j < NINDIRECT; j++){
if(a[j])
bfree(ip->dev, a[j]);
}
brelse(bp);
bfree(ip->dev, ip->addrs[NDIRECT]);
ip->addrs[NDIRECT] = 0;
}
if(ip->addrs[NDIRECT + 1]){
inbp = bread(ip->dev, ip->addrs[NDIRECT + 1]);
a = (uint*)(inbp->data);
for (j = 0; j < NINDIRECT; j++){
if (a[j]) {
bp = bread(ip->dev, a[j]);
tmp = (uint*)bp->data;
for(k = 0; k < NINDIRECT; k++){
if(tmp[k])
bfree(ip->dev, tmp[k]);
}
brelse(bp);
bfree(ip->dev, a[j]);
a[j] = 0;
}
}
brelse(inbp);
bfree(ip->dev, ip->addrs[NDIRECT + 1]);
ip->addrs[NDIRECT + 1] = 0;
}
ip->size = 0;
iupdate(ip);
}
2. Symbolic links(moderate)
2.1 要求
You will implement the symlink(char *target, char *path) system call, which creates a new symbolic link at path that refers to file named by target. For further information, see the man page symlink. To test, add symlinktest to the Makefile and run it. Your solution is complete when the tests produce the following output (including usertests succeeding).
实现 symlink
接口,比较简单,与 link
的区别在于,symlink
会创建文件,而 link
接口只是增加目标文件的引用计数,并写入目录。
2.2 分析
实现主要有 2 点:
- 创建链接文件,通过
sys_symlink
接口创建 - 访问链接文件,通过
sys_open
访问
2.3 实现
- 创建文件
在 inode
结构中增加 char symlinkpath[128];
,用于存储目标文件的名字。
uint64 sys_symlink(void)
{
char path[MAXPATH], target[MAXPATH];
struct inode *ip;
if(argstr(0, target, MAXPATH) < 0 || argstr(1, path, MAXPATH) < 0)
return -1;
begin_op();
if ((ip = namei(path)) == 0){
ip = create(path, T_SYMLINK, 0, 0);
if (ip == 0){
end_op();
return -1;
}
}else if (ip->type != T_SYMLINK){
end_op();
return -1;
}else{
ilock(ip);
}
memset(ip->symlinkpath, 0, MAXPATH);
memmove(ip->symlinkpath, target, sizeof(target));
iunlockput(ip);
end_op();
return 0;
}
- 访问文件
需要注意如果有 O_NOFOLLOW
的 flag,则直接访问链接文件,而不是访问 inode.symlinkpath
的文件。
其次要注意存在链接文件 链接 链接文件的操作,有点套娃,比如 a->b,b->c,c->a,此时如果没有防范措施会无限套娃,因此根据 hints 加了个递归层次限制。
uint64 sys_open(void)
{
char path[MAXPATH];
int fd, omode;
struct file *f;
struct inode *ip, *symip;
int n;
if((n = argstr(0, path, MAXPATH)) < 0 || argint(1, &omode) < 0)
return -1;
begin_op();
if(omode & O_CREATE){
ip = create(path, T_FILE, 0, 0);
if(ip == 0){
end_op();
return -1;
}
}
else {
if((ip = namei(path)) == 0){
end_op();
return -1;
}
ilock(ip);
if(ip->type == T_DIR && omode != O_RDONLY){
iunlockput(ip);
end_op();
return -1;
}
}
int cnt = 0;
while(ip->type == T_SYMLINK && !(omode & O_NOFOLLOW)){
if (cnt >= 10) {
iunlockput(ip);
end_op();
return -1;
}
symip = namei(ip->symlinkpath);
if (symip) {
cnt++;
iunlockput(ip);
ip = symip;
ilock(ip);
}
else {
break;
}
}
if (cnt == 0 && ip->type == T_SYMLINK && !(omode & O_NOFOLLOW)){
iunlockput(ip);
end_op();
return -1;
}
if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
iunlockput(ip);
end_op();
return -1;
}
if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
if(f)
fileclose(f);
iunlockput(ip);
end_op();
return -1;
}
if(ip->type == T_DEVICE){
f->type = FD_DEVICE;
f->major = ip->major;
} else {
f->type = FD_INODE;
f->off = 0;
}
f->ip = ip;
f->readable = !(omode & O_WRONLY);
f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
if((omode & O_TRUNC) && ip->type == T_FILE){
itrunc(ip);
}
iunlock(ip);
end_op();
return fd;
}
9. Lab: file system的更多相关文章
- MIT 6.S081 Lab File System
前言 打开自己的blog一看,居然三个月没更新了...回想一下前几个月,开题 + 实验室杂活貌似也没占非常多的时间,还是自己太懈怠了吧,掉线城和文明6真的是时间刹手( 不过好消息是把15445的所有l ...
- RH133读书 笔记(4) - Lab 4 System Services
Lab 4 System Services Goal: Develop skills using system administration tools and setting up and admi ...
- RH253读书笔记(1)-Lab 1 System Monitoring
Lab 1 System Monitoring Goal: To build skills to better assess system resources, performance and sec ...
- RH133读书笔记(11)-Lab 11 System Rescue and Troubleshooting
Lab 11 System Rescue and Troubleshooting Goal: To build skills in system rescue procedures. Estimate ...
- MIT-6.828-JOS-lab5:File system, Spawn and Shell
Lab 5: File system, Spawn and Shell tags: mit-6.828 os 概述 本lab将实现JOS的文件系统,只要包括如下四部分: 引入一个文件系统进程(FS进程 ...
- Can Microsoft’s exFAT file system bridge the gap between OSes?
转自:http://arstechnica.com/information-technology/2013/06/review-is-microsofts-new-data-sharing-syste ...
- File System Design Case Studies
SRC=http://www.cs.rutgers.edu/~pxk/416/notes/13-fs-studies.html Paul Krzyzanowski April 24, 2014 Int ...
- MIT6.828 La5 File system, Spawn and Shell
Lab 5: File system, Spawn and Shell 1. File system preliminaries 在lab中我们要使用的文件系统比大多数"真实"文件 ...
- Design and Implementation of the Sun Network File System
Introduction The network file system(NFS) is a client/service application that provides shared file ...
随机推荐
- 解决 Vue 项目 invalid host header 问题(两种方案)
问题出现背景 做微信H5网页时,使用花生壳内网穿透进行调试时,打开网页显示:invalid host header 分析问题 这句话的意思是:无效的Host请求头: 因为在vue在调试时相当于启动了一 ...
- Java Object 类常用方法总结
总结 public final native Class<?> getClass() //返回此 Object 运行时的类 public native int hashCode() //返 ...
- java 知识点梳理
1.ArrayList与linkedList 区别 ArrayList 采用的是数组形式来保存对象的,这种方式将对象放在连续的位置中,所以最大的缺点就是插入删除时非常麻烦; 优点是查找比较快. Lin ...
- Activemq持久化之kahadb特性
介绍数据的持久化是很多系统都会涉及到的一个问题,尤其是redis,activemq这些数据主要是存储在内存中的.既然存在内存中,就会面临宕机时数据丢失的风险.这一问题的解决方案就是通过某种方式将数据写 ...
- 请说说Struts1和Struts2的区别?
特性 Struts1 Struts2 Action Struts1.x要求Action类要扩展自一个抽象基类.Struts1.x的一个共有的问题是面向抽象类编程而不是面向接口编程. Struts2 ...
- XML技术的作用?
XML技术用于数据存储.信息配置.数据交换三方面. 可以将数据存储在XML中,通过节点.元素内容.属性标示数据内容及关系. 可以使用XML很方便的做信息配置,软件的各种配置参数和对象关系都存贮在XML ...
- spring-boot-learning 缓存之redis
什么是BSD协议: BSD是"Berkeley Software Distribution"的缩写,意思是"伯克利软件发行版". BSD开源协议是一个给于使用者 ...
- @RequestMapping与@Autowired的作用
@RequestMapping RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上.用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径. @Autowired @ ...
- 爬虫-ip代理
代理(proxy) 代理服务器:实现请求转发,从而可以实现更换请求的ip地址 代理的匿名度: 透明:服务器知道你使用了代理并且知道你的真实ip 匿名:服务器知道你使用了代理,但是不知道你的真实ip 高 ...
- 学习GlusterFS(七)
初始环境: 系统环境:centos73.10.0-514.26.2.el7.x86_64 机器数量:两台 硬盘:至少两块,一块为系统盘,另一块留作他用 命名规则:node1 node2 IP规划:19 ...