bio切分函数 ---- 非递归实现

来源:互联网 发布:日语特点 知乎 编辑:程序博客网 时间:2024/05/20 08:01

以前的实现方式: 递归式的,但是在内核中递归是一个非常危险的举动, 所以把它实现成非递归的

数据结构:

struct md_bio_pair { 
        struct list_head bio_head;
        struct bio *oldbio;
        atomic_t count;
        int err;
};   

本来打算用bio自己的bi_next将bio串在一起的,但是后面的代码中使用了bi_next, 所以只能用一个新的链表,把要切分的bio串起来。


函数如下: 

int do_split(struct bio *bio, struct asd_io_context *ioctx)
{
        struct md_bio_pair *bp;
        int chksize, split_offset, first_flag = 1, i=0, sum=0, ret = 0;
        unsigned int remaining = bio->bi_size >> SECTOR_BITS, len;
        unsigned short start_idx = 0;
        struct bio *clone;
        sector_t next_sec;
        struct list_head *pos = NULL;
        struct big_bio *tmp_big = NULL;
 
 
        chksize = ioctx->chunk_size;
        split_offset = chksize - (bio->bi_sector & (chksize - 1));
 
        bp = mempool_alloc(asd_sys.src.biopair_mempool,GFP_NOIO);
        if(IS_ERR(bp)){
                klog(ERROR,"do_split fail\n");
        }
        memset(bp, 0, sizeof(struct md_bio_pair));
        atomic_set(&bp->count,0);
        bp->oldbio = bio;
        INIT_LIST_HEAD(&bp->bio_head);
next_sec = bio->bi_sector;
        do{
                if(unlikely(first_flag)){
                        len = split_offset;
                        first_flag = 0;
                } else {
                        len = MIN(remaining, chksize);
                }
 
                sum = 0;
                for(i = start_idx; i < bio->bi_vcnt; i++){
                        sum += bio->bi_io_vec[i].bv_len >> SECTOR_BITS;
                        if(sum >= len){
                                break;
                        }
                }
                clone = split_bvec(bp, next_sec, start_idx, i+1, len, asd_sys.src.bioset);
                start_idx = i + 1;
                atomic_inc(&bp->count);
                remaining -= len;
                next_sec += len;
        }while(remaining > 0);
 
        list_for_each(pos, &bp->bio_head){
                tmp_big = list_entry(pos, struct big_bio, list);
                if(ret = asd_make_request(ioctx->q, tmp_big->bio)){
                        klog(ERROR,"====ghost.ret :%d=====\n",ret);
                }
        }
ioctx->bioret = 0;
return 0;
}

/*
 * Creates a little bio that is just does part of a bvec.
 */
struct bio* split_bvec(struct md_bio_pair* bp, sector_t sector,
                        unsigned short start_idx, unsigned short end_idx,
                        unsigned int len, struct bio_set *bs)
{
        struct bio *clone, *bio = bp->oldbio;
        int nr = end_idx - start_idx + 1, i; /* the num of bi_vcnt */
        unsigned long flag_md;
        struct big_bio* tmp_big = kzalloc(sizeof(struct big_bio), GFP_KERNEL);
        if(!tmp_big){
                klog(ERROR, "malloc tmp_big fail\n");
        }
 
        clone = bio_alloc_bioset(GFP_NOIO, nr, bs);
        for(i=start_idx; i < end_idx; i++){
                clone->bi_io_vec[i-start_idx] = bio->bi_io_vec[i];
        }
 
        clone->bi_sector = sector;
        clone->bi_bdev = bio->bi_bdev;
        clone->bi_rw = bio->bi_rw;
        clone->bi_vcnt = nr - 1;
        clone->bi_size = len << SECTOR_BITS;
 
        clone->bi_hw_segments = bio_hw_segments(clone->bi_bdev->bd_disk->queue,clone);
        clone->bi_phys_segments = bio_phys_segments(clone->bi_bdev->bd_disk->queue,
                                clone);
clone->bi_end_io = md_bio_pair_end;
        clone->bi_private = bp;
        clone->bi_destructor = md_bio_destructor;
 
        tmp_big->bio = clone;
        list_add_tail(&tmp_big->list, &bp->bio_head);
        return clone;
}


/* for each bio's callback in md_bio_pair */
static int md_bio_pair_end(struct bio *bi, unsigned int done, int err)
{
        struct md_bio_pair *bp = (struct md_bio_pair *)bi->bi_private;
 
        if(err){
                bp->err = err;
                klog(ERROR,"=====err :%d====\n");
        }
 
        if(bi->bi_size)
                return 1;
 
        md_bio_pair_release(bp);
        return 0;
}


static void md_bio_destructor(struct bio *bio)
{
        bio_free(bio, asd_sys.src.bioset);
}       
void md_bio_pair_release(struct md_bio_pair *bp)
{
        struct big_bio *tmp_big = NULL;
        struct bio *master = bp->oldbio;
        struct list_head* pos, *n;
        unsigned long flag_md; 
  
        if (atomic_dec_and_test(&bp->count)){
                list_for_each_safe(pos, n, &bp->bio_head){
                        tmp_big = list_entry(pos, struct big_bio, list);
                        list_del(pos);
                        tmp_big->bio->bi_destructor(tmp_big->bio);
                        kfree(tmp_big);
                        tmp_big = NULL;
                }       
                bio_endio(master, master->bi_size, bp->err);
                mempool_free(bp, asd_sys.src.biopair_mempool);
        }
}         

原创粉丝点击