kfree_rcu实现浅析

文章http://t.csdnimg.cn/9sS23和http://t.csdnimg.cn/0wa6h分析了rcu的基本实现原理。不过在阅读内核代码的过程中,我们经常能看到函数kfree_rcu()的使用。那么kfree究竟是怎么和rcu联系在一起的呢?
本文分析基于linux内核4.19.195
直接上代码。

/*** kfree_rcu() - kfree an object after a grace period.* @ptr:	pointer to kfree* @rcu_head:	the name of the struct rcu_head within the type of @ptr.** Many rcu callbacks functions just call kfree() on the base structure.* These functions are trivial, but their size adds up, and furthermore* when they are used in a kernel module, that module must invoke the* high-latency rcu_barrier() function at module-unload time.** The kfree_rcu() function handles this issue.  Rather than encoding a* function address in the embedded rcu_head structure, kfree_rcu() instead* encodes the offset of the rcu_head structure within the base structure.* Because the functions are not allowed in the low-order 4096 bytes of* kernel virtual memory, offsets up to 4095 bytes can be accommodated.* If the offset is larger than 4095 bytes, a compile-time error will* be generated in __kfree_rcu().  If this error is triggered, you can* either fall back to use of call_rcu() or rearrange the structure to* position the rcu_head structure into the first 4096 bytes.** Note that the allowable offset might decrease in the future, for example,* to allow something like kmem_cache_free_rcu().** The BUILD_BUG_ON check must not involve any function calls, hence the* checks are done in macros here.*/
#define kfree_rcu(ptr, rcu_head)					\__kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head))

注释写的非常清楚,kfree_rcu的作用,就是在一个gp后,将相关对象通过kfree释放掉。

/** Helper macro for kfree_rcu() to prevent argument-expansion eyestrain.*/
#define __kfree_rcu(head, offset) \do { \BUILD_BUG_ON(!__is_kfree_rcu_offset(offset)); \kfree_call_rcu(head, (rcu_callback_t)(unsigned long)(offset)); \} while (0)
/** Queue an RCU callback for lazy invocation after a grace period.* This will likely be later named something like "call_rcu_lazy()",* but this change will require some way of tagging the lazy RCU* callbacks in the list of pending callbacks. Until then, this* function may only be called from __kfree_rcu().*/
void kfree_call_rcu(struct rcu_head *head,rcu_callback_t func)
{__call_rcu(head, func, rcu_state_p, -1, 1);
}
EXPORT_SYMBOL_GPL(kfree_call_rcu);

最后还是通过__call_rcu来实现。
奇怪的是,__kfree_rcu的第二个参数,获取的是offsetof(typeof(*(ptr)), rcu_head),最后将这个值,作为rcu_callback_t类型的变量,传递给了__call_rcu。这个值显然是个偏移的量,作为callback调用的函数肯定会触发系统panic,那么内核是怎么识别并处理这个变量的呢,然后又是怎么使用kfree去将这个变量释放的呢?这里并没有看到有kfree的传入。
调用rcu callback的流程,最终会走到函数__rcu_reclaim,下面来看这个函数的实现

/** Does the specified offset indicate that the corresponding rcu_head* structure can be handled by kfree_rcu()?*/
#define __is_kfree_rcu_offset(offset) ((offset) < 4096)
/** Reclaim the specified callback, either by invoking it (non-lazy case)* or freeing it directly (lazy case).  Return true if lazy, false otherwise.*/
static inline bool __rcu_reclaim(const char *rn, struct rcu_head *head)
{unsigned long offset = (unsigned long)head->func;rcu_lock_acquire(&rcu_callback_map);if (__is_kfree_rcu_offset(offset)) {RCU_TRACE(trace_rcu_invoke_kfree_callback(rn, head, offset);)kfree((void *)head - offset);rcu_lock_release(&rcu_callback_map);return true;} else {RCU_TRACE(trace_rcu_invoke_callback(rn, head);)head->func(head);rcu_lock_release(&rcu_callback_map);return false;}
}

