并发I / O – 缓冲损坏,阻止设备驱动程序

我开发块分层设备驱动程序。 因此,我拦截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)**这样的东西?

问题的根源是Block I / O方法的“特性”。 特别是(见Linex网站参考说明 )

** Biovecs 可以在多个bios之间共享 – bvec iter可以代表现有biovec的任意范围,包括biovec中途的起点和终点。 这使得能够有效地分割任意bios。 请注意,这意味着我们使用bi_size来确定何时到达bio的末尾,而不是bi_vcnt – 并且bio_iovec()宏在构造biovecs时会考虑bi_size。*

因此,在我的情况下,这是磁盘扇区溢出的缓冲区的原因。

在将BIO发送到支持的设备驱动程序之前,诀窍是在.bi_opf中设置REQ_NOMERGE_FLAGS

第二个原因是支持的设备驱动程序返回非实际的.bi_iter 因此,我们需要保存它(在向后端提交BIO请求之前)并在我们的“ bio_endio() ”例程中恢复它。

您是否考虑过将vmap与全局同步一起使用?

使用kmap_atomic有一些限制:

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

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

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