当前位置:网站首页>[MIT 6.S081] Lab 9: file system
[MIT 6.S081] Lab 9: file system
2022-07-27 18:27:00 【PeakCrosser】
Lab 9: file system
- Lab Guidance: https://pdos.csail.mit.edu/6.828/2020/labs/fs.html
- Lab Code: https://github.com/peakcrosser7/xv6-labs-2020/tree/fs
Large files (moderate)
The main points of
- Implement secondary indirect block index (doubly-indirect block) Of inode structure :
ip->addrs[]Before 11 The first element is a direct block (direct block), The first 12 Element is a first level indirect block index (singly-indirect block), The first 13 Element is a secondary indirect block index (doubly-indirect block). - modify
bmap()Function to fit double-indirect block
step
- modify
kernel/fs.hMacro definition of the direct block number inNDIRECTby 11.
According to the requirements of the experiment , inode In the original 12 The direct block number is modified to 了 11 individual .
#define NDIRECT 11 // lab9-1
- modify inode Array of block numbers of related structures . Specific include
kernel/fs.hDisks in inode Structurestruct dinodeOfaddrsField ; andkernel/file.hMemory in inode Structurestruct inodeOfaddrsField . Set the array size of both toNDIRECT+2, Because of reality inode The total number of block numbers has not changed , butNDIRECTLess 1.
// On-disk inode structure
struct dinode {
// ...
uint addrs[NDIRECT+2]; // Data block addresses // lab9-1
};
// in-memory copy of an inode
struct inode {
// ...
uint addrs[NDIRECT+2]; // lab9-1
};
- stay
kernel/fs.hAdd to the definitionNDOUBLYINDIRECT, Indicates the total number of secondary indirect block numbers , analogyNINDIRECT. Because it's secondary , Therefore, the block number that can be represented should be the primary indirect block numberNINDIRECTThe square of .
#define NDOUBLYINDIRECT (NINDIRECT * NINDIRECT) // lab9-1
- modify
kernel/fs.cMediumbmap()function .
This function returns inode The block number in the disk corresponding to the relative block number of .
because inode Middle front of structureNDIRECTThe block number is consistent with that before modification , Therefore, you only need to add a pair ofNDIRECTnamely 13 Processing code of secondary indirect index of blocks . Treatment method and treatmentNDIRECTThe method of block number, that is, the first level indirect block number, is similar , Just need to index twice .
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;
}
// doubly-indirect block - lab9-1
bn -= NINDIRECT;
if(bn < NDOUBLYINDIRECT) {
// get the address of doubly-indirect 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;
// get the address of singly-indirect block
if((addr = a[bn / NINDIRECT]) == 0) {
a[bn / NINDIRECT] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
bn %= NINDIRECT;
// get the address of direct block
if((addr = a[bn]) == 0) {
a[bn] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
return addr;
}
panic("bmap: out of range");
}
- modify
kernel/fs.cMediumitrunc()function .
This function is used to release inode A block of data .
Due to the addition of a secondary indirect block structure , Therefore, you also need to add code for the release of blocks in this part . The way of release is the same as the structure of the indirect block number of the same level , Only two loops are needed to traverse the secondary indirect block and the primary indirect block respectively .
void
itrunc(struct inode *ip)
{
int i, j, k; // lab9-1
struct buf *bp, *bp2; // lab9-1
uint *a, *a2; // lab9-1
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;
}
// free the doubly-indirect block - lab9-1
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]) {
bp2 = bread(ip->dev, a[j]);
a2 = (uint*)bp2->data;
for(k = 0; k < NINDIRECT; ++k) {
if(a2[k]) {
bfree(ip->dev, a2[k]);
}
}
brelse(bp2);
bfree(ip->dev, a[j]);
a[j] = 0;
}
}
brelse(bp);
bfree(ip->dev, ip->addrs[NDIRECT + 1]);
ip->addrs[NDIRECT + 1] = 0;
}
ip->size = 0;
iupdate(ip);
}
- modify
kernel/fs.hMacro definition of the maximum file size inMAXFILE. Due to the addition of a secondary indirect block structure , xv6 The upper limit of the supported file size naturally increases , Here you need to change it to the correct value .
#define MAXFILE (NDIRECT + NINDIRECT + NDOUBLYINDIRECT) // lab9-1
Have a problem
- stay xv6 In the implementation of
bigfileadopt , But enforcementusertestsappearvirtio_disk_intr statusOf panic, As shown in the figure below :
solve : The panic The author is not very clear about the specific reasons for the emergence of , But at the beginning, the author did not modifyNDIRECTby 11, But to keep 12, But inbmap()anditrunc()Revision in China . But willNDIRECTIt is amended as follows 11 after , There is no need to panic.
test
- stay xv6 In the implementation of
bigfile:
- stay xv6 In the implementation of
usertests:
./grade-lab-fs bigfileIndividual tests :
Symbolic links (moderate)
The main points of
- Add symbolic links ( Soft link ) System call
symlink - modify
openSystem calls handle symbolic links , And when the target file of symbolic link is still a symbolic link file, you need to recursively find the target file . - With
O_NOFOLLOWOpening symbolic links does not track to linked files . - Other system calls do not track symbolic links , Then deal with the symbolic link file itself .
step
Add something about
symlinkDefinition declaration of system call . Includekernel/syscall.h,kernel/syscall.c,user/usys.planduser/user.h.




