virt_to_page函数
在 Linux 内核中使用 virt_to_page 接口将内核虚拟地址转换为对应的 struct page * 指针时,需要格外小心。以下是关键的使用注意事项:
地址必须在内核线性映射区域 (Low Memory / Directly Mapped Region)
virt_to_page 仅适用于通过 kmalloc, alloc_pages (GFP_KERNEL 或 GFP_ATOMIC 等标志)、__get_free_pages 等函数分配的物理上连续的内存块的首地址。
不适用于:
vmalloc 分配的内存:这些地址在内核的 VMALLOC 区域,没有直接的 1:1 物理映射。使用 vmalloc_to_page 代替。
用户空间地址:用户空间地址需要通过 get_user_pages 或类似机制获取其对应的 struct page *。
内核镜像代码/数据段、模块代码段等特殊区域的地址:这些地址通常没有对应的 struct page 结构体,或者映射关系复杂。
IO 映射地址 (ioremap 返回的):使用 phys_to_page(page_t ...
根据物理地址获得虚拟地址
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081#include <linux/init.h>#include <linux/module.h>#include <linux/platform_device.h>#include <linux/mm.h>#include <linux/rwsem.h>#include <linux/rmap.h>#include "klookup_symbol.h"#include <linux/slab.h>static int g_enter_num;struct vma_info { struct list_head list; struct vm_area_struc ...
Linux Page Cache 工作原理解析
Linux pagecache介绍
Linux 的 Page Cache(页面缓存) 是内核用于显著提升文件系统 I/O 性能的核心机制。它的核心思想非常简单而有效:将磁盘上的文件数据缓存在空闲的物理内存(RAM)中。
核心原理与工作流程
初次读取:
当进程请求读取磁盘上的文件数据时(例如,使用 read() 系统调用)。
内核首先检查请求的数据块是否已经存在于 Page Cache 中。
如果不在(Cache Miss):
内核发起实际的磁盘 I/O 操作,将数据从磁盘读取出来。
内核将这份读取到的数据复制一份,存放在物理内存的一个或多个页面(Page)中(通常是 4KB 大小的块)。
这个内存中的副本就是 Page Cache。
最后,内核将数据从 Page Cache 复制到用户进程提供的缓冲区。
如果在(Cache Hit):
内核直接将数据从 Page Cache 复制到用户进程的缓冲区。
避免了耗时的磁盘 I/O 操作! 这是性能提升的关键。
后续读取:
如果其他进程(或同一个进程再次)请求访问相同文件区域的相同数据。
内核直接 ...
Linux Smack模块功能与应用介绍
Linux smack模块介绍
Linux 的 Smack(Simplified Mandatory Access Control Kernel)是一种 Linux 内核安全模块,属于 LSM(Linux Security Module)框架的实现之一。它的设计目标是提供强制访问控制功能,同时力求简单性和易用性,主要面向嵌入式系统和资源受限环境。
以下是 Smack 的核心概念和介绍:
核心思想:标签(Labels)
Smack 的核心是为系统中的所有主体(Subject - 通常是进程)和对象(Object - 文件、目录、套接字、管道、设备等)分配一个简单的、人类可读的文本字符串作为安全标签。
例如:System, Application, User, Internet, Secret。
标签名称通常很短(最多 255 个字符,但实践中都很简洁),便于配置和理解。
访问控制规则:
Smack 的规则基于主体标签对对象标签的访问权限。
规则非常直接:一个带有标签 A 的进程(主体)能否访问(读、写、执行等)一个带有标签 B 的对象(文件、目录等)?
访问决策由一个简单的访问 ...
Linux virt_to_page使用注意事项
Linux接口virt_to_page使用注意事项
在 Linux 内核中使用 virt_to_page 接口将内核虚拟地址转换为对应的 struct page * 指针时,需要格外小心。以下是关键的使用注意事项:
地址必须在内核线性映射区域 (Low Memory / Directly Mapped Region)
virt_to_page 仅适用于通过 kmalloc, alloc_pages (GFP_KERNEL 或 GFP_ATOMIC 等标志)、__get_free_pages 等函数分配的物理上连续的内存块的首地址。
不适用于:
vmalloc 分配的内存:这些地址在内核的 VMALLOC 区域,没有直接的 1:1 物理映射。使用 vmalloc_to_page 代替。
用户空间地址:用户空间地址需要通过 get_user_pages 或类似机制获取其对应的 struct page *。
内核镜像代码/数据段、模块代码段等特殊区域的地址:这些地址通常没有对应的 struct page 结构体,或者映射关系复杂。
IO 映射地址 (ioremap 返 ...
软件工程与计算机科学区别解析
软件工程和计算机科学有什么区别
软件工程(Software Engineering)和计算机科学(Computer Science)是紧密相关但目标、侧重点和应用场景不同的两个领域。简单来说:
🧠 核心区别:
计算机科学(CS)
是什么? 研究“计算”本身的理论、原理和数学基础。
核心问题:“计算机能做什么?如何高效地计算?如何用数学建模问题?”
重点领域:
算法与数据结构(如何高效解决问题)
计算理论(可计算性、复杂度)
人工智能/机器学习
操作系统原理
计算机网络理论
编程语言设计
密码学
目标: 探索知识的边界,解决抽象问题 ✅
软件工程(SE)
是什么? 研究如何系统化、可维护、高效地构建可靠软件。
核心问题:“如何多人协作开发高质量软件?如何管理需求、测试、部署和维护?”
重点领域:
软件开发生命周期(需求分析 → 设计 → 编码 → 测试 → 维护)
项目管理与团队协作(敏捷开发、DevOps)
软件架构设计
质量保证与测试(自动化测试、CI/CD)
软件维护与演化 ...
Docker文件系统格式及存储驱动详解
docker支持的文件系统格式
Docker 支持的文件系统格式主要涉及两个层面:
存储驱动 (Storage Driver): 这是 Docker 的核心组件,负责管理镜像层和容器层如何在宿主机文件系统上存储、分层和联合挂载。存储驱动决定了 Docker 使用哪种联合文件系统 (Union File System) 技术。
**底层文件系统 (Underlying Filesystem)**: 这是存储驱动实际读写数据的宿主机文件系统格式(如 ext4, xfs, btrfs, zfs, ntfs 等)。存储驱动需要底层文件系统的特定功能支持才能工作。
一、 Linux 上主要的存储驱动及其支持的底层文件系统
**overlay2 (推荐且默认)**:
技术: 基于 OverlayFS 联合文件系统。
底层文件系统要求:
ext4 (推荐,需要启用 d_type=true 选项,现代发行版默认启用)。
xfs (推荐,需要启用 ftype=1 选项,RHEL/CentOS 7 及以上默认启用)。
btrfs (需要配置为 d_type 支持)。
f2fs (需要配置为 ...
Linux下查看进程用到了哪些动态库的函数
Linux下查看进程用到了哪些动态库的函数
Linux下查看进程用到了哪些动态库的接口
在Linux下,查看进程使用的动态库及其接口,可以通过以下方法实现:
1. 查看进程加载的动态库文件方法 1:通过 /proc/<PID>/maps 文件1cat /proc/<PID>/maps | grep '\.so'
说明:列出进程内存映射中所有加载的 .so 动态库文件路径。替换 <PID> 为实际进程ID。
方法 2:使用 pmap 命令1pmap -x <PID> | grep '\.so'
说明:显示进程的内存映射,过滤出动态库路径。
方法 3:使用 lsof 命令1lsof -p <PID> | grep '\.so'
说明:列出进程打开的文件,过滤出共享库文件(.so)。
2. 查看动态库导出的接口(符号)方法 1:使用 nm 命令1nm -D /path/to/library.so
说明:-D 选项显示动态符号表(导出的接口)。示例输出: ...
Linux查看进程动态库方法总结
如何查找进程用到的动态库
在Linux系统中,查看进程使用的动态库(共享库)有多种方法,以下是几种常用且高效的方式:
方法1:通过 /proc 文件系统(推荐)步骤:
获取目标进程的PID(例如通过 ps -ef | grep 进程名 查询)
直接查看进程的内存映射文件:1cat /proc/<PID>/maps | grep '\.so'
示例:1cat /proc/1234/maps | grep '\.so'
输出特点:显示所有加载的.so文件及其内存地址,清晰易读。
方法2:使用 lsof 命令命令:
1lsof -p <PID> | grep '\.so'
示例:
1lsof -p 1234 | grep '\.so'
输出特点:列出进程打开的所有.so文件(包括完整路径),适合查看详细信息。
方法3:使用 pmap 命令命令:
1pmap <PID> | grep '\.so'
示例:
1pmap 1234 | grep ...
Linux UCE中断处理流程
Linux UCE中断入口
在 Linux 内核中,UCE (Uncorrectable Error) 中断(更准确地说是异常)通常指的是由硬件报告的无法纠正的严重错误,最常见的是内存 ECC (Error Correcting Code) 不可纠正错误或总线不可纠正错误。这些错误表明硬件发生了致命故障,通常无法安全地继续执行。
处理这类错误的入口点在内核中称为MCE (Machine Check Exception) 处理路径。UCE 是 MCE 的一种类型(严重等级最高)。
以下是 Linux 内核处理 UCE 的核心入口点流程(以 x86/x86_64 架构为例):
硬件触发:
当 CPU 检测到或接收到来自其他硬件组件(如内存控制器、PCIe 设备)报告的不可纠正错误时,会触发一个**机器检查异常 (Machine Check Exception)**。在 x86 上,这个异常对应的中断向量号是 #18。
汇编入口点 (entry_INT18):
内核在初始化时,通过中断描述符表 (IDT) 将向量 18 关联到特定的汇编入口点函数。在 x86_64 内核中 ...
Linux限定函数执行时间方法总结
Linux中限定函数执行时间的接口
在 Linux 中,有多种方法可以限定函数的执行时间。以下是几种常用接口和技术:
1. 信号机制(SIGALRM)使用 alarm() 或 setitimer() 设置定时器,超时后发送 SIGALRM 信号中断执行。
示例代码:1234567891011121314151617181920212223242526#include <unistd.h>#include <signal.h>#include <setjmp.h>#include <stdio.h>static jmp_buf env;void timeout_handler(int sig) { longjmp(env, 1); // 跳转回 setjmp 位置}int main() { signal(SIGALRM, timeout_handler); alarm(3); // 设置 3 秒超时 if (setjmp(env) == 0) { // 尝试 ...
刷新SELinux标签的内核接口
刷新selinux标签的内核接口
在 Linux 内核中,刷新 SELinux 标签(Security Context)的核心接口是 setxattr() 系统调用,通过操作扩展属性(Extended Attributes)实现。以下是关键细节:
1. 底层机制:扩展属性 (xattr)
SELinux 标签存储在文件的 security.selinux 扩展属性中。
刷新标签本质是修改该属性:1setfattr -n security.selinux -v "new_context" /path/to/file
2. 用户空间工具的内核调用
restorecon 工具(最常用):
调用 selabel_lookup(3) 库函数,根据策略规则(file_contexts)计算正确标签。
通过 setxattr() 将新标签写入 security.selinux 属性。
setfiles 工具:
直接解析策略文件并调用 setxattr() 批量修改标签。
3. 关键内核接口
系统调用:1int setxattr(const char *path, co ...
普通用户无法通过su切换到root
普通用户无法通过su切换到root
普通用户无法通过 su 切换到 root 是 Linux 系统设计中常见的安全措施,尤其是在 Ubuntu 及其衍生版(如 Mint)中。原因和解决方法如下:
主要原因:
Root 账户默认被禁用
Ubuntu 等系统默认不设置 root 密码,因此无法直接用 su 切换。
目的是强制用户通过 sudo 执行特权命令,减少安全风险。
用户不在 sudo 组
只有属于 sudo 组(或 wheel 组,取决于发行版)的用户才能使用 sudo 或 su。
错误的密码
若已启用 root 账户但切换失败,可能是密码输入错误(注意:su 需输入 root 密码,而非用户密码)。
解决方案:1. 使用 sudo 临时获取 root 权限(推荐) 123sudo -i # 切换到 root 环境(输入当前用户密码)sudo su # 等价于上一条命令sudo <command> # 直接以 root 权限执行命令
✅ 前提:当前用户必须在 sudo 组中(Ubuntu ...
Linux内核AES加密算法使用指南
Linux内核AES加密算法用法
在 Linux 内核中使用 AES 加密算法主要通过 内核加密 API 实现。这个 API 提供了一个抽象层,允许内核模块(如文件系统加密 dm-crypt/LUKS、IPSec、磁盘加密等)使用各种加密算法,包括 AES,而无需关心底层具体的实现(是软件实现还是硬件加速)。
以下是使用内核 AES 加密的基本步骤和要点:
核心组件:
struct crypto_skcipher: 这是表示对称密钥加密(如 AES)上下文的句柄。它封装了算法、密钥、操作模式(如 CBC, XTS, CTR, GCM 等)等信息。
struct skcipher_request: 这是用于封装单次加密或解密操作请求的结构。它包含输入/输出数据的散列表(struct scatterlist)、初始化向量(IV)、异步操作完成后的回调函数等信息。
struct scatterlist: 用于描述分散/聚集 I/O 的数据缓冲区。内核加密 API 通常操作的是 scatterlist 而不是直接的线性内存地址,以高效处理可能分散在物理 ...
Linux init_module与finit_module区别
Linux init_module和finit_module的区别
init_module 和 finit_module 都是 Linux 内核中用于加载内核模块的系统调用,但它们在数据传递方式和效率上有显著区别:
1. init_module
原型:int init_module(void *module_image, unsigned long len, const char *param_values);
工作方式:
需要用户空间程序预先将整个内核模块文件(.ko)读入内存。
通过指针 module_image 将模块数据传递给内核。
len 指定内存中模块数据的大小。
param_values 传递模块参数(字符串格式,如 "debug=1")。
缺点:
消耗用户态内存(需完整加载模块)。
额外内存拷贝(用户态→内核态)。
2. finit_module
原型:int finit_module(int fd, const char *param_values, int flags);
工作方式:
通过文件描述符 fd 传递模块(需提前打开模块文件) ...