块设备驱动程序 - 了解收到的 ioctl

Posted

技术标签:

【中文标题】块设备驱动程序 - 了解收到的 ioctl【英文标题】:Block device driver - Understanding received ioctl 【发布时间】:2018-05-02 15:43:00 【问题描述】:

我刚刚实现了一个虚拟块设备,在使用它时,我看到了与 ioctls 相关的奇怪行为。

我的设备只是一个内存区域,分为两个 512 字节的扇区。我目前可以使用系统调用在特定偏移量处读取/写入它。

设备还受到保护,防止并发写访问。它接受无限数量的读者,但一次只接受一个作家,并且只有在当前没有人阅读它的情况下。

Ioctl 尚未处理,但尽管如此,我仍在记录相关信息。

int block_mod_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg)

    DEBUG("Entering IOCTL handling function\n");
    switch(cmd)
    
        default:
            WARNING("Unknown ioctl call: %x\n", cmd);
            WARNING("Ioctl: type=%x\tnumber=%x\tdirection=%x\tsize=%x\n", _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_DIR(cmd), _IOC_SIZE(cmd));
            return -1;
    
    return 0;

我在玩dd,发现了一个奇怪的行为,经过一番挖掘后我不明白。

# dd if=/dev/blkmodtest of=file.out seek=10
[  107.367797] Oppened in read only mode
[  107.368595] Read access: 1   Write access: 0
[  107.370367] Reading from device
[  107.372939] Closed read only mode
[  107.373690] Read access: 0   Write access: 0
2+0 records in
2+0 records out
1024 bytes (1.0 kB, 1.0 KiB) copied, 0.00584625 s, 175 kB/s

# dd if=/dev/blkmodtest of=file.out skip=10
[  111.982493] Oppened in read only mode
[  111.983326] Read access: 1   Write access: 0
[  111.985247] Unknown ioctl call: 80306d02
[  111.986096] Ioctl: type=6d   number=2    direction=2 size=30
[  111.987618] Unknown ioctl call: 80306d02
[  111.988436] Ioctl: type=6d   number=2    direction=2 size=30
dd: /dev/blkmodtest: cannot skip: Invalid argument
[  111.991032] Closed read only mode
[  111.991705] Read access: 0   Write access: 0
0+0 records in
0+0 records out
0 bytes copied, 0.00783969 s, 0.0 kB/s

似乎dd 正在发出我的驱动程序无法(显然)处理的ioctl 调用。我知道我不应该给skip=10,而是给seek=10,因为我正在从设备上读取,但这是出于测试目的。

我目前正在尝试了解为什么发布此 ioctl 以及出于什么目的? p>

如果我很好地理解了我找到的文档,ioctl 类型是'm',应将其描述为以下文件之一 (source):

'm' 00-09   linux/mmtimer.h     conflict!
'm' all linux/mtio.h        conflict!
'm' all linux/soundcard.h   conflict!
'm' all linux/synclink.h    conflict!
'm' 00-19   drivers/message/fusion/mptctl.h conflict!
'm' 00 drivers/scsi/megaraid/megaraid_ioctl.h conflict!

我已经检查了这些文件,但找不到有用的信息来帮助我进一步了解该特定案例中发生的情况。

【问题讨论】:

【参考方案1】:

设置循环设备(sudo losetup loop0 /path/to/some/image),strace dd if=/dev/loop0 of=out.data skip=10 bs=40 count=2的输出包含

open("/dev/loop0", O_RDONLY)            = 3
dup2(3, 0)                              = 0
close(3)                                = 0
lseek(0, 0, SEEK_CUR)                   = 0
ioctl(0, MTIOCGET, 0x7fffac670080)      = -1 EINVAL (Invalid argument)
lseek(0, 400, SEEK_CUR)                 = 400
fstat(0, st_mode=S_IFBLK|0660, st_rdev=makedev(7, 0), ...) = 0

这表明dd 正在尝试在您的块设备上执行MTIOCGET ioctl。 man 4 st显示

st 驱动程序提供到各种 SCSI 磁带设备的接口。 [...] MTIOCGET — 获取状态 此请求接受类型为 (struct mtget *) 的参数。

换句话说,dd 怀疑您的块设备可能是某种 SCSI 磁带设备,并使用您看到的ioctl() 询问它的状态。

您的司机可以为此返回EINVAL;这就是例如循环设备也可以。

【讨论】:

以上是关于块设备驱动程序 - 了解收到的 ioctl的主要内容,如果未能解决你的问题,请参考以下文章

linux字符设备驱动--基本知识介绍

虚拟字符设备驱动开发

虚拟块驱动编写

Linux下GPIO驱动

Linux 0.11源码阅读笔记-块设备驱动程序

ioctl 失败:不允许操作 - 我的文件的块布局