procfs介绍

procfs文件系统是内核中的一个特殊文件系统。它是一个虚拟文件系统: 它不是实际的存储设备中的文件,而是存在于内存中。procfs中的文件是用来允许用户空间的程序访问内核中的某些信息,例如查看内核中注册的中断信息:

cat /proc/interrupts

           CPU0       CPU1       CPU2       CPU3
  0:          5          0          0          0   IO-APIC   2-edge      timer
  1:          0          0          0         13   IO-APIC   1-edge      i8042
  8:          0          0          0          0   IO-APIC   8-edge      rtc0
  9:          0     368804          0          0   IO-APIC   9-fasteoi   acpi
 12:          0          0        143          0   IO-APIC  12-edge      i8042
 14:          0          0          0          0   IO-APIC  14-edge      ata_piix
 15:          0          0          0          0   IO-APIC  15-edge      ata_piix
 18:          0          0          0          0   IO-APIC  18-fasteoi   uhci_hcd:usb2
 19:          0          0         33          0   IO-APIC  19-fasteoi   ehci_hcd:usb1
 22:          0          0          0          0   IO-APIC  22-fasteoi   virtio2
 24:          0     936221          0          0   PCI-MSI 512000-edge      ahci[0000:00:1f.2]
 25:          0          0          0         22   PCI-MSI 81920-edge      virtio0-config
 26:     327418          0          0          0   PCI-MSI 81921-edge      virtio0-input.0
 27:          0     241094          0          0   PCI-MSI 81922-edge      virtio0-output.0
 28:          0          0         32          0   PCI-MSI 98304-edge      virtio1-config
 29:          0          0          0     116038   PCI-MSI 98305-edge      virtio1-input.0
 30:      52544          0          0          0   PCI-MSI 98306-edge      virtio1-output.0
 31:          0          0          0          0   PCI-MSI 487424-edge      xhci_hcd
 32:          0          5          0          0   PCI-MSI 524288-edge      virtio3-config
 33:          0          0        628          0   PCI-MSI 524289-edge      virtio3-virtqueues
 34:       2095          0          0          0   PCI-MSI 49152-edge      prl_tg
 35:          0       1052          0          0   PCI-MSI 516096-edge      snd_hda_intel:card0
NMI:          0          0          0          0   Non-maskable interrupts
LOC:    4873373    6149246    6152313    5156109   Local timer interrupts
SPU:          0          0          0          0   Spurious interrupts
PMI:          0          0          0          0   Performance monitoring interrupts
IWI:          0          0          0          0   IRQ work interrupts
RTR:          0          0          0          0   APIC ICR read retries
RES:     234988     236899     225375     230700   Rescheduling interrupts
CAL:    2632929    2570121    2843690    2792553   Function call interrupts
TLB:    1183090    1370524    1324835    1302239   TLB shootdowns
TRM:          0          0          0          0   Thermal event interrupts
THR:          0          0          0          0   Threshold APIC interrupts
DFR:          0          0          0          0   Deferred Error APIC interrupts
MCE:          0          0          0          0   Machine check exceptions
MCP:        580        580        580        580   Machine check polls
ERR:          0
MIS:          0
PIN:          0          0          0          0   Posted-interrupt notification event
NPI:          0          0          0          0   Nested posted-interrupt event
PIW:          0          0          0          0   Posted-interrupt wakeup event

procfs主要接口

接口函数原型
创建目录struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent)
创建文件struct proc_dir_entry *proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct file_operations *proc_fops)

 

添加一个procfs 文件实现例程

procfs用来进行相关驱动信息的读取,还是建议使用debugfs来做调试功能。

  • 要为 procfs 创建接口,只需要调用proc_create接口。

  • 读/写处理函数依附在 struct file_operations结构体。

  • 卸载操作使用remove_proc_entry

#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>

/*** 驱动信息 ***/
MODULE_LICENSE("Dual BSD/GPL");
#define DRIVER_NAME "MyDevice"              
#define PROC_NAME "MyDevice_test"           

/* procfs 测试变量 */
static char proc_test_string[16];
static int  flag_read = 0;

/* /proc/MyDevice_test访问时调用的函数 */
static int mydevice_proc_open(struct inode *inode, struct file *file)
{
    printk("mydevice_proc_open\n");
    flag_read = 0;
    return 0;
}

/* /proc/MyDevice_test read */
static ssize_t mydevice_proc_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
    printk("mydevice_proc_read\n");

    if (flag_read == 0) {
        int len;
        len = sprintf(buf, "%s\n", proc_test_string);
        flag_read = 1;
        return len;
    } else {
        return 0;
    }
}

/* /proc/MyDevice_test write */
static ssize_t mydevice_proc_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
    printk("mydevice_proc_write\n");

    if (count > sizeof(proc_test_string)) count = sizeof(proc_test_string) - 1;
    if (copy_from_user(proc_test_string, buf, count)) {
        return -EFAULT;
    }
    proc_test_string[count] = '\0';
    return count;   
}

/* file_operations  */
static struct file_operations mydevice_proc_fops = {
    .owner = THIS_MODULE,
    .open  = mydevice_proc_open,
    .read  = mydevice_proc_read,
    .write = mydevice_proc_write,
};

/* 加载 (insmod)时调用的函数 */
static int mydevice_init(void)
{
    struct proc_dir_entry *entry;
    
    printk("mydevice_init\n");
    /* 创建 procfs */
    entry = proc_create(PROC_NAME, S_IRUGO | S_IWUGO, NULL, &mydevice_proc_fops);
    if (entry == NULL) {
        printk(KERN_ERR "proc_create\n");
        return -ENOMEM;
    }

    return 0;
}

/* 卸载(rmmod)时调用的函数 */
static void mydevice_exit(void)
{
    printk("mydevice_exit\n");

    /* procfs 卸载く */
    remove_proc_entry(PROC_NAME, NULL);
}

module_init(mydevice_init);
module_exit(mydevice_exit);

加载模块后,该proc_create函数会创建一个文件/proc/MyDevice_testS_IRUGO | S_IWUGO0666 相同,为所有用户提供RW 访问权限。

作者:SteveChen  创建时间:2025-03-30 18:08
最后编辑:SteveChen  更新时间:2025-03-30 18:10
上一篇:
下一篇: