Linux磁盘之inode
什么是 inode ?
文件储存在硬盘上,硬盘的最小存储单位叫作”扇区”(Sector)。每一个扇区储存512字节(至关于0.5KB)。
操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率过低,而是一次性连续读取多个扇区,即一次性读取一个”块”(block)。这种由多个扇区组成的”块”,是文件存取的最小单位。”块”的大小,最多见的是4KB,即连续八个 sector组成一个 block。
文件数据都储存在”块”中,那么很显然,咱们还必须找到一个地方储存文件的元信息,好比文件的建立者、文件的建立日期、文件的大小等等。这种储存文件元信息的区域就叫作inode,中文译名为”索引节点”。每个文件都有对应的inode(数据结构里面应该叫inode节点),里面包含了与该文件有关的一些信息。由于每个文件都必须有一个inode,因此有可能发生inode已经用光,但是硬盘还未存满的情况。这时,就无法在硬盘上创建新文件(一个inode由inode number+inode table组成)。
我们简单理解就是一个文件对应一个inode,而linux各个分区可用的inode一般是有限的,使用df -i 可以查看分区的inode使用率。一般经常出现硬盘空间没占满,但inode占满了,这种一般是因为有大量的小文件生成, 在Linux中创建文件系统时,通常同时将会创建大量的inode,文件系统磁盘空间中大约百分之一空间分配给了inode表。在每个Linux存储设备或存储设备的分区(存储设备可以是硬盘、软盘、U盘…)被格式化为ext4、ext3、xfs等文件系统,一般生成两部分:第一部分是Inode(很多个),第二部分是Block(很多个)。
当我们使用cp命令时,系统会分配一个空闲的inode号,在inode表中生成新条目 在目录中创建一个目录项,将名称与inode编号关联 拷贝数据生成新的文件
当我们使用rm命令时,会使链接数递减,从而释放的inode号可以被重用,把数据块放在空闲列表中,删除目录项数据实际上不会马上被删除,但当另一个文件使用数据块时将被覆盖。
当我们使用mv命令时,如果mv命令的目标和源在相同的文件系统,作为mv命令,用新的文件名创建对应新的目录项,删除旧目录条目对应的旧的文件名,不影响inode表(除时间戳)或磁盘上的数据位置,没有数据被移动!如果目标和源在一个不同的文件系统,mv相当于cp和rm
关于inode的大小
假定在一块1GB的硬盘中,每个inode节点的大小为128字节,每1KB就设置一个inode,那么inode table的大小就会达到128MB,占整块硬盘的12.8%。(计算inode的节点数量和占据的大小)
关于inode号码(inode number)
每个inode都有一个号码,操作系统用inode号码来识别不同的文件,Unix/Linux系统内部不使用文件名,而使用inode号码来识别文件。对于系统来说,文件名只是inode number便于识别的别称或者绰号。表面上,用户通过文件名,打开文件。实际上,系统内部这个过程分成三步:首先,系统找到这个文件名对应的inode号码;其次,通过inode号码,获取inode信息;最后,根据inode信息,找到文件数据所在的block,读出数据。当一个分区被格式化为ext2或ext3的文件系统的时候,会自动产生inode number,每个分区都有自己的文件系统,也有一套属于自己的inode。inode number可以决定在这个分区中存储多少文件或目录,因为每个文件和目录都会有与之相对应的inode number。
inode包含文件的元数据信息,具体来说有以下内容: (通过stat命令可以查看)元数据(metadata):用来描述一个文件的特征的系统数据。 size: 文件的字节数 * 文件拥有者的User ID * 文件的Group ID * 文件的读、写、执行权限 * 文件的时间戳,共有三个:ctime指inode上一次变动的时间,mtime指文件内容上一次变动的时间,atime指文件上一次打开的时间。 * 链接数,即有多少文件名指向这个inode * 文件数据block的位置
我们也把inode区叫inode table,即inode table用于储存文件元信息的区域。inode table记录这个inode number对应文件所对应的metadata(元数据)。
举例:
当你存储一个文件之前,Linux系统会找到文件所对应的inode number。然后根据这个文件的inode number读取到相对应的inode table。由inode table中的“pointer”可以知道文件存放在哪几个block才能存储这个文件。(这里是数据结构了)
注: 以后我们说磁盘满了,就不要单单说数据被占满了,而是inode有可能满了,导致文件创建不成功。有时候用df -h查看空间并没有满,但是写不进去东西了,就可能是inode数量被消耗殆尽了。
下面这张图还是很说明问题
系统环境采样:
[root@fp-web-130 ~]# cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)
[root@fp-web-130 ~]# uname -r
3.10.0-327.el7.x86_64
一、用df -i 这个命令可以看到文件系统 inode节点数 已使用数 剩余数 已使用百分比等
[root@fp-web-130 ~]# df -i
二、使用stat命令查看文件inode详细信息(显示文件和文件系统状态(查看文件属性),即显示文件的元数据(meta data) )
我们随便拿个创建的文件看下怎么使用(另外stat * 命令直接显示该目录下所有文件的信息)
解释stat结果说明:
File:文件名
Size:文件大小(单位:B)
Blocks:文件所占扇区个数,为8的倍数(通常的 Linux 的扇区大小为 512 B,连续八个扇区组成一个block)
IO Block:每个数据块的大小(单位:B)
regular file:普通文件(此处显示文件的类型)
Inode:文件的Inode号 ( node讲解 )
Links:硬链接次数 (软硬链接讲解)
Access:权限
Uid:(属主id/属主名)
Gid:(属组id/属组名)
Access:最近访问时间
Modify:数据改动时间
Change:元数据改动时间
以上返回的结果参数均属于文件的元数据,元数据即用来描述数据的数据。
注: Inode:270219136 和下面的用ls -i 取得的inode号一致。
三、使用ls -i //查看某个文件的inode号
四、关于linux不能再创建文件有两种情况
1、inode满了,没有清理 ,可以通过df -i 查看
2、磁盘的空间满了,可以通过 df -h查看
五、查看inode默认节点大小
我们看到用不同文件类型方式创建了文件系统,有xfs,lvm,ext3等
[root@fp-web-130 ~]# dumpe2fs /dev/sdb5 | grep -i "inode size" //该命令用于查看ext3或ext4文件类型的inode节点默认创建的大小
[root@fp-web-130 ~]# dumpe2fs /dev/sda1|egrep -i "block size|Inode size" //我们同样用这个命令来查看xfs会出错,dumpe2fs 不支持
所以我们使用 xfs_info 或 xfs_growfs来查看xfs文件格式的inode默认创建的大小(super-block我们翻译为超级块)
[root@fp-web-130 ~]# xfs_info /dev/sda1
六、可以用inode删除文件(linux系统级别是通过inode号来查找文件的,所以效率更高)
[root@fp-web-130 src]# touch test.txt
[root@fp-web-130 src]# ll -i test.txt
330651 -rw-r--r-- 1 root root 0 Feb 8 22:11 a
[root@fp-web-130 src]# rm `find . -inum 330651`
rm: remove regular empty file ‘./text.txt’? yes
[root@fp-web-130 src]# ll
total 0
七、超级块(super-block)
超级块用于存储一个已安装的文件系统全局配置参数(例如:块大小,总的块数和inode)和动态信息(例如:当前空闲块数和inode数),其处于文件系统开始位置的1K处,所占大小为1KB,为了系统的健壮性,最初每个块组都有超级块和组描述符表(GDT)一个拷贝,但是当文件很大时,这样浪费很多块(尤其是GDT占用的块多),后来采用了一种稀疏的方式存储这些拷贝,只有快组号是3,5,7的幂的块组才拷贝这个拷贝。通常情况下,只有主拷贝(第0块块组)的超级块信息被文件系统使用,其他拷贝在文件系统被破坏的情况下才使用
八、理解下inode结构体
先看inode结构体的定义,inode 结构包含大量关于文件的信息,inode 结构由内核在内部用来表示文件
struct inode
索引节点对象由inode结构体表示,定义文件在linux/fs.h中。
struct inode {
undefined
struct hlist_node i_hash; 哈希表
struct list_head i_list; 索引节点链表
struct list_head i_dentry; 目录项链表
unsigned long i_ino; 节点号
atomic_t i_count; 引用记数
umode_t i_mode; 访问权限控制
unsigned int i_nlink; 硬链接数
uid_t i_uid; 使用者id
gid_t i_gid; 使用者id组
kdev_t i_rdev; 实设备标识符
loff_t i_size; 以字节为单位的文件大小
struct timespec i_atime; 最后访问时间
struct timespec i_mtime; 最后修改(modify)时间
struct timespec i_ctime; 最后改变(change)时间
unsigned int i_blkbits; 以位为单位的块大小
unsigned long i_blksize; 以字节为单位的块大小
unsigned long i_version; 版本号
unsigned long i_blocks; 文件的块数
unsigned short i_bytes; 使用的字节数
spinlock_t i_lock; 自旋锁
struct rw_semaphore i_alloc_sem; 索引节点信号量
struct inode_operations *i_op; 索引节点操作表
struct file_operations *i_fop; 默认的索引节点操作
struct super_block *i_sb; 相关的超级块
struct file_lock *i_flock; 文件锁链表
struct address_space *i_mapping; 相关的地址映射
struct address_space i_data; 设备地址映射
struct dquot *i_dquot[MAXQUOTAS];节点的磁盘限额
struct list_head i_devices; 块设备链表
struct pipe_inode_info *i_pipe; 管道信息
struct block_device *i_bdev; 块设备驱动
unsigned long i_dnotify_mask;目录通知掩码
struct dnotify_struct *i_dnotify; 目录通知
unsigned long i_state; 状态标志
unsigned long dirtied_when;首次修改时间
unsigned int i_flags; 文件系统标志
unsigned char i_sock; 套接字
atomic_t i_writecount; 写者记数
void *i_security; 安全模块
__u32 i_generation; 索引节点版本号
union {
undefined
void *generic_ip;文件特殊信息
} u;
};
九、文件描述符(区别于inode)
inode 或i节点是指对文件的索引。如一个系统,所有文件是放在磁盘或flash上,就要编个目录来说明每个文件在什么地方,有什么属性,及大小等。就像书本的目录一样,便于查找和管理。这目录是操作系统需要的,用来找文件或叫管理文件。许多操作系统都用到这个概念,如linux, 某些嵌入式文件系统等。当然,对某个系统来说,有许多i节点。所以对i节点本身也是要进行管理的。
在linux中,内核通过inode来找到每个文件,但一个文件可以被许多用户同时打开或一个用户同时打开多次。这就有一个问题,如何管理文件的当前位移量,因为可能每个用户打开文件后进行的操作都不一样,这样文件位移量也不同,当然还有其他的一些问题。所以linux又搞了一个文件描述符(file descriptor)这个东西,来分别为每一个用户服务。每个用户每次打开一个文件,就产生一个文件描述符,多次打开就产生多个文件描述符,一一对应,不管是同一个用户,还是多个用户。该文件描述符就记录了当前打开的文件的偏移量等数据。所以一个i节点可以有0个或多个文件描述符。多个文件描述符可以对应一个i节点。