在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;
}