⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ll_rw_blk.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	while (!rq) {		DEFINE_WAIT(wait);		struct request_list *rl = &q->rq;		prepare_to_wait_exclusive(&rl->wait[rw], &wait,				TASK_UNINTERRUPTIBLE);		rq = get_request(q, rw, bio, GFP_NOIO);		if (!rq) {			struct io_context *ioc;			__generic_unplug_device(q);			spin_unlock_irq(q->queue_lock);			io_schedule();			/*			 * After sleeping, we become a "batching" process and			 * will be able to allocate at least one request, and			 * up to a big batch of them for a small period time.			 * See ioc_batching, ioc_set_batching			 */			ioc = current_io_context(GFP_NOIO);			ioc_set_batching(q, ioc);			spin_lock_irq(q->queue_lock);		}		finish_wait(&rl->wait[rw], &wait);	}	return rq;}struct request *blk_get_request(request_queue_t *q, int rw, int gfp_mask){	struct request *rq;	BUG_ON(rw != READ && rw != WRITE);	spin_lock_irq(q->queue_lock);	if (gfp_mask & __GFP_WAIT) {		rq = get_request_wait(q, rw, NULL);	} else {		rq = get_request(q, rw, NULL, gfp_mask);		if (!rq)			spin_unlock_irq(q->queue_lock);	}	/* q->queue_lock is unlocked at this point */	return rq;}EXPORT_SYMBOL(blk_get_request);/** * blk_requeue_request - put a request back on queue * @q:		request queue where request should be inserted * @rq:		request to be inserted * * Description: *    Drivers often keep queueing requests until the hardware cannot accept *    more, when that condition happens we need to put the request back *    on the queue. Must be called with queue lock held. */void blk_requeue_request(request_queue_t *q, struct request *rq){	if (blk_rq_tagged(rq))		blk_queue_end_tag(q, rq);	elv_requeue_request(q, rq);}EXPORT_SYMBOL(blk_requeue_request);/** * blk_insert_request - insert a special request in to a request queue * @q:		request queue where request should be inserted * @rq:		request to be inserted * @at_head:	insert request at head or tail of queue * @data:	private data * * Description: *    Many block devices need to execute commands asynchronously, so they don't *    block the whole kernel from preemption during request execution.  This is *    accomplished normally by inserting aritficial requests tagged as *    REQ_SPECIAL in to the corresponding request queue, and letting them be *    scheduled for actual execution by the request queue. * *    We have the option of inserting the head or the tail of the queue. *    Typically we use the tail for new ioctls and so forth.  We use the head *    of the queue for things like a QUEUE_FULL message from a device, or a *    host that is unable to accept a particular command. */void blk_insert_request(request_queue_t *q, struct request *rq,			int at_head, void *data){	int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK;	unsigned long flags;	/*	 * tell I/O scheduler that this isn't a regular read/write (ie it	 * must not attempt merges on this) and that it acts as a soft	 * barrier	 */	rq->flags |= REQ_SPECIAL | REQ_SOFTBARRIER;	rq->special = data;	spin_lock_irqsave(q->queue_lock, flags);	/*	 * If command is tagged, release the tag	 */	if (blk_rq_tagged(rq))		blk_queue_end_tag(q, rq);	drive_stat_acct(rq, rq->nr_sectors, 1);	__elv_add_request(q, rq, where, 0);	if (blk_queue_plugged(q))		__generic_unplug_device(q);	else		q->request_fn(q);	spin_unlock_irqrestore(q->queue_lock, flags);}EXPORT_SYMBOL(blk_insert_request);/** * blk_rq_map_user - map user data to a request, for REQ_BLOCK_PC usage * @q:		request queue where request should be inserted * @rq:		request structure to fill * @ubuf:	the user buffer * @len:	length of user data * * Description: *    Data will be mapped directly for zero copy io, if possible. Otherwise *    a kernel bounce buffer is used. * *    A matching blk_rq_unmap_user() must be issued at the end of io, while *    still in process context. * *    Note: The mapped bio may need to be bounced through blk_queue_bounce() *    before being submitted to the device, as pages mapped may be out of *    reach. It's the callers responsibility to make sure this happens. The *    original bio must be passed back in to blk_rq_unmap_user() for proper *    unmapping. */int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf,		    unsigned int len){	unsigned long uaddr;	struct bio *bio;	int reading;	if (len > (q->max_sectors << 9))		return -EINVAL;	if (!len || !ubuf)		return -EINVAL;	reading = rq_data_dir(rq) == READ;	/*	 * if alignment requirement is satisfied, map in user pages for	 * direct dma. else, set up kernel bounce buffers	 */	uaddr = (unsigned long) ubuf;	if (!(uaddr & queue_dma_alignment(q)) && !(len & queue_dma_alignment(q)))		bio = bio_map_user(q, NULL, uaddr, len, reading);	else		bio = bio_copy_user(q, uaddr, len, reading);	if (!IS_ERR(bio)) {		rq->bio = rq->biotail = bio;		blk_rq_bio_prep(q, rq, bio);		rq->buffer = rq->data = NULL;		rq->data_len = len;		return 0;	}	/*	 * bio is the err-ptr	 */	return PTR_ERR(bio);}EXPORT_SYMBOL(blk_rq_map_user);/** * blk_rq_map_user_iov - map user data to a request, for REQ_BLOCK_PC usage * @q:		request queue where request should be inserted * @rq:		request to map data to * @iov:	pointer to the iovec * @iov_count:	number of elements in the iovec * * Description: *    Data will be mapped directly for zero copy io, if possible. Otherwise *    a kernel bounce buffer is used. * *    A matching blk_rq_unmap_user() must be issued at the end of io, while *    still in process context. * *    Note: The mapped bio may need to be bounced through blk_queue_bounce() *    before being submitted to the device, as pages mapped may be out of *    reach. It's the callers responsibility to make sure this happens. The *    original bio must be passed back in to blk_rq_unmap_user() for proper *    unmapping. */int blk_rq_map_user_iov(request_queue_t *q, struct request *rq,			struct sg_iovec *iov, int iov_count){	struct bio *bio;	if (!iov || iov_count <= 0)		return -EINVAL;	/* we don't allow misaligned data like bio_map_user() does.  If the	 * user is using sg, they're expected to know the alignment constraints	 * and respect them accordingly */	bio = bio_map_user_iov(q, NULL, iov, iov_count, rq_data_dir(rq)== READ);	if (IS_ERR(bio))		return PTR_ERR(bio);	rq->bio = rq->biotail = bio;	blk_rq_bio_prep(q, rq, bio);	rq->buffer = rq->data = NULL;	rq->data_len = bio->bi_size;	return 0;}EXPORT_SYMBOL(blk_rq_map_user_iov);/** * blk_rq_unmap_user - unmap a request with user data * @bio:	bio to be unmapped * @ulen:	length of user buffer * * Description: *    Unmap a bio previously mapped by blk_rq_map_user(). */int blk_rq_unmap_user(struct bio *bio, unsigned int ulen){	int ret = 0;	if (bio) {		if (bio_flagged(bio, BIO_USER_MAPPED))			bio_unmap_user(bio);		else			ret = bio_uncopy_user(bio);	}	return 0;}EXPORT_SYMBOL(blk_rq_unmap_user);/** * blk_rq_map_kern - map kernel data to a request, for REQ_BLOCK_PC usage * @q:		request queue where request should be inserted * @rq:		request to fill * @kbuf:	the kernel buffer * @len:	length of user data * @gfp_mask:	memory allocation flags */int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf,		    unsigned int len, unsigned int gfp_mask){	struct bio *bio;	if (len > (q->max_sectors << 9))		return -EINVAL;	if (!len || !kbuf)		return -EINVAL;	bio = bio_map_kern(q, kbuf, len, gfp_mask);	if (IS_ERR(bio))		return PTR_ERR(bio);	if (rq_data_dir(rq) == WRITE)		bio->bi_rw |= (1 << BIO_RW);	rq->bio = rq->biotail = bio;	blk_rq_bio_prep(q, rq, bio);	rq->buffer = rq->data = NULL;	rq->data_len = len;	return 0;}EXPORT_SYMBOL(blk_rq_map_kern);/** * blk_execute_rq_nowait - insert a request into queue for execution * @q:		queue to insert the request in * @bd_disk:	matching gendisk * @rq:		request to insert * @at_head:    insert request at head or tail of queue * @done:	I/O completion handler * * Description: *    Insert a fully prepared request at the back of the io scheduler queue *    for execution.  Don't wait for completion. */void blk_execute_rq_nowait(request_queue_t *q, struct gendisk *bd_disk,			   struct request *rq, int at_head,			   void (*done)(struct request *)){	int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK;	rq->rq_disk = bd_disk;	rq->flags |= REQ_NOMERGE;	rq->end_io = done;	elv_add_request(q, rq, where, 1);	generic_unplug_device(q);}/** * blk_execute_rq - insert a request into queue for execution * @q:		queue to insert the request in * @bd_disk:	matching gendisk * @rq:		request to insert * @at_head:    insert request at head or tail of queue * * Description: *    Insert a fully prepared request at the back of the io scheduler queue *    for execution and wait for completion. */int blk_execute_rq(request_queue_t *q, struct gendisk *bd_disk,		   struct request *rq, int at_head){	DECLARE_COMPLETION(wait);	char sense[SCSI_SENSE_BUFFERSIZE];	int err = 0;	/*	 * we need an extra reference to the request, so we can look at	 * it after io completion	 */	rq->ref_count++;	if (!rq->sense) {		memset(sense, 0, sizeof(sense));		rq->sense = sense;		rq->sense_len = 0;	}	rq->waiting = &wait;	blk_execute_rq_nowait(q, bd_disk, rq, at_head, blk_end_sync_rq);	wait_for_completion(&wait);	rq->waiting = NULL;	if (rq->errors)		err = -EIO;	return err;}EXPORT_SYMBOL(blk_execute_rq);/** * blkdev_issue_flush - queue a flush * @bdev:	blockdev to issue flush for * @error_sector:	error sector * * Description: *    Issue a flush for the block device in question. Caller can supply *    room for storing the error offset in case of a flush error, if they *    wish to.  Caller must run wait_for_completion() on its own. */int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector){	request_queue_t *q;	if (bdev->bd_disk == NULL)		return -ENXIO;	q = bdev_get_queue(bdev);	if (!q)		return -ENXIO;	if (!q->issue_flush_fn)		return -EOPNOTSUPP;	return q->issue_flush_fn(q, bdev->bd_disk, error_sector);}EXPORT_SYMBOL(blkdev_issue_flush);static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io){	int rw = rq_data_dir(rq);	if (!blk_fs_request(rq) || !rq->rq_disk)		return;	if (rw == READ) {		__disk_stat_add(rq->rq_disk, read_sectors, nr_sectors);		if (!new_io)			__disk_stat_inc(rq->rq_disk, read_merges);	} else if (rw == WRITE) {		__disk_stat_add(rq->rq_disk, write_sectors, nr_sectors);		if (!new_io)			__disk_stat_inc(rq->rq_disk, write_merges);	}	if (new_io) {		disk_round_stats(rq->rq_disk);		rq->rq_disk->in_flight++;	}}/* * add-request adds a request to the linked list. * queue lock is held and interrupts disabled, as we muck with the * request queue list. */static inline void add_request(request_queue_t * q, struct request * req){	drive_stat_acct(req, req->nr_sectors, 1);	if (q->activity_fn)		q->activity_fn(q->activity_data, rq_data_dir(req));	/*	 * elevator indicated where it wants this request to be	 * inserted at elevator_merge time	 */	__elv_add_request(q, req, ELEVATOR_INSERT_SORT, 0);} /* * disk_round_stats()	- Round off the performance stats on a struct * disk_stats. * * The average IO queue length and utilisation statistics are maintained * by observing the current state of the queue length and the amount of * time it has been in this state for. * * Normally, that accounting is done on IO completion, but that can result * in more than a second's worth of IO being accounted for within any one * second, leading to >100% utilisation.  To deal with that, we call this * function to do a round-off before returning the results when reading * /proc/diskstats.  This accounts immediately for all queue usage up to * the current jiffies and restarts the counters again. */void disk_round_stats(struct gendisk *disk){	unsigned long now = jiffies;	__disk_stat_add(disk, time_in_queue,			disk->in_flight * (now - disk->stamp));	disk->stamp = now;	if (disk->in_flight)		__disk_stat_add(disk, io_ticks, (now - disk->stamp_idle));	disk->stamp_idle = now;}/* * queue lock must be held */static void __blk_put_request(request_queue_t *q, struct request *req){	struct request_list *rl = req->rl;	if (unlikely(!q))		return;	if (unlikely(--req->ref_count))		return;	req->rq_status = RQ_INACTIVE;	req->rl = NULL;	/*	 * Request may not have originated from ll_rw_blk. if not,	 * it didn't come out of our reserved rq pools	 */	if (rl) {		int rw = rq_data_dir(req);		elv_completed_request(q, req);		BUG_ON(!list_empty(&req->queuelist));		blk_free_request(q, req);		freed_request(q, rw);	}}void blk_put_request(struct request *req){	/*	 * if req->rl isn't set, this request didnt originate from the	 * block layer, so it's safe to just disregard it	 */	if (req->rl) {		unsigned lo

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -