Linux 内核中根据文件inode号获取其对应的struct inode

文章目录

  • 前言
  • 一、简介
  • 二、LKM demo
    • 2.1 iget_locked
    • 2.2 LKM demo
    • 2.3 ext4_iget

前言

文件inode号和struct inode结构体请参考:
Linux文件路径,目录项,inode号关联
Linux文件系统 struct inode 结构体解析

一、简介

在Linux中,每个文件和目录都与一个唯一的inode号相关联。inode号是文件系统中inode的唯一标识符,用于表示文件或目录的元数据。

这就意味inode号在文件系统中是不可以重复的。

在同一个文件系统中,文件的inode号是唯一的,不会重复。每个文件系统维护着一个独立的inode表,其中的inode号在该文件系统中是唯一的。

然而,不同文件系统之间的inode号可以重复。当不同的文件系统挂载到同一个系统上时,它们各自维护着独立的inode号空间。因此,不同文件系统中的文件可以拥有相同的inode号,但它们在各自的文件系统中是唯一的。

这意味着,如果在不同文件系统中有两个文件的inode号是相同的,那么它们实际上是不同的文件,属于不同的文件系统。

需要注意的是,文件系统的实现可能会限制inode号的范围或分配策略,具体取决于文件系统的设计和实现。

因此当涉及到多个文件系统时,不同文件系统中的inode号确实可以重复。这是因为每个文件系统都有自己的inode号空间,用于在该文件系统中唯一标识文件和目录。

当不同的文件系统挂载到同一个操作系统中时,每个文件系统会独立地管理自己的inode号。这意味着,即使两个文件系统中存在具有相同inode号的文件,它们仍然被视为不同的文件,并且彼此之间没有任何关联。

这种情况可能发生在以下情况下:
(1)多个独立的物理磁盘或分区:每个磁盘或分区上的文件系统都有自己的inode号空间,它们彼此独立。

(2)文件系统镜像:如果相同的文件系统映像被多次挂载,每次挂载都会创建一个独立的inode号空间。

(3)网络文件系统(NFS):当使用NFS挂载远程文件系统时,本地文件系统和远程文件系统的inode号彼此独立。

这种设计允许不同的文件系统在同一个操作系统中并存,并通过挂载点进行访问。每个文件系统都有自己的inode号空间,确保了在各自范围内的唯一性。

需要注意的是,尽管不同文件系统中的inode号可以重复,但通常并不鼓励依赖inode号来唯一标识文件。在跨文件系统或跨系统的环境中,使用文件路径或其他唯一标识符更可靠和可移植。

二、LKM demo

2.1 iget_locked

通常前面的知识我们可以知道不同文件系统中的文件可以拥有相同的inode号,它们在各自的文件系统中是唯一的,因此我们根据在内核态编程中根据文件inode号获取其对应的struct inode结构体,那么需要明确文件系统和inode号才能获取其对应的struct inode结构体,不能单独通过inode号获取其struct inode结构体,可以使用iget_locked函数。

/*** iget_locked - obtain an inode from a mounted file system* @sb:		super block of file system* @ino:	inode number to get** Search for the inode specified by @ino in the inode cache and if present* return it with an increased reference count. This is for file systems* where the inode number is sufficient for unique identification of an inode.** If the inode is not in cache, allocate a new inode and return it locked,* hashed, and with the I_NEW flag set.  The file system gets to fill it in* before unlocking it via unlock_new_inode().*/
struct inode *iget_locked(struct super_block *sb, unsigned long ino)
{struct hlist_head *head = inode_hashtable + hash(sb, ino);struct inode *inode;
again:spin_lock(&inode_hash_lock);inode = find_inode_fast(sb, head, ino);spin_unlock(&inode_hash_lock);if (inode) {if (IS_ERR(inode))return NULL;wait_on_inode(inode);if (unlikely(inode_unhashed(inode))) {iput(inode);goto again;}return inode;}inode = alloc_inode(sb);if (inode) {struct inode *old;spin_lock(&inode_hash_lock);/* We released the lock, so.. */old = find_inode_fast(sb, head, ino);if (!old) {inode->i_ino = ino;spin_lock(&inode->i_lock);inode->i_state = I_NEW;hlist_add_head(&inode->i_hash, head);spin_unlock(&inode->i_lock);inode_sb_list_add(inode);spin_unlock(&inode_hash_lock);/* Return the locked inode with I_NEW set, the* caller is responsible for filling in the contents*/return inode;}/** Uhhuh, somebody else created the same inode under* us. Use the old inode instead of the one we just* allocated.*/spin_unlock(&inode_hash_lock);destroy_inode(inode);if (IS_ERR(old))return NULL;inode = old;wait_on_inode(inode);if (unlikely(inode_unhashed(inode))) {iput(inode);goto again;}}return inode;
}
EXPORT_SYMBOL(iget_locked);

