|
@@ -80,3 +80,156 @@ static void drive_stat_acct(struct request *rq, int new_io)
|
|
|
* The partition is already being removed,
|
|
|
* the request will be accounted on the disk only
|
|
|
*
|
|
|
+ * We take a reference on disk->part0 although that
|
|
|
+ * partition will never be deleted, so we can treat
|
|
|
+ * it as any other partition.
|
|
|
+ */
|
|
|
+ part = &rq->rq_disk->part0;
|
|
|
+ hd_struct_get(part);
|
|
|
+ }
|
|
|
+ part_round_stats(cpu, part);
|
|
|
+ part_inc_in_flight(part, rw);
|
|
|
+ rq->part = part;
|
|
|
+ }
|
|
|
+
|
|
|
+ part_stat_unlock();
|
|
|
+}
|
|
|
+
|
|
|
+void blk_queue_congestion_threshold(struct request_queue *q)
|
|
|
+{
|
|
|
+ int nr;
|
|
|
+
|
|
|
+ nr = q->nr_requests - (q->nr_requests / 8) + 1;
|
|
|
+ if (nr > q->nr_requests)
|
|
|
+ nr = q->nr_requests;
|
|
|
+ q->nr_congestion_on = nr;
|
|
|
+
|
|
|
+ nr = q->nr_requests - (q->nr_requests / 8) - (q->nr_requests / 16) - 1;
|
|
|
+ if (nr < 1)
|
|
|
+ nr = 1;
|
|
|
+ q->nr_congestion_off = nr;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * blk_get_backing_dev_info - get the address of a queue's backing_dev_info
|
|
|
+ * @bdev: device
|
|
|
+ *
|
|
|
+ * Locates the passed device's request queue and returns the address of its
|
|
|
+ * backing_dev_info
|
|
|
+ *
|
|
|
+ * Will return NULL if the request queue cannot be located.
|
|
|
+ */
|
|
|
+struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev)
|
|
|
+{
|
|
|
+ struct backing_dev_info *ret = NULL;
|
|
|
+ struct request_queue *q = bdev_get_queue(bdev);
|
|
|
+
|
|
|
+ if (q)
|
|
|
+ ret = &q->backing_dev_info;
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(blk_get_backing_dev_info);
|
|
|
+
|
|
|
+void blk_rq_init(struct request_queue *q, struct request *rq)
|
|
|
+{
|
|
|
+ memset(rq, 0, sizeof(*rq));
|
|
|
+
|
|
|
+ INIT_LIST_HEAD(&rq->queuelist);
|
|
|
+ INIT_LIST_HEAD(&rq->timeout_list);
|
|
|
+ rq->cpu = -1;
|
|
|
+ rq->q = q;
|
|
|
+ rq->__sector = (sector_t) -1;
|
|
|
+ INIT_HLIST_NODE(&rq->hash);
|
|
|
+ RB_CLEAR_NODE(&rq->rb_node);
|
|
|
+ rq->cmd = rq->__cmd;
|
|
|
+ rq->cmd_len = BLK_MAX_CDB;
|
|
|
+ rq->tag = -1;
|
|
|
+ rq->ref_count = 1;
|
|
|
+ rq->start_time = jiffies;
|
|
|
+ set_start_time_ns(rq);
|
|
|
+ rq->part = NULL;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(blk_rq_init);
|
|
|
+
|
|
|
+static void req_bio_endio(struct request *rq, struct bio *bio,
|
|
|
+ unsigned int nbytes, int error)
|
|
|
+{
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (unlikely(rq->cmd_flags & REQ_QUIET))
|
|
|
+ set_bit(BIO_QUIET, &bio->bi_flags);
|
|
|
+
|
|
|
+ bio->bi_size -= nbytes;
|
|
|
+ bio->bi_sector += (nbytes >> 9);
|
|
|
+
|
|
|
+ if (bio_integrity(bio))
|
|
|
+ bio_integrity_advance(bio, nbytes);
|
|
|
+
|
|
|
+ /* don't actually finish bio if it's part of flush sequence */
|
|
|
+ if (bio->bi_size == 0 && !(rq->cmd_flags & REQ_FLUSH_SEQ))
|
|
|
+ bio_endio(bio, error);
|
|
|
+}
|
|
|
+
|
|
|
+void blk_dump_rq_flags(struct request *rq, char *msg)
|
|
|
+{
|
|
|
+ int bit;
|
|
|
+
|
|
|
+ printk(KERN_INFO "%s: dev %s: type=%x, flags=%x\n", msg,
|
|
|
+ rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->cmd_type,
|
|
|
+ rq->cmd_flags);
|
|
|
+
|
|
|
+ printk(KERN_INFO " sector %llu, nr/cnr %u/%u\n",
|
|
|
+ (unsigned long long)blk_rq_pos(rq),
|
|
|
+ blk_rq_sectors(rq), blk_rq_cur_sectors(rq));
|
|
|
+ printk(KERN_INFO " bio %p, biotail %p, buffer %p, len %u\n",
|
|
|
+ rq->bio, rq->biotail, rq->buffer, blk_rq_bytes(rq));
|
|
|
+
|
|
|
+ if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
|
|
|
+ printk(KERN_INFO " cdb: ");
|
|
|
+ for (bit = 0; bit < BLK_MAX_CDB; bit++)
|
|
|
+ printk("%02x ", rq->cmd[bit]);
|
|
|
+ printk("\n");
|
|
|
+ }
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(blk_dump_rq_flags);
|
|
|
+
|
|
|
+static void blk_delay_work(struct work_struct *work)
|
|
|
+{
|
|
|
+ struct request_queue *q;
|
|
|
+
|
|
|
+ q = container_of(work, struct request_queue, delay_work.work);
|
|
|
+ spin_lock_irq(q->queue_lock);
|
|
|
+ __blk_run_queue(q);
|
|
|
+ spin_unlock_irq(q->queue_lock);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * blk_delay_queue - restart queueing after defined interval
|
|
|
+ * @q: The &struct request_queue in question
|
|
|
+ * @msecs: Delay in msecs
|
|
|
+ *
|
|
|
+ * Description:
|
|
|
+ * Sometimes queueing needs to be postponed for a little while, to allow
|
|
|
+ * resources to come back. This function will make sure that queueing is
|
|
|
+ * restarted around the specified time. Queue lock must be held.
|
|
|
+ */
|
|
|
+void blk_delay_queue(struct request_queue *q, unsigned long msecs)
|
|
|
+{
|
|
|
+ if (likely(!blk_queue_dead(q)))
|
|
|
+ queue_delayed_work(kblockd_workqueue, &q->delay_work,
|
|
|
+ msecs_to_jiffies(msecs));
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(blk_delay_queue);
|
|
|
+
|
|
|
+/**
|
|
|
+ * blk_start_queue - restart a previously stopped queue
|
|
|
+ * @q: The &struct request_queue in question
|