Linux内核设计模式–Reference Counts, kcref

refcount_dec_and_test 简介 refcount_dec_and_test 是 Linux 内核中的一个函数,用于处理引用计数的递减和测试操作。这个函数是引用计数机制的核心组件之一,主要用于确定何时可以安全地释放资源。 阅读详情

http://www.douban.com/group/topic/7814532/

设计模式最早来源于建筑学,后被计算机科学引用。简单来说,一个设计模式描述了某类设计问题,并且针对此类问题给出了一个被实践证明有效的解决方案。

Linux内核的开发中也遇到过很多设计问题,并且针对这些问题,内核开发者给出了很好的通用解决方案,只不过长久以来没有人很好的归纳和文档化这些设计模式,导致不是每个开发者都能对这些设计模式心知肚明。

以下介绍了几种Linux内核的常用设计模式

Reference Counts
使用RC来管理一个对象的生命周期是很普遍的。RC的主要思想就是,使用一个计数器,当对象被引用时递增计数器,当引用被解除时递减计数器。当计数器的值为零时,对象所使用的各种资源可以被释放。

管理RC的机制看起来是很直接的。然而,有些微妙之处会使得这个机制产生问题。由于这个原因(当然还有其他的一些原因),Linux内核中出现了 一个数据类型”kref”以及围绕它的一些辅助函数(参考Documentation/kref.txt, <linux/kref.h>, and lib/kref.c). kref封装了一些容易引起问题的“微妙”,值得一提的是,它们还显式地告诉程序员,某个计数器是作为RC来使用的。由于命名对于设计模式来说是非常重要 的,所以在这里提供kref这样一个名字给内核开发人员来使用,会让评审者更加轻松。

Andrew Morton说:

我很希望看到一个patch时,我可以说”啊哈,它用了kref。我了解这个玩意儿,我知道它很安全而且考虑了各种出错处理。”我不希望说:”哦,该死的,这个patch居然实现了它自己的RC方式,我需要review这个实现是否有问题。”

从内核显式地支持设计模式这方面来看,引入kref,可以说即成功又不足。说成功是由于,kref非常清楚地把一种重要的设计模式具体化,并且被 很好地文档化,其使用也是高可视的。说到不足,由于kref只是包装了RC的部分情形。内核中还有一些用到RC的地方无法用kref模式来很好的解决。一 个不能提供完全功能的RC机制实际上在鼓励错误,因为大家可能会在不适用的地方使用kref并且还以为kref可以搞定。

为了理解RC的复杂性,需要先理解:一般来说,有两种截然不同的引用对象的方式。我们称之为外部引用和内部引用,在某些场合也会被称为强引用和弱引用。

我们通常想到的是外部引用。一般通过get,put来改变计数器。并且在这种模式下,一个子系统的对象可以被其他子系统的对象引用。存在一个外部引用表示:对象正在被使用。

相反的,一个内部引用一般是不会被计数的,并且只被对象所属的子系统内部持有。不同的内部引用可以有完全不同的意义以及不同的实现。

也许最常见的内部引用实例是:提供”lookup by name” 服务的高速缓存。如果你知道对象的名字,就可以在高速缓存中找到这个对象,并获得一个外部引用。这样的高速缓存中的对象是通过一个链表串起来的,而对象在 链表中的“存在”就是对象的一个内部引用。不过它并不是一个计数性质的引用。它不表示“对象正在被使用”,只表示“对象被索引以备有人想用它”。这种情况 下,只有当此对象的所有外部引用都被解除时,对象才会从链表中删除或者延迟一段时间后删除。很明显,内部引用的存在以及其特性会对RC的实现造成很大的影 响。

通过对put操作的实现可以看出不同的RC类型的区别,而get操作上是没有什么区别的。It takes an external reference and produces another external reference. get一般是如下的实现:

assert(obj->refcount > 0) ; increment(obj->refcount);

or, in Linux-kernel C:

BUG_ON(atomic_read(&obj->refcnt)) ; atomic_inc(&obj->refcnt);

注意:get必须在对象已经被至少一处引用时才能使用。一般来说对象初始化时会把RC置1.

“put”操作有三种变种。

1 atomic_dec(&obj->refcnt);

2 if (atomic_dec_and_test(&obj->refcnt)) { … do stuff … }

3 if (atomic_dec_and_lock(&obj->refcnt, &subsystem_lock)) {

….. do stuff ….

spin_unlock(&subsystem_lock);

}

The “kref” style
从中间的开始,2号变种正是kref的类型。这种类型适合在最后一个外部引用解除后就失效的对象。当RC为零时,对象需要被释放。因此需要在此用atomic_dec_and_test()来判断是否满足条件。

适合这种类型的对象不需要担心任何内部引用。sysfs中的对象就是这种类型,它大量的使用了kref。然而,如果一个使用kref类型的对象有内部引用的话,它不允许根据内部引用来创建外部引用,除非存在其他的外部引用。必要的话,可以使用如下的原语:

atomic_inc_not_zero(&obj->refcnt);

如果计数器不为零,它会递增计数器并且返回一个结果来表示是否成功。atomic_inc_not_zero() 是一个相对比较新的函数,出现在2005年的”lockless page cache work”系列patch中。因此它还没有被广泛使用,悲哀的是,kref并没有使用这个原语。

此类引用中没有使用kref,甚至没有使用atomic_dec_and_test() 的两个例子是结构体super_block中的s_count和s_active。

s_active 正好适合kref类型的RC,一个超级块从s_active置1(alloc_super()中置1)开始它的生命周期,并且当s_active变为0 时,没有新的外部引用可以再被获得。这个规则存在于grab_super()中,虽然并不是一幕了然。现在的代码由于历史原因,当s_active为非零 时,在s_count之上加了一个非常大的值(S_BIAS), grab_super() 中会判断s_count是否大于S_BIAS,而不是判断s_active是否为0。这里其实只要简单地用atomic_inc_not_zero()来 判断就可以了,而且可以避免使用spinlocks。

s_count 是另外一种引用,它既有内部的也有外部的。它是内部引用,由于它的语义要比s_active 这种计数的引用更弱。s_count 记录的引用仅仅表示”这个超级块目前还不能被释放” ,而并不声称它是活动的。它是外部引用,因为它很象一个kref,从1*S_BIAS 开始它的生命周期,当它变为0(in __put_super()),超级块就被释放。

因此这两个RC可以被替换为两个krefs, 并且:

S_BIAS 设为 1
grab_super() 使用atomic_inc_not_zero()而不是判断是否大于S_BIAS
spinlock 也可以不要了。

The “kcref” style
Linux内核并没有”kcref” ,但是它可以用来作为下一类RC的名字。”c”是”cached”的缩写,因为这类RC经常在高速缓存中使用。所以它是Kernel Cached REFerence.

kcref 象上面所说的变种-3一样,使用atomic_dec_and_lock()。因为在最后一次put时,需要释放对象或者做特殊处理。这需要在锁的保护下进行,以防止在满足释放的条件时,又有新的引用产生。

在结构体inode中有一个简单的例子i_count。以下是iput()中的一段重要代码:

if (atomic_dec_and_lock(&inode->i_count, &inode_lock))

iput_final(inode);

iput_final()中检查inode的状态并决定是销毁它呢,还是留在高速缓存中以备后用。

inode_lock用来防止基于内部引用(inode哈希表)创建新的外部引用。所以,只有在持有inode_lock时才能从内部引用创建外部引用。很正常的, iget_locked() (or iget5_locked())就是用来做这个事情的。

另外一个稍微复杂一点的例子是结构体dentry。它的d_count就类似kcref。不过它更复杂的是,在我们确保没有新的引用可被创建时, 需要用2个锁来保护,即dcache_lock和dentry->d_lock。这要求我们持有它们中的一个,然后用 atomic_dec_and_lock()来锁另外一个(prune_one_dentry());或者我们用 atomic_dec_and_lock()来持有dcache_lock,然后请求获得de->d_lock并且重新判断RC(dput())。 这是一个很好的例子,可以用来证明,你永远无法保证可以把所有的RC类型都封装起来。需要两个锁的情况是很难预计到的。

一个更复杂的kcref类型的RC是struct vfsmount.mnt_count。它复杂在两个RC直间的相互影响。首先,mnt_count很明显是一个外部引用的计数器。然 后,mnt_pinned,它是来自进程统计模块的内部引用的计数器。很特别的是它记录了有多少个统计文件被打开了。这里的复杂在于,当只有内部引用存在 时,它们将全部转化为外部引用。你可以深入研究一下细节。

