Linux内核设备驱动之proc文件系统笔记整理

yizhihongxing

下面是关于“Linux内核设备驱动之proc文件系统笔记整理”的完整攻略:

概述

proc文件系统是一个伪文件系统(虚拟文件系统),它存在于内存中,不占用硬盘空间。它允许内核把内部数据结构暴露给用户空间,并提供了一种简单的接口,以便用户空间程序与内核模块之间相互通信和传递信息。

本篇攻略对proc文件系统进行详细讲解,介绍proc文件系统的特性、常用文件操作、编写proc文件的方法以及示例代码等。

特性

  • proc文件系统是一个伪文件系统(虚拟文件系统),不占用硬盘空间,存在于内存中。
  • proc文件系统建立在内核中,是内核数据结构的一种映射,可以获得内核的各种数据信息。
  • proc文件系统不要求提供存储器操作,无需磁盘空间即可存取当前系统运行的各种数据信息。
  • proc文件系统不要求硬件支持,基本所有的Linux操作系统都支持proc文件系统。

常用文件操作

在proc文件系统中,常用的文件操作有:

  • 读文件:将文件的内容读出来,可以通过cat等命令实现。
  • 写文件:向文件写入数据,可以通过echo等命令实现。
  • 打开文件:在应用程序中打开一个文件,是通过open()函数实现的。
  • 关闭文件:关闭文件可以通过close()函数实现。

编写proc文件的方法

编写proc文件需要原理内核模块,使用proc接口来处理读/写等操作,并将其挂载到proc文件系统中。下面介绍一下编写proc文件的方法:

1. 创建结构体

首先需要定义一个包含读操作和写操作的结构体:

struct file_operations fop = {
    .read = my_read,
    .write = my_write
};

my_readmy_write是读写操作的函数地址,需要编写对应的读写函数实现。

2. 指定proc文件名

定义好file_operations结构体之后,需要用proc_create函数来注册proc文件。此函数原型为:

struct proc_dir_entry *proc_create(const char *name, mode_t mode, struct proc_dir_entry *parent, const struct file_operations *proc_fops);

其中,name是proc文件的文件名,mode是文件的权限,parent是proc文件的父目录,proc_fops是文件操作结构体。

3. 实现读函数

file_operations结构体中定义的读函数,实际上就是读取内核数据结构并将其以ASCII码的形式输出。读函数的原型如下:

ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *ppos);

其中,file是文件指针,用于访问文件的数据;buf是用于存储文件数据的缓冲区;count是要读取数据字节数;ppos是文件偏移量。读函数需要返回成功读取的字节数。

4. 实现写函数(可选)

与读函数类似,写函数实现了将用户输入的数据解析并放入内核数据结构中的功能。写函数的原型如下:

ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos);

其中,file是文件指针,用于访问文件的数据;buf是包含写入数据的缓冲区;count是要写入数据的字节数;ppos是文件偏移量。写函数需要返回成功写入的字节数。

示例说明

为了更好地理解proc文件系统的用法和创建过程,以下提供两个示例。

示例1:实现读取系统级别内存信息的proc文件

此示例实现了一个proc文件用来读取系统级别的内存信息。具体实现步骤如下:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/mm.h>

#define PROC_MEMINFO "proc-test"

MODULE_AUTHOR("My Name");
MODULE_LICENSE("GPL");

static struct proc_dir_entry *meminfo_entry;

static int meminfo_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
    int len;

    // 读取系统内存信息,并将信息格式化
    len = sprintf(page, "Total RAM: %lu\n", totalram_pages);
    len += sprintf(page + len, "Free RAM : %lu\n", freeram_pages);
    len += sprintf(page + len, "Shared RAM: %lu\n", totalcma_pages);
    len += sprintf(page + len, "Number of processes : %d\n", nr_processes());
    return len;
}

static int __init meminfo_init(void)
{
    // 创建目录项
    meminfo_entry = proc_create(PROC_MEMINFO, 0, NULL, &meminfo_file_ops);
    if (meminfo_entry == NULL) {
        printk(KERN_ERR "meminfo: Could not create proc entry\n");
        return -ENOMEM;
    }
    printk(KERN_INFO "meminfo: Module loaded.\n");
    return 0;
}

static void __exit meminfo_exit(void)
{
    // 移除目录项
    remove_proc_entry(PROC_MEMINFO, NULL);
    printk(KERN_INFO "meminfo: Module unloaded.\n");
}

module_init(meminfo_init);
module_exit(meminfo_exit);

在该示例中创建了一个名为proc-test的proc文件,读函数meminfo_read_proc实现了读取系统内存信息的功能。这个函数会读取系统内存信息,并将信息格式化后放入page缓冲区中。

示例2:实现简单的统计字符数和行数的proc文件

此示例实现了一个proc文件用来读取指定文件的字符数和行数。具体实现步骤如下:

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

#define PROC_MYFILE "proc-mycalc"

MODULE_AUTHOR("My Name");
MODULE_LICENSE("GPL");

static char my_str[100];
static struct proc_dir_entry *myfile_entry;

static int mycalc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
    char tmp_str[100];
    unsigned int length = 0;
    unsigned int words = 0;
    int i = 0;
    mm_segment_t old_fs;
    struct file *f;

    // 打开指定的文件
    f = filp_open(my_str, O_RDONLY, 0);
    if (IS_ERR(f)) {
        printk(KERN_ERR "mycalc: Could not open file %s\n", my_str);
        return -1;
    }

    // 读取文件内容并计算字符数和行数
    old_fs = get_fs();
    set_fs(KERNEL_DS);
    while (vfs_read(f, tmp_str, 100, &f->f_pos) > 0) {
        for (i = 0; i < 100; i++) {
            if (tmp_str[i] == '\n') {
                words++;
            } else {
                length++;
            }
        }
    }
    set_fs(old_fs);

    filp_close(f, NULL);

    return sprintf(page, "Length: %u\nWords : %u\n", length, words);
}

