Merge git://git.infradead.org/mtd-2.6
[linux-2.6] / fs / ioprio.c
1 /*
2  * fs/ioprio.c
3  *
4  * Copyright (C) 2004 Jens Axboe <axboe@kernel.dk>
5  *
6  * Helper functions for setting/querying io priorities of processes. The
7  * system calls closely mimmick getpriority/setpriority, see the man page for
8  * those. The prio argument is a composite of prio class and prio data, where
9  * the data argument has meaning within that class. The standard scheduling
10  * classes have 8 distinct prio levels, with 0 being the highest prio and 7
11  * being the lowest.
12  *
13  * IOW, setting BE scheduling class with prio 2 is done ala:
14  *
15  * unsigned int prio = (IOPRIO_CLASS_BE << IOPRIO_CLASS_SHIFT) | 2;
16  *
17  * ioprio_set(PRIO_PROCESS, pid, prio);
18  *
19  * See also Documentation/block/ioprio.txt
20  *
21  */
22 #include <linux/kernel.h>
23 #include <linux/ioprio.h>
24 #include <linux/blkdev.h>
25 #include <linux/capability.h>
26 #include <linux/syscalls.h>
27 #include <linux/security.h>
28 #include <linux/pid_namespace.h>
29
30 static int set_task_ioprio(struct task_struct *task, int ioprio)
31 {
32         int err;
33         struct io_context *ioc;
34
35         if (task->uid != current->euid &&
36             task->uid != current->uid && !capable(CAP_SYS_NICE))
37                 return -EPERM;
38
39         err = security_task_setioprio(task, ioprio);
40         if (err)
41                 return err;
42
43         task_lock(task);
44         do {
45                 ioc = task->io_context;
46                 /* see wmb() in current_io_context() */
47                 smp_read_barrier_depends();
48                 if (ioc)
49                         break;
50
51                 ioc = alloc_io_context(GFP_ATOMIC, -1);
52                 if (!ioc) {
53                         err = -ENOMEM;
54                         break;
55                 }
56                 task->io_context = ioc;
57         } while (1);
58
59         if (!err) {
60                 ioc->ioprio = ioprio;
61                 ioc->ioprio_changed = 1;
62         }
63
64         task_unlock(task);
65         return err;
66 }
67
68 asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
69 {
70         int class = IOPRIO_PRIO_CLASS(ioprio);
71         int data = IOPRIO_PRIO_DATA(ioprio);
72         struct task_struct *p, *g;
73         struct user_struct *user;
74         struct pid *pgrp;
75         int ret;
76
77         switch (class) {
78                 case IOPRIO_CLASS_RT:
79                         if (!capable(CAP_SYS_ADMIN))
80                                 return -EPERM;
81                         /* fall through, rt has prio field too */
82                 case IOPRIO_CLASS_BE:
83                         if (data >= IOPRIO_BE_NR || data < 0)
84                                 return -EINVAL;
85
86                         break;
87                 case IOPRIO_CLASS_IDLE:
88                         break;
89                 case IOPRIO_CLASS_NONE:
90                         if (data)
91                                 return -EINVAL;
92                         break;
93                 default:
94                         return -EINVAL;
95         }
96
97         ret = -ESRCH;
98         /*
99          * We want IOPRIO_WHO_PGRP/IOPRIO_WHO_USER to be "atomic",
100          * so we can't use rcu_read_lock(). See re-copy of ->ioprio
101          * in copy_process().
102          */
103         read_lock(&tasklist_lock);
104         switch (which) {
105                 case IOPRIO_WHO_PROCESS:
106                         if (!who)
107                                 p = current;
108                         else
109                                 p = find_task_by_vpid(who);
110                         if (p)
111                                 ret = set_task_ioprio(p, ioprio);
112                         break;
113                 case IOPRIO_WHO_PGRP:
114                         if (!who)
115                                 pgrp = task_pgrp(current);
116                         else
117                                 pgrp = find_vpid(who);
118                         do_each_pid_task(pgrp, PIDTYPE_PGID, p) {
119                                 ret = set_task_ioprio(p, ioprio);
120                                 if (ret)
121                                         break;
122                         } while_each_pid_task(pgrp, PIDTYPE_PGID, p);
123                         break;
124                 case IOPRIO_WHO_USER:
125                         if (!who)
126                                 user = current->user;
127                         else
128                                 user = find_user(who);
129
130                         if (!user)
131                                 break;
132
133                         do_each_thread(g, p) {
134                                 if (p->uid != who)
135                                         continue;
136                                 ret = set_task_ioprio(p, ioprio);
137                                 if (ret)
138                                         goto free_uid;
139                         } while_each_thread(g, p);
140 free_uid:
141                         if (who)
142                                 free_uid(user);
143                         break;
144                 default:
145                         ret = -EINVAL;
146         }
147
148         read_unlock(&tasklist_lock);
149         return ret;
150 }
151
152 static int get_task_ioprio(struct task_struct *p)
153 {
154         int ret;
155
156         ret = security_task_getioprio(p);
157         if (ret)
158                 goto out;
159         ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM);
160         if (p->io_context)
161                 ret = p->io_context->ioprio;
162 out:
163         return ret;
164 }
165
166 int ioprio_best(unsigned short aprio, unsigned short bprio)
167 {
168         unsigned short aclass = IOPRIO_PRIO_CLASS(aprio);
169         unsigned short bclass = IOPRIO_PRIO_CLASS(bprio);
170
171         if (aclass == IOPRIO_CLASS_NONE)
172                 aclass = IOPRIO_CLASS_BE;
173         if (bclass == IOPRIO_CLASS_NONE)
174                 bclass = IOPRIO_CLASS_BE;
175
176         if (aclass == bclass)
177                 return min(aprio, bprio);
178         if (aclass > bclass)
179                 return bprio;
180         else
181                 return aprio;
182 }
183
184 asmlinkage long sys_ioprio_get(int which, int who)
185 {
186         struct task_struct *g, *p;
187         struct user_struct *user;
188         struct pid *pgrp;
189         int ret = -ESRCH;
190         int tmpio;
191
192         read_lock(&tasklist_lock);
193         switch (which) {
194                 case IOPRIO_WHO_PROCESS:
195                         if (!who)
196                                 p = current;
197                         else
198                                 p = find_task_by_vpid(who);
199                         if (p)
200                                 ret = get_task_ioprio(p);
201                         break;
202                 case IOPRIO_WHO_PGRP:
203                         if (!who)
204                                 pgrp = task_pgrp(current);
205                         else
206                                 pgrp = find_vpid(who);
207                         do_each_pid_task(pgrp, PIDTYPE_PGID, p) {
208                                 tmpio = get_task_ioprio(p);
209                                 if (tmpio < 0)
210                                         continue;
211                                 if (ret == -ESRCH)
212                                         ret = tmpio;
213                                 else
214                                         ret = ioprio_best(ret, tmpio);
215                         } while_each_pid_task(pgrp, PIDTYPE_PGID, p);
216                         break;
217                 case IOPRIO_WHO_USER:
218                         if (!who)
219                                 user = current->user;
220                         else
221                                 user = find_user(who);
222
223                         if (!user)
224                                 break;
225
226                         do_each_thread(g, p) {
227                                 if (p->uid != user->uid)
228                                         continue;
229                                 tmpio = get_task_ioprio(p);
230                                 if (tmpio < 0)
231                                         continue;
232                                 if (ret == -ESRCH)
233                                         ret = tmpio;
234                                 else
235                                         ret = ioprio_best(ret, tmpio);
236                         } while_each_thread(g, p);
237
238                         if (who)
239                                 free_uid(user);
240                         break;
241                 default:
242                         ret = -EINVAL;
243         }
244
245         read_unlock(&tasklist_lock);
246         return ret;
247 }
248