The “plain” style
最后一种RC类型是只递减计数器而不做任何其他事情。这种类型在内核中比较少见。理由很简单,把一个不再被引用的对象留在原地并不是个好主意。

struct buffer_head使用了该类RC(fs/buffer.c and <linux/buffer_head.h>). 看一下这个函数put_bh():

static inline void put_bh(struct buffer_head *bh)

{

smp_mb__before_atomic_dec();

atomic_dec(&bh->b_count);

}

这样做是没有问题的,因为buffer_heads的生命周期严格地和页生命周期绑定。一个或多而buffer_heads使用同一个页。 buffer_heads们都会保留在页中,直到页被释放,到时所有的buffer_heads都会被清除(drop_buffers())

总而言之,”plain”型适用于:开发者知道总有一个内部引用保持对象不会释放,并且在某处这个内部引用会最终被用来找到和释放该对象。

反模式
设计模式是被证明有效以及应该被鼓励的方法,反模式是历史证明无效的并不被鼓励的方法。

笔者认为在RC中使用”bias”就是一个反模式的例子。在这里”bias”指在RC上加上或减去一个很大的值,而它仅仅是为了保存一个bit的 信息。我们在前面的s_count例子中就看到了bias。在那个例子中,bias仅仅指明了s_active为非零,而这完全可以直接判断。所以 bias在此完全没有价值,反而会掩盖代码的真实意图。

另外一个bias例子在struct sysfs_dirent(fs/sysfs/sysfs.h and fs/sysfs/dir.c)。有趣的是sysfs_dirent有两个refcount,就和superblocks一样,而且也叫s_count and s_active。在此,当对象被解除有效时,s_active有一个很大的负bias。这样的信息其实可以放在s_flags中。因为在flag中存储 一个bit的信息是最容易理解的。

总而言之,使用bias不能增加代码的可读性,因为它不是一个通用的模式。对于refcount来说它是一个反模式,并且必须避免。

结论
简单地使用”kref” , “kcref” ;以及 “external” , “internal”这样的术语可以很好地看出不同RC类型之间的区别。用代码来具体化它们,并且尽量使用这种封装,这对于开发人员来说,可以帮助它们更 好的选择RC的模式;对于review者来说可以更好地看清代码的原意。

本篇所介绍的设计模式:

kref: 如果当最后一个外部引用解除时,对象的生命周期就结束,那么可以使用kref。如果对象有内部引用的话,内部引用必须通过 atomic_inc_not_zero()被提升为外部引用。例如:struct super_block.s_active/s_count
kcref: 当最后一个外部引用解除时,对象的生命周期并不结束,这种情况可以使用带有atomic_dec_and_lock()的kcref。只有当持有锁时,一个内部引用才可以变为外部引用。例如:struct inode.i_count
plain: 当对象的生命周期从属于其他对象时,可以使用plain模式。非零的RC必须被当作传递给父对象的内部引用。而内部引用提升为外部引用的规则必须和其父对象的规则一致。例如:struct buffer_head.b_count
biased-reference: 当你觉得想要在RC上使用一个bias来标志一些特殊状态的时候,请不要这样做,而应该使用一个flag。

Power Automate实战:用SharePoint REST API批量处理列表数据(附JSON解析技巧) 本文深入探讨了如何利用Power Automate调用SharePoint REST API实现列表数据的批量自动化处理。文章详细解析了API的协同工作原理、高效的数据获取与筛选技巧,并重点分享了JSON数据解析的核心难点与实战解决方案,旨在帮助企业用户构建稳定可靠的数据处理流程,提升运营效率。 阅读详情

相关推荐

深入解析SGLang框架:从架构设计到核心组件实现

本文深入解析了SGLang框架的架构设计与核心组件实现。SGLang是一个专为大语言模型推理设计的高效框架,其核心优势在于清晰的分层架构、高效的调度策略以及精细的内存管理。文章详细剖析了其客户端接入、服务器端调度、模型执行引擎及Tokenizer/Detokenizer管理器等关键组件,揭示了其实现高性能推理的内部机制。

