2014-12-05 229 views
7

我正在編寫一個用作僞驅動程序的Linux內核模塊(LKM) - 我無法弄清楚如何在LKM之間進行IOCTL調用(wait.c)和用戶級程序(user.c)。Linux內核模塊/ IOCTL:不適用於設備的ioctl

設備驅動程序的神奇數字是​​- LKM不與物理塊/字符設備通信,它只是一個練習。從我所知道的情況來看,對KERN_IOCTL_CREATE_EVENT的IOCTL調用沒有正確格式化&幻數不正確。

的IOCTL調用,我嘗試使用是:

#include <sys/ioctl.h> 
#define KERN_IOCTL_CREATE_EVENT _IOWR(WAIT_DEVICE_MAGIC, 1, int) 

int main(){ 
int ret; 
int fd; 
fd = open("/dev/wait", 0); 
if(fd < 0){ 
    return -1; 
} 
ret = ioctl(fd, KERN_IOCTL_CREATE_EVENT, 0); 

錯誤:

[fail]: KERN_IOCTL_CREATE_EVENT: Inappropriate ioctl for device 

用戶模式應用程序可以打開/關閉文件描述符指向設備:/dev/waitcase/switch聲明不接受IOCTL調用。有什麼建議麼?

這裏是# uname -a

Linux vagrant-ubuntu-trusty-64 3.13.11.11+ #1 SMP Mon Dec 1 20:50:23 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux 

wait.c

#include <linux/miscdevice.h> 
#include <linux/moduleparam.h> 
#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/string.h> 
#include <asm/uaccess.h> 
#include <linux/sched.h> 
#include <linux/ioctl.h> 
#include <linux/cdev.h> 
#include <linux/init.h> 
#include <linux/wait.h> 
#include <linux/fs.h> 

#include "wait.h" 

MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("Tyler Fisher <[email protected]>"); 
MODULE_DESCRIPTION("In-kernel wait queue"); 

static unsigned long event_table_size = 50; 
module_param(event_table_size, ulong, (S_IRUSR | S_IRGRP | S_IROTH)); 
MODULE_PARM_DESC(event_table_size, "Size of event table (i.e. how many processes can be blocking)"); 

/* IOCTL function headers */ 
static int wait_open(struct inode *, struct file *); 
static int wait_close(struct inode *, struct file *); 
static long wait_ioctl(struct inode *, struct file *, unsigned int, unsigned long); 

/* other function headers */ 
static long event_open(int event_id); 

/* file operations */ 
static struct file_operations wait_fops = { 
    .owner = THIS_MODULE, 
    .open = wait_open, 
    .release = wait_close, 
    .llseek = noop_llseek, 
    .unlocked_ioctl = wait_ioctl 
}; 

/* device handler */ 
static struct miscdevice wait_misc_device = { 
    .minor = MISC_DYNAMIC_MINOR, 
    .name = WAIT_DEVICE_NAME, 
    .fops = &wait_fops 
}; 

/* open wait device */ 
static int wait_open(struct inode *inode, struct file *file){ 
    dev_t node = iminor(inode); 
    if(MINOR(node) != WAIT_DEVICE_MINOR){ 
     return -ENODEV; 
    } 
    return 0; 
} 

static int wait_close(struct inode *inode, struct file *file){ 
    return 0; 
} 

static long wait_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long sub_cmd){ 
switch(cmd){ 
    case KERN_IOCTL_CREATE_EVENT: 
     printk(KERN_INFO "[wait device]: create event %lu\n", sub_cmd); 
     return event_open(sub_cmd); 

    default: 
     return -ENOENT; 
    } 
} 

static long event_open(int id){ 
    return 0; 
} 

static long __init wait_init(void){ 
    if(misc_register(&wait_misc_device) < 0){ 
     printk(KERN_ERR "[wait device] failed to register device\n"); 
     return -1; 
    } 
    printk(KERN_INFO "[wait device] has been registered\n"); 
    return 0; 
} 

static void __exit wait_exit(void){ 
    misc_deregister(&wait_misc_device); 
    printk(KERN_INFO "[wait device] has been unregistered\n"); 
} 

module_init(wait_init); 
module_exit(wait_exit); 

wait.h的輸出

#include <linux/ioctl.h> 

#define WAIT_DEVICE_NAME "wait" 
#define WAIT_DEVICE_MAGIC 0xBF 
#define WAIT_DEVICE_MAJOR 200 
#define WAIT_DEVICE_MINOR 0 

#define KERN_IOCTL_CREATE_EVENT  _IOWR(WAIT_DEVICE_MAGIC, 0x01, int) 

#define MAX_WAITING 5 

用於IOCTL測試程序調用:

user.c的

#include <sys/ioctl.h> 
#include <fcntl.h> 
#include <stdio.h> 

#define WAIT_DEVICE_MAGIC 0xBF 
#define KERN_IOCTL_CREATE_EVENT _IOWR(WAIT_DEVICE_MAGIC, 0x01, int) 
#define KERN_IOCTL_DESTROY_EVENT _IOWR(WAIT_DEVICE_MAGIC, 0x02, int) 
#define KERN_IOCTL_LOCK_EVENT  _IOWR(WAIT_DEVICE_MAGIC, 0x03, int) 
#define KERN_IOCTL_UNLOCK_EVENT _IOWR(WAIT_DEVICE_MAGIC, 0x04, int) 

