ext3: new export ops
[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
45         task->ioprio = ioprio;
46
47         ioc = task->io_context;
48         /* see wmb() in current_io_context() */
49         smp_read_barrier_depends();
50
51         if (ioc)
52                 ioc->ioprio_changed = 1;
53
54         task_unlock(task);
55         return 0;
56 }
57
58 asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
59 {
60         int class = IOPRIO_PRIO_CLASS(ioprio);
61         int data = IOPRIO_PRIO_DATA(ioprio);
62         struct task_struct *p, *g;
63         struct user_struct *user;
64         struct pid *pgrp;
65         int ret;
66
67         switch (class) {
68                 case IOPRIO_CLASS_RT:
69                         if (!capable(CAP_SYS_ADMIN))
70                                 return -EPERM;
71                         /* fall through, rt has prio field too */
72                 case IOPRIO_CLASS_BE:
73                         if (data >= IOPRIO_BE_NR || data < 0)
74                                 return -EINVAL;
75
76                         break;
77                 case IOPRIO_CLASS_IDLE:
78                         if (!capable(CAP_SYS_ADMIN))
79                                 return -EPERM;
80                         break;
81                 default:
82                         return -EINVAL;
83         }
84
85         ret = -ESRCH;
86         /*
87          * We want IOPRIO_WHO_PGRP/IOPRIO_WHO_USER to be "atomic",
88          * so we can't use rcu_read_lock(). See re-copy of ->ioprio
89          * in copy_process().
90          */
91         read_lock(&tasklist_lock);
92         switch (which) {
93                 case IOPRIO_WHO_PROCESS:
94                         if (!who)
95                                 p = current;
96                         else
97                                 p = find_task_by_vpid(who);
98                         if (p)
99                                 ret = set_task_ioprio(p, ioprio);
100                         break;
101                 case IOPRIO_WHO_PGRP:
102                         if (!who)
103                                 pgrp = task_pgrp(current);
104                         else
105                                 pgrp = find_vpid(who);
106                         do_each_pid_task(pgrp, PIDTYPE_PGID, p) {
107                                 ret = set_task_ioprio(p, ioprio);
108                                 if (ret)
109                                         break;
110                         } while_each_pid_task(pgrp, PIDTYPE_PGID, p);
111                         break;
112                 case IOPRIO_WHO_USER:
113                         if (!who)
114                                 user = current->user;
115                         else
116                                 user = find_user(who);
117
118                         if (!user)
119                                 break;
120
121                         do_each_thread(g, p) {
122                                 if (p->uid != who)
123                                         continue;
124                                 ret = set_task_ioprio(p, ioprio);
125                                 if (ret)
126                                         goto free_uid;
127                         } while_each_thread(g, p);
128 free_uid:
129                         if (who)
130                                 free_uid(user);
131                         break;
132                 default:
133                         ret = -EINVAL;
134         }
135
136         read_unlock(&tasklist_lock);
137         return ret;
138 }
139
140 static int get_task_ioprio(struct task_struct *p)
141 {
142         int ret;
143
144         ret = security_task_getioprio(p);
145         if (ret)
146                 goto out;
147         ret = p->ioprio;
148 out:
149         return ret;
150 }
151
152 int ioprio_best(unsigned short aprio, unsigned short bprio)
153 {
154         unsigned short aclass = IOPRIO_PRIO_CLASS(aprio);
155         unsigned short bclass = IOPRIO_PRIO_CLASS(bprio);
156
157         if (aclass == IOPRIO_CLASS_NONE)
158                 aclass = IOPRIO_CLASS_BE;
159         if (bclass == IOPRIO_CLASS_NONE)
160                 bclass = IOPRIO_CLASS_BE;
161
162         if (aclass == bclass)
163                 return min(aprio, bprio);
164         if (aclass > bclass)
165                 return bprio;
166         else
167                 return aprio;
168 }
169
170 asmlinkage long sys_ioprio_get(int which, int who)
171 {
172         struct task_struct *g, *p;
173         struct user_struct *user;
174         struct pid *pgrp;
175         int ret = -ESRCH;
176         int tmpio;
177
178         read_lock(&tasklist_lock);
179         switch (which) {
180                 case IOPRIO_WHO_PROCESS:
181                         if (!who)
182                                 p = current;
183                         else
184                                 p = find_task_by_vpid(who);
185                         if (p)
186                                 ret = get_task_ioprio(p);
187                         break;
188                 case IOPRIO_WHO_PGRP:
189                         if (!who)
190                                 pgrp = task_pgrp(current);
191                         else
192                                 pgrp = find_vpid(who);
193                         do_each_pid_task(pgrp, PIDTYPE_PGID, p) {
194                                 tmpio = get_task_ioprio(p);
195                                 if (tmpio < 0)
196                                         continue;
197                                 if (ret == -ESRCH)
198                                         ret = tmpio;
199                                 else
200                                         ret = ioprio_best(ret, tmpio);
201                         } while_each_pid_task(pgrp, PIDTYPE_PGID, p);
202                         break;
203                 case IOPRIO_WHO_USER:
204                         if (!who)
205                                 user = current->user;
206                         else
207                                 user = find_user(who);
208
209                         if (!user)
210                                 break;
211
212                         do_each_thread(g, p) {
213                                 if (p->uid != user->uid)
214                                         continue;
215                                 tmpio = get_task_ioprio(p);
216                                 if (tmpio < 0)
217                                         continue;
218                                 if (ret == -ESRCH)
219                                         ret = tmpio;
220                                 else
221                                         ret = ioprio_best(ret, tmpio);
222                         } while_each_thread(g, p);
223
224                         if (who)
225                                 free_uid(user);
226                         break;
227                 default:
228                         ret = -EINVAL;
229         }
230
231         read_unlock(&tasklist_lock);
232         return ret;
233 }
234