Код для записи и чтения файла устройства из модуля ядра? - PullRequest
2 голосов
/ 28 января 2012

Я много раз пробовал следующий код.

#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

и затем, когда я пытаюсь написать echo hi> / dev / my_dev, экран зависает примерно через 30 секунд.

1 Ответ

6 голосов
/ 29 января 2012

Проблема в том, что вы должны возвращать количество байтов, прочитанных / записанных в ваших методах чтения / записи, возвращаемое значение 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;
}

Редактировать: испортил пример кода, исправив его.

Edit2: пример метода чтения.

...