f_op pointer changes reflections:
----------------------------------------


I tried to change the f_op pointer to different file_operations structures based on minor number of the device file being  opened.

Steps:
-------

- A driver is written to register with kernel for major number 254 for the file myown. And changed the f_op pointer in open    function to different file_oprations structure based on the minor number.Used MINOR macro.

- Then created three character deivce files with same major number and different minor numbers.

crw-r--r-- 1 root root 254, 0 Oct 22 19:20 /dev/myown
crw-r--r-- 1 root root 254, 1 Oct 22 19:20 /dev/myown1
crw-r--r-- 1 root root 254, 3 Oct 22 23:33 /dev/myown2

- In the driver I registered with kernel for major number 254 and file name "myown".

- When the minor number is 1, I changed the f_op pointer in open function call implementation to different structure,where functions for device file with minor number 1 is written.

- Wrote a samll application program to open the device file myown & myown1 and wrote a character in it and observed.

- When I opened the device file with minor number 1 and wrote in it I could see write function from struct rwstruct1 getting  hit.

- But when I opened device file with other minor number immediately and wrote in it, the original structure which I used    during register_chrdev function didnt hit.


Observation:
------------
- The f_op pointer wont revert back to the original file_operations structure which is used during the register_chrdev()     function.We need to manually change the f_op pointer if we wanted to point to file_operations structure for different minor    number.

  Exp from LDD3
- The operations associated with the file. The kernel assigns the pointer as part of its implementation of open and then         reads it when it needs to dispatch any operations. The value in filp->f_op is never saved by the kernel for later              reference; this means that you can change the file operations associated with your file, and the new methods will be           effective after you return to the caller. For example, the code for open associated with major number 1 /dev/null,             /dev/zero, and so on) substitutes the operations in filp->f_op depending on the minor number being opened. This practice       allows the implementation of several behaviors under the same major number without introducing overhead at each system         call. The ability to replace the file operations is the kernel equivalent of �method overriding� in object-oriented            programming.


Driver code:
----------------
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>

static int sample_write(struct file *file,const char* data,int len,loff_t *off);
static int sample_open(struct inode* inode,struct file* filep);

static int sample1_write(struct file *file,const char* data,int len,loff_t *off);
static int sample1_open(struct inode* inode,struct file* filep);

static struct file_operations rwstruct1
={
open:sample1_open,
write:sample1_write,
owner:THIS_MODULE
};

static struct file_operations rwstruct
={
open:sample_open,
write:sample_write,
owner:THIS_MODULE
};

static int major;

int init_module(void)
{
printk("inside init_module");
major = register_chrdev(254,"myown",&rwstruct);
printk(KERN_EMERG "The major umber assigned is %d",major);
return 0;
}

void cleanup_module(void)
{
unregister_chrdev(254,"myown");
printk(KERN_EMERG "The major number cleaned up is ");

}

static int sample_open(struct inode* inode,struct file* file)
{
printk(KERN_EMERG "Inside open %d\n",inode->i_rdev);
int type = MINOR(inode->i_rdev);
printk(KERN_EMERG "Type valye with MINOR %d\n",type);
if( type == 1)
{
file->f_op = &rwstruct1;
printk(KERN_EMERG "After setting f_op to minor struct");
}
//else
//file->f_op = &rwstruct;

// If else part is missed out then after you open myown1 , if we tried to access any other device with 254 as major number and different minor number (apart from 1) then control wont go to sample_write/ sample_read.

return 0;
}

static int sample_write(struct file *file,const char* data,int len,loff_t *off)
{
printk(KERN_EMERG "Inside sample_write lengths is %d \n",len);
return 0;
}

static int sample1_open(struct inode* inode,struct file* file)
{
printk(KERN_EMERG "Inside sample1_open ");
return 0;
}

static int sample1_write(struct file *file,const char* data,int len,loff_t *off)
{
printk(KERN_EMERG "Inside sample1_write lengths is %d \n",len);
return 0;

}

Application code:
----------------------

#include <stdio.h>
#include <unistd.h>
#include <fnctl.h>

int main()
{

int fd;
fd = open("/dev/myown",O_WRONLY);  // change the file name to myown1 and observe kernel messages
printf("Writing to myown a character");
write(fd,"c",1);
close(fd);
}
Hosted by www.Geocities.ws

1