Files
2021-08-19 18:38:31 +08:00

222 lines
4.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Lab9: file system
# Large files
(1). 在fs.h中添加宏定义
```c
#define NDIRECT 11
#define NINDIRECT (BSIZE / sizeof(uint))
#define NDINDIRECT ((BSIZE / sizeof(uint)) * (BSIZE / sizeof(uint)))
#define MAXFILE (NDIRECT + NINDIRECT + NDINDIRECT)
#define NADDR_PER_BLOCK (BSIZE / sizeof(uint)) // 一个块中的地址数量
```
(2). 由于`NDIRECT`定义改变其中一个直接块变为了二级间接块需要修改inode结构体中`addrs`元素数量
```c
// fs.h
struct dinode {
...
uint addrs[NDIRECT + 2]; // Data block addresses
};
// file.h
struct inode {
...
uint addrs[NDIRECT + 2];
};
```
(3). 修改`bmap`支持二级索引
```c
static uint
bmap(struct inode *ip, uint bn)
{
uint addr, *a;
struct buf *bp;
if(bn < NDIRECT){
...
}
bn -= NDIRECT;
if(bn < NINDIRECT){
...
}
bn -= NINDIRECT;
// 二级间接块的情况
if(bn < NDINDIRECT) {
int level2_idx = bn / NADDR_PER_BLOCK; // 要查找的块号位于二级间接块中的位置
int level1_idx = bn % NADDR_PER_BLOCK; // 要查找的块号位于一级间接块中的位置
// 读出二级间接块
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[level2_idx]) == 0) {
a[level2_idx] = addr = balloc(ip->dev);
// 更改了当前块的内容,标记以供后续写回磁盘
log_write(bp);
}
brelse(bp);
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
if((addr = a[level1_idx]) == 0) {
a[level1_idx] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
return addr;
}
panic("bmap: out of range");
}
```
(4). 修改`itrunc`释放所有块
```c
void
itrunc(struct inode *ip)
{
int i, j;
struct buf *bp;
uint *a;
for(i = 0; i < NDIRECT; i++){
...
}
if(ip->addrs[NDIRECT]){
...
}
struct buf* bp1;
uint* a1;
if(ip->addrs[NDIRECT + 1]) {
bp = bread(ip->dev, ip->addrs[NDIRECT + 1]);
a = (uint*)bp->data;
for(i = 0; i < NADDR_PER_BLOCK; i++) {
// 每个一级间接块的操作都类似于上面的
// if(ip->addrs[NDIRECT])中的内容
if(a[i]) {
bp1 = bread(ip->dev, a[i]);
a1 = (uint*)bp1->data;
for(j = 0; j < NADDR_PER_BLOCK; j++) {
if(a1[j])
bfree(ip->dev, a1[j]);
}
brelse(bp1);
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
(1). 配置系统调用的常规操作,如在***user/usys.pl***、***user/user.h***中添加一个条目,在***kernel/syscall.c***、***kernel/syscall.h***中添加相关内容
(2). 添加提示中的相关定义,`T_SYMLINK`以及`O_NOFOLLOW`
```c
// fcntl.h
#define O_NOFOLLOW 0x004
// stat.h
#define T_SYMLINK 4
```
(3). 在***kernel/sysfile.c***中实现`sys_symlink`,这里需要注意的是`create`返回已加锁的inode此外`iunlockput`既对inode解锁还将其引用计数减1计数为0时回收此inode
```c
uint64
sys_symlink(void) {
char target[MAXPATH], path[MAXPATH];
struct inode* ip_path;
if(argstr(0, target, MAXPATH) < 0 || argstr(1, path, MAXPATH) < 0) {
return -1;
}
begin_op();
// 分配一个inode结点create返回锁定的inode
ip_path = create(path, T_SYMLINK, 0, 0);
if(ip_path == 0) {
end_op();
return -1;
}
// 向inode数据块中写入target路径
if(writei(ip_path, 0, (uint64)target, 0, MAXPATH) < MAXPATH) {
iunlockput(ip_path);
end_op();
return -1;
}
iunlockput(ip_path);
end_op();
return 0;
}
```
(4). 修改`sys_open`支持打开符号链接
```c
uint64
sys_open(void)
{
...
if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
...
}
// 处理符号链接
if(ip->type == T_SYMLINK && !(omode & O_NOFOLLOW)) {
// 若符号链接指向的仍然是符号链接,则递归的跟随它
// 直到找到真正指向的文件
// 但深度不能超过MAX_SYMLINK_DEPTH
for(int i = 0; i < MAX_SYMLINK_DEPTH; ++i) {
// 读出符号链接指向的路径
if(readi(ip, 0, (uint64)path, 0, MAXPATH) != MAXPATH) {
iunlockput(ip);
end_op();
return -1;
}
iunlockput(ip);
ip = namei(path);
if(ip == 0) {
end_op();
return -1;
}
ilock(ip);
if(ip->type != T_SYMLINK)
break;
}
// 超过最大允许深度后仍然为符号链接,则返回错误
if(ip->type == T_SYMLINK) {
iunlockput(ip);
end_op();
return -1;
}
}
if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
...
}
...
return fd;
}
```