2 FreeBSD 核心( 三 )


运行(*mountroot)(mountrootvfsops)后,就指明了root file system的mount.
。vfs_mountroot()(@kern/vfs_conf.c)
管理mount的了文件系统的信息的struct mount(@sys/mount.h),对它进行确认
,然后设定传递过来的对虚拟文件系统的操作群(&ufs_vfsops),才进行"root"
标记 。根据VFS_MOUNT(mp,...)进行mount这个虚拟文件系统 。mount成功后,就
追加file system的list 。这里,由于传递了&ufs_vfsops,就可以调用
ffs_mount()(@ufs/ffs/ffs_vfsops.c)
。ffs_mount()
首先调用bdevvp()(@kern/vfs_subr.c),进行VBLK类别,spec_vnodeop_p
(@misc/specfs/spec_vnops.c) v-node操作,保证设定了驱动号的rootdev的
v-node的最新信息,然后设定rootvp 。最后,通过ffs_mountfs()调用进行实际
的mount rootvp操作 。
。ffs_mountfs()
各种各样的检查完了后,调用VOP_OPEN(),打开rootvp的v-node 。在这里,如果
v-node的v_op成员在spec_vnodeop_p存在的话,就调用spec_open()(@misc/
specfs/spec_vnops.c) 。
.spec_open
由于VBLK里包含v-node的种类,从v-node指定的device号取得major的
号,调用对应driver的XXopen() routine

续上,由VOP_IOCTL()(还是的通过spec_ioctl()(@misc/specfs/spec_vnops.c))
可以得到partition信息,然后该检查super block的内容 。正确的话,就在struct
ufsmount(@ufs/ufs/ufsmount.h)设定unix file system,这样处理过程就完了 。

2.2.4 struct buf 和block的输入输出routine
前节的ffs_mountfs()提到使用bread()(@kern/vfs_bio.c)读出partition的
super block 。这个接口函数很快就会解释 。它主要用于读取block型的device到
kernel内部的buffer中 。
bread(struct vnode *vp, /*(in)输入对象的v-node*/
daddr_t blkno, /*(in)block号*/
int size, /*(in)读出的byte数量,block长的倍数*/
struct ucred * cred,/*(in)权限信息*/
struct buf ** bpp)/*(out)存储读来的data*/
同样的buffer link后的block输出的子程序是bwrite() 。
bwrite(struct buf *bp) /*(out)可以输出的struct buf*/
两者之间共同的地方就是struct buf(@/sys/buf.h),它用于io处理中给device driver
做桥梁作用的数据结构 。它记录了v-node,io的区别,可以io的block位置/byte数,存
储实际data buffer的address,io处理的进展情况等 。

bread则通过getblk()对block输入的结构struct buf进行操作 。getblk()调用在核心
管理buffer link和返回指定大小的block的struct buf 。这个(缓冲区)内容在目的
block是否存在与指定v-node的指定位置block是否已经构成缓冲环有关 。struct buf
里面有一个标志位,当缓冲环内容变化是,这个标志位就会改变 。bread()根据这个
flag判断block是否已经缓冲,如果已经完成,它就终止退出 。如果不是这样,则在
struct buf的mark里面标志,然后调用VOP_STRATEGY() 。在v-node登记的strategy
routine记录了io处理的过程,所以bread()当实际的处理完了后,就调用biowait()
进入等待状态 。然后,就转移到别的进程A 。io处理完了后,调用biodone(),进程A
也可以继续进行 。还有,调用bread()的一边,当完成操作后,就调用brelse(),在
里面对struct buf的flag重新设置,让它对别的程序开放 。

bwrite也是同样的通过VOP_STRATEGY()对io处理要求进行登记,同时也调用biowait()
进入等待状态,同样,当实际操作完了后,也设置flag进行复位,使得其他程序可以
使用io,当空闲的时候,io就挂起,转向其他进程处理 。
进程等待进入的时候,当然不限于只是调用biowait() 。在bread()或者bwrite()之前,
系统必须分配足够的资源供它使用,比如一些缓冲区等 。当进行实际io时候,1个block
也可以,多个block也可以,而且这样可以获得更高的效率,这样看起来,就象实际上
是连续操作了 。

推荐阅读