Linux 文件系统

文件描述符(File Descriptor,FD)(win里一般称为文件句柄)是操作系统中用于标识和管理已打开文件或I/O资源的整数值。
当进程请求打开一个文件或资源时,操作系统为该资源分配一个文件描述符,并将其返回给进程。进程随后使用该文件描述符来进行读写操作。 是一个进程级别的概念。

  • 继承:在创建子进程时,文件描述符可以在父子进程之间共享(例如通过 fork())。
  • 复制:通过系统调用 dup() 或 dup2() 可以复制文件描述符,使它们引用同一个文件或资源。

文件描述符不仅用于操作文件,还可以指向:

  • 管道(Pipes):用于进程间通信。
  • 套接字(Sockets):用于网络通信。
  • 设备文件:例如硬盘、串口等设备。

文件分配表(File Allocation Table, FAT)。

何为文件索引节点?文件与磁盘的爱恨情仇。
阮一峰的个人网站
inode(索引节点)。理解inode

文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector)。每个扇区储存512字节(相当于0.5KB)。 操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个"块"(block)。这种由多个扇区组成的"块",是文件存取的最小单位。“块"的大小,最常见的是4KB,即连续八个 sector组成一个 block。 文件数据都储存在"块"中,那么很显然,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode,中文译名为"索引节点”。
可以用stat命令,查看某个文件的inode信息。 inode也会消耗硬盘空间,所以硬盘格式化的时候,操作系统自动将硬盘分成两个区域。一个是数据区,存放文件数据;另一个是inode区(inode table),存放inode所包含的信息。 Unix/Linux系统内部不使用文件名,而使用inode号码来识别文件。

超级块(Superblock)位于每个文件系统的开头,提供了操作系统如何解释和管理该文件系统的元数据。(记录各个inode?)

软链接和硬链接:

  • 软链接是一个独立的文件,它包含了另一个文件或目录的路径。它类似于 Windows 系统中的快捷方式。
  • 硬链接是文件的一个直接引用(或者说是指针),它与原文件共享相同的inode。删除原文件后,硬链接仍然有效,因为它直接引用了文件的数据;文件只有当所有硬链接都被删除后,数据才会被清除。inode信息中有一项叫做"链接数",记录指向该inode的文件名总数。

linux软件更新过程:软件更新变得简单:系统通过inode号码,识别运行中的文件,不通过文件名。更新的时候,新版文件以同样的文件名,生成一个新的inode,不会影响到运行中的文件。等到下一次运行这个软件的时候,文件名就自动指向新版文件,旧版文件的inode则被回收。


Linux 虚拟文件系统

linux I/O原理、监控、和调优思路
图解Linux虚拟文件系统(VFS)之关系篇

虚拟文件系统(Virtual File System,VFS):它提供了一个统一的接口,使得用户和应用程序可以通过相同的方式访问不同类型的文件系统。

通过VFS用户可以使用相同的系统调用(如openreadwrite等)来访问不同类型的文件系统,包括本地文件系统(如ext4、XFS等)、网络文件系统(如NFS、CIFS等)以及虚拟文件系统(如procfs、sysfs等)。

VFS由以下几个主要组件组成:

  1. 虚拟文件系统接口:VFS定义了一组通用的文件系统操作接口。
  2. 超级块(super_block):每个文件系统都有一个超级块,它包含了文件系统的元数据信息,如文件系统类型、块大小、inode表等,超级块提供了对文件系统的整体描述和管理。
  3. 目录项(dentry):Directory Entry,用于表示文件系统中的目录和文件,dentry包含了目录和文件对应的inode指针、层级关系(parent)等。

    dentry结构体的主要作用是提供文件系统层次结构的表示,它们通过形成一个树状结构来组织目录和文件,每个dentry都有一个唯一的路径名,可以通过遍历dentry树来找到特定文件或目录。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
struct dentry {
    struct dentry *d_parent;
    struct qstr d_name;
    struct inode *d_inode;

    const struct dentry_operations *d_op;
    struct super_block *d_sb;
    struct list_head d_child;
    struct list_head d_subdirs;
    ....
};
  1. 文件节点(inode):inode是文件系统中的一个数据结构,用于存储文件或目录的元数据信息,如文件大小、权限、所有者等,每个文件或目录都对应一个唯一的inode。
  2. 文件对象(file):file是表示打开文件的数据结构,它包含了对应的inode指针、当前读写位置等信息,通过file可以进行文件的读写操作。
  • 索引节点(index node, inode),用来记录文件的元数据,比如 inode 编号、文件大小、访问权限、修改日期、数据的位置等。索引节点和文件一一对应,它跟文件内容一样,都会被持久化存储到磁盘中。所以记住,索引节点同样占用磁盘空间。
  • 目录项(directory entry, dentry),用来记录文件的名字、索引节点指针以及与其他目录项的关联关系。多个关联的目录项,就构成了文件系统的目录结构。不过,不同于索引节点,目录项是由内核维护的一个内存数据结构,所以通常也被叫做目录项缓存。

ramfs是一种基于内存的文件系统。它将所有的文件数据存储在内存(RAM)中,而不是像传统的文件系统那样存储在磁盘等外部存储设备上。

定义好文件系统后,通过register_filesystem函数将文件系统注册至Linux系统,注册成功的文件系统会插入全局文件系统链表,已注册的文件系统能够用来创建超级块(super block)。

文件系统挂载:新文件系统生成一个挂载实例(struct mount),让新挂载实例和父文件系统的挂载实例建立父子关系。每个文件系统都有一个根目录,当索引一个文件路径进入到一个新的文件系统后,会从新的文件系统根目录开始索引。


Memory Cgroup(内存控制组)

Memory Cgroup 是 cgroup(控制组)的一个子系统,用于控制和限制进程组或任务组的内存使用。它是 Linux 内核提供的一种资源管理机制,主要目的是隔离和限制内存资源的使用,确保系统的稳定性和公平性。

  • 可以通过配置参数来设置内存使用的硬限制(memory.limit_in_bytes)。当进程组使用的内存达到这个硬限制时,会触发内存回收机制,如通过OOM - Killer(内存不足杀手)选择并终止进程组中的某些进程来释放内存。
  • 会收集进程组的各种内存使用统计信息,包括rss( Resident Set Size,实际驻留在内存中的内存大小)、cache(缓存内存大小)等。