Linux文件系统之inode与软硬连接

一、inode是什么?

理解inode,要从文件储存说起。

文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector)。每个扇区储存512字节(相当于0.5KB)。

操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个"块"(block)。这种由多个扇区组成的"块",是文件存取的最小单位。"块"的大小,最常见的是4KB,即连续八个 sector组成一个 block。

文件数据都储存在"块"中,那么很显然,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode,中文译名为"索引节点"。

每一个文件都有对应的inode,里面包含了与该文件有关的一些信息。

二、inode的内容

inode包含文件的元信息,具体来说有以下内容:

  * 文件的字节数

  * 文件拥有者的User ID

  * 文件的Group ID

  * 文件的读、写、执行权限

  * 文件的时间戳,共有三个:ctime指inode上一次变动的时间,mtime指文件内容上一次变动的时间,atime指文件上一次打开的时间。

  * 链接数,即有多少文件名指向这个inode

  * 文件数据block的位置

inode结构图:

294d1cfb39cd1b06.png

inode要记录的数据非常多,但偏偏只有128bytes而已,而inode记录一个block号码要花掉4bytes,假设我一个文件有400MB,且每个block为4KB时,那么至少也要10万条block号码的记录。inode哪有那么多可记录的信息?为此,我们的系统聪明的将inode记录block号码的区域定义为12个直接,1个双间接,一个3间接记录区 这样子inode能够指定多少个block呢?我们以较小的1KB的block来说明:

(1) 12个直接指向   12*1K = 12K
(2)每条block号码的记录会花去4bytes,因此1K的block大小能够记录256条记录。所以间接地256*1K = 256K
(3)双间接 256*256*1K = 256^2K
 (4)三间接     256*256*256*1K = 256^3K

总额:12+256+256*256+256+256+256=16GB 此时我们知道当文件系统将block格式化为1K大小时,能够容纳的最大文件为16GB,比较一下文件系统的限制表的结果可以发现结果是一致的。但是这个方法不能够用在2K及4K的block大小的计算中,因为2K的block将会受到Ext2文件系统本身的限制,所以计算的结果会有不符合 。

可以用stat命令,查看某个文件的inode信息:

