开发中proc文件系统的简单使用

news2024/10/7 15:26:12

使用proc文件系统


文章目录

  • 使用proc文件系统
  • 1.meminfo文件
  • 2. free命令
  • 3、创建 /proc 节点
  • 4、使用 file_operations 实现 proc 文件读写 导向内核信息
  • 5、使用 seq_file 实现 proc 文件的读取


在Linux系统中, “/proc”文件系统十分有用, 它被内核用于向用户导出信息。 “/proc”文件系统是一个虚拟文件系统, 通过它可以在Linux内核空间和用户空间之间进行通信。 在/proc文件系统中, 我们可以将对虚拟文件的读写作为与内核中实体进行通信的一种手段, 与普通文件不同的是, 这些虚拟文件的内容都是动态创建的。

“/proc”下的绝大多数文件是只读的, 以显示内核信息为主。 但是“/proc”下的文件也并不是完全只读的, 若节点可写, 还可用于一定的控制或配置目的, 例如前面介绍的写/proc/sys/kernel/printk可以改变printk() 的打印级别。

Linux系统的许多命令本身都是通过分析“/proc”下的文件来完成的, 如ps、 top、 uptime和free等。 例如, free命令通过分析/proc/meminfo文件得到可用内存信息, 下面显示了对应的meminfo文件和free命令的结果。

1.meminfo文件

在这里插入图片描述

2. free命令

在这里插入图片描述

3、创建 /proc 节点

  • struct proc_dir_entry
    内核使用
    proc_dir_entry 结构体来描述
    /proc 文件系统中的一个目录或者文件节点
/* 进程目录项结构体 /
struct proc_dir_entry {
    unsigned int low_ino; / 低位 inode 编号 /
    umode_t mode; / 文件访问权限 /
    nlink_t nlink; / 链接计数 /
    kuid_t uid; / 用户 ID /
    kgid_t gid; / 组 ID /
    loff_t size; / 文件大小 */
    const struct inode_operations proc_iops; / inode 操作函数集指针 */
    const struct file_operations proc_fops; / 文件操作函数集指针 */
    struct proc_dir_entry *next, *parent, subdir; / 目录项指针 */
    void data; / 自定义数据指针 /
    atomic_t count; / 使用计数 /
    atomic_t in_use; / 调用模块的进程数;负数表示正在卸载 */
    struct completion pde_unload_completion; / 卸载完成信号量指针 /
    struct list_head pde_openers; / 打开文件的进程链表头 /
    spinlock_t pde_unload_lock; / 卸载锁 /
    u8 namelen; / 名称长度 /
    char name[]; / 名称 */
};
  • proc_create
    内核提供了一套
    API用于在
    proc 文件系统中创建 文件节点
    /目录:
static struct proc_dir_entry *proc_create(  const char *name, umode_t mode,
                                            struct proc_dir_entry *parent, 
                const struct file_operations *proc_fops);    
                                            
@ name: 节点名
@ mode:    权限位
@ parent:父目录
@ proc_fops: 文件操作结构体

    struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent);

@ name: 目录名
@ parent:父目录
  • remove_proc_entry()
    内核提供
    remove_proc_entry 来移除
    proc 文件系统中的 文件
    /目录 项:
void remove_proc_entry(const char *name, struct proc_dir_entry *parent);

@ name: 文件/目录 名
@ parent:父目录

4、使用 file_operations 实现 proc 文件读写 导向内核信息

在调用 proc_create() 创建文件项时, 提供了一个 file_operations结构体, 实现里面的read, write方法即可实现proc 文件读写,demo 程序如下:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <asm/stat.h>
#include <linux/proc_fs.h>

MODULE_LICENSE("GPL");

#define LOG_TAG    "my_test1: "

static char my_buf[256];

//====================================================================================
static ssize_t my_proc_read(struct file *fp, char __user *buf, size_t size, loff_t *pos)
{
    int len = strlen(my_buf);

    pr_info(LOG_TAG "enter %s()\n", __func__);

    if( 0 == *pos )    {
        strncpy(buf, my_buf, sizeof(my_buf));
        *pos += len;
        return len;
    } else
        return 0;
}

