一、文件系统概述

1. 引导块

前文中介绍过磁盘需要进行分区和格式化,才能创建文件系统并使用,那么一块已经被各式化了分区其结构是什么样的呢?分区是按照柱面来划分的,而柱面包含的是磁道,磁道上包含的是扇区,一个分区上的前两个扇区(512 bytes * 2 = 1024 bytes)为引导块(Boot block),其作用为引导当前分区上的操作系统(与之相对的MBR是引导整个磁盘上的操作系统的,即指定启动哪一个分区上的操作系统),当然如果一块磁盘上只装了一个操作系统,那么Boot block并无太大意义,可能不被使用。除掉引导块,该分区剩余部分将被用来存放数据。

2. 索引

设想一下,如果一个目录下随意存放了10000个文件,而另一个目录下按照字母顺序,新建了10个目录,将10000个文件分别按字母放进不同的目录,并为其建立了索引,那么要找到具体某一个文件,必然是建立了索引的目录其检索速度更快。而索引的建立方式可以是多种多样的,比如按字母升序、字母降序、创建时间等等,不同的索引组织方式,就形成了不同的文件系统,但不论索引组织方式如何变化,其最终目的都是帮助用户实现按照文件名找到具体的文件。

 

针对不同的应用场景,文件系统的选择必然是不同的,比如有的文件系统需要让用户频繁的进行目录或文件的创建、删除、移动等操作,那么ext系列的文件系统是不错的选择;而有些服务器被当做数据库来使用,而数据库本身要不断的创建数据、更新数据、备份数据、扩展文件大小等等,其使用方式和普通用户的交互式使用是不同的,那么xfs这种文件系统会更加合适。至于如何选择合适的文件系统,需要根据实际生产环境来加以评估。

7. 文件系统——文件系统的索引、ext文件系统及块组(tune2fs,dumpe2fs,du,df)_块组

二、ext文件系统

1. 磁盘块

在文件系统中,索引通常位于磁盘块的首部,索引中存放了文件所在的条目信息。磁盘通过移动磁头、旋转盘片来定位到具体的扇区上,从而完成随机存取,而为了便于查找和管理,需要对扇区重新编号,按某种特定的逻辑结构进行排列,这个逻辑结构即为磁盘块。前文在介绍格式化时曾提到过为分区指定块大小,如1024 bytes, 2048bytes等,这个块大小指的就是磁盘块的大小。那么如果一个文件的大小为3k,而磁盘块大小为1024 bytes,那么就需要3个磁盘块来存放这个文件。这些磁盘块有自身的编号,所以要查找该文件的位置,只需要根据索引中记录的块编号,定位到具体的块上即可。索引中记录的这些条目信息(如文件对应的磁盘块指针、磁盘块二级指针、磁盘块三级指针、三个时间戳、大小、权限、属组属主等等,注意文件名不在此处存放),和文件本身的内容并无关系。因此,改变一个文件内容,实际是改变的磁盘块信息,而改变文件属性信息,是改变的文件的索引信息。

2. inode

索引中每一个文件的条目也自身的编号,这种编号称为inodeindex node)号,故查找某一个文件,首先要找到该文件的inode号。

如果一个文件大小为3k,那么只需要31024 bytes的磁盘块来存放它;但如果一个文件有3G,那么就需要 3 * 2^20个磁盘块来存放该文件,与之对应的,索引中的文件条目也需要保存这 3 * 2^20个磁盘块的信息,这将导致该条目无比巨大,这当然是不允许的。那么有没有方法能够压缩条目的大小呢?答案是一定的,我们可以采用层次化的方式来存放数据。比如将磁盘块所在的位置划分为一个个区域,如第1个区域有1000个磁盘块,第2个区域有3000个磁盘块,第3个区域有10000个区域......而将某一个区域作为一个整体来存放某一个文件,条目中建立具体的磁盘块指针(对应小文件,指向具体的磁盘块)、二级指针或三级指针(对应大文件,指向某一区域),这样就能大大减小索引条目的大小。当然建立二级指针或三级指针并不表示文件可以无限大,因为二级、三级指针也会受到索引条目大小的限制,故早期的ext2系列的文件系统,一个文件不能超过16 TB

3.文件的路径映射

如果要查找某一个具体的文件,指定查找位置为/根目录,和指定/var/log目录,其查找范围截然不同,故查找效率也很不一样。因此目录实际上是一个文件的查找路径的映射。我们知道在Linux系统中,目录也是文件,既然是文件,那么它就会在索引中建立相应的条目,在具体的磁盘块上保存数据。前面提到过,索引中不保存文件名,其实文件名和相应的inode号都保存在目录中

7. 文件系统——文件系统的索引、ext文件系统及块组(tune2fs,dumpe2fs,du,df)_Linux _02

我们查看某个目录下的文件信息,会发现目录的大小要比普通文件的大小小很多,这是由于这个大小只是目录本身的大小,而非目录下的文件的大小。

7. 文件系统——文件系统的索引、ext文件系统及块组(tune2fs,dumpe2fs,du,df)_Linux _03

比如要查找/var/log/messages这个文件,那么其查找过程如下:

查找到/根目录(根目录是自查找文件),获取根目录中/var的文件名及对应的inode号,

   根据/下查找到的inode号找到对应的索引中/varinode

      根据该条目找到具体保存/var文件信息的磁盘块,在该磁盘块上找到/var/log的文件名及其对应的inode

      根据/var/loginode号找到对应的索引中/var/log的条目,根据该条目找到具体保存/var/log文件信息的磁盘块

      在该磁盘块上找到/var/log/messages的文件名及其对应的inode

      根据/var/log/messagesinode号找到对应的索引中/var/log/messages的条目

      根据该条目找到具体保存/var/log/messages文件信息的磁盘块

7. 文件系统——文件系统的索引、ext文件系统及块组(tune2fs,dumpe2fs,du,df)_Linux _04

由此可以看出,一旦某个目录被删除了,那么目录中的文件就找不到了

 

4. ext文件系统的扩展属性

之前使用ls -l 命令可以列出文件的详细信息,事实上,使用lsattr命令可以列出文件的扩展属性:

[root@localhost tutor]# lsattr

——————————————运行结果————————————————

-------------e- ./memory1.sh
# 这里某个属性如果没有启用,就使用“-”表示,启用了就显示相关属性
-------------e- ./blank_line.sh
-------------e- ./if_cup.sh
-------------e- ./if_even_odd.sh
-------------e- ./if_cpu1.sh
-------------e- ./if_user3.sh
-------------e- ./3sum.sh
-------------e- ./version.sh
-------------e- ./abc
-------------e- ./inittab

 

命令lsattr是用来显示属性信息的,此外还有一个chattr命令,可以用来修改属信息:

[root@localhost tutor]# man chattr

——————————————运行结果————————————————
CHATTR(1)                                     CHATTR(1)
 
NAME
       chattr - change file attributes on a Linux file system
 
SYNOPSIS
       chattr [ -RVf ] [ -v version ] [ mode ] files...
 
DESCRIPTION
       chattr changes the file attributes on a Linux file system.
 
       The format of a symbolic mode is +-=[acdeijstuADST].
# 这里可以增删的属性为中括号中所列举的内容: [acdeijstuADST],使用 + - 可以增删属性
The  letters  acdeijstuADST select the new attributes for the files: append only (a), compressed (c), no dump (d), extent format (e), immutable (i), data journalling  (j),  secure deletion (s), no tail-merging (t), undeletable (u), no atime updates (A), synchronous directory updates (D), synchronous updates (S), and top of directory hierarchy (T).
# 常用属性有:
# i:只读属性;
# a:只允许增添内容;
# A:任何时候访问文件都不会改变文件的访问时间戳
# c:保存文件时自动压缩文件


 

[root@localhost tutor]# chattr +i inittab

inittab这个文件加上i属性


[root@localhost tutor]# lsattr

-------------e- ./memory1.sh
-------------e- ./blank_line.sh
-------------e- ./if_cup.sh
-------------e- ./if_even_odd.sh
-------------e- ./if_cpu1.sh
-------------e- ./if_user3.sh
-------------e- ./3sum.sh
-------------e- ./version.sh
-------------e- ./abc
----i--------e- ./inittab
# 可以看到 inittab文件已经具备i属性了

 

[root@localhost tutor]# vim inittab

编辑此文件,会发现inittab变成了只读文件,可见i属性为设置只读属性7. 文件系统——文件系统的索引、ext文件系统及块组(tune2fs,dumpe2fs,du,df)_Linux _05

[root@localhost tutor]# mv inittab inittab_1

mv: cannot move `inittab' to `inittab_1': Operation not permitted
# 有了i属性后,无法移动或修改文件名

 

[root@localhost tutor]# rm inittab

