1. block_read_full_page(struct page *page, get_block_t *get_block)
其中page是读操作的数据存放的位置, 即OS从硬盘上读取数据将会存放到page中.
2. 为这个page分配buffer_head, head = alloc_page_buffers(page); 每个bh对应文件系统的block.
3. 调用submit_bh(READ, bh); 此时的动作为:
分配BIO. 即:
if (buffer_page(bh))
bio->bi_io_vec[0].bv_buffer = bh_page_data(bh);
else
bio->bi_io_vec[0].bv_buffer = bh_data(bh);
bio->bi_io_vec[0].bv_len = bh->b_size;
bio->bi_vcnt = 1;
bio->bi_idx = 0;
bio->bi_size = bh->b_size;
即数据流为page -> buffer_head -> bio
4. submit_bio(int rw, struct bio *bio) -> generic_make_request -> __make_request -> add_request(q, req);
此时的动作是将此BIO作为一个request的member插入到request_queue中
5. 在将来某个时候, SCSI命令将会执行时, 调用scsi_prep_fn(q,ret)
scsi_init_io SCSI初始化IO操作, 它调用blk_rq_map_sg(req->q, req, cmd->request_buffer) ;此时cmd->request_buffer是数据是
1) 是scatter-gather list
2) 就简单的buffer.
因此, 此时的数据流为page -> buffer_head -> bio -> request -> scsi_cmnd的request_buffer.
6. usb_stor_Bulk_transport -> usb_stor_bulk_transfer_sg -> usb_stor_bulk_transfer_sglist or usb_stor_bulk_transfer_buf ->
对于usb_stor_bulk_transfer_buf,
usb_fill_bulk_urb/usb_stor_msg_common -> usb_submit_urb
在usb_fill_bulk_urb中, urb-> transfer_buffer被设置为srb->request_buffer (注: SRB即前面的CMD)
6. 然后在usb_submit_urb()时, 它调用HCD的usb_hcd_submit_urb(). 后者的动作将会将URB的数据转换成HC的硬件数据, 并将其加入到OHCI/UHCI/EHCI的Queue中, status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
对于OHCI, 它的函数为ohci_urb_enqueue -> td_submit_urb (ohci, urb);
对于bulk传输, 将调用td_fill()根据urb->transfer_dma来设置硬件的TD的buffer pointer, 最终写IO寄存器ohci_writel (ohci, OHCI_BLF, &ohci->regs->cmdstatus);
因此, VFS的读操作的数据流为page -> buffer_head -> bio -> request -> scsi_cmnd的request_buffer -> urb的transfer_buffer/transfer_dma -> 硬件TD.