📄 9.html
字号:
if (bh) {<br>
__remove_from_free_list(bh);<br>
init_buffer(bh);<br>
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>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -