我正在编写一个内核模块,该模块涉及字符设备上的ioctl操作。我的驱动程序接受ioctl调用,我想将一些数据从内核空间传递到用户空间。我在传递大数据结构时遇到麻烦。我想知道是否有办法解决此问题,并以某种方式解决此限制。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include "ioctl_def.h"
typedef struct
{
char data[9999];
} DATA;
#define MAGIC 'v'
#define IOCTL_GET_DATA _IOR(MAGIC, 1, DATA)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Noob");
MODULE_DESCRIPTION("Test module");
MODULE_VERSION("0.01");
#define MAJOR 400
#define NAME "vdev"
static void __exit modexit(void)
{
printk(KERN_INFO "Modexit\n");
unregister_chrdev(MAJOR, NAME);
}
static int dev_open( struct inode *n, struct file *f )
{
printk(KERN_INFO "Devopen\n");
try_module_get(THIS_MODULE);
return 0;
}
static int dev_release( struct inode *n, struct file *f )
{
printk(KERN_INFO "Devrelease\n");
module_put(THIS_MODULE);
return 0;
}
static long dev_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{
printk("dev_ioctl cmd: %d\n", cmd);
if((_IOC_TYPE(cmd) != MAGIC))
{
return -ENOTTY;
}
switch(cmd)
{
case IOCTL_GET_DATA:
{
printk("IOCTL_GET_DATA: %d\n", cmd);
DATA d;
memset(&d, 0, sizeof(DATA));
snprintf(d.data, sizeof(d.data), "%s", "Hello");
copy_to_user((void*)arg, &d, _IOC_SIZE(cmd));
}
break;
}
return 0;
}
static ssize_t dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
{
printk("input length: %d\n", count);
char* data = kmalloc(count, GFP_KERNEL);
memset(data, 0, count);
if (copy_from_user(data + *offset, buf, (unsigned long)count))
{
printk("read error!\n");
}
else
{
if (data[count - 1] == 10) // ascii line feed dec = 10
{
data[count - 1] = 0;
}
printk("%s", data);
}
kfree(data);
return count;
}
static const struct file_operations fops = {
.owner = THIS_MODULE,
.open = dev_open,
.write = dev_write,
.release = dev_release,
// .read = dev_read,
.unlocked_ioctl = dev_ioctl
};
static int __init modinit(void)
{
printk(KERN_INFO "Modinit\n");
unregister_chrdev(MAJOR, NAME);
int ret = register_chrdev(MAJOR, NAME, &fops);
if( ret < 0 )
{
printk(KERN_ERR "Could not register chardev\n" );
}
printk(KERN_ERR "Device initialized\n" );
return ret;
}
module_init(modinit);
module_exit(modexit);
当前代码可以编译OKAY,但数据大小不足以在用户空间中容纳我的应用程序。但是,每当我增加数组来存储更多数据时,例如
typedef struct
{
char data[99999];
} DATA;
代码将无法编译,并且会发生以下错误:
vdev.c:54:3: error: case label does not reduce to an integer constant
case IOCTL_GET_DATA:
^~~~
答案 0 :(得分:1)
ioctl代码的参数“大小”受(16K -1)限制。您尝试传递的“大小”等于99999,该值超出了该限制。
头文件include/uapi/asm-generic/ioctl.h包含以下注释,解释了这种限制的来源:
/* ioctl command encoding: 32 bits total, command in lower 16 bits,
* size of the parameter structure in the lower 14 bits of the
* upper 16 bits.
* Encoding the size of the parameter structure in the ioctl request
* is useful for catching programs compiled with old versions
* and to avoid overwriting user space outside the user buffer area.
* The highest 2 bits are reserved for indicating the ``access mode''.
* NOTE: This limits the max parameter size to 16kB -1 !
*/
有许多“标准”方法可以将数据从内核传递给用户。例如。可以将其实现为字符设备的.read
方法,该方法自然会处理任何长度(包括可变长度)的数据。
仅在“其他非自然方法”或已经用于其他用途的“非标准”情况下,才需要诉诸ioctl
。