Linux Block IO III

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层上使用一个磁盘的工作就准备就绪了

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.