Block IO中关键对象通常在发现存储设备的时候已经构造好,其中,最关键的是gendisk及其关联request_queue的构造,二者的构造同样遵循**“分配->初始化->注册”**的流程。由于设备对象的初始化是从软件栈的底层到上层的, 即初始阶段Block层只是准备好相关的代码,供更底层的SCSI子系统或IDE子系统来”调用”,完成Block层相关对象的构造。
以SCSI磁盘驱动为例,其在SCSI LLDD的扫描并构造设备对象时,已经完成了request_queue中相应接口的注册,供Block层使用:
scsi_probe_add_add_lun() scsi_alloc_sdev() sdev->request_queue = scsi_alloc_queue(sdev) __scsi_alloc_queue(sdev->host, scsi_request_fn); blk_init_queue(request_fn, NULL) blk_init_queue_node() blk_init_allocated_queue() q->request_fn = rfn; //scsi_request_fn blk_queue_make_request(q, blk_queue_bio) q->make_request_fn = mfn; //blk_queue_bio blk_queue_prep_rq(q, scsi_prep_fn); q->prep_rq_fn = pfn //scsi_prep_fn blk_queue_unprep_rq(q, scsi_unprep_fn); q->softirq_done_fn = fn //scsi_unprep_fn blk_queue_softirq_done(q, scsi_softirq_done); q->softirq_done_fn = fn blk_queue_rq_timed_out(q, scsi_times_out); q->rq_timed_out_fn = fn //scsi_times_out blk_queue_lld_busy(q, scsi_lld_busy); q->lld_busy_fn = fn //scsi_lld_busy
当位于SCSI HLDD的sd驱动匹配到已经注册到内核的SCSI磁盘对象时,即开始在内核中构造相应的对象,而gendisk等Block层中的对象是在其”同步”阶段分配以及缺省初始化,并在 “异步”阶段初始化并注册的,。
scsi_alloc_sdev() sdev->request_queue = scsi_alloc_queue(sdev);
同步阶段
sd_probe() gd = alloc_disk(SD_MINORS) //分配gendisk对象 alloc_disk_node(minors, NUMA_NO_NODE) kzalloc_node() init_part_stats() disk_expand_part_tbl() hd_ref_init() rand_initialize_disk() disk_to_dev(disk)->class = &block_class disk_to_dev(disk)->type = &disk_type device_initialize(disk_to_dev(disk))
异步阶段
sd_probe_async() init sdp sdkp gendisk gd=sdkp->disk gd->major = sd_major((index & 0xf0) >> 4); gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); gd->minors = SD_MINORS; gd->fops = &sd_fops; //注册gendisk对象的操作方法集 gd->private_data = &sdkp->driver; gd->queue = sdkp->device->request_queue; //gendisk使用LLDD已经准备好的request_queue add_disk(gd) //注册gendisk对象到内核 bdi_register_dev() blk_register_region() register_disk() blk_register_queue() disk_add_events() blk_integrity_add() sd_revalidate_disk(gd) sd_spinup_disk() //转动磁盘 scsi_execute_req() sd_readcapacity() set_capacity(disk)
至此,在Block层上使用一个磁盘的工作就准备就绪了