staticintchunk_io(structpstore*ps,void*area,chunk_tchunk,intrw,intmetadata){// 略
/*
* Issue the synchronous I/O from a different thread
* to avoid generic_make_request recursion.
*/INIT_WORK_ONSTACK(&req.work,do_metadata);queue_work(ps->metadata_wq,&req.work);flush_work(&req.work);// 略
}staticvoiddo_metadata(structwork_struct*work){structmdata_req*req=container_of(work,structmdata_req,work);req->result=dm_io(req->io_req,1,req->where,NULL);}
以下は, generic_make_requestのソースコードです. このコードにおいて, current->bio_listというのを使って, bioをキューするケースがあるというのがキモです. コメント(We only want…)を読むと, 「一つのタスクについてmake_request_fnがアクティブになるのはone at a timeであるべきだ. current->bio_listがnon-NULLであるということは, make_request_fnが今アクティブであるということだ. この場合, listのtailに格納して, あとで処理する」ということが書かれています.
voidgeneric_make_request(structbio*bio){structbio_listbio_list_on_stack;if(!generic_make_request_checks(bio))return;/*
* We only want one ->make_request_fn to be active at a time, else
* stack usage with stacked devices could be a problem. So use
* current->bio_list to keep a list of requests submited by a
* make_request_fn function. current->bio_list is also used as a
* flag to say if generic_make_request is currently active in this
* task or not. If it is NULL, then no make_request is active. If
* it is non-NULL, then a make_request is active, and new requests
* should be added at the tail
*/if(current->bio_list){bio_list_add(current->bio_list,bio);// (#1)
return;}/* following loop may be a bit non-obvious, and so deserves some
* explanation.
* Before entering the loop, bio->bi_next is NULL (as all callers
* ensure that) so we have a list with a single bio.
* We pretend that we have just taken it off a longer list, so
* we assign bio_list to a pointer to the bio_list_on_stack,
* thus initialising the bio_list of new bios to be
* added. ->make_request() may indeed add some more bios
* through a recursive call to generic_make_request. If it
* did, we find a non-NULL value in bio_list and re-enter the loop
* from the top. In this case we really did just take the bio
* of the top of the list (no pretending) and so remove it from
* bio_list, and call into ->make_request() again.
*/BUG_ON(bio->bi_next);bio_list_init(&bio_list_on_stack);current->bio_list=&bio_list_on_stack;do{structrequest_queue*q=bdev_get_queue(bio->bi_bdev);q->make_request_fn(q,bio);// (#2)
bio=bio_list_pop(current->bio_list);// (#3)
}while(bio);current->bio_list=NULL;/* deactivate */}EXPORT_SYMBOL(generic_make_request);