【操作系统】实验八 proc文件系统
🕺作者: 主页
我的专栏 C语言从0到1 探秘C++ 数据结构从0到1 探秘Linux 😘欢迎关注:👍点赞🙌收藏✍️留言
🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的很重要,有问题可在评论区提出,感谢支持!!!
文章目录
- 实验八
 - 实验目的
 - 实验准备
 - 编译内核模块
 - 加载内核模块
 - 查看和操作文件内容
 - 卸载内核模块
 
实验八
实验目的
通过加载内核模块,为/proc文件系统创建以下内容:
- 一个名叫proc_test的子目录。
 - 一个名叫current的文件,只读,读出的内容是读它的进程的情况。
 - 一个名叫current_too的链接,指向current。
 - 一个名叫hello的文件,可读可写。读出的内容是上次写的内容前面加两句话。
 
实验准备
- 复制文件到工作目录: 
- 使用将 proc_test.c 文件复制到工作目录。
 
 

- 进入工作目录: 
- 进入工作目录。
 
 

编译内核模块
- 编译 proc_test.c 模块: 
- 编写proc_test.c代码
 
 
#include <linux/sched.h>
#include <linux/init_task.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>#define MAX_LENGTH 1024static char hello_content[MAX_LENGTH] = "hello world\n";  // 初始化一个长度为 1024 的字符数组,并赋值 "hello world\n"//用于处理对 /proc/proc_test/hello 文件的写操作。它从用户空间接收数据并将其复制到内核空间的 hello_content 数组中,偏移量为12。如果写入的字符数超过了数组长度,会返回错误。
static ssize_t hello_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) {if (count > MAX_LENGTH - 1)  // 如果写入的字符数大于 MAX_LENGTH - 1,则返回错误return -EINVAL;if (copy_from_user(hello_content + 12, buffer, count))  // 将用户空间的数据复制到内核空间的 hello_content 数组中,偏移量为 12return -EFAULT;hello_content[count + 12] = '\0';  // 在 hello_content 数组中写入字符串结束符'\0'return count;  // 返回成功写入的字符数
}
//用于处理对 /proc/proc_test/hello 文件的读操作。它将 hello_content 的内容输出到 seq_file 结构体中,从而在读取文件时显示出来。
static int hello_proc_show(struct seq_file *m, void *v) {seq_printf(m, "%s", hello_content);  // 将 hello_content 的内容输出到 seq_file 结构体 m 中return 0;
}
//用于打开 /proc/proc_test/hello 文件。它调用 single_open 函数来打开文件,并指定 hello_proc_show 函数来显示文件内容。
static int hello_proc_open(struct inode *inode, struct file *file) {return single_open(file, hello_proc_show, NULL);  // 打开 proc 文件,调用 hello_proc_show 函数来显示内容
}
//定义了对 /proc/proc_test/hello 文件的操作集合,包括打开、读取、写入、定位和释放文件。
static const struct proc_ops hello_proc_ops = {.proc_open = hello_proc_open,  // 打开文件操作.proc_read = seq_read,  // 读取文件操作.proc_write = hello_proc_write,  // 写文件操作.proc_lseek = seq_lseek,  // 文件定位操作.proc_release = single_release,  // 释放文件操作
};
//用于处理对 /proc/proc_test/current 文件的读操作。它输出当前进程的相关信息,如进程ID、优先级、进程名等。
static int current_proc_show(struct seq_file *m, void *v) {struct task_struct *cur = current;seq_printf(m, "进程ID: %d\n", cur->pid);  // 输出进程IDseq_printf(m, "优先级: %d\n", cur->prio);  // 输出进程优先级seq_printf(m, "静态优先级: %d\n", cur->static_prio);  // 输出静态优先级seq_printf(m, "正常优先级: %d\n", cur->normal_prio);  // 输出正常优先级seq_printf(m, "策略: %d\n", cur->policy);  // 输出进程调度策略seq_printf(m, "进程名: %s\n", cur->comm);  // 输出进程名return 0;
}
//用于打开 /proc/proc_test/current 文件。它调用 single_open 函数来打开文件,并指定 current_proc_show 函数来显示文件内容。
static int current_proc_open(struct inode *inode, struct file *file) {return single_open(file, current_proc_show, NULL);  // 打开 proc 文件,调用 current_proc_show 函数来显示内容
}
// 定义了对 /proc/proc_test/current 文件的操作集合,包括打开、读取、定位和释放文件。
static const struct proc_ops current_proc_ops = {.proc_open = current_proc_open,  // 打开文件操作.proc_read = seq_read,  // 读取文件操作.proc_lseek = seq_lseek,  // 文件定位操作.proc_release = single_release,  // 释放文件操作
};
//模块的初始化函数,它在内核加载模块时被调用。它创建了一个名为 /proc/proc_test 的目录,并在其中创建了文件 current、current_too 和 hello。
static int __init proc_test_init(void) {struct proc_dir_entry *test_dir;test_dir = proc_mkdir("proc_test", NULL);  // 创建一个目录 /proc/proc_testproc_create("current", 0, test_dir, ¤t_proc_ops);  // 在 /proc/proc_test 目录下创建一个名为 "current" 的文件proc_symlink("current_too", test_dir, "current");  // 在 /proc/proc_test 目录下创建一个名为 "current_too" 的符号链接,指向 "current"proc_create("hello", 0666, test_dir, &hello_proc_ops);  // 在 /proc/proc_test 目录下创建一个名为 "hello" 的文件,可读可写权限为 0666return 0;
}
//模块的退出函数,它在内核卸载模块时被调用。它移除了之前创建的 /proc/proc_test 目录及其下的文件。
static void __exit proc_test_exit(void) {remove_proc_entry("proc_test/current", NULL);  // 移除 /proc/proc_test 目录下的文件 "current"remove_proc_entry("proc_test/current_too", NULL);  // 移除 /proc/proc_test 目录下的文件 "current_too"remove_proc_entry("proc_test/hello", NULL);  // 移除 /proc/proc_test 目录下的文件 "hello"remove_proc_entry("proc_test", NULL);  // 移除 /proc/proc_test 目录
}MODULE_LICENSE("GPL");  // 指定模块的许可证为 GPL
module_init(proc_test_init);  // 指定模块的初始化函数
module_exit(proc_test_exit);  // 指定模块的退出函数
 
- 使用makefile文件编译内核模块。
 
obj-m:=proc_test.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD       := $(shell pwd)
default:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
 
- 使用make命令编译
 
make
 
加载内核模块
- 加载编译后的模块: 
- 使用insmod加载模块。
 
 
insmod proc_test.ko
 
- 检查是否加载成功:
 
- 使用lsmod命令检查模块是否加载。
 
lsmod | grep proc_test
 
- 检查是否创建了 /proc/proc_test 目录: 
- 进入/proc目录查看。
 
 
cd /proc
ls
 

- 检查 /proc/proc_test 目录下是否创建了三个文件: 
- current、current_too 和 hello。
 
 
cd /proc/proc_test
ls
 

查看和操作文件内容
- 查看 current 文件的内容: 
- 使用more命令查看。
 
 
more current
 
- 查看 current_too 文件的内容: 
- 使用more命令查看。
 
 
more current_too
 
- 查看 hello 文件的内容: 
- 使用more命令查看。
 
 
more hello
 
- 写入 hello 文件: 
- 使用echo命令将数据输入到hello文件。
 
 

- 再次查看 hello 文件的内容: 
- 使用more命令查看。
 
 
more hello
 
卸载内核模块
- 卸载加载的内核模块: 
- 使用rmmod卸载模块。
 
 
rmmod proc_test
 
- 检查是否卸载成功: 
- 使用lsmod命令检查模块是否卸载。
 
 
lsmod | grep proc_test
 
相关文章:
【操作系统】实验八 proc文件系统
🕺作者: 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux 😘欢迎关注:👍点赞🙌收藏✍️留言 🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的很重要&…...
基于RMF的信贷风控标签客户分层管理
根据美国 数据库营销研究所Arthur Hughes的研究,客户数据库中有3个神奇的要素,这3个要素构成了数据分析最好的指标:最近一次消费 (Recency)、消费频率(Frequency)、消费金额 (Monetary)。这就是RMF模型,RMF模型是用户分层的重要手…...
【MySQL】如何通过DDL去创建和修改员工信息表
🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 💫个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-fmKISDBsFq74ab2Z {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…...
Spring 事务原理一
从本篇博客开始,我们将梳理Spring事务相关的知识点。在开始前,想先给自己定一个目标:通过此次梳理要完全理解事务的基本概念及Spring实现事务的基本原理。为实现这个目标我想按以下几个步骤进行: 讲解事务中的一些基本概念使用Sp…...
creo草绘3个实例学习笔记
creo草绘3个实例 文章目录 creo草绘3个实例草绘01草绘02草绘03 草绘01 草绘02 草绘03...
Modern C++ std::move的实现原理
前言 有一节我们分析了std::bind的实现原理,本节稍作休息分析一个比较简单的std::move 原理 std::move的原理太简单了,一句话:就是把传进来的参数强转为右值引用类型。作用为调用移动构造函数,或移动赋值函数。下面通过例子和代…...
爬虫工作量由小到大的思维转变---<第四十章 Scrapy Redis 实现IP代理池管理的最佳实践>
前言: 本篇是要结合上篇一起看的姊妹篇:爬虫工作量由小到大的思维转变---<第三十九章 Scrapy-redis 常用的那个RetryMiddleware>-CSDN博客 IP代理池的管理对于确保爬虫的稳定性和数据抓取的匿名性至关重要。围绕Scrapy-Redis框架和一个具体的IP代理池中…...
C# 实现 XOR 密码
XOR密码(异或密码)是一种简单的加密算法,它使用异或(XOR)操作来对明文和密钥进行加密和解密。 异或操作是一种位运算,它对两个二进制数的对应位进行比较,如果两个位相同(都为0或都为…...
【Web前端开发基础】CSS3之空间转换和动画
CSS3之空间转换和动画 目录 CSS3之空间转换和动画一、空间转换1.1 概述1.2 3D转换常用的属性1.3 3D转换:translate3d(位移)1.4 3D转换:perspective(视角)1.5 3D转换:rotate3d(旋转&a…...
Go实现一个简单的烟花秀效果(附带源码)
在 Go 语言中,要实现烟花秀效果可以使用 github.com/fogleman/gg 包进行绘图。以下是一个简单的例子: 首先,确保你已经安装了(有时候需要梯子才可以安装) github.com/fogleman/gg 包: go get -u github.c…...
【数学建模】插值与拟合
文章目录 插值插值方法用Python解决插值问题 拟合最小二乘拟合数据拟合的Python实现 适用情况 处理由试验、测量得到的大量数据或一些过于复杂而不便于计算的函数表达式时,构造一个简单函数作为要考察数据或复杂函数的近似 定义 给定一组数据,需要确定满…...
全卷积网络:革新图像分析
一、介绍 全卷积网络(FCN)的出现标志着计算机视觉领域的一个重要里程碑,特别是在涉及图像分析的任务中。本文深入探讨了 FCN 的概念、它们的架构、它们与传统卷积神经网络 (CNN) 的区别以及它们在各个领域的应用。 就像…...
ubuntu20.04 格式化 硬盘 扩展硬盘GParted
如何在 Ubuntu 22.04 LTS 上安装分区编辑器 GParted?_gparted安装-CSDN博客 sudo apt install gparted 步骤5:启动GParted 安装完成后,您可以在应用程序菜单中找到GParted。点击它以启动分区编辑器。 通过以上步骤,您可以在Ubun…...
docker的资源限制(cgroup)
前瞻 Docker 通过 Cgroup 来控制容器使用的资源配额,包括 CPU、内存、磁盘三大方面, 基本覆盖了常见的资源配额和使用量控制。 Cgroup 是 ControlGroups 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离进程组所使用的物理资源(如 CPU、…...
ChatGPT与文心一言:应用示例与体验比较
ChatGPT 和文心一言哪个更好用? 为了更好地感受ChatGPT和文心一言这两款AI助手如何在实际运用中竞相辉映,我将提供一些典型的应用示例。这些示例都取自真实的用户体验,以帮助解释这两种工具如何让日常生活或工作变得更加轻松。 ChatGPT Ch…...
紫光展锐T760_芯片性能介绍_展锐T760安卓核心板定制
展锐T760核心板是一款基于国产5G芯片的智能模块,采用紫光展锐T760制程工艺为台积电6nm工艺,支持工艺具有出色的能效表现。其采用主流的44架构的八核设计,包括4颗2.2GHz A76核心和4颗A55核心设计,内存单元板载可达8GB Ram256GB ROM…...
从动力系统研究看当今数学界
6.3... Milnor’s definition of “attractors” which has been criticized above by us). The work of [KSS2] of asserting the existence of “nice open set” of Ω(p.148) would be likely not verified, for example we think the first sentence “… since f is nont…...
【征服redis15】分布式锁的功能与整体设计方案
目录 1. 分布式锁的概念 2.基于数据库做分布式锁 2.1 基于表主键唯一做分布式锁 2.2 基于表字段版本号做分布式锁 2.3 基于数据库排他锁做分布式锁 3.使用Redis做分布式锁 3.1 redis实现分布式锁的基本原理 3.2 问题一:增加超时机制,防止长期持有…...
MATLAB中实现机械臂逆运动学求解的方法之一是使用阻尼最小二乘法
MATLAB中实现机械臂逆运动学求解的方法之一是使用阻尼最小二乘法。阻尼最小二乘法通常用于处理数值求解问题中的不稳定性和噪声。以下是一个简单的MATLAB代码示例,演示了机械臂逆运动学的阻尼最小二乘法求解: % 机械臂参数 L1 1; % 机械臂长度 L2 1;…...
2024.1.24 GNSS 学习笔记
1.伪距观测值公式 2.载波相位观测值公式 3.单点定位技术(Single Point Positionin, SPP) 仅使用伪距观测值,不使用其他的辅助信息获得ECEF框架下绝对定位技术。 使用广播星历的轨钟进行定位,考虑到轨钟的米级精度,所以对于<1米的误差&…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
