Definations: - Add defination NINDIRECT_2: the number of double-indirect block, equals to (NINDIRECT * BSIZE) / sizeof(uint) - Modify NDIRECT from 12 to 11, otherwise mkfs will be failed because of (BSIZE % sizeof(struct dinode)) != 0
Modify block array size: inode.addrs[NDIRECT+2], dinode.addrs[NDIRECT+2] to store the double-indirect block infomation
Modify bmap(): - If NINDIRECT <= bn < NINDIRECT_2, then perform double-indirect block index
Patch
Date: Fri,4 Apr 202517:20:01+0800
Subject:[PATCH] lab: large files
---
kernel/file.h |2+-
kernel/fs.c |24++++++++++++++++++++++++
kernel/fs.h |12++++++++----3 files changed,33insertions(+),5deletions(-)
diff --git a/kernel/file.h b/kernel/file.h
index b076d1d..5c4eb3a 100755--- a/kernel/file.h
+++ b/kernel/file.h
@@ -26,7+26,7 @@ structinode{short minor;short nlink;
uint size;- uint addrs[NDIRECT+1];+ uint addrs[NDIRECT+2];};// map major device number to device functions.
diff --git a/kernel/fs.c b/kernel/fs.c
index f33553a..1f0dc89 100755--- a/kernel/fs.c
+++ b/kernel/fs.c
@@ -400,6+400,30 @@ bmap(structinode*ip, uint bn)brelse(bp);return addr;}+ bn -= NINDIRECT;++if(bn < NINDIRECT_2){+// Load double indirect block, allocating if necessary.+if((addr = ip->addrs[IXINDIRECT_2])==0)+ ip->addrs[IXINDIRECT_2]= addr =balloc(ip->dev);+ bp =bread(ip->dev, addr);+ a =(uint*)bp->data;+if((addr = a[bn / NINDIRECT_1])==0){+ a[bn / NINDIRECT_1]= addr =balloc(ip->dev);+log_write(bp);+}+brelse(bp);++// Load indirect block, allocating if necessary.+ bp =bread(ip->dev, addr);+ a =(uint*)bp->data;+if((addr = a[bn % NINDIRECT_1])==0){+ a[bn % NINDIRECT_1]= addr =balloc(ip->dev);+log_write(bp);+}+brelse(bp);+return addr;+}panic("bmap: out of range");}
diff --git a/kernel/fs.h b/kernel/fs.h
index 139dcc9..1568866100755--- a/kernel/fs.h
+++ b/kernel/fs.h
@@ -24,9+24,13 @@ structsuperblock{#defineFSMAGIC0x10203040-#define NDIRECT 12-#define NINDIRECT(BSIZE /sizeof(uint))-#define MAXFILE(NDIRECT + NINDIRECT)+#define NDIRECT 11+#define IXINDIRECT_1(NDIRECT)+#define IXINDIRECT_2(IXINDIRECT_1 +1)+#define NINDIRECT_1(BSIZE /sizeof(uint))+#define NINDIRECT(NINDIRECT_1)+#define NINDIRECT_2((NINDIRECT_1*BSIZE)/sizeof(uint))+#define MAXFILE(NDIRECT + NINDIRECT_1 + NINDIRECT_2)// On-disk inode structurestructdinode{
@@ -35,7+39,7 @@ structdinode{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];// Data block addresses+ uint addrs[NDIRECT+2];// Data block addresses};// Inodes per block.--2.25.1
Lab: Symbolic links
Overview
implement the symlink(char *target, char *path) system call
My solution:
Implement the symlink(target, path) system call - Add T_SYMLINK to kernel/stat.h - Store the target path of a symbolic link in the inode’s data blocks - I choose to store the target path to inode->addrs field directly, so I have to modify iput(). - We shouldn’t perform itrunc() when inode->type == T_SYMLINK, otherwise we will get an panic(“virtio_disk_intr status”) because of itrunc() will treat symbolic link which stored in inode->addrs as directly or indirectly blocks then will free it, and then it will cause panic. - Add O_NOFOLLOW to kernel/fcntl.h, when a process specifies O_NOFOLLOW in the flags to open, open should open the symlink (and not follow the symbolic link). - Follow the symbolic link to reach the file - If the linked file is also a symbolic link, we should recursively follow it until a non-link file is reached - If the links form a cycle, or , if the depth of links reaches some threshold (e.g., 10), you must return an error code
Patch
Subject:[PATCH] add symlink syscall
---
Makefile |1+
kernel/fcntl.h |1+
kernel/fs.c |3+-
kernel/stat.h |1+
kernel/syscall.c |2++
kernel/syscall.h |1+
kernel/sysfile.c |91++++++++++++++++++++++++++++++++++++++++++++++++
user/user.h |1+
user/usys.pl |1+9 files changed,101insertions(+),1deletion(-)
diff --git a/Makefile b/Makefile
index d8509b1..7c258af 100755--- a/Makefile
+++ b/Makefile
@@ -175,6+175,7 @@ UPROGS=\
$U/_grind\
$U/_wc\
$U/_zombie\
+ $U/_symlinktest\
diff --git a/kernel/fcntl.h b/kernel/fcntl.h
index 44861b9..b42df18 100755--- a/kernel/fcntl.h
+++ b/kernel/fcntl.h
@@ -3,3+3,4 @@
#defineO_RDWR0x002#defineO_CREATE0x200#defineO_TRUNC0x400+#define O_NOFOLLOW 0x800
\ No newline at end of file
diff --git a/kernel/fs.c b/kernel/fs.c
index 1f0dc89..ff0848c 100755--- a/kernel/fs.c
+++ b/kernel/fs.c
@@ -343,7+343,8 @@ iput(structinode*ip)release(&icache.lock);-itrunc(ip);+if(ip->type != T_SYMLINK)+itrunc(ip);
ip->type =0;iupdate(ip);
ip->valid =0;
diff --git a/kernel/stat.h b/kernel/stat.h
index 19543af..9554d30 100755--- a/kernel/stat.h
+++ b/kernel/stat.h
@@ -1,6+1,7 @@
#defineT_DIR1// Directory#defineT_FILE2// File#defineT_DEVICE3// Device+#define T_SYMLINK 4// Symbolic linkstructstat{int dev;// File system's disk device
diff --git a/kernel/syscall.c b/kernel/syscall.c
index c1b3670..1697b62 100755--- a/kernel/syscall.c
+++ b/kernel/syscall.c
@@ -104,6+104,7 @@ extern uint64 sys_unlink(void);extern uint64 sys_wait(void);extern uint64 sys_write(void);extern uint64 sys_uptime(void);+extern uint64 sys_symlink(void);staticuint64(*syscalls[])(void)={[SYS_fork] sys_fork,
@@ -127,6+128,7 @@ staticuint64(*syscalls[])(void)={[SYS_link] sys_link,[SYS_mkdir] sys_mkdir,[SYS_close] sys_close,+[SYS_symlink] sys_symlink,};void
diff --git a/kernel/syscall.h b/kernel/syscall.h
index bc5f356..0fbf6ed 100755--- a/kernel/syscall.h
+++ b/kernel/syscall.h
@@ -20,3+20,4 @@
#defineSYS_link19#defineSYS_mkdir20#defineSYS_close21+#define SYS_symlink 22
\ No newline at end of file
diff --git a/kernel/sysfile.c b/kernel/sysfile.c
index 5dc453b..a47ffd3 100755--- a/kernel/sysfile.c
+++ b/kernel/sysfile.c
@@ -283,6+283,53 @@ create(char*path,short type,short major,short minor)return ip;}+#define FOLLOW_DEPTH_MAX 10+// Follow a symbolic link to its target.+// Returns the target inode with ilock(), or 0 if the target is not found.+structinode*+_follow_symlink(structinode*ip,int depth,int*symlink_stack)+{+char*target;+structinode*new_ip,*target_ip;+ target =(char*)ip->addrs;+if(!target)+panic("follow_symlink(): no target");++ symlink_stack[depth]= ip->inum;++// Find the inode for the target path.+ new_ip =namei(target);+if(!new_ip)+return0;++for(uint i =0; i < depth+1; i++){+// circular symlink detected+if(symlink_stack[i]== new_ip->inum)+return0;+}++ilock(new_ip);+if(!(new_ip->type & T_SYMLINK)){+ target_ip = new_ip;+}else{+// maximum depth exceeded+if(depth+1>= FOLLOW_DEPTH_MAX)+return0;++ target_ip =_follow_symlink(new_ip, depth+1, symlink_stack);+iunlockput(new_ip);+}++return target_ip;+}++staticstructinode*+follow_symlink(structinode*ip)+{+int symlink_stack[FOLLOW_DEPTH_MAX];+return_follow_symlink(ip,0, symlink_stack);+}+
uint64
sys_open(void){
@@ -316,6+363,16 @@ sys_open(void)}}+if(!(omode & O_NOFOLLOW)&& ip->type == T_SYMLINK){+structinode*target_ip =follow_symlink(ip);+iunlockput(ip);+if(target_ip ==0){+end_op();+return-1;+}+ ip = target_ip;+}+if(ip->type == T_DEVICE &&(ip->major <0|| ip->major >= NDEV)){iunlockput(ip);end_op();
@@ -484,3+541,37 @@ sys_pipe(void)}return0;}++uint64
+sys_symlink(void)+{+constchar target[MAXPATH], linkpath[MAXPATH];+ uint ntarget;++if(argstr(0,(char*)target,sizeof target)<0||+argstr(1,(char*)linkpath,sizeof linkpath)<0)+return-1;++ ntarget =strlen(target);+if(ntarget >=sizeof(((structinode*)0)->addrs)-1){+printf("sys_symlink(): target path too long\n");+return-1;+}++begin_op();+structinode*ip =create((char*)linkpath, T_SYMLINK,0,0);+if(ip ==0){+end_op();+return-1;+}++memmove(ip->addrs, target, ntarget);+ ip->addrs[ntarget]=0;// null-terminate the string+ ip->type = T_SYMLINK;+ ip->size = ntarget;+iupdate(ip);+iunlockput(ip);+end_op();++return0;+}
\ No newline at end of file
diff --git a/user/user.h b/user/user.h
index b71ecda..5ce5b1b 100755--- a/user/user.h
+++ b/user/user.h
@@ -16,6+16,7 @@ intmknod(constchar*,short,short);intunlink(constchar*);intfstat(int fd,structstat*);intlink(constchar*,constchar*);+intsymlink(constchar*,constchar*);intmkdir(constchar*);intchdir(constchar*);intdup(int);
diff --git a/user/usys.pl b/user/usys.pl
index 01e426e..65a8d6b 100755--- a/user/usys.pl
+++ b/user/usys.pl
@@ -36,3+36,4 @@ entry("getpid");entry("sbrk");entry("sleep");entry("uptime");+entry("symlink");
\ No newline at end of file
--2.25.1
Verify
make[1]: Leaving directory '/home/code'
== Test running bigfile ==
$ make qemu-gdb
running bigfile: OK (47.6s)
== Test running symlinktest ==
$ make qemu-gdb
(0.4s)
== Test symlinktest: symlinks ==
symlinktest: symlinks: OK
== Test symlinktest: concurrent symlinks ==
symlinktest: concurrent symlinks: OK
== Test usertests ==
$ make qemu-gdb
usertests: OK (96.2s)
== Test time ==
time: OK
Score: 100/100
sysfile.c
#defineFOLLOW_DEPTH_MAX10// Follow a symbolic link to its target.// Returns the target inode with ilock(), or 0 if the target is not found.structinode*_follow_symlink(structinode*ip,int depth,int*symlink_stack){char*target;structinode*new_ip,*target_ip;
target =(char*)ip->addrs;if(!target)panic("follow_symlink(): no target");
symlink_stack[depth]= ip->inum;// Find the inode for the target path.
new_ip =namei(target);if(!new_ip)return0;for(uint i =0; i < depth+1; i++){// circular symlink detectedif(symlink_stack[i]== new_ip->inum)return0;}ilock(new_ip);if(!(new_ip->type & T_SYMLINK)){
target_ip = new_ip;}else{// maximum depth exceededif(depth+1>= FOLLOW_DEPTH_MAX)return0;
target_ip =_follow_symlink(new_ip, depth+1, symlink_stack);iunlockput(new_ip);}return target_ip;}staticstructinode*follow_symlink(structinode*ip){int symlink_stack[FOLLOW_DEPTH_MAX];return_follow_symlink(ip,0, symlink_stack);}
uint64
sys_open(void){char path[MAXPATH];int fd, omode;structfile*f;structinode*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(!(omode & O_NOFOLLOW)&& ip->type == T_SYMLINK){structinode*target_ip =follow_symlink(ip);iunlockput(ip);if(target_ip ==0){end_op();return-1;}
ip = target_ip;}if(ip->type == T_DEVICE &&(ip->major <0|| ip->major >= NDEV)){iunlockput(ip);end_op();return-1;}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;}
uint64
sys_symlink(void){constchar target[MAXPATH], linkpath[MAXPATH];
uint ntarget;if(argstr(0,(char*)target,sizeof target)<0||argstr(1,(char*)linkpath,sizeof linkpath)<0)return-1;
ntarget =strlen(target);if(ntarget >=sizeof(((structinode*)0)->addrs)-1){printf("sys_symlink(): target path too long\n");return-1;}begin_op();structinode*ip =create((char*)linkpath, T_SYMLINK,0,0);if(ip ==0){end_op();return-1;}memmove(ip->addrs, target, ntarget);
ip->addrs[ntarget]=0;// null-terminate the string
ip->type = T_SYMLINK;
ip->size = ntarget;iupdate(ip);iunlockput(ip);end_op();return0;}
fs.c
voidiput(structinode*ip){acquire(&icache.lock);if(ip->ref ==1&& ip->valid && ip->nlink ==0){// inode has no links and no other references: truncate and free.// ip->ref == 1 means no other process can have ip locked,// so this acquiresleep() won't block (or deadlock).acquiresleep(&ip->lock);release(&icache.lock);if(ip->type != T_SYMLINK)itrunc(ip);
ip->type =0;iupdate(ip);
ip->valid =0;releasesleep(&ip->lock);acquire(&icache.lock);}
ip->ref--;release(&icache.lock);}