linux bio bh关系,Linux BIO

blk_sysfs.cstatic struct queue_sysfs_entry queue_ra_entry = {

.attr = {.name = "read_ahead_kb", .mode = S_IRUGO | S_IWUSR },

.show = queue_ra_show,

.store = queue_ra_store,

};

static struct queue_sysfs_entry queue_max_sectors_entry = {

.attr = {.name = "max_sectors_kb", .mode = S_IRUGO | S_IWUSR },

.show = queue_max_sectors_show,

.store = queue_max_sectors_store,

};

blk-map.cFunctions related to mapping data to requests

static inline struct bio *bio_kmalloc(gfp_t gfp_mask, unsigned int nr_iovecs)

{

return bio_alloc_bioset(gfp_mask, nr_iovecs, NULL);

}

blk_rq_map_user_iov - map user data to a request, for REQ_TYPE_BLOCK_PC usage

scsi_ioctl.c

static int sg_io(struct request_queue *q, struct gendisk *bd_disk,

struct sg_io_hdr *hdr, fmode_t mode);

scst/sg.c

static int sg_start_req(Sg_request *srp, unsigned char *cmd);

=> scsi_dispatch_cmd

=> scsi_request_fn

=> __blk_run_queue_uncond

=> __blk_run_queue

=> blk_queue_bio

=> generic_make_request

=> submit_bio

=> submit_bh

* generic_make_request - hand a buffer to its device driver for I/O

* @bio:  The bio describing the location in memory and on the device.

*

* generic_make_request() is used to make I/O requests of block

* devices. It is passed a &struct bio, which describes the I/O that needs

* to be done.

submit_bio - submit a bio to the block device layer for I/O

void submit_bio(int rw, struct bio *bio);

void generic_make_request(struct bio *bio);

在每个进程的task_struct中,都包含有两个变量----struct bio *bio_list,实际的提交操作会由generic_make_request()调用__generic_make_request()函数完成。

/* stacked block device info */

struct bio_list *bio_list;/**

* generic_make_request - hand a buffer to its device driver for I/O

* @bio:  The bio describing the location in memory and on the device.

*

* generic_make_request() is used to make I/O requests of block

* devices. It is passed a &struct bio, which describes the I/O that needs

* to be done.

*

* generic_make_request() does not return any status.  The

* success/failure status of the request, along with notification of

* completion, is delivered asynchronously through the bio->bi_end_io

* function described (one day) else where.

*

* The caller of generic_make_request must make sure that bi_io_vec

* are set to describe the memory buffer, and that bi_dev and bi_sector are

* set to describe the device address, and the

* bi_end_io and optionally bi_private are set to describe how

* completion notification should be signaled.

*

* generic_make_request and the drivers it calls may use bi_next if this

* bio happens to be merged with someone else, and may resubmit the bio to

* a lower device by calling into generic_make_request recursively, which

* means the bio should NOT be touched after the call to ->make_request_fn.

*/

void generic_make_request(struct bio *bio)

{

struct bio_list bio_list_on_stack;

if (!generic_make_request_checks(bio))

return;

/*

* We only want one ->make_request_fn to be active at a time, else

* stack usage with stacked devices could be a problem.  So use

* current->bio_list to keep a list of requests submited by a

* make_request_fn function.  current->bio_list is also used as a

* flag to say if generic_make_request is currently active in this

* task or not.  If it is NULL, then no make_request is active.  If

* it is non-NULL, then a make_request is active, and new requests

* should be added at the tail

*/

if (current->bio_list) {

bio_list_add(current->bio_list, bio);

return;

}

/* following loop may be a bit non-obvious, and so deserves some

* explanation.

* Before entering the loop, bio->bi_next is NULL (as all callers

* ensure that) so we have a list with a single bio.

* We pretend that we have just taken it off a longer list, so

* we assign bio_list to a pointer to the bio_list_on_stack,

* thus initialising the bio_list of new bios to be

* added.  ->make_request() may indeed add some more bios

* through a recursive call to generic_make_request.  If it

* did, we find a non-NULL value in bio_list and re-enter the loop

* from the top.  In this case we really did just take the bio

* of the top of the list (no pretending) and so remove it from

* bio_list, and call into ->make_request() again.

*/

BUG_ON(bio->bi_next);

bio_list_init(&bio_list_on_stack);

current->bio_list = &bio_list_on_stack;

do {

struct request_queue *q = bdev_get_queue(bio->bi_bdev);

将bio发送给disk,调用blk_queue_bio

q->make_request_fn(q, bio);

bio = bio_list_pop(current->bio_list);

} while (bio);

current->bio_list = NULL; /* deactivate */

}void blk_queue_bio(struct request_queue *q, struct bio *bio)

