内核数据结构-XArray

news/2024/4/27 22:44:01/文章来源:https://blog.csdn.net/lzhf1122/article/details/128946640

内核数据结构-XArray

  • XArray简介
  • XArray 基本数据结构
  • Xarray结构图
  • API介绍
  • Xarray锁
  • 参考链接

XArray简介

XArray是一种抽象数据类型,类似于一个大的指针数组,它满足了许多与哈希或常规可调整大小数组相同的需求。由于 xarray 中的数据都是指针,使用 RCU 这种无锁的方法查找数据是再合适不过了。

xarray 数据结构主要的应用场景是在文件缓存。我们知道在Linux内核中,为了加快文件的访问速度,将空闲的内存页就用做了磁盘的 cache。一个文件的缓存通过 address_space 数据结构进行管理,而这里面用于记录文件数据与内存页之间映射关系的数据结构就是采用了 xarray。当每次需要访问文件的数据时,都需要先查找这个缓存表,所以它的最重要的需求就是查找速度要快。如果把文件的偏移看作是虚拟地址,那么这个表其实做的事情就是——虚拟地址->内存页 的映射。这不就是虚拟内存的页表所做的事情吗!所以其实 xarray 就是类似于内存的页表结构,二者的区别就是 xarray 的 “地址” 范围是可变的,而页表的地址范围是固定的(CPU的寻址位宽决定)。

XArray 基本数据结构

XArray主要包括结构体struct xarray和结构体struct xa_node.
struct xarray:

278 /**279  * struct xarray - The anchor of the XArray.280  * @xa_lock: Lock that protects the contents of the XArray.281  *282  * To use the xarray, define it statically or embed it in your data structure.283  * It is a very small data structure, so it does not usually make sense to284  * allocate it separately and keep a pointer to it in your data structure.285  *286  * You may use the xa_lock to protect your own data structures as well.287  */288 /*289  * If all of the entries in the array are NULL, @xa_head is a NULL pointer.290  * If the only non-NULL entry in the array is at index 0, @xa_head is that291  * entry.  If any other entry in the array is non-NULL, @xa_head points292  * to an @xa_node.293  */294 struct xarray {295     spinlock_t  xa_lock;296 /* private: The rest of the data structure is not to be used directly. */297     gfp_t       xa_flags;298     void __rcu *    xa_head;299 };

成员说明:
xa_lock: 用于保护XArray内容的锁。
xa_head:用于顶级的xa_node节点。

struct xa_node:

1117 /*
1118  * @count is the count of every non-NULL element in the ->slots array
1119  * whether that is a value entry, a retry entry, a user pointer,
1120  * a sibling entry or a pointer to the next level of the tree.
1121  * @nr_values is the count of every element in ->slots which is
1122  * either a value entry or a sibling of a value entry.
1123  */
1124 struct xa_node {
1125     unsigned char   shift;      /* Bits remaining in each slot */
1126     unsigned char   offset;     /* Slot offset in parent */
1127     unsigned char   count;      /* Total entry count */
1128     unsigned char   nr_values;  /* Value entry count */
1129     struct xa_node __rcu *parent;   /* NULL at top of tree */
1130     struct xarray   *array;     /* The array we belong to */
1131     union {
1132         struct list_head private_list;  /* For tree user */
1133         struct rcu_head rcu_head;   /* Used when freeing node */
1134     };
1135     void __rcu  *slots[XA_CHUNK_SIZE];
1136     union {
1137         unsigned long   tags[XA_MAX_MARKS][XA_MARK_LONGS];
1138         unsigned long   marks[XA_MAX_MARKS][XA_MARK_LONGS];
1139     };
1140 };

成员说明

(1)shift成员用于指定当前xa_node的slots数组中成员的单位,当shift为0时,说明当前xa_node的slots数组中成员为叶子节点,当shift为6时,说明当前xa_node的slots数组中成员指向的xa_node可以最多包含2^6(即64)个节点,
(2)offset成员表示该xa_node在父节点的slots数组中的偏移。(这里要注意,如果xa_node在父节点为NULL,offset是任意的值,因为没有被初始化)
(3)count成员表示该xa_node有多少个slots已经被使用。
(4)nr_values成员表示该xa_node有多少个slots存储的Value Entry。
(5)parent成员指向该xa_node的父节点
(6)array成员指向该xa_node所属的xarray
(7)slots是个指针数组,该数组既可以存储下一级的节点, 也可以用于存储即将插入的对象指针.