原来在函数__rcu_reclaim进行了处理,如果__is_kfree_rcu_offset(offset)返回true,则会调用kfree,将相关变量释放,否则,需要将这个“offset”当做一个函数指针进行调用,从而触发相关的资源回收。
那么问题来了,为什么内核要专门弄个if else来实现这个kfree_rcu,而不是在kfree_rcu中,通过传入kfree作为callback function?这样做岂不是更优雅,也能够去掉一个分支判断的损耗?
其实,内核也确实节省不了这个if else的分支判断。原因在于,rcu callback链表里面,连着的都是struct rcu_head的对象,但是kfree释放的对象的地址,无法直接等同于这个struct rcu_head的对象的地址;内核中很多结构是通过包含struct rcu_head来实现rcu相关逻辑的。所以,上述所谓的“优雅”的方法,会导致kfree无法获取到被释放对象的正确地址。从而,内核只能通过这种不优雅的方式,实现kfree_rcu。

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

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

相关文章

kubernetes集群部署:node节点部署和CRI-O运行时安装(三)

关于CRI-O Kubernetes最初使用Docker作为默认的容器运行时。然而&#xff0c;随着Kubernetes的发展和OCI标准的确立&#xff0c;社区开始寻找更专门化的解决方案&#xff0c;以减少复杂性和提高性能。CRI-O的主要目标是提供一个轻量级的容器运行时&#xff0c;它可以直接运行O…

Docker学习笔记(三)Dockerfile

一、什么是Dockerfile Dockerfile 是一个用于自动化构建 Docker 镜像的文本文件&#xff0c;其中包含了从一个基础镜像开始&#xff0c;到最终形成所需定制镜像的所有指令集。这个文件中的每一条指令都对应着构建镜像过程中的一个步骤或一层&#xff0c;指导 Docker 如何安装软…

PHP智慧门店微信小程序系统源码

&#x1f50d;【引领未来零售新风尚】&#x1f50d; &#x1f680;升级启航&#xff0c;智慧零售新篇章&#x1f680; 告别传统门店的束缚&#xff0c;智慧门店v3微信小程序携带着前沿科技与人性化设计&#xff0c;正式启航&#xff01;这个版本不仅是对过往功能的全面优化&a…

从GREE格力看如何起全球商标名称!

有些主体需要走出去出口到国外&#xff0c;普推商标知产老杨看到在一些海外电商平台的出售产品&#xff0c;也会需要英文商标&#xff0c;有的会申请申请注册中英结合商标&#xff0c;在国外申请注册也是比较方便。 格力开始想用“GLEE”(快乐)这个词作为商标名称&#xff0c;但…

【JavaWeb程序设计】JSP编程II

目录 一、输入并运行下面的import_test.jsp页面 1.1 代码运行结果 1.2 修改编码之后的运行结果 二、errorPage属性和isErrorPage属性的使用 2.1 下面的hello.jsp页面执行时将抛出一个异常&#xff0c;它指定了错误处理页面为errorHandler.jsp。 2.1.2 运行截图 2.2 下面…

医疗器械FDA | FDA如何对医疗器械网络安全认证进行审查?

FDA医械网络安全文件出具​https://link.zhihu.com/?targethttps%3A//www.wanyun.cn/Support%3Fshare%3D24315_ea8a0e47-b38d-4cd6-8ed1-9e7711a8ad5e FDA对医疗器械的网络安全认证进行审查时&#xff0c;主要关注以下几个方面&#xff0c;以确保医疗器械在网络环境中的安全性…

2 极/2 零 (2P2Z) 补偿器

极/2 零 &#xff08;2P2Z&#xff09; 补偿器是模拟 II 型控制器的数字实现。它是一种滤波器&#xff0c;通过考虑两个极点和一个零点&#xff0c;将特定的增益和相位升压引入系统。您必须战略性地选择每个极点和零点的频率位置&#xff0c;这将有助于实现所需的系统性能。在该…

团队编程:提升代码质量与知识共享的利器

目录 前言1. 什么是团队编程&#xff1f;1.1 团队编程的起源1.2 团队编程的工作流程 2. 团队编程的优势2.1 提高代码质量2.2 促进知识共享2.3 增强团队协作2.4 提高开发效率 3. 团队编程的挑战3.1 开发成本较高3.2 需要良好的团队协作3.3 个人风格和习惯的差异3.4 长时间的集中…

