C - IOCTL 参数大小限制



我正在编写一个内核模块,该模块涉及字符设备上的 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 "Modexitn");
unregister_chrdev(MAJOR, NAME);
}
static int dev_open( struct inode *n, struct file *f )
{
printk(KERN_INFO "Devopenn");
try_module_get(THIS_MODULE);
return 0;
}
static int dev_release( struct inode *n, struct file *f )
{ 
printk(KERN_INFO "Devreleasen");
module_put(THIS_MODULE);
return 0;
}
static long dev_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{ 
printk("dev_ioctl cmd: %dn", cmd);
if((_IOC_TYPE(cmd) != MAGIC))
{
return -ENOTTY; 
}
switch(cmd)
{
case IOCTL_GET_DATA:
{
printk("IOCTL_GET_DATA: %dn", 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: %dn", 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 "Modinitn");
unregister_chrdev(MAJOR, NAME);
int ret = register_chrdev(MAJOR, NAME, &fops);
if( ret < 0 )
{ 
printk(KERN_ERR "Could not register chardevn" ); 
}
printk(KERN_ERR "Device initializedn" );
return ret;
}
module_init(modinit);
module_exit(modexit);

当前代码编译正常,但数据大小不足以满足我在用户空间中的应用程序。但是,每当我增加数组以存储更多数据时,例如

typedef struct
{
char data[99999];
} DATA;

代码无法编译,并发生以下错误:

vdev.c:54:3: error: case label does not reduce to an integer constant
case IOCTL_GET_DATA:
^~~~

ioctl 代码的参数 'size' 限制为 (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,当其他方法自然不适合或已经用于其他目的时。

最新更新