coffee的博客 576

高阶函数和函数柯里化 持续更新中...

1 函数柯里化定义 把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数 2 柯里化函数实例 function curry (fn) { return function curriedFn(...args) { console.log(1111,args) // 判断实参和形参的个数 // 如果传递参数个数小于形参的个数,返回一个函数 ...

qq_36336872的博客 433

蒙特卡洛+概率潮流!基于蒙特卡洛和新能源出力模拟的概率潮流分布程序代码!

最后,导出光照强度、风速、网损和节点电压的概率分布图,并计算了各节点电压和网损的平均值和方差,展示了接入前后的节点电压对比图。在不确定性增加的电力系统中,概率潮流成为含随机因素规划问题的求解前提,可以更加真实地反映电力系统的全面信息。此外,概率潮流还可用于研究风电和光伏发电出力以及电动汽车消耗功率和向电力系统反向供电功率的不确定性对电力系统的影响,发现系统运行中的潜在风险,为系统运行控制提供参考。概率潮流的目的是揭示电网中随机变量对系统的影响,发现电网中的薄弱环节,为规划和调度部门的决策提供有价值的信息。

weixin_48747334的博客 1918

linux内核中用到的设计模式,Linux内核设计模式–Reference Counts

这是翻译版,英文原址:========设计模式最早来源于建筑学,后被计算机科学引用。简单来说,一个设计模式描述了某类设计问题,并且针对此类问题给出了一个被实践证明有效的解决方案。Linux内核的开发中也遇到过很多设计问题,并且针对这些问题,内核开发者给出了很好的通用解决方案,只不过长久以来没有人很好的归纳和文档化这些设计模式,导致不是每个开发者都能对这些设计模式心知肚明。以下介绍了几种Linux内...

weixin_39928017的博客 333

无人自行车平衡控制:最小二乘法动态零点拟合实践

本文探讨了无人自行车平衡控制中动态零点的重要性及实现方法。通过最小二乘法拟合车头角度与ROL值的线性关系,解决了固定零点在转向时导致的稳定性问题。实践表明,动态零点拟合能显著提升系统平衡稳定性并降低能耗。

uran的专栏 660

Fast-LIO2轮速计融合实战:打滑检测与协方差调参避坑指南

多传感器融合是提升移动机器人定位鲁棒性的关键手段。在激光雷达与惯性测量单元(IMU)紧耦合的基础上,加入轮式编码器作为额外的速度约束,能够有效抑制长走廊、重复纹理等退化场景下的漂移。其核心原理是通过运动学模型将轮速转换为机体系速度,并作为因子引入迭代误差状态卡尔曼滤波器(ESIKF)。然而,打滑现象与协方差参数设置是融合成败的关键。本文从工程实践出发,系统梳理了传感器配置、外参标定、打滑检测策略(运动学一致性、轮速自洽性)以及观测噪声协方差R与初始协方差P0的调参方法,并给出实测参数与问题排查速查表,为在F

weixin_34159110的博客 433

深入理解Linux文件系统之文件系统挂载(下)

接着:深入理解Linux文件系统之文件系统挂载(上)本文为文件系统挂载专题文章的第二篇,主要介绍如何通过挂载实例关联挂载点和超级块并添加到全局文件系统树。4. 添加到全局文件系统树4.1 ...

宋宝华 1999

机器学习入门基础 | 基于python的高光谱图像特征挖掘:PCA + 形态学属性处理可视化实战

本文介绍了一种基于PCA和形态学操作的高光谱图像特征提取方法。通过主成分分析降低数据维度,再运用面积开闭操作增强空间结构特征,有效去除噪声并填补孔洞。实验采用WHU-HI-HanChuan数据集,提供完整的Python实现代码,包括数据加载、PCA降维、形态学处理及结果可视化等步骤。该方法能够显著改善图像质量,为后续分类和变化检测任务提供更好的特征输入。实验结果表明,不同阈值的形态学处理能呈现不同程度的空间结构增强效果,对区域生长、分割和聚类等应用具有重要价值。

lestatlu的博客 1045

linux的虚拟文件系统三(文件I/O之open流程)

到目前为止,文章主要都是从理论上来讲述VFS的运行机制;接下来我们将深入源代码层中,通过阐述两个具有代表性的系统 调用sys_open()和sys_read()来更好地理解VFS向具体文件系统提供的接口机制。由于本文更关注的是文件操作的整个流程体制,所以我 们在追踪源代码时,对一些细节性的处理不予关心。又由于篇幅所限,只列出相关代码。本文中的源代码来自于linux-4.9.92内核版本。 在深入...

To_run_away的博客 2174

一步一步详解LSTM网络【从RNN到LSTM到GRU等,直至attention】

本文主要译至并加上了部分笔者的见解,对于全面理解LSTM有一定的帮助。

zik的博客 3078

YOLO26涨点改进 | 全网独家首发 主干改进篇 | TGRS 2025 | RepViT-TD,告别庞大骨干!YOLO26 + RepViT-TD轻量又强大,实现更快更准的小目标检测!

本文提出将RepViT-TD轻量级主干网络应用于YOLO26目标检测框架,以提升小目标检测性能。RepViT-TD通过优化计算资源分配,强化前两层高分辨率特征提取能力,在保持轻量化的同时(仅4.85M参数)显著提升微小目标的检测精度(AI-TODv2数据集AP50达54.6%)。文章详细介绍了三种主干改进方案(RepVit_ldy1/2/3)的代码实现,并提供了完整的YAML配置文件修改指南,使模型能高效部署于边缘设备。实验表明,该方法在计算复杂度(38.19G FLOPs)和检测精度间取得了良好平衡。

Ai缝合怪、助力小伙伴高效发论文 328

文件系统专题之 “索引节点高速缓存”

VFS也用了一个高速缓存来加快对索引节点的访问,和块高速缓存不同的一点是每个缓冲区不用再分为两个部分了,因为inode结构中已经有了类似于块高速缓存中缓冲区首部的域。索引节点高速缓存的实现代码全部在fs/inode.c,这部分代码并没有随着内核版本的变化做很多的修改。 1.索引节点链表 每个索引节点可能处于哈希表中,也可能同时处于下列“类型”链表的一种中: ·

河西无名式 1505

LVGL colorwheel组件教程一(调色板)

【代码】LVGL colorwheel组件教程一(调色板)

摸鱼专家 429

linux内存一致性,Linux内核 文件一致性之主动一致性

与内核中很多其他函数一样,该函数是典型的三段式。首先检查参数等信息,然后调用filemap_write_and_wait_range()同步文件脏数据。等文件脏数据写入完成以后,调用具体文件系统的fsync方法,该方法主要是回写文件元数据,即inode信息。在此之前,需要对inode加锁,即mutex_lock。点击(此处)折叠或打开int filemap_write_and_wait_range...

weixin_35615010的博客 882

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Linux kernel 引用计数kref

引用计数-kref 1、 前言 众所周知,C/C++语言本身并不支持垃圾回收机制,虽然语言本身具有极高的灵活性,但是当遇到大型的项目时,繁琐的内存管理往往让人痛苦异常。现代的C/C++类库一般会提供智能指针来作为内存管理的折中方案,比如STL的auto_ptr,Boost的Smart_ptr库,QT的QPointer家族,甚至是基于C语言构建的GTK+也通过引用计数来实现类似的功能。Linux内核是如何解决这个问题呢?同样作为C语言的解决方案,Linux内核采用的也是引用计数的方式。如果您更熟悉C++,可以

carlos博客 1297

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

linux 内核 assert,Linux 内核设计模式(一)

原标题:Linux 内核设计模式(一)在内核社区中,讨论热度持续高涨的话题之一就是保持质量。非常明显的是:我们需要保持、甚至提高质量,不太明显的是:如何最佳实现这一目标。一个广泛使用的方法已经真正成功实现了这个目标,该方法增加了内核各种方面的可见性,这使得那些方面的质量更加明显,所以这往往会带来质量的提升。这种可见性的增加可以有许多形式:checkpatch.pl脚本强调了许多来自公认代码格式化样...

weixin_29168675的博客 535

Linux内核(linux-5.2.9)--内核对象(对象的引用计数)

一个分配好的内存对象可能会在多种场景中被多次传递并使用,在这种情况下,为了能够正确的使用内存对象,引入了“引用计数”功能。 防止内存泄漏:确保已分配的对象最终都会被正确释放; 防止访问已释放的内存:确保不会使用已经被释放的对象。 数据结构 kref 为任何内存数据结构添加引用计数提供了一种简单但有效的方法。Kref相关的定义如下: struct kre...

其疾如风 其徐如林 侵略如火 不动如山 3897

Linux 内核编程第二部分(四)

最后但同样重要的是,让我们简要讨论另一个问题 -内存屏障。这是什么意思?有时,程序流对人类程序员来说变得不可知,因为微处理器、内存控制器和编译器可以重新排序内存读取和写入。在大多数情况下,这些“技巧”保持良性并且被优化。但是有些情况 - 通常跨硬件边界,例如多核系统上的 CPU 核心、CPU 到外围设备,以及反之亦然的UP) - 在这些情况下,这种重新排序不应该发生;必须遵守原始和预期的内存加载和存储顺序。内存屏障(通常是嵌入在*mb*()宏中的机器级指令)是一种抑制这种重新排序的方法;

龙哥盟 1921

Linux 内核编程(六)

最后但同样重要的是,让我们简要讨论另一个问题 -内存屏障。这是什么意思?有时,程序流程对人类程序员来说变得不可知,因为微处理器、内存控制器和编译器可能重新排序内存读取和写入。在大多数情况下,这些“技巧”保持良性并且被优化。但是有些情况 - 通常跨硬件边界,例如多核系统上的 CPU 核心、CPU 到外围设备,以及反之亦然的UP) - 在这些情况下,不应该发生重新排序;必须遵守原始和预期的内存加载和存储顺序。内存屏障(通常是嵌入在*mb*()宏中的机器级指令)是一种抑制这种重新排序的方法;

龙哥盟 1905

Linux内核对象引用计数和生命周期管理

int value;int pad;if(!data)2.如果对对象的引用不是临时的(pointer is not temporary),特别是对象会以指针引用的形式传递到异步上下文(另一个被处理器调度的独立线程),必须在传递这个指针引用之前,增加对对象的引用计数。调用kref_get增加引用计数前,如果上下文已经持有了一个引用计数,则kref_get过程不需要锁保护。

tugouxp的专栏 1329

【inode】Linux服务器inode索引节点用满原因以及解决方法

系统出现异常 我们团队的阿里云服务器在前几天运行过程中,服务器CPU负载长时间达到100%,并且不能通过ssh连接服务器。 经过重启服务器后对服务器进行连接,发现 服务器上的crontab不能正常运行 php-fpm服务不能正常开启 crontab的报错提示为 正在启动 crond:crond: can’t open ...

weixin_34162401的博客 1049

babyos2(26)fs(4), lock

之前为了简化问题,兼之之前没有实现semaphore,文件系统的操作未加锁。上次为了实现读取硬盘时睡眠等待,实现了一个sem类,所以为babyos2文件系统加锁的时机已经成熟。 主要用类三个锁: 1.inode table的锁 2.file table的锁 3.inode的锁。 前面两个比较简单,占用锁时间不会太长,用的自选锁,inode可能持有锁时间比较长,所以用的semaphore。...

孤舟钓客 395

Linux 文件锁与 inode

1. 进程 A 排他锁住某文件之后,进程 B 可以修改该文件,但不能锁住该文件。 2. 进程 A 排他锁住某文件之后,进程 B 修改该文件之后,因为文件 inode 没有改变,所以依然不能锁住该文件。 3. 进程 A 排他锁住某文件之后,进程 B 可以删除该文件,并创建同名文件,此时进程 B 可以锁住该文件。 由于 vi, sed 等程序修改文件会改变文件 inode, 所以会导致被 A 进

码农 1984

inode节点hash处理

static struct hlist_head *inode_hashtable __read_mostly; /*  * Initialize the waitqueues and inode hash table.  */ void __init inode_init_early(void) { unsigned int loop; /* If hashes a

星空探索 897

ocfs2_inode_lock_full_nested()

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33851177的博客 247
上一篇: 关于热插拔usb hotplug /proc/sys/kernel mdev udev busybox
下一篇: Linux USB驱动框架分析
#Page#
博客等级 码龄23年 1691粉丝 360原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值