- 论坛徽章:
- 0
|
- 7, return from driver
- ==================
- exec bio_endio method defined by bio issuer,
- since request may collect bios from different issuers.
- static void req_bio_endio(struct request *rq, struct bio *bio,
- unsigned int nbytes, int error)
- {
- struct request_queue *q = rq->q;
- if (&q->bar_rq != rq) {
- if (error)
- clear_bit(BIO_UPTODATE, &bio->bi_flags);
- else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
- error = -EIO;
- if (unlikely(nbytes > bio->bi_size)) {
- printk(KERN_ERR "%s: want %u bytes done, %u left\n",
- __func__, nbytes, bio->bi_size);
- nbytes = bio->bi_size;
- }
- bio->bi_size -= nbytes;
- bio->bi_sector += (nbytes >> 9);
-
- if (bio->bi_size == 0)
- bio_endio(bio, error);
- } else {
- /*
- * Okay, this is the barrier request in progress, just
- * record the error;
- */
- if (error && !q->orderr)
- q->orderr = error;
- }
- }
- /*
- * after bios in request processed
- */
- void __blk_put_request(struct request_queue *q, struct request *req)
- {
- if (unlikely(!q))
- return;
- if (unlikely(--req->ref_count))
- return;
- elv_completed_request(q, req);
- /*
- * Request may not have originated from ll_rw_blk. if not,
- * it didn't come out of our reserved rq pools
- */
- if (req->cmd_flags & REQ_ALLOCED) {
- int rw = rq_data_dir(req);
- int priv = req->cmd_flags & REQ_ELVPRIV;
- BUG_ON(!list_empty(&req->queuelist));
- BUG_ON(!hlist_unhashed(&req->hash));
- blk_free_request(q, req);
- freed_request(q, rw, priv);
- }
- }
- /*
- * bio processed one after another
- */
- static int __end_that_request_first(struct request *req, int error, int nr_bytes)
- {
- int total_bytes, bio_nbytes, next_idx = 0;
- struct bio *bio;
- blk_add_trace_rq(req->q, req, BLK_TA_COMPLETE);
- /*
- * for a REQ_BLOCK_PC request, we want to carry any eventual
- * sense key with us all the way through
- */
- if (!blk_pc_request(req))
- req->errors = 0;
- if (error && (blk_fs_request(req) && !(req->cmd_flags & REQ_QUIET))) {
- printk(KERN_ERR "end_request: I/O error, dev %s, sector %llu\n",
- req->rq_disk ? req->rq_disk->disk_name : "?",
- (unsigned long long)req->sector);
- }
- if (blk_fs_request(req) && req->rq_disk) {
- struct hd_struct *part = get_part(req->rq_disk, req->sector);
- const int rw = rq_data_dir(req);
- all_stat_add(req->rq_disk, part, sectors[rw],
- nr_bytes >> 9, req->sector);
- }
- total_bytes = bio_nbytes = 0;
-
- while ((bio = req->bio) != NULL) {
- int nbytes;
- /*
- * For an empty barrier request, the low level driver must
- * store a potential error location in ->sector. We pass
- * that back up in ->bi_sector.
- */
- if (blk_empty_barrier(req))
- bio->bi_sector = req->sector;
- if (nr_bytes >= bio->bi_size) {
- /* 1,
- * bio complete as a whole
- */
- req->bio = bio->bi_next;
-
- nbytes = bio->bi_size;
- /* 2,
- * call endio method
- */
- req_bio_endio(req, bio, nbytes, error);
-
- next_idx = 0;
- bio_nbytes = 0;
- } else {
- int idx = bio->bi_idx + next_idx;
- /* 3,
- * check vectors in bio
- */
- if (unlikely(bio->bi_idx >= bio->bi_vcnt)) {
- blk_dump_rq_flags(req, "__end_that");
- printk(KERN_ERR "%s: bio idx %d >= vcnt %d\n",
- __func__, bio->bi_idx, bio->bi_vcnt);
- break;
- }
- nbytes = bio_iovec_idx(bio, idx)->bv_len;
- BIO_BUG_ON(nbytes > bio->bi_size);
- /*
- * not a complete bvec done
- */
- if (unlikely(nbytes > nr_bytes)) {
- bio_nbytes += nr_bytes;
- total_bytes += nr_bytes;
- break;
- }
- /*
- * advance to the next vector
- */
- next_idx++;
- bio_nbytes += nbytes;
- }
- total_bytes += nbytes;
- nr_bytes -= nbytes;
- bio = req->bio;
- if (bio) {
- /*
- * end more in this run, or just return 'not-done'
- */
- if (unlikely(nr_bytes <= 0))
- break;
- }
- }
- /*
- * completely done
- */
- if (!req->bio)
- return 0;
- /*
- * if the request wasn't completed, update state
- */
- if (bio_nbytes) {
- req_bio_endio(req, bio, bio_nbytes, error);
-
- bio->bi_idx += next_idx;
- bio_iovec(bio)->bv_offset += nr_bytes;
- bio_iovec(bio)->bv_len -= nr_bytes;
- }
- /* 4,
- * prepare request for next round
- */
- blk_recalc_rq_sectors(req, total_bytes >> 9);
- blk_recalc_rq_segments(req);
- return 1;
- }
- static void end_that_request_last(struct request *req, int error)
- {
- struct gendisk *disk = req->rq_disk;
- if (blk_rq_tagged(req))
- blk_queue_end_tag(req->q, req);
- if (blk_queued_rq(req))
- blkdev_dequeue_request(req);
- if (unlikely(laptop_mode) && blk_fs_request(req))
- laptop_io_completion();
- /*
- * Account IO completion. bar_rq isn't accounted as a normal
- * IO on queueing nor completion. Accounting the containing
- * request is enough.
- */
- if (disk && blk_fs_request(req) && req != &req->q->bar_rq) {
- unsigned long duration = jiffies - req->start_time;
- const int rw = rq_data_dir(req);
- struct hd_struct *part = get_part(disk, req->sector);
- __all_stat_inc(disk, part, ios[rw], req->sector);
- __all_stat_add(disk, part, ticks[rw], duration, req->sector);
- disk_round_stats(disk);
- disk->in_flight--;
-
- if (part) {
- part_round_stats(part);
- part->in_flight--;
- }
- }
- if (req->end_io)
- req->end_io(req, error);
- else {
- if (blk_bidi_rq(req))
- __blk_put_request(req->next_rq->q, req->next_rq);
- __blk_put_request(req->q, req);
- }
- }
- static int blk_end_io(struct request *rq, int error, unsigned int nr_bytes,
- unsigned int bidi_bytes,
- int (drv_callback)(struct request *))
- {
- struct request_queue *q = rq->q;
- unsigned long flags = 0UL;
- if (blk_fs_request(rq) ||
- blk_pc_request(rq)) {
- if (__end_that_request_first(rq, error, nr_bytes))
- return 1;
- /* Bidi request must be completed as a whole */
- if (blk_bidi_rq(rq) &&
- __end_that_request_first(rq->next_rq, error, bidi_bytes))
- return 1;
- }
- /* Special feature for tricky drivers */
- if (drv_callback && drv_callback(rq))
- return 1;
- add_disk_randomness(rq->rq_disk);
- spin_lock_irqsave(q->queue_lock, flags);
- end_that_request_last(rq, error);
- spin_unlock_irqrestore(q->queue_lock, flags);
- return 0;
- }
- int blk_end_request(struct request *rq, int error, unsigned int nr_bytes)
- {
- return blk_end_io(rq, error, nr_bytes, 0, NULL);
- }
- int __blk_end_request(struct request *rq, int error, unsigned int nr_bytes)
- {
- if (blk_fs_request(rq) ||
- blk_pc_request(rq)) {
- if (__end_that_request_first(rq, error, nr_bytes))
- return 1;
- }
- add_disk_randomness(rq->rq_disk);
- end_that_request_last(rq, error);
- return 0;
- }
- /*
- * feed completed request to softirq
- */
- void blk_complete_request(struct request *req)
- {
- struct list_head *cpu_list;
- unsigned long flags;
- BUG_ON(!req->q->softirq_done_fn);
- local_irq_save(flags);
- cpu_list = &__get_cpu_var(blk_cpu_done);
- list_add_tail(&req->donelist, cpu_list);
-
- raise_softirq_irqoff(BLOCK_SOFTIRQ);
- local_irq_restore(flags);
- }
- /*
- * standard softirq method for completed request
- */
- static void blk_done_softirq(struct softirq_action *h)
- {
- struct list_head *cpu_list, local_list;
- local_irq_disable();
- cpu_list = &__get_cpu_var(blk_cpu_done);
- list_replace_init(cpu_list, &local_list);
- local_irq_enable();
- while (!list_empty(&local_list)) {
- struct request *rq;
- rq = list_entry(local_list.next, struct request, donelist);
-
- list_del_init(&rq->donelist);
- rq->q->softirq_done_fn(rq);
- }
- }
复制代码 |
|