xv6-lab9-fs
Large files(moderate)
实现二级间接块
题目理解
原始文件的data block分布
- 12个直接块
- 1个一级间接块–>指向256个数据块
目标的data block分布
- 11个直接块
- 1个一级间接块–>指向256个数据块
- 1个二级间接块–>指向
256*256
个数据块
lab实现的原理很简单——添加二级间接块
代码实现
修改关于数据块数目宏定义
1 |
修改disk inode
1 | struct dinode { |
修改inode
1 | // in-memory copy of an inode |
修改bmap:将逻辑块号映射到磁盘的物理块地址
- 原始bmap理解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30// 将逻辑块号映射到磁盘的物理块地址
// ip: 文件inode
// bn: 该文件的指定数据块号
static uint
bmap(struct inode *ip, uint bn)
{
uint addr, *a;
struct buf *bp;
if(bn < NDIRECT){ // 当bn指向直接块
if((addr = ip->addrs[bn]) == 0) // 检查bn指定的块是否已经分配
ip->addrs[bn] = addr = balloc(ip->dev); // 没有分配则在文件对象所在设备分配一个块
return addr; // 返回块地址
}
bn -= NDIRECT;
if(bn < NINDIRECT){ // 当bn指向间接块
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){ // 检查bn指定的块是否已经分配
a[bn] = addr = balloc(ip->dev); // 没有分配则在文件对象所在设备分配一个块
log_write(bp); // 分配块更改了间接块的数据,需要log写回
}
brelse(bp); // 释放缓存
return addr; // 返回块地址
}
panic("bmap: out of range");
} - 需要增加的二级间接块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29if(bn < NINDIRECT){ // 当bn指向间接块
// ...
}
bn -= NINDIRECT;
if (bn < NDINDIRECT){
if((addr = ip->addrs[NDIRECT + 1]) == 0) // 看二级间接块L1是否分配
ip->addrs[NDIRECT + 1] = addr = balloc(ip->dev);
// L1
bp = bread(ip->dev, addr); // 读取L1间接块
a = (uint*)bp->data; // 获取L1间接块存放的地址列表
if ((addr = a[bn / NINDIRECT]) == 0){ // 看二级间接块L2是否分配
a[bn / NINDIRECT] = addr = balloc(ip->dev); // 没有分配则在文件对象所在设备分配一个块
log_write(bp); // 分配块更改了间接块的数据,需要log写回
}
brelse(bp); // 释放
// L2
bp = bread(ip->dev, addr); // 读取L2间接块
a = (uint*)bp->data; // 获取L2间接块存放的地址列表
if ((addr = a[bn % NINDIRECT]) == 0){ // 看二级间接块L2指向数据块是否分配
a[bn % NINDIRECT] = addr = balloc(ip->dev); // 没有分配则在文件对象所在设备分配一个块
log_write(bp); // 分配块更改了间接块的数据,需要log写回
}
brelse(bp); // 释放
return addr;
}
panic("bmap: out of range");
// ...
修改itrunc
- 原始itrunc理解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30// 截断inode对应文件对象
void
itrunc(struct inode *ip)
{
int i, j;
struct buf *bp;
uint *a;
for(i = 0; i < NDIRECT; i++){ // 迭代直接块
if(ip->addrs[i]){ // 如果已经分配
bfree(ip->dev, ip->addrs[i]); // 释放指定设备的物理地址的块,内部会
ip->addrs[i] = 0; // addrs数组指定位置 置为零
}
}
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); // 释放bp cache
bfree(ip->dev, ip->addrs[NDIRECT]); // 释放间接块本身
ip->addrs[NDIRECT] = 0;
}
ip->size = 0;
iupdate(ip); // 同步inode到dinode
} - 需要增加的二级itrunc截断过程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28if(ip->addrs[NDIRECT]){
// ...
}
struct buf* bp1;
uint* a1;
if(ip->addrs[NDIRECT + 1]){ // 是否分配了二级间接块
bp = bread(ip->dev, ip->addrs[NDIRECT + 1]); // 分配了,则读取二级间接块
a = (uint*)bp->data; // 读取二级间接块L1记录的地址列表
for(i = 0; i < NINDIRECT; i++){
if(a[i]){
bp1 = bread(ip->dev, a[i]); // 读取二级间接块L2
a1 = (uint*)bp1->data; // 读取二级间接块L2记录的地址列表
for(j = 0; j < NINDIRECT; j++){
if(a1[j]){
bfree(ip->dev, a1[j]); // 释放L2指向的block
}
}
brelse(bp1);
bfree(ip->dev, a[i]); // 释放L1指向的block
}
}
brelse(bp); // 释放bp cache
bfree(ip->dev, ip->addrs[NDIRECT + 1]); // 释放二级间接块本身
ip->addrs[NDIRECT + 1] = 0;
}
ip->size = 0;
iupdate(ip);
// ...
Symbolic links(moderate)
实现symlink系统调用
题目理解
实现的函数声明
- 为target创建一个符号链接
1
int symlink(char *target, char *path);
代码实现
通用的需要添加的
user/usys.pl
1
entry("symlink");
user/user.h
1
int symlink(char *target, char *path);
kernel/sysfile.c
1
2
3
4
5uint64
sys_symlink(void) {
// 待补充
return 0;
}kernel/syscall.c
1
2
3extern uint64 sys_symlink(void);
[SYS_symlink] sys_symlink,kernel/syscall.h
1
kernel/stat.h
1
kernel/fcntl.h
1
Makefile
1
$U/_symlinktest\
symlink实现
符号链接的内容就是目标路径字符串
1 | uint64 |
open修改
原始sys_open
1 | uint64 |
1 | // ... |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 bhhxx's blog!