实验一 bigfile 链接到标题
其实这个实验的要求并不难,主要是要理解xv6的文件系统的实现细节。
几个我认为的重点:
- buffer层的函数细节要弄清楚
- log层的函数使用要弄清楚
- 索引节点的结构和使用要弄清楚
- 一点define的细节要弄清楚 代码:
static uint bmap(struct inode *ip, uint bn) {
uint addr, *a;
struct buf *bp;
if (bn < NDIRECT) {
if ((addr = ip->addrs[bn]) == 0) {
addr = balloc(ip->dev);
if (addr == 0)
return 0;
ip->addrs[bn] = addr;
}
return addr;
}
bn -= NDIRECT;
if (bn < NINDIRECT) {
// Load indirect block, allocating if necessary.
if ((addr = ip->addrs[NDIRECT]) == 0) {
addr = balloc(ip->dev);
if (addr == 0)
return 0;
ip->addrs[NDIRECT] = addr;
}
bp = bread(ip->dev, addr);
a = (uint *)bp->data;
if ((addr = a[bn]) == 0) {
addr = balloc(ip->dev);
if (addr) {
a[bn] = addr;
log_write(bp);
}
}
brelse(bp);
return addr;
}
bn -= NINDIRECT;
if (bn < NINDIRECT * NINDIRECT) {
// Load indirect block, allocating if necessary.
if ((addr = ip->addrs[NDIRECT + 1]) == 0) {
addr = balloc(ip->dev);
if (addr == 0)
return 0;
ip->addrs[NDIRECT + 1] = addr;
}
bp = bread(ip->dev, addr); // 读一个buff,addr指磁盘地址,这里是读一个间接块
a = (uint *)bp->data;
// 一个uint占4字节,一个block的地址是4字节
// a就是一个uint数组,a[0]是第一个block的地址,a[1]是第二个block的地址
if ((addr = a[bn / NINDIRECT]) == 0) {
addr = balloc(ip->dev);
if (addr) {
a[bn / NINDIRECT] = addr;
log_write(bp);
}
}
brelse(bp);
bp = bread(ip->dev, addr); // 读一个buff,addr指2级间接块的地址
a = (uint *)bp->data;
if ((addr = a[bn % NINDIRECT]) == 0) {
addr = balloc(ip->dev);
if (addr) {
a[bn % NINDIRECT] = addr;
log_write(bp);
}
}
brelse(bp);
return addr;
}
panic("bmap: out of range");
}
实验二 symlink 链接到标题
这个实验主要是多个细节点要想好
我现在其实也没有想太好,虽然弄出来了,但是感觉有点乱,主要是因为我没有把整个文件系统的实现细节弄清楚,所以在实现这个功能的时候有点乱,感觉有点像在拼图一样,虽然最后拼出来了,但是感觉不是很清晰。
整体sys_symlink的实现可以参照create的实现,主要是要弄清楚create的实现细节,尤其是普通文件的实现细节,其中得自己注意inode的创建,日志(log)的处理,文件夹操作(dirlookup,namex)和已有软连接文件重复创建。这好些细节。
然后就是sys_open的代码增加,注意不要搞个死循环。
我应该花时间梳理一下整个文件系统的实现细节,看看函数的设计。最好画个图。现在没时间了,先把这个实验写完了再说。
symlink的实现 链接到标题
uint64 sys_symlink(void) {
// printf("symlink loaded!\n\n");
// 这里DIRSIZE就是文件名字的长度
char name[DIRSIZ], new[MAXPATH], old[MAXPATH];
struct inode *dp, *ip;
// 读取连接的路径,这里old指需要存在data里的路径
if (argstr(0, old, MAXPATH) < 0 || argstr(1, new, MAXPATH) < 0)
return -1;
// 成功读取参数后开始事务,只用写new路径里的inode
// 甚至可以根本不用看old里的inode,直接把old路径存到new路径的inode里就行了
begin_op();
// 现在dp指向new路径的父目录了,接下来在这个目录下创建一个新的inode,类型为T_SYMLINK
if ((dp = nameiparent(new, name)) == 0)
goto bad;
ilock(dp);
if ((ip = dirlookup(dp, name, 0)) != 0) {
iunlockput(dp);
ilock(ip);
if (ip->type == T_SYMLINK) {
iunlockput(ip);
end_op();
return 0;
}
iunlockput(ip);
goto bad;
}
if ((ip = ialloc(dp->dev, T_SYMLINK)) == 0) {
iunlockput(dp);
goto bad;
}
ilock(ip);
ip->nlink = 1;
ip->major = 0;
ip->minor = 0;
int oldlen = strlen(old) + 1;
if (oldlen > MAXPATH)
oldlen = MAXPATH;
writei(ip, 0, (uint64)old, 0,
oldlen); // 这里可能写错了,等会看看是不是usersrc
if (dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0) {
iunlockput(dp);
itrunc(ip);
iunlockput(ip);
goto bad;
}
iunlockput(dp);
iunlockput(ip);
end_op();
return 0;
bad:
end_op();
return -1;
}
open的修改 链接到标题
这里是不是不需要end_op()这个,毕竟循环找连接的目标文件并不需要写,真正的写放在symlink里了,open里只是读而已。
if (!(omode & O_NOFOLLOW)) {
int n = 10;
while (n--) {
if ((ip = namei(path)) == 0) {
break;
}
ilock(ip);
if (ip->type != T_SYMLINK) {
iunlockput(ip);
break;
}
if (readi(ip, 0, (uint64)path, 0, MAXPATH) == -1) {
iunlockput(ip);
return -1;
}
iunlockput(ip);
}
if (n == -1) {
end_op();
return -1;
}
}
结果 链接到标题
