TCM(Target Core Module)是LIO(Linux IO Target)的别称,是内核态的iSCSI target。TCMU(TCM in Userspace)是LIO的用户态实现,允许用户程序方便地对接各种用户态后端实现。基于TCMU框架和LIO loopback(tcm_loop)模块,可以方便地实现用户态iSCSI target。本文介绍Alibaba Cloud Linux 3中针对TCMU在拷贝上的优化。
使用限制
操作系统:Alibaba Cloud Linux 3
内核版本:
5.10.134-14
及以上版本
TCMU现有流程在读写操作中均存在二次拷贝的问题,这在高吞吐场景下对性能造成了显著的影响。Alibaba Cloud Linux 3针对TCMU实现了两种类型的优化。
bypass data area:提供
ioctl
接口使得用户态控制TCMU直接在用户态数据buffer
与内核sgl
页之间拷贝数据。zero copy:提供
ioctl
接口使得用户态控制TCMU将内核的sg
页映射到用户态,从而方便tcmu-runner
直接访问。
适用场景
tcmu-runner
可根据自己当前的场景来选择采用哪种优化。
bypass data area
适用于backstore
管理自己的数据buffer
场景。
DMA_FROM_DEVICE类命令如
read
、inquiry
等,需要先将数据从用户态buffer
拷贝到data area
,再从data area
拷贝到sgl
页。开启bypass data area
后数据将直接从用户态buffer
拷贝到sgl
页。DMA_TO_DEVICE类命令如
write
、writesame
等,需要先将数据从sgl
页拷贝到data area
,再从data area
拷贝到用户态buffer
。开启bypass data area
后数据将直接从sgl
页拷贝到用户态buffer
。
zero copy
适用于backstore
不管理自己的数据buffer
,读写都直接使用TCMU的data area
场景。开启该优化需要注意:
当IO命令大小在256 KB及以上时才会相对于拷贝有比较明显的性能提升,因此需要根据业务IO模型来评估是否需要开启。
如果IO命令在
tcmu-runner
hang
住时导致命令超时,内存映射被解除,后续再访问将触发SIGBUS,因此需要评估该场景的影响。只有当IO命令大小是4 KB对齐,且每个
sg
页偏移也是4 KB对齐时才会走zero copy
流程。说明4 KB对齐:起始偏移和长度都是4 KB倍数。
设备配置接口
针对读写命令类型,bypass data area
和zero copy
分别提供不同的配置。当两者都开启时,将优先走zero copy
优化路径,即仅当无法满足走zero copy
路径时才会走bypass data area
优化路径。
bypass data area
read_bypass_data_area
:针对读命令类型(DMA_FROM_DEVICE),默认为false
;设置为true
将开启该优化。write_bypass_data_area
:针对写命令类型(DMA_TO_DEVICE),默认为false
;设置为true
将开启该优化。
查询配置属性
不同设备的配置属性路径不同,本文以在user_0/testblk为例。
sudo cat /sys/kernel/config/target/core/user_0/testblk/attrib/read_bypass_data_area
sudo cat /sys/kernel/config/target/core/user_0/testblk/attrib/write_bypass_data_area
修改配置属性
sudo bash -c "echo 1 > /sys/kernel/config/target/core/user_0/testblk/attrib/read_bypass_data_area"
sudo bash -c "echo 1 > /sys/kernel/config/target/core/user_0/testblk/attrib/write_bypass_data_area"
zero copy
read_zc_size
:针对读命令类型(DMA_FROM_DEVICE),默认为0 KB;当设置为非零值时,如果命令的数据长度大于该值且满足对齐要求,将开启该优化。write_zc_size
:针对写命令类型(DMA_TO_DEVICE),默认为0 KB;当设置为非零值时,如果命令的数据长度大于该值且满足对齐要求,将开启该优化。
查询配置属性
不同设备的配置属性路径不同,本文以在user_0/testblk为例。
sudo cat /sys/kernel/config/target/core/user_0/testblk/attrib/read_zc_size
sudo cat /sys/kernel/config/target/core/user_0/testblk/attrib/write_zc_size
修改配置属性
sudo bash -c "echo 256 > /sys/kernel/config/target/core/user_0/testblk/attrib/read_zc_size"
sudo bash -c "echo 256 > /sys/kernel/config/target/core/user_0/testblk/attrib/write_zc_size"
用户编程接口
参考接口文件/usr/include/linux/target_core_user.h
中的定义。
struct tcmu_data_xfer {
__u16 cmd_id;
__u16 __pad1;
__u32 iov_cnt;
struct iovec __user *iovec;
};
struct tcmu_cmd_zerocopy {
struct iovec __user *iov;
__u32 iov_cnt;
__u16 cmd_id;
};
#define TCMU_IOCTL_CMD_COPY_TO_SGL _IOW('T', 0xe0, struct tcmu_data_xfer)
#define TCMU_IOCTL_CMD_COPY_FROM_SGL _IOR('T', 0xe1, struct tcmu_data_xfer)
#define TCMU_IOCTL_CMD_ZEROCOPY _IOW('T', 0xe2, struct tcmu_cmd_zerocopy)