这个实验有两个任务。
1.Large files
在inode和dinode的数据结构里边是只有直接映射和一级间接映射的,我们的任务是在直接映射里面拿一个位置来放二级映射。和页表有点像,不是么。
首先在改变数据结构:
#define NDIRECT 11
#define NINDIRECT (BSIZE / sizeof(uint))
#define DOUBLENINDIRECT (NINDIRECT * NINDIRECT)
#define MAXFILE (NDIRECT + NINDIRECT + DOUBLENINDIRECT)
// 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+1+1]; // 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+1+1];
};
接着我们在根据块号找缓冲块地址的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 < DOUBLENINDIRECT)
{
if ((addr = ip->addrs[NDIRECT+1]) == 0)
{
ip->addrs[NDIRECT+1] = addr = balloc(ip->dev);
}
bp = bread(ip->dev, addr);
a = (uint*)bp->data;// 第一个间接块
uint num = bn / NINDIRECT;// 第一个间接块偏移
uint off = bn % NINDIRECT;// 第二个间接块偏移
// 处理第一个间接块
if ((addr = a[num]) == 0)
{
a[num] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
// 处理第二个间接块
if ((addr = a[off]) == 0)
{
a[off] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
return addr;
}
panic("bmap: out of range");
}
最后在itrunc中处理释放各级缓冲块以及映射块:
void
itrunc(struct inode *ip)
{
int i, j, k;
struct buf *bp, *bp1;
uint *a, *b;
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 (j = 0; j < NINDIRECT; j++)
{
if (a[j])
{
bp1 = bread(ip->dev, a[j]);// 读入第二间接块
b = (uint*)bp1->data;
for (k = 0; k < NINDIRECT; k++)
{
if (b[k])
bfree(ip->dev, b[k]);// 释放map上数据块映射
}
brelse(bp1);// 释放第二间接块的缓存块
bfree(ip->dev, a[j]);// 释放map上第二间接块的映射
}
}
brelse(bp);// 释放第一间接块的缓存块
bfree(ip->dev, ip->addrs[NDIRECT+1]);// 释放第一间接块的映射
ip->addrs[NDIRECT+1] = 0;
}
ip->size = 0;
iupdate(ip);
}
好像还得改一个FSSIZE
测试通过辣:

2.Symbolic links
软链接的实现是个inode,inode的数据块中存储了链接文件的路径,然后我们在打开一个文件的时候如果指定要追踪,就按照文件链接的路径一直搜索下去,否则就直接返回当前的inode。
系统调用的添加和以前一样,之后就是写系统调用,在系统调用中创建一个文件的inode,然后把路径写入inode的数据块中,由于create里边涉及到inode对应磁盘块的更新,我们用xv6的日志系统括起来,也就是begin_op,logwrite,end_op三个元素:
uint64
sys_symlink(void){
char target[MAXPATH], path[MAXPATH];
struct inode *ip;
if (argstr(0, target, MAXPATH)<0 || argstr(1, path, MAXPATH)<0)
return -1;
// 创建软链接文件inode
begin_op();
if ((ip=create(path, T_SYMLINK, 0, 0))==0)
{
end_op();
return -1;
}
// 将文件路径target写入文件
if (writei(ip,0,(uint64)target,0,MAXPATH)<0)
{
end_op();
return -1;
}
iunlockput(ip);
end_op();
return 0;
}
之后在open的系统调用中,当inode类型是软连接,在文件的打开模式表示跟踪的情况下,进行递归查询inode直到查到当前inode不是软链接为止。代码如下所示:
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)
{
// 标记O_NOFOLLOW表示直接打开这个文件而不是跟踪软链接
// 未标记则继续跟踪
if (!(omode & O_NOFOLLOW))
{
int cycle = 0;
char target[MAXPATH];
while (ip->type==T_SYMLINK)
{
if (cycle == 10)
{
iunlockput(ip);
end_op();
return -1;
}
cycle++;
memset(target,0,sizeof(target));
readi(ip,0,(uint64)target,0,MAXPATH);
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;
}
测试通过辣:

usertests也没问题: