proc文件系统怎么玩?

前言

最近在做测试,怎么实现的呢?通过实现了一个KO,然后KO加载后就会注册一个proc节点。然后通过echo给这个节点进行输入指令,调用对应的文件节点,最后实现测试的函数调用。

这里对proc这个东西一直感觉很神奇,很多cat、cpu等信息都可以从里面获取到。于是这里来看看这个文件系统。

1、什么是proc文件系统

  • (1) proc是虚拟文件系统,虚拟的意思就是proc文件系统里的文件不对应硬盘上任何文件,我们用去查看proc目录下的文件大小都是零;

  • (2) proc文件系统是开放给上层了解内核运行状态的窗口,通过读取proc系统里的文件,可以知道内核中一些重要数据结构的数值,从而知道内核的运行情况,也可以方便调试内核和应用程序;

  • (3) proc文件系统的思路:在内核中构建一个虚拟文件系统/proc,内核运行时将内核中一些关键的数据结构以文件的方式呈现在/proc目录中的一些特定文件中,这样相当于将不可见的内核中的数据结构以可视化的方式呈现给内核的开发者

  • (4) proc文件系统是一种无存储的文件系统,当读其中的文件时,其内容动态生成当写文件时,文件所关联的写函数被调用每个proc文件都关联的字节特定的读写函数,因而它提供了另外的一种和内核通信的机制内核部件可以通过该文件系统向用户空间提供接口来提供查询信息修改软件行为,因而它是一种比较重要的特殊文件系统。

2、常见的proc文件介绍

在这里插入图片描述

3、和sys文件系统的比较

  • (1)proc文件系统主要是用来调试内核,在内核运行时可以知道内核中一些重要的数据结构的值,一般都是读很少写;

  • (2)proc文件系统出现的比sys文件系统早,proc文件系统的目录结构比较乱,在proc文件系统下面有很多文件夹,比如一个进程就有一个文件夹,现在内核越来越复杂,支持的设备类型也越来越多,显得很混乱;于是又开发出了sys系统,sys系统可以说是proc的升级,将来用sys系统会是主流;

  • (3)proc文件系统和sys文件系统都是虚拟系统,并且有对应关系,比如"/proc/misc"对应于"sys/class/misc"下面的设备,都是描述misc类设备的;

4、怎么注册一个proc文件系统的节点

Linux系统上的/proc目录是一种文件系统,即proc文件系统(procfs),它以文件系统的方式为用户提供访问系统内核数据的操作接口。

proc文件系统是一种内核和内核模块用来向进程(process)发送信息的机制,因此被称为proc。

与其它常见的文件系统不同的是,proc是一种伪文件系统(也即虚拟文件系统),它只存在于内存当中,因此它会在系统启动时创建并挂载到/proc目录,在系统关闭时卸载并释放。

下面是设备上/proc的挂载信息。

$ mount | grep proc
proc on /proc type proc (rw,relatime)

proc文件系统存储的是当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看系统和进程的信息,或者改变内核的运行状态,因此可以把它视为Linux内核开放给用户的控制和信息中心。实际上,proc文件系统是内核空间和用户空间之间的一种通信媒介。

在这里插入图片描述

使用proc_create实例分析

proc虚拟文件系统也可以创建虚拟文件节点,实现用户空间与内核空间的交互。

在驱动中创建节点,可以实现对硬件的控制。proc_create函数原型(在kernel-3.10/include/linux/proc_fs.h文件)如下所示:

1-proc_create函数原型

static inline struct proc_dir_entry *proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct file_operations *proc_fops)
{
    return proc_create_data(name, mode, parent, proc_fops, NULL);
}
  • name:表示你要创建的设备节点的名称,可随意命名即可;
  • mode:表示节点的权限,一般赋值0644;
  • parent:表示父节点,如果直接在proc目录创建节点,直接赋值NULL即可;
  • proc_fops:表示与节点相关联的file_operations;

如下代码是我实现的一个test程序,可供参考学习proc_create的使用:

2-test 实例

#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/ioctl.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/wait.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/proc_fs.h>

#define BUFSIZE  1024 

static char *buf;
static unsigned int len;

/***********************
 * file_operations->open
 * 无操作
 ***********************/

static int test_proc_open(struct inode *inode, struct file *file)
{
    return 0;
}

/************************
 * file_operations->read
 * 可以在adb工具进入机器的pro目录,执行adb shell && cd proc && cat tets_rw,
 * 即可读出节点test_rw的内容是12345
 ************************/

static ssize_t test_proc_read(struct file *file,
                char __user *buffer,size_t count, loff_t *f_pos) 
{
    if(*f_pos > 0)
        return 0;

printk("---start read---\n");
    printk("the string is >>>>> %s\n", buf);

if(copy_to_user(buffer, buf, len))
        return -EFAULT;
    *f_pos = *f_pos + len;
    return len;
}

/************************
 * file_operations->write
 * 可以在adb工具进入机器的pro目录,
 * 执行adb shell && cd proc && echo 12345 > tets_rw,即可把12345写入节点test_rw
 ************************/

static ssize_t test_proc_write(struct file *file, const char __user *buffer,
                                        size_t count, loff_t *f_pos) 
{

if(count <= 0)
        return -EFAULT;
    printk("---start write---\n");

len = count > BUFSIZE ? BUFSIZE : count;

// kfree memory by kmalloc before
    if(buf != NULL)
        kfree(buf);
    buf = (char*)kmalloc(len+1, GFP_KERNEL);
    if(buf == NULL)
    {
        printk("test_proc_create kmalloc fail!\n");
        return -EFAULT;
    }

//memset(buf, 0, sizeof(buf));
    memset(buf, 0, len+1);

if(copy_from_user(buf, buffer, len))
        return -EFAULT;
    printk("test_proc_write writing :%s",buf);
    return len;
}

static struct file_operations test_fops = {
    .owner  = THIS_MODULE,
    .open   = test_proc_open,
//  .release = single_release,
    .read   = test_proc_read,
//  .llseek = seq_lseek,
    .write  = test_proc_write,
};

static int __init test_init(void)
{
    struct proc_dir_entry* file;

//创建proc文件并关联file_operations
    file = proc_create("test_rw", 0644, NULL, &test_fops);
    if (!file)
        return -ENOMEM;
    printk("test_rw init success!\n");
    return 0;
}

static void __exit test_exit(void)
{
    remove_proc_entry("test_rw", NULL);
    printk("test_exit\n");

}

module_init(test_init);
module_exit(test_exit);

MODULE_AUTHOR("caizd");
MODULE_DESCRIPTION("Proc_create Test Driver");
MODULE_LICENSE("GPL");

3-试一下

可以将上面的代码编译成一个ko,然后编近kernel,然后验证。

root@inwatch_portal:/ # cd proc
cd proc
root@inwatch_portal:/proc # echo 12345 > test_rw
echo 12345 > test_rw
root@inwatch_portal:/proc # cat test_rw
cat test_rw
12345

5、怎么编译成ko

单独整一篇算了!!!

https://zhuanlan.zhihu.com/p/584749553
https://www.elecfans.com/emb/202210101902598.html
https://zhuanlan.zhihu.com/p/584749553
https://zhuanlan.zhihu.com/p/557870063

猜你喜欢

转载自blog.csdn.net/weixin_45264425/article/details/130393838