本文主要是介绍6.1810: Operating System Engineering 2023 <Lab8 fs: File system>,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、本节任务
二、Lab8: file system
在这一节,我们将为 xv6 的文件系统加入大文件和符号链接。
2.1 Large files (moderate)
这个部分需要我们增加 xv6 文件的大小上限,由于 inode 结构体中有 12 个直接映射项,1 个一级间接映射项,所以 xv6 文件系统中的最大文件大小为 (12 + (1024B / 4B)) 个块,即 268 个块,在 xv6 中,每个块大小为 1024B。而通过再增加一个二级间接映射项可以让我们的文件大小增加到 (11 + 256 + 256*256) = 65803 个块,而下面我们就是要实现这个二级间接映射项。
首先修改 fs.h 文件中的宏和 dinode 中 addrs 的大小,以及 file.h 文件中 inode 结构体中 addrs 的大小也要同步修改过来。这样做的目的是减少一个直接映射项,增加一个二级间接映射项。
#define NDIRECT 11
#define NINDIRECT (BSIZE / sizeof(uint))
#define MAXFILE (NDIRECT + NINDIRECT + NINDIRECT * NINDIRECT)// On-disk inode structure
struct dinode {short type; // File typeshort major; // Major device number (T_DEVICE only)short minor; // Minor device number (T_DEVICE only)short nlink; // Number of links to inode in file systemuint size; // Size of file (bytes)uint addrs[NDIRECT+2]; // Data block addresses
};
// in-memory copy of an inode
struct inode {uint dev; // Device numberuint inum; // Inode numberint ref; // Reference countstruct sleeplock lock; // protects everything below hereint valid; // inode has been read from disk?short type; // copy of disk inodeshort major;short minor;short nlink;uint size;uint addrs[NDIRECT+2];
};
然后再修改 fs.c 文件中的 bmap 和 itrunc 函数,bmap 函数的作用是通过逻辑块号 bn 来到 addrs 数组中找到其在磁盘上的真实块号;而 itrunc 函数的作用是将 inode 的 addrs 清空。直接映射项的真实块号就是 addrs[bn],而一级间接映射项的真实块号还需要从 addrs[NDIRECT] 指向的块上寻找真实块号,二级间接映射项需要从 addrs[NDIRECT+1] 指向的块上先找到对应一级间接映射项,然后再找到真实块号。
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){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);a = (uint*)bp->data;if((addr = a[bn/NINDIRECT]) == 0){addr = balloc(ip->dev);if(addr == 0)return 0;a[bn/NINDIRECT] = addr;log_write(bp);}brelse(bp);bn = bn % NINDIRECT;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;}panic("bmap: out of range");
}
void
itrunc(struct inode *ip)
{int i, j;struct buf *bp;struct buf *bp1;uint *a;uint *a1;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]){bp1 = bread(ip->dev, a[i]);a1 = (uint*)bp1->data;for(j = 0; j < NINDIRECT; j++){if(a1[j])bfree(ip->dev, a1[j]);}brelse(bp1);bfree(ip->dev, a[i]);a[i] = 0;}}brelse(bp);bfree(ip->dev, ip->addrs[NDIRECT+1]);ip->addrs[NDIRECT+1] = 0;}ip->size = 0;iupdate(ip);
}
最后通过测试。
2.2 Symbolic links (moderate)
首先创建一个新系统调用 symlink,怎么添加系统调用在之前的 lab 中已经做过了,这里就不多赘述了。
下面是 symlink 系统调用的实现,首先使用 create 创建一个新文件,文件的类型为 T_SYMLINK,然后使用 writei 向文件的数据块写入 target 路径,这样使用 open 系统调用时如果发现文件是链接文件,则从文件的数据块中读取 target 文件的路径。最后记得使用 iunlockput(ip) 释放 inode 的锁和引用:
uint64 sys_symlink(void)
{int n;char target[MAXPATH];char path[MAXPATH];struct inode *ip;if((n = argstr(0, target, MAXPATH)) < 0 || argstr(1, path, MAXPATH) < 0){return -1;}begin_op();ip = create(path, T_SYMLINK, 0, 0);if(ip == 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 系统调用,当识别到文件的类型为 T_SYMLINK 的时候,并且模式不为 O_NOFOLLOW,则循环地通过链接路径找到被链接的文件,若被链接的文件就是当前文件本身,形成的环路,或者链接的深度超过了 10,则报错:
uint64
sys_open(void)
{char path[MAXPATH];char target[MAXPATH];int fd, omode;struct file *f;struct inode *ip;struct inode *tip;int n, depth;argint(1, &omode);if((n = argstr(0, path, MAXPATH)) < 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;}}depth = 0;while(ip->type == T_SYMLINK && !(omode & O_NOFOLLOW)){if(readi(ip, 0, (uint64)target, 0, MAXPATH) != MAXPATH)panic("open symlink: readi");// the links form a cycleif(strncmp(target, path, n) == 0){iunlockput(ip);end_op();return -1;}// target file does not existif((tip = namei(target)) == 0){iunlockput(ip);end_op();return -1;}iunlock(ip);ilock(tip);ip = tip;depth++;if(depth >= 10){iunlockput(ip);end_op();return -1;}}
.....
.....
最后通过所有测试。
这篇关于6.1810: Operating System Engineering 2023 <Lab8 fs: File system>的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!