1

这个问题是关于我在作为 Oracle Virtual Box 中的虚拟机运行的 Ubuntu Linux 操作系统中从用户空间到内核空间的 ioctl 错误调用。编译模块代码后,使用“sudo insmod ioctl_module.ko”命令将其加载到 Linux 内核中,您可以通过下面的消息列表看到成功。出于某种原因,从用户空间到内核模块函数的 ioctl 调用说其中一个参数无效,我看不出它是无效的。(另外,这只是我第二次发布堆栈溢出问题,所以我希望我正确地遵循了你的约定!)谢谢,凯伦

用户级代码错误信息:

saasbook@saasbook:~/cs552/osPrimer/invokeKernelServices/user_level_code$./ioctl_test

testStruct.field1 的大小 = 1

testStruct.field2 的大小 = 1

第一个 ioctl:参数无效

ioctl_test.c 的代码清单:

https://gist.github.com/KarenWest/6629582

可以看到 ioctl_module 在内核中:

/invokeKernelServices$ dmesg

[13563.849593] 加载模块

[13578.846063] pseudo_device_ioctl

ioctl_module.c 的代码列表:

https://gist.github.com/KarenWest/6629557


我现在可以更具体地回答几天前的问题。使用 ioctl.h 位定义,使用 _IOW 的#define 宏,将它们一起移位和 oring,我看到 IOCTL_TEST = 0x4002006 是正确的,而 cmd = 0x804a030 是不正确的,但我无法弄清楚为什么 cmd 有错误价值。cmd 是上述 ioctl 入口点的参数:

static int pseudo_device_ioctl(struct inode *inode, struct file *file,
            unsigned int cmd, unsigned long arg)

因此,我查看了 proc_fs.h 输入文件的 proc_dir_entry 结构,其中该结构中的 proc_fops 指针设置为我的 ioctl 入口点函数,将 pseudo_dev_proc_operations 初始化为 file_operations 结构,并将 proc_entry 初始化为指向 proc_dir_entry 结构的指针(所有这些都在上面git上的代码链接中),所有这些都在ioctl_module.c的initialization_routine()中初始化,我知道一旦代码在ioctl_test.c级别调用,操作系统就应该用正确的值设置这个ioctl设置为将其定向到我的 ioctl 函数,它确实如此。但是,发送到我的 ioctl 函数设置 (cmd) 的参数不正确,并且与 IOCTL_TEST 不匹配,这就是失败的原因。

pseudo_dev_proc_operations.unlocked_ioctl = pseudo_device_ioctl;
pseudo_dev_proc_operations.compat_ioctl = pseudo_device_ioctl;

proc_entry = create_proc_entry("ioctl_test", 0666, NULL);
proc_entry->proc_fops = &pseudo_dev_proc_operations;

所以我跟着 proc_fs.h 的 proc_fops 指针(它被初始化为 pseudo_dev_proc_operations,它把它带到我的 ioctl pseudo_device_ioctl 函数)看看为什么 cmd 参数在处理过程中可能会搞砸,我迷失了 - 不知道为什么会这样。

如果有人有任何进一步的评论可以帮助我找出我哪里出错了,请告诉我。谢谢!凯伦


这可能会有所帮助 - 只需阅读以下内容:

“Linux内核模块编程指南:

第 7 章 与设备文件对话

7.1。与设备文件对话(写入和 IOCTL)”

4

1 回答 1

0
#define _IOC_NRBITS     8
#define _IOC_TYPEBITS   8

/*
 * Let any architecture override either of the following before
 * including this file.
 */
#ifndef _IOC_SIZEBITS
# define _IOC_SIZEBITS  14
#endif
#ifndef _IOC_DIRBITS
# define _IOC_DIRBITS   2
#endif

#define _IOC_NRMASK     ((1 << _IOC_NRBITS)-1)
#define _IOC_TYPEMASK   ((1 << _IOC_TYPEBITS)-1)
#define _IOC_SIZEMASK   ((1 << _IOC_SIZEBITS)-1)
#define _IOC_DIRMASK    ((1 << _IOC_DIRBITS)-1)

#define _IOC_NRSHIFT    0
#define _IOC_TYPESHIFT  (_IOC_NRSHIFT+_IOC_NRBITS)
#define _IOC_SIZESHIFT  (_IOC_TYPESHIFT+_IOC_TYPEBITS)
#define _IOC_DIRSHIFT   (_IOC_SIZESHIFT+_IOC_SIZEBITS)

/*
 * Direction bits, which any architecture can choose to override
 * before including this file.
 */
#ifndef _IOC_NONE
# define _IOC_NONE      0U
#endif
#ifndef _IOC_WRITE
# define _IOC_WRITE     1U
#endif
#ifndef _IOC_READ
# define _IOC_READ      2U
#endif

#define _IOC(dir,type,nr,size) \
        (((dir)  << _IOC_DIRSHIFT) | \
         ((type) << _IOC_TYPESHIFT) | \
         ((nr)   << _IOC_NRSHIFT) | \
         ((size) << _IOC_SIZESHIFT))

#define _IOC_TYPECHECK(t) (sizeof(t))
#define _IOR(type,nr,size)      _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOW(type,nr,size)      _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))**
#define _IOWR(type,nr,size)     _IOC(_IOC_READ|_IOC_WRITE,(type),nr),_IOC_TYPECHECK(size)))

如您所见,您在用户空间 ioctl_test.c 中使用的 _IOW 和您在模块 ioctl 函数中使用的 _IOWR 对于相同的参数计算为不同的值。因此,您的开关盒失败了。尝试在你的模块中使用 _IOW。

于 2013-09-20T07:03:00.803 回答