2014-12-05 5 views
7

Ich schreibe gerade ein Linux Kernel Module (LKM), das als Pseudo-Treiber dient - ich kann nicht herausfinden, wie ich IOCTL-Aufrufe zwischen LKM machen kann (wait.c) und das Programm auf Benutzerebene (user.c).Linux Kernel Modul/IOCTL: unangemessenes ioctl für Gerät

Die magische Nummer für den Gerätetreiber ist 0xBF - das LKM kommuniziert nicht mit einem physischen Block/Char Gerät, es ist einfach eine Übung. Von dem, was ich sagen kann, ist der IOCTL Anruf KERN_IOCTL_CREATE_EVENT nicht richtig formatiert & die magische Zahl ist falsch.

Der IOCTL-Aufruf, den ich zu verwenden ist versucht, ist:

#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); 

Fehler:

[fail]: KERN_IOCTL_CREATE_EVENT: Inappropriate ioctl for device 

Die Anwendung im Benutzermodus kann/öffnen ein Dateideskriptor auf das Gerät zeigen schließen: /dev/wait aber Die case/switch Anweisung akzeptiert den IOCTL-Aufruf nicht. Irgendwelche Vorschläge? Hier

ist die Ausgabe von # 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 

Das Testprogramm für die IOCTL ruft:

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 

Um die LKM zu testen - klar dmesg, kompilieren & user.cw/GCC ausführen:

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

Die Menge der Debugging-Fehler ist peinlich. Es tut mir leid, dass ich dies teile - und mir ist bewusst, dass dies dazu führen könnte, dass das Thema in Vergessenheit gerät.

# 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

Möglicherweise müssen Sie Ihre aktualisierten Kernel-Header installieren. Ohne dieses könnte das User Space Programm das korrekte ioctl nicht finden, aus irgendeinem Grund hatte ich ein ähnliches Problem auf Ubuntu und das einzige, was funktionierte, war die Installation der aktualisierten Kernel Header. – askb

+0

Ich habe den Kernel mit sudo make modules_install install aktualisiert - und das linux-headers-generic-Paket installiert - aktuelle Kernel-Version ist 3.13.11.11+ – Tyler

Antwort

2

Okay. Damit. Hier ist die Lösung.

Im Linux Kernel 2.6.x die Erklärung für _ioctl Anrufe geändert von

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

An:

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

Die Lösung ist somit:

... 
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

auch sicherstellen, dass diese file_operation implementieren wenn du 32-b machst es ruft einen 64-Bit-Kernel auf.

Das Symptom ist, dass Ihr ioctl Handler nie ausgeführt wird.