static struct workqueue_struct *kthrotld_workqueue;
struct throtl_service_queue {
+ /*
+ * Bios queued directly to this service_queue or dispatched from
+ * children throtl_grp's.
+ */
+ struct bio_list bio_lists[2]; /* queued bios [READ/WRITE] */
+ unsigned int nr_queued[2]; /* number of queued bios */
+
+ /*
+ * RB tree of active children throtl_grp's, which are sorted by
+ * their ->disptime.
+ */
struct rb_root pending_tree; /* RB tree of active tgs */
struct rb_node *first_pending; /* first node in the tree */
unsigned int nr_pending; /* # queued in the tree */
unsigned int flags;
- /* Two lists for READ and WRITE */
- struct bio_list bio_lists[2];
-
- /* Number of queued bios on READ and WRITE lists */
- unsigned int nr_queued[2];
-
/* bytes per second rate limits */
uint64_t bps[2];
/* init a service_queue, assumes the caller zeroed it */
static void throtl_service_queue_init(struct throtl_service_queue *sq)
{
+ bio_list_init(&sq->bio_lists[0]);
+ bio_list_init(&sq->bio_lists[1]);
sq->pending_tree = RB_ROOT;
}
throtl_service_queue_init(&tg->service_queue);
RB_CLEAR_NODE(&tg->rb_node);
tg->td = blkg->q->td;
- bio_list_init(&tg->bio_lists[0]);
- bio_list_init(&tg->bio_lists[1]);
tg->bps[READ] = -1;
tg->bps[WRITE] = -1;
* this function with a different bio if there are other bios
* queued.
*/
- BUG_ON(tg->nr_queued[rw] && bio != bio_list_peek(&tg->bio_lists[rw]));
+ BUG_ON(tg->service_queue.nr_queued[rw] &&
+ bio != bio_list_peek(&tg->service_queue.bio_lists[rw]));
/* If tg->bps = -1, then BW is unlimited */
if (tg->bps[rw] == -1 && tg->iops[rw] == -1) {
static void throtl_add_bio_tg(struct bio *bio, struct throtl_grp *tg,
struct throtl_service_queue *parent_sq)
{
+ struct throtl_service_queue *sq = &tg->service_queue;
bool rw = bio_data_dir(bio);
- bio_list_add(&tg->bio_lists[rw], bio);
+ bio_list_add(&sq->bio_lists[rw], bio);
/* Take a bio reference on tg */
blkg_get(tg_to_blkg(tg));
- tg->nr_queued[rw]++;
+ sq->nr_queued[rw]++;
tg->td->nr_queued[rw]++;
throtl_enqueue_tg(tg, parent_sq);
}
static void tg_update_disptime(struct throtl_grp *tg,
struct throtl_service_queue *parent_sq)
{
+ struct throtl_service_queue *sq = &tg->service_queue;
unsigned long read_wait = -1, write_wait = -1, min_wait = -1, disptime;
struct bio *bio;
- if ((bio = bio_list_peek(&tg->bio_lists[READ])))
+ if ((bio = bio_list_peek(&sq->bio_lists[READ])))
tg_may_dispatch(tg, bio, &read_wait);
- if ((bio = bio_list_peek(&tg->bio_lists[WRITE])))
+ if ((bio = bio_list_peek(&sq->bio_lists[WRITE])))
tg_may_dispatch(tg, bio, &write_wait);
min_wait = min(read_wait, write_wait);
static void tg_dispatch_one_bio(struct throtl_grp *tg, bool rw,
struct bio_list *bl)
{
+ struct throtl_service_queue *sq = &tg->service_queue;
struct bio *bio;
- bio = bio_list_pop(&tg->bio_lists[rw]);
- tg->nr_queued[rw]--;
+ bio = bio_list_pop(&sq->bio_lists[rw]);
+ sq->nr_queued[rw]--;
/* Drop bio reference on blkg */
blkg_put(tg_to_blkg(tg));
static int throtl_dispatch_tg(struct throtl_grp *tg, struct bio_list *bl)
{
+ struct throtl_service_queue *sq = &tg->service_queue;
unsigned int nr_reads = 0, nr_writes = 0;
unsigned int max_nr_reads = throtl_grp_quantum*3/4;
unsigned int max_nr_writes = throtl_grp_quantum - max_nr_reads;
/* Try to dispatch 75% READS and 25% WRITES */
- while ((bio = bio_list_peek(&tg->bio_lists[READ])) &&
+ while ((bio = bio_list_peek(&sq->bio_lists[READ])) &&
tg_may_dispatch(tg, bio, NULL)) {
tg_dispatch_one_bio(tg, bio_data_dir(bio), bl);
break;
}
- while ((bio = bio_list_peek(&tg->bio_lists[WRITE])) &&
+ while ((bio = bio_list_peek(&sq->bio_lists[WRITE])) &&
tg_may_dispatch(tg, bio, NULL)) {
tg_dispatch_one_bio(tg, bio_data_dir(bio), bl);
struct bio_list *bl)
{
unsigned int nr_disp = 0;
- struct throtl_grp *tg;
while (1) {
- tg = throtl_rb_first(parent_sq);
+ struct throtl_grp *tg = throtl_rb_first(parent_sq);
+ struct throtl_service_queue *sq = &tg->service_queue;
if (!tg)
break;
nr_disp += throtl_dispatch_tg(tg, bl);
- if (tg->nr_queued[0] || tg->nr_queued[1])
+ if (sq->nr_queued[0] || sq->nr_queued[1])
tg_update_disptime(tg, parent_sq);
if (nr_disp >= throtl_quantum)
{
struct throtl_data *td = q->td;
struct throtl_grp *tg;
+ struct throtl_service_queue *sq;
bool rw = bio_data_dir(bio), update_disptime = true;
struct blkcg *blkcg;
bool throttled = false;
if (unlikely(!tg))
goto out_unlock;
- if (tg->nr_queued[rw]) {
+ sq = &tg->service_queue;
+
+ if (sq->nr_queued[rw]) {
/*
* There is already another bio queued in same dir. No
* need to update dispatch time.
rw == READ ? 'R' : 'W',
tg->bytes_disp[rw], bio->bi_size, tg->bps[rw],
tg->io_disp[rw], tg->iops[rw],
- tg->nr_queued[READ], tg->nr_queued[WRITE]);
+ sq->nr_queued[READ], sq->nr_queued[WRITE]);
bio_associate_current(bio);
throtl_add_bio_tg(bio, tg, &q->td->service_queue);
bio_list_init(&bl);
while ((tg = throtl_rb_first(parent_sq))) {
+ struct throtl_service_queue *sq = &tg->service_queue;
+
throtl_dequeue_tg(tg, parent_sq);
- while ((bio = bio_list_peek(&tg->bio_lists[READ])))
+ while ((bio = bio_list_peek(&sq->bio_lists[READ])))
tg_dispatch_one_bio(tg, bio_data_dir(bio), &bl);
- while ((bio = bio_list_peek(&tg->bio_lists[WRITE])))
+ while ((bio = bio_list_peek(&sq->bio_lists[WRITE])))
tg_dispatch_one_bio(tg, bio_data_dir(bio), &bl);
}
spin_unlock_irq(q->queue_lock);