有没有很多人跟我有一样的疑惑,文件是放在磁盘中的,但是操作文件却是在内存中,这两者是怎么关联的呢,虽然至今还没有找到更详细的答案,但是对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操作都是异步的,会通过特定的条件触发把内容从内存刷新到磁盘。
本作品采用
知识共享署名-非商业性使用 4.0 国际许可协议进行许可。