大数据期末复习——hadoop、hive等基础知识

一、题型分析 1、Hadoop环境搭建 2、hadoop的三大组件 HDFS&#xff1a;NameNode&#xff0c;DataNode&#xff0c;SecondaryNameNode YARN&#xff1a;ResourceManager&#xff0c;NodeManager &#xff08;Yarn的工作原理&#xff09; MapReduce&#xff1a;Map&#xff0…

七人互助拼团模式:共创共赢的电商新篇章

在当今电商行业的繁荣浪潮中&#xff0c;七人互助拼团模式犹如一股清流&#xff0c;凭借其独特的激励机制与深厚的互助合作文化&#xff0c;赢得了消费者与商家的广泛赞誉。这一模式不仅重新定义了团购体验&#xff0c;更在无形中强化了社群间的联系与协作&#xff0c;共同绘制…

中英双语介绍日本东京(Tokyo)

中文版 东京介绍 东京是日本的首都&#xff0c;也是日本的政治、经济、文化和国际交流中心。以下是对东京的详细介绍&#xff0c;包括其地理位置、人口、经济、教育、文化和主要景点。 地理位置 东京位于日本关东地区的南部&#xff0c;地理坐标大致为北纬35度41分&#xf…

C语言_练习题

求最小公倍数 思路&#xff1a;假设两个数&#xff0c;5和7&#xff0c;那么最小至少也要7吧&#xff0c;所以先假定最小公倍数是两个数之间较大的&#xff0c;然后看7能不能同时整除5和7&#xff0c;不能就加1继续除 int GetLCM(int _num1, int _num2) {int max _num1>_n…

C++11中新特性介绍-之(二)

11.自动类型推导 (1) auto类型自动推导 auto自动推导变量的类型 auto并不代表某个实际的类型&#xff0c;只是一个类型声明的占位符 auto并不是万能的在任意场景下都能推导&#xff0c;使用auto声明的变量必须进行初始化&#xff0c;以让编译器推导出它的实际类型&#xff0c;…

Python入门 2024/7/6

目录 数据容器入门 列表的定义语法 基本语法 嵌套列表 ​编辑 列表的下表索引 ​编辑 列表的常用操作 列表的常见方法 查找元素的下标 修改下标索引的值 插入元素 追加元素 追加一批元素 删除元素 删除某元素在列表中的第一个匹配项 清空列表内容 统计元素在…

2024亚太杯中文赛数学建模B题完整论文讲解(含每一问python代码+结果+可视化图)

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了2024 年第十四届 APMCM 亚太地区大学生数学建模竞赛B题洪水灾害的数据分析与预测完整的成品论文。 本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人…

web服务之Nginx

web服务之Nginx &#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Li…

将IConfiguration对象转换成一个具体的对象,以面向对象的方式来使用配置

我们倾向于将IConfiguration对象转换成一个具体的对象&#xff0c;以面向对象的方式来使用配置&#xff0c;我们将这个转换过程称为配置绑定。除了将配置树叶子节点配置节的绑定为某种标量对象外&#xff0c;我们还可以直接将一个配置节绑定为一个具有对应结构的符合对象。除此…

【音视频 | RTSP】RTSP协议详解 及 抓包例子解析(详细而不赘述)

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

华为开发者大会2024纪要:鸿蒙OS的全新篇章与AI大模型的革命

华为开发者大会2024纪要:鸿蒙OS的全新篇章与AI大模型的革命 在科技的浪潮中,华为再次引领潮流,2024年的开发者大会带来了一系列令人瞩目的创新成果。从鸿蒙操作系统的全新Beta版到盘古大模型的震撼发布,华为正以前所未有的速度重塑智能生态。以下是本次大会的亮点,让我们…

MUNIK解读ISO26262--系统架构

功能安全之系统阶段-系统架构 我们来浅析下功能安全系统阶段重要话题——“系统架构” 目录概览&#xff1a; 系统架构的作用系统架构类型系统架构层级的相关安全机制梳理 1.系统架构的作用 架构的思维包括抽象思维、分层思维、结构化思维和演化思维。通过将复杂系统分解…