Linux文件系统中的inode索引结点 VFS inode

Linux中VFS文件系统的组织

当我们读取一个文件时,实际上是在目录中找到了这个文件的inode编号,然后根据inode的指针,把硬盘中数据块组合起来,放入内存供进一步的处理。

当我们写入一个文件时,是分配一个空闲inode给该文件,将其inode编号记入该文件所属的目录,然后选取空闲的数据块,让inode的指针指向这些数据块,并放入内存中的数据。

硬盘扇区 sector

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

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

"块"的大小,最常见的是4KB,即连续八个sector组成一个 block。

索引结点 inode

有一个结构储存文件的元信息,叫做"索引节点"(inode)。

每一个文件(包括目录)都有对应的inode,里面包含了与该文件有关的信息(除了文件名)。可以用“stat + 文件名”命令来查看。

Size 文件大小

Blocks 块编号

IO Blocks  block的大小

文件类型:  普通文件/目录/符号链接

Device 设备编号

Inode  索引结点编号

Links 硬链接数

Access 访问权限

Uid 用户id

Gid 组id

Acess Modify Change 三个时间

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

查看每个inode的大小,sudo dumpe2fs -h /dev/hda | grep "Inode size"

操作系统会把硬盘分成两个区域:一个是数据区,存放文件数据;另一个是inode区(inode table),存放inode。inode节点的总数,在格式化时就给定,一般是每1KB或每2KB就设置一个inode。由于每个文件都必须有一个inode,因此有可能发生inode已经用光,但是硬盘还未存满的情况。这时就无法在硬盘上创建新文件。

硬链接 hard link

多个文件名指向同一个inode编号。即,可以用不同的文件名访问同样的内容。

对文件内容进行修改,会影响到所有文件名;删除一个文件名,不影响另一个文件名的访问。

使用ln命令创建硬链接:“ln 源文件 新文件

硬链接数

每创建一个硬链接,对应文件的硬链接数就会增加1。删除一个文件名,就会使得inode节点中的"链接数"减1。当这个值减到0,表明没有文件名指向这个inode,系统就会回收这个inode号码,以及其所对应block区域。
注意:目录文件的"链接数"。创建目录时,默认会生成两个目录项:"."和".."。前者的inode号码就是当前目录的inode号码,等同于当前目录的"硬链接";后者的inode号码就是当前目录的父目录的inode号码,等同于父目录的"硬链接"。所以,任何一个目录的"硬链接"总数,总是等于2加上它的子目录总数(含隐藏目录)

软链接 symbolic link

文件A和文件B的inode编号不一样,文件A的内容是文件B的路径。

创建软连接:“ln -s 源文文件或目录 目标文件或目录

设备号 device number

主设备号:标识设备驱动程序。 The major number identifies the driver associated with the device

副设备号:用于具体确定设备。The minor number is used by the kernel to determine exactly which device is being referred to.


inode结构体定义在Linux内核源码<linux/fs.h>中。

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;
};
/*
 *索引节点的操作inode_operations定义在linux/fs.h中 
 */
struct inode_operations {
	int (*create) (struct inode *, struct dentry *,int);
	/*VFS通过系统调用create()和open()来调用该函数,从而为dentry对象创建一个新的索引节点。在创建时使用mode制定初始模式*/
	struct dentry * (*lookup) (struct inode *, struct dentry *);
	/*该韩式在特定目录中寻找索引节点,该索引节点要对应于dentry中给出的文件名*/
	int (*link) (struct dentry *, struct inode *, struct dentry *);
	/*该函数被系统调用link()电泳,用来创建硬连接。硬链接名称由dentry参数指定,连接对象是dir目录中ld_dentry目录想所代表的文件*/
	int (*unlink) (struct inode *, struct dentry *);
	/*该函数被系统调用unlink()调用,从目录dir中删除由目录项dentry制动的索引节点对象*/
	int (*symlink) (struct inode *, struct dentry *, const char *);
	/*该函数被系统电泳symlik()调用,创建符号连接,该符号连接名称由symname指定,连接对象是dir目录中的dentry目录项*/
	int (*mkdir) (struct inode *, struct dentry *, int);
	/*该函数被mkdir()调用,创建一个新鲁姆。创建时使用mode制定的初始模式*/
	int (*rmdir) (struct inode *, struct dentry *);
	/*该函数被系统调用rmdir()调用,删除dir目录中的dentry目录项代表的文件*/
	int (*mknod) (struct inode *, struct dentry *, int, dev_t);
	/*该函数被系统调用mknod()调用,创建特殊文件(设备文件、命名管道或套接字)。要创建的文件放在dir目录中,其目录项问dentry,关联的设备为rdev,初始权限由mode指定*/
	int (*rename) (struct inode *, struct dentry *,
			struct inode *, struct dentry *);
	/*VFS调用该函数来移动文件。文件源路径在old_dir目录中,源文件由old_dentry目录项所指定,目标路径在new_dir目录中,目标文件由new_dentry指定*/
	int (*readlink) (struct dentry *, char *, int);
	/*该函数被系统调用readlink()调用,拷贝数据到特定的缓冲buffer中。拷贝的数据来自dentry指定的符号链接,最大拷贝大小可达到buflen字节*/
	int (*follow_link) (struct dentry *, struct nameidata *);
	/*该函数由VFS调用,从一个符号连接查找他指向的索引节点,由dentry指向的连接被解析*/
	int (*put_link) (struct dentry *, struct nameidata *);
	/*在follow_link()调用之后,该函数由vfs调用进行清楚工作*/
	void (*truncate) (struct inode *);
	/*该函数由VFS调用,修改文件的大小,在调用之前,索引节点的i_size项必须被设置成预期的大小*/
	int (*permission) (struct inode *, int);
	/*该函数用来检查给低昂的inode所代表的文件是否允许特定的访问模式,如果允许特定的访问模式,返回0,否则返回负值的错误码。多数文件系统 都将此区域设置为null,使用VFS提供的通用方法进行检查,这种检查操作仅仅比较索引及诶但对象中的访问模式位是否和mask一致,比较复杂的系统, 比如支持访问控制链(ACL)的文件系统,需要使用特殊的permission()方法*/
	int (*setattr) (struct dentry *, struct iattr *);
	/*该函数被notify_change调用,在修改索引节点之后,通知发生了改变事件*/
	int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *);
	/*在通知索引节点需要从磁盘中更新时,VFS会调用该函数*/
	int (*setxattr) (struct dentry *, const char *,
			const void *, size_t, int);
	/*该函数由VFS调用,向dentry指定的文件设置扩展属性,属性名为name,值为value*/
	ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
	/*该函数被VFS调用,向value中拷贝给定文件的扩展属性name对应的数值*/
	ssize_t (*listxattr) (struct dentry *, char *, size_t);
	/*该函数将特定文件所有属性别表拷贝到一个缓冲列表中*/
	int (*removexattr) (struct dentry *, const char *);
	/*该函数从给定文件中删除指定的属性*/
};


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值