Blame view

block/blk-cgroup.c 26.8 KB
31e4c28d9   Vivek Goyal   blkio: Introduce ...
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   * Common Block IO controller cgroup interface
   *
   * Based on ideas and code from CFQ, CFS and BFQ:
   * Copyright (C) 2003 Jens Axboe <axboe@kernel.dk>
   *
   * Copyright (C) 2008 Fabio Checconi <fabio@gandalf.sssup.it>
   *		      Paolo Valente <paolo.valente@unimore.it>
   *
   * Copyright (C) 2009 Vivek Goyal <vgoyal@redhat.com>
   * 	              Nauman Rafique <nauman@google.com>
   */
  #include <linux/ioprio.h>
220841906   Vivek Goyal   blkio: Export dis...
14
15
  #include <linux/seq_file.h>
  #include <linux/kdev_t.h>
9d6a986c0   Vivek Goyal   blkio: Export som...
16
  #include <linux/module.h>
accee7854   Stephen Rothwell   block: include li...
17
  #include <linux/err.h>
9195291e5   Divyesh Shah   blkio: Increment ...
18
  #include <linux/blkdev.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
19
  #include <linux/slab.h>
31e4c28d9   Vivek Goyal   blkio: Introduce ...
20
  #include "blk-cgroup.h"
34d0f179d   Gui Jianfeng   io-controller: Ad...
21
  #include <linux/genhd.h>
3e2520668   Vivek Goyal   blkio: Implement ...
22

84c124da9   Divyesh Shah   blkio: Changes to...
23
  #define MAX_KEY_LEN 100
3e2520668   Vivek Goyal   blkio: Implement ...
24
25
  static DEFINE_SPINLOCK(blkio_list_lock);
  static LIST_HEAD(blkio_list);
b1c357696   Vivek Goyal   blkio: Take care ...
26

31e4c28d9   Vivek Goyal   blkio: Introduce ...
27
  struct blkio_cgroup blkio_root_cgroup = { .weight = 2*BLKIO_WEIGHT_DEFAULT };
9d6a986c0   Vivek Goyal   blkio: Export som...
28
  EXPORT_SYMBOL_GPL(blkio_root_cgroup);
67523c48a   Ben Blum   cgroups: blkio su...
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
  static struct cgroup_subsys_state *blkiocg_create(struct cgroup_subsys *,
  						  struct cgroup *);
  static int blkiocg_can_attach(struct cgroup_subsys *, struct cgroup *,
  			      struct task_struct *, bool);
  static void blkiocg_attach(struct cgroup_subsys *, struct cgroup *,
  			   struct cgroup *, struct task_struct *, bool);
  static void blkiocg_destroy(struct cgroup_subsys *, struct cgroup *);
  static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *);
  
  struct cgroup_subsys blkio_subsys = {
  	.name = "blkio",
  	.create = blkiocg_create,
  	.can_attach = blkiocg_can_attach,
  	.attach = blkiocg_attach,
  	.destroy = blkiocg_destroy,
  	.populate = blkiocg_populate,
  #ifdef CONFIG_BLK_CGROUP
  	/* note: blkio_subsys_id is otherwise defined in blk-cgroup.h */
  	.subsys_id = blkio_subsys_id,
  #endif
  	.use_id = 1,
  	.module = THIS_MODULE,
  };
  EXPORT_SYMBOL_GPL(blkio_subsys);
34d0f179d   Gui Jianfeng   io-controller: Ad...
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  static inline void blkio_policy_insert_node(struct blkio_cgroup *blkcg,
  					    struct blkio_policy_node *pn)
  {
  	list_add(&pn->node, &blkcg->policy_list);
  }
  
  /* Must be called with blkcg->lock held */
  static inline void blkio_policy_delete_node(struct blkio_policy_node *pn)
  {
  	list_del(&pn->node);
  }
  
  /* Must be called with blkcg->lock held */
  static struct blkio_policy_node *
  blkio_policy_search_node(const struct blkio_cgroup *blkcg, dev_t dev)
  {
  	struct blkio_policy_node *pn;
  
  	list_for_each_entry(pn, &blkcg->policy_list, node) {
  		if (pn->dev == dev)
  			return pn;
  	}
  
  	return NULL;
  }
31e4c28d9   Vivek Goyal   blkio: Introduce ...
78
79
80
81
82
  struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup)
  {
  	return container_of(cgroup_subsys_state(cgroup, blkio_subsys_id),
  			    struct blkio_cgroup, css);
  }
9d6a986c0   Vivek Goyal   blkio: Export som...
83
  EXPORT_SYMBOL_GPL(cgroup_to_blkio_cgroup);
31e4c28d9   Vivek Goyal   blkio: Introduce ...
84

9195291e5   Divyesh Shah   blkio: Increment ...
85
86
87
88
  /*
   * Add to the appropriate stat variable depending on the request type.
   * This should be called with the blkg->stats_lock held.
   */
84c124da9   Divyesh Shah   blkio: Changes to...
89
90
  static void blkio_add_stat(uint64_t *stat, uint64_t add, bool direction,
  				bool sync)
9195291e5   Divyesh Shah   blkio: Increment ...
91
  {
84c124da9   Divyesh Shah   blkio: Changes to...
92
93
  	if (direction)
  		stat[BLKIO_STAT_WRITE] += add;
9195291e5   Divyesh Shah   blkio: Increment ...
94
  	else
84c124da9   Divyesh Shah   blkio: Changes to...
95
96
97
  		stat[BLKIO_STAT_READ] += add;
  	if (sync)
  		stat[BLKIO_STAT_SYNC] += add;
9195291e5   Divyesh Shah   blkio: Increment ...
98
  	else
84c124da9   Divyesh Shah   blkio: Changes to...
99
  		stat[BLKIO_STAT_ASYNC] += add;
9195291e5   Divyesh Shah   blkio: Increment ...
100
  }
cdc1184cf   Divyesh Shah   blkio: Add io_que...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  /*
   * Decrements the appropriate stat variable if non-zero depending on the
   * request type. Panics on value being zero.
   * This should be called with the blkg->stats_lock held.
   */
  static void blkio_check_and_dec_stat(uint64_t *stat, bool direction, bool sync)
  {
  	if (direction) {
  		BUG_ON(stat[BLKIO_STAT_WRITE] == 0);
  		stat[BLKIO_STAT_WRITE]--;
  	} else {
  		BUG_ON(stat[BLKIO_STAT_READ] == 0);
  		stat[BLKIO_STAT_READ]--;
  	}
  	if (sync) {
  		BUG_ON(stat[BLKIO_STAT_SYNC] == 0);
  		stat[BLKIO_STAT_SYNC]--;
  	} else {
  		BUG_ON(stat[BLKIO_STAT_ASYNC] == 0);
  		stat[BLKIO_STAT_ASYNC]--;
  	}
  }
  
  #ifdef CONFIG_DEBUG_BLK_CGROUP
812df48d1   Divyesh Shah   blkio: Add more d...
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
  /* This should be called with the blkg->stats_lock held. */
  static void blkio_set_start_group_wait_time(struct blkio_group *blkg,
  						struct blkio_group *curr_blkg)
  {
  	if (blkio_blkg_waiting(&blkg->stats))
  		return;
  	if (blkg == curr_blkg)
  		return;
  	blkg->stats.start_group_wait_time = sched_clock();
  	blkio_mark_blkg_waiting(&blkg->stats);
  }
  
  /* This should be called with the blkg->stats_lock held. */
  static void blkio_update_group_wait_time(struct blkio_group_stats *stats)
  {
  	unsigned long long now;
  
  	if (!blkio_blkg_waiting(stats))
  		return;
  
  	now = sched_clock();
  	if (time_after64(now, stats->start_group_wait_time))
  		stats->group_wait_time += now - stats->start_group_wait_time;
  	blkio_clear_blkg_waiting(stats);
  }
  
  /* This should be called with the blkg->stats_lock held. */
  static void blkio_end_empty_time(struct blkio_group_stats *stats)
  {
  	unsigned long long now;
  
  	if (!blkio_blkg_empty(stats))
  		return;
  
  	now = sched_clock();
  	if (time_after64(now, stats->start_empty_time))
  		stats->empty_time += now - stats->start_empty_time;
  	blkio_clear_blkg_empty(stats);
  }
  
  void blkiocg_update_set_idle_time_stats(struct blkio_group *blkg)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&blkg->stats_lock, flags);
  	BUG_ON(blkio_blkg_idling(&blkg->stats));
  	blkg->stats.start_idle_time = sched_clock();
  	blkio_mark_blkg_idling(&blkg->stats);
  	spin_unlock_irqrestore(&blkg->stats_lock, flags);
  }
  EXPORT_SYMBOL_GPL(blkiocg_update_set_idle_time_stats);
  
  void blkiocg_update_idle_time_stats(struct blkio_group *blkg)
  {
  	unsigned long flags;
  	unsigned long long now;
  	struct blkio_group_stats *stats;
  
  	spin_lock_irqsave(&blkg->stats_lock, flags);
  	stats = &blkg->stats;
  	if (blkio_blkg_idling(stats)) {
  		now = sched_clock();
  		if (time_after64(now, stats->start_idle_time))
  			stats->idle_time += now - stats->start_idle_time;
  		blkio_clear_blkg_idling(stats);
  	}
  	spin_unlock_irqrestore(&blkg->stats_lock, flags);
  }
  EXPORT_SYMBOL_GPL(blkiocg_update_idle_time_stats);
a11cdaa7a   Divyesh Shah   block: Update to ...
194
  void blkiocg_update_avg_queue_size_stats(struct blkio_group *blkg)
cdc1184cf   Divyesh Shah   blkio: Add io_que...
195
196
197
198
199
200
201
202
203
204
  {
  	unsigned long flags;
  	struct blkio_group_stats *stats;
  
  	spin_lock_irqsave(&blkg->stats_lock, flags);
  	stats = &blkg->stats;
  	stats->avg_queue_size_sum +=
  			stats->stat_arr[BLKIO_STAT_QUEUED][BLKIO_STAT_READ] +
  			stats->stat_arr[BLKIO_STAT_QUEUED][BLKIO_STAT_WRITE];
  	stats->avg_queue_size_samples++;
812df48d1   Divyesh Shah   blkio: Add more d...
205
  	blkio_update_group_wait_time(stats);
cdc1184cf   Divyesh Shah   blkio: Add io_que...
206
207
  	spin_unlock_irqrestore(&blkg->stats_lock, flags);
  }
a11cdaa7a   Divyesh Shah   block: Update to ...
208
  EXPORT_SYMBOL_GPL(blkiocg_update_avg_queue_size_stats);
e5ff082e8   Vivek Goyal   blkio: Fix anothe...
209
  void blkiocg_set_start_empty_time(struct blkio_group *blkg)
28baf4429   Divyesh Shah   blkio: Fix compil...
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  {
  	unsigned long flags;
  	struct blkio_group_stats *stats;
  
  	spin_lock_irqsave(&blkg->stats_lock, flags);
  	stats = &blkg->stats;
  
  	if (stats->stat_arr[BLKIO_STAT_QUEUED][BLKIO_STAT_READ] ||
  			stats->stat_arr[BLKIO_STAT_QUEUED][BLKIO_STAT_WRITE]) {
  		spin_unlock_irqrestore(&blkg->stats_lock, flags);
  		return;
  	}
  
  	/*
e5ff082e8   Vivek Goyal   blkio: Fix anothe...
224
225
226
  	 * group is already marked empty. This can happen if cfqq got new
  	 * request in parent group and moved to this group while being added
  	 * to service tree. Just ignore the event and move on.
28baf4429   Divyesh Shah   blkio: Fix compil...
227
  	 */
e5ff082e8   Vivek Goyal   blkio: Fix anothe...
228
229
230
231
  	if(blkio_blkg_empty(stats)) {
  		spin_unlock_irqrestore(&blkg->stats_lock, flags);
  		return;
  	}
28baf4429   Divyesh Shah   blkio: Fix compil...
232
233
234
235
236
  	stats->start_empty_time = sched_clock();
  	blkio_mark_blkg_empty(stats);
  	spin_unlock_irqrestore(&blkg->stats_lock, flags);
  }
  EXPORT_SYMBOL_GPL(blkiocg_set_start_empty_time);
a11cdaa7a   Divyesh Shah   block: Update to ...
237
238
239
240
241
242
  void blkiocg_update_dequeue_stats(struct blkio_group *blkg,
  			unsigned long dequeue)
  {
  	blkg->stats.dequeue += dequeue;
  }
  EXPORT_SYMBOL_GPL(blkiocg_update_dequeue_stats);
812df48d1   Divyesh Shah   blkio: Add more d...
243
244
245
246
  #else
  static inline void blkio_set_start_group_wait_time(struct blkio_group *blkg,
  					struct blkio_group *curr_blkg) {}
  static inline void blkio_end_empty_time(struct blkio_group_stats *stats) {}
cdc1184cf   Divyesh Shah   blkio: Add io_que...
247
  #endif
a11cdaa7a   Divyesh Shah   block: Update to ...
248
  void blkiocg_update_io_add_stats(struct blkio_group *blkg,
cdc1184cf   Divyesh Shah   blkio: Add io_que...
249
250
251
252
253
254
255
256
  			struct blkio_group *curr_blkg, bool direction,
  			bool sync)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&blkg->stats_lock, flags);
  	blkio_add_stat(blkg->stats.stat_arr[BLKIO_STAT_QUEUED], 1, direction,
  			sync);
812df48d1   Divyesh Shah   blkio: Add more d...
257
258
  	blkio_end_empty_time(&blkg->stats);
  	blkio_set_start_group_wait_time(blkg, curr_blkg);
cdc1184cf   Divyesh Shah   blkio: Add io_que...
259
260
  	spin_unlock_irqrestore(&blkg->stats_lock, flags);
  }
a11cdaa7a   Divyesh Shah   block: Update to ...
261
  EXPORT_SYMBOL_GPL(blkiocg_update_io_add_stats);
cdc1184cf   Divyesh Shah   blkio: Add io_que...
262

a11cdaa7a   Divyesh Shah   block: Update to ...
263
  void blkiocg_update_io_remove_stats(struct blkio_group *blkg,
cdc1184cf   Divyesh Shah   blkio: Add io_que...
264
265
266
267
268
269
270
271
272
  						bool direction, bool sync)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&blkg->stats_lock, flags);
  	blkio_check_and_dec_stat(blkg->stats.stat_arr[BLKIO_STAT_QUEUED],
  					direction, sync);
  	spin_unlock_irqrestore(&blkg->stats_lock, flags);
  }
a11cdaa7a   Divyesh Shah   block: Update to ...
273
  EXPORT_SYMBOL_GPL(blkiocg_update_io_remove_stats);
cdc1184cf   Divyesh Shah   blkio: Add io_que...
274

303a3acb2   Divyesh Shah   blkio: Add io con...
275
  void blkiocg_update_timeslice_used(struct blkio_group *blkg, unsigned long time)
220841906   Vivek Goyal   blkio: Export dis...
276
  {
303a3acb2   Divyesh Shah   blkio: Add io con...
277
278
279
280
281
  	unsigned long flags;
  
  	spin_lock_irqsave(&blkg->stats_lock, flags);
  	blkg->stats.time += time;
  	spin_unlock_irqrestore(&blkg->stats_lock, flags);
220841906   Vivek Goyal   blkio: Export dis...
282
  }
303a3acb2   Divyesh Shah   blkio: Add io con...
283
  EXPORT_SYMBOL_GPL(blkiocg_update_timeslice_used);
220841906   Vivek Goyal   blkio: Export dis...
284

84c124da9   Divyesh Shah   blkio: Changes to...
285
286
  void blkiocg_update_dispatch_stats(struct blkio_group *blkg,
  				uint64_t bytes, bool direction, bool sync)
9195291e5   Divyesh Shah   blkio: Increment ...
287
288
289
290
291
292
  {
  	struct blkio_group_stats *stats;
  	unsigned long flags;
  
  	spin_lock_irqsave(&blkg->stats_lock, flags);
  	stats = &blkg->stats;
84c124da9   Divyesh Shah   blkio: Changes to...
293
294
295
296
297
  	stats->sectors += bytes >> 9;
  	blkio_add_stat(stats->stat_arr[BLKIO_STAT_SERVICED], 1, direction,
  			sync);
  	blkio_add_stat(stats->stat_arr[BLKIO_STAT_SERVICE_BYTES], bytes,
  			direction, sync);
9195291e5   Divyesh Shah   blkio: Increment ...
298
299
  	spin_unlock_irqrestore(&blkg->stats_lock, flags);
  }
84c124da9   Divyesh Shah   blkio: Changes to...
300
  EXPORT_SYMBOL_GPL(blkiocg_update_dispatch_stats);
9195291e5   Divyesh Shah   blkio: Increment ...
301

84c124da9   Divyesh Shah   blkio: Changes to...
302
303
  void blkiocg_update_completion_stats(struct blkio_group *blkg,
  	uint64_t start_time, uint64_t io_start_time, bool direction, bool sync)
9195291e5   Divyesh Shah   blkio: Increment ...
304
305
306
307
308
309
310
  {
  	struct blkio_group_stats *stats;
  	unsigned long flags;
  	unsigned long long now = sched_clock();
  
  	spin_lock_irqsave(&blkg->stats_lock, flags);
  	stats = &blkg->stats;
84c124da9   Divyesh Shah   blkio: Changes to...
311
312
313
314
315
316
  	if (time_after64(now, io_start_time))
  		blkio_add_stat(stats->stat_arr[BLKIO_STAT_SERVICE_TIME],
  				now - io_start_time, direction, sync);
  	if (time_after64(io_start_time, start_time))
  		blkio_add_stat(stats->stat_arr[BLKIO_STAT_WAIT_TIME],
  				io_start_time - start_time, direction, sync);
9195291e5   Divyesh Shah   blkio: Increment ...
317
318
  	spin_unlock_irqrestore(&blkg->stats_lock, flags);
  }
84c124da9   Divyesh Shah   blkio: Changes to...
319
  EXPORT_SYMBOL_GPL(blkiocg_update_completion_stats);
9195291e5   Divyesh Shah   blkio: Increment ...
320

812d40264   Divyesh Shah   blkio: Add io_mer...
321
322
323
324
325
326
327
328
329
330
331
  void blkiocg_update_io_merged_stats(struct blkio_group *blkg, bool direction,
  					bool sync)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&blkg->stats_lock, flags);
  	blkio_add_stat(blkg->stats.stat_arr[BLKIO_STAT_MERGED], 1, direction,
  			sync);
  	spin_unlock_irqrestore(&blkg->stats_lock, flags);
  }
  EXPORT_SYMBOL_GPL(blkiocg_update_io_merged_stats);
31e4c28d9   Vivek Goyal   blkio: Introduce ...
332
  void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
220841906   Vivek Goyal   blkio: Export dis...
333
  			struct blkio_group *blkg, void *key, dev_t dev)
31e4c28d9   Vivek Goyal   blkio: Introduce ...
334
335
336
337
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&blkcg->lock, flags);
8d2a91f89   Divyesh Shah   blkio: Initialize...
338
  	spin_lock_init(&blkg->stats_lock);
31e4c28d9   Vivek Goyal   blkio: Introduce ...
339
  	rcu_assign_pointer(blkg->key, key);
b1c357696   Vivek Goyal   blkio: Take care ...
340
  	blkg->blkcg_id = css_id(&blkcg->css);
31e4c28d9   Vivek Goyal   blkio: Introduce ...
341
342
  	hlist_add_head_rcu(&blkg->blkcg_node, &blkcg->blkg_list);
  	spin_unlock_irqrestore(&blkcg->lock, flags);
2868ef7b3   Vivek Goyal   blkio: Some debug...
343
344
  	/* Need to take css reference ? */
  	cgroup_path(blkcg->css.cgroup, blkg->path, sizeof(blkg->path));
220841906   Vivek Goyal   blkio: Export dis...
345
  	blkg->dev = dev;
31e4c28d9   Vivek Goyal   blkio: Introduce ...
346
  }
9d6a986c0   Vivek Goyal   blkio: Export som...
347
  EXPORT_SYMBOL_GPL(blkiocg_add_blkio_group);
31e4c28d9   Vivek Goyal   blkio: Introduce ...
348

b1c357696   Vivek Goyal   blkio: Take care ...
349
350
351
352
353
354
355
356
357
358
  static void __blkiocg_del_blkio_group(struct blkio_group *blkg)
  {
  	hlist_del_init_rcu(&blkg->blkcg_node);
  	blkg->blkcg_id = 0;
  }
  
  /*
   * returns 0 if blkio_group was still on cgroup list. Otherwise returns 1
   * indicating that blk_group was unhashed by the time we got to it.
   */
31e4c28d9   Vivek Goyal   blkio: Introduce ...
359
360
  int blkiocg_del_blkio_group(struct blkio_group *blkg)
  {
b1c357696   Vivek Goyal   blkio: Take care ...
361
362
363
364
365
366
367
  	struct blkio_cgroup *blkcg;
  	unsigned long flags;
  	struct cgroup_subsys_state *css;
  	int ret = 1;
  
  	rcu_read_lock();
  	css = css_lookup(&blkio_subsys, blkg->blkcg_id);
0f3942a39   Jens Axboe   block: kill some ...
368
369
370
371
372
373
374
375
  	if (css) {
  		blkcg = container_of(css, struct blkio_cgroup, css);
  		spin_lock_irqsave(&blkcg->lock, flags);
  		if (!hlist_unhashed(&blkg->blkcg_node)) {
  			__blkiocg_del_blkio_group(blkg);
  			ret = 0;
  		}
  		spin_unlock_irqrestore(&blkcg->lock, flags);
b1c357696   Vivek Goyal   blkio: Take care ...
376
  	}
0f3942a39   Jens Axboe   block: kill some ...
377

b1c357696   Vivek Goyal   blkio: Take care ...
378
379
  	rcu_read_unlock();
  	return ret;
31e4c28d9   Vivek Goyal   blkio: Introduce ...
380
  }
9d6a986c0   Vivek Goyal   blkio: Export som...
381
  EXPORT_SYMBOL_GPL(blkiocg_del_blkio_group);
31e4c28d9   Vivek Goyal   blkio: Introduce ...
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
  
  /* called under rcu_read_lock(). */
  struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg, void *key)
  {
  	struct blkio_group *blkg;
  	struct hlist_node *n;
  	void *__key;
  
  	hlist_for_each_entry_rcu(blkg, n, &blkcg->blkg_list, blkcg_node) {
  		__key = blkg->key;
  		if (__key == key)
  			return blkg;
  	}
  
  	return NULL;
  }
9d6a986c0   Vivek Goyal   blkio: Export som...
398
  EXPORT_SYMBOL_GPL(blkiocg_lookup_group);
31e4c28d9   Vivek Goyal   blkio: Introduce ...
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  
  #define SHOW_FUNCTION(__VAR)						\
  static u64 blkiocg_##__VAR##_read(struct cgroup *cgroup,		\
  				       struct cftype *cftype)		\
  {									\
  	struct blkio_cgroup *blkcg;					\
  									\
  	blkcg = cgroup_to_blkio_cgroup(cgroup);				\
  	return (u64)blkcg->__VAR;					\
  }
  
  SHOW_FUNCTION(weight);
  #undef SHOW_FUNCTION
  
  static int
  blkiocg_weight_write(struct cgroup *cgroup, struct cftype *cftype, u64 val)
  {
  	struct blkio_cgroup *blkcg;
f8d461d69   Vivek Goyal   blkio: Propagate ...
417
418
  	struct blkio_group *blkg;
  	struct hlist_node *n;
3e2520668   Vivek Goyal   blkio: Implement ...
419
  	struct blkio_policy_type *blkiop;
34d0f179d   Gui Jianfeng   io-controller: Ad...
420
  	struct blkio_policy_node *pn;
31e4c28d9   Vivek Goyal   blkio: Introduce ...
421
422
423
424
425
  
  	if (val < BLKIO_WEIGHT_MIN || val > BLKIO_WEIGHT_MAX)
  		return -EINVAL;
  
  	blkcg = cgroup_to_blkio_cgroup(cgroup);
bcf4dd434   Gui Jianfeng   blk-cgroup: Fix p...
426
  	spin_lock(&blkio_list_lock);
f8d461d69   Vivek Goyal   blkio: Propagate ...
427
  	spin_lock_irq(&blkcg->lock);
31e4c28d9   Vivek Goyal   blkio: Introduce ...
428
  	blkcg->weight = (unsigned int)val;
34d0f179d   Gui Jianfeng   io-controller: Ad...
429

3e2520668   Vivek Goyal   blkio: Implement ...
430
  	hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) {
34d0f179d   Gui Jianfeng   io-controller: Ad...
431
432
433
434
  		pn = blkio_policy_search_node(blkcg, blkg->dev);
  
  		if (pn)
  			continue;
3e2520668   Vivek Goyal   blkio: Implement ...
435
436
437
  		list_for_each_entry(blkiop, &blkio_list, list)
  			blkiop->ops.blkio_update_group_weight_fn(blkg,
  					blkcg->weight);
3e2520668   Vivek Goyal   blkio: Implement ...
438
  	}
f8d461d69   Vivek Goyal   blkio: Propagate ...
439
  	spin_unlock_irq(&blkcg->lock);
bcf4dd434   Gui Jianfeng   blk-cgroup: Fix p...
440
  	spin_unlock(&blkio_list_lock);
31e4c28d9   Vivek Goyal   blkio: Introduce ...
441
442
  	return 0;
  }
303a3acb2   Divyesh Shah   blkio: Add io con...
443
  static int
84c124da9   Divyesh Shah   blkio: Changes to...
444
  blkiocg_reset_stats(struct cgroup *cgroup, struct cftype *cftype, u64 val)
303a3acb2   Divyesh Shah   blkio: Add io con...
445
446
447
  {
  	struct blkio_cgroup *blkcg;
  	struct blkio_group *blkg;
812df48d1   Divyesh Shah   blkio: Add more d...
448
  	struct blkio_group_stats *stats;
303a3acb2   Divyesh Shah   blkio: Add io con...
449
  	struct hlist_node *n;
cdc1184cf   Divyesh Shah   blkio: Add io_que...
450
451
  	uint64_t queued[BLKIO_STAT_TOTAL];
  	int i;
812df48d1   Divyesh Shah   blkio: Add more d...
452
453
454
455
  #ifdef CONFIG_DEBUG_BLK_CGROUP
  	bool idling, waiting, empty;
  	unsigned long long now = sched_clock();
  #endif
303a3acb2   Divyesh Shah   blkio: Add io con...
456
457
458
459
460
  
  	blkcg = cgroup_to_blkio_cgroup(cgroup);
  	spin_lock_irq(&blkcg->lock);
  	hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) {
  		spin_lock(&blkg->stats_lock);
812df48d1   Divyesh Shah   blkio: Add more d...
461
462
463
464
465
466
  		stats = &blkg->stats;
  #ifdef CONFIG_DEBUG_BLK_CGROUP
  		idling = blkio_blkg_idling(stats);
  		waiting = blkio_blkg_waiting(stats);
  		empty = blkio_blkg_empty(stats);
  #endif
cdc1184cf   Divyesh Shah   blkio: Add io_que...
467
  		for (i = 0; i < BLKIO_STAT_TOTAL; i++)
812df48d1   Divyesh Shah   blkio: Add more d...
468
469
  			queued[i] = stats->stat_arr[BLKIO_STAT_QUEUED][i];
  		memset(stats, 0, sizeof(struct blkio_group_stats));
cdc1184cf   Divyesh Shah   blkio: Add io_que...
470
  		for (i = 0; i < BLKIO_STAT_TOTAL; i++)
812df48d1   Divyesh Shah   blkio: Add more d...
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
  			stats->stat_arr[BLKIO_STAT_QUEUED][i] = queued[i];
  #ifdef CONFIG_DEBUG_BLK_CGROUP
  		if (idling) {
  			blkio_mark_blkg_idling(stats);
  			stats->start_idle_time = now;
  		}
  		if (waiting) {
  			blkio_mark_blkg_waiting(stats);
  			stats->start_group_wait_time = now;
  		}
  		if (empty) {
  			blkio_mark_blkg_empty(stats);
  			stats->start_empty_time = now;
  		}
  #endif
303a3acb2   Divyesh Shah   blkio: Add io con...
486
487
488
489
490
  		spin_unlock(&blkg->stats_lock);
  	}
  	spin_unlock_irq(&blkcg->lock);
  	return 0;
  }
