在Intel Xeon E3-1270 CPU上使用带IOCTL的IOWR时,有没有人遇到系统锁定问题?我在使用上述CPU的3个不同的戴尔盒子上有3个不同的发行版(Centos 7.2,Ubuntu 14.04,Ubuntu 16.04),每次我使用带有IOWR的IOCTL时,只要我访问arg变量中发送的内存,系统就会锁定ioctl电话。
这是一个示例代码:
内核模块标题:
#include <linux/ioctl.h>
#define IOC_MAGIC 'k'
typedef struct
{
int test1;
int test2;
} bufferTest;
#define IOCTL_HELLO _IO(IOC_MAGIC,0)
#define IOCTL_BUFFER_TEST _IOWR(IOC_MAGIC,1, bufferTest)
内核模块来源:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h> // required for various structures related to files liked fops.
#include <linux/semaphore.h>
#include <linux/cdev.h>
#include "ioctl_basic.h" //ioctl header file
#include <linux/version.h>
#include <asm/uaccess.h>
int open(struct inode *inode, struct file *filp)
{
printk(KERN_INFO "Inside open \n");
return 0;
}
int release(struct inode *inode, struct file *filp)
{
printk (KERN_INFO "Inside close \n");
return 0;
}
long ioctl_funcs(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret=0;
int index=0;
bufferTest *bufferPtr = NULL;
void *userPtr = NULL;
printk(KERN_INFO "ioctl_func: %u\n", cmd);
switch(cmd) {
case IOCTL_HELLO:
printk(KERN_INFO "Hello ioctl world\n");
ret = 1;
break;
case IOCTL_BUFFER_TEST:
bufferPtr = (bufferTest *)arg;
userPtr = (void *)arg;
if (access_ok(VERIFY_WRITE, userPtr, sizeof(bufferTest)))
{
printk(KERN_INFO "Success verify memory write\n");
printk(KERN_INFO "test1: %d, test2: %d\n", bufferPtr->test1, bufferPtr->test2);
}
else
printk(KERN_INFO "Failed to verify memory write\n");
break;
default:
printk(KERN_INFO "Unknown command: %d\n", cmd);
break;
}
return ret;
}
struct file_operations fops = {
.open = open,
.unlocked_ioctl = ioctl_funcs,
.release = release
};
struct cdev *kernel_cdev;
int char_arr_init (void) {
int ret;
dev_t dev_no,dev;
kernel_cdev = cdev_alloc();
kernel_cdev->ops = &fops;
kernel_cdev->owner = THIS_MODULE;
printk (" Inside init module\n");
ret = alloc_chrdev_region( &dev_no , 0, 1,"char_arr_dev");
if (ret < 0) {
printk("Major number allocation is failed\n");
return ret;
}
Major = MAJOR(dev_no);
dev = MKDEV(Major,0);
printk (" The major number for your device is %d\n", Major);
ret = cdev_add( kernel_cdev,dev,1);
if(ret < 0 )
{
printk(KERN_INFO "Unable to allocate cdev");
return ret;
}
return 0;
}
void char_arr_cleanup(void) {
printk(KERN_INFO " Inside cleanup_module\n");
cdev_del(kernel_cdev);
unregister_chrdev_region(Major, 1);
}
MODULE_LICENSE("GPL");
module_init(char_arr_init);
module_exit(char_arr_cleanup);
测试代码:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include "ioctl_basic.h" //ioctl header file
main ( ) {
int fd;
bufferTest buffer;
fd = open("/dev/temp", O_RDWR);
if (fd == -1)
{
printf("Error in opening file \n");
return;
}
ioctl(fd,IOCTL_HELLO); //ioctl call
buffer.test1 = 5;
buffer.test2 = 10;
printf("buffer ptr: %p, test1: %d, test2: %d\n", &buffer, buffer.test1, buffer.test2);
ioctl(fd,IOCTL_BUFFER_TEST,&buffer);
close(fd);
}
在内核模块中,我将(bufferTest *)转换为arg参数,一旦我尝试打印“test1”或“test2”,系统就会锁定。在我没有使用此特定CPU的任何其他系统上都不会发生这种情况。
如果我使用copy_to_user和copy_from_user将arg参数复制到内核模块中的本地结构,那么一切正常,但我认为使用IOWR定义我可以直接访问内存。看起来Xeon E3-1270处理器出现了某种问题,我无法弄清楚它是什么。还有其他人遇到过这个问题吗?
答案 0 :(得分:2)
如果我使用copy_to_user和copy_from_user将arg参数复制到内核模块中的本地结构,那么一切正常,但我认为使用IOWR定义我可以直接访问内存。
不,与ioctl请求的类型无关,您需要以常见方式访问用户空间内存。除copy_from_user
之外,还有__get_user
宏用于从用户空间读取简单类型:
if (access_ok(VERIFY_WRITE, userPtr, sizeof(bufferTest)))
{
int test1, test2;
printk(KERN_INFO "Success verify memory write\n");
__get_user(test1, &buffer->test1); // Read value of 'buffer->test1' into test1
__get_user(test2, &buffer->test2); // Read value of 'buffer->test2' into test2
printk(KERN_INFO "test1: %d, test2: %d\n", test1, test2);
}
Linux内核不了解ioctl类型及其含义。它们的用法只是一种约定。