blk_sysfs.c

static 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.c Functions 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--;

}