blkio: Some debugging aids for CFQ
[safe/jmp/linux-2.6] / block / blk-cgroup.c
1 /*
2  * Common Block IO controller cgroup interface
3  *
4  * Based on ideas and code from CFQ, CFS and BFQ:
5  * Copyright (C) 2003 Jens Axboe <axboe@kernel.dk>
6  *
7  * Copyright (C) 2008 Fabio Checconi <fabio@gandalf.sssup.it>
8  *                    Paolo Valente <paolo.valente@unimore.it>
9  *
10  * Copyright (C) 2009 Vivek Goyal <vgoyal@redhat.com>
11  *                    Nauman Rafique <nauman@google.com>
12  */
13 #include <linux/ioprio.h>
14 #include "blk-cgroup.h"
15
16 extern void cfq_unlink_blkio_group(void *, struct blkio_group *);
17
18 struct blkio_cgroup blkio_root_cgroup = { .weight = 2*BLKIO_WEIGHT_DEFAULT };
19
20 struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup)
21 {
22         return container_of(cgroup_subsys_state(cgroup, blkio_subsys_id),
23                             struct blkio_cgroup, css);
24 }
25
26 void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
27                                 struct blkio_group *blkg, void *key)
28 {
29         unsigned long flags;
30
31         spin_lock_irqsave(&blkcg->lock, flags);
32         rcu_assign_pointer(blkg->key, key);
33         blkg->blkcg_id = css_id(&blkcg->css);
34         hlist_add_head_rcu(&blkg->blkcg_node, &blkcg->blkg_list);
35         spin_unlock_irqrestore(&blkcg->lock, flags);
36 #ifdef CONFIG_DEBUG_BLK_CGROUP
37         /* Need to take css reference ? */
38         cgroup_path(blkcg->css.cgroup, blkg->path, sizeof(blkg->path));
39 #endif
40 }
41
42 static void __blkiocg_del_blkio_group(struct blkio_group *blkg)
43 {
44         hlist_del_init_rcu(&blkg->blkcg_node);
45         blkg->blkcg_id = 0;
46 }
47
48 /*
49  * returns 0 if blkio_group was still on cgroup list. Otherwise returns 1
50  * indicating that blk_group was unhashed by the time we got to it.
51  */
52 int blkiocg_del_blkio_group(struct blkio_group *blkg)
53 {
54         struct blkio_cgroup *blkcg;
55         unsigned long flags;
56         struct cgroup_subsys_state *css;
57         int ret = 1;
58
59         rcu_read_lock();
60         css = css_lookup(&blkio_subsys, blkg->blkcg_id);
61         if (!css)
62                 goto out;
63
64         blkcg = container_of(css, struct blkio_cgroup, css);
65         spin_lock_irqsave(&blkcg->lock, flags);
66         if (!hlist_unhashed(&blkg->blkcg_node)) {
67                 __blkiocg_del_blkio_group(blkg);
68                 ret = 0;
69         }
70         spin_unlock_irqrestore(&blkcg->lock, flags);
71 out:
72         rcu_read_unlock();
73         return ret;
74 }
75
76 /* called under rcu_read_lock(). */
77 struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg, void *key)
78 {
79         struct blkio_group *blkg;
80         struct hlist_node *n;
81         void *__key;
82
83         hlist_for_each_entry_rcu(blkg, n, &blkcg->blkg_list, blkcg_node) {
84                 __key = blkg->key;
85                 if (__key == key)
86                         return blkg;
87         }
88
89         return NULL;
90 }
91
92 #define SHOW_FUNCTION(__VAR)                                            \
93 static u64 blkiocg_##__VAR##_read(struct cgroup *cgroup,                \
94                                        struct cftype *cftype)           \
95 {                                                                       \
96         struct blkio_cgroup *blkcg;                                     \
97                                                                         \
98         blkcg = cgroup_to_blkio_cgroup(cgroup);                         \
99         return (u64)blkcg->__VAR;                                       \
100 }
101
102 SHOW_FUNCTION(weight);
103 #undef SHOW_FUNCTION
104
105 static int
106 blkiocg_weight_write(struct cgroup *cgroup, struct cftype *cftype, u64 val)
107 {
108         struct blkio_cgroup *blkcg;
109
110         if (val < BLKIO_WEIGHT_MIN || val > BLKIO_WEIGHT_MAX)
111                 return -EINVAL;
112
113         blkcg = cgroup_to_blkio_cgroup(cgroup);
114         blkcg->weight = (unsigned int)val;
115         return 0;
116 }
117
118 struct cftype blkio_files[] = {
119         {
120                 .name = "weight",
121                 .read_u64 = blkiocg_weight_read,
122                 .write_u64 = blkiocg_weight_write,
123         },
124 };
125
126 static int blkiocg_populate(struct cgroup_subsys *subsys, struct cgroup *cgroup)
127 {
128         return cgroup_add_files(cgroup, subsys, blkio_files,
129                                 ARRAY_SIZE(blkio_files));
130 }
131
132 static void blkiocg_destroy(struct cgroup_subsys *subsys, struct cgroup *cgroup)
133 {
134         struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup);
135         unsigned long flags;
136         struct blkio_group *blkg;
137         void *key;
138
139         rcu_read_lock();
140 remove_entry:
141         spin_lock_irqsave(&blkcg->lock, flags);
142
143         if (hlist_empty(&blkcg->blkg_list)) {
144                 spin_unlock_irqrestore(&blkcg->lock, flags);
145                 goto done;
146         }
147
148         blkg = hlist_entry(blkcg->blkg_list.first, struct blkio_group,
149                                 blkcg_node);
150         key = rcu_dereference(blkg->key);
151         __blkiocg_del_blkio_group(blkg);
152
153         spin_unlock_irqrestore(&blkcg->lock, flags);
154
155         /*
156          * This blkio_group is being unlinked as associated cgroup is going
157          * away. Let all the IO controlling policies know about this event.
158          *
159          * Currently this is static call to one io controlling policy. Once
160          * we have more policies in place, we need some dynamic registration
161          * of callback function.
162          */
163         cfq_unlink_blkio_group(key, blkg);
164         goto remove_entry;
165 done:
166         free_css_id(&blkio_subsys, &blkcg->css);
167         rcu_read_unlock();
168         kfree(blkcg);
169 }
170
171 static struct cgroup_subsys_state *
172 blkiocg_create(struct cgroup_subsys *subsys, struct cgroup *cgroup)
173 {
174         struct blkio_cgroup *blkcg, *parent_blkcg;
175
176         if (!cgroup->parent) {
177                 blkcg = &blkio_root_cgroup;
178                 goto done;
179         }
180
181         /* Currently we do not support hierarchy deeper than two level (0,1) */
182         parent_blkcg = cgroup_to_blkio_cgroup(cgroup->parent);
183         if (css_depth(&parent_blkcg->css) > 0)
184                 return ERR_PTR(-EINVAL);
185
186         blkcg = kzalloc(sizeof(*blkcg), GFP_KERNEL);
187         if (!blkcg)
188                 return ERR_PTR(-ENOMEM);
189
190         blkcg->weight = BLKIO_WEIGHT_DEFAULT;
191 done:
192         spin_lock_init(&blkcg->lock);
193         INIT_HLIST_HEAD(&blkcg->blkg_list);
194
195         return &blkcg->css;
196 }
197
198 /*
199  * We cannot support shared io contexts, as we have no mean to support
200  * two tasks with the same ioc in two different groups without major rework
201  * of the main cic data structures.  For now we allow a task to change
202  * its cgroup only if it's the only owner of its ioc.
203  */
204 static int blkiocg_can_attach(struct cgroup_subsys *subsys,
205                                 struct cgroup *cgroup, struct task_struct *tsk,
206                                 bool threadgroup)
207 {
208         struct io_context *ioc;
209         int ret = 0;
210
211         /* task_lock() is needed to avoid races with exit_io_context() */
212         task_lock(tsk);
213         ioc = tsk->io_context;
214         if (ioc && atomic_read(&ioc->nr_tasks) > 1)
215                 ret = -EINVAL;
216         task_unlock(tsk);
217
218         return ret;
219 }
220
221 static void blkiocg_attach(struct cgroup_subsys *subsys, struct cgroup *cgroup,
222                                 struct cgroup *prev, struct task_struct *tsk,
223                                 bool threadgroup)
224 {
225         struct io_context *ioc;
226
227         task_lock(tsk);
228         ioc = tsk->io_context;
229         if (ioc)
230                 ioc->cgroup_changed = 1;
231         task_unlock(tsk);
232 }
233
234 struct cgroup_subsys blkio_subsys = {
235         .name = "blkio",
236         .create = blkiocg_create,
237         .can_attach = blkiocg_can_attach,
238         .attach = blkiocg_attach,
239         .destroy = blkiocg_destroy,
240         .populate = blkiocg_populate,
241         .subsys_id = blkio_subsys_id,
242         .use_id = 1,
243 };