Linux操作系统分析实验-文件操作,实验三

一、实验目的

1、 理解Linux中虚拟文件系统的内容

2、 学习编写内核模块的方法

3、 在虚拟文件系统/proc中实现文件操作算法

二、实验内容

编写一个内核模块,在/proc文件系统中增加一个目录hello,并在这个目录中增加一个文件world,文件的内容为hello world。

实验涉及的内核函数

1、在proc中创建目录函数 proc_mkdir

该函数原型为:

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

name:要创建的目录的名称

parent:指向该目录的父目录的指针

返回指向当前目录的指针结构体。

2、创建version文件的函数为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);

第一个参数name为文件名,

第二个参数mode为文件的读写权限,

第三个参数parent为其父目录的结构体指针,第四个参数proc_fops为文件的读写操作结构体。

3、实现内核空间与用户空间的数据传递函数:

copy_to_user()和copy_from_user()这两个函数。

(旧内核是raw_copy_to_user() 和 raw_copy_from_user()这两个函数)

 copy_to_user() 函数的完整形态为

unsigned long copy_to_user(void *to, const void *from, unsigned long count);

函数的作用是将内核空间的数据复制到用户空间。其中

to:目标地址(用户空间)

from:源地址(内核空间)

count:将要拷贝数据的字节数

返回:成功返回0,失败返回没有拷贝成功的数据字节数

4、从 /proc 中删除一个文件函数 remove_proc_entry() 

函数的原型是:

remove_proc_entry(const char *name, struct proc_dir_entry *parent)

name:要删除的文件名

parent :文件在 /proc 文件系统中的位置

三、实验原理

1、/proc 文件系统是Linux上的一种虚拟文件系统,存储的是当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息。

2、最初开发 /proc 文件系统是为了提供有关系统中进程的信息。但是由于这个文件系统非常有用,因此内核中的很多元素也开始使用它来报告信息或启用动态运行时配置。

用户一般不可以随便在/proc 文件系统中添加信息

3、   /proc 目录下文件详解

(1)内存

/proc/buddyinfo

伙伴系统的信息

/proc/pagetypeinfo

伙伴系统进一步细分信息

/proc/zoneinfo

内存区域使用情况

/proc/slabinfo

内核对象缓存(slab caches)的统计信息

/proc/meminfo

当前内存信息

/proc/vmstat

虚拟内存统计信息

/proc/vmallocinfo

虚拟内存分配信息

/proc/swaps

swap分区使用情况

/proc/mtd

内存设备分区表信息

/proc/dma

DMA(直接内存访问)通道的列表

/proc/mtrr

系统使用的Memory Type Range Registers (MTRRs)

/proc/kpagecount

系统中物理页的引用计数
/proc/kpageflags系统中物理页的标志

(2)I/O

/proc/filesystems

目前系统支持的文件系统

/proc/diskstats

磁盘设备的统计信息

/proc/ioports

当前系统硬件设备使用的IO端口列表

/proc/iomem

I/O 内存映射

/proc/locks

当前被内核锁定的文件

/proc/mounts

当前挂载信息

(3)CPU

/proc/cpuinfocpu相关信息
/proc/loadavg  当前系统负载
/proc/softirqs系统软中断信息
/proc/schedstat调度器信息
/proc/sched_debug调度器debug信息

            

(4)kernel

/proc/cmdline  在引导启动时传递给Linux内核的参数
/proc/crypto内核支持的加密方式
/proc/modules当前系统已经加载的模块(lsmod)
/proc/version内核版本信息
/proc/stat系统和内核的统计信息
/proc/fb内核编译期间帧缓冲信息
/proc/kmsg内核日志信息
/proc/kcore表示系统物理内存,可以用gdb检查内核数据结构的当前状态
/proc/kallsyms内核符号信息,主要用于调试
/proc/timer_list内核各种计时器信息
/proc/timer_stats系统中定时器的使用情况
/proc/sysrq-trigger内核触发器(危险!)
/proc/execdomainsLinux内核当前支持的execution domains

          

(5)other

/proc/interrupts中断表
/proc/uptime系统运行时间
/proc/devices设备信息(主设备号等)
/proc/mdstat 虚拟设备信息(软raid等)
/proc/misc其他的主要设备(设备号为10)上注册的驱动
/proc/cgroupcgroup相关信息
/proc/consoles系统中所有控制台的信息
/proc/keys证书相关
/proc/key-users关于密钥用户的信息,包括密钥使用情况的统计数据

         

4、/proc 目录下的目录

acpi包含高级配置和电源接口(ACPI)相关的信息
bus提供了系统中所有总线和连接到这些总线上的设备的信息
driver包含内核识别的驱动程序的信息。这个目录通常用于内核开发和调试
fs文件系统相关的信息
ipmi包含通过 Intelligent Platform Management Interface (IPMI) 接口收集的硬件监控和管理信息
irq包含中断请求(IRQ)的信息
scsi提供 SCSI 设备的信息
sys是一个非常重要的目录,包含了系统级别的参数和设置
sysvipc包含系统虚拟进程通信(SysV IPC)的相关信息
tty包含了与终端(TTY)设备相关的信息

四、实验步骤

   要求写出实验过程和思路(用文字表述,或画流程图,或写出伪代码 都可以)。

本实验是编写一个内核模块,在/proc文件系统中增加一个目录hello,并在这个目录中增加一个文件world,文件的内容为hello world。实验步骤如下:

(1)利用proc_mkdir()函数创建目录:

          proc_parent = proc_mkdir("hello",NULL);

(2)在/proc目录下有version和softirqs等文件,本实验利用proc_create函数创建一个version文件world :

显然,创建version文件的函数为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);

该函数接收4个参数,第一个参数为文件名,第二个参数为文件的读写权限,第三个参数为其父目录的结构体指针,第四个参数为文件的读写操作结构体。

参照/proc/version文件的实现代码和本实验要求,可写出创建world文件的主要代码:

其中,world文件的父目录指针即为先前创建hello目录所返回的指针,proc_fops定义了该文件所能执行的操作,由于本实验只要求读取文件内容,因此只实现了read属性:

其中,read_proc为实现读取文件内容的函数指针,其实现如下:

(4)定义模块的初始化和清理函数

其实现如下:

(5)编写Makefile

为编译该模块,还需编写Makefile文件

五、实验数据及源代码

Proc_hello.c

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <asm/uaccess.h>static struct proc_dir_entry* proc_parent;
int len, temp;
char* msg; //字符数组static ssize_t read_proc(struct file* filp, char __user* buf, size_t count, loff_t* offp) {//该函数将文件内容通过msg复制给buf,以此实现文件内容的读取。//read_proc为实现读取文件内容的函数指针if (count > temp)count = temp;temp = temp - count;raw_copy_to_user(buf, msg, count);if (count == 0)temp = len;return count;
}static const struct file_operations proc_fops = {//赋予文件world只读的属性.read = read_proc
};void create_new_proc_entry(void) {//create a new directory named hello, and return a pointer point to this dir//创建一个名为hello的新目录,并返回指向该目录的指针proc_parent = proc_mkdir("hello", NULL); //创建一个目录helloif (!proc_parent) //创建目录失败printk(KERN_INFO "Error creating proc entry");//create a file named world, add read attribute to this file using proc_fops//创建一个名为world的文件,使用proc_fops将read属性添加到此文件//world文件的父目录指针即为先前创建hello目录所返回的指针proc_create("world", 0, proc_parent,&proc_fops); //第一个参数为文件名,第二个参数为文件的读写权限,第三个参数为其父目录的结构体指针,第四个参数为文件的读写操作结构体。msg = "hello world\n"; //文件内容len = strlen(msg); //获得字符串msg的长度temp = len;printk(KERN_INFO "1.len = %d", len);printk(KERN_INFO "proc initialized");
}int proc_init(void) { //模块的初始化函数create_new_proc_entry();return 0;
}void proc_cleanup(void) { //模块的退出和清理函数printk(KERN_INFO " Inside cleanup_module\n");remove_proc_entry("hello", proc_parent); //移除目录helloremove_proc_entry("world", NULL); //移除文件world
}module_init(proc_init); //向内核注册模块提供新功能
module_exit(proc_cleanup); //注销由模块提供所有的功能
MODULE_LICENSE("GPL"); //模块具有GUN公共许可证

Makefile文件

ifneq ($(KERNELRELEASE),) obj-m := proc_hello.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build 
PWD := $(shell pwd)
default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif 
clean:$(MAKE) -C $(KERNELDIR) M=$(PWD) clean

六、实验结果分析(截屏的实验结果,与实验结果对应的实验分析)

1、实验结果与实验程序、实验步骤、实验原理的对应分析;

2、实验过程中的问题及原因和解决办法。

首先下载Linux内核版本并解压,然后将proc_hello.c文件拷贝至Linux/fs/proc目录下,由于该目录下原本就有Makefile文件,因此要对原Makefile文件备份后再拷贝本实验中的Makefile:

mv Makefile Makefile.bak

mv my_makefile Makefile

然后,再使用make命令编译模块:

编译成功后,再使用insmod命令安装模块,可以看到该目录下多了一个ko文件,该文件即为编译成功的模块文件。

最后切换至/proc目录,即可看到结果。

出现的问题以及可能出现的问题:

权限问题:

原因:编写和加载内核模块通常需要特权,而非特权用户可能会遇到权限问题。

解决办法:使用 sudo 或在超级用户权限下执行相关操作。

模块加载失败:

原因:可能是由于编译错误、符号冲突等原因引起的。

解决办法:检查模块加载时的日志输出(使用 dmesg 命令),查找错误消息以便识别和解决问题。

七、实验思考题

1、编写一个有两个进程并发运行的程序,并在结尾设定一个死循环,编译完成后让其在后台运行,然后在前台用cat 命令查看/proc目录下的文件/proc/meminfo (当前内存信息)、/proc/vmstat (虚拟内存统计信息)、/proc/vmallocinfo(虚拟内存分配息)、/proc/filesystems(目前系统支持的文件系统)、/proc/locks(当前被内核锁定的文件)、/proc/cpuinfo ( cpu相关信息)和/proc/modules(当前系统已经加载的模块(lsmod))中信息,分析其含义。

创建一个简单的C程序,该程序创建两个并发运行的进程,然后进入死循环。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>void processFunction(int processNumber) {for (int i = 0; i < 5; i++) {printf("Process %d: Iteration %d\n", processNumber, i);sleep(1);}
}int main() {pid_t childPid;// 创建第一个子进程if ((childPid = fork()) == 0) {// 子进程1执行的代码processFunction(1);exit(0);}// 创建第二个子进程if ((childPid = fork()) == 0) {// 子进程2执行的代码processFunction(2);exit(0);}// 父进程执行的代码printf("Parent process: Waiting for child processes to finish...\n");// 进入死循环while (1) {// 保持程序运行sleep(1);}return 0;
}

编译这个程序

使用cat命令查看/proc目录下的信息。

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

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

相关文章

推荐给前端同学的自动化测试库

对于前端开发而言&#xff0c;自动化测试不仅能够提高开发效率&#xff0c;还能确保应用的稳定性和可靠性。而Python提供了多种适用于前端自动化测试的库。这些库能够帮助前端开发者轻松实现UI测试、API测试和性能测试等多种需求。本文将介绍几个Python中常用的前端自动化测试库…

YOLO11改进-模块-引入Histogram Transformer Block(HTB)解决恶劣天气(雨雾雪)

本篇文章将介绍一个新的改进机制——HTB&#xff0c;并阐述如何将其应用于YOLOv11中&#xff0c;显著提升模型性能。在现代计算机视觉任务中&#xff0c;尤其是在目标检测领域&#xff0c;YOLO系列模型因其快速和准确的检测性能而备受关注。随着YOLOv11的提出&#xff0c;我们迎…

【微服务】全面构建微服务监控体系:确保系统稳定与性能优化的关键

目录 引言一、微服务监控概述1.1 微服务监控的定义1.2 微服务监控的重要性1.3 监控的核心目标1.4 微服务监控的关键指标1.5 监控的策略 二、微服务监控的架构2.1 监控架构图2.2 架构组件2.3 监控架构示意图 三、微服务监控的工具3.1 工具概述3.2 Prometheus3.3 Grafana3.4 ELK …

CTF(二)

导言&#xff1a; 本文主要讲述在CTF竞赛中&#xff0c;web类反序列化题目unseping。。 靶场链接&#xff1a;攻防世界 (xctf.org.cn) 反序列化漏洞&#xff1a;反序列化漏洞&#xff08;二&#xff09;_fst反序列化 rocksdb 字段值错误-CSDN博客 打开后可以看到&#xff1…

2024-10-16 学习人工智能的Day8

函数 定义&#xff08;创建&#xff09; 函数的创建def开始&#xff0c;后接函数名&#xff0c;在给参数表最后冒号表示函数基础信息给定 换行书写函数内部定义&#xff0c;在函数内部定义操作&#xff0c;最后函数自带返回&#xff0c;无定义返回值返回为None&…

Scala的reduce

reduce是一种集合操作&#xff0c;用于对集合中的元素进行聚合操作&#xff0c;返回一个单一的结果。它通过指定的二元操作&#xff08;即取两个元素 进行操作&#xff09;对集合中所有的元素进行递归处理&#xff0c;并最终将其合并为一个值。 def main(args: Array[String]):…

涂鸦智能落地 Koupleless 合并部署,实现云服务降本增效

文&#xff5c;八幡、朵拉 杭州涂鸦智能技术专家 主要研究微服务与可观测、消息引擎、任务调度、数据层中间件等领域。 本文 5389 字 阅读 15 分钟 当前涂鸦通过 Koupleless 的静态合并部署能力&#xff0c;很好地解决了资源浪费问题。 为了进一步提升研发效率&#xff0c;涂鸦…

MYSQL 拼接函数

目录 1、CONCAT 2、CONCAT_WS 1、CONCAT 解释&#xff1a;用于拼接两个或多个字符串成一个字符串。如果任何一个参数为 NULL&#xff0c;则 CONCAT 函数的结果也会是 NULL。 语法格式&#xff1a;SELECT concat(column_name1,column_name2,...) FROM table_name 中文注释&…

关于Docker

文章目录 DockerWSLWMWare虚拟机CentOS7安装dockerdocker基础命令docker数据卷挂载本地目录或文件 Docker Docker是一个快速构建、运行、管理应用的工具。 能够快速部署项目、项目依赖的组件、项目运行的环境。 项目传统的部署方式缺点&#xff1a; 各类环境、组件命令太多&…

英语写作中“认为是……”consider/view/regard/deem的用法

“认为是……”是常见的表达&#xff0c;英语写作中可以使用consider、view、regard、deem和它们的被动态表达。注意&#xff0c;在科技论文写作中它们的被动态往往更常用&#xff0c;所以我们下面只给出被动态的用法&#xff1a; Be considered …… Be considered to be/as…

cmake Qt模板

