By cszhao1980
当一个设备被mount进系统,就会在“mount表”中占据一个表项,mount表的定义如下:
0272: struct mount
0273: {
0274: int m_dev /* device mounted */
0275: int *m_bufp; /* pointer to superblock */
0276: int *m_inodp; /* pointer to mounted on inode */
0277: } mount[NMOUNT];
m_dev记录被mount设备的设备号;
m_bufp指向一个缓存,其内容是设备的“超级块”;
m_inodep指向所谓的“mount on” inode,我们会在后面的讨论中对其进一步了解。
首先,我们来看一看root设备是怎样被mount进系统的。
首先,rootdev的定义如下:
4695: int rootdev {(0<<8)|0};
显然,其设备号为0,即我们的RK磁盘设备。
然后,在main()函数中调用iinit()函数——它负责把rootdev Load进系统:
1615: iinit();
6922: iinit()
6923: {
6924: register *cp, *bp;
6925:
6926: (*bdevsw[rootdev.d_major].d_open)(rootdev, 1);
6927: bp = bread(rootdev, 1);
6928: cp = getblk(NODEV);
6929: if(u.u_error)
6930: panic("iinit");
6931: bcopy(bp->b_addr, cp->b_addr, 256);
6932: brelse(bp);
6933: mount[0].m_bufp = cp;
6934: mount[0].m_dev = rootdev;
6935: cp = cp->b_addr;
6936: cp->s_flock = 0;
6937: cp->s_ilock = 0;
6938: cp->s_ronly = 0;
6939: time[0] = cp->s_time[0];
6940: time[1] = cp->s_time[1];
6941: }
如果您对上一章的内容比较清楚的话,iinit()函数就显得很简单了:
(1) 利用块设备表调用rootdev(RK磁盘)的d_open函数,如果您还记得的话,
该函数是个空函数,也就是说对RK磁盘来说,无需进行open操作,就直接可用;
(2) 然后,调用bread()函数将rootdev的#1块(即超级块)读入缓存;
(3) 接着它又调用getblk(NODEV)申请了一个“空闲设备”缓存——该缓存没有与任何
实际设备相关连。接着将超级块的内容通过bcopy函数,拷贝到给缓存中。
(4) 调用brelse函数,将rootdev缓存送还AV队列;
(5) 将mount表的#0表项分配给rootdev,其m_dev设置为rootdev(0),而m_bufp指向装
有超级块内容的“空闲设备”缓存;
(6) 接下来的操作就跟超级块的内容有关了,我们接下来就看一下超级块。
超级块的内容如下所示:
5561: struct filsys
5562: {
5563: int s_isize; /* size in blocks of I list */
5564: int s_fsize; /* size in blocks of entire volume */
5565: int s_nfree; /* number of in core free blocks (0-100) */
5566:
5567: int s_free[100]; /* in core free blocks */
5568: int s_ninode; /* number of in core I nodes (0-100) */
5569: int s_inode[100]; /* in core free I nodes */
5570: char s_flock; /* lock during free list manipulation */
5571: char s_ilock; /* lock during I list manipulation */
5572: char s_fmod; /* super block modified flag */
5573: char s_ronly; /* mounted read-only flag */
5574: int s_time[2]; /* current date of last update */
5575: int pad[50];
5576: };
内容不少,我们先了解其中几项:
(1) s_isize:即有多少个块是用来存放inde列表的;
(2) s_fsize:整个文件系统共有多少个块;
(3) s_ninode:读入内存的inode项数;
(4) s_inode[100]:存放读入内存的indode项;
在上述操作中,并没有设置mount数组项中所谓的“mount on”inode指针——这时因为rootdev
的mount是很“自然”的事,它的文件系统根目录,直接变成了系统根目录,没有mount点之说。
下面我们来看smount ()函数——它用来处理mount sys call,即通过该函数可以将一个设备mount到系统中。
mount的过程和上述过程类似,莱昂解释的也比较清晰,我只简单说几点。
1. 参数传递
smount有三个参数,都通过.u_arg[]数组传递:
(1) u_arg[0] (u.dirp) ——指向一个Path name字符串,该Path name的文件inode-i_dev为要mount的
设备的设备号;smount会调用getmdev()函数来得到设备id;
(该文件应该为一设备描述文件,也许就是“特殊块设备”(IFBLK)文件);
(2) u_arg[1] ——指向“要mount到的”目录的Path name;
(3) u_arg[2] —— read only flag;
2. mount点
被mount到的目录被称为mount点,该目录的inode会设置IMOUNT标志。
3. IFBLK/ IFCHR分别为特殊块设备、特殊字符设备标志;
很自然的,我们接下来看一下sumount函数,即unmount sys call的处理函数。
我们基本上可以将其理解为smount的“反”函数,即:
(1) 将该设备从系统mount表中删除;
(2) 将mount点的IMOUNT标志清除;
(3) 释放该文件系统的超级块。
除此之外,还需要注意两点:
(1) 在unmount设备时,会Loop系统的inode数组,如果数组项中有该设备上的文件
(即该文件处理active状态),则禁止unmount设备;
(2) 在所有操作之前,调用update()进行了文件系统更新。
update(7201)执行三种更新:
(1) Loop mount表,将每个文件系统的超级块(内存中的)的内容写回磁盘;
(2) Loop inode数组,将inode写回磁盘;
(3) 调用bflush,将“延迟写”块写入磁盘。
博客地址:http://blog.csdn.net/cszhao1980
博客专栏地址:http://blog.csdn.net/column/details/lions-unix.html