Xarray结构图

xarray 作为一个树形结构,每个树中的节点(也就是 xa_node )包含着 XA_CHUNK_SIZE(默认为64) 个 slot。叶子结点中的 slot 指向实际实际的数据(在文件缓存中就是存放文件数据的内存页框指针),中间结点中的 slot 则指向下一级表,类似于页表的页目录。正如前面所说的,它类似于虚拟内存的页表,xarray 的查找 key 是一个类似于地址的 index,存储的主体则是指针。下面以一个 node 包含 16个 slot 的 xarray 为例,绘制 xarray 的结构图:
在这里插入图片描述
总的来讲和系统的页表很像。有了这个图像概念在心里,有些函数就相对比较容易理解了。

API介绍

先理解一下slots中存放的Entry的规则
slots中存储的entry必须4字节对齐,低两位决定了Xarray如何解析其内容。

  • 低2位是00时,它是一个Pointer Entry
  • 低2位是10时,它是一个Internal Entry,一般指向下一级的xa_node.但是有些Internal Entry有特别的含义,比如:
    0-62: Sibling entries
    256: Zero entry
    257: Retry entry
  • 低2为是x1时,它是一个Value Entry,或者tagged pointer。

(1)定义一个XArray数组:

DEFINE_XARRAY(array_name);
/* or */
struct xarray array;
xa_init(&array);

(2)在XArray里存放一个值:

void *xa_store(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp);

这个函数会把参数给出的entry,放到请求的index这个地方。如果要XArray需要分配内存,会使用给定的gfp来分配。如果成功,返回值是之前存放在index的值。删除一个entry可以通过在这里存放NULL来实现,或者调用

void *xa_erase(struct xarray *xa, unsigned long index);

(3)xa_store的变体:

  • xa_insert用于存放但不覆盖现有的entry
  • 另一个变体:xa_cmpxchg,只有当存的值和old参数匹配上时,才会将entry存在index处。
static inline int __must_check xa_insert(struct xarray *xa,unsigned long index, void *entry, gfp_t gfp);
static inline void *xa_cmpxchg(struct xarray *xa, unsigned long index,void *old, void *entry, gfp_t gfp);

(4)用xa_load()从XArray里取出一个值:

void *xa_load(struct xarray *xa, unsigned long index);

返回值是存放在index处的值。XArray里,空entry和存入NULL的entry是等价的。因此xa_load不会对空entry有特殊的处理。
(5)非空entry上还可以设置最多3个比特的标签,标签管理函数:

bool xa_get_mark(struct xarray *xa, unsigned long index, xa_mark_t mark);
void xa_set_mark(struct xarray *xa, unsigned long index, xa_mark_t mark);
void xa_clear_mark(struct xarray *xa, unsigned long index, xa_mark_t mark);

mark的值是XA_MARK_0, XA_MARK_1, XA_MARK_2三者之一。 xa_set_mark用于在index处的entry上设置标签 xa_clear_mark用于清除标签 xa_get_mark用于返回index处的entry的标签
(6)XArray是很稀疏的,因此一个普遍的准则是,不要进行低效的遍历查找非空项。要查找多个非空项,应该使用这个宏:

xa_for_each(xa, entry, index, max, filter) {/* Process "entry" */
}

在进入循环之前,需要把index设为遍历的起点,max设为遍历的最大index,filter指定需要过滤的mark。 循环执行时,index会被设为当前匹配到的entry。可以在循环里修改index,来改变迭代过程。修改XArray自身也是允许的。
(7)删除一个Xarray中所有的Entry

void xa_destroy(struct xarray *xa);

还有其他很多操作XArray的普通API。特殊情况下还可以使用高级API。

Xarray锁

使用NormalAPI时,不必担心锁的问题。XArray使用RCU和内部自旋锁来同步访问:
无需锁定:

xa_empty()
xa_marked()

采取RCU读取锁定:

