一、内核原型(linux2.6.28-7)

long (*compat_ioctl)(struct tty_struct *tty, struct file * file,

                     unsigned int cmd, unsigned long arg);

     implement ioctl processing for 32 bit process on 64 bit system

     Optional

二、What is compat_ioctl

There is one more method called as "compat_ioctl()" that a 64 bit driver
has to implement. It gets called when 64 bit kernel gets ioctl() call
from 32 bit user.

Tasks to be done by compat_ioctl() :

1. Acquire BKL, since kernel calls compat_ioctl without BKL.

2. 32 to 64 bit conversion for long and pointer objects passed by user

3. Process input data, get results.

4. 64 to 32 bit conversion in order to pass the output data back to user

5. Release BKL

三、中文档案

Linux 64Bit 下的 ioctl和compat_ioctl ioctl32 Unknown cmd fd

前段时间将我们的程序移植到Mips64的Linux 2.6环境下,做可行性试验。

由于用户态程程序规模太大,而且之前没有对64bit的情况做考虑,

所以,用户态程序任然使用32位模式编译,内核运行在64bit。

我们有一个内核模块之前是在2.4.21下的,拿到2.6后,把部分api做了些更改,直接编译并加载。

用户态程序在调用ioctl的时候,总是失败。

dmesg看一下内核信息,有如下类似信息:

ioctl32(add_vopp:9767): Unknown cmd fd(3) cmd(80048f00){00} arg(ff240ae0)

后来在内核中的ioctl中添加debug代码,发现根本没调用到内核中的ioctl函数。

经过查找,发现了以下资源

The new way of ioctl()

32 bit user/64 bit kernel

What is compat_ioctl () 

more on compat_ioctl

产生问题的分析:

我们的程序通过Linux的

ssize_t read(int fd, void *buf, size_t count); 

系统调用从虚拟设备中读取内核中。

使用

int ioctl(int fd, int request, ...);

系统调用来对设备进行控制,并传递一些数据。

ioctl是我们扩展非标准系统调用的手段。

read系统调用,对应内核中struct file_operations 结构中的

ssize_t (*read) (struct file *filp, char *buf, size_t count, loff_t *f_pos)

当用户态位32bit, 内核位64bit的时候,

用户态的程序,和内核态的程序,在数据类型不一致。

比如指针,用户态的指针实际上是unsigned long 4Byte

内核态的指针是unsigned ong: 8Byte.

对于这种不一致,从用户态陷入内核态的时候,大部分标准调用的参数已经做了相应的转化。

不存在问题。比如ssize_t,内核态和用户态不一致,

对于这种已知类型,内核代码已经做了转换,因为他知道该怎么转,

所以我们的程序调用read,write,等系统调用,都能正确的返回结果。

再来看看ioctl系统调用,

用户态系统调用,int ioctl(int fd, int request, ...);

内核中对应的函数

int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)

request是请求号,用来区分不同得到请求。后面的可变参数随便选。

如果想传入或传出自定义结构,可以传个指针类型。

如果没数据传递,可以空着。

当然也可以传这个int或char之类的类型来向内核传递数据。

问题来了,内核不知道你传递的是那种类型,他无法给你转化。

总结一下:

1). Linux2.6对64bit kernel 在struct file_operation中增加了一个成员

long (*compat_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg);

用来提供32位用户态程序的方法,

可以通过filp->f_dentry->d_inode方法获得。

3). 关于ioctl的请求号,经常是通过宏定义生成的
举例如下:

#define IoctlGetNetDeviceInfo    _IOWR(Ioctl_Magic, 1, struct_NetDeviceInfo)

#define IoctlNetQueueInit          _IOR(Ioctl_Magic, 4, struct_NetDeviceListen)

#define IoctlNetQueueDestroy     _IO(Ioctl_Magic, 5)

注意_IOWR和IOR宏, 他们的最后一个参数是一个数据类型,展开时会包含sizeof()操作,

于是32bit用户态程序和64bit内核之间,生成的ioctl的request号很可能就会不同,

在compat函数中switch()的时候,就会switch不到。

要想办法避免:

提供64bit和32bit大小一致的结构。

在用户态下提供一个伪结构,伪结构和内核内的结构宽度一致。

用_IO宏,而不用_IOWR或_IOR宏,反正只是为了得到一个号码,实际传输数据大小,自己心理有数,内核代码处理好就行了。

4). 如果compat收到的最后参数arg是一个用户态指针, 它在用户态是32位的,在内核中为了保证安全,

可以使用compat_ptr(art)宏将其安全的转化为一个64位的指针(仍然是用户指针)

