ioctl,unlocked_ioctl 处理方法【转】

来源:互联网 发布:淘宝旺铺功能 编辑:程序博客网 时间:2024/05/22 00:08
kernel 2.6.35 及之前的版本中struct file_operations 一共有3个ioctl :
ioctl,unlocked_ioctl和compat_ioctl
现在只有unlocked_ioctl和compat_ioctl 了

在kernel 2.6.36 中已经完全删除了struct file_operations 中的ioctl 函数指针,取而代之的是unlocked_ioctl 。

这个指针函数变了之后最大的影响是参数中少了inode ,不过这个不是问题,因为用户程序中的ioctl对应的系统调用接口没有变化,所以用户程序不需要改变,一切都交给内核处理了,如果想在unlocked_ioctl中获得inode 等信息可以用如下方法:
struct inode *inode = file->f_mapping->host;
struct block_device *bdev = inode->i_bdev;
struct gendisk *disk = bdev->bd_disk;
fmode_t mode = file->f_mode;

和int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)相比
compat_ioctl少了inode参数, 可以通过filp->f_dentry->d_inode方法获得。
2011-08-27 16:28

http://blog.csdn.net/zhangqingsup/article/details/5721924

 

区别:

ioctl 和 unlock_ioctl

ioctl 不会lock_kernel()

 

compat_ioctl被使用在用户空间为32位模式,而内核运行在64位模式时。这时候,需要将64位转成32位。

 

引用

http://blog.chinaunix.net/u1/38994/showart_2248151.html

对几个ioctl执行顺序的分析

 

关于ioctl,unlocked_ioctl和compat_ioctl执行的顺序

对于ioctl操作,优先执行f_op->unlocked_ioctl,如果没有unlocked_ioctl,那么执行f_op->ioctl

sys_ioctl
==> vfs_ioctl
==> file_ioctl
==> do_ioctl
static long do_ioctl(struct file *filp, unsigned int cmd,
        unsigned long arg)
{
    int error = -ENOTTY;

    if (!filp->f_op)
        goto out;

    if (filp->f_op->unlocked_ioctl) { // 优先执行f_op->unlocked_ioctl
        error = filp->f_op->unlocked_ioctl(filp, cmd, arg);
        if (error == -ENOIOCTLCMD)
            error = -EINVAL;
        goto out;
    } else if (filp->f_op->ioctl) { // 如果没有unlocked_ioctl,那么执行f_op->ioctl
        lock_kernel();
        error = filp->f_op->ioctl(filp->f_path.dentry->d_inode,
                      filp, cmd, arg);
        unlock_kernel();
    }

 out:
    return error;
}

对于compat_sys_ioctl系统调用的使用比较麻烦一些,因为默认kernel是不将它built-in进内核的,
可以通过fs/Makefile看到如下定义obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o
对于CONFIG_COMPAT的定义于cpu体系结构有关,比如下面几个默认cpu配置了CONFIG_COMPAT=y
arch/x86_64/defconfig
arch/sparc64/defconfig
arch/powerpc/configs/ppc64_defconfig
arch/s390/defconfig
arch/parisc/configs/a500_defconfig
arch/mips/configs/ip32_defconfig

compat_sys_ioctl
filp->f_op->compat_ioctl(filp, cmd, arg);
如果该cmd在compat_ioctl中没有找到对应的处理,同时没有filp->f_op方法集[luther.gliethttp]
或者filp->f_op->ioct且filp->f_op->unlocked_ioctl均没有,那么将尝试调用vfs_ioctl,看看是不是一些经典的ioctl命令.

对于sound/core/control.c文件[luther.gliethttp]
#ifdef CONFIG_COMPAT
#include "control_compat.c"
#else
#define snd_ctl_ioctl_compat    NULL
#endif
下面的"controlC%i"声卡对应的控制节点fops的compat_ioctl,当没有定义CONFIG_COMPAT时,将被置为NULL
static const struct file_operations snd_ctl_f_ops =
{
    .owner =    THIS_MODULE,
    .read =        snd_ctl_read,
    .open =        snd_ctl_open,
    .release =    snd_ctl_release,
    .poll =        snd_ctl_poll,
    .unlocked_ioctl =    snd_ctl_ioctl,
    .compat_ioctl =    snd_ctl_ioctl_compat,
    .fasync =    snd_ctl_fasync,
};

 

