在 xfs_bio_io.c
文件中,定义了一个函数 xfs_rw_bdev
,该函数负责处理 XFS 文件系统的块设备读写操作。以下是对该函数的详细分析:
函数原型
int xfs_rw_bdev(
struct block_device *bdev,
sector_t sector,
unsigned int count,
char *data,
enum req_op op)
- 参数解释:
bdev
:指向块设备的指针。sector
:起始扇区。count
:要读写的字节数。data
:数据缓冲区的指针。op
:操作类型,例如读或写。
主要逻辑
-
虚拟内存处理:
- 如果数据缓冲区来自虚拟内存(通过
is_vmalloc_addr
检查),并且操作是写操作,则使用flush_kernel_vmap_range
刷新内核虚拟映射范围(第26-27行)。
- 如果数据缓冲区来自虚拟内存(通过
-
创建并初始化 bio 结构:
- 使用
bio_alloc
分配一个新的 bio 结构,设置操作标志和同步标志(第29行)。 - 设置 bio 的扇区(第31行)。
- 使用
-
数据分页处理:
- 循环处理所有数据,将数据分页并添加到 bio 中(第33-51行)。
- 如果
bio_add_page
无法一次添加完整的页面,将创建新的 bio 并链接到当前 bio(第38-46行)。 - 提交每个已满的 bio 到底层设备(第46行)。
-
提交并等待最后一个 bio 完成:
- 使用
submit_bio_wait
提交最后一个 bio 并等待其完成(第53行)。 - 释放最后一个 bio 的引用(第54行)。
- 使用
-
读操作后的虚拟内存处理:
- 如果操作是读操作,并且数据缓冲区来自虚拟内存,使用
invalidate_kernel_vmap_range
使内核虚拟映射范围无效(第56-57行)。
- 如果操作是读操作,并且数据缓冲区来自虚拟内存,使用
错误处理
- 函数返回
submit_bio_wait
的结果,该结果表示操作成功或失败(第58行)。
总结
xfs_rw_bdev
函数是 XFS 文件系统与块设备交互的核心部分,它处理数据的读写请求,确保数据正确地从用户空间传输到块设备,或者从块设备传输到用户空间。通过使用 bio 结构,XFS 能够有效地管理大量的数据页,并确保数据在内核和硬件之间正确同步。
int
xfs_rw_bdev(
struct block_device *bdev,
sector_t sector,
unsigned int count,
char *data,
enum req_op op)
{
unsigned int is_vmalloc = is_vmalloc_addr(data);
unsigned int left = count;
int error;
struct bio *bio;
if (is_vmalloc && op == REQ_OP_WRITE)
flush_kernel_vmap_range(data, count);
bio = bio_alloc(bdev, bio_max_vecs(left), op | REQ_META | REQ_SYNC,
GFP_KERNEL);
bio->bi_iter.bi_sector = sector;
do {
struct page *page = kmem_to_page(data);
unsigned int off = offset_in_page(data);
unsigned int len = min_t(unsigned, left, PAGE_SIZE - off);
while (bio_add_page(bio, page, len, off) != len) {
struct bio *prev = bio;
bio = bio_alloc(prev->bi_bdev, bio_max_vecs(left),
prev->bi_opf, GFP_KERNEL);
bio->bi_iter.bi_sector = bio_end_sector(prev);
bio_chain(prev, bio);
submit_bio(prev);
}
data += len;
left -= len;
} while (left > 0);
error = submit_bio_wait(bio);
bio_put(bio);
if (is_vmalloc && op == REQ_OP_READ)
invalidate_kernel_vmap_range(data, count);
return error;
}