84c124da9   Divyesh Shah   blkio: Changes to...
491
492
  static void blkio_get_key_name(enum stat_sub_type type, dev_t dev, char *str,
  				int chars_left, bool diskname_only)
303a3acb2   Divyesh Shah   blkio: Add io con...
493
  {
84c124da9   Divyesh Shah   blkio: Changes to...
494
  	snprintf(str, chars_left, "%d:%d", MAJOR(dev), MINOR(dev));
303a3acb2   Divyesh Shah   blkio: Add io con...
495
496
497
498
499
500
  	chars_left -= strlen(str);
  	if (chars_left <= 0) {
  		printk(KERN_WARNING
  			"Possibly incorrect cgroup stat display format");
  		return;
  	}
84c124da9   Divyesh Shah   blkio: Changes to...
501
502
  	if (diskname_only)
  		return;
303a3acb2   Divyesh Shah   blkio: Add io con...
503
  	switch (type) {
84c124da9   Divyesh Shah   blkio: Changes to...
504
  	case BLKIO_STAT_READ:
303a3acb2   Divyesh Shah   blkio: Add io con...
505
506
  		strlcat(str, " Read", chars_left);
  		break;
84c124da9   Divyesh Shah   blkio: Changes to...
507
  	case BLKIO_STAT_WRITE:
303a3acb2   Divyesh Shah   blkio: Add io con...
508
509
  		strlcat(str, " Write", chars_left);
  		break;
84c124da9   Divyesh Shah   blkio: Changes to...
510
  	case BLKIO_STAT_SYNC:
303a3acb2   Divyesh Shah   blkio: Add io con...
511
512
  		strlcat(str, " Sync", chars_left);
  		break;
84c124da9   Divyesh Shah   blkio: Changes to...
513
  	case BLKIO_STAT_ASYNC:
303a3acb2   Divyesh Shah   blkio: Add io con...
514
515
  		strlcat(str, " Async", chars_left);
  		break;
84c124da9   Divyesh Shah   blkio: Changes to...
516
  	case BLKIO_STAT_TOTAL:
303a3acb2   Divyesh Shah   blkio: Add io con...
517
518
519
520
521
522
  		strlcat(str, " Total", chars_left);
  		break;
  	default:
  		strlcat(str, " Invalid", chars_left);
  	}
  }
84c124da9   Divyesh Shah   blkio: Changes to...
523
524
525
526
527
528
529
  static uint64_t blkio_fill_stat(char *str, int chars_left, uint64_t val,
  				struct cgroup_map_cb *cb, dev_t dev)
  {
  	blkio_get_key_name(0, dev, str, chars_left, true);
  	cb->fill(cb, str, val);
  	return val;
  }
303a3acb2   Divyesh Shah   blkio: Add io con...
530

84c124da9   Divyesh Shah   blkio: Changes to...
531
532
533
  /* This should be called with blkg->stats_lock held */
  static uint64_t blkio_get_stat(struct blkio_group *blkg,
  		struct cgroup_map_cb *cb, dev_t dev, enum stat_type type)
303a3acb2   Divyesh Shah   blkio: Add io con...
534
535
536
  {
  	uint64_t disk_total;
  	char key_str[MAX_KEY_LEN];
84c124da9   Divyesh Shah   blkio: Changes to...
537
538
539
540
541
542
543
544
545
  	enum stat_sub_type sub_type;
  
  	if (type == BLKIO_STAT_TIME)
  		return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
  					blkg->stats.time, cb, dev);
  	if (type == BLKIO_STAT_SECTORS)
  		return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
  					blkg->stats.sectors, cb, dev);
  #ifdef CONFIG_DEBUG_BLK_CGROUP
cdc1184cf   Divyesh Shah   blkio: Add io_que...
546
547
548
549
550
551
552
553
554
  	if (type == BLKIO_STAT_AVG_QUEUE_SIZE) {
  		uint64_t sum = blkg->stats.avg_queue_size_sum;
  		uint64_t samples = blkg->stats.avg_queue_size_samples;
  		if (samples)
  			do_div(sum, samples);
  		else
  			sum = 0;
  		return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, sum, cb, dev);
  	}
812df48d1   Divyesh Shah   blkio: Add more d...
555
556
557
558
559
560
561
562
563
  	if (type == BLKIO_STAT_GROUP_WAIT_TIME)
  		return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
  					blkg->stats.group_wait_time, cb, dev);
  	if (type == BLKIO_STAT_IDLE_TIME)
  		return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
  					blkg->stats.idle_time, cb, dev);
  	if (type == BLKIO_STAT_EMPTY_TIME)
  		return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
  					blkg->stats.empty_time, cb, dev);
84c124da9   Divyesh Shah   blkio: Changes to...
564
565
566
567
  	if (type == BLKIO_STAT_DEQUEUE)
  		return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
  					blkg->stats.dequeue, cb, dev);
  #endif
303a3acb2   Divyesh Shah   blkio: Add io con...
568

84c124da9   Divyesh Shah   blkio: Changes to...
569
570
571
572
  	for (sub_type = BLKIO_STAT_READ; sub_type < BLKIO_STAT_TOTAL;
  			sub_type++) {
  		blkio_get_key_name(sub_type, dev, key_str, MAX_KEY_LEN, false);
  		cb->fill(cb, key_str, blkg->stats.stat_arr[type][sub_type]);
303a3acb2   Divyesh Shah   blkio: Add io con...
573
  	}
84c124da9   Divyesh Shah   blkio: Changes to...
574
575
576
  	disk_total = blkg->stats.stat_arr[type][BLKIO_STAT_READ] +
  			blkg->stats.stat_arr[type][BLKIO_STAT_WRITE];
  	blkio_get_key_name(BLKIO_STAT_TOTAL, dev, key_str, MAX_KEY_LEN, false);
303a3acb2   Divyesh Shah   blkio: Add io con...
577
578
579
  	cb->fill(cb, key_str, disk_total);
  	return disk_total;
  }
84c124da9   Divyesh Shah   blkio: Changes to...
580
  #define SHOW_FUNCTION_PER_GROUP(__VAR, type, show_total)		\
220841906   Vivek Goyal   blkio: Export dis...
581
  static int blkiocg_##__VAR##_read(struct cgroup *cgroup,		\
303a3acb2   Divyesh Shah   blkio: Add io con...
582
  		struct cftype *cftype, struct cgroup_map_cb *cb)	\
220841906   Vivek Goyal   blkio: Export dis...
583
584
585
586
  {									\
  	struct blkio_cgroup *blkcg;					\
  	struct blkio_group *blkg;					\
  	struct hlist_node *n;						\
303a3acb2   Divyesh Shah   blkio: Add io con...
587
  	uint64_t cgroup_total = 0;					\
220841906   Vivek Goyal   blkio: Export dis...
588
589
590
591
592
593
594
  									\
  	if (!cgroup_lock_live_group(cgroup))				\
  		return -ENODEV;						\
  									\
  	blkcg = cgroup_to_blkio_cgroup(cgroup);				\
  	rcu_read_lock();						\
  	hlist_for_each_entry_rcu(blkg, n, &blkcg->blkg_list, blkcg_node) {\
303a3acb2   Divyesh Shah   blkio: Add io con...
595
596
  		if (blkg->dev) {					\
  			spin_lock_irq(&blkg->stats_lock);		\
84c124da9   Divyesh Shah   blkio: Changes to...
597
598
  			cgroup_total += blkio_get_stat(blkg, cb,	\
  						blkg->dev, type);	\
303a3acb2   Divyesh Shah   blkio: Add io con...
599
600
  			spin_unlock_irq(&blkg->stats_lock);		\
  		}							\
220841906   Vivek Goyal   blkio: Export dis...
601
  	}								\
303a3acb2   Divyesh Shah   blkio: Add io con...
602
603
  	if (show_total)							\
  		cb->fill(cb, "Total", cgroup_total);			\
220841906   Vivek Goyal   blkio: Export dis...
604
605
606
607
  	rcu_read_unlock();						\
  	cgroup_unlock();						\
  	return 0;							\
  }
84c124da9   Divyesh Shah   blkio: Changes to...
608
609
610
611
612
613
  SHOW_FUNCTION_PER_GROUP(time, BLKIO_STAT_TIME, 0);
  SHOW_FUNCTION_PER_GROUP(sectors, BLKIO_STAT_SECTORS, 0);
  SHOW_FUNCTION_PER_GROUP(io_service_bytes, BLKIO_STAT_SERVICE_BYTES, 1);
  SHOW_FUNCTION_PER_GROUP(io_serviced, BLKIO_STAT_SERVICED, 1);
  SHOW_FUNCTION_PER_GROUP(io_service_time, BLKIO_STAT_SERVICE_TIME, 1);
  SHOW_FUNCTION_PER_GROUP(io_wait_time, BLKIO_STAT_WAIT_TIME, 1);
812d40264   Divyesh Shah   blkio: Add io_mer...
614
  SHOW_FUNCTION_PER_GROUP(io_merged, BLKIO_STAT_MERGED, 1);
cdc1184cf   Divyesh Shah   blkio: Add io_que...
615
  SHOW_FUNCTION_PER_GROUP(io_queued, BLKIO_STAT_QUEUED, 1);
220841906   Vivek Goyal   blkio: Export dis...
616
  #ifdef CONFIG_DEBUG_BLK_CGROUP
84c124da9   Divyesh Shah   blkio: Changes to...
617
  SHOW_FUNCTION_PER_GROUP(dequeue, BLKIO_STAT_DEQUEUE, 0);
cdc1184cf   Divyesh Shah   blkio: Add io_que...
618
  SHOW_FUNCTION_PER_GROUP(avg_queue_size, BLKIO_STAT_AVG_QUEUE_SIZE, 0);
812df48d1   Divyesh Shah   blkio: Add more d...
619
620
621
  SHOW_FUNCTION_PER_GROUP(group_wait_time, BLKIO_STAT_GROUP_WAIT_TIME, 0);
  SHOW_FUNCTION_PER_GROUP(idle_time, BLKIO_STAT_IDLE_TIME, 0);
  SHOW_FUNCTION_PER_GROUP(empty_time, BLKIO_STAT_EMPTY_TIME, 0);
220841906   Vivek Goyal   blkio: Export dis...
622
623
  #endif
  #undef SHOW_FUNCTION_PER_GROUP
34d0f179d   Gui Jianfeng   io-controller: Ad...
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
  static int blkio_check_dev_num(dev_t dev)
  {
  	int part = 0;
  	struct gendisk *disk;
  
  	disk = get_gendisk(dev, &part);
  	if (!disk || part)
  		return -ENODEV;
  
  	return 0;
  }
  
  static int blkio_policy_parse_and_set(char *buf,
  				      struct blkio_policy_node *newpn)
  {
  	char *s[4], *p, *major_s = NULL, *minor_s = NULL;
  	int ret;
  	unsigned long major, minor, temp;
  	int i = 0;
  	dev_t dev;
  
  	memset(s, 0, sizeof(s));
  
  	while ((p = strsep(&buf, " ")) != NULL) {
  		if (!*p)
  			continue;
  
  		s[i++] = p;
  
  		/* Prevent from inputing too many things */
  		if (i == 3)
  			break;
  	}
  
  	if (i != 2)
  		return -EINVAL;
  
  	p = strsep(&s[0], ":");
  	if (p != NULL)
  		major_s = p;
  	else
  		return -EINVAL;
  
  	minor_s = s[0];
  	if (!minor_s)
  		return -EINVAL;
  
  	ret = strict_strtoul(major_s, 10, &major);
  	if (ret)
  		return -EINVAL;
  
  	ret = strict_strtoul(minor_s, 10, &minor);
  	if (ret)
  		return -EINVAL;
  
  	dev = MKDEV(major, minor);
  
  	ret = blkio_check_dev_num(dev);
  	if (ret)
  		return ret;
  
  	newpn->dev = dev;
  
  	if (s[1] == NULL)
  		return -EINVAL;
  
  	ret = strict_strtoul(s[1], 10, &temp);
  	if (ret || (temp < BLKIO_WEIGHT_MIN && temp > 0) ||
  	    temp > BLKIO_WEIGHT_MAX)
  		return -EINVAL;
  
  	newpn->weight =  temp;
  
  	return 0;
  }
  
  unsigned int blkcg_get_weight(struct blkio_cgroup *blkcg,
  			      dev_t dev)
  {
  	struct blkio_policy_node *pn;
  
  	pn = blkio_policy_search_node(blkcg, dev);
  	if (pn)
  		return pn->weight;
  	else
  		return blkcg->weight;
  }
  EXPORT_SYMBOL_GPL(blkcg_get_weight);
  
  
  static int blkiocg_weight_device_write(struct cgroup *cgrp, struct cftype *cft,
  				       const char *buffer)
  {
  	int ret = 0;
  	char *buf;
  	struct blkio_policy_node *newpn, *pn;
  	struct blkio_cgroup *blkcg;
  	struct blkio_group *blkg;
  	int keep_newpn = 0;
  	struct hlist_node *n;
  	struct blkio_policy_type *blkiop;
  
  	buf = kstrdup(buffer, GFP_KERNEL);
  	if (!buf)
  		return -ENOMEM;
  
  	newpn = kzalloc(sizeof(*newpn), GFP_KERNEL);
  	if (!newpn) {
  		ret = -ENOMEM;
  		goto free_buf;
  	}
  
  	ret = blkio_policy_parse_and_set(buf, newpn);
  	if (ret)
  		goto free_newpn;
  
  	blkcg = cgroup_to_blkio_cgroup(cgrp);
  
  	spin_lock_irq(&blkcg->lock);
  
  	pn = blkio_policy_search_node(blkcg, newpn->dev);
  	if (!pn) {
  		if (newpn->weight != 0) {
  			blkio_policy_insert_node(blkcg, newpn);
  			keep_newpn = 1;
  		}
  		spin_unlock_irq(&blkcg->lock);
  		goto update_io_group;
  	}
  
  	if (newpn->weight == 0) {
  		/* weight == 0 means deleteing a specific weight */
  		blkio_policy_delete_node(pn);
  		spin_unlock_irq(&blkcg->lock);
  		goto update_io_group;
  	}
  	spin_unlock_irq(&blkcg->lock);
  
  	pn->weight = newpn->weight;
  
  update_io_group:
  	/* update weight for each cfqg */
  	spin_lock(&blkio_list_lock);
  	spin_lock_irq(&blkcg->lock);
  
  	hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) {
  		if (newpn->dev == blkg->dev) {
  			list_for_each_entry(blkiop, &blkio_list, list)
  				blkiop->ops.blkio_update_group_weight_fn(blkg,
  							 newpn->weight ?
  							 newpn->weight :
  							 blkcg->weight);
  		}
  	}
  
  	spin_unlock_irq(&blkcg->lock);
  	spin_unlock(&blkio_list_lock);
  
  free_newpn:
  	if (!keep_newpn)
  		kfree(newpn);
  free_buf:
  	kfree(buf);
  	return ret;
  }
  
  static int blkiocg_weight_device_read(struct cgroup *cgrp, struct cftype *cft,
  				      struct seq_file *m)
  {
  	struct blkio_cgroup *blkcg;
  	struct blkio_policy_node *pn;
  
  	seq_printf(m, "dev\tweight
  ");
  
  	blkcg = cgroup_to_blkio_cgroup(cgrp);
0f3942a39   Jens Axboe   block: kill some ...
800
801
802
803
804
805
806
807
  	if (!list_empty(&blkcg->policy_list)) {
  		spin_lock_irq(&blkcg->lock);
  		list_for_each_entry(pn, &blkcg->policy_list, node) {
  			seq_printf(m, "%u:%u\t%u
  ", MAJOR(pn->dev),
  				   MINOR(pn->dev), pn->weight);
  		}
  		spin_unlock_irq(&blkcg->lock);
34d0f179d   Gui Jianfeng   io-controller: Ad...
808
  	}
34d0f179d   Gui Jianfeng   io-controller: Ad...
809

34d0f179d   Gui Jianfeng   io-controller: Ad...
810
811
  	return 0;
  }
31e4c28d9   Vivek Goyal   blkio: Introduce ...
812
813
  struct cftype blkio_files[] = {
  	{
34d0f179d   Gui Jianfeng   io-controller: Ad...
814
815
816
817
818
819
  		.name = "weight_device",
  		.read_seq_string = blkiocg_weight_device_read,
  		.write_string = blkiocg_weight_device_write,
  		.max_write_len = 256,
  	},
  	{
31e4c28d9   Vivek Goyal   blkio: Introduce ...
820
821
822
823
  		.name = "weight",
  		.read_u64 = blkiocg_weight_read,
  		.write_u64 = blkiocg_weight_write,
  	},
220841906   Vivek Goyal   blkio: Export dis...
824
825
  	{
  		.name = "time",
303a3acb2   Divyesh Shah   blkio: Add io con...
826
  		.read_map = blkiocg_time_read,
220841906   Vivek Goyal   blkio: Export dis...
827
828
829
  	},
  	{
  		.name = "sectors",
303a3acb2   Divyesh Shah   blkio: Add io con...
830
  		.read_map = blkiocg_sectors_read,
303a3acb2   Divyesh Shah   blkio: Add io con...
831
832
833
834
  	},
  	{
  		.name = "io_service_bytes",
  		.read_map = blkiocg_io_service_bytes_read,
303a3acb2   Divyesh Shah   blkio: Add io con...
835
836
837
838
  	},
  	{
  		.name = "io_serviced",
  		.read_map = blkiocg_io_serviced_read,
303a3acb2   Divyesh Shah   blkio: Add io con...
839
840
841
842
  	},
  	{
  		.name = "io_service_time",
  		.read_map = blkiocg_io_service_time_read,
303a3acb2   Divyesh Shah   blkio: Add io con...
843
844
845
846
  	},
  	{
  		.name = "io_wait_time",
  		.read_map = blkiocg_io_wait_time_read,
84c124da9   Divyesh Shah   blkio: Changes to...
847
848
  	},
  	{
812d40264   Divyesh Shah   blkio: Add io_mer...
849
850
851
852
  		.name = "io_merged",
  		.read_map = blkiocg_io_merged_read,
  	},
  	{
cdc1184cf   Divyesh Shah   blkio: Add io_que...
853
854
855
856
  		.name = "io_queued",
  		.read_map = blkiocg_io_queued_read,
  	},
  	{
84c124da9   Divyesh Shah   blkio: Changes to...
857
858
  		.name = "reset_stats",
  		.write_u64 = blkiocg_reset_stats,
220841906   Vivek Goyal   blkio: Export dis...
859
860
  	},
  #ifdef CONFIG_DEBUG_BLK_CGROUP
cdc1184cf   Divyesh Shah   blkio: Add io_que...
861
862
863
864
865
  	{
  		.name = "avg_queue_size",
  		.read_map = blkiocg_avg_queue_size_read,
  	},
  	{
812df48d1   Divyesh Shah   blkio: Add more d...
866
867
868
869
870
871
872
873
874
875
876
877
  		.name = "group_wait_time",
  		.read_map = blkiocg_group_wait_time_read,
  	},
  	{
  		.name = "idle_time",
  		.read_map = blkiocg_idle_time_read,
  	},
  	{
  		.name = "empty_time",
  		.read_map = blkiocg_empty_time_read,
  	},
  	{
220841906   Vivek Goyal   blkio: Export dis...
878
  		.name = "dequeue",
303a3acb2   Divyesh Shah   blkio: Add io con...
879
  		.read_map = blkiocg_dequeue_read,
cdc1184cf   Divyesh Shah   blkio: Add io_que...
880
  	},
220841906   Vivek Goyal   blkio: Export dis...
881
  #endif
31e4c28d9   Vivek Goyal   blkio: Introduce ...
882
883
884
885
886
887
888
889
890
891
892
  };
  
  static int blkiocg_populate(struct cgroup_subsys *subsys, struct cgroup *cgroup)
  {
  	return cgroup_add_files(cgroup, subsys, blkio_files,
  				ARRAY_SIZE(blkio_files));
  }
  
  static void blkiocg_destroy(struct cgroup_subsys *subsys, struct cgroup *cgroup)
  {
  	struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup);
b1c357696   Vivek Goyal   blkio: Take care ...
893
894
895
  	unsigned long flags;
  	struct blkio_group *blkg;
  	void *key;
3e2520668   Vivek Goyal   blkio: Implement ...
896
  	struct blkio_policy_type *blkiop;
34d0f179d   Gui Jianfeng   io-controller: Ad...
897
  	struct blkio_policy_node *pn, *pntmp;
b1c357696   Vivek Goyal   blkio: Take care ...
898
899
  
  	rcu_read_lock();
0f3942a39   Jens Axboe   block: kill some ...
900
901
  	do {
  		spin_lock_irqsave(&blkcg->lock, flags);
b1c357696   Vivek Goyal   blkio: Take care ...
902

0f3942a39   Jens Axboe   block: kill some ...
903
904
905
906
  		if (hlist_empty(&blkcg->blkg_list)) {
  			spin_unlock_irqrestore(&blkcg->lock, flags);
  			break;
  		}
b1c357696   Vivek Goyal   blkio: Take care ...
907

0f3942a39   Jens Axboe   block: kill some ...
908
909
910
911
  		blkg = hlist_entry(blkcg->blkg_list.first, struct blkio_group,
  					blkcg_node);
  		key = rcu_dereference(blkg->key);
  		__blkiocg_del_blkio_group(blkg);
31e4c28d9   Vivek Goyal   blkio: Introduce ...
912

0f3942a39   Jens Axboe   block: kill some ...
913
  		spin_unlock_irqrestore(&blkcg->lock, flags);
b1c357696   Vivek Goyal   blkio: Take care ...
914

0f3942a39   Jens Axboe   block: kill some ...
915
916
917
918
919
920
921
922
923
924
925
926
  		/*
  		 * This blkio_group is being unlinked as associated cgroup is
  		 * going away. Let all the IO controlling policies know about
  		 * this event. Currently this is static call to one io
  		 * controlling policy. Once we have more policies in place, we
  		 * need some dynamic registration of callback function.
  		 */
  		spin_lock(&blkio_list_lock);
  		list_for_each_entry(blkiop, &blkio_list, list)
  			blkiop->ops.blkio_unlink_group_fn(key, blkg);
  		spin_unlock(&blkio_list_lock);
  	} while (1);
34d0f179d   Gui Jianfeng   io-controller: Ad...
927

34d0f179d   Gui Jianfeng   io-controller: Ad...
928
929
930
931
  	list_for_each_entry_safe(pn, pntmp, &blkcg->policy_list, node) {
  		blkio_policy_delete_node(pn);
  		kfree(pn);
  	}
0f3942a39   Jens Axboe   block: kill some ...
932

31e4c28d9   Vivek Goyal   blkio: Introduce ...
933
  	free_css_id(&blkio_subsys, &blkcg->css);
b1c357696   Vivek Goyal   blkio: Take care ...
934
  	rcu_read_unlock();
67523c48a   Ben Blum   cgroups: blkio su...
935
936
  	if (blkcg != &blkio_root_cgroup)
  		kfree(blkcg);
31e4c28d9   Vivek Goyal   blkio: Introduce ...
937
938
939
940
941
  }
  
  static struct cgroup_subsys_state *
  blkiocg_create(struct cgroup_subsys *subsys, struct cgroup *cgroup)
  {
0341509fd   Li Zefan   blk-cgroup: Fix a...
942
943
  	struct blkio_cgroup *blkcg;
  	struct cgroup *parent = cgroup->parent;
31e4c28d9   Vivek Goyal   blkio: Introduce ...
944

0341509fd   Li Zefan   blk-cgroup: Fix a...
945
  	if (!parent) {
31e4c28d9   Vivek Goyal   blkio: Introduce ...
946
947
948
949
950
  		blkcg = &blkio_root_cgroup;
  		goto done;
  	}
  
  	/* Currently we do not support hierarchy deeper than two level (0,1) */
0341509fd   Li Zefan   blk-cgroup: Fix a...
951
  	if (parent != cgroup->top_cgroup)
96aa1b419   Ciju Rajan K   blkio: Fix return...
952
  		return ERR_PTR(-EPERM);
31e4c28d9   Vivek Goyal   blkio: Introduce ...
953
954
955
956
957
958
959
960
961
  
  	blkcg = kzalloc(sizeof(*blkcg), GFP_KERNEL);
  	if (!blkcg)
  		return ERR_PTR(-ENOMEM);
  
  	blkcg->weight = BLKIO_WEIGHT_DEFAULT;
  done:
  	spin_lock_init(&blkcg->lock);
  	INIT_HLIST_HEAD(&blkcg->blkg_list);
34d0f179d   Gui Jianfeng   io-controller: Ad...
962
  	INIT_LIST_HEAD(&blkcg->policy_list);
31e4c28d9   Vivek Goyal   blkio: Introduce ...
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
  	return &blkcg->css;
  }
  
  /*
   * We cannot support shared io contexts, as we have no mean to support
   * two tasks with the same ioc in two different groups without major rework
   * of the main cic data structures.  For now we allow a task to change
   * its cgroup only if it's the only owner of its ioc.
   */
  static int blkiocg_can_attach(struct cgroup_subsys *subsys,
  				struct cgroup *cgroup, struct task_struct *tsk,
  				bool threadgroup)
  {
  	struct io_context *ioc;
  	int ret = 0;
  
  	/* task_lock() is needed to avoid races with exit_io_context() */
  	task_lock(tsk);
  	ioc = tsk->io_context;
  	if (ioc && atomic_read(&ioc->nr_tasks) > 1)
  		ret = -EINVAL;
  	task_unlock(tsk);
  
  	return ret;
  }
  
  static void blkiocg_attach(struct cgroup_subsys *subsys, struct cgroup *cgroup,
  				struct cgroup *prev, struct task_struct *tsk,
  				bool threadgroup)
  {
  	struct io_context *ioc;
  
  	task_lock(tsk);
  	ioc = tsk->io_context;
  	if (ioc)
  		ioc->cgroup_changed = 1;
  	task_unlock(tsk);
  }
3e2520668   Vivek Goyal   blkio: Implement ...
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
  void blkio_policy_register(struct blkio_policy_type *blkiop)
  {
  	spin_lock(&blkio_list_lock);
  	list_add_tail(&blkiop->list, &blkio_list);
  	spin_unlock(&blkio_list_lock);
  }
  EXPORT_SYMBOL_GPL(blkio_policy_register);
  
  void blkio_policy_unregister(struct blkio_policy_type *blkiop)
  {
  	spin_lock(&blkio_list_lock);
  	list_del_init(&blkiop->list);
  	spin_unlock(&blkio_list_lock);
  }
  EXPORT_SYMBOL_GPL(blkio_policy_unregister);
67523c48a   Ben Blum   cgroups: blkio su...
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
  
  static int __init init_cgroup_blkio(void)
  {
  	return cgroup_load_subsys(&blkio_subsys);
  }
  
  static void __exit exit_cgroup_blkio(void)
  {
  	cgroup_unload_subsys(&blkio_subsys);
  }
  
  module_init(init_cgroup_blkio);
  module_exit(exit_cgroup_blkio);
  MODULE_LICENSE("GPL");