mirror of
https://github.com/duguosheng/6.S081-All-in-one.git
synced 2026-02-03 02:43:48 +08:00
222 lines
4.7 KiB
Markdown
222 lines
4.7 KiB
Markdown
# 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;
|
||
}
|
||
``` |