1 block 里面的sem本质上是一个队列,是对action的排队 目前来说, action包括(io, unmap, remap, merge) 2 block 里面为什么一定要一把状态的锁, 因为在某些流程处理中, {检测状态 = >做相应操作} 后面的相应操作必须要依赖前面的状态。 如果不用状态锁的话, 其它上下文可能会改变该状态,从而使后面的操作没有意义。 3 put_block中为什么用atomic_dec_and_block。这是为了将{ref_cnt等于0, 拿树的锁}做成一个原子的事务。即: 拿树的锁是基于ref_cnt为0的情况。 这里可以对比理解一下: 引用计数可以使用原子变量, 而状态需要加锁(而不用原子变量)。 因为引用计数通过atomic_dec_and_block保证{检测, 操作}是放在一个原子操作中的。 |
struct block *search_and_get_block(struct sd *sd, sector_t blk) { struct block_block *block = NULL; find: read_lock_irqsave(&sd->tree_lock, flag); if ((block = radix_tree_lookup(&sd->active_blocks_tree, blk))) { get_block(block); read_unlock_irqrestore(&sd->tree_lock, flag); goto out; } read_unlock_irqrestore(&sd->tree_lock, flag); block = alloc_and_init_block(sd, blk); write_lock_irqsave(&sd->tree_lock, flag); ret = radix_tree_insert(&sd->active_blocks_tree, blk, block); if (ret == -EEXIST) { /* other ctx has inserted it */ write_unlock_irqrestore(&sd->tree_lock, flag); free_block(block); goto find; } else if (ret == -ENOMEM) { /* NOMEM during insert */ write_unlock_irqrestore(&sd->tree_lock, flag); free_block(block); goto out; } /* insert successfuly */ get_block(block); write_unlock_irqrestore(&sd->tree_lock, flag); out: return block; } |
void put_block(struct block *block) { struct sd *sd = block->sd; lock_block(block); if (block->status == PART_IN_LOCAL) { atomic_dec(&block->ref); unlock_block(block); return; } if (atomic_dec_and_lock(&block->ref, &sd->tree_lock)) { radix_tree_delete(&sd->blk_tree, block->blk_no); set_bitmap(sd, block); spin_unlock(&sd->tree_lock); unlock_block(block); free_block(block); return; } unlock(block); } |