new_and_malloc
new_and_malloc

Reputation: 11

How to get the reference count on Linux driver level?

In the Linux kernel the opened file is indicated by struct file, and the file descriptor table contains a pointers which is point to struct file. f_count is an important member in the struct file. f_count, which means Reference Count. The system call dup() and fork() make other file descriptor point to same struct file.

As shown in the picture (sorry, my reputation is too low, the picture can not be uploaded), fd1 and fd2 point to the struct file, so the Reference Count is equal to 2, thus f_count = 2.

My question is how can i get the value of the f_count by programming.

UPDATE:ok,In order to make myself more clear i will show my code, both the char device driver,Makefile and my application.:D

deviceDriver.c

#include "linux/kernel.h"
#include "linux/module.h"
#include "linux/fs.h"
#include "linux/init.h"
#include "linux/types.h"
#include "linux/errno.h"
#include "linux/uaccess.h"
#include "linux/kdev_t.h"
#define MAX_SIZE 1024

static int my_open(struct inode *inode, struct file *file);
static int my_release(struct inode *inode, struct file *file);
static ssize_t my_read(struct file *file, char __user *user, size_t      t, loff_t *f);
static ssize_t my_write(struct file *file, const char __user *user, size_t t, loff_t *f);

static char message[MAX_SIZE] = "-------congratulations--------!";
static int device_num = 0;//device number
static int counter = 0;
static int mutex = 0;
static char* devName = "myDevice";//device name

struct file_operations pStruct =
{ open:my_open, release:my_release, read:my_read, write:my_write, };

/* regist the module */
int init_module()
{
    int ret;
    /  **/
   ret = register_chrdev(0, devName, &pStruct);
if (ret < 0)
{
    printk("regist failure!\n");
    return -1;
}
else
{
    printk("the device has been registered!\n");
    device_num = ret;
    printk("<1>the virtual device's major number %d.\n", device_num);
    printk("<1>Or you can see it by using\n");
    printk("<1>------more /proc/devices-------\n");
    printk("<1>To talk to the driver,create a dev file with\n");
    printk("<1>------'mknod /dev/myDevice c %d 0'-------\n", device_num);
    printk("<1>Use \"rmmode\" to remove the module\n");

    return 0;
}
}

void cleanup_module()
{
    unregister_chrdev(device_num, devName);
   printk("unregister it success!\n");
}

static int my_open(struct inode *inode, struct file *file)
{
    if(mutex)
            return -EBUSY;
    mutex = 1;//lock
    printk("<1>main  device : %d\n", MAJOR(inode->i_rdev));
    printk("<1>slave device : %d\n", MINOR(inode->i_rdev));
    printk("<1>%d times to call the device\n", ++counter);
    try_module_get(THIS_MODULE);
    return 0;
}
/* release */
static int my_release(struct inode *inode, struct file *file)
{
    printk("Device released!\n");
    module_put(THIS_MODULE);
    mutex = 0;//unlock
    return 0;
}

static ssize_t my_read(struct file *file, char __user *user, size_t t, loff_t *f)
{
    if(copy_to_user(user,message,sizeof(message)))
    {
      return -EFAULT;
    }
    return sizeof(message);
}

static ssize_t my_write(struct file *file, const char __user *user, size_t t, loff_t *f)
{
    if(copy_from_user(message,user,sizeof(message)))
    {
       return -EFAULT;
    }
    return sizeof(message);
}

Makefile:

# If KERNELRELEASE is defined, we've been invoked from the
# kernel build system and can use its language.
ifeq ($(KERNELRELEASE),)
# Assume the source tree is where the running kernel was built
# You should set KERNELDIR in the environment if it's elsewhere
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
# The current directory is passed to sub-makes as argument
PWD := $(shell pwd)
modules:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules modules_install clean
else
    # called from kernel build system: just declare what our modules are
    obj-m := devDrv.o
endif    

application.c:

#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#define MAX_SIZE 1024

int main(void)
{
    int fd;
    char buf[MAX_SIZE];
    char get[MAX_SIZE];
    char devName[20], dir[50] = "/dev/";
    system("ls /dev/");
    printf("Please input the device's name you wanna to use :");
    gets(devName);
    strcat(dir, devName);
    fd = open(dir, O_RDWR | O_NONBLOCK);
    if (fd != -1)
    {
        read(fd, buf, sizeof(buf));
        printf("The device was inited with a string : %s\n", buf);
        /* test fot writing */
        printf("Please input a string  :\n");
        gets(get);
        write(fd, get, sizeof(get));
        /* test for reading */
       read(fd, buf, sizeof(buf)); 
       system("dmesg");
       printf("\nThe string in the device now is : %s\n", buf);
       close(fd);
       return 0;
  }
  else
  {
      printf("Device open failed\n");
      return -1;
  }
}

Any idea to get the struct file's(char device file) f_count? Is it poassible get it by the way of printk?

Upvotes: 0

Views: 4003

Answers (1)

cosinus0
cosinus0

Reputation: 613

You should divide reference counter to module from other module and from user-space application. lsmod show how many modules use your module.

sctp                  247143  4 
libcrc32c              12644  1 sctp

It is impossible load sctp without libcrc32c because sctp use exported function from libcrc32 to calculate control sum for packets. The reference counter itself is embedded in the module data structure and can be obtained with the function uint module_refcount(struct module* module);

You can use:

printk("Module reference counter: %d\n", (int)module_refcount(THIS_MODULE));

THIS_MODULE it is a reference to current loadable module (for build-in module it is NULL) inside .owner field (inside struct file_operations).

If there is a need manually modify module's counter use:

int try_module_get(struct module* module);
void module_put(struct module* module);

If module unloaded it will return false. You also can move thru all modules. Modules linked via list.

File opening inside kernel it is bad idea. Inside kernel you can get access to inode. Try read man pages for dup and fork. In you system you can investigate lsof tools.

Upvotes: 2

Related Questions