2012-03-13 2 views
2

Я делаю простой простой драйвер символов, который, как предполагается, должен писать на мое устройство char/dev/coffee_bean, и при чтении он должен отображать строку «Привет!». в консоли. Я читаю с устройства через «cat/dev/coffee_bean», вместо этого моя система сбрасывается и сбрасывается. Bellow - мой исходный код. Спасибо за помощь.Сбой аватара простого символа

#include <linux/kernel.h> 
#include <linux/module.h> 
#include <linux/fs.h> 
#include <linux/cdev.h> 
#include <linux/kdev_t.h> 
#include <linux/types.h> 
#include <linux/completion.h> 
#include <linux/slab.h> 
#include <asm/uaccess.h> 
#include <linux/semaphore.h> 
MODULE_LICENSE("Dual BSD/GPL"); 

#define DEVICE_NAME "coffee_grinds" 
#define COUNT 4 
#define FIRST_MINOR 0 
#define CONST_QUANTUM 4000 
#define CONST_QSET 4000 

int test; 

module_param(test, int, S_IRUGO); 

struct my_char_structure{ 
    struct cdev my_cdev; 
    struct semaphore sem; 
    unsigned int access_key; 
    unsigned long size; 
}; 

static dev_t dev_num; 

int dev_open(struct inode *in_node, struct file *filp){ 
    struct my_char_structure *my_dev; 

    my_dev = container_of(in_node->i_cdev, struct my_char_structure, my_cdev); 
    filp->private_data = my_dev; 
    return 0; 
} 

int dev_release(struct inode *inode, struct file *filp){ 
    return 0; 
} 

ssize_t dev_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp){ 
    struct my_char_structure *my_dev = filp->private_data; 
    ssize_t retval = -ENOMEM; /* value used in "goto out" statements */ 
    char *my_string; 
    int counting; 
    printk(KERN_ALERT "Write was accessed, Lol"); 
    if (down_interruptible(&my_dev->sem)) 
     return -ERESTARTSYS; 
    my_string = kmalloc(count,GFP_KERNEL); 
    counting = copy_from_user(my_string,buff,count); 
    printk(KERN_ALERT "You wrote %s",my_string); 
    kfree(my_string); 
    up(&my_dev->sem); 

    printk(KERN_ALERT "We wrote %d bytes",counting); 
     return retval; 
    // Here is some experimental code 
} 

    ssize_t dev_read(struct file *filp, char __user *buff, size_t count, loff_t *offp){ 
     struct my_char_structure *my_dev = filp->private_data; 
     ssize_t retval = 0; 
     char *my_string; 

     printk(KERN_ALERT "Read was accessed Lol"); 

     if (down_interruptible(&my_dev->sem)) 
      return -ERESTARTSYS; 
     my_string = "Hi there!"; 
     copy_to_user(buff,my_string,10); 
     up(&my_dev->sem); 
     return retval; 

    } 

struct file_operations fops = { 
    .owner = THIS_MODULE, 
    .read = dev_read, 
    .write = dev_write, 
    .open = dev_open, 
    .release= dev_release, 
}; 

int start_mod(void){ 
    //Because we are dealing with a fictitious device, I want 
    //the driver to create my two devices with arbitrarly 
    //assigned major numbers. 
    static struct my_char_structure Dev; 
    static struct my_char_structure *my_dev = &Dev; 
    int err; 

    alloc_chrdev_region(&dev_num, FIRST_MINOR, COUNT, DEVICE_NAME); 

    sema_init(&(my_dev->sem),1); 

    cdev_init(&(my_dev->my_cdev), &fops); 
    my_dev->my_cdev.owner = THIS_MODULE; 
    my_dev->my_cdev.ops = &fops;// fops is my file operations struct 

    err = cdev_add(&my_dev->my_cdev, dev_num, COUNT); 
    if(err) 
     printk(KERN_ALERT "There was an error %d.",err); 
    printk(KERN_ALERT " insmod to major number %d",MAJOR(dev_num)); 

    return 0; 
} 

void end_mod(void){ 

    unregister_chrdev_region(dev_num, COUNT); 

} 

module_init(start_mod); 
module_exit(end_mod); 

ответ

2

Глядя на полный код, который вы опубликовали сейчас, я не вижу очевидной причины аварии. То, что вы делаете, сделано в других драйверах.