{

const bool sync = !!(bio->bi_rw & REQ_SYNC);

struct blk_plug *plug;

int el_ret, rw_flags, where = ELEVATOR_INSERT_SORT;

struct request *req;

unsigned int request_count = 0;

/*

* low level driver can indicate that it wants pages above a

* certain limit bounced to low memory (ie for highmem, or even

* ISA dma in theory)

*/

blk_queue_bounce(q, &bio);

if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {

bio_endio(bio, -EIO);

return;

}

if (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) {

spin_lock_irq(q->queue_lock);

where = ELEVATOR_INSERT_FLUSH;

goto get_rq;

}

/*

* Check if we can merge with the plugged list before grabbing

* any locks.

*/

if (blk_attempt_plug_merge(q, bio, &request_count))

return;

spin_lock_irq(q->queue_lock);

el_ret = elv_merge(q, &req, bio);

if (el_ret == ELEVATOR_BACK_MERGE) {

if (bio_attempt_back_merge(q, req, bio)) {

elv_bio_merged(q, req, bio);

if (!attempt_back_merge(q, req))

elv_merged_request(q, req, el_ret);

goto out_unlock;

}

} else if (el_ret == ELEVATOR_FRONT_MERGE) {

if (bio_attempt_front_merge(q, req, bio)) {

elv_bio_merged(q, req, bio);

if (!attempt_front_merge(q, req))

elv_merged_request(q, req, el_ret);

goto out_unlock;

}

}

get_rq:

/*

* This sync check and mask will be re-done in init_request_from_bio(),

* but we need to set it earlier to expose the sync flag to the

* rq allocator and io schedulers.

*/

rw_flags = bio_data_dir(bio);

if (sync)

rw_flags |= REQ_SYNC;

/*

* Grab a free request. This is might sleep but can not fail.

* Returns with the queue unlocked.

*/

req = get_request(q, rw_flags, bio, GFP_NOIO);

if (unlikely(!req)) {

bio_endio(bio, -ENODEV);/* @q is dead */

goto out_unlock;

}

/*

* After dropping the lock and possibly sleeping here, our request

* may now be mergeable after it had proven unmergeable (above).

* We don't worry about that case for efficiency. It won't happen

* often, and the elevators are able to handle it.

*/

init_request_from_bio(req, bio);

if (test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags))

req->cpu = raw_smp_processor_id();

plug = current->plug;

if (plug) {

/*

* If this is the first request added after a plug, fire

* of a plug trace. If others have been added before, check

* if we have multiple devices in this plug. If so, make a

* note to sort the list before dispatch.

*/

if (list_empty(&plug->list))

trace_block_plug(q);

else {

if (request_count >= BLK_MAX_REQUEST_COUNT) {

blk_flush_plug_list(plug, false);

trace_block_plug(q);

}

}

list_add_tail(&req->queuelist, &plug->list);

blk_account_io_start(req, true);

} else {

spin_lock_irq(q->queue_lock);

add_acct_request(q, req, where);

__blk_run_queue(q);

out_unlock:

spin_unlock_irq(q->queue_lock);

}

}/**

* __blk_run_queue - run a single device queue

* @q:The queue to run

*

* Description:

*    See @blk_run_queue. This variant must be called with the queue lock

*    held and interrupts disabled.

*/

void __blk_run_queue(struct request_queue *q)

{

if (unlikely(blk_queue_stopped(q)))

return;

__blk_run_queue_uncond(q);

}

/**

* __blk_run_queue_uncond - run a queue whether or not it has been stopped

* @q:The queue to run

*

* Description:

*    Invoke request handling on a queue if there are any pending requests.

*    May be used to restart request handling after a request has completed.

*    This variant runs the queue whether or not the queue has been

*    stopped. Must be called with the queue lock held and interrupts

*    disabled. See also @blk_run_queue.

*/

inline void __blk_run_queue_uncond(struct request_queue *q)

{

if (unlikely(blk_queue_dead(q)))

return;

/*

* Some request_fn implementations, e.g. scsi_request_fn(), unlock

* the queue lock internally. As a result multiple threads may be

* running such a request function concurrently. Keep track of the

* number of active request_fn invocations such that blk_drain_queue()

* can wait until all these request_fn calls have finished.

*/

q->request_fn_active++;

调用请求处理函数

q->request_fn(q);

q->request_fn_active--;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值