Linux驱动适配内核时,对于不同版本内核中有变化函数的处理

news/2024/4/15 4:26:57/文章来源:https://blog.csdn.net/tmaccs/article/details/136567093

一、情景

Linux驱动适配不同内核时,由于内核版本的不同,有些函数可能没有,或者函数直接变化了,高版本可能增加了一些参数。

二、常规处理方案,根据内核版本判断

一般情况我们处理方式是在使用这些函数时,通过宏来判断当前的内核版本,根据版本来决定怎么使用函数,比如:

#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0)generic_fillattr(inode, stat);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5,12,0) && LINUX_VERSION_CODE < KERNEL_VERSION(6,3,0)generic_fillattr(mnt_userns, inode, stat);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(6,3,0) && LINUX_VERSION_CODE < KERNEL_VERSION(6,6,0)generic_fillattr(idmap, inode, stat);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(6,6,0)generic_fillattr(idmap,request_mask,inode, stat);
#endif

这种我们需要准确知道generic_fillattr这个函数在哪个内核版本怎么变化了。但是Linux的内核有那么多,要找到从哪个版本开始变化了,很多时候是个巨大的工作量。

三、以vfs_getattr函数为例,介绍推荐的处理方案,编译时测试并决定

Linux的驱动适配,我们都需要在对应适配的内核中去编译一次,基于这个原理,我们可以在编译时,通过测试脚本,来确定使用的函数在当前内核中是否存在,以及是怎么样的形式。

不同内核版本的vfs_getattr

低版本内核中,接受三个参数:

int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
{struct inode *inode = dentry->d_inode;int retval;retval = security_inode_getattr(mnt, dentry);if (retval)return retval;if (inode->i_op->getattr)return inode->i_op->getattr(mnt, dentry, stat);generic_fillattr(inode, stat);return 0;
}

高一点的版本中,mnt和dentry参数直接变成了path结构体,而只接受2个参数:

int vfs_getattr(struct path *path, struct kstat *stat)
{struct inode *inode = path->dentry->d_inode;int retval;retval = security_inode_getattr(path->mnt, path->dentry);if (retval)return retval;if (inode->i_op->getattr)return inode->i_op->getattr(path->mnt, path->dentry, stat);generic_fillattr(inode, stat);return 0;
}

更高的版本中,多传入了2个参数,提供了额外的功能,允许调用者对文件属性获取操作进行更细粒度的控制,
request_mask:用于指定要获取的文件属性的掩码,即希望获取哪些属性的位掩码。
query_flags:用于指定其他查询标志,例如是否忽略安全性检查等。

int vfs_getattr(const struct path *path, struct kstat *stat,u32 request_mask, unsigned int query_flags)
{int retval;retval = security_inode_getattr(path);if (retval)return retval;return vfs_getattr_nosec(path, stat, request_mask, query_flags);
}
测试脚本

我们创建一个名为generate-kernel-function的脚本,包括以下函数:

通用函数:
prefix="KERNEL_API_"while [ "${1:0:1}" = "-" ] ; docase "$1" in-t)shifttmpdir=$1;;-o)shiftoutfile=$1;;esacshift
donerun() {( $@ || return 1 ) >/dev/null 2>&1
}do_test() {local var="$1"local val="$2"[ -n "$var" ]var="${prefix}$var"local src="$tmp_dir/test.c"local obj="$tmp_dir/test.o"cat > "$src"if ( run gcc -o "$obj" -c "$src" ) ; thenout "#define $var ${val:-1}"elif [ -z "$val" ] ; thenout "#undef $var"elseout "// not $var $val"fi
}

do_test 这个函数接受两个参数:

$1:变量名,用于指定要测试的条件。
$2:值,用于指定测试条件的预期值。
函数首先将这两个参数保存到本地变量 var 和 val 中。然后,它检查是否提供了变量名 $var,并在必要时添加前缀。接着,它定义了两个本地变量 src 和 obj,用于指定测试代码的源文件和目标文件的路径。
接下来,函数使用 cat 命令将标准输入中的内容输出到文件 $src 中,以生成测试代码。
接着,函数调用 c_run 函数编译源文件 $src 并生成目标文件 $obj。如果编译成功,则输出 #define $var ${val:-1},其中 ${val:-1} 表示如果 $val 未定义,则使用默认值 1。如果编译失败且 $val 未定义,则输出 #undef $var,表示未定义该变量。否则,输出 // not $var $val,表示未达到预期值。

测试函数:
do_test "VFS_GETATTR_ARGS" 2 <<END
#include <linux/fs.h>
int test(struct path path, struct kstat exec_file_stat, u32 request_mask, unsigned int query_flags) {return vfs_getattr(&path, &exec_file_stat);
}
ENDdo_test "VFS_GETATTR_ARGS" 3 <<END
#include <linux/fs.h>
int test(struct vfsmount *path, struct dentry *dentry, struct kstat exec_file_stat) {return vfs_getattr(path, dentry, &exec_file_stat);
}
ENDdo_test "VFS_GETATTR_ARGS" 4 <<END
#include <linux/fs.h>
int test(struct path path, struct kstat exec_file_stat, u32 request_mask, unsigned int query_flags) {return vfs_getattr(&path, &exec_file_stat, 0, 0);
}
END
编译脚本中调用,和实际的使用

在编译的Makefile文件中,我们可以通过:

generate-kernel-function -t `pwd`/tmp -o kernel-function.h

调用测试函数,并根据测试的结果生成宏,并输出到的一个头文件中,而在实际使用vfs_getattr函数的地方,我们通过判断哪个宏存在,就可以正确的调用对应的函数:

#if (2 == KERNEL_API_VFS_GETATTR_ARGS)
#define our_vfs_getattr(path, exec_file_stat) vfs_getattr(path, exec_file_stat)
#elif (3 == KERNEL_API_VFS_GETATTR_ARGS)
#define our_vfs_getattr(path, exec_file_stat) vfs_getattr((path)->mnt, (path)->dentry, exec_file_stat)
#elif (4 == KERNEL_API_VFS_GETATTR_ARGS)
#define our_vfs_getattr(path, exec_file_stat) vfs_getattr(path, exec_file_stat, 0, 0)
#else
#error The number of arguments to vfs_getattr is neither 2 nor 3 nor 4
#endifstatic int get_exec_eigenvalue(const char* exe_path, uint64_t* eigenvalue) {struct kstat exec_file_stat;our_nameidata_t nd;if (our_nd_from_name(exe_path, 0, &nd) == 0) {if (our_vfs_getattr(&(nd.path), &exec_file_stat)) {
}

四、是否有某个函数测试的例子

测试函数
do_test "HAVE_PATH_LOOKUP" <<END
#include <linux/fs.h>
#include <linux/namei.h>
void test(const char *path) {struct nameidata nd;path_lookup(path, LOOKUP_FOLLOW, &nd);
}
END
c代码中使用
#ifdef KERNEL_API_HAVE_PATH_LOOKUPrc = path_lookup(mnt, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd);
#elserc = kern_path(mnt, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &(nd.path));
#endif

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

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

相关文章

支持向量机 SVM | 线性可分:软间隔模型

目录 一. 软间隔模型1. 松弛因子的解释小节 2. SVM软间隔模型总结 线性可分SVM中&#xff0c;若想找到分类的超平面&#xff0c;数据必须是线性可分的&#xff1b;但在实际情况中&#xff0c;线性数据集存在少量的异常点&#xff0c;导致SVM无法对数据集线性划分 也就是说&…

看一看阿里云,如何把抽象云概念,用可视化表达出来。

云数据库RDS_关系型数据库 云数据库RDS_关系型数据库 专有宿主机 云数据库RDS_关系型数据库_MySQL源码优化版 内容协作平台CCP-企业网盘协同办公-文件实时共享

数据结构从入门到精通——栈

栈 前言一、栈1.1栈的概念及结构1.2栈的实现1.3栈的面试题 二、栈的具体实现代码栈的初始化栈的销毁入栈出栈返回栈顶元素返回栈中的元素个数检测是否为空Stack.hStack.ctest.c 前言 栈&#xff0c;作为一种后进先出&#xff08;LIFO&#xff09;的数据结构&#xff0c;在计算…

2.DOM-事件基础(注册事件、tab栏切换)(案例:注册、轮播图)

案例 注册事件 <!-- //disabled默认情况用户不能点击 --><input type"button" value"我已阅读用户协议(5)" disabled><script>// 分析&#xff1a;// 1.修改标签中的文字内容// 2.定时器// 3.修改标签的disabled属性// 4.清除定时器// …

3d合并的模型为什么没有模型---模大狮模型网

当合并多个3D模型后&#xff0c;发现合并后的模型没有显示任何内容或模型消失的情况通常有以下几个可能的原因&#xff1a; 蒙皮和骨骼绑定问题&#xff1a;如果合并的模型包含了蒙皮和骨骼动画&#xff0c;并且在合并过程中未正确处理这些信息&#xff0c;可能导致模型显示不出…

华为配置基于VLAN限速示例

华为配置基于VLAN限速示例 组网图形 图1 流量监管配置组网图 表1 Switch为上行流量提供的QoS保障 流量类型 CIR(kbps) PIR(kbps) DSCP优先级 语音 2000 10000 46 视频 4000 10000 30 数据 4000 10000 14 ^^^ 流分类简介配置注意事项组网需求配置思路操作步…

Linux服务器安装jdk

背景: 安装JDK是我们java程序在服务器运行的必要条件,下面描述几个简单的命令就可再服务器上成功安装jdk 命令总览: yum update -y yum list | grep jdk yum -y install java-1.8.0-openjdk java -version 1.查看可安装版本 yum list | grep jdk 2.如果查不到可先进行 yum upd…

手写分布式配置中心(三)增加实时刷新功能(短轮询)

要实现配置自动实时刷新&#xff0c;需要改造之前的代码。代码在https://gitee.com/summer-cat001/config-center​​​​​​​ 服务端改造 服务端增加一个版本号version&#xff0c;新增配置的时候为1&#xff0c;每次更新配置就加1。 Overridepublic long insertConfigDO(…

ArcGIS学习(十)城市用地对比分析

ArcGIS学习(十)城市用地对比分析 1.城市用地变更分析 本任务给大家带来的内容是城市用地对比分析,包括两个关卡:城市用地变更分析 用地规划方案实施评价 城市用地变更分析和用地规划方案实施评价是我们进行用地分析时常见的两种场景。其中:城市用地变更分析主要是对不同…

访问修饰符、Object(方法,使用、equals)、查看equals底层、final--学习JavaEE的day15

day15 一、访问修饰符 含义&#xff1a; 修饰类、方法、属性&#xff0c;定义使用的范围 理解&#xff1a;给类、方法、属性定义访问权限的关键字 注意&#xff1a; ​ 1.修饰类只能使用public和默认的访问权限 ​ 2.修饰方法和属性可以使用所有的访问权限 访问修饰符本类本包…

H5小游戏,斗地主

H5小游戏源码、JS开发网页小游戏开源源码大合集。无需运行环境,解压后浏览器直接打开。有需要的,私信本人,发演示地址,可以后再订阅,发源码,含60+小游戏源码。如五子棋、象棋、植物大战僵尸、开心消消乐、扑鱼达人、飞机大战等等 <!DOCTYPE html> <html> <…

BERT学习【BERT的例子以及作用】

一、case 1.case1 多输入单输出。通过输入一个句子&#xff08;sequence&#xff09;&#xff0c;然后输出一个句子的分类&#xff08;这个句子是正向还是负向&#xff09;。将句子输入BERT&#xff0c;然后通过softmax输出分类。 2.case2 多输入多输出。输入一个句子&…

评测本地部署的语音识别模型

1 引言 最近&#xff0c;朋友给我发来了一段音频&#xff0c;想转录成文字&#xff0c;并使用大型润色文本。音频中的普通话带有一定的口音&#xff0c;并且讲解内容较为专业&#xff0c;所以一般的语音识别工具很难达到较高的识别率。 于是试用了两个大模型。Whisper 是目前…

ai脚本创作的软件有哪些?分享3款好用的工具!

随着人工智能技术的飞速发展&#xff0c;AI脚本创作软件已经成为内容创作者们的新宠。这些软件不仅能够帮助我们更高效地生成文章、视频脚本等&#xff0c;还能为我们提供独特的创意视角和无限的灵感。本文将带您深入了解几款备受瞩目的AI脚本创作软件&#xff0c;看看它们如何…

Truenas入门级教程

Truenas入门教程 前言&#xff1a;系统相关配置 采用I3 4160&#xff0c;采用了2块500G的硬盘&#xff0c;内存为8G&#xff0c;两个网卡只用了其中一个&#xff0c;系统安装的是core版本 硬件采用DELL3020MT机箱&#xff0c;自带3个SATA网口&#xff0c;后期网口不够&#…

C++:Stack和Queue的模拟实现

创作不易&#xff0c;感谢三连&#xff01; 一、容器适配器 适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结)&#xff0c;该种模式是将一个类的接口转换成客户希望的另外一个接口。 就如同是电源适配器将不适用的交流电…

Java中的List

List集合的特有方法 方法介绍 方法名描述void add(int index,E element)在此集合中的指定位置插入指定的元素E remove(int index)删除指定索引处的元素&#xff0c;返回被删除的元素E set(int index,E element)修改指定索引处的元素&#xff0c;返回被修改的元素E get(int inde…

正则表达式-分组

1、oracle-正则表达式&#xff1a;将09/29/2008 用正则表达式转换成2008-09-29 select regexp_replace(09/29/2008, ^([0-9]{2})/([0-9]{2})/([0-9]{4})$, \3-\1-\2) replace from dual; 解析&#xff1a;regexp_replace-替换&#xff0c; 第一个参数&#xff1a;需要进行处…

《TCP/IP详解 卷一》第13章 TCP连接管理

目录 13.1 引言 13.2 TCP连接的建立与终止 13.2.1 TCP半关闭 13.2.2 同时打开与关闭 13.2.3 初始序列号 13.2.4 例子 13.2.5 连接建立超时 13.2.6 连接与转换器 13.3 TCP 选项 13.3.1 最大段大小选项 13.3.2 选择确认选项 13.3.3 窗口缩放选项 13.3.4 时间戳选项与…

DCFL: for Oriented Tiny Object Detection

文章目录 AbstractIntroductionContributionRelated Work定向目标检测微小目标检测多尺度学习标签分配上下文信息特征增强MethodOverview动态先验Coarse Prior MatchingFiner Dynamic Posterior MatchingAblation StudyAnalysis不平衡问题的调解可视化速度Conclusionhh 源代码 …