In Section 3.3.3, the operating system (OS) loads the root file system successfully, so that data can interact with the root device. Installing the file system means that the file system in the hard disk is loaded as the root file system, in order for the OS to interact data with the root device.
There are three steps to install the file system:
1. Read the super block from the hard disk and load it into super_block[8] in the system.
2. Read the specified i node from the Ramdisk and load it into inode_table[32] in the system.
3. Mount the super block of the hard disk into the specified i node of inode_table[32].
The overall structure of the file system of the hard disk, after it is completely installed, is shown in Figure 5.1.
The command “mount/dev/hd1/mnt” can be used to install the file system in shell.
This command includes three parameters, that is, mount, /dev/hd1, and /mnt. “mount” is the name of a command with the purpose of installing the file system. “/dev/hd1” and
“/mnt” are directory path names, to indicate the mount file system of the device “hd1” to
the directory file “mnt.” After shell receives this command, it creates a new process. This process calls mount(), which is eventually mapped into the system function sys_mount().
The task of installing the file system is finished by sys_mount().
5.1.1 Get the Super Block of Peripherals
Tip:
The hard disk can be partitioned. Each partition can be taken as a device. In this and the following chapter, the entire hard disk is a partition by default. hd1 represents the hard disk.
The function sys_mount() first calls the function namei() to get the i node of the device hd1 file based on the directory name “/dev/hd1.” It then gets the device id from the i node and reads out the super block of the device based on the device id.
The code is as follows:
Root i node i node of mnt file directory i node_table[32]
Super block on disk super_block[8]
Disk Figure 5.1 Schematic diagram of a successful file system installation.
//code path:fs/super.c:
int sys_mount(char * dev_name, char * dir_name, int rw_flag) {
struct m_inode * dev_i, * dir_i;
struct super_block * sb;
int dev;
if (!(dev_i = namei(dev_name))) //get inode of device hd1 file return -ENOENT;
dev = dev_i->i_zone[0]; //get device number based on inode if (!S_ISBLK(dev_i->i_mode)) { //if hd1 file is not block device file
iput(dev_i); //free its inode
return -EPERM;
The process of getting the i node in the function namei() is similar to that in Section 4.1.1.
There are three steps to read the device super block by read_super(). First, it chooses an free slot to store the super block in super_block. Second, it loads the super block into this item. Finally, it loads the i node bitmap and logic block bitmap on the basis of the information from the super block. Besides, before being operated, the super block table item should be locked to avoid interfering with other actions. After the operation is fin- ished, it will be unlocked. The code is as follows:
}
iput(dev_i);//free inode of device hd1 file if (!(dir_i = namei(dir_name)))
return -ENOENT;
if (dir_i->i_count ! = 1 || dir_i->i_num = = ROOT_INO) { iput(dir_i);
return -EBUSY;
}
if (!S_ISDIR(dir_i->i_mode)) { iput(dir_i);
return -EPERM;
}
if (!(sb = read_super(dev))) { //get super block of device from device number iput(dir_i);
return -EBUSY;
}
if (sb->s_imount) { iput(dir_i);
return -EBUSY;
}
if (dir_i->i_mount) { iput(dir_i);
return -EPERM;
}
sb->s_imount = dir_i;
dir_i->i_mount = 1;
dir_i->i_dirt = 1; /* NOTE! we don’t iput(dir_i) */
return 0; /* we do that in umount */
}
//code path:fs/super.c:
static struct super_block * read_super(int dev) {
struct super_block * s;
struct buffer_head * bh;
int i,block;
if (!dev) return NULL;
check_disk_change(dev);
if (s = get_super(dev)) // if super block of hd1 has been loaded, return
//directly
return s;
for (s = 0+super_block ;; s++) { //find free item for hd1 in super_block if (s >= NR_SUPER+super_block)
return NULL;
if (!s->s_dev) //the second item of super_block is free
break;
}
s->s_dev = dev; // following s->... is to set parameters in super
//block item
s->s_isup = NULL; //corresponding to memory operation
5.1.2 Confirm the Mount Point of the Root File System
The system calls namei() to get the i node of the mnt directory file based on the directory name “/mnt.” It then analyzes the property of the i node and checks whether the i node is available to mount the file system. The code is as follows:
s->s_imount = NULL;
s->s_time = 0;
s->s_rd_only = 0;
s->s_dirt = 0;
lock_super(s); //lock super block item to avoid interfacing if (!(bh = bread(dev,1))) {
//read super block according to device number and block number of hd1
//(1 indicates the second block in device,which is the logic block number of super block) s->s_dev = 0;
free_super(s);
return NULL;
}
*((struct d_super_block *) s) = // load information of super block into item,namely
//the second item
*((struct d_super_block *) bh->b_data);
brelse(bh);
if (s->s_magic ! = SUPER_MAGIC) { //check super magic number to determine whether s->s_dev = 0; //the file system of device is available free_super(s);
return NULL;
}
for (i = 0;i<I_MAP_SLOTS;i++)
//load inode bitmap and logic block bitmap, and correspond them with s_imap and s_zmap s->s_imap[i] = NULL;
for (i = 0;i<Z_MAP_SLOTS;i++) s->s_zmap[i] = NULL;
block = 2;
for (i = 0 ; i < s->s_imap_blocks ; i++) if (s->s_imap[i] = bread(dev,block)) block++;
else
break;
for (i = 0 ; i < s->s_zmap_blocks ; i++) if (s->s_zmap[i] = bread(dev,block)) block++;
else
break;
if (block ! = 2+s->s_imap_blocks+s->s_zmap_blocks) {
//check whether logic block amount read form device is equal to that the device should have for(i = 0;i<I_MAP_SLOTS;i++)
brelse(s->s_imap[i]);
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;
s->s_zmap[0]->b_data[0] | = 1;
free_super(s); // completing process of setting, unlock super block
//item
return s;
}
//code path:fs/super.c:
int sys_mount(char * dev_name, char * dir_name, int rw_flag) {
struct m_inode * dev_i, * dir_i;
struct super_block * sb;
int dev;
Here, mnt is available to mount the file system.
5.1.3 Mount the Super Block with the Root File System
Make sure that the mount point and the mounted point are clear before mounting; that is, the file system of the device hd1 is not installed and other file systems are not installed in the directory file mnt. After these, the system mounts them all. The code is as follows:
if (!(dev_i = namei(dev_name))) //get inode of hd1 device file return -ENOENT;
dev = dev_i->i_zone[0]; //get device id from inode
if (!S_ISBLK(dev_i->i_mode)) { //if file hd1 is not block device file iput(dev_i); //free its inode
return -EPERM;
}
iput(dev_i); //free inode of hd1 device file if (!(dir_i = namei(dir_name))) //get inode of mnt directory file return -ENOENT;
if (dir_i->i_count ! = 1 || dir_i->i_num = = ROOT_INO) {
//only if inode of mnt is referred once and it is not root inode, it is available iput(dir_i);
return -EBUSY;
}
if (!S_ISDIR(dir_i->i_mode)) { //confirm that mnt is directory file iput(dir_i);
return -EPERM;
}
if (!(sb=read_super(dev))) { //get super block of device from device id iput(dir_i);
return -EBUSY;
}
if (sb->s_imount) { iput(dir_i);
return -EBUSY;
}
if (dir_i->i_mount) { iput(dir_i);
return -EPERM;
}
sb->s_imount = dir_i;
dir_i->i_mount = 1;
dir_i->i_dirt = 1; /* NOTE! we don’t iput(dir_i) */
return 0; /* we do that in umount */
}
//code path:fs/super.c:
int sys_mount(char * dev_name, char * dir_name, int rw_flag) {
……
if (!(sb = read_super(dev))) { //get super block of device from device id iput(dir_i);
return -EBUSY;
}
if (sb->s_imount) { // determine the file system of hd1 is not
//installed
iput(dir_i); //in other places
return -EBUSY;
}
We will explain how the file system works through three examples about file operation in Sections 5.2 and 5.8.
Example 1: the user process opens a file in the hard disk and reads out the content.
Example 2: the user process creates a new file in the hard disk and writes the content.
Example 3: the user process closes the file and deletes it.
Example 1: the user process opens a file that exists in the hard disk and reads out the content. This example is divided into two parts: open file and read file. The code is as follows: