Linux内核学习轨迹第六部:文件操作的全链路(第四节)

解决UNITE数据库注释高unassigned率:手把手教你训练专属真菌分类器(含预训练模型分享) 本文针对使用UNITE数据库进行真菌ITS序列注释时出现的高未分配率问题,提供了详细的实战解决方案。通过对比vsearch直接注释与Naive Bayes分类器的原理差异,文章手把手指导读者在QIIME 2环境中训练专属分类器,包括数据准备、模型训练、参数优化及效果验证,并分享了预训练模型,旨在显著提升真菌群落分析的注释准确性和数据利用率。 阅读详情

4. 文件操作的全链路:open/read/write/close的内核实现

用户态所有的文件IO操作,最终都通过VFS的统一接口完成。VFS层封装了所有文件系统的共性逻辑:路径解析、权限检查、缓存管理、参数校验、安全钩子,而与存储格式相关的差异化逻辑,完全下沉到具体文件系统的file_operations函数集实现。
本章节基于Linux 6.6 LTS内核,完整拆解最核心的4个文件操作系统调用的全链路内核实现,纠正行业内常见的认知误区,同时补充工程场景的避坑指南。

4.1 open() 系统调用全链路实现

open()是所有文件操作的入口,核心目标是:完成路径解析、权限校验、文件创建(可选)、分配文件描述符(fd)、创建内核file实例,最终返回fd给用户态。

4.1.1 用户态原型与内核入口

用户态原型:
// 基础版本
int open(const char *pathname, int flags);
// 带创建权限的版本,O_CREAT标志必须传mode参数
int open(const char *pathname, int flags, mode_t mode);

  • 核心flags参数:O_RDONLY/O_WRONLY/O_RDWR(访问模式)、O_CREAT(文件不存在则创建)、O_EXCL(配合O_CREAT,文件已存在则报错)、O_APPEND(追加写)、O_NONBLOCK(非阻塞IO)、O_DIRECT(直接IO)、O_SYNC(同步写)。
内核入口:Linux 6.6内核默认使用sys_openat2()(更安全的带路径解析限制的版本),兼容传统的sys_open(),最终都会落到核心函数do_filp_open()。

4.1.2 核心数据结构

1.struct nameidata:路径解析的核心上下文结构,存储路径解析过程中的中间状态、挂载信息、dentry、inode等,定义在include/linux/namei.h中,核心字段:

struct nameidata {
    struct path     path;       // 当前解析到的路径(dentry + vfsmount)
    struct qstr     last;       // 最后一个路径分量的名称
    struct path     root;       // 进程的根目录,用于绝对路径解析
    unsigned int    flags;      // 路径解析标志,比如LOOKUP_FOLLOW(跟随软链接)
    unsigned int    depth;      // 软链接嵌套深度,防止循环引用
};

2.struct files_struct:进程的文件描述符表,每个进程有一个独立的实例,管理该进程所有打开的fd与file实例的映射,定义在include/linux/fdtable.h中,核心字段:

struct files_struct {
    atomic_t        count;      // 引用计数,线程共享时计数
    spinlock_t      file_lock;  // 保护文件描述符表的锁
    struct fdtable __rcu *fdt;  // fd表,rcu保护
    struct fdtable  fdtab;      // 内嵌的初始fd表,默认支持64个fd
};

4.1.3 open() 全链路执行流程

用户态 open() → sys_open()/sys_openat2() → do_sys_open()
    ↓
1. 分配空闲文件描述符fd

   ├→ 调用get_unused_fd_flags(),在进程的files_struct中找到最小的可用fd
   ├→ 检查进程的fd限制(ulimit -n),超过则返回EMFILE错误
   └→ 预留fd位置,等待后续与file实例绑定
    ↓
2. 路径解析:do_filp_open()

   ├→ 初始化struct nameidata上下文,设置路径解析标志
   ├→ 优先使用RCU-walk(无锁快速路径)解析路径:
   │  ├→ 基于RCU机制遍历dcache,不需要加dentry引用计数,性能极高
   │  ├→ 全程无锁,仅在最后一步验证dentry的有效性
   │  └→ 解析失败(比如dentry被释放、跨挂载点),回退到ref-walk慢速路径
   ├→ ref-walk慢速路径:
   │  ├→ 逐级解析路径分量,给每个dentry加引用计数
   │  ├→ 处理跨挂载点、软链接、权限检查
   │  └→ 路径不存在且设置了O_CREAT时,停留在父目录的dentry
   ├→ 路径解析完成,得到最终的dentry和inode
   └→ 权限检查:检查进程是否有对应目录的访问权限、文件的读写权限
    ↓
3. 文件创建(O_CREAT标志)

   ├→ 如果文件不存在,且设置了O_CREAT,调用vfs_create()
   ├→ 调用父目录inode的i_op->create(),创建新的inode和dentry
   ├→ 初始化inode的权限、所有者、时间戳,写入磁盘
   └→ 把新的dentry加入dcache,建立与inode的关联
    ↓
4. 创建并初始化file实例

   ├→ 调用alloc_empty_file(),分配file实例
   ├→ 初始化file的核心字段:
   │  ├→ f_path:绑定解析得到的dentry和vfsmount
   │  ├→ f_op:从inode->i_fop复制文件操作函数集
   │  ├→ f_mode/f_flags:设置访问模式、打开标志
   │  ├→ f_pos:初始化为0,文件读写偏移
   │  └→ f_ra:初始化文件预读状态
   ├→ 调用security_file_open(),执行安全钩子检查
   └→ 调用file->f_op->open(),执行具体文件系统的打开逻辑
    ↓
5. fd与file实例绑定

   ├→ 调用fd_install(),把file实例写入进程的files_struct的fd表中
   ├→ 建立fd到file实例的映射
    ↓
6. 返回fd给用户态,open()完成

4.1.4 核心工程细节

1.RCU-walk与ref-walk的差异

RCU-walk是现代内核的默认路径解析模式,性能比ref-walk高10倍以上,99%的路径解析都会在RCU-walk中完成。只有当路径涉及软链接、跨挂载点、dentry未命中dcache时,才会回退到ref-walk。

2.软链接的处理

路径解析遇到软链接时,内核会递归解析软链接的目标路径,默认最大嵌套深度为40,超过会返回ELOOP错误。设置O_NOFOLLOW标志可以禁止跟随软链接,防范软链接攻击。

3.O_CREAT的权限坑

使用O_CREAT标志时,必须传入第三个参数mode,否则文件的权限会是随机值(来自栈上的脏数据),导致权限安全问题。标准用法:open("test.txt", O_CREAT|O_RDWR, 0644)。

4.2 read() 系统调用全链路实现

read()是文件读操作的核心接口,VFS层完成参数校验、权限检查、页缓存管理,具体的磁盘IO由文件系统的read_iter函数实现。Linux 6.6内核已全面使用迭代器接口read_iter,替代传统的read接口。
4.2.1 用户态原型与内核入口
用户态原型:
ssize_t read(int fd, void *buf, size_t count);

内核入口:sys_read() → ksys_read() → vfs_read()。
4.2.2 read() 全链路执行流程
用户态 read() → sys_read() → ksys_read() → vfs_read()
    ↓
1. fd到file实例的转换

   ├→ 调用fget(),根据fd从进程的files_struct中找到对应的file实例
   ├→ 增加file实例的引用计数f_count,防止并发释放
   └→ 检查file是否可读,不可读则返回EBADF错误
    ↓
2. 参数合法性校验

   ├→ 检查count是否合法,超过SSIZE_MAX则截断
   ├→ 调用access_ok(),检查用户态缓冲区buf是否可写,防止内核地址泄露
   ├→ 检查文件的访问模式,是否允许读
   └→ 检查文件是否被强制锁,处理锁冲突
    ↓
3. 调用文件系统的读接口

   ├→ 初始化iov_iter迭代器,封装用户态缓冲区buf和count
   ├→ 调用call_read_iter(),执行file->f_op->read_iter()
   └→ 具体文件系统的读逻辑分为缓冲IO和直接IO两种模式
    ↓
4. 缓冲IO模式(默认)

   ├→ 调用filemap_read(),通用页缓存读逻辑
   ├→ 根据f_pos和count,计算需要读取的页范围
   ├→ 遍历每个页,在文件的address_space->i_pages中查找缓存页
   │  ├→ 页缓存命中:直接复制页数据到用户态缓冲区
   │  ├→ 页缓存未命中:
   │  │  ├→ 分配空白物理页,加入页缓存
   │  │  ├→ 调用文件系统的readpage(),从磁盘读取数据到页
   │  │  ├→ 等待IO完成,设置页的PG_uptodate标志
   │  │  └→ 复制数据到用户态缓冲区
   ├→ 触发文件预读:根据访问模式,预读后续的页到缓存中
   └→ 更新文件的f_pos,增加读取的字节数
    ↓
5. 直接IO模式(O_DIRECT标志)

   ├→ 检查用户态缓冲区、读取长度、f_pos是否按块大小对齐(通常512字节/4KB),未对齐则返回EINVAL
   ├→ 调用文件系统的direct_IO()函数,绕过页缓存
   ├→ 直接提交bio请求到块设备层,等待IO完成
   ├→ 数据直接从磁盘传输到用户态缓冲区,零拷贝
   └→ 更新文件的f_pos
    ↓
6. 收尾操作

   ├→ 更新文件的访问时间atime(默认 relatime 模式,仅当atime早于mtime/ctime时更新)
   ├→ 调用fput(),减少file实例的引用计数
   └→ 返回读取的字节数,出错则返回负的错误码

4.2.3 核心工程细节

1.atime的性能优化

默认的relatime模式已经极大减少了atime的更新开销,对于读密集型的应用,挂载时设置noatime(完全关闭atime更新)、nodiratime(关闭目录atime更新),可以减少元数据写入,提升读性能30%以上。

2.预读机制的控制

内核会根据文件的访问模式自动调整预读窗口,顺序读时预读窗口最大到128页(512KB)。用户态可以通过posix_fadvise()手动控制预读:
  • 顺序读:posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL),预读窗口翻倍;
  • 随机读:posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM),关闭预读,避免无效IO;
  • 预加载:posix_fadvise(fd, offset, len, POSIX_FADV_WILLNEED),提前把指定范围的文件加载到页缓存。

3.O_DIRECT的对齐坑

直接IO要求用户态缓冲区的内存地址、读取长度、文件偏移,都必须按磁盘的逻辑块大小(通常512字节,高级格式化SSD为4KB)对齐,否则会返回EINVAL错误。很多新手踩坑:用malloc分配的缓冲区,地址可能未对齐,需要用posix_memalign()分配对齐的内存。

4.3 write() 系统调用全链路实现

write()是文件写操作的核心接口,默认缓冲IO模式下,write()仅把数据复制到页缓存就返回,脏页由内核回写线程异步写入磁盘,性能极高;同步模式下,会等待数据写入磁盘才返回,保证数据持久化。

4.3.1 用户态原型与内核入口

用户态原型:
ssize_t write(int fd, const void *buf, size_t count);
内核入口:sys_write() → ksys_write() → vfs_write()。

4.3.2 write() 全链路执行流程

用户态 write() → sys_write() → ksys_write() → vfs_write()
    ↓
1. fd到file实例的转换

   ├→ 调用fget(),根据fd找到对应的file实例,增加引用计数
   └→ 检查file是否可写,不可写则返回EBADF错误
    ↓
2. 参数合法性校验

   ├→ 检查count是否合法,用户态缓冲区buf是否可读
   ├→ 检查文件的访问模式,是否允许写
   ├→ 检查磁盘配额、文件大小限制(RLIMIT_FSIZE),超过则触发SIGXFSZ信号
   └→ O_APPEND模式下,原子性地把f_pos设置为文件末尾i_size
    ↓
3. 调用文件系统的写接口

   ├→ 初始化iov_iter迭代器,封装用户态缓冲区
   ├→ 调用call_write_iter(),执行file->f_op->write_iter()
   └→ 分为缓冲IO和直接IO两种模式
    ↓
4. 缓冲IO模式(默认)

   ├→ 调用generic_perform_write(),通用页缓存写逻辑
   ├→ 根据f_pos和count,计算需要写入的页范围
   ├→ 遍历每个页,在address_space->i_pages中查找缓存页
   │  ├→ 页不存在:分配新的物理页,加入页缓存,设置PG_locked
   │  ├→ 页存在但未uptodate:先从磁盘读取完整页,再写入
   │  ├→ 把用户态数据复制到页缓存中
   │  ├→ 标记页为脏页PG_dirty,加入脏页链表
   │  └→ 唤醒内核回写线程pdflush/bdi_writeback,异步回写脏页
   ├→ 更新文件的f_pos,增加写入的字节数
   └→ 如果写入超过了原文件大小,更新inode的i_size
    ↓
5. 直接IO模式(O_DIRECT标志)

   ├→ 检查缓冲区、长度、偏移是否按块大小对齐,未对齐则返回EINVAL
   ├→ 调用文件系统的direct_IO()函数,绕过页缓存
   ├→ 直接提交bio写请求到块设备层
   ├→ O_SYNC模式下,等待IO完成,确保数据写入磁盘
   └→ 更新文件的f_pos和i_size
    ↓
6. 同步写处理(O_SYNC/O_DSYNC标志)

   ├→ O_SYNC:等待数据和元数据都写入磁盘,才返回
   ├→ O_DSYNC:仅等待数据写入磁盘,元数据不强制同步,性能更高
   └→ 调用vfs_fsync_range(),强制回写脏页和元数据到磁盘
    ↓
7. 收尾操作

   ├→ 更新文件的修改时间mtime、元数据修改时间ctime
   ├→ 调用fput(),减少file实例的引用计数
   └→ 返回写入的字节数

4.3.3 核心工程细节

1.O_APPEND的原子性

O_APPEND模式下,内核会在write()调用时,原子性地把f_pos设置为文件末尾,保证多进程并发追加写时,数据不会相互覆盖,是日志文件的最佳实践。如果不用O_APPEND,用lseek(fd, 0, SEEK_END) + write(),在多进程场景下会有竞态,导致数据覆盖。

2.缓冲IO的持久化风险

缓冲IO模式下,write()返回仅代表数据复制到了页缓存,还没有写入磁盘。如果系统崩溃、断电,页缓存中的脏页会丢失,导致数据损坏。需要持久化的场景,必须在write()后调用fsync()/fdatasync(),强制把脏页和元数据写入磁盘。

3.脏页回写的触发条件

脏页不会无限期留在内存中,满足以下任一条件会触发回写:
  • 脏页的过期时间超过dirty_expire_centisecs(默认30秒);
  • 系统脏页比例超过dirty_background_ratio(默认10%),唤醒回写线程异步回写;
  • 系统脏页比例超过dirty_ratio(默认20%),阻塞所有写操作,同步回写脏页;
  • 用户态调用fsync()/sync(),强制回写。

4.4 close() 系统调用全链路实现

close()的核心目标是:释放文件描述符、减少file实例的引用计数,当引用计数为0时,执行文件系统的关闭逻辑,释放相关资源。

4.4.1 用户态原型与内核入口

用户态原型:
int close(int fd);
内核入口:sys_close() → __close_fd()。
4.4.2 close() 全链路执行流程
用户态 close() → sys_close() → __close_fd()
    ↓
1. 从进程的文件描述符表中移除fd

   ├→ 加files_struct的锁,找到fd对应的file实例
   ├→ 把fd表中对应的位置清空,标记为可用
   ├→ 释放fd的占用,解除fd与file实例的绑定
   └→ 释放锁
    ↓
2. 减少file实例的引用计数

   ├→ 调用fput(),把file->f_count减1
   └→ 如果引用计数大于0,说明还有其他进程/线程持有该file实例,直接返回0,close完成
    ↓
3. 引用计数为0,执行文件关闭逻辑

   ├→ 调用file->f_op->release(),执行具体文件系统的关闭逻辑
   ├→ 释放文件的异步IO、锁、事件通知相关资源
   ├→ 刷新文件的脏页到磁盘(非强制,由内核回写线程处理)
   ├→ 释放file实例的private_data私有数据
   └→ 释放file实例,回收内存
    ↓
4. 返回0,close完成

4.4.3 核心工程细节

1.close()的返回值忽略坑

很多工程师忽略close()的返回值,实际上close()可能会返回错误,比如NFS挂载的文件,close()时会等待脏页回写,如果回写失败会返回EIO错误。忽略这个错误会导致数据丢失而不自知,正确的做法是必须检查close()的返回值。

2.文件句柄泄漏

打开的文件没有调用close(),会导致文件句柄泄漏,fd和file实例无法释放,最终超过进程的fd限制(ulimit -n),导致后续open()失败返回EMFILE。长生命周期的服务必须保证每个open()都有对应的close(),可以用lsof -p 查看进程打开的fd,排查泄漏。

3.fork()之后的fd继承

fork()创建子进程时,子进程会继承父进程所有打开的fd,file实例的引用计数加1。父子进程共享同一个file实例,包括共享f_pos读写偏移。如果子进程不需要这些fd,应该在fork之后立即关闭,否则会导致句柄泄漏,同时父进程close()之后,file实例的引用计数不为0,无法释放。

4.5 工程实践与避坑指南

1.文件描述符限制调优

生产环境的长生命周期服务,默认的ulimit -n(1024)通常不够,需要调大:
  • 临时调整:ulimit -n 1048576,仅对当前shell生效;
  • 永久调整:编辑/etc/security/limits.conf,添加:
* soft nofile 1048576
* hard nofile 1048576
root soft nofile 1048576
root hard nofile 1048576

  • 内核全局限制:/proc/sys/fs/file-max,系统最大可打开的fd总数,通常设置为内存大小的10%,比如32GB内存设置为33554432。

2.open()的安全最佳实践

  • 打开不可信路径时,必须使用O_NOFOLLOW禁止跟随软链接,防范软链接攻击;
  • 创建文件时,必须显式指定mode参数,避免权限泄露;
  • 打开普通文件时,使用O_NOCTTY,避免文件成为进程的控制终端;
  • 非阻塞IO场景,使用O_NONBLOCK,避免read/write阻塞。

3.IO模式选型最佳实践

IO模式
优势
劣势
适用场景
缓冲IO
性能极高,内核自动优化预读、回写、缓存
数据持久化风险,占用内存
绝大多数通用场景,读密集型应用
直接IO
绕过页缓存,零拷贝,数据直接写入磁盘,内存占用低
对齐要求严格,性能依赖IO调度,小IO性能差
数据库、大数据等自己实现缓存的应用,大文件顺序读写
同步IO(O_SYNC)
数据持久化有保障,断电不丢失
性能极差,延迟高
金融、数据库等强数据一致性场景

4.常见的IO性能坑

  • 频繁小IO写入:每次写入几个字节,会导致大量的页缓存脏页标记、元数据更新,性能极差。最佳实践是用用户态缓冲区,攒够一页(4KB)再写入;
  • 频繁调用fsync():每次write()都调用fsync(),会导致大量的磁盘IO,性能下降100倍以上。最佳实践是批量写入后统一fsync(),比如日志文件每1秒fsync()一次;
  • 多线程并发写同一个文件,不加锁:会导致数据相互覆盖,除非使用O_APPEND模式。O_APPEND仅保证单次write()的原子性,超过页大小的write()可能会被拆分,不保证原子性。
基于大模型的JMeter日志智能分析服务化实践 在软件性能测试领域,日志分析是定位系统瓶颈、评估稳定性的关键环节。传统基于规则或正则表达式的分析方法,在面对格式多变、上下文关联复杂的海量日志时,往往效率低下且难以深入。大语言模型(LLM)凭借其强大的自然语言理解与推理能力,为这一挑战提供了新的解决方案。其技术价值在于能够自动化地从非结构化文本中提取语义信息、关联分散的上下文,并生成可操作的根因分析与优化建议,从而将工程师从繁琐的日志筛查中解放出来,显著提升问题诊断的深度与效率。这一技术可广泛应用于自动化测试报告生成、实时监控预警、脚本调试辅助等工程实践场 阅读详情

相关推荐

《科研伦理与学术规范》期末考试答案2023

26单选(2 分)某学术杂志的评稿人同时是某高校相关专业的硕士生导师,在评判一个稿件的时候,他发现该作者研究的题目很有价值, 他便一边压下这个稿子,一边将稿子的纲要传给自己门下的硕士生, 指导他们使用这个题目独立写出一篇论文,并帮助他们发表在其他期 刊上。D.要善待实验动物,是指在饲养管理和使用实验动物过程中,要采取有效措施,使实验动物免遭不必要的伤害、饥渴、不适、惊恐、折磨、疾病和疼痛,保证动物能够实现自然行为,受到良好的管理与照料,为其提供清洁、舒适的生活环境。张某在压力之下不得不屈从。

Glenseeds的博客 4万+

Linux内核学习轨迹第八部:深入解析Linux内核数据包发送全链路(第四节)

源码覆盖net/ipv4/tcp_output.c(TCP发送核心)、net/core/dev.c(发送队列核心)、net/sched/(TC流量控制)、drivers/net/ethernet/(网卡驱动发送逻辑),完整拆解从用户态写入数据,到网卡硬件发送完成的全链路流程,深度解析TSO/GSO、TCP发送队列、流量控制、拥塞控制、驱动发送机制,同时提供生产环境的发送性能调优、丢包排查、避坑指南。如果超时未收到ACK,会触发重传机制,重新发送对应的数据包。

新时代农民工 351

Maven的下载安装配置教程(详细图文)

目录 一、简单了解一下什么是Maven 二、maven的下载 三、maven的安装 四、maven的环境变量配置 五、setting文件配置 六、开发工具配置Maven 一、简单了解一下什么是Maven Maven就是一款帮助程序员构建项目的工具,我们只需要告诉Maven需要哪些Jar 包,它会帮助我们下载所有的Jar,极大提升开发效率。 1.Maven翻译为“专家“, ”内行”的意思,是著名Apache公司下基于Java开发的开源项目。 2.Maven项目对象模型(POM)是一..

bakelFF的博客 12万+

Linux内核学习轨迹第六部:VFS的设计思想与整体架构(第一节)

很多工程师对VFS的理解停留在「文件操作的封装」表层,却不理解四大核心对象的生命周期、挂载的底层实现、目录项缓存的工作机制、IO全链路的内核流转,最终在遇到实际问题时手足无措。:无论底层是什么资源,VFS都把它抽象为一个file实例,对应一套file_operations操作函数集,用户态通过统一的POSIX接口操作,VFS层把接口调用转发给对应的操作函数,最终实现对底层资源的访问,这就是「一切皆文件」的底层逻辑。为避免内容过长导致异常,本章节先完成前3个核心模块的完整拆解,后续模块可按需继续补充。

新时代农民工 723

EETI_eGTouch驱动移植及校准

一.环境 芯片:NXP IMX6Q 内核版本:4.1.15 uname:Linux myimx6ek314 4.1.15-myimx6-g5d588fa6-dirty #4 SMP PREEMPT Tue Nov 17 17:26:34 CST 2020 armv7l armv7l armv7l GNU/Linux 二.官方《EETI_eGTouch_Linux_Programming_Guide_v2.5l.pdf》文档勘误 HID_MULTITOUCH =Y or N(官方文档设置为M): 正确设置H

Garden的博客 4332

RT-Thread网络编程:基于STM32F407的TCP客户端实现(含完整代码解析)

本文详细介绍了在STM32F407平台上,基于RT-Thread操作系统和LWIP协议栈实现工业级可靠TCP客户端的完整过程。内容涵盖底层ETH驱动配置、Socket编程、连接保活与断线重连机制、数据收发协议设计以及资源管理,提供了可应用于实际项目的健壮代码框架与调试技巧。

weixin_29184371的博客 492

Linux内核学习轨迹第六部:文件系统的注册、挂载与卸载全流程(第三节)

最基础的挂载,把一个块设备的文件系统挂载到一个目录上,比如mount /dev/sda1 /data,底层流程就是上面的标准流程,需要块设备,读取磁盘超级块,创建super_block实例。挂载命名空间是Linux Namespace的一种,实现了进程间的挂载树隔离,每个挂载命名空间有独立的挂载树,进程只能看到自己所在命名空间的挂载实例,是容器技术的核心底层基础。:把一个文件/目录挂载到另一个文件/目录上,实现目录/文件的镜像访问,比如mount --bind /a /b,访问/b等价于访问/a。

新时代农民工 485

行为预测模型:Social LSTM与Graph Neural Networks

行为预测模型:Social LSTM与Graph Neural Networks ,人工智能,计算机视觉,大模型,AI,本文围绕行为预测模型Social LSTM与Graph Neural Networks展开,介绍了两者的基础概念、原理、应用场景,还对比了它们在优势、劣势和适用场景上的不同,最后给出了相应的代码示例。Social LSTM基于LSTM,通过社交池化层处理多智能体交互;图神经网络处理图结构数据,靠消息传递获取信息,二者各有侧重,适用于不同场景。

不踩坑,不知道坑有多深;不总结,踩过的坑白踩。 15万+

Linux内核学习轨迹第二部:Linux内核全局架构与启动全流程深度拆解

存放内核核心功能的实现代码,包括进程调度、中断处理、软中断、定时器、锁机制、模块加载、系统调用实现,是内核的核心骨架。的核心思想,整体分为5个纵向层级、10+个核心子系统,所有子系统严格遵循「高内聚、低耦合」的设计原则,同时定义了清晰的依赖关系,驱动开发本质上是在内核标准化的子系统框架下,实现硬件适配的标准化接口。,从顶层架构、源码组织、启动全链路、子系统初始化依赖、镜像与内存布局五个维度,完成内核全局逻辑的深度拆解,所有内容均对应内核实际源码路径,可直接落地到驱动开发、内核定制、生产环境故障排查中。

新时代农民工 196

Vue3 - Element Plus 全局修改更换主题色配置详细教程,element-plus自定义主题色全局替换主色调强力解决方案,支持动态修改主题颜色/动态皮肤,将默认蓝色主题色更换为其他颜色!

vue3,nuxt3,element-plus,组件库,主题色,修改主题颜色,更换主题色,如何修改组件默认主题蓝色,项目主题色定制,修改失败,主题色覆盖不了,:root直接修改,hover颜色没改,自定义主题色,vue3全局设置elementPlus主题色最新详细修改教程,怎么修改全局的颜色,scss变量,覆盖原来的主题色改为自己的颜色,统一替换,有没有好办法,颜色不变,失败,无效,动态主题切换,主题颜色怎么在项目里直接改,plus主题色更换,覆盖默认主题色,最强最好用,设置主题色,换肤,皮肤,动态更换

🏆 前端领域优质创作者 1万+

YOLO11,ultralytics-main源代码目录结构详解

本文详细介绍了YOLO11框架的ultralytics-main源代码目录结构,帮助用户更好地理解和使用YOLO模型。主要目录包括:docker文件夹,包含多种Docker镜像文件,适用于不同硬件环境;docs文件夹,存放YOLO的说明文档;examples文件夹,提供YOLO使用的示例代码;tests文件夹,包含单元测试模块;ultralytics文件夹,为核心代码所在,包含推理逻辑、配置、数据处理等模块。其中,engine文件夹负责训练和推理引擎,models文件夹存放模型架构,nn定义神经网络结构

qq_30279827的博客 1282

Linux内核学习轨迹第四部:深入解析Linux内核进程管理与调度(第一小节)

对于有一定内核基础的工程师而言,进程管理与调度是穿透整个Linux内核的核心主线——从用户态程序的启动、运行到退出,所有行为都围绕「进程」这个核心抽象展开;而调度器则是内核的「大脑」,决定了CPU资源如何在海量进程之间分配,直接决定了系统的吞吐量、响应延迟、实时性与公平性。本章节基于,从设计思想、源码实现、工程实践、问题排查四个维度,完整拆解进程管理与调度子系统的全链路逻辑,纠正行业内常见的认知误区,给有基础的工程师建立体系化的内核认知,同时提供可落地的问题排查与调优方案。。在Linux中,进程是。

新时代农民工 913

《基于FPGA的数字信号处理》专栏的导航与说明

《基于FPGA的数字信号处理》专栏的导航与说明

孤独的单刀 4160

Linux内核学习轨迹第七部:多队列块层blk-mq深度拆解(第四节)

发起IO的CPU核心只会操作自己对应的软件队列,不会和其他CPU核心产生锁冲突,多核场景下的并行能力得到了质的提升。量身设计的,彻底解决了传统单队列的全局自旋锁竞争瓶颈,实现了IO请求的全链路并行处理,把NVMe设备的IOPS和延迟性能提升了一个数量级,是现代Linux IO栈的核心基石。blk-mq的核心设计目标就是彻底解决这三个问题,通过**「Per-CPU软件队列 + 多硬件队列」的全并行架构**,消除全局锁,最大化发挥多核CPU和多队列硬件的性能。

新时代农民工 418

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Linux内核学习轨迹第七部: 多队列块层blk-mq深度拆解(第四节)

发起IO的CPU核心只会操作自己对应的软件队列,不会和其他CPU核心产生锁冲突,多核场景下的并行能力得到了质的提升。量身设计的,彻底解决了传统单队列的全局自旋锁竞争瓶颈,实现了IO请求的全链路并行处理,把NVMe设备的IOPS和延迟性能提升了一个数量级,是现代Linux IO栈的核心基石。blk-mq的核心设计目标就是彻底解决这三个问题,通过「Per-CPU软件队列 + 多硬件队列」的全并行架构,消除全局锁,最大化发挥多核CPU和多队列硬件的性能。

新时代农民工 346

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Linux 内核网络栈收包流程全链路微观追踪:从硬中断到 socket read 的完整轨迹

网络性能的本质是 CPU 周期、内存带宽与总线吞吐的协同调度。从网卡 DMA 写入、NAPI 批量收割、skb 零拷贝指针滑动,到 Socket 缓冲唤醒与用户态拷贝,透视这一条精密的数据包流动轨迹,才能在面对超高并发与万兆流量洪峰时,精准定位系统每一微秒的延迟来源,筑起无懈可击的高性能网络架构底座。

iymei4986533030的博客 380

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Linux内核学习轨迹第八部:套接字Socket层全解析(第二节)

2.ops:协议操作函数集,是Socket层与下层协议的核心桥梁,结构体struct proto_ops中定义了该Socket支持的所有操作(bind/listen/connect/send/recv等),不同的协议(TCP/UDP/UNIX域套接字)会实现不同的函数集,Socket层通过函数指针调用对应的协议逻辑,实现了协议无关性。,是Socket在内核协议栈中的「实体」,存储了该套接字对应的所有协议相关的状态、配置、缓冲区、统计信息,是TCP/UDP等协议处理数据包的核心载体。

新时代农民工 406

Linux内核学习轨迹第八部:Linux网络协议栈的整体架构与分层设计(第一节)

Linux网络协议栈是内核最核心、最复杂的子系统之一,是所有网络通信的底层基石。协议栈在数据包收发的全链路预留了大量钩子点,最典型的就是Netfilter框架,允许内核模块、eBPF程序在数据包处理的关键节点插入自定义逻辑,实现防火墙、NAT、流量监控、数据包修改等功能,无需修改内核源码,极大提升了协议栈的灵活性。是内核与物理网卡的桥梁,负责初始化网卡硬件、处理网卡的收发中断、通过NAPI机制高效收发数据包,把链路层的以太网帧转换为网卡可识别的电信号,同时把网卡收到的电信号转换为内核可处理的数据包。

新时代农民工 365

Linux内核学习轨迹第五部:缺页异常处理全链路深度解析(第七小节)

当进程访问的虚拟地址没有建立页表映射,或者访问权限不匹配时,CPU会触发缺页异常,陷入内核,由内核的缺页异常处理函数完成物理内存分配、页表映射、权限调整等操作,异常处理完成后,CPU重新执行触发异常的指令。当进程访问文件映射的虚拟地址,对应的文件页不在页缓存中时,触发文件映射缺页异常,由do_fault()函数处理,通常是主缺页异常,需要访问磁盘。缺页异常处理时,如果系统没有足够的空闲内存,内核会先触发内存回收,如果回收后还是没有足够的内存,会触发OOM Killer,杀死进程释放内存。

新时代农民工 327

Linux内核GT911触摸驱动开发:从设备树到多点上报全链路实践

GT911作为汇顶科技主流电容触控芯片,广泛应用于嵌入式Linux设备,其核心特性包括5点同步触摸、动态I²C地址切换(0x14/0x5D)及MT_PROTOCOL_B多点协议支持。在Linux驱动框架下,需严格遵循input子系统规范,完成设备树精准描述、寄存器级初始化、坐标字节序解析与中断线程化处理。技术价值体现在高可靠性触控响应、低延迟事件上报及跨平台兼容性;典型应用场景涵盖RK3566/RK3568等ARM64开发板、工业HMI、车载中控及Android终端。本文聚焦GT911在正点原子开发板上的驱

weixin_34184158的博客 378

Linux内核学习轨迹第八部:核心数据结构sk_buff全字段深度解析(第三节)

它为数据包缓冲区预留了headroom(头部空闲空间)和tailroom(尾部空闲空间),协议栈各层添加协议头(以太网头、IP头、TCP头)时,只需移动指针,无需拷贝整个数据包内容,实现了协议栈各层之间的零拷贝处理,极大降低了CPU开销。,是整个网络栈的“流通货币”。针对网络协议的分层特性,sk_buff专门设计了固定的协议头指针(链路层、网络层、传输层),各层协议可以快速定位自己的协议头,无需遍历数据包内容,同时完美兼容IPv4/IPv6、TCP/UDP、VLAN、隧道等多种协议的嵌套场景。

新时代农民工 675

Linux内核学习轨迹第七部:块设备子系统的整体架构(第一节)

线上服务的IO性能瓶颈、磁盘卡顿、数据丢失、存储故障,绝大多数根源都是对块设备子系统的底层机制、IO请求全生命周期、多队列架构、IO调度器的认知不足。,从架构设计、核心数据结构、源码实现、全链路流程、工程实践五个维度,完整拆解块设备子系统与Linux IO栈,同时提供可落地的性能调优、故障排查方案。,内核会对IO请求做合并、排序、批量处理,最大化发挥存储硬件的性能,这是与字符设备最本质的差异。内核提供IO调度器,对请求做合并、排序、优先级调度,优化硬件性能。串口、键盘、终端、声卡。:块设备的核心特征是。

新时代农民工 380

Linux内核学习轨迹第四部:深入解析Linux内核进程管理与调度(第二小节)

Linux中,所有的进程、线程、内核线程的创建,最终都会落到clone()系统调用,fork()、vfork()、pthread_create()、kthread_create(),都是对clone()的封装,只是传入的flags标志不同,决定了子进程和父进程共享哪些资源。fork()创建了子进程,但子进程还是执行和父进程相同的代码,execve()系统调用的作用,就是加载一个新的可执行文件到进程的地址空间,替换原来的代码段、数据段、栈、堆,让进程执行新的程序。

新时代农民工 613

Linux内核学习轨迹第七部:块设备驱动框架与开发流程(第六节)

gendisk必须绑定一个初始化完成的request_queue,驱动通过blk_mq_init_queue()API创建队列,这是Linux 6.6内核的标准API,替代了旧的blk_init_queue()。块设备驱动的核心职责,是把blk-mq层下发的struct requestIO请求,转换为物理存储硬件可识别的指令,控制硬件完成数据读写,并在IO完成后通知内核,完成整个IO链路的闭环。,完整实现了blk-mq驱动的核心流程,可直接编译运行,用于学习和理解驱动开发的核心逻辑。

新时代农民工 345

Linux内核学习轨迹第四部: 多核调度与负载均衡机制(第六小节)

很多工程师隔离了CPU核心,却没有给进程绑定亲和性,导致隔离的CPU核心完全空闲,浪费资源。调度组(sched_group)**的层级结构,它把CPU按共享缓存、NUMA节点、物理CPU的层级,划分为不同的调度域,每个调度域内的CPU之间做负载均衡,层级化的设计既保证了负载均衡的效果,又最小化了均衡的开销。对于实时进程、延迟敏感的进程,可以通过内核启动参数isolcpus隔离CPU核心,隔离后的CPU核心不会被普通进程使用,只能通过CPU亲和性手动绑定进程,同时不会触发负载均衡,避免其他进程的干扰。

新时代农民工 590

Linux内核学习轨迹第七部:BIO结构体全解析与IO请求的生命周期(第三节)

BIO通过bi_io_vec数组,把多个不连续的物理内存页,封装到单个BIO中,一次性下发给磁盘,磁盘会把连续的扇区数据,分别写入/读出这些不连续的内存页,极大减少了IO请求数量,降低了硬件中断开销。BIO的本质是(对块设备的一段连续IO操作的标准化封装),它把上层发起的IO请求,拆解为对磁盘连续扇区的读写操作,同时管理IO对应的内存缓冲区、完成回调、错误处理、统计信息等全生命周期信息。理解BIO的结构、字段语义、完整生命周期,是吃透Linux IO栈全链路的核心,也是IO性能调优、故障排查的基础。

新时代农民工 390
上一篇: Linux内核学习轨迹第六部:文件系统的注册、挂载与卸载全流程(第三节)
下一篇: Linux内核学习轨迹第六部:目录项缓存dcache与inode缓存(第五节)
WythePlus
博客等级 码龄11年 397粉丝 300原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值