The function read() is eventually mapped to sys_read() to execute. Before executing the main content, the system will first check the feasibility of this operation, including whether the file handle passed by the user process and bytes of number read are in a reasonable range, whether the page where the user process data are is written into the data is not read-only, and so on. After these checks, begin to perform the main content, that is, call the function file_read() and read the file data specified by the process. The code is as follows:
In file_read(), the system locates the logic block number of the specified file data block in the peripheral by bmp(). The code is as follows:
//code path:include/linux/fs.h:
#define BLOCK_SIZE 1024
//code path:fs/file_dev.c:
int file_read(struct m_inode * inode, struct file * filp, char * buf, int count) { int left,chars,nr;
struct buffer_head * bh;
//file path:fs/read_write.c:
int sys_read(unsigned int fd,char * buf,int count) //read data from the file “hello.txt”
{ // fd is the file handle, buf is a user space pointer, and count is the number of bytes //to read
struct file * file;
struct m_inode * inode;
if (fd> = NR_OPEN || count<0 || !(file = current->filp[fd]))//whether fd and count is
//within reasonable range,file
//is opened or not
return -EINVAL;
if (!count) //if number of bytes is 0, return
return 0;
verify_area(buf,count); //verify the property of page where buf is. If it is
//read-only, copy this page(refer to chapter 6)
inode = file->f_inode;
if (inode->i_pipe)
return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO;
if (S_ISCHR(inode->i_mode))
return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos);
if (S_ISBLK(inode->i_mode))
return block_read(inode->i_zone[0],&file->f_pos,buf,count);
if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) { //analyze node-i property of file
//“hello.txt” and it is common file
if (count+file->f_pos > inode->i_size) count = inode->i_size - file->f_pos;
if (count< = 0) return 0;
return file_read(inode,file,buf,count); //read data specified by process }
printk(“(Read)inode->i_mode =%06o\n\r”,inode->i_mode);
return -EINVAL;
}
Note that when the function bmp() calls the function _bmp(), add another parameter.
The code is as follows:
We will first introduce how the i node manages files.
The i node manages file data block through its structure i_zone. The diagram is shown in Figures 5.5 through 5.7.
I_zone[9] records the file data block context info. When the number of file data block is more than 9, Linux has to find another tactic: it continues to store the index value of the logic block in the data block of the data area to manage the data block hierarchically, in order to enlarge the number of data blocks for management.
i node of file
i_zone[9]
Logical blocks
The total amount of file data block is less than or equal to 7 KB
Figure 5.5 Management schematic diagram of the i node when file data is less than 7 blocks.
//code path:fs/inode.c:
int bmap(struct m_inode * inode,int block) {
return _bmap(inode,block,0); //last parameter is creating flag. 0
//means operating a existed block. 1
//means creating a new block.
}
if ((left = count)< = 0) return 0;
while (left) { // not more than data about one buffer block(1KB) is copied into
//buf memory in every loop
if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) {
// file operation pointer offset divided by BLOCK_SIZE(1024) is where the data operated //locates
//in this case, filp->f_pos is 0
//based on the data block number in file, find the logic block number in the peripheral if (!(bh = bread(inode->i_dev,nr))) //read data from the peripheral break;
} else
bh = NULL;
……
}
i node of file
i_zone[9]
Logical block of file
Indirect block in level 1
The total amount of file data block is more than 7 KB, and less than or equal to (7 + 512) KB
512 blocks
Figure 5.6 Management schematic diagram of the i node when file data is between 7 blocks and (7 + 512) blocks.
i node of file
i_zone[9]
Logical block of file
Level 1 indirect blocks
Level 2 indirect blocks
The total amount of file data block is more than 7 + 512 blocks, and less than or equal to 7 + 512 + 512 * 512 blocks
512 blocks
blocks512 512
blocks 512 * 512 blocks
Figure 5.7 Management schematic diagram of the i node when file data is between (7 + 512) blocks and Minix.
When the total amount of data is not more than 7 KB, the first seven members of i_zone[9] are used, recording the block number of these seven data blocks in the data area.
When the total amount of data is more than 7 KB, one should start a one-level indi- rect management program. The eighth member of i_zone[9] records the block number of a data block; however, it stores the logic block number of the next 512 data blocks in the peripherals, not the file data context. On the basis of these block numbers, find the cor- responding data block. Because the amount of data block is 1024 bytes and each block number occupies 2 bytes, a data block can store a block number of 512. In this way, the management limit is 7 + 512 data blocks, that is, (7 + 512) KB.
When the total amount of data is more than (7 + 512) KB, we use two-level indirect man- agement instead. The ninth member of i_zone[9] records the block number of a data block;
however, it stores the logic block number of the next 512 data blocks in the peripherals, not the file data context. These 512 data blocks store another 512 data blocks. In this way, the maxi- mum blocks of management is 7 + 512 + 512 * 512 data blocks, that is, (7 + 512 + 512 * 512) KB.
In case 1, it is in the process of reading the first data block in the file “hello.txt.” It is in the situation of having less than seven logic blocks. The code is as follows:
//code path:fs/inode.c:
static int _bmap(struct m_inode * inode,int block,int create) {
struct buffer_head * bh;
int i;
if (block<0) //if operating file data block number is less than 0 panic(“_bmap: block<0”);
if (block > = 7+512+512*512) // if operating file data block number is greater than //allowable maximum
panic(“_bmap: block>big”);
//= = = = = = = = = = = = = = = =not more than 7 logic blocks = = = = = = = = = = = = = = = = if (block<7) { //operating file data block number is less than 7
if (create && !inode->i_zone[block]) //create a new data block if (inode->i_zone[block] = new_block(inode->i_dev)) {
inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
}
return inode->i_zone[block]; // return value of logic block number recorded in //block item of i_zone
}
// = = = = = = = = = = = = between 7 and (7+512) logic blocks = = = = = = = = = = = = = = = = block - = 7;
if (block<512) {
if (create && !inode->i_zone[7]) //creat a new data block if (inode->i_zone[7] = new_block(inode->i_dev)) {
inode->i_dirt = 1;
inode->i_ctime = CURRENT_TIME;
}
if (!inode->i_zone[7]) // one-level indirect block has no index number, stop //finding, return 0
return 0;
if (!(bh = bread(inode->i_dev,inode->i_zone[7]))) //get one-level indirect block return 0;
i = ((unsigned short *) (bh->b_data))[block]; // get logic block number of item //block in indirect block if (create && !i) // whether create a new data block
//or not