I'm a frog dragon
I'm a frog dragon

Reputation: 8895

Reason to pass data using struct inode and struct file in Linux device driver programming

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 ?

Upvotes: 12

Views: 9559

Answers (5)

Vivek Kumar
Vivek Kumar

Reputation: 1

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

Upvotes: 0

rodrigo
rodrigo

Reputation: 98526

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.

Upvotes: 10

Ziming Zhao
Ziming Zhao

Reputation: 41

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.

Upvotes: 0

Klas Lindbäck
Klas Lindbäck

Reputation: 33283

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

Upvotes: 8

Jekyll
Jekyll

Reputation: 1434

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;
 }

Upvotes: 0

Related Questions