static ssize_t my_proc_write(struct file *file,  const char __user *buf, size_t size, loff_t *pos)
{
    int len = size < sizeof(my_buf) ? size : sizeof(my_buf);

    pr_info(LOG_TAG "enter %s()\n", __func__);

    if( 0 == *pos)    {
        memset(my_buf, '\0', sizeof(my_buf));
        len = copy_from_user(my_buf, buf, len);
        *pos += len;
        my_buf[len - 1] = '\0';
        return size;
    }else 
        return 0;
}


static struct file_operations my_file_ops = {
    .owner     = THIS_MODULE,
    .read     = my_proc_read,
    .write     = my_proc_write,
};

//====================================================================================
static int __init my_module_init(void)
{
    struct proc_dir_entry * my_proc_node = NULL;

    pr_info(LOG_TAG "enter %s()\n", __func__);

    my_proc_node = proc_create("my_test1", S_IRUGO | S_IWUGO, NULL, &my_file_ops);
    if( NULL == my_proc_node )    {
        pr_err(LOG_TAG "creat /proc/my_test1 failed\n");
        remove_proc_entry("my_test1", NULL);
        return -1;
    }

    pr_info(LOG_TAG "creat /proc/my_test1 success\n");
    return 0;
}

static void __exit my_module_exit(void)
{
    pr_info(LOG_TAG "enter %s()\n", __func__);

    pr_info(LOG_TAG "remove /proc/my_test1\n");
    remove_proc_entry("my_test1", NULL);
}

module_init(my_module_init);
module_exit(my_module_exit);

5、使用 seq_file 实现 proc 文件的读取

seq_file只是在普通的文件read中加入了内核缓冲的功能,从而实现顺序多次遍历,读取大数据量的简单接口。内核使用 seq_file 结构体来描述seq_file:

/* 序列文件结构体 */
struct seq_file {
    char buf; / 缓冲区指针 /
    size_t size; / 缓冲区大小 /
    size_t from; / 开始位置 /
    size_t count; / 计数器 /
    loff_t index; / 索引 /
    loff_t read_pos; / 读取位置 /
    u64 version; / 版本号 /
    struct mutex lock; / 互斥锁 */
    const struct seq_operations op; / 序列操作函数集指针 /
    int poll_event; / poll() 事件 */
    #ifdef CONFIG_USER_NS
    struct user_namespace user_ns; / 用户命名空间 */
    #endifvoid private; / 私有数据指针 */
};

seq_file一般只提供只读接口,在使用seq_read时,主要靠下述四个操作来完成内核自定义缓冲区的遍历的输出操作,其中pos作为遍历的iterator,在seq_read函数中被多次使用,用以定位当前从内核自定义链表(不止是链表, 还可以是哈希表, 数组, 红黑树)中读取的当前位置,当多次读取时,pos非常重要,且pos总是遵循从0,1,2…end+1遍历的次序,其即必须作为遍历内核自定义链表的下标,也可以作为返回内容的标识。但是我在使用中仅仅将其作为返回内容的标示,并没有将其作为遍历链表的下标,从而导致返回数据量大时造成莫名奇妙的错误,注意:start返回的void*v如果非0,被show输出后,在作为参数传递给next函数,next可以对其修改,也可以忽略;当next或者start返回NULL时,在seq_open中控制路径到达seq_end。

struct seq_operations {
    void * (*start) (struct seq_file *m, loff_t *pos);
    void (*stop) (struct seq_file *m, void *v);
    void * (*next) (struct seq_file *m, void *v, loff_t *pos);
    int (*show) (struct seq_file *m, void *v);
};

在读取 proc file 时:

  • 如果只有一条记录, 调用过程是:
    start->show->stop,
    start->stop.
  • 如果有多条记录并且能通过缓冲区一次传第完, 调用过程是,继续
    start->show->next->show->next-> … ->nex->show->stop,
    start->stop .
  • 如果有多条记录, 比且不能一次通过缓冲区传送完成, 调用过程是:
    start->show->next->show->…->show->stop,
    start->show->next->show->…->show->stop, … , start->stop.

