注:本文分析基于linux-4.18.0-193.14.2.el8_2内核版本,即CentOS 8.2

1 inode

内存中,每个文件都有一个inode,一切皆文件,其实应该是说一切皆inode。inode保存了文件系统中一个文件的属性描述,比如文件类型,文件权限,属主,文件创建、读取或修改的时间等等。除了内存中的inode,磁盘中也有对应的inode结构,比如ext4文件系统中,内存中的inode是struct ext4_inode_info,而磁盘中的inode是struct ext4_inode_info,今天我们主要分析下内存中的inode结构。

2 inode主要成员变量

struct inode {umode_t            i_mode;  //文件类型和访问权限unsigned short      i_opflags;kuid_t            i_uid; //inode所属文件的所有者idkgid_t          i_gid; //inode所属文件所在组idunsigned int     i_flags;...const struct inode_operations    *i_op; //该inode操作函数集合struct super_block *i_sb;  //指向所属超级块对象struct address_space *i_mapping; //指向inode在内存中的pagecache...unsigned long     i_ino;  //inode节点号 ls -i 可以查看文件inode号...struct timespec64   i_atime; //文件最后访问时间struct timespec64    i_mtime; //文件最后修改时间struct timespec64    i_ctime; //文件创建时间spinlock_t     i_lock; /* i_blocks, i_bytes, maybe i_size */unsigned short          i_bytes; //文件在最后一块中的字节数unsigned int        i_blkbits; //block size(字节位数),一般为9enum rw_hint       i_write_hint;blkcnt_t       i_blocks; //文件的总块数,这里一个block为512 byte,也就是扇区大小...unsigned long     dirtied_when;   //inode变脏的时间unsigned long       dirtied_time_when;//通过该变量链接到全局inode哈希表inode_hashtable,用于inode的快速查找//哈希值通过超级块和inode number计算struct hlist_node i_hash; //通过该变量挂载到bdi_writeback的b_io链表,等待BDI回写,也就是这是脏inodestruct list_head    i_io_list;  /* backing dev IO list *///该inode所在设备对应的bdi_writeback结构,用于inode的回写struct bdi_writeback   *i_wb;  ...struct list_head i_lru;  //通过该变量链接到超级块的s_inode_lru链表struct list_head i_sb_list; //通过该变量链接到超级块的s_inodes上struct list_head  i_wb_list;  //通过该变量链接到超级块的s_inodes_wb上,回写统计union {//所有引用该inode的目录项将形成一个链表//比如文件被链接到其他的文件,就会有多个dentrystruct hlist_head i_dentry; struct rcu_head       i_rcu;};...const struct file_operations *i_fop; //该inode对应的文件的操作函数集合struct file_lock_context    *i_flctx;struct address_space   i_data; //内嵌在inode的pagecache对象...void           *i_private; /* fs or device private pointer */RH_KABI_RESERVE(1)RH_KABI_RESERVE(2)
};

3 创建一个inode

我们以ext4的创建目录——mkdir为例,看下inode的创建过程,

const struct inode_operations ext4_dir_inode_operations = {.create      = ext4_create,....mkdir        = ext4_mkdir,...
};const struct file_operations ext4_dir_operations = {.llseek      = ext4_dir_llseek,.read        = generic_read_dir,....open        = ext4_dir_open,.release   = ext4_release_dir,
};static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{...//调用ext4文件系统的alloc_inode函数,创建新的inodeinode = ext4_new_inode_start_handle(dir, S_IFDIR | mode,&dentry->d_name,0, NULL, EXT4_HT_DIR, credits);...//对于目录文件,i_op和i_fop指向的也是对应的目录操作函数//如果是普通文件,i_op和i_fop指向的会是file操作函数inode->i_op = &ext4_dir_inode_operations;inode->i_fop = &ext4_dir_operations;...
}

ext4_new_inode_start_handle通过以下调用路径,

ext4_new_inode_start_handle ->__ext4_new_inode ->new_inode

最终在new_inode中将分配成功的inode挂到对应超级块的s_inodes链表上,这个链表就是这超级块所有的inode对象。

struct inode *new_inode(struct super_block *sb)
{struct inode *inode;spin_lock_prefetch(&sb->s_inode_list_lock);//调用对应文件系统的alloc_inode方法创建一个inodeinode = new_inode_pseudo(sb);if (inode)//将该inode挂载到对应超级块的s_inodes链表上inode_sb_list_add(inode);return inode;
}

4 添加inode到inode cache链表

超级块上除了s_inodes链表,还有一个LRU链表s_inode_lru,这放的是未使用,或者干净的inode,比如回写完毕的inode就会挂载到这个链表上,这个链表也称为inode cache,在系统需要回收内存时,就会对这个链表下手,回收最近最少使用的inode。

