3.3.3 Process 1 Loads the Root File System into the Root Device
3.3.3.2 Mount the i node of the Root Device to the Root
Back to mount_root, it calls iget() to read the root i node from the Ramdisk. The signifi- cance of the root i node is as follows: any i node in the system can be located through the root i node, which means we can find any files in the system.
The code is as follows:
//the code path:fs/super.c:
static struct super_block * read_super(int dev) {
……
for (i = 0;i<I_MAP_SLOTS;i++) //initialize s_imap[8] and s_zmap[8]
s->s_imap[i] = NULL;
for (i = 0;i<Z_MAP_SLOTS;i++) s->s_zmap[i] = NULL;
block = 2; //the 1st block of Ramdisk
//is super block,
//the 2nd is I-node bitmap and //logical bitmap
for (i = 0 ; i < s->s_imap_blocks ; i++) //read all the logical block of //I-node bitmap to the buffer if (s->s_imap[i] = bread(dev,block)) //mount them to s_imap[8]
block++;
else break;
for (i = 0 ; i < s->s_zmap_blocks ; i++) //read all the logical block of logical bitmap to the buffer
if (s->s_zmap[i] = bread(dev,block)) //mount them to s_zmap[8]
block++;
else break;
if (block ! = 2+s->s_imap_blocks+s->s_zmap_blocks) { //if the number of blocks is wrong, for(i = 0;i<I_MAP_SLOTS;i++) //that means the system error
brelse(s->s_imap[i]); //free them for(i = 0;i<Z_MAP_SLOTS;i++)
brelse(s->s_zmap[i]);
s->s_dev = 0;
free_super(s);
return NULL;
}s->s_imap[0]->b_data[0] | = 1; //avoid return 0 and mix up with 0 I-node s->s_zmap[0]->b_data[0] | = 1;
free_super(s);
return s;
}
//the code path:fs/super.c:
void mount_root(void) {
……
if (!(p = read_super(ROOT_DEV))) panic(“Unable to mount root”);
if (!(mi = iget(ROOT_DEV,ROOT_INO)))
panic(“Unable to read root i-node”);
……
}
In iget(), the OS would apply for a free i node slot in inode_table[32] (inode_table[32]
is used by the OS to control the maximum number of concurrent opening files). At this stage, it should be the first i node; initialize the i node, including the device number of the i node, the node number of the i node. The location of the root i node in the kernel i node table is shown in Figure 3.45.
The code is as follows:
//the code path:fs/inode.c:
struct m_inode * iget(int dev,int nr) {
struct m_inode * inode, * empty;
if (!dev)
panic(“iget with dev ==0”);
empty = get_empty_inode(); //apply a location for I-node in //inode_table[32]
inode = inode_table;
while (inode < NR_INODE+inode_table) { //find the same inode if (inode->i_dev ! = dev || inode->i_num ! = nr) {
inode++;
continue;
ROM BIOS and VGA
\0 \0 \0 Kernel
Enable interrupt
0x00000 0x9FFFF 0xFFFFF 0x3FFFFF 0x5FFFFF 0xFFFFFF
Kernel code area Kernel data area
super_block[8]
Loadsuper block
Unlock
RAM Drive Load i node bitmap
Load logical block bitmap
s_ninodes s_nzones s_imap_blocks s_zmap_blocks s_firstdatazone s_log_zone_size s_max_size s_magic s_imap[8]
s_zmap[8]
s_dev s_isup s_imount s_time s_wait s_lock s_rd_only s_dirt Process status
Process 0 Process 1
Ready Interruptible
Current process
Figure 3.44 Read the logical bitmap and the i node bitmap.
The function read_inode() first locks the i node in inode_table[32] so that the i node will not be used by another program until it is released. The function then calculates the logical block number of the i node through the super block of the i node and reads in the i node logical block, gets the information of the i node, and loads it to the i node location that has just been locked, as shown in Figure 3.46. Note the change in inode_table. Finally, it will free the buffer and unlock the i node.
The code is as follows:
}
wait_on_inode(inode); //wait for unlocking
if (inode->i_dev ! = dev || inode->i_num ! = nr) { //if it changes when waiting,
inode = inode_table; //go on finding continue;
}
inode->i_count++;
if (inode->i_mount) { int i;
for (i = 0 ; i<NR_SUPER ; i++) //if it is the mount point, if (super_block[i].s_imount = =inode) //find the super block
break;
if (i > = NR_SUPER) {
printk(“Mounted inode hasn’t got sb\n”);
if (empty)
iput(empty);
return inode;
}
iput(inode);
dev = super_block[i].s_dev; //get the device number in the //super block
nr = ROOT_INO; //ROOT_INO is 1,the node number //of root I
inode = inode_table;
continue;
} if (empty)
iput(empty);
return inode;
}
if (!empty)
return (NULL);
inode = empty;
inode->i_dev = dev; //initialize
inode->i_num = nr;
read_inode(inode); //read the root I-node from the
//Ramdisk return inode;
}
//the code path:fs/inode.c:
static void read_inode(struct m_inode * inode) {
……
lock_inode(inode); //lock the inode
if (!(sb = get_super(inode->i_dev))) //get the super block of the I-node
……
block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks + (inode->i_num-1)/INODES_PER_BLOCK;
if (!(bh = bread(inode->i_dev,block))) //read the logical block of I-node panic(“unable to read i-node block”);
*(struct d_inode *)inode = //copy all ((struct d_inode *)bh->b_data)
[(inode->i_num-1)%INODES_PER_BLOCK];
brelse(bh); //free the buffer blocks
unlock_inode(inode); //unlock
Back to iGet, it returns the pointer inode to the function mount_root and assigns it to pointer mi.
The following is the process of loading the root file system:
Mount the Ramdisk root i node in inode_table[32] to the s_isup and s_imount in super_block[8]. Hence, the OS could find the files step by step through the relationship established here.