一、常用模块 1. 构建完成后自动调用windeployqt打包 add_custom_command(TARGET ${PROJECT_NAME} POST_BUILDCOMMAND "${QT_PATH}/bin/windeployqt.exe" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.exe" )需要将QT_PATH设为Qt的安装目录。还可以用-…

TypeScript 和 JavaScript的区别

一、类型系统 TypeScript&#xff1a; 是一种静态类型语言&#xff0c;它在编译时进行类型检查。开发者可以在编写代码时指定变量、函数参数和返回值的类型&#xff0c;从而在代码运行之前发现类型错误。提供了类型注解、接口、枚举等特性&#xff0c;使得代码更加结构化和易于…

具体应用案例:树莓集团助力传统制造业数字化转型

以一家传统制造业企业为例&#xff0c;在树莓集团的支持下&#xff0c;该企业逐步完成了数字化转型&#xff1a; 1. 生产智能化&#xff1a; 通过树莓集团提供的物联网和智能制造解决方案&#xff0c;企业的生产线实现了全面数字化&#xff0c;实时监控设备状态&#xff0c;进行…

证明一个特定形式的函数在其三个正根中,两个较小根处的导数之和小于零

假设 M M M和 Q Q Q是给定的正的常数&#xff0c;然后定义一个函数 f ( r ) f(r) f(r)。这个函数的定义如下&#xff1a; f ( r ) 1 − M r 2 Q r 4 − r 2 , r > 0 f(r) 1 - \frac{M}{r^2} \frac{Q}{r^4} - r^2, \quad r > 0 f(r)1−r2M​r4Q​−r2,r>0。 如果 …

出现 request.getScheme() 获取不到https 解决方法

目录 1. 问题所示2. 原理分析3. 解决方法1. 问题所示 涉及到 Nginx 和 Tomcat 之间的交互,以及如何在这种架构下正确处理请求的协议和客户端信息 问题的根源主要在Nginx中 当 Nginx 作为反向代理时,与客户端之间建立 SSL 连接,而 Tomcat 只接收到来自 Nginx 的 HTTP 请求…

CasADi库C++用法整理学习---以NMPC代码为例

参考几个使用方法博客 1 官方文档写的很清楚 对SM&#xff0c;DM&#xff0c;XM数据类型疑惑。什么时候使用什么样的类型&#xff0c;还是都可以&#xff1f; x MX.sym(“x”) 这将创建一个 11 矩阵&#xff0c;即一个包含名为 x 的符号基元的标量。这只是显示名称&#xff…

关键词提取技术:TF-IDF 详解

1. 什么是TF-IDF&#xff1f; TF-IDF&#xff08;Term Frequency-Inverse Document Frequency&#xff09; 是一种统计方法&#xff0c;用于评估单词在文档集或语料库中的重要性。它是自然语言处理和信息检索中的核心技术之一。 TF-IDF主要基于以下两个概念&#xff1a; TF&a…

书籍推荐:《从零构建大型语言模型》附免费PDF下载

通过从头开始构建一个大型语言模型&#xff0c;了解如何创建、训练和调整大型语言模型 &#xff08;LLMs&#xff09;&#xff01; 一、构建大型语言模型&#xff08;从头开始&#xff09; 在《构建大型语言模型&#xff08;从头开始&#xff09;》中&#xff0c;你将了解如何…

C++ —— 关于继承(inheritance)

目录 1. 继承的概念及定义 1.1 继承的概念 1.2 继承的定义格式 1.3 继承基类成员访问方式的变化 1.4 类模板的继承 2.基类与派生类的转换 3. 继承中的作用域 3.1 隐藏规则 4. 派⽣类的默认成员函数 4.1 4个常见默认成员函数 4.2 实现⼀个不能被继承的类 5. 继承与友元…

webpack 学习入门

webpack 1. 简介1.1 webpack 是什么1.2 webpack 五个核心概念1.2.1 入口 - Entry1.2.2 出口 - Output1.2.3 Loader1.2.4 插件 - Plugins1.2.6 模式 - Mode 2. webpack 初体验2.1 初始化配置2.1.1. 准备2.1.2. 写代码2.1.3 编译打包应用 3. webpack 开发环境的基本配置3.1 打包样…