seq_file 的缓冲区通常为1K, 但是会动态增长以便能容纳至少一条记录(当单条记录的大小大于1页的时候,这个就很有用), 通常, 应该在start中进行必要的加锁, 在stop中进行必要的解锁一边避免竟态。
当使用seq_read时, 需要实现seq_operations, 并且将file和seq_file关联起来(通常在open操作中进行), 同时, seq_file也提供了游离的 seq_lseek, seq_release用于支持llseek和release操作。
使用seq_file 的demo如下:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <asm/stat.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>

#define LOG_TAG    "my_test2: "

MODULE_LICENSE("GPL");

static char my_buf[][32] = {    {"i am the 0th record"},    //buf[0]
                {"i am the 1th record"},    //buf[1]
                {"i am the 2th record"},    //buf[2]
                {"i am the 3th record"},    //buf[3]
                {"i am the 4th record"},    //buf[4]
};

//==========================================================================
static void* my_seq_start (struct seq_file *m, loff_t *pos)
{
    pr_info(LOG_TAG "enter %s()\n", __func__);

    if( *pos < 0 || *pos > 4 /*my_buf[][32] index*/)    {
        pr_err(LOG_TAG "invalid pos %ld\n", (long)*pos);
        return NULL;
    }else    
        return my_buf[*pos];
}

static void my_seq_stop (struct seq_file *m, void *v)
{
    pr_info(LOG_TAG "enter %s()\n", __func__);
    pr_info(LOG_TAG "do nothing\n");
}

static void* my_seq_next (struct seq_file *m, void *v, loff_t *pos)
{
    pr_info(LOG_TAG "enter %s()\n", __func__);

    if( ++(*pos) < 0  || *pos > 4 /*my_buf[][32] index*/)    {
        pr_info(LOG_TAG "end\n");
        return NULL;
    }else
        return my_buf[*pos];
}

static int my_seq_show (struct seq_file *m, void *v)
{
    seq_printf(m, "%s\n", (char*)v);
    return 0;    
}

static struct seq_operations my_seq_ops = {
    .start    =    my_seq_start,
    .stop    =    my_seq_stop,
    .next    =    my_seq_next,
    .show    =    my_seq_show,
      };
//==========================================================================

static int my_proc_open(struct inode * inode , struct file * file) 
{ 
    return seq_open(file, &my_seq_ops ); 
}

static struct file_operations my_file_ops = {
    .owner      = THIS_MODULE,
    .open     = my_proc_open,
    .read      = seq_read,
    .llseek  = seq_lseek,
    .release = seq_release,
};

//==========================================================================
static int __init my_module_init(void)
{
    struct proc_dir_entry * my_proc_node = NULL;

    pr_info(LOG_TAG "enter %s()\n", __func__);

    my_proc_node = proc_create("my_test2", S_IRUGO, NULL, &my_file_ops);
    if( NULL == my_proc_node )    {
        pr_err(LOG_TAG "creat /proc/my_test2 failed\n");
        remove_proc_entry("my_test2", NULL);
        return -1;
    }

    pr_info(LOG_TAG "creat /proc/my_test2 success\n");
    return 0;
}

static void __exit my_module_exit(void)
{
    pr_info(LOG_TAG "enter %s()\n", __func__);

    pr_info(LOG_TAG "remove /proc/my_test2\n");
    remove_proc_entry("my_test2", NULL);
}

module_init(my_module_init);
module_exit(my_module_exit);    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/517659.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

可视化图表API格式要求有哪些?Sugar BI详细代码示例(4)

Sugar BI中的每个图表可以对应一个数据 API&#xff0c;用户浏览报表时&#xff0c;选定一定的过滤条件&#xff0c;点击「查询」按钮将会通过 API 拉取相应的数据&#xff1b;前面说过&#xff0c;为了确保用户数据的安全性&#xff0c;Sugar BI上的所有数据请求都在Sugar BI的…