添加到s_inode_lru链表的路径主要有两个:

  • 回写完毕的inode,也就是干净的inode
  • inode没有其他进程引用

不过最终都是通过inode_lru_list_add将inode挂载到s_inode_lru链表,

static void inode_lru_list_add(struct inode *inode)
{//将inode挂载到超级块的s_inode_lru链表if (list_lru_add(&inode->i_sb->s_inode_lru, &inode->i_lru))this_cpu_inc(nr_unused);elseinode->i_state |= I_REFERENCED;
}

先看回写完毕的inode,

inode_sync_complete ->inode_add_lru ->inode_lru_list_add

然后是无其他进程引用时,

iput ->iput_final ->inode_add_lru ->inode_lru_list_add

5 从inode cache中删除inode(回收inode cache)

上面我们提到系统回收内存时,会对操作s_inode_lru链表,我们也大概看下,

long prune_icache_sb(struct super_block *sb, struct shrink_control *sc)
{LIST_HEAD(freeable);long freed;//遍历超级块的s_inode_lru链表,按照回收控制结构sc指定的回收数量,//将可回收的inode隔离到freeable链表中集中回收freed = list_lru_shrink_walk(&sb->s_inode_lru, sc,inode_lru_isolate, &freeable);//将隔离出来的inode进行回收,这样隔离后可以避免锁竞争dispose_list(&freeable);return freed;
}

回收inode主要是要从几个链表中抽离,和脏数据回写

  • 超级块的s_inode_lru链表
  • bdi_writeback的b_io链表
  • 超级块的s_inodes链表
  • 回写pagecache
  • 全局inode哈希表
static void dispose_list(struct list_head *head)
{while (!list_empty(head)) {struct inode *inode;inode = list_first_entry(head, struct inode, i_lru);//将inode从超级块的s_inode_lru链表摘除list_del_init(&inode->i_lru);//回收inodeevict(inode);cond_resched();}
}static void evict(struct inode *inode)
{const struct super_operations *op = inode->i_sb->s_op;BUG_ON(!(inode->i_state & I_FREEING));BUG_ON(!list_empty(&inode->i_lru));//从bdi_writeback的b_io链表摘除if (!list_empty(&inode->i_io_list))inode_io_list_del(inode);//将inode从超级块的s_inodes链表摘除inode_sb_list_del(inode);//等待该inode回写完毕inode_wait_for_writeback(inode);//调用对应文件系统的evict_inode方法,回写pagecacheif (op->evict_inode) {op->evict_inode(inode);} else {truncate_inode_pages_final(&inode->i_data);clear_inode(inode);}//如果是块设备inodeif (S_ISBLK(inode->i_mode) && inode->i_bdev)bd_forget(inode);//如果是字符型设备if (S_ISCHR(inode->i_mode) && inode->i_cdev)cd_forget(inode);//从全局inode哈希表中摘除remove_inode_hash(inode);...//回收inodedestroy_inode(inode);
}

处理完这些引用后,就可以调用destroy_inode回收到slab缓存,对于ext4,调用的是ext4_destroy_inode,

static void destroy_inode(struct inode *inode)
{BUG_ON(!list_empty(&inode->i_lru));__destroy_inode(inode);//调用对应文件系统的destroy_inode方法,将inode回收到slab缓存//对于ext4,调用的是ext4_destroy_inodeif (inode->i_sb->s_op->destroy_inode)inode->i_sb->s_op->destroy_inode(inode);elsecall_rcu(&inode->i_rcu, i_callback);
}static void ext4_destroy_inode(struct inode *inode)
{   if (!list_empty(&(EXT4_I(inode)->i_orphan))) {...}//调用ext4_i_callback将inode释放会slab缓存call_rcu(&inode->i_rcu, ext4_i_callback);
}static void ext4_i_callback(struct rcu_head *head)
{struct inode *inode = container_of(head, struct inode, i_rcu);//释放回slab缓存kmem_cache_free(ext4_inode_cachep, EXT4_I(inode));
}

6 结构关系

  • 一块磁盘,三个分区,sda1和sda2是ext4文件系统,sda3是xfs文件系统
  • 全局超级块链表super_blocks将三个超级块串联在一起
  • sda1上的ext4_inode_info结构中内嵌inode结构,其中i_sb指向对应的超级块
  • A、B、C三个inode挂载到超级块s_nodes链表,A,B两个未使用的inode还会挂载到s_inode_lru链表
  • sda2上的ext4文件系统同sda1一样
  • 而sda3上的xfs除了对应的xfs_inode结构不同,大体结构也是一样的,这其实就是VFS的作用,对所有文件系统抽象了一层

文件系统之inode相关推荐

  1. Linux文件系统之inode,block,superblock

            文件存储在硬盘上,硬盘的最小存储单位叫做扇区sector,每个扇区存储512个字节(0.5)kb,系统读取文件时不会一个一个扇区的读,而是一次性连续读取多个扇区,即一次性读1个'块'( ...

  2. 文件系统:inode、entry、superblock

    文件系统: inode:记录文件的基本数据信息: dentry(目录项):记录文件的文件名.父目录.子目录等信息 superblock(超级块):每个文件系统都有一个superblock; inode ...

  3. Linux 文件系统之 inode 概述

    inode是一个重要概念,是理解Unix/Linux文件系统和硬盘储存的基础. 我觉得,理解inode,不仅有助于提高系统操作水平,还有助于体会Unix设计哲学,即如何把底层的复杂性抽象成一个简单概念 ...

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

    一.inode是什么? 理解inode,要从文件储存说起. 文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector).每个扇区储存512字节(相当于0.5KB). 操作系统 ...

  5. [OS-Linux]详解Linux的文件系统、inode和动静态库

    本文详解了Linux中的文件系统,包括inode.软连接,硬链接.动静态库. 目录 一.理解文件系统 二.inode 三.硬链接和软连接 1.硬链接 2.软连接 四.动态库和静态库 1. 静态库与动态 ...

  6. 以下关于linux文件系统中inode,linux文件系统—inode及相关概念.docx

    linux文件系统-inode及相关概念 linux文件系统-inode及相关概念 博客分类: /category/156693Linux/blogs/tag/LinuxLinux/blogs/tag ...

  7. 【Linux】文件系统与inode、软硬链接

    目录 一.磁盘结构 二.文件系统 2.1 文件系统的区域划分 2.2 文件系统分区介绍 2.3 文件名与inode 三.软硬链接 3.1 软链接 3.2 硬链接 一.磁盘结构 理解文件系统前首先我们要 ...

  8. Linux 文件系统与inode,软硬链接

    目录 磁盘的结构 磁盘的抽象(虚拟,逻辑)结构 分区 Block Group 块组: 分析: 文件名 vs inode编号 创建/删除/查看 一个文件,操作系统做了什么? 软硬链接 软连接 硬链接 对 ...

  9. 理解Linux文件系统之 inode

    一.inode是什么? 理解inode,要从文件储存说起. 文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector).每个扇区储存512字节(相当于0.5KB). 操作系统 ...

  10. 【Linux】什么是文件系统及inode?如何创建软硬链接?软硬链接有什么作用?

    inode 软硬链接 创建软硬链接 理解硬链接 理解软链接 inode 了解一下文件系统: Linux ext2文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分区 ...

最新文章

  1. 皮一皮:我好像知道了什么...
  2. python读取txt文件并写入excel-Python读excel生成数据存入txt文件
  3. Linux常用命令 积累
  4. 在“3_人民日报语料”中统计“日语借词”的词频;
  5. 开场 Live,分享点干货——「深入了解 Node.js 包与模块机制」
  6. Windows 7 / Vista 分区问题
  7. 等级考试(二):二级C++---宏观把控
  8. vue.js中H5使用微信摇一摇抽奖,判断摇一摇次数
  9. linux lvs 存储层,LVS集群配置之LVS介绍
  10. c语言 电阻器的分类,电阻器的分类
  11. Rust:FFI 编程中的 CStr 和 CString
  12. C#——NPOI对Excel的操作、导入导出时异常处理(二)
  13. 硬件探索——数字钟的设计与制作
  14. 蓝桥杯,基础练习 Fibonacci数列(斐波那契数列) C++
  15. 【Day3.3】美攻铁道市场零距离接触行驶中的火车
  16. 用C语言实现求水仙花数
  17. Project2 分段切割路面,只取一个种子点
  18. Module and Component
  19. 【VNC使用指南】Ubuntu Kylin 使用 TigerVNC
  20. java计算机毕业设计星星电影购票网站源码+mysql数据库+lw文档+系统+调试部署

热门文章

  1. html 协议 302,http协议301、302的原理和实现
  2. 大厂高薪校招真 相:逼走老员工
  3. 服务器内部转发以及客户端重定向概念的学习
  4. NRF52832 RNG随机数产生器
  5. Android 源码编译问题总结
  6. arm linux之data abort异常处理
  7. python报错UnicodeDecodeError: ‘gbk‘ codec can‘t decode byte 0x97 in position的解决方法
  8. ObjectArx块操作封装
  9. R软件学习笔记—Legend
  10. 当图网络遇上计算机视觉!计算机视觉中基于图神经网络和图Transformer的方法和最新进展...