xa_load()
xa_for_each()
xa_find()
xa_find_after()
xa_extract()
xa_get_mark()

内部采用xa_lock:

xa_store()
xa_store_bh()
xa_store_irq()
xa_insert()
xa_insert_bh()
xa_insert_irq()
xa_erase()
xa_erase_bh()
xa_erase_irq()
xa_cmpxchg()
xa_cmpxchg_bh()
xa_cmpxchg_irq()
xa_store_range()
xa_alloc()
xa_alloc_bh()
xa_alloc_irq()
xa_reserve()
xa_reserve_bh()
xa_reserve_irq()
xa_destroy()
xa_set_mark()
xa_clear_mark()

以下高级api需要拿xa_lock后调用:

__xa_store()
__xa_insert()
__xa_erase()
__xa_cmpxchg()
__xa_alloc()
__xa_reserve()
__xa_set_mark()
__xa_clear_mark()

参考链接

链接: 内核基础设施(一)xarray
链接: Linux lib 之 xarray
链接: xarray这个数据结构
链接: The XArray data structure
链接: 内核基础设施——XArray
链接: XArray

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

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

相关文章

以太网知识-GMII / RGMII接口

今天和海翎光电的小编一起分析MII/RMII/SMII,以及GMII/RGMII/SGMII接口的信号定义,及相关知识,同时小编也对RJ-45接口进行了总结,分析了在10/100模式下和1000M模式下的连接方法。GMII 接口分析GMII接口提供了8位数据通道&#xff…

shell条件测试

文章目录三、shell条件测试3.1条件测试的基本语法3.2 文件测试表达式3.3字符串测试表达式3.4 整数测试表达式3.5 逻辑操作符三、shell条件测试 为了能够正确处理Shell程序运行过程中遇到的各种情况,Linux Shell提供了一组测试运算符。通过这些运算符,Sh…

go语言的并发编程

并发编程是 Go语言的一个重要特性,而 go语言也是基于此而设计出来的。 本文将会介绍如何使用go-gc中的“runtime”方法实现 go语言中的并发编程。 在之前的文章中,我们已经对 runtime方法进行了详细介绍,这次文章将对 runtime方法进行深入分析,并讲解如何在go-gc中使用该方…

智能建筑电力监控自动化的解决方案

引言 安科瑞 李亚俊 壹捌柒贰壹零玖捌柒伍柒 所谓智能建筑就是采用计算机技术和通讯技术对建筑的设备进行自动监控,对信息资源进行管理和为用户提供信息服务等。美国智能建筑研究机构把智能建筑定义为:通过对建筑物的结构、系统、服务和管理四个基本要…

数据库模式(schema)是什么?

在数据库的术语中,模式(schema)是一个逻辑概念,用于组织数据库中的对象。模式中的对象通常包括表、索引、数据类型、序列、视图、存储过程、主键、外键等等。 模式可以为数据库对象提供逻辑隔离功能,不用应用程序可以…

负载均衡下的webshell上传

负载均衡下的webshell上传1.应用场景2.面临的困难2.1 shell文件上传问题2.2 命令执行时的漂移2.3 大工具投放失败2.4 内网穿透工具失效3.一些解决方案3.1 关机3.2 基于IP判断执行主机3.3 脚本实现web层的流量转发3.3.1 创建antproxy.jsp脚本3.3.2 修改 Shell 配置4.总结1.应用场…

开发必看!三分钟读懂Salesforce SOQL查询和限制

SOQL是支持我们与Salesforce数据库交互的查询语言。开发人员在编写Apex时通常会使用到SOQL,此外,它还允许管理员和开发人员从组织内部检索数据并在导出结果时生成强大的数据报告。 SOQL 查询对于编写代码的开发人员,以及通过使用子句扩展查询…

STM32 复用JLink下载线输出调试信息

编写STM32程序时,要输出调试信息的话,一般是通过一个串口输出,电脑端使用串口调试助手显示调试信息。这样的话,就需要占用一个串口资源。还有一种SEGGER的RTT方式,直接使用JLink下载线输出调试信息,这样可以…

在线支付系列【21】微信支付服务商接入前准备