进击数据基础设施新蓝海,厂商如何“择木而栖”?

文 | 螳螂观察 作者 | 李永华 多样的应用需求&#xff0c;倒逼底层存储能力不断升级&#xff1b; 复杂的数据状况&#xff0c;要求存储能够“兼容并蓄”&#xff1b; 客户企业在数字化方面的战略转型升级&#xff0c;总是触及到存储…… 当数据基础设施成为新的蓝海&#…

大学计算机基础-题库刷题-精选

题库刷题&#xff1a; 写在前面&#xff1a; 这个是我准备应对学校转专业考试而刷的题库&#xff0c; 也是大学计算机的题库&#xff0c;同样适用于大学计算机这门课的期末考试。 精选了一些重要的题目。 目录 题库刷题&#xff1a; 写在前面&#xff1a; 题目1&#x…

内卷时代,大厂产品经理仅用3步破局

本文首发自「慕课网」&#xff0c;想了解更多IT干货内容&#xff0c;程序员圈内热闻&#xff0c;欢迎关注"慕课网"&#xff01; 作者&#xff1a;申悦|慕课网讲师 在当下互联网环境下&#xff0c;产品经理究竟要如何破局&#xff1f; 我认为&#xff0c;既然要破局…

RocketMQ学习笔记:生产者Producer

DefaultMQProducer 根据上文&#xff1a;RocketMQ学习笔记&#xff1a;消息Message - 掘金 (juejin.cn)&#xff0c;我们定位到Producer中的这一行代码&#xff1a; java 复制代码 DefaultMQProducer producer new DefaultMQProducer("ProducerGroupName"); pro…

2023年3月GESP能力等级认证C++一级真题

一、单选题&#xff08;每题2分&#xff0c;共30分&#xff09; 1.以下不属于计算机输入设备的有&#xff08;B &#xff09;。(2分) A&#xff0e;键盘 B&#xff0e;音箱 C&#xff0e;鼠标 D&#xff0e;传感器 2.计算机系统中存储的基本单位用 B 来表示&#xff0c;它…

Git 常用命令笔记

下载安装这里就不赘述了&#xff0c;直接下一步就行&#xff01; 一、常用命令 1. 增加删除/文件 添加当前目录的所有文件到暂存区 git add .添加指定文件到暂存区 git add [file1] [file2] ...添加指定目录到暂存区&#xff0c;包括子目录 git add [dir]对于同一个文件的多…

多种方法解决There is no tracking information for the current branch的错误

文章目录 1. 复现错误2. 分析错误3. 解决错误3.1 远程有分支3.2 远程无分支 4. 总结 1. 复现错误 今天发布某版本的项目&#xff0c;准备创建个v0point1分支&#xff0c;后期如果修改该版本&#xff0c;直接在该分支上修改即可。 首先&#xff0c;使用git branch v0point1命令…

问道游戏私人服务器架设+详细搭建教程+外网教程

搭建条件: 1、服务器一台, 2、下载服务端 搭建教程&#xff1a; 1.先安装宝塔 2、放行安全组的相应端口 具体要放行的端口有&#xff1a;3306、888、8888、5000、8101、8110、8120、8160-8168&#xff08;这个是范围之8160是一线&#xff0c;依次类推&#xff09; 3、安装数据库…

别点了!CAS登录对接,这个Bug让你反复登录!

目录 引言 背景描述 问题描述 问题排查 软件测试工程师发展规划路线 引言 你是否曾经在登录一个网站时&#xff0c;不断输入账号密码&#xff0c;却发现自己总是无法成功登录&#xff1f;或者你是否曾经遇到过跨域问题导致的登录失败&#xff1f; 今天我要和大家分享的就…

Speech and Language Processing之神经网络

上面这句话很好的解释了一件事&#xff0c;就是“大力出奇迹” &#xff0c;当神经元的数目足够足够多的时候&#xff0c;机器所能做到的事情就很复杂、很难理解了&#xff0c;这是不是说明chatgpt的成功也是因为大&#xff1f; 现代神经网络是一个由小型计算单元组成的网络&am…

前端 Web 性能清单

&#x1f482; 个人网站:【海拥】【摸鱼游戏】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 想寻找共同学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 提高 Web 应用程序的性…

HS6621系列低功耗国产蓝牙芯片 支持蓝牙5.1

HS6621CxC是一个功耗优化的蓝牙低功耗和专有的2.4 ghz应用真正的芯片上系统(SOC)解决方案。它集成了一个具有蓝牙基带和丰富外设的低功耗射频收发器I0扩展。HS6621CxC还集成了电源管理&#xff0c;提供高效率电源管理。它的目标是2.4 G蓝牙低功耗系统&#xff0c;人机界面设备(…

尚无忧【已对接硬件】共享自习室,共享麻将馆,共享茶室,共享空间,共享台球室,共享健身房无人值thinkphp开发

1、定位功能&#xff1a;可定位附近是否有店 2、能通过关键字搜索现有的店铺 3、个性轮播图展示&#xff0c;系统公告消息提醒 4、个性化功能展示&#xff0c;智能排序&#xff0c;距离、价格排序 5、现有店铺清单展示&#xff0c;订房可查看房间单价&#xff0c;根据日期、…

面试了一位6年的软件测试,一问三不知,他还反怼我...

最近看了很多简历&#xff0c;很多候选人年限不小&#xff0c;但是做的都是一些非常传统的项目&#xff0c;想着也不能通过简历就直接否定一个人&#xff0c;何况现在大环境越来 越难&#xff0c;大家找工作也不容易&#xff0c;于是就打算见一见。 在沟通中发现&#xff0c;由…

linux 修改 /etc/locale.conf无效问题处理办法

问题背景&#xff1a; 我在做测试系统文档转换成其他格式文档时&#xff0c;按照系统要求配置系统的编码格式为&#xff1a;utf-8 但是 尤其是设置&#xff1a;LC_ALLZh_CN.UTF- 8 但是 即使 我已经设置了 /etc/locale.conf内容如下&#xff1a; 并且source /etc/locale.con…

【FPGA-DSP】第十期:sysgen算法封装与调用

参考视频教程第10期 - sysgen算法封装与调用 - 基于FPGA的数字信号处理系统开发笔记_哔哩哔哩_bilibili 该教程主要实现如何将sysgen编写的算法模块给实际的应用起来 添加封装有两种方式&#xff1a; 在Vivado中使用ip核添加算法模块封装在Sysgen中将算法模块封装 Sysgen开发…

为何使用 B+ 树而非二叉查找树或 B 树做索引?

二叉树 B-Tree BTree 一、为何使用 B 树而非二叉查找树做索引&#xff1f; 我们知道二叉树的查找效率为 O(logn)&#xff0c;当树过高时&#xff0c;查找效率会下降。另外由于我们的索引文件并不小&#xff0c;所以是存储在磁盘上的。 文件系统需要从磁盘读取数据时&#xff0c…

【Vue工程】010-UnoCSS 即时按需原子 CSS 引擎

【Vue工程】010-UnoCSS 即时按需原子 CSS 引擎 文章目录 【Vue工程】010-UnoCSS 即时按需原子 CSS 引擎一、概述1、简介2、官网 二、基本使用1、安装2、修改 vite.config.ts3、根目录创建 uno.config.ts4、在 main.ts 中引入5、VS Code 安装 UnoCSS 插件6、在组件中使用7、访问…

ABAP 好用的事务码工具记录(持续更新)

性能优化类 SM50-某个程序RUNNING时间过长的时候&#xff0c;可以直接跳转到对应程序位置。 使用说明&#xff1a;一般选择仅活动进程&#xff0c;过滤列表中的活动程序和用户名&#xff0c;这样可以快速的定位到进程。 通过管理>>程序>>调试直接跳转到程序运行的…