Командата ioctl на Linux се променя между потребителско пространство и пространство на ядрото

Не съм сигурен дали някой има някакви идеи тук, не съм виждал това преди. Пиша мъниче, за да тествам моя модул на ядрото, когато проверявам стойността на командата в потребителското пространство, получавам различна стойност от тази, когато погледна в пространството на ядрото.

Част от мъничето:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "ain.h"
#include "ain_ioctl.h"
#define AI_DEVICE   "/dev/ain"

void main()
{
    int fd, error, ioctl_par = 0;
    char* dev;
    long ret;

    dev = AI_DEVICE;

    printf("Starting driver test\n");

    fd = open(dev, O_RDWR);
    if (fd < 0) {
    /* Failed to open -> Print error-message and exit */
    printf("%s failed to open, error: %s\n", dev, strerror(errno));
    }

    printf("Doing the IOCTL now... cmd: %d\n", AIN_IOC_GET_AN0_CONF);
    fflush(stdout);

    ret = ioctl(fd, AIN_IOC_GET_AN0_CONF, &ioctl_par);

Файлът ain_ioctl.h:

#define AIN_IOC_MAGIC  'e'
#define AIN_IOC_GET_AN0_CONF    _IOR(AIN_IOC_MAGIC, 46, int)

Рутината ioctl в ядрото:

int ain_ioctl (struct inode * inodep, struct file * filp, unsigned int cmd, unsigned long arg)
{
    printk("In the ain_ioctl function, cmd: %d. type: %d, dir: %d, nr: %d, size: %d\n", 
        cmd, _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));

    printk("Testing against command: %d. type: %d, dir: %d, nr: %d, size: %d\n",
        AIN_IOC_GET_AN0_CONF, _IOC_TYPE(AIN_IOC_GET_AN0_CONF), _IOC_DIR(AIN_IOC_GET_AN0_CONF), 
        _IOC_NR(AIN_IOC_GET_AN0_CONF), _IOC_SIZE(AIN_IOC_GET_AN0_CONF));

Сега бих очаквал идентичен изход в печатното пространство на потребителя, както в ядрото. И в първия набор отпечатъци в ядрото към втория. Това обаче не е това, което виждам...

Изход:

mike@linux-4puc:~> ./a.out 
Starting driver test
Doing the IOCTL now... cmd: -2147195602

mike@linux-4puc:~> dmesg | tail
[75253.205136] In the ain_ioctl function, cmd: -1078168112. type: 117, dir: 2, nr: 208, size: 16316
[75253.205140] Testing against            cmd: -2147195602. type: 101, dir: 2, nr: 46, size: 4

Някой има ли идеи защо командата ми действа по различен начин, когато я предам на ядрото чрез командата ioctl, отколкото когато просто проверявам стойностите, като ги кодирам твърдо (както правя в моите разпечатки)?

Единствените предупреждения, които виждам, когато изграждам, изглежда нямат нищо общо с ioctl извикванията:

makedepend: warning: ignoring option -Wall 
makedepend: warning: ignoring option -Wall 
makedepend: warning: ain.c (reading /usr/src/linux/include/linux/compiler-gcc.h), line 94: incomplete include == "#include gcc_header(__GNUC__)" 
makedepend: warning: ain.c (reading /usr/src/linux/include/linux/string.h, line 13): cannot find include file "stdarg.h" 

Благодаря.


person Mike    schedule 15.08.2012    source източник


Отговори (2)


-1078168112 (защо не ги отпечатвате в шестнадесетичен?) изглежда като указател на стека. Вероятно &ioctl_par. Това предполага, че вашият ioctl метод получава различни параметри от очакваните.

В текущия източник на ядрото виждам ioctl методи, приемащи 3 параметъра, а не 4. Ioctl с 4 аргумента изглежда е по-стар интерфейс.

Получавате ли някакви предупреждения по време на компилирането на модула? Обърнете им внимание!

person Alan Curry    schedule 15.08.2012
comment
Нямам предупреждения за ioctl. Само относно опциите за изграждане, ще ги включа в първоначалния въпрос. Стойностите в шестнадесетичен са: 0x8004652e = -2147195602 0xbf9c28e0 = -1078168112 - person Mike; 16.08.2012

Отговорът на Алън Къри не беше пълният „правилен“ отговор, но ме доведе до решението. Шестнадесетичната стойност на командата беше далеч, така че погледнах други извиквания на ioctl в ядрото.

Системата, която имам, е базирана на по-старо ядро ​​2.4X и го актуализирам за 3.1. Проблемът тук е списъкът с параметри за извикването на ioctl. Наличието на указател на inode в списъка с параметри причиняваше проблема, тъй като той приемаше указателя на файла за команда.

Правилно решение:

long ain_ioctl (struct file * filp, unsigned int cmd, unsigned long arg) { 
    ...
person Mike    schedule 16.08.2012