blkio: Introduce blkio controller cgroup interface
[linux-2.6.git] / 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 struct blkio_cgroup blkio_root_cgroup = { .weight = 2*BLKIO_WEIGHT_DEFAULT };
17
18 struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup)
19 {
20         return container_of(cgroup_subsys_state(cgroup, blkio_subsys_id),
21                             struct blkio_cgroup, css);
22 }
23
24 void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
25                                 struct blkio_group *blkg, void *key)
26 {
27         unsigned long flags;
28
29         spin_lock_irqsave(&blkcg->lock, flags);
30         rcu_assign_pointer(blkg->key, key);
31         hlist_add_head_rcu(&blkg->blkcg_node, &blkcg->blkg_list);
32         spin_unlock_irqrestore(&blkcg->lock, flags);
33 }
34
35 int blkiocg_del_blkio_group(struct blkio_group *blkg)
36 {
37         /* Implemented later */
38         return 0;
39 }
40
41 /* called under rcu_read_lock(). */
42 struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg, void *key)
43 {
44         struct blkio_group *blkg;
45         struct hlist_node *n;
46         void *__key;
47
48         hlist_for_each_entry_rcu(blkg, n, &blkcg->blkg_list, blkcg_node) {
49                 __key = blkg->key;
50                 if (__key == key)
51                         return blkg;
52         }
53
54         return NULL;
55 }
56
57 #define SHOW_FUNCTION(__VAR)                                            \
58 static u64 blkiocg_##__VAR##_read(struct cgroup *cgroup,                \
59                                        struct cftype *cftype)           \
60 {                                                                       \
61         struct blkio_cgroup *blkcg;                                     \
62                                                                         \
63         blkcg = cgroup_to_blkio_cgroup(cgroup);                         \
64         return (u64)blkcg->__VAR;                                       \
65 }
66
67 SHOW_FUNCTION(weight);
68 #undef SHOW_FUNCTION
69
70 static int
71 blkiocg_weight_write(struct cgroup *cgroup, struct cftype *cftype, u64 val)
72 {
73         struct blkio_cgroup *blkcg;
74
75         if (val < BLKIO_WEIGHT_MIN || val > BLKIO_WEIGHT_MAX)
76                 return -EINVAL;
77
78         blkcg = cgroup_to_blkio_cgroup(cgroup);
79         blkcg->weight = (unsigned int)val;
80         return 0;
81 }
82
83 struct cftype blkio_files[] = {
84         {
85                 .name = "weight",
86                 .read_u64 = blkiocg_weight_read,
87                 .write_u64 = blkiocg_weight_write,
88         },
89 };
90
91 static int blkiocg_populate(struct cgroup_subsys *subsys, struct cgroup *cgroup)
92 {
93         return cgroup_add_files(cgroup, subsys, blkio_files,
94                                 ARRAY_SIZE(blkio_files));
95 }
96
97 static void blkiocg_destroy(struct cgroup_subsys *subsys, struct cgroup *cgroup)
98 {
99         struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup);
100
101         free_css_id(&blkio_subsys, &blkcg->css);
102         kfree(blkcg);
103 }
104
105 static struct cgroup_subsys_state *
106 blkiocg_create(struct cgroup_subsys *subsys, struct cgroup *cgroup)
107 {
108         struct blkio_cgroup *blkcg, *parent_blkcg;
109
110         if (!cgroup->parent) {
111                 blkcg = &blkio_root_cgroup;
112                 goto done;
113         }
114
115         /* Currently we do not support hierarchy deeper than two level (0,1) */
116         parent_blkcg = cgroup_to_blkio_cgroup(cgroup->parent);
117         if (css_depth(&parent_blkcg->css) > 0)
118                 return ERR_PTR(-EINVAL);
119
120         blkcg = kzalloc(sizeof(*blkcg), GFP_KERNEL);
121         if (!blkcg)
122                 return ERR_PTR(-ENOMEM);
123
124         blkcg->weight = BLKIO_WEIGHT_DEFAULT;
125 done:
126         spin_lock_init(&blkcg->lock);
127         INIT_HLIST_HEAD(&blkcg->blkg_list);
128
129         return &blkcg->css;
130 }
131
132 /*
133  * We cannot support shared io contexts, as we have no mean to support
134  * two tasks with the same ioc in two different groups without major rework
135  * of the main cic data structures.  For now we allow a task to change
136  * its cgroup only if it's the only owner of its ioc.
137  */
138 static int blkiocg_can_attach(struct cgroup_subsys *subsys,
139                                 struct cgroup *cgroup, struct task_struct *tsk,
140                                 bool threadgroup)
141 {
142         struct io_context *ioc;
143         int ret = 0;
144
145         /* task_lock() is needed to avoid races with exit_io_context() */
146         task_lock(tsk);
147         ioc = tsk->io_context;
148         if (ioc && atomic_read(&ioc->nr_tasks) > 1)
149                 ret = -EINVAL;
150         task_unlock(tsk);
151
152         return ret;
153 }
154
155 static void blkiocg_attach(struct cgroup_subsys *subsys, struct cgroup *cgroup,
156                                 struct cgroup *prev, struct task_struct *tsk,
157                                 bool threadgroup)
158 {
159         struct io_context *ioc;
160
161         task_lock(tsk);
162         ioc = tsk->io_context;
163         if (ioc)
164                 ioc->cgroup_changed = 1;
165         task_unlock(tsk);
166 }
167
168 struct cgroup_subsys blkio_subsys = {
169         .name = "blkio",
170         .create = blkiocg_create,
171         .can_attach = blkiocg_can_attach,
172         .attach = blkiocg_attach,
173         .destroy = blkiocg_destroy,
174         .populate = blkiocg_populate,
175         .subsys_id = blkio_subsys_id,
176         .use_id = 1,
177 };