iget_locked 函数通常在文件系统中使用,用于从已挂载的文件系统中获取一个 inode(索引节点)。

该函数的实现过程如下:
首先,根据给定的 inode 号 ino 和文件系统的超级块 sb,使用 hash 函数计算哈希值。该哈希值用于定位 inode 缓存中相应的哈希表条目。

函数获取自旋锁 inode_hash_lock,以在执行必要的操作时锁定 inode 缓存。

它搜索哈希链表(由 hlist_head 指针 head 指示),以查找与给定的 inode 号 ino 相关联的 inode。它使用 find_inode_fast 函数进行搜索。

如果在缓存中找到了 inode,函数通过使用 IS_ERR 函数检查它是否是有效的 inode。如果该 inode 无效,则返回 NULL。否则,它使用 wait_on_inode 函数等待 inode 上的任何挂起操作完成。

如果发现 inode 是未哈希的(即不在哈希表中),它将释放该 inode,并回到开始处重新搜索。

如果在缓存中未找到该 inode,则继续使用 alloc_inode 函数分配一个新的 inode。这将创建一个新的 struct inode 数据结构并进行初始化。

分配完 inode 后,函数释放自旋锁,并重新获取它,以执行另一次搜索以查找该 inode。这是必要的,因为在 alloc_inode 调用期间释放了锁,而另一个线程可能在此期间将该 inode 添加到缓存中。

如果没有其他线程添加了相同 inode 号的 inode,将设置新分配的 inode 的字段。将 i_ino 字段设置为给定的 inode 号 ino,将 i_state 字段设置为 I_NEW,以表示该 inode 是新的且尚未完全初始化,然后使用 hlist_add_head 将 inode 添加到哈希表中。使用 inode_sb_list_add 将 inode 添加到超级块的 inode 列表中。

然后,释放自旋锁和 inode 缓存锁,并将带有设置了 I_NEW 标志的锁定 inode 返回给调用者。调用者负责填充 inode 的内容。

如果在自旋锁释放期间有其他线程添加了相同 inode 号的 inode,则函数选择使用现有的 inode 而不是新分配的 inode。它使用 wait_on_inode 等待现有 inode 上的任何挂起操作完成。如果现有 inode 是未哈希的,则释放它,并回到开始处重新搜索。

最后,函数将获得的 inode(无论是新分配的还是现有的)返回给调用者。

/** find_inode_fast is the fast path version of find_inode, see the comment at* iget_locked for details.*/
static struct inode *find_inode_fast(struct super_block *sb,struct hlist_head *head, unsigned long ino)
{struct inode *inode = NULL;repeat:hlist_for_each_entry(inode, head, i_hash) {if (inode->i_ino != ino)continue;if (inode->i_sb != sb)continue;spin_lock(&inode->i_lock);if (inode->i_state & (I_FREEING|I_WILL_FREE)) {__wait_on_freeing_inode(inode);goto repeat;}if (unlikely(inode->i_state & I_CREATING)) {spin_unlock(&inode->i_lock);return ERR_PTR(-ESTALE);}__iget(inode);spin_unlock(&inode->i_lock);return inode;}return NULL;
}

该函数的作用是在给定的哈希链表 head 中快速查找与给定 inode 号 ino 和超级块 sb 相匹配的 inode。

函数使用 hlist_for_each_entry 宏遍历哈希链表中的每个 inode。对于每个 inode,它首先检查 inode 号和超级块是否与给定的匹配,如果不匹配,则继续遍历下一个 inode。

如果找到匹配的 inode,函数将获取 inode 的自旋锁,然后进行一系列的检查:
● 首先,它检查 inode 的状态是否处于 I_FREEING 或 I_WILL_FREE 状态,这表示 inode 正在释放或即将被释放。如果是这种情况,函数将调用 __wait_on_freeing_inode 函数等待 inode 完全释放,然后重新从头开始查找。

● 接下来,函数检查 inode 的状态是否处于 I_CREATING 状态,这表示 inode 正在创建过程中。如果是这种情况,函数将释放 inode 的自旋锁,并返回一个指向 -ESTALE 错误的指针,表示 inode 已过期。

● 最后,如果 inode 的状态正常,函数将调用 __iget 函数增加 inode 的引用计数,然后释放 inode 的自旋锁,并返回指向该 inode 的指针。

如果在整个哈希链表中没有找到匹配的 inode,函数将返回 NULL。

这个函数用于快速查找 inode,以加速文件系统中对 inode 的访问操作。

2.2 LKM demo

接下来我们给出一个LKM示例根据inode号来获取对应的struct inode结构体:

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>#include <linux/fs.h>
#include <linux/fs_struct.h>/* Module parameter */
static unsigned long ino = 1837047;module_param(ino, ulong, 0);static int __init hello_init(void)
{struct fs_struct *fs;struct path pwd;//unsigned long ino = 1837047;struct inode *inode;struct super_block *sb;fs = current->fs;get_fs_pwd(fs, &pwd);/* The root of the dentry tree */sb = pwd.dentry->d_sb;inode = iget_locked(sb, ino);if(inode)printk("inode num = %ld\n", inode->i_ino);return -1;
}module_init(hello_init);MODULE_LICENSE("GPL");
 ls -il 3.txt
1837252# insmod hello.ko ino=1837252
insmod: ERROR: could not insert module hello.ko: Operation not permitted# dmesg -c
inode num = 1837252

2.3 ext4_iget

我们简单看一下ext4文件系统根据inode号获取其struct inode结构体的方式:

// linux-5.4.18/fs/ext4/ext4.htypedef enum {EXT4_IGET_NORMAL =	0,EXT4_IGET_SPECIAL =	0x0001, /* OK to iget a system inode */EXT4_IGET_HANDLE = 	0x0002	/* Inode # is from a handle */
} ext4_iget_flags;extern struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,ext4_iget_flags flags, const char *function,unsigned int line);#define ext4_iget(sb, ino, flags) \__ext4_iget((sb), (ino), (flags), __func__, __LINE__)

ext4文件系统通过ext4_iget宏来获取struct inode结构体,宏定义 ext4_iget调用 __ext4_iget 函数来获取指定inode号对应的 struct inode 结构体。

该宏定义接受三个参数:

sb:指向 super_block 结构体的指针,表示要操作的超级块。
ino:表示要获取的inode号。
flags:表示 ext4_iget_flags 类型的标志位,用于指定 __ext4_iget 函数的行为。

宏定义将参数传递给 __ext4_iget 函数,并在最后两个参数 funcLINE 中传递了调用该宏的函数名和行号。这些信息通常用于调试目的,以便在发生错误时能够追踪到具体的调用位置。

对于第三个参数flags:

typedef enum {EXT4_IGET_NORMAL =	0,EXT4_IGET_SPECIAL =	0x0001, /* OK to iget a system inode */EXT4_IGET_HANDLE = 	0x0002	/* Inode # is from a handle */
} ext4_iget_flags;

枚举类型 ext4_iget_flags,用于表示 ext4_iget 函数的标志或选项。

ext4_iget_flags 枚举类型包含三个成员:

EXT4_IGET_NORMAL:表示普通的 iget 操作。它用于指示 iget 函数应该获取普通文件或目录的 inode。

EXT4_IGET_SPECIAL:表示可以 iget 系统级 inode。系统级 inode 是用于各种系统级操作或文件类型(如超级块或日志文件)的特殊目的 inode。

EXT4_IGET_HANDLE:用于当 inode 号是从一个句柄(handle)中获取时。句柄是用于跨文件系统和进程访问 inode 的标识符,通常用于实现文件系统的高级功能。