linux2.6内核compat_ioctl函数的更多相关文章

  1. Linux2.6 内核的 Initrd 机制解析(转)

    from: https://www.ibm.com/developerworks/cn/linux/l-k26initrd/ 简介: Linux 的 initrd 技术是一个非常普遍使用的机制,lin ...

  2. Linux2.6 内核的 Initrd 机制解析

    文章来自:www.ibm.com/developerworks/cn/linux/l-k26initrd/ 1.什么是 Initrd initrd 的英文含义是 boot loader initial ...

  3. Linux2.6内核实现的是NPTL

    NPTL是一个1×1的线程模型,即一个线程对于一个操作系统的调度进程,优点是非常简单.而其他一些操作系统比如Solaris则是MxN的,M对应创建的线程数,N对应操作系统可以运行的实体.(N<M ...

  4. Linux2.6内核进程调度系列--scheduler_tick()函数1.总体思想

    参考的是ULK第三版,Linux2.6.11.12内核版本. 调度程序依靠几个函数来完成调度工作,其中最重要的第一个函数是scheduler_tick函数,主要步骤如下: /** * 维持当前最新的t ...

  5. Linux2.6内核进程调度系列--scheduler_tick()函数3.更新普通进程的时间片

    RT /** * 运行到此,说明进程是普通进程.现在开始更新普通进程的时间片. */ /* 首先递减普通进程的时间片计数器.如果用完,继续执行以下操作 */ if (!--p->time_sli ...

  6. Linux2.6内核进程调度系列--scheduler_tick()函数2.更新实时进程的时间片

    RT /** * 递减当前进程的时间片计数器,并检查是否已经用完时间片. * 由于进程的调度类型不同,函数所执行的操作也有很大差别. */ /* 如果是实时进程,就进一步根据是FIFO还是RR类型的实 ...

  7. Linux2.6内核--进程调度理论

    从1991年Linux的第1版到后来的2.4内核系列,Linux的调度程序都相当简陋,设计近乎原始,见0.11版内核进程调度.当然它很容易理解,但是它在众多可运行进程或者多处理器的环境下都难以胜任. ...

  8. linux2.6内核链表

    一.        链表数据结构简介      链表是一种常用的组织有序数据的数据结构,它通过指针将一系列数据节点连接成一条数据链,是线性表的一种重要实现方式.相对于数组,链表具有更好的动态性,建立链 ...

  9. 【转载】linux2.6内核initrd机制解析

    题记 很久之前就分析过这部分内容,但是那个时候不够深入,姑且知道这么个东西存在,到底怎么用,来龙去脉咋回事就不知道了.前段时间工作上遇到了一个initrd的问题,没办法只能再去研究研究,还好,有点眉目 ...

随机推荐

  1. 使用 Bootstrap Typeahead 组件

    Bootstrap 中的 Typeahead 组件就是通常所说的自动完成 AutoComplete,功能很强大,但是,使用上并不太方便.这里我们将介绍一下这个组件的使用. 第一,简单使用 首先,最简单 ...

  2. asp.net中调用javascript自定义函数的方法(包括引入JavaScript文件)总结

    通常javascript代码可以与HTML标签一起直接放在前 端页面中,但如果JS代码多的话一方面不利于维护,另一方面也对搜索引擎不友好,因为页面因此而变得臃肿:所以一般有良好开发习惯的程序员都会把 ...

  3. JAVA基础知识之IO——对象序列化

    对象序列化 Java对象序列化(Serialize)是指将Java对象写入IO流,反序列化(Deserilize)则是从IO流中恢复该Java对象. 对象序列化将程序运行时内存中的对象以字节码的方式保 ...

  4. jar 文件

    使用类库中的类: 1.当前应用程序所在目录中没有包名的类,直接用. 2.java库. import语句导入. 3.当前目录的子孙目录有报名的类,set classpath,之前有写. 4.扩展ext文 ...

  5. java 反编译和文档生成器

    挺有趣的东西. 代码在上一篇中有. 反编译器javap.exe javadoc.exe制作源文件类结构的html格式文档

  6. #ifdef DEBUG的理解

    今天看到一段代码,对ifdef的概念比较模糊,于是去学习了一下,找到一个很好的解释,如下: 在工程设置里有一些设置会对该工程自动产生一系列的宏,用以控制程序的编译和运行.就好象楼上说的一样,如果你把代 ...

  7. P1533 可怜的狗狗

    http://www.luogu.org/problem/show?pid=1533 题目背景 小卡由于公务需要出差,将新家中的狗狗们托付给朋友嘉嘉,但是嘉嘉是一个很懒的人,他才没那么多时间帮小卡喂狗 ...

  8. 未完成的任务之:下载、安装、体验 Gentoo

    Gentoo,伟大的Gentoo是Linux世界最年轻的发行版本,正因为年轻,所以能吸取在她之前的所有发行版本的优点,这也是Gentoo被称为最完美的Linux发行版本的原因之一. 如果你需要一个桌面 ...

  9. VirtualBox中安装CentOS-6.6虚拟机(转载)

    1. 下载 可以到官网下载,http://mirror.centos.org/centos/ 如果下载速度太慢的话,也可以到163镜像下载: http://mirrors.163.com/centos ...

  10. uTenux——LED驱动讲解

    LED驱动讲解,对于一个嵌入式的工程师还是一个刚开是学习相关电子设计的朋友,对于LED的驱动问题应该不甚陌生.我所说的LED驱动并不是类似大功率LED照明的那个驱动,而是简单的控制器对LED的控制驱动 ...