有道无术,术尚可求,有术无道,止于术。 文章目录项目概述接入准备1. 注册服务商号(获取服务商mchid)2. 注册公众号(获取服务商APPID)3. 绑定应用ID和服务商ID4. 入驻子商户(特约商户进…

使用Jmeter抓取手机APP报文并进行APP接口测试

Jmeter是一个比较常用的接口测试工具,尤其是接口性能测试。当然它也可以用来测试手机APP的HTTP接口,我在Fiddler抓取手机APP报文 和 接口测试代理工具charles mock测试 分别介绍了Fiddler和charles 如何抓取APP报文,本文介绍使用Jmeter来抓取…

内网渗透(十三)之内网信息收集-收集域环境中的基本信息

系列文章第一章节之基础知识篇 内网渗透(一)之基础知识-内网渗透介绍和概述 内网渗透(二)之基础知识-工作组介绍 内网渗透(三)之基础知识-域环境的介绍和优点 内网渗透(四)之基础知识-搭建域环境 内网渗透(五)之基础知识-Active Directory活动目录介绍和使用 内网渗透(六)之基…

Jmeter之实现参数化的不同方式详解

参数化简介 定义:动态的获取、设置或生成数据,是一种由程序驱动代替人工驱动的数据设计方案,提高脚本的编写效率以及编写质量 适用场景:当提交的数据量较大时,每次修改太麻烦,可以使用参数化 本文介绍实现…

linux yum安装卸载jdk8

1>安装1 yum -y list java* 列出jdk列表2 yum install -y java-1.8.0-openjdk-demo.x86_64(安装这个java -version 正常显示,但是javac不能用,因为yum install java 只是安装了java的运行时环境,并不支持编译,安装成…

NLP学习——信息抽取

信息抽取 自动从半结构或无结构的文本中抽取出结构化信息的任务。常见的信息抽取任务有三类:实体抽取、关系抽取、事件抽取。 1、实体抽取 从一段文本中抽取出文本内容并识别为预定义的类别。 实体抽取任务中的复杂问题: 重复嵌套,原文中…

使用openai-whisper 语音转文字

前言:最近由于ChatGPT 的大热,AI 应用领域再次进入大众的视线,今天介绍一款AI应用whisper 可以较为准确的将人声转换为文字(支持多国语言)一、安装安装有两种方式pip 和源码编译安装,这里介绍pip安装方式安…

欧盟砍伐森林法规和遵守情况 用Dimitra技术解决森林砍伐问题

两千年前,西欧有80%的地区被列为森林。今天,这个数字只有34%。森林砍伐影响着这个星球上的每个人。它造成了大约10%的全球变暖。如果不设法解决森林砍伐问题,就不可能应对全球变暖。 毁林是有目的的清除林地的行为。此外,工业化农…

cmd常用的操作命令

使用windows系统,通常在cmd中输入指令,会调用相应的一些程序或者执行一些功能,学会使用CMD中的命令,可以加快我们一些操作,省时省力。 ipconfig ------查询IP地址 gpedit.msc-----组策略 sndrec32-------录音机 Nsloo…

ClickHouse 合并树表引擎 MergeTree 索引与数据存储方式

目录 1. 一级索引 1.1 稀疏索引 1.2 索引粒度 1.3 索引数据的生成规则 1.4 索引的查询过程 2. 二级索引 2.1 granularity 与 index_granularity 2.2 跳数索引的生成规则

JVM从看懂到看开Ⅲ -- 类加载与字节码技术【上】

文章目录类文件结构魔数版本常量池访问标识与继承信息Field 信息Method 信息附加属性字节码指令初识javap工具图解方法执行流程通过字节码指令来分析分析 i问题条件判断指令循环控制指令构造方法cinit()Vinit()V方法调用多态原理异常处理try-catch多个single-catchfinallyfinal…

MDQ60-16-ASEMI三相整流模块MDQ60-16

编辑-Z MDQ60-16在MDQ封装里采用的4个芯片,是一款机床用三相可控整流模块。MDQ60-16的浪涌电流Ifsm为920A,漏电流(Ir)为5mA,其工作时耐温度范围为-40~150摄氏度。MDQ60-16采用GPP硅芯片材质,里面有4颗芯片组成。MDQ60-16的电性参…