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