当前位置: 首页 > ds >正文

【linux仓库】万物至简的设计典范:如何用‘文件’这一个概念操纵整个Linux世界?

🌟 各位看官好,我是egoist2023!

🌍 Linux == Linux is not Unix !

🚀 今天来学习一切皆文件的相关知识。

👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享给更多人哦!

目录

书接上文

前言 

一切皆文件

刨根问底

总结


书接上文

本文深入剖析了Linux文件描述符(FD)的核心机制。我们从open系统调用的返回值切入,揭示了其“数组下标”的本质特性。通过追溯进程task_struct中的files_struct结构,我们阐明了0、1、2号FD被固定分配为标准输入、输出、错误的规则,并验证了C库FILE结构体对FD的封装关系。

在此基础上,我们系统讲解了FD的分配规则重定向的底层实现(基于dup2系统调用),以及父子进程间FD的继承机制

然而,这一切精巧的设计,都服务于一个更为宏大和深刻的Linux设计哲学——“一切皆文件”

FD,正是这一哲学得以实现的基石与枢纽。它不仅仅是一个用于访问普通文件的句柄,更是一个统一的抽象接口。正是凭借FD这个“万能手柄”,Linux才能将形态各异的外部设备——无论是磁盘、键盘、显示器,还是网络套接字、管道——都抽象为一种可以统一进行读写(read/write)操作的对象。

接下来,我们将超越普通文件的范畴,深入虚拟文件系统(VFS) 层,探索Linux是如何用“文件”这同一个概念,来统一抽象万物的。我们将看到,正是FD机制的存在,才使得“一切皆文件”从一句口号,变成了一个强大而优雅的现实。

前言 

OS要不要管理硬件呢?它是软硬件资源的管理者,要管理,那么该如何管理呢?

先描述,再组织!!!

struct device
{int type;int status;...struct list_head node;
}

一切皆文件

首先,在windows中是⽂件的东西,它们在linux中也是⽂件;其次⼀些在windows中不是⽂件的东

西,⽐如进程、磁盘、显⽰器、键盘这样硬件设备也被抽象成了⽂件,你可以使⽤访问⽂件的⽅法访问它们获得信息;甚⾄管道,也是⽂件;将来我们要学习⽹络编程中的socket(套接字)这样的东西,使⽤的接⼝跟⽂件接⼝也是⼀致的。

这样做最明显的好处是,开发者仅需要使⽤⼀套 API 和开发⼯具,即可调取 Linux 系统中绝⼤部分的资源。举个简单的例⼦,Linux 中⼏乎所有读(读⽂件,读系统状态,读PIPE)的操作都可以⽤

read 函数来进行;几乎所有更改(更改⽂件,更改系统参数,写 PIPE)的操作都可以⽤ write 函

数来进⾏。

之前我们讲过,当打开⼀个⽂件时,操作系统为了管理所打开的⽂件,都会为这个⽂件创建⼀个file结构体,该结构体定义在 /usr/src/kernels/3.10.0-1160.71.1.el7.x86_64/include/linux/fs.h 下,以下展示了该结构部分我们关系的内容:

struct file {...struct inode *f_inode; /* cached value */const struct file_operations *f_op;...atomic_long_t f_count;  // 表⽰打开⽂件的引⽤计数,如果有多个⽂件指针指向它,就会增加f_count的值。unsigned int f_flags;   // 表⽰打开⽂件的权限fmode_t f_mode;         // 设置对⽂件的访问模式,例如:只读,只写等。所有的标志在头⽂件<fcntl.h> 中定义loff_t f_pos;           // 表⽰当前读写⽂件的位置...} __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */

值得关注的是 struct file 中的 f_op 指针指向了⼀个 file_operations 结构体,这个结构体中的成员除了struct module* owner 其余都是函数指针。该结构和 struct file 都在fs.h下。

struct file_operations {struct module *owner;//指向拥有该模块的指针;loff_t (*llseek) (struct file *, loff_t, int);//llseek ⽅法⽤作改变⽂件中的当前读/写位置, 并且新位置作为(正的)返回值.ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);//⽤来从设备中获取数据. 在这个位置的⼀个空指针导致 read 系统调⽤以 -
EINVAL("Invalid argument") 失败. ⼀个⾮负返回值代表了成功读取的字节数( 返回值是⼀个
"signed size" 类型, 常常是⽬标平台本地的整数类型).ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);//发送数据给设备. 如果 NULL, -EINVAL 返回给调⽤ write 系统调⽤的程序. 如果⾮负, 返
回值代表成功写的字节数.ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化⼀个异步读 -- 可能在函数返回前不结束的读操作.ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化设备上的⼀个异步写.int (*readdir) (struct file *, void *, filldir_t);//对于设备⽂件这个成员应当为 NULL; 它⽤来读取⽬录, 并且仅对**⽂件系统**有⽤.unsigned int (*poll) (struct file *, struct poll_table_struct *);int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);long (*compat_ioctl) (struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);//mmap ⽤来请求将设备内存映射到进程的地址空间. 如果这个⽅法是 NULL, mmap 系统调⽤返回 -ENODEV.int (*open) (struct inode *, struct file *);//打开⼀个⽂件int (*flush) (struct file *, fl_owner_t id);//flush 操作在进程关闭它的设备⽂件描述符的拷⻉时调用;int (*release) (struct inode *, struct file *);//在⽂件结构被释放时引⽤这个操作. 如同 open, release 可以为 NULL.int (*fsync) (struct file *, struct dentry *, int datasync);//用户调⽤来刷新任何挂着的数据.int (*aio_fsync) (struct kiocb *, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct file_lock *);//lock ⽅法⽤来实现⽂件加锁; 加锁对常规⽂件是必不可少的特性, 但是设备驱动⼏乎从不实现它.ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long,         unsigned long, unsigned long);int (*check_flags)(int);int (*flock) (struct file *, int, struct file_lock *);ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *,size_t, unsigned int);ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *,size_t, unsigned int);int (*setlease)(struct file *, long, struct file_lock **);
};

file_operation 就是把系统调⽤和驱动程序关联起来的关键数据结构,这个结构的每⼀个成员都

对应着⼀个系统调用。读取 file_operation 中相应的函数指针,接着把控制权转交给函数,从⽽

完成了Linux设备驱动程序的⼯作。

上图中的外设,每个设备都可以有⾃⼰的read、write,但⼀定是对应着不同的操作⽅法!!但通过struct file 下 file_operation 中的各种函数回调,让我们开发者只⽤file便可调取 Linux 系统中绝⼤部分的资源!!这便是“linux下⼀切皆⽂件”的核心理解。

刨根问底

当我们打开⽂件时,操作系统在内存中要创建相应的数据结构来描述⽬标⽂件。⽽进程执⾏open系统调⽤,所以必须让进程和⽂件关联起来。每个进程都有⼀个指针*files, 指向⼀张表files_struct,该表最重要的部分就是包含⼀个指针数组,每个元素都是⼀个指向打开⽂件的指针!

Linux中,打开文件,要为我们创建struct fle,三个核心:
1.文件属性
2.文件内核缓冲区
3.底层设备文件的操作表(方法集)

根据上面所讲:

struct file 中还有一个 f_op 指针,它指向⼀个 file_operations 结构体。这个file_operations即是一个方法集,如read、write等等。

而每个设备都提供了自身需求的对应方法集的实现。

这样便做到了在上层部分函数接口都是统一的,而在下层部分每个函数接口的实现方法都是不同的。

而上层不就是C++中实现多态的基类吗?下层不就是C++中实现多态的派生类。

输出结论:一切皆文件!是站在进程的视角,在struct file结构体之上,看待文件的视角,strcutfile的方法集是一样的,但访问方式是不同的,因为不同的设备有不同的实现方法。

总结

本文深入解析了Linux"一切皆文件"的设计哲学,重点剖析了文件描述符(FD)的核心机制。从进程task_struct中的files_struct结构出发,阐述了FD作为"数组下标"的本质特性及其分配规则。通过分析struct file和file_operations结构体,揭示了Linux如何通过统一接口(如read/write)抽象各类设备资源,实现不同设备的差异化操作。关键点在于:上层提供统一接口,下层由各设备实现具体操作,类似C++的多态机制,使进程能以统一视角访问异构资源。这种设计极大简化了开发,使开发者仅需一套API即可操作绝大多数系统资源。

 

http://www.xdnf.cn/news/19796.html

相关文章:

  • 在Docker中安装MySQL时3306端口占用问题
  • 论文学习30:LViT: Language Meets Vision Transformerin Medical Image Segmentation
  • 使用云手机进行游戏搬砖划算吗?
  • 国内真实的交换机、路由器和分组情况
  • 【保姆级喂饭教程】把chrome谷歌浏览器中的插件导出为CRX安装包
  • LeetCode 925.长按键入
  • 数据结构:希尔排序 (Shell Sort)
  • 【51单片机】【protues仿真】基于51单片机呼叫系统
  • 基于Force-closure评估的抓取计算流程
  • 生成知识图谱与技能树的工具指南:PlantUML、Mermaid 和 D3.js
  • 【AI报表】JimuReport 积木报表 v2.1.3 版本发布,免费可视化报表和大屏
  • 【leetcode】222. 完全二叉树的节点个数
  • Altium Designer中的Net-Tie:解决多网络合并与电气隔离的利器
  • CPTS-Vintage 票据,基于资源的约束委派 (RBCD),DPAPI密钥
  • 自制扫地机器人(二) Arduino 机器人避障设计——东方仙盟
  • Veo Videos Generation API 对接说明
  • 鸿蒙NEXT表单选择组件详解:Radio与Checkbox的使用指南
  • 开源 C++ QT Widget 开发(十)IPC进程间通信--共享内存
  • 零跑汽车8月交付57066台,同比增长超88%
  • amd cpu是x86架构吗
  • 【Audio】静音或振动模式下重复来电响铃
  • stdexcept介绍与使用指南
  • 【LeetCode】3670. 没有公共位的整数最大乘积 (SOSDP)
  • Day19_【机器学习—线性回归 (3)—回归模型评估方法】
  • Docker一键快速部署压测工具,高效测试 API 接口性能
  • ES6手录01-let与const
  • 学习日记-spring-day47-9.1
  • PyCharm 2025版本中新建python工程文件自动创建.venv的意义和作用
  • 教育 AI 的下半场:个性化学习路径生成背后,技术如何平衡效率与教育本质?
  • 第二十八天-DAC数模转换实验