Add a new file type
T_SYMLINKTokernel/stat.hin .
Add new file flag bit
O_NOFOLLOWTokernel/fcntl.hin .
stay
kernel/sysfile.cTo realizesys_symlink()function .
This function is used to generate symbolic links . Symbolic link is equivalent to a special independent file , The stored data is the path of the target file .
So in this function , First, throughcreate()Create a symbolic link path corresponding to inode structure ( Use at the same timeT_SYMLINKDistinguish from ordinary files ). And then throughwritei()Write the path of the linked target file inode ( Of block) Then you can . In the process , There is no need to judge whether the target path of the connection is valid .
It should be noted that there are some lock release rules for file systems . functioncreate()Will return the created inode, At this time, it will also hold its inode Lock of . And laterwritei()It can only be written when it is locked . After finishing the operation ( Success or not ), All need to be callediunlockput()To release inode The lock and itself , The function isiunlock()andiput()The combination of , The former is released inode Lock of ; The latter is to reduce one inode References to ( Corresponding Fieldref, Record the memory pointing to this inode Number of pointers , there inode It's actually in memory inode, From memory inode cacheicacheDistributed , Whenrefby 0 It will be recycled toicachein ), It means that it is no longer necessary to hold this inode The pointer of continues to operate on it 了 .
// lab9-2
uint64 sys_symlink(void) {
char target[MAXPATH], path[MAXPATH];
struct inode *ip;
int n;
if ((n = argstr(0, target, MAXPATH)) < 0
|| argstr(1, path, MAXPATH) < 0) {
return -1;
}
begin_op();
// create the symlink's inode
if((ip = create(path, T_SYMLINK, 0, 0)) == 0) {
end_op();
return -1;
}
// write the target path to the inode
if(writei(ip, 0, (uint64)target, 0, n) != n) {
iunlockput(ip);
end_op();
return -1;
}
iunlockput(ip);
end_op();
return 0;
}
- modify
kernel/sysfileOfsys_open()function .
This function uses , For symbolic links, generally, what you need to open is the linked target file , Therefore, additional processing of symbolic link files is required .
Considering that the operation of tracking symbolic links is relatively independent , Here the author writes an independent functionfollow_symlink()The target file used to find symbolic links .
When tracking symbolic links, you need to take into account that the target of symbolic links may still be symbolic links , At this time need Recursively track target links Until you get the real file . Two problems need to be solved : First, symbolic links may form rings , This will keep tracking recursively , therefore Ring forming detection is required ; On the other hand, we need Limit the depth of links , To reduce the burden of the system ( These two points are also the requirements of the experiment ).
For the depth of the link , Here inkernel/fs.hIt definesNSYMLINKUsed to indicate the maximum symbolic link depth , Beyond this depth, the trace will not continue, but an error will be returned .
// the max depth of symlinks - lab9-2
#define NSYMLINK 10
And for the detection of looping , Here is also the simplest algorithm : Create a size of NSYMLINK Array of inums[] be used for Record the file tracked each time inode number, Every time the target file is tracked inode Post metropolis Put it inode number And inums Compare the records in the array , If there is repetition, it is proved to be a ring .
So on the whole follow_symlink() The process of function is actually relatively simple , At most NSYMLINK Track symbolic links recursively for times : Use readi() Function to read the path of the target file recorded in the symbolic link file , And then use namei() Get the corresponding file path inode, Then with what has been recorded inode number Compare and judge whether it forms a ring . Until the goal inode Type is not T_SYMLINK That is, symbolic link type .
And in the sys_open() in , You need to create a file object f=filealloc() Before , For symbolic links , In Africa NO_FOLLOW Under the circumstances You need to change the current file's inode Replace with follow_symlink() Get the target file inode And then carry out the following operations .
Finally, consider the rules of lock release in this process . For the case that symbolic links are not considered originally , stay sys_open() in , from create() or namei() Got the current file inode After that, he actually held the inode Lock of , It won't pass until the end of the function iunlock() Release ( Not used when the execution is successful iput() Release inode Of ref quote , The author believes that the follow-up is sys_close() Call this before execution inode It will always be active for the operation of the file , Therefore, references cannot be reduced ). And for symbolic links , Because the final open is the linked target file , Therefore, it will release the current inode The lock of gets the target in turn inode Lock of . When dealing with symbolic links, you need to ip->type Field to read , Naturally, it cannot be released at this time inode Lock of , So we're entering follow_symlink() Always keep inode The holding of the lock , When Use readi() After reading the target file path recorded in the symbolic link , At this point, the current symbolic link is no longer needed inode, Then use iunlockput() Release the lock and inode. When judging whether the type of the target file is not a symbolic link , Then lock it . In this way, the target file will also be held when the function returns correctly inode Lock of , The consistency before and after function call is achieved .
// recursively follow the symlinks - lab9-2
// Caller must hold ip->lock
// and when function returned, it holds ip->lock of returned ip
static struct inode* follow_symlink(struct inode* ip) {
uint inums[NSYMLINK];
int i, j;
char target[MAXPATH];
for(i = 0; i < NSYMLINK; ++i) {
inums[i] = ip->inum;
// read the target path from symlink file
if(readi(ip, 0, (uint64)target, 0, MAXPATH) <= 0) {
iunlockput(ip);
printf("open_symlink: open symlink failed\n");
return 0;
}
iunlockput(ip);
// get the inode of target path
if((ip = namei(target)) == 0) {
printf("open_symlink: path \"%s\" is not exist\n", target);
return 0;
}
for(j = 0; j <= i; ++j) {
if(ip->inum == inums[j]) {
printf("open_symlink: links form a cycle\n");
return 0;
}
}
ilock(ip);
if(ip->type != T_SYMLINK) {
return ip;
}
}
iunlockput(ip);
printf("open_symlink: the depth of links reaches the limit\n");
return 0;
}
uint64
sys_open(void)
{
// ...
if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
iunlockput(ip);
end_op();
return -1;
}
// handle the symlink - lab9-2
if(ip->type == T_SYMLINK && (omode & O_NOFOLLOW) == 0) {
if((ip = follow_symlink(ip)) == 0) {
// There is no need to call iunlockput() Release the lock , Because in follow_symlinktest() When the return fails ip The lock of has been released in the function
end_op();
return -1;
}
}
if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
if(f)
fileclose(f);
iunlockput(ip);
end_op();
return -1;
}
// ...
}
- Last in
MakefileAdd a pair of test filessymlinktest.cCompilation of .
Have a problem
- stay xv6 In the implementation of
symlinktestThere will beFailed to open 1Error of , As shown in the figure below :
solve : According to the output of the above figure, combineuser/symlinktest.cCode for , You can see that the file cannot be opened due to looping 1, According to the code, we can know that there is no ring here .
Finally, the author detected the looped code and found the problem , As shown in the following figure , The author It was not inode number But to perform inode The pointer to , And compare through the pointer . And one thing to note is , therestruct inodeIt's actually in memory inode cache , When callingiput()stayrefThe reference count is 0 In fact, it should inode Being recycled You can useiget()Storage disk inode Information ( Equivalent to having a memory inode The cache pool ).
And if you usestruct inodeCompare with the pointer of , be It is possible that inode The cache is recycled and reused , This produces repetition . Therefore, it should be described above , Record inode number namelyip->inums, And use it to compare , This value is the disk pair inode The number of , Have uniqueness , This should be used inode Ring formation detection . The correct code is shown above .
test
- stay xv6 In the implementation of
symlinktesttest :
- stay xv6 In the implementation of
userteststest :
./grade-lab-fs symlinktestIndividual tests :
边栏推荐
- The first PCIe 5.0 SSD master of Jiangsu Huacun: TSMC 12NM process, mass production in 2020
- [MIT 6.S081] Lab 5: xv6 lazy page allocation
- 记一次 .NET 某智慧物流 WCS系统 CPU 爆高分析
- [MIT 6.S081] Lec 6: Isolation & system call entry/exit 笔记
- Disassembly of Xiaomi cc9 Pro: the cost of rear five shots is several times that of Xiaolong 855!
- 二叉树概念
- Golang concurrent cache breakdown or merge request
- 发布自己的npm组件库
- 2. 改变颜色空间及颜色检测
- 黑客用激光攻击,百米外就能激活语音助手
猜你喜欢
随机推荐
嘉楠耘智已完成预路演,预计11月20日登陆纳斯达克
Here comes the first 5g SOC of MediaTek! A77+g77+apu3.0, officially released on November 26!
被“赶出”比特大陆之后,詹克团首度发声:将通过法律途径尽快回归!
Collection! 0 basic open source data visualization platform flyfish large screen development guide
MySQL solves the problem of insert failure caused by duplicate unique indexes
Is it difficult to operate email safely? COREMAIL joins hands with cloud store to create a new ecosystem of corporate email office!
Mysql四种锁
[learning notes] advanced version of MySQL database - index optimization, slow query, locking mechanism, etc
Together with Samsung, vivo will promote exynos980 dual-mode 5g mobile phone!
@DateTimeFormat 接收不到时分秒,转换时报类型异常
[MIT 6.S081] Lab 4: traps
数据库的常用命令1
宣布收购文晔30%股份,大联大意欲何为?
Press Google and NVIDIA! Alibaba optical 800 chip won the world's first authoritative test again
@Convert 注解在jpa中进行查询的注意事项
深度学习-论文阅读:动作结构性图卷积网络AS-GCN
Glory and Xiaomi reported on the double 11: they all called themselves champions
【学习笔记】Redis中有序集合zset的实现原理——跳表
What every Salesforce developer should know about Dates and Times in Apex
[MIT 6.S081] Lec 5: Calling conventions and stack frames RISC-V 笔记







![[MIT 6.S081] Lab8: locks](/img/9f/0ff7a0226837a3c420f49e6da8209f.png)
