Dr.Knowitall
Dr.Knowitall

Reputation: 10468

Simple character driver crash

I'm making a simple a simple character driver that is suppose to write to my char device "/dev/coffee_bean" and when read from, it should display the string "Hi There!" in the console. I read from the device via "cat /dev/coffee_bean", instead my system crashes and resets. Bellow is my source code. Thanks for help.

#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);

Upvotes: 2

Views: 2463

Answers (3)

mannukaushikece
mannukaushikece

Reputation: 11

cannot tell by just looking at the code.you can do yourself a favour for checking errors.At all the places where conditions ca fail you can use KERN_ERR to print errors and you can add goto OUT(where OUT:return -1) so that there will be minimal chances of crashing.This can definitely tell you that where it is wrong.Also first create only write function and check whether it is working correctly or not and then start making dev_read function.

Upvotes: 1

Kaz
Kaz

Reputation: 58500

Looking at the full code you have posted now, I don't see any obvious cause for the crash. The things you are doing are done in other drivers.

Just some observations.

There is very little error checking. That will bite you because the successful execution of the next thing generally depends on the successful execution the previous thing as a precondition.

Also, when you do get to the point that the read function is called without any crash, you will find that it doesn't produce anything because you return 0 and do not move the offset! Most programs will interpret the zero return as end-of-file.

You have to honor the buffer size that is passed in otherwise you will corrupt user space. The cat program might not do a read(fd, buf, 5); (note that 5 is less than the 10 bytes you are copying to user space) but something might.

By the way, copy_to_user and copy_from_user are functions you have to test for failure also and return -EFAULT to user space, telling the calling application it passed in a bad area.

To debug the crash, there are two traditional approaches. One is to add more printk statements. In a block of code where there are no branches, and printing isn't buffered, if one print statement produces output prior to the crash but another one doesn't, the crash is somewhere between them.

The other technique is to interpret the crash dump: machine registers, byte surrounding the instruction pointer, call trace, etc. If you have that info from the crash, you can usually pinpoint where the crash is and by looking at the machine code and the values of registers, you can guess what the C variables and data structures are doing.

Good luck.

Upvotes: 2

Kaz
Kaz

Reputation: 58500

Things could go wrong before dev_read is reached. Did you see your KERN_ALERT message on the console?

Obviously that is not all there is to your source code, because the module is initialized, the character device registered, and there are other functions like the open routine. What makes you think the bug is in dev_read just because reading from the device crashes the machine?

sizeof(my_string) is sizeof(char *) which is 4 or 8. You're taking the size of the pointer. If you're on a 64 bit kernel, you will at most get Hi there without the ! when you have this debugged well enough to go that far. :)

I.e. it is apparent that you might benefit from tutorials in the basics of C, like the difference between arrays and pointers.

Upvotes: 3

Related Questions