使用我的char驱动程序时出现分段错误

时间:2017-04-21 15:42:37

标签: c linux char driver

我正在尝试编写一个名为my_module的char驱动程序。对于我想以下列方式行动的每一台设备:

  • 如果我是第一次打开设备的文件,我正在分配内存 对于结构体,设备文件中的“private_data”字段稍后会指向该字段。

  • 如果我之后打开设备的文件,我将继续使用“private_data”指向的相同结构

问题:当我第二次打开文件时,我遇到了分段错误。如果每次使用“open”时都为结构重新分配内存,则没有错误。

我做错了什么?

/* my_module.c: Example char device module.
    *
    */
    /* Kernel Programming */
    #define MODULE
    #define LINUX
    #define __KERNEL__

    #include <linux/kernel.h>   
    #include <linux/module.h>
    #include <linux/fs.h>               
    #include <asm/uaccess.h>
    #include <linux/errno.h>  
    #include<linux/slab.h> /* included for the purpose of using kmalloc and kfree */

    #include "my_module.h"

    #define CAN_READ 1

    #define CANT_READ -1

    #define CAN_WRITE 1

    #define CANT_WRITE -1

    #define MY_DEVICE "my_device"

    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("Anonymous");

    #define BUF_LEN 4096


    /* globals */
    int my_major = 0; /* will hold the major # of my device driver */
    int can_read = CANT_READ;
    int can_write = CANT_WRITE;
    char * buffp = NULL;




    struct file_operations my_fops = {
    .open = my_open,
    .release = my_release,
    .read = my_read,
    .write = my_write,
    .ioctl = my_ioctl,
    .owner = THIS_MODULE
    };

    typedef struct driver_t {
    int can_read;
    int can_write;
    int curr_index_write_d;
    int curr_index_read_d;
    char * d_ptr;
    } Driver;



    Driver * driverCreate( char * buffer, int can_read_arg, int can_write_arg ) {

    Driver * driver = (Driver*)kmalloc(sizeof(*driver),GFP_KERNEL);

    if(!driver){
        return NULL;
    }
    driver->curr_index_write_d=0;
    driver->curr_index_read_d=0;
    driver->d_ptr=buffer;
    driver->can_read=can_read_arg;
    driver->can_write=can_write_arg;
    return driver;
    }










    int init_module(void)
    {
    //printk(KERN_WARNING "start of module! ");
    my_major = register_chrdev(my_major, MY_DEVICE, &my_fops);

    if (my_major < 0)
    {
    //printk(KERN_WARNING "can't get dynamic major\n");
        return my_major;
    }

    //
    // do_init();
    //
    return 0;
    }


    void cleanup_module(void)
    {
    //printk(KERN_WARNING "end of module! ");
    unregister_chrdev(my_major, MY_DEVICE);

    //
    // do clean_up();
    //
    return;
    }


    int my_open(struct inode *inode, struct file *filp)
    {
    if(MOD_IN_USE>1) {
        return 0;
    }
    if (filp->f_mode & FMODE_READ)
    {
        can_read = CAN_READ;

    }

    if (filp->f_mode & FMODE_WRITE)
    {
        can_write = CAN_WRITE;
    }
    char * ptr = kmalloc(BUF_LEN, GFP_KERNEL);
    if (!ptr) {
        return my_major;
    }
    Driver * driver = driverCreate(ptr,can_read,can_write);
    if (!driver) {
        return my_major;
    }
    filp->private_data = driver;
    MOD_INC_USE_COUNT;
    return 0;
    }










    int my_release(struct inode *inode, struct file *filp)
    {
        /*
    if(MOD_IN_USE>1) {
        printk(KERN_WARNING "\nclose: MOD IN USE: %d\n", (int)MOD_IN_USE);
        MOD_DEC_USE_COUNT;
        return 0;
    }
    printk(KERN_WARNING "\nclose:(suupose to be 1) MOD IN USE: %d\n", (int)MOD_IN_USE);
    Driver * d_ptr = (Driver*)(filp->private_data);
    char * ptr = d_ptr->d_ptr;

    if (filp->f_mode & FMODE_READ)
    {
        d_ptr->can_read = CANT_READ;
        can_read = CANT_READ;
    //
    // handle read closing
    // 
    }

    if (filp->f_mode & FMODE_WRITE)
    {
        d_ptr->can_write = CANT_WRITE;
        can_write = CANT_WRITE;
        //
        // handle write closing
        //
    }

    if(ptr != NULL) {
        kfree(ptr);
        kfree(filp->private_data);
        filp->private_data=NULL;
        printk( KERN_WARNING "Memory is now free ");
    }
    else {
        printk( KERN_WARNING "No memory to free ");
    }
    */
    return 0;
    }












    ssize_t my_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
    {

    Driver * d_ptr = (Driver*)(filp->private_data);
    char * ptr = d_ptr->d_ptr;

    int curr_index_write = d_ptr->curr_index_write_d;
    int curr_index_read = d_ptr->curr_index_read_d;

    if(d_ptr->can_read == CANT_READ) {
        return 0;
    }



    if( curr_index_write - curr_index_read == 0 ) {

        return 0;
    }

    int length = (count >= (curr_index_write - curr_index_read) ? 
        (curr_index_write - curr_index_read) : count  );

    copy_to_user((char*)buf,(ptr+curr_index_read),length);


    d_ptr->curr_index_read_d = curr_index_write;


    return length;
    //
    // Do read operation.
    // Return number of bytes read.

    }


    ssize_t my_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
    {
    Driver * d_ptr = (Driver*)(filp->private_data);

    int curr_index_write = d_ptr->curr_index_write_d;

    char * ptr = d_ptr->d_ptr;    

    if(can_write == CANT_WRITE) {
        return 0;
    }

    if( BUF_LEN < curr_index_write + count ) {
        return -ENOMEM;
    }

    copy_from_user((ptr+curr_index_write),(char*)buf,count);

    d_ptr->curr_index_write_d = curr_index_write + count;

    return count;

    //
    // Do write operation.
    // Return number of bytes written.
    }


    int my_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
    {

    if(filp->private_data==NULL) {
        return 0;
    }
    Driver * d_ptr = (Driver*)(filp->private_data);

    switch(cmd)
    {
        case MY_RESET:

        d_ptr->curr_index_write_d = 0;
        d_ptr->curr_index_read_d = 0;
    //
    // handle OP 1.
    //
        break;
        case MY_RESTART:

        d_ptr->curr_index_read_d = 0;
    //
    // handle OP 1.
    //
        break;

        default:
        return -ENOTTY;
    }

    return 0;
    }

1 个答案:

答案 0 :(得分:0)

而不是这一行

  driver->d_ptr=buffer;

尝试

   driver->d_ptr=strdup(buffer);

请记住,d_ptr是指向char的指针。它首先需要内存分配并复制到它。 strdup()完成了这项工作。