在LINUX系统中有一个重要的概念:一切都是文件。 其实这是UNIX哲学的一个体现,而Linux是重写UNIX而来,所以这个概念也就传承了下来。在UNIX系统中,把一切资源都看作是文件,包括硬件设备。UNIX系统把每个硬件都看成是一个文件,通常称为设备文件,这样用户就可以用读写文件的方式实现对硬件的访问。
和 DOS 等操作系统不同,Linux 操作系统中单独的文件系统并不是由驱动器号或驱动器名称(如 A: 或 C: 等)来标识的。相反,和 UNIX 操作系统一样,Linux 操作系统将独立的文件系统组合成了一个层次化的树形结构,并且由一个单独的实体代表这一文件系统。Linux 将新的文件系统通过一个称为“挂装”或“挂上”的操作将其挂装到某个目录上,从而让不同的文件系统结合成为一个整体。Linux 操作系统的一个重要特点是它支持许多不同类型的文件系统。Linux 中最普遍使用的文件系统是 Ext2,它也是 Linux 土生土长的文件系统。但 Linux 也能够支持 FAT、VFAT、FAT32、MINIX 等不同类型的文件系统,从而可以方便地和其它操作系统交换数据。由于 Linux 支持许多不同的文件系统,并且将它们组织成了一个统一的虚拟文件系统.
一、访问文件分层
我们应用程序访问硬盘,不会直接写代码来访问,而是通过OS的提供接口, OS的接口通常是文件系统的接口,对Linux操作系统而言,访问硬盘从软件到硬件,从上到下大致可以分为三层:
一、虚拟文件系统:通用抽象接口、具体文件系统、系统文件缓存。
二、设备驱动层:通用驱动接口、具体驱动接口
三、设备层(具体的硬件设备,可以理解为磁盘)
1、 虚拟文件系统(VirtualFileSystem,VFS):
目前在Linux操作系统中支持很多种文件系统,包括Ext2、Ext4、Btrfs和XFS等,多达几十个文件系统。虽然支持的文件系统种类很多,但从用户层面使用方式无任何差别,用户并不感知其中的差异,这个得益于虚拟文件系统提供通用抽象接口。
虚拟文件系统(VirtualFileSystem,VFS):隐藏了各种硬件的具体细节,把文件系统操作和不同文件系统的具体实现细节分离了开来,为所有的设备提供了统一的接口,VFS提供了多达数十种不同的文件系统。
虚拟文件系统可以分为逻辑文件系统和设备驱动程序。逻辑文件系统指Linux所支持的文件系统,如ext2,fat等,设备驱动程序指为每一种硬件控制器所编写的设备驱动程序模块。
虚拟文件系统(VFS)是 Linux 内核中非常有用的一个方面,因为它为文件系统提供了一个通用的接口抽象。VFS 在 SCI 和内核所支持的文件系统之间提供了一个交换层。即VFS 在用户和文件系统之间提供了一个交换层。
VFS 在用户应用程序和文件系统之间提供了一个交换层:用户应用程序不需要关注文件所在的文件系统类型,而只需要像使用 Ext2文件系统中的文件一样使用文件。 在 VFS上面,是对诸如 open、close、read 和 write 之类的函数的一个通用 API 抽象。在 VFS 下面是文件系统抽象,它定义了上层函数的实现方式。它们是给定文件系统(超过 50 个)的插件。文件系统的源代码可以在 ./linux/fs 中找到。
由于考虑到磁盘的缺点, 文件系统层之下是缓冲区缓存,它为文件系统层提供了一个通用函数集(与具体文件系统无关)。
因此文件系统在读写数据方法做了一些性能方面的优化:文件系统对磁盘访问的性能优化是通过页缓存(页缓存其实就是内存)完成的,这个页缓存与CPU中的缓存有异曲同工之妙。文件系统通过页缓存在数据写和读两方面分别作了优化。
写方面的优化主要: 是延迟批量写,也就是数据先写到页缓存中,经过积累后再磁盘驱动提交。这种积累和延迟写主要目的是为了增加数据的连续性,也就是为了规避磁盘机械臂的摆动,因为磁盘机械臂摆动是最耗时的。
读方面的优化主要:是预读功能,预读就是根据当前应用读取数据的模式,提前将数据读到内存当中。由于应用访问数据的区域局部性特点,这种预读就可以避免应用直接从磁盘读取数据的延时,从而提高读性能。
这个缓存层通过将数据保留一段时间(或者随即预先读取数据以便在需要是就可用)优化了对物理设备的访问。
2、 设备驱动:
缓冲区缓存之下是设备驱动程序,它实现了特定物理设备的接口。 常见的硬盘类型有PATA, SATA和AHCI等,在Linux系统中,对不同硬盘所提供的驱动模块一般都存放在内核目录树drivers/ata中,而对于一般通用的硬盘驱动,也许会直接被编译到内核中,而不会以模块的方式出现,可以通过查看/boot/config-xxx.xxx文件来确认: CONFIG_SATA_AHCI=y 驱动通用抽象接口: 不同的硬盘驱动,会提供不同的IO接口,内核认为这种杂乱的接口,不利于管理,需要把这些接口抽象一下,形成一个统一的对外接口,这样,不管你是什么硬盘,什么驱动,对外而言,它们所提供的IO接口没什么区别,都一视同仁的被看作块设备来处理。 所以,如果驱动通用抽象接口做的任何修改,将会直接影响到所有文件系统,不管是ext3,ext4还是其它文件系统,只要在这一层次做了某种修改,对它们都会产生影响。
3、磁盘读写原理:
关于硬盘读写原理, 可以参考另外博文:https://blog.csdn.net/hguisu/article/details/7408047
二、常见文件系统类型
Linux 系统能够支持的文件系统非常多,除 Linux 默认文件系统 Ext2、Ext3 和 Ext4 之外,还能支持 fat16、fat32、NTFS(需要重新编译内核)等 Windows 文件系统。也就是说,Linux 可以通过挂载的方式使用 Windows 文件系统中的数据。Linux 所能够支持的文件系统在 "/usr/src/kemels/当前系统版本/fs" 目录中(需要在安装时选择),该目录中的每个子目录都是一个可以识别的文件系统。我们介绍较为常见的 Linux 支持的文件系统,如表 1 所示。
文件系统 | 描 述 |
---|---|
Ext | Linux 中最早的文件系统,由于在性能和兼容性上具有很多缺陷,现在已经很少使用 |
Ext2 | 是 Ext 文件系统的升级版本,Red Hat Linux 7.2 版本以前的系统默认都是 Ext2 文件系统。于 1993 年发布,支持最大 16TB 的分区和最大 2TB 的文件(1TB=1024GB=1024x1024KB) |
Ext3 | 是 Ext2 文件系统的升级版本,最大的区别就是带日志功能,以便在系统突然停止时提高文件系统的可靠性。支持最大 16TB 的分区和最大 2TB 的文件 |
Ext4 | 是 Ext3 文件系统的升级版。Ext4 在性能、伸缩性和可靠性方面进行了大量改进。Ext4 的变化可以说是翻天覆地的,比如向下兼容 Ext3、最大 1EB 文件系统和 16TB 文件、无限数量子目录、Extents 连续数据块 概念、多块分配、延迟分配、持久预分配、快速 FSCK、日志校验、无日志模式、在线碎片整理、inode 增强、默认启用 barrier 等。它是 CentOS 6.3 的默认文件系统 |
swap | swap 是 Linux 中用于交换分区的文件系统(类似于 Windows 中的虚拟内存),当内存不够用时,使用交换分区暂时替代内存。一般大小为内存的 2 倍,但是不要超过 2GB。它是 Linux 的必需分区 |
NFS | NFS 是网络文件系统(Network File System)的缩写,是用来实现不同主机之间文件共享的一种网络服务,本地主机可以通过挂载的方式使用远程共享的资源 |
iso9660 | 光盘的标准文件系统。Linux 要想使用光盘,必须支持 iso9660 文件系统 |
fat | 就是 Windows 下的 fatl6 文件系统,在 Linux 中识别为 fat |
vfat | 就是 Windows 下的 fat32 文件系统,在 Linux 中识别为 vfat。支持最大 32GB 的分区和最大 4GB 的文件 |
NTFS | 就是 Windows 下的 NTFS 文件系统,不过 Linux 默认是不能识别 NTFS 文件系统的,如果需要识别,则需要重新编译内核才能支持。它比 fat32 文件系统更加安全,速度更快,支持最大 2TB 的分区和最大 64GB 的文件 |
ufs | Sun 公司的操作系统 Solaris 和 SunOS 所采用的文件系统 |
proc | Linux 中基于内存的虚拟文件系统,用来管理内存存储目录 /proc |
sysfs | 和 proc —样,也是基于内存的虚拟文件系统,用来管理内存存储目录 /sysfs |
tmpfs | 也是一种基于内存的虚拟文件系统,不过也可以使用 swap 交换分区 |
三、文件系统和硬盘关联:物理磁盘到文件系统
硬盘最基本的组成部分是由坚硬金属材料制成的涂以磁性介质的盘片,不同容量硬盘的盘片数不等。每个盘片有两面,都可记录信息。盘片被分成许多扇形的区域,每个区域叫一个扇区,每个扇区可存储128×2的N次方(N=0.1.2.3)字节信息。在DOS中每扇区是128×2的2次方=512字节,盘片表面上以盘片中心为圆心,不同半径的同心圆称为磁道。硬盘中,不同盘片相同半径的磁道所组成的圆柱称为柱面。磁道与柱面都是表示不同半径的圆,在许多场合,磁道和柱面可以互换使用,我们知道,每个磁盘有两个面,每个面都有一个磁头,习惯用磁头号来区分。扇区,磁道(或柱面)和磁头数构成了硬盘结构的基本参数,帮这些参数可以得到硬盘的容量,基计算公式为: 存储容量=磁头数×磁道(柱面)数×每道扇区数×每扇区字节数 要点: (1)硬盘有数个盘片,每盘片两个面,每个面一个磁头 (2)盘片被划分为多个扇形区域即扇区 (3)同一盘片不同半径的同心圆为磁道 (4)不同盘片相同半径构成的圆柱面即柱面 (5)公式: 存储容量=磁头数×磁道(柱面)数×每道扇区数×每扇区字节数 (6)信息记录可表示为:××磁道(柱面),××磁头,××扇区
文件最终是保存在硬盘上的,一块新硬盘,我们是怎么样写入文件保存起来呢? 根据上面磁盘的内部结构,步骤如下: 第一步:磁盘分区:fdisk /dev/vdb 第二步:磁盘格式化:写入文件系统ext4 :mkfs.ext4 /dev/vdb1; && echo /dev/vdb1 /mnt ext4 defaults 0 0 >> /etc/fstab ; 第三步:磁盘挂载:mount /dev/vdb1 /mnt; 第四步:文件保存磁盘/dev/vdb:echo 11 /mnt/123.txt
删除分区: #fdisk /dev/sda command(m for help): d 选择分区号 记住q---不存储离开 w---存储离开
第一步:磁盘分区
硬盘不能直接使用,必须对硬盘进行分割,分割成的一块一块的硬盘区域就是磁盘分区。分区的目的是分区允许在一个磁盘上有多个文件系统。
1、磁盘分区
是使用分区编辑器(partition editor)在磁盘上划分几个逻辑部分,盘片一旦划分成数个分区(Partition),不同类的目录与文件可以存储进不同的分区。在传统的磁盘管理中,将一个硬盘分为两大类分区:主分区和扩展分区。主分区是能够安装操作系统,能够进行计算机启动的分区,这样的分区可以直接格式化,然后安装系统,直接存放文件。
2、分区种类:主分区,扩展分区和逻辑分区:
linux分区不同于windows,硬盘和硬盘分区在Linux都表示为设备. 硬盘分区一共有三种:主分区,扩展分区和逻辑分区。 硬盘的分区主要分为主分区(Primary Partion)和扩展分区(Extension Partion)两种,主分区和扩展分区的数目之和不能大于四个。 主分区(Primary Partion): 可以马上被使用但不能再分区。 扩展分区(Extension Partion): 必须再进行分区后才能使用,也就是说它必须还要进行二次分区。 逻辑分区((Logical Partion)): 由扩展分区建立起来的分区。逻辑分区没有数量上限制。 扩展分区只不过是逻辑分区的“容器”,实际上只有主分区和逻辑分区进行数据存储。
3、Linux下硬盘分区的标识
硬盘分区的标识一般使用/dev/hd[a-z]X或者/dev/sd[a-z]X来标识,其中[a-z]代表硬盘号,X代表硬盘内的分区号。
整块硬盘分区的块号标识:
Linux下用hda、hdb、sda、sdb 等来标识不同的硬盘;其中: IDE接口硬盘:表示为/dev/hda1、/dev/hdb ...; SCSI 接口的硬盘、SATA接口的硬盘表示为/dev/sda、/dev/sdb ... ... ;
硬盘内的分区:如果X的值是1到4,表示硬盘的主分区(包含扩展分区);逻辑分区从是从5开始的,比如/dev/hda5肯定是逻辑分区了;例如:
用hda1、hda2、 hda5、hda6 来标识不同的分区。其中,字母a 代表第一块硬盘,b代表第二块硬盘,依次类推。而数字1 代表一块硬盘的第一个分区、2 代表第二个分区,依次类推。1 到4 对应的是主分区(Primary Partition)或扩展分区(Extension Partition)。从5开始,对应的都是硬盘的逻辑分区(Logical Partition)。一块硬盘即使只有一个主分区,逻辑分区也是从5开始编号的,这点应特别注意。
总结:一个硬盘分区首先要大确认在哪个硬盘,然后再确认它所在硬盘内的哪个分区。对于/dev/hda 类似的表示方法,也并不寞生吧;我们在Linux通过fdisk -l 就可以查到硬盘是/dev/hda还是/dev/hdb;
[root@localhost ~]# fdisk -l Disk /dev/hda: 80.0 GB, 80026361856 bytes 255 heads, 63 sectors/track, 9729 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System /dev/hda1 * 1 970 7791493 7 HPFS/NTFS /dev/hda2 971 9729 70356667 5 Extended /dev/hda5 971 2915 15623181 b W95 FAT32 /dev/hda6 2916 4131 9767488 83 linux /dev/hda7 4132 5590 11719386 83 linux /dev/hda8 5591 6806 9767488 83 linux /dev/hda9 6807 9657 22900626 83 linux /dev/hda10 9658 9729 578308 82 linux swap / Solaris
请注意第一行, Disk /dev/hda: 80.0 GB, 80026361856 bytes ,这个就是表示机器中只有一个硬盘设备/dev/hda ,体积大小为 80.0G;下面的就是硬盘的分区,每个分区都有详细的信息,在这里不详细说了;
4、Linux下磁盘分区和目录的关系如下:
– 任何一个分区都必须挂载到某个目录上。 – 目录是逻辑上的区分。分区是物理上的区分。 – 磁盘Linux分区都必须挂载到目录树中的某个具体的目录上才能进行读写操作。 – 根目录是所有Linux的文件和目录所在的地方,需要挂载上一个磁盘分区。
第二步:磁盘格式化:写入文件系统
磁盘分区完毕后还需要进行格式化(format),之后操作系统才能够使用这个分区。 格式化的目的是能使操作系统可以使用的文件系统格式(即我们上面提到文件系统类型).
传统的磁盘与文件系统之应用中,一个分区就是只能够被格式化成为一个文件系统,所以我们可以说一个 filesystem 就是一个 partition。但是由于新技术的利用,例如我们常听到的LVM与软件磁盘阵列(software raid), 这些技术可以将一个分区格式化为多个文件系统(例如LVM),也能够将多个分区合成一个文件系统(LVM, RAID)! 所以说,目前我们在格式化时已经不再说成针对 partition 来格式化了, 通常我们可以称呼一个可被挂载的数据为一个文件系统而不是一个分区。
第三步:磁盘格式化:挂载文件系统
linux系统中每个分区都是一个文件系统,都有自己的目录层次结构。linux会将这些分属不同分区的、单独的文件系统按一定的方式形成一个系统的总的目录层次结构。这里所说的“按一定方式”就是指的挂载。
将一个文件系统的顶层目录挂到另一个文件系统的子目录上,使它们成为一个整体,称为挂载。把该子目录称为挂载点.
例如要读取硬盘中的一个格式化好的分区、光盘或软件等设备时,必须先把这些设备对应到某个目录上,而这个目录就称为“挂载点(mount point)”,这样才可以读取这些设备。 挂载后将物理分区细节屏蔽掉,用户只有统一的逻辑概念。所有的东西都是文件。
注意: 1、挂载点必须是一个目录。 2、一个分区挂载在一个已存在的目录上,这个目录可以不为空,但挂载后这个目录下以前的内容将不可用。
对于其他操作系统建立的文件系统的挂载也是这样。但是需要理解的是:光盘、软盘、其他操作系统使用的文件系统的格式与linux使用的文件系统格式是不一样的。光盘是ISO9660;软盘是fat16或ext2;windows NT是fat16、NTFS;windows98是fat16、fat32;windows2000和windowsXP是fat16、fat32、 NTFS。挂载前要了解linux是否支持所要挂载的文件系统格式。
四、文件系统存储原理
1、文件存储结构
这与操作系统的文件数据有关。较新的操作系统的文件数据除了文件实际内容外, 通常含有非常多的属性,Linux 操作系统的文件权限(rwx)与文件属性(拥有者、群组、时间参数等)。 文件系统通常会将这两部份的数据分别存放在不同的区块,权限与属性放置到 inode 中,至于实际数据则放置到 data block 区块中。 另外,还有一个超级区块 (superblock) 会记录整个文件系统的整体信息,包括 inode 与 block 的总量、使用量、剩余量等。
对于一个磁盘分区来说,在被指定为相应的文件系统后,整个分区被分为 1024,2048 和 4096 字节大小的块。根据块使用的不同,可分为:
- 超级块(Superblock): 这是整个文件系统的第一块空间。包括整个文件系统的基本信息,如块大小,inode/block的总量、使用量、剩余量,指向空间 inode 和数据块的指针等相关信息。
- inode块(文件索引节点) : 文件系统索引,记录文件的属性。它是文件系统的最基本单元,是文件系统连接任何子目录、任何文件的桥梁。每个子目录和文件只有唯一的一个 inode 块。它包含了文件系统中文件的基本属性(文件的长度、创建及修改时间、权限、所属关系)、存放数据的位置等相关信息. 在 Linux 下可以通过 "ls -li" 命令查看文件的 inode 信息。硬连接和源文件具有相同的 inode 。
- 数据块(Block) :实际记录文件的内容,若文件太大时,会占用多个 block。为了提高目录访问效率,Linux 还提供了表达路径与 inode 对应关系的 dentry 结构。它描述了路径信息并连接到节点 inode,它包括各种目录信息,还指向了 inode 和超级块。
就像一本书有封面、目录和正文一样。在文件系统中"
- 超级块就相当于封面,从封面可以得知这本书的基本信息;
- inode 块相当于目录,从目录可以得知各章节内容的位置;
- 数据块则相当于书的正文,记录着具体内容。
Linux正统的文件系统(如ext2、3等)将硬盘分区时会划分出超级块、inode Table区块和data block数据区域。一个文件由一个超级块、inode和数据区域块组成。Inode包含文件的属性(如读写属性、owner等,以及指向数据块的指针),数据区域块则是文件内容。当查看某个文件时,会先从inode table中查出文件属性及数据存放点,再从数据块中读取数据。
ext2文件系统示意图
我们将 inode 与 block 区块用图解来说明一下,如下图所示,文件系统先格式化出 inode 与 block 的区块,假设某一个文件的属性与权限数据是放置到 inode 4 号(下图较小方格内),而这个 inode 记录了文件数据的实际放置点为 2, 7, 13, 15 这四个 block 号码,此时我们的操作系统就能够据此来排列磁盘的阅读顺序,可以一口气将四个 block 内容读出来! 那么数据的读取就如同下图中的箭头所指定的模样了。
图 inode/block 数据存取示意图
这种数据存取的方法我们称为索引式文件系统(indexed allocation)。那有没有其他的惯用文件系统可以比较一下啊? 有的,那就是我们惯用的闪盘(闪存),闪盘使用的文件系统一般为 FAT 格式。FAT 这种格式的文件系统并没有 inode 存在,所以 FAT 没有办法将这个文件的所有 block 在一开始就读取出来。每个 block 号码都记录在前一个 block 当中, 其读取方式有点像下图所示:
图、FAT文件系统数据存取示意图
上图中我们假设文件的数据依序写入1->7->4->15号这四个 block 号码中, 但这个文件系统没有办法一口气就知道四个 block 的号码,他得要一个一个的将 block 读出后,才会知道下一个 block 在何处。 如果同一个文件数据写入的 block 分散的太过厉害时,则我们的磁盘读取头将无法在磁盘转一圈就读到所有的数据, 因此磁盘就会多转好几圈才能完整的读取到这个文件的内容!
2、文件碎片
常常会听到所谓的“碎片整理”吧? 需要碎片整理的原因就是文件写入的 block 太过于离散了,此时文件读取的效能将会变的很差所致。 这个时候可以透过碎片整理将同一个文件所属的 blocks 汇整在一起,这样数据的读取会比较容易啊! 想当然尔,FAT 的文件系统需要经常的碎片整理一下,那么 Ext2 是否需要磁盘重整呢?
由于 Ext2 是索引式文件系统,基本上不太需要常常进行碎片整理的。但是如果文件系统使用太久, 常常删除/编辑/新增文件时,那么还是可能会造成文件数据太过于离散的问题,此时或许会需要进行重整一下的。 不过,老实说,鸟哥倒是没有在 Linux 操作系统上面进行过 Ext2/Ext3 文件系统的碎片整理说!似乎不太需要啦!^_^
3、理解文件连接
可以用ln命令对一个已经存在的文件再建立一个新的连接,而不复制文件的内容。连接有软连接和硬连接之分,软连接又叫符号连接。它们各自的特点是: 硬连接:原文件名和连接文件名都指向相同的物理地址。目录不能有硬连接;硬连接不能跨越文件系统(不能跨越不同的分区)文件在磁盘中只有一个拷贝,节省硬盘空间; 由于删除文件要在同一个索引节点属于唯一的连接时才能成功,因此可以防止不必要的误删除。 符号连接:用ln -s命令建立文件的符号连接符号连接是linux特殊文件的一种,作为一个文件,它的数据是它所连接的文件的路径名。类似windows下的快捷方式。 可以删除原有的文件而保存连接文件,没有防止误删除功能。
具体关系可以看下图:
图5:软链接和硬链接
从图上可以看出硬链接和软链接的区别:
1:硬链接原文件和新文件的inode编号一致。而软链接不一样。 2:对原文件删除,会导致软链接不可用,而硬链接不受影响。 3:对原文件的修改,软、硬链接文件内容也一样的修改,因为都是指向同一个文件内容的。
4、文件系统在内核中的表示
内核数据结构
Linux内核的VFS子系统可以图示如下:
文件与IO: 每个进程在PCB(Process Control Block)中都保存着一份文件描述符表,文件描述符就是这个表的索引,每个表项都有一个指向已打开文件的指针,现在我们明确一下:已打开的文件在内核中用file结构体表示,文件描述符表中的指针指向file结构体。
file结构体:
在file结构体中维护File Status Flag(file结构体的成员f_flags)和当前读写位置(file结构体的成员f_pos)。在上图中,进程1和进程2都打开同一文件,但是对应不同的file结构体,因此可以有不同的File Status Flag和读写位置。file结构体中比较重要的成员还有f_count,表示引用计数(Reference Count),后面我们会讲到,dup、fork等系统调用会导致多个文件描述符指向同一个file结构体,例如有fd1和fd2都引用同一个file结构体,那么它的引用计数就是2,当close(fd1)时并不会释放file结构体,而只是把引用计数减到1,如果再close(fd2),引用计数就会减到0同时释放file结构体,这才真的关闭了文件。
file_operations结构体:
每个file结构体都指向一个file_operations结构体,这个结构体的成员都是函数指针,指向实现各种文件操作的内核函数。比如在用户程序中read一个文件描述符,read通过系统调用进入内核,然后找到这个文件描述符所指向的file结构体,找到file结构体所指向的file_operations结构体,调用它的read成员所指向的内核函数以完成用户请求。在用户程序中调用lseek、read、write、ioctl、open等函数,最终都由内核调用file_operations的各成员所指向的内核函数完成用户请求。file_operations结构体中的release成员用于完成用户程序的close请求,之所以叫release而不叫close是因为它不一定真的关闭文件,而是减少引用计数,只有引用计数减到0才关闭文件。对于同一个文件系统上打开的常规文件来说,read、write等文件操作的步骤和方法应该是一样的,调用的函数应该是相同的,所以图中的三个打开文件的file结构体指向同一个file_operations结构体。如果打开一个字符设备文件,那么它的read、write操作肯定和常规文件不一样,不是读写磁盘的数据块而是读写硬件设备,所以file结构体应该指向不同的file_operations结构体,其中的各种文件操作函数由该设备的驱动程序实现。
dentry结构体:
每个file结构体都有一个指向dentry结构体的指针,“dentry”是directory entry(目录项)的缩写。我们传给open、stat等函数的参数的是一个路径,例如/home/akaedu/a,需要根据路径找到文件的inode。为了减少读盘次数,内核缓存了目录的树状结构,称为dentry cache,其中每个节点是一个dentry结构体,只要沿着路径各部分的dentry搜索即可,从根目录/找到home目录,然后找到akaedu目录,然后找到文件a。dentry cache只保存最近访问过的目录项,如果要找的目录项在cache中没有,就要从磁盘读到内存中。
inode结构体:
每个dentry结构体都有一个指针指向inode结构体。inode结构体保存着从磁盘inode读上来的信息。在上图的例子中,有两个dentry,分别表示/home/akaedu/a和/home/akaedu/b,它们都指向同一个inode,说明这两个文件互为硬链接。inode结构体中保存着从磁盘分区的inode读上来信息,例如所有者、文件大小、文件类型和权限位等。每个inode结构体都有一个指向inode_operations结构体的指针,后者也是一组函数指针指向一些完成文件目录操作的内核函数。和file_operations不同,inode_operations所指向的不是针对某一个文件进行操作的函数,而是影响文件和目录布局的函数,例如添加删除文件和目录、跟踪符号链接等等,属于同一文件系统的各inode结构体可以指向同一个inode_operations结构体。
inode结构体有一个指向super_block结构体的指针。super_block结构体保存着从磁盘分区的超级块读上来的信息,例如文件系统类型、块大小等。super_block结构体的s_root成员是一个指向dentry的指针,表示这个文件系统的根目录被mount到哪里,在上图的例子中这个分区被mount到/home目录下。
file、dentry、inode、super_block这几个结构体组成了VFS的核心概念。对于ext2文件系统来说,在磁盘存储布局上也有inode和超级块的概念,所以很容易和VFS中的概念建立对应关系。而另外一些文件系统格式来自非UNIX系统(例如Windows的FAT32、NTFS),可能没有inode或超级块这样的概念,但为了能mount到Linux系统,也只好在驱动程序中硬凑一下,在Linux下看FAT32和NTFS分区会发现权限位是错的,所有文件都是rwxrwxrwx,因为它们本来就没有inode和权限位的概念,这是硬凑出来的。
五、Linux文件结构
文件结构是文件存放在磁盘等存贮设备上的组织方法。主要体现在对文件和目录的组织上。 目录提供了管理文件的一个方便而有效的途径。
Linux使用标准的目录结构,在安装的时候,安装程序就已经为用户创建了文件系统和完整而固定的目录组成形式,并指定了每个目录的作用和其中的文件类型。
完整的目录树可划分为小的部分,这些小部分又可以单独存放在自己的磁盘或分区上。这样,相对稳定的部分和经常变化的部分可单独存放在不同的分区中,从而方便备份或系统管理。目录树的主要部分有 root、/usr、/var、/home 等(图2) 。这样的布局可方便在 Linux 计算机之间共享文件系统的某些部分。
图2
Linux采用的是树型结构。最上层是根目录,其他的所有目录都是从根目录出发而生成的。
微软的DOS和windows也是采用树型结构,但是在DOS和 windows中这样的树型结构的根是磁盘分区的盘符,有几个分区就有几个树型结构,他们之间的关系是并列的。最顶部的是不同的磁盘(分区),如:C,D,E,F等。
但是在linux中,无论操作系统管理几个磁盘分区,这样的目录树只有一个。从结构上讲,各个磁盘分区上的树型目录不一定是并列的。
linux主要目录的功用:
/bin 二进制可执行命令 /dev 设备特殊文件
/etc 系统管理和配置文件 /etc/rc.d 启动的配置文件和脚本 /home 用户主目录的基点,比如用户user的主目录就是/home/user,可以用~user表示 /lib 标准程序设计库,又叫动态链接共享库,作用类似windows里的.dll文件 /sbin 系统管理命令,这里存放的是系统管理员使用的管理程序 /tmp 公用的临时文件存储点 /root 系统管理员的主目录(呵呵,特权阶级) /mnt 系统提供这个目录是让用户临时挂载其他的文件系统。 /lost found 这个目录平时是空的,系统非正常关机而留下“无家可归”的文件(windows下叫什么.chk)就在这里 /proc 虚拟的目录,是系统内存的映射。可直接访问这个目录来获取系统信息。 /var 某些大文件的溢出区,比方说各种服务的日志文件 /usr 最庞大的目录,要用到的应用程序和文件几乎都在这个目录。其中包含: /usr/X11R6 存放X window的目录 /usr/bin 众多的应用程序 /usr/sbin 超级用户的一些管理程序 /usr/doc linux文档 /usr/include linux下开发和编译应用程序所需要的头文件 /usr/lib 常用的动态链接库和软件包的配置文件 /usr/man 帮助文档 /usr/src 源代码,linux内核的源代码就放在/usr/src/linux里 /usr/local/bin 本地增加的命令 /usr/local/lib 本地增加的库
六、Linux文件
Linux下面的文件类型主要有: 1) 普通文件:C语言元代码、SHELL脚本、二进制的可执行文件等。分为纯文本和二进制。 2) 目录文件:目录,存储文件的唯一地方。 3) 链接文件:指向同一个文件或目录的的文件。 4) 设备文件:与系统外设相关的,通常在/dev下面。分为块设备和字符设备。
5)管道(FIFO)文件 : 提供进程建通信的一种方式 6)套接字(socket) 文件: 该文件类型与网络通信有关
可以通过ls –l, file, stat几个命令来查看文件的类型等相关信息。
七、Linux文件/目录管理命令
磁盘和文件空间 :fdisk df du
文件目录与管理: cd pwd mkdir rmdir ls cp rm mv
查看文件内容 cat、tac、more、less、head 、tail
文件目录与权限 :chmod chown chgrp umask
文件查找:which、whereis、locate、find、find