📄 9.html
字号:
bh->b_dev = dev;<br> bh->b_blocknr = block;<br> ...<br> return bh;<br> }<br> refill_freelist(size);<br> goto try_again;<br>}<br>---------------------------------------------------------------------------------------------------<p>The real I/O is started by ll_rw_block(). It lives in drivers/block/ll_rw_blk.c.<p>---------------------------------------------------------------------------------------------------<br>ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) {<br> int i;<p> for (i = 0; i < nr; i++) {<br> struct buffer_head *bh = bhs[i];<p> bh->b_end_io = end_buffer_io_sync;<p> submit_bh(rw, bh);<br> }<br>}<br>---------------------------------------------------------------------------------------------------<p>Here bh->b_end_io specifies what to do when I/O is finished. In this case:<p>---------------------------------------------------------------------------------------------------<br>end_buffer_io_sync(struct buffer_head *bh, int uptodate) {<br> mark_buffer_uptodate(bh, uptodate);<br> unlock_buffer(bh);<br>}<br>---------------------------------------------------------------------------------------------------<p>So, ll_rw_block() just feeds the requests it gets one by one to submit_bh():<p>---------------------------------------------------------------------------------------------------<br>submit_bh(int rw, struct buffer_head *bh) {<br> bh->b_rdev = bh->b_dev;<br> bh->b_rsector = bh->b_blocknr * (bh->b_size >> 9);<p> generic_make_request(rw, bh);<br>}<br>---------------------------------------------------------------------------------------------------<p>So, submit_bh() just passes things along to generic_make_request(), the routine to send I/O requests to block devices:<p>---------------------------------------------------------------------------------------------------<br>generic_make_request (int rw, struct buffer_head *bh) {<br> request_queue_t *q;<p> q = blk_get_queue(bh->b_rdev);<br> q->make_request_fn(q, rw, bh);<br>}<br>---------------------------------------------------------------------------------------------------<p>Thus, it finds the right queue and calls the request function for that queue.<p>---------------------------------------------------------------------------------------------------<br>struct blk_dev_struct {<br> request_queue_t request_queue;<br> queue_proc *queue;<br> void *data;<br>} blk_dev[MAX_BLKDEV];<p>request_queue_t *blk_get_queue(kdev_t dev)<br>{<br> return blk_dev[MAJOR(dev)].queue(dev);<br>}<br>---------------------------------------------------------------------------------------------------<p>In our case (/dev/hda), the blk_dev struct was filled by hwif_init (from drivers/ide/ide-probe.c):<br>and this ide_get_queue() is found in drivers/ide/ide.c:<p>---------------------------------------------------------------------------------------------------<br>blk_dev[hwif->major].data = hwif;<br> blk_dev[hwif->major].queue = ide_get_queue;<p>#define DEVICE_NR(dev) (MINOR(dev) >> PARTN_BITS)<p>request_queue_t *ide_get_queue (kdev_t dev) {<br> ide_hwif_t *hwif = (ide_hwif_t *) blk_dev[MAJOR(dev)].data;<br> return &hwif->drives[DEVICE_NR(dev) & 1].queue;<br>}<br>---------------------------------------------------------------------------------------------------<p>This .queue field was filled by ide_init_queue():<br>And blk_init_queue() (from ll_rw_blk.c again):<p>---------------------------------------------------------------------------------------------------<br>ide_init_queue(ide_drive_t *drive) {<br> request_queue_t *q = &drive->queue;<p> q->queuedata = HWGROUP(drive);<br> blk_init_queue(q, do_ide_request);<br>}<p>blk_init_queue(request_queue_t *q, request_fn_proc *rfn) {<br> ...<br> q->request_fn = rfn;<br> q->make_request_fn = __make_request;<br> q->merge_requests_fn = ll_merge_requests_fn;<br> ...<br>}<br>---------------------------------------------------------------------------------------------------<p>Aha, so we found the q->make_request_fn. Here it is:<p>---------------------------------------------------------------------------------------------------<br> __make_request(request_queue_t *q, int rw, struct buffer_head *bh) {<br> /* try to merge request with adjacent ones */<br> ...<br> /* get a struct request and fill it with device, start,length, ... */<br> ...<br> add_request(q, req, insert_here);<br> if (!q->plugged)<br> q->request_fn(q);<br> }<p> add_request(request_queue_t *q, struct request *req,<br> struct list_head *insert_here) {<br> list_add(&req->queue, insert_here);<br> }<p>---------------------------------------------------------------------------------------------------<p>When the request has been queued, q->request_fn is called. What is that? We can see it above - it is do_ide_request() and lives in ide.c.<p>---------------------------------------------------------------------------------------------------<p> do_ide_request(request_queue_t *q) {<br> ide_do_request(q->queuedata, 0);<br> }<p> ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq) {<br> ide_startstop_t startstop;<p> while (!hwgroup->busy) {<br> hwgroup->busy = 1;<br> drive = choose_drive(hwgroup);<br> startstop = start_request(drive);<br> if (startstop == ide_stopped)<br> hwgroup->busy = 0;<br> }<br> }<p> ide_startstop_t<br> start_request (ide_drive_t *drive) {<br> unsigned long block, blockend;<br> struct request *rq;<p> rq = blkdev_entry_next_request(&drive->queue.queue_head);<br> block = rq->sector;<br> block += drive->part[minor & PARTN_MASK].start_sect;<br> SELECT_DRIVE(hwif, drive);<br> return (DRIVER(drive)->do_request(drive, rq, block));<br> }<br>---------------------------------------------------------------------------------------------------<p>So, in the case of a partitioned disk it is only at this very low level that we add in the starting sector of the partition in order to get an absolute sector.<br>The first actual port access happened already:<p>---------------------------------------------------------------------------------------------------<br> #define SELECT_DRIVE(hwif,drive) \<br> OUT_BYTE((drive)->select.all,<br>hwif->io_ports[IDE_SELECT_OFFSET]);<br>---------------------------------------------------------------------------------------------------<p>but this do_request function must do the rest. For a disk it is defined in ide-disk.c, in the ide_driver_t idedisk_driver, and the function turns out to be do_rw_disk().<p>---------------------------------------------------------------------------------------------------<br> ide_startstop_t<br> do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long<br>block) {<br> if (IDE_CONTROL_REG)<br> OUT_BYTE(drive->ctl,IDE_CONTROL_REG);<br> OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG);<br> if (drive->select.b.lba) {<br> OUT_BYTE(block,IDE_SECTOR_REG);<br> OUT_BYTE(block>>=8,IDE_LCYL_REG);<br> OUT_BYTE(block>>=8,IDE_HCYL_REG);<p>OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);<br> } else {<br> unsigned int sect,head,cyl,track;<br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -