【 linux 】文件系统

目录

[1. 聊一聊硬件](#1. 聊一聊硬件)

[2. 文件系统](#2. 文件系统)

[2.1 结构](#2.1 结构)

[2.2 路径解析](#2.2 路径解析)

[2.3 挂载分区](#2.3 挂载分区)

[2.4 总结](#2.4 总结)


1. 聊一聊硬件

想知道文件是如何管理的和硬件是分不开的,这里看一下硬件磁盘的组成和原理

磁盘存储的基本单位是扇区 ,一个扇区通常能存储512字节,除了扇区一个磁盘还有磁道,柱面,传动臂等结构

柱面,磁头,扇区三者组成了CHS定址

OS文件系统访问磁盘,不以扇区为单位,而是以" "为单位,一般是4KB,连续8个扇区,"块"是文件存取的最小单位

为了便于管理,OS对磁盘进行了分区分组。这样对一组的管理就是对磁盘的管理

文件=内容+属性,linux下,内容和属性是分开存储的,内容存储在Data Blocks区,属性存储在inode区,一个文件,一个inode

一个文件的属性inode长这样

复制代码
struct ext2_inode {
    __le16  i_mode;     /* File mode */
    __le16  i_uid;      /* Low 16 bits of Owner Uid */
    __le32  i_size;     /* Size in bytes */
    __le32  i_atime;    /* Access time */
    __le32  i_ctime;    /* Creation time */
    __le32  i_mtime;    /* Modification time */
    __le32  i_dtime;    /* Deletion Time */
    __le16  i_gid;      /* Low 16 bits of Group Id */
    __le16  i_links_count;  /* Links count */
    __le32  i_blocks;   /* Blocks count */
    __le32  i_flags;    /* File flags */
    union...

文件名属性并未纳入inode数据结构中,任何文件的内容大小可以不同,但是属性大小是相同的

认识了硬盘这种"块"设备,块是分区下的结构,如何找到块,又如何管理这些inode就是文件系统的工作

2. 文件系统

2.1 结构

文件系统的目的是组织和管理硬盘中的文件,文件系统将整个分区划分成若干个大小的块组,只要能管理一个分区,就能管理所有分区,就能管理所有磁盘文件

依次介绍一下各部分的作用

1. Super Block

**存放⽂件系统本⾝的结构信息,描述整个分区的⽂件系统信息。**记录的信息主要有:bolck和inode的总量,未使⽤的block和inode的数量,⼀个block和inode的⼤⼩,最近⼀次挂载的时间,最近⼀次写⼊数据的时间,最近⼀次检验磁盘的时间等其他⽂件系统的相关信息

2. GDT

块组描述符表,描述块组属性信息,整个分区分成多个块组就对应有多少个块组描述符。每个块组描述符存储⼀个块组的描述信息,如在这个块组中从哪⾥开始是inodeTable,从哪⾥开始是Data Blocks,空闲的inode和数据块还有多少个等等。块组描述符在每个块组的开头都有⼀份拷⻉

3. Block Bitmap

记录着Data Blocks中哪个数据块已被占用,哪个数据块还没有被占用

4. Inode Bitmap

每个bit表示一个inode是否空闲可用

5. Inode Table

存放文件属性,当前分组所有indoe属性的集合,inode编号以分区为单位,不可跨分区

6. Data Block

数据区:存放文件内容,也就是一个个的block,根据不同的文件类型情况不同。对于普通⽂件,⽂件的数据存储在数据块中。对于⽬录,该⽬录下的所有文件名和目录名 存储在所在⽬录的数据块中,除了⽂件名外,ls-l命令 看到的其它信息保存在该⽂件的inode中,Block号按照分区划分,不可跨分区

创建一个文件的过程

目录也是文件,属性不用多说,内容保存的是文件名和inode的映射关系

复制代码
Filename: mnt, Inode: 
1048577
Filename: tmp, Inode: 1179650
Filename: sys, Inode: 917506
Filename: libx32, Inode: 17
Filename: srv, Inode: 786434
Filename: lib64, Inode: 16
Filename: sbin, Inode: 18
Filename: dev, Inode: 131073
Filename: swapfile, Inode: 12
Filename: run, Inode: 104857

所以,访问文件,必须打开当前目录,获得对应的inode号,然后进行文件访问

2.2 路径解析

要想访问当前文件需要知道当前文件的目录,目录也是文件,所以也需要知道上一级目录,如此递归下去,出口就是根目录。从根目录开始依次访问每个目录下指定的目录,直到访问到文件,这个过程叫linux路径解析

如果访问任何文件,都从/目录开始进行路径解析太慢了,所以linux会缓存历史路径结构,Linux中,在内核中维护树状路径结构的内核结构体叫做: struct dentry

cs 复制代码
struct dentry
{
     struct inode *d_inode;      /* Where the name belongs to  - NULL is
                                  negative */
     struct dentry *d_parent;    /* parent directory */
     struct list_head d_lru;     /* LRU list */
     struct list_head d_subdirs; /* our children */
     struct super_block *d_sb;   /* The root of the dentry tree */
     ...
}

每个文件都有对应的dentry结构,包括普通文件。这样所有被打开的文件,就可以在内存中形成整个树形结构。dentry是纯内存结构,磁盘上不存在dentry,磁盘上只有目录文件的数据块,内核读取后转化成内存中的dentry

2.3 挂载分区

挂载分区是为了解决跨分区问题,

挂载 = 把分区的根目录"嫁接"到现有目录树的某个节点上

cs 复制代码
挂载前:                          挂载后 (mount /dev/sdb1 /mnt/data):
/                                /
├── home                         ├── home
├── etc                          ├── etc
└── mnt                          └── mnt
    └── data  ← (空目录)             └── data  ← 现在指向 /dev/sdb1 的根目录
                                         ├── photos/
                                         ├── videos/
                                         └── backup.tar.gz

挂载的本质是在 VFS 层创建一个特殊的 dentry,其 d_flags 标记为 DCACHE_MOUNTED,并将该 dentry 的 d_inode 指向新分区的根 inode,路径解析时,内核遇到带 DCACHE_MOUNTED 标志的 dentry,会自动跳转到对应文件系统的根 dentry 继续解析

2.4 总结

进程pcb中有两个指针*fs和*files,*fs指向fs_struct,存储的是该进程当前的文件系统上下文信息, 它保存了进程的**根目录、当前工作目录和 umask,**本质上是该进程在 VFS 目录树中的"导航状态"

注意的是fs_struct 存储的是路径解析的起点(锚点) ,而不是 路径解析过程中产生的 dentry 链或缓存结构。只存储两个特定的 dentry 引用 (root 和 pwd)作为解析基准,是进程级别的上下文配置 ,告诉 VFS "从哪里开始解析"。解析过程中经过的所有中间 dentry,都存在于全局的 dentry cache (dcache) 中,不属于任何进程的 fs_struct

struct file 中确实包含 struct path,而 struct path 内部又包含了 dentry防止路径发生变化或者相对路径缺失。struct file中的path打开后是永不改变的

串联一下

cs 复制代码
open("config.txt")
    │
    ▼
1. VFS 从 current->fs->pwd.dentry 出发 ← fs_struct 提供起点
    │
    ▼
2. 在全局 dcache 中逐级查找 "config.txt" ← dcache 提供缓存
    │
    ▼
3. 找到目标 dentry + inode
    │
    ▼
4. 分配 struct file,将结果存入 f_path + f_inode ← file 记住结果
    │
    ▼
5. 返回 fd,存入 current->files->fd[n] ← files_struct 管理描述符
    │
    ▼
6. 后续 read(fd) 直接使用 file->f_path/f_inode ← 不再碰 fs_struct

最后一张图加深记忆


相关推荐
无限进步_5 小时前
【C++】weak_ptr、循环引用与线程安全
开发语言·数据结构·c++·算法·安全
duoduo_sing5 小时前
数据库备份终极方案:从脚本手动到自动化热备+异地同步实战
运维·数据库·自动化·用友
罗超驿5 小时前
9.LeetCode 209. 长度最小的子数组 | 滑动窗口专题详解
java·算法·leetcode·面试
都在酒里6 小时前
Linux字符设备驱动开发(七):输入子系统——驱动GPIO按键并上报事件
linux·驱动开发·交互
水蓝烟雨6 小时前
0135. 分发糖果
算法·leetcode
IronMurphy6 小时前
【算法五十二】5. 最长回文子串
算法
风曦Kisaki6 小时前
# Linux运维Day06:HAproxy负载均衡(代理调度软件对比)、Tomcat服务部署与LNMJ架构
linux·运维·负载均衡
早睡身体真不戳6 小时前
【无标题】
java·服务器·windows
Lewiis6 小时前
白话选择排序
数据结构·算法·排序算法