static ssize_t mycalc_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
    int len = count;

    if (len > 99) {
        len = 99;
    }
    if (copy_from_user(my_str, buffer, len)) {
        return -EFAULT;
    }
    my_str[len-1] = '\0';
    return count;
}

static struct file_operations mycalc_file_ops = {
    .owner = THIS_MODULE,
    .read = mycalc_read_proc,
    .write = mycalc_write_proc,
};

static int __init mycalc_init(void)
{
    // 创建目录项
    myfile_entry = proc_create(PROC_MYFILE, 0666, NULL, &mycalc_file_ops);
    if (myfile_entry == NULL) {
        printk(KERN_ERR "mycalc: Could not create proc entry\n");
        return -ENOMEM;
    }
    printk(KERN_INFO "mycalc: Module loaded.\n");
    return 0;
}

static void __exit mycalc_exit(void)
{
    // 移除目录项
    remove_proc_entry(PROC_MYFILE, NULL);
    printk(KERN_INFO "mycalc: Module unloaded.\n");
}

module_init(mycalc_init);
module_exit(mycalc_exit);

在该示例中创建了一个名为proc-mycalc的proc文件,读函数mycalc_read_proc实现了读取指定文件的字符数和行数的功能。写函数mycalc_write_proc实现了写入文件名的功能。这些函数都是自己实现的,没有调用任何已有的函数。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Linux内核设备驱动之proc文件系统笔记整理 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • Linux之find命令的参数

    当我们需要在Linux系统中查找文件或目录时,可以使用find命令。find命令的参数非常多,可以根据不同的需求进行调整。下面详细讲解一下find命令的参数: find的基本语法 命令格式:find [路径] [参数] [表达式] 路径:查找的目标路径 参数:查找的选项 表达式:查找的条件 其中,表示条件的表达式的最后一个参数通常是对文件或目录进行操作的“.…

    other 2023年6月27日
    00
  • PHP使用递归方式列出当前目录下所有文件的方法

    让我来详细讲解PHP使用递归方式列出当前目录下所有文件的方法。 1. 确定目录 首先,我们需要确定要列出文件的目录。可以使用php中的getcwd()函数来获取当前执行脚本的目录,或者使用chdir()函数切换到指定的目录。 2. 递归函数 接下来,我们需要编写递归函数来遍历目录下的所有文件和子目录。递归函数的基本框架如下所示: function recur…

    other 2023年6月27日
    00
  • log4j.properties 配置(实例讲解)

    下面是 “log4j.properties配置(实例讲解)” 的完整攻略: 什么是log4j.properties? log4j是一个Java语言的日志记录工具,它让我们可以更方便、更高效地记录程序运行时的信息。log4j.properties是log4j的配置文件,它可以设置log4j如何记录日志信息,包括输出到哪些文件、控制台还是网络等等。下面我们来详细…

    other 2023年6月25日
    00
  • jquery判断checkbox是否被选中4种方法

    以下是详细讲解“jQuery判断checkbox是否被选中4种方法”的完整攻略,过程中至少包含两条示例说明的标准Markdown格式文本: jQuery判断checkbox是否被选中4种方法 在jQuery中,checkbox是否被选中是一种常见的操作。本文将介绍4种判断checkbox是否被选中的方法。 方法1:使用prop()方法 prop()方法用于获…

    other 2023年5月10日
    00
  • uni.getLocation和wx.getLocation方法调用无效也不返回失败的解决方案

    问题描述: 在使用uni.getLocation和wx.getLocation方法时,调用无效也不返回失败,导致页面无法得到正确的位置信息。 解决方案: 确认是否开启权限 在微信小程序和uni-app中,获取用户位置需要先开启相应的授权。在调用getLocation方法前可以先调用getSetting方法检查是否已经授权。如果没有授权,可以使用wx.open…

    other 2023年6月26日
    00
  • Unity3D之UGUI学习笔记:EventSystem

    Unity3D之UGUI学习笔记:EventSystem的完整攻略 在Unity3D中,UGUI(Unity GUI)是一种用于创建用户界面的工具集。EventSystem是UGUI中的一个重要组件,它用于处理用户输入事件。在本文中,我们将详细介绍EventSystem的作用和使用方法,并提供两个示例说明。 EventSystem的作用 EventSyste…

    other 2023年5月5日
    00
  • Android布局优化之ViewStub控件

    当一个Activity包含大量的布局文件时,加载时间会变慢,影响用户体验。因此,Android中布局优化显得很有必要。ViewStub控件便是Android中一种有效的布局优化方式。 一、什么是ViewStub控件 在Android的布局文件中,可以使用ViewStub控件定义一个不可见的布局,这个布局不会在加载时被加载到内存中,只有在需要显示时才被实例化,…

    other 2023年6月27日
    00
  • Windows下Apache应用环境塔建安全设置(目录权限设置)

    Windows下Apache应用环境搭建安全设置是非常重要的一个环节,可以有效的保障Apache应用在使用过程中的安全性。其中,目录权限设置是其中一个重要的步骤。 目录权限设置 在Apache服务器中,目录权限设置是非常重要的,需要对目录进行设定,以保证在使用过程中的安全性,避免非法访问或者恶意攻击。 1. 设定目录读写权限 对于目录的读写权限,我们需要设定…

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部