Two Ways to Synchronize Data from the Buffer to the

Một phần của tài liệu The art of linux kernel design (Trang 284 - 287)

Here are two ways to synchronize data from the buffer area to the hard disk. One is regular synchronization “updata” and the other is that the OS forces synchronization because the buffer area is limited.

The first way is as follows:

It is designed such that when the shell process runs for the first time, the update pro- cess is started. This process will reside in the memory. Its function is to synchronize data from the buffer area to the peripherals.

This process will call pause(), which is eventually mapped to the function sys_pause(), resulting in the process being in an interruptible wait state. The OS will wake the updata process intervally. When it runs, call the function sync() and synchronize data from the buffer area to the peripherals.

The function sync() is eventually mapped to the system calling the function sys_

sync() to run. In order to guarantee the integrity of the file synchronization contents, it needs to synchronize the file i node bitmap, the file i node, the file data block, and the logic block bitmap corresponding to data block. Sys_sync() writes the modified file i node into the buffer area (others are already in the buffer area) and then traverses the entire buffer.

As soon as the content of the buffer block is modified (b_dirt is set as 1), all are synchro- nized to the peripherals.

//code path:fs/file_dev.c:

int file_write(struct m_inode * inode, struct file * filp, char * buf, int count) {

……

if (!(bh = bread(inode->i_dev,block))) //apply for buffer block break;

c = pos% BLOCK_SIZE; //calculate the number of bytes

//to be written into buffer block p = c + bh->b_data;

bh->b_dirt = 1;

c = BLOCK_SIZE-c;

if (c > count-i) c = count-i;

pos + = c;

if (pos > inode->i_size) { inode->i_size = pos;

inode->i_dirt = 1;

} i + = c;

while (c— >0)

*(p++) = get_fs_byte(buf++); //write data into specified //buffer block

brelse(bh);

}

inode->i_mtime = CURRENT_TIME;

if (!(filp->f_flags & O_APPEND)) { filp->f_pos = pos;

inode->i_ctime = CURRENT_TIME;

}

return (i?i:-1);

}

The code is as follows:

The task that synchronizes the i node is completed by the function sync_inode().

The code is as follows:

//code path:fs/buffer.c:

int sys_sync(void) {

int i;

struct buffer_head * bh;

sync_inodes(); //write i-node into buffer area

bh = start_buffer;

for (i=0 ; i<NR_BUFFERS ; i++,bh++) { //traverse the entire buffer area wait_on_buffer(bh); //\if buffer block is in-use, wait for

//unlocking this buffer block

if (bh->b_dirt) //as soon as content of this buffer block //is modified

ll_rw_block(WRITE,bh); //synchronize content of buffer block to //peripherals

} return 0;

}

//code path:fs/inode.c:

void sync_inodes(void) {

int i;

struct m_inode * inode;

inode = 0+inode_table;

for(i=0 ; i<NR_INODE ; i++,inode++) { //traverse all i-node

wait_on_inode(inode); //if i-node traversed is in use, //wait for this i-node to be unlocked if (inode->i_dirt && !inode->i_pipe) //if content of i-node has been

//modified and it is not i-node of pipe file write_inode(inode); //synchronize i-node to buffer area }

}

//code path:fs/inode.c:

static void write_inode(struct m_inode * inode) {

struct super_block * sb;

struct buffer_head * bh;

int block;

lock_inode(inode); //lock up i-node to avoid

//interruption if (!inode->i_dirt || !inode->i_dev) {

unlock_inode(inode);

return;

}

if (!(sb = get_super(inode->i_dev))) //get super block of peripherals panic(“trying to write inode without device”);

block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +

(inode->i_num-1)/INODES_PER_BLOCK; //logic block number of i-node bitmap in //peripherals

if (!(bh = bread(inode->i_dev,block))) //load logic block where i-node is into //buffer area

panic(“unable to read i-node block”);

After synchronization is completed, the update process will be suspended, and con- tinues to synchronize the buffer block after the next waking up.

The second way is as follows:

Example 2 is simple because data written in the buffer area is less. We may alter it slightly. The code is as follows:

Consider the following scenario: the data to be written is more than 10 MB, but the buffer area is certainly not more than 10 MB. How can data be written then if the buffer area is full before process update is woken up? For data to continue to be written, data in the buffer area must be forced to synchronize with the hard disk, in order to leave enough space to write on.

This task is completed by the function getblk(), introduced in Section 3.3.1.2. When all free blocks in the buffer area are unable to be written in data(b_dirt is 1), it means it needs more space.

The code is as follows:

((struct d_inode *)bh->b_data) //synchronize i-node to buffer area [(inode->i_num-1)%INODES_PER_BLOCK] =

*(struct d_inode *)inode;

bh->b_dirt = 1; //set b_dirt of buffer block as 1

inode->i_dirt = 0; //set i_dirt of i-node as 0

brelse(bh);

unlock_inode(inode); //unlock i-node

}

void main() {

char str1[] = “Hello, world”;

int i;

//create new file

int fd = creat(“/mnt/user/user1/user2/hello.txt”,0644));

//write in file for(i = 0;i<1000000;i++) {

int size = write(fd,str1,strlen(str1));

} }

//code path:fs/buffer.c:

struct buffer_head * getblk(int dev,int block) {

struct buffer_head * tmp, * bh;

repeat:

if (bh = get_hash_table(dev,block)) return bh;

tmp = free_list;

do {

Those are two ways to synchronize data.

They are worth discussing below.

In Section 5.5.3, the data block that p points to is newly applied so that writing data from the beginning of a specified data block does not affect existing data. However, if the file “hello.txt” is not a newly created file but an existing file, writing data in any data block that p points to will overwrite the existing data beyond the writing point in this data block (unless p points to end).

It means that the user can only add in data at the end of the file. If data is modified in the middle of the file, relying solely on the function sys_write() is not enough. Thus, how does OS handle more complex situations of modifying data? It is explained in detail below.

Một phần của tài liệu The art of linux kernel design (Trang 284 - 287)

Tải bản đầy đủ (PDF)

(524 trang)