Find the answer to your Linux question:
Results 1 to 3 of 3
Hello all. I'm playing around with the locking mechanisms within the Linux kernel. I've got a global variable which gets incremented every time a user-space process writes to the device. ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Just Joined!
    Join Date
    Jan 2008
    Posts
    16

    Trying to create a race condition.


    Hello all.

    I'm playing around with the locking mechanisms within the Linux kernel. I've got a global variable which gets incremented every time a user-space process writes to the device.

    The code for the driver is below.

    Code:
    #include<linux/module.h>
    #include<linux/init.h>
    #include<linux/mutex.h>
    #include<linux/fs.h>
    #include<linux/cdev.h>
    #include<linux/uaccess.h>
    #include<linux/spinlock.h>
    #include<linux/slab.h>
    #include<linux/list.h>
    
    
    #define PRINT_FUNC printk("In function: %s\n", __func__)
    
    int counter = 0;
    
    static int file_open(struct inode *, struct file *) ;
    static int file_close(struct inode *, struct file *);
    static int file_read(struct file *, char *, size_t , loff_t *) ;
    static int file_write(struct file *, const char *, size_t , loff_t *); 
    
    static DEFINE_MUTEX(lock);
    
    static struct file_operations fops = {
            .owner = THIS_MODULE,
            .open = file_open,
            .release = file_close,
            .read = file_read,
            .write = file_write,
    };
    
    
    static struct item_list
    {
            struct list_head head;
            int val;
    };
    
    static int file_open(struct inode *inode, struct file *filep)
    {
            PRINT_FUNC;
            return 0;
    }
    
    static int file_close(struct inode *inode, struct file *filep)
    {
            PRINT_FUNC;
            return 0;
    }
    
    static int file_read(struct file *filep, char *buf, size_t size, loff_t *offset)
    {
            PRINT_FUNC;
    
            return 0;
    }
    
    static int file_write(struct file *filep, const char *buf, size_t size, loff_t *offset)
    {
    
            long long num;
            char *buf_in;
            int retval,pos = 0;
    
            counter +=1;
    
            printk(KERN_ERR"%d\n",counter);
    
            mutex_lock(&lock);
    
            if (!(buf_in = kzalloc(size,GFP_KERNEL))) {
                    printk(KERN_ERR"Unable to allocate memory\n");
                    retval = -ENOMEM;
                    goto err;
            }
    
            if (copy_from_user(buf_in,buf,size) != 0) {
                    printk(KERN_ERR"Transfer error\n");
                    retval = -EINVAL;
                    goto err;
            }
    
            num = (int)simple_strtol(buf_in,NULL,10);
            memset(buf_in,'0',size);
            kfree(buf_in);
    
            mutex_unlock(&lock);
    
            return size;
    err:
            if (buf_in) kfree(buf_in);
            mutex_unlock(&lock);
            return retval;
    }
    
    
    static int module_insert(void)
    {
            mutex_init(&lock);
            if (register_chrdev(222,"mychar_dev",&fops)) {
                    printk(KERN_ERR"Char device registration err\n");
            }
    
            return 0;
    }
    
    static void module_removed(void)
    {
            counter = 0;
            unregister_chrdev(222,"mychar_dev");
    }
    
    module_init(module_insert);
    module_exit(module_removed);
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("Me");
    MODULE_VERSION("v0.1");
    This driver simply displays the counter via dmesg, but the counter variable seems to be in sync, even if I run 5+ processes (my script :- below)

    Code:
    #!/bin/bash
    COUNTER=0
    while [ $COUNTER -lt 10 ]; do 
            echo -n $COUNTER > mychar_dev
            let COUNTER+=1;
            sleep 2;
            echo Written $COUNTER
    done
    If I run the script the counter increments correctly, even though the counter variable isn't within the critical section. Below is the dmesg output.

    Code:
    [  813.498153] 1
    [  813.498157] In function: file_close
    [  815.498038] In function: file_open
    [  815.498047] 2
    [  815.498052] In function: file_close
    [  876.430729] In function: file_open
    [  876.430835] 3
    [  876.430840] In function: file_close
    [  876.430855] In function: file_open
    [  876.430924] 4
    [  876.430927] In function: file_close
    [  876.430937] In function: file_open
    [  876.431005] 5
    [  876.431008] In function: file_close
    [  876.431017] In function: file_open
    [  876.431085] 6
    [  876.431088] In function: file_close
    [  876.431097] In function: file_open
    [  876.431165] 7
    
    And so one. Surely there would be inconsistence with the counter.
    Could someone please point me in the right direction? Kernel locking is really tricky to get right. The code was run on my SMP machine, and my netbook (UP).

    Thanks.

  2. #2
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,527
    The kernel will cache the device writes until it either times out, or the device is flushed. So, writing the value of the counter to the device very quickly, will likely result in the observed behavior.
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

  3. #3
    Just Joined!
    Join Date
    Jan 2008
    Posts
    16
    Quote Originally Posted by Rubberman View Post
    The kernel will cache the device writes until it either times out, or the device is flushed. So, writing the value of the counter to the device very quickly, will likely result in the observed behavior.
    Excellent.

    I manage to produce these results in the finish . I just ran my scripts and my program about 10 times simultaneously. I didn't know about the caching feature within the kernel. I'll look into this.

    Thanks Rubberman!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •