2012-01-28 3 views
2

Я пробовал следующий код много раз.Код для записи и чтения в файле устройства из модуля ядра?

#include<linux/module.h> 
#include<linux/kernel.h> 
#include<linux/fs.h> 
#include<linux/cdev.h> 
#include<asm/uaccess.h> 
#include<linux/semaphore.h> 

MODULE_LICENSE("DUAL BSD/GPL"); 
static int dev_open(struct inode *,struct file *); 
static int dev_release(struct inode *,struct file *); 
ssize_t dev_read(struct file *,char *, size_t ,loff_t *); 
ssize_t dev_write(struct file *,const char *,size_t ,loff_t *); 

static int major; 
int dev_major = 0; 
int dev_minor = 0; 
struct cdev *cdev; 

struct device { 
    char array[100]; 
    struct semaphore sem; 
}chr_arr; 

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

ssize_t dev_read(struct file *filp,char *buf,size_t count,loff_t *offset) 
{ 
    int i; 
    i=copy_to_user(buf,chr_arr.array,count); 
    printk(KERN_ALERT"buff:%s",buf); 
    return i; 
} 

ssize_t dev_write(struct file *filp,const char *buf,size_t count,loff_t *offset) 
{ 
    //printk(KERN_ALERT"\nsorry,byebye"); 
    int j; 
    //msg_ptr = kmalloc(count,GFP_KERNEL); 
    //for(j=0;j<count;j++) 
    if(count>100) 
     return -1; 
    j = copy_from_user(chr_arr.array,buf,count); 
    //printk(KERN_ALERT"msg_ptr:%s",msg_ptr); 
    return j; 
} 

static int dev_open(struct inode *inode,struct file *filp) 
{ 
    filp->private_data = inode->i_cdev; 
    if(down_interruptible(&chr_arr.sem)) 
    { 
     printk(KERN_INFO " could not hold semaphore"); 
     return -1; 
    } 
    //printk(KERN_ALERT"ah ha the device is open !now we can go further"); 
    return 0; 
} 

static int dev_release(struct inode *inode,struct file *filp) 
{ 
    up(&chr_arr.sem); 
    //module_put(THIS_MODULE); 
    return 0; 
} 

static int init_device(void) 
{ 
    int result; 
    dev_t dev_no,dev; 
    result = alloc_chrdev_region(&dev_no,0,1,"chr_dev"); 
    if(result < 0) 
    { 
     printk("sorry no major number left"); 
     return result; 
    } 
    major = MAJOR(dev_no); 
    dev = MKDEV(major,0); 
    cdev = cdev_alloc(); 
    cdev->ops = &dev_ops; 
    sema_init(&chr_arr.sem,1); 
    printk("the major number allocated is %d\n",major); 
    result = cdev_add(cdev,dev,1); 
    if(result < 0) 
    { 
     printk(KERN_INFO "Unable to allocate cdev"); 
     return result; 
    } 
    return 0; 
} 

static void clean_device(void) 
{ 
    cdev_del(cdev); 
    unregister_chrdev_region(major,1); 
} 

module_init(init_device); 
module_exit(clean_device); 

, но это дает мне следующее предупреждение.

CC [M] /home/karan/practice/scrw/scrw1.o 
In file included from /usr/src/linux-2.6.34.10-0.6/arch/x86/include/asm/uaccess.h:571:0, 
      from /home/karan/practice/scrw/scrw1.c:4: 
In function ‘copy_from_user’,inlined from ‘write’ at /home/karan/practice/scrw/scrw1.c:43:6: 
/usr/src/linux-2.6.34.10-0.6/arch/x86/include/asm/uaccess_32.h:212:26: warning: call to ‘copy_from_user_overflow’ declared with attribute warning: copy_from_user() buffer size is not provably correct 
Building modules, stage 2. 
MODPOST 1 modules 
CC  /home/karan/practice/scrw/scrw1.mod.o 
LD [M] /home/karan/practice/scrw/scrw1.ko 

, а затем, когда я пытаюсь написать эхо привет>/DEV/my_dev экран замирает после 30 секунд или около того.

+2

не должен ли вы проверить на счет <100? – ypnos

+0

@ypnos thats ok, но его не работает всякий раз, когда я нахожу команду эха, которая зависает через несколько секунд .... – karan421

+0

Проблема, вероятно, лежит где-то в другом месте. Можете ли вы показать больше своего кода? Вы также можете попытаться перекомпилировать ваше ядро ​​с включенными параметрами отладки, таким образом вы можете получить трассировку стека, когда произойдет замораживание. – ldx

ответ

6

Проблема заключается в том, что вы должны вернуть количество байтов, считанных/записанных в ваших методах чтения/записи, возвращаемое значение copy_ {from, to} _user() равно 0, если все пойдет хорошо. Возврат, например. подсчитывать в методе записи, если копирование успешно:

unsigned long ret; 
printk(KERN_INFO "Inside write \n"); 
if (count > sizeof(char_arr.array) - 1) 
    return -EINVAL; 
ret = copy_from_user(char_arr.array, buff, count); 
if (ret) 
    return -EFAULT; 
char_arr.array[count] = '\0'; 
return count; 

Вы также должны убедиться в том, что оконечное «\ 0» символа добавляется при копировании в буфер (если вы хотите иметь дело только со строками). Если это двоичные данные, вы имеете дело с сохранением его длины в своей структуре.

Пример чтения метод:

ssize_t dev_read(struct file *filp,char *buf,size_t count,loff_t *offset) 
{ 
    int len = count >= strlen(chr_arr.array) ? strlen(chr_arr.array) : count; 

    if (*offset >= strlen(chr_arr.array)) 
     return 0; 

    if (copy_to_user(buf,chr_arr.array,len)) 
     return -EFAULT; 

    return len; 
} 

Edit: перепутались пример кода, фиксируя его.

Редактировать2: пример метода чтения.

+0

теперь записывать функцию работает нормально, но функция чтения не ... всякий раз, когда я использую cat/dev/my_dev, он читает мгновенно, я пробовал с возвратом count a dwithout также ..... пожалуйста, помогите – karan421

+0

Это потому, что вы должны вернуть 0 после того, как пользователь доходит до конца вашего устройства. Вы можете использовать смещение для сохранения текущей позиции. – ldx

+0

Я думаю, что когда любой пользователь пишет hi (echo hi>/dev/my_dev) в файле устройства, он не будет идти в конец файла устройства (пожалуйста, исправьте меня, если я ошибаюсь) .... и как я могу использовать смещение не могли бы вы показать мне коды ... действительно спасибо вам за энтузиазм и интерес ... – karan421