ubi 下ubi_ltree_entry获取与初始化过程

本文深入探讨了Ubi系统中读写锁的实现原理,包括加锁函数、结构体定义以及初始化过程。重点分析了如何通过rw_semaphore在实际锁定volume时完成锁的获取与释放。

在ubi中,每次写读一个volume是,都会对当期的这个volume进加锁。用到的就是rw_semaphore。关于读写锁可以查看一下网上别人写的东西。


获取这个锁的函数(这里我主要以write为例来说明)是:

/**
 * leb_write_lock - lock logical eraseblock for writing.
 * @ubi: UBI device description object
 * @vol_id: volume ID
 * @lnum: logical eraseblock number
 *
 * This function locks a logical eraseblock for writing. Returns zero in case
 * of success and a negative error code in case of failure.
 */
static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum)
{
	<span style="color:#CC0000;">struct ubi_ltree_entry *le;</span>//我们看到在这里,是定义了这样的一个结构体指针。

	le = ltree_add_entry(ubi, vol_id, lnum);//在这个函数里会进行对mutex的初始化操作。
	if (IS_ERR(le))
		return PTR_ERR(le);
	down_write(&le->mutex);//获取这个锁。
	return 0;
}

/**
 * struct ubi_ltree_entry - an entry in the lock tree.
 * @rb: links RB-tree nodes
 * @vol_id: volume ID of the locked logical eraseblock
 * @lnum: locked logical eraseblock number
 * @users: how many tasks are using this logical eraseblock or wait for it
 * @mutex: read/write mutex to implement read/write access serialization to
 *         the (@vol_id, @lnum) logical eraseblock
 *
 * This data structure is used in the EBA sub-system to implement per-LEB
 * locking. When a logical eraseblock is being locked - corresponding
 * &struct ubi_ltree_entry object is inserted to the lock tree (@ubi->ltree).
 * See EBA sub-system for details.  //从这段话可以看出,在lock这个volume时,才把这样的一个结构体insert到lock tree.
 */
struct ubi_ltree_entry {
	struct rb_node rb;
	int vol_id;//对应的volume id 
	int lnum;//这个锁对应的lnum
	int users;
	struct rw_semaphore mutex;
};
/*
 * the rw-semaphore definition
 * -<span style="color:#FF0000;"> if count is 0 then there are no active readers or writers</span>
 * - if count is +ve then that is the number of active readers
 * <span style="color:#CC0000;">- if count is -1 then there is one active writer</span>
 * - if wait_list is not empty, then there are processes waiting for the semaphore
 */
struct rw_semaphore {
	__s32			count;//在ubi中,通过debug,这个值,在初始时完后是0。同时在获取一次后是-1.
	raw_spinlock_t		wait_lock;
	struct list_head	wait_list;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
	struct lockdep_map dep_map;
#endif
};

通过上面的代码,其实主要的初始化不是在attach的时候,而是在你真正要lock这个volume的时候。



/**
 * ltree_add_entry - add new entry to the lock tree.
 * @ubi: UBI device description object
 * @vol_id: volume ID
 * @lnum: logical eraseblock number
 *
 * This function adds new entry for logical eraseblock (@vol_id, @lnum) to the
 * lock tree. If such entry is already there, its usage counter is increased.
 * Returns pointer to the lock tree entry or %-ENOMEM if memory allocation
 * failed.
 */
static struct ubi_ltree_entry *ltree_add_entry(struct ubi_device *ubi,
					       int vol_id, int lnum)
{
	struct ubi_ltree_entry *le, *le1, *le_free;

	le = kmalloc(sizeof(struct ubi_ltree_entry), GFP_NOFS);
	if (!le)
		return ERR_PTR(-ENOMEM);

	le->users = 0;
	init_rwsem(&le->mutex);//调用这个函数对rw mutex进行初始化。
	le->vol_id = vol_id;
	le->lnum = lnum;

	spin_lock(&ubi->ltree_lock);
	le1 = ltree_lookup(ubi, vol_id, lnum);  //查看这个对应 volume id 和lnum的mutex有没有已经被锁住。

	if (le1) {
		/*
		 * This logical eraseblock is already locked. The newly
		 * allocated lock entry is not needed.
		 */
		le_free = le;
		le = le1;
	} else {  //下面的操作就不用看了,就是把这个锁加入到lock tree中去。
        struct rb_node **p, *parent = NULL;

        /*
         * No lock entry, add the newly allocated one to the
         * @ubi->ltree RB-tree.
         */
        le_free = NULL;

        p = &ubi->ltree.rb_node;
        while (*p) {
            parent = *p;
            le1 = rb_entry(parent, struct ubi_ltree_entry, rb);

            if (vol_id < le1->vol_id)
                p = &(*p)->rb_left;
            else if (vol_id > le1->vol_id)
                p = &(*p)->rb_right;
            else {
                ubi_assert(lnum != le1->lnum);
                if (lnum < le1->lnum)
                    p = &(*p)->rb_left;
                else
                    p = &(*p)->rb_right;
            }
        }

        rb_link_node(&le->rb, parent, p);
        rb_insert_color(&le->rb, &ubi->ltree);
    }
    le->users += 1;
    spin_unlock(&ubi->ltree_lock);

    kfree(le_free);
    return le;
}





<think> 嗯,用户这次询问的是UBI子系统中的bad_peb_limit参数,看起来是在研究Flash存储管理技术。从用户能精准提出这个内核参数来看,应该是嵌入式系统开发者或文件系统研究人员,可能正在调试MTD/NAND相关驱动。 注意到用户引用了两篇中文技术笔记,但真正需要的是bad_peb_limit的官方解释。这个参数在UBI文档里有明确定义,需要结合MTD坏块管理机制来说明。用户上次没有提问历史,可能是首次接触UBI。 bad_peb_limit本质是UBI的容错阈值参数,控制着当物理擦除块(PEB)出现坏块时的处理策略。关键点在于: 1) 它是最大允许坏块比例的上限值 2) 触发后会停止擦除块分配 3) 需要区分出厂坏块和运行时坏块 特别要注意它和ubi->max_beb_per1024的关系,后者是出厂坏块预留值——这两个参数共同构成了UBI的双重坏块防护机制。 用户可能真正关心的是如何合理配置这个参数。应该强调默认值128的百分比含义(12.5%),以及实际调整时需要考虑Flash芯片的标称坏块率。之前引用的资料[^2]提到dirty block回收机制,这和bad_peb_limit存在间接关联:当坏块过多导致可用块不足时,GC回收效率会急剧下降。 需要提醒参数设置陷阱:设置过高可能导致突发坏块超出物理限制,设置过低又可能过早拒绝正常服务。这个平衡点在汽车电子等严苛环境中尤为重要。可惜用户没说明具体应用场景,否则可以给出更针对性建议。 </think> 根据 UBI 子系统的设计逻辑,`ubi->bad_peb_limit` 是一个关键阈值参数,其含义和相关技术信息如下: --- ### **含义** `ubi->bad_peb_limit` 定义了 **UBI 允许的最大坏块(Bad PEB)数量上限**。当检测到的坏块数量超过此阈值时,UBI 会停止分配新的物理擦除块(PEB),并可能触发以下行为: 1. **停止卷操作**:标记卷为只读或失效状态 2. **拒绝新写请求**:防止数据写入不可靠的存储区域 3. **发出系统警报**:通知管理层需干预或更换存储设备 --- ### **作用机制** 1. **坏块计数** UBI 在运行时动态跟踪两类坏块: - **出厂坏块(Factory-bad PEBs)**:芯片出厂时标记的坏块 - **运行时坏块(Run-time bad PEBs)**:擦除/写入失败产生的新坏块 两者的总和受 `bad_peb_limit` 约束。 2. **阈值触发逻辑** 当满足以下条件时触发保护机制: $$ \text{total\_bad\_pebs} \geq \text{ubi->bad\_peb\_limit} $$ 此时 UBI 主动拒绝进一步分配 PEB,避免数据损坏[^1]。 3. **预留块的关系** UBI 初始化时会预留部分 PEB(通过 `ubi->beb_rsvd_pebs` 配置),用于替换坏块。但若坏块增长过快导致 `bad_peb_limit` 被突破,预留机制将失效[^2]。 --- ### **技术细节** - **默认值设定**:通常为 `max_beb_per1024` 参数的 1/2(例如若 `max_beb_per1024=40`,则 `bad_peb_limit ≈ 总PEB数 × 2%`) - **动态调整**:可通过内核模块参数或 sysfs 接口在运行时修改 - **关联参数**: - `max_beb_per1024`:控制出厂坏块预留比例 - `ubi->avail_pebs`:实时可用块数,当 `avail_pebs < min_io_size` 时触发空间不足警告 --- ### **应用场景** 1. **高可靠性系统**:在工业设备中降低阈值,提前预警存储介质老化 2. **损耗均衡优化**:结合 `wear_leveling_threshold` 共同延长 Flash 寿命 3. **故障诊断**:快速定位因坏块超限导致的卷挂载失败问题 > 示例代码(UBI 坏块检查逻辑片段): > ```c > if (ubi->bad_peb_count >= ubi->bad_peb_limit) { > ubi_warn("Bad PEB limit (%d) reached", ubi->bad_peb_limit); > ubi_ro_mode(ubi); // 切换到只读模式 > } > ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值