The disk layer reads and writes blocks on an virtio hard drive. The buffer cache layer caches disk blocks and synchronizes access to them, making sure that only one kernel process at a time can modify the data stored in any particular block. The logging layer allows higher layers to wrap updates to several blocks in a transaction, and ensures that the blocks are updated atomically in the face of crashes (i.e., all of them are updated or none). The inode layer provides individual files, each represented as an inode with a unique i number and some blocks holding the file’s data. The directory layer implements each directory as a special kind of inode whose content is a sequence of directory entries, each of which contains a file’s name and i-number. The pathname layer provides hierarchical path names like /usr/rtm/xv6/fs.c, and resolves them with recursive lookup. The file descriptor layer abstracts many Unix resources (e.g., pipes, devices, files, etc.) using the file system interface, simplifying the lives of application programmers.
buffer cache:内存数据与硬盘数据映射(caching and synchronizing access to the disk)
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
// On-disk inode structure structdinode { short type; // File type short major; // Major device number (T_DEVICE only) 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 + 2]; // Data block addresses };
// in-memory copy of an inode structinode { uint dev; // Device number uint inum; // Inode number int ref; // Reference count structsleeplocklock;// protects everything below here int valid; // inode has been read from disk?
short type; // copy of disk inode short major; short minor; short nlink; uint size; uint addrs[NDIRECT+2]; };
voiditrunc(struct inode *ip) { int i, j; structbuf *bp, *buffer; uint *a, *b;
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; }
if (ip->addrs[NDIRECT + 1]) { // 载入二级索引块 bp = bread(ip->dev, ip->addrs[NDIRECT + 1]); a = (uint *)bp->data; for (i = 0; i < NINDIRECT; i++) { // 载入一级索引块 if (a[i] == 0) break; buffer = bread(ip->dev, a[i]); b = (uint *)buffer->data; for (j = 0; j < NINDIRECT; j++) { // 释放数据块 if (b[j] == 0) break; bfree(ip->dev, b[j]); } // 释放一级索引块 brelse(buffer); 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
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).
staticstruct inode *create(char *path, short type, short major, short minor) { ilock(ip); ip->major = major; ip->minor = minor; ip->nlink = 1; iupdate(ip); return ip; }
sys_symlink函数实际上只需在path处创建一个SYMLINK类型的文件,将target写入文件即可。需要注意的是create方法调用后已经持有了ip->lock,不需要再次加锁。另外各操作应在begin_op()——end_op(),不然会报log_write outside of trans错误。 sys_symlink实现代码如下:
set confirm off set architecture riscv:rv64 target remote 127.0.0.1:25000 symbol-file kernel/kernel set disassemble-next-line auto set riscv use-compressed-breakpoints yes