12

I'm studying Chapter 3.5 of Linux Device Drivers, 3rd edition. This section introduces a method to retrieve a custom structure we defined ourselves from struct inode *inode in the open function:

int scull_open(struct inode *inode, struct file *filp)
{
    struct scull_dev *dev;

    dev = container_of(inode->i_cdev, struct scull_dev, cdev);
    filp->private_data = dev; /* for other methods */

    }
    return 0;          
}

From my understanding, while the device is opened, the struct inode *inode representing the device is passed to scull_open. Then, the custom structure dev is extracted and passed to filp->private_data so that other methods such as scull_read can use it:

ssize_t scull_read(struct file *filp, char _ _user *buf, size_t count,
                loff_t *f_pos)
{
    struct scull_dev *dev = filp->private_data; 
    /* other codes that uses *dev   */
}

This seems fine to me until I realized that we already had a struct scull_dev *dev during initialization in scull_setup_cdev here.

I'm rather confused since I thought we can make struct scull_dev *dev a global variable, then scull_read and other methods will eventually have access to it without going through all the passing using inode and file.

My question is, why don't we just make it a global variable?

Can anyone provide some practical examples of using this method to pass data ?

I'm a frog dragon
  • 7,865
  • 7
  • 46
  • 49

5 Answers5

10

The main reason is so that your driver can manage more than one device. For example, you can create (mknod) several devices /dev/scull1, /dev/scull2, /dev/scull3... and then each of these will have a different scull_dev associated with it.

With a global variable you are limited to one. And even if your driver only supports one such device, there is little reason not to design the code future proof.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
8

Thread-safety! What if two threads/processes are using the driver simultaneously?

Klas Lindbäck
  • 33,105
  • 5
  • 57
  • 82
  • 1
    Even threads in different single-threaded processes. (Which most people would naively just call "processes" rather than "threads".) – R.. GitHub STOP HELPING ICE Sep 09 '11 at 12:54
  • 1
    Thanks, but I'm still having some doubts. Let's say I have a simple user program (let's call it `open_device.c`) to communicate with my driver through system calls like `open()`, `read()`,`write()`, etc. If I'm very sure that at a single time, I will only use **one** `open_device.c` to access my driver, do I still need to take care of the thread safety concern ? Does the thread safety issue happen only when I'm using **two** or **more** `open_device.c` to access my driver? – I'm a frog dragon Sep 13 '11 at 08:47
  • 1
    What is the lifetime of the struct, does it persist between system calls? If it does, your program will break if you open a second file before you close the first. – Klas Lindbäck Sep 13 '11 at 09:16
  • 1
    Can you please elaborate as to why you think this makes it thread-safe? I can't see any extra protection it would give. All threads would point to the same scull_dev structure, effectively making it a global variable. – Michael Sep 16 '12 at 14:34
0

I donot think it is a thead-safety issue. It is more like a design choice. If I am not mistaken, thread-safety is achieved by down and up the semaphore in scull_dev. If you dig into the code, you can see open, read, write all used down_interruptible().

I guess the author 1) believes accessing scull_dev directly doesnot look good 2) wants to show us how to use private_data. By putting the point to scull_dev in struct file whose pointer is sent to each operation, each operation can access it without using global variable.

0

The scull driver is implemented with 4 minors, each of which has a separate scull_dev, each scull_dev has "struct cdev" embedded in it. Now Let's say User has opened scull0 from /dev/scull0. In the open() function you need to point to the correct scull_dev structure. The scull_dev structures are dynamically allocated.

You can see the full implementation here https://github.com/mharsch/ldd3-samples/blob/master/scull/main.c#L450

0

You can also avoid using the private data to store your actual device, which is a common choice if you need private data for something different. In that case you will need to retrieve the minor number in the scull_read routine. It will be something like that:

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

    int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
    printk( "reading on minor number %d\n", minor);
    /* use dev[minor] in ur code */
    return 0;
 }
Julien Roncaglia
  • 17,397
  • 4
  • 57
  • 75
Jekyll
  • 1,434
  • 11
  • 13