接下来我们给出一个LKM示例根据inode号来获取对应的struct inode结构体:

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>#include <linux/fs.h>
#include <linux/fs_struct.h>#include <linux/kallsyms.h>/* Module parameter */
static unsigned long ino = 1837047;module_param(ino, ulong, 0);typedef enum {EXT4_IGET_NORMAL =	0,EXT4_IGET_SPECIAL =	0x0001, /* OK to iget a system inode */EXT4_IGET_HANDLE = 	0x0002	/* Inode # is from a handle */
} ext4_iget_flags;struct inode *(*my__ext4_iget)(struct super_block *sb, unsigned long ino,ext4_iget_flags flags, const char *function,unsigned int line);static int __init hello_init(void)
{struct fs_struct *fs;struct path pwd;//unsigned long ino = 1837047;struct inode *inode;struct super_block *sb;fs = current->fs;get_fs_pwd(fs, &pwd);/* The root of the dentry tree */sb = pwd.dentry->d_sb;my__ext4_iget = (void *)kallsyms_lookup_name("__ext4_iget");inode = my__ext4_iget(sb, ino, EXT4_IGET_NORMAL, __func__, __LINE__);if(inode)printk("inode num = %ld\n", inode->i_ino);return -1;
}module_init(hello_init);MODULE_LICENSE("GPL");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/132169.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

web3 React dapp中编写balance组件从redux取出并展示用户资产

好啊 上文WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量中 我们拿到了用户的一个本身 和 交易所token数量 并放进了redux中做了一个全局管理 然后 我们继续 先 起来ganache的一个模拟环境 ganache -d然后 我们启动自己的项目 顺手发…

Spring底层原理学习笔记--第二讲--(BeanFactory实现与ApplicaitonContext实现)

BeanFactory实现 package com.lucifer.itheima.a02;import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.fac…

聚观早报 |小米CarWith启动兼容测试;「天工」大模型开放

【聚观365】11月6日消息 小米CarWith启动兼容测试 「天工」大模型开放 邮政快递揽收超20亿件 华为Mate 60 Pro开启预约申购 VERTU持续探索前沿科技 小米CarWith启动兼容测试 小米CarWith是打造“人车家生态”中不可或缺的一环&#xff0c;在最新升级的2.0版本中&#xff…

Jupyter notebook如何加载torch环境

默认你已经安装了anaconda 和 pytorch 环境。 1&#xff0c;必须要以管理员身份打开 Anaconda prompt终端&#xff0c; 2&#xff0c;进入pytorch环境中&#xff1a; conda activate pytorch_393&#xff0c;安装必要插件&#xff1a; &#xff08;1&#xff09;conda inst…

项目管理之如何识别并应对项目风险

项目风险管理是项目管理中不可忽视的环节&#xff0c;如何识别并应对项目的风险对于项目的成功实施至关重要。本文将介绍风险管理的流程、风险分解结构、定性及定量风险评估方法&#xff0c;以及消极和积极的风险应对策略&#xff0c;旨在帮助读者更好地理解和应对项目风险。 …

win10端口转发

1. 写在前面 核心命令 netsh&#xff0c; 此工具在win10下&#xff0c;支持大量网络相关配置&#xff0c;可参考&#xff1a;netsh官方文档 2. 命令行批模式 在CMD或PowerShell中&#xff0c;执行以下命令&#xff0c; 可能会提示需要管理员权限执行 # 添加转发规则&#x…

使用new_zeros和zeros_like分别返回与输入相同尺寸/类型/device的tensor和ndarray

torch.Tensor.new_zeros(size, dtypeNone, deviceNone) 返回尺寸为size的全为0的tensor&#xff0c;默认&#xff0c;返回的tensor与该tensor具有相同的dtype和device&#xff0c;可以用于在模型训练过程中创建新tensor&#xff0c;并保证该tensor在对应的device上 1&#xff0…

华为政企闪存存储产品集

产品类型产品型号产品说明 maintainProductOceanStor Dorado 2000 SAS 128GB华为OceanStor Dorado 2000是一款简单、可靠、绿色的全闪存存储系统&#xff0c;极简部署、智能运维、轻量便捷&#xff0c;功能齐全&#xff0c;广泛适用于虚拟化、数据库、办公自动化、分支机构等…

Gorm 中的迁移指南

探索使用 GORM 在 Go 中进行数据库迁移和模式更改的世界 在应用程序开发的不断变化的景观中&#xff0c;数据库模式更改是不可避免的。GORM&#xff0c;强大的 Go 对象关系映射库&#xff0c;通过迁移提供了一种无缝的解决方案来管理这些变化。本文将作为您全面的指南&#xf…

