如何在Linux驱动程序级别获取引用计数?

时间:2015-03-26 10:41:04

标签: linux linux-kernel linux-device-driver

在Linux内核中,打开的文件由struct file表示,文件描述符表包含指向struct file的指针。 f_count是struct文件中的重要成员。 f_count,表示引用计数。系统调用dup()fork()使其他文件描述符指向同一struct file

如图所示(抱歉,我的声誉太低,图片无法上传),fd1fd2指向struct file,因此引用计数为等于2,因此f_count = 2

我的问题是如何通过编程获得f_count的价值。

更新:好的,为了让自己更清楚,我将展示我的代码,包括char设备驱动程序,Makefile和我的应用程序。: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);
}

生成文件:

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

有任何想法获取struct file&#39;(字符设备文件)f_count?它是否通过printk的方式得到了它?

1 个答案:

答案 0 :(得分:2)

您应该将参考计数器与其他模块和用户空间应用程序中的模块分开。 lsmod显示有多少模块使用您的模块。

sctp                  247143  4 
libcrc32c              12644  1 sctp

如果没有sctp,则无法加载libcrc32c,因为sctp使用libcrc32中的导出函数来计算数据包的控制和。 引用计数器本身嵌入在模块数据结构中,可以使用函数uint module_refcount(struct module* module);

获得

您可以使用:

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

THIS_MODULE它是.owner字段(struct file_operations内)当前可加载模块(内置模块为NULL)的引用。

如果需要手动修改模块的计数器使用:

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

如果模块已卸载,则会返回false。您也可以通过所有模块移动。通过列表链接的模块。

在内核中打开文件是个坏主意。在内核中,您可以访问inode。尝试阅读dupfork的手册页。在您的系统中,您可以调查lsof工具。