Всего несколько наблюдений.

Существует очень небольшая проверка ошибок. Это вас укусит, потому что успешное выполнение следующей вещи обычно зависит от успешного исполнения предыдущей вещи как предварительного условия.

Кроме того, когда вы дойдете до того, что функция чтения вызывается без какого-либо сбоя, вы обнаружите, что она ничего не производит, потому что вы возвращаете 0 и не перемещаете смещение! Большинство программ интерпретируют нулевой возврат как конец файла.

Вы должны соблюдать размер буфера, который передается в противном случае, вы повредите пространство пользователя. Программа cat может не делать read(fd, buf, 5); (обратите внимание, что 5 меньше, чем 10 байтов, которые вы копируете в пользовательское пространство), но что-то может.

Кстати, copy_to_user и copy_from_user являются функциями, которые вы должны проверить на неудачу также и вернуть -EFAULT пространство пользователя, говоря о вызове приложения оно передается в плохом районе.

Для отладки аварии существуют два традиционных подхода. Один из них заключается в том, чтобы добавить больше операторов printk. В блоке кода, где нет ветвей, и печать не буферизована, если один оператор печати выводит выходные данные перед сбоем, а другой - нет, авария находится где-то между ними.

Другой метод заключается в интерпретации дампа сбоя: машинные регистры, байты, окружающие указатель команд, трассировку вызова и т. Д. Если у вас есть эта информация из аварии, вы обычно можете определить, где находится авария, и, посмотрев на машинный код и значения регистров, вы можете догадаться, что делают переменные C и структуры данных.

Удачи.

+0

Спасибо Kaz, я отлаживал свою программу, и авария была связана с тем, как я выделил память для своей строки. Устройство больше не сбой, но вместо этого я получаю ошибку сегментации, которая исходит от функции copy_to_user(). Я подозреваю, что я получаю эту ошибку, потому что я не использую переданную переменную count. Спасибо пакет за то, что нашли время, чтобы посмотреть мой код !!! –

+1

Но у вас есть выделение в рутине записи; вы сказали, что он рухнул на чтение. Основная проблема в процедуре записи заключается в том, что 'kmalloc' очень ограничен в том, насколько большой блок он может вернуть. Он возвращает физически смежные страницы (которые являются ценным ресурсом). Но аргумент 'read' может быть очень большим. То есть в общем, использование значения из пользовательского пространства в качестве размера 'kmalloc' (кроме, скажем, корневой привилегированной серверной программы, которая знает, что она делает) не является отличной идеей. Будьте готовы к возврату null, даже если есть много памяти. – Kaz

+0

Ну, я хочу только напечатать что-то маленькое, как «Привет там», и выделить байты с помощью kmalloc, которые остановили его от сбоя. Прямо сейчас я не ищу полностью работоспособного драйвера для реализации записи. Я просто хочу сначала прочитать работу. Это мой первый драйвер, написанный, который реализует чтение/запись. Я только начал учиться 2 недели назад. –

3

Все может пойти не так, как только dev_read будет достигнута. Вы видели сообщение KERN_ALERT на консоли?

Очевидно, что это не все, что есть в вашем исходном коде, потому что модуль инициализирован, зарегистрированное устройство символов и есть другие функции, такие как открытая процедура. Что заставляет вас думать, что ошибка находится в dev_read только потому, что чтение с устройства приводит к сбою машины?

sizeof(my_string) is sizeof(char *), который составляет 4 или 8. Вы берете размер указателя. Если вы находитесь на 64-битном ядре, вы получите не больше Hi there без !, если у вас достаточно отлаженная отладка, чтобы зайти так далеко.)

I.e. очевидно, что вы можете извлечь пользу из учебников по основам C, как разница между массивами и указателями.

+0

Ой, я сделал эту ошибку, прежде чем взять размер указателя, я забыл об этом. Я добавлю остальную часть источника. –

1

не может сказать, просто взглянув на код. Вы можете сделать себе одолжение для проверки ошибок.Во всех местах, где условия не работают, вы можете использовать KERN_ERR для печати ошибок, и вы можете добавить goto OUT (где OUT: return -1), чтобы были минимальные шансы на сбой. Это может определенно сказать вам, что там, где это неправильно. Также сначала создайте только функцию записи и проверьте, работает ли она корректно или нет, а затем запустите функцию dev_read.

Смежные вопросы