2.通用文件模型及VFS-inode链接
2.通用文件模型及VFS-inode链接
参考链接
Inode详解
一、inode简介
Linux内核文件系统最重要的数据结构为inode,则一个inode就代表一个文件,inode结构体保存文件的大小、文件的块大小、创建时间等各种参数。一个文件的inode只有唯一一个。
Linux内核inode源码如下:include\linux\fs.h
/*
* Keep mostly read-only and often accessed (especially for
* the RCU path lookup and 'stat' data) fields at the beginning
* of the 'struct inode'
*/
struct inode {
umode_t i_mode;
unsigned short i_opflags;
kuid_t i_uid;
kgid_t i_gid;
unsigned int i_flags;
#ifdef CONFIG_FS_POSIX_ACL
struct posix_acl *i_acl;
struct posix_acl *i_default_acl;
#endif
const struct inode_operations *i_op;
struct super_block *i_sb;
struct address_space *i_mapping;
#ifdef CONFIG_SECURITY
void *i_security;
#endif
/* Stat data, not accessed from path walking */
unsigned long i_ino;
/*
* Filesystems may only read i_nlink directly. They shall use the
* following functions for modification:
*
* (set|clear|inc|drop)_nlink
* inode_(inc|dec)_link_count
*/
union {
const unsigned int i_nlink;
unsigned int __i_nlink;
};
dev_t i_rdev;
loff_t i_size;
struct timespec i_atime;
struct timespec i_mtime;
struct timespec i_ctime;
spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
unsigned short i_bytes;
unsigned int i_blkbits;
enum rw_hint i_write_hint;
blkcnt_t i_blocks;
#ifdef __NEED_I_SIZE_ORDERED
seqcount_t i_size_seqcount;
#endif
/* Misc */
unsigned long i_state;
struct mutex i_mutex;
unsigned long dirtied_when; /* jiffies of first dirtying */
unsigned long dirtied_time_when;
struct hlist_node i_hash;
struct list_head i_io_list; /* backing dev IO list */
#ifdef CONFIG_CGROUP_WRITEBACK
struct bdi_writeback *i_wb; /* the associated cgroup wb */
/* foreign inode detection, see wbc_detach_inode() */
int i_wb_frn_winner;
u16 i_wb_frn_avg_time;
u16 i_wb_frn_history;
#endif
struct list_head i_lru; /* inode LRU list */
struct list_head i_sb_list;
union {
struct hlist_head i_dentry;
struct rcu_head i_rcu;
};
u64 i_version;
atomic_t i_count;
atomic_t i_dio_count;
atomic_t i_writecount;
#ifdef CONFIG_IMA
atomic_t i_readcount; /* struct files open RO */
#endif
const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
struct file_lock_context *i_flctx;
struct address_space i_data;
struct list_head i_devices;
union {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct cdev *i_cdev;
char *i_link;
};
__u32 i_generation;
#ifdef CONFIG_FSNOTIFY
__u32 i_fsnotify_mask; /* all events this inode cares about */
struct hlist_head i_fsnotify_marks;
#endif
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
struct fscrypt_info *i_crypt_info;
#endif
void *i_private; /* fs or device private pointer */
};
文件数据存储在"块"中,很显然我们必须要找到一个地方存储此文件"元信息"(文件大小,文件作者,文件创建日期),存储文件元信息的区域就叫做inode(索引节点)
。
inode也会占用硬盘空间,所以我们在硬盘格式化时,操作系统自动将硬盘分为两个区域:
1.一个是数据区
,存放数据;
2.另一个为inode区
,存放所包含的信息。每个inode节点的大小一般为128字节或者256字节。
我们可以通过df命令
来查看硬盘分区的inode总数和已经使用的数量。
li@li:~$ df -i
文件系统 Inode 已用(I) 可用(I) 已用(I)% 挂载点
udev 493944 480 493464 1% /dev
tmpfs 500212 1063 499149 1% /run
/dev/sda1 3276800 550576 2726224 17% /
tmpfs 500212 1 500211 1% /dev/shm
tmpfs 500212 6 500206 1% /run/lock
tmpfs 500212 18 500194 1% /sys/fs/cgroup
/dev/loop0 65095 65095 0 100% /snap/gtk-common-themes/1519
/dev/loop1 11736 11736 0 100% /snap/core20/1242
/dev/loop2 1388 1388 0 100% /snap/gnome-calculator/884
/dev/loop4 872 872 0 100% /snap/gnome-system-monitor/157
/dev/loop3 17441 17441 0 100% /snap/gnome-3-38-2004/87
/dev/loop7 64986 64986 0 100% /snap/gtk-common-themes/1515
/dev/loop8 29 29 0 100% /snap/bare/5
/dev/loop11 305 305 0 100% /snap/gnome-characters/761
/dev/loop10 18508 18508 0 100% /snap/gnome-3-34-1804/66
/dev/loop13 479 479 0 100% /snap/snapd/14066
/dev/loop14 938 938 0 100% /snap/gnome-system-monitor/174
/dev/loop15 10836 10836 0 100% /snap/core18/2253
/dev/loop16 401 401 0 100% /snap/gnome-logs/106
/dev/loop17 401 401 0 100% /snap/gnome-logs/103
/dev/loop18 18500 18500 0 100% /snap/gnome-3-34-1804/77
vmhgfs-fuse 0 0 0 - /mnt/hgfs
tmpfs 500212 25 500187 1% /run/user/121
tmpfs 500212 34 500178 1% /run/user/1000
/dev/loop19 10847 10847 0 100% /snap/core18/2284
/dev/loop20 11777 11777 0 100% /snap/core20/1328
/dev/loop21 482 482 0 100% /snap/snapd/14549
/dev/loop6 305 305 0 100% /snap/gnome-characters/741
/dev/loop9 1386 1386 0 100% /snap/gnome-calculator/920
inode的成员可能分为两类:
1.描述文件状态的元数据(比如访问权限、文件大小等);
2.保存实际文件内容的数据段(指向数据的指针,文本文件用于保存文本)。
二、inode是什么
理解inode,要从文件储存说起。
文件储存在硬盘上,硬盘的最小存储单位是扇区(Sector)。每个扇区储存512字节。
操作系统读取硬盘的时候,不会一个一个扇区的读取,而是一次性连续读取多个扇区,即一次性读取一个块(block),这种由多个扇区组成的块是文件的最小单位。块的大小最常见的是4kb,即连续8个sector组成一个block。
文件数据都储存在块中,那么很显然,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的的创建日期、文件的大小等,这种储存文件元信息的区域就叫做inode,中文译为索引节点。
三、inode编号
系统中所有的inode都有一个特定的编号,用于唯一标识各个inode,文件名称和inode之间的关联即通过该编号直接建立。
每个inode都有一个号码,操作系统用inode号码来识别不同的文件。
这里重复一遍,Unix/Linux系统内部不使用文件名,而使用inode号码来识别文件,对于系统来说,文件名只是inode号码便于识别的别称或者绰号。
用户通过文件名打开文件,实际上在系统中这个过程分成三步;
1.首先,系统找到这个文件名对应的inode号码;
2.其次,通过inode号码,获取inode信息;
3.最后,根据inode信息找到文件数据所在的block,读出数据。
使用ls -i命令,可以看到文件名对应的inode号码。
li@li:~$ ls -i
538889 a.out 526533 git 944994 linux_driver 526543 tool 656723 vsCode 524358 模板 524357 下载
539052 c++ 539079 lcl 656639 linux_src 539312 tools 538400 work 524363 视频 524361 音乐
944995 code 541014 lcl_git 541029 misc.c 524424 VMwareTools-10.3.22-15902021 541030 work_test 524362 图片 524356 桌面
524291 examples.desktop 524410 linux 1049036 test 524418 VMwareTools-10.3.22-15902021.tar.gz 524359 公共的 524360 文档
li@li:~$
四、inode源码注释
linux 内核inode VS file
struct inode {
umode_t i_mode; //文件类型和访问权限
unsigned short i_opflags;
kuid_t i_uid; //创建文件的用户标识符
kgid_t i_gid; //创建文件的用户所属的组标识符
unsigned int i_flags;
#ifdef CONFIG_FS_POSIX_ACL
struct posix_acl *i_acl;
struct posix_acl *i_default_acl;
#endif
const struct inode_operations *i_op;
struct super_block *i_sb; //指向文件所属文件系统的超级块
struct address_space *i_mapping; //指向文件的地址空间
#ifdef CONFIG_SECURITY
void *i_security;
#endif
/* Stat data, not accessed from path walking */
unsigned long i_ino; //索引节点的编号
/*
* Filesystems may only read i_nlink directly. They shall use the
* following functions for modification:
*
* (set|clear|inc|drop)_nlink
* inode_(inc|dec)_link_count
*/
union {
const unsigned int i_nlink; //硬链接计数
unsigned int __i_nlink;
};
dev_t i_rdev;
loff_t i_size; //文件的长度
struct timespec i_atime; //上一次访问文件的时间
struct timespec i_mtime; //上一次修改文件数据的时间
struct timespec i_ctime; //上一次修改文件索引节点的时间
spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
unsigned short i_bytes; //文件长度除以块长度的余数
unsigned int i_blkbits; //块长度以2为底的对数
enum rw_hint i_write_hint;
blkcnt_t i_blocks; //文件的块数
#ifdef __NEED_I_SIZE_ORDERED
seqcount_t i_size_seqcount;
#endif
/* Misc */
unsigned long i_state;
struct mutex i_mutex;
unsigned long dirtied_when; /* jiffies of first dirtying */
unsigned long dirtied_time_when;
struct hlist_node i_hash;
struct list_head i_io_list; /* backing dev IO list */
#ifdef CONFIG_CGROUP_WRITEBACK
struct bdi_writeback *i_wb; /* the associated cgroup wb */
/* foreign inode detection, see wbc_detach_inode() */
int i_wb_frn_winner;
u16 i_wb_frn_avg_time;
u16 i_wb_frn_history;
#endif
struct list_head i_lru; /* inode LRU list */
struct list_head i_sb_list;
union {
struct hlist_head i_dentry;
struct rcu_head i_rcu;
};
u64 i_version;
atomic_t i_count; //索引节点的引用计数
atomic_t i_dio_count;
atomic_t i_writecount;
#ifdef CONFIG_IMA
atomic_t i_readcount; /* struct files open RO */
#endif
const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
struct file_lock_context *i_flctx;
struct address_space i_data;
struct list_head i_devices;
union {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev; //指向块设备
struct cdev *i_cdev; //指向字符设备
char *i_link;
};
__u32 i_generation;
#ifdef CONFIG_FSNOTIFY
__u32 i_fsnotify_mask; /* all events this inode cares about */
struct hlist_head i_fsnotify_marks;
#endif
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
struct fscrypt_info *i_crypt_info;
#endif
void *i_private; /* fs or device private pointer */
};
超级块,i节点,数据块,目录块,间接块
将磁盘块分为三个部分:
1)超级块,文件系统中第一个块被称为超级块
。这个块存放文件系统本身的结构信息。比如,超级块记录了每个区域的大小,超级块也存放未被使用的磁盘块的信息。
2) i-节点表。超级块的下一个部分就是i-节点表,每个文件都有一些属性,如文件的大小、文件所有者、和创建时间等
,这些性质被记录在一个称为i-节点的结构中。所有i-节点都有相同的大小,并且i-节点表是这些结构的一个列表,文件系统中每个文件在该表中都有一个i-节点。
3)数据区。文件系统的第3个部分是数据区。文件的内容保存在这个区域。磁盘上所有块的大小都一样。如果文件包含了超过一个块的内容,则文件内容会存放在多个磁盘块中。一个较大的文件很容易分布上千个独立的磁盘块中。
五、文件分类
普通文件、目录、字符设备文件、块设备文件、命名管道(FIFO)、套接字(socket)。
字符设备文件、块设备文件、命名管道(FIFO)、套接字(socket)这4种是特殊文件,这些文件只有索引节点,没有数据,字符设备文件和块设备文件用来存储设备号、直接把设备号存储在索引节点中
。
六、链接
在linux系统中有种文件是链接文件,可以解决文件的共享使用。链接分为两种:一种是硬链接,另一种是软连接或者也称为符号链接
。
硬链接:相当于一个文件取了多个名称,多个文件名称对应一个索引节点,索引节点成员i_nlink是硬链接计数,删除文件只需将相应的目录项删除,该文件的链接数减1,如果删除目录项后该文件的链接数为零,这时系统才把真正的文件从磁盘上删除。;
软连接:这种文件的数据是另一个文件的路径,可对一个文件或目录创建软连接。
inode(索引节点)的成员i_op指向索引节点操作命令inode_operations,i_fop指向文件操作集合file_operations。两者间的区别:inode_operations用来操作目录和文件属性。file_operations用于访问文件的数据。
索引节点操作集合的数据结构是结构体inode_operations,具体源码如下:
struct inode_operations {
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
const char * (*follow_link) (struct dentry *, void **);
int (*permission) (struct inode *, int);
int (*permission2) (struct vfsmount *, struct inode *, int);
struct posix_acl * (*get_acl)(struct inode *, int);
int (*readlink) (struct dentry *, char __user *,int);
void (*put_link) (struct inode *, void *);
int (*create) (struct inode *,struct dentry *, umode_t, bool);
int (*link) (struct dentry *,struct inode *,struct dentry *);
int (*unlink) (struct inode *,struct dentry *);
int (*symlink) (struct inode *,struct dentry *,const char *);
int (*mkdir) (struct inode *,struct dentry *,umode_t);
int (*rmdir) (struct inode *,struct dentry *);
int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t);
int (*rename) (struct inode *, struct dentry *,
struct inode *, struct dentry *);
int (*rename2) (struct inode *, struct dentry *,
struct inode *, struct dentry *, unsigned int);
int (*setattr) (struct dentry *, struct iattr *);
int (*setattr2) (struct vfsmount *, struct dentry *, struct iattr *);
int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
int (*removexattr) (struct dentry *, const char *);
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
u64 len);
int (*update_time)(struct inode *, struct timespec *, int);
int (*atomic_open)(struct inode *, struct dentry *,
struct file *, unsigned open_flag,
umode_t create_mode, int *opened);
int (*tmpfile) (struct inode *, struct dentry *, umode_t);
int (*set_acl)(struct inode *, struct posix_acl *, int);
} ____cacheline_aligned;
文件操作集合的数据结构是结构体file_operations,具体源码如下:
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
int (*iterate) (struct file *, struct dir_context *);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, loff_t, loff_t, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **, void **);
long (*fallocate)(struct file *file, int mode, loff_t offset,
loff_t len);
void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMU
unsigned (*mmap_capabilities)(struct file *);
#endif
};
硬链接:通过索引节点来进行链接
,在linux文件系统中,保存在磁盘分区中的文件不管是什么类型都会给它分配一个编号,这个编号被称为索引节点(inode index)。硬链接的作用之一是允许一个文件拥有多个有效路径名称,这样用户就可以建立硬链接到重要文件,以防止"误删除"源数据。
软连接:是存放另一个文件的路径的形式存在。
Linux建立软链接、硬链接
软硬链接的特点:
1、软连接可以跨文件系统,硬链接不可以;
2、软连接可以对目录进行链接,硬链接不可以;
- 什么叫CPU?
- SATA接口中数据线各针脚的定义
- 为何有些安卓后台程序就是关不掉呢?
- 突然断电对电脑有什么危害?
- win7win10下装centos7双系统
- 一键重装win7系统详细教程
- vmware workstation 15.5 pro 简易安装 win7 64位旗舰版 虚拟机
- u盘格式化后数据能恢复吗?
- linux环境下如何重装系统,linux如何重装系统
- windows11系统新手保姆级U盘安装教程
- 电脑Win10 企业版如何激活
- 记录一次wifi图标消失,无法连接问题的解决方法(报错代码56)
- win10 固定本机IP
- 【Ubuntu&ROS】双系统登Ubuntu和Windows开机选择界面消失问题解决办法
- 如何设置路由器连上电信宽带
- 将Kali2安装到U盘的实践----图文并茂,详细的让你哭
- Cisco 路由器作业1.1 路由器初始化配置