Lab: file system
Large files
your job:
Modify bmap() so that it implements a doubly-indirect block, in addition to direct blocks and a singly-indirect block. You’ll have to have only 11 direct blocks, rather than 12, to make room for your new doubly-indirect block; you’re not allowed to change the size of an on-disk inode. The first 11 elements of ip->addrs[] should be direct blocks; the 12th should be a singly-indirect block (just like the current one); the 13th should be your new doubly-indirect block. You are done with this exercise when bigfile writes 65803 blocks and usertests runs successfully:
//fs.h
#define NDIRECT 11
#define DNDIRECT 12
#define NINDIRECT (BSIZE / sizeof(uint))
#define DNINDIRECT (NINDIRECT * NINDIRECT)
#define MAXFILE (NDIRECT + NINDIRECT + DNINDIRECT)
struct dinode {
/* ....
* ....
*/
uint addrs[DNDIRECT+1]; // Data block addresses
};
// bmap of fs.c
bmap(struct inode *ip, uint bn)
{
/* ...
* ...
*/
bn -= NINDIRECT;
if(bn < DNINDIRECT){
if((addr = ip->addrs[DNDIRECT]) == 0)
ip->addrs[DNDIRECT] = addr = balloc(ip->dev);
for(int i = 0; i < 2; i++){
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
int num = (i == 0 ? bn / NINDIRECT : bn % NINDIRECT);
if((addr = a[num]) == 0){
a[num] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
}
return addr;
}
panic("bmap: out of range");
}
// itrunc of fs.c
void
itrunc(struct inode *ip)
{
int i, j;
struct buf *bp, *bp1;
uint *a, *a1;
/* ...
* ...
*/
if(ip->addrs[DNDIRECT]){
bp = bread(ip->dev, ip->addrs[DNDIRECT]);
a = (uint*)bp->data;
for(j = 0; j < NINDIRECT; j++){
if(!a[j])
continue;
bp1 = bread(ip->dev, a[j]);
a1 = (uint*)bp1->data;
for(i = 0; i < NINDIRECT; i++){
if(a1[i])
bfree(ip->dev, a1[i]);
}
brelse(bp1);
bfree(ip->dev, a[j]);
}
brelse(bp);
bfree(ip->dev, ip->addrs[DNDIRECT]);
ip->addrs[DNDIRECT] = 0;
}
ip->size = 0;
iupdate(ip);
}
Symbolic links
your job:
You will implement the symlink(char *target, char *path) system call, which creates a new symbolic link at path that refers to file named by target. For further information, see the man page symlink. To test, add symlinktest to the Makefile and run it. Your solution is complete when the tests produce the following output (including usertests succeeding).
system call, modify system call in user/user.h and user/usys.pl:
// symlink for system call in sysfile.c
uint64
sys_symlink(void)
{
char new[MAXPATH], target[MAXPATH];
struct inode *tp;
if(argstr(0, target, MAXPATH) == -1 || argstr(1, new, MAXPATH) == -1)
return -1;
begin_op();
if((tp = namei(new)) != 0){
iput(tp);
end_op();
return -1;
}
if((tp = create(new, T_SYMLINK, 0, 0)) == 0){
end_op();
return -1;
}
if(writei(tp, 0, (uint64)target, 0, MAXPATH) < 0){
iunlockput(tp);
end_op();
return -1;
}
iunlockput(tp);
end_op();
return 0;
}
open symbolic link file:
// sys_open in sysfile.c
struct inode * looksymlink(struct inode *);
int maxtime = 0;
uint64
sys_open(void)
{
char path[MAXPATH];
int fd, omode;
struct file *f;
struct inode *ip, *tp;
int n;
if((n = argstr(0, path, MAXPATH)) < 0 || argint(1, &omode) < 0)
return -1;
if(omode & O_NOFOLLOW){
if(omode & ~(O_NOFOLLOW | O_RDONLY))
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(ip->type == T_SYMLINK && omode != (O_RDONLY | O_NOFOLLOW)){
tp = looksymlink(ip);
if(tp){
ilock(tp);
ip = tp;
} else {
end_op();
return -1;
}
}
}
/* ...
* ...
*/
maxtime = 0;
return fd;
}
// Caller must hold ip->lock.
struct inode *looksymlink(struct inode * ip){
char path[MAXPATH];
struct inode *tp, *dp;
if(maxtime > 10){
return 0;
}
if(ip->type == T_SYMLINK){
maxtime++;
if(readi(ip, 0, (uint64)path, 0, MAXPATH) == 0){
return 0;
}
if((tp = namei(path)) == 0 || tp == ip){
iunlockput(ip);
return 0;
}
ilock(tp);
iunlockput(ip);
dp = looksymlink(tp);
return dp;
} else if(ip->type == T_FILE){
iunlock(ip);
return ip;
}
return 0;
}
static struct inode*
create(char *path, short type, short major, short minor)
{
/* ...
* ...
*/
if((ip = dirlookup(dp, name, 0)) != 0){
iunlockput(dp);
ilock(ip);
if((type == T_FILE && (ip->type == T_FILE || ip->type == T_DEVICE)) || (type == T_SYMLINK && ip->type == T_SYMLINK))
return ip;
iunlockput(ip);
return 0;
}
/* ...
* ...
*/
return ip;
}
#define T_SYMLINK 4 in file stat.h and #define O_NOFOLLOW 0x010 in fcntl.h
总结
honestly, this lab is simple, nothing to summary.
Please find complete code here github