rm: remove regular file `inittab'? y
rm: cannot remove `inittab': Operation not permitted
# 也无法删除该文件

三、块组(block group

上述过程描述的是文件查找的过程,那么文件创建过程又是怎样的呢?

首先需要在索引中创建一个inode号,然后在磁盘上创建一个或多个磁盘块以备数据的存储。现在的问题是如何确定哪一个inode和哪一个磁盘块是空闲的?可以扫描整个inode表和整个磁盘空间,但是可以想象这样做的效率是极其低下的。为了避免全表扫描,可以建立一个位图(bit map),让每一个inode对应一个位,每一个磁盘块对应一个位,这样只需要分别扫描inode位图块位图,找出其中没有被占用的位,即可确定空闲的inode和磁盘块了。当然位图也需要占用相应的磁盘空间。

 

如果磁盘上存储了海量数目的文件,即使用了扫描位图的方式,其效率仍然比较低下,因此可以将磁盘块按照逻辑结构划分为块组(block group),如将100万个磁盘块划分为每5万个磁盘块一组,这样整个磁盘就划分成了20个块组,每一个组都自我管理,每次只扫描其中的一个块组,一个组的磁盘空间不够用,也可以跨组,通过这种方式可以大大提高效率。这些组的划分规则和管理方式也需要相应的磁盘空间来存储。

7. 文件系统——文件系统的索引、ext文件系统及块组(tune2fs,dumpe2fs,du,df)_块组_06

1. 超级块(Super Block

这里每一个块组内的磁盘块个数是相同的,而每一个组都是自我管理的;但是 Block Group 0(块组0)比较独特,它的第21024个字节所在的块被称为超级块(Super Block,这个块是用来保存该磁盘上所有的块组的信息的,即每一个组从哪一个块开始,到哪一个块结束等信息。因此一旦超级块坏掉了,其他所有块组的信息都无法读取了,因此超级块需要有很多备份,存放于其他块组中,但使用只使用块组0中的超级块,一旦坏了就从其他块组中找一个加以恢复。

 

2. 全局描述表(Group Description Table

紧跟在super block后面的是GDT,表示全局描述表,也称为块组描述表(Group Description Table,通常说到表,其中存放的多半是结构化信息,GDT也不例外,它存放的是块位图(Block Bitmap)和 inode位图(Inode Bitmap),即哪些块是已用的,哪些块是空闲的;哪些inode是已用的,哪些inode是空闲的,这样的位图比整个磁盘的位图要小得多,故扫描效率会提高很多。而通过Inode表(Inode Table就可以找到相应的磁盘块(Data Blocks)

 

超级块(Super Block)并不是每个块组都有,但GDT每个块组都有

 

3. 查看超级块和块组信息的相关命令

使用tune2fs -l这个命令可以显示组信息,其中-l选项就是用来显示超级块信息的。

[root@localhost tutor]# tune2fs -l /dev/sdb3

——————————————运行结果————————————————

tune2fs 1.41.12 (17-May-2010)
Filesystem volume name:   MYDAT
Last mounted on:          /mydata
Filesystem UUID:          ead64b7a-80bd-4ad7-af3f-bece9a76e04c
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash
Default mount options:    (none)
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              655872
Block count:              10490412
Reserved block count:     200000
Free blocks:              10286628
Free inodes:              655860
First block:              1
Block size:               1024
Fragment size:            1024
Reserved GDT blocks:      256
# 块组描述表(Group Description Table)的相关信息
Blocks per group:         8192
Fragments per group:      8192
Inodes per group:         512
Inode blocks per group:   128
Flex block group size:    16
Filesystem created:       Fri Jul 11 01:09:30 2014
Last mount time:          Fri Jul 11 13:35:43 2014
Last write time:          Fri Jul 11 13:35:43 2014
Mount count:              6
Maximum mount count:      37
Last checked:             Fri Jul 11 01:09:30 2014
Check interval:           15552000 (6 months)
Next check after:         Wed Jan  7 00:09:30 2015
Lifetime writes:          193 MB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:               256
Required extra isize:     28
Desired extra isize:      28
Journal inode:            8
Default directory hash:   half_md4
Directory Hash Seed:      7cfc9fb6-e210-4e90-9482-6dc66b1a3e26
Journal backup:           inode blocks

 

可以使用dumpe2fs命令来查看超级块和块组的信息

[root@localhost tutor]# dumpe2fs /dev/sdb3 | less

——————————————运行结果————————————————

dumpe2fs 1.41.12 (17-May-2010)
Filesystem volume name:   MYDAT
Last mounted on:          /mydata
Filesystem UUID:          ead64b7a-80bd-4ad7-af3f-bece9a76e04c
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash
Default mount options:    (none)
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              655872
Block count:              10490412
Reserved block count:     200000
Free blocks:              10286628
Free inodes:              655860
First block:              1
Block size:               1024
Fragment size:            1024
Reserved GDT blocks:      256
Blocks per group:         8192
Fragments per group:      8192
Inodes per group:         512
Inode blocks per group:   128
Flex block group size:    16
Filesystem created:       Fri Jul 11 01:09:30 2014
Last mount time:          Fri Jul 11 13:35:43 2014
Block size:               1024
Fragment size:            1024
Reserved GDT blocks:      256
Blocks per group:         8192
Fragments per group:      8192
Inodes per group:         512
Inode blocks per group:   128
Group 0: (Blocks 1-8192) [ITABLE_ZEROED]
  Checksum 0xf3e0, unused inodes 500
  Primary superblock at 1, Group descriptors at 2-42
  # 超级块在第一个块组上
  Reserved GDT blocks at 43-298
  # 有保留GDT的组在第43到298个上
  Block bitmap at 299 (+298), Inode bitmap at 315 (+314)
  # 块位图在第299个块上,inode位图在315个块上
  Inode table at 331-458 (+330)
  # inode表在第331到458个块上
  5800 free blocks, 500 free inodes, 2 directories, 500 unused inodes
  # 一个有5800个块,500个空闲inode,已经使用了2个目录,还有500个空闲的inode
  Free blocks: 2393-8192
  # 空闲块为第2393到8192个
  Free inodes: 13-512
  # 空闲inode为13到512个
Group 2: (Blocks 16385-24576) [INODE_UNINIT, BLOCK_UNINIT, ITABLE_ZEROED]
          # 没有超级块的备份
  Checksum 0x1592, unused inodes 512
  Block bitmap at 301 (+4294951212), Inode bitmap at 317 (+4294951228)
  Inode table at 587-714 (+4294951498)
  8192 free blocks, 512 free inodes, 0 directories, 512 unused inodes
  Free blocks: 16385-24576
  Free inodes: 1025-1536
Group 3: (Blocks 24577-32768) [INODE_UNINIT, ITABLE_ZEROED]
  Checksum 0xfb42, unused inodes 512
  Backup superblock at 24577, Group descriptors at 24578-24618
      # 有超级块的备份,超级块的备份通常放在第3、5、7、9等块组上,一旦超级块坏了
  # 可以复制备份进行恢复
  Reserved GDT blocks at 24619-24874
  Block bitmap at 302 (+4294943021), Inode bitmap at 318 (+4294943037)
  Inode table at 715-842 (+4294943434)
  7894 free blocks, 512 free inodes, 0 directories, 512 unused inodes
  Free blocks: 24875-32768
  Free inodes: 1537-2048

 

如果使用-h选项,可以只查看超级块信息

[root@localhost tutor]# dumpe2fs -h /dev/sdb3 |less

——————————————运行结果————————————————

dumpe2fs 1.41.12 (17-May-2010)
Filesystem volume name:   MYDAT
Last mounted on:          /mydata
Filesystem UUID:          ead64b7a-80bd-4ad7-af3f-bece9a76e04c
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash
Default mount options:    (none)
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              655872
Block count:              10490412
Reserved block count:     200000
Free blocks:              10286628
Free inodes:              655860
First block:              1
Block size:               1024
Fragment size:            1024
Reserved GDT blocks:      256
Blocks per group:         8192
Fragments per group:      8192
Fragments per group:      8192
Inodes per group:         512
Inode blocks per group:   128
Flex block group size:    16
Filesystem created:       Fri Jul 11 01:09:30 2014
Last mount time:          Fri Jul 11 13:35:43 2014
Last write time:          Fri Jul 11 13:35:43 2014
Mount count:              6
Maximum mount count:      37
Last checked:             Fri Jul 11 01:09:30 2014
Check interval:           15552000 (6 months)
Next check after:         Wed Jan  7 00:09:30 2015
Lifetime writes:          193 MB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:               256
Required extra isize:     28
Desired extra isize:      28
Journal inode:            8
Default directory hash:   half_md4
Directory Hash Seed:      7cfc9fb6-e210-4e90-9482-6dc66b1a3e26
Journal backup:           inode blocks
Journal features:         (none)
Journal size:             32M
Journal length:           32768
Journal sequence:         0x00000007
Journal start:            0

 

使用du,表示disk usage,命令可以查看每个文件的大小,它也可以显示某一个目录下所有文件组合起来的大小。

[root@localhost tutor]# du /var/log

——————————————运行结果————————————————

# 这里显示的是/var/log目录下每个文件的块大小
4       /var/log/ntpstats
4       /var/log/httpd
12      /var/log/ConsoleKit
4       /var/log/prelink
4       /var/log/samba/old
8       /var/log/samba
4       /var/log/cups
4       /var/log/ppp
692     /var/log/audit
156     /var/log/gdm
1460    /var/log/sa
4       /var/log/sssd
7100    /var/log

 

如果使用-s选项,表示summary,可以显示目录里所有文件的总大小,如果再加上-h选项,表示human readable,就能显示出人比较易读的方式:

[root@localhost tutor]# du -s /var/log

7100    /var/log

 

[root@localhost tutor]# du -sh /var/log

7.0M    /var/log

 

如果想查看/var目录下每一个子目录,包括其中文件的大小,可以使用如下方式:

[root@localhost tutor]# du -sh /var/*

——————————————运行结果————————————————

4.0K    /var/account
279M    /var/cache
4.0K    /var/crash
4.0K    /var/cvs
8.0K    /var/db
8.0K    /var/empty
4.0K    /var/games
4.0K    /var/gdm
77M     /var/lib
4.0K    /var/local
16K     /var/lock
7.0M    /var/log
0       /var/mail
4.0K    /var/nis
4.0K    /var/opt
4.0K    /var/preserve
356K    /var/run
120K    /var/spool
4.0K    /var/tmp
1.2M    /var/www
12K     /var/yp

 

使用df命令,表示disk free,可以用来显示磁盘空余空间量,其常用选项为-l,表示local,只显示本地文件系统,如果不加-l选项,可能会显示nfs的文件系统。注意,不论格式化的块大小是多少,该命令都显示为1k大小

[root@localhost tutor]# df -l

——————————————运行结果————————————————

Filesystem                   1K-blocks    Used Available  Use%   Mounted on
# 文件系统                    使用的单位  已用空间  可用空间  使用比例 挂载点 
/dev/mapper/VolGroup-lv_root  23262376 4449116  17631564  21%    /
tmpfs                           510172     120    510052   1%    /dev/shm
/dev/sda1                       495844   34840    435404   8%    /boot
/dev/sdb3                     10323251   36623  10086628   1%    /mydata
/dev/sr0                           288     288         0 100%    /media/20140715_2041

该命令同样也能使用-h选项,转换成人们易读的形式:

[root@localhost tutor]# df -lh

——————————————运行结果————————————————

Filesystem                    Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root   23G  4.3G   17G  21% /
tmpfs                         499M  120K  499M   1% /dev/shm
/dev/sda1                     485M   35M  426M   8% /boot
/dev/sdb3                     9.9G   36M  9.7G   1% /mydata
/dev/sr0                      288K  288K     0 100% /media/20140715_2041

 

使用-P选项,会显示成posix兼容的风格

[root@localhost tutor]# df -lP

——————————————运行结果————————————————

Filesystem                   1024-blocks    Used Available Capacity Mounted on
/dev/mapper/VolGroup-lv_root    23262376 4449116  17631564      21% /
tmpfs                             510172     120    510052       1% /dev/shm
/dev/sda1                         495844   34840    435404       8% /boot
/dev/sdb3                       10323251   36623  10086628       1% /mydata
/dev/sr0                             288     288         0     100% /media/20140715_2041

 

使用 -i 选项,则显示的是inode的使用信息而非块信息

[root@localhost tutor]# df -li

——————————————运行结果————————————————

Filesystem                    Inodes  IUsed   IFree IUse% Mounted on
/dev/mapper/VolGroup-lv_root 1479856 129332 1350524    9% /
tmpfs                         127543      5  127538    1% /dev/shm
/dev/sda1                     128016     38  127978    1% /boot
/dev/sdb3                     655872     12  655860    1% /mydata
/dev/sr0                           0      0       0     - /media/20140715_2041

 

如果该命令带上具体路径,则可以只显示单个文件系统的信息:

[root@localhost tutor]# df -l /dev/sdb3

Filesystem     1K-blocks  Used Available Use% Mounted on
/dev/sdb3       10323251 36623  10086628   1% /mydata