欢迎光临散文网 会员登陆 & 注册

xv6文件系统(1),buffer-inode

2023-03-18 19:50 作者:米诺斯人  | 我要投稿

补一下之前的坑

// Disk layout:磁盘内容分部

// [ boot block | super block | log | inode blocks |

//                                          free bit map | data blocks]

//

// mkfs computes the super block and builds an initial file system. The

// super block describes the disk layout:

// struct superblock {

//   uint magic;        // Must be FSMAGIC

//   uint size;         // Size of file system image (block number)

//   uint nblocks;      // Number of data blocks

//   uint ninodes;      // Number of inodes.

//   uint nlog;         // Number of log blocks

//   uint logstart;     // Block number of first log block

//   uint inodestart;   // Block number of first inode block

//   uint bmapstart;    // Block number of first free map block

// };


【superblock 存储了磁盘的布局layout,一般在boot时,就把superblock装入内存】

————————

buffer层:

所有buffer node(循环链表)的信息被链表的spinlock保护;而每一个buffer的data被buffer自己的sleeplock保护。

bget spinlock.lock后顺序查找一个符合要求的buf,改变buf的信息(如ref-count)锁住其sleeplock,返回。

bread方法读取磁盘特定的块区:bget通过遍历,获取一个buffer,如果该block已经在buffer则直接返回,否则找到一个空闲buf把磁盘数据装入其中,再返回。返回的buf的sleeplock是锁住的。

bwrite在buf的sleeplock锁住的情况下把buf数据写入磁盘

brelse 释放资源改变信息,如ref-count--;解开buf的sleeplock

bpin增加buf的引用计数

punpin减少buf的引用计数

这两个引用计数ref count的api用于buf所有权转移(比如从函数的stack转移到log缓存中)

————————————

log层:

先提一下log_write;这个方法被较为底层的各种方法调用,用缓存buf的方式(引用计数、更改log头)代替把buf直接写到disk上。

之后begin_op write_log write_head commit end_op等方法没什么可说的;就是把data全部写入log区后才开始从log区向真正的datablock区转移。

【值得注意的是】,log层并不与inode层分离,可以看作同一层;inode层的读写api嵌入了很多log层api用以减少写磁盘次数(log_write),因此很多操作为:begin_op(); iput(buf); end_op();

————————————————

balloc、bfree:根据bitmap分配、释放一块空闲的磁盘区域(引用计数)

——————————————

inode层

由于这是第一次提起inode,下面记录一些关键信息。

The on-disk inode is defined by a struct dinode (kernel/fs.h:32). The type field distinguishes between files, directories, and special files (devices). A type of zero indicates that an ondisk inode is free. The nlink field counts the number of directory entries that refer to this inode, in order to recognize when the on-disk inode and its data blocks should be freed. The size field records the number of bytes of content in the file. The addrs array records the block numbers of the disk blocks holding the file’s content.

以上为dinode结构体的概述。

n->ref为文件的引用计数(内存)

n->type为文件类型:file、dir、dev、free等

n->nlink为本文件被其他文件引用的引用计数(磁盘)

n->size为文件大小

n->addr[]为文件分布的块区地址,文件按addr[0]、addr[1]、...顺序排列

inode in proc和dinode的关系有点类似buffer缓存层和disk磁盘的关系。

ialloc+iget取得inode,ilock上锁并且从dinode加载inode,iupdate调用log_write把inode写回磁盘,iput释放inode(如果inode->nlink和inode->ref减为0,再调用itruncate彻底从磁盘释放inode)

着重说一下itruncate中inode文件彻底释放:释放inode->addr[]数组中的每个块区,即把对应的bitmap标记为0(即bfree,和balloc相反)【inode会释放ref cnt不为0的buffer对应的block吗?】不会,bread获取buffer只能通过balloc,释放只能通过bfree。balloc和bfree一一对应。

上面基本是inode的内部接口,下面介绍inode的外部接口

readi根据偏移量计算出需要读取的块区,比如读取文件的第n块,那就是inode->addr[n];然后判断是把文件向虚拟地址拷贝还是实地址,虚拟地址需要手动查页表。

writei类似,除了用log_write缓存代替write_disk直写外(因此需要调用begin_op和end_op来通知log模块),不多赘述。









xv6文件系统(1),buffer-inode的评论 (共 条)

分享到微博请遵守国家法律