int main(){ 
    int fd; 
    if(fd = open("/dev/wait", O_RDWR) < 0){ 
     perror("failed to open /dev/wait"); 
     return -1; 
    } 

    /* test IOCTL: event creation */ 
    if(ioctl(fd, KERN_IOCTL_CREATE_EVENT, 0) < 0){ 
     perror("[fail]: KERN_IOCTL_CREATE_EVENT"); 
     return -1; 
    } 
    return 0; 
} 

的Makefile

obj-m += wait.o 
CFLAGS_wait.o += -DDEBUG 

all: 
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 

clean: 
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 

爲了測試出LKM - 清晰的dmesg,編譯&執行user.cw/GCC:

# dmesg -c > /dev/null 2>&1 
# make 
# rmmod wait.ko 
# insmod wait.ko 
# gcc user.c -o user && ./user 

調試錯誤的數量令人尷尬。我對分享這件事感到不滿 - 並意識到這可能導致問題被關閉/降低爲遺忘。

# sh test.sh 
[+] cleared dmesg 
make -C /lib/modules/3.13.11.11+/build M=/home/vagrant/PROG40000-kernel-synchronization modules 
make[1]: Entering directory `/home/vagrant/ubuntu-trusty' 
    CC [M] /home/vagrant/PROG40000-kernel-synchronization/wait.o 
/home/vagrant/PROG40000-kernel-synchronization/wait.c:61:1: warning: initialization from incompatible pointer type [enabled by default] 
}; 
^ 
/home/vagrant/PROG40000-kernel-synchronization/wait.c:61:1: warning: (near initialization for ‘wait_fops.unlocked_ioctl’) [enabled by default] 
In file included from include/linux/moduleparam.h:4:0, 
       from /home/vagrant/PROG40000-kernel-synchronization/wait.c:11: 
/home/vagrant/PROG40000-kernel-synchronization/wait.c: In function ‘__inittest’: 
include/linux/init.h:297:4: warning: return from incompatible pointer type [enabled by default] 
    { return initfn; }  \ 
    ^
/home/vagrant/PROG40000-kernel-synchronization/wait.c:167:1: note: in expansion of macro ‘module_init’ 
module_init(wait_init); 
^ 
    Building modules, stage 2. 
    MODPOST 1 modules 
    CC  /home/vagrant/PROG40000-kernel-synchronization/wait.mod.o 
    LD [M] /home/vagrant/PROG40000-kernel-synchronization/wait.ko 
make[1]: Leaving directory `/home/vagrant/ubuntu-trusty' 
[--dmesg--] 
[13112.810008] [wait device] has been unregistered 
[13112.819049] [wait device] has been registered 
[-/dmesg--] 
[+] compiled user-mode program 
----- 
[fail]: KERN_IOCTL_CREATE_EVENT: Inappropriate ioctl for device 
[fail]: KERN_IOCTL_CREATE_EVENT: Inappropriate ioctl for device 
[+] executed user-mode program 
----- 
[--dmesg--] 
[13112.810008] [wait device] has been unregistered 
[13112.819049] [wait device] has been registered 
[13112.893049] SOMEONE DARE READ FROM ME!? 
[13112.893057] [wait device] invalid magic number: 0:0:191 
[13112.893535] [wait device] invalid magic number: 0:0:191 
[-/dmesg--] 
+0

您可能需要安裝更新的內核頭文件。如果沒有這個,用戶空間程序無法找到正確的ioctl,由於某種原因,我在Ubuntu上遇到類似的問題,唯一有用的工作是安裝更新的內核頭文件。 – askb 2014-12-05 13:30:16

+0

我使用sudo make modules_install install更新了內核 - 並安裝了linux-headers-generic軟件包 - 當前內核版本爲3.13.11.11+ – Tyler 2014-12-05 15:06:13

回答

2

好的。所以。這是解決方案。

在Linux內核2.6中。X爲_ioctl電話申報從

static long wait_ioctl(struct inode *, struct file *, unsigned int, unsigned long); 

更改爲:

static long wait_ioctl(struct file *, unsigned int, unsigned long); 

修復的方法是這樣的:

... 
static long wait_ioctl(struct file *, unsigned int, unsigned long); 
... 
static long wait_ioctl(struct file *file, unsigned int cmd, unsigned long sub_cmd){ 
    if(_IOC_TYPE(cmd) != WAIT_DEVICE_MAGIC){ 
     printk(KERN_INFO "[wait device] invalid magic number: %u:%u:%u", _IOC_TYPE(cmd), cmd, WAIT_DEVICE_MAGIC); 
     return -ENOTTY; 
    } 
.... 
0

.compat_ioctl

還要確保實現這一file_operation如果你正在製作32-b它調用一個64位內核。

症狀是您的ioctl處理程序從不運行。

相關問題