open一个字符设备的过程是从
VFS层open系统调用 ===> def_chr_fops-->open ===> cdev->fops->open===> device specific operation

如果是同一类设备,比如系统中有多个framebuffer,那么就把共有的操作放在cdev->fops->open ,这时向系统注册的仅仅是这一个驱动程序;
将这类主设备号相同的一类设备(如/dev/fb0 /dev/fb1等)放在一个数组中,然后在cdev->fops->open根据次设备号作为Index来调用体现不同设备差异的那些操作,即 device specific operation , 这就是为什么framebuffer/block 等硬件驱动中实现的都不是file_operations这种操作,而是跟具体设备相关的那些操作。
这就是所谓的一类设备都应一种驱动。


可以认为大多数简单的设备,仅仅需要实现到cdev->fops->open 这个位置,等他们变得复杂,能够提炼出共性的时候就 需要实现到[红色device specific operation 这个位置。

 

对于ioctl操作,优先执行f_op->unlocked_ioctl,如果没有unlocked_ioctl,那么执行f_op->ioctl


在学习ARM开发中.ioctl在内2.6.32中。file_operatioins中还有ioctl.自己升级到2.6.36时,使用vim 查错源代码时,发现没有ioctl只有unlocked_ioctl与compat_ioctl函数了。

自己改写这个unlocked_ioctl函数,但是,不知如何用应用程序测试,
当在内核使用ioctl函数时,我在应用程序中使用ioctl(fd,"on"来测试是否调用了ioctl函数。
可是改成unlocked_ioctl函数时,使用unlocked_ioctl()函数时,提示没有这个函数,请问怎么办?
long  test_ioctl(struct file *filp,unsigned int cmd,unsigned long value){
        struct newdev *p = filp->private_data;
        printk("ioctl %X \n",p);
        switch(cmd){
                case 0:
                        p->on();break;
                case 1:
                        p->off();break;
                default:
                        printk("Unknow cmd\n";
                        return -EINVAL;
        }
        return 0;
}

struct file_operations fops = {
        .open = test_open,
        .unlocked_ioctl = test_ioctl,
};

void test_on(void){
        printk("test_on test\n";
}

void test_off(void){
        printk("test_off test \n";
}

void initial_device(struct newdev *d){
        d->on = test_on;
        d->off = test_off;
}


应用程序如下:

int main(int argc,char *argv[]){

        int fd;
        char buf[10];
        printf("1\n";
        printf("argc[%d]\n",argc);
        if (argc != 2){
                printf("Usage %s string \n",argv[0]);
                return -1;
        }
        printf("2\n";

        fd = open("/dev/test",O_RDWR);
        printf("3\n";

        if (fd < 0 ){
                printf("fd open errror\n";
                return -1;

        }
        printf("4\n";
        if (!strncasecmp(argv[1],"on",2))
                unlocked_ioctl(fd,0);
        if (!strncasecmp(argv[1],"off",3))
                unlocked_ioctl(fd,1);

        return 0;
}

root@xu-laptop:/usr/src/linux-2.6.36/drivers/new/10th# gcc -o app app.c
/tmp/cc4PWyCc.o: In function `main':
app.c.text+0xf1): undefined reference to `unlocked_ioctl'
app.c.text+0x12a): undefined reference to `unlocked_ioctl'
collect2: ld returned 1 exit status

root@xu-laptop:/usr/src/linux-2.6.36/drivers/new/10th# 为了把BKL从内核中慢慢去掉,加入了unlocked_ioctl,但是有很多地方都用到ioctl,所以一直保留着,直到b19dd42f的时候,最后移除了所有对ioctl的使用,才把ioctl从file_operations里面去掉。

0 0
原创粉丝点击