Concurrent I/O - 缓冲区破坏,块设备驱动程序

5
我正在开发一个块分层设备驱动程序。所以,我拦截 WRITE 请求并加密数据,并在 end_bio() 例程中解密数据(处理 READ 请求期间)。因此,在单个流中所有的工作都很正常。但是,如果尝试同时从两个或更多进程执行 I/O 操作,则会出现缓冲区内容损坏。我没有任何用于缓冲区的本地存储。 我需要在我的驱动程序中计算 BIO 合并吗? Linux I/O 子系统是否有与并发 I/O 请求数量有关的某些要求? 使用堆栈或编译是否有相关的技巧和提示? 这是在内核4.15下进行的。
此时,我使用以下限制来扫描磁盘扇区:
    /*
     * A portion of the bio_copy_data() ...
     */
    for (vcnt = 0, src_iter = src->bi_iter; ; vcnt++)
        {
        if ( !src_iter.bi_size)
            {
            if ( !(src = src->bi_next) )
                break;

            src_iter = src->bi_iter;
            }

        src_bv = bio_iter_iovec(src, src_iter);

        src_p = bv_page = kmap_atomic(src_bv.bv_page);
        src_p += src_bv.bv_offset;

        nlbn    = src_bv.bv_len512;
        for ( ; nlbn--; lbn++ , src_p += 512 )
                {
                {
                /* Simulate a processing of data in the I/O buffer */
               char *srcp = src_p, *dstp = src_p;
               int  count = DUDRV$K_SECTORSZ;

               while ( count--)
                {
                *(dstp++) = ~ (*(srcp++));
                }

                }
                }
        kunmap_atomic(bv_page);
        **bio_advance_iter**(src, &src_iter, src_bv.bv_len);
        }

这正确吗?还是我需要使用类似于 bio_for_each_segment(bvl, bio, iter) 的东西?


1
以下的答案是否对您有所帮助?谢谢! - Fabio Manzano
抱歉,不行。我稍后会发布答案。 - Ruslan R. Laishev
2个回答

1

你是否考虑过使用全局同步的vmap替代呢?

使用kmap_atomic有一些限制:

由于映射仅限于发出它的CPU,因此它的性能表现良好,但发出任务因此需要留在该CPU上直到完成,以免其他任务取代其映射。

kmap_atomic()也可以被中断上下文使用,因为它不会睡眠,调用者在kunmap_atomic()被调用之后才能睡眠。

参考资料:https://www.kernel.org/doc/Documentation/vm/highmem.txt


1
谢谢你的尝试,@Fabio!我已经找到了问题的根源,请看下面的答案。 - Ruslan R. Laishev

1
问题的根源在于块I/O方法的“特性”。特别是(请参见Linex网站reference的描述)
Biovecs可以在多个bios之间共享 - bvec迭代器可以表示现有biovec的任意范围,无论是从中间开始还是结束。这就是使任意Bios有效分割的原因。请注意,这意味着我们仅使用bi_size来确定何时到达bio的末尾,而不是bi_vcnt - 并且当构造biovecs时,bio_iovec()宏考虑了bi_size。
因此,在我的情况下,这是导致磁盘扇区溢出的原因。
诀窍是在将BIO发送到后端设备驱动程序之前,在.bi_opf中设置REQ_NOMERGE_FLAGS。
第二个原因是非实际的.bi_iter由后端设备驱动程序返回。因此,在提交BIO请求到后端之前,我们需要保存它,并在我们的“bio_endio()”例程中恢复它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接