[root@localhost ~]# stat anaconda-ks.cfg 
  File: `anaconda-ks.cfg'
  Size: 1874            Blocks: 8          IO Block: 4096   regular file
Device: fd00h/64768d    Inode: 131083      Links: 1
Access: (0600/-rw-------)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2016-12-29 16:35:26.562699425 +0800
Modify: 2016-12-26 15:29:45.735999937 +0800
Change: 2016-12-26 15:29:49.750999936 +0800

总之,除了文件名以外的所有文件信息,都存在inode之中。至于为什么没有文件名,下文会有详细解释。

三、inode的大小

inode也会消耗硬盘空间,所以硬盘格式化的时候,操作系统自动将硬盘分成两个区域。一个是数据区,存放文件数据;另一个是inode区(inode table),存放inode所包含的信息。

每个inode节点的大小,一般是128字节或256字节。inode节点的总数,在格式化时就给定,一般是每1KB或每2KB就设置一个inode。假定在一块1GB的硬盘中,每个inode节点的大小为128字节,每1KB就设置一个inode,那么inode table的大小就会达到128MB,占整块硬盘的12.8%。

查看每个硬盘分区的inode总数和已经使用的数量,可以使用df命令:

[root@localhost ~]# df -i
Filesystem            Inodes IUsed   IFree IUse% Mounted on
/dev/mapper/vg0-root 1310720  7556 1303164    1% /
tmpfs                 125517     1  125516    1% /dev/shm
/dev/sda1              51200    38   51162    1% /boot
/dev/mapper/vg0-usr   655360 25449  629911    4% /usr
/dev/mapper/vg0-var  1310720  1132 1309588    1% /var

查看每个inode节点的大小,可以用如下命令:

[root@localhost ~]# dumpe2fs -h /dev/sda1 | grep 'Inode size' 
dumpe2fs 1.41.12 (17-May-2010)
Inode size:               128

或者 # tune2fs -l /dev/sda7 | grep "Inode size" Inode size: 256

由于每个文件都必须有一个inode,因此有可能发生inode已经用光,但是硬盘还未存满的情况。这时,就无法在硬盘上创建新文件。

四、inode号码

每个inode都有一个号码,操作系统用inode号码来识别不同的文件。

这里值得重复一遍,Unix/Linux系统内部不使用文件名,而使用inode号码来识别文件。对于系统来说,文件名只是inode号码便于识别的别称或者绰号。

表面上,用户通过文件名,打开文件。实际上,系统内部这个过程分成三步:首先,系统找到这个文件名对应的inode号码;其次,通过inode号码,获取inode信息;最后,根据inode信息,找到文件数据所在block,读出数据。

使用ls -i命令,可以看到文件名对应的inode号码:

[root@localhost ~]# ls -i anaconda-ks.cfg 
131083 anaconda-ks.cfg

五、目录文件

Unix/Linux系统中,目录(directory)也是一种文件。打开目录,实际上就是打开目录文件。

目录文件的结构非常简单,就是一系列目录项(dirent)的列表。每个目录项,由两部分组成:所包含文件的文件名,以及该文件名对应的inode号码。

inode与目录关系图:

d9208ece2fd046ee.pngls命令只列出目录文件中的所有文件名:

[root@localhost ~]# ls /var/log
anaconda.ifcfg.log    anaconda.yum.log  cron        maillog   secure
anaconda.log          audit             dmesg       messages  spooler
anaconda.program.log  boot.log          dmesg.old   ntpstats  tallylog
anaconda.storage.log  btmp              dracut.log  prelink   wtmp
anaconda.syslog       ConsoleKit        lastlog     sa        yum.log

ls -i命令列出整个目录文件,即文件名和inode号码:

[root@localhost ~]# ls -i /var/log
524312 anaconda.ifcfg.log    524293 ConsoleKit  524305 prelink
524308 anaconda.log          524322 cron        524302 sa
524310 anaconda.program.log  524318 dmesg       524299 secure
524311 anaconda.storage.log  524314 dmesg.old   524301 spooler
524309 anaconda.syslog       524307 dracut.log  524292 tallylog
524313 anaconda.yum.log      524294 lastlog     524295 wtmp
524306 audit                 524300 maillog     524342 yum.log
524319 boot.log              524298 messages
524296 btmp                  524303 ntpstats

如果要查看文件的详细信息,就必须根据inode号码,访问inode节点,读取信息。ls -l命令列出文件的详细信息。

[root@localhost ~]# ls -l /var/log
total 1328
-rw-------. 1 root root   2646 Dec 26 15:29 anaconda.ifcfg.log
-rw-------. 1 root root  23138 Dec 26 15:29 anaconda.log
-rw-------. 1 root root  45436 Dec 26 15:29 anaconda.program.log
-rw-------. 1 root root 113674 Dec 26 15:29 anaconda.storage.log
...

理解了上面这些知识,就能理解目录的权限。目录文件的读权限(r)和写权限(w),都是针对目录文件本身。由于目录文件内只有文件名和inode号码,所以如果只有读权限,只能获取文件名,无法获取其他信息,因为其他信息都储存在inode节点中,而读取inode节点内的信息需要目录文件的执行权限(x)。

六、inode的特殊作用

由于inode号码与文件名分离,这种机制导致了一些Unix/Linux系统特有的现象。

1.有时,文件名包含特殊字符,无法正常删除。这时,直接删除inode节点,就能起到删除文件的作用。

  

2.打开一个文件以后,系统就以inode号码来识别这个文件,不再考虑文件名。因此,通常来说,系统无法从inode号码得知文件名。   

3.cp与inode:分配一个空闲的inode号,在inode表中生成新条目在目录中创建一个目录项,将名称与inode编号关联拷贝数据生成新的文件。

4.rm与inode:链接数递减,从而释放的inode号可以被重用把数据块放空闲列表中删除目录项数据实际上不会马上被删除,但当另一个文件使用数据块时将被覆盖。

5.mv与inode:如果mv命令的目标和源在相同的文件系统,作为mv 命令用新的文件名创建对应新的目录项删除旧目录条目对应的旧的文件名不影响inode表(除时间戳)或磁盘上的数据位置:没有数据被移动!如果目标和源在一个不同的文件系统, mv相当于cp和rm。如果mv命令的目标和源在相同的文件系统,作为mv 命令用新的文件名创建对应新的目录项删除旧目录条目对应的旧的文件名不影响inode表(除时间戳)或磁盘上的数据位置:没有数据被移动!如果目标和源在一个不同的文件系统, mv相当于cp和rm。

注:第3点使得软件更新变得简单,可以在不关闭软件的情况下进行更新,不需要重启。因为系统通过inode号码,识别运行中的文件,不通过文件名。更新的时候,新版文件以同样的文件名,生成一个新的inode,不会影响到运行中的文件。等到下一次运行这个软件的时候,文件名就自动指向新版文件,旧版文件的inode则被回收。

猜你喜欢

转载自www.linuxidc.com/Linux/2017-02/140311.htm