You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

操作系统如何处理非块设备扇区大小倍数的I/O写入?

非扇区对齐写入的处理机制(Linux内核视角)

你的理解完全正确:块设备的最小原子操作单位是扇区(比如你提到的512字节),操作系统无法直接向块设备写入小于扇区大小的数据。当执行非扇区对齐的无缓冲写入时,内核会执行**读-改-写(Read-Modify-Write)**流程,而非填充0字节覆盖整个扇区。

核心处理逻辑

  1. 读取目标扇区:内核先将包含待写入数据的整个扇区从磁盘读入内核内存缓冲区。
  2. 修改缓冲区数据:将用户空间的300字节数据拷贝到缓冲区的对应偏移位置,保留扇区内未被修改的原有数据。
  3. 写入完整扇区:将修改后的整个512字节缓冲区写回磁盘的对应扇区。

这种流程确实会带来额外开销:多一次磁盘读操作,且需要占用内核内存作为临时缓冲,因此非对齐写入的性能远低于扇区对齐的写入。

Linux内核中负责该流程的组件

这个逻辑主要由文件系统层和**块设备层(Block Layer)**协同处理:

  • 文件系统层:以ext4为例,当处理O_DIRECT(无缓冲)的非对齐写入时,文件系统会触发读-改-写流程,负责读取目标扇区、合并用户数据到缓冲区。
  • 块设备层:负责将文件系统的I/O请求转换成磁盘能识别的扇区大小操作,通过bio结构体管理I/O请求,最终提交给磁盘驱动执行。

Linux内核代码示例

以ext4文件系统的无缓冲I/O处理函数ext4_direct_IO(位于fs/ext4/file.c)为例,简化后的核心逻辑如下:

static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter)
{
    struct inode *inode = file_inode(iocb->ki_filp);
    loff_t pos = iocb->ki_pos;
    size_t count = iov_iter_count(iter);
    unsigned int blksize = inode->i_blkbits;
    struct page *page;
    ssize_t ret = 0;

    // 检查写入是否扇区对齐
    if (!IS_ALIGNED(pos, blksize) || !IS_ALIGNED(count, blksize)) {
        // 计算目标页的索引
        pgoff_t index = pos >> PAGE_SHIFT;
        // 读取对应扇区所在的页到内核缓存
        page = read_cache_page(inode->i_mapping, index,
                               (filler_t *)ext4_readpage, NULL);
        if (IS_ERR(page)) {
            ret = PTR_ERR(page);
            goto out;
        }

        // 将用户数据拷贝到页的对应偏移位置
        ret = copy_from_iter(page_address(page) + (pos & (PAGE_SIZE - 1)),
                             count, iter);
        if (ret < 0) {
            put_page(page);
            goto out;
        }

        // 标记页为脏页,触发后续写入
        set_page_dirty(page);
        // 构建bio结构体,提交写请求到块层
        struct bio *bio = bio_alloc(GFP_KERNEL, 1);
        bio_set_dev(bio, inode->i_sb->s_bdev);
        bio->bi_iter.bi_sector = pos >> 9; // 转换为扇区地址(512B扇区)
        bio_add_page(bio, page, PAGE_SIZE, 0);
        bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
        submit_bio(bio);

        put_page(page);
    }
    // ... 对齐写入的处理逻辑
out:
    return ret;
}

块层通过submit_bio函数将构建好的bio请求提交给磁盘驱动,最终驱动会执行整个扇区的写入操作,保证磁盘数据的一致性。

内容的提问来源于stack exchange,提问作者Marco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 01:57:35