| 
					
				 | 
			
			
				@@ -142,3 +142,181 @@ static inline struct throtl_grp *td_root_tg(struct throtl_data *td) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return blkg_to_tg(td->queue->root_blkg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+enum tg_state_flags { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	THROTL_TG_FLAG_on_rr = 0,	/* on round-robin busy list */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define THROTL_TG_FNS(name)						\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static inline void throtl_mark_tg_##name(struct throtl_grp *tg)		\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{									\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	(tg)->flags |= (1 << THROTL_TG_FLAG_##name);			\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}									\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static inline void throtl_clear_tg_##name(struct throtl_grp *tg)	\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{									\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	(tg)->flags &= ~(1 << THROTL_TG_FLAG_##name);			\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}									\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static inline int throtl_tg_##name(const struct throtl_grp *tg)		\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{									\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return ((tg)->flags & (1 << THROTL_TG_FLAG_##name)) != 0;	\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+THROTL_TG_FNS(on_rr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define throtl_log_tg(td, tg, fmt, args...)	do {			\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	char __pbuf[128];						\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	blkg_path(tg_to_blkg(tg), __pbuf, sizeof(__pbuf));		\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	blk_add_trace_msg((td)->queue, "throtl %s " fmt, __pbuf, ##args); \ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} while (0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define throtl_log(td, fmt, args...)	\ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	blk_add_trace_msg((td)->queue, "throtl " fmt, ##args) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static inline unsigned int total_nr_queued(struct throtl_data *td) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return td->nr_queued[0] + td->nr_queued[1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Worker for allocating per cpu stat for tgs. This is scheduled on the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * system_wq once there are some groups on the alloc_list waiting for 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * allocation. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void tg_stats_alloc_fn(struct work_struct *work) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	static struct tg_stats_cpu *stats_cpu;	/* this fn is non-reentrant */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct delayed_work *dwork = to_delayed_work(work); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	bool empty = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+alloc_stats: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!stats_cpu) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		stats_cpu = alloc_percpu(struct tg_stats_cpu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (!stats_cpu) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			/* allocation failed, try again after some time */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			schedule_delayed_work(dwork, msecs_to_jiffies(10)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	spin_lock_irq(&tg_stats_alloc_lock); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!list_empty(&tg_stats_alloc_list)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		struct throtl_grp *tg = list_first_entry(&tg_stats_alloc_list, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							 struct throtl_grp, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							 stats_alloc_node); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		swap(tg->stats_cpu, stats_cpu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		list_del_init(&tg->stats_alloc_node); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	empty = list_empty(&tg_stats_alloc_list); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	spin_unlock_irq(&tg_stats_alloc_lock); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!empty) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		goto alloc_stats; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void throtl_pd_init(struct blkcg_gq *blkg) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct throtl_grp *tg = blkg_to_tg(blkg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	unsigned long flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	RB_CLEAR_NODE(&tg->rb_node); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	bio_list_init(&tg->bio_lists[0]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	bio_list_init(&tg->bio_lists[1]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	tg->limits_changed = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	tg->bps[READ] = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	tg->bps[WRITE] = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	tg->iops[READ] = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	tg->iops[WRITE] = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 * Ugh... We need to perform per-cpu allocation for tg->stats_cpu 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 * but percpu allocator can't be called from IO path.  Queue tg on 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 * tg_stats_alloc_list and allocate from work item. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	spin_lock_irqsave(&tg_stats_alloc_lock, flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	list_add(&tg->stats_alloc_node, &tg_stats_alloc_list); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	schedule_delayed_work(&tg_stats_alloc_work, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	spin_unlock_irqrestore(&tg_stats_alloc_lock, flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void throtl_pd_exit(struct blkcg_gq *blkg) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct throtl_grp *tg = blkg_to_tg(blkg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	unsigned long flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	spin_lock_irqsave(&tg_stats_alloc_lock, flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	list_del_init(&tg->stats_alloc_node); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	spin_unlock_irqrestore(&tg_stats_alloc_lock, flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	free_percpu(tg->stats_cpu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void throtl_pd_reset_stats(struct blkcg_gq *blkg) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct throtl_grp *tg = blkg_to_tg(blkg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int cpu; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (tg->stats_cpu == NULL) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	for_each_possible_cpu(cpu) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		struct tg_stats_cpu *sc = per_cpu_ptr(tg->stats_cpu, cpu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		blkg_rwstat_reset(&sc->service_bytes); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		blkg_rwstat_reset(&sc->serviced); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static struct throtl_grp *throtl_lookup_tg(struct throtl_data *td, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					   struct blkcg *blkcg) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 * This is the common case when there are no blkcgs.  Avoid lookup 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 * in this case 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (blkcg == &blkcg_root) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return td_root_tg(td); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return blkg_to_tg(blkg_lookup(blkcg, td->queue)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static struct throtl_grp *throtl_lookup_create_tg(struct throtl_data *td, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						  struct blkcg *blkcg) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct request_queue *q = td->queue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct throtl_grp *tg = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 * This is the common case when there are no blkcgs.  Avoid lookup 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 * in this case 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (blkcg == &blkcg_root) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		tg = td_root_tg(td); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		struct blkcg_gq *blkg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		blkg = blkg_lookup_create(blkcg, q); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		/* if %NULL and @q is alive, fall back to root_tg */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (!IS_ERR(blkg)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			tg = blkg_to_tg(blkg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		else if (!blk_queue_dying(q)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			tg = td_root_tg(td); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return tg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static struct throtl_grp *throtl_rb_first(struct throtl_rb_root *root) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* Service tree is empty */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!root->count) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!root->left) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		root->left = rb_first(&root->rb); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (root->left) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return rb_entry_tg(root->left); 
			 |