最新知识付费变现小程序源码/独立后台知识付费小程序源码/修复登录接口

最新知识付费变现小程序源码&#xff0c;独立后台知识付费小程序源码&#xff0c;最新版修复登录接口。 主要功能 会员系统&#xff0c;用户登录/注册购买记录 收藏记录 基本设置 后台控制导航颜色 字体颜色 标题等设置 流量主广告开关小程序广告显示隐藏 广告主审核过审核…

aardio使用任意版本Python的用法

aardio中调用python的方法有两种,py3 和 process.python模块 py3模块:如果经常要拿到python返回的值或从aardio中传数据给python去处理,aardio和python的交互比较多的话,可以考虑使用py3模块,缺点是:py3模块使用起来比较麻烦些,尤其是在异步多线程操作的话,中间需要学习…

Openssl生成证书-nginx使用ssl

Openssl生成证书并用nginx使用 安装openssl yum install openssl -y创库目录存放证书 mkdir /etc/nginx/cert cd /etc/nginx/cert配置本地解析 cat >>/etc/hosts << EOF 10.10.10.21 kubernetes-master.com EOF10.10.10.21 主机ip、 kubernetes-master.com 本…

使用 Python 进行自然语言处理第 4 部分:文本表示

一、说明 本文是在 2023 年 3 月为 WomenWhoCode 数据科学跟踪活动发表的系列文章中。早期的文章位于&#xff1a;第 1 部分&#xff08;涵盖 NLP 简介&#xff09;、第 2 部分&#xff08;涵盖 NLTK 和 SpaCy 库&#xff09;、第 2 部分&#xff08;涵盖NLTK和SpaCy库&#xf…

什么是数据库迁移

在企业应用程序的上下文中&#xff0c;数据库迁移意味着将数据从一个平台移动到另一个平台。您可能想要迁移到不同平台的原因有很多。例如&#xff0c;一家公司可能决定通过迁移到基于云的数据库来节省资金。或者公司可能会发现某些特定的数据库软件具有对其业务需求至关重要的…

spring-boot中实现分片上传文件

一、上传文件基本实现 1、前端效果图展示&#xff0c;这里使用element-ui plus来展示样式效果 2、基础代码如下 <template><div><el-uploadref"uploadRef"class"upload-demo":limit"1":on-change"handleExceed":auto-…

JavaEE-博客系统3(功能设计)

本部分内容为&#xff1a;实现登录功能&#xff1b;强制要求用户登录&#xff1b;实现显示用户信息&#xff1b;退出登录&#xff1b;发布博客 该部分的后端代码如下&#xff1a; Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws Ser…

mysql 中!= 到底走不走索引?

mysql 中! 到底走不走索引&#xff1f; 很多人疑惑! 到底走不走索引&#xff0c; 这里可以肯定的说该操作是可以走索引的&#xff0c;但实际情况中都为啥都不走索引呢&#xff1f; 首先我们要知道走索引与数据量和数据趋势&#xff08;cardinality&#xff09;有很大的关系&…

异构融合计算技术白皮书(2023年)研读3

读到工业和信息化部电子第五研究所所做的《异构融合计算技术白皮书&#xff08;2023年&#xff09;》&#xff0c;我关注的重点是FPGA与异构计算。续前篇&#xff0c;前篇为第1至4点。 5 运行一致性 P23 运行一致性计算资源分解&#xff0c;裸金属、虚拟机、容器、函数等更小…

bug: https://aip.baidubce.com/oauth/2.0/token报错blocked by CORS policy

还是跟以前一样&#xff0c;我们先看报错点&#xff1a;&#xff08;注意小编这里是H5解决跨域的&#xff0c;不过解决跨域的原理都差不多&#xff09; Access to XMLHttpRequest at https://aip.baidubce.com/oauth/2.0/token from origin http://localhost:8000 has been blo…

设计模式之装饰模式

一、概念 装饰模式是一种结构型设计模式&#xff0c;允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。 二、构造 部件&#xff08;Component&#xff09;声明封装器和被封装对象的公用接口。 具体部件&#xff08;Concrete Component&#xff09;类是…