1. 关于目录,文件,数据块
对于使用计算机的人而言,经常有一种 错误的认知:目录(或者说,文件夹)里面存放着文件。实际上,目录里面并不存放文件,以及文件数据。
实际上,目录是一个特殊的文件,针对这个特殊的文件也存在一些特殊的规则,比如利用命令cp /dev/null <your directory>
并不能够销毁这个特殊的文件,因为目录的一些特殊的比特位保证了这一安全性,降低了人工操作带来的风险。在一些老版本的Unix系统里面,用户可以利用cat
命令打开目录,查看里面的信息,在一些衍生于Debian系统的发行版linux里面,也可以利用vi
工具打开目录,查看一些信息。
在Linux里面,一个文件的信息被存放于两个位置:
数据块(data block)当中
inode当中
硬盘的最小存储单位叫做“扇区”(Sector)。每个扇区储存512字节(相当于0.5KB)。操作系统读取磁盘的时候,不会一个个扇区“挨个读取”,而是一次读取多个扇区,即一次读取一个“块”(block),这种由多个扇区组成的”块”,是文件存取的最小单位。”块”的大小,最常见的是4KB,即连续八个 sector组成一个 block。data block当中存放了文件的真实内容,而文件的元数据信息,被存放到了inode当中。data block和inode被文件系统有效地组织到了一起。
当文件系统被创建之后,inode的数量以及data block的数量也被固定下来。我们不能够修改inode的数量,也不能够修改data block的数量。
当我们创建一个文件的时候,inode编号将作为该文件的唯一id,即,一个文件在同一时刻仅拥有一个inode编号。当我们向一个文件写入内容的时候,数据被存放到了data block当中。而该文件的文件名,被存放到了该文件所在的目录文件当中。
对于目录这种“特殊的文件”,可以简单地理解为是一张表,这张表里面存放了隶属于该目录的文件的文件名,以及所匹配的inode编号。
因此,在linux里面,文件被“拆分”到了3个地方,索引存于inode,文件名存于目录,数据存于data block。
2. 关于硬链接以及复制
基于上述内容对于目录的描述,可以比较容易解释linux里面的另外一个重要的概念: hard link(硬链接)。
对于文件而言,真正的ID是inode编号,而并非文件名。回忆一下目录文件: 一张含有文件名和inode编号的表。在这张表里面,我们暂定用一个如下结构表示一个文件: [directory : (filename, inode_number)],这里以/etc/passwd文件举例,假设其inode编号为123456(确实有点儿假……),则可以写为[/etc/ : (passwd, 123456)],假设我们在终端上面键入了如下命令:
[root@centos7-front1 ~]# ln /etc/passwd /root/hard_link_passwd
则会在/root目录下面出现一个新的文件名,叫做hard_link_passwd。如果用上述结构表示这个文件,则为[/root/ : (hard_link_passwd, 123456)],因此,这种目录或文件名不同,但是inode编号相同的文件,称为硬链接。由于硬链接inode编号相同,而且对于同一个inode结构体,便会拥有相同的地址映射以及相同的块设备链表。因此,对于用户空间而言,修改/etc/passwd,就相当于修改了/root/hard_link_passwd,反之亦然。
同样基于上述内容对于目录的描述,针对i_device相同的mv操作,仅仅是删除了原目录里面对应的[directory : (filename, inode_number)],并且在目标目录新建了另一个[directory : (filename, inode_number)],由于并没有对于data block的任何操作,因此速度很快。
3. 初步查看inode
利用ls -i
命令可以查看到当前目录下面的所有文件的inode编号,注意inode编号仅仅是inode结构体里面的一项,并不代表inode全部,下面截取/etc/目录下的前5个文件:
[root@centos7-front1 etc]# ls -i | head -n 5 768684 abrt 34370879 adjtime 33554592 aliases 35506331 aliases.db 100705463 alternatives
利用stat
命令可以查看一个文件更加详细的inode信息,包括inode编号,占用的块数量,块大小,硬链接个数,atime, mtime, ctime, ……下面用stat命令查看/etc目录(如上文所说,目录也是一种特殊的文件)
[root@centos7-front1 /]# stat /etc File: ‘/etc’ Size: 8192 Blocks: 24 IO Block: 4096 directory Device: 803h/2051d Inode: 33554561 Links: 85 Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2017-03-28 17:13:00.510221799 -0400 Modify: 2017-03-28 12:37:32.150999451 -0400 Change: 2017-03-28 12:37:32.150999451 -0400 Birth: -
从上述结果中,我们可以看出,针对/etc目录而言,其大小为8192kb,为该目录下的文件所分配的块数量为24个,类型为directory,设备名称为803h/2051d,其Inode编号为33554561,其硬链接个数为85个,权限为0755,Uid和Gid均为0,还有atime, mtime, ctime这些信息。
当然,利用stat
命令查到的某个文件的inode信息并不是全部的inode结构体里面的信息。内核使用的inode结构体如下所示:
struct inode { 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 { void *generic_ip; // 文件特殊信息 */ } u; };
4. 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@centos7-front1 ~]# df -i Filesystem Inodes IUsed IFree IUse% Mounted on /dev/sda3 23860224 59694 23800530 1% / devtmpfs 122809 367 122442 1% /dev tmpfs 125170 1 125169 1% /dev/shm tmpfs 125170 433 124737 1% /run tmpfs 125170 13 125157 1% /sys/fs/cgroup /dev/sda1 256000 329 255671 1% /boot tmpfs 125170 1 125169 1% /run/user/0
查看某个分区的文件系统所分配的单个inode节点的大小,在ext文件系统下,可以使用dumpe2fs
命令,例如CentOS6系统上,针对/dev/sda3分区:
[root@maCentos6 ~]# dumpe2fs -h /dev/sda3 | grep -i "inode size" dumpe2fs 1.41.12 (17-May-2010) Inode size: 256
在xfs文件系统下,可以使用xfs_info
命令,例如CentOS7系统上,针对/dev/sda3分区:
[root@centos7-front1 ~]# xfs_info /dev/sda1 meta-data=/dev/sda1 isize=256 agcount=4, agsize=16000 blks = sectsz=512 attr=2, projid32bit=1 = crc=0 finobt=0 data = bsize=4096 blocks=64000, imaxpct=25 = sunit=0 swidth=0 blks naming =version 2 bsize=4096 ascii-ci=0 ftype=0 log =internal bsize=4096 blocks=853, version=2 = sectsz=512 sunit=0 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0
4. 参考链接
本文出自 “技术成就梦想” 博客,请务必保留此出处http://jiangche00.blog.51cto.com/4377920/1911681
原文地址:http://jiangche00.blog.51cto.com/4377920/1911681