Large files
在了解xv6在磁盘上的存储结构后
发现限制创建最大文件的原因就是 xv6目前有12个直接数据块和一个间接数据块
我们需要把一个直接数据块修改成二级间接数据块才能满足要求
要修改fs.h的结构体 fs.c中的bmap()函数
主要的细节在最初的bmap()中已经体现到了 照葫芦画瓢即可
要注意块号bn与连续的块的索引到底是什么关系
两层间接 怎样去访问 怎样分配新的data block
理解了这些 代码非常好写
我做这部分的时候是一气呵成的
但最后不要忘了修改一处 fs.h 的MAXFILE
否则去测试的时候跟没修改过的bmap()是一样的
static uint
bmap(struct inode *ip, uint bn)
{
uint addr, *a;
struct buf *bp;
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;
if(bn < NDOUIN){
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){
addr = a[bn/NINDIRECT] = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
if((addr = a[bn%NINDIRECT]) == 0){
addr = a[bn%NINDIRECT] = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
return addr;
}
panic("bmap: out of range");
}
itrunc()需要添加类似的代码 以释放block
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;
}
}
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]){
bp = bread(ip->dev, ip->addrs[NDIRECT+1]);
a = (uint*)bp->data;
for(i=0;i<NINDIRECT;i++){
if(a[i]){
struct buf *bp2 = bread(ip->dev, a[i]);
uint *b=(uint*)bp2->data;
for(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;
}
ip->size = 0;
iupdate(ip);
}
Symbolic links
这一部分我认为是比较难的 如果要写的比较严谨 要考虑的地方还是很多的
但在测试的时候发现给的用例可能没有这么严谨
只要把基本逻辑写清楚即可
首先就是在xv6里添加系统调用 需要在各处添加的声明代码
一定要仔细阅读xv6book的file system部分 阅读关于file的代码
不仔细阅读会有很多的坑
里面关于事务 和 锁的部分值得去学习
比如创建新的inode的create()调用后会持有返回inode的锁
这时 如果你额外上锁就会造成死锁
个人认为hints里的要求和提示都有点模糊 事实上我添加些判断或者去掉确实不影响tests通过
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 = create(path, T_SYMLINK, 0, 0)) == 0) {
end_op();
return -1;
}
if(writei(ip, 0, (uint64)target, 0, MAXPATH) != MAXPATH) {
iunlockput(ip);
end_op();
return -1;
}
iunlockput(ip);
end_op();
return 0;
}
要求在open调用里添加关于符号链接的处理
额外写了一个递归查找符号链接所连接的原inode函数
struct inode * getip(char *path,int depth,int omode){
if(depth > 10)
{
return 0;
}
struct inode *ip;
ip=namei(path);
if(ip==0)
{
return 0;
}
ilock(ip);
if(!(omode & O_NOFOLLOW) && ip->type==T_SYMLINK)
{
char next[MAXPATH];
if(readi(ip,0,(uint64)next,0,MAXPATH) == 0)
{
iunlockput(ip);
return 0;
}
iunlockput(ip);
return getip(next, depth+1 ,omode);
}
iunlock(ip);
return ip;
}
在open里修改
if(omode & O_CREATE){
ip = create(path, T_FILE, 0, 0);
if(ip == 0){
end_op();
return -1;
}
} else {
if((ip=getip(path , 0 , omode )) == 0){
end_op();
return -1;
}