一直有個疑惑,檔案是放在磁碟中的,但是操作檔案卻是在記憶體中,這兩者是怎麼關聯的呢,雖然至今還沒有找到更詳細的答案,但是對linux底層資料結構進行梳理後,發現了其中的一些線索,與大家分享。
一、相關的linux資料結構
1. fd
在程式語言裡面,開啟一個檔案一般的操作需要建立一個檔案描述符fd:
int fd = open(...);
fd是一個int型,其實是一個陣列的下標,前三個0,1,2被輸入,輸出,錯誤佔用了
新建新的fd的時候,首先分配一個file物件,然後放到陣列裡面,返回這個陣列的下標,就是fd了
2. file
struct file{
file_operations *fop;
path *f_path;
loff_t f_pos;
}
file結構中有一個f_path指標,指向path結構,其中f_pos還儲存了檔案的位置
3. path
struct path{
dentry *dentry
...
}
path連線著一個dentry結構
4. dentry
struct dentry{
inode *d_inode;
...
}
dentry結構連線著inode結構
5. inode
struct inode{
address_space *i_mapping;
address_space *i_data;
}
inode結構連線著address_space結構
6. address_space
struct address_space{
radix_tree_root page_tree;
}
page_tree是一個基樹,節點中存放著page節點,page就是系統中的頁,所以address_space連線著page結構。
7. page
struct page{
void *private;
}
private指向buffer_head
8. buffer_head
struct buffer_head{
sector_t block_nr; // 邏輯塊號
block_device *b_bdev; // 磁碟裝置號
}
block_nr存放的資料的邏輯塊號,通過邏輯塊號,就可以和磁碟關聯起來了。
9. bio
struct bio{
bio_vec *bi_io_vec; // 連結串列
sector_t bi_sector; // 磁碟上相關的扇區
struct block_device *bi_bdev; // 相關的塊裝置
}
一個bio連線著n個bio_vec結構,用於表示page中內容的位置
10. bio_vec
struct bio_vec{
page *bv_page; // 指向包含的頁
int bv_len; // 長度
int bv_offset; //頁中的偏移
}
11. task_struct
struct task_struct{
struct bio *bio_list; // 指向bio的連結串列頭
}
二、讀寫操作
file中的file_operations是一個操作結構,裡面包含對檔案的read,write等操作,所有對檔案的操作,都會轉移到該檔案file->f_op->read/write等操作。
三、記憶體到磁碟的路徑
linux2.6之後,使用了bio的結構來描述IO操作,由於效率的原因,所以buffer_head使用場景變少了,用bio結構描述一個讀/寫操作,然後使用IO排程演算法進行排程。
通過以上結構體,可以得出一條線索:
fd->file->path->dentry->inode->address_space->page->buffer_head->磁碟塊號
或者
task_struct->bio->磁碟塊號
磁碟的IO操作都是非同步的,會通過特定的條件觸發把內容從記憶體重新整理到磁碟。