[MIT6.S081]Lab9: File System
# [MIT6.S081]Lab9: File System
Lab: file system (mit.edu) (opens new window)
# Large files
在这个 assignment 中我们要扩充 xv6 文件的大小从 268 个块到 65803 个块,一开始我们的 inode 存储了 12 个 direct 的块号,以及一个 singly-indirect 块号 (类似于页表的多级映射,这里是单级)。每个 singly-indirect 块号代表了一个包含了 256 个块号的块。我们通过拿掉一个 direct 的块号,添加一个 doubly-indirect 块号(二级映射),而一个 doubly-indirect 块号代表了一个包含 256 个 singly-indirect 块号的块。
如此一来我们最后的块个数是 (12 - 1) * 1 + 256 + 256 * 256 = 65803
首先我们修改一些宏定义和数组长度
// fs.h
#define NDIRECT 11
// On-disk inode structure
struct dinode {
// ......
uint addrs[NDIRECT+2]; // Data block addresses
};
// file.h
struct inode {
// ......
uint addrs[NDIRECT+2];
};
接着我们先修改 bmap()
函数
如果他不在一级索引的范围内,那么我们可以像前面一样给块号减去一个 NINDIRECT
,有助于我们后面直接判断二级索引的范围是 < NINDIRECT * NINDIRECT
。
接下里的部分很前面类似,只是要映射两次,需要注意的是对于第一层的索引,我们的块号取得是 nb / NINDIRECT
,而第二层的索引是 bn % NINDIRECT
。
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;
if(bn < NINDIRECT * NINDIRECT) { // 二级索引的范围
if((addr = ip->addrs[NDIRECT + 1]) == 0)
ip->addrs[NDIRECT + 1] = addr = balloc(ip->dev);
bp = bread(ip->dev, addr);
a = (uint *)bp->data; // 二级索引的第一级
if ((addr = a[bn / NINDIRECT]) == 0) { // bn / NINDIRECT 是第一级的 index
a[bn / NINDIRECT] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp); // 释放锁
bp = bread(ip->dev, addr);
a = (uint *)bp->data; // 二级索引的第二级
if ((addr = a[bn % NINDIRECT]) == 0) {
a[bn % NINDIRECT] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp); // 释放锁
return addr;
}
最后我们还要修改 itrunc()
函数,同样十分类似,只是多嵌套了一层映射,另外要注意 NDIRECT
和 NINDIRECT
不要用错。
if (ip->addrs[NDIRECT + 1]) {// 二级索引
bp = bread(ip->dev, ip->addrs[NDIRECT + 1]);
a = (uint *)bp->data; // 一级 index
for (int i = 0; i < NINDIRECT; i++) {
if (a[i]) {
bp2 = bread(ip->dev, a[i]); // 二级 index
uint *b = (uint *)bp2->data;
for (int j = 0; j < NINDIRECT; j++) {
if (b[j]) {
bfree(ip->dev, b[j]);
}
}
brelse(bp2);
bfree(ip->dev, a[i]);
}
}
brelse(bp);
bfree(ip->dev, ip->addrs[NDIRECT + 1]);
ip->addrs[NDIRECT + 1] = 0;
}
# Symbolic links
在这个 assignment 中要为 xv6 添加软连接,实现 symlink 的系统调用。
添加系统调用过程不再赘述,具体的实现部分参考其他函数和手册给出的 hints 一步步实现即可。
// sysfile.c
uint64 sys_symlink(void) {
struct inode *ip;
char target[MAXPATH];
char path[MAXPATH];
if (argstr(0, target, MAXPATH) < 0 || argstr(1, path, MAXPATH) < 0) {
return -1;
}
begin_op();
if ((ip = create(path, T_SYMLINK, 0, 0)) == 0) {
end_op();
return -1;
}
if (writei(ip, 0, (uint64)target, 0, MAXPATH) < 0) { // 存储路径
end_op();
return -1;
}
iunlockput(ip);
end_op();
return 0;
}
uint64
sys_open(void)
{
char path[MAXPATH];
int fd, omode;
struct file *f;
struct inode *ip;
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;
}
}
if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
iunlockput(ip);
end_op();
return -1;
}
if ((ip->type == T_SYMLINK) && ((omode & O_NOFOLLOW) == 0)) {
int cnt = 0;
char target[MAXPATH];
while (1) {
if (++cnt > 10) {
iunlockput(ip);
end_op();
return -1;
}
if (ip->type != T_SYMLINK) { // 如果不是 symlink 了九条出去
break;
}
readi(ip, 0, (uint64)target, 0, MAXPATH); // 从 ip 中读取数据(路径名)
iunlockput(ip);
if ((ip = namei(target)) == 0) { // 找不到文件
end_op();
return -1;
}
ilock(ip);
}
}
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;
}
# 实验结果
Last Updated: 3/4/2023, 5:38:14 PM