• ioctl cmd 不能等于 2 的小问题


    平时很少写内核模块,今天遇到一个小问题,写了一个内核模块,想在用户态通过 ioctl与该模块进行交互,于是在内核模块和用户态程序中定义了相同的枚举变量,如下所示:

    enum {
       CMD_1,
       CMD_2,
       CMD_3,
       CMD_4,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    很明显,CMD_3等于 2, 但在调用 ioctl(fd, CMD_3, …)后,发现该请求一直没有到达内核模块,折腾了好长时间才知道 ioctlcmd不能随意指定,比如 2就是一个特殊的值。在 ioctl请求到达内核模块之前,内核中的其他代码还进行了处理,如下所示(4.19内核):

    int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
             unsigned long arg)
    {
        int error = 0;
        int __user *argp = (int __user *)arg;
        struct inode *inode = file_inode(filp);
    
        switch (cmd) {
        case FIOCLEX:
            set_close_on_exec(fd, 1);
            break;
    
        case FIONCLEX:
            set_close_on_exec(fd, 0);
            break;
    
        case FIONBIO:
            error = ioctl_fionbio(filp, argp);
            break;
    
        case FIOASYNC:
            error = ioctl_fioasync(fd, filp, argp);
            break;
    
        case FIOQSIZE:
            if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode) ||
                S_ISLNK(inode->i_mode)) {
                loff_t res = inode_get_bytes(inode);
                error = copy_to_user(argp, &res, sizeof(res)) ?
                        -EFAULT : 0;
            } else
                error = -ENOTTY;
            break;
    
        case FIFREEZE:
            error = ioctl_fsfreeze(filp);
            break;
    
        case FITHAW:
            error = ioctl_fsthaw(filp);
            break;
    
        case FS_IOC_FIEMAP:
            return ioctl_fiemap(filp, arg);
    
        case FIGETBSZ:
            /* anon_bdev filesystems may not have a block size */
            if (!inode->i_sb->s_blocksize)
                return -EINVAL;
            return put_user(inode->i_sb->s_blocksize, argp);
    
        case FICLONE:
            return ioctl_file_clone(filp, arg, 0, 0, 0);
    
        case FICLONERANGE:
            return ioctl_file_clone_range(filp, argp);
    
        case FIDEDUPERANGE:
            return ioctl_file_dedupe_range(filp, argp);
    
        default:
            if (S_ISREG(inode->i_mode))
                error = file_ioctl(filp, cmd, arg);
            else
                error = vfs_ioctl(filp, cmd, arg);
            break;
        }
        return error;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    在上面的代码中,进入内核模块的函数是 file_ioctl()vfs_ioctl(),但由于 FIGETBSZ的值等于 2,因此当传入的 cmd等于 2时,就无法进入内核模块。具体可以参考这个问题:ioctl is not called if cmd 2

    解决办法是使用 ioctl提供的宏(比如_IO_IOR_IOW, _OIWR)来定义 cmd。典型的用法如 KVM提供给用户态程序(比如 QEMU)的 ioctl cmd,如下所示:

    #define KVMIO 0xAE
    
    #define KVM_CREATE_VCPU           _IO(KVMIO,   0x41)
    #define KVM_RUN                   _IO(KVMIO,   0x80)
    #define KVM_GET_REGS              _IOR(KVMIO,  0x81, struct kvm_regs)
    #define KVM_SET_REGS              _IOW(KVMIO,  0x82, struct kvm_regs)
    #define KVM_CREATE_DEVICE         _IOWR(KVMIO,  0xe0, struct kvm_create_device)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    简单场景的话,可以像下面这样使用:

    #define CMD_1 _IO(’X', 0)
    #define CMD_2 _IO(‘X', 1)
    #define CMD_3 _IO(‘X', 2)
    #define CMD_4 _IO(‘X', 3)
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    分布式文件存储 - - - MinIO从入门到飞翔
    OpenCV(四十四):亚像素级别角点位置优化
    Java 中通过 key 获取锁
    Hqst网络变压器读书笔记 :公司发展中的首要因素
    Linux 下搭建 Hive 环境
    云原生之史上最全K8S环境搭建(强烈建议收藏)
    PL/SQL工具下载地址
    LeetCode646-最长数队链
    图文结合丨Prometheus+Grafana+GreatSQL性能监控系统搭建指南(上)
    android 后台运行service实现和后台的持续交互
  • 原文地址:https://